aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/devinet.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2011-02-18 15:42:28 -0500
committerDavid S. Miller <davem@davemloft.net>2011-02-18 15:42:28 -0500
commitfd23c3b31107e2fc483301ee923d8a1db14e53f4 (patch)
treea9f6628d11b135660418c1ba5edb23c3c75cc0e9 /net/ipv4/devinet.c
parent1cbb1a61d59b7552e1e3fde485d8af5699fe16e0 (diff)
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>
Diffstat (limited to 'net/ipv4/devinet.c')
-rw-r--r--net/ipv4/devinet.c45
1 files changed, 45 insertions, 0 deletions
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index 748cb5b337bd..2fe50765a672 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -51,6 +51,7 @@
51#include <linux/inetdevice.h> 51#include <linux/inetdevice.h>
52#include <linux/igmp.h> 52#include <linux/igmp.h>
53#include <linux/slab.h> 53#include <linux/slab.h>
54#include <linux/hash.h>
54#ifdef CONFIG_SYSCTL 55#ifdef CONFIG_SYSCTL
55#include <linux/sysctl.h> 56#include <linux/sysctl.h>
56#endif 57#endif
@@ -92,6 +93,38 @@ static const struct nla_policy ifa_ipv4_policy[IFA_MAX+1] = {
92 [IFA_LABEL] = { .type = NLA_STRING, .len = IFNAMSIZ - 1 }, 93 [IFA_LABEL] = { .type = NLA_STRING, .len = IFNAMSIZ - 1 },
93}; 94};
94 95
96/* inet_addr_hash's shifting is dependent upon this IN4_ADDR_HSIZE
97 * value. So if you change this define, make appropriate changes to
98 * inet_addr_hash as well.
99 */
100#define IN4_ADDR_HSIZE 256
101static struct hlist_head inet_addr_lst[IN4_ADDR_HSIZE];
102static DEFINE_SPINLOCK(inet_addr_hash_lock);
103
104static inline unsigned int inet_addr_hash(struct net *net, __be32 addr)
105{
106 u32 val = (__force u32) addr ^ hash_ptr(net, 8);
107
108 return ((val ^ (val >> 8) ^ (val >> 16) ^ (val >> 24)) &
109 (IN4_ADDR_HSIZE - 1));
110}
111
112static void inet_hash_insert(struct net *net, struct in_ifaddr *ifa)
113{
114 unsigned int hash = inet_addr_hash(net, ifa->ifa_address);
115
116 spin_lock(&inet_addr_hash_lock);
117 hlist_add_head_rcu(&ifa->hash, &inet_addr_lst[hash]);
118 spin_unlock(&inet_addr_hash_lock);
119}
120
121static void inet_hash_remove(struct in_ifaddr *ifa)
122{
123 spin_lock(&inet_addr_hash_lock);
124 hlist_del_init_rcu(&ifa->hash);
125 spin_unlock(&inet_addr_hash_lock);
126}
127
95static void rtmsg_ifa(int event, struct in_ifaddr *, struct nlmsghdr *, u32); 128static void rtmsg_ifa(int event, struct in_ifaddr *, struct nlmsghdr *, u32);
96 129
97static BLOCKING_NOTIFIER_HEAD(inetaddr_chain); 130static BLOCKING_NOTIFIER_HEAD(inetaddr_chain);
@@ -265,6 +298,7 @@ static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
265 } 298 }
266 299
267 if (!do_promote) { 300 if (!do_promote) {
301 inet_hash_remove(ifa);
268 *ifap1 = ifa->ifa_next; 302 *ifap1 = ifa->ifa_next;
269 303
270 rtmsg_ifa(RTM_DELADDR, ifa, nlh, pid); 304 rtmsg_ifa(RTM_DELADDR, ifa, nlh, pid);
@@ -281,6 +315,7 @@ static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
281 /* 2. Unlink it */ 315 /* 2. Unlink it */
282 316
283 *ifap = ifa1->ifa_next; 317 *ifap = ifa1->ifa_next;
318 inet_hash_remove(ifa1);
284 319
285 /* 3. Announce address deletion */ 320 /* 3. Announce address deletion */
286 321
@@ -368,6 +403,8 @@ static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh,
368 ifa->ifa_next = *ifap; 403 ifa->ifa_next = *ifap;
369 *ifap = ifa; 404 *ifap = ifa;
370 405
406 inet_hash_insert(dev_net(in_dev->dev), ifa);
407
371 /* Send message first, then call notifier. 408 /* Send message first, then call notifier.
372 Notifier will trigger FIB update, so that 409 Notifier will trigger FIB update, so that
373 listeners of netlink will know about new ifaddr */ 410 listeners of netlink will know about new ifaddr */
@@ -521,6 +558,7 @@ static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh)
521 if (tb[IFA_ADDRESS] == NULL) 558 if (tb[IFA_ADDRESS] == NULL)
522 tb[IFA_ADDRESS] = tb[IFA_LOCAL]; 559 tb[IFA_ADDRESS] = tb[IFA_LOCAL];
523 560
561 INIT_HLIST_NODE(&ifa->hash);
524 ifa->ifa_prefixlen = ifm->ifa_prefixlen; 562 ifa->ifa_prefixlen = ifm->ifa_prefixlen;
525 ifa->ifa_mask = inet_make_mask(ifm->ifa_prefixlen); 563 ifa->ifa_mask = inet_make_mask(ifm->ifa_prefixlen);
526 ifa->ifa_flags = ifm->ifa_flags; 564 ifa->ifa_flags = ifm->ifa_flags;
@@ -728,6 +766,7 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg)
728 if (!ifa) { 766 if (!ifa) {
729 ret = -ENOBUFS; 767 ret = -ENOBUFS;
730 ifa = inet_alloc_ifa(); 768 ifa = inet_alloc_ifa();
769 INIT_HLIST_NODE(&ifa->hash);
731 if (!ifa) 770 if (!ifa)
732 break; 771 break;
733 if (colon) 772 if (colon)
@@ -1069,6 +1108,7 @@ static int inetdev_event(struct notifier_block *this, unsigned long event,
1069 struct in_ifaddr *ifa = inet_alloc_ifa(); 1108 struct in_ifaddr *ifa = inet_alloc_ifa();
1070 1109
1071 if (ifa) { 1110 if (ifa) {
1111 INIT_HLIST_NODE(&ifa->hash);
1072 ifa->ifa_local = 1112 ifa->ifa_local =
1073 ifa->ifa_address = htonl(INADDR_LOOPBACK); 1113 ifa->ifa_address = htonl(INADDR_LOOPBACK);
1074 ifa->ifa_prefixlen = 8; 1114 ifa->ifa_prefixlen = 8;
@@ -1710,6 +1750,11 @@ static struct rtnl_af_ops inet_af_ops = {
1710 1750
1711void __init devinet_init(void) 1751void __init devinet_init(void)
1712{ 1752{
1753 int i;
1754
1755 for (i = 0; i < IN4_ADDR_HSIZE; i++)
1756 INIT_HLIST_HEAD(&inet_addr_lst[i]);
1757
1713 register_pernet_subsys(&devinet_ops); 1758 register_pernet_subsys(&devinet_ops);
1714 1759
1715 register_gifconf(PF_INET, inet_gifconf); 1760 register_gifconf(PF_INET, inet_gifconf);