]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network: netdev: use request queue to create independent netdevs
authorYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 14 Feb 2022 18:28:18 +0000 (03:28 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 15 Feb 2022 07:06:37 +0000 (16:06 +0900)
src/network/netdev/netdev.c
src/network/netdev/netdev.h
src/network/netdev/tunnel.c
src/network/netdev/vxlan.c
src/network/networkd-queue.c
src/network/networkd-queue.h

index 151a94f928e4bd288d1bc8625e161b9e590f35c8..72cbf66696c6551b25b87d1b95475b7bf048010e 100644 (file)
@@ -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;
 }
 
index b631e8e23ff55615f971ec38fdf80f37054c8bb2..f383315ac33ccfc7429f4546489f7ad9c1aaa695 100644 (file)
@@ -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);
 
index bb6e4f75869f434611d3292bdacbd623268adcb5..3ba4484b6b2a992ec3101ff545f3a92c3358842c 100644 (file)
@@ -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;
 }
 
index bdedf3e7a9ed99f700ab0095cc34e44677b0ffd4..d93084c2d40904a19c2833dded568bb00b7c12ba 100644 (file)
@@ -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;
 }
 
index f1760a29e09d35ff37162aa5193ee38f1759d4a5..5d06735774a1bef4763a726a94ef69f07a36faae 100644 (file)
@@ -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;
index e1dc0a063a380fb842c2e478846197cbbc6fb890..9b2c6baf44056410617d95d0c249fbcf8e052efa 100644 (file)
@@ -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,