]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network: fix logic for checking gateway address is ready
authorYu Watanabe <watanabe.yu+github@gmail.com>
Fri, 20 Aug 2021 18:51:39 +0000 (03:51 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Sun, 22 Aug 2021 06:35:22 +0000 (15:35 +0900)
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
src/network/networkd-route.c
src/network/networkd-route.h

index 92cbb1c843d2f2192aef2e9e0bcd52f4704bb145..5584d450255851cacdc0e4053dd80a4aea727945 100644 (file)
@@ -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) {
index 46fbf4f324c7cb25809231d11f3465b214c37d6f..a364ca45b79a66a5be7b27daed1d403307600999 100644 (file)
@@ -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;
-
-                        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;
-                }
+        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;
+        }
 
         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;
index 2d262819add0f3877d10aece97b1afbbd4dd369d..235a91f08d59c41ce2f966474976f6001781793e 100644 (file)
@@ -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);