Skip to content

Commit 7c28bd0

Browse files
Eric Dumazetdavem330
authored andcommitted
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]> Signed-off-by: David S. Miller <[email protected]>
1 parent 8d5b2c0 commit 7c28bd0

File tree

3 files changed

+30
-18
lines changed

3 files changed

+30
-18
lines changed

include/net/net_namespace.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ struct ctl_table_header;
2828
struct net_generic;
2929
struct sock;
3030

31+
32+
#define NETDEV_HASHBITS 8
33+
#define NETDEV_HASHENTRIES (1 << NETDEV_HASHBITS)
34+
3135
struct net {
3236
atomic_t count; /* To decided when the network
3337
* namespace should be freed.

net/core/dev.c

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -193,18 +193,15 @@ static struct list_head ptype_all __read_mostly; /* Taps */
193193
DEFINE_RWLOCK(dev_base_lock);
194194
EXPORT_SYMBOL(dev_base_lock);
195195

196-
#define NETDEV_HASHBITS 8
197-
#define NETDEV_HASHENTRIES (1 << NETDEV_HASHBITS)
198-
199196
static inline struct hlist_head *dev_name_hash(struct net *net, const char *name)
200197
{
201198
unsigned hash = full_name_hash(name, strnlen(name, IFNAMSIZ));
202-
return &net->dev_name_head[hash & ((1 << NETDEV_HASHBITS) - 1)];
199+
return &net->dev_name_head[hash & (NETDEV_HASHENTRIES - 1)];
203200
}
204201

205202
static inline struct hlist_head *dev_index_hash(struct net *net, int ifindex)
206203
{
207-
return &net->dev_index_head[ifindex & ((1 << NETDEV_HASHBITS) - 1)];
204+
return &net->dev_index_head[ifindex & (NETDEV_HASHENTRIES - 1)];
208205
}
209206

210207
/* Device list insertion */

net/core/rtnetlink.c

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -682,22 +682,33 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
682682
static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
683683
{
684684
struct net *net = sock_net(skb->sk);
685-
int idx;
686-
int s_idx = cb->args[0];
685+
int h, s_h;
686+
int idx = 0, s_idx;
687687
struct net_device *dev;
688-
689-
idx = 0;
690-
for_each_netdev(net, dev) {
691-
if (idx < s_idx)
692-
goto cont;
693-
if (rtnl_fill_ifinfo(skb, dev, RTM_NEWLINK,
694-
NETLINK_CB(cb->skb).pid,
695-
cb->nlh->nlmsg_seq, 0, NLM_F_MULTI) <= 0)
696-
break;
688+
struct hlist_head *head;
689+
struct hlist_node *node;
690+
691+
s_h = cb->args[0];
692+
s_idx = cb->args[1];
693+
694+
for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
695+
idx = 0;
696+
head = &net->dev_index_head[h];
697+
hlist_for_each_entry(dev, node, head, index_hlist) {
698+
if (idx < s_idx)
699+
goto cont;
700+
if (rtnl_fill_ifinfo(skb, dev, RTM_NEWLINK,
701+
NETLINK_CB(cb->skb).pid,
702+
cb->nlh->nlmsg_seq, 0,
703+
NLM_F_MULTI) <= 0)
704+
goto out;
697705
cont:
698-
idx++;
706+
idx++;
707+
}
699708
}
700-
cb->args[0] = idx;
709+
out:
710+
cb->args[1] = idx;
711+
cb->args[0] = h;
701712

702713
return skb->len;
703714
}

0 commit comments

Comments
 (0)