aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/devinet.c
diff options
context:
space:
mode:
authorEric Dumazet <eric.dumazet@gmail.com>2009-11-12 02:44:25 -0500
committerDavid S. Miller <davem@davemloft.net>2009-11-13 23:46:55 -0500
commiteec4df9885f7822cdeca82577a25cac4598fa7cf (patch)
tree36295f78f105e3f69b571edb3b2feddaf99dfb73 /net/ipv4/devinet.c
parent342bde1b70c79bfc8509b017b3987f3c7541ff8e (diff)
ipv4: speedup inet_dump_ifaddr()
Stephen Hemminger a écrit : > On Thu, 12 Nov 2009 15:11:36 +0100 > Eric Dumazet <eric.dumazet@gmail.com> wrote: > >> When handling large number of netdevices, inet_dump_ifaddr() >> is very slow because it has O(N^2) complexity. >> >> Instead of scanning one single list, we can use the NETDEV_HASHENTRIES >> sub lists of the dev_index hash table, and RCU lookups. >> >> Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> > > You might be able to make RCU critical section smaller by moving > it into loop. > Indeed. But we dump at most one skb (<= 8192 bytes ?), so rcu_read_lock holding time is small, unless we meet many netdevices without addresses. I wonder if its really common... Thanks [PATCH net-next-2.6] ipv4: speedup inet_dump_ifaddr() When handling large number of netdevices, inet_dump_ifaddr() is very slow because it has O(N2) complexity. Instead of scanning one single list, we can use the NETDEV_HASHENTRIES sub lists of the dev_index hash table, and RCU lookups. Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Acked-by: Stephen Hemminger <shemminger@vyatta.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/devinet.c')
-rw-r--r--net/ipv4/devinet.c61
1 files changed, 38 insertions, 23 deletions
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index c2045f9615da..7620382058a0 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -1174,39 +1174,54 @@ nla_put_failure:
1174static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) 1174static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
1175{ 1175{
1176 struct net *net = sock_net(skb->sk); 1176 struct net *net = sock_net(skb->sk);
1177 int idx, ip_idx; 1177 int h, s_h;
1178 int idx, s_idx;
1179 int ip_idx, s_ip_idx;
1178 struct net_device *dev; 1180 struct net_device *dev;
1179 struct in_device *in_dev; 1181 struct in_device *in_dev;
1180 struct in_ifaddr *ifa; 1182 struct in_ifaddr *ifa;
1181 int s_ip_idx, s_idx = cb->args[0]; 1183 struct hlist_head *head;
1184 struct hlist_node *node;
1182 1185
1183 s_ip_idx = ip_idx = cb->args[1]; 1186 s_h = cb->args[0];
1184 idx = 0; 1187 s_idx = idx = cb->args[1];
1185 for_each_netdev(net, dev) { 1188 s_ip_idx = ip_idx = cb->args[2];
1186 if (idx < s_idx)
1187 goto cont;
1188 if (idx > s_idx)
1189 s_ip_idx = 0;
1190 in_dev = __in_dev_get_rtnl(dev);
1191 if (!in_dev)
1192 goto cont;
1193 1189
1194 for (ifa = in_dev->ifa_list, ip_idx = 0; ifa; 1190 for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
1195 ifa = ifa->ifa_next, ip_idx++) { 1191 idx = 0;
1196 if (ip_idx < s_ip_idx) 1192 head = &net->dev_index_head[h];
1197 continue; 1193 rcu_read_lock();
1198 if (inet_fill_ifaddr(skb, ifa, NETLINK_CB(cb->skb).pid, 1194 hlist_for_each_entry_rcu(dev, node, head, index_hlist) {
1195 if (idx < s_idx)
1196 goto cont;
1197 if (idx > s_idx)
1198 s_ip_idx = 0;
1199 in_dev = __in_dev_get_rcu(dev);
1200 if (!in_dev)
1201 goto cont;
1202
1203 for (ifa = in_dev->ifa_list, ip_idx = 0; ifa;
1204 ifa = ifa->ifa_next, ip_idx++) {
1205 if (ip_idx < s_ip_idx)
1206 continue;
1207 if (inet_fill_ifaddr(skb, ifa,
1208 NETLINK_CB(cb->skb).pid,
1199 cb->nlh->nlmsg_seq, 1209 cb->nlh->nlmsg_seq,
1200 RTM_NEWADDR, NLM_F_MULTI) <= 0) 1210 RTM_NEWADDR, NLM_F_MULTI) <= 0) {
1201 goto done; 1211 rcu_read_unlock();
1202 } 1212 goto done;
1213 }
1214 }
1203cont: 1215cont:
1204 idx++; 1216 idx++;
1217 }
1218 rcu_read_unlock();
1205 } 1219 }
1206 1220
1207done: 1221done:
1208 cb->args[0] = idx; 1222 cb->args[0] = h;
1209 cb->args[1] = ip_idx; 1223 cb->args[1] = idx;
1224 cb->args[2] = ip_idx;
1210 1225
1211 return skb->len; 1226 return skb->len;
1212} 1227}