rtnetlink: speedup rtnl_dump_ifinfo()
Subsystems (2)
PATCH 1/1 rtnetlink: speedup rtnl_dump_ifinfo()
When handling large number of netdevice, rtnl_dump_ifinfo() is very slow because it has O(N^2) complexity.
Instead of scanning one single list, we can use the 256 sub lists of the dev_index hash table.
This considerably speedups "ip link" operations
Signed-off-by Eric Dumazet <[email protected]>
--- include/net/net_namespace.h | 4 +++ net/core/dev.c | 7 +----- net/core/rtnetlink.c | 37 ++++++++++++++++++++++------------ 3 files changed, 30 insertions(+), 18 deletions(-)
include/net/net_namespace.h +4 -0
@@ -28,6 +28,10 @@ struct ctl_table_header;struct net_generic ;struct sock ; + +#define NETDEV_HASHBITS 8 +#define NETDEV_HASHENTRIES (1 << NETDEV_HASHBITS) +struct net {atomic_t count;/* To decided when the network * namespace should be freed.
net/core/dev.c +2 -5
@@ -193,18 +193,15 @@ static struct list_head ptype_all __read_mostly; /* Taps */DEFINE_RWLOCK (dev_base_lock);EXPORT_SYMBOL (dev_base_lock); -#define NETDEV_HASHBITS 8 -#define NETDEV_HASHENTRIES (1 << NETDEV_HASHBITS) -static inline struct hlist_head *dev_name_hash (struct net *net,const char *name) {unsigned hash =full_name_hash (name,strnlen (name,IFNAMSIZ )); -return &net->dev_name_head[hash & ((1 <<NETDEV_HASHBITS ) -1 )]; +return &net->dev_name_head[hash & (NETDEV_HASHENTRIES -1 )]; }static inline struct hlist_head *dev_index_hash (struct net *net,int ifindex) { -return &net->dev_index_head[ifindex & ((1 <<NETDEV_HASHBITS ) -1 )]; +return &net->dev_index_head[ifindex & (NETDEV_HASHENTRIES -1 )]; }/* Device list insertion */
net/core/rtnetlink.c +24 -13
@@ -682,22 +682,33 @@ nla_put_failure:static int rtnl_dump_ifinfo (struct sk_buff *skb,struct netlink_callback *cb) {struct net *net =sock_net (skb->sk); -int idx; -int s_idx = cb->args[0 ]; +int h, s_h; +int idx =0 , s_idx;struct net_device *dev; - - idx =0 ; -for_each_netdev (net, dev) { -if (idx < s_idx) - goto cont; -if (rtnl_fill_ifinfo (skb, dev,RTM_NEWLINK , -NETLINK_CB (cb->skb).pid, - cb->nlh->nlmsg_seq,0 ,NLM_F_MULTI ) <=0 ) -break ; +struct hlist_head *head; +struct hlist_node *node; + + s_h = cb->args[0 ]; + s_idx = cb->args[1 ]; + +for (h = s_h; h <NETDEV_HASHENTRIES ; h++, s_idx =0 ) { + idx =0 ; + head = &net->dev_index_head[h]; +hlist_for_each_entry (dev, node, head, index_hlist) { +if (idx < s_idx) + goto cont; +if (rtnl_fill_ifinfo (skb, dev,RTM_NEWLINK , +NETLINK_CB (cb->skb).pid, + cb->nlh->nlmsg_seq,0 , +NLM_F_MULTI ) <=0 ) + goto out; cont: - idx++; + idx++; + } } - cb->args[0 ] = idx; +out: + cb->args[1 ] = idx; + cb->args[0 ] = h;return skb->len; }
From: Eric Dumazet <[email protected]>
Date: Thu, 22 Oct 2009 16:34:41 +0200
Quoted 9 lines
When handling large number of netdevice,
rtnl_dump_ifinfo()is very slow because it has O(N^2) complexity.Instead of scanning one single list, we can use the 256 sub lists of the
dev_indexhash table.This considerably speedups "ip link" operations
Signed-off-by Eric Dumazet <[email protected]>
Applied, thanks!