From: Yu Watanabe Date: Mon, 14 Feb 2022 18:28:18 +0000 (+0900) Subject: network: netdev: use request queue to create independent netdevs X-Git-Tag: v251-rc1~280^2~4 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=5d4a925af0f85f6f8a8cf48e53cc8884c92cf9c8;p=thirdparty%2Fsystemd.git network: netdev: use request queue to create independent netdevs --- diff --git a/src/network/netdev/netdev.c b/src/network/netdev/netdev.c index 151a94f928e..72cbf66696c 100644 --- a/src/network/netdev/netdev.c +++ b/src/network/netdev/netdev.c @@ -623,20 +623,21 @@ int netdev_join(NetDev *netdev, Link *link, link_netlink_message_handler_t callb static int netdev_is_ready_to_create(NetDev *netdev, Link *link) { assert(netdev); - assert(link); if (netdev->state != NETDEV_STATE_LOADING) return false; - if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED)) - return false; + if (link) { + if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED)) + return false; - if (netdev_get_create_type(netdev) == NETDEV_CREATE_AFTER_CONFIGURED && - link->state != LINK_STATE_CONFIGURED) - return false; + if (netdev_get_create_type(netdev) == NETDEV_CREATE_AFTER_CONFIGURED && + link->state != LINK_STATE_CONFIGURED) + return false; - if (link->set_link_messages > 0) - return false; + if (link->set_link_messages > 0) + return false; + } if (NETDEV_VTABLE(netdev)->is_ready_to_create) return NETDEV_VTABLE(netdev)->is_ready_to_create(netdev, link); @@ -751,6 +752,44 @@ int link_request_stacked_netdev(Link *link, NetDev *netdev) { return 0; } +int request_process_independent_netdev(Request *req) { + int r; + + assert(req); + assert(req->type == REQUEST_TYPE_NETDEV_INDEPENDENT); + assert(req->netdev); + + r = netdev_is_ready_to_create(req->netdev, NULL); + if (r <= 0) + return r; + + r = netdev_create(req->netdev, NULL, NULL); + if (r < 0) + return r; + + return 1; +} + +static int netdev_request(NetDev *netdev) { + int r; + + assert(netdev); + + if (!IN_SET(netdev_get_create_type(netdev), NETDEV_CREATE_MASTER, NETDEV_CREATE_INDEPENDENT) && + !netdev_is_stacked_and_independent(netdev)) + return 0; + + r = netdev_is_ready_to_create(netdev, NULL); + if (r < 0) + return r; + if (r > 0) + /* If the netdev has no dependency, then create it now. */ + return netdev_create(netdev, NULL, NULL); + + /* Otherwise, wait for the dependencies being resolved. */ + return netdev_queue_request(netdev, NULL); +} + int netdev_load_one(Manager *manager, const char *filename) { _cleanup_(netdev_unrefp) NetDev *netdev_raw = NULL, *netdev = NULL; const char *dropin_dirname; @@ -861,20 +900,11 @@ int netdev_load_one(Manager *manager, const char *filename) { log_netdev_debug(netdev, "loaded %s", netdev_kind_to_string(netdev->kind)); - if (IN_SET(netdev_get_create_type(netdev), NETDEV_CREATE_MASTER, NETDEV_CREATE_INDEPENDENT)) { - r = netdev_create(netdev, NULL, NULL); - if (r < 0) - return r; - } - - if (netdev_is_stacked_and_independent(netdev)) { - r = netdev_create(netdev, NULL, NULL); - if (r < 0) - return r; - } - - netdev = NULL; + r = netdev_request(netdev); + if (r < 0) + return log_netdev_warning_errno(netdev, r, "Failed to request to create: %m"); + TAKE_PTR(netdev); return 0; } diff --git a/src/network/netdev/netdev.h b/src/network/netdev/netdev.h index b631e8e23ff..f383315ac33 100644 --- a/src/network/netdev/netdev.h +++ b/src/network/netdev/netdev.h @@ -210,6 +210,7 @@ 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 netdev_join(NetDev *netdev, Link *link, link_netlink_message_handler_t cb); +int request_process_independent_netdev(Request *req); int request_process_stacked_netdev(Request *req); int link_request_stacked_netdev(Link *link, NetDev *netdev); diff --git a/src/network/netdev/tunnel.c b/src/network/netdev/tunnel.c index bb6e4f75869..3ba4484b6b2 100644 --- a/src/network/netdev/tunnel.c +++ b/src/network/netdev/tunnel.c @@ -657,12 +657,14 @@ static int netdev_tunnel_is_ready_to_create(NetDev *netdev, Link *link) { Tunnel *t; assert(netdev); - assert(link); t = TUNNEL(netdev); assert(t); + if (t->independent) + return true; + return tunnel_get_local_address(t, link, NULL) >= 0; } diff --git a/src/network/netdev/vxlan.c b/src/network/netdev/vxlan.c index bdedf3e7a9e..d93084c2d40 100644 --- a/src/network/netdev/vxlan.c +++ b/src/network/netdev/vxlan.c @@ -427,12 +427,14 @@ static int netdev_vxlan_is_ready_to_create(NetDev *netdev, Link *link) { VxLan *v; assert(netdev); - assert(link); v = VXLAN(netdev); assert(v); + if (v->independent) + return true; + return vxlan_get_local_address(v, link, NULL, NULL) >= 0; } diff --git a/src/network/networkd-queue.c b/src/network/networkd-queue.c index f1760a29e09..5d06735774a 100644 --- a/src/network/networkd-queue.c +++ b/src/network/networkd-queue.c @@ -46,6 +46,7 @@ static void request_free_object(RequestType type, void *object) { case REQUEST_TYPE_NEIGHBOR: neighbor_free(object); break; + case REQUEST_TYPE_NETDEV_INDEPENDENT: case REQUEST_TYPE_NETDEV_STACKED: netdev_unref(object); break; @@ -101,10 +102,12 @@ void request_drop(Request *req) { static void request_hash_func(const Request *req, struct siphash *state) { assert(req); - assert(req->link); assert(state); - siphash24_compress(&req->link->ifindex, sizeof(req->link->ifindex), state); + siphash24_compress_boolean(req->link, state); + if (req->link) + siphash24_compress(&req->link->ifindex, sizeof(req->link->ifindex), state); + siphash24_compress(&req->type, sizeof(req->type), state); switch (req->type) { @@ -116,6 +119,7 @@ static void request_hash_func(const Request *req, struct siphash *state) { 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. */ @@ -165,13 +169,17 @@ static int request_compare_func(const struct Request *a, const struct Request *b assert(a); assert(b); - assert(a->link); - assert(b->link); - r = CMP(a->link->ifindex, b->link->ifindex); + r = CMP(!!a->link, !!b->link); if (r != 0) return r; + if (a->link) { + r = CMP(a->link->ifindex, b->link->ifindex); + if (r != 0) + return r; + } + r = CMP(a->type, b->type); if (r != 0) return r; @@ -184,6 +192,7 @@ static int request_compare_func(const struct Request *a, const struct Request *b 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: @@ -222,6 +231,48 @@ DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR( request_compare_func, request_free); +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( Link *link, RequestType type, @@ -342,6 +393,9 @@ int manager_process_requests(sd_event_source *s, void *userdata) { 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; @@ -369,9 +423,10 @@ int manager_process_requests(sd_event_source *s, void *userdata) { default: return -EINVAL; } - if (r < 0) - link_enter_failed(req->link); - if (r > 0) { + 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; diff --git a/src/network/networkd-queue.h b/src/network/networkd-queue.h index e1dc0a063a3..9b2c6baf440 100644 --- a/src/network/networkd-queue.h +++ b/src/network/networkd-queue.h @@ -28,6 +28,7 @@ typedef enum RequestType { REQUEST_TYPE_IPV6_PROXY_NDP, REQUEST_TYPE_NDISC, REQUEST_TYPE_NEIGHBOR, + REQUEST_TYPE_NETDEV_INDEPENDENT, REQUEST_TYPE_NETDEV_STACKED, REQUEST_TYPE_NEXTHOP, REQUEST_TYPE_RADV, @@ -66,6 +67,10 @@ typedef struct Request { void request_drop(Request *req); +int netdev_queue_request( + NetDev *netdev, + Request **ret); + int link_queue_request( Link *link, RequestType type,