aboutsummaryrefslogtreecommitdiffstats
path: root/net/bridge
diff options
context:
space:
mode:
authorVlad Yasevich <vyasevic@redhat.com>2013-02-13 07:00:12 -0500
committerDavid S. Miller <davem@davemloft.net>2013-02-13 19:41:46 -0500
commit407af3299ef1ac7e87ce3fb530e32a009d1a9efd (patch)
tree9572e0b02eb9f6c2952b490f3a79f4b790fcea3c /net/bridge
parent85f46c6baef1486ce20e13dd7cdea5dd15be2a90 (diff)
bridge: Add netlink interface to configure vlans on bridge ports
Add a netlink interface to add and remove vlan configuration on bridge port. The interface uses the RTM_SETLINK message and encodes the vlan configuration inside the IFLA_AF_SPEC. It is possble to include multiple vlans to either add or remove in a single message. Signed-off-by: Vlad Yasevich <vyasevic@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/bridge')
-rw-r--r--net/bridge/br_device.c1
-rw-r--r--net/bridge/br_if.c1
-rw-r--r--net/bridge/br_netlink.c139
-rw-r--r--net/bridge/br_private.h1
4 files changed, 124 insertions, 18 deletions
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index 35a2c2c84f33..091bedf266a0 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -316,6 +316,7 @@ static const struct net_device_ops br_netdev_ops = {
316 .ndo_fdb_dump = br_fdb_dump, 316 .ndo_fdb_dump = br_fdb_dump,
317 .ndo_bridge_getlink = br_getlink, 317 .ndo_bridge_getlink = br_getlink,
318 .ndo_bridge_setlink = br_setlink, 318 .ndo_bridge_setlink = br_setlink,
319 .ndo_bridge_dellink = br_dellink,
319}; 320};
320 321
321static void br_dev_free(struct net_device *dev) 322static void br_dev_free(struct net_device *dev)
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index af9d65ab4001..335c60cebfd1 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -23,6 +23,7 @@
23#include <linux/if_ether.h> 23#include <linux/if_ether.h>
24#include <linux/slab.h> 24#include <linux/slab.h>
25#include <net/sock.h> 25#include <net/sock.h>
26#include <linux/if_vlan.h>
26 27
27#include "br_private.h" 28#include "br_private.h"
28 29
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
index 39ca9796f3f7..534a9f4587a9 100644
--- a/net/bridge/br_netlink.c
+++ b/net/bridge/br_netlink.c
@@ -16,6 +16,7 @@
16#include <net/rtnetlink.h> 16#include <net/rtnetlink.h>
17#include <net/net_namespace.h> 17#include <net/net_namespace.h>
18#include <net/sock.h> 18#include <net/sock.h>
19#include <uapi/linux/if_bridge.h>
19 20
20#include "br_private.h" 21#include "br_private.h"
21#include "br_private_stp.h" 22#include "br_private_stp.h"
@@ -119,10 +120,14 @@ nla_put_failure:
119 */ 120 */
120void br_ifinfo_notify(int event, struct net_bridge_port *port) 121void br_ifinfo_notify(int event, struct net_bridge_port *port)
121{ 122{
122 struct net *net = dev_net(port->dev); 123 struct net *net;
123 struct sk_buff *skb; 124 struct sk_buff *skb;
124 int err = -ENOBUFS; 125 int err = -ENOBUFS;
125 126
127 if (!port)
128 return;
129
130 net = dev_net(port->dev);
126 br_debug(port->br, "port %u(%s) event %d\n", 131 br_debug(port->br, "port %u(%s) event %d\n",
127 (unsigned int)port->port_no, port->dev->name, event); 132 (unsigned int)port->port_no, port->dev->name, event);
128 133
@@ -144,6 +149,7 @@ errout:
144 rtnl_set_sk_err(net, RTNLGRP_LINK, err); 149 rtnl_set_sk_err(net, RTNLGRP_LINK, err);
145} 150}
146 151
152
147/* 153/*
148 * Dump information about all ports, in response to GETLINK 154 * Dump information about all ports, in response to GETLINK
149 */ 155 */
@@ -162,6 +168,64 @@ out:
162 return err; 168 return err;
163} 169}
164 170
171const struct nla_policy ifla_br_policy[IFLA_MAX+1] = {
172 [IFLA_BRIDGE_FLAGS] = { .type = NLA_U16 },
173 [IFLA_BRIDGE_MODE] = { .type = NLA_U16 },
174 [IFLA_BRIDGE_VLAN_INFO] = { .type = NLA_BINARY,
175 .len = sizeof(struct bridge_vlan_info), },
176};
177
178static int br_afspec(struct net_bridge *br,
179 struct net_bridge_port *p,
180 struct nlattr *af_spec,
181 int cmd)
182{
183 struct nlattr *tb[IFLA_BRIDGE_MAX+1];
184 int err = 0;
185
186 err = nla_parse_nested(tb, IFLA_BRIDGE_MAX, af_spec, ifla_br_policy);
187 if (err)
188 return err;
189
190 if (tb[IFLA_BRIDGE_VLAN_INFO]) {
191 struct bridge_vlan_info *vinfo;
192
193 vinfo = nla_data(tb[IFLA_BRIDGE_VLAN_INFO]);
194
195 if (vinfo->vid >= VLAN_N_VID)
196 return -EINVAL;
197
198 switch (cmd) {
199 case RTM_SETLINK:
200 if (p) {
201 err = nbp_vlan_add(p, vinfo->vid);
202 if (err)
203 break;
204
205 if (vinfo->flags & BRIDGE_VLAN_INFO_MASTER)
206 err = br_vlan_add(p->br, vinfo->vid);
207 } else
208 err = br_vlan_add(br, vinfo->vid);
209
210 if (err)
211 break;
212
213 break;
214
215 case RTM_DELLINK:
216 if (p) {
217 nbp_vlan_delete(p, vinfo->vid);
218 if (vinfo->flags & BRIDGE_VLAN_INFO_MASTER)
219 br_vlan_delete(p->br, vinfo->vid);
220 } else
221 br_vlan_delete(br, vinfo->vid);
222 break;
223 }
224 }
225
226 return err;
227}
228
165static const struct nla_policy ifla_brport_policy[IFLA_BRPORT_MAX + 1] = { 229static const struct nla_policy ifla_brport_policy[IFLA_BRPORT_MAX + 1] = {
166 [IFLA_BRPORT_STATE] = { .type = NLA_U8 }, 230 [IFLA_BRPORT_STATE] = { .type = NLA_U8 },
167 [IFLA_BRPORT_COST] = { .type = NLA_U32 }, 231 [IFLA_BRPORT_COST] = { .type = NLA_U32 },
@@ -241,6 +305,7 @@ int br_setlink(struct net_device *dev, struct nlmsghdr *nlh)
241{ 305{
242 struct ifinfomsg *ifm; 306 struct ifinfomsg *ifm;
243 struct nlattr *protinfo; 307 struct nlattr *protinfo;
308 struct nlattr *afspec;
244 struct net_bridge_port *p; 309 struct net_bridge_port *p;
245 struct nlattr *tb[IFLA_BRPORT_MAX + 1]; 310 struct nlattr *tb[IFLA_BRPORT_MAX + 1];
246 int err; 311 int err;
@@ -248,38 +313,76 @@ int br_setlink(struct net_device *dev, struct nlmsghdr *nlh)
248 ifm = nlmsg_data(nlh); 313 ifm = nlmsg_data(nlh);
249 314
250 protinfo = nlmsg_find_attr(nlh, sizeof(*ifm), IFLA_PROTINFO); 315 protinfo = nlmsg_find_attr(nlh, sizeof(*ifm), IFLA_PROTINFO);
251 if (!protinfo) 316 afspec = nlmsg_find_attr(nlh, sizeof(*ifm), IFLA_AF_SPEC);
317 if (!protinfo && !afspec)
252 return 0; 318 return 0;
253 319
254 p = br_port_get_rtnl(dev); 320 p = br_port_get_rtnl(dev);
255 if (!p) 321 /* We want to accept dev as bridge itself if the AF_SPEC
322 * is set to see if someone is setting vlan info on the brigde
323 */
324 if (!p && ((dev->priv_flags & IFF_EBRIDGE) && !afspec))
256 return -EINVAL; 325 return -EINVAL;
257 326
258 if (protinfo->nla_type & NLA_F_NESTED) { 327 if (p && protinfo) {
259 err = nla_parse_nested(tb, IFLA_BRPORT_MAX, 328 if (protinfo->nla_type & NLA_F_NESTED) {
260 protinfo, ifla_brport_policy); 329 err = nla_parse_nested(tb, IFLA_BRPORT_MAX,
330 protinfo, ifla_brport_policy);
331 if (err)
332 return err;
333
334 spin_lock_bh(&p->br->lock);
335 err = br_setport(p, tb);
336 spin_unlock_bh(&p->br->lock);
337 } else {
338 /* Binary compatability with old RSTP */
339 if (nla_len(protinfo) < sizeof(u8))
340 return -EINVAL;
341
342 spin_lock_bh(&p->br->lock);
343 err = br_set_port_state(p, nla_get_u8(protinfo));
344 spin_unlock_bh(&p->br->lock);
345 }
261 if (err) 346 if (err)
262 return err; 347 goto out;
263 348 }
264 spin_lock_bh(&p->br->lock);
265 err = br_setport(p, tb);
266 spin_unlock_bh(&p->br->lock);
267 } else {
268 /* Binary compatability with old RSTP */
269 if (nla_len(protinfo) < sizeof(u8))
270 return -EINVAL;
271 349
272 spin_lock_bh(&p->br->lock); 350 if (afspec) {
273 err = br_set_port_state(p, nla_get_u8(protinfo)); 351 err = br_afspec((struct net_bridge *)netdev_priv(dev), p,
274 spin_unlock_bh(&p->br->lock); 352 afspec, RTM_SETLINK);
275 } 353 }
276 354
277 if (err == 0) 355 if (err == 0)
278 br_ifinfo_notify(RTM_NEWLINK, p); 356 br_ifinfo_notify(RTM_NEWLINK, p);
279 357
358out:
280 return err; 359 return err;
281} 360}
282 361
362/* Delete port information */
363int br_dellink(struct net_device *dev, struct nlmsghdr *nlh)
364{
365 struct ifinfomsg *ifm;
366 struct nlattr *afspec;
367 struct net_bridge_port *p;
368 int err;
369
370 ifm = nlmsg_data(nlh);
371
372 afspec = nlmsg_find_attr(nlh, sizeof(*ifm), IFLA_AF_SPEC);
373 if (!afspec)
374 return 0;
375
376 p = br_port_get_rtnl(dev);
377 /* We want to accept dev as bridge itself as well */
378 if (!p && !(dev->priv_flags & IFF_EBRIDGE))
379 return -EINVAL;
380
381 err = br_afspec((struct net_bridge *)netdev_priv(dev), p,
382 afspec, RTM_DELLINK);
383
384 return err;
385}
283static int br_validate(struct nlattr *tb[], struct nlattr *data[]) 386static int br_validate(struct nlattr *tb[], struct nlattr *data[])
284{ 387{
285 if (tb[IFLA_ADDRESS]) { 388 if (tb[IFLA_ADDRESS]) {
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index f0f24610d111..a42f9d49a64e 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -713,6 +713,7 @@ extern int br_netlink_init(void);
713extern void br_netlink_fini(void); 713extern void br_netlink_fini(void);
714extern void br_ifinfo_notify(int event, struct net_bridge_port *port); 714extern void br_ifinfo_notify(int event, struct net_bridge_port *port);
715extern int br_setlink(struct net_device *dev, struct nlmsghdr *nlmsg); 715extern int br_setlink(struct net_device *dev, struct nlmsghdr *nlmsg);
716extern int br_dellink(struct net_device *dev, struct nlmsghdr *nlmsg);
716extern int br_getlink(struct sk_buff *skb, u32 pid, u32 seq, 717extern int br_getlink(struct sk_buff *skb, u32 pid, u32 seq,
717 struct net_device *dev); 718 struct net_device *dev);
718 719