]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network: introduce KeepMaster= setting
authorYu Watanabe <watanabe.yu+github@gmail.com>
Thu, 2 Sep 2021 21:10:07 +0000 (06:10 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Fri, 3 Sep 2021 15:23:20 +0000 (00:23 +0900)
Closes #20624.

man/systemd.network.xml
src/network/networkd-bridge-mdb.c
src/network/networkd-network-gperf.gperf
src/network/networkd-network.c
src/network/networkd-network.h
src/network/networkd-setlink.c
test/fuzz/fuzz-network-parser/directives.network

index 0fb749a1f9344507466261bfbe9ba1cc4ad2250b..48326a25c123ae8321dc2417c0ff8212975eeb72 100644 (file)
             has been unsuccessful for some time. (IPv4 link-local address autoconfiguration will usually
             happen in parallel with repeated attempts to acquire a DHCPv4 lease).</para>
 
-            <para>Defaults to <option>no</option> when <varname>Bridge=</varname> is set or when the specified
+            <para>Defaults to <option>no</option> when <varname>KeepMaster=</varname> or
+            <varname>Bridge=</varname> is set or when the specified
             <varname>MACVLAN=</varname>/<varname>MACVTAP=</varname> has <varname>Mode=passthru</varname>, or
             <option>ipv6</option> otherwise.</para>
           </listitem>
@@ -923,6 +924,20 @@ IPv6Token=prefixstable:2002:da8:1::</programlisting></para>
           An integer greater than or equal to 1280 bytes. When unset, the kernel's default will be used.
           </para></listitem>
         </varlistentry>
+        <varlistentry>
+          <term><varname>KeepMaster=</varname></term>
+          <term><varname>Bond=</varname></term>
+          <term><varname>Bridge=</varname></term>
+          <term><varname>VRF=</varname></term>
+          <listitem>
+            <para>Takes a boolean value. When enabled, the current master interface index will not be
+            changed, and <varname>BatmanAdvanced=</varname>, <varname>Bond=</varname>,
+            <varname>Bridge=</varname>, and <varname>VRF=</varname> settings are ignored. This may be
+            useful when a netdev with a master interface is created by another program, e.g.
+            <citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry>.
+            Defaults to false.</para>
+          </listitem>
+        </varlistentry>
         <varlistentry>
           <term><varname>BatmanAdvanced=</varname></term>
           <term><varname>Bond=</varname></term>
index 6cd10c78e02e7b04342a381bcb043eacebfebf1b..ed8a10cad809f468d84b29f43a1364acc0439cbc 100644 (file)
@@ -190,16 +190,6 @@ int link_request_static_bridge_mdb(Link *link) {
         if (hashmap_isempty(link->network->bridge_mdb_entries_by_section))
                 goto finish;
 
-        if (!link->network->bridge) {
-                if (!streq_ptr(link->kind, "bridge")) {
-                        log_link_warning(link, "Link is neither a bridge master nor a bridge port, ignoring [BridgeMDB] sections.");
-                        goto finish;
-                } else if (link->manager->bridge_mdb_on_master_not_supported) {
-                        log_link_debug(link, "Kernel seems not to support bridge MDB entries on bridge master, ignoring [BridgeMDB] sections.");
-                        goto finish;
-                }
-        }
-
         HASHMAP_FOREACH(mdb, link->network->bridge_mdb_entries_by_section) {
                 r = link_queue_request(link, REQUEST_TYPE_BRIDGE_MDB, mdb, false,
                                        &link->static_bridge_mdb_messages, bridge_mdb_configure_handler, NULL);
index 405ddccc8b53863818474acfbb93d853cf85a4d1..ef5248fa38209c0a644d88081f78ec4c841951d8 100644 (file)
@@ -79,6 +79,7 @@ SR-IOV.Trust,                                config_parse_sr_iov_boolean,
 SR-IOV.LinkState,                            config_parse_sr_iov_link_state,                           0,                             0
 SR-IOV.MACAddress,                           config_parse_sr_iov_mac,                                  0,                             0
 Network.Description,                         config_parse_string,                                      0,                             offsetof(Network, description)
+Network.KeepMaster,                          config_parse_bool,                                        0,                             offsetof(Network, keep_master)
 Network.BatmanAdvanced,                      config_parse_ifname,                                      0,                             offsetof(Network, batadv_name)
 Network.Bond,                                config_parse_ifname,                                      0,                             offsetof(Network, bond_name)
 Network.Bridge,                              config_parse_ifname,                                      0,                             offsetof(Network, bridge_name)
index cdca91c7c2e78838c33f7bcdc41694729a142948..4aee6fa43cac19a668880fcc01cf5e9131dc8fc0 100644 (file)
@@ -135,6 +135,26 @@ int network_verify(Network *network) {
                                        "%s: Conditions in the file do not match the system environment, skipping.",
                                        network->filename);
 
+        if (network->keep_master) {
+                if (network->batadv_name)
+                        log_warning("%s: BatmanAdvanced= set with KeepMaster= enabled, ignoring BatmanAdvanced=.",
+                                    network->filename);
+                if (network->bond_name)
+                        log_warning("%s: Bond= set with KeepMaster= enabled, ignoring Bond=.",
+                                    network->filename);
+                if (network->bridge_name)
+                        log_warning("%s: Bridge= set with KeepMaster= enabled, ignoring Bridge=.",
+                                    network->filename);
+                if (network->vrf_name)
+                        log_warning("%s: VRF= set with KeepMaster= enabled, ignoring VRF=.",
+                                    network->filename);
+
+                network->batadv_name = mfree(network->batadv_name);
+                network->bond_name = mfree(network->bond_name);
+                network->bridge_name = mfree(network->bridge_name);
+                network->vrf_name = mfree(network->vrf_name);
+        }
+
         (void) network_resolve_netdev_one(network, network->batadv_name, NETDEV_KIND_BATADV, &network->batadv);
         (void) network_resolve_netdev_one(network, network->bond_name, NETDEV_KIND_BOND, &network->bond);
         (void) network_resolve_netdev_one(network, network->bridge_name, NETDEV_KIND_BRIDGE, &network->bridge);
@@ -174,7 +194,7 @@ int network_verify(Network *network) {
         if (network->link_local < 0) {
                 network->link_local = ADDRESS_FAMILY_IPV6;
 
-                if (network->bridge)
+                if (network->keep_master || network->bridge)
                         network->link_local = ADDRESS_FAMILY_NO;
                 else {
                         NetDev *netdev;
index 95c86e72304066423dd4593be59f11655458615c..81d484ce535b04cddf378d58f4bb970ce796ff9c 100644 (file)
@@ -84,6 +84,7 @@ struct Network {
         LIST_HEAD(Condition, conditions);
 
         /* Master or stacked netdevs */
+        bool keep_master;
         NetDev *batadv;
         NetDev *bridge;
         NetDev *bond;
index 06aa2067f70255564a9c377c112e51f0c0f5bd7d..21e20f10f5958a9bc6a47744d509588c06b22294 100644 (file)
@@ -515,9 +515,16 @@ static bool link_is_ready_to_call_set_link(Request *req) {
         switch (op) {
         case SET_LINK_BOND:
         case SET_LINK_BRIDGE:
+                if (!link->master_set)
+                        return false;
+                if (link->network->keep_master && link->master_ifindex <= 0)
+                        return false;
+                break;
         case SET_LINK_BRIDGE_VLAN:
                 if (!link->master_set)
                         return false;
+                if (link->network->keep_master && link->master_ifindex <= 0 && !streq_ptr(link->kind, "bridge"))
+                        return false;
                 break;
         case SET_LINK_CAN:
                 /* Do not check link->set_flgas_messages here, as it is ok even if link->flags
@@ -672,8 +679,18 @@ int link_request_to_set_bond(Link *link) {
         assert(link);
         assert(link->network);
 
-        if (!link->network->bond)
-                return 0;
+        if (!link->network->bond) {
+                Link *master;
+
+                if (!link->network->keep_master)
+                        return 0;
+
+                if (link_get_master(link, &master) < 0)
+                        return 0;
+
+                if (!streq_ptr(master->kind, "bond"))
+                        return 0;
+        }
 
         return link_request_set_link(link, SET_LINK_BOND, link_set_bond_handler, NULL);
 }
@@ -682,8 +699,18 @@ int link_request_to_set_bridge(Link *link) {
         assert(link);
         assert(link->network);
 
-        if (!link->network->bridge)
-                return 0;
+        if (!link->network->bridge) {
+                Link *master;
+
+                if (!link->network->keep_master)
+                        return 0;
+
+                if (link_get_master(link, &master) < 0)
+                        return 0;
+
+                if (!streq_ptr(master->kind, "bridge"))
+                        return 0;
+        }
 
         return link_request_set_link(link, SET_LINK_BRIDGE, link_set_bridge_handler, NULL);
 }
@@ -695,8 +722,18 @@ int link_request_to_set_bridge_vlan(Link *link) {
         if (!link->network->use_br_vlan)
                 return 0;
 
-        if (!link->network->bridge && !streq_ptr(link->kind, "bridge"))
-                return 0;
+        if (!link->network->bridge && !streq_ptr(link->kind, "bridge")) {
+                Link *master;
+
+                if (!link->network->keep_master)
+                        return 0;
+
+                if (link_get_master(link, &master) < 0)
+                        return 0;
+
+                if (!streq_ptr(master->kind, "bridge"))
+                        return 0;
+        }
 
         return link_request_set_link(link, SET_LINK_BRIDGE_VLAN, link_set_bridge_vlan_handler, NULL);
 }
@@ -763,6 +800,11 @@ int link_request_to_set_master(Link *link) {
         assert(link);
         assert(link->network);
 
+        if (link->network->keep_master) {
+                link->master_set = true;
+                return 0;
+        }
+
         link->master_set = false;
 
         if (link->network->batadv || link->network->bond || link->network->bridge || link->network->vrf)
index a3711cb77d9c487ee24b6c8de89657260f246882..71ead0df9c7b6a767ba981f0efece8c67e3d075a 100644 (file)
@@ -178,6 +178,7 @@ MultiPathRoute=
 TCPAdvertisedMaximumSegmentSize=
 NextHop=
 [Network]
+KeepMaster=
 IPv6DuplicateAddressDetection=
 IPMasquerade=
 ProxyARP=