]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network/brvlan: rework bridge vlan ID assignment
authorYu Watanabe <watanabe.yu+github@gmail.com>
Sat, 11 Nov 2023 09:15:55 +0000 (18:15 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Sun, 12 Nov 2023 18:58:46 +0000 (03:58 +0900)
No functional change, just refactoring.

src/network/networkd-bridge-vlan.c
src/network/networkd-bridge-vlan.h
src/network/networkd-setlink.c

index 36e3610a8f91a23148afd04d00135df181dae4b3..bfc404f154dc340b222b62ab6e4ef71e92cdb701 100644 (file)
@@ -17,9 +17,9 @@
 #include "parse-util.h"
 #include "vlan-util.h"
 
-static bool is_bit_set(unsigned bit, uint32_t scope) {
-        assert(bit < sizeof(scope)*8);
-        return scope & (UINT32_C(1) << bit);
+static bool is_bit_set(unsigned nr, const uint32_t *addr) {
+        assert(nr < BRIDGE_VLAN_BITMAP_MAX);
+        return addr[nr / 32] & (UINT32_C(1) << (nr % 32));
 }
 
 static void set_bit(unsigned nr, uint32_t *addr) {
@@ -27,116 +27,159 @@ static void set_bit(unsigned nr, uint32_t *addr) {
                 addr[nr / 32] |= (UINT32_C(1) << (nr % 32));
 }
 
-static int find_next_bit(int i, uint32_t x) {
-        int j;
+static int add_single(sd_netlink_message *m, uint16_t id, bool untagged, bool is_pvid) {
+        assert(m);
+        assert(id < BRIDGE_VLAN_BITMAP_MAX);
+        return sd_netlink_message_append_data(m, IFLA_BRIDGE_VLAN_INFO,
+                                              &(struct bridge_vlan_info) {
+                                                      .vid = id,
+                                                      .flags = (untagged ? BRIDGE_VLAN_INFO_UNTAGGED : 0) |
+                                                               (is_pvid ? BRIDGE_VLAN_INFO_PVID : 0),
+                                              },
+                                              sizeof(struct bridge_vlan_info));
+}
 
-        if (i >= 32)
-                return -1;
+static int add_range(sd_netlink_message *m, uint16_t begin, uint16_t end, bool untagged) {
+        int r;
 
-        /* find first bit */
-        if (i < 0)
-                return BUILTIN_FFS_U32(x);
+        assert(m);
+        assert(begin <= end);
+        assert(end < BRIDGE_VLAN_BITMAP_MAX);
 
-        /* mask off prior finds to get next */
-        j = __builtin_ffs(x >> i);
-        return j ? j + i : 0;
-}
+        if (begin == end)
+                return add_single(m, begin, untagged, /* is_pvid = */ false);
 
-int bridge_vlan_append_info(
-                const Link *link,
-                sd_netlink_message *req,
-                uint16_t pvid,
-                const uint32_t *br_vid_bitmap,
-                const uint32_t *br_untagged_bitmap) {
+        r = sd_netlink_message_append_data(m, IFLA_BRIDGE_VLAN_INFO,
+                                           &(struct bridge_vlan_info) {
+                                                   .vid = begin,
+                                                   .flags = (untagged ? BRIDGE_VLAN_INFO_UNTAGGED : 0) |
+                                                            BRIDGE_VLAN_INFO_RANGE_BEGIN,
+                                           },
+                                           sizeof(struct bridge_vlan_info));
+        if (r < 0)
+                return r;
 
-        struct bridge_vlan_info br_vlan;
-        bool done, untagged = false;
-        uint16_t begin, end;
-        int r, cnt;
+        r = sd_netlink_message_append_data(m, IFLA_BRIDGE_VLAN_INFO,
+                                           &(struct bridge_vlan_info) {
+                                                   .vid = end,
+                                                   .flags = (untagged ? BRIDGE_VLAN_INFO_UNTAGGED : 0) |
+                                                            BRIDGE_VLAN_INFO_RANGE_END,
+                                           },
+                                           sizeof(struct bridge_vlan_info));
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
+static int bridge_vlan_append_set_info(Link *link, sd_netlink_message *m) {
+        uint16_t begin = UINT16_MAX;
+        bool untagged;
+        int r;
 
         assert(link);
-        assert(req);
-        assert(br_vid_bitmap);
-        assert(br_untagged_bitmap);
-
-        cnt = 0;
-
-        begin = end = UINT16_MAX;
-        for (int k = 0; k < BRIDGE_VLAN_BITMAP_LEN; k++) {
-                uint32_t untagged_map = br_untagged_bitmap[k];
-                uint32_t vid_map = br_vid_bitmap[k];
-                unsigned base_bit = k * 32;
-                int i = -1;
-
-                done = false;
-                do {
-                        int j = find_next_bit(i, vid_map);
-                        if (j > 0) {
-                                /* first hit of any bit */
-                                if (begin == UINT16_MAX && end == UINT16_MAX) {
-                                        begin = end = j - 1 + base_bit;
-                                        untagged = is_bit_set(j - 1, untagged_map);
-                                        goto next;
-                                }
-
-                                /* this bit is a continuation of prior bits */
-                                if (j - 2 + base_bit == end && untagged == is_bit_set(j - 1, untagged_map) && (uint16_t)j - 1 + base_bit != pvid && (uint16_t)begin != pvid) {
-                                        end++;
-                                        goto next;
-                                }
-                        } else
-                                done = true;
+        assert(link->network);
+        assert(m);
+
+        for (uint16_t k = 0; k < BRIDGE_VLAN_BITMAP_MAX; k++) {
 
+                if (k > 0 && k == link->network->pvid) {
+                        /* PVID needs to be sent alone. Finish previous bits. */
                         if (begin != UINT16_MAX) {
-                                cnt++;
-                                if (done && k < BRIDGE_VLAN_BITMAP_LEN - 1)
-                                        break;
-
-                                br_vlan.flags = 0;
-                                if (untagged)
-                                        br_vlan.flags |= BRIDGE_VLAN_INFO_UNTAGGED;
-
-                                if (begin == end) {
-                                        br_vlan.vid = begin;
-
-                                        if (begin == pvid)
-                                                br_vlan.flags |= BRIDGE_VLAN_INFO_PVID;
-
-                                        r = sd_netlink_message_append_data(req, IFLA_BRIDGE_VLAN_INFO, &br_vlan, sizeof(br_vlan));
-                                        if (r < 0)
-                                                return r;
-                                } else {
-                                        br_vlan.vid = begin;
-                                        br_vlan.flags |= BRIDGE_VLAN_INFO_RANGE_BEGIN;
-
-                                        r = sd_netlink_message_append_data(req, IFLA_BRIDGE_VLAN_INFO, &br_vlan, sizeof(br_vlan));
-                                        if (r < 0)
-                                                return r;
-
-                                        br_vlan.vid = end;
-                                        br_vlan.flags &= ~BRIDGE_VLAN_INFO_RANGE_BEGIN;
-                                        br_vlan.flags |= BRIDGE_VLAN_INFO_RANGE_END;
-
-                                        r = sd_netlink_message_append_data(req, IFLA_BRIDGE_VLAN_INFO, &br_vlan, sizeof(br_vlan));
-                                        if (r < 0)
-                                                return r;
-                                }
-
-                                if (done)
-                                        break;
+                                assert(begin < k);
+
+                                r = add_range(m, begin, k - 1, untagged);
+                                if (r < 0)
+                                        return r;
+
+                                begin = UINT16_MAX;
                         }
-                        if (j > 0) {
-                                begin = end = j - 1 + base_bit;
-                                untagged = is_bit_set(j - 1, untagged_map);
+
+                        untagged = is_bit_set(k, link->network->br_untagged_bitmap);
+                        r = add_single(m, k, untagged, /* is_pvid = */ true);
+                        if (r < 0)
+                                return r;
+
+                        continue;
+                }
+
+                if (!is_bit_set(k, link->network->br_vid_bitmap)) {
+                        /* This bit is not set. Finish previous bits. */
+                        if (begin != UINT16_MAX) {
+                                assert(begin < k);
+
+                                r = add_range(m, begin, k - 1, untagged);
+                                if (r < 0)
+                                        return r;
+
+                                begin = UINT16_MAX;
                         }
 
-                next:
-                        i = j;
-                } while (!done);
+                        continue;
+                }
+
+                if (begin != UINT16_MAX) {
+                        bool u;
+
+                        assert(begin < k);
+
+                        u = is_bit_set(k, link->network->br_untagged_bitmap);
+                        if (untagged == u)
+                                continue;
+
+                        /* Tagging flag is changed from the previous bits. Finish them. */
+                        r = add_range(m, begin, k - 1, untagged);
+                        if (r < 0)
+                                return r;
+
+                        begin = k;
+                        untagged = u;
+                        continue;
+                }
+
+                /* This is the starting point of a new bit sequence. Save the position and the tagging flag. */
+                begin = k;
+                untagged = is_bit_set(k, link->network->br_untagged_bitmap);
+        }
+
+        /* No pending bit sequence.
+         * Why? There is a trick. The conf parsers below only accepts vlan ID in the range 0…4094, but in
+         * the above loop, we run 0…4095. */
+        assert_cc(BRIDGE_VLAN_BITMAP_MAX > VLANID_MAX);
+        assert(begin == UINT16_MAX);
+        return 0;
+}
+
+int bridge_vlan_set_message(Link *link, sd_netlink_message *m) {
+        int r;
+
+        assert(link);
+        assert(m);
+
+        r = sd_rtnl_message_link_set_family(m, AF_BRIDGE);
+        if (r < 0)
+                return r;
+
+        r = sd_netlink_message_open_container(m, IFLA_AF_SPEC);
+        if (r < 0)
+                return r;
+
+        if (link->master_ifindex <= 0) {
+                /* master needs BRIDGE_FLAGS_SELF flag */
+                r = sd_netlink_message_append_u16(m, IFLA_BRIDGE_FLAGS, BRIDGE_FLAGS_SELF);
+                if (r < 0)
+                        return r;
         }
 
-        assert(cnt > 0);
-        return cnt;
+        r = bridge_vlan_append_set_info(link, m);
+        if (r < 0)
+                return r;
+
+        r = sd_netlink_message_close_container(m);
+        if (r < 0)
+                return r;
+
+        return 0;
 }
 
 void network_adjust_bridge_vlan(Network *network) {
index f44b8101a556d3f29f4ef7292eb2aacdadc6b547..af159e06c0e49c7014ff53548b4eeccef1c75b2d 100644 (file)
@@ -19,12 +19,7 @@ typedef struct Network Network;
 
 void network_adjust_bridge_vlan(Network *network);
 
-int bridge_vlan_append_info(
-                const Link * link,
-                sd_netlink_message *req,
-                uint16_t pvid,
-                const uint32_t *br_vid_bitmap,
-                const uint32_t *br_untagged_bitmap);
+int bridge_vlan_set_message(Link *link, sd_netlink_message *m);
 
 CONFIG_PARSER_PROTOTYPE(config_parse_brvlan_pvid);
 CONFIG_PARSER_PROTOTYPE(config_parse_brvlan_vlan);
index 541c4b8a728feba7f4fc080d19dd33b9ac922d4d..ae8db4d8c8a382aea465db2045f2403393452494 100644 (file)
@@ -326,29 +326,9 @@ static int link_configure_fill_message(
                         return r;
                 break;
         case REQUEST_TYPE_SET_LINK_BRIDGE_VLAN:
-                r = sd_rtnl_message_link_set_family(req, AF_BRIDGE);
-                if (r < 0)
-                        return r;
-
-                r = sd_netlink_message_open_container(req, IFLA_AF_SPEC);
-                if (r < 0)
-                        return r;
-
-                if (link->master_ifindex <= 0) {
-                        /* master needs BRIDGE_FLAGS_SELF flag */
-                        r = sd_netlink_message_append_u16(req, IFLA_BRIDGE_FLAGS, BRIDGE_FLAGS_SELF);
-                        if (r < 0)
-                                return r;
-                }
-
-                r = bridge_vlan_append_info(link, req, link->network->pvid, link->network->br_vid_bitmap, link->network->br_untagged_bitmap);
-                if (r < 0)
-                        return r;
-
-                r = sd_netlink_message_close_container(req);
+                r = bridge_vlan_set_message(link, req);
                 if (r < 0)
                         return r;
-
                 break;
         case REQUEST_TYPE_SET_LINK_CAN:
                 r = can_set_netlink_message(link, req);