rtnetlink: RTEXT_FILTER_SKIP_STATS support to avoid dumping inet/inet6 stats
authorSowmini Varadhan <sowmini.varadhan@oracle.com>
Fri, 11 Sep 2015 20:48:48 +0000 (16:48 -0400)
committerDavid S. Miller <davem@davemloft.net>
Tue, 15 Sep 2015 22:25:02 +0000 (15:25 -0700)
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>
include/net/rtnetlink.h
include/uapi/linux/rtnetlink.h
net/core/rtnetlink.c
net/ipv4/devinet.c
net/ipv6/addrconf.c

index 18fdb98..aff6ceb 100644 (file)
@@ -122,7 +122,8 @@ struct rtnl_af_ops {
        int                     family;
 
        int                     (*fill_link_af)(struct sk_buff *skb,
-                                               const struct net_device *dev);
+                                               const struct net_device *dev,
+                                               u32 ext_filter_mask);
        size_t                  (*get_link_af_size)(const struct net_device *dev);
 
        int                     (*validate_link_af)(const struct net_device *dev,
index 06625b4..4db0b3c 100644 (file)
@@ -667,6 +667,7 @@ struct tcamsg {
 #define RTEXT_FILTER_VF                (1 << 0)
 #define RTEXT_FILTER_BRVLAN    (1 << 1)
 #define RTEXT_FILTER_BRVLAN_COMPRESSED (1 << 2)
+#define        RTEXT_FILTER_SKIP_STATS (1 << 3)
 
 /* End of information exported to user level */
 
index a466821..e545229 100644 (file)
@@ -1272,7 +1272,7 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
                        if (!(af = nla_nest_start(skb, af_ops->family)))
                                goto nla_put_failure;
 
-                       err = af_ops->fill_link_af(skb, dev);
+                       err = af_ops->fill_link_af(skb, dev, ext_filter_mask);
 
                        /*
                         * Caller may return ENODATA to indicate that there
index 2d9cb17..7350084 100644 (file)
@@ -1654,7 +1654,8 @@ static size_t inet_get_link_af_size(const struct net_device *dev)
        return nla_total_size(IPV4_DEVCONF_MAX * 4); /* IFLA_INET_CONF */
 }
 
-static int inet_fill_link_af(struct sk_buff *skb, const struct net_device *dev)
+static int inet_fill_link_af(struct sk_buff *skb, const struct net_device *dev,
+                            u32 ext_filter_mask)
 {
        struct in_device *in_dev = rcu_dereference_rtnl(dev->ip_ptr);
        struct nlattr *nla;
index 030fefd..75d3dde 100644 (file)
@@ -4729,7 +4729,8 @@ static void snmp6_fill_stats(u64 *stats, struct inet6_dev *idev, int attrtype,
        }
 }
 
-static int inet6_fill_ifla6_attrs(struct sk_buff *skb, struct inet6_dev *idev)
+static int inet6_fill_ifla6_attrs(struct sk_buff *skb, struct inet6_dev *idev,
+                                 u32 ext_filter_mask)
 {
        struct nlattr *nla;
        struct ifla_cacheinfo ci;
@@ -4749,6 +4750,9 @@ static int inet6_fill_ifla6_attrs(struct sk_buff *skb, struct inet6_dev *idev)
 
        /* XXX - MC not implemented */
 
+       if (ext_filter_mask & RTEXT_FILTER_SKIP_STATS)
+               return 0;
+
        nla = nla_reserve(skb, IFLA_INET6_STATS, IPSTATS_MIB_MAX * sizeof(u64));
        if (!nla)
                goto nla_put_failure;
@@ -4784,14 +4788,15 @@ static size_t inet6_get_link_af_size(const struct net_device *dev)
        return inet6_ifla6_size();
 }
 
-static int inet6_fill_link_af(struct sk_buff *skb, const struct net_device *dev)
+static int inet6_fill_link_af(struct sk_buff *skb, const struct net_device *dev,
+                             u32 ext_filter_mask)
 {
        struct inet6_dev *idev = __in6_dev_get(dev);
 
        if (!idev)
                return -ENODATA;
 
-       if (inet6_fill_ifla6_attrs(skb, idev) < 0)
+       if (inet6_fill_ifla6_attrs(skb, idev, ext_filter_mask) < 0)
                return -EMSGSIZE;
 
        return 0;
@@ -4946,7 +4951,7 @@ static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev,
        if (!protoinfo)
                goto nla_put_failure;
 
-       if (inet6_fill_ifla6_attrs(skb, idev) < 0)
+       if (inet6_fill_ifla6_attrs(skb, idev, 0) < 0)
                goto nla_put_failure;
 
        nla_nest_end(skb, protoinfo);