diff -Nru nplan-0.32~16.04.5/debian/changelog nplan-0.32~16.04.6/debian/changelog --- nplan-0.32~16.04.5/debian/changelog 2018-05-08 14:36:24.000000000 +0000 +++ nplan-0.32~16.04.6/debian/changelog 2018-07-03 16:55:11.000000000 +0000 @@ -1,3 +1,21 @@ +nplan (0.32~16.04.6) xenial; urgency=medium + + [ Mathieu Trudel-Lapierre ] + * tests/integration.py: Fix autopkgtests involving bonds/bridges to do proper + cleanup every time, so later tests don't unnecessarily wait for an + interface not configured to be up. (LP: #1775097) + + [ Daniel Axtens ] + * Generate udev rules files to rename devices (LP: #1770082) + Due to a systemd issue[1], using link files to rename interfaces + doesn't work as expected. Link files will not rename an interface + if it was already renamed, and interfaces are renamed in initrd, so + set-name will often not work as expected when rebooting. However, + rules files will cause a renaming, even if the interface has been + renamed in initrd. + + -- Mathieu Trudel-Lapierre Tue, 03 Jul 2018 12:55:11 -0400 + nplan (0.32~16.04.5) xenial; urgency=medium * bond/bridge: Support suffixes for time-based values so things like diff -Nru nplan-0.32~16.04.5/src/networkd.c nplan-0.32~16.04.6/src/networkd.c --- nplan-0.32~16.04.5/src/networkd.c 2018-05-08 14:34:51.000000000 +0000 +++ nplan-0.32~16.04.6/src/networkd.c 2018-06-29 17:24:20.000000000 +0000 @@ -348,6 +348,47 @@ } static void +write_rules_file(net_definition* def, const char* rootdir) +{ + GString* s = NULL; + g_autofree char* path = g_strjoin(NULL, "run/udev/rules.d/99-netplan-", def->id, ".rules", NULL); + + /* do we need to write a .rules file? + * It's only required for reliably setting the name of a physical device + * until systemd issue #9006 is resolved. */ + if (def->type >= ND_VIRTUAL) + return; + + /* Matching by name does not work. + * + * As far as I can tell, if you match by the name coming out of + * initrd, systemd complains that a link file is matching on a + * renamed name. If you match by the unstable kernel name, the + * device no longer has that name when udevd reads the file, so + * the rule doesn't fire. So only support mac and driver. */ + if (!def->set_name || (!def->match.mac && !def->match.driver)) + return; + + /* build file contents */ + s = g_string_sized_new(200); + + g_string_append(s, "SUBSYSTEM==\"net\", ACTION==\"add\", "); + + if (def->match.driver) { + g_string_append_printf(s,"DRIVERS==\"%s\", ", def->match.driver); + } else { + g_string_append(s, "DRIVERS==\"?*\", "); + } + + if (def->match.mac) + g_string_append_printf(s, "ATTR{address}==\"%s\", ", def->match.mac); + + g_string_append_printf(s, "NAME=\"%s\"\n", def->set_name); + + g_string_free_to_file(s, rootdir, path, NULL); +} + +static void write_wpa_conf(net_definition* def, const char* rootdir) { GHashTableIter iter; @@ -396,9 +437,10 @@ { g_autofree char* path_base = g_strjoin(NULL, "run/systemd/network/10-netplan-", def->id, NULL); - /* We want this for all backends when renaming, as *.link files are + /* We want this for all backends when renaming, as *.link and *.rules files are * evaluated by udev, not networkd itself or NetworkManager. */ write_link_file(def, rootdir, path_base); + write_rules_file(def, rootdir); if (def->backend != BACKEND_NETWORKD) { g_debug("networkd: definition %s is not for us (backend %i)", def->id, def->backend); @@ -438,6 +480,7 @@ unlink_glob(rootdir, "/run/systemd/network/10-netplan-*"); unlink_glob(rootdir, "/run/netplan/wpa-*.conf"); unlink_glob(rootdir, "/run/systemd/system/multi-user.target.wants/netplan-wpa@*.service"); + unlink_glob(rootdir, "/run/udev/rules.d/99-netplan-*"); } /** diff -Nru nplan-0.32~16.04.5/tests/generate.py nplan-0.32~16.04.6/tests/generate.py --- nplan-0.32~16.04.5/tests/generate.py 2018-05-08 14:33:45.000000000 +0000 +++ nplan-0.32~16.04.6/tests/generate.py 2018-06-29 17:24:20.000000000 +0000 @@ -38,6 +38,8 @@ ND_WIFI_DHCP4 = '[Match]\nName=%s\n\n[Network]\nDHCP=ipv4\n\n[DHCP]\nUseMTU=true\nRouteMetric=600\n' ND_DHCP6 = '[Match]\nName=%s\n\n[Network]\nDHCP=ipv6\n\n[DHCP]\nUseMTU=true\nRouteMetric=100\n' ND_DHCPYES = '[Match]\nName=%s\n\n[Network]\nDHCP=yes\n\n[DHCP]\nUseMTU=true\nRouteMetric=100\n' +UDEV_MAC_RULE = 'SUBSYSTEM=="net", ACTION=="add", DRIVERS=="%s", ATTR{address}=="%s", NAME="%s"\n' +UDEV_NO_MAC_RULE = 'SUBSYSTEM=="net", ACTION=="add", DRIVERS=="%s", NAME="%s"\n' class TestBase(unittest.TestCase): @@ -90,6 +92,20 @@ with open(os.path.join(networkd_dir, '10-netplan-' + fname)) as f: self.assertEqual(f.read(), contents) + def assert_networkd_udev(self, file_contents_map): + udev_dir = os.path.join(self.workdir.name, 'run', 'udev', 'rules.d') + if not file_contents_map: + # it can either not exist, or can only contain 90-netplan.rules + self.assertTrue((not os.path.exists(udev_dir)) or + (os.listdir(udev_dir) == ['90-netplan.rules'])) + return + + self.assertEqual(set(os.listdir(udev_dir)) - set(['90-netplan.rules']), + {'99-netplan-' + f for f in file_contents_map}) + for fname, contents in file_contents_map.items(): + with open(os.path.join(udev_dir, '99-netplan-' + fname)) as f: + self.assertEqual(f.read(), contents) + def assert_nm(self, connections_map=None, conf=None): # check config conf_path = os.path.join(self.workdir.name, 'run', 'NetworkManager', 'conf.d', 'netplan.conf') @@ -115,7 +131,7 @@ if os.path.exists(con_dir): self.assertEqual(os.listdir(con_dir), []) - def assert_udev(self, contents): + def assert_nm_udev(self, contents): rule_path = os.path.join(self.workdir.name, 'run/udev/rules.d/90-netplan.rules') if contents is None: self.assertFalse(os.path.exists(rule_path)) @@ -130,19 +146,19 @@ def test_no_files(self): subprocess.check_call([exe_generate, '--root-dir', self.workdir.name]) self.assertEqual(os.listdir(self.workdir.name), []) - self.assert_udev(None) + self.assert_nm_udev(None) def test_no_configs(self): self.generate('network:\n version: 2') # should not write any files self.assertEqual(os.listdir(self.workdir.name), ['etc']) - self.assert_udev(None) + self.assert_nm_udev(None) def test_empty_config(self): self.generate('') # should not write any files self.assertEqual(os.listdir(self.workdir.name), ['etc']) - self.assert_udev(None) + self.assert_nm_udev(None) def test_file_args(self): conf = os.path.join(self.workdir.name, 'config') @@ -296,6 +312,7 @@ UseMTU=true RouteMetric=100 '''}) + self.assert_networkd_udev(None) def test_eth_wol(self): self.generate('''network: @@ -306,10 +323,11 @@ dhcp4: n''') self.assert_networkd({'eth0.link': '[Match]\nOriginalName=eth0\n\n[Link]\nWakeOnLan=magic\n'}) + self.assert_networkd_udev(None) self.assert_nm(None, '''[keyfile] # devices managed by networkd unmanaged-devices+=interface-name:eth0,''') - self.assert_udev(None) + self.assert_nm_udev(None) # should not allow NM to manage everything self.assertFalse(os.path.exists(self.nm_enable_all_conf)) @@ -322,6 +340,7 @@ dhcp4: n''') self.assert_networkd({'eth1.link': '[Match]\nOriginalName=eth1\n\n[Link]\nWakeOnLan=off\nMTUBytes=1280\n'}) + self.assert_networkd_udev(None) def test_mtu_all(self): self.generate(textwrap.dedent(""" @@ -347,6 +366,7 @@ 'eth1.link': '[Match]\nOriginalName=eth1\n\n[Link]\nWakeOnLan=off\nMTUBytes=1280\n', 'eth1.network': '[Match]\nName=eth1\n\n[Network]\nBond=bond0\nLinkLocalAddressing=no\n' }) + self.assert_networkd_udev(None) def test_eth_match_by_driver_rename(self): self.generate('''network: @@ -358,9 +378,10 @@ set-name: lom1''') self.assert_networkd({'def1.link': '[Match]\nDriver=ixgbe\n\n[Link]\nName=lom1\nWakeOnLan=off\n'}) + self.assert_networkd_udev({'def1.rules': (UDEV_NO_MAC_RULE % ('ixgbe', 'lom1'))}) # NM cannot match by driver, so blacklisting needs to happen via udev self.assert_nm(None, None) - self.assert_udev('ACTION=="add|change", SUBSYSTEM=="net", ENV{ID_NET_DRIVER}=="ixgbe", ENV{NM_UNMANAGED}="1"\n') + self.assert_nm_udev('ACTION=="add|change", SUBSYSTEM=="net", ENV{ID_NET_DRIVER}=="ixgbe", ENV{NM_UNMANAGED}="1"\n') def test_eth_match_by_mac_rename(self): self.generate('''network: @@ -372,10 +393,11 @@ set-name: lom1''') self.assert_networkd({'def1.link': '[Match]\nMACAddress=11:22:33:44:55:66\n\n[Link]\nName=lom1\nWakeOnLan=off\n'}) + self.assert_networkd_udev({'def1.rules': (UDEV_MAC_RULE % ('?*', '11:22:33:44:55:66', 'lom1'))}) self.assert_nm(None, '''[keyfile] # devices managed by networkd unmanaged-devices+=mac:11:22:33:44:55:66,''') - self.assert_udev(None) + self.assert_nm_udev(None) def test_eth_implicit_name_match_dhcp4(self): self.generate('''network: @@ -385,6 +407,7 @@ dhcp4: y''') self.assert_networkd({'engreen.network': ND_DHCP4 % 'engreen'}) + self.assert_networkd_udev(None) def test_eth_match_dhcp4(self): self.generate('''network: @@ -405,7 +428,8 @@ UseMTU=true RouteMetric=100 '''}) - self.assert_udev('ACTION=="add|change", SUBSYSTEM=="net", ENV{ID_NET_DRIVER}=="ixgbe", ENV{NM_UNMANAGED}="1"\n') + self.assert_networkd_udev(None) + self.assert_nm_udev('ACTION=="add|change", SUBSYSTEM=="net", ENV{ID_NET_DRIVER}=="ixgbe", ENV{NM_UNMANAGED}="1"\n') def test_eth_match_name(self): self.generate('''network: @@ -417,10 +441,11 @@ dhcp4: true''') self.assert_networkd({'def1.network': ND_DHCP4 % 'green'}) + self.assert_networkd_udev(None) self.assert_nm(None, '''[keyfile] # devices managed by networkd unmanaged-devices+=interface-name:green,''') - self.assert_udev(None) + self.assert_nm_udev(None) def test_eth_set_mac(self): self.generate('''network: @@ -435,6 +460,7 @@ self.assert_networkd({'def1.network': ND_DHCP4 % 'green', 'def1.link': '[Match]\nOriginalName=green\n\n[Link]\nWakeOnLan=off\nMACAddress=00:01:02:03:04:05\n' }) + self.assert_networkd_udev(None) def test_eth_match_name_rename(self): self.generate('''network: @@ -449,6 +475,10 @@ # the .network needs to match on the renamed name self.assert_networkd({'def1.link': '[Match]\nOriginalName=green\n\n[Link]\nName=blue\nWakeOnLan=off\n', 'def1.network': ND_DHCP4 % 'blue'}) + + # The udev rules engine does support renaming by name + self.assert_networkd_udev(None) + self.assert_nm(None, '''[keyfile] # devices managed by networkd unmanaged-devices+=interface-name:blue,''') @@ -462,10 +492,11 @@ dhcp4: true''') self.assert_networkd({'def1.network': ND_DHCP4 % '*'}) + self.assert_networkd_udev(None) self.assert_nm(None, '''[keyfile] # devices managed by networkd unmanaged-devices+=interface-name:*,''') - self.assert_udev(None) + self.assert_nm_udev(None) def test_eth_match_all(self): self.generate('''network: @@ -477,10 +508,11 @@ self.assert_networkd({'def1.network': '[Match]\n\n[Network]\nDHCP=ipv4\n\n' '[DHCP]\nUseMTU=true\nRouteMetric=100\n'}) + self.assert_networkd_udev(None) self.assert_nm(None, '''[keyfile] # devices managed by networkd unmanaged-devices+=type:ethernet,''') - self.assert_udev(None) + self.assert_nm_udev(None) def test_match_multiple(self): self.generate('''network: @@ -518,7 +550,7 @@ self.assert_nm(None, '''[keyfile] # devices managed by networkd unmanaged-devices+=interface-name:eth0,''') - self.assert_udev(None) + self.assert_nm_udev(None) # should not allow NM to manage everything self.assertFalse(os.path.exists(self.nm_enable_all_conf)) @@ -537,7 +569,7 @@ unmanaged-devices+=interface-name:eth0,''') # should allow NM to manage everything else self.assertTrue(os.path.exists(self.nm_enable_all_conf)) - self.assert_udev(None) + self.assert_nm_udev(None) def test_bridge_set_mac(self): self.generate('''network: @@ -561,10 +593,11 @@ dhcp4: true''') self.assert_networkd({'eth0.network': ND_DHCP4 % 'eth0'}) + self.assert_networkd_udev(None) self.assert_nm(None, '''[keyfile] # devices managed by networkd unmanaged-devices+=interface-name:eth0,''') - self.assert_udev(None) + self.assert_nm_udev(None) def test_eth_dhcp6(self): self.generate('''network: @@ -941,7 +974,7 @@ self.assert_nm(None, '''[keyfile] # devices managed by networkd unmanaged-devices+=interface-name:wl0,''') - self.assert_udev(None) + self.assert_nm_udev(None) # generates wpa config and enables wpasupplicant unit with open(os.path.join(self.workdir.name, 'run/netplan/wpa-wl0.conf')) as f: @@ -996,7 +1029,7 @@ self.assert_nm(None, '''[keyfile] # devices managed by networkd unmanaged-devices+=interface-name:wl0,''') - self.assert_udev(None) + self.assert_nm_udev(None) def test_wifi_match(self): err = self.generate('''network: @@ -1035,7 +1068,7 @@ self.assert_nm(None, '''[keyfile] # devices managed by networkd unmanaged-devices+=interface-name:br0,''') - self.assert_udev(None) + self.assert_nm_udev(None) def test_bridge_type_renderer(self): self.generate('''network: @@ -1051,7 +1084,7 @@ self.assert_nm(None, '''[keyfile] # devices managed by networkd unmanaged-devices+=interface-name:br0,''') - self.assert_udev(None) + self.assert_nm_udev(None) def test_bridge_def_renderer(self): self.generate('''network: @@ -1079,7 +1112,7 @@ self.assert_nm(None, '''[keyfile] # devices managed by networkd unmanaged-devices+=interface-name:br0,''') - self.assert_udev(None) + self.assert_nm_udev(None) def test_bridge_forward_declaration(self): self.generate('''network: @@ -1186,7 +1219,7 @@ self.assert_nm(None, '''[keyfile] # devices managed by networkd unmanaged-devices+=interface-name:bn0,''') - self.assert_udev(None) + self.assert_nm_udev(None) def test_bond_components(self): self.generate('''network: @@ -1423,7 +1456,7 @@ self.assert_nm(None, '''[keyfile] # devices managed by networkd unmanaged-devices+=interface-name:engreen,interface-name:en1,interface-name:enblue,interface-name:enred,''') - self.assert_udev(None) + self.assert_nm_udev(None) class TestNetworkManager(TestBase): @@ -1452,7 +1485,7 @@ # should allow NM to manage everything else self.assertTrue(os.path.exists(self.nm_enable_all_conf)) self.assert_networkd({'eth0.link': '[Match]\nOriginalName=eth0\n\n[Link]\nWakeOnLan=magic\n'}) - self.assert_udev(None) + self.assert_nm_udev(None) def test_eth_mtu(self): self.generate('''network: @@ -1608,6 +1641,7 @@ set-name: lom1''') self.assert_networkd({'def1.link': '[Match]\nDriver=ixgbe\n\n[Link]\nName=lom1\nWakeOnLan=off\n'}) + self.assert_networkd_udev({'def1.rules': (UDEV_NO_MAC_RULE % ('ixgbe', 'lom1'))}) self.assert_nm({'def1': '''[connection] id=netplan-def1 type=ethernet @@ -1622,7 +1656,7 @@ [ipv6] method=ignore '''}) - self.assert_udev(None) + self.assert_nm_udev(None) def test_eth_match_by_mac_rename(self): self.generate('''network: @@ -1635,6 +1669,7 @@ set-name: lom1''') self.assert_networkd({'def1.link': '[Match]\nMACAddress=11:22:33:44:55:66\n\n[Link]\nName=lom1\nWakeOnLan=off\n'}) + self.assert_networkd_udev({'def1.rules': (UDEV_MAC_RULE % ('?*', '11:22:33:44:55:66', 'lom1'))}) self.assert_nm({'def1': '''[connection] id=netplan-def1 type=ethernet @@ -1649,7 +1684,7 @@ [ipv6] method=ignore '''}) - self.assert_udev(None) + self.assert_nm_udev(None) def test_eth_implicit_name_match_dhcp4(self): self.generate('''network: @@ -1728,7 +1763,7 @@ method=ignore '''}) self.assert_networkd({}) - self.assert_udev(None) + self.assert_nm_udev(None) def test_eth_match_name_rename(self): self.generate('''network: @@ -1741,6 +1776,9 @@ set-name: blue dhcp4: true''') + # The udev rules engine does support renaming by name + self.assert_networkd_udev(None) + # NM needs to match on the renamed name self.assert_nm({'def1': '''[connection] id=netplan-def1 @@ -1758,7 +1796,7 @@ '''}) # ... while udev renames it self.assert_networkd({'def1.link': '[Match]\nOriginalName=green\n\n[Link]\nName=blue\nWakeOnLan=off\n'}) - self.assert_udev(None) + self.assert_nm_udev(None) def test_eth_match_name_glob(self): err = self.generate('''network: @@ -1825,7 +1863,7 @@ method=ignore '''}) self.assert_networkd({}) - self.assert_udev(None) + self.assert_nm_udev(None) def test_eth_global_renderer(self): self.generate('''network: @@ -1850,7 +1888,7 @@ method=ignore '''}) self.assert_networkd({}) - self.assert_udev(None) + self.assert_nm_udev(None) def test_eth_type_renderer(self): self.generate('''network: @@ -1876,7 +1914,7 @@ method=ignore '''}) self.assert_networkd({}) - self.assert_udev(None) + self.assert_nm_udev(None) def test_eth_def_renderer(self): self.generate('''network: @@ -1902,7 +1940,7 @@ method=ignore '''}) self.assert_networkd({}) - self.assert_udev(None) + self.assert_nm_udev(None) def test_global_renderer_only(self): self.generate(None, confs={'01-default-nm.yaml': 'network: {version: 2, renderer: NetworkManager}'}) @@ -1911,7 +1949,7 @@ # but not configure anything else self.assert_nm(None, None) self.assert_networkd({}) - self.assert_udev(None) + self.assert_nm_udev(None) def test_eth_dhcp6(self): self.generate('''network: @@ -1984,7 +2022,7 @@ address1=2001:FFfe::1/64 '''}) self.assert_networkd({}) - self.assert_udev(None) + self.assert_nm_udev(None) def test_eth_manual_addresses_dhcp(self): self.generate('''network: @@ -2244,7 +2282,7 @@ psk=c0mpany '''}) self.assert_networkd({}) - self.assert_udev(None) + self.assert_nm_udev(None) def test_wifi_match_mac(self): self.generate('''network: @@ -2340,7 +2378,7 @@ psk=s3cret '''}) self.assert_networkd({}) - self.assert_udev(None) + self.assert_nm_udev(None) def test_wifi_adhoc(self): self.generate('''network: @@ -2391,7 +2429,7 @@ method=ignore '''}) self.assert_networkd({}) - self.assert_udev(None) + self.assert_nm_udev(None) def test_bridge_type_renderer(self): self.generate('''network: @@ -2414,7 +2452,7 @@ method=ignore '''}) self.assert_networkd({}) - self.assert_udev(None) + self.assert_nm_udev(None) def test_bridge_set_mac(self): self.generate('''network: @@ -2464,7 +2502,7 @@ method=ignore '''}) self.assert_networkd({}) - self.assert_udev(None) + self.assert_nm_udev(None) def test_bridge_forward_declaration(self): self.generate('''network: @@ -2525,7 +2563,7 @@ method=ignore '''}) self.assert_networkd({}) - self.assert_udev(None) + self.assert_nm_udev(None) def test_bridge_components(self): self.generate('''network: @@ -2585,7 +2623,7 @@ method=ignore '''}) self.assert_networkd({}) - self.assert_udev(None) + self.assert_nm_udev(None) def test_bridge_params(self): self.generate('''network: @@ -2668,7 +2706,7 @@ method=ignore '''}) self.assert_networkd({}) - self.assert_udev(None) + self.assert_nm_udev(None) def test_bond_empty(self): self.generate('''network: @@ -2748,7 +2786,7 @@ method=ignore '''}) self.assert_networkd({}) - self.assert_udev(None) + self.assert_nm_udev(None) def test_bond_empty_params(self): self.generate('''network: @@ -2809,7 +2847,7 @@ method=ignore '''}) self.assert_networkd({}) - self.assert_udev(None) + self.assert_nm_udev(None) def test_bond_with_params(self): self.generate('''network: @@ -2912,7 +2950,7 @@ method=ignore '''}) self.assert_networkd({}) - self.assert_udev(None) + self.assert_nm_udev(None) def test_bond_primary_slave(self): self.generate('''network: @@ -2979,7 +3017,7 @@ method=ignore '''}) self.assert_networkd({}) - self.assert_udev(None) + self.assert_nm_udev(None) def test_gateway(self): self.generate('''network: @@ -3120,7 +3158,7 @@ [ipv6] method=auto '''}) - self.assert_udev(None) + self.assert_nm_udev(None) def test_vlan_parent_match(self): self.generate('''network: @@ -3173,7 +3211,7 @@ [ipv6] method=ignore ''' % uuid}) - self.assert_udev(None) + self.assert_nm_udev(None) class TestConfigErrors(TestBase): @@ -3896,7 +3934,7 @@ self.assert_nm(None, '''[keyfile] # devices managed by networkd unmanaged-devices+=interface-name:engreen,''') - self.assert_udev(None) + self.assert_nm_udev(None) def test_add_def(self): self.generate('''network: @@ -3915,7 +3953,7 @@ self.assert_nm(None, '''[keyfile] # devices managed by networkd unmanaged-devices+=interface-name:enblue,interface-name:engreen,''') - self.assert_udev(None) + self.assert_nm_udev(None) def test_change_def(self): self.generate('''network: @@ -3955,7 +3993,7 @@ self.assert_nm(None, '''[keyfile] # devices managed by networkd unmanaged-devices+=interface-name:engreen,''') - self.assert_udev(None) + self.assert_nm_udev(None) def test_ref(self): self.generate('''network: diff -Nru nplan-0.32~16.04.5/tests/integration.py nplan-0.32~16.04.6/tests/integration.py --- nplan-0.32~16.04.5/tests/integration.py 2018-05-08 14:36:19.000000000 +0000 +++ nplan-0.32~16.04.6/tests/integration.py 2018-06-29 17:19:22.000000000 +0000 @@ -368,6 +368,7 @@ def test_eth_and_bridge(self): self.setup_eth(None) self.start_dnsmasq(None, self.dev_e2_ap) + self.addCleanup(subprocess.call, ['ip', 'link', 'delete', 'mybr'], stderr=subprocess.DEVNULL) with open(self.config, 'w') as f: f.write('''network: renderer: %(r)s @@ -451,6 +452,7 @@ def test_bridge_path_cost(self): self.setup_eth(None) self.start_dnsmasq(None, self.dev_e2_ap) + self.addCleanup(subprocess.call, ['ip', 'link', 'delete', 'mybr'], stderr=subprocess.DEVNULL) with open(self.config, 'w') as f: f.write('''network: renderer: %(r)s @@ -485,6 +487,7 @@ def test_bridge_ageing_time(self): self.setup_eth(None) self.start_dnsmasq(None, self.dev_e2_ap) + self.addCleanup(subprocess.call, ['ip', 'link', 'delete', 'mybr'], stderr=subprocess.DEVNULL) with open(self.config, 'w') as f: f.write('''network: renderer: %(r)s @@ -518,6 +521,7 @@ def test_bridge_max_age(self): self.setup_eth(None) self.start_dnsmasq(None, self.dev_e2_ap) + self.addCleanup(subprocess.call, ['ip', 'link', 'delete', 'mybr'], stderr=subprocess.DEVNULL) with open(self.config, 'w') as f: f.write('''network: renderer: %(r)s @@ -551,6 +555,7 @@ def test_bridge_hello_time(self): self.setup_eth(None) self.start_dnsmasq(None, self.dev_e2_ap) + self.addCleanup(subprocess.call, ['ip', 'link', 'delete', 'mybr'], stderr=subprocess.DEVNULL) with open(self.config, 'w') as f: f.write('''network: renderer: %(r)s @@ -584,6 +589,7 @@ def test_bridge_priority(self): self.setup_eth(None) self.start_dnsmasq(None, self.dev_e2_ap) + self.addCleanup(subprocess.call, ['ip', 'link', 'delete', 'mybr'], stderr=subprocess.DEVNULL) with open(self.config, 'w') as f: f.write('''network: renderer: %(r)s @@ -617,6 +623,7 @@ def test_bridge_forward_delay(self): self.setup_eth(None) self.start_dnsmasq(None, self.dev_e2_ap) + self.addCleanup(subprocess.call, ['ip', 'link', 'delete', 'mybr'], stderr=subprocess.DEVNULL) with open(self.config, 'w') as f: f.write('''network: renderer: %(r)s @@ -650,6 +657,7 @@ def test_bridge_stp_false(self): self.setup_eth(None) self.start_dnsmasq(None, self.dev_e2_ap) + self.addCleanup(subprocess.call, ['ip', 'link', 'delete', 'mybr'], stderr=subprocess.DEVNULL) with open(self.config, 'w') as f: f.write('''network: renderer: %(r)s @@ -1695,6 +1703,7 @@ def test_bridge_port_priority(self): self.setup_eth(None) self.start_dnsmasq(None, self.dev_e2_ap) + self.addCleanup(subprocess.call, ['ip', 'link', 'delete', 'mybr'], stderr=subprocess.DEVNULL) with open(self.config, 'w') as f: f.write('''network: renderer: %(r)s @@ -1980,6 +1989,7 @@ def test_bridge_port_priority(self): self.setup_eth(None) self.start_dnsmasq(None, self.dev_e2_ap) + self.addCleanup(subprocess.call, ['ip', 'link', 'delete', 'mybr'], stderr=subprocess.DEVNULL) with open(self.config, 'w') as f: f.write('''network: renderer: %(r)s