Skip to content

Commit

Permalink
network: fix logic for checking gateway address is ready
Browse files Browse the repository at this point in the history
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 systemd/systemd#8686 (comment).
  • Loading branch information
yuwata committed Aug 22, 2021
1 parent 66dc9b4 commit 3333350
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 37 deletions.
7 changes: 1 addition & 6 deletions src/network/networkd-nexthop.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
72 changes: 42 additions & 30 deletions src/network/networkd-route.c
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand All @@ -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;
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion src/network/networkd-route.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit 3333350

Please sign in to comment.