aboutsummaryrefslogtreecommitdiffstats
path: root/net/core
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/core
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/core')
-rw-r--r--net/core/rtnetlink.c72
1 files changed, 72 insertions, 0 deletions
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