Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ipv4: Add hash table of interface addresses.

This will be used to optimize __ip_dev_find() and friends.

With help from Eric Dumazet.

Signed-off-by: David S. Miller <davem@davemloft.net>

+46
+1
include/linux/inetdevice.h
··· 144 144 #define IN_DEV_ARP_NOTIFY(in_dev) IN_DEV_MAXCONF((in_dev), ARP_NOTIFY) 145 145 146 146 struct in_ifaddr { 147 + struct hlist_node hash; 147 148 struct in_ifaddr *ifa_next; 148 149 struct in_device *ifa_dev; 149 150 struct rcu_head rcu_head;
+45
net/ipv4/devinet.c
··· 51 51 #include <linux/inetdevice.h> 52 52 #include <linux/igmp.h> 53 53 #include <linux/slab.h> 54 + #include <linux/hash.h> 54 55 #ifdef CONFIG_SYSCTL 55 56 #include <linux/sysctl.h> 56 57 #endif ··· 92 91 [IFA_BROADCAST] = { .type = NLA_U32 }, 93 92 [IFA_LABEL] = { .type = NLA_STRING, .len = IFNAMSIZ - 1 }, 94 93 }; 94 + 95 + /* inet_addr_hash's shifting is dependent upon this IN4_ADDR_HSIZE 96 + * value. So if you change this define, make appropriate changes to 97 + * inet_addr_hash as well. 98 + */ 99 + #define IN4_ADDR_HSIZE 256 100 + static struct hlist_head inet_addr_lst[IN4_ADDR_HSIZE]; 101 + static DEFINE_SPINLOCK(inet_addr_hash_lock); 102 + 103 + static inline unsigned int inet_addr_hash(struct net *net, __be32 addr) 104 + { 105 + u32 val = (__force u32) addr ^ hash_ptr(net, 8); 106 + 107 + return ((val ^ (val >> 8) ^ (val >> 16) ^ (val >> 24)) & 108 + (IN4_ADDR_HSIZE - 1)); 109 + } 110 + 111 + static void inet_hash_insert(struct net *net, struct in_ifaddr *ifa) 112 + { 113 + unsigned int hash = inet_addr_hash(net, ifa->ifa_address); 114 + 115 + spin_lock(&inet_addr_hash_lock); 116 + hlist_add_head_rcu(&ifa->hash, &inet_addr_lst[hash]); 117 + spin_unlock(&inet_addr_hash_lock); 118 + } 119 + 120 + static void inet_hash_remove(struct in_ifaddr *ifa) 121 + { 122 + spin_lock(&inet_addr_hash_lock); 123 + hlist_del_init_rcu(&ifa->hash); 124 + spin_unlock(&inet_addr_hash_lock); 125 + } 95 126 96 127 static void rtmsg_ifa(int event, struct in_ifaddr *, struct nlmsghdr *, u32); 97 128 ··· 298 265 } 299 266 300 267 if (!do_promote) { 268 + inet_hash_remove(ifa); 301 269 *ifap1 = ifa->ifa_next; 302 270 303 271 rtmsg_ifa(RTM_DELADDR, ifa, nlh, pid); ··· 315 281 /* 2. Unlink it */ 316 282 317 283 *ifap = ifa1->ifa_next; 284 + inet_hash_remove(ifa1); 318 285 319 286 /* 3. Announce address deletion */ 320 287 ··· 402 367 403 368 ifa->ifa_next = *ifap; 404 369 *ifap = ifa; 370 + 371 + inet_hash_insert(dev_net(in_dev->dev), ifa); 405 372 406 373 /* Send message first, then call notifier. 407 374 Notifier will trigger FIB update, so that ··· 558 521 if (tb[IFA_ADDRESS] == NULL) 559 522 tb[IFA_ADDRESS] = tb[IFA_LOCAL]; 560 523 524 + INIT_HLIST_NODE(&ifa->hash); 561 525 ifa->ifa_prefixlen = ifm->ifa_prefixlen; 562 526 ifa->ifa_mask = inet_make_mask(ifm->ifa_prefixlen); 563 527 ifa->ifa_flags = ifm->ifa_flags; ··· 766 728 if (!ifa) { 767 729 ret = -ENOBUFS; 768 730 ifa = inet_alloc_ifa(); 731 + INIT_HLIST_NODE(&ifa->hash); 769 732 if (!ifa) 770 733 break; 771 734 if (colon) ··· 1108 1069 struct in_ifaddr *ifa = inet_alloc_ifa(); 1109 1070 1110 1071 if (ifa) { 1072 + INIT_HLIST_NODE(&ifa->hash); 1111 1073 ifa->ifa_local = 1112 1074 ifa->ifa_address = htonl(INADDR_LOOPBACK); 1113 1075 ifa->ifa_prefixlen = 8; ··· 1750 1710 1751 1711 void __init devinet_init(void) 1752 1712 { 1713 + int i; 1714 + 1715 + for (i = 0; i < IN4_ADDR_HSIZE; i++) 1716 + INIT_HLIST_HEAD(&inet_addr_lst[i]); 1717 + 1753 1718 register_pernet_subsys(&devinet_ops); 1754 1719 1755 1720 register_gifconf(PF_INET, inet_gifconf);