From: Yu Watanabe Date: Mon, 17 May 2021 18:42:19 +0000 (+0900) Subject: network: introduce UplinkInterface= setting for DHCP server X-Git-Tag: v249-rc1~76^2~49 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=165d7c5c4210669890a360579d72aa47de25522e;p=thirdparty%2Fsystemd.git network: introduce UplinkInterface= setting for DHCP server --- diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 18a2c1030ef..020a5ffb721 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -2405,6 +2405,16 @@ IPv6Token=prefixstable:2002:da8:1:: network traffic. + + UplinkInterface= + Specifies name or index of uplink interface, or one of the special values + :none and :auto. When emitting DNS, NTP, or SIP servers + are enabled but no servers are specified, the servers configured in the uplink interface will + be emitted. When :auto, the link which has default gateway with higher + priority will be automatically selected. When :none, no uplink interface + will be selected. Defaults to :auto. + + EmitDNS= DNS= diff --git a/src/network/networkd-dhcp-server.c b/src/network/networkd-dhcp-server.c index 3443e498a16..055aa82ba24 100644 --- a/src/network/networkd-dhcp-server.c +++ b/src/network/networkd-dhcp-server.c @@ -97,6 +97,26 @@ static int link_find_dhcp_server_address(Link *link, Address **ret) { return -ENOENT; } +static int dhcp_server_find_uplink(Link *link, Link **ret) { + assert(link); + + if (link->network->dhcp_server_uplink_name) + return link_get_by_name(link->manager, link->network->dhcp_server_uplink_name, ret); + + if (link->network->dhcp_server_uplink_index > 0) + return link_get(link->manager, link->network->dhcp_server_uplink_index, ret); + + if (link->network->dhcp_server_uplink_index == 0) { + /* It is not necessary to propagate error in automatic selection. */ + if (manager_find_uplink(link->manager, AF_INET, link, ret) < 0) + *ret = NULL; + return 0; + } + + *ret = NULL; + return 0; +} + static int link_push_uplink_to_dhcp_server( Link *link, sd_dhcp_lease_server_type_t what, @@ -363,7 +383,7 @@ static int dhcp4_server_configure(Link *link) { else { /* Emission is requested, but nothing explicitly configured. Let's find a suitable upling */ if (!acquired_uplink) { - (void) manager_find_uplink(link->manager, AF_INET, link, &uplink); + (void) dhcp_server_find_uplink(link, &uplink); acquired_uplink = true; } @@ -468,6 +488,7 @@ int link_request_dhcp_server(Link *link) { } static bool dhcp_server_is_ready_to_configure(Link *link) { + Link *uplink = NULL; Address *a; assert(link); @@ -493,6 +514,12 @@ static bool dhcp_server_is_ready_to_configure(Link *link) { if (!address_is_ready(a)) return false; + if (dhcp_server_find_uplink(link, &uplink) < 0) + return false; + + if (uplink && !uplink->network) + return false; + return true; } @@ -633,3 +660,55 @@ int config_parse_dhcp_server_address( network->dhcp_server_address_prefixlen = prefixlen; return 0; } + +int config_parse_dhcp_server_uplink( + 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; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + + if (isempty(rvalue) || streq(rvalue, ":auto")) { + network->dhcp_server_uplink_index = 0; /* uplink will be selected automatically */ + network->dhcp_server_uplink_name = mfree(network->dhcp_server_uplink_name); + return 0; + } + + if (streq(rvalue, ":none")) { + network->dhcp_server_uplink_index = -1; /* uplink will not be selected automatically */ + network->dhcp_server_uplink_name = mfree(network->dhcp_server_uplink_name); + return 0; + } + + r = parse_ifindex(rvalue); + if (r > 0) { + network->dhcp_server_uplink_index = r; + network->dhcp_server_uplink_name = mfree(network->dhcp_server_uplink_name); + return 0; + } + + if (!ifname_valid_full(rvalue, IFNAME_VALID_ALTERNATIVE)) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "Invalid interface name in %s=, ignoring assignment: %s", lvalue, rvalue); + return 0; + } + + r = free_and_strdup_warn(&network->dhcp_server_uplink_name, rvalue); + if (r < 0) + return r; + + network->dhcp_server_uplink_index = 0; + return 0; +} diff --git a/src/network/networkd-dhcp-server.h b/src/network/networkd-dhcp-server.h index a02cd995ec0..3f23f97bb8d 100644 --- a/src/network/networkd-dhcp-server.h +++ b/src/network/networkd-dhcp-server.h @@ -15,3 +15,4 @@ int request_process_dhcp_server(Request *req); 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); +CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_server_uplink); diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index a0da17ab031..c1e4efd1e4f 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -264,6 +264,7 @@ IPv6AcceptRA.PrefixDenyList, config_parse_ndisc_address_filter, 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.UplinkInterface, config_parse_dhcp_server_uplink, 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) diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index 3f2dac62c51..143e49b4ac6 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -617,6 +617,7 @@ static Network *network_free(Network *network) { free(network->name); free(network->dhcp_server_timezone); + free(network->dhcp_server_uplink_name); for (sd_dhcp_lease_server_type_t t = 0; t < _SD_DHCP_LEASE_SERVER_TYPE_MAX; t++) free(network->dhcp_server_emit[t].addresses); diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index ca472a61744..7436b8ea321 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -191,6 +191,8 @@ struct Network { bool dhcp_server_bind_to_interface; unsigned char dhcp_server_address_prefixlen; struct in_addr dhcp_server_address; + int dhcp_server_uplink_index; + char *dhcp_server_uplink_name; struct in_addr dhcp_server_relay_target; char *dhcp_server_relay_agent_circuit_id; char *dhcp_server_relay_agent_remote_id; diff --git a/test/fuzz/fuzz-network-parser/directives.network b/test/fuzz/fuzz-network-parser/directives.network index 05b67512ae8..195ed8f0cc8 100644 --- a/test/fuzz/fuzz-network-parser/directives.network +++ b/test/fuzz/fuzz-network-parser/directives.network @@ -366,6 +366,7 @@ RelayTarget= RelayAgentCircuitId= RelayAgentRemoteId= ServerAddress= +UplinkInterface= [DHCPServerStaticLease] MACAddress= Address=