summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFelix Fietkau2023-12-05 11:37:50 +0000
committerFelix Fietkau2023-12-05 11:59:05 +0000
commitcc9e928f0a12f04c82356c02dd9a84ac6b383fb9 (patch)
tree537e864d9f58e02d5dccdb96cc8492921cd545c2
parentf1763852dfbabf60486bd721ec7a6a1bc8dd88c0 (diff)
downloadnetifd-cc9e928f0a12f04c82356c02dd9a84ac6b383fb9.tar.gz
bridge: rework config change pvid handling
Fix issues when a member port is moved from one VLAN to another Signed-off-by: Felix Fietkau <nbd@nbd.name>
-rw-r--r--bridge.c25
1 files changed, 14 insertions, 11 deletions
diff --git a/bridge.c b/bridge.c
index f400743..2128ec7 100644
--- a/bridge.c
+++ b/bridge.c
@@ -223,7 +223,9 @@ bridge_set_member_vlan(struct bridge_member *bm, struct bridge_vlan *vlan, bool
if (!port)
return;
- if (bridge_member_vlan_is_pvid(bm, port))
+ if (!add && bm->pvid == vlan->vid)
+ bm->pvid = 0;
+ else if (add && bridge_member_vlan_is_pvid(bm, port))
bm->pvid = vlan->vid;
__bridge_set_member_vlan(bm, vlan, port, add);
@@ -275,12 +277,12 @@ bridge_set_vlan_state(struct bridge_state *bst, struct bridge_vlan *vlan, bool a
{
struct bridge_member *bm;
struct bridge_vlan *vlan2;
+ bool clear_pvid = false;
bridge_set_local_vlan(bst, vlan, add);
vlist_for_each_element(&bst->members, bm, node) {
struct bridge_vlan_port *port;
- int new_pvid = -1;
port = bridge_find_vlan_member_port(bm, vlan);
if (!port)
@@ -293,17 +295,18 @@ bridge_set_vlan_state(struct bridge_state *bst, struct bridge_vlan *vlan, bool a
vlan2 = bridge_recalc_member_pvid(bm);
if (vlan2 && vlan2->vid != vlan->vid) {
bridge_set_member_vlan(bm, vlan2, false);
+ bm->pvid = vlan2->vid;
bridge_set_member_vlan(bm, vlan2, true);
+ } else if (!vlan2) {
+ clear_pvid = true;
}
- new_pvid = vlan2 ? vlan2->vid : 0;
}
- if (!bm->present)
- continue;
+ if (bm->present)
+ __bridge_set_member_vlan(bm, vlan, port, add);
- __bridge_set_member_vlan(bm, vlan, port, add);
- if (new_pvid >= 0)
- bm->pvid = new_pvid;
+ if (clear_pvid)
+ bm->pvid = 0;
}
}
@@ -1369,14 +1372,14 @@ 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->has_vlans || !bst->active)
- goto out;
-
if (node_old)
vlan_old = container_of(node_old, struct bridge_vlan, node);
if (node_new)
vlan_new = container_of(node_new, struct bridge_vlan, node);
+ if (!bst->has_vlans || !bst->active)
+ goto out;
+
if (node_new && node_old && bridge_vlan_equal(vlan_old, vlan_new)) {
list_splice_init(&vlan_old->hotplug_ports, &vlan_new->hotplug_ports);
goto out;