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.
Unified · Split
| @@ -122,7 +122,8 @@ struct rtnl_af_ops { · 121 unmodified lines | |||
| 122 | int family; | 122 | int family; |
| 123 | 123 | ||
| 124 | int (*fill_link_af)(struct sk_buff *skb, | 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 | size_t (*get_link_af_size)(const struct net_device *dev); | 127 | size_t (*get_link_af_size)(const struct net_device *dev); |
| 127 | 128 | ||
| 128 | int (*validate_link_af)(const struct net_device *dev, | 129 | int (*validate_link_af)(const struct net_device *dev, |
| @@ -667,6 +667,7 @@ struct tcamsg { · 666 unmodified lines | |||
| 667 | #define RTEXT_FILTER_VF (1 << 0) | 667 | #define RTEXT_FILTER_VF (1 << 0) |
| 668 | #define RTEXT_FILTER_BRVLAN (1 << 1) | 668 | #define RTEXT_FILTER_BRVLAN (1 << 1) |
| 669 | #define RTEXT_FILTER_BRVLAN_COMPRESSED (1 << 2) | 669 | #define RTEXT_FILTER_BRVLAN_COMPRESSED (1 << 2) |
| 670 | #define RTEXT_FILTER_SKIP_STATS (1 << 3) | ||
| 670 | 671 | ||
| 671 | /* End of information exported to user level */ | 672 | /* End of information exported to user level */ |
| 672 | 673 | ||
| @@ -1272,7 +1272,7 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, · 1271 unmodified lines | |||
| 1272 | if (!(af = nla_nest_start(skb, af_ops->family))) | 1272 | if (!(af = nla_nest_start(skb, af_ops->family))) |
| 1273 | goto nla_put_failure; | 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 | * Caller may return ENODATA to indicate that there | 1278 | * Caller may return ENODATA to indicate that there |
| @@ -1654,7 +1654,8 @@ static size_t inet_get_link_af_size(const struct net_device *dev) · 1653 unmodified lines | |||
| 1654 | return nla_total_size(IPV4_DEVCONF_MAX * 4); /* IFLA_INET_CONF */ | 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 | struct in_device *in_dev = rcu_dereference_rtnl(dev->ip_ptr); | 1660 | struct in_device *in_dev = rcu_dereference_rtnl(dev->ip_ptr); |
| 1660 | struct nlattr *nla; | 1661 | struct nlattr *nla; |
| @@ -4729,7 +4729,8 @@ static void snmp6_fill_stats(u64 *stats, struct inet6_dev *idev, int attrtype, · 4728 unmodified lines | |||
| 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 | struct nlattr *nla; | 4735 | struct nlattr *nla; |
| 4735 | struct ifla_cacheinfo ci; | 4736 | struct ifla_cacheinfo ci; |
| @@ -4749,6 +4750,9 @@ static int inet6_fill_ifla6_attrs(struct sk_buff *skb, struct inet6_dev *idev) · 13 unmodified lines | |||
| 4749 | 4750 | ||
| 4750 | /* XXX - MC not implemented */ | 4751 | /* XXX - MC not implemented */ |
| 4751 | 4752 | ||
| 4753 | if (ext_filter_mask & RTEXT_FILTER_SKIP_STATS) | ||
| 4754 | return 0; | ||
| 4755 | |||
| 4752 | nla = nla_reserve(skb, IFLA_INET6_STATS, IPSTATS_MIB_MAX * sizeof(u64)); | 4756 | nla = nla_reserve(skb, IFLA_INET6_STATS, IPSTATS_MIB_MAX * sizeof(u64)); |
| 4753 | if (!nla) | 4757 | if (!nla) |
| 4754 | goto nla_put_failure; | 4758 | goto nla_put_failure; |
| @@ -4784,14 +4788,15 @@ static size_t inet6_get_link_af_size(const struct net_device *dev) · 29 unmodified lines | |||
| 4784 | return inet6_ifla6_size(); | 4788 | return inet6_ifla6_size(); |
| 4785 | } | 4789 | } |
| 4786 | 4790 | ||
| 4787 | static int inet6_fill_link_af(struct sk_buff *skb, const struct net_device *dev) | 4791 | static int inet6_fill_link_af(struct sk_buff *skb, const struct net_device *dev, |
| 4792 | u32 ext_filter_mask) | ||
| 4788 | { | 4793 | { |
| 4789 | struct inet6_dev *idev = __in6_dev_get(dev); | 4794 | struct inet6_dev *idev = __in6_dev_get(dev); |
| 4790 | 4795 | ||
| 4791 | if (!idev) | 4796 | if (!idev) |
| 4792 | return -ENODATA; | 4797 | return -ENODATA; |
| 4793 | 4798 | ||
| 4794 | if (inet6_fill_ifla6_attrs(skb, idev) < 0) | 4799 | if (inet6_fill_ifla6_attrs(skb, idev, ext_filter_mask) < 0) |
| 4795 | return -EMSGSIZE; | 4800 | return -EMSGSIZE; |
| 4796 | 4801 | ||
| 4797 | return 0; | 4802 | return 0; |
| @@ -4946,7 +4951,7 @@ static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev, · 148 unmodified lines | |||
| 4946 | if (!protoinfo) | 4951 | if (!protoinfo) |
| 4947 | goto nla_put_failure; | 4952 | goto nla_put_failure; |
| 4948 | 4953 | ||
| 4949 | if (inet6_fill_ifla6_attrs(skb, idev) < 0) | 4954 | if (inet6_fill_ifla6_attrs(skb, idev, 0) < 0) |
| 4950 | goto nla_put_failure; | 4955 | goto nla_put_failure; |
| 4951 | 4956 | ||
| 4952 | nla_nest_end(skb, protoinfo); | 4957 | nla_nest_end(skb, protoinfo); |