aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoopa Prabhu <roopa@cumulusnetworks.com>2015-02-26 02:55:40 -0500
committerDavid S. Miller <davem@davemloft.net>2015-02-26 11:25:43 -0500
commitfed0a159c8c5e453d79d6a73897c576efea0a8a5 (patch)
tree2240c310159853566c8916a6f324cb5f89ff342d
parent9003019192f045eee8e451916a4bc289c2a3e1be (diff)
bridge: fix link notification skb size calculation to include vlan ranges
my previous patch skipped vlan range optimizations during skb size calculations for simplicity. This incremental patch considers vlan ranges during skb size calculations. This leads to a bit of code duplication in the fill and size calculation functions. But, I could not find a prettier way to do this. will take any suggestions. Previously, I had reused the existing br_get_link_af_size size calculation function to calculate skb size for notifications. Reusing it this time around creates some change in behaviour issues for the usual .get_link_af_size callback. This patch adds a new br_get_link_af_size_filtered() function to base the size calculation on the incoming filter flag and include vlan ranges. Signed-off-by: Roopa Prabhu <roopa@cumulusnetworks.com> Reviewed-by: Scott Feldman <sfeldma@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/bridge/br_netlink.c92
1 files changed, 85 insertions, 7 deletions
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
index 17e0177467f5..3de0eefe2b82 100644
--- a/net/bridge/br_netlink.c
+++ b/net/bridge/br_netlink.c
@@ -22,9 +22,64 @@
22#include "br_private.h" 22#include "br_private.h"
23#include "br_private_stp.h" 23#include "br_private_stp.h"
24 24
25static size_t br_get_link_af_size(const struct net_device *dev) 25static int br_get_num_vlan_infos(const struct net_port_vlans *pv,
26 u32 filter_mask)
27{
28 u16 vid_range_start = 0, vid_range_end = 0;
29 u16 vid_range_flags = 0;
30 u16 pvid, vid, flags;
31 int num_vlans = 0;
32
33 if (filter_mask & RTEXT_FILTER_BRVLAN)
34 return pv->num_vlans;
35
36 if (!(filter_mask & RTEXT_FILTER_BRVLAN_COMPRESSED))
37 return 0;
38
39 /* Count number of vlan info's
40 */
41 pvid = br_get_pvid(pv);
42 for_each_set_bit(vid, pv->vlan_bitmap, VLAN_N_VID) {
43 flags = 0;
44 if (vid == pvid)
45 flags |= BRIDGE_VLAN_INFO_PVID;
46
47 if (test_bit(vid, pv->untagged_bitmap))
48 flags |= BRIDGE_VLAN_INFO_UNTAGGED;
49
50 if (vid_range_start == 0) {
51 goto initvars;
52 } else if ((vid - vid_range_end) == 1 &&
53 flags == vid_range_flags) {
54 vid_range_end = vid;
55 continue;
56 } else {
57 if ((vid_range_end - vid_range_start) > 0)
58 num_vlans += 2;
59 else
60 num_vlans += 1;
61 }
62initvars:
63 vid_range_start = vid;
64 vid_range_end = vid;
65 vid_range_flags = flags;
66 }
67
68 if (vid_range_start != 0) {
69 if ((vid_range_end - vid_range_start) > 0)
70 num_vlans += 2;
71 else
72 num_vlans += 1;
73 }
74
75 return num_vlans;
76}
77
78static size_t br_get_link_af_size_filtered(const struct net_device *dev,
79 u32 filter_mask)
26{ 80{
27 struct net_port_vlans *pv; 81 struct net_port_vlans *pv;
82 int num_vlan_infos;
28 83
29 if (br_port_exists(dev)) 84 if (br_port_exists(dev))
30 pv = nbp_get_vlan_info(br_port_get_rtnl(dev)); 85 pv = nbp_get_vlan_info(br_port_get_rtnl(dev));
@@ -36,8 +91,12 @@ static size_t br_get_link_af_size(const struct net_device *dev)
36 if (!pv) 91 if (!pv)
37 return 0; 92 return 0;
38 93
94 num_vlan_infos = br_get_num_vlan_infos(pv, filter_mask);
95 if (!num_vlan_infos)
96 return 0;
97
39 /* Each VLAN is returned in bridge_vlan_info along with flags */ 98 /* Each VLAN is returned in bridge_vlan_info along with flags */
40 return pv->num_vlans * nla_total_size(sizeof(struct bridge_vlan_info)); 99 return num_vlan_infos * nla_total_size(sizeof(struct bridge_vlan_info));
41} 100}
42 101
43static inline size_t br_port_info_size(void) 102static inline size_t br_port_info_size(void)
@@ -54,7 +113,7 @@ static inline size_t br_port_info_size(void)
54 + 0; 113 + 0;
55} 114}
56 115
57static inline size_t br_nlmsg_size(struct net_device *dev) 116static inline size_t br_nlmsg_size(struct net_device *dev, u32 filter_mask)
58{ 117{
59 return NLMSG_ALIGN(sizeof(struct ifinfomsg)) 118 return NLMSG_ALIGN(sizeof(struct ifinfomsg))
60 + nla_total_size(IFNAMSIZ) /* IFLA_IFNAME */ 119 + nla_total_size(IFNAMSIZ) /* IFLA_IFNAME */
@@ -64,7 +123,8 @@ static inline size_t br_nlmsg_size(struct net_device *dev)
64 + nla_total_size(4) /* IFLA_LINK */ 123 + nla_total_size(4) /* IFLA_LINK */
65 + nla_total_size(1) /* IFLA_OPERSTATE */ 124 + nla_total_size(1) /* IFLA_OPERSTATE */
66 + nla_total_size(br_port_info_size()) /* IFLA_PROTINFO */ 125 + nla_total_size(br_port_info_size()) /* IFLA_PROTINFO */
67 + nla_total_size(br_get_link_af_size(dev)); /* IFLA_AF_SPEC */ 126 + nla_total_size(br_get_link_af_size_filtered(dev,
127 filter_mask)); /* IFLA_AF_SPEC */
68} 128}
69 129
70static int br_port_fill_attrs(struct sk_buff *skb, 130static int br_port_fill_attrs(struct sk_buff *skb,
@@ -299,6 +359,7 @@ void br_ifinfo_notify(int event, struct net_bridge_port *port)
299 struct net *net; 359 struct net *net;
300 struct sk_buff *skb; 360 struct sk_buff *skb;
301 int err = -ENOBUFS; 361 int err = -ENOBUFS;
362 u32 filter = RTEXT_FILTER_BRVLAN_COMPRESSED;
302 363
303 if (!port) 364 if (!port)
304 return; 365 return;
@@ -307,12 +368,11 @@ void br_ifinfo_notify(int event, struct net_bridge_port *port)
307 br_debug(port->br, "port %u(%s) event %d\n", 368 br_debug(port->br, "port %u(%s) event %d\n",
308 (unsigned int)port->port_no, port->dev->name, event); 369 (unsigned int)port->port_no, port->dev->name, event);
309 370
310 skb = nlmsg_new(br_nlmsg_size(port->dev), GFP_ATOMIC); 371 skb = nlmsg_new(br_nlmsg_size(port->dev, filter), GFP_ATOMIC);
311 if (skb == NULL) 372 if (skb == NULL)
312 goto errout; 373 goto errout;
313 374
314 err = br_fill_ifinfo(skb, port, 0, 0, event, 0, 375 err = br_fill_ifinfo(skb, port, 0, 0, event, 0, filter, port->dev);
315 RTEXT_FILTER_BRVLAN_COMPRESSED, port->dev);
316 if (err < 0) { 376 if (err < 0) {
317 /* -EMSGSIZE implies BUG in br_nlmsg_size() */ 377 /* -EMSGSIZE implies BUG in br_nlmsg_size() */
318 WARN_ON(err == -EMSGSIZE); 378 WARN_ON(err == -EMSGSIZE);
@@ -723,6 +783,24 @@ static int br_fill_info(struct sk_buff *skb, const struct net_device *brdev)
723 return 0; 783 return 0;
724} 784}
725 785
786static size_t br_get_link_af_size(const struct net_device *dev)
787{
788 struct net_port_vlans *pv;
789
790 if (br_port_exists(dev))
791 pv = nbp_get_vlan_info(br_port_get_rtnl(dev));
792 else if (dev->priv_flags & IFF_EBRIDGE)
793 pv = br_get_vlan_info((struct net_bridge *)netdev_priv(dev));
794 else
795 return 0;
796
797 if (!pv)
798 return 0;
799
800 /* Each VLAN is returned in bridge_vlan_info along with flags */
801 return pv->num_vlans * nla_total_size(sizeof(struct bridge_vlan_info));
802}
803
726static struct rtnl_af_ops br_af_ops __read_mostly = { 804static struct rtnl_af_ops br_af_ops __read_mostly = {
727 .family = AF_BRIDGE, 805 .family = AF_BRIDGE,
728 .get_link_af_size = br_get_link_af_size, 806 .get_link_af_size = br_get_link_af_size,