]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network: use request queue to configure bridge MDB
authorYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 17 May 2021 20:45:28 +0000 (05:45 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 7 Jun 2021 21:33:27 +0000 (06:33 +0900)
src/network/networkd-bridge-mdb.c
src/network/networkd-bridge-mdb.h
src/network/networkd-link.c
src/network/networkd-queue.c
src/network/networkd-queue.h

index 7c3ef596efc9910d8f0ff85df4bd6bb665a21856..3bf1e068f00d5bd084d4aa045fb67dd252cd9dc3 100644 (file)
@@ -7,6 +7,7 @@
 #include "networkd-link.h"
 #include "networkd-manager.h"
 #include "networkd-network.h"
+#include "networkd-queue.h"
 #include "string-util.h"
 #include "vlan-util.h"
 
@@ -79,7 +80,7 @@ static int bridge_mdb_new_static(
         return 0;
 }
 
-static int set_mdb_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
+static int bridge_mdb_configure_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
         int r;
 
         assert(link);
@@ -94,7 +95,7 @@ static int set_mdb_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link)
         if (r == -EINVAL && streq_ptr(link->kind, "bridge") && (!link->network || !link->network->bridge)) {
                 /* To configure bridge MDB entries on bridge master, 1bc844ee0faa1b92e3ede00bdd948021c78d7088 (v5.4) is required. */
                 if (!link->manager->bridge_mdb_on_master_not_supported) {
-                        log_link_warning_errno(link, r, "Kernel seems not to support configuring bridge MDB entries on bridge master, ignoring: %m");
+                        log_link_warning_errno(link, r, "Kernel seems not to support bridge MDB entries on bridge master, ignoring: %m");
                         link->manager->bridge_mdb_on_master_not_supported = true;
                 }
         } else if (r < 0 && r != -EEXIST) {
@@ -124,15 +125,16 @@ static int link_get_bridge_master_ifindex(Link *link) {
 }
 
 /* send a request to the kernel to add an MDB entry */
-static int bridge_mdb_configure(Link *link, BridgeMDB *mdb) {
+static int bridge_mdb_configure(BridgeMDB *mdb, Link *link, link_netlink_message_handler_t callback) {
         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
         struct br_mdb_entry entry;
         int master, r;
 
+        assert(mdb);
         assert(link);
         assert(link->network);
         assert(link->manager);
-        assert(mdb);
+        assert(callback);
 
         if (DEBUG_LOGGING) {
                 _cleanup_free_ char *a = NULL;
@@ -154,11 +156,6 @@ static int bridge_mdb_configure(Link *link, BridgeMDB *mdb) {
                 .vid = mdb->vlan_id,
         };
 
-        /* create new RTM message */
-        r = sd_rtnl_message_new_mdb(link->manager->rtnl, &req, RTM_NEWMDB, master);
-        if (r < 0)
-                return log_link_error_errno(link, r, "Could not create RTM_NEWMDB message: %m");
-
         switch (mdb->family) {
         case AF_INET:
                 entry.addr.u.ip4 = mdb->group_addr.in.s_addr;
@@ -174,11 +171,16 @@ static int bridge_mdb_configure(Link *link, BridgeMDB *mdb) {
                 assert_not_reached("Invalid address family");
         }
 
+        /* create new RTM message */
+        r = sd_rtnl_message_new_mdb(link->manager->rtnl, &req, RTM_NEWMDB, master);
+        if (r < 0)
+                return log_link_error_errno(link, r, "Could not create RTM_NEWMDB message: %m");
+
         r = sd_netlink_message_append_data(req, MDBA_SET_ENTRY, &entry, sizeof(entry));
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not append MDBA_SET_ENTRY attribute: %m");
 
-        r = netlink_call_async(link->manager->rtnl, NULL, req, set_mdb_handler,
+        r = netlink_call_async(link->manager->rtnl, NULL, req, callback,
                                link_netlink_destroy_callback, link);
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
@@ -188,18 +190,13 @@ static int bridge_mdb_configure(Link *link, BridgeMDB *mdb) {
         return 1;
 }
 
-int link_set_bridge_mdb(Link *link) {
+int link_request_static_bridge_mdb(Link *link) {
         BridgeMDB *mdb;
         int r;
 
         assert(link);
         assert(link->manager);
 
-        if (link->static_bridge_mdb_messages != 0) {
-                log_link_debug(link, "MDB entries are configuring.");
-                return 0;
-        }
-
         link->static_bridge_mdb_configured = false;
 
         if (!link->network)
@@ -208,48 +205,77 @@ int link_set_bridge_mdb(Link *link) {
         if (hashmap_isempty(link->network->bridge_mdb_entries_by_section))
                 goto finish;
 
-        if (!link_has_carrier(link)) {
-                log_link_debug(link, "Link does not have carrier yet, setting MDB entries later.");
-                return 0;
-        }
-
-        if (link->network->bridge) {
-                Link *master;
-
-                r = link_get(link->manager, link->network->bridge->ifindex, &master);
-                if (r < 0)
-                        return log_link_error_errno(link, r, "Failed to get Link object for Bridge=%s", link->network->bridge->ifname);
-
-                if (!link_has_carrier(master)) {
-                        log_link_debug(link, "Bridge interface %s does not have carrier yet, setting MDB entries later.", link->network->bridge->ifname);
-                        return 0;
+        if (!link->network->bridge) {
+                if (!streq_ptr(link->kind, "bridge")) {
+                        log_link_warning(link, "Link is neither a bridge master nor a bridge port, ignoring [BridgeMDB] sections.");
+                        goto finish;
+                } else if (link->manager->bridge_mdb_on_master_not_supported) {
+                        log_link_debug(link, "Kernel seems not to support bridge MDB entries on bridge master, ignoring [BridgeMDB] sections.");
+                        goto finish;
                 }
-
-        } else if (!streq_ptr(link->kind, "bridge")) {
-                log_link_warning(link, "Link is neither a bridge master nor a bridge port, ignoring [BridgeMDB] sections.");
-                goto finish;
-        } else if (link->manager->bridge_mdb_on_master_not_supported) {
-                log_link_debug(link, "Kernel seems not to support configuring bridge MDB entries on bridge master, ignoring [BridgeMDB] sections.");
-                goto finish;
         }
 
         HASHMAP_FOREACH(mdb, link->network->bridge_mdb_entries_by_section) {
-                r = bridge_mdb_configure(link, mdb);
+                r = link_queue_request(link, REQUEST_TYPE_BRIDGE_MDB, mdb, false,
+                                       &link->static_bridge_mdb_messages, bridge_mdb_configure_handler, NULL);
                 if (r < 0)
-                        return log_link_error_errno(link, r, "Failed to add MDB entry to multicast group database: %m");
-
-                link->static_bridge_mdb_messages++;
+                        return log_link_error_errno(link, r, "Failed to request MDB entry to multicast group database: %m");
         }
 
 finish:
         if (link->static_bridge_mdb_messages == 0) {
                 link->static_bridge_mdb_configured = true;
                 link_check_ready(link);
+        } else {
+                log_link_debug(link, "Setting bridge MDB entries.");
+                link_set_state(link, LINK_STATE_CONFIGURING);
         }
 
         return 0;
 }
 
+static bool bridge_mdb_is_ready_to_configure(Link *link) {
+        Link *master;
+
+        if (!link_is_ready_to_configure(link, false))
+                return false;
+
+        if (!link->network->bridge)
+                return true; /* The interface is bridge master. */
+
+        if (link->master_ifindex <= 0)
+                return false;
+
+        if (link->master_ifindex != link->network->bridge->ifindex)
+                return false;
+
+        if (link_get(link->manager, link->master_ifindex, &master) < 0)
+                return false;
+
+        if (!streq_ptr(master->kind, "bridge"))
+                return false;
+
+        if (!IN_SET(master->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
+                return false;
+
+        if (!link_has_carrier(master))
+                return false;
+
+        return true;
+}
+
+int request_process_bridge_mdb(Request *req) {
+        assert(req);
+        assert(req->link);
+        assert(req->mdb);
+        assert(req->type == REQUEST_TYPE_BRIDGE_MDB);
+
+        if (!bridge_mdb_is_ready_to_configure(req->link))
+                return 0;
+
+        return bridge_mdb_configure(req->mdb, req->link, req->netlink_handler);
+}
+
 static int bridge_mdb_verify(BridgeMDB *mdb) {
         if (section_is_invalid(mdb->section))
                 return -EINVAL;
index efdfa4eae9f6123cb44071cd216e093706b63f18..9ca262e0ce9acaa664649d34328efc71066d671c 100644 (file)
@@ -9,6 +9,7 @@
 
 typedef struct Link Link;
 typedef struct Network Network;
+typedef struct Request Request;
 
 typedef struct BridgeMDB {
         Network *network;
@@ -23,7 +24,8 @@ BridgeMDB *bridge_mdb_free(BridgeMDB *mdb);
 
 void network_drop_invalid_bridge_mdb_entries(Network *network);
 
-int link_set_bridge_mdb(Link *link);
+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);
index 05b1658e15fb44cf71b5b95e76d553120fb1c12c..23c751a39f478136a8ddcc221bf58dbf90e7fcee 100644 (file)
@@ -826,10 +826,6 @@ static int link_set_static_configs(Link *link) {
         assert(link->network);
         assert(link->state != _LINK_STATE_INVALID);
 
-        r = link_set_bridge_mdb(link);
-        if (r < 0)
-                return r;
-
         r = link_set_ipv6_proxy_ndp_addresses(link);
         if (r < 0)
                 return r;
@@ -846,6 +842,10 @@ static int link_set_static_configs(Link *link) {
         if (r < 0)
                 return r;
 
+        r = link_request_static_bridge_mdb(link);
+        if (r < 0)
+                return r;
+
         r = link_request_static_neighbors(link);
         if (r < 0)
                 return r;
@@ -2802,30 +2802,7 @@ static int link_carrier_gained(Link *link) {
                         return r;
         }
 
-        r = link_handle_bound_by_list(link);
-        if (r < 0)
-                return r;
-
-        if (!link->static_bridge_mdb_configured) {
-                r = link_set_bridge_mdb(link);
-                if (r < 0)
-                        return r;
-        }
-
-        if (streq_ptr(link->kind, "bridge")) {
-                Link *slave;
-
-                SET_FOREACH(slave, link->slaves) {
-                        if (slave->static_bridge_mdb_configured)
-                                continue;
-
-                        r = link_set_bridge_mdb(slave);
-                        if (r < 0)
-                                link_enter_failed(slave);
-                }
-        }
-
-        return 0;
+        return link_handle_bound_by_list(link);
 }
 
 static int link_carrier_lost(Link *link) {
index 758cd4de2a44b2603780c46870b92cbd95454a18..563cdc4f950062f1d6db43a5114975b909699c54 100644 (file)
@@ -2,6 +2,7 @@
 
 #include "networkd-address.h"
 #include "networkd-bridge-fdb.h"
+#include "networkd-bridge-mdb.h"
 #include "networkd-dhcp-server.h"
 #include "networkd-manager.h"
 #include "networkd-neighbor.h"
@@ -18,6 +19,9 @@ static void request_free_object(RequestType type, void *object) {
         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:
                 break;
         case REQUEST_TYPE_NEIGHBOR:
@@ -131,6 +135,9 @@ int manager_process_requests(sd_event_source *s, void *userdata) {
                         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;
index 9eab751da42529f1e450bdd9593fb932d799b89c..f963d18d744c28ff3b13e2902c7cc8f0b901b50c 100644 (file)
@@ -7,6 +7,7 @@
 
 typedef struct Address Address;
 typedef struct BridgeFDB BridgeFDB;
+typedef struct BridgeMDB BridgeMDB;
 typedef struct Neighbor Neighbor;
 typedef struct NextHop NextHop;
 typedef struct Route Route;
@@ -20,6 +21,7 @@ typedef void (*request_on_free_handler_t)(Request*);
 typedef enum RequestType {
         REQUEST_TYPE_ADDRESS,
         REQUEST_TYPE_BRIDGE_FDB,
+        REQUEST_TYPE_BRIDGE_MDB,
         REQUEST_TYPE_DHCP_SERVER,
         REQUEST_TYPE_NEIGHBOR,
         REQUEST_TYPE_NEXTHOP,
@@ -36,6 +38,7 @@ typedef struct Request {
         union {
                 Address *address;
                 BridgeFDB *fdb;
+                BridgeMDB *mdb;
                 Neighbor *neighbor;
                 NextHop *nexthop;
                 Route *route;