From 033295c188bfba28b693fb9da789678503c335c7 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 20 Feb 2019 11:32:29 +0900 Subject: [PATCH 1/9] network: fix invalid memory access This fixes a bug introduced by 959f65d32ec15cf84afe3efff1a18b0987b56c60. --- src/network/networkd-link.c | 8 +++++++- src/network/networkd-manager.c | 6 +++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index e6a1cfd5d2..f894bb5c58 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -592,8 +592,8 @@ static void link_detach_from_manager(Link *link) { } static Link *link_free(Link *link) { + Link *carrier, *master; Address *address; - Link *carrier; Route *route; Iterator i; @@ -661,6 +661,12 @@ static Link *link_free(Link *link) { hashmap_free(link->bond_slaves); + if (link->network) { + if (link->network->bond && + link_get(link->manager, link->network->bond->ifindex, &master) >= 0) + (void) hashmap_remove(master->bond_slaves, INT_TO_PTR(link->ifindex)); + } + return mfree(link); } diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index 8eb6e86c33..00f6545e24 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -1427,9 +1427,6 @@ void manager_free(Manager *m) { sd_netlink_unref(m->genl); sd_resolve_unref(m->resolve); - while ((network = m->networks)) - network_free(network); - while ((link = hashmap_first(m->dhcp6_prefixes))) manager_dhcp6_prefix_remove_all(m, link); hashmap_free(m->dhcp6_prefixes); @@ -1445,6 +1442,9 @@ void manager_free(Manager *m) { m->links_requesting_uuid = set_free(m->links_requesting_uuid); set_free(m->duids_requesting_uuid); + while ((network = m->networks)) + network_free(network); + hashmap_free(m->networks_by_name); m->netdevs = hashmap_free_with_destructor(m->netdevs, netdev_unref); From b102cdca6b8b05c6cba687ada5801a229906a7dd Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 20 Feb 2019 10:07:20 +0900 Subject: [PATCH 2/9] network: do not disable dynamic addressing for bridge slaves This effectively reverts 5971cb9de9081b537945d28895df70992e5664d0 and 2b00a4e03dc375465de7f60f3a6937cbe8ffdf31. Usually, it is not necessary to assign addresses to bridge slaves, but such functionality is supported by kernel. If users explicitly request such configuration, networkd should support that. --- src/network/networkd-link.c | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index f894bb5c58..77f345aeda 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -158,7 +158,7 @@ static bool link_ipv6_enabled(Link *link) { if (!socket_ipv6_is_supported()) return false; - if (link->network->bridge || link->network->bond) + if (link->network->bond) return false; if (manager_sysctl_ipv6_enabled(link->manager) == 0) @@ -959,23 +959,20 @@ void link_check_ready(Link *link) { !link->ipv4ll_route) return; - if (!link->network->bridge) { + if (link_ipv6ll_enabled(link) && + in_addr_is_null(AF_INET6, (const union in_addr_union*) &link->ipv6ll_address)) + return; - if (link_ipv6ll_enabled(link) && - in_addr_is_null(AF_INET6, (const union in_addr_union*) &link->ipv6ll_address)) - return; + if ((link_dhcp4_enabled(link) && !link_dhcp6_enabled(link) && + !link->dhcp4_configured) || + (link_dhcp6_enabled(link) && !link_dhcp4_enabled(link) && + !link->dhcp6_configured) || + (link_dhcp4_enabled(link) && link_dhcp6_enabled(link) && + !link->dhcp4_configured && !link->dhcp6_configured)) + return; - if ((link_dhcp4_enabled(link) && !link_dhcp6_enabled(link) && - !link->dhcp4_configured) || - (link_dhcp6_enabled(link) && !link_dhcp4_enabled(link) && - !link->dhcp6_configured) || - (link_dhcp4_enabled(link) && link_dhcp6_enabled(link) && - !link->dhcp4_configured && !link->dhcp6_configured)) - return; - - if (link_ipv6_accept_ra_enabled(link) && !link->ndisc_configured) - return; - } + if (link_ipv6_accept_ra_enabled(link) && !link->ndisc_configured) + return; if (link->state != LINK_STATE_CONFIGURED) link_enter_configured(link); @@ -1420,7 +1417,7 @@ int link_set_mtu(Link *link, uint32_t mtu) { return log_link_error_errno(link, r, "Could not allocate RTM_SETLINK message: %m"); /* If IPv6 not configured (no static IPv6 address and IPv6LL autoconfiguration is disabled) - * for this interface, or if it is a bridge slave, then disable IPv6 else enable it. */ + * for this interface, then disable IPv6 else enable it. */ (void) link_enable_ipv6(link); /* IPv6 protocol requires a minimum MTU of IPV6_MTU_MIN(1280) bytes From 8f1918016f762bafdb6178b99faa655c599c51f1 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 20 Feb 2019 10:17:11 +0900 Subject: [PATCH 3/9] network: disable LinkLocalAddressing= and IPv6AcceptRA= on bridge slaves by default If they are not explicitly configured, then let's disable these functionality on bridge slaves. --- src/network/networkd-network.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index a83df49038..dff542e194 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -141,7 +141,10 @@ static int network_verify(Network *network) { } if (network->link_local < 0) - network->link_local = ADDRESS_FAMILY_IPV6; + network->link_local = network->bridge ? ADDRESS_FAMILY_NO : ADDRESS_FAMILY_IPV6; + + if (network->ipv6_accept_ra < 0 && network->bridge) + network->ipv6_accept_ra = false; /* IPMasquerade=yes implies IPForward=yes */ if (network->ip_masquerade) From 34bf3c005148b88e953232cd6cb3db448aea5ccd Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 15 Feb 2019 12:35:30 +0900 Subject: [PATCH 4/9] network: extend 'enslaved' state to bridge slave interfaces Currently, the interface's operstate is set to 'enslaved' only when it is managed by networkd. --- src/network/networkd-link.c | 53 ++++++++++++++++++++++++++----------- src/network/networkd-link.h | 2 ++ 2 files changed, 39 insertions(+), 16 deletions(-) diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 77f345aeda..2be5c2853a 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -328,6 +328,24 @@ static int link_enable_ipv6(Link *link) { return 0; } +static bool link_is_enslaved(Link *link) { + if (link->flags & IFF_SLAVE) + /* Even if the link is not managed by networkd, honor IFF_SLAVE flag. */ + return true; + + if (!link->enslaved_raw) + return false; + + if (!link->network) + return false; + + if (link->network->bridge) + /* TODO: support the case when link is not managed by networkd. */ + return true; + + return false; +} + void link_update_operstate(Link *link, bool also_update_bond_master) { LinkOperationalState operstate; @@ -373,7 +391,7 @@ void link_update_operstate(Link *link, bool also_update_bond_master) { operstate = LINK_OPERSTATE_OFF; if (IN_SET(operstate, LINK_OPERSTATE_DEGRADED, LINK_OPERSTATE_CARRIER) && - link->flags & IFF_SLAVE) + link_is_enslaved(link)) operstate = LINK_OPERSTATE_ENSLAVED; if (IN_SET(operstate, LINK_OPERSTATE_CARRIER, LINK_OPERSTATE_ENSLAVED, LINK_OPERSTATE_ROUTABLE) && @@ -2514,6 +2532,8 @@ static int netdev_join_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *li assert(link); assert(link->network); + assert(link->enslaving > 0); + assert(!link->enslaved_raw); link->enslaving--; @@ -2528,8 +2548,10 @@ static int netdev_join_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *li } else log_link_debug(link, "Joined netdev"); - if (link->enslaving <= 0) + if (link->enslaving == 0) { + link->enslaved_raw = true; link_joined(link); + } return 1; } @@ -2546,12 +2568,8 @@ static int link_enter_join_netdev(Link *link) { link_set_state(link, LINK_STATE_CONFIGURING); link_dirty(link); - - if (!link->network->bridge && - !link->network->bond && - !link->network->vrf && - hashmap_isempty(link->network->stacked_netdevs)) - return link_joined(link); + link->enslaving = 0; + link->enslaved_raw = false; if (link->network->bond) { if (link->network->bond->state == NETDEV_STATE_READY && @@ -2563,6 +2581,8 @@ static int link_enter_join_netdev(Link *link) { LOG_NETDEV_INTERFACE(link->network->bond), LOG_LINK_MESSAGE(link, "Enslaving by '%s'", link->network->bond->ifname)); + link->enslaving++; + r = netdev_join(link->network->bond, link, netdev_join_handler); if (r < 0) { log_struct_errno(LOG_WARNING, r, @@ -2572,8 +2592,6 @@ static int link_enter_join_netdev(Link *link) { link_enter_failed(link); return r; } - - link->enslaving++; } if (link->network->bridge) { @@ -2582,6 +2600,8 @@ static int link_enter_join_netdev(Link *link) { LOG_NETDEV_INTERFACE(link->network->bridge), LOG_LINK_MESSAGE(link, "Enslaving by '%s'", link->network->bridge->ifname)); + link->enslaving++; + r = netdev_join(link->network->bridge, link, netdev_join_handler); if (r < 0) { log_struct_errno(LOG_WARNING, r, @@ -2591,8 +2611,6 @@ static int link_enter_join_netdev(Link *link) { link_enter_failed(link); return r; } - - link->enslaving++; } if (link->network->vrf) { @@ -2601,6 +2619,8 @@ static int link_enter_join_netdev(Link *link) { LOG_NETDEV_INTERFACE(link->network->vrf), LOG_LINK_MESSAGE(link, "Enslaving by '%s'", link->network->vrf->ifname)); + link->enslaving++; + r = netdev_join(link->network->vrf, link, netdev_join_handler); if (r < 0) { log_struct_errno(LOG_WARNING, r, @@ -2610,8 +2630,6 @@ static int link_enter_join_netdev(Link *link) { link_enter_failed(link); return r; } - - link->enslaving++; } HASHMAP_FOREACH(netdev, link->network->stacked_netdevs, i) { @@ -2626,6 +2644,8 @@ static int link_enter_join_netdev(Link *link) { LOG_NETDEV_INTERFACE(netdev), LOG_LINK_MESSAGE(link, "Enslaving by '%s'", netdev->ifname)); + link->enslaving++; + r = netdev_join(netdev, link, netdev_join_handler); if (r < 0) { log_struct_errno(LOG_WARNING, r, @@ -2635,10 +2655,11 @@ static int link_enter_join_netdev(Link *link) { link_enter_failed(link); return r; } - - link->enslaving++; } + if (link->enslaving == 0) + return link_joined(link); + return 0; } diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index 37be3e3bb3..fca8c083ec 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -76,6 +76,8 @@ typedef struct Link { unsigned routing_policy_rule_messages; unsigned routing_policy_rule_remove_messages; unsigned enslaving; + /* link_is_enslaved() has additional checks. So, it is named _raw. */ + bool enslaved_raw; Set *addresses; Set *addresses_foreign; From 45e11abfff78ddab19672f136b96299749989992 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 20 Feb 2019 10:31:15 +0900 Subject: [PATCH 5/9] network: make bridge master also follow operstates of slave interfaces If one of bridge slaves is in off, no-carrier, or dormant, then operstate of the bridge master is set to degraded. --- src/network/networkd-link.c | 57 +++++++++++++++++++++++-------------- src/network/networkd-link.h | 2 +- 2 files changed, 36 insertions(+), 23 deletions(-) diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 2be5c2853a..22b639bad6 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -346,8 +346,21 @@ static bool link_is_enslaved(Link *link) { return false; } -void link_update_operstate(Link *link, bool also_update_bond_master) { +static void link_update_master_operstate(Link *link, NetDev *netdev) { + Link *master; + + if (!netdev) + return; + + if (link_get(link->manager, netdev->ifindex, &master) < 0) + return; + + link_update_operstate(master, true); +} + +void link_update_operstate(Link *link, bool also_update_master) { LinkOperationalState operstate; + Iterator i; assert(link); @@ -356,7 +369,6 @@ void link_update_operstate(Link *link, bool also_update_bond_master) { else if (link_has_carrier(link)) { Address *address; uint8_t scope = RT_SCOPE_NOWHERE; - Iterator i; /* if we have carrier, check what addresses we have */ SET_FOREACH(address, link->addresses, i) { @@ -394,12 +406,10 @@ void link_update_operstate(Link *link, bool also_update_bond_master) { link_is_enslaved(link)) operstate = LINK_OPERSTATE_ENSLAVED; - if (IN_SET(operstate, LINK_OPERSTATE_CARRIER, LINK_OPERSTATE_ENSLAVED, LINK_OPERSTATE_ROUTABLE) && - !hashmap_isempty(link->bond_slaves)) { - Iterator i; + if (IN_SET(operstate, LINK_OPERSTATE_CARRIER, LINK_OPERSTATE_ENSLAVED, LINK_OPERSTATE_ROUTABLE)) { Link *slave; - HASHMAP_FOREACH(slave, link->bond_slaves, i) { + HASHMAP_FOREACH(slave, link->slaves, i) { link_update_operstate(slave, false); if (IN_SET(slave->operstate, @@ -414,13 +424,9 @@ void link_update_operstate(Link *link, bool also_update_bond_master) { link_dirty(link); } - if (also_update_bond_master && link->network && link->network->bond) { - Link *master; - - if (link_get(link->manager, link->network->bond->ifindex, &master) < 0) - return; - - link_update_operstate(master, true); + if (also_update_master && link->network) { + link_update_master_operstate(link, link->network->bond); + link_update_master_operstate(link, link->network->bridge); } } @@ -677,12 +683,16 @@ static Link *link_free(Link *link) { hashmap_remove(link->bound_by_links, INT_TO_PTR(carrier->ifindex)); hashmap_free(link->bound_by_links); - hashmap_free(link->bond_slaves); + hashmap_free(link->slaves); if (link->network) { if (link->network->bond && link_get(link->manager, link->network->bond->ifindex, &master) >= 0) - (void) hashmap_remove(master->bond_slaves, INT_TO_PTR(link->ifindex)); + (void) hashmap_remove(master->slaves, INT_TO_PTR(link->ifindex)); + + if (link->network->bridge && + link_get(link->manager, link->network->bridge->ifindex, &master) >= 0) + (void) hashmap_remove(master->slaves, INT_TO_PTR(link->ifindex)); } return mfree(link); @@ -1686,23 +1696,22 @@ static int link_set_bond(Link *link) { return r; } -static int link_append_bond_slave(Link *link) { +static int link_append_to_master(Link *link, NetDev *netdev) { Link *master; int r; assert(link); - assert(link->network); - assert(link->network->bond); + assert(netdev); - r = link_get(link->manager, link->network->bond->ifindex, &master); + r = link_get(link->manager, netdev->ifindex, &master); if (r < 0) return r; - r = hashmap_ensure_allocated(&master->bond_slaves, NULL); + r = hashmap_ensure_allocated(&master->slaves, NULL); if (r < 0) return r; - r = hashmap_put(master->bond_slaves, INT_TO_PTR(link->ifindex), link); + r = hashmap_put(master->slaves, INT_TO_PTR(link->ifindex), link); if (r < 0) return r; @@ -2499,6 +2508,10 @@ static int link_joined(Link *link) { r = link_set_bridge(link); if (r < 0) log_link_error_errno(link, r, "Could not set bridge message: %m"); + + r = link_append_to_master(link, link->network->bridge); + if (r < 0) + log_link_error_errno(link, r, "Failed to add to bridge master's slave list: %m"); } if (link->network->bond) { @@ -2506,7 +2519,7 @@ static int link_joined(Link *link) { if (r < 0) log_link_error_errno(link, r, "Could not set bond message: %m"); - r = link_append_bond_slave(link); + r = link_append_to_master(link, link->network->bond); if (r < 0) log_link_error_errno(link, r, "Failed to add to bond master's slave list: %m"); } diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index fca8c083ec..8b88d3de5d 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -131,7 +131,7 @@ typedef struct Link { Hashmap *bound_by_links; Hashmap *bound_to_links; - Hashmap *bond_slaves; + Hashmap *slaves; } Link; typedef int (*link_netlink_message_handler_t)(sd_netlink*, sd_netlink_message*, Link*); From 2be6c5d2ec97c8b78b9fab2f597cc6e857941272 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 20 Feb 2019 11:33:00 +0900 Subject: [PATCH 6/9] test-network: add more tests for Bridge= --- .../conf/bridge99-ignore-carrier-loss.network | 1 + test/test-network/conf/bridge99.network | 1 + test/test-network/systemd-networkd-tests.py | 27 +++++++++++++++++-- 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/test/test-network/conf/bridge99-ignore-carrier-loss.network b/test/test-network/conf/bridge99-ignore-carrier-loss.network index 922d57091e..89c253b4ad 100644 --- a/test/test-network/conf/bridge99-ignore-carrier-loss.network +++ b/test/test-network/conf/bridge99-ignore-carrier-loss.network @@ -4,4 +4,5 @@ Name=bridge99 [Network] Address=192.168.0.15/24 Gateway=192.168.0.1 +IPv6AcceptRA=no IgnoreCarrierLoss=true diff --git a/test/test-network/conf/bridge99.network b/test/test-network/conf/bridge99.network index 39e48ce2e1..1a00ec10dc 100644 --- a/test/test-network/conf/bridge99.network +++ b/test/test-network/conf/bridge99.network @@ -4,3 +4,4 @@ Name=bridge99 [Network] Address=192.168.0.15/24 Gateway=192.168.0.1 +IPv6AcceptRA=no diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py index bc90aaeb26..5657b7870e 100755 --- a/test/test-network/systemd-networkd-tests.py +++ b/test/test-network/systemd-networkd-tests.py @@ -1198,8 +1198,7 @@ class NetworkdNetWorkBridgeTests(unittest.TestCase, Utilities): output = subprocess.check_output(['ip', 'addr', 'show', 'bridge99']).rstrip().decode('utf-8') print(output) - self.assertRegex(output, '192.168.0.15') - self.assertRegex(output, '192.168.0.1') + self.assertRegex(output, '192.168.0.15/24') output = subprocess.check_output(['bridge', '-d', 'link', 'show', 'dummy98']).rstrip().decode('utf-8') print(output) @@ -1212,13 +1211,37 @@ class NetworkdNetWorkBridgeTests(unittest.TestCase, Utilities): if (os.path.exists('/sys/devices/virtual/net/bridge00/lower_dummy98/brport/multicast_to_unicast')): self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'multicast_to_unicast'), '1') + output = subprocess.check_output(['networkctl', 'status', 'test1']).rstrip().decode('utf-8') + self.assertRegex(output, 'State: enslaved \(configured\)') + + output = subprocess.check_output(['networkctl', 'status', 'dummy98']).rstrip().decode('utf-8') + self.assertRegex(output, 'State: enslaved \(configured\)') + + output = subprocess.check_output(['networkctl', 'status', 'bridge99']).rstrip().decode('utf-8') + self.assertRegex(output, 'State: routable \(configured\)') + self.assertEqual(subprocess.call(['ip', 'address', 'add', '192.168.0.16/24', 'dev', 'bridge99']), 0) time.sleep(1) + output = subprocess.check_output(['ip', 'addr', 'show', 'bridge99']).rstrip().decode('utf-8') + print(output) + self.assertRegex(output, '192.168.0.16/24') + + output = subprocess.check_output(['networkctl', 'status', 'bridge99']).rstrip().decode('utf-8') + self.assertRegex(output, 'State: routable \(configured\)') + self.assertEqual(subprocess.call(['ip', 'link', 'del', 'test1']), 0) + time.sleep(3) + + output = subprocess.check_output(['networkctl', 'status', 'bridge99']).rstrip().decode('utf-8') + self.assertRegex(output, 'State: degraded \(configured\)') + self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy98']), 0) time.sleep(3) + output = subprocess.check_output(['networkctl', 'status', 'bridge99']).rstrip().decode('utf-8') + self.assertRegex(output, 'State: no-carrier \(configured\)') + output = subprocess.check_output(['ip', 'address', 'show', 'bridge99']).rstrip().decode('utf-8') print(output) self.assertRegex(output, 'NO-CARRIER') From 6609924c320d5166f1c7539778c0042923cf5514 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 20 Feb 2019 12:45:40 +0900 Subject: [PATCH 7/9] test-network: add more tests for IgnoreCarrierLoss= Suggested by @amishmm in #9262. --- .../conf/bridge99-ignore-carrier-loss.network | 4 ++ test/test-network/systemd-networkd-tests.py | 42 +++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/test/test-network/conf/bridge99-ignore-carrier-loss.network b/test/test-network/conf/bridge99-ignore-carrier-loss.network index 89c253b4ad..d4741d687d 100644 --- a/test/test-network/conf/bridge99-ignore-carrier-loss.network +++ b/test/test-network/conf/bridge99-ignore-carrier-loss.network @@ -6,3 +6,7 @@ Address=192.168.0.15/24 Gateway=192.168.0.1 IPv6AcceptRA=no IgnoreCarrierLoss=true + +[RoutingPolicyRule] +To=8.8.8.8 +Table=100 diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py index 5657b7870e..fa5e08e750 100755 --- a/test/test-network/systemd-networkd-tests.py +++ b/test/test-network/systemd-networkd-tests.py @@ -1271,6 +1271,48 @@ class NetworkdNetWorkBridgeTests(unittest.TestCase, Utilities): self.assertRegex(output, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99') self.assertRegex(output, 'inet 192.168.0.16/24 scope global secondary bridge99') + subprocess.call(['ip', 'rule', 'del', 'table', '100']) + + def test_bridge_ignore_carrier_loss_frequent_loss_and_gain(self): + self.copy_unit_to_networkd_unit_path('26-bridge.netdev', '26-bridge-slave-interface-1.network', + 'bridge99-ignore-carrier-loss.network') + self.start_networkd() + + self.assertTrue(self.link_exits('bridge99')) + + self.assertEqual(subprocess.call(['ip', 'link', 'add', 'dummy98', 'type', 'dummy']), 0) + self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy98', 'up']), 0) + self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy98']), 0) + + self.assertEqual(subprocess.call(['ip', 'link', 'add', 'dummy98', 'type', 'dummy']), 0) + self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy98', 'up']), 0) + self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy98']), 0) + + self.assertEqual(subprocess.call(['ip', 'link', 'add', 'dummy98', 'type', 'dummy']), 0) + self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy98', 'up']), 0) + self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy98']), 0) + + self.assertEqual(subprocess.call(['ip', 'link', 'add', 'dummy98', 'type', 'dummy']), 0) + self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy98', 'up']), 0) + + time.sleep(3) + + output = subprocess.check_output(['ip', 'address', 'show', 'bridge99']).rstrip().decode('utf-8') + print(output) + self.assertRegex(output, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99') + + output = subprocess.check_output(['networkctl', 'status', 'bridge99']).rstrip().decode('utf-8') + self.assertRegex(output, 'State: routable \(configured\)') + + output = subprocess.check_output(['networkctl', 'status', 'dummy98']).rstrip().decode('utf-8') + self.assertRegex(output, 'State: enslaved \(configured\)') + + output = subprocess.check_output(['ip', 'rule', 'list', 'table', '100']).rstrip().decode('utf-8') + print(output) + self.assertEqual(output, '0: from all to 8.8.8.8 lookup 100') + + subprocess.call(['ip', 'rule', 'del', 'table', '100']) + class NetworkdNetWorkLLDPTests(unittest.TestCase, Utilities): links = ['veth99'] From 85fc09c97aa7bf361e8998956d545500fb0506be Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 21 Feb 2019 10:04:25 +0900 Subject: [PATCH 8/9] man: mention that LinkLocalAddressing= is disabled by default when Bridge= is set --- man/systemd.network.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/man/systemd.network.xml b/man/systemd.network.xml index fc2ac4b505..2058ba74a3 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -318,10 +318,10 @@ LinkLocalAddressing= - Enables link-local address autoconfiguration. Accepts - yes, no, - ipv4, or ipv6. Defaults to - ipv6. + Enables link-local address autoconfiguration. Accepts yes, + no, ipv4, or ipv6. If + Bridge= is set, defaults to no, and if not, + defaults to ipv6. From 7d4ea8f91cca708bdba05d8cea8804fac9cb47c5 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 21 Feb 2019 10:07:02 +0900 Subject: [PATCH 9/9] man: update explanation about operational state of network interfaces --- man/networkctl.xml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/man/networkctl.xml b/man/networkctl.xml index 955d199949..1fc94d7eda 100644 --- a/man/networkctl.xml +++ b/man/networkctl.xml @@ -118,21 +118,22 @@ carrier - the link has a carrier, or for bond master, all bonding slave network interfaces are - enslaved to the master. + the link has a carrier, or for bond or bridge master, all bonding or bridge slave + network interfaces are enslaved to the master. degraded the link has carrier and addresses valid on the local link configured, or for bond - master, one of the bonding slave network interfaces is in off, no-carrier, or dormant + or bridge master, one of the bonding or bridge slave network interfaces is in off, + no-carrier, or dormant enslaved - the link has carrier and is enslaved to other network interfaces + the link has carrier and is enslaved to bond or bridge master network interface