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

rtnetlink: RTEXT_FILTER_SKIP_STATS support to avoid dumping inet/inet6 stats

Many commonly used functions like getifaddrs() invoke RTM_GETLINK
to dump the interface information, and do not need the
the AF_INET6 statististics that are always returned by default
from rtnl_fill_ifinfo().

Computing the statistics can be an expensive operation that impacts
scaling, so it is desirable to avoid this if the information is
not needed.

This patch adds a the RTEXT_FILTER_SKIP_STATS extended info flag that
can be passed with netlink_request() to avoid statistics computation
for the ifinfo path.

Signed-off-by: Sowmini Varadhan <sowmini.varadhan@oracle.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Sowmini Varadhan and committed by
David S. Miller
d5566fd7 ad1e7b97

+15 -7
+2 -1
include/net/rtnetlink.h
··· 122 122 int family; 123 123 124 124 int (*fill_link_af)(struct sk_buff *skb, 125 - const struct net_device *dev); 125 + const struct net_device *dev, 126 + u32 ext_filter_mask); 126 127 size_t (*get_link_af_size)(const struct net_device *dev); 127 128 128 129 int (*validate_link_af)(const struct net_device *dev,
+1
include/uapi/linux/rtnetlink.h
··· 667 667 #define RTEXT_FILTER_VF (1 << 0) 668 668 #define RTEXT_FILTER_BRVLAN (1 << 1) 669 669 #define RTEXT_FILTER_BRVLAN_COMPRESSED (1 << 2) 670 + #define RTEXT_FILTER_SKIP_STATS (1 << 3) 670 671 671 672 /* End of information exported to user level */ 672 673
+1 -1
net/core/rtnetlink.c
··· 1272 1272 if (!(af = nla_nest_start(skb, af_ops->family))) 1273 1273 goto nla_put_failure; 1274 1274 1275 - err = af_ops->fill_link_af(skb, dev); 1275 + err = af_ops->fill_link_af(skb, dev, ext_filter_mask); 1276 1276 1277 1277 /* 1278 1278 * Caller may return ENODATA to indicate that there
+2 -1
net/ipv4/devinet.c
··· 1654 1654 return nla_total_size(IPV4_DEVCONF_MAX * 4); /* IFLA_INET_CONF */ 1655 1655 } 1656 1656 1657 - static int inet_fill_link_af(struct sk_buff *skb, const struct net_device *dev) 1657 + static int inet_fill_link_af(struct sk_buff *skb, const struct net_device *dev, 1658 + u32 ext_filter_mask) 1658 1659 { 1659 1660 struct in_device *in_dev = rcu_dereference_rtnl(dev->ip_ptr); 1660 1661 struct nlattr *nla;
+9 -4
net/ipv6/addrconf.c
··· 4729 4729 } 4730 4730 } 4731 4731 4732 - static int inet6_fill_ifla6_attrs(struct sk_buff *skb, struct inet6_dev *idev) 4732 + static int inet6_fill_ifla6_attrs(struct sk_buff *skb, struct inet6_dev *idev, 4733 + u32 ext_filter_mask) 4733 4734 { 4734 4735 struct nlattr *nla; 4735 4736 struct ifla_cacheinfo ci; ··· 4749 4748 ipv6_store_devconf(&idev->cnf, nla_data(nla), nla_len(nla)); 4750 4749 4751 4750 /* XXX - MC not implemented */ 4751 + 4752 + if (ext_filter_mask & RTEXT_FILTER_SKIP_STATS) 4753 + return 0; 4752 4754 4753 4755 nla = nla_reserve(skb, IFLA_INET6_STATS, IPSTATS_MIB_MAX * sizeof(u64)); 4754 4756 if (!nla) ··· 4788 4784 return inet6_ifla6_size(); 4789 4785 } 4790 4786 4791 - static int inet6_fill_link_af(struct sk_buff *skb, const struct net_device *dev) 4787 + static int inet6_fill_link_af(struct sk_buff *skb, const struct net_device *dev, 4788 + u32 ext_filter_mask) 4792 4789 { 4793 4790 struct inet6_dev *idev = __in6_dev_get(dev); 4794 4791 4795 4792 if (!idev) 4796 4793 return -ENODATA; 4797 4794 4798 - if (inet6_fill_ifla6_attrs(skb, idev) < 0) 4795 + if (inet6_fill_ifla6_attrs(skb, idev, ext_filter_mask) < 0) 4799 4796 return -EMSGSIZE; 4800 4797 4801 4798 return 0; ··· 4951 4946 if (!protoinfo) 4952 4947 goto nla_put_failure; 4953 4948 4954 - if (inet6_fill_ifla6_attrs(skb, idev) < 0) 4949 + if (inet6_fill_ifla6_attrs(skb, idev, 0) < 0) 4955 4950 goto nla_put_failure; 4956 4951 4957 4952 nla_nest_end(skb, protoinfo);