mirror of
https://github.com/systemd/systemd-stable.git
synced 2024-12-22 13:33:56 +03:00
network: dhcp-server: introduce ServerAddress= setting
This may be useful when the link which DHCP server running on has multiple static addresses.
This commit is contained in:
parent
998545a7d9
commit
0017ba3165
@ -2344,6 +2344,14 @@ IPv6Token=prefixstable:2002:da8:1::</programlisting></para>
|
||||
|
||||
<variablelist class='network-directives'>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>ServerAddress=</varname></term>
|
||||
<listitem><para>Specifies server address for the DHCP server. Takes an IPv4 address with prefix
|
||||
length, e.g., <literal>192.168.0.1/24</literal>. This setting may be useful when the link which
|
||||
DHCP server running on has multiple static addresses. When unset, one of static addresses in
|
||||
the link will be automatically selected. Defaults to unset.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>PoolOffset=</varname></term>
|
||||
<term><varname>PoolSize=</varname></term>
|
||||
|
@ -1157,6 +1157,32 @@ int link_request_static_addresses(Link *link) {
|
||||
req->after_configure = static_address_after_configure;
|
||||
}
|
||||
|
||||
if (in4_addr_is_set(&link->network->dhcp_server_address)) {
|
||||
_cleanup_(address_freep) Address *address = NULL;
|
||||
|
||||
r = address_new(&address);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
address->family = AF_INET;
|
||||
address->in_addr.in = link->network->dhcp_server_address;
|
||||
address->prefixlen = link->network->dhcp_server_address_prefixlen;
|
||||
address_set_broadcast(address);
|
||||
|
||||
/* The same address may be explicitly configured in [Address] or [Network] section.
|
||||
* Configure the DHCP server address only when it is not. */
|
||||
if (!link_is_static_address_configured(link, address)) {
|
||||
Request *req;
|
||||
|
||||
r = link_request_address(link, TAKE_PTR(address), true, &link->static_address_messages,
|
||||
static_address_handler, &req);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
req->after_configure = static_address_after_configure;
|
||||
}
|
||||
}
|
||||
|
||||
if (link->static_address_messages == 0) {
|
||||
link->static_addresses_configured = true;
|
||||
link_check_ready(link);
|
||||
|
@ -29,33 +29,70 @@ static bool link_dhcp4_server_enabled(Link *link) {
|
||||
if (!link->network)
|
||||
return false;
|
||||
|
||||
if (link->network->bond)
|
||||
return false;
|
||||
|
||||
if (link->iftype == ARPHRD_CAN)
|
||||
return false;
|
||||
|
||||
return link->network->dhcp_server;
|
||||
}
|
||||
|
||||
static Address* link_find_dhcp_server_address(Link *link) {
|
||||
void network_adjust_dhcp_server(Network *network) {
|
||||
assert(network);
|
||||
|
||||
if (!network->dhcp_server)
|
||||
return;
|
||||
|
||||
if (network->bond) {
|
||||
log_warning("%s: DHCPServer= is enabled for bond slave. Disabling DHCP server.",
|
||||
network->filename);
|
||||
network->dhcp_server = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!in4_addr_is_set(&network->dhcp_server_address)) {
|
||||
Address *address;
|
||||
bool have = false;
|
||||
|
||||
ORDERED_HASHMAP_FOREACH(address, network->addresses_by_section) {
|
||||
if (section_is_invalid(address->section))
|
||||
continue;
|
||||
if (address->family == AF_INET &&
|
||||
!in4_addr_is_localhost(&address->in_addr.in) &&
|
||||
in4_addr_is_null(&address->in_addr_peer.in)) {
|
||||
have = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!have) {
|
||||
log_warning("%s: DHCPServer= is enabled, but no static address configured. "
|
||||
"Disabling DHCP server.",
|
||||
network->filename);
|
||||
network->dhcp_server = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int link_find_dhcp_server_address(Link *link, Address **ret) {
|
||||
Address *address;
|
||||
|
||||
assert(link);
|
||||
assert(link->network);
|
||||
|
||||
/* The first statically configured address if there is any */
|
||||
ORDERED_HASHMAP_FOREACH(address, link->network->addresses_by_section)
|
||||
/* If ServerAddress= is specified, then use the address. */
|
||||
if (in4_addr_is_set(&link->network->dhcp_server_address))
|
||||
return link_get_ipv4_address(link, &link->network->dhcp_server_address,
|
||||
link->network->dhcp_server_address_prefixlen, ret);
|
||||
|
||||
/* If not, then select one from static addresses. */
|
||||
SET_FOREACH(address, link->static_addresses)
|
||||
if (address->family == AF_INET &&
|
||||
in_addr_is_set(address->family, &address->in_addr))
|
||||
return address;
|
||||
!in4_addr_is_localhost(&address->in_addr.in) &&
|
||||
in4_addr_is_null(&address->in_addr_peer.in)) {
|
||||
*ret = address;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If that didn't work, find a suitable address we got from the pool */
|
||||
SET_FOREACH(address, link->pool_addresses)
|
||||
if (address->family == AF_INET)
|
||||
return address;
|
||||
|
||||
return NULL;
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static int link_push_uplink_to_dhcp_server(
|
||||
@ -277,10 +314,9 @@ int dhcp4_server_configure(Link *link) {
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "Failed to set callback for DHCPv4 server instance: %m");
|
||||
|
||||
address = link_find_dhcp_server_address(link);
|
||||
if (!address)
|
||||
return log_link_error_errno(link, SYNTHETIC_ERRNO(EBUSY),
|
||||
"Failed to find suitable address for DHCPv4 server instance.");
|
||||
r = link_find_dhcp_server_address(link, &address);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Failed to find suitable address for DHCPv4 server instance: %m");
|
||||
|
||||
/* use the server address' subnet as the pool */
|
||||
r = sd_dhcp_server_configure_pool(link->dhcp_server, &address->in_addr.in, address->prefixlen,
|
||||
@ -429,7 +465,6 @@ int config_parse_dhcp_server_relay_agent_suboption(
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
|
||||
|
||||
if (isempty(rvalue)) {
|
||||
*suboption_value = mfree(*suboption_value);
|
||||
return 0;
|
||||
@ -492,3 +527,48 @@ int config_parse_dhcp_server_emit(
|
||||
emit->addresses[emit->n_addresses++] = a.in;
|
||||
}
|
||||
}
|
||||
|
||||
int config_parse_dhcp_server_address(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
const char *section,
|
||||
unsigned section_line,
|
||||
const char *lvalue,
|
||||
int ltype,
|
||||
const char *rvalue,
|
||||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
Network *network = userdata;
|
||||
union in_addr_union a;
|
||||
unsigned char prefixlen;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
|
||||
if (isempty(rvalue)) {
|
||||
network->dhcp_server_address = (struct in_addr) {};
|
||||
network->dhcp_server_address_prefixlen = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = in_addr_prefix_from_string(rvalue, AF_INET, &a, &prefixlen);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, r,
|
||||
"Failed to parse %s=, ignoring assignment: %s", lvalue, rvalue);
|
||||
return 0;
|
||||
}
|
||||
if (in4_addr_is_null(&a.in) || in4_addr_is_localhost(&a.in)) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, 0,
|
||||
"DHCP server address cannot be the ANY address or a localhost address, "
|
||||
"ignoring assignment: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
network->dhcp_server_address = a.in;
|
||||
network->dhcp_server_address_prefixlen = prefixlen;
|
||||
return 0;
|
||||
}
|
||||
|
@ -2,12 +2,14 @@
|
||||
#pragma once
|
||||
|
||||
#include "conf-parser.h"
|
||||
#include "networkd-link.h"
|
||||
#include "networkd-util.h"
|
||||
|
||||
typedef struct Link Link;
|
||||
typedef struct Network Network;
|
||||
|
||||
void network_adjust_dhcp_server(Network *network);
|
||||
|
||||
int dhcp4_server_configure(Link *link);
|
||||
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_server_relay_agent_suboption);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_server_emit);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_server_address);
|
||||
|
@ -261,6 +261,7 @@ IPv6AcceptRA.PrefixAllowList, config_parse_ndisc_address_filter,
|
||||
IPv6AcceptRA.PrefixDenyList, config_parse_ndisc_address_filter, 0, offsetof(Network, ndisc_deny_listed_prefix)
|
||||
IPv6AcceptRA.RouteAllowList, config_parse_ndisc_address_filter, 0, offsetof(Network, ndisc_allow_listed_route_prefix)
|
||||
IPv6AcceptRA.RouteDenyList, config_parse_ndisc_address_filter, 0, offsetof(Network, ndisc_deny_listed_route_prefix)
|
||||
DHCPServer.ServerAddress, config_parse_dhcp_server_address, 0, 0
|
||||
DHCPServer.RelayTarget, config_parse_in_addr_non_null, AF_INET, offsetof(Network, dhcp_server_relay_target)
|
||||
DHCPServer.RelayAgentCircuitId, config_parse_dhcp_server_relay_agent_suboption, 0, offsetof(Network, dhcp_server_relay_agent_circuit_id)
|
||||
DHCPServer.RelayAgentRemoteId, config_parse_dhcp_server_relay_agent_suboption, 0, offsetof(Network, dhcp_server_relay_agent_remote_id)
|
||||
|
@ -240,6 +240,8 @@ int network_verify(Network *network) {
|
||||
network_drop_invalid_traffic_control(network);
|
||||
network_drop_invalid_sr_iov(network);
|
||||
|
||||
network_adjust_dhcp_server(network);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -189,10 +189,11 @@ struct Network {
|
||||
/* DHCP Server Support */
|
||||
bool dhcp_server;
|
||||
bool dhcp_server_bind_to_interface;
|
||||
unsigned char dhcp_server_address_prefixlen;
|
||||
struct in_addr dhcp_server_address;
|
||||
struct in_addr dhcp_server_relay_target;
|
||||
char *dhcp_server_relay_agent_circuit_id;
|
||||
char *dhcp_server_relay_agent_remote_id;
|
||||
|
||||
NetworkDHCPServerEmitAddress dhcp_server_emit[_SD_DHCP_LEASE_SERVER_TYPE_MAX];
|
||||
bool dhcp_server_emit_router;
|
||||
bool dhcp_server_emit_timezone;
|
||||
|
@ -364,6 +364,7 @@ BindToInterface=
|
||||
RelayTarget=
|
||||
RelayAgentCircuitId=
|
||||
RelayAgentRemoteId=
|
||||
ServerAddress=
|
||||
[NextHop]
|
||||
Id=
|
||||
Gateway=
|
||||
|
Loading…
Reference in New Issue
Block a user