bridge: only overwrite implicit vlan assignment if vlans are configured
authorFelix Fietkau <nbd@nbd.name>
Thu, 5 Nov 2020 11:00:12 +0000 (12:00 +0100)
committerFelix Fietkau <nbd@nbd.name>
Thu, 5 Nov 2020 11:03:49 +0000 (12:03 +0100)
When VLAN filtering is enabled, but no vlans are defined, the implicit
VLANs should stay, so that forwarding between ports still works.
This is useful for setups where VLANs are assigned by external scripts
instead of being configured via netifd

Signed-off-by: Felix Fietkau <nbd@nbd.name>
bridge.c
config.c

index eebd8e9df98b10c3bf2be31c24f0ca21578d4a7f..3f8f9a82afb14a18c9daa95c0ede9a4aff1cd4d8 100644 (file)
--- a/bridge.c
+++ b/bridge.c
@@ -39,6 +39,7 @@ enum {
        BRIDGE_ATTR_QUERY_RESPONSE_INTERVAL,
        BRIDGE_ATTR_LAST_MEMBER_INTERVAL,
        BRIDGE_ATTR_VLAN_FILTERING,
+       BRIDGE_ATTR_HAS_VLANS,
        __BRIDGE_ATTR_MAX
 };
 
@@ -59,6 +60,7 @@ static const struct blobmsg_policy bridge_attrs[__BRIDGE_ATTR_MAX] = {
        [BRIDGE_ATTR_QUERY_RESPONSE_INTERVAL] = { "query_response_interval", BLOBMSG_TYPE_INT32 },
        [BRIDGE_ATTR_LAST_MEMBER_INTERVAL] = { "last_member_interval", BLOBMSG_TYPE_INT32 },
        [BRIDGE_ATTR_VLAN_FILTERING] = { "vlan_filtering", BLOBMSG_TYPE_BOOL },
+       [BRIDGE_ATTR_HAS_VLANS] = { "__has_vlans", BLOBMSG_TYPE_BOOL }, /* internal */
 };
 
 static const struct uci_blob_param_info bridge_attr_info[__BRIDGE_ATTR_MAX] = {
@@ -105,6 +107,7 @@ struct bridge_state {
        struct blob_attr *ifnames;
        bool active;
        bool force_active;
+       bool has_vlans;
 
        struct uloop_timeout retry;
        struct bridge_member *primary_port;
@@ -327,7 +330,7 @@ bridge_enable_interface(struct bridge_state *bst)
        if (ret < 0)
                return ret;
 
-       if (bst->config.vlan_filtering) {
+       if (bst->has_vlans) {
                /* delete default VLAN 1 */
                system_bridge_vlan(bst->dev.ifname, 1, false, BRVLAN_F_SELF);
 
@@ -378,7 +381,7 @@ bridge_enable_member(struct bridge_member *bm)
                goto error;
        }
 
-       if (bst->config.vlan_filtering) {
+       if (bst->has_vlans) {
                /* delete default VLAN 1 */
                system_bridge_vlan(bm->dev.dev->ifname, 1, false, 0);
 
@@ -539,6 +542,7 @@ bridge_set_up(struct bridge_state *bst)
        struct bridge_member *bm;
        int ret;
 
+       bst->has_vlans = !avl_is_empty(&bst->dev.vlans.avl);
        if (!bst->n_present) {
                if (!bst->force_active)
                        return -ENOENT;
@@ -1056,7 +1060,7 @@ bridge_vlan_update(struct vlist_tree *tree, struct vlist_node *node_new,
        struct bridge_state *bst = container_of(tree, struct bridge_state, dev.vlans);
        struct bridge_vlan *vlan_new = NULL, *vlan_old = NULL;
 
-       if (!bst->config.vlan_filtering || !bst->active)
+       if (!bst->has_vlans || !bst->active)
                goto out;
 
        if (node_old)
index 3546787e46f508c1a6d5687ef13cbe852a208e89..8122a955a5f388604d57631498e1812fbe1b38e5 100644 (file)
--- a/config.c
+++ b/config.c
@@ -76,18 +76,15 @@ config_bridge_has_vlans(const char *br_name)
 }
 
 static void
-config_fixup_bridge_vlan_filtering(struct uci_section *s, const char *name)
+config_fixup_bridge_var(struct uci_section *s, const char *name, const char *val)
 {
        struct uci_ptr ptr = {
                .p = s->package,
                .s = s,
-               .option = "vlan_filtering",
-               .value = "1",
+               .option = name,
+               .value = val,
        };
 
-       if (!config_bridge_has_vlans(name))
-               return;
-
        uci_lookup_ptr(uci_ctx, &ptr, NULL, false);
        if (ptr.o)
                return;
@@ -95,6 +92,19 @@ config_fixup_bridge_vlan_filtering(struct uci_section *s, const char *name)
        uci_set(uci_ctx, &ptr);
 }
 
+static void
+config_fixup_bridge_vlan_filtering(struct uci_section *s, const char *name)
+{
+       bool has_vlans = config_bridge_has_vlans(name);
+
+       config_fixup_bridge_var(s, "__has_vlans", has_vlans ? "1" : "0");
+
+       if (!has_vlans)
+               return;
+
+       config_fixup_bridge_var(s, "vlan_filtering", "1");
+}
+
 static int
 config_parse_bridge_interface(struct uci_section *s, struct device_type *devtype)
 {