aboutsummaryrefslogtreecommitdiffstats
path: root/net
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
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')
-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
-rw-r--r--net/core/rtnetlink.c72
5 files changed, 196 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
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index c1e4db60eeca..2c9ccbfbd93c 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -2464,6 +2464,77 @@ out:
2464 return err; 2464 return err;
2465} 2465}
2466 2466
2467static int rtnl_bridge_dellink(struct sk_buff *skb, struct nlmsghdr *nlh,
2468 void *arg)
2469{
2470 struct net *net = sock_net(skb->sk);
2471 struct ifinfomsg *ifm;
2472 struct net_device *dev;
2473 struct nlattr *br_spec, *attr = NULL;
2474 int rem, err = -EOPNOTSUPP;
2475 u16 oflags, flags = 0;
2476 bool have_flags = false;
2477
2478 if (nlmsg_len(nlh) < sizeof(*ifm))
2479 return -EINVAL;
2480
2481 ifm = nlmsg_data(nlh);
2482 if (ifm->ifi_family != AF_BRIDGE)
2483 return -EPFNOSUPPORT;
2484
2485 dev = __dev_get_by_index(net, ifm->ifi_index);
2486 if (!dev) {
2487 pr_info("PF_BRIDGE: RTM_SETLINK with unknown ifindex\n");
2488 return -ENODEV;
2489 }
2490
2491 br_spec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC);
2492 if (br_spec) {
2493 nla_for_each_nested(attr, br_spec, rem) {
2494 if (nla_type(attr) == IFLA_BRIDGE_FLAGS) {
2495 have_flags = true;
2496 flags = nla_get_u16(attr);
2497 break;
2498 }
2499 }
2500 }
2501
2502 oflags = flags;
2503
2504 if (!flags || (flags & BRIDGE_FLAGS_MASTER)) {
2505 struct net_device *br_dev = netdev_master_upper_dev_get(dev);
2506
2507 if (!br_dev || !br_dev->netdev_ops->ndo_bridge_dellink) {
2508 err = -EOPNOTSUPP;
2509 goto out;
2510 }
2511
2512 err = br_dev->netdev_ops->ndo_bridge_dellink(dev, nlh);
2513 if (err)
2514 goto out;
2515
2516 flags &= ~BRIDGE_FLAGS_MASTER;
2517 }
2518
2519 if ((flags & BRIDGE_FLAGS_SELF)) {
2520 if (!dev->netdev_ops->ndo_bridge_dellink)
2521 err = -EOPNOTSUPP;
2522 else
2523 err = dev->netdev_ops->ndo_bridge_dellink(dev, nlh);
2524
2525 if (!err)
2526 flags &= ~BRIDGE_FLAGS_SELF;
2527 }
2528
2529 if (have_flags)
2530 memcpy(nla_data(attr), &flags, sizeof(flags));
2531 /* Generate event to notify upper layer of bridge change */
2532 if (!err)
2533 err = rtnl_bridge_notify(dev, oflags);
2534out:
2535 return err;
2536}
2537
2467/* Protected by RTNL sempahore. */ 2538/* Protected by RTNL sempahore. */
2468static struct rtattr **rta_buf; 2539static struct rtattr **rta_buf;
2469static int rtattr_max; 2540static int rtattr_max;
@@ -2647,6 +2718,7 @@ void __init rtnetlink_init(void)
2647 rtnl_register(PF_BRIDGE, RTM_GETNEIGH, NULL, rtnl_fdb_dump, NULL); 2718 rtnl_register(PF_BRIDGE, RTM_GETNEIGH, NULL, rtnl_fdb_dump, NULL);
2648 2719
2649 rtnl_register(PF_BRIDGE, RTM_GETLINK, NULL, rtnl_bridge_getlink, NULL); 2720 rtnl_register(PF_BRIDGE, RTM_GETLINK, NULL, rtnl_bridge_getlink, NULL);
2721 rtnl_register(PF_BRIDGE, RTM_DELLINK, rtnl_bridge_dellink, NULL, NULL);
2650 rtnl_register(PF_BRIDGE, RTM_SETLINK, rtnl_bridge_setlink, NULL, NULL); 2722 rtnl_register(PF_BRIDGE, RTM_SETLINK, rtnl_bridge_setlink, NULL, NULL);
2651} 2723}
2652 2724