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))
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;
}
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;
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;
}
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;