diff --git a/src/basic/alloc-util.h b/src/basic/alloc-util.h index 65d5175619..57f1b186ee 100644 --- a/src/basic/alloc-util.h +++ b/src/basic/alloc-util.h @@ -13,6 +13,7 @@ #endif typedef void (*free_func_t)(void *p); +typedef void* (*mfree_func_t)(void *p); /* If for some reason more than 4M are allocated on the stack, let's abort immediately. It's better than * proceeding and smashing the stack limits. Note that by default RLIMIT_STACK is 8M on Linux. */ diff --git a/src/network/netdev/netdev.c b/src/network/netdev/netdev.c index c3cdb4f621..187b24c558 100644 --- a/src/network/netdev/netdev.c +++ b/src/network/netdev/netdev.c @@ -578,14 +578,14 @@ static int independent_netdev_create(NetDev *netdev) { return 0; } -static int stacked_netdev_create(NetDev *netdev, Link *link, link_netlink_message_handler_t callback) { +static int stacked_netdev_create(NetDev *netdev, Link *link, Request *req) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; int r; assert(netdev); assert(netdev->manager); assert(link); - assert(callback); + assert(req); r = sd_rtnl_message_new_link(netdev->manager->rtnl, &m, RTM_NEWLINK, 0); if (r < 0) @@ -595,13 +595,10 @@ static int stacked_netdev_create(NetDev *netdev, Link *link, link_netlink_messag if (r < 0) return r; - r = netlink_call_async(netdev->manager->rtnl, NULL, m, callback, - link_netlink_destroy_callback, link); + r = request_call_netlink_async(netdev->manager->rtnl, m, req); if (r < 0) return r; - link_ref(link); - netdev->state = NETDEV_STATE_CREATING; log_netdev_debug(netdev, "Creating"); return 0; @@ -632,40 +629,29 @@ static int netdev_is_ready_to_create(NetDev *netdev, Link *link) { return true; } -int request_process_stacked_netdev(Request *req) { - NetDev *netdev; - Link *link; +static int stacked_netdev_process_request(Request *req, Link *link, void *userdata) { + NetDev *netdev = ASSERT_PTR(userdata); int r; assert(req); - assert(req->type == REQUEST_TYPE_NETDEV_STACKED); - assert(req->netlink_handler); - - netdev = ASSERT_PTR(req->netdev); - link = ASSERT_PTR(req->link); + assert(link); r = netdev_is_ready_to_create(netdev, link); if (r <= 0) return r; - r = stacked_netdev_create(netdev, link, req->netlink_handler); + r = stacked_netdev_create(netdev, link, req); if (r < 0) return log_netdev_warning_errno(netdev, r, "Failed to create netdev: %m"); return 1; } -static int link_create_stacked_netdev_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { +static int create_stacked_netdev_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, void *userdata) { int r; assert(m); assert(link); - assert(link->create_stacked_netdev_messages > 0); - - link->create_stacked_netdev_messages--; - - if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) - return 0; r = sd_netlink_message_get_errno(m); if (r < 0 && r != -EEXIST) { @@ -696,10 +682,12 @@ int link_request_stacked_netdev(Link *link, NetDev *netdev) { return 0; /* Already created. */ link->stacked_netdevs_created = false; - r = link_queue_request(link, REQUEST_TYPE_NETDEV_STACKED, netdev_ref(netdev), true, - &link->create_stacked_netdev_messages, - link_create_stacked_netdev_handler, - NULL); + r = link_queue_request_full(link, REQUEST_TYPE_NETDEV_STACKED, + netdev_ref(netdev), (mfree_func_t) netdev_unref, + trivial_hash_func, trivial_compare_func, + stacked_netdev_process_request, + &link->create_stacked_netdev_messages, + create_stacked_netdev_handler, NULL); if (r < 0) return log_link_error_errno(link, r, "Failed to request stacked netdev '%s': %m", netdev->ifname); @@ -708,14 +696,11 @@ int link_request_stacked_netdev(Link *link, NetDev *netdev) { return 0; } -int request_process_independent_netdev(Request *req) { - NetDev *netdev; +static int independent_netdev_process_request(Request *req, Link *link, void *userdata) { + NetDev *netdev = ASSERT_PTR(userdata); int r; - assert(req); - assert(req->type == REQUEST_TYPE_NETDEV_INDEPENDENT); - - netdev = ASSERT_PTR(req->netdev); + assert(!link); r = netdev_is_ready_to_create(netdev, NULL); if (r <= 0) @@ -747,9 +732,9 @@ static int netdev_request_to_create(NetDev *netdev) { } else { /* Otherwise, wait for the dependencies being resolved. */ - r = netdev_queue_request(netdev, NULL); + r = netdev_queue_request(netdev, independent_netdev_process_request, NULL); if (r < 0) - return log_netdev_warning_errno(netdev, r, "Failed to request to create: %m"); + return log_netdev_warning_errno(netdev, r, "Failed to request to create netdev: %m"); } return 0; diff --git a/src/network/netdev/netdev.h b/src/network/netdev/netdev.h index ccf58f7ccb..6054e322d6 100644 --- a/src/network/netdev/netdev.h +++ b/src/network/netdev/netdev.h @@ -109,7 +109,6 @@ typedef enum NetDevCreateType { typedef struct Manager Manager; typedef struct Condition Condition; -typedef struct Request Request; typedef struct NetDev { Manager *manager; @@ -209,8 +208,6 @@ int netdev_set_ifindex(NetDev *netdev, sd_netlink_message *newlink); int netdev_generate_hw_addr(NetDev *netdev, Link *link, const char *name, const struct hw_addr_data *hw_addr, struct hw_addr_data *ret); -int request_process_independent_netdev(Request *req); -int request_process_stacked_netdev(Request *req); int link_request_stacked_netdev(Link *link, NetDev *netdev); const char *netdev_kind_to_string(NetDevKind d) _const_; diff --git a/src/network/networkd-address-label.c b/src/network/networkd-address-label.c index da9a1794b7..745b959f77 100644 --- a/src/network/networkd-address-label.c +++ b/src/network/networkd-address-label.c @@ -65,19 +65,17 @@ static int address_label_new_static(Network *network, const char *filename, unsi return 0; } -static int address_label_configure_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { +static int address_label_configure_handler( + sd_netlink *rtnl, + sd_netlink_message *m, + Request *req, + Link *link, + void *userdata) { + int r; - assert(rtnl); assert(m); assert(link); - assert(link->ifname); - assert(link->static_address_label_messages > 0); - - link->static_address_label_messages--; - - if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) - return 1; r = sd_netlink_message_get_errno(m); if (r < 0 && r != -EEXIST) { @@ -95,7 +93,7 @@ static int address_label_configure_handler(sd_netlink *rtnl, sd_netlink_message return 1; } -static int address_label_configure(AddressLabel *label, Link *link, link_netlink_message_handler_t callback) { +static int address_label_configure(AddressLabel *label, Link *link, Request *req) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; int r; @@ -104,7 +102,7 @@ static int address_label_configure(AddressLabel *label, Link *link, link_netlink assert(link->ifindex > 0); assert(link->manager); assert(link->manager->rtnl); - assert(callback); + assert(req); r = sd_rtnl_message_new_addrlabel(link->manager->rtnl, &m, RTM_NEWADDRLABEL, link->ifindex, AF_INET6); @@ -123,29 +121,20 @@ static int address_label_configure(AddressLabel *label, Link *link, link_netlink if (r < 0) return r; - r = netlink_call_async(link->manager->rtnl, NULL, m, callback, - link_netlink_destroy_callback, link); - if (r < 0) - return r; - - link_ref(link); - return 0; + return request_call_netlink_async(link->manager->rtnl, m, req); } -int request_process_address_label(Request *req) { - Link *link; +static int address_label_process_request(Request *req, Link *link, void *userdata) { + AddressLabel *label = ASSERT_PTR(userdata); int r; assert(req); - assert(req->label); - assert(req->type == REQUEST_TYPE_ADDRESS_LABEL); - - link = ASSERT_PTR(req->link); + assert(link); if (!link_is_ready_to_configure(link, false)) return 0; - r = address_label_configure(req->label, link, req->netlink_handler); + r = address_label_configure(label, link, req); if (r < 0) return log_link_warning_errno(link, r, "Failed to configure address label: %m"); @@ -162,8 +151,11 @@ int link_request_static_address_labels(Link *link) { link->static_address_labels_configured = false; HASHMAP_FOREACH(label, link->network->address_labels_by_section) { - r = link_queue_request(link, REQUEST_TYPE_ADDRESS_LABEL, label, false, - &link->static_address_label_messages, address_label_configure_handler, NULL); + r = link_queue_request_full(link, REQUEST_TYPE_ADDRESS_LABEL, + label, NULL, trivial_hash_func, trivial_compare_func, + address_label_process_request, + &link->static_address_label_messages, + address_label_configure_handler, NULL); if (r < 0) return log_link_warning_errno(link, r, "Failed to request address label: %m"); } diff --git a/src/network/networkd-address-label.h b/src/network/networkd-address-label.h index 582dd05b88..1e2ee70dee 100644 --- a/src/network/networkd-address-label.h +++ b/src/network/networkd-address-label.h @@ -9,7 +9,6 @@ typedef struct Link Link; typedef struct Network Network; -typedef struct Request Request; typedef struct AddressLabel { Network *network; @@ -26,7 +25,6 @@ AddressLabel *address_label_free(AddressLabel *label); void network_drop_invalid_address_labels(Network *network); int link_request_static_address_labels(Link *link); -int request_process_address_label(Request *req); CONFIG_PARSER_PROTOTYPE(config_parse_address_label); CONFIG_PARSER_PROTOTYPE(config_parse_address_label_prefix); diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c index f883c79a9e..19a357130b 100644 --- a/src/network/networkd-address.c +++ b/src/network/networkd-address.c @@ -316,7 +316,7 @@ DEFINE_PRIVATE_HASH_OPS( address_kernel_hash_func, address_kernel_compare_func); -void address_hash_func(const Address *a, struct siphash *state) { +static void address_hash_func(const Address *a, struct siphash *state) { assert(a); siphash24_compress(&a->family, sizeof(a->family), state); @@ -1023,9 +1023,6 @@ int address_configure_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, assert(link); assert(error_msg); - if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) - return 0; - r = sd_netlink_message_get_errno(m); if (r < 0 && r != -EEXIST) { log_link_message_warning_errno(link, m, r, error_msg); @@ -1036,11 +1033,7 @@ int address_configure_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, return 1; } -static int address_configure( - const Address *address, - Link *link, - link_netlink_message_handler_t callback) { - +static int address_configure(const Address *address, Link *link, Request *req) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; int r; @@ -1050,7 +1043,7 @@ static int address_configure( assert(link->ifindex > 0); assert(link->manager); assert(link->manager->rtnl); - assert(callback); + assert(req); log_address_debug(address, "Configuring", link); @@ -1091,12 +1084,7 @@ static int address_configure( if (r < 0) return r; - r = netlink_call_async(link->manager->rtnl, NULL, m, callback, link_netlink_destroy_callback, link); - if (r < 0) - return r; - - link_ref(link); - return 0; + return request_call_netlink_async(link->manager->rtnl, m, req); } static bool address_is_ready_to_configure(Link *link, const Address *address) { @@ -1116,21 +1104,17 @@ static bool address_is_ready_to_configure(Link *link, const Address *address) { return true; } -int request_process_address(Request *req) { - Address *address; - Link *link; +static int address_process_request(Request *req, Link *link, Address *address) { int r; assert(req); - assert(req->type == REQUEST_TYPE_ADDRESS); - - address = ASSERT_PTR(req->address); - link = ASSERT_PTR(req->link); + assert(link); + assert(address); if (!address_is_ready_to_configure(link, address)) return 0; - r = address_configure(address, link, req->netlink_handler); + r = address_configure(address, link, req); if (r < 0) return log_link_warning_errno(link, r, "Failed to configure address: %m"); @@ -1143,7 +1127,7 @@ int link_request_address( Address *address, bool consume_object, unsigned *message_counter, - link_netlink_message_handler_t netlink_handler, + address_netlink_handler_t netlink_handler, Request **ret) { Address *acquired, *existing; @@ -1212,8 +1196,12 @@ int link_request_address( return r; log_address_debug(existing, "Requesting", link); - r = link_queue_request(link, REQUEST_TYPE_ADDRESS, existing, false, - message_counter, netlink_handler, ret); + r = link_queue_request_safe(link, REQUEST_TYPE_ADDRESS, + existing, NULL, + address_hash_func, + address_compare_func, + address_process_request, + message_counter, netlink_handler, ret); if (r < 0) return log_link_warning_errno(link, r, "Failed to request address: %m"); if (r == 0) @@ -1224,13 +1212,10 @@ int link_request_address( return 1; } -static int static_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { +static int static_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, Address *address) { int r; assert(link); - assert(link->static_address_messages > 0); - - link->static_address_messages--; r = address_configure_handler_internal(rtnl, m, link, "Failed to set static address"); if (r <= 0) @@ -1300,10 +1285,12 @@ void address_cancel_request(Address *address) { req = (Request) { .link = address->link, .type = REQUEST_TYPE_ADDRESS, - .address = address, + .userdata = address, + .hash_func = (hash_func_t) address_hash_func, + .compare_func = (compare_func_t) address_compare_func, }; - request_drop(ordered_set_get(address->link->manager->request_queue, &req)); + request_detach(address->link->manager, &req); address_cancel_requesting(address); } diff --git a/src/network/networkd-address.h b/src/network/networkd-address.h index b116237638..563a3de4e2 100644 --- a/src/network/networkd-address.h +++ b/src/network/networkd-address.h @@ -18,6 +18,12 @@ typedef struct Manager Manager; typedef struct Network Network; typedef struct Request Request; typedef int (*address_ready_callback_t)(Address *address); +typedef int (*address_netlink_handler_t)( + sd_netlink *rtnl, + sd_netlink_message *m, + Request *req, + Link *link, + Address *address); struct Address { Link *link; @@ -97,17 +103,15 @@ int link_request_address( Address *address, bool consume_object, unsigned *message_counter, - link_netlink_message_handler_t netlink_handler, + address_netlink_handler_t netlink_handler, Request **ret); int link_request_static_address(Link *link, Address *address, bool consume); int link_request_static_addresses(Link *link); -int request_process_address(Request *req); int manager_rtnl_process_address(sd_netlink *nl, sd_netlink_message *message, Manager *m); int network_drop_invalid_addresses(Network *network); -void address_hash_func(const Address *a, struct siphash *state); int address_compare_func(const Address *a1, const Address *a2); DEFINE_NETWORK_CONFIG_STATE_FUNCTIONS(Address, address); diff --git a/src/network/networkd-bridge-fdb.c b/src/network/networkd-bridge-fdb.c index b09b2ad735..803e27cdae 100644 --- a/src/network/networkd-bridge-fdb.c +++ b/src/network/networkd-bridge-fdb.c @@ -93,16 +93,11 @@ static int bridge_fdb_new_static( return 0; } -static int bridge_fdb_configure_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { +static int bridge_fdb_configure_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, void *userdata) { int r; + assert(m); assert(link); - assert(link->static_bridge_fdb_messages > 0); - - link->static_bridge_fdb_messages--; - - if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) - return 0; r = sd_netlink_message_get_errno(m); if (r < 0 && r != -EEXIST) { @@ -168,14 +163,14 @@ static int bridge_fdb_configure_message(const BridgeFDB *fdb, Link *link, sd_net return 0; } -static int bridge_fdb_configure(BridgeFDB *fdb, Link *link, link_netlink_message_handler_t callback) { +static int bridge_fdb_configure(BridgeFDB *fdb, Link *link, Request *req) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; int r; assert(fdb); assert(link); assert(link->manager); - assert(callback); + assert(req); r = sd_rtnl_message_new_neigh(link->manager->rtnl, &m, RTM_NEWNEIGH, link->ifindex, AF_BRIDGE); if (r < 0) @@ -185,13 +180,7 @@ static int bridge_fdb_configure(BridgeFDB *fdb, Link *link, link_netlink_message if (r < 0) return r; - r = netlink_call_async(link->manager->rtnl, NULL, m, callback, - link_netlink_destroy_callback, link); - if (r < 0) - return r; - - link_ref(link); - return 0; + return request_call_netlink_async(link->manager->rtnl, m, req); } static bool bridge_fdb_is_ready_to_configure(BridgeFDB *fdb, Link *link) { @@ -219,20 +208,17 @@ static bool bridge_fdb_is_ready_to_configure(BridgeFDB *fdb, Link *link) { return true; } -int request_process_bridge_fdb(Request *req) { - BridgeFDB *fdb; - Link *link; +static int bridge_fdb_process_request(Request *req, Link *link, void *userdata) { + BridgeFDB *fdb = ASSERT_PTR(userdata); int r; assert(req); - assert(req->type == REQUEST_TYPE_BRIDGE_FDB); - assert_se(link = req->link); - assert_se(fdb = req->fdb); + assert(link); if (!bridge_fdb_is_ready_to_configure(fdb, link)) return 0; - r = bridge_fdb_configure(fdb, link, req->netlink_handler); + r = bridge_fdb_configure(fdb, link, req); if (r < 0) return log_link_warning_errno(link, r, "Failed to configure bridge FDB: %m"); @@ -249,8 +235,14 @@ int link_request_static_bridge_fdb(Link *link) { link->static_bridge_fdb_configured = false; HASHMAP_FOREACH(fdb, link->network->bridge_fdb_entries_by_section) { - r = link_queue_request(link, REQUEST_TYPE_BRIDGE_FDB, fdb, false, - &link->static_bridge_fdb_messages, bridge_fdb_configure_handler, NULL); + r = link_queue_request_full(link, REQUEST_TYPE_BRIDGE_FDB, + fdb, NULL, + trivial_hash_func, + trivial_compare_func, + bridge_fdb_process_request, + &link->static_bridge_fdb_messages, + bridge_fdb_configure_handler, + NULL); if (r < 0) return log_link_error_errno(link, r, "Failed to request static bridge FDB entry: %m"); } diff --git a/src/network/networkd-bridge-fdb.h b/src/network/networkd-bridge-fdb.h index b1098760d2..b59d673d04 100644 --- a/src/network/networkd-bridge-fdb.h +++ b/src/network/networkd-bridge-fdb.h @@ -14,7 +14,6 @@ typedef struct Link Link; typedef struct Network Network; -typedef struct Request Request; typedef enum NeighborCacheEntryFlags { NEIGHBOR_CACHE_ENTRY_FLAGS_USE = NTF_USE, @@ -47,8 +46,6 @@ void network_drop_invalid_bridge_fdb_entries(Network *network); int link_request_static_bridge_fdb(Link *link); -int request_process_bridge_fdb(Request *req); - CONFIG_PARSER_PROTOTYPE(config_parse_fdb_hwaddr); CONFIG_PARSER_PROTOTYPE(config_parse_fdb_vlan_id); CONFIG_PARSER_PROTOTYPE(config_parse_fdb_destination); diff --git a/src/network/networkd-bridge-mdb.c b/src/network/networkd-bridge-mdb.c index af01a89f47..3af4afe4a1 100644 --- a/src/network/networkd-bridge-mdb.c +++ b/src/network/networkd-bridge-mdb.c @@ -81,16 +81,11 @@ static int bridge_mdb_new_static( return 0; } -static int bridge_mdb_configure_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { +static int bridge_mdb_configure_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, void *userdata) { int r; + assert(m); assert(link); - assert(link->static_bridge_mdb_messages > 0); - - link->static_bridge_mdb_messages--; - - if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) - return 1; r = sd_netlink_message_get_errno(m); if (r == -EINVAL && streq_ptr(link->kind, "bridge") && link->master_ifindex <= 0) { @@ -114,7 +109,7 @@ static int bridge_mdb_configure_handler(sd_netlink *rtnl, sd_netlink_message *m, } /* send a request to the kernel to add an MDB entry */ -static int bridge_mdb_configure(BridgeMDB *mdb, Link *link, link_netlink_message_handler_t callback) { +static int bridge_mdb_configure(BridgeMDB *mdb, Link *link, Request *req) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; struct br_mdb_entry entry; int r; @@ -122,7 +117,7 @@ static int bridge_mdb_configure(BridgeMDB *mdb, Link *link, link_netlink_message assert(mdb); assert(link); assert(link->manager); - assert(callback); + assert(req); if (DEBUG_LOGGING) { _cleanup_free_ char *a = NULL; @@ -164,13 +159,7 @@ static int bridge_mdb_configure(BridgeMDB *mdb, Link *link, link_netlink_message if (r < 0) return r; - r = netlink_call_async(link->manager->rtnl, NULL, m, callback, - link_netlink_destroy_callback, link); - if (r < 0) - return r; - - link_ref(link); - return 0; + return request_call_netlink_async(link->manager->rtnl, m, req); } static bool bridge_mdb_is_ready_to_configure(Link *link) { @@ -205,19 +194,17 @@ static bool bridge_mdb_is_ready_to_configure(Link *link) { return true; } -int request_process_bridge_mdb(Request *req) { - Link *link; +static int bridge_mdb_process_request(Request *req, Link *link, void *userdata) { + BridgeMDB *mdb = ASSERT_PTR(userdata); int r; assert(req); - assert(req->mdb); - assert(req->type == REQUEST_TYPE_BRIDGE_MDB); - assert_se(link = req->link); + assert(link); if (!bridge_mdb_is_ready_to_configure(link)) return 0; - r = bridge_mdb_configure(req->mdb, link, req->netlink_handler); + r = bridge_mdb_configure(mdb, link, req); if (r < 0) return log_link_warning_errno(link, r, "Failed to configure bridge MDB: %m"); @@ -240,8 +227,14 @@ int link_request_static_bridge_mdb(Link *link) { goto finish; HASHMAP_FOREACH(mdb, link->network->bridge_mdb_entries_by_section) { - r = link_queue_request(link, REQUEST_TYPE_BRIDGE_MDB, mdb, false, - &link->static_bridge_mdb_messages, bridge_mdb_configure_handler, NULL); + r = link_queue_request_full(link, REQUEST_TYPE_BRIDGE_MDB, + mdb, NULL, + trivial_hash_func, + trivial_compare_func, + bridge_mdb_process_request, + &link->static_bridge_mdb_messages, + bridge_mdb_configure_handler, + NULL); if (r < 0) return log_link_error_errno(link, r, "Failed to request MDB entry to multicast group database: %m"); } diff --git a/src/network/networkd-bridge-mdb.h b/src/network/networkd-bridge-mdb.h index ce91e3f572..edea255769 100644 --- a/src/network/networkd-bridge-mdb.h +++ b/src/network/networkd-bridge-mdb.h @@ -9,7 +9,6 @@ typedef struct Link Link; typedef struct Network Network; -typedef struct Request Request; typedef struct BridgeMDB { Network *network; @@ -25,7 +24,6 @@ BridgeMDB *bridge_mdb_free(BridgeMDB *mdb); void network_drop_invalid_bridge_mdb_entries(Network *network); int link_request_static_bridge_mdb(Link *link); -int request_process_bridge_mdb(Request *req); CONFIG_PARSER_PROTOTYPE(config_parse_mdb_group_address); CONFIG_PARSER_PROTOTYPE(config_parse_mdb_vlan_id); diff --git a/src/network/networkd-dhcp-prefix-delegation.c b/src/network/networkd-dhcp-prefix-delegation.c index bba66f71ed..edc893e9f6 100644 --- a/src/network/networkd-dhcp-prefix-delegation.c +++ b/src/network/networkd-dhcp-prefix-delegation.c @@ -288,13 +288,10 @@ static int dhcp_pd_check_ready(Link *link) { return 1; } -static int dhcp_pd_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { +static int dhcp_pd_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, Route *route) { int r; assert(link); - assert(link->dhcp_pd_messages > 0); - - link->dhcp_pd_messages--; r = route_configure_handler_internal(rtnl, m, link, "Failed to add prefix route for DHCP delegated subnet prefix"); if (r <= 0) @@ -344,13 +341,10 @@ static int dhcp_pd_request_route(Link *link, const struct in6_addr *prefix, usec return 0; } -static int dhcp_pd_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { +static int dhcp_pd_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, Address *address) { int r; assert(link); - assert(link->dhcp_pd_messages > 0); - - link->dhcp_pd_messages--; r = address_configure_handler_internal(rtnl, m, link, "Could not set DHCP-PD address"); if (r <= 0) @@ -658,13 +652,10 @@ void dhcp4_pd_prefix_lost(Link *uplink) { (void) link_remove(tunnel); } -static int dhcp4_unreachable_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { +static int dhcp4_unreachable_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, Route *route) { int r; assert(link); - assert(link->dhcp4_messages > 0); - - link->dhcp4_messages--; r = route_configure_handler_internal(rtnl, m, link, "Failed to set unreachable route for DHCPv4 delegated prefix"); if (r <= 0) @@ -677,13 +668,10 @@ static int dhcp4_unreachable_route_handler(sd_netlink *rtnl, sd_netlink_message return 1; } -static int dhcp6_unreachable_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { +static int dhcp6_unreachable_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, Route *route) { int r; assert(link); - assert(link->dhcp6_messages > 0); - - link->dhcp6_messages--; r = route_configure_handler_internal(rtnl, m, link, "Failed to set unreachable route for DHCPv6 delegated prefix"); if (r <= 0) @@ -704,7 +692,7 @@ static int dhcp_request_unreachable_route( NetworkConfigSource source, const union in_addr_union *server_address, unsigned *counter, - link_netlink_message_handler_t callback) { + route_netlink_handler_t callback) { _cleanup_(route_freep) Route *route = NULL; Route *existing; diff --git a/src/network/networkd-dhcp-server.c b/src/network/networkd-dhcp-server.c index 515c9c44be..79ded2e99e 100644 --- a/src/network/networkd-dhcp-server.c +++ b/src/network/networkd-dhcp-server.c @@ -571,13 +571,10 @@ static bool dhcp_server_is_ready_to_configure(Link *link) { return true; } -int request_process_dhcp_server(Request *req) { - Link *link; +static int dhcp_server_process_request(Request *req, Link *link, void *userdata) { int r; - assert(req); - assert(req->type == REQUEST_TYPE_DHCP_SERVER); - assert_se(link = req->link); + assert(link); if (!dhcp_server_is_ready_to_configure(link)) return 0; @@ -601,7 +598,7 @@ int link_request_dhcp_server(Link *link) { return 0; log_link_debug(link, "Requesting DHCP server."); - r = link_queue_request(link, REQUEST_TYPE_DHCP_SERVER, NULL, false, NULL, NULL, NULL); + r = link_queue_request(link, REQUEST_TYPE_DHCP_SERVER, dhcp_server_process_request, NULL); if (r < 0) return log_link_warning_errno(link, r, "Failed to request configuration of DHCP server: %m"); diff --git a/src/network/networkd-dhcp-server.h b/src/network/networkd-dhcp-server.h index 1af1c65c66..cb2a8b6a34 100644 --- a/src/network/networkd-dhcp-server.h +++ b/src/network/networkd-dhcp-server.h @@ -5,13 +5,11 @@ typedef struct Link Link; typedef struct Network Network; -typedef struct Request Request; void network_adjust_dhcp_server(Network *network); int link_request_dhcp_server_address(Link *link); int link_request_dhcp_server(Link *link); -int request_process_dhcp_server(Request *req); CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_server_relay_agent_suboption); CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_server_emit); diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c index 420113e129..0f7be769ea 100644 --- a/src/network/networkd-dhcp4.c +++ b/src/network/networkd-dhcp4.c @@ -177,16 +177,11 @@ static int dhcp4_retry(Link *link) { return dhcp4_request_address_and_routes(link, false); } -static int dhcp4_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { +static int dhcp4_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, Route *route) { int r; + assert(m); assert(link); - assert(link->dhcp4_messages > 0); - - link->dhcp4_messages--; - - if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) - return 1; r = sd_netlink_message_get_errno(m); if (r == -ENETUNREACH && !link->dhcp4_route_retrying) { @@ -829,13 +824,10 @@ int dhcp4_lease_lost(Link *link) { return link_request_static_routes(link, true); } -static int dhcp4_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { +static int dhcp4_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, Address *address) { int r; assert(link); - assert(link->dhcp4_messages > 0); - - link->dhcp4_messages--; r = address_configure_handler_internal(rtnl, m, link, "Could not set DHCPv4 address"); if (r <= 0) @@ -1597,15 +1589,10 @@ static int dhcp4_configure_duid(Link *link) { return dhcp_configure_duid(link, link_get_dhcp4_duid(link)); } -int request_process_dhcp4_client(Request *req) { - Link *link; +static int dhcp4_process_request(Request *req, Link *link, void *userdata) { int r; - assert(req); - assert(req->link); - assert(req->type == REQUEST_TYPE_DHCP4_CLIENT); - - link = req->link; + assert(link); if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED)) return 0; @@ -1619,7 +1606,7 @@ int request_process_dhcp4_client(Request *req) { if (r <= 0) return r; - r = dhcp4_configure(req->link); + r = dhcp4_configure(link); if (r < 0) return log_link_warning_errno(link, r, "Failed to configure DHCPv4 client: %m"); @@ -1629,7 +1616,6 @@ int request_process_dhcp4_client(Request *req) { log_link_debug(link, "DHCPv4 client is configured%s.", r > 0 ? ", acquiring DHCPv4 lease" : ""); - return 1; } @@ -1644,7 +1630,7 @@ int link_request_dhcp4_client(Link *link) { if (link->dhcp_client) return 0; - r = link_queue_request(link, REQUEST_TYPE_DHCP4_CLIENT, NULL, false, NULL, NULL, NULL); + r = link_queue_request(link, REQUEST_TYPE_DHCP4_CLIENT, dhcp4_process_request, NULL); if (r < 0) return log_link_warning_errno(link, r, "Failed to request configuring of the DHCPv4 client: %m"); diff --git a/src/network/networkd-dhcp4.h b/src/network/networkd-dhcp4.h index 830e39f66a..1d30cd15df 100644 --- a/src/network/networkd-dhcp4.h +++ b/src/network/networkd-dhcp4.h @@ -5,7 +5,6 @@ typedef struct Link Link; typedef struct Network Network; -typedef struct Request Request; typedef enum DHCPClientIdentifier { DHCP_CLIENT_ID_MAC, @@ -25,7 +24,6 @@ int dhcp4_start(Link *link); int dhcp4_lease_lost(Link *link); int dhcp4_check_ready(Link *link); -int request_process_dhcp4_client(Request *req); int link_request_dhcp4_client(Link *link); CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_client_identifier); diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c index 244c3a2a4d..c443098889 100644 --- a/src/network/networkd-dhcp6.c +++ b/src/network/networkd-dhcp6.c @@ -136,13 +136,10 @@ int dhcp6_check_ready(Link *link) { return 0; } -static int dhcp6_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { +static int dhcp6_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, Address *address) { int r; assert(link); - assert(link->dhcp6_messages > 0); - - link->dhcp6_messages--; r = address_configure_handler_internal(rtnl, m, link, "Could not set DHCPv6 address"); if (r <= 0) @@ -715,15 +712,10 @@ int dhcp6_update_mac(Link *link) { return 0; } -int request_process_dhcp6_client(Request *req) { - Link *link; +static int dhcp6_process_request(Request *req, Link *link, void *userdata) { int r; - assert(req); - assert(req->link); - assert(req->type == REQUEST_TYPE_DHCP6_CLIENT); - - link = req->link; + assert(link); if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED)) return 0; @@ -751,7 +743,6 @@ int request_process_dhcp6_client(Request *req) { log_link_debug(link, "DHCPv6 client is configured%s.", r > 0 ? ", acquiring DHCPv6 lease" : ""); - return 1; } @@ -766,7 +757,7 @@ int link_request_dhcp6_client(Link *link) { if (link->dhcp6_client) return 0; - r = link_queue_request(link, REQUEST_TYPE_DHCP6_CLIENT, NULL, false, NULL, NULL, NULL); + r = link_queue_request(link, REQUEST_TYPE_DHCP6_CLIENT, dhcp6_process_request, NULL); if (r < 0) return log_link_warning_errno(link, r, "Failed to request configuring of the DHCPv6 client: %m"); diff --git a/src/network/networkd-dhcp6.h b/src/network/networkd-dhcp6.h index 52347c5e7b..81267c255f 100644 --- a/src/network/networkd-dhcp6.h +++ b/src/network/networkd-dhcp6.h @@ -13,7 +13,6 @@ typedef enum DHCP6ClientStartMode { } DHCP6ClientStartMode; typedef struct Link Link; -typedef struct Request Request; bool link_dhcp6_with_address_enabled(Link *link); int dhcp6_check_ready(Link *link); @@ -21,7 +20,6 @@ int dhcp6_update_mac(Link *link); int dhcp6_start(Link *link); int dhcp6_start_on_ra(Link *link, bool information_request); -int request_process_dhcp6_client(Request *req); int link_request_dhcp6_client(Link *link); int link_serialize_dhcp6_client(Link *link, FILE *f); diff --git a/src/network/networkd-ipv4ll.c b/src/network/networkd-ipv4ll.c index 5e3854281c..67eb9d2aa1 100644 --- a/src/network/networkd-ipv4ll.c +++ b/src/network/networkd-ipv4ll.c @@ -70,7 +70,7 @@ static int ipv4ll_address_lost(Link *link) { return address_remove(existing); } -static int ipv4ll_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { +static int ipv4ll_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, Address *address) { int r; assert(link); diff --git a/src/network/networkd-ipv6-proxy-ndp.c b/src/network/networkd-ipv6-proxy-ndp.c index 22a75bf56b..8166851ed3 100644 --- a/src/network/networkd-ipv6-proxy-ndp.c +++ b/src/network/networkd-ipv6-proxy-ndp.c @@ -26,13 +26,17 @@ void network_adjust_ipv6_proxy_ndp(Network *network) { } } -static int ipv6_proxy_ndp_address_configure_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { +static int ipv6_proxy_ndp_address_configure_handler( + sd_netlink *rtnl, + sd_netlink_message *m, + Request *req, + Link *link, + struct in6_addr *address) { + int r; + assert(m); assert(link); - assert(link->static_ipv6_proxy_ndp_messages > 0); - - link->static_ipv6_proxy_ndp_messages--; r = sd_netlink_message_get_errno(m); if (r < 0) @@ -48,11 +52,7 @@ static int ipv6_proxy_ndp_address_configure_handler(sd_netlink *rtnl, sd_netlink } /* send a request to the kernel to add an IPv6 Proxy entry to the neighbour table */ -static int ipv6_proxy_ndp_address_configure( - const struct in6_addr *address, - Link *link, - link_netlink_message_handler_t callback) { - +static int ipv6_proxy_ndp_address_configure(const struct in6_addr *address, Link *link, Request *req) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; int r; @@ -60,7 +60,7 @@ static int ipv6_proxy_ndp_address_configure( assert(link); assert(link->manager); assert(link->manager->rtnl); - assert(callback); + assert(req); /* create new netlink message */ r = sd_rtnl_message_new_neigh(link->manager->rtnl, &m, RTM_NEWNEIGH, link->ifindex, AF_INET6); @@ -75,28 +75,20 @@ static int ipv6_proxy_ndp_address_configure( if (r < 0) return r; - r = netlink_call_async(link->manager->rtnl, NULL, m, callback, - link_netlink_destroy_callback, link); - if (r < 0) - return r; - - link_ref(link); - return 0; + return request_call_netlink_async(link->manager->rtnl, m, req); } -int request_process_ipv6_proxy_ndp_address(Request *req) { - Link *link; +static int ipv6_proxy_ndp_address_process_request(Request *req, Link *link, struct in6_addr *address) { int r; assert(req); - assert(req->ipv6_proxy_ndp); - assert(req->type == REQUEST_TYPE_IPV6_PROXY_NDP); - assert_se(link = req->link); + assert(link); + assert(address); if (!link_is_ready_to_configure(link, false)) return 0; - r = ipv6_proxy_ndp_address_configure(req->ipv6_proxy_ndp, link, req->netlink_handler); + r = ipv6_proxy_ndp_address_configure(address, link, req); if (r < 0) return log_link_warning_errno(link, r, "Failed to configure IPv6 proxy NDP address: %m"); @@ -113,9 +105,14 @@ int link_request_static_ipv6_proxy_ndp_addresses(Link *link) { link->static_ipv6_proxy_ndp_configured = false; SET_FOREACH(address, link->network->ipv6_proxy_ndp_addresses) { - r = link_queue_request(link, REQUEST_TYPE_IPV6_PROXY_NDP, address, false, - &link->static_ipv6_proxy_ndp_messages, - ipv6_proxy_ndp_address_configure_handler, NULL); + r = link_queue_request_safe(link, REQUEST_TYPE_IPV6_PROXY_NDP, + address, NULL, + in6_addr_hash_func, + in6_addr_compare_func, + ipv6_proxy_ndp_address_process_request, + &link->static_ipv6_proxy_ndp_messages, + ipv6_proxy_ndp_address_configure_handler, + NULL); if (r < 0) return log_link_warning_errno(link, r, "Failed to request IPv6 proxy NDP address: %m"); } diff --git a/src/network/networkd-ipv6-proxy-ndp.h b/src/network/networkd-ipv6-proxy-ndp.h index b35cd56182..e57d28f99d 100644 --- a/src/network/networkd-ipv6-proxy-ndp.h +++ b/src/network/networkd-ipv6-proxy-ndp.h @@ -5,11 +5,9 @@ typedef struct Link Link; typedef struct Network Network; -typedef struct Request Request; void network_adjust_ipv6_proxy_ndp(Network *network); int link_request_static_ipv6_proxy_ndp_addresses(Link *link); -int request_process_ipv6_proxy_ndp_address(Request *req); CONFIG_PARSER_PROTOTYPE(config_parse_ipv6_proxy_ndp_address); diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 48f8e40fb4..e925739d06 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -906,7 +906,7 @@ static void link_drop_requests(Link *link) { ORDERED_SET_FOREACH(req, link->manager->request_queue) if (req->link == link) - request_drop(req); + request_detach(link->manager, req); } static Link *link_drop(Link *link) { diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c index 7f2366ba70..8cbc67f542 100644 --- a/src/network/networkd-ndisc.c +++ b/src/network/networkd-ndisc.c @@ -203,13 +203,10 @@ static int ndisc_check_ready(Link *link) { return 0; } -static int ndisc_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { +static int ndisc_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, Route *route) { int r; assert(link); - assert(link->ndisc_messages > 0); - - link->ndisc_messages--; r = route_configure_handler_internal(rtnl, m, link, "Could not set NDisc route"); if (r <= 0) @@ -254,13 +251,10 @@ static int ndisc_request_route(Route *in, Link *link, sd_ndisc_router *rt) { ndisc_route_handler, NULL); } -static int ndisc_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { +static int ndisc_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, Address *address) { int r; assert(link); - assert(link->ndisc_messages > 0); - - link->ndisc_messages--; r = address_configure_handler_internal(rtnl, m, link, "Could not set NDisc address"); if (r <= 0) @@ -1122,14 +1116,10 @@ int ndisc_start(Link *link) { return 1; } -int request_process_ndisc(Request *req) { - Link *link; +static int ndisc_process_request(Request *req, Link *link, void *userdata) { int r; - assert(req); - assert(req->type == REQUEST_TYPE_NDISC); - - link = ASSERT_PTR(req->link); + assert(link); if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED)) return 0; @@ -1148,7 +1138,6 @@ int request_process_ndisc(Request *req) { log_link_debug(link, "IPv6 Router Discovery is configured%s.", r > 0 ? " and started" : ""); - return 1; } @@ -1163,7 +1152,7 @@ int link_request_ndisc(Link *link) { if (link->ndisc) return 0; - r = link_queue_request(link, REQUEST_TYPE_NDISC, NULL, false, NULL, NULL, NULL); + r = link_queue_request(link, REQUEST_TYPE_NDISC, ndisc_process_request, NULL); if (r < 0) return log_link_warning_errno(link, r, "Failed to request configuring of the IPv6 Router Discovery: %m"); diff --git a/src/network/networkd-ndisc.h b/src/network/networkd-ndisc.h index 1958652778..f88a002c73 100644 --- a/src/network/networkd-ndisc.h +++ b/src/network/networkd-ndisc.h @@ -6,7 +6,6 @@ typedef struct Link Link; typedef struct Network Network; -typedef struct Request Request; typedef enum IPv6AcceptRAStartDHCP6Client { IPV6_ACCEPT_RA_START_DHCP6_CLIENT_NO, @@ -48,7 +47,6 @@ int ndisc_start(Link *link); void ndisc_vacuum(Link *link); void ndisc_flush(Link *link); -int request_process_ndisc(Request *req); int link_request_ndisc(Link *link); CONFIG_PARSER_PROTOTYPE(config_parse_ipv6_accept_ra_start_dhcp6_client); diff --git a/src/network/networkd-neighbor.c b/src/network/networkd-neighbor.c index 8887389807..435fa7002e 100644 --- a/src/network/networkd-neighbor.c +++ b/src/network/networkd-neighbor.c @@ -87,7 +87,7 @@ static int neighbor_dup(const Neighbor *neighbor, Neighbor **ret) { return 0; } -void neighbor_hash_func(const Neighbor *neighbor, struct siphash *state) { +static void neighbor_hash_func(const Neighbor *neighbor, struct siphash *state) { assert(neighbor); siphash24_compress(&neighbor->family, sizeof(neighbor->family), state); @@ -106,7 +106,7 @@ void neighbor_hash_func(const Neighbor *neighbor, struct siphash *state) { hw_addr_hash_func(&neighbor->ll_addr, state); } -int neighbor_compare_func(const Neighbor *a, const Neighbor *b) { +static int neighbor_compare_func(const Neighbor *a, const Neighbor *b) { int r; r = CMP(a->family, b->family); @@ -193,11 +193,7 @@ static int neighbor_configure_message(Neighbor *neighbor, Link *link, sd_netlink return 0; } -static int neighbor_configure( - Neighbor *neighbor, - Link *link, - link_netlink_message_handler_t callback) { - +static int neighbor_configure(Neighbor *neighbor, Link *link, Request *req) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; int r; @@ -206,7 +202,7 @@ static int neighbor_configure( assert(link->ifindex > 0); assert(link->manager); assert(link->manager->rtnl); - assert(callback); + assert(req); log_neighbor_debug(neighbor, "Configuring", link); @@ -219,31 +215,20 @@ static int neighbor_configure( if (r < 0) return r; - r = netlink_call_async(link->manager->rtnl, NULL, m, callback, - link_netlink_destroy_callback, link); - if (r < 0) - return r; - - link_ref(link); - - return 0; + return request_call_netlink_async(link->manager->rtnl, m, req); } -int request_process_neighbor(Request *req) { - Neighbor *neighbor; - Link *link; +static int neighbor_process_request(Request *req, Link *link, Neighbor *neighbor) { int r; assert(req); - assert(req->type == REQUEST_TYPE_NEIGHBOR); - - neighbor = ASSERT_PTR(req->neighbor); - link = ASSERT_PTR(req->link); + assert(link); + assert(neighbor); if (!link_is_ready_to_configure(link, false)) return 0; - r = neighbor_configure(neighbor, link, req->netlink_handler); + r = neighbor_configure(neighbor, link, req); if (r < 0) return log_link_warning_errno(link, r, "Failed to configure neighbor: %m"); @@ -251,17 +236,11 @@ int request_process_neighbor(Request *req) { return 1; } -static int static_neighbor_configure_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { +static int static_neighbor_configure_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, Neighbor *neighbor) { int r; assert(m); assert(link); - assert(link->static_neighbor_messages > 0); - - link->static_neighbor_messages--; - - if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) - return 1; r = sd_netlink_message_get_errno(m); if (r < 0 && r != -EEXIST) { @@ -279,13 +258,7 @@ static int static_neighbor_configure_handler(sd_netlink *rtnl, sd_netlink_messag return 1; } -static int link_request_neighbor( - Link *link, - const Neighbor *neighbor, - unsigned *message_counter, - link_netlink_message_handler_t netlink_handler, - Request **ret) { - +static int link_request_neighbor(Link *link, const Neighbor *neighbor) { Neighbor *existing; int r; @@ -309,8 +282,14 @@ static int link_request_neighbor( existing->source = neighbor->source; log_neighbor_debug(existing, "Requesting", link); - r = link_queue_request(link, REQUEST_TYPE_NEIGHBOR, existing, false, - message_counter, netlink_handler, ret); + r = link_queue_request_safe(link, REQUEST_TYPE_NEIGHBOR, + existing, NULL, + neighbor_hash_func, + neighbor_compare_func, + neighbor_process_request, + &link->static_neighbor_messages, + static_neighbor_configure_handler, + NULL); if (r <= 0) return r; @@ -329,8 +308,7 @@ int link_request_static_neighbors(Link *link) { link->static_neighbors_configured = false; HASHMAP_FOREACH(neighbor, link->network->neighbors_by_section) { - r = link_request_neighbor(link, neighbor, &link->static_neighbor_messages, - static_neighbor_configure_handler, NULL); + r = link_request_neighbor(link, neighbor); if (r < 0) return log_link_warning_errno(link, r, "Could not request neighbor: %m"); } diff --git a/src/network/networkd-neighbor.h b/src/network/networkd-neighbor.h index ac1678de18..758475a8ff 100644 --- a/src/network/networkd-neighbor.h +++ b/src/network/networkd-neighbor.h @@ -13,7 +13,6 @@ typedef struct Link Link; typedef struct Manager Manager; typedef struct Network Network; -typedef struct Request Request; typedef struct Neighbor { Network *network; @@ -29,9 +28,6 @@ typedef struct Neighbor { Neighbor *neighbor_free(Neighbor *neighbor); -void neighbor_hash_func(const Neighbor *neighbor, struct siphash *state); -int neighbor_compare_func(const Neighbor *a, const Neighbor *b); - void network_drop_invalid_neighbors(Network *network); int link_drop_managed_neighbors(Link *link); @@ -39,7 +35,6 @@ int link_drop_foreign_neighbors(Link *link); void link_foreignize_neighbors(Link *link); int link_request_static_neighbors(Link *link); -int request_process_neighbor(Request *req); int manager_rtnl_process_neighbor(sd_netlink *rtnl, sd_netlink_message *message, Manager *m); diff --git a/src/network/networkd-nexthop.c b/src/network/networkd-nexthop.c index 8f555d9685..3eb9d62f7c 100644 --- a/src/network/networkd-nexthop.c +++ b/src/network/networkd-nexthop.c @@ -104,7 +104,7 @@ static int nexthop_new_static(Network *network, const char *filename, unsigned s return 0; } -void nexthop_hash_func(const NextHop *nexthop, struct siphash *state) { +static void nexthop_hash_func(const NextHop *nexthop, struct siphash *state) { assert(nexthop); siphash24_compress(&nexthop->protocol, sizeof(nexthop->protocol), state); @@ -124,7 +124,7 @@ void nexthop_hash_func(const NextHop *nexthop, struct siphash *state) { } } -int nexthop_compare_func(const NextHop *a, const NextHop *b) { +static int nexthop_compare_func(const NextHop *a, const NextHop *b) { int r; r = CMP(a->protocol, b->protocol); @@ -425,11 +425,7 @@ static int nexthop_remove(NextHop *nexthop) { return 0; } -static int nexthop_configure( - NextHop *nexthop, - Link *link, - link_netlink_message_handler_t callback) { - +static int nexthop_configure(NextHop *nexthop, Link *link, Request *req) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; int r; @@ -439,7 +435,7 @@ static int nexthop_configure( assert(link->manager); assert(link->manager->rtnl); assert(link->ifindex > 0); - assert(callback); + assert(req); log_nexthop_debug(nexthop, "Configuring", link); @@ -489,25 +485,14 @@ static int nexthop_configure( } } - r = netlink_call_async(link->manager->rtnl, NULL, m, callback, - link_netlink_destroy_callback, link); - if (r < 0) - return r; - - link_ref(link); - return 0; + return request_call_netlink_async(link->manager->rtnl, m, req); } -static int static_nexthop_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { +static int static_nexthop_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, NextHop *nexthop) { int r; + assert(m); assert(link); - assert(link->static_nexthop_messages > 0); - - link->static_nexthop_messages--; - - if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) - return 1; r = sd_netlink_message_get_errno(m); if (r < 0 && r != -EEXIST) { @@ -561,7 +546,7 @@ static bool nexthop_is_ready_to_configure(Link *link, const NextHop *nexthop) { ORDERED_SET_FOREACH(req, link->manager->request_queue) { if (req->type != REQUEST_TYPE_NEXTHOP) continue; - if (req->nexthop->id != 0) + if (((NextHop*) req->userdata)->id != 0) return false; /* first configure nexthop with id. */ } } @@ -569,21 +554,17 @@ static bool nexthop_is_ready_to_configure(Link *link, const NextHop *nexthop) { return gateway_is_ready(link, FLAGS_SET(nexthop->flags, RTNH_F_ONLINK), nexthop->family, &nexthop->gw); } -int request_process_nexthop(Request *req) { - NextHop *nexthop; - Link *link; +static int nexthop_process_request(Request *req, Link *link, NextHop *nexthop) { int r; assert(req); - assert(req->type == REQUEST_TYPE_NEXTHOP); - - nexthop = ASSERT_PTR(req->nexthop); - link = ASSERT_PTR(req->link); + assert(link); + assert(nexthop); if (!nexthop_is_ready_to_configure(link, nexthop)) return 0; - r = nexthop_configure(nexthop, link, req->netlink_handler); + r = nexthop_configure(nexthop, link, req); if (r < 0) return log_link_warning_errno(link, r, "Failed to configure nexthop"); @@ -591,13 +572,7 @@ int request_process_nexthop(Request *req) { return 1; } -static int link_request_nexthop( - Link *link, - NextHop *nexthop, - unsigned *message_counter, - link_netlink_message_handler_t netlink_handler, - Request **ret) { - +static int link_request_nexthop(Link *link, NextHop *nexthop) { NextHop *existing; int r; @@ -625,8 +600,14 @@ static int link_request_nexthop( existing->source = nexthop->source; log_nexthop_debug(existing, "Requesting", link); - r = link_queue_request(link, REQUEST_TYPE_NEXTHOP, existing, false, - message_counter, netlink_handler, ret); + r = link_queue_request_safe(link, REQUEST_TYPE_NEXTHOP, + existing, NULL, + nexthop_hash_func, + nexthop_compare_func, + nexthop_process_request, + &link->static_nexthop_messages, + static_nexthop_handler, + NULL); if (r <= 0) return r; @@ -647,8 +628,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, &link->static_nexthop_messages, - static_nexthop_handler, NULL); + r = link_request_nexthop(link, nh); if (r < 0) return log_link_warning_errno(link, r, "Could not request nexthop: %m"); } diff --git a/src/network/networkd-nexthop.h b/src/network/networkd-nexthop.h index 16eb02f7eb..6f2aa6f6dc 100644 --- a/src/network/networkd-nexthop.h +++ b/src/network/networkd-nexthop.h @@ -16,7 +16,6 @@ typedef struct Link Link; typedef struct Manager Manager; typedef struct Network Network; -typedef struct Request Request; typedef struct NextHop { Network *network; @@ -39,9 +38,6 @@ typedef struct NextHop { NextHop *nexthop_free(NextHop *nexthop); -void nexthop_hash_func(const NextHop *nexthop, struct siphash *state); -int nexthop_compare_func(const NextHop *a, const NextHop *b); - void network_drop_invalid_nexthops(Network *network); int link_drop_managed_nexthops(Link *link); @@ -49,7 +45,6 @@ int link_drop_foreign_nexthops(Link *link); void link_foreignize_nexthops(Link *link); int link_request_static_nexthops(Link *link, bool only_ipv4); -int request_process_nexthop(Request *req); 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); diff --git a/src/network/networkd-queue.c b/src/network/networkd-queue.c index 5f420c08c3..1463f610b2 100644 --- a/src/network/networkd-queue.c +++ b/src/network/networkd-queue.c @@ -1,107 +1,47 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ -#include "networkd-address.h" -#include "networkd-address-label.h" -#include "networkd-bridge-fdb.h" -#include "networkd-bridge-mdb.h" -#include "networkd-dhcp-server.h" -#include "networkd-dhcp4.h" -#include "networkd-dhcp6.h" -#include "networkd-ipv6-proxy-ndp.h" +#include "netdev.h" +#include "netlink-util.h" +#include "networkd-link.h" #include "networkd-manager.h" -#include "networkd-ndisc.h" -#include "networkd-neighbor.h" -#include "networkd-nexthop.h" -#include "networkd-route.h" -#include "networkd-routing-policy-rule.h" #include "networkd-queue.h" -#include "networkd-setlink.h" -#include "qdisc.h" -#include "tclass.h" - -static void request_free_object(RequestType type, void *object) { - switch (type) { - case REQUEST_TYPE_ACTIVATE_LINK: - break; - case REQUEST_TYPE_ADDRESS: - address_free(object); - break; - case REQUEST_TYPE_ADDRESS_LABEL: - address_label_free(object); - break; - case REQUEST_TYPE_BRIDGE_FDB: - bridge_fdb_free(object); - break; - case REQUEST_TYPE_BRIDGE_MDB: - bridge_mdb_free(object); - break; - case REQUEST_TYPE_DHCP_SERVER: - case REQUEST_TYPE_DHCP4_CLIENT: - case REQUEST_TYPE_DHCP6_CLIENT: - break; - case REQUEST_TYPE_IPV6_PROXY_NDP: - free(object); - break; - case REQUEST_TYPE_NDISC: - break; - case REQUEST_TYPE_NEIGHBOR: - neighbor_free(object); - break; - case REQUEST_TYPE_NETDEV_INDEPENDENT: - case REQUEST_TYPE_NETDEV_STACKED: - netdev_unref(object); - break; - case REQUEST_TYPE_NEXTHOP: - nexthop_free(object); - break; - case REQUEST_TYPE_RADV: - break; - case REQUEST_TYPE_ROUTE: - route_free(object); - break; - case REQUEST_TYPE_ROUTING_POLICY_RULE: - routing_policy_rule_free(object); - break; - case REQUEST_TYPE_SET_LINK: - break; - case REQUEST_TYPE_TC_QDISC: - qdisc_free(object); - break; - case REQUEST_TYPE_TC_CLASS: - tclass_free(object); - break; - case REQUEST_TYPE_UP_DOWN: - break; - default: - assert_not_reached(); - } -} +#include "string-table.h" static Request *request_free(Request *req) { if (!req) return NULL; - if (req->link && req->link->manager) - /* To prevent from triggering assertions in hash functions, remove this request before - * freeing object below. */ - ordered_set_remove(req->link->manager->request_queue, req); - if (req->consume_object) - request_free_object(req->type, req->object); - link_unref(req->link); + /* To prevent from triggering assertions in the hash and compare functions, remove this request + * before freeing userdata below. */ + if (req->manager) + ordered_set_remove(req->manager->request_queue, req); + + if (req->free_func) + req->free_func(req->userdata); + + if (req->counter) + (*req->counter)--; + + link_unref(req->link); /* link may be NULL, but link_unref() can handle it gracefully. */ return mfree(req); } -DEFINE_TRIVIAL_CLEANUP_FUNC(Request*, request_free); +DEFINE_TRIVIAL_REF_UNREF_FUNC(Request, request, request_free); +DEFINE_TRIVIAL_DESTRUCTOR(request_destroy_callback, Request, request_unref); + +void request_detach(Manager *manager, Request *req) { + assert(manager); -void request_drop(Request *req) { if (!req) return; - if (req->message_counter) - (*req->message_counter)--; + req = ordered_set_remove(manager->request_queue, req); + if (!req) + return; - request_free(req); + req->manager = NULL; + request_unref(req); } static void request_hash_func(const Request *req, struct siphash *state) { @@ -114,61 +54,11 @@ static void request_hash_func(const Request *req, struct siphash *state) { siphash24_compress(&req->type, sizeof(req->type), state); - switch (req->type) { - case REQUEST_TYPE_ACTIVATE_LINK: - break; - case REQUEST_TYPE_ADDRESS: - address_hash_func(req->address, state); - break; - case REQUEST_TYPE_ADDRESS_LABEL: - case REQUEST_TYPE_BRIDGE_FDB: - case REQUEST_TYPE_BRIDGE_MDB: - case REQUEST_TYPE_NETDEV_INDEPENDENT: - case REQUEST_TYPE_NETDEV_STACKED: - /* TODO: Currently, these types do not have any specific hash and compare functions. - * Fortunately, all these objects are 'static', thus we can use the trivial functions. */ - trivial_hash_func(req->object, state); - break; - case REQUEST_TYPE_DHCP_SERVER: - case REQUEST_TYPE_DHCP4_CLIENT: - case REQUEST_TYPE_DHCP6_CLIENT: - /* These types do not have an object. */ - break; - case REQUEST_TYPE_IPV6_PROXY_NDP: - in6_addr_hash_func(req->ipv6_proxy_ndp, state); - break; - case REQUEST_TYPE_NDISC: - /* This type does not have an object. */ - break; - case REQUEST_TYPE_NEIGHBOR: - neighbor_hash_func(req->neighbor, state); - break; - case REQUEST_TYPE_NEXTHOP: - nexthop_hash_func(req->nexthop, state); - break; - case REQUEST_TYPE_RADV: - /* This type does not have an object. */ - break; - case REQUEST_TYPE_ROUTE: - route_hash_func(req->route, state); - break; - case REQUEST_TYPE_ROUTING_POLICY_RULE: - routing_policy_rule_hash_func(req->rule, state); - break; - case REQUEST_TYPE_SET_LINK: - trivial_hash_func(req->set_link_operation_ptr, state); - break; - case REQUEST_TYPE_TC_QDISC: - qdisc_hash_func(req->qdisc, state); - break; - case REQUEST_TYPE_TC_CLASS: - tclass_hash_func(req->tclass, state); - break; - case REQUEST_TYPE_UP_DOWN: - break; - default: - assert_not_reached(); - } + siphash24_compress(&req->hash_func, sizeof(req->hash_func), state); + siphash24_compress(&req->compare_func, sizeof(req->compare_func), state); + + if (req->hash_func) + req->hash_func(req->userdata, state); } static int request_compare_func(const struct Request *a, const struct Request *b) { @@ -191,46 +81,18 @@ static int request_compare_func(const struct Request *a, const struct Request *b if (r != 0) return r; - switch (a->type) { - case REQUEST_TYPE_ACTIVATE_LINK: - return 0; - case REQUEST_TYPE_ADDRESS: - return address_compare_func(a->address, b->address); - case REQUEST_TYPE_ADDRESS_LABEL: - case REQUEST_TYPE_BRIDGE_FDB: - case REQUEST_TYPE_BRIDGE_MDB: - case REQUEST_TYPE_NETDEV_INDEPENDENT: - case REQUEST_TYPE_NETDEV_STACKED: - return trivial_compare_func(a->object, b->object); - case REQUEST_TYPE_DHCP_SERVER: - case REQUEST_TYPE_DHCP4_CLIENT: - case REQUEST_TYPE_DHCP6_CLIENT: - return 0; - case REQUEST_TYPE_IPV6_PROXY_NDP: - return in6_addr_compare_func(a->ipv6_proxy_ndp, b->ipv6_proxy_ndp); - case REQUEST_TYPE_NDISC: - return 0; - case REQUEST_TYPE_NEIGHBOR: - return neighbor_compare_func(a->neighbor, b->neighbor); - case REQUEST_TYPE_NEXTHOP: - return nexthop_compare_func(a->nexthop, b->nexthop); - case REQUEST_TYPE_ROUTE: - return route_compare_func(a->route, b->route); - case REQUEST_TYPE_RADV: - return 0; - case REQUEST_TYPE_ROUTING_POLICY_RULE: - return routing_policy_rule_compare_func(a->rule, b->rule); - case REQUEST_TYPE_SET_LINK: - return trivial_compare_func(a->set_link_operation_ptr, b->set_link_operation_ptr); - case REQUEST_TYPE_TC_QDISC: - return qdisc_compare_func(a->qdisc, b->qdisc); - case REQUEST_TYPE_TC_CLASS: - return tclass_compare_func(a->tclass, b->tclass); - case REQUEST_TYPE_UP_DOWN: - return 0; - default: - assert_not_reached(); - } + r = CMP(PTR_TO_UINT64(a->hash_func), PTR_TO_UINT64(b->hash_func)); + if (r != 0) + return r; + + r = CMP(PTR_TO_UINT64(a->compare_func), PTR_TO_UINT64(b->compare_func)); + if (r != 0) + return r; + + if (a->compare_func) + return a->compare_func(a->userdata, b->userdata); + + return 0; } DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR( @@ -238,217 +100,204 @@ DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR( Request, request_hash_func, request_compare_func, - request_free); + request_unref); -int netdev_queue_request( - NetDev *netdev, - Request **ret) { - - _cleanup_(request_freep) Request *req = NULL; - Request *existing; - int r; - - assert(netdev); - assert(netdev->manager); - - req = new(Request, 1); - if (!req) - return -ENOMEM; - - *req = (Request) { - .netdev = netdev_ref(netdev), - .type = REQUEST_TYPE_NETDEV_INDEPENDENT, - .consume_object = true, - }; - - existing = ordered_set_get(netdev->manager->request_queue, req); - if (existing) { - /* To prevent from removing the existing request. */ - req->netdev = netdev_unref(req->netdev); - - if (ret) - *ret = existing; - return 0; - } - - r = ordered_set_ensure_put(&netdev->manager->request_queue, &request_hash_ops, req); - if (r < 0) - return r; - - if (ret) - *ret = req; - - TAKE_PTR(req); - return 1; -} - -int link_queue_request( +static int request_new( + Manager *manager, Link *link, RequestType type, - void *object, - bool consume_object, - unsigned *message_counter, - link_netlink_message_handler_t netlink_handler, + void *userdata, + mfree_func_t free_func, + hash_func_t hash_func, + compare_func_t compare_func, + request_process_func_t process, + unsigned *counter, + request_netlink_handler_t netlink_handler, Request **ret) { - _cleanup_(request_freep) Request *req = NULL; + _cleanup_(request_unrefp) Request *req = NULL; Request *existing; int r; - assert(link); - assert(link->manager); - assert(type >= 0 && type < _REQUEST_TYPE_MAX); - assert(IN_SET(type, - REQUEST_TYPE_ACTIVATE_LINK, - REQUEST_TYPE_DHCP_SERVER, - REQUEST_TYPE_DHCP4_CLIENT, - REQUEST_TYPE_DHCP6_CLIENT, - REQUEST_TYPE_NDISC, - REQUEST_TYPE_RADV, - REQUEST_TYPE_SET_LINK, - REQUEST_TYPE_UP_DOWN) || - object); - assert(IN_SET(type, - REQUEST_TYPE_DHCP_SERVER, - REQUEST_TYPE_DHCP4_CLIENT, - REQUEST_TYPE_DHCP6_CLIENT, - REQUEST_TYPE_NDISC, - REQUEST_TYPE_RADV, - REQUEST_TYPE_TC_QDISC, - REQUEST_TYPE_TC_CLASS) || - netlink_handler); - - req = new(Request, 1); - if (!req) { - if (consume_object) - request_free_object(type, object); - return -ENOMEM; - } - - *req = (Request) { - .link = link_ref(link), - .type = type, - .object = object, - .consume_object = consume_object, - .message_counter = message_counter, - .netlink_handler = netlink_handler, - }; - - existing = ordered_set_get(link->manager->request_queue, req); - if (existing) { - /* To prevent from removing the existing request. */ - req->link = link_unref(req->link); - - if (ret) - *ret = existing; - return 0; - } - - r = ordered_set_ensure_put(&link->manager->request_queue, &request_hash_ops, req); - if (r < 0) - return r; - - if (req->message_counter) - (*req->message_counter)++; - - if (ret) - *ret = req; - - TAKE_PTR(req); - return 1; -} - -int manager_process_requests(sd_event_source *s, void *userdata) { - Manager *manager = userdata; - int r; - assert(manager); + assert(process); + + req = new(Request, 1); + if (!req) { + if (free_func) + free_func(userdata); + return -ENOMEM; + } + + *req = (Request) { + .n_ref = 1, + .link = link_ref(link), /* link may be NULL, but link_ref() handles it gracefully. */ + .type = type, + .userdata = userdata, + .free_func = free_func, + .hash_func = hash_func, + .compare_func = compare_func, + .process = process, + .netlink_handler = netlink_handler, + }; + + existing = ordered_set_get(manager->request_queue, req); + if (existing) { + if (ret) + *ret = existing; + return 0; + } + + r = ordered_set_ensure_put(&manager->request_queue, &request_hash_ops, req); + if (r < 0) + return r; + + req->manager = manager; + req->counter = counter; + if (req->counter) + (*req->counter)++; + + if (ret) + *ret = req; + + TAKE_PTR(req); + return 1; +} + +int netdev_queue_request( + NetDev *netdev, + request_process_func_t process, + Request **ret) { + + assert(netdev); + + return request_new(netdev->manager, NULL, REQUEST_TYPE_NETDEV_INDEPENDENT, + netdev_ref(netdev), (mfree_func_t) netdev_unref, + trivial_hash_func, trivial_compare_func, + process, NULL, NULL, ret); +} + +int link_queue_request_full( + Link *link, + RequestType type, + void *userdata, + mfree_func_t free_func, + hash_func_t hash_func, + compare_func_t compare_func, + request_process_func_t process, + unsigned *counter, + request_netlink_handler_t netlink_handler, + Request **ret) { + + assert(link); + + return request_new(link->manager, link, type, + userdata, free_func, hash_func, compare_func, + process, counter, netlink_handler, ret); +} + +int manager_process_requests(sd_event_source *s, void *userdata) { + Manager *manager = ASSERT_PTR(userdata); + int r; for (;;) { bool processed = false; Request *req; ORDERED_SET_FOREACH(req, manager->request_queue) { - switch (req->type) { - case REQUEST_TYPE_ACTIVATE_LINK: - r = request_process_activation(req); + _unused_ _cleanup_(request_unrefp) Request *ref = request_ref(req); + _cleanup_(link_unrefp) Link *link = link_ref(req->link); + + assert(req->process); + + r = req->process(req, link, req->userdata); + if (r == 0) + continue; + + processed = true; + request_detach(manager, req); + + if (r < 0 && link) { + link_enter_failed(link); + /* link_enter_failed() may remove multiple requests, + * hence we need to exit from the loop. */ break; - case REQUEST_TYPE_ADDRESS: - r = request_process_address(req); - break; - case REQUEST_TYPE_ADDRESS_LABEL: - r = request_process_address_label(req); - break; - case REQUEST_TYPE_BRIDGE_FDB: - r = request_process_bridge_fdb(req); - break; - case REQUEST_TYPE_BRIDGE_MDB: - r = request_process_bridge_mdb(req); - break; - case REQUEST_TYPE_DHCP_SERVER: - r = request_process_dhcp_server(req); - break; - case REQUEST_TYPE_DHCP4_CLIENT: - r = request_process_dhcp4_client(req); - break; - case REQUEST_TYPE_DHCP6_CLIENT: - r = request_process_dhcp6_client(req); - break; - case REQUEST_TYPE_IPV6_PROXY_NDP: - r = request_process_ipv6_proxy_ndp_address(req); - break; - case REQUEST_TYPE_NDISC: - r = request_process_ndisc(req); - break; - case REQUEST_TYPE_NEIGHBOR: - r = request_process_neighbor(req); - break; - case REQUEST_TYPE_NETDEV_INDEPENDENT: - r = request_process_independent_netdev(req); - break; - case REQUEST_TYPE_NETDEV_STACKED: - r = request_process_stacked_netdev(req); - break; - case REQUEST_TYPE_NEXTHOP: - r = request_process_nexthop(req); - break; - case REQUEST_TYPE_RADV: - r = request_process_radv(req); - break; - case REQUEST_TYPE_ROUTE: - r = request_process_route(req); - break; - case REQUEST_TYPE_ROUTING_POLICY_RULE: - r = request_process_routing_policy_rule(req); - break; - case REQUEST_TYPE_SET_LINK: - r = request_process_set_link(req); - break; - case REQUEST_TYPE_TC_QDISC: - r = request_process_qdisc(req); - break; - case REQUEST_TYPE_TC_CLASS: - r = request_process_tclass(req); - break; - case REQUEST_TYPE_UP_DOWN: - r = request_process_link_up_or_down(req); - break; - default: - return -EINVAL; - } - if (r < 0) { - if (req->link) - link_enter_failed(req->link); - } else if (r > 0) { - ordered_set_remove(manager->request_queue, req); - request_free(req); - processed = true; } } + /* When at least one request is processed, then another request may be ready now. */ if (!processed) break; } return 0; } + +static int request_netlink_handler(sd_netlink *nl, sd_netlink_message *m, Request *req) { + assert(req); + + if (req->counter) { + assert(*req->counter > 0); + (*req->counter)--; + req->counter = NULL; /* To prevent double decrement on free. */ + } + + if (req->link && IN_SET(req->link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) + return 0; + + if (req->netlink_handler) + return req->netlink_handler(nl, m, req, req->link, req->userdata); + + return 0; +} + +int request_call_netlink_async(sd_netlink *nl, sd_netlink_message *m, Request *req) { + int r; + + assert(nl); + assert(m); + assert(req); + + r = netlink_call_async(nl, NULL, m, request_netlink_handler, request_destroy_callback, req); + if (r < 0) + return r; + + request_ref(req); + return 0; +} + +static const char *const request_type_table[_REQUEST_TYPE_MAX] = { + [REQUEST_TYPE_ACTIVATE_LINK] = "activate link", + [REQUEST_TYPE_ADDRESS] = "address", + [REQUEST_TYPE_ADDRESS_LABEL] = "address label", + [REQUEST_TYPE_BRIDGE_FDB] = "bridge FDB", + [REQUEST_TYPE_BRIDGE_MDB] = "bridge MDB", + [REQUEST_TYPE_DHCP_SERVER] = "DHCP server", + [REQUEST_TYPE_DHCP4_CLIENT] = "DHCPv4 client", + [REQUEST_TYPE_DHCP6_CLIENT] = "DHCPv6 client", + [REQUEST_TYPE_IPV6_PROXY_NDP] = "IPv6 proxy NDP", + [REQUEST_TYPE_NDISC] = "NDisc", + [REQUEST_TYPE_NEIGHBOR] = "neighbor", + [REQUEST_TYPE_NETDEV_INDEPENDENT] = "independent netdev", + [REQUEST_TYPE_NETDEV_STACKED] = "stacked netdev", + [REQUEST_TYPE_NEXTHOP] = "nexthop", + [REQUEST_TYPE_RADV] = "RADV", + [REQUEST_TYPE_ROUTE] = "route", + [REQUEST_TYPE_ROUTING_POLICY_RULE] = "routing policy rule", + [REQUEST_TYPE_SET_LINK_ADDRESS_GENERATION_MODE] = "IPv6LL address generation mode", + [REQUEST_TYPE_SET_LINK_BOND] = "bond configurations", + [REQUEST_TYPE_SET_LINK_BRIDGE] = "bridge configurations", + [REQUEST_TYPE_SET_LINK_BRIDGE_VLAN] = "bridge VLAN configurations", + [REQUEST_TYPE_SET_LINK_CAN] = "CAN interface configurations", + [REQUEST_TYPE_SET_LINK_FLAGS] = "link flags", + [REQUEST_TYPE_SET_LINK_GROUP] = "interface group", + [REQUEST_TYPE_SET_LINK_IPOIB] = "IPoIB configurations", + [REQUEST_TYPE_SET_LINK_MAC] = "MAC address", + [REQUEST_TYPE_SET_LINK_MASTER] = "master interface", + [REQUEST_TYPE_SET_LINK_MTU] = "MTU", + [REQUEST_TYPE_TC_QDISC] = "QDisc", + [REQUEST_TYPE_TC_CLASS] = "TClass", + [REQUEST_TYPE_UP_DOWN] = "bring link up or down", +}; + +DEFINE_STRING_TABLE_LOOKUP_TO_STRING(request_type, RequestType); diff --git a/src/network/networkd-queue.h b/src/network/networkd-queue.h index 593f3dde6e..d1110119cc 100644 --- a/src/network/networkd-queue.h +++ b/src/network/networkd-queue.h @@ -2,20 +2,18 @@ #pragma once #include "sd-event.h" +#include "sd-netlink.h" -#include "networkd-link.h" +#include "alloc-util.h" +#include "hash-funcs.h" -typedef struct Address Address; -typedef struct AddressLabel AddressLabel; -typedef struct BridgeFDB BridgeFDB; -typedef struct BridgeMDB BridgeMDB; -typedef struct Neighbor Neighbor; +typedef struct Link Link; typedef struct NetDev NetDev; -typedef struct NextHop NextHop; -typedef struct Route Route; -typedef struct RoutingPolicyRule RoutingPolicyRule; -typedef struct QDisc QDisc; -typedef struct TClass TClass; +typedef struct Manager Manager; +typedef struct Request Request; + +typedef int (*request_process_func_t)(Request *req, Link *link, void *userdata); +typedef int (*request_netlink_handler_t)(sd_netlink *nl, sd_netlink_message *m, Request *req, Link *link, void *userdata); typedef enum RequestType { REQUEST_TYPE_ACTIVATE_LINK, @@ -35,7 +33,17 @@ typedef enum RequestType { REQUEST_TYPE_RADV, REQUEST_TYPE_ROUTE, REQUEST_TYPE_ROUTING_POLICY_RULE, - REQUEST_TYPE_SET_LINK, + REQUEST_TYPE_SET_LINK_ADDRESS_GENERATION_MODE, /* Setting IPv6LL address generation mode. */ + REQUEST_TYPE_SET_LINK_BOND, /* Setting bond configs. */ + REQUEST_TYPE_SET_LINK_BRIDGE, /* Setting bridge configs. */ + REQUEST_TYPE_SET_LINK_BRIDGE_VLAN, /* Setting bridge VLAN configs. */ + REQUEST_TYPE_SET_LINK_CAN, /* Setting CAN interface configs. */ + REQUEST_TYPE_SET_LINK_FLAGS, /* Setting IFF_NOARP or friends. */ + REQUEST_TYPE_SET_LINK_GROUP, /* Setting interface group. */ + REQUEST_TYPE_SET_LINK_IPOIB, /* Setting IPoIB configs. */ + REQUEST_TYPE_SET_LINK_MAC, /* Setting MAC address. */ + REQUEST_TYPE_SET_LINK_MASTER, /* Setting IFLA_MASTER. */ + REQUEST_TYPE_SET_LINK_MTU, /* Setting MTU. */ REQUEST_TYPE_TC_CLASS, REQUEST_TYPE_TC_QDISC, REQUEST_TYPE_UP_DOWN, @@ -43,44 +51,88 @@ typedef enum RequestType { _REQUEST_TYPE_INVALID = -EINVAL, } RequestType; -typedef struct Request { - Link *link; - RequestType type; - bool consume_object; - union { - Address *address; - AddressLabel *label; - BridgeFDB *fdb; - BridgeMDB *mdb; - struct in6_addr *ipv6_proxy_ndp; - Neighbor *neighbor; - NextHop *nexthop; - Route *route; - RoutingPolicyRule *rule; - void *set_link_operation_ptr; - NetDev *netdev; - QDisc *qdisc; - TClass *tclass; - void *object; - }; - void *userdata; - unsigned *message_counter; - link_netlink_message_handler_t netlink_handler; -} Request; +struct Request { + unsigned n_ref; -void request_drop(Request *req); + Manager *manager; /* must be non-NULL */ + Link *link; /* can be NULL */ + + RequestType type; + + /* Target object, e.g. Address, Route, NetDev, and so on. */ + void *userdata; + /* freeing userdata when the request is completed or failed. */ + mfree_func_t free_func; + + /* hash and compare functions for userdata, used for dedup requests. */ + hash_func_t hash_func; + compare_func_t compare_func; + + /* Checks the request dependencies, and then processes this request, e.g. call address_configure(). + * Return 1 when processed, 0 when its dependencies not resolved, and negative errno on failure. */ + request_process_func_t process; + + /* incremented when requested, decremented when request is completed or failed. */ + unsigned *counter; + /* called in netlink handler, the 'counter' is decremented before this is called. + * If this is specified, then the 'process' function must increment the reference of this + * request, and pass this request to the netlink_call_async(), and set the destroy function + * to the slot. */ + request_netlink_handler_t netlink_handler; +}; + +Request *request_ref(Request *req); +Request *request_unref(Request *req); +DEFINE_TRIVIAL_CLEANUP_FUNC(Request*, request_unref); + +void request_detach(Manager *manager, Request *req); int netdev_queue_request( NetDev *netdev, + request_process_func_t process, Request **ret); -int link_queue_request( +int link_queue_request_full( Link *link, RequestType type, - void *object, - bool consume_object, - unsigned *message_counter, - link_netlink_message_handler_t netlink_handler, + void *userdata, + mfree_func_t free_func, + hash_func_t hash_func, + compare_func_t compare_func, + request_process_func_t process, + unsigned *counter, + request_netlink_handler_t netlink_handler, Request **ret); +static inline int link_queue_request( + Link *link, + RequestType type, + request_process_func_t process, + Request **ret) { + + return link_queue_request_full(link, type, NULL, NULL, NULL, NULL, + process, NULL, NULL, ret); +} + +#define link_queue_request_safe(link, type, userdata, free_func, hash_func, compare_func, process, counter, netlink_handler, ret) \ + ({ \ + typeof(userdata) (*_f)(typeof(userdata)) = (free_func); \ + void (*_h)(const typeof(*userdata)*, struct siphash*) = (hash_func); \ + int (*_c)(const typeof(*userdata)*, const typeof(*userdata)*) = (compare_func); \ + int (*_p)(Request*, Link*, typeof(userdata)) = (process); \ + int (*_n)(sd_netlink*, sd_netlink_message*, Request*, Link*, typeof(userdata)) = (netlink_handler); \ + \ + link_queue_request_full(link, type, userdata, \ + (mfree_func_t) _f, \ + (hash_func_t) _h, \ + (compare_func_t) _c, \ + (request_process_func_t) _p, \ + counter, \ + (request_netlink_handler_t) _n, \ + ret); \ + }) + int manager_process_requests(sd_event_source *s, void *userdata); +int request_call_netlink_async(sd_netlink *nl, sd_netlink_message *m, Request *req); + +const char* request_type_to_string(RequestType t) _const_; diff --git a/src/network/networkd-radv.c b/src/network/networkd-radv.c index 507f0a0ccc..b9f5c55f4c 100644 --- a/src/network/networkd-radv.c +++ b/src/network/networkd-radv.c @@ -582,15 +582,10 @@ static int radv_is_ready_to_configure(Link *link) { return true; } -int request_process_radv(Request *req) { - Link *link; +static int radv_process_request(Request *req, Link *link, void *userdata) { int r; - assert(req); - assert(req->link); - assert(req->type == REQUEST_TYPE_RADV); - - link = req->link; + assert(link); r = radv_is_ready_to_configure(link); if (r <= 0) @@ -622,7 +617,7 @@ int link_request_radv(Link *link) { if (link->radv) return 0; - r = link_queue_request(link, REQUEST_TYPE_RADV, NULL, false, NULL, NULL, NULL); + r = link_queue_request(link, REQUEST_TYPE_RADV, radv_process_request, NULL); if (r < 0) return log_link_warning_errno(link, r, "Failed to request configuring of the IPv6 Router Advertisement engine: %m"); diff --git a/src/network/networkd-radv.h b/src/network/networkd-radv.h index 952fa8ae58..ebebb3942b 100644 --- a/src/network/networkd-radv.h +++ b/src/network/networkd-radv.h @@ -16,7 +16,6 @@ typedef struct Link Link; typedef struct Network Network; -typedef struct Request Request; typedef enum RADVPrefixDelegation { RADV_PREFIX_DELEGATION_NONE = 0, @@ -68,7 +67,6 @@ int radv_update_mac(Link *link); int radv_add_prefix(Link *link, const struct in6_addr *prefix, uint8_t prefix_len, usec_t lifetime_preferred_usec, usec_t lifetime_valid_usec); -int request_process_radv(Request *req); int link_request_radv(Link *link); const char* radv_prefix_delegation_to_string(RADVPrefixDelegation i) _const_; diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c index 2de75f2485..c9fb872ae5 100644 --- a/src/network/networkd-route.c +++ b/src/network/networkd-route.c @@ -110,7 +110,7 @@ Route *route_free(Route *route) { return mfree(route); } -void route_hash_func(const Route *route, struct siphash *state) { +static void route_hash_func(const Route *route, struct siphash *state) { assert(route); siphash24_compress(&route->family, sizeof(route->family), state); @@ -152,7 +152,7 @@ void route_hash_func(const Route *route, struct siphash *state) { } } -int route_compare_func(const Route *a, const Route *b) { +static int route_compare_func(const Route *a, const Route *b) { int r; r = CMP(a->family, b->family); @@ -1141,9 +1141,6 @@ int route_configure_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Li assert(link); assert(error_msg); - if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) - return 0; - r = sd_netlink_message_get_errno(m); if (r < 0 && r != -EEXIST) { log_link_message_warning_errno(link, m, r, "Could not set route"); @@ -1154,11 +1151,7 @@ int route_configure_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Li return 1; } -static int route_configure( - const Route *route, - Link *link, - link_netlink_message_handler_t callback) { - +static int route_configure(const Route *route, Link *link, Request *req) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; int r; @@ -1168,7 +1161,7 @@ static int route_configure( assert(link->manager); assert(link->manager->rtnl); assert(link->ifindex > 0); - assert(callback); + assert(req); log_route_debug(route, "Configuring", link, link->manager); @@ -1250,13 +1243,7 @@ static int route_configure( return r; } - r = netlink_call_async(link->manager->rtnl, NULL, m, callback, - link_netlink_destroy_callback, link); - if (r < 0) - return r; - - link_ref(link); - return 0; + return request_call_netlink_async(link->manager->rtnl, m, req); } static int route_is_ready_to_configure(const Route *route, Link *link) { @@ -1323,19 +1310,13 @@ static int route_is_ready_to_configure(const Route *route, Link *link) { return true; } -int request_process_route(Request *req) { +static int route_process_request(Request *req, Link *link, Route *route) { _cleanup_(converted_routes_freep) ConvertedRoutes *converted = NULL; - Route *route; - Link *link; int r; assert(req); - assert(req->link); - assert(req->route); - assert(req->type == REQUEST_TYPE_ROUTE); - - link = req->link; - route = req->route; + assert(link); + assert(route); r = route_is_ready_to_configure(route, link); if (r < 0) @@ -1373,7 +1354,7 @@ int request_process_route(Request *req) { } } - r = route_configure(route, link, req->netlink_handler); + r = route_configure(route, link, req); if (r < 0) return log_link_warning_errno(link, r, "Failed to configure route: %m"); @@ -1395,7 +1376,7 @@ int link_request_route( Route *route, bool consume_object, unsigned *message_counter, - link_netlink_message_handler_t netlink_handler, + route_netlink_handler_t netlink_handler, Request **ret) { Route *existing; @@ -1442,8 +1423,12 @@ int link_request_route( } log_route_debug(existing, "Requesting", link, link->manager); - r = link_queue_request(link, REQUEST_TYPE_ROUTE, existing, false, - message_counter, netlink_handler, ret); + r = link_queue_request_safe(link, REQUEST_TYPE_ROUTE, + existing, NULL, + route_hash_func, + route_compare_func, + route_process_request, + message_counter, netlink_handler, ret); if (r <= 0) return r; @@ -1451,13 +1436,10 @@ int link_request_route( return 1; } -static int static_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { +static int static_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, Route *route) { int r; assert(link); - assert(link->static_route_messages > 0); - - link->static_route_messages--; r = route_configure_handler_internal(rtnl, m, link, "Could not set route"); if (r <= 0) @@ -1482,8 +1464,10 @@ static int link_request_static_route(Link *link, Route *route) { static_route_handler, NULL); log_route_debug(route, "Requesting", link, link->manager); - return link_queue_request(link, REQUEST_TYPE_ROUTE, route, false, - &link->static_route_messages, static_route_handler, NULL); + return link_queue_request_safe(link, REQUEST_TYPE_ROUTE, + route, NULL, route_hash_func, route_compare_func, + route_process_request, + &link->static_route_messages, static_route_handler, NULL); } static int link_request_wireguard_routes(Link *link, bool only_ipv4) { @@ -1567,10 +1551,12 @@ void route_cancel_request(Route *route, Link *link) { req = (Request) { .link = link, .type = REQUEST_TYPE_ROUTE, - .route = route, + .userdata = route, + .hash_func = (hash_func_t) route_hash_func, + .compare_func = (compare_func_t) route_compare_func, }; - request_drop(ordered_set_get(link->manager->request_queue, &req)); + request_detach(link->manager, &req); route_cancel_requesting(route); } diff --git a/src/network/networkd-route.h b/src/network/networkd-route.h index ee8e36f83d..b431e1a30f 100644 --- a/src/network/networkd-route.h +++ b/src/network/networkd-route.h @@ -14,8 +14,15 @@ typedef struct Manager Manager; typedef struct Network Network; typedef struct Request Request; +typedef struct Route Route; +typedef int (*route_netlink_handler_t)( + sd_netlink *rtnl, + sd_netlink_message *m, + Request *req, + Link *link, + Route *route); -typedef struct Route { +struct Route { Link *link; Manager *manager; Network *network; @@ -66,10 +73,8 @@ typedef struct Route { usec_t lifetime_usec; /* Used when kernel does not support RTA_EXPIRES attribute. */ sd_event_source *expire; -} Route; +}; -void route_hash_func(const Route *route, struct siphash *state); -int route_compare_func(const Route *a, const Route *b); extern const struct hash_ops route_hash_ops; int route_new(Route **ret); @@ -92,10 +97,9 @@ int link_request_route( Route *route, bool consume_object, unsigned *message_counter, - link_netlink_message_handler_t netlink_handler, + route_netlink_handler_t netlink_handler, Request **ret); int link_request_static_routes(Link *link, bool only_ipv4); -int request_process_route(Request *req); int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, Manager *m); diff --git a/src/network/networkd-routing-policy-rule.c b/src/network/networkd-routing-policy-rule.c index 5812aee03b..8f4297a86a 100644 --- a/src/network/networkd-routing-policy-rule.c +++ b/src/network/networkd-routing-policy-rule.c @@ -153,7 +153,7 @@ static int routing_policy_rule_dup(const RoutingPolicyRule *src, RoutingPolicyRu return 0; } -void routing_policy_rule_hash_func(const RoutingPolicyRule *rule, struct siphash *state) { +static void routing_policy_rule_hash_func(const RoutingPolicyRule *rule, struct siphash *state) { assert(rule); siphash24_compress(&rule->family, sizeof(rule->family), state); @@ -194,7 +194,7 @@ void routing_policy_rule_hash_func(const RoutingPolicyRule *rule, struct siphash } } -int routing_policy_rule_compare_func(const RoutingPolicyRule *a, const RoutingPolicyRule *b) { +static int routing_policy_rule_compare_func(const RoutingPolicyRule *a, const RoutingPolicyRule *b) { int r; r = CMP(a->family, b->family); @@ -604,11 +604,7 @@ static int routing_policy_rule_remove(RoutingPolicyRule *rule) { return 0; } -static int routing_policy_rule_configure( - RoutingPolicyRule *rule, - Link *link, - link_netlink_message_handler_t callback) { - +static int routing_policy_rule_configure(RoutingPolicyRule *rule, Link *link, Request *req) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; int r; @@ -618,7 +614,7 @@ static int routing_policy_rule_configure( assert(link->ifindex > 0); assert(link->manager); assert(link->manager->rtnl); - assert(callback); + assert(req); log_routing_policy_rule_debug(rule, "Configuring", link, link->manager); @@ -630,13 +626,7 @@ static int routing_policy_rule_configure( if (r < 0) return r; - r = netlink_call_async(link->manager->rtnl, NULL, m, callback, - link_netlink_destroy_callback, link); - if (r < 0) - return r; - - link_ref(link); - return 0; + return request_call_netlink_async(link->manager->rtnl, m, req); } static void manager_mark_routing_policy_rules(Manager *m, bool foreign, const Link *except) { @@ -728,21 +718,17 @@ void link_foreignize_routing_policy_rules(Link *link) { } } -int request_process_routing_policy_rule(Request *req) { - RoutingPolicyRule *rule; - Link *link; +static int routing_policy_rule_process_request(Request *req, Link *link, RoutingPolicyRule *rule) { int r; assert(req); - assert(req->type == REQUEST_TYPE_ROUTING_POLICY_RULE); - - link = ASSERT_PTR(req->link); - rule = ASSERT_PTR(req->rule); + assert(link); + assert(rule); if (!link_is_ready_to_configure(link, false)) return 0; - r = routing_policy_rule_configure(rule, link, req->netlink_handler); + r = routing_policy_rule_configure(rule, link, req); if (r < 0) return log_link_warning_errno(link, r, "Failed to configure routing policy rule: %m"); @@ -750,19 +736,17 @@ int request_process_routing_policy_rule(Request *req) { return 1; } -static int static_routing_policy_rule_configure_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { +static int static_routing_policy_rule_configure_handler( + sd_netlink *rtnl, + sd_netlink_message *m, + Request *req, + Link *link, + RoutingPolicyRule *rule) { + int r; - assert(rtnl); assert(m); assert(link); - assert(link->ifname); - assert(link->static_routing_policy_rule_messages > 0); - - link->static_routing_policy_rule_messages--; - - if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) - return 1; r = sd_netlink_message_get_errno(m); if (r < 0 && r != -EEXIST) { @@ -780,13 +764,7 @@ static int static_routing_policy_rule_configure_handler(sd_netlink *rtnl, sd_net return 1; } -static int link_request_routing_policy_rule( - Link *link, - RoutingPolicyRule *rule, - unsigned *message_counter, - link_netlink_message_handler_t netlink_handler, - Request **ret) { - +static int link_request_routing_policy_rule(Link *link, RoutingPolicyRule *rule) { RoutingPolicyRule *existing; int r; @@ -815,8 +793,14 @@ static int link_request_routing_policy_rule( existing->source = rule->source; log_routing_policy_rule_debug(existing, "Requesting", link, link->manager); - r = link_queue_request(link, REQUEST_TYPE_ROUTING_POLICY_RULE, existing, false, - message_counter, netlink_handler, ret); + r = link_queue_request_safe(link, REQUEST_TYPE_ROUTING_POLICY_RULE, + existing, NULL, + routing_policy_rule_hash_func, + routing_policy_rule_compare_func, + routing_policy_rule_process_request, + &link->static_routing_policy_rule_messages, + static_routing_policy_rule_configure_handler, + NULL); if (r <= 0) return r; @@ -828,26 +812,17 @@ static int link_request_static_routing_policy_rule(Link *link, RoutingPolicyRule int r; if (IN_SET(rule->family, AF_INET, AF_INET6)) - return link_request_routing_policy_rule(link, rule, - &link->static_routing_policy_rule_messages, - static_routing_policy_rule_configure_handler, - NULL); + return link_request_routing_policy_rule(link, rule); rule->family = AF_INET; - r = link_request_routing_policy_rule(link, rule, - &link->static_routing_policy_rule_messages, - static_routing_policy_rule_configure_handler, - NULL); + r = link_request_routing_policy_rule(link, rule); if (r < 0) { rule->family = AF_UNSPEC; return r; } rule->family = AF_INET6; - r = link_request_routing_policy_rule(link, rule, - &link->static_routing_policy_rule_messages, - static_routing_policy_rule_configure_handler, - NULL); + r = link_request_routing_policy_rule(link, rule); rule->family = AF_UNSPEC; return r; } diff --git a/src/network/networkd-routing-policy-rule.h b/src/network/networkd-routing-policy-rule.h index 2d1ce19165..b6ce2fa19c 100644 --- a/src/network/networkd-routing-policy-rule.h +++ b/src/network/networkd-routing-policy-rule.h @@ -12,7 +12,6 @@ typedef struct Link Link; typedef struct Manager Manager; typedef struct Network Network; -typedef struct Request Request; typedef struct RoutingPolicyRule { Manager *manager; @@ -58,13 +57,9 @@ const char *fr_act_type_full_to_string(int t) _const_; RoutingPolicyRule *routing_policy_rule_free(RoutingPolicyRule *rule); -void routing_policy_rule_hash_func(const RoutingPolicyRule *rule, struct siphash *state); -int routing_policy_rule_compare_func(const RoutingPolicyRule *a, const RoutingPolicyRule *b); - void network_drop_invalid_routing_policy_rules(Network *network); int link_request_static_routing_policy_rules(Link *link); -int request_process_routing_policy_rule(Request *req); int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, Manager *m); int manager_drop_routing_policy_rules_internal(Manager *m, bool foreign, const Link *except); diff --git a/src/network/networkd-setlink.c b/src/network/networkd-setlink.c index 8878de3a2c..148277685e 100644 --- a/src/network/networkd-setlink.c +++ b/src/network/networkd-setlink.c @@ -14,23 +14,6 @@ #include "networkd-manager.h" #include "networkd-queue.h" #include "networkd-setlink.h" -#include "string-table.h" - -static const char *const set_link_operation_table[_SET_LINK_OPERATION_MAX] = { - [SET_LINK_ADDRESS_GENERATION_MODE] = "IPv6LL address generation mode", - [SET_LINK_BOND] = "bond configurations", - [SET_LINK_BRIDGE] = "bridge configurations", - [SET_LINK_BRIDGE_VLAN] = "bridge VLAN configurations", - [SET_LINK_CAN] = "CAN interface configurations", - [SET_LINK_FLAGS] = "link flags", - [SET_LINK_GROUP] = "interface group", - [SET_LINK_IPOIB] = "IPoIB configurations", - [SET_LINK_MAC] = "MAC address", - [SET_LINK_MASTER] = "master interface", - [SET_LINK_MTU] = "MTU", -}; - -DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(set_link_operation, SetLinkOperation); static int get_link_default_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { return link_getlink_handler_internal(rtnl, m, link, "Failed to sync link information"); @@ -54,42 +37,36 @@ static int get_link_update_flag_handler(sd_netlink *rtnl, sd_netlink_message *m, static int set_link_handler_internal( sd_netlink *rtnl, sd_netlink_message *m, + Request *req, Link *link, - SetLinkOperation op, bool ignore, link_netlink_message_handler_t get_link_handler) { int r; assert(m); + assert(req); assert(link); - assert(link->set_link_messages > 0); - assert(op >= 0 && op < _SET_LINK_OPERATION_MAX); - - link->set_link_messages--; - - if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) - goto on_error; r = sd_netlink_message_get_errno(m); if (r < 0) { const char *error_msg; - error_msg = strjoina("Failed to set ", set_link_operation_to_string(op), ignore ? ", ignoring" : ""); + error_msg = strjoina("Failed to set ", request_type_to_string(req->type), ignore ? ", ignoring" : ""); log_link_message_warning_errno(link, m, r, error_msg); if (!ignore) link_enter_failed(link); - goto on_error; + return 0; } - log_link_debug(link, "%s set.", set_link_operation_to_string(op)); + log_link_debug(link, "%s set.", request_type_to_string(req->type)); if (get_link_handler) { r = link_call_getlink(link, get_link_handler); if (r < 0) { link_enter_failed(link); - goto on_error; + return 0; } } @@ -97,27 +74,12 @@ static int set_link_handler_internal( link_check_ready(link); return 1; - -on_error: - switch (op) { - case SET_LINK_FLAGS: - assert(link->set_flags_messages > 0); - link->set_flags_messages--; - break; - case SET_LINK_MASTER: - link->master_set = true; - break; - default: - break; - } - - return 0; } -static int link_set_addrgen_mode_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { +static int link_set_addrgen_mode_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, void *userdata) { int r; - r = set_link_handler_internal(rtnl, m, link, SET_LINK_ADDRESS_GENERATION_MODE, /* ignore = */ true, NULL); + r = set_link_handler_internal(rtnl, m, req, link, /* ignore = */ true, NULL); if (r <= 0) return r; @@ -130,49 +92,43 @@ static int link_set_addrgen_mode_handler(sd_netlink *rtnl, sd_netlink_message *m return 0; } -static int link_set_bond_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { - return set_link_handler_internal(rtnl, m, link, SET_LINK_BOND, /* ignore = */ false, NULL); +static int link_set_bond_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, void *userdata) { + return set_link_handler_internal(rtnl, m, req, link, /* ignore = */ false, NULL); } -static int link_set_bridge_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { - return set_link_handler_internal(rtnl, m, link, SET_LINK_BRIDGE, /* ignore = */ true, NULL); +static int link_set_bridge_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, void *userdata) { + return set_link_handler_internal(rtnl, m, req, link, /* ignore = */ true, NULL); } -static int link_set_bridge_vlan_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { - return set_link_handler_internal(rtnl, m, link, SET_LINK_BRIDGE_VLAN, /* ignore = */ false, NULL); +static int link_set_bridge_vlan_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, void *userdata) { + return set_link_handler_internal(rtnl, m, req, link, /* ignore = */ false, NULL); } -static int link_set_can_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { - return set_link_handler_internal(rtnl, m, link, SET_LINK_CAN, /* ignore = */ false, NULL); +static int link_set_can_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, void *userdata) { + return set_link_handler_internal(rtnl, m, req, link, /* ignore = */ false, NULL); } -static int link_set_flags_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { - return set_link_handler_internal(rtnl, m, link, SET_LINK_FLAGS, /* ignore = */ false, get_link_update_flag_handler); +static int link_set_flags_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, void *userdata) { + return set_link_handler_internal(rtnl, m, req, link, /* ignore = */ false, get_link_default_handler); } -static int link_set_group_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { - return set_link_handler_internal(rtnl, m, link, SET_LINK_GROUP, /* ignore = */ false, NULL); +static int link_set_group_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, void *userdata) { + return set_link_handler_internal(rtnl, m, req, link, /* ignore = */ false, NULL); } -static int link_set_ipoib_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { - return set_link_handler_internal(rtnl, m, link, SET_LINK_IPOIB, /* ignore = */ true, NULL); +static int link_set_ipoib_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, void *userdata) { + return set_link_handler_internal(rtnl, m, req, link, /* ignore = */ true, NULL); } -static int link_set_mac_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { - return set_link_handler_internal(rtnl, m, link, SET_LINK_MAC, /* ignore = */ true, get_link_default_handler); +static int link_set_mac_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, void *userdata) { + return set_link_handler_internal(rtnl, m, req, link, /* ignore = */ true, get_link_default_handler); } -static int link_set_mac_allow_retry_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { +static int link_set_mac_allow_retry_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, void *userdata) { int r; assert(m); assert(link); - assert(link->set_link_messages > 0); - - link->set_link_messages--; - - if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) - return 0; r = sd_netlink_message_get_errno(m); if (r == -EBUSY) { @@ -189,24 +145,22 @@ static int link_set_mac_allow_retry_handler(sd_netlink *rtnl, sd_netlink_message return 0; } - /* set_link_mac_handler() also decrements set_link_messages, so increment the value once. */ - link->set_link_messages++; - return link_set_mac_handler(rtnl, m, link); + return link_set_mac_handler(rtnl, m, req, link, userdata); } -static int link_set_master_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { - return set_link_handler_internal(rtnl, m, link, SET_LINK_MASTER, /* ignore = */ false, get_link_master_handler); +static int link_set_master_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, void *userdata) { + return set_link_handler_internal(rtnl, m, req, link, /* ignore = */ false, get_link_master_handler); } -static int link_unset_master_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { +static int link_unset_master_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, void *userdata) { /* Some devices do not support setting master ifindex. Let's ignore error on unsetting master ifindex. */ - return set_link_handler_internal(rtnl, m, link, SET_LINK_MASTER, /* ignore = */ true, get_link_master_handler); + return set_link_handler_internal(rtnl, m, req, link, /* ignore = */ true, get_link_master_handler); } -static int link_set_mtu_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { +static int link_set_mtu_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, void *userdata) { int r; - r = set_link_handler_internal(rtnl, m, link, SET_LINK_MTU, /* ignore = */ true, get_link_default_handler); + r = set_link_handler_internal(rtnl, m, req, link, /* ignore = */ true, get_link_default_handler); if (r <= 0) return r; @@ -222,17 +176,17 @@ static int link_set_mtu_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *l static int link_configure_fill_message( Link *link, sd_netlink_message *req, - SetLinkOperation op, + RequestType type, void *userdata) { int r; - switch (op) { - case SET_LINK_ADDRESS_GENERATION_MODE: + switch (type) { + case REQUEST_TYPE_SET_LINK_ADDRESS_GENERATION_MODE: r = ipv6ll_addrgen_mode_fill_message(req, PTR_TO_UINT8(userdata)); if (r < 0) return r; break; - case SET_LINK_BOND: + case REQUEST_TYPE_SET_LINK_BOND: r = sd_netlink_message_set_flags(req, NLM_F_REQUEST | NLM_F_ACK); if (r < 0) return r; @@ -266,7 +220,7 @@ static int link_configure_fill_message( return r; break; - case SET_LINK_BRIDGE: + case REQUEST_TYPE_SET_LINK_BRIDGE: r = sd_rtnl_message_link_set_family(req, AF_BRIDGE); if (r < 0) return r; @@ -369,7 +323,7 @@ static int link_configure_fill_message( if (r < 0) return r; break; - case SET_LINK_BRIDGE_VLAN: + case REQUEST_TYPE_SET_LINK_BRIDGE_VLAN: r = sd_rtnl_message_link_set_family(req, AF_BRIDGE); if (r < 0) return r; @@ -394,12 +348,12 @@ static int link_configure_fill_message( return r; break; - case SET_LINK_CAN: + case REQUEST_TYPE_SET_LINK_CAN: r = can_set_netlink_message(link, req); if (r < 0) return r; break; - case SET_LINK_FLAGS: { + case REQUEST_TYPE_SET_LINK_FLAGS: { unsigned ifi_change = 0, ifi_flags = 0; if (link->network->arp >= 0) { @@ -428,27 +382,27 @@ static int link_configure_fill_message( break; } - case SET_LINK_GROUP: + case REQUEST_TYPE_SET_LINK_GROUP: r = sd_netlink_message_append_u32(req, IFLA_GROUP, (uint32_t) link->network->group); if (r < 0) return r; break; - case SET_LINK_MAC: + case REQUEST_TYPE_SET_LINK_MAC: r = netlink_message_append_hw_addr(req, IFLA_ADDRESS, &link->requested_hw_addr); if (r < 0) return r; break; - case SET_LINK_IPOIB: + case REQUEST_TYPE_SET_LINK_IPOIB: r = ipoib_set_netlink_message(link, req); if (r < 0) return r; break; - case SET_LINK_MASTER: + case REQUEST_TYPE_SET_LINK_MASTER: r = sd_netlink_message_append_u32(req, IFLA_MASTER, PTR_TO_UINT32(userdata)); if (r < 0) return r; break; - case SET_LINK_MTU: + case REQUEST_TYPE_SET_LINK_MTU: r = sd_netlink_message_append_u32(req, IFLA_MTU, PTR_TO_UINT32(userdata)); if (r < 0) return r; @@ -460,44 +414,30 @@ static int link_configure_fill_message( return 0; } -static int link_configure( - Link *link, - SetLinkOperation op, - void *userdata, - link_netlink_message_handler_t callback) { - - _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; +static int link_configure(Link *link, Request *req) { + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; int r; assert(link); assert(link->manager); - assert(link->manager->rtnl); - assert(link->network); - assert(op >= 0 && op < _SET_LINK_OPERATION_MAX); - assert(callback); + assert(req); - log_link_debug(link, "Setting %s", set_link_operation_to_string(op)); + log_link_debug(link, "Setting %s", request_type_to_string(req->type)); - if (op == SET_LINK_BOND) - r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_NEWLINK, link->master_ifindex); - else if (IN_SET(op, SET_LINK_CAN, SET_LINK_IPOIB)) - r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_NEWLINK, link->ifindex); + if (req->type == REQUEST_TYPE_SET_LINK_BOND) + r = sd_rtnl_message_new_link(link->manager->rtnl, &m, RTM_NEWLINK, link->master_ifindex); + else if (IN_SET(req->type, REQUEST_TYPE_SET_LINK_CAN, REQUEST_TYPE_SET_LINK_IPOIB)) + r = sd_rtnl_message_new_link(link->manager->rtnl, &m, RTM_NEWLINK, link->ifindex); else - r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_SETLINK, link->ifindex); + r = sd_rtnl_message_new_link(link->manager->rtnl, &m, RTM_SETLINK, link->ifindex); if (r < 0) - return log_link_debug_errno(link, r, "Could not allocate netlink message: %m"); + return r; - r = link_configure_fill_message(link, req, op, userdata); + r = link_configure_fill_message(link, m, req->type, req->userdata); if (r < 0) - return log_link_debug_errno(link, r, "Could not create netlink message: %m"); + return r; - r = netlink_call_async(link->manager->rtnl, NULL, req, callback, - link_netlink_destroy_callback, link); - if (r < 0) - return log_link_debug_errno(link, r, "Could not send netlink message: %m"); - - link_ref(link); - return 0; + return request_call_netlink_async(link->manager->rtnl, m, req); } static bool netdev_is_ready(NetDev *netdev) { @@ -511,66 +451,63 @@ static bool netdev_is_ready(NetDev *netdev) { return true; } -static bool link_is_ready_to_call_set_link(Request *req) { - SetLinkOperation op; - Link *link; +static int link_is_ready_to_set_link(Link *link, Request *req) { int r; + assert(link); + assert(link->manager); + assert(link->network); assert(req); - assert(req->link); - assert(req->link->manager); - assert(req->link->network); - link = req->link; - op = PTR_TO_INT(req->set_link_operation_ptr); - - if (!IN_SET(link->state, LINK_STATE_INITIALIZED, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED)) + if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED)) return false; - switch (op) { - case SET_LINK_BOND: - case SET_LINK_BRIDGE: + switch (req->type) { + case REQUEST_TYPE_SET_LINK_BOND: + case REQUEST_TYPE_SET_LINK_BRIDGE: if (!link->master_set) return false; + if (link->network->keep_master && link->master_ifindex <= 0) return false; break; - case SET_LINK_BRIDGE_VLAN: + + case REQUEST_TYPE_SET_LINK_BRIDGE_VLAN: if (!link->master_set) return false; + if (link->network->keep_master && link->master_ifindex <= 0 && !streq_ptr(link->kind, "bridge")) return false; + break; - case SET_LINK_CAN: + + case REQUEST_TYPE_SET_LINK_CAN: /* Do not check link->set_flgas_messages here, as it is ok even if link->flags * is outdated, and checking the counter causes a deadlock. */ if (FLAGS_SET(link->flags, IFF_UP)) { /* The CAN interface must be down to configure bitrate, etc... */ r = link_down_now(link); - if (r < 0) { - link_enter_failed(link); - return false; - } + if (r < 0) + return r; } break; - case SET_LINK_MAC: + + case REQUEST_TYPE_SET_LINK_MAC: if (req->netlink_handler == link_set_mac_handler) { /* This is the second attempt to set hardware address. On the first attempt * req->netlink_handler points to link_set_mac_allow_retry_handler(). * The first attempt failed as the interface was up. */ r = link_down_now(link); - if (r < 0) { - link_enter_failed(link); - return false; - } + if (r < 0) + return r; } break; - case SET_LINK_MASTER: { + + case REQUEST_TYPE_SET_LINK_MASTER: { uint32_t m = 0; Request req_mac = { .link = link, - .type = REQUEST_TYPE_SET_LINK, - .set_link_operation_ptr = INT_TO_PTR(SET_LINK_MAC), + .type = REQUEST_TYPE_SET_LINK_MAC, }; if (link->network->batadv) { @@ -589,10 +526,8 @@ static bool link_is_ready_to_call_set_link(Request *req) { if (FLAGS_SET(link->flags, IFF_UP)) { /* link must be down when joining to bond master. */ r = link_down_now(link); - if (r < 0) { - link_enter_failed(link); - return false; - } + if (r < 0) + return r; } } else if (link->network->bridge) { if (ordered_set_contains(link->manager->request_queue, &req_mac)) @@ -609,11 +544,10 @@ static bool link_is_ready_to_call_set_link(Request *req) { req->userdata = UINT32_TO_PTR(m); break; } - case SET_LINK_MTU: { + case REQUEST_TYPE_SET_LINK_MTU: { Request req_ipoib = { .link = link, - .type = REQUEST_TYPE_SET_LINK, - .set_link_operation_ptr = INT_TO_PTR(SET_LINK_IPOIB), + .type = REQUEST_TYPE_SET_LINK_IPOIB, }; return !ordered_set_contains(link->manager->request_queue, &req_ipoib); @@ -625,53 +559,44 @@ static bool link_is_ready_to_call_set_link(Request *req) { return true; } -int request_process_set_link(Request *req) { - SetLinkOperation op; +static int link_process_set_link(Request *req, Link *link, void *userdata) { int r; assert(req); - assert(req->link); - assert(req->type == REQUEST_TYPE_SET_LINK); - assert(req->netlink_handler); + assert(link); - op = PTR_TO_INT(req->set_link_operation_ptr); + r = link_is_ready_to_set_link(link, req); + if (r <= 0) + return r; - assert(op >= 0 && op < _SET_LINK_OPERATION_MAX); - - if (!link_is_ready_to_call_set_link(req)) - return 0; - - r = link_configure(req->link, op, req->userdata, req->netlink_handler); + r = link_configure(link, req); if (r < 0) - return log_link_error_errno(req->link, r, "Failed to set %s: %m", - set_link_operation_to_string(op)); - - if (op == SET_LINK_FLAGS) - req->link->set_flags_messages++; + return log_link_warning_errno(link, r, "Failed to set %s", request_type_to_string(req->type)); return 1; } static int link_request_set_link( Link *link, - SetLinkOperation op, - link_netlink_message_handler_t netlink_handler, + RequestType type, + request_netlink_handler_t netlink_handler, Request **ret) { Request *req; int r; assert(link); - assert(op >= 0 && op < _SET_LINK_OPERATION_MAX); - assert(netlink_handler); - r = link_queue_request(link, REQUEST_TYPE_SET_LINK, INT_TO_PTR(op), false, - &link->set_link_messages, netlink_handler, &req); + r = link_queue_request_full(link, type, NULL, NULL, NULL, NULL, + link_process_set_link, + &link->set_link_messages, + netlink_handler, + &req); if (r < 0) - return log_link_error_errno(link, r, "Failed to request to set %s: %m", - set_link_operation_to_string(op)); + return log_link_warning_errno(link, r, "Failed to request to set %s: %m", + request_type_to_string(type)); - log_link_debug(link, "Requested to set %s", set_link_operation_to_string(op)); + log_link_debug(link, "Requested to set %s", request_type_to_string(type)); if (ret) *ret = req; @@ -707,7 +632,9 @@ int link_request_to_set_addrgen_mode(Link *link) { return 0; } - r = link_request_set_link(link, SET_LINK_ADDRESS_GENERATION_MODE, link_set_addrgen_mode_handler, &req); + r = link_request_set_link(link, REQUEST_TYPE_SET_LINK_ADDRESS_GENERATION_MODE, + link_set_addrgen_mode_handler, + &req); if (r < 0) return r; @@ -732,7 +659,8 @@ int link_request_to_set_bond(Link *link) { return 0; } - return link_request_set_link(link, SET_LINK_BOND, link_set_bond_handler, NULL); + return link_request_set_link(link, REQUEST_TYPE_SET_LINK_BOND, + link_set_bond_handler, NULL); } int link_request_to_set_bridge(Link *link) { @@ -752,7 +680,9 @@ int link_request_to_set_bridge(Link *link) { return 0; } - return link_request_set_link(link, SET_LINK_BRIDGE, link_set_bridge_handler, NULL); + return link_request_set_link(link, REQUEST_TYPE_SET_LINK_BRIDGE, + link_set_bridge_handler, + NULL); } int link_request_to_set_bridge_vlan(Link *link) { @@ -775,7 +705,9 @@ int link_request_to_set_bridge_vlan(Link *link) { return 0; } - return link_request_set_link(link, SET_LINK_BRIDGE_VLAN, link_set_bridge_vlan_handler, NULL); + return link_request_set_link(link, REQUEST_TYPE_SET_LINK_BRIDGE_VLAN, + link_set_bridge_vlan_handler, + NULL); } int link_request_to_set_can(Link *link) { @@ -788,7 +720,9 @@ int link_request_to_set_can(Link *link) { if (!streq_ptr(link->kind, "can")) return 0; - return link_request_set_link(link, SET_LINK_CAN, link_set_can_handler, NULL); + return link_request_set_link(link, REQUEST_TYPE_SET_LINK_CAN, + link_set_can_handler, + NULL); } int link_request_to_set_flags(Link *link) { @@ -801,7 +735,9 @@ int link_request_to_set_flags(Link *link) { link->network->promiscuous < 0) return 0; - return link_request_set_link(link, SET_LINK_FLAGS, link_set_flags_handler, NULL); + return link_request_set_link(link, REQUEST_TYPE_SET_LINK_FLAGS, + link_set_flags_handler, + NULL); } int link_request_to_set_group(Link *link) { @@ -811,7 +747,9 @@ int link_request_to_set_group(Link *link) { if (link->network->group < 0) return 0; - return link_request_set_link(link, SET_LINK_GROUP, link_set_group_handler, NULL); + return link_request_set_link(link, REQUEST_TYPE_SET_LINK_GROUP, + link_set_group_handler, + NULL); } int link_request_to_set_mac(Link *link, bool allow_retry) { @@ -832,7 +770,7 @@ int link_request_to_set_mac(Link *link, bool allow_retry) { if (hw_addr_equal(&link->hw_addr, &link->requested_hw_addr)) return 0; - return link_request_set_link(link, SET_LINK_MAC, + return link_request_set_link(link, REQUEST_TYPE_SET_LINK_MAC, allow_retry ? link_set_mac_allow_retry_handler : link_set_mac_handler, NULL); } @@ -848,7 +786,9 @@ int link_request_to_set_ipoib(Link *link) { link->network->ipoib_umcast < 0) return 0; - return link_request_set_link(link, SET_LINK_IPOIB, link_set_ipoib_handler, NULL); + return link_request_set_link(link, REQUEST_TYPE_SET_LINK_IPOIB, + link_set_ipoib_handler, + NULL); } int link_request_to_set_master(Link *link) { @@ -863,15 +803,19 @@ int link_request_to_set_master(Link *link) { link->master_set = false; if (link->network->batadv || link->network->bond || link->network->bridge || link->network->vrf) - return link_request_set_link(link, SET_LINK_MASTER, link_set_master_handler, NULL); + return link_request_set_link(link, REQUEST_TYPE_SET_LINK_MASTER, + link_set_master_handler, + NULL); else - return link_request_set_link(link, SET_LINK_MASTER, link_unset_master_handler, NULL); + return link_request_set_link(link, REQUEST_TYPE_SET_LINK_MASTER, + link_unset_master_handler, + NULL); } int link_request_to_set_mtu(Link *link, uint32_t mtu) { - Request *req; const char *origin; uint32_t min_mtu; + Request *req; int r; assert(link); @@ -907,7 +851,9 @@ int link_request_to_set_mtu(Link *link, uint32_t mtu) { if (link->mtu == mtu) return 0; - r = link_request_set_link(link, SET_LINK_MTU, link_set_mtu_handler, &req); + r = link_request_set_link(link, REQUEST_TYPE_SET_LINK_MTU, + link_set_mtu_handler, + &req); if (r < 0) return r; @@ -991,14 +937,16 @@ static int link_up_dsa_slave(Link *link) { return 1; } -static int link_up_or_down_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Link *link, bool up, bool on_activate) { +static int link_up_or_down_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, void *userdata) { + bool on_activate, up; int r; assert(m); + assert(req); assert(link); - if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) - goto on_error; + on_activate = req->type == REQUEST_TYPE_ACTIVATE_LINK; + up = PTR_TO_INT(req->userdata); r = sd_netlink_message_get_errno(m); if (r == -ENETDOWN && up && link_up_dsa_slave(link) > 0) @@ -1012,82 +960,55 @@ static int link_up_or_down_handler_internal(sd_netlink *rtnl, sd_netlink_message log_link_message_warning_errno(link, m, r, error_msg); if (on_activate) - goto on_error; + return 0; } r = link_call_getlink(link, get_link_update_flag_handler); if (r < 0) { link_enter_failed(link); - goto on_error; + return 0; } + link->set_flags_messages++; + if (on_activate) { link->activated = true; link_check_ready(link); } - return 1; - -on_error: - assert(link->set_flags_messages > 0); - link->set_flags_messages--; - return 0; } -static int link_activate_up_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { - return link_up_or_down_handler_internal(rtnl, m, link, /* up = */ true, /* on_activate = */ true); -} - -static int link_activate_down_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { - return link_up_or_down_handler_internal(rtnl, m, link, /* up = */ false, /* on_activate = */ true); -} - -static int link_up_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { - return link_up_or_down_handler_internal(rtnl, m, link, /* up = */ true, /* on_activate = */ false); -} - -static int link_down_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { - return link_up_or_down_handler_internal(rtnl, m, link, /* up = */ false, /* on_activate = */ false); -} - static const char *up_or_down(bool up) { return up ? "up" : "down"; } -static int link_up_or_down(Link *link, bool up, link_netlink_message_handler_t callback) { - _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; +static int link_up_or_down(Link *link, bool up, Request *req) { + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; int r; assert(link); assert(link->manager); assert(link->manager->rtnl); - assert(callback); + assert(req); log_link_debug(link, "Bringing link %s", up_or_down(up)); - r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_SETLINK, link->ifindex); + r = sd_rtnl_message_new_link(link->manager->rtnl, &m, RTM_SETLINK, link->ifindex); if (r < 0) return r; - r = sd_rtnl_message_link_set_flags(req, up ? IFF_UP : 0, IFF_UP); + r = sd_rtnl_message_link_set_flags(m, up ? IFF_UP : 0, IFF_UP); if (r < 0) return r; - r = netlink_call_async(link->manager->rtnl, NULL, req, callback, - link_netlink_destroy_callback, link); - if (r < 0) - return r; - - link_ref(link); - - return 0; + return request_call_netlink_async(link->manager->rtnl, m, req); } static bool link_is_ready_to_activate(Link *link) { assert(link); - if (!IN_SET(link->state, LINK_STATE_INITIALIZED, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED)) + if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED)) return false; if (link->set_link_messages > 0) @@ -1096,23 +1017,17 @@ static bool link_is_ready_to_activate(Link *link) { return true; } -int request_process_activation(Request *req) { - Link *link; - bool up; +static int link_process_activation(Request *req, Link *link, void *userdata) { + bool up = PTR_TO_INT(userdata); int r; assert(req); - assert(req->link); - assert(req->type == REQUEST_TYPE_ACTIVATE_LINK); - assert(req->netlink_handler); - - link = req->link; - up = PTR_TO_INT(req->userdata); + assert(link); if (!link_is_ready_to_activate(link)) return 0; - r = link_up_or_down(link, up, req->netlink_handler); + r = link_up_or_down(link, up, req); if (r < 0) return log_link_warning_errno(link, r, "Failed to activate link: %m"); @@ -1120,7 +1035,6 @@ int request_process_activation(Request *req) { } int link_request_to_activate(Link *link) { - Request *req; bool up; int r; @@ -1151,13 +1065,14 @@ int link_request_to_activate(Link *link) { link->activated = false; - r = link_queue_request(link, REQUEST_TYPE_ACTIVATE_LINK, NULL, false, &link->set_flags_messages, - up ? link_activate_up_handler : link_activate_down_handler, &req); + r = link_queue_request_full(link, REQUEST_TYPE_ACTIVATE_LINK, + INT_TO_PTR(up), NULL, NULL, NULL, + link_process_activation, + &link->set_flags_messages, + link_up_or_down_handler, NULL); if (r < 0) return log_link_error_errno(link, r, "Failed to request to activate link: %m"); - req->userdata = INT_TO_PTR(up); - log_link_debug(link, "Requested to activate link"); return 0; } @@ -1192,22 +1107,17 @@ static bool link_is_ready_to_bring_up_or_down(Link *link, bool up) { return true; } -int request_process_link_up_or_down(Request *req) { - Link *link; - bool up; +static int link_process_up_or_down(Request *req, Link *link, void *userdata) { + bool up = PTR_TO_INT(userdata); int r; assert(req); - assert(req->link); - assert(req->type == REQUEST_TYPE_UP_DOWN); - - link = req->link; - up = PTR_TO_INT(req->userdata); + assert(link); if (!link_is_ready_to_bring_up_or_down(link, up)) return 0; - r = link_up_or_down(link, up, req->netlink_handler); + r = link_up_or_down(link, up, req); if (r < 0) return log_link_warning_errno(link, r, "Failed to bring link %s: %m", up_or_down(up)); @@ -1215,19 +1125,19 @@ int request_process_link_up_or_down(Request *req) { } int link_request_to_bring_up_or_down(Link *link, bool up) { - Request *req; int r; assert(link); - r = link_queue_request(link, REQUEST_TYPE_UP_DOWN, NULL, false, &link->set_flags_messages, - up ? link_up_handler : link_down_handler, &req); + r = link_queue_request_full(link, REQUEST_TYPE_UP_DOWN, + INT_TO_PTR(up), NULL, NULL, NULL, + link_process_up_or_down, + &link->set_flags_messages, + link_up_or_down_handler, NULL); if (r < 0) return log_link_warning_errno(link, r, "Failed to request to bring link %s: %m", up_or_down(up)); - req->userdata = INT_TO_PTR(up); - log_link_debug(link, "Requested to bring link %s", up_or_down(up)); return 0; } diff --git a/src/network/networkd-setlink.h b/src/network/networkd-setlink.h index e943f2012a..7e5ba32ef1 100644 --- a/src/network/networkd-setlink.h +++ b/src/network/networkd-setlink.h @@ -2,29 +2,9 @@ #pragma once #include +#include typedef struct Link Link; -typedef struct Request Request; - -typedef enum SetLinkOperation { - SET_LINK_ADDRESS_GENERATION_MODE, /* Setting IPv6LL address generation mode. */ - SET_LINK_BOND, /* Setting bond configs. */ - SET_LINK_BRIDGE, /* Setting bridge configs. */ - SET_LINK_BRIDGE_VLAN, /* Setting bridge VLAN configs. */ - SET_LINK_CAN, /* Setting CAN interface configs. */ - SET_LINK_FLAGS, /* Setting IFF_NOARP or friends. */ - SET_LINK_GROUP, /* Setting interface group. */ - SET_LINK_IPOIB, /* Setting IPoIB configs. */ - SET_LINK_MAC, /* Setting MAC address. */ - SET_LINK_MASTER, /* Setting IFLA_MASTER. */ - SET_LINK_MTU, /* Setting MTU. */ - _SET_LINK_OPERATION_MAX, - _SET_LINK_OPERATION_INVALID = -EINVAL, -} SetLinkOperation; - -/* SetLinkOperation is casted to int, then stored in void* with INT_TO_PTR(). */ -assert_cc(sizeof(SetLinkOperation) <= sizeof(void*)); -assert_cc(sizeof(SetLinkOperation) <= sizeof(int)); int link_request_to_set_addrgen_mode(Link *link); int link_request_to_set_bond(Link *link); @@ -40,12 +20,8 @@ int link_request_to_set_mtu(Link *link, uint32_t mtu); int link_configure_mtu(Link *link); -int request_process_set_link(Request *req); - -int request_process_activation(Request *req); int link_request_to_activate(Link *link); -int request_process_link_up_or_down(Request *req); int link_request_to_bring_up_or_down(Link *link, bool up); int link_down_now(Link *link); diff --git a/src/network/tc/qdisc.c b/src/network/tc/qdisc.c index 7b2dacbd5c..6aef268d1f 100644 --- a/src/network/tc/qdisc.c +++ b/src/network/tc/qdisc.c @@ -151,7 +151,7 @@ static const char *qdisc_get_tca_kind(const QDisc *qdisc) { QDISC_VTABLE(qdisc)->tca_kind : qdisc->tca_kind; } -void qdisc_hash_func(const QDisc *qdisc, struct siphash *state) { +static void qdisc_hash_func(const QDisc *qdisc, struct siphash *state) { assert(qdisc); assert(state); @@ -160,7 +160,7 @@ void qdisc_hash_func(const QDisc *qdisc, struct siphash *state) { siphash24_compress_string(qdisc_get_tca_kind(qdisc), state); } -int qdisc_compare_func(const QDisc *a, const QDisc *b) { +static int qdisc_compare_func(const QDisc *a, const QDisc *b) { int r; assert(a); @@ -293,15 +293,11 @@ int link_find_qdisc(Link *link, uint32_t handle, uint32_t parent, const char *ki return -ENOENT; } -static int qdisc_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { +static int qdisc_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, QDisc *qdisc) { int r; + assert(m); assert(link); - assert(link->tc_messages > 0); - link->tc_messages--; - - if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) - return 1; r = sd_netlink_message_get_errno(m); if (r < 0 && r != -EEXIST) { @@ -319,7 +315,7 @@ static int qdisc_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { return 1; } -static int qdisc_configure(QDisc *qdisc, Link *link) { +static int qdisc_configure(QDisc *qdisc, Link *link, Request *req) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; int r; @@ -328,6 +324,7 @@ static int qdisc_configure(QDisc *qdisc, Link *link) { assert(link->manager); assert(link->manager->rtnl); assert(link->ifindex > 0); + assert(req); log_qdisc_debug(qdisc, link, "Configuring"); @@ -346,12 +343,7 @@ static int qdisc_configure(QDisc *qdisc, Link *link) { return r; } - r = netlink_call_async(link->manager->rtnl, NULL, m, qdisc_handler, link_netlink_destroy_callback, link); - if (r < 0) - return r; - - link_ref(link); - return 0; + return request_call_netlink_async(link->manager->rtnl, m, req); } static bool qdisc_is_ready_to_configure(QDisc *qdisc, Link *link) { @@ -367,19 +359,17 @@ static bool qdisc_is_ready_to_configure(QDisc *qdisc, Link *link) { return link_find_tclass(link, qdisc->parent, NULL) >= 0; } -int request_process_qdisc(Request *req) { - QDisc *qdisc; - Link *link; +static int qdisc_process_request(Request *req, Link *link, QDisc *qdisc) { int r; assert(req); - assert_se(link = req->link); - assert_se(qdisc = req->qdisc); + assert(link); + assert(qdisc); if (!qdisc_is_ready_to_configure(qdisc, link)) return 0; - r = qdisc_configure(qdisc, link); + r = qdisc_configure(qdisc, link, req); if (r < 0) return log_link_warning_errno(link, r, "Failed to configure QDisc: %m"); @@ -410,8 +400,14 @@ int link_request_qdisc(Link *link, QDisc *qdisc) { existing->source = qdisc->source; log_qdisc_debug(existing, link, "Requesting"); - r = link_queue_request(link, REQUEST_TYPE_TC_QDISC, existing, false, - &link->tc_messages, NULL, NULL); + r = link_queue_request_safe(link, REQUEST_TYPE_TC_QDISC, + existing, NULL, + qdisc_hash_func, + qdisc_compare_func, + qdisc_process_request, + &link->tc_messages, + qdisc_handler, + NULL); if (r < 0) return log_link_warning_errno(link, r, "Failed to request QDisc: %m"); if (r == 0) diff --git a/src/network/tc/qdisc.h b/src/network/tc/qdisc.h index 54afe97ced..adaaf260c4 100644 --- a/src/network/tc/qdisc.h +++ b/src/network/tc/qdisc.h @@ -8,7 +8,6 @@ typedef struct Link Link; typedef struct Manager Manager; typedef struct Network Network; -typedef struct Request Request; typedef enum QDiscKind { QDISC_KIND_BFIFO, @@ -77,12 +76,8 @@ DEFINE_NETWORK_CONFIG_STATE_FUNCTIONS(QDisc, qdisc); QDisc* qdisc_free(QDisc *qdisc); int qdisc_new_static(QDiscKind kind, Network *network, const char *filename, unsigned section_line, QDisc **ret); -void qdisc_hash_func(const QDisc *qdisc, struct siphash *state); -int qdisc_compare_func(const QDisc *a, const QDisc *b); - int link_find_qdisc(Link *link, uint32_t handle, uint32_t parent, const char *kind, QDisc **qdisc); -int request_process_qdisc(Request *req); int link_request_qdisc(Link *link, QDisc *qdisc); void network_drop_invalid_qdisc(Network *network); diff --git a/src/network/tc/tclass.c b/src/network/tc/tclass.c index e01e151d8f..d3b3c19bdf 100644 --- a/src/network/tc/tclass.c +++ b/src/network/tc/tclass.c @@ -121,7 +121,7 @@ static const char *tclass_get_tca_kind(const TClass *tclass) { TCLASS_VTABLE(tclass)->tca_kind : tclass->tca_kind; } -void tclass_hash_func(const TClass *tclass, struct siphash *state) { +static void tclass_hash_func(const TClass *tclass, struct siphash *state) { assert(tclass); assert(state); @@ -130,7 +130,7 @@ void tclass_hash_func(const TClass *tclass, struct siphash *state) { siphash24_compress_string(tclass_get_tca_kind(tclass), state); } -int tclass_compare_func(const TClass *a, const TClass *b) { +static int tclass_compare_func(const TClass *a, const TClass *b) { int r; assert(a); @@ -255,15 +255,11 @@ static void log_tclass_debug(TClass *tclass, Link *link, const char *str) { strna(tclass_get_tca_kind(tclass))); } -static int tclass_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { +static int tclass_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, TClass *tclass) { int r; + assert(m); assert(link); - assert(link->tc_messages > 0); - link->tc_messages--; - - if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) - return 1; r = sd_netlink_message_get_errno(m); if (r < 0 && r != -EEXIST) { @@ -281,7 +277,7 @@ static int tclass_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { return 1; } -static int tclass_configure(TClass *tclass, Link *link) { +static int tclass_configure(TClass *tclass, Link *link, Request *req) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; int r; @@ -290,6 +286,7 @@ static int tclass_configure(TClass *tclass, Link *link) { assert(link->manager); assert(link->manager->rtnl); assert(link->ifindex > 0); + assert(req); log_tclass_debug(tclass, link, "Configuring"); @@ -308,12 +305,7 @@ static int tclass_configure(TClass *tclass, Link *link) { return r; } - r = netlink_call_async(link->manager->rtnl, NULL, m, tclass_handler, link_netlink_destroy_callback, link); - if (r < 0) - return r; - - link_ref(link); - return 0; + return request_call_netlink_async(link->manager->rtnl, m, req); } static bool tclass_is_ready_to_configure(TClass *tclass, Link *link) { @@ -326,19 +318,17 @@ static bool tclass_is_ready_to_configure(TClass *tclass, Link *link) { return link_find_qdisc(link, tclass->classid, tclass->parent, tclass_get_tca_kind(tclass), NULL) >= 0; } -int request_process_tclass(Request *req) { - TClass *tclass; - Link *link; +static int tclass_process_request(Request *req, Link *link, TClass *tclass) { int r; assert(req); - assert_se(link = req->link); - assert_se(tclass = req->tclass); + assert(link); + assert(tclass); if (!tclass_is_ready_to_configure(tclass, link)) return 0; - r = tclass_configure(tclass, link); + r = tclass_configure(tclass, link, req); if (r < 0) return log_link_warning_errno(link, r, "Failed to configure TClass: %m"); @@ -369,8 +359,14 @@ int link_request_tclass(Link *link, TClass *tclass) { existing->source = tclass->source; log_tclass_debug(existing, link, "Requesting"); - r = link_queue_request(link, REQUEST_TYPE_TC_CLASS, existing, false, - &link->tc_messages, NULL, NULL); + r = link_queue_request_safe(link, REQUEST_TYPE_TC_CLASS, + existing, NULL, + tclass_hash_func, + tclass_compare_func, + tclass_process_request, + &link->tc_messages, + tclass_handler, + NULL); if (r < 0) return log_link_warning_errno(link, r, "Failed to request TClass: %m"); if (r == 0) diff --git a/src/network/tc/tclass.h b/src/network/tc/tclass.h index c588b38abe..606bb3fef3 100644 --- a/src/network/tc/tclass.h +++ b/src/network/tc/tclass.h @@ -8,7 +8,6 @@ typedef struct Link Link; typedef struct Manager Manager; typedef struct Network Network; -typedef struct Request Request; typedef enum TClassKind { TCLASS_KIND_DRR, @@ -59,12 +58,8 @@ DEFINE_NETWORK_CONFIG_STATE_FUNCTIONS(TClass, tclass); TClass* tclass_free(TClass *tclass); int tclass_new_static(TClassKind kind, Network *network, const char *filename, unsigned section_line, TClass **ret); -void tclass_hash_func(const TClass *qdisc, struct siphash *state); -int tclass_compare_func(const TClass *a, const TClass *b); - int link_find_tclass(Link *link, uint32_t classid, TClass **ret); -int request_process_tclass(Request *req); int link_request_tclass(Link *link, TClass *tclass); void network_drop_invalid_tclass(Network *network);