On 03/07/2026 09:54, Luke Howard wrote:
Dynamic VLAN entries as specified in IEEE Std 802.1Q-2022,
Clause 8.8.5. These allow a user-space VLAN registration
protocol such as MVRP to mark a bridge's VLAN entries as
dynamic, so they can be distinguished from administratively
configured static entries.

Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Luke Howard <[email protected]>
---
This patch adds support for Dynamic VLAN Entries, as specified
in 802.1Q. I have marked it as RFC as a similar patch to add
support for Dynamic Reservation Entries to the FDB was rejected
on the argument that the dynamic bit should be stored separately.

Our MVRP implementation [1] will use this flag if available.

[1] https://github.com/PADL/OpenSRP

Hi,
Do this tracking entirely in your app, it doesn't bring anything to the
kernel and just adding flags because it is convenient is not acceptable.
These VLANs are the same from kernel POV and this flag doesn't change
anything functionally.
Alternatively perhaps a proto field similar to routes could help you out to
distinguish who installed a VLAN entry, not sure if that would help your
user-space app though, and you'll have to add a new rt proto id that should
get accepted.

Cheers,
 Nik

---
  include/uapi/linux/if_bridge.h |  1 +
  net/bridge/br_netlink.c        |  6 ++++++
  net/bridge/br_vlan.c           | 18 ++++++++++++++----
  3 files changed, 21 insertions(+), 4 deletions(-)

diff --git a/include/uapi/linux/if_bridge.h b/include/uapi/linux/if_bridge.h
index 21a700c02ef76..a3abbfe79694b 100644
--- a/include/uapi/linux/if_bridge.h
+++ b/include/uapi/linux/if_bridge.h
@@ -134,6 +134,7 @@ enum {
  #define BRIDGE_VLAN_INFO_RANGE_END    (1<<4) /* VLAN is end of vlan range */
  #define BRIDGE_VLAN_INFO_BRENTRY      (1<<5) /* Global bridge VLAN entry */
  #define BRIDGE_VLAN_INFO_ONLY_OPTS    (1<<6) /* Skip create/delete/flags */
+#define BRIDGE_VLAN_INFO_DYNAMIC       (1<<7) /* 802.1Q Dynamic VLAN 
Registration Entry */
struct bridge_vlan_info {
        __u16 flags;
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
index b2cd4e39326d0..90f2e103f53d5 100644
--- a/net/bridge/br_netlink.c
+++ b/net/bridge/br_netlink.c
@@ -388,6 +388,9 @@ static int br_fill_ifvlaninfo_compressed(struct sk_buff 
*skb,
                if (v->flags & BRIDGE_VLAN_INFO_UNTAGGED)
                        flags |= BRIDGE_VLAN_INFO_UNTAGGED;
+ if (v->flags & BRIDGE_VLAN_INFO_DYNAMIC)
+                       flags |= BRIDGE_VLAN_INFO_DYNAMIC;
+
                if (vid_range_start == 0) {
                        goto initvars;
                } else if ((v->vid - vid_range_end) == 1 &&
@@ -440,6 +443,9 @@ static int br_fill_ifvlaninfo(struct sk_buff *skb,
                if (v->flags & BRIDGE_VLAN_INFO_UNTAGGED)
                        vinfo.flags |= BRIDGE_VLAN_INFO_UNTAGGED;
+ if (v->flags & BRIDGE_VLAN_INFO_DYNAMIC)
+                       vinfo.flags |= BRIDGE_VLAN_INFO_DYNAMIC;
+
                if (nla_put(skb, IFLA_BRIDGE_VLAN_INFO,
                            sizeof(vinfo), &vinfo))
                        goto nla_put_failure;
diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c
index 5560afcaaca32..e6bc59e3a4c4f 100644
--- a/net/bridge/br_vlan.c
+++ b/net/bridge/br_vlan.c
@@ -54,9 +54,11 @@ static void __vlan_delete_pvid(struct net_bridge_vlan_group 
*vg, u16 vid)
        vg->pvid = 0;
  }
-/* Update the BRIDGE_VLAN_INFO_PVID and BRIDGE_VLAN_INFO_UNTAGGED flags of @v.
- * If @commit is false, return just whether the BRIDGE_VLAN_INFO_PVID and
- * BRIDGE_VLAN_INFO_UNTAGGED bits of @flags would produce any change onto @v.
+/* Update the BRIDGE_VLAN_INFO_PVID, BRIDGE_VLAN_INFO_UNTAGGED and
+ * BRIDGE_VLAN_INFO_DYNAMIC flags of @v.
+ * If @commit is false, return just whether the BRIDGE_VLAN_INFO_PVID,
+ * BRIDGE_VLAN_INFO_UNTAGGED and BRIDGE_VLAN_INFO_DYNAMIC bits of @flags
+ * would produce any change onto @v.
   */
  static bool __vlan_flags_update(struct net_bridge_vlan *v, u16 flags,
                                bool commit)
@@ -71,7 +73,8 @@ static bool __vlan_flags_update(struct net_bridge_vlan *v, 
u16 flags,
/* check if anything would be changed on commit */
        change = !!(flags & BRIDGE_VLAN_INFO_PVID) == !!(vg->pvid != v->vid) ||
-                ((flags ^ v->flags) & BRIDGE_VLAN_INFO_UNTAGGED);
+                ((flags ^ v->flags) & (BRIDGE_VLAN_INFO_UNTAGGED |
+                                       BRIDGE_VLAN_INFO_DYNAMIC));
if (!commit)
                goto out;
@@ -86,6 +89,11 @@ static bool __vlan_flags_update(struct net_bridge_vlan *v, 
u16 flags,
        else
                v->flags &= ~BRIDGE_VLAN_INFO_UNTAGGED;
+ if (flags & BRIDGE_VLAN_INFO_DYNAMIC)
+               v->flags |= BRIDGE_VLAN_INFO_DYNAMIC;
+       else
+               v->flags &= ~BRIDGE_VLAN_INFO_DYNAMIC;
+
  out:
        return change;
  }
@@ -1874,6 +1882,8 @@ static bool br_vlan_fill_vids(struct sk_buff *skb, u16 
vid, u16 vid_range,
                info.flags |= BRIDGE_VLAN_INFO_UNTAGGED;
        if (flags & BRIDGE_VLAN_INFO_PVID)
                info.flags |= BRIDGE_VLAN_INFO_PVID;
+       if (flags & BRIDGE_VLAN_INFO_DYNAMIC)
+               info.flags |= BRIDGE_VLAN_INFO_DYNAMIC;
if (nla_put(skb, BRIDGE_VLANDB_ENTRY_INFO, sizeof(info), &info))
                goto out_err;

---
base-commit: 2bb62a85aff6d4c14a62a476dfabaada3c1cc014
change-id: 20260703-vlan-dynamic-entry-56a028e8990e

Best regards,
--
Luke Howard <[email protected]>



Reply via email to