aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorVlad Yasevich <vyasevic@redhat.com>2013-02-13 07:00:14 -0500
committerDavid S. Miller <davem@davemloft.net>2013-02-13 19:42:15 -0500
commit7885198861fc9a3dfdc6bb90dc0ba12689d6cd57 (patch)
treea75ed0f9b3fe72be08dcb13216c87f4f8e37bb75 /net
parent6cbdceeb1cb12c7d620161925a8c3e81daadb2e4 (diff)
bridge: Implement vlan ingress/egress policy with PVID.
At ingress, any untagged traffic is assigned to the PVID. Any tagged traffic is filtered according to membership bitmap. At egress, if the vlan matches the PVID, the frame is sent untagged. Otherwise the frame is sent tagged. Signed-off-by: Vlad Yasevich <vyasevic@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/8021q/vlan_core.c1
-rw-r--r--net/bridge/br_device.c3
-rw-r--r--net/bridge/br_forward.c8
-rw-r--r--net/bridge/br_input.c7
-rw-r--r--net/bridge/br_private.h34
-rw-r--r--net/bridge/br_vlan.c83
6 files changed, 126 insertions, 10 deletions
diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c
index 71b64fde8dc9..f3b6f515eba6 100644
--- a/net/8021q/vlan_core.c
+++ b/net/8021q/vlan_core.c
@@ -144,6 +144,7 @@ err_free:
144 kfree_skb(skb); 144 kfree_skb(skb);
145 return NULL; 145 return NULL;
146} 146}
147EXPORT_SYMBOL(vlan_untag);
147 148
148 149
149/* 150/*
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index 091bedf266a0..9509139da49c 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -30,6 +30,7 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
30 struct net_bridge_fdb_entry *dst; 30 struct net_bridge_fdb_entry *dst;
31 struct net_bridge_mdb_entry *mdst; 31 struct net_bridge_mdb_entry *mdst;
32 struct br_cpu_netstats *brstats = this_cpu_ptr(br->stats); 32 struct br_cpu_netstats *brstats = this_cpu_ptr(br->stats);
33 u16 vid = 0;
33 34
34 rcu_read_lock(); 35 rcu_read_lock();
35#ifdef CONFIG_BRIDGE_NETFILTER 36#ifdef CONFIG_BRIDGE_NETFILTER
@@ -45,7 +46,7 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
45 brstats->tx_bytes += skb->len; 46 brstats->tx_bytes += skb->len;
46 u64_stats_update_end(&brstats->syncp); 47 u64_stats_update_end(&brstats->syncp);
47 48
48 if (!br_allowed_ingress(br, br_get_vlan_info(br), skb)) 49 if (!br_allowed_ingress(br, br_get_vlan_info(br), skb, &vid))
49 goto out; 50 goto out;
50 51
51 BR_INPUT_SKB_CB(skb)->brdev = dev; 52 BR_INPUT_SKB_CB(skb)->brdev = dev;
diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c
index 35b0671f135d..092b20e4ee4c 100644
--- a/net/bridge/br_forward.c
+++ b/net/bridge/br_forward.c
@@ -64,6 +64,10 @@ int br_forward_finish(struct sk_buff *skb)
64 64
65static void __br_deliver(const struct net_bridge_port *to, struct sk_buff *skb) 65static void __br_deliver(const struct net_bridge_port *to, struct sk_buff *skb)
66{ 66{
67 skb = br_handle_vlan(to->br, nbp_get_vlan_info(to), skb);
68 if (!skb)
69 return;
70
67 skb->dev = to->dev; 71 skb->dev = to->dev;
68 72
69 if (unlikely(netpoll_tx_running(to->br->dev))) { 73 if (unlikely(netpoll_tx_running(to->br->dev))) {
@@ -89,6 +93,10 @@ static void __br_forward(const struct net_bridge_port *to, struct sk_buff *skb)
89 return; 93 return;
90 } 94 }
91 95
96 skb = br_handle_vlan(to->br, nbp_get_vlan_info(to), skb);
97 if (!skb)
98 return;
99
92 indev = skb->dev; 100 indev = skb->dev;
93 skb->dev = to->dev; 101 skb->dev = to->dev;
94 skb_forward_csum(skb); 102 skb_forward_csum(skb);
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
index 787d7dad6b7e..a63f227ad963 100644
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -45,6 +45,10 @@ static int br_pass_frame_up(struct sk_buff *skb)
45 return NET_RX_DROP; 45 return NET_RX_DROP;
46 } 46 }
47 47
48 skb = br_handle_vlan(br, br_get_vlan_info(br), skb);
49 if (!skb)
50 return NET_RX_DROP;
51
48 indev = skb->dev; 52 indev = skb->dev;
49 skb->dev = brdev; 53 skb->dev = brdev;
50 54
@@ -61,11 +65,12 @@ int br_handle_frame_finish(struct sk_buff *skb)
61 struct net_bridge_fdb_entry *dst; 65 struct net_bridge_fdb_entry *dst;
62 struct net_bridge_mdb_entry *mdst; 66 struct net_bridge_mdb_entry *mdst;
63 struct sk_buff *skb2; 67 struct sk_buff *skb2;
68 u16 vid = 0;
64 69
65 if (!p || p->state == BR_STATE_DISABLED) 70 if (!p || p->state == BR_STATE_DISABLED)
66 goto drop; 71 goto drop;
67 72
68 if (!br_allowed_ingress(p->br, nbp_get_vlan_info(p), skb)) 73 if (!br_allowed_ingress(p->br, nbp_get_vlan_info(p), skb, &vid))
69 goto drop; 74 goto drop;
70 75
71 /* insert into forwarding database after filtering to avoid spoofing */ 76 /* insert into forwarding database after filtering to avoid spoofing */
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index ce2235255c2f..ea8e7efd9137 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -67,6 +67,7 @@ struct br_ip
67 67
68struct net_port_vlans { 68struct net_port_vlans {
69 u16 port_idx; 69 u16 port_idx;
70 u16 pvid;
70 union { 71 union {
71 struct net_bridge_port *port; 72 struct net_bridge_port *port;
72 struct net_bridge *br; 73 struct net_bridge *br;
@@ -554,10 +555,13 @@ static inline void br_mdb_uninit(void)
554/* br_vlan.c */ 555/* br_vlan.c */
555#ifdef CONFIG_BRIDGE_VLAN_FILTERING 556#ifdef CONFIG_BRIDGE_VLAN_FILTERING
556extern bool br_allowed_ingress(struct net_bridge *br, struct net_port_vlans *v, 557extern bool br_allowed_ingress(struct net_bridge *br, struct net_port_vlans *v,
557 struct sk_buff *skb); 558 struct sk_buff *skb, u16 *vid);
558extern bool br_allowed_egress(struct net_bridge *br, 559extern bool br_allowed_egress(struct net_bridge *br,
559 const struct net_port_vlans *v, 560 const struct net_port_vlans *v,
560 const struct sk_buff *skb); 561 const struct sk_buff *skb);
562extern struct sk_buff *br_handle_vlan(struct net_bridge *br,
563 const struct net_port_vlans *v,
564 struct sk_buff *skb);
561extern int br_vlan_add(struct net_bridge *br, u16 vid); 565extern int br_vlan_add(struct net_bridge *br, u16 vid);
562extern int br_vlan_delete(struct net_bridge *br, u16 vid); 566extern int br_vlan_delete(struct net_bridge *br, u16 vid);
563extern void br_vlan_flush(struct net_bridge *br); 567extern void br_vlan_flush(struct net_bridge *br);
@@ -594,10 +598,23 @@ static inline int br_vlan_get_tag(const struct sk_buff *skb, u16 *vid)
594 598
595 return err; 599 return err;
596} 600}
601
602static inline u16 br_get_pvid(const struct net_port_vlans *v)
603{
604 /* Return just the VID if it is set, or VLAN_N_VID (invalid vid) if
605 * vid wasn't set
606 */
607 smp_rmb();
608 return (v->pvid & VLAN_TAG_PRESENT) ?
609 (v->pvid & ~VLAN_TAG_PRESENT) :
610 VLAN_N_VID;
611}
612
597#else 613#else
598static inline bool br_allowed_ingress(struct net_bridge *br, 614static inline bool br_allowed_ingress(struct net_bridge *br,
599 struct net_port_vlans *v, 615 struct net_port_vlans *v,
600 struct sk_buff *skb) 616 struct sk_buff *skb,
617 u16 *vid)
601{ 618{
602 return true; 619 return true;
603} 620}
@@ -609,6 +626,13 @@ static inline bool br_allowed_egress(struct net_bridge *br,
609 return true; 626 return true;
610} 627}
611 628
629static inline struct sk_buff *br_handle_vlan(struct net_bridge *br,
630 const struct net_port_vlans *v,
631 struct sk_buff *skb)
632{
633 return skb;
634}
635
612static inline int br_vlan_add(struct net_bridge *br, u16 vid) 636static inline int br_vlan_add(struct net_bridge *br, u16 vid)
613{ 637{
614 return -EOPNOTSUPP; 638 return -EOPNOTSUPP;
@@ -648,10 +672,14 @@ static inline struct net_port_vlans *nbp_get_vlan_info(
648 return NULL; 672 return NULL;
649} 673}
650 674
651static inline u16 br_vlan_get_tag(const struct sk_buff *skb) 675static inline u16 br_vlan_get_tag(const struct sk_buff *skb, u16 *tag)
652{ 676{
653 return 0; 677 return 0;
654} 678}
679static inline u16 br_get_pvid(const struct net_port_vlans *v)
680{
681 return VLAN_N_VID; /* Returns invalid vid */
682}
655#endif 683#endif
656 684
657/* br_netfilter.c */ 685/* br_netfilter.c */
diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c
index f2bf5a197ea3..20057de56db0 100644
--- a/net/bridge/br_vlan.c
+++ b/net/bridge/br_vlan.c
@@ -66,12 +66,68 @@ static void __vlan_flush(struct net_port_vlans *v)
66 kfree_rcu(v, rcu); 66 kfree_rcu(v, rcu);
67} 67}
68 68
69/* Called under RCU */ 69/* Strip the tag from the packet. Will return skb with tci set 0. */
70bool br_allowed_ingress(struct net_bridge *br, struct net_port_vlans *v, 70static struct sk_buff *br_vlan_untag(struct sk_buff *skb)
71 struct sk_buff *skb) 71{
72 if (skb->protocol != htons(ETH_P_8021Q)) {
73 skb->vlan_tci = 0;
74 return skb;
75 }
76
77 skb->vlan_tci = 0;
78 skb = vlan_untag(skb);
79 if (skb)
80 skb->vlan_tci = 0;
81
82 return skb;
83}
84
85struct sk_buff *br_handle_vlan(struct net_bridge *br,
86 const struct net_port_vlans *pv,
87 struct sk_buff *skb)
72{ 88{
73 u16 vid; 89 u16 vid;
74 90
91 if (!br->vlan_enabled)
92 goto out;
93
94 /* At this point, we know that the frame was filtered and contains
95 * a valid vlan id. If the vlan id matches the pvid of current port
96 * send untagged; otherwise, send taged.
97 */
98 br_vlan_get_tag(skb, &vid);
99 if (vid == br_get_pvid(pv))
100 skb = br_vlan_untag(skb);
101 else {
102 /* Egress policy says "send tagged". If output device
103 * is the bridge, we need to add the VLAN header
104 * ourselves since we'll be going through the RX path.
105 * Sending to ports puts the frame on the TX path and
106 * we let dev_hard_start_xmit() add the header.
107 */
108 if (skb->protocol != htons(ETH_P_8021Q) &&
109 pv->port_idx == 0) {
110 /* vlan_put_tag expects skb->data to point to
111 * mac header.
112 */
113 skb_push(skb, ETH_HLEN);
114 skb = __vlan_put_tag(skb, skb->vlan_tci);
115 if (!skb)
116 goto out;
117 /* put skb->data back to where it was */
118 skb_pull(skb, ETH_HLEN);
119 skb->vlan_tci = 0;
120 }
121 }
122
123out:
124 return skb;
125}
126
127/* Called under RCU */
128bool br_allowed_ingress(struct net_bridge *br, struct net_port_vlans *v,
129 struct sk_buff *skb, u16 *vid)
130{
75 /* If VLAN filtering is disabled on the bridge, all packets are 131 /* If VLAN filtering is disabled on the bridge, all packets are
76 * permitted. 132 * permitted.
77 */ 133 */
@@ -84,8 +140,25 @@ bool br_allowed_ingress(struct net_bridge *br, struct net_port_vlans *v,
84 if (!v) 140 if (!v)
85 return false; 141 return false;
86 142
87 br_vlan_get_tag(skb, &vid); 143 if (br_vlan_get_tag(skb, vid)) {
88 if (test_bit(vid, v->vlan_bitmap)) 144 u16 pvid = br_get_pvid(v);
145
146 /* Frame did not have a tag. See if pvid is set
147 * on this port. That tells us which vlan untagged
148 * traffic belongs to.
149 */
150 if (pvid == VLAN_N_VID)
151 return false;
152
153 /* PVID is set on this port. Any untagged ingress
154 * frame is considered to belong to this vlan.
155 */
156 __vlan_hwaccel_put_tag(skb, pvid);
157 return true;
158 }
159
160 /* Frame had a valid vlan tag. See if vlan is allowed */
161 if (test_bit(*vid, v->vlan_bitmap))
89 return true; 162 return true;
90 163
91 return false; 164 return false;