From 3333350a0e1917395d3654731ca985ea668bca9b Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sat, 21 Aug 2021 03:51:39 +0900 Subject: [PATCH 1/2] network: fix logic for checking gateway address is ready This fixes the followings: - The corresponding route or address to the gateway address must be in the same link. - IPv6 link local address is not necessary to be reachable. Fixes an issue reported in https://github.com/systemd/systemd/issues/8686#issuecomment-902562324. --- src/network/networkd-nexthop.c | 7 +--- src/network/networkd-route.c | 70 ++++++++++++++++++++-------------- src/network/networkd-route.h | 2 +- 3 files changed, 43 insertions(+), 36 deletions(-) diff --git a/src/network/networkd-nexthop.c b/src/network/networkd-nexthop.c index 92cbb1c843d..5584d450255 100644 --- a/src/network/networkd-nexthop.c +++ b/src/network/networkd-nexthop.c @@ -793,12 +793,7 @@ static bool nexthop_is_ready_to_configure(Link *link, const NextHop *nexthop) { } } - if (nexthop->onlink <= 0 && - in_addr_is_set(nexthop->family, &nexthop->gw) && - !manager_address_is_reachable(link->manager, nexthop->family, &nexthop->gw)) - return false; - - return true; + return gateway_is_ready(link, nexthop->onlink, nexthop->family, &nexthop->gw); } int request_process_nexthop(Request *req) { diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c index 46fbf4f324c..a364ca45b79 100644 --- a/src/network/networkd-route.c +++ b/src/network/networkd-route.c @@ -750,6 +750,8 @@ static bool prefix_route_address_is_reachable(const Address *a, int family, cons if (a->family != family) return false; + if (!address_is_ready(a)) + return false; if (FLAGS_SET(a->flags, IFA_F_NOPREFIXROUTE)) return false; if (in_addr_is_set(a->family, &a->in_addr_peer)) @@ -763,37 +765,34 @@ static bool prefix_route_address_is_reachable(const Address *a, int family, cons FAMILY_ADDRESS_SIZE(family) * 8) > 0; } -bool manager_address_is_reachable(Manager *manager, int family, const union in_addr_union *address) { - Link *link; +static bool link_address_is_reachable(Link *link, int family, const union in_addr_union *address) { + Route *route; - assert(manager); + assert(link); + assert(link->manager); assert(IN_SET(family, AF_INET, AF_INET6)); assert(address); - HASHMAP_FOREACH(link, manager->links_by_index) { - Route *route; - SET_FOREACH(route, link->routes) - if (route_address_is_reachable(route, family, address)) - return true; - SET_FOREACH(route, link->routes_foreign) - if (route_address_is_reachable(route, family, address)) - return true; - } + SET_FOREACH(route, link->routes) + if (route_address_is_reachable(route, family, address)) + return true; + SET_FOREACH(route, link->routes_foreign) + if (route_address_is_reachable(route, family, address)) + return true; /* If we do not manage foreign routes, then there may exist a prefix route we do not know, * which was created on configuring an address. Hence, also check the addresses. */ - if (!manager->manage_foreign_routes) - HASHMAP_FOREACH(link, manager->links_by_index) { - Address *a; + if (!link->manager->manage_foreign_routes) { + Address *a; - SET_FOREACH(a, link->addresses) - if (prefix_route_address_is_reachable(a, family, address)) - return true; - SET_FOREACH(a, link->addresses_foreign) - if (prefix_route_address_is_reachable(a, family, address)) - return true; - } + SET_FOREACH(a, link->addresses) + if (prefix_route_address_is_reachable(a, family, address)) + return true; + SET_FOREACH(a, link->addresses_foreign) + if (prefix_route_address_is_reachable(a, family, address)) + return true; + } return false; } @@ -1689,6 +1688,22 @@ int link_request_static_routes(Link *link, bool only_ipv4) { return 0; } +bool gateway_is_ready(Link *link, int onlink, int family, const union in_addr_union *gw) { + assert(link); + assert(gw); + + if (onlink > 0) + return true; + + if (!in_addr_is_set(family, gw)) + return true; + + if (family == AF_INET6 && in6_addr_is_link_local(&gw->in6)) + return true; + + return link_address_is_reachable(link, family, gw); +} + static int route_is_ready_to_configure(const Route *route, Link *link) { MultipathRoute *m; NextHop *nh = NULL; @@ -1732,19 +1747,13 @@ static int route_is_ready_to_configure(const Route *route, Link *link) { return r; } - if (route->gateway_onlink <= 0 && - in_addr_is_set(route->gw_family, &route->gw) > 0 && - !manager_address_is_reachable(link->manager, route->gw_family, &route->gw)) + if (!gateway_is_ready(link, route->gateway_onlink, route->gw_family, &route->gw)) return false; ORDERED_SET_FOREACH(m, route->multipath_routes) { union in_addr_union a = m->gateway.address; Link *l = NULL; - if (route->gateway_onlink <= 0 && - !manager_address_is_reachable(link->manager, m->gateway.family, &a)) - return false; - if (m->ifname) { if (link_get_by_name(link->manager, m->ifname, &l) < 0) return false; @@ -1756,6 +1765,9 @@ static int route_is_ready_to_configure(const Route *route, Link *link) { } if (l && !link_is_ready_to_configure(l, true)) return false; + + if (!gateway_is_ready(l ?: link, route->gateway_onlink, m->gateway.family, &a)) + return false; } return true; diff --git a/src/network/networkd-route.h b/src/network/networkd-route.h index 2d262819add..235a91f08d5 100644 --- a/src/network/networkd-route.h +++ b/src/network/networkd-route.h @@ -78,8 +78,8 @@ int route_configure_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Li int route_remove(const Route *route, Manager *manager, Link *link); int link_has_route(Link *link, const Route *route); -bool manager_address_is_reachable(Manager *manager, int family, const union in_addr_union *address); int manager_find_uplink(Manager *m, int family, Link *exclude, Link **ret); +bool gateway_is_ready(Link *link, int onlink, int family, const union in_addr_union *gw); int link_drop_routes(Link *link); int link_drop_foreign_routes(Link *link); From 180c5116b3ce09c2bac4f40bc976dc0a7023fee0 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sat, 21 Aug 2021 03:54:35 +0900 Subject: [PATCH 2/2] test-network: add testcases that gateway address is IPv6 link local --- test/test-network/conf/25-nexthop.network | 4 ++++ test/test-network/conf/25-route-static.network | 4 ++++ test/test-network/systemd-networkd-tests.py | 2 ++ 3 files changed, 10 insertions(+) diff --git a/test/test-network/conf/25-nexthop.network b/test/test-network/conf/25-nexthop.network index 6f54e3f0d50..3e87bd40a93 100644 --- a/test/test-network/conf/25-nexthop.network +++ b/test/test-network/conf/25-nexthop.network @@ -38,6 +38,10 @@ Id=7 Family=ipv6 Blackhole=yes +[NextHop] +Id=8 +Gateway=fe80::222:4dff:ff:ff:ff:ff + [NextHop] Gateway=192.168.5.2 diff --git a/test/test-network/conf/25-route-static.network b/test/test-network/conf/25-route-static.network index 09aae8067ad..94b2e8730fd 100644 --- a/test/test-network/conf/25-route-static.network +++ b/test/test-network/conf/25-route-static.network @@ -17,6 +17,10 @@ Destination=2001:1234:5:9fff:ff:ff:ff:ff/128 [Route] Gateway=2001:1234:5:8fff:ff:ff:ff:ff +[Route] +Destination=2001:1234:5:afff:ff:ff:ff:ff/128 +Gateway=fe80::222:4dff:ff:ff:ff:ff + [Route] Destination=149.10.124.64 Scope=link diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py index 83878614231..e5610bf1b28 100755 --- a/test/test-network/systemd-networkd-tests.py +++ b/test/test-network/systemd-networkd-tests.py @@ -2337,6 +2337,7 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities): print(output) self.assertIn('2001:1234:5:8fff:ff:ff:ff:ff proto static', output) self.assertIn('2001:1234:5:8f63::1 proto kernel', output) + self.assertIn('2001:1234:5:afff:ff:ff:ff:ff via fe80:0:222:4dff:ff:ff:ff:ff proto static', output) print('### ip -6 route show default') output = check_output('ip -6 route show default') @@ -2985,6 +2986,7 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities): self.assertIn('id 3 dev veth99', output) self.assertIn('id 4 dev veth99', output) self.assertRegex(output, 'id 5 via 192.168.10.1 dev veth99 .*onlink') + self.assertIn('id 8 via fe80:0:222:4dff:ff:ff:ff:ff dev veth99', output) self.assertRegex(output, r'id [0-9]* via 192.168.5.2 dev veth99') output = check_output('ip nexthop list dev dummy98')