bridge: Add netlink interface to configure vlans on bridge ports
[deliverable/linux.git] / net / bridge / br_vlan.c
CommitLineData
243a2e63
VY
1#include <linux/kernel.h>
2#include <linux/netdevice.h>
3#include <linux/rtnetlink.h>
4#include <linux/slab.h>
5
6#include "br_private.h"
7
8static int __vlan_add(struct net_port_vlans *v, u16 vid)
9{
10 int err;
11
12 if (test_bit(vid, v->vlan_bitmap))
13 return -EEXIST;
14
15 if (v->port_idx && vid) {
16 struct net_device *dev = v->parent.port->dev;
17
18 /* Add VLAN to the device filter if it is supported.
19 * Stricly speaking, this is not necessary now, since devices
20 * are made promiscuous by the bridge, but if that ever changes
21 * this code will allow tagged traffic to enter the bridge.
22 */
23 if (dev->features & NETIF_F_HW_VLAN_FILTER) {
24 err = dev->netdev_ops->ndo_vlan_rx_add_vid(dev, vid);
25 if (err)
26 return err;
27 }
28 }
29
30 set_bit(vid, v->vlan_bitmap);
31 return 0;
32}
33
34static int __vlan_del(struct net_port_vlans *v, u16 vid)
35{
36 if (!test_bit(vid, v->vlan_bitmap))
37 return -EINVAL;
38
39 if (v->port_idx && vid) {
40 struct net_device *dev = v->parent.port->dev;
41
42 if (dev->features & NETIF_F_HW_VLAN_FILTER)
43 dev->netdev_ops->ndo_vlan_rx_kill_vid(dev, vid);
44 }
45
46 clear_bit(vid, v->vlan_bitmap);
47 if (bitmap_empty(v->vlan_bitmap, BR_VLAN_BITMAP_LEN)) {
48 if (v->port_idx)
49 rcu_assign_pointer(v->parent.port->vlan_info, NULL);
50 else
51 rcu_assign_pointer(v->parent.br->vlan_info, NULL);
52 kfree_rcu(v, rcu);
53 }
54 return 0;
55}
56
57static void __vlan_flush(struct net_port_vlans *v)
58{
59 bitmap_zero(v->vlan_bitmap, BR_VLAN_BITMAP_LEN);
60 if (v->port_idx)
61 rcu_assign_pointer(v->parent.port->vlan_info, NULL);
62 else
63 rcu_assign_pointer(v->parent.br->vlan_info, NULL);
64 kfree_rcu(v, rcu);
65}
66
a37b85c9
VY
67/* Called under RCU */
68bool br_allowed_ingress(struct net_bridge *br, struct net_port_vlans *v,
69 struct sk_buff *skb)
70{
71 u16 vid;
72
73 /* If VLAN filtering is disabled on the bridge, all packets are
74 * permitted.
75 */
76 if (!br->vlan_enabled)
77 return true;
78
79 /* If there are no vlan in the permitted list, all packets are
80 * rejected.
81 */
82 if (!v)
83 return false;
84
85 br_vlan_get_tag(skb, &vid);
86 if (test_bit(vid, v->vlan_bitmap))
87 return true;
88
89 return false;
90}
91
85f46c6b
VY
92/* Called under RCU. */
93bool br_allowed_egress(struct net_bridge *br,
94 const struct net_port_vlans *v,
95 const struct sk_buff *skb)
96{
97 u16 vid;
98
99 if (!br->vlan_enabled)
100 return true;
101
102 if (!v)
103 return false;
104
105 br_vlan_get_tag(skb, &vid);
106 if (test_bit(vid, v->vlan_bitmap))
107 return true;
108
109 return false;
110}
111
243a2e63
VY
112/* Must be protected by RTNL */
113int br_vlan_add(struct net_bridge *br, u16 vid)
114{
115 struct net_port_vlans *pv = NULL;
116 int err;
117
118 ASSERT_RTNL();
119
120 pv = rtnl_dereference(br->vlan_info);
121 if (pv)
122 return __vlan_add(pv, vid);
123
124 /* Create port vlan infomration
125 */
126 pv = kzalloc(sizeof(*pv), GFP_KERNEL);
127 if (!pv)
128 return -ENOMEM;
129
130 pv->parent.br = br;
131 err = __vlan_add(pv, vid);
132 if (err)
133 goto out;
134
135 rcu_assign_pointer(br->vlan_info, pv);
136 return 0;
137out:
138 kfree(pv);
139 return err;
140}
141
142/* Must be protected by RTNL */
143int br_vlan_delete(struct net_bridge *br, u16 vid)
144{
145 struct net_port_vlans *pv;
146
147 ASSERT_RTNL();
148
149 pv = rtnl_dereference(br->vlan_info);
150 if (!pv)
151 return -EINVAL;
152
153 __vlan_del(pv, vid);
154 return 0;
155}
156
157void br_vlan_flush(struct net_bridge *br)
158{
159 struct net_port_vlans *pv;
160
161 ASSERT_RTNL();
162
163 pv = rtnl_dereference(br->vlan_info);
164 if (!pv)
165 return;
166
167 __vlan_flush(pv);
168}
169
170int br_vlan_filter_toggle(struct net_bridge *br, unsigned long val)
171{
172 if (!rtnl_trylock())
173 return restart_syscall();
174
175 if (br->vlan_enabled == val)
176 goto unlock;
177
178 br->vlan_enabled = val;
179
180unlock:
181 rtnl_unlock();
182 return 0;
183}
184
185/* Must be protected by RTNL */
186int nbp_vlan_add(struct net_bridge_port *port, u16 vid)
187{
188 struct net_port_vlans *pv = NULL;
189 int err;
190
191 ASSERT_RTNL();
192
193 pv = rtnl_dereference(port->vlan_info);
194 if (pv)
195 return __vlan_add(pv, vid);
196
197 /* Create port vlan infomration
198 */
199 pv = kzalloc(sizeof(*pv), GFP_KERNEL);
200 if (!pv) {
201 err = -ENOMEM;
202 goto clean_up;
203 }
204
205 pv->port_idx = port->port_no;
206 pv->parent.port = port;
207 err = __vlan_add(pv, vid);
208 if (err)
209 goto clean_up;
210
211 rcu_assign_pointer(port->vlan_info, pv);
212 return 0;
213
214clean_up:
215 kfree(pv);
216 return err;
217}
218
219/* Must be protected by RTNL */
220int nbp_vlan_delete(struct net_bridge_port *port, u16 vid)
221{
222 struct net_port_vlans *pv;
223
224 ASSERT_RTNL();
225
226 pv = rtnl_dereference(port->vlan_info);
227 if (!pv)
228 return -EINVAL;
229
230 return __vlan_del(pv, vid);
231}
232
233void nbp_vlan_flush(struct net_bridge_port *port)
234{
235 struct net_port_vlans *pv;
236
237 ASSERT_RTNL();
238
239 pv = rtnl_dereference(port->vlan_info);
240 if (!pv)
241 return;
242
243 __vlan_flush(pv);
244}
This page took 0.032913 seconds and 5 git commands to generate.