bridge: fix setting pvid for updated vlans
authorFelix Fietkau <nbd@nbd.name>
Thu, 17 Jun 2021 08:39:26 +0000 (10:39 +0200)
committerFelix Fietkau <nbd@nbd.name>
Thu, 17 Jun 2021 08:39:28 +0000 (10:39 +0200)
defer adding back changed vlans until config processing is done

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

index ecb9b0373cb45a0f1a6f3286aac51277b50ab02d..f3e2fed6f8a05785fbb3a7790cdc9b8585890bdd 100644 (file)
--- a/bridge.c
+++ b/bridge.c
@@ -79,6 +79,7 @@ static const struct uci_blob_param_list bridge_attr_list = {
 static struct device *bridge_create(const char *name, struct device_type *devtype,
        struct blob_attr *attr);
 static void bridge_config_init(struct device *dev);
+static void bridge_dev_vlan_update(struct device *dev);
 static void bridge_free(struct device *dev);
 static void bridge_dump_info(struct device *dev, struct blob_buf *b);
 static enum dev_change_type
@@ -93,6 +94,7 @@ static struct device_type bridge_device_type = {
 
        .create = bridge_create,
        .config_init = bridge_config_init,
+       .vlan_update = bridge_dev_vlan_update,
        .reload = bridge_reload,
        .free = bridge_free,
        .dump_info = bridge_dump_info,
@@ -1185,7 +1187,7 @@ bridge_vlan_update(struct vlist_tree *tree, struct vlist_node *node_new,
                list_splice_init(&vlan_old->hotplug_ports, &vlan_new->hotplug_ports);
 
        if (node_new)
-               bridge_set_vlan_state(bst, vlan_new, true);
+               vlan_new->pending = true;
 
        bst->dev.config_pending = true;
 
@@ -1193,6 +1195,21 @@ out:
        bridge_vlan_free(vlan_old);
 }
 
+static void
+bridge_dev_vlan_update(struct device *dev)
+{
+       struct bridge_state *bst = container_of(dev, struct bridge_state, dev);
+       struct bridge_vlan *vlan;
+
+       vlist_for_each_element(&dev->vlans, vlan, node) {
+               if (!vlan->pending)
+                       continue;
+
+               vlan->pending = false;
+               bridge_set_vlan_state(bst, vlan, true);
+       }
+}
+
 static struct device *
 bridge_create(const char *name, struct device_type *devtype,
        struct blob_attr *attr)
index 26254cc2eb902a9b7b7a2aef97d998fbe3edbeff..9bad50734e74333cbe053c3d954b3b0d4164d82d 100644 (file)
--- a/device.c
+++ b/device.c
@@ -129,6 +129,9 @@ void device_vlan_update(bool done)
                        vlist_update(&dev->vlans);
                } else {
                        vlist_flush(&dev->vlans);
+
+                       if (dev->type->vlan_update)
+                               dev->type->vlan_update(dev);
                }
        }
 }
index c6fc02b90f523f30fde5870f805570ceacf07991..db6dc3359138633d594f5673ce8ea42c475f94b8 100644 (file)
--- a/device.h
+++ b/device.h
@@ -83,6 +83,7 @@ struct device_type {
                struct blob_attr *attr);
        void (*config_init)(struct device *);
        enum dev_change_type (*reload)(struct device *, struct blob_attr *);
+       void (*vlan_update)(struct device *);
        void (*dump_info)(struct device *, struct blob_buf *buf);
        void (*dump_stats)(struct device *, struct blob_buf *buf);
        int (*check_state)(struct device *);
@@ -277,6 +278,7 @@ struct bridge_vlan {
 
        uint16_t vid;
        bool local;
+       bool pending;
 };
 
 extern const struct uci_blob_param_list device_attr_list;