[3.13.y.z extended stable] Patch "bridge: Check if vlan filtering is enabled only once." has been added to staging queue

Kamal Mostafa kamal at canonical.com
Fri Oct 31 20:53:21 UTC 2014

This is a note to let you know that I have just added a patch titled

    bridge: Check if vlan filtering is enabled only once.

to the linux-3.13.y-queue branch of the 3.13.y.z extended stable tree 
which can be found at:


This patch is scheduled to be released in version

If you, or anyone else, feels it should not be added to this tree, please 
reply to this email.

For more information about the 3.13.y.z tree, see



>From 8ecacb4a14abf87da4d4ef82788b3ad23c9fe665 Mon Sep 17 00:00:00 2001
From: Vlad Yasevich <vyasevich at gmail.com>
Date: Fri, 12 Sep 2014 16:26:16 -0400
Subject: bridge: Check if vlan filtering is enabled only once.

[ Upstream commit 20adfa1a81af00bf2027644507ad4fa9cd2849cf ]

The bridge code checks if vlan filtering is enabled on both
ingress and egress.   When the state flip happens, it
is possible for the bridge to currently be forwarding packets
and forwarding behavior becomes non-deterministic.  Bridge
may drop packets on some interfaces, but not others.

This patch solves this by caching the filtered state of the
packet into skb_cb on ingress.  The skb_cb is guaranteed to
not be over-written between the time packet entres bridge
forwarding path and the time it leaves it.  On egress, we
can then check the cached state to see if we need to
apply filtering information.

Signed-off-by: Vladislav Yasevich <vyasevic at redhat.com>
Signed-off-by: David S. Miller <davem at davemloft.net>
Signed-off-by: Kamal Mostafa <kamal at canonical.com>
 net/bridge/br_private.h |  3 +++
 net/bridge/br_vlan.c    | 15 +++++++++++----
 2 files changed, 14 insertions(+), 4 deletions(-)

diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 280f601..cd37763 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -309,6 +309,9 @@ struct br_input_skb_cb {
 	int igmp;
 	int mrouters_only;
+	bool vlan_filtered;

 #define BR_INPUT_SKB_CB(__skb)	((struct br_input_skb_cb *)(__skb)->cb)
diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c
index 4f5341a..f71b4d8 100644
--- a/net/bridge/br_vlan.c
+++ b/net/bridge/br_vlan.c
@@ -141,7 +141,8 @@ struct sk_buff *br_handle_vlan(struct net_bridge *br,
 	u16 vid;

-	if (!br->vlan_enabled)
+	/* If this packet was not filtered at input, let it pass */
+	if (!BR_INPUT_SKB_CB(skb)->vlan_filtered)
 		goto out;

 	/* At this point, we know that the frame was filtered and contains
@@ -186,8 +187,10 @@ bool br_allowed_ingress(struct net_bridge *br, struct net_port_vlans *v,
 	/* If VLAN filtering is disabled on the bridge, all packets are
 	 * permitted.
-	if (!br->vlan_enabled)
+	if (!br->vlan_enabled) {
+		BR_INPUT_SKB_CB(skb)->vlan_filtered = false;
 		return true;
+	}

 	/* If there are no vlan in the permitted list, all packets are
 	 * rejected.
@@ -195,6 +198,8 @@ bool br_allowed_ingress(struct net_bridge *br, struct net_port_vlans *v,
 	if (!v)
 		goto drop;

+	BR_INPUT_SKB_CB(skb)->vlan_filtered = true;
 	err = br_vlan_get_tag(skb, vid);
 	if (!*vid) {
 		u16 pvid = br_get_pvid(v);
@@ -239,7 +244,8 @@ bool br_allowed_egress(struct net_bridge *br,
 	u16 vid;

-	if (!br->vlan_enabled)
+	/* If this packet was not filtered at input, let it pass */
+	if (!BR_INPUT_SKB_CB(skb)->vlan_filtered)
 		return true;

 	if (!v)
@@ -258,7 +264,8 @@ bool br_should_learn(struct net_bridge_port *p, struct sk_buff *skb, u16 *vid)
 	struct net_bridge *br = p->br;
 	struct net_port_vlans *v;

-	if (!br->vlan_enabled)
+	/* If filtering was disabled at input, let it pass. */
+	if (!BR_INPUT_SKB_CB(skb)->vlan_filtered)
 		return true;

 	v = rcu_dereference(p->vlan_info);

More information about the kernel-team mailing list