mirror of
https://github.com/systemd/systemd-stable.git
synced 2025-02-09 09:57:26 +03:00
network: nexthop: drop unnecessary nexthops
Similar to addresses or routes, this makes networkd drops unnecessary nexthops on configuring links or when a link is dropped.
This commit is contained in:
parent
0e9d129c16
commit
25b82b6e0e
@ -1980,6 +1980,10 @@ static int link_drop_foreign_config(Link *link) {
|
||||
if (k < 0 && r >= 0)
|
||||
r = k;
|
||||
|
||||
k = link_drop_foreign_nexthops(link);
|
||||
if (k < 0 && r >= 0)
|
||||
r = k;
|
||||
|
||||
k = manager_drop_foreign_routing_policy_rules(link->manager);
|
||||
if (k < 0 && r >= 0)
|
||||
r = k;
|
||||
@ -2003,6 +2007,10 @@ static int link_drop_config(Link *link) {
|
||||
if (k < 0 && r >= 0)
|
||||
r = k;
|
||||
|
||||
k = link_drop_nexthops(link);
|
||||
if (k < 0 && r >= 0)
|
||||
r = k;
|
||||
|
||||
k = manager_drop_routing_policy_rules(link->manager, link);
|
||||
if (k < 0 && r >= 0)
|
||||
r = k;
|
||||
|
@ -151,6 +151,16 @@ DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(
|
||||
nexthop_compare_func,
|
||||
nexthop_free);
|
||||
|
||||
static bool nexthop_equal(const NextHop *a, const NextHop *b) {
|
||||
if (a == b)
|
||||
return true;
|
||||
|
||||
if (!a || !b)
|
||||
return false;
|
||||
|
||||
return nexthop_compare_func(a, b) == 0;
|
||||
}
|
||||
|
||||
static void nexthop_copy(NextHop *dest, const NextHop *src) {
|
||||
assert(dest);
|
||||
assert(src);
|
||||
@ -345,6 +355,56 @@ static void log_nexthop_debug(const NextHop *nexthop, uint32_t id, const char *s
|
||||
}
|
||||
}
|
||||
|
||||
static int nexthop_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
|
||||
/* Note that link may be NULL. */
|
||||
if (link && IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
|
||||
return 1;
|
||||
|
||||
r = sd_netlink_message_get_errno(m);
|
||||
if (r < 0 && r != -ENOENT)
|
||||
log_link_message_warning_errno(link, m, r, "Could not drop nexthop, ignoring");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int nexthop_remove(const NextHop *nexthop, Manager *manager, Link *link) {
|
||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
|
||||
int r;
|
||||
|
||||
assert(nexthop);
|
||||
assert(manager);
|
||||
|
||||
/* link may be NULL. */
|
||||
|
||||
if (nexthop->id == 0) {
|
||||
log_link_debug(link, "Cannot remove nexthop without valid ID, ignoring.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_nexthop_debug(nexthop, nexthop->id, "Removing", link);
|
||||
|
||||
r = sd_rtnl_message_new_nexthop(manager->rtnl, &req, RTM_DELNEXTHOP, AF_UNSPEC, RTPROT_UNSPEC);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not create RTM_DELNEXTHOP message: %m");
|
||||
|
||||
r = sd_netlink_message_append_u32(req, NHA_ID, nexthop->id);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not append NHA_ID attribute: %m");
|
||||
|
||||
r = netlink_call_async(manager->rtnl, NULL, req, nexthop_remove_handler,
|
||||
link_netlink_destroy_callback, link);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
|
||||
|
||||
link_ref(link); /* link may be NULL, link_ref() is OK with that */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nexthop_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
||||
int r;
|
||||
|
||||
@ -478,6 +538,124 @@ int link_set_nexthops(Link *link) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool link_has_nexthop(const Link *link, const NextHop *nexthop) {
|
||||
NextHop *net_nexthop;
|
||||
|
||||
assert(link);
|
||||
assert(nexthop);
|
||||
|
||||
if (!link->network)
|
||||
return false;
|
||||
|
||||
HASHMAP_FOREACH(net_nexthop, link->network->nexthops_by_section)
|
||||
if (nexthop_equal(net_nexthop, nexthop))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool links_have_nexthop(const Manager *manager, const NextHop *nexthop, const Link *except) {
|
||||
Link *link;
|
||||
|
||||
assert(manager);
|
||||
|
||||
HASHMAP_FOREACH(link, manager->links) {
|
||||
if (link == except)
|
||||
continue;
|
||||
|
||||
if (link_has_nexthop(link, nexthop))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int manager_drop_nexthops_internal(Manager *manager, bool foreign, const Link *except) {
|
||||
NextHop *nexthop;
|
||||
Set *nexthops;
|
||||
int k, r = 0;
|
||||
|
||||
assert(manager);
|
||||
|
||||
nexthops = foreign ? manager->nexthops_foreign : manager->nexthops;
|
||||
SET_FOREACH(nexthop, nexthops) {
|
||||
/* do not touch nexthop created by the kernel */
|
||||
if (nexthop->protocol == RTPROT_KERNEL)
|
||||
continue;
|
||||
|
||||
/* The nexthop will be configured later, or already configured by a link. */
|
||||
if (links_have_nexthop(manager, nexthop, except))
|
||||
continue;
|
||||
|
||||
/* The existing links do not have the nexthop. Let's drop this now. It may be
|
||||
* re-configured later. */
|
||||
k = nexthop_remove(nexthop, manager, NULL);
|
||||
if (k < 0 && r >= 0)
|
||||
r = k;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int manager_drop_foreign_nexthops(Manager *manager) {
|
||||
return manager_drop_nexthops_internal(manager, true, NULL);
|
||||
}
|
||||
|
||||
static int manager_drop_nexthops(Manager *manager, const Link *except) {
|
||||
return manager_drop_nexthops_internal(manager, false, except);
|
||||
}
|
||||
|
||||
int link_drop_foreign_nexthops(Link *link) {
|
||||
NextHop *nexthop;
|
||||
int k, r = 0;
|
||||
|
||||
assert(link);
|
||||
assert(link->manager);
|
||||
|
||||
SET_FOREACH(nexthop, link->nexthops_foreign) {
|
||||
/* do not touch nexthop created by the kernel */
|
||||
if (nexthop->protocol == RTPROT_KERNEL)
|
||||
continue;
|
||||
|
||||
if (link_has_nexthop(link, nexthop))
|
||||
k = nexthop_add(link, nexthop, NULL);
|
||||
else
|
||||
k = nexthop_remove(nexthop, link->manager, link);
|
||||
if (k < 0 && r >= 0)
|
||||
r = k;
|
||||
}
|
||||
|
||||
k = manager_drop_foreign_nexthops(link->manager);
|
||||
if (k < 0 && r >= 0)
|
||||
r = k;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int link_drop_nexthops(Link *link) {
|
||||
NextHop *nexthop;
|
||||
int k, r = 0;
|
||||
|
||||
assert(link);
|
||||
assert(link->manager);
|
||||
|
||||
SET_FOREACH(nexthop, link->nexthops) {
|
||||
/* do not touch nexthop created by the kernel */
|
||||
if (nexthop->protocol == RTPROT_KERNEL)
|
||||
continue;
|
||||
|
||||
k = nexthop_remove(nexthop, link->manager, link);
|
||||
if (k < 0 && r >= 0)
|
||||
r = k;
|
||||
}
|
||||
|
||||
k = manager_drop_nexthops(link->manager, link);
|
||||
if (k < 0 && r >= 0)
|
||||
r = k;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int manager_rtnl_process_nexthop(sd_netlink *rtnl, sd_netlink_message *message, Manager *m) {
|
||||
_cleanup_(nexthop_freep) NextHop *tmp = NULL;
|
||||
NextHop *nexthop = NULL;
|
||||
|
@ -37,6 +37,8 @@ NextHop *nexthop_free(NextHop *nexthop);
|
||||
void network_drop_invalid_nexthops(Network *network);
|
||||
|
||||
int link_set_nexthops(Link *link);
|
||||
int link_drop_nexthops(Link *link);
|
||||
int link_drop_foreign_nexthops(Link *link);
|
||||
|
||||
int manager_get_nexthop_by_id(Manager *manager, uint32_t id, NextHop **ret);
|
||||
int manager_rtnl_process_nexthop(sd_netlink *rtnl, sd_netlink_message *message, Manager *m);
|
||||
|
Loading…
x
Reference in New Issue
Block a user