aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_main.c3
-rw-r--r--include/linux/netdevice.h3
-rw-r--r--include/uapi/linux/rtnetlink.h1
-rw-r--r--net/bridge/br_netlink.c94
-rw-r--r--net/bridge/br_private.h3
-rw-r--r--net/bridge/br_vlan.c2
-rw-r--r--net/core/rtnetlink.c16
7 files changed, 104 insertions, 18 deletions
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 6999269b3a4a..4e2aa47193cb 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -7079,7 +7079,8 @@ static int ixgbe_ndo_bridge_setlink(struct net_device *dev,
7079} 7079}
7080 7080
7081static int ixgbe_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, 7081static int ixgbe_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
7082 struct net_device *dev) 7082 struct net_device *dev,
7083 u32 filter_mask)
7083{ 7084{
7084 struct ixgbe_adapter *adapter = netdev_priv(dev); 7085 struct ixgbe_adapter *adapter = netdev_priv(dev);
7085 u16 mode; 7086 u16 mode;
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 1b90f9401000..1964ca66df56 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1019,7 +1019,8 @@ struct net_device_ops {
1019 struct nlmsghdr *nlh); 1019 struct nlmsghdr *nlh);
1020 int (*ndo_bridge_getlink)(struct sk_buff *skb, 1020 int (*ndo_bridge_getlink)(struct sk_buff *skb,
1021 u32 pid, u32 seq, 1021 u32 pid, u32 seq,
1022 struct net_device *dev); 1022 struct net_device *dev,
1023 u32 filter_mask);
1023 int (*ndo_bridge_dellink)(struct net_device *dev, 1024 int (*ndo_bridge_dellink)(struct net_device *dev,
1024 struct nlmsghdr *nlh); 1025 struct nlmsghdr *nlh);
1025 int (*ndo_change_carrier)(struct net_device *dev, 1026 int (*ndo_change_carrier)(struct net_device *dev,
diff --git a/include/uapi/linux/rtnetlink.h b/include/uapi/linux/rtnetlink.h
index 7a5eb196ade9..7a2144e1afae 100644
--- a/include/uapi/linux/rtnetlink.h
+++ b/include/uapi/linux/rtnetlink.h
@@ -630,6 +630,7 @@ struct tcamsg {
630 630
631/* New extended info filters for IFLA_EXT_MASK */ 631/* New extended info filters for IFLA_EXT_MASK */
632#define RTEXT_FILTER_VF (1 << 0) 632#define RTEXT_FILTER_VF (1 << 0)
633#define RTEXT_FILTER_BRVLAN (1 << 1)
633 634
634/* End of information exported to user level */ 635/* End of information exported to user level */
635 636
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
index 534a9f4587a9..fe1980d5a7e4 100644
--- a/net/bridge/br_netlink.c
+++ b/net/bridge/br_netlink.c
@@ -65,15 +65,21 @@ static int br_port_fill_attrs(struct sk_buff *skb,
65 * Create one netlink message for one interface 65 * Create one netlink message for one interface
66 * Contains port and master info as well as carrier and bridge state. 66 * Contains port and master info as well as carrier and bridge state.
67 */ 67 */
68static int br_fill_ifinfo(struct sk_buff *skb, const struct net_bridge_port *port, 68static int br_fill_ifinfo(struct sk_buff *skb,
69 u32 pid, u32 seq, int event, unsigned int flags) 69 const struct net_bridge_port *port,
70 u32 pid, u32 seq, int event, unsigned int flags,
71 u32 filter_mask, const struct net_device *dev)
70{ 72{
71 const struct net_bridge *br = port->br; 73 const struct net_bridge *br;
72 const struct net_device *dev = port->dev;
73 struct ifinfomsg *hdr; 74 struct ifinfomsg *hdr;
74 struct nlmsghdr *nlh; 75 struct nlmsghdr *nlh;
75 u8 operstate = netif_running(dev) ? dev->operstate : IF_OPER_DOWN; 76 u8 operstate = netif_running(dev) ? dev->operstate : IF_OPER_DOWN;
76 77
78 if (port)
79 br = port->br;
80 else
81 br = netdev_priv(dev);
82
77 br_debug(br, "br_fill_info event %d port %s master %s\n", 83 br_debug(br, "br_fill_info event %d port %s master %s\n",
78 event, dev->name, br->dev->name); 84 event, dev->name, br->dev->name);
79 85
@@ -99,7 +105,7 @@ static int br_fill_ifinfo(struct sk_buff *skb, const struct net_bridge_port *por
99 nla_put_u32(skb, IFLA_LINK, dev->iflink))) 105 nla_put_u32(skb, IFLA_LINK, dev->iflink)))
100 goto nla_put_failure; 106 goto nla_put_failure;
101 107
102 if (event == RTM_NEWLINK) { 108 if (event == RTM_NEWLINK && port) {
103 struct nlattr *nest 109 struct nlattr *nest
104 = nla_nest_start(skb, IFLA_PROTINFO | NLA_F_NESTED); 110 = nla_nest_start(skb, IFLA_PROTINFO | NLA_F_NESTED);
105 111
@@ -108,6 +114,40 @@ static int br_fill_ifinfo(struct sk_buff *skb, const struct net_bridge_port *por
108 nla_nest_end(skb, nest); 114 nla_nest_end(skb, nest);
109 } 115 }
110 116
117 /* Check if the VID information is requested */
118 if (filter_mask & RTEXT_FILTER_BRVLAN) {
119 struct nlattr *af;
120 const struct net_port_vlans *pv;
121 struct bridge_vlan_info vinfo;
122 u16 vid;
123
124 if (port)
125 pv = nbp_get_vlan_info(port);
126 else
127 pv = br_get_vlan_info(br);
128
129 if (!pv || bitmap_empty(pv->vlan_bitmap, BR_VLAN_BITMAP_LEN))
130 goto done;
131
132 af = nla_nest_start(skb, IFLA_AF_SPEC);
133 if (!af)
134 goto nla_put_failure;
135
136 for (vid = find_first_bit(pv->vlan_bitmap, BR_VLAN_BITMAP_LEN);
137 vid < BR_VLAN_BITMAP_LEN;
138 vid = find_next_bit(pv->vlan_bitmap,
139 BR_VLAN_BITMAP_LEN, vid+1)) {
140 vinfo.vid = vid;
141 vinfo.flags = 0;
142 if (nla_put(skb, IFLA_BRIDGE_VLAN_INFO,
143 sizeof(vinfo), &vinfo))
144 goto nla_put_failure;
145 }
146
147 nla_nest_end(skb, af);
148 }
149
150done:
111 return nlmsg_end(skb, nlh); 151 return nlmsg_end(skb, nlh);
112 152
113nla_put_failure: 153nla_put_failure:
@@ -135,7 +175,7 @@ void br_ifinfo_notify(int event, struct net_bridge_port *port)
135 if (skb == NULL) 175 if (skb == NULL)
136 goto errout; 176 goto errout;
137 177
138 err = br_fill_ifinfo(skb, port, 0, 0, event, 0); 178 err = br_fill_ifinfo(skb, port, 0, 0, event, 0, 0, port->dev);
139 if (err < 0) { 179 if (err < 0) {
140 /* -EMSGSIZE implies BUG in br_nlmsg_size() */ 180 /* -EMSGSIZE implies BUG in br_nlmsg_size() */
141 WARN_ON(err == -EMSGSIZE); 181 WARN_ON(err == -EMSGSIZE);
@@ -154,16 +194,17 @@ errout:
154 * Dump information about all ports, in response to GETLINK 194 * Dump information about all ports, in response to GETLINK
155 */ 195 */
156int br_getlink(struct sk_buff *skb, u32 pid, u32 seq, 196int br_getlink(struct sk_buff *skb, u32 pid, u32 seq,
157 struct net_device *dev) 197 struct net_device *dev, u32 filter_mask)
158{ 198{
159 int err = 0; 199 int err = 0;
160 struct net_bridge_port *port = br_port_get_rcu(dev); 200 struct net_bridge_port *port = br_port_get_rcu(dev);
161 201
162 /* not a bridge port */ 202 /* not a bridge port and */
163 if (!port) 203 if (!port && !(filter_mask & RTEXT_FILTER_BRVLAN))
164 goto out; 204 goto out;
165 205
166 err = br_fill_ifinfo(skb, port, pid, seq, RTM_NEWLINK, NLM_F_MULTI); 206 err = br_fill_ifinfo(skb, port, pid, seq, RTM_NEWLINK, NLM_F_MULTI,
207 filter_mask, dev);
167out: 208out:
168 return err; 209 return err;
169} 210}
@@ -395,6 +436,29 @@ static int br_validate(struct nlattr *tb[], struct nlattr *data[])
395 return 0; 436 return 0;
396} 437}
397 438
439static size_t br_get_link_af_size(const struct net_device *dev)
440{
441 struct net_port_vlans *pv;
442
443 if (br_port_exists(dev))
444 pv = nbp_get_vlan_info(br_port_get_rcu(dev));
445 else if (dev->priv_flags & IFF_EBRIDGE)
446 pv = br_get_vlan_info((struct net_bridge *)netdev_priv(dev));
447 else
448 return 0;
449
450 if (!pv)
451 return 0;
452
453 /* Each VLAN is returned in bridge_vlan_info along with flags */
454 return pv->num_vlans * nla_total_size(sizeof(struct bridge_vlan_info));
455}
456
457struct rtnl_af_ops br_af_ops = {
458 .family = AF_BRIDGE,
459 .get_link_af_size = br_get_link_af_size,
460};
461
398struct rtnl_link_ops br_link_ops __read_mostly = { 462struct rtnl_link_ops br_link_ops __read_mostly = {
399 .kind = "bridge", 463 .kind = "bridge",
400 .priv_size = sizeof(struct net_bridge), 464 .priv_size = sizeof(struct net_bridge),
@@ -408,11 +472,18 @@ int __init br_netlink_init(void)
408 int err; 472 int err;
409 473
410 br_mdb_init(); 474 br_mdb_init();
411 err = rtnl_link_register(&br_link_ops); 475 err = rtnl_af_register(&br_af_ops);
412 if (err) 476 if (err)
413 goto out; 477 goto out;
414 478
479 err = rtnl_link_register(&br_link_ops);
480 if (err)
481 goto out_af;
482
415 return 0; 483 return 0;
484
485out_af:
486 rtnl_af_unregister(&br_af_ops);
416out: 487out:
417 br_mdb_uninit(); 488 br_mdb_uninit();
418 return err; 489 return err;
@@ -421,5 +492,6 @@ out:
421void __exit br_netlink_fini(void) 492void __exit br_netlink_fini(void)
422{ 493{
423 br_mdb_uninit(); 494 br_mdb_uninit();
495 rtnl_af_unregister(&br_af_ops);
424 rtnl_link_unregister(&br_link_ops); 496 rtnl_link_unregister(&br_link_ops);
425} 497}
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index a42f9d49a64e..ce2235255c2f 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -73,6 +73,7 @@ struct net_port_vlans {
73 } parent; 73 } parent;
74 struct rcu_head rcu; 74 struct rcu_head rcu;
75 unsigned long vlan_bitmap[BR_VLAN_BITMAP_LEN]; 75 unsigned long vlan_bitmap[BR_VLAN_BITMAP_LEN];
76 u16 num_vlans;
76}; 77};
77 78
78struct net_bridge_fdb_entry 79struct net_bridge_fdb_entry
@@ -715,7 +716,7 @@ extern void br_ifinfo_notify(int event, struct net_bridge_port *port);
715extern int br_setlink(struct net_device *dev, struct nlmsghdr *nlmsg); 716extern int br_setlink(struct net_device *dev, struct nlmsghdr *nlmsg);
716extern int br_dellink(struct net_device *dev, struct nlmsghdr *nlmsg); 717extern int br_dellink(struct net_device *dev, struct nlmsghdr *nlmsg);
717extern int br_getlink(struct sk_buff *skb, u32 pid, u32 seq, 718extern int br_getlink(struct sk_buff *skb, u32 pid, u32 seq,
718 struct net_device *dev); 719 struct net_device *dev, u32 filter_mask);
719 720
720#ifdef CONFIG_SYSFS 721#ifdef CONFIG_SYSFS
721/* br_sysfs_if.c */ 722/* br_sysfs_if.c */
diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c
index d8690bfe63d4..f2bf5a197ea3 100644
--- a/net/bridge/br_vlan.c
+++ b/net/bridge/br_vlan.c
@@ -28,6 +28,7 @@ static int __vlan_add(struct net_port_vlans *v, u16 vid)
28 } 28 }
29 29
30 set_bit(vid, v->vlan_bitmap); 30 set_bit(vid, v->vlan_bitmap);
31 v->num_vlans++;
31 return 0; 32 return 0;
32} 33}
33 34
@@ -44,6 +45,7 @@ static int __vlan_del(struct net_port_vlans *v, u16 vid)
44 } 45 }
45 46
46 clear_bit(vid, v->vlan_bitmap); 47 clear_bit(vid, v->vlan_bitmap);
48 v->num_vlans--;
47 if (bitmap_empty(v->vlan_bitmap, BR_VLAN_BITMAP_LEN)) { 49 if (bitmap_empty(v->vlan_bitmap, BR_VLAN_BITMAP_LEN)) {
48 if (v->port_idx) 50 if (v->port_idx)
49 rcu_assign_pointer(v->parent.port->vlan_info, NULL); 51 rcu_assign_pointer(v->parent.port->vlan_info, NULL);
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 2c9ccbfbd93c..f3a112ec86d5 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -2315,6 +2315,13 @@ static int rtnl_bridge_getlink(struct sk_buff *skb, struct netlink_callback *cb)
2315 int idx = 0; 2315 int idx = 0;
2316 u32 portid = NETLINK_CB(cb->skb).portid; 2316 u32 portid = NETLINK_CB(cb->skb).portid;
2317 u32 seq = cb->nlh->nlmsg_seq; 2317 u32 seq = cb->nlh->nlmsg_seq;
2318 struct nlattr *extfilt;
2319 u32 filter_mask = 0;
2320
2321 extfilt = nlmsg_find_attr(cb->nlh, sizeof(struct rtgenmsg),
2322 IFLA_EXT_MASK);
2323 if (extfilt)
2324 filter_mask = nla_get_u32(extfilt);
2318 2325
2319 rcu_read_lock(); 2326 rcu_read_lock();
2320 for_each_netdev_rcu(net, dev) { 2327 for_each_netdev_rcu(net, dev) {
@@ -2324,14 +2331,15 @@ static int rtnl_bridge_getlink(struct sk_buff *skb, struct netlink_callback *cb)
2324 if (br_dev && br_dev->netdev_ops->ndo_bridge_getlink) { 2331 if (br_dev && br_dev->netdev_ops->ndo_bridge_getlink) {
2325 if (idx >= cb->args[0] && 2332 if (idx >= cb->args[0] &&
2326 br_dev->netdev_ops->ndo_bridge_getlink( 2333 br_dev->netdev_ops->ndo_bridge_getlink(
2327 skb, portid, seq, dev) < 0) 2334 skb, portid, seq, dev, filter_mask) < 0)
2328 break; 2335 break;
2329 idx++; 2336 idx++;
2330 } 2337 }
2331 2338
2332 if (ops->ndo_bridge_getlink) { 2339 if (ops->ndo_bridge_getlink) {
2333 if (idx >= cb->args[0] && 2340 if (idx >= cb->args[0] &&
2334 ops->ndo_bridge_getlink(skb, portid, seq, dev) < 0) 2341 ops->ndo_bridge_getlink(skb, portid, seq, dev,
2342 filter_mask) < 0)
2335 break; 2343 break;
2336 idx++; 2344 idx++;
2337 } 2345 }
@@ -2372,14 +2380,14 @@ static int rtnl_bridge_notify(struct net_device *dev, u16 flags)
2372 2380
2373 if ((!flags || (flags & BRIDGE_FLAGS_MASTER)) && 2381 if ((!flags || (flags & BRIDGE_FLAGS_MASTER)) &&
2374 br_dev && br_dev->netdev_ops->ndo_bridge_getlink) { 2382 br_dev && br_dev->netdev_ops->ndo_bridge_getlink) {
2375 err = br_dev->netdev_ops->ndo_bridge_getlink(skb, 0, 0, dev); 2383 err = br_dev->netdev_ops->ndo_bridge_getlink(skb, 0, 0, dev, 0);
2376 if (err < 0) 2384 if (err < 0)
2377 goto errout; 2385 goto errout;
2378 } 2386 }
2379 2387
2380 if ((flags & BRIDGE_FLAGS_SELF) && 2388 if ((flags & BRIDGE_FLAGS_SELF) &&
2381 dev->netdev_ops->ndo_bridge_getlink) { 2389 dev->netdev_ops->ndo_bridge_getlink) {
2382 err = dev->netdev_ops->ndo_bridge_getlink(skb, 0, 0, dev); 2390 err = dev->netdev_ops->ndo_bridge_getlink(skb, 0, 0, dev, 0);
2383 if (err < 0) 2391 if (err < 0)
2384 goto errout; 2392 goto errout;
2385 } 2393 }