aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--include/uapi/linux/if_bridge.h18
-rw-r--r--net/bridge/br_netlink.c2
-rw-r--r--net/bridge/br_private.h4
-rw-r--r--net/core/rtnetlink.c85
4 files changed, 102 insertions, 7 deletions
diff --git a/include/uapi/linux/if_bridge.h b/include/uapi/linux/if_bridge.h
index a8fe9549ddbc..b3885791e11e 100644
--- a/include/uapi/linux/if_bridge.h
+++ b/include/uapi/linux/if_bridge.h
@@ -97,5 +97,23 @@ struct __fdb_entry {
97 __u16 unused; 97 __u16 unused;
98}; 98};
99 99
100/* Bridge Flags */
101#define BRIDGE_FLAGS_MASTER 1 /* Bridge command to/from master */
102#define BRIDGE_FLAGS_SELF 2 /* Bridge command to/from lowerdev */
100 103
104#define BRIDGE_MODE_VEB 0 /* Default loopback mode */
105#define BRIDGE_MODE_VEPA 1 /* 802.1Qbg defined VEPA mode */
106
107/* Bridge management nested attributes
108 * [IFLA_AF_SPEC] = {
109 * [IFLA_BRIDGE_FLAGS]
110 * [IFLA_BRIDGE_MODE]
111 * }
112 */
113enum {
114 IFLA_BRIDGE_FLAGS,
115 IFLA_BRIDGE_MODE,
116 __IFLA_BRIDGE_MAX,
117};
118#define IFLA_BRIDGE_MAX (__IFLA_BRIDGE_MAX - 1)
101#endif /* _UAPI_LINUX_IF_BRIDGE_H */ 119#endif /* _UAPI_LINUX_IF_BRIDGE_H */
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
index 743511bb7319..14b065cbd214 100644
--- a/net/bridge/br_netlink.c
+++ b/net/bridge/br_netlink.c
@@ -166,8 +166,6 @@ int br_setlink(struct net_device *dev, struct nlmsghdr *nlh)
166 br_port_state_selection(p->br); 166 br_port_state_selection(p->br);
167 spin_unlock_bh(&p->br->lock); 167 spin_unlock_bh(&p->br->lock);
168 168
169 br_ifinfo_notify(RTM_NEWLINK, p);
170
171 return 0; 169 return 0;
172} 170}
173 171
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index fdcd5f626ca6..6f40c14a2a65 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -158,7 +158,9 @@ struct net_bridge_port
158 158
159static inline struct net_bridge_port *br_port_get_rcu(const struct net_device *dev) 159static inline struct net_bridge_port *br_port_get_rcu(const struct net_device *dev)
160{ 160{
161 struct net_bridge_port *port = rcu_dereference(dev->rx_handler_data); 161 struct net_bridge_port *port =
162 rcu_dereference_rtnl(dev->rx_handler_data);
163
162 return br_port_exists(dev) ? port : NULL; 164 return br_port_exists(dev) ? port : NULL;
163} 165}
164 166
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}