From: Yu Watanabe Date: Thu, 2 Sep 2021 21:10:07 +0000 (+0900) Subject: network: introduce KeepMaster= setting X-Git-Tag: v250-rc1~730^2~2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=57aef9d7373c97d04beb6c5fc268496c3fdcf0a4;p=thirdparty%2Fsystemd.git network: introduce KeepMaster= setting Closes #20624. --- diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 0fb749a1f93..48326a25c12 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -427,7 +427,8 @@ has been unsuccessful for some time. (IPv4 link-local address autoconfiguration will usually happen in parallel with repeated attempts to acquire a DHCPv4 lease). - Defaults to when Bridge= is set or when the specified + Defaults to when KeepMaster= or + Bridge= is set or when the specified MACVLAN=/MACVTAP= has Mode=passthru, or otherwise. @@ -923,6 +924,20 @@ IPv6Token=prefixstable:2002:da8:1:: An integer greater than or equal to 1280 bytes. When unset, the kernel's default will be used. + + KeepMaster= + Bond= + Bridge= + VRF= + + Takes a boolean value. When enabled, the current master interface index will not be + changed, and BatmanAdvanced=, Bond=, + Bridge=, and VRF= settings are ignored. This may be + useful when a netdev with a master interface is created by another program, e.g. + systemd-nspawn1. + Defaults to false. + + BatmanAdvanced= Bond= diff --git a/src/network/networkd-bridge-mdb.c b/src/network/networkd-bridge-mdb.c index 6cd10c78e02..ed8a10cad80 100644 --- a/src/network/networkd-bridge-mdb.c +++ b/src/network/networkd-bridge-mdb.c @@ -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); diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 405ddccc8b5..ef5248fa382 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -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) diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index cdca91c7c2e..4aee6fa43ca 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -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; diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index 95c86e72304..81d484ce535 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -84,6 +84,7 @@ struct Network { LIST_HEAD(Condition, conditions); /* Master or stacked netdevs */ + bool keep_master; NetDev *batadv; NetDev *bridge; NetDev *bond; diff --git a/src/network/networkd-setlink.c b/src/network/networkd-setlink.c index 06aa2067f70..21e20f10f59 100644 --- a/src/network/networkd-setlink.c +++ b/src/network/networkd-setlink.c @@ -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) diff --git a/test/fuzz/fuzz-network-parser/directives.network b/test/fuzz/fuzz-network-parser/directives.network index a3711cb77d9..71ead0df9c7 100644 --- a/test/fuzz/fuzz-network-parser/directives.network +++ b/test/fuzz/fuzz-network-parser/directives.network @@ -178,6 +178,7 @@ MultiPathRoute= TCPAdvertisedMaximumSegmentSize= NextHop= [Network] +KeepMaster= IPv6DuplicateAddressDetection= IPMasquerade= ProxyARP=