]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network: introduce UplinkInterface= setting for DHCP server
authorYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 17 May 2021 18:42:19 +0000 (03:42 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 7 Jun 2021 21:33:27 +0000 (06:33 +0900)
man/systemd.network.xml
src/network/networkd-dhcp-server.c
src/network/networkd-dhcp-server.h
src/network/networkd-network-gperf.gperf
src/network/networkd-network.c
src/network/networkd-network.h
test/fuzz/fuzz-network-parser/directives.network

index 18a2c1030ef0163a461e2aa7c6570718f41ea5ca..020a5ffb721de4e833014ecfcc3aa663f088bed9 100644 (file)
@@ -2405,6 +2405,16 @@ IPv6Token=prefixstable:2002:da8:1::</programlisting></para>
         network traffic.</para></listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><varname>UplinkInterface=</varname></term>
+        <listitem><para>Specifies name or index of uplink interface, or one of the special values
+        <literal>:none</literal> and <literal>:auto</literal>. 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 <literal>:auto</literal>, the link which has default gateway with higher
+        priority will be automatically selected. When <literal>:none</literal>, no uplink interface
+        will be selected. Defaults to <literal>:auto</literal>.</para></listitem>
+      </varlistentry>
+
       <varlistentry>
         <term><varname>EmitDNS=</varname></term>
         <term><varname>DNS=</varname></term>
index 3443e498a16c50df45f737422565653a321656d5..055aa82ba249e00a44fe34442340a47f9d15433a 100644 (file)
@@ -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;
+}
index a02cd995ec049c3247a9417add3d072a7709cdc6..3f23f97bb8dbb789a268eba197711e41be5a830c 100644 (file)
@@ -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);
index a0da17ab031b1cc01bc8e467ee2a5404b944f8cc..c1e4efd1e4f8dff063489054939a30c3f416a1ab 100644 (file)
@@ -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)
index 3f2dac62c51ac5bdb533758af5ff8de4d7ea00ac..143e49b4ac6cce9636606ea2a06044647d47bb78 100644 (file)
@@ -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);
index ca472a6174482b2866f2b4371ac333ca12c70363..7436b8ea32109472eae3ce2e2725064e231c325e 100644 (file)
@@ -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;
index 05b67512ae8c48a9a23a88ebadfb9aa206f8fce1..195ed8f0cc8d13591076436fafc571e8e298dfd6 100644 (file)
@@ -366,6 +366,7 @@ RelayTarget=
 RelayAgentCircuitId=
 RelayAgentRemoteId=
 ServerAddress=
+UplinkInterface=
 [DHCPServerStaticLease]
 MACAddress=
 Address=