network: also check addresses when determine a gateway address is reachable or not
authorYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 12 Jul 2021 06:46:44 +0000 (15:46 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 12 Jul 2021 07:35:48 +0000 (16:35 +0900)
Fixes #20201.

src/network/networkd-route.c

index 7b36b481419c89a890adbd31809d23fa7e4770d9..0ab4419eba9e8af58013ed97d21543e5751cf8af 100644 (file)
@@ -746,6 +746,26 @@ static bool route_address_is_reachable(const Route *route, int family, const uni
                         FAMILY_ADDRESS_SIZE(family) * 8) > 0;
 }
 
+static bool prefix_route_address_is_reachable(const Address *a, int family, const union in_addr_union *address) {
+        assert(a);
+        assert(IN_SET(family, AF_INET, AF_INET6));
+        assert(address);
+
+        if (a->family != family)
+                return false;
+        if (FLAGS_SET(a->flags, IFA_F_NOPREFIXROUTE))
+                return false;
+        if (in_addr_is_set(a->family, &a->in_addr_peer))
+                return false;
+
+        return in_addr_prefix_intersect(
+                        family,
+                        &a->in_addr,
+                        a->prefixlen,
+                        address,
+                        FAMILY_ADDRESS_SIZE(family) * 8) > 0;
+}
+
 bool manager_address_is_reachable(Manager *manager, int family, const union in_addr_union *address) {
         Link *link;
 
@@ -764,6 +784,20 @@ bool manager_address_is_reachable(Manager *manager, int family, const union in_a
                                 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;
+                }
+
         return false;
 }