diff --git a/src/network/networkd-nexthop.c b/src/network/networkd-nexthop.c index 0d6f881ca05..7675ea4c559 100644 --- a/src/network/networkd-nexthop.c +++ b/src/network/networkd-nexthop.c @@ -105,7 +105,6 @@ static NextHop* nexthop_free(NextHop *nexthop) { } DEFINE_TRIVIAL_REF_UNREF_FUNC(NextHop, nexthop, nexthop_free); -DEFINE_SECTION_CLEANUP_FUNCTIONS(NextHop, nexthop_unref); DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR( nexthop_hash_ops, @@ -123,7 +122,7 @@ DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR( NextHop, nexthop_detach); -static int nexthop_new(NextHop **ret) { +int nexthop_new(NextHop **ret) { _cleanup_(nexthop_unrefp) NextHop *nexthop = NULL; nexthop = new(NextHop, 1); @@ -339,7 +338,7 @@ static int nexthop_get(Link *link, const NextHop *in, NextHop **ret) { return -ENOENT; } -static int nexthop_get_request_by_id(Manager *manager, uint32_t id, Request **ret) { +int nexthop_get_request_by_id(Manager *manager, uint32_t id, Request **ret) { Request *req; assert(manager); @@ -459,7 +458,7 @@ static int nexthop_acquire_id(Manager *manager, NextHop *nexthop) { return -EBUSY; } -static void log_nexthop_debug(const NextHop *nexthop, const char *str, Manager *manager) { +void log_nexthop_debug(const NextHop *nexthop, const char *str, Manager *manager) { _cleanup_free_ char *state = NULL, *group = NULL, *flags = NULL; struct nexthop_grp *nhg; Link *link = NULL; @@ -569,6 +568,33 @@ int nexthop_remove(NextHop *nexthop, Manager *manager) { return 0; } +int nexthop_remove_and_cancel(NextHop *nexthop, Manager *manager) { + _cleanup_(request_unrefp) Request *req = NULL; + bool waiting = false; + + assert(nexthop); + assert(nexthop->id > 0); + assert(manager); + + /* If the nexthop is remembered by the manager, then use the remembered object. */ + (void) nexthop_get_by_id(manager, nexthop->id, &nexthop); + + /* Cancel the request for the nexthop. If the request is already called but we have not received the + * notification about the request, then explicitly remove the nexthop. */ + if (nexthop_get_request_by_id(manager, nexthop->id, &req) >= 0) { + request_ref(req); /* avoid the request freed by request_detach() */ + waiting = req->waiting_reply; + request_detach(req); + nexthop_cancel_requesting(nexthop); + } + + /* If we know that the nexthop will come or already exists, remove it. */ + if (waiting || (nexthop->manager && nexthop_exists(nexthop))) + return nexthop_remove(nexthop, manager); + + return 0; +} + static int nexthop_configure(NextHop *nexthop, Link *link, Request *req) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; int r; @@ -633,19 +659,32 @@ static int nexthop_configure(NextHop *nexthop, Link *link, Request *req) { return request_call_netlink_async(link->manager->rtnl, m, req); } -static int static_nexthop_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, NextHop *nexthop) { +int nexthop_configure_handler_internal(sd_netlink_message *m, Link *link, const char *error_msg) { int r; assert(m); assert(link); + assert(error_msg); r = sd_netlink_message_get_errno(m); if (r < 0 && r != -EEXIST) { - log_link_message_warning_errno(link, m, r, "Could not set nexthop"); + log_link_message_warning_errno(link, m, r, error_msg); link_enter_failed(link); - return 1; + return 0; } + return 1; +} + +static int static_nexthop_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, NextHop *nexthop) { + int r; + + assert(link); + + r = nexthop_configure_handler_internal(m, link, "Failed to set static nexthop"); + if (r <= 0) + return r; + if (link->static_nexthop_messages == 0) { log_link_debug(link, "Nexthops set"); link->static_nexthops_configured = true; @@ -740,7 +779,12 @@ static int nexthop_process_request(Request *req, Link *link, NextHop *nexthop) { return 1; } -static int link_request_nexthop(Link *link, const NextHop *nexthop) { +int link_request_nexthop( + Link *link, + const NextHop *nexthop, + unsigned *message_counter, + nexthop_netlink_handler_t netlink_handler) { + _cleanup_(nexthop_unrefp) NextHop *tmp = NULL; NextHop *existing = NULL; int r; @@ -780,8 +824,8 @@ static int link_request_nexthop(Link *link, const NextHop *nexthop) { nexthop_hash_func, nexthop_compare_func, nexthop_process_request, - &link->static_nexthop_messages, - static_nexthop_handler, + message_counter, + netlink_handler, NULL); if (r <= 0) return r; @@ -807,7 +851,7 @@ int link_request_static_nexthops(Link *link, bool only_ipv4) { if (only_ipv4 && nh->family != AF_INET) continue; - r = link_request_nexthop(link, nh); + r = link_request_nexthop(link, nh, &link->static_nexthop_messages, static_nexthop_handler); if (r < 0) return log_link_warning_errno(link, r, "Could not request nexthop: %m"); } @@ -866,16 +910,17 @@ int link_drop_nexthops(Link *link, bool only_static) { if (!nexthop_exists(nexthop)) continue; - if (only_static) { - if (nexthop->source != NETWORK_CONFIG_SOURCE_STATIC) + if (nexthop->source == NETWORK_CONFIG_SOURCE_FOREIGN) { + if (only_static) continue; - } else { + /* Do not mark foreign nexthop when KeepConfiguration= is enabled. */ - if (nexthop->source == NETWORK_CONFIG_SOURCE_FOREIGN && - link->network && + if (link->network && FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_STATIC)) continue; - } + + } else if (nexthop->source != NETWORK_CONFIG_SOURCE_STATIC) + continue; /* Ignore dynamically configurad nexthops. */ /* Ignore nexthops bound to other links. */ if (nexthop->ifindex > 0 && nexthop->ifindex != link->ifindex) @@ -1106,6 +1151,7 @@ int manager_rtnl_process_nexthop(sd_netlink *rtnl, sd_netlink_message *message, NextHop *n = ASSERT_PTR(req->userdata); nexthop->source = n->source; + nexthop->provider = n->provider; } r = sd_rtnl_message_get_family(message, &nexthop->family); diff --git a/src/network/networkd-nexthop.h b/src/network/networkd-nexthop.h index de3f64c3749..1466e2702f2 100644 --- a/src/network/networkd-nexthop.h +++ b/src/network/networkd-nexthop.h @@ -16,13 +16,21 @@ typedef struct Link Link; typedef struct Manager Manager; typedef struct Network Network; +typedef struct NextHop NextHop; +typedef int (*nexthop_netlink_handler_t)( + sd_netlink *rtnl, + sd_netlink_message *m, + Request *req, + Link *link, + NextHop *address); -typedef struct NextHop { +struct NextHop { Network *network; Manager *manager; ConfigSection *section; NetworkConfigSource source; NetworkConfigState state; + union in_addr_union provider; /* DHCP server or router address */ unsigned n_ref; @@ -44,12 +52,17 @@ typedef struct NextHop { /* For managing routes and nexthops that depend on this nexthop. */ Set *nexthops; Set *routes; -} NextHop; +}; +void log_nexthop_debug(const NextHop *nexthop, const char *str, Manager *manager); + +int nexthop_new(NextHop **ret); NextHop* nexthop_ref(NextHop *nexthop); NextHop* nexthop_unref(NextHop *nexthop); +DEFINE_SECTION_CLEANUP_FUNCTIONS(NextHop, nexthop_unref); int nexthop_remove(NextHop *nexthop, Manager *manager); +int nexthop_remove_and_cancel(NextHop *nexthop, Manager *manager); int network_drop_invalid_nexthops(Network *network); @@ -62,9 +75,16 @@ static inline int link_drop_static_nexthops(Link *link) { } void link_forget_nexthops(Link *link); +int nexthop_configure_handler_internal(sd_netlink_message *m, Link *link, const char *error_msg); +int link_request_nexthop( + Link *link, + const NextHop *nexthop, + unsigned *message_counter, + nexthop_netlink_handler_t netlink_handler); int link_request_static_nexthops(Link *link, bool only_ipv4); int nexthop_get_by_id(Manager *manager, uint32_t id, NextHop **ret); +int nexthop_get_request_by_id(Manager *manager, uint32_t id, Request **ret); int nexthop_is_ready(Manager *manager, uint32_t id, NextHop **ret); int manager_rtnl_process_nexthop(sd_netlink *rtnl, sd_netlink_message *message, Manager *m); int manager_build_nexthop_ids(Manager *manager);