aboutsummaryrefslogtreecommitdiffstats
path: root/net/bridge
diff options
context:
space:
mode:
authorVlad Yasevich <vyasevich@gmail.com>2014-09-12 16:26:16 -0400
committerDavid S. Miller <davem@davemloft.net>2014-09-13 17:21:56 -0400
commit20adfa1a81af00bf2027644507ad4fa9cd2849cf (patch)
tree9a3a341354ecc5645ac36c583aa71b7beaba9f27 /net/bridge
parent9a72c2da690d78e93cff24b9f616412508678dd5 (diff)
bridge: Check if vlan filtering is enabled only once.
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@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/bridge')
-rw-r--r--net/bridge/br_private.h3
-rw-r--r--net/bridge/br_vlan.c14
2 files changed, 13 insertions, 4 deletions
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 62a7fa2e3569..b6c04cbcfdc5 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -309,6 +309,9 @@ struct br_input_skb_cb {
309 int igmp; 309 int igmp;
310 int mrouters_only; 310 int mrouters_only;
311#endif 311#endif
312#ifdef CONFIG_BRIDGE_VLAN_FILTERING
313 bool vlan_filtered;
314#endif
312}; 315};
313 316
314#define BR_INPUT_SKB_CB(__skb) ((struct br_input_skb_cb *)(__skb)->cb) 317#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 e1bcd653899b..f645197b33d1 100644
--- a/net/bridge/br_vlan.c
+++ b/net/bridge/br_vlan.c
@@ -125,7 +125,8 @@ struct sk_buff *br_handle_vlan(struct net_bridge *br,
125{ 125{
126 u16 vid; 126 u16 vid;
127 127
128 if (!br->vlan_enabled) 128 /* If this packet was not filtered at input, let it pass */
129 if (!BR_INPUT_SKB_CB(skb)->vlan_filtered)
129 goto out; 130 goto out;
130 131
131 /* Vlan filter table must be configured at this point. The 132 /* Vlan filter table must be configured at this point. The
@@ -164,8 +165,10 @@ bool br_allowed_ingress(struct net_bridge *br, struct net_port_vlans *v,
164 /* If VLAN filtering is disabled on the bridge, all packets are 165 /* If VLAN filtering is disabled on the bridge, all packets are
165 * permitted. 166 * permitted.
166 */ 167 */
167 if (!br->vlan_enabled) 168 if (!br->vlan_enabled) {
169 BR_INPUT_SKB_CB(skb)->vlan_filtered = false;
168 return true; 170 return true;
171 }
169 172
170 /* If there are no vlan in the permitted list, all packets are 173 /* If there are no vlan in the permitted list, all packets are
171 * rejected. 174 * rejected.
@@ -173,6 +176,7 @@ bool br_allowed_ingress(struct net_bridge *br, struct net_port_vlans *v,
173 if (!v) 176 if (!v)
174 goto drop; 177 goto drop;
175 178
179 BR_INPUT_SKB_CB(skb)->vlan_filtered = true;
176 proto = br->vlan_proto; 180 proto = br->vlan_proto;
177 181
178 /* If vlan tx offload is disabled on bridge device and frame was 182 /* If vlan tx offload is disabled on bridge device and frame was
@@ -251,7 +255,8 @@ bool br_allowed_egress(struct net_bridge *br,
251{ 255{
252 u16 vid; 256 u16 vid;
253 257
254 if (!br->vlan_enabled) 258 /* If this packet was not filtered at input, let it pass */
259 if (!BR_INPUT_SKB_CB(skb)->vlan_filtered)
255 return true; 260 return true;
256 261
257 if (!v) 262 if (!v)
@@ -270,7 +275,8 @@ bool br_should_learn(struct net_bridge_port *p, struct sk_buff *skb, u16 *vid)
270 struct net_bridge *br = p->br; 275 struct net_bridge *br = p->br;
271 struct net_port_vlans *v; 276 struct net_port_vlans *v;
272 277
273 if (!br->vlan_enabled) 278 /* If filtering was disabled at input, let it pass. */
279 if (!BR_INPUT_SKB_CB(skb)->vlan_filtered)
274 return true; 280 return true;
275 281
276 v = rcu_dereference(p->vlan_info); 282 v = rcu_dereference(p->vlan_info);