diff options
author | David S. Miller <davem@davemloft.net> | 2011-02-18 15:42:28 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-02-18 15:42:28 -0500 |
commit | fd23c3b31107e2fc483301ee923d8a1db14e53f4 (patch) | |
tree | a9f6628d11b135660418c1ba5edb23c3c75cc0e9 /net/ipv4/devinet.c | |
parent | 1cbb1a61d59b7552e1e3fde485d8af5699fe16e0 (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.c | 45 |
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 | ||
101 | static struct hlist_head inet_addr_lst[IN4_ADDR_HSIZE]; | ||
102 | static DEFINE_SPINLOCK(inet_addr_hash_lock); | ||
103 | |||
104 | static 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 | |||
112 | static 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 | |||
121 | static 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 | |||
95 | static void rtmsg_ifa(int event, struct in_ifaddr *, struct nlmsghdr *, u32); | 128 | static void rtmsg_ifa(int event, struct in_ifaddr *, struct nlmsghdr *, u32); |
96 | 129 | ||
97 | static BLOCKING_NOTIFIER_HEAD(inetaddr_chain); | 130 | static 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 | ||
1711 | void __init devinet_init(void) | 1751 | void __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); |