Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: rtnetlink: add support for the IFLA_STATS_LINK_XSTATS_SLAVE attribute

This patch adds support for the IFLA_STATS_LINK_XSTATS_SLAVE attribute
which allows to export per-slave statistics if the master device supports
the linkxstats callback. The attribute is passed down to the linkxstats
callback and it is up to the callback user to use it (an example has been
added to the only current user - the bridge). This allows us to query only
specific slaves of master devices like bridge ports and export only what
we're interested in instead of having to dump all ports and searching only
for a single one. This will be used to export per-port IGMP/MLD stats and
also per-port vlan stats in the future, possibly other statistics as well.

Signed-off-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Nikolay Aleksandrov and committed by
David S. Miller
80e73cc5 545c321b

+108 -7
+3 -2
include/net/rtnetlink.h
··· 98 98 const struct net_device *dev, 99 99 const struct net_device *slave_dev); 100 100 struct net *(*get_link_net)(const struct net_device *dev); 101 - size_t (*get_linkxstats_size)(const struct net_device *dev); 101 + size_t (*get_linkxstats_size)(const struct net_device *dev, 102 + int attr); 102 103 int (*fill_linkxstats)(struct sk_buff *skb, 103 104 const struct net_device *dev, 104 - int *prividx); 105 + int *prividx, int attr); 105 106 }; 106 107 107 108 int __rtnl_link_register(struct rtnl_link_ops *ops);
+1
include/uapi/linux/if_link.h
··· 822 822 IFLA_STATS_UNSPEC, /* also used as 64bit pad attribute */ 823 823 IFLA_STATS_LINK_64, 824 824 IFLA_STATS_LINK_XSTATS, 825 + IFLA_STATS_LINK_XSTATS_SLAVE, 825 826 __IFLA_STATS_MAX, 826 827 }; 827 828
+56 -3
net/bridge/br_netlink.c
··· 1234 1234 return 0; 1235 1235 } 1236 1236 1237 - static size_t br_get_linkxstats_size(const struct net_device *dev) 1237 + static size_t bridge_get_linkxstats_size(const struct net_device *dev) 1238 1238 { 1239 1239 struct net_bridge *br = netdev_priv(dev); 1240 1240 struct net_bridge_vlan_group *vg; ··· 1254 1254 nla_total_size(0); 1255 1255 } 1256 1256 1257 - static int br_fill_linkxstats(struct sk_buff *skb, const struct net_device *dev, 1258 - int *prividx) 1257 + static size_t brport_get_linkxstats_size(const struct net_device *dev) 1258 + { 1259 + return nla_total_size(0); 1260 + } 1261 + 1262 + static size_t br_get_linkxstats_size(const struct net_device *dev, int attr) 1263 + { 1264 + size_t retsize = 0; 1265 + 1266 + switch (attr) { 1267 + case IFLA_STATS_LINK_XSTATS: 1268 + retsize = bridge_get_linkxstats_size(dev); 1269 + break; 1270 + case IFLA_STATS_LINK_XSTATS_SLAVE: 1271 + retsize = brport_get_linkxstats_size(dev); 1272 + break; 1273 + } 1274 + 1275 + return retsize; 1276 + } 1277 + 1278 + static int bridge_fill_linkxstats(struct sk_buff *skb, 1279 + const struct net_device *dev, 1280 + int *prividx) 1259 1281 { 1260 1282 struct net_bridge *br = netdev_priv(dev); 1261 1283 struct net_bridge_vlan_group *vg; ··· 1318 1296 *prividx = vl_idx; 1319 1297 1320 1298 return -EMSGSIZE; 1299 + } 1300 + 1301 + static int brport_fill_linkxstats(struct sk_buff *skb, 1302 + const struct net_device *dev, 1303 + int *prividx) 1304 + { 1305 + struct nlattr *nest; 1306 + 1307 + nest = nla_nest_start(skb, LINK_XSTATS_TYPE_BRIDGE); 1308 + if (!nest) 1309 + return -EMSGSIZE; 1310 + nla_nest_end(skb, nest); 1311 + 1312 + return 0; 1313 + } 1314 + 1315 + static int br_fill_linkxstats(struct sk_buff *skb, const struct net_device *dev, 1316 + int *prividx, int attr) 1317 + { 1318 + int ret = -EINVAL; 1319 + 1320 + switch (attr) { 1321 + case IFLA_STATS_LINK_XSTATS: 1322 + ret = bridge_fill_linkxstats(skb, dev, prividx); 1323 + break; 1324 + case IFLA_STATS_LINK_XSTATS_SLAVE: 1325 + ret = brport_fill_linkxstats(skb, dev, prividx); 1326 + break; 1327 + } 1328 + 1329 + return ret; 1321 1330 } 1322 1331 1323 1332 static struct rtnl_af_ops br_af_ops __read_mostly = {
+48 -2
net/core/rtnetlink.c
··· 3519 3519 if (!attr) 3520 3520 goto nla_put_failure; 3521 3521 3522 - err = ops->fill_linkxstats(skb, dev, prividx); 3522 + err = ops->fill_linkxstats(skb, dev, prividx, *idxattr); 3523 + nla_nest_end(skb, attr); 3524 + if (err) 3525 + goto nla_put_failure; 3526 + *idxattr = 0; 3527 + } 3528 + } 3529 + 3530 + if (stats_attr_valid(filter_mask, IFLA_STATS_LINK_XSTATS_SLAVE, 3531 + *idxattr)) { 3532 + const struct rtnl_link_ops *ops = NULL; 3533 + const struct net_device *master; 3534 + 3535 + master = netdev_master_upper_dev_get(dev); 3536 + if (master) 3537 + ops = master->rtnl_link_ops; 3538 + if (ops && ops->fill_linkxstats) { 3539 + int err; 3540 + 3541 + *idxattr = IFLA_STATS_LINK_XSTATS_SLAVE; 3542 + attr = nla_nest_start(skb, 3543 + IFLA_STATS_LINK_XSTATS_SLAVE); 3544 + if (!attr) 3545 + goto nla_put_failure; 3546 + 3547 + err = ops->fill_linkxstats(skb, dev, prividx, *idxattr); 3523 3548 nla_nest_end(skb, attr); 3524 3549 if (err) 3525 3550 goto nla_put_failure; ··· 3580 3555 3581 3556 if (stats_attr_valid(filter_mask, IFLA_STATS_LINK_XSTATS, 0)) { 3582 3557 const struct rtnl_link_ops *ops = dev->rtnl_link_ops; 3558 + int attr = IFLA_STATS_LINK_XSTATS; 3583 3559 3584 3560 if (ops && ops->get_linkxstats_size) { 3585 - size += nla_total_size(ops->get_linkxstats_size(dev)); 3561 + size += nla_total_size(ops->get_linkxstats_size(dev, 3562 + attr)); 3586 3563 /* for IFLA_STATS_LINK_XSTATS */ 3564 + size += nla_total_size(0); 3565 + } 3566 + } 3567 + 3568 + if (stats_attr_valid(filter_mask, IFLA_STATS_LINK_XSTATS_SLAVE, 0)) { 3569 + struct net_device *_dev = (struct net_device *)dev; 3570 + const struct rtnl_link_ops *ops = NULL; 3571 + const struct net_device *master; 3572 + 3573 + /* netdev_master_upper_dev_get can't take const */ 3574 + master = netdev_master_upper_dev_get(_dev); 3575 + if (master) 3576 + ops = master->rtnl_link_ops; 3577 + if (ops && ops->get_linkxstats_size) { 3578 + int attr = IFLA_STATS_LINK_XSTATS_SLAVE; 3579 + 3580 + size += nla_total_size(ops->get_linkxstats_size(dev, 3581 + attr)); 3582 + /* for IFLA_STATS_LINK_XSTATS_SLAVE */ 3587 3583 size += nla_total_size(0); 3588 3584 } 3589 3585 }