summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/network/networkd-route-util.c137
-rw-r--r--src/network/networkd-route-util.h15
2 files changed, 152 insertions, 0 deletions
diff --git a/src/network/networkd-route-util.c b/src/network/networkd-route-util.c
index e07dbb213c..4c9920b609 100644
--- a/src/network/networkd-route-util.c
+++ b/src/network/networkd-route-util.c
@@ -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",
diff --git a/src/network/networkd-route-util.h b/src/network/networkd-route-util.h
index 3dd3d3ace8..b862cd6774 100644
--- a/src/network/networkd-route-util.h
+++ b/src/network/networkd-route-util.h
@@ -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_;