Compare commits

...

8 Commits

Author SHA1 Message Date
Yu Watanabe 74294ac92b
Merge dda1e98c04 into c946b13575 2024-11-22 21:09:58 +01:00
Yu Watanabe dda1e98c04 network/nexthop: add one more assertion
This may help issue #35164.
2024-11-21 16:54:26 +09:00
Yu Watanabe 3d417da827 network: introduce address_forget() and friends and use it where applicable
No functional change, just refactoring.
2024-11-21 16:47:36 +09:00
Yu Watanabe 5209f43ad2 network/nexthop: drop outdated comment and add one debugging log
All NextHop objects are managed by Manager since
352eba2e49.
2024-11-21 16:47:36 +09:00
Yu Watanabe a16844ff60 network/ndisc: unref Route objects that depend on the nexthop
No functional change, as when this function is called, the set will be
freed and contained Route objects will be unref()ed anyway soon later
by nexthop_detach() -> nexthop_free().
Even though, when the routes are forgotten from the Manager, then it is
not necessary to keep them by the nexthop. Let's unref earlier.
2024-11-21 16:47:36 +09:00
Yu Watanabe 5344ee6c94 network/ndisc: constify several arguments and add several assertions
Follow-up for 0f8afaf94d.

No functional change, just for safety.
2024-11-21 16:47:36 +09:00
Yu Watanabe 3985e93dab network/nexthop: do not share NextHop.nexthops and NextHop.routes with duplicated object
Otherwise, these may be freed twice.
But, fortunately, when this function is called, both are NULL.
So, this should not change any behavior. But for safety.
2024-11-21 16:47:36 +09:00
Yu Watanabe c6f6f506fc network: drop outdated comment
All Route objects are managed by Manager since
8d01e44c1f.
2024-11-21 16:47:36 +09:00
7 changed files with 180 additions and 172 deletions

View File

@ -1129,6 +1129,23 @@ void log_address_debug(const Address *address, const char *str, const Link *link
address->family == AF_INET ? strna(address->label) : ""); address->family == AF_INET ? strna(address->label) : "");
} }
static void address_forget(Link *link, Address *address, bool removed_by_us, const char *msg) {
assert(link);
assert(address);
assert(msg);
Request *req;
if (address_get_request(link, address, &req) >= 0)
address_enter_removed(req->userdata);
if (!address->link && address_get(link, address, &address) < 0)
return;
address_enter_removed(address);
log_address_debug(address, msg, link);
(void) address_drop(address, removed_by_us);
}
static int address_set_netlink_message(const Address *address, sd_netlink_message *m, Link *link) { static int address_set_netlink_message(const Address *address, sd_netlink_message *m, Link *link) {
uint32_t flags; uint32_t flags;
int r; int r;
@ -1181,16 +1198,8 @@ static int address_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Remov
(r == -EADDRNOTAVAIL || !address->link) ? LOG_DEBUG : LOG_WARNING, (r == -EADDRNOTAVAIL || !address->link) ? LOG_DEBUG : LOG_WARNING,
r, "Could not drop address"); r, "Could not drop address");
if (address->link) { /* If the address cannot be removed, then assume the address is already removed. */
/* If the address cannot be removed, then assume the address is already removed. */ address_forget(link, address, /* removed_by_us = */ true, "Forgetting");
log_address_debug(address, "Forgetting", link);
Request *req;
if (address_get_request(link, address, &req) >= 0)
address_enter_removed(req->userdata);
(void) address_drop(address, /* removed_by_us = */ true);
}
} }
return 1; return 1;
@ -1775,14 +1784,7 @@ int link_request_static_addresses(Link *link) {
} }
int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message, Manager *m) { int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message, Manager *m) {
_cleanup_(address_unrefp) Address *tmp = NULL; int r;
struct ifa_cacheinfo cinfo;
Link *link;
uint16_t type;
Address *address = NULL;
Request *req = NULL;
bool is_new = false, update_dhcp4;
int ifindex, r;
assert(rtnl); assert(rtnl);
assert(message); assert(message);
@ -1796,6 +1798,7 @@ int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message,
return 0; return 0;
} }
uint16_t type;
r = sd_netlink_message_get_type(message, &type); r = sd_netlink_message_get_type(message, &type);
if (r < 0) { if (r < 0) {
log_warning_errno(r, "rtnl: could not get message type, ignoring: %m"); log_warning_errno(r, "rtnl: could not get message type, ignoring: %m");
@ -1805,6 +1808,7 @@ int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message,
return 0; return 0;
} }
int ifindex;
r = sd_rtnl_message_addr_get_ifindex(message, &ifindex); r = sd_rtnl_message_addr_get_ifindex(message, &ifindex);
if (r < 0) { if (r < 0) {
log_warning_errno(r, "rtnl: could not get ifindex from message, ignoring: %m"); log_warning_errno(r, "rtnl: could not get ifindex from message, ignoring: %m");
@ -1814,6 +1818,7 @@ int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message,
return 0; return 0;
} }
Link *link;
r = link_get_by_index(m, ifindex, &link); r = link_get_by_index(m, ifindex, &link);
if (r < 0) { if (r < 0) {
/* when enumerating we might be out of sync, but we will get the address again, so just /* when enumerating we might be out of sync, but we will get the address again, so just
@ -1823,6 +1828,7 @@ int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message,
return 0; return 0;
} }
_cleanup_(address_unrefp) Address *tmp = NULL;
r = address_new(&tmp); r = address_new(&tmp);
if (r < 0) if (r < 0)
return log_oom(); return log_oom();
@ -1890,28 +1896,22 @@ int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message,
assert_not_reached(); assert_not_reached();
} }
update_dhcp4 = tmp->family == AF_INET6; /* Then, find the managed Address object corresponding to the received address. */
Address *address = NULL;
/* Then, find the managed Address and Request objects corresponding to the received address. */
(void) address_get(link, tmp, &address); (void) address_get(link, tmp, &address);
(void) address_get_request(link, tmp, &req);
if (type == RTM_DELADDR) { if (type == RTM_DELADDR) {
if (address) { if (address)
bool removed_by_us = FLAGS_SET(address->state, NETWORK_CONFIG_STATE_REMOVING); address_forget(link, address,
/* removed_by_us = */ FLAGS_SET(address->state, NETWORK_CONFIG_STATE_REMOVING),
address_enter_removed(address); "Forgetting removed");
log_address_debug(address, "Forgetting removed", link); else
(void) address_drop(address, removed_by_us);
} else
log_address_debug(tmp, "Kernel removed unknown", link); log_address_debug(tmp, "Kernel removed unknown", link);
if (req)
address_enter_removed(req->userdata);
goto finalize; goto finalize;
} }
bool is_new = false;
if (!address) { if (!address) {
/* If we did not know the address, then save it. */ /* If we did not know the address, then save it. */
r = address_attach(link, tmp); r = address_attach(link, tmp);
@ -1931,6 +1931,8 @@ int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message,
} }
/* Also update information that cannot be obtained through netlink notification. */ /* Also update information that cannot be obtained through netlink notification. */
Request *req = NULL;
(void) address_get_request(link, tmp, &req);
if (req && req->waiting_reply) { if (req && req->waiting_reply) {
Address *a = ASSERT_PTR(req->userdata); Address *a = ASSERT_PTR(req->userdata);
@ -1978,6 +1980,7 @@ int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message,
} else if (r < 0) } else if (r < 0)
log_link_debug_errno(link, r, "rtnl: failed to read IFA_FLAGS attribute, ignoring: %m"); log_link_debug_errno(link, r, "rtnl: failed to read IFA_FLAGS attribute, ignoring: %m");
struct ifa_cacheinfo cinfo;
r = sd_netlink_message_read_cache_info(message, IFA_CACHEINFO, &cinfo); r = sd_netlink_message_read_cache_info(message, IFA_CACHEINFO, &cinfo);
if (r >= 0) if (r >= 0)
address_set_lifetime(m, address, &cinfo); address_set_lifetime(m, address, &cinfo);
@ -2000,7 +2003,7 @@ int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message,
link_enter_failed(link); link_enter_failed(link);
finalize: finalize:
if (update_dhcp4) { if (tmp->family == AF_INET6) {
r = dhcp4_update_ipv6_connectivity(link); r = dhcp4_update_ipv6_connectivity(link);
if (r < 0) { if (r < 0) {
log_link_warning_errno(link, r, "Failed to notify IPv6 connectivity to DHCPv4 client: %m"); log_link_warning_errno(link, r, "Failed to notify IPv6 connectivity to DHCPv4 client: %m");

View File

@ -705,10 +705,6 @@ Manager* manager_free(Manager *m) {
sd_netlink_unref(m->genl); sd_netlink_unref(m->genl);
sd_resolve_unref(m->resolve); sd_resolve_unref(m->resolve);
/* reject (e.g. unreachable) type routes are managed by Manager, but may be referenced by a
* link. E.g., DHCP6 with prefix delegation creates unreachable routes, and they are referenced
* by the upstream link. And the links may be referenced by netlink slots. Hence, two
* set_free() must be called after the above sd_netlink_unref(). */
m->routes = set_free(m->routes); m->routes = set_free(m->routes);
m->nexthops_by_id = hashmap_free(m->nexthops_by_id); m->nexthops_by_id = hashmap_free(m->nexthops_by_id);

View File

@ -215,7 +215,7 @@ static int ndisc_remove_unused_nexthops(Link *link) {
#define NDISC_NEXTHOP_APP_ID SD_ID128_MAKE(76,d2,0f,1f,76,1e,44,d1,97,3a,52,5c,05,68,b5,0d) #define NDISC_NEXTHOP_APP_ID SD_ID128_MAKE(76,d2,0f,1f,76,1e,44,d1,97,3a,52,5c,05,68,b5,0d)
static uint32_t ndisc_generate_nexthop_id(NextHop *nexthop, Link *link, sd_id128_t app_id, uint64_t trial) { static uint32_t ndisc_generate_nexthop_id(const NextHop *nexthop, Link *link, sd_id128_t app_id, uint64_t trial) {
assert(nexthop); assert(nexthop);
assert(link); assert(link);
@ -232,7 +232,7 @@ static uint32_t ndisc_generate_nexthop_id(NextHop *nexthop, Link *link, sd_id128
return (uint32_t) ((result & 0xffffffff) ^ (result >> 32)); return (uint32_t) ((result & 0xffffffff) ^ (result >> 32));
} }
static bool ndisc_nexthop_equal(NextHop *a, NextHop *b) { static bool ndisc_nexthop_equal(const NextHop *a, const NextHop *b) {
assert(a); assert(a);
assert(b); assert(b);
@ -250,9 +250,11 @@ static bool ndisc_nexthop_equal(NextHop *a, NextHop *b) {
return true; return true;
} }
static bool ndisc_take_nexthop_id(NextHop *nexthop, NextHop *existing, Manager *manager) { static bool ndisc_take_nexthop_id(NextHop *nexthop, const NextHop *existing, Manager *manager) {
assert(nexthop); assert(nexthop);
assert(nexthop->id == 0);
assert(existing); assert(existing);
assert(existing->id > 0);
assert(manager); assert(manager);
if (!ndisc_nexthop_equal(nexthop, existing)) if (!ndisc_nexthop_equal(nexthop, existing))
@ -300,7 +302,7 @@ static int ndisc_nexthop_find_id(NextHop *nexthop, Link *link) {
return false; return false;
} }
static int ndisc_nexthop_new(Route *route, Link *link, NextHop **ret) { static int ndisc_nexthop_new(const Route *route, Link *link, NextHop **ret) {
_cleanup_(nexthop_unrefp) NextHop *nexthop = NULL; _cleanup_(nexthop_unrefp) NextHop *nexthop = NULL;
int r; int r;

View File

@ -247,6 +247,23 @@ static void log_neighbor_debug(const Neighbor *neighbor, const char *str, const
IN_ADDR_TO_STRING(neighbor->dst_addr.family, &neighbor->dst_addr.address)); IN_ADDR_TO_STRING(neighbor->dst_addr.family, &neighbor->dst_addr.address));
} }
static void neighbor_forget(Link *link, Neighbor *neighbor, const char *msg) {
assert(link);
assert(neighbor);
assert(msg);
Request *req;
if (neighbor_get_request(link, neighbor, &req) >= 0)
neighbor_enter_removed(req->userdata);
if (!neighbor->link && neighbor_get(link, neighbor, &neighbor) < 0)
return;
neighbor_enter_removed(neighbor);
log_neighbor_debug(neighbor, "Forgetting", link);
neighbor_detach(neighbor);
}
static int neighbor_configure(Neighbor *neighbor, Link *link, Request *req) { static int neighbor_configure(Neighbor *neighbor, Link *link, Request *req) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
int r; int r;
@ -421,16 +438,8 @@ static int neighbor_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Remo
(r == -ESRCH || !neighbor->link) ? LOG_DEBUG : LOG_WARNING, (r == -ESRCH || !neighbor->link) ? LOG_DEBUG : LOG_WARNING,
r, "Could not remove neighbor"); r, "Could not remove neighbor");
if (neighbor->link) { /* If the neighbor cannot be removed, then assume the neighbor is already removed. */
/* If the neighbor cannot be removed, then assume the neighbor is already removed. */ neighbor_forget(link, neighbor, "Forgetting");
log_neighbor_debug(neighbor, "Forgetting", link);
Request *req;
if (neighbor_get_request(link, neighbor, &req) >= 0)
neighbor_enter_removed(req->userdata);
neighbor_detach(neighbor);
}
} }
return 1; return 1;
@ -529,13 +538,7 @@ int link_drop_static_neighbors(Link *link) {
} }
int manager_rtnl_process_neighbor(sd_netlink *rtnl, sd_netlink_message *message, Manager *m) { int manager_rtnl_process_neighbor(sd_netlink *rtnl, sd_netlink_message *message, Manager *m) {
_cleanup_(neighbor_unrefp) Neighbor *tmp = NULL; int r;
Neighbor *neighbor = NULL;
Request *req = NULL;
uint16_t type, state;
bool is_new = false;
int ifindex, r;
Link *link;
assert(rtnl); assert(rtnl);
assert(message); assert(message);
@ -549,6 +552,7 @@ int manager_rtnl_process_neighbor(sd_netlink *rtnl, sd_netlink_message *message,
return 0; return 0;
} }
uint16_t type;
r = sd_netlink_message_get_type(message, &type); r = sd_netlink_message_get_type(message, &type);
if (r < 0) { if (r < 0) {
log_warning_errno(r, "rtnl: could not get message type, ignoring: %m"); log_warning_errno(r, "rtnl: could not get message type, ignoring: %m");
@ -558,6 +562,7 @@ int manager_rtnl_process_neighbor(sd_netlink *rtnl, sd_netlink_message *message,
return 0; return 0;
} }
uint16_t state;
r = sd_rtnl_message_neigh_get_state(message, &state); r = sd_rtnl_message_neigh_get_state(message, &state);
if (r < 0) { if (r < 0) {
log_warning_errno(r, "rtnl: received neighbor message with invalid state, ignoring: %m"); log_warning_errno(r, "rtnl: received neighbor message with invalid state, ignoring: %m");
@ -566,6 +571,7 @@ int manager_rtnl_process_neighbor(sd_netlink *rtnl, sd_netlink_message *message,
/* Currently, we are interested in only static neighbors. */ /* Currently, we are interested in only static neighbors. */
return 0; return 0;
int ifindex;
r = sd_rtnl_message_neigh_get_ifindex(message, &ifindex); r = sd_rtnl_message_neigh_get_ifindex(message, &ifindex);
if (r < 0) { if (r < 0) {
log_warning_errno(r, "rtnl: could not get ifindex from message, ignoring: %m"); log_warning_errno(r, "rtnl: could not get ifindex from message, ignoring: %m");
@ -575,12 +581,14 @@ int manager_rtnl_process_neighbor(sd_netlink *rtnl, sd_netlink_message *message,
return 0; return 0;
} }
Link *link;
r = link_get_by_index(m, ifindex, &link); r = link_get_by_index(m, ifindex, &link);
if (r < 0) if (r < 0)
/* when enumerating we might be out of sync, but we will get the neighbor again. Also, /* when enumerating we might be out of sync, but we will get the neighbor again. Also,
* kernel sends messages about neighbors after a link is removed. So, just ignore it. */ * kernel sends messages about neighbors after a link is removed. So, just ignore it. */
return 0; return 0;
_cleanup_(neighbor_unrefp) Neighbor *tmp = NULL;
r = neighbor_new(&tmp); r = neighbor_new(&tmp);
if (r < 0) if (r < 0)
return log_oom(); return log_oom();
@ -604,25 +612,20 @@ int manager_rtnl_process_neighbor(sd_netlink *rtnl, sd_netlink_message *message,
return 0; return 0;
} }
/* Then, find the managed Neighbor and Request objects corresponding to the netlink notification. */ /* Then, find the managed Neighbor object corresponding to the netlink notification. */
Neighbor *neighbor = NULL;
(void) neighbor_get(link, tmp, &neighbor); (void) neighbor_get(link, tmp, &neighbor);
(void) neighbor_get_request(link, tmp, &req);
if (type == RTM_DELNEIGH) { if (type == RTM_DELNEIGH) {
if (neighbor) { if (neighbor)
neighbor_enter_removed(neighbor); neighbor_forget(link, neighbor, "Forgetting removed");
log_neighbor_debug(neighbor, "Forgetting removed", link); else
neighbor_detach(neighbor);
} else
log_neighbor_debug(tmp, "Kernel removed unknown", link); log_neighbor_debug(tmp, "Kernel removed unknown", link);
if (req)
neighbor_enter_removed(req->userdata);
return 0; return 0;
} }
/* If we did not know the neighbor, then save it. */ /* If we did not know the neighbor, then save it. */
bool is_new = false;
if (!neighbor) { if (!neighbor) {
r = neighbor_attach(link, tmp); r = neighbor_attach(link, tmp);
if (r < 0) { if (r < 0) {
@ -634,6 +637,8 @@ int manager_rtnl_process_neighbor(sd_netlink *rtnl, sd_netlink_message *message,
} }
/* Also update information that cannot be obtained through netlink notification. */ /* Also update information that cannot be obtained through netlink notification. */
Request *req = NULL;
(void) neighbor_get_request(link, tmp, &req);
if (req && req->waiting_reply) { if (req && req->waiting_reply) {
Neighbor *n = ASSERT_PTR(req->userdata); Neighbor *n = ASSERT_PTR(req->userdata);

View File

@ -78,7 +78,9 @@ static NextHop* nexthop_detach_impl(NextHop *nexthop) {
nexthop_detach_from_group_members(nexthop); nexthop_detach_from_group_members(nexthop);
hashmap_remove(nexthop->manager->nexthops_by_id, UINT32_TO_PTR(nexthop->id)); NextHop *n;
n = hashmap_remove(nexthop->manager->nexthops_by_id, UINT32_TO_PTR(nexthop->id));
assert(!n || n == nexthop);
nexthop->manager = NULL; nexthop->manager = NULL;
return nexthop; return nexthop;
} }
@ -261,6 +263,8 @@ static int nexthop_dup(const NextHop *src, NextHop **ret) {
dest->network = NULL; dest->network = NULL;
dest->section = NULL; dest->section = NULL;
dest->group = NULL; dest->group = NULL;
dest->nexthops = NULL;
dest->routes = NULL;
HASHMAP_FOREACH(nhg, src->group) { HASHMAP_FOREACH(nhg, src->group) {
_cleanup_free_ struct nexthop_grp *g = NULL; _cleanup_free_ struct nexthop_grp *g = NULL;
@ -491,8 +495,11 @@ static void nexthop_forget_dependents(NextHop *nexthop, Manager *manager) {
/* If a nexthop is removed, the kernel silently removes routes that depend on the removed nexthop. /* If a nexthop is removed, the kernel silently removes routes that depend on the removed nexthop.
* Let's forget them. */ * Let's forget them. */
Route *route; for (;;) {
SET_FOREACH(route, nexthop->routes) { _cleanup_(route_unrefp) Route *route = set_steal_first(nexthop->routes);
if (!route)
break;
Request *req; Request *req;
if (route_get_request(manager, route, &req) >= 0) if (route_get_request(manager, route, &req) >= 0)
route_enter_removed(req->userdata); route_enter_removed(req->userdata);
@ -501,6 +508,26 @@ static void nexthop_forget_dependents(NextHop *nexthop, Manager *manager) {
log_route_debug(route, "Forgetting silently removed", manager); log_route_debug(route, "Forgetting silently removed", manager);
route_detach(route); route_detach(route);
} }
nexthop->routes = set_free(nexthop->routes);
}
static void nexthop_forget(Manager *manager, NextHop *nexthop, const char *msg) {
assert(manager);
assert(nexthop);
assert(msg);
Request *req;
if (nexthop_get_request_by_id(manager, nexthop->id, &req) >= 0)
nexthop_enter_removed(req->userdata);
if (!nexthop->manager && nexthop_get_by_id(manager, nexthop->id, &nexthop) < 0)
return;
nexthop_enter_removed(nexthop);
log_nexthop_debug(nexthop, msg, manager);
nexthop_forget_dependents(nexthop, nexthop->manager);
nexthop_detach(nexthop);
} }
static int nexthop_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, RemoveRequest *rreq) { static int nexthop_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, RemoveRequest *rreq) {
@ -518,18 +545,8 @@ static int nexthop_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Remov
(r == -ENOENT || !nexthop->manager) ? LOG_DEBUG : LOG_WARNING, (r == -ENOENT || !nexthop->manager) ? LOG_DEBUG : LOG_WARNING,
r, "Could not drop nexthop, ignoring"); r, "Could not drop nexthop, ignoring");
nexthop_forget_dependents(nexthop, manager); /* If the nexthop cannot be removed, then assume the nexthop is already removed. */
nexthop_forget(manager, nexthop, "Forgetting");
if (nexthop->manager) {
/* If the nexthop cannot be removed, then assume the nexthop is already removed. */
log_nexthop_debug(nexthop, "Forgetting", manager);
Request *req;
if (nexthop_get_request_by_id(manager, nexthop->id, &req) >= 0)
nexthop_enter_removed(req->userdata);
nexthop_detach(nexthop);
}
} }
return 1; return 1;
@ -962,20 +979,6 @@ int link_drop_nexthops(Link *link, bool only_static) {
return r; return r;
} }
static void nexthop_forget_one(NextHop *nexthop) {
assert(nexthop);
assert(nexthop->manager);
Request *req;
if (nexthop_get_request_by_id(nexthop->manager, nexthop->id, &req) >= 0)
nexthop_enter_removed(req->userdata);
nexthop_enter_removed(nexthop);
log_nexthop_debug(nexthop, "Forgetting silently removed", nexthop->manager);
nexthop_forget_dependents(nexthop, nexthop->manager);
nexthop_detach(nexthop);
}
void link_forget_nexthops(Link *link) { void link_forget_nexthops(Link *link) {
assert(link); assert(link);
assert(link->manager); assert(link->manager);
@ -992,7 +995,7 @@ void link_forget_nexthops(Link *link) {
if (nexthop->family != AF_INET) if (nexthop->family != AF_INET)
continue; continue;
nexthop_forget_one(nexthop); nexthop_forget(link->manager, nexthop, "Forgetting silently removed");
} }
/* Remove all group nexthops their all members are removed in the above. */ /* Remove all group nexthops their all members are removed in the above. */
@ -1013,7 +1016,7 @@ void link_forget_nexthops(Link *link) {
if (!hashmap_isempty(nexthop->group)) if (!hashmap_isempty(nexthop->group))
continue; /* At least one group member still exists. */ continue; /* At least one group member still exists. */
nexthop_forget_one(nexthop); nexthop_forget(link->manager, nexthop, "Forgetting silently removed");
} }
} }
@ -1077,11 +1080,6 @@ static int nexthop_update_group(NextHop *nexthop, sd_netlink_message *message) {
} }
int manager_rtnl_process_nexthop(sd_netlink *rtnl, sd_netlink_message *message, Manager *m) { int manager_rtnl_process_nexthop(sd_netlink *rtnl, sd_netlink_message *message, Manager *m) {
uint16_t type;
uint32_t id, ifindex;
NextHop *nexthop = NULL;
Request *req = NULL;
bool is_new = false;
int r; int r;
assert(rtnl); assert(rtnl);
@ -1096,6 +1094,7 @@ int manager_rtnl_process_nexthop(sd_netlink *rtnl, sd_netlink_message *message,
return 0; return 0;
} }
uint16_t type;
r = sd_netlink_message_get_type(message, &type); r = sd_netlink_message_get_type(message, &type);
if (r < 0) { if (r < 0) {
log_warning_errno(r, "rtnl: could not get message type, ignoring: %m"); log_warning_errno(r, "rtnl: could not get message type, ignoring: %m");
@ -1105,6 +1104,7 @@ int manager_rtnl_process_nexthop(sd_netlink *rtnl, sd_netlink_message *message,
return 0; return 0;
} }
uint32_t id;
r = sd_netlink_message_read_u32(message, NHA_ID, &id); r = sd_netlink_message_read_u32(message, NHA_ID, &id);
if (r == -ENODATA) { if (r == -ENODATA) {
log_warning_errno(r, "rtnl: received nexthop message without NHA_ID attribute, ignoring: %m"); log_warning_errno(r, "rtnl: received nexthop message without NHA_ID attribute, ignoring: %m");
@ -1117,25 +1117,20 @@ int manager_rtnl_process_nexthop(sd_netlink *rtnl, sd_netlink_message *message,
return 0; return 0;
} }
NextHop *nexthop = NULL;
(void) nexthop_get_by_id(m, id, &nexthop); (void) nexthop_get_by_id(m, id, &nexthop);
(void) nexthop_get_request_by_id(m, id, &req);
if (type == RTM_DELNEXTHOP) { if (type == RTM_DELNEXTHOP) {
if (nexthop) { if (nexthop)
nexthop_enter_removed(nexthop); nexthop_forget(m, nexthop, "Forgetting removed");
log_nexthop_debug(nexthop, "Forgetting removed", m); else
nexthop_forget_dependents(nexthop, m);
nexthop_detach(nexthop);
} else
log_nexthop_debug(&(const NextHop) { .id = id }, "Kernel removed unknown", m); log_nexthop_debug(&(const NextHop) { .id = id }, "Kernel removed unknown", m);
if (req)
nexthop_enter_removed(req->userdata);
return 0; return 0;
} }
/* If we did not know the nexthop, then save it. */ /* If we did not know the nexthop, then save it. */
bool is_new = false;
if (!nexthop) { if (!nexthop) {
r = nexthop_add_new(m, id, &nexthop); r = nexthop_add_new(m, id, &nexthop);
if (r < 0) { if (r < 0) {
@ -1147,6 +1142,8 @@ int manager_rtnl_process_nexthop(sd_netlink *rtnl, sd_netlink_message *message,
} }
/* Also update information that cannot be obtained through netlink notification. */ /* Also update information that cannot be obtained through netlink notification. */
Request *req = NULL;
(void) nexthop_get_request_by_id(m, id, &req);
if (req && req->waiting_reply) { if (req && req->waiting_reply) {
NextHop *n = ASSERT_PTR(req->userdata); NextHop *n = ASSERT_PTR(req->userdata);
@ -1182,6 +1179,7 @@ int manager_rtnl_process_nexthop(sd_netlink *rtnl, sd_netlink_message *message,
else else
nexthop->blackhole = r; nexthop->blackhole = r;
uint32_t ifindex;
r = sd_netlink_message_read_u32(message, NHA_OIF, &ifindex); r = sd_netlink_message_read_u32(message, NHA_OIF, &ifindex);
if (r == -ENODATA) if (r == -ENODATA)
nexthop->ifindex = 0; nexthop->ifindex = 0;
@ -1192,10 +1190,12 @@ int manager_rtnl_process_nexthop(sd_netlink *rtnl, sd_netlink_message *message,
else else
nexthop->ifindex = (int) ifindex; nexthop->ifindex = (int) ifindex;
/* All blackhole or group nexthops are managed by Manager. Note that the linux kernel does not /* The linux kernel does not set NHA_OID attribute when NHA_BLACKHOLE or NHA_GROUP is set.
* set NHA_OID attribute when NHA_BLACKHOLE or NHA_GROUP is set. Just for safety. */ * But let's check that for safety. */
if (!nexthop_bound_to_link(nexthop)) if (!nexthop_bound_to_link(nexthop) && nexthop->ifindex != 0) {
log_debug("rtnl: received blackhole or group nexthop with NHA_OIF attribute, ignoring the attribute.");
nexthop->ifindex = 0; nexthop->ifindex = 0;
}
nexthop_enter_configured(nexthop); nexthop_enter_configured(nexthop);
if (req) if (req)

View File

@ -460,6 +460,23 @@ void log_route_debug(const Route *route, const char *str, Manager *manager) {
strna(proto), strna(scope), strna(route_type_to_string(route->type)), strna(flags)); strna(proto), strna(scope), strna(route_type_to_string(route->type)), strna(flags));
} }
static void route_forget(Manager *manager, Route *route, const char *msg) {
assert(manager);
assert(route);
assert(msg);
Request *req;
if (route_get_request(manager, route, &req) >= 0)
route_enter_removed(req->userdata);
if (!route->manager && route_get(manager, route, &route) < 0)
return;
route_enter_removed(route);
log_route_debug(route, msg, manager);
route_detach(route);
}
static int route_set_netlink_message(const Route *route, sd_netlink_message *m) { static int route_set_netlink_message(const Route *route, sd_netlink_message *m) {
int r; int r;
@ -564,16 +581,8 @@ static int route_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, RemoveR
LOG_DEBUG : LOG_WARNING, LOG_DEBUG : LOG_WARNING,
r, "Could not drop route, ignoring"); r, "Could not drop route, ignoring");
if (route->manager) { /* If the route cannot be removed, then assume the route is already removed. */
/* If the route cannot be removed, then assume the route is already removed. */ route_forget(manager, route, "Forgetting");
log_route_debug(route, "Forgetting", manager);
Request *req;
if (route_get_request(manager, route, &req) >= 0)
route_enter_removed(req->userdata);
route_detach(route);
}
} }
return 1; return 1;
@ -1088,7 +1097,6 @@ static int process_route_one(
Route *tmp, Route *tmp,
const struct rta_cacheinfo *cacheinfo) { const struct rta_cacheinfo *cacheinfo) {
Request *req = NULL;
Route *route = NULL; Route *route = NULL;
Link *link = NULL; Link *link = NULL;
bool is_new = false, update_dhcp4; bool is_new = false, update_dhcp4;
@ -1099,13 +1107,15 @@ static int process_route_one(
assert(IN_SET(type, RTM_NEWROUTE, RTM_DELROUTE)); assert(IN_SET(type, RTM_NEWROUTE, RTM_DELROUTE));
(void) route_get(manager, tmp, &route); (void) route_get(manager, tmp, &route);
(void) route_get_request(manager, tmp, &req);
(void) route_get_link(manager, tmp, &link); (void) route_get_link(manager, tmp, &link);
update_dhcp4 = link && tmp->family == AF_INET6 && tmp->dst_prefixlen == 0; update_dhcp4 = link && tmp->family == AF_INET6 && tmp->dst_prefixlen == 0;
switch (type) { switch (type) {
case RTM_NEWROUTE: case RTM_NEWROUTE: {
Request *req = NULL;
(void) route_get_request(manager, tmp, &req);
if (!route) { if (!route) {
if (!manager->manage_foreign_routes && !(req && req->waiting_reply)) { if (!manager->manage_foreign_routes && !(req && req->waiting_reply)) {
route_enter_configured(tmp); route_enter_configured(tmp);
@ -1159,20 +1169,14 @@ static int process_route_one(
(void) route_setup_timer(route, cacheinfo); (void) route_setup_timer(route, cacheinfo);
break; break;
}
case RTM_DELROUTE: case RTM_DELROUTE:
if (route) { if (route)
route_enter_removed(route); route_forget(manager, route, "Forgetting removed");
log_route_debug(route, "Forgetting removed", manager); else
route_detach(route);
} else
log_route_debug(tmp, log_route_debug(tmp,
manager->manage_foreign_routes ? "Kernel removed unknown" : "Ignoring received", manager->manage_foreign_routes ? "Kernel removed unknown" : "Ignoring received",
manager); manager);
if (req)
route_enter_removed(req->userdata);
break; break;
default: default:
@ -1574,13 +1578,7 @@ void link_forget_routes(Link *link) {
if (!IN_SET(route->type, RTN_UNICAST, RTN_BROADCAST, RTN_ANYCAST, RTN_MULTICAST)) if (!IN_SET(route->type, RTN_UNICAST, RTN_BROADCAST, RTN_ANYCAST, RTN_MULTICAST))
continue; continue;
Request *req; route_forget(link->manager, route, "Forgetting silently removed");
if (route_get_request(link->manager, route, &req) >= 0)
route_enter_removed(req->userdata);
route_enter_removed(route);
log_route_debug(route, "Forgetting silently removed", link->manager);
route_detach(route);
} }
} }

View File

@ -550,6 +550,23 @@ static void log_routing_policy_rule_debug(const RoutingPolicyRule *rule, const c
strna(rule->iif), strna(rule->oif), strna(table)); strna(rule->iif), strna(rule->oif), strna(table));
} }
static void routing_policy_rule_forget(Manager *manager, RoutingPolicyRule *rule, const char *msg) {
assert(manager);
assert(rule);
assert(msg);
Request *req;
if (routing_policy_rule_get_request(manager, rule, rule->family, &req) >= 0)
routing_policy_rule_enter_removed(req->userdata);
if (!rule->manager && routing_policy_rule_get(manager, rule, rule->family, &rule) < 0)
return;
routing_policy_rule_enter_removed(rule);
log_routing_policy_rule_debug(rule, "Forgetting", NULL, manager);
routing_policy_rule_detach(rule);
}
static int routing_policy_rule_set_netlink_message(const RoutingPolicyRule *rule, sd_netlink_message *m) { static int routing_policy_rule_set_netlink_message(const RoutingPolicyRule *rule, sd_netlink_message *m) {
int r; int r;
@ -708,16 +725,8 @@ static int routing_policy_rule_remove_handler(sd_netlink *rtnl, sd_netlink_messa
(r == -ENOENT || !rule->manager) ? LOG_DEBUG : LOG_WARNING, (r == -ENOENT || !rule->manager) ? LOG_DEBUG : LOG_WARNING,
r, "Could not drop routing policy rule, ignoring"); r, "Could not drop routing policy rule, ignoring");
if (rule->manager) { /* If the rule cannot be removed, then assume the rule is already removed. */
/* If the rule cannot be removed, then assume the rule is already removed. */ routing_policy_rule_forget(manager, rule, "Forgetting");
log_routing_policy_rule_debug(rule, "Forgetting", NULL, manager);
Request *req;
if (routing_policy_rule_get_request(manager, rule, rule->family, &req) >= 0)
routing_policy_rule_enter_removed(req->userdata);
routing_policy_rule_detach(rule);
}
} }
return 1; return 1;
@ -1046,10 +1055,6 @@ static bool routing_policy_rule_is_created_by_kernel(const RoutingPolicyRule *ru
} }
int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, Manager *m) { int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, Manager *m) {
_cleanup_(routing_policy_rule_unrefp) RoutingPolicyRule *tmp = NULL;
RoutingPolicyRule *rule = NULL;
Request *req = NULL;
uint16_t type;
int r; int r;
assert(rtnl); assert(rtnl);
@ -1063,6 +1068,7 @@ int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, Man
return 0; return 0;
} }
uint16_t type;
r = sd_netlink_message_get_type(message, &type); r = sd_netlink_message_get_type(message, &type);
if (r < 0) { if (r < 0) {
log_warning_errno(r, "rtnl: could not get message type, ignoring: %m"); log_warning_errno(r, "rtnl: could not get message type, ignoring: %m");
@ -1072,6 +1078,7 @@ int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, Man
return 0; return 0;
} }
_cleanup_(routing_policy_rule_unrefp) RoutingPolicyRule *tmp = NULL;
r = routing_policy_rule_new(&tmp); r = routing_policy_rule_new(&tmp);
if (r < 0) { if (r < 0) {
log_oom(); log_oom();
@ -1240,23 +1247,20 @@ int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, Man
return 0; return 0;
} }
RoutingPolicyRule *rule = NULL;
(void) routing_policy_rule_get(m, tmp, tmp->family, &rule); (void) routing_policy_rule_get(m, tmp, tmp->family, &rule);
(void) routing_policy_rule_get_request(m, tmp, tmp->family, &req);
if (type == RTM_DELRULE) { if (type == RTM_DELRULE) {
if (rule) { if (rule)
routing_policy_rule_enter_removed(rule); routing_policy_rule_forget(m, rule, "Forgetting removed");
log_routing_policy_rule_debug(rule, "Forgetting removed", NULL, m); else
routing_policy_rule_detach(rule);
} else
log_routing_policy_rule_debug(tmp, "Kernel removed unknown", NULL, m); log_routing_policy_rule_debug(tmp, "Kernel removed unknown", NULL, m);
if (req)
routing_policy_rule_enter_removed(req->userdata);
return 0; return 0;
} }
Request *req = NULL;
(void) routing_policy_rule_get_request(m, tmp, tmp->family, &req);
bool is_new = false; bool is_new = false;
if (!rule) { if (!rule) {
if (!req && !m->manage_foreign_rules) { if (!req && !m->manage_foreign_rules) {