]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network: introduce {manager,link}_address_is_reachable()
authorYu Watanabe <watanabe.yu+github@gmail.com>
Fri, 25 Feb 2022 07:47:47 +0000 (16:47 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Sun, 27 Feb 2022 00:36:48 +0000 (09:36 +0900)
src/network/networkd-route-util.c
src/network/networkd-route-util.h

index e07dbb213cf5bdd4e4882ff5c8a0bc1d2610d7fd..4c9920b6090803676056e385b1baa84586639653 100644 (file)
@@ -150,6 +150,143 @@ bool gateway_is_ready(Link *link, bool onlink, int family, const union in_addr_u
         return false;
 }
 
+static int link_address_is_reachable_internal(
+                Link *link,
+                int family,
+                const union in_addr_union *address,
+                const union in_addr_union *prefsrc, /* optional */
+                Route **ret) {
+
+        Route *route, *found = NULL;
+
+        assert(link);
+        assert(IN_SET(family, AF_INET, AF_INET6));
+        assert(address);
+
+        SET_FOREACH(route, link->routes) {
+                if (!route_exists(route))
+                        continue;
+
+                if (route->type != RTN_UNICAST)
+                        continue;
+
+                if (route->family != family)
+                        continue;
+
+                if (in_addr_prefix_covers(family, &route->dst, route->dst_prefixlen, address) <= 0)
+                        continue;
+
+                if (prefsrc &&
+                    in_addr_is_set(family, prefsrc) &&
+                    in_addr_is_set(family, &route->prefsrc) &&
+                    !in_addr_equal(family, prefsrc, &route->prefsrc))
+                        continue;
+
+                if (found && found->priority <= route->priority)
+                        continue;
+
+                found = route;
+        }
+
+        if (!found)
+                return -ENOENT;
+
+        if (ret)
+                *ret = found;
+
+        return 0;
+}
+
+int link_address_is_reachable(
+                Link *link,
+                int family,
+                const union in_addr_union *address,
+                const union in_addr_union *prefsrc, /* optional */
+                Address **ret) {
+
+        Route *route;
+        Address *a;
+        int r;
+
+        assert(link);
+        assert(IN_SET(family, AF_INET, AF_INET6));
+        assert(address);
+
+        /* This checks if the address is reachable, and optionally return the Address object of the
+         * preferred source to access the address. */
+
+        r = link_address_is_reachable_internal(link, family, address, prefsrc, &route);
+        if (r < 0)
+                return r;
+
+        if (!in_addr_is_set(route->family, &route->prefsrc)) {
+                if (ret)
+                        *ret = NULL;
+                return 0;
+        }
+
+        r = link_get_address(link, route->family, &route->prefsrc, 0, &a);
+        if (r < 0)
+                return r;
+
+        if (!address_is_ready(a))
+                return -EBUSY;
+
+        if (ret)
+                *ret = a;
+
+        return 0;
+}
+
+int manager_address_is_reachable(
+                Manager *manager,
+                int family,
+                const union in_addr_union *address,
+                const union in_addr_union *prefsrc, /* optional */
+                Address **ret) {
+
+        Route *route, *found = NULL;
+        Address *a;
+        Link *link;
+        int r;
+
+        assert(manager);
+
+        HASHMAP_FOREACH(link, manager->links_by_index) {
+                if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
+                        continue;
+
+                if (link_address_is_reachable_internal(link, family, address, prefsrc, &route) < 0)
+                        continue;
+
+                if (found && found->priority <= route->priority)
+                        continue;
+
+                found = route;
+        }
+
+        if (!found)
+                return -ENOENT;
+
+        if (!in_addr_is_set(found->family, &found->prefsrc)) {
+                if (ret)
+                        *ret = NULL;
+                return 0;
+        }
+
+        r = link_get_address(found->link, found->family, &found->prefsrc, 0, &a);
+        if (r < 0)
+                return r;
+
+        if (!address_is_ready(a))
+                return -EBUSY;
+
+        if (ret)
+                *ret = a;
+
+        return 0;
+}
+
 static const char * const route_type_table[__RTN_MAX] = {
         [RTN_UNICAST]     = "unicast",
         [RTN_LOCAL]       = "local",
index 3dd3d3ace8e6e3f9644e2b0c349d0167a0ac79ef..b862cd677444a6b05c175ed26c26d7feb72cc331 100644 (file)
@@ -8,6 +8,7 @@
 
 typedef struct Link Link;
 typedef struct Manager Manager;
+typedef struct Address Address;
 
 unsigned routes_max(void);
 
@@ -15,6 +16,20 @@ int manager_find_uplink(Manager *m, int family, Link *exclude, Link **ret);
 
 bool gateway_is_ready(Link *link, bool onlink, int family, const union in_addr_union *gw);
 
+int link_address_is_reachable(
+                Link *link,
+                int family,
+                const union in_addr_union *address,
+                const union in_addr_union *prefsrc, /* optional */
+                Address **ret);
+
+int manager_address_is_reachable(
+                Manager *manager,
+                int family,
+                const union in_addr_union *address,
+                const union in_addr_union *prefsrc, /* optional */
+                Address **ret);
+
 int route_type_from_string(const char *s) _pure_;
 const char *route_type_to_string(int t) _const_;