aboutsummaryrefslogtreecommitdiffstats
path: root/net/core
diff options
context:
space:
mode:
authorJohn Fastabend <john.r.fastabend@intel.com>2012-10-24 04:13:03 -0400
committerDavid S. Miller <davem@davemloft.net>2012-10-31 13:18:29 -0400
commit2469ffd723f76ac2d3ce3d4f31ee31ee0a06cd38 (patch)
treed385b74ac144c06e11e70e2ace08b00b3433d77f /net/core
parente5a55a898720096f43bc24938f8875c0a1b34cd7 (diff)
net: set and query VEB/VEPA bridge mode via PF_BRIDGE
Hardware switches may support enabling and disabling the loopback switch which puts the device in a VEPA mode defined in the IEEE 802.1Qbg specification. In this mode frames are not switched in the hardware but sent directly to the switch. SR-IOV capable NICs will likely support this mode I am aware of at least two such devices. Also I am told (but don't have any of this hardware available) that there are devices that only support VEPA modes. In these cases it is important at a minimum to be able to query these attributes. This patch adds an additional IFLA_BRIDGE_MODE attribute that can be set and dumped via the PF_BRIDGE:{SET|GET}LINK operations. Also anticipating bridge attributes that may be common for both embedded bridges and software bridges this adds a flags attribute IFLA_BRIDGE_FLAGS currently used to determine if the command or event is being generated to/from an embedded bridge or software bridge. Finally, the event generation is pulled out of the bridge module and into rtnetlink proper. For example using the macvlan driver in VEPA mode on top of an embedded switch requires putting the embedded switch into a VEPA mode to get the expected results. -------- -------- | VEPA | | VEPA | <-- macvlan vepa edge relays -------- -------- | | | | ------------------ | VEPA | <-- embedded switch in NIC ------------------ | | ------------------- | external switch | <-- shiny new physical ------------------- switch with VEPA support A packet sent from the macvlan VEPA at the top could be loopbacked on the embedded switch and never seen by the external switch. So in order for this to work the embedded switch needs to be set in the VEPA state via the above described commands. By making these attributes nested in IFLA_AF_SPEC we allow future extensions to be made as needed. CC: Lennert Buytenhek <buytenh@wantstofly.org> CC: Stephen Hemminger <shemminger@vyatta.com> Signed-off-by: John Fastabend <john.r.fastabend@intel.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/core')
-rw-r--r--net/core/rtnetlink.c85
1 files changed, 81 insertions, 4 deletions
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index a068666b322f..8d2af0f77d36 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -2295,13 +2295,60 @@ static int rtnl_bridge_getlink(struct sk_buff *skb, struct netlink_callback *cb)
2295 return skb->len; 2295 return skb->len;
2296} 2296}
2297 2297
2298static inline size_t bridge_nlmsg_size(void)
2299{
2300 return NLMSG_ALIGN(sizeof(struct ifinfomsg))
2301 + nla_total_size(IFNAMSIZ) /* IFLA_IFNAME */
2302 + nla_total_size(MAX_ADDR_LEN) /* IFLA_ADDRESS */
2303 + nla_total_size(sizeof(u32)) /* IFLA_MASTER */
2304 + nla_total_size(sizeof(u32)) /* IFLA_MTU */
2305 + nla_total_size(sizeof(u32)) /* IFLA_LINK */
2306 + nla_total_size(sizeof(u32)) /* IFLA_OPERSTATE */
2307 + nla_total_size(sizeof(u8)) /* IFLA_PROTINFO */
2308 + nla_total_size(sizeof(struct nlattr)) /* IFLA_AF_SPEC */
2309 + nla_total_size(sizeof(u16)) /* IFLA_BRIDGE_FLAGS */
2310 + nla_total_size(sizeof(u16)); /* IFLA_BRIDGE_MODE */
2311}
2312
2313static int rtnl_bridge_notify(struct net_device *dev, u16 flags)
2314{
2315 struct net *net = dev_net(dev);
2316 struct net_device *master = dev->master;
2317 struct sk_buff *skb;
2318 int err = -EOPNOTSUPP;
2319
2320 skb = nlmsg_new(bridge_nlmsg_size(), GFP_ATOMIC);
2321 if (!skb) {
2322 err = -ENOMEM;
2323 goto errout;
2324 }
2325
2326 if (!flags && master && master->netdev_ops->ndo_bridge_getlink)
2327 err = master->netdev_ops->ndo_bridge_getlink(skb, 0, 0, dev);
2328 else if (dev->netdev_ops->ndo_bridge_getlink)
2329 err = dev->netdev_ops->ndo_bridge_getlink(skb, 0, 0, dev);
2330
2331 if (err < 0)
2332 goto errout;
2333
2334 rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC);
2335 return 0;
2336errout:
2337 WARN_ON(err == -EMSGSIZE);
2338 kfree_skb(skb);
2339 rtnl_set_sk_err(net, RTNLGRP_LINK, err);
2340 return err;
2341}
2342
2298static int rtnl_bridge_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, 2343static int rtnl_bridge_setlink(struct sk_buff *skb, struct nlmsghdr *nlh,
2299 void *arg) 2344 void *arg)
2300{ 2345{
2301 struct net *net = sock_net(skb->sk); 2346 struct net *net = sock_net(skb->sk);
2302 struct ifinfomsg *ifm; 2347 struct ifinfomsg *ifm;
2303 struct net_device *dev; 2348 struct net_device *dev;
2304 int err = -EINVAL; 2349 struct nlattr *br_spec, *attr = NULL;
2350 int rem, err = -EOPNOTSUPP;
2351 u16 flags = 0;
2305 2352
2306 if (nlmsg_len(nlh) < sizeof(*ifm)) 2353 if (nlmsg_len(nlh) < sizeof(*ifm))
2307 return -EINVAL; 2354 return -EINVAL;
@@ -2316,15 +2363,45 @@ static int rtnl_bridge_setlink(struct sk_buff *skb, struct nlmsghdr *nlh,
2316 return -ENODEV; 2363 return -ENODEV;
2317 } 2364 }
2318 2365
2319 if (dev->master && dev->master->netdev_ops->ndo_bridge_setlink) { 2366 br_spec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC);
2367 if (br_spec) {
2368 nla_for_each_nested(attr, br_spec, rem) {
2369 if (nla_type(attr) == IFLA_BRIDGE_FLAGS) {
2370 flags = nla_get_u16(attr);
2371 break;
2372 }
2373 }
2374 }
2375
2376 if (!flags || (flags & BRIDGE_FLAGS_MASTER)) {
2377 if (!dev->master ||
2378 !dev->master->netdev_ops->ndo_bridge_setlink) {
2379 err = -EOPNOTSUPP;
2380 goto out;
2381 }
2382
2320 err = dev->master->netdev_ops->ndo_bridge_setlink(dev, nlh); 2383 err = dev->master->netdev_ops->ndo_bridge_setlink(dev, nlh);
2321 if (err) 2384 if (err)
2322 goto out; 2385 goto out;
2386
2387 flags &= ~BRIDGE_FLAGS_MASTER;
2323 } 2388 }
2324 2389
2325 if (dev->netdev_ops->ndo_bridge_setlink) 2390 if ((flags & BRIDGE_FLAGS_SELF)) {
2326 err = dev->netdev_ops->ndo_bridge_setlink(dev, nlh); 2391 if (!dev->netdev_ops->ndo_bridge_setlink)
2392 err = -EOPNOTSUPP;
2393 else
2394 err = dev->netdev_ops->ndo_bridge_setlink(dev, nlh);
2395
2396 if (!err)
2397 flags &= ~BRIDGE_FLAGS_SELF;
2398 }
2327 2399
2400 if (attr && nla_type(attr) == IFLA_BRIDGE_FLAGS)
2401 memcpy(nla_data(attr), &flags, sizeof(flags));
2402 /* Generate event to notify upper layer of bridge change */
2403 if (!err)
2404 err = rtnl_bridge_notify(dev, flags);
2328out: 2405out:
2329 return err; 2406 return err;
2330} 2407}