]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/network/networkd-mdb.c
Merge pull request #17085 from yuwata/network-configure-mdb-entries-on-bridge-master
[thirdparty/systemd.git] / src / network / networkd-mdb.c
index f27d4da254d7de79c17d0349345ed6e5cb94ccd4..542ba75ad0f8ab51a4218730f6f74c5911b7fb72 100644 (file)
@@ -103,7 +103,13 @@ static int set_mdb_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link)
                 return 1;
 
         r = sd_netlink_message_get_errno(m);
-        if (r < 0 && r != -EEXIST) {
+        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");
+                        link->manager->bridge_mdb_on_master_not_supported = true;
+                }
+        } else if (r < 0 && r != -EEXIST) {
                 log_link_message_warning_errno(link, m, r, "Could not add MDB entry");
                 link_enter_failed(link);
                 return 1;
@@ -117,11 +123,23 @@ static int set_mdb_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link)
         return 1;
 }
 
+static int link_get_bridge_master_ifindex(Link *link) {
+        assert(link);
+
+        if (link->network && link->network->bridge)
+                return link->network->bridge->ifindex;
+
+        if (streq_ptr(link->kind, "bridge"))
+                return link->ifindex;
+
+        return 0;
+}
+
 /* send a request to the kernel to add an MDB entry */
 static int mdb_entry_configure(Link *link, MdbEntry *mdb_entry) {
         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
         struct br_mdb_entry entry;
-        int r;
+        int master, r;
 
         assert(link);
         assert(link->network);
@@ -136,14 +154,20 @@ static int mdb_entry_configure(Link *link, MdbEntry *mdb_entry) {
                                strna(a), mdb_entry->vlan_id);
         }
 
+        master = link_get_bridge_master_ifindex(link);
+        if (master <= 0)
+                return log_link_error_errno(link, SYNTHETIC_ERRNO(EINVAL), "Invalid bridge master ifindex %i", master);
+
         entry = (struct br_mdb_entry) {
-                .state = MDB_PERMANENT,
+                /* If MDB entry is added on bridge master, then the state must be MDB_TEMPORARY.
+                 * See br_mdb_add_group() in net/bridge/br_mdb.c of kernel. */
+                .state = master == link->ifindex ? MDB_TEMPORARY : MDB_PERMANENT,
                 .ifindex = link->ifindex,
                 .vid = mdb_entry->vlan_id,
         };
 
         /* create new RTM message */
-        r = sd_rtnl_message_new_mdb(link->manager->rtnl, &req, RTM_NEWMDB, link->network->bridge->ifindex);
+        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");
 
@@ -178,30 +202,39 @@ static int mdb_entry_configure(Link *link, MdbEntry *mdb_entry) {
 
 int link_set_bridge_mdb(Link *link) {
         MdbEntry *mdb_entry;
-        Link *master;
         int r;
 
         assert(link);
+        assert(link->manager);
 
         link->bridge_mdb_configured = false;
 
         if (!link->network)
                 return 0;
 
-        if (!link->network->bridge) {
-                link->bridge_mdb_configured = true;
-                return 0;
-        }
+        if (LIST_IS_EMPTY(link->network->static_mdb_entries))
+                goto finish;
 
         if (!link_has_carrier(link))
                 return log_link_debug(link, "Link does not have carrier yet, setting MDB entries later.");
 
-        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->network->bridge) {
+                Link *master;
 
-        if (!link_has_carrier(master))
-                return log_link_debug(link, "Bridge interface %s does not have carrier yet, setting MDB entries later.", link->network->bridge->ifname);
+                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))
+                        return log_link_debug(link, "Bridge interface %s does not have carrier yet, setting MDB entries later.", link->network->bridge->ifname);
+
+        } 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;
+        }
 
         LIST_FOREACH(static_mdb_entries, mdb_entry, link->network->static_mdb_entries) {
                 r = mdb_entry_configure(link, mdb_entry);
@@ -211,6 +244,7 @@ int link_set_bridge_mdb(Link *link) {
                 link->bridge_mdb_messages++;
         }
 
+finish:
         if (link->bridge_mdb_messages == 0) {
                 link->bridge_mdb_configured = true;
                 link_check_ready(link);