diff --git a/man/networkctl.xml b/man/networkctl.xml index 9e2a65b879..22f9744c95 100644 --- a/man/networkctl.xml +++ b/man/networkctl.xml @@ -413,14 +413,23 @@ s - Service VLAN, m - Two-port MAC Relay (TPMR) reload - Reload .netdev and .network files. - If a new .netdev file is found, then the corresponding netdev is created. - Note that even if an existing .netdev is modified or removed, - systemd-networkd does not update or remove the netdev. - If a new, modified or removed .network file is found, then all interfaces - which match the file are reconfigured. + + Reload .netdev and .network files. - + If a new or modified .netdev file is found, then the corresponding + netdev is created or updated, respectively. Note, if the corresponding interface already exists, + then some of new settings may not be applied. E.g., VLAN ID cannot be changed after the interface + was created, so changing [VLAN] Id= will not take effect if the matching VLAN + interface already exists. To apply such settings, the interfaces need to be removed manually before + reload. Also note that even if a .netdev file is removed, + systemd-networkd does not remove the existing netdev corresponding to the file. + + + If a new, modified, or removed .network file is found, then all + interfaces that matched the file are reconfigured. + + + diff --git a/src/network/fuzz-netdev-parser.c b/src/network/fuzz-netdev-parser.c index f0988bd4cc..7e29ba9b8e 100644 --- a/src/network/fuzz-netdev-parser.c +++ b/src/network/fuzz-netdev-parser.c @@ -10,6 +10,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { _cleanup_(manager_freep) Manager *manager = NULL; _cleanup_fclose_ FILE *f = NULL; _cleanup_(unlink_tempfilep) char netdev_config[] = "/tmp/fuzz-networkd.XXXXXX"; + _cleanup_(netdev_unrefp) NetDev *netdev = NULL; if (outside_size_range(size, 0, 65536)) return 0; @@ -22,6 +23,6 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { fflush(f); assert_se(manager_new(&manager, /* test_mode = */ true) >= 0); - (void) netdev_load_one(manager, netdev_config); + (void) netdev_load_one(manager, netdev_config, &netdev); return 0; } diff --git a/src/network/netdev/netdev.c b/src/network/netdev/netdev.c index 80538a60ec..1e046397d5 100644 --- a/src/network/netdev/netdev.c +++ b/src/network/netdev/netdev.c @@ -242,6 +242,7 @@ static NetDev* netdev_free(NetDev *netdev) { condition_free_list(netdev->conditions); free(netdev->filename); strv_free(netdev->dropins); + hashmap_free(netdev->stats_by_path); free(netdev->description); free(netdev->ifname); @@ -724,7 +725,7 @@ static int independent_netdev_create(NetDev *netdev) { return 0; } - r = sd_rtnl_message_new_link(netdev->manager->rtnl, &m, RTM_NEWLINK, 0); + r = sd_rtnl_message_new_link(netdev->manager->rtnl, &m, RTM_NEWLINK, netdev->ifindex); if (r < 0) return r; @@ -753,7 +754,7 @@ static int stacked_netdev_create(NetDev *netdev, Link *link, Request *req) { assert(link); assert(req); - r = sd_rtnl_message_new_link(netdev->manager->rtnl, &m, RTM_NEWLINK, 0); + r = sd_rtnl_message_new_link(netdev->manager->rtnl, &m, RTM_NEWLINK, netdev->ifindex); if (r < 0) return r; @@ -798,9 +799,6 @@ static bool link_is_ready_to_create_stacked_netdev(Link *link) { static int netdev_is_ready_to_create(NetDev *netdev, Link *link) { assert(netdev); - if (netdev->state != NETDEV_STATE_LOADING) - return false; - if (link && !link_is_ready_to_create_stacked_netdev(link)) return false; @@ -862,9 +860,6 @@ int link_request_stacked_netdev(Link *link, NetDev *netdev) { if (!netdev_is_stacked(netdev)) return -EINVAL; - if (!IN_SET(netdev->state, NETDEV_STATE_LOADING, NETDEV_STATE_FAILED) || netdev->ifindex > 0) - return 0; /* Already created. */ - if (!netdev_is_managed(netdev)) return 0; /* Already detached, due to e.g. reloading .netdev files. */ @@ -921,6 +916,9 @@ static int netdev_request_to_create(NetDev *netdev) { if (!netdev_is_managed(netdev)) return 0; /* Already detached, due to e.g. reloading .netdev files. */ + if (netdev->state != NETDEV_STATE_LOADING) + return 0; /* Already configured (at least tried previously). Not necessary to reconfigure. */ + r = netdev_is_ready_to_create(netdev, NULL); if (r < 0) return r; @@ -940,21 +938,20 @@ static int netdev_request_to_create(NetDev *netdev) { return 0; } -int netdev_load_one(Manager *manager, const char *filename) { +int netdev_load_one(Manager *manager, const char *filename, NetDev **ret) { _cleanup_(netdev_unrefp) NetDev *netdev_raw = NULL, *netdev = NULL; const char *dropin_dirname; int r; assert(manager); assert(filename); + assert(ret); r = null_or_empty_path(filename); if (r < 0) return log_warning_errno(r, "Failed to check if \"%s\" is empty: %m", filename); - if (r > 0) { - log_debug("Skipping empty file: %s", filename); - return 0; - } + if (r > 0) + return log_debug_errno(SYNTHETIC_ERRNO(ENOENT), "Skipping empty file: %s", filename); netdev_raw = new(NetDev, 1); if (!netdev_raw) @@ -979,10 +976,8 @@ int netdev_load_one(Manager *manager, const char *filename) { return r; /* config_parse_many() logs internally. */ /* skip out early if configuration does not match the environment */ - if (!condition_test_list(netdev_raw->conditions, environ, NULL, NULL, NULL)) { - log_debug("%s: Conditions in the file do not match the system environment, skipping.", filename); - return 0; - } + if (!condition_test_list(netdev_raw->conditions, environ, NULL, NULL, NULL)) + return log_debug_errno(SYNTHETIC_ERRNO(ESTALE), "%s: Conditions in the file do not match the system environment, skipping.", filename); if (netdev_raw->kind == _NETDEV_KIND_INVALID) return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), "NetDev has no Kind= configured in \"%s\", ignoring.", filename); @@ -1009,7 +1004,7 @@ int netdev_load_one(Manager *manager, const char *filename) { config_item_perf_lookup, network_netdev_gperf_lookup, CONFIG_PARSE_WARN, netdev, - NULL, + &netdev->stats_by_path, &netdev->dropins); if (r < 0) return r; /* config_parse_many() logs internally. */ @@ -1025,17 +1020,9 @@ int netdev_load_one(Manager *manager, const char *filename) { if (!netdev->filename) return log_oom(); - r = netdev_attach(netdev); - if (r < 0) - return r; - log_syntax(/* unit = */ NULL, LOG_DEBUG, filename, /* config_line = */ 0, /* error = */ 0, "Successfully loaded."); - r = netdev_request_to_create(netdev); - if (r < 0) - return r; /* netdev_request_to_create() logs internally. */ - - TAKE_PTR(netdev); + *ret = TAKE_PTR(netdev); return 0; } @@ -1049,8 +1036,95 @@ int netdev_load(Manager *manager) { if (r < 0) return log_error_errno(r, "Failed to enumerate netdev files: %m"); - STRV_FOREACH(f, files) - (void) netdev_load_one(manager, *f); + STRV_FOREACH(f, files) { + _cleanup_(netdev_unrefp) NetDev *netdev = NULL; + + if (netdev_load_one(manager, *f, &netdev) < 0) + continue; + + if (netdev_attach(netdev) < 0) + continue; + + if (netdev_request_to_create(netdev) < 0) + continue; + + TAKE_PTR(netdev); + } + + return 0; +} + +int netdev_reload(Manager *manager) { + _cleanup_hashmap_free_ Hashmap *new_netdevs = NULL; + _cleanup_strv_free_ char **files = NULL; + int r; + + assert(manager); + + r = conf_files_list_strv(&files, ".netdev", NULL, 0, NETWORK_DIRS); + if (r < 0) + return log_error_errno(r, "Failed to enumerate netdev files: %m"); + + STRV_FOREACH(f, files) { + _cleanup_(netdev_unrefp) NetDev *netdev = NULL; + NetDev *old; + + if (netdev_load_one(manager, *f, &netdev) < 0) + continue; + + if (netdev_get(manager, netdev->ifname, &old) < 0) { + log_netdev_debug(netdev, "Found new .netdev file: %s", netdev->filename); + + if (netdev_attach_name_full(netdev, netdev->ifname, &new_netdevs) >= 0) + TAKE_PTR(netdev); + + continue; + } + + if (!stats_by_path_equal(netdev->stats_by_path, old->stats_by_path)) { + log_netdev_debug(netdev, "Found updated .netdev file: %s", netdev->filename); + + /* Copy ifindex. */ + netdev->ifindex = old->ifindex; + + if (netdev_attach_name_full(netdev, netdev->ifname, &new_netdevs) >= 0) + TAKE_PTR(netdev); + + continue; + } + + /* Keep the original object, and drop the new one. */ + if (netdev_attach_name_full(old, old->ifname, &new_netdevs) >= 0) + netdev_ref(old); + } + + /* Detach old NetDev objects from Manager. + * Note, the same object may be registered with multiple names, and netdev_detach() may drop multiple + * entries. Hence, hashmap_free_with_destructor() cannot be used. */ + for (NetDev *n; (n = hashmap_first(manager->netdevs)); ) + netdev_detach(n); + + /* Attach new NetDev objects to Manager. */ + for (;;) { + _cleanup_(netdev_unrefp) NetDev *netdev = hashmap_steal_first(new_netdevs); + if (!netdev) + break; + + netdev->manager = manager; + if (netdev_attach(netdev) < 0) + continue; + + /* Create a new netdev or update existing netdev, */ + if (netdev_request_to_create(netdev) < 0) + continue; + + TAKE_PTR(netdev); + } + + /* Reassign NetDev objects to Link object. */ + Link *link; + HASHMAP_FOREACH(link, manager->links_by_index) + link_assign_netdev(link); return 0; } diff --git a/src/network/netdev/netdev.h b/src/network/netdev/netdev.h index 786fe9e9f6..106f47acad 100644 --- a/src/network/netdev/netdev.h +++ b/src/network/netdev/netdev.h @@ -118,6 +118,7 @@ typedef struct NetDev { char *filename; char **dropins; + Hashmap *stats_by_path; LIST_HEAD(Condition, conditions); @@ -218,7 +219,8 @@ void netdev_detach(NetDev *netdev); int netdev_set_ifindex_internal(NetDev *netdev, int ifindex); int netdev_load(Manager *manager); -int netdev_load_one(Manager *manager, const char *filename); +int netdev_reload(Manager *manager); +int netdev_load_one(Manager *manager, const char *filename, NetDev **ret); void netdev_drop(NetDev *netdev); void netdev_enter_failed(NetDev *netdev); int netdev_enter_ready(NetDev *netdev); diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index ca2b008a34..6639d59b32 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -1188,7 +1188,7 @@ int manager_reload(Manager *m, sd_bus_message *message) { (void) notify_reloading(); - r = netdev_load(m); + r = netdev_reload(m); if (r < 0) goto finish; diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py index 79d593bb7e..82339583be 100755 --- a/test/test-network/systemd-networkd-tests.py +++ b/test/test-network/systemd-networkd-tests.py @@ -358,6 +358,10 @@ def remove_network_unit(*units): if has_link: udevadm_reload() +def touch_network_unit(*units): + for unit in units: + touch(os.path.join(network_unit_dir, unit)) + def clear_network_units(): has_link = False if os.path.exists(network_unit_dir): @@ -1711,11 +1715,7 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities): self.check_link_attr('bond97', 'bonding', 'arp_missed_max', '10') self.check_link_attr('bond97', 'bonding', 'peer_notif_delay', '300000') - def test_vlan(self): - copy_network_unit('21-vlan.netdev', '11-dummy.netdev', - '21-vlan.network', '21-vlan-test1.network') - start_networkd() - + def check_vlan(self, id, flags): self.wait_online('test1:degraded', 'vlan99:routable') self.networkctl_check_unit('vlan99', '21-vlan', '21-vlan') self.networkctl_check_unit('test1', '11-dummy', '21-vlan-test1') @@ -1727,11 +1727,17 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities): output = check_output('ip -d link show vlan99') print(output) self.assertIn(' mtu 2000 ', output) - self.assertIn('REORDER_HDR', output) - self.assertIn('LOOSE_BINDING', output) - self.assertIn('GVRP', output) - self.assertIn('MVRP', output) - self.assertIn(' id 99 ', output) + if flags: + self.assertIn('REORDER_HDR', output) + self.assertIn('LOOSE_BINDING', output) + self.assertIn('GVRP', output) + self.assertIn('MVRP', output) + else: + self.assertNotIn('REORDER_HDR', output) + self.assertNotIn('LOOSE_BINDING', output) + self.assertNotIn('GVRP', output) + self.assertNotIn('MVRP', output) + self.assertIn(f' id {id} ', output) self.assertIn('ingress-qos-map { 4:100 7:13 }', output) self.assertIn('egress-qos-map { 0:1 1:3 6:6 7:7 10:3 }', output) @@ -1744,6 +1750,32 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities): print(output) self.assertRegex(output, 'inet 192.168.23.5/24 brd 192.168.23.255 scope global vlan99') + def test_vlan(self): + copy_network_unit('21-vlan.netdev', '11-dummy.netdev', + '21-vlan.network', '21-vlan-test1.network') + start_networkd() + self.check_vlan(id=99, flags=True) + + # Test for reloading .netdev file. See issue #34907. + with open(os.path.join(network_unit_dir, '21-vlan.netdev.d/override.conf'), mode='a', encoding='utf-8') as f: + f.write('[VLAN]\nId=42\n') + + # VLAN ID cannot be changed, so we need to remove the existing netdev. + check_output("ip link del vlan99") + networkctl_reload() + self.check_vlan(id=42, flags=True) + + with open(os.path.join(network_unit_dir, '21-vlan.netdev.d/override.conf'), mode='a', encoding='utf-8') as f: + f.write('[VLAN]\n' + 'GVRP=no\n' + 'MVRP=no\n' + 'LooseBinding=no\n' + 'ReorderHeader=no\n') + + # flags can be changed, hence it is not necessary to remove the existing netdev. + networkctl_reload() + self.check_vlan(id=42, flags=False) + def test_vlan_on_bond(self): # For issue #24377 (https://github.com/systemd/systemd/issues/24377), # which is fixed by b05e52000b4eee764b383cc3031da0a3739e996e (PR#24020). @@ -1787,6 +1819,11 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities): print(output) self.assertRegex(output, 'macvtap mode ' + mode + ' ') + touch_network_unit('21-macvtap.netdev') + networkctl_reload() + self.wait_online('macvtap99:degraded', + 'test1:carrier' if mode == 'passthru' else 'test1:degraded') + @expectedFailureIfModuleIsNotAvailable('macvlan') def test_macvlan(self): first = True @@ -1837,6 +1874,11 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities): if ' bclim ' in output: # This is new in kernel and iproute2 v6.4 self.assertIn(' bclim 2147483647 ', output) + touch_network_unit('21-macvlan.netdev') + networkctl_reload() + self.wait_online('macvlan99:degraded', + 'test1:carrier' if mode == 'passthru' else 'test1:degraded') + @expectedFailureIfModuleIsNotAvailable('ipvlan') def test_ipvlan(self): first = True @@ -1862,6 +1904,10 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities): print(output) self.assertRegex(output, 'ipvlan *mode ' + mode.lower() + ' ' + flag) + touch_network_unit('25-ipvlan.netdev') + networkctl_reload() + self.wait_online('ipvlan99:degraded', 'test1:degraded') + @expectedFailureIfModuleIsNotAvailable('ipvtap') def test_ipvtap(self): first = True @@ -1887,6 +1933,10 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities): print(output) self.assertRegex(output, 'ipvtap *mode ' + mode.lower() + ' ' + flag) + touch_network_unit('25-ipvtap.netdev') + networkctl_reload() + self.wait_online('ipvtap99:degraded', 'test1:degraded') + def test_veth(self): copy_network_unit('25-veth.netdev', '26-netdev-link-local-addressing-yes.network', '25-veth-mtu.netdev') @@ -2197,6 +2247,19 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities): print(output) self.assertRegex(output, 'ipip (ipip )?remote any local any dev dummy98') + touch_network_unit( + '25-ipip-tunnel.netdev', + '25-ipip-tunnel-local-any.netdev', + '25-ipip-tunnel-remote-any.netdev', + '25-ipip-tunnel-any-any.netdev') + networkctl_reload() + self.wait_online( + 'ipiptun99:routable', + 'ipiptun98:routable', + 'ipiptun97:routable', + 'ipiptun96:routable', + 'dummy98:degraded') + def test_gre_tunnel(self): copy_network_unit('12-dummy.netdev', '25-gretun.network', '25-gre-tunnel.netdev', '25-tunnel.network', @@ -2240,6 +2303,19 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities): self.assertNotRegex(output, 'iseq') self.assertNotRegex(output, 'oseq') + touch_network_unit( + '25-gre-tunnel.netdev', + '25-gre-tunnel-local-any.netdev', + '25-gre-tunnel-remote-any.netdev', + '25-gre-tunnel-any-any.netdev') + networkctl_reload() + self.wait_online( + 'gretun99:routable', + 'gretun98:routable', + 'gretun97:routable', + 'gretun96:routable', + 'dummy98:degraded') + def test_ip6gre_tunnel(self): copy_network_unit('12-dummy.netdev', '25-ip6gretun.network', '25-ip6gre-tunnel.netdev', '25-tunnel.network', @@ -2265,6 +2341,19 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities): print(output) self.assertRegex(output, 'ip6gre remote any local any dev dummy98') + touch_network_unit( + '25-ip6gre-tunnel.netdev', + '25-ip6gre-tunnel-local-any.netdev', + '25-ip6gre-tunnel-remote-any.netdev', + '25-ip6gre-tunnel-any-any.netdev') + networkctl_reload() + self.wait_links( + 'dummy98', + 'ip6gretun99', + 'ip6gretun98', + 'ip6gretun97', + 'ip6gretun96') + def test_gretap_tunnel(self): copy_network_unit('12-dummy.netdev', '25-gretap.network', '25-gretap-tunnel.netdev', '25-tunnel.network', @@ -2292,6 +2381,15 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities): self.assertRegex(output, 'iseq') self.assertRegex(output, 'oseq') + touch_network_unit( + '25-gretap-tunnel.netdev', + '25-gretap-tunnel-local-any.netdev') + networkctl_reload() + self.wait_online( + 'gretap99:routable', + 'gretap98:routable', + 'dummy98:degraded') + def test_ip6gretap_tunnel(self): copy_network_unit('12-dummy.netdev', '25-ip6gretap.network', '25-ip6gretap-tunnel.netdev', '25-tunnel.network', @@ -2309,6 +2407,15 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities): print(output) self.assertRegex(output, 'ip6gretap remote 2001:473:fece:cafe::5179 local any dev dummy98') + touch_network_unit( + '25-ip6gretap-tunnel.netdev', + '25-ip6gretap-tunnel-local-any.netdev') + networkctl_reload() + self.wait_online( + 'ip6gretap99:routable', + 'ip6gretap98:routable', + 'dummy98:degraded') + def test_vti_tunnel(self): copy_network_unit('12-dummy.netdev', '25-vti.network', '25-vti-tunnel.netdev', '25-tunnel.network', @@ -2336,6 +2443,19 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities): print(output) self.assertRegex(output, 'vti remote any local any dev dummy98') + touch_network_unit( + '25-vti-tunnel.netdev', + '25-vti-tunnel-local-any.netdev', + '25-vti-tunnel-remote-any.netdev', + '25-vti-tunnel-any-any.netdev') + networkctl_reload() + self.wait_online( + 'vtitun99:routable', + 'vtitun98:routable', + 'vtitun97:routable', + 'vtitun96:routable', + 'dummy98:degraded') + def test_vti6_tunnel(self): copy_network_unit('12-dummy.netdev', '25-vti6.network', '25-vti6-tunnel.netdev', '25-tunnel.network', @@ -2358,6 +2478,17 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities): print(output) self.assertRegex(output, 'vti6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98') + touch_network_unit( + '25-vti6-tunnel.netdev', + '25-vti6-tunnel-local-any.netdev', + '25-vti6-tunnel-remote-any.netdev') + networkctl_reload() + self.wait_online( + 'vti6tun99:routable', + 'vti6tun98:routable', + 'vti6tun97:routable', + 'dummy98:degraded') + def test_ip6tnl_tunnel(self): copy_network_unit('12-dummy.netdev', '25-ip6tnl.network', '25-ip6tnl-tunnel.netdev', '25-tunnel.network', @@ -2404,6 +2535,23 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities): print(output) self.assertIn('default dev ip6tnl-slaac proto static', output) + touch_network_unit( + '25-ip6tnl-tunnel.netdev', + '25-ip6tnl-tunnel-local-any.netdev', + '25-ip6tnl-tunnel-remote-any.netdev', + '25-ip6tnl-tunnel-local-slaac.netdev', + '25-ip6tnl-tunnel-external.netdev') + networkctl_reload() + self.wait_online( + 'ip6tnl99:routable', + 'ip6tnl98:routable', + 'ip6tnl97:routable', + 'ip6tnl-slaac:degraded', + 'ip6tnl-external:degraded', + 'dummy98:degraded', + 'veth99:routable', + 'veth-peer:degraded') + def test_sit_tunnel(self): copy_network_unit('12-dummy.netdev', '25-sit.network', '25-sit-tunnel.netdev', '25-tunnel.network', @@ -2431,6 +2579,19 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities): print(output) self.assertRegex(output, "sit (ip6ip )?remote any local any dev dummy98") + touch_network_unit( + '25-sit-tunnel.netdev', + '25-sit-tunnel-local-any.netdev', + '25-sit-tunnel-remote-any.netdev', + '25-sit-tunnel-any-any.netdev') + networkctl_reload() + self.wait_online( + 'sittun99:routable', + 'sittun98:routable', + 'sittun97:routable', + 'sittun96:routable', + 'dummy98:degraded') + def test_isatap_tunnel(self): copy_network_unit('12-dummy.netdev', '25-isatap.network', '25-isatap-tunnel.netdev', '25-tunnel.network') @@ -2443,6 +2604,10 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities): print(output) self.assertRegex(output, "isatap ") + touch_network_unit('25-isatap-tunnel.netdev') + networkctl_reload() + self.wait_online('isataptun99:routable', 'dummy98:degraded') + def test_6rd_tunnel(self): copy_network_unit('12-dummy.netdev', '25-6rd.network', '25-6rd-tunnel.netdev', '25-tunnel.network') @@ -2455,6 +2620,10 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities): print(output) self.assertRegex(output, '6rd-prefix 2602::/24') + touch_network_unit('25-6rd-tunnel.netdev') + networkctl_reload() + self.wait_online('sittun99:routable', 'dummy98:degraded') + @expectedFailureIfERSPANv0IsNotSupported() def test_erspan_tunnel_v0(self): copy_network_unit('12-dummy.netdev', '25-erspan.network', @@ -2487,6 +2656,15 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities): self.assertIn('ikey 0.0.0.102', output) self.assertIn('iseq', output) + touch_network_unit( + '25-erspan0-tunnel.netdev', + '25-erspan0-tunnel-local-any.netdev') + networkctl_reload() + self.wait_online( + 'erspan99:routable', + 'erspan98:routable', + 'dummy98:degraded') + def test_erspan_tunnel_v1(self): copy_network_unit('12-dummy.netdev', '25-erspan.network', '25-erspan1-tunnel.netdev', '25-tunnel.network', @@ -2520,6 +2698,15 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities): self.assertIn('iseq', output) self.assertIn('oseq', output) + touch_network_unit( + '25-erspan1-tunnel.netdev', + '25-erspan1-tunnel-local-any.netdev') + networkctl_reload() + self.wait_online( + 'erspan99:routable', + 'erspan98:routable', + 'dummy98:degraded') + @expectedFailureIfERSPANv2IsNotSupported() def test_erspan_tunnel_v2(self): copy_network_unit('12-dummy.netdev', '25-erspan.network', @@ -2554,6 +2741,15 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities): self.assertIn('iseq', output) self.assertIn('oseq', output) + touch_network_unit( + '25-erspan2-tunnel.netdev', + '25-erspan2-tunnel-local-any.netdev') + networkctl_reload() + self.wait_online( + 'erspan99:routable', + 'erspan98:routable', + 'dummy98:degraded') + def test_tunnel_independent(self): copy_network_unit('25-ipip-tunnel-independent.netdev', '26-netdev-link-local-addressing-yes.network') start_networkd() @@ -2590,6 +2786,10 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities): self.assertIn('xfrm99@lo:', output) self.assertIn('xfrm if_id 0x99 ', output) + touch_network_unit('25-xfrm.netdev') + networkctl_reload() + self.wait_online('dummy98:degraded', 'xfrm98:degraded', 'xfrm99:degraded') + @expectedFailureIfModuleIsNotAvailable('fou') def test_fou(self): # The following redundant check is necessary for CentOS CI. @@ -2718,6 +2918,10 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities): self.assertRegex(output, 'RXSC: 8c16456c83a90002, state on') self.assertRegex(output, '0: PN [0-9]*, state off, key 02030400000000000000000000000000') + touch_network_unit('25-macsec.netdev') + networkctl_reload() + self.wait_online('dummy98:degraded', 'macsec99:routable') + def test_nlmon(self): copy_network_unit('25-nlmon.netdev', '26-netdev-link-local-addressing-yes.network') start_networkd()