diff options
-rw-r--r-- | drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 3 | ||||
-rw-r--r-- | include/linux/netdevice.h | 3 | ||||
-rw-r--r-- | include/uapi/linux/rtnetlink.h | 1 | ||||
-rw-r--r-- | net/bridge/br_netlink.c | 94 | ||||
-rw-r--r-- | net/bridge/br_private.h | 3 | ||||
-rw-r--r-- | net/bridge/br_vlan.c | 2 | ||||
-rw-r--r-- | net/core/rtnetlink.c | 16 |
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 | ||
7081 | static int ixgbe_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, | 7081 | static 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 | */ |
68 | static int br_fill_ifinfo(struct sk_buff *skb, const struct net_bridge_port *port, | 68 | static 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 | |||
150 | done: | ||
111 | return nlmsg_end(skb, nlh); | 151 | return nlmsg_end(skb, nlh); |
112 | 152 | ||
113 | nla_put_failure: | 153 | nla_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 | */ |
156 | int br_getlink(struct sk_buff *skb, u32 pid, u32 seq, | 196 | int 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); | ||
167 | out: | 208 | out: |
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 | ||
439 | static 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 | |||
457 | struct rtnl_af_ops br_af_ops = { | ||
458 | .family = AF_BRIDGE, | ||
459 | .get_link_af_size = br_get_link_af_size, | ||
460 | }; | ||
461 | |||
398 | struct rtnl_link_ops br_link_ops __read_mostly = { | 462 | struct 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 | |||
485 | out_af: | ||
486 | rtnl_af_unregister(&br_af_ops); | ||
416 | out: | 487 | out: |
417 | br_mdb_uninit(); | 488 | br_mdb_uninit(); |
418 | return err; | 489 | return err; |
@@ -421,5 +492,6 @@ out: | |||
421 | void __exit br_netlink_fini(void) | 492 | void __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 | ||
78 | struct net_bridge_fdb_entry | 79 | struct net_bridge_fdb_entry |
@@ -715,7 +716,7 @@ extern void br_ifinfo_notify(int event, struct net_bridge_port *port); | |||
715 | extern int br_setlink(struct net_device *dev, struct nlmsghdr *nlmsg); | 716 | extern int br_setlink(struct net_device *dev, struct nlmsghdr *nlmsg); |
716 | extern int br_dellink(struct net_device *dev, struct nlmsghdr *nlmsg); | 717 | extern int br_dellink(struct net_device *dev, struct nlmsghdr *nlmsg); |
717 | extern int br_getlink(struct sk_buff *skb, u32 pid, u32 seq, | 718 | extern 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 | } |