aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/arp.h19
-rw-r--r--include/net/ndisc.h19
-rw-r--r--include/net/neighbour.h52
-rw-r--r--net/core/neighbour.c20
-rw-r--r--net/decnet/dn_neigh.c6
-rw-r--r--net/ipv4/arp.c9
-rw-r--r--net/ipv6/ndisc.c7
7 files changed, 83 insertions, 49 deletions
diff --git a/include/net/arp.h b/include/net/arp.h
index 21ee1860abbc..5e0f891d476c 100644
--- a/include/net/arp.h
+++ b/include/net/arp.h
@@ -9,28 +9,17 @@
9 9
10extern struct neigh_table arp_tbl; 10extern struct neigh_table arp_tbl;
11 11
12static inline u32 arp_hashfn(u32 key, const struct net_device *dev, u32 hash_rnd) 12static inline u32 arp_hashfn(const void *pkey, const struct net_device *dev, u32 *hash_rnd)
13{ 13{
14 u32 key = *(const u32 *)pkey;
14 u32 val = key ^ hash32_ptr(dev); 15 u32 val = key ^ hash32_ptr(dev);
15 16
16 return val * hash_rnd; 17 return val * hash_rnd[0];
17} 18}
18 19
19static inline struct neighbour *__ipv4_neigh_lookup_noref(struct net_device *dev, u32 key) 20static inline struct neighbour *__ipv4_neigh_lookup_noref(struct net_device *dev, u32 key)
20{ 21{
21 struct neigh_hash_table *nht = rcu_dereference_bh(arp_tbl.nht); 22 return ___neigh_lookup_noref(&arp_tbl, neigh_key_eq32, arp_hashfn, &key, dev);
22 struct neighbour *n;
23 u32 hash_val;
24
25 hash_val = arp_hashfn(key, dev, nht->hash_rnd[0]) >> (32 - nht->hash_shift);
26 for (n = rcu_dereference_bh(nht->hash_buckets[hash_val]);
27 n != NULL;
28 n = rcu_dereference_bh(n->next)) {
29 if (n->dev == dev && *(u32 *)n->primary_key == key)
30 return n;
31 }
32
33 return NULL;
34} 23}
35 24
36static inline struct neighbour *__ipv4_neigh_lookup(struct net_device *dev, u32 key) 25static inline struct neighbour *__ipv4_neigh_lookup(struct net_device *dev, u32 key)
diff --git a/include/net/ndisc.h b/include/net/ndisc.h
index 6bbda34d5e59..b3a7751251b4 100644
--- a/include/net/ndisc.h
+++ b/include/net/ndisc.h
@@ -156,24 +156,7 @@ static inline u32 ndisc_hashfn(const void *pkey, const struct net_device *dev, _
156 156
157static inline struct neighbour *__ipv6_neigh_lookup_noref(struct net_device *dev, const void *pkey) 157static inline struct neighbour *__ipv6_neigh_lookup_noref(struct net_device *dev, const void *pkey)
158{ 158{
159 struct neigh_hash_table *nht; 159 return ___neigh_lookup_noref(&nd_tbl, neigh_key_eq128, ndisc_hashfn, pkey, dev);
160 const u32 *p32 = pkey;
161 struct neighbour *n;
162 u32 hash_val;
163
164 nht = rcu_dereference_bh(nd_tbl.nht);
165 hash_val = ndisc_hashfn(pkey, dev, nht->hash_rnd) >> (32 - nht->hash_shift);
166 for (n = rcu_dereference_bh(nht->hash_buckets[hash_val]);
167 n != NULL;
168 n = rcu_dereference_bh(n->next)) {
169 u32 *n32 = (u32 *) n->primary_key;
170 if (n->dev == dev &&
171 ((n32[0] ^ p32[0]) | (n32[1] ^ p32[1]) |
172 (n32[2] ^ p32[2]) | (n32[3] ^ p32[3])) == 0)
173 return n;
174 }
175
176 return NULL;
177} 160}
178 161
179static inline struct neighbour *__ipv6_neigh_lookup(struct net_device *dev, const void *pkey) 162static inline struct neighbour *__ipv6_neigh_lookup(struct net_device *dev, const void *pkey)
diff --git a/include/net/neighbour.h b/include/net/neighbour.h
index 9f912e4d4232..14e3f017966b 100644
--- a/include/net/neighbour.h
+++ b/include/net/neighbour.h
@@ -197,6 +197,7 @@ struct neigh_table {
197 __u32 (*hash)(const void *pkey, 197 __u32 (*hash)(const void *pkey,
198 const struct net_device *dev, 198 const struct net_device *dev,
199 __u32 *hash_rnd); 199 __u32 *hash_rnd);
200 bool (*key_eq)(const struct neighbour *, const void *pkey);
200 int (*constructor)(struct neighbour *); 201 int (*constructor)(struct neighbour *);
201 int (*pconstructor)(struct pneigh_entry *); 202 int (*pconstructor)(struct pneigh_entry *);
202 void (*pdestructor)(struct pneigh_entry *); 203 void (*pdestructor)(struct pneigh_entry *);
@@ -247,6 +248,57 @@ static inline void *neighbour_priv(const struct neighbour *n)
247#define NEIGH_UPDATE_F_ISROUTER 0x40000000 248#define NEIGH_UPDATE_F_ISROUTER 0x40000000
248#define NEIGH_UPDATE_F_ADMIN 0x80000000 249#define NEIGH_UPDATE_F_ADMIN 0x80000000
249 250
251
252static inline bool neigh_key_eq16(const struct neighbour *n, const void *pkey)
253{
254 return *(const u16 *)n->primary_key == *(const u16 *)pkey;
255}
256
257static inline bool neigh_key_eq32(const struct neighbour *n, const void *pkey)
258{
259 return *(const u32 *)n->primary_key == *(const u32 *)pkey;
260}
261
262static inline bool neigh_key_eq128(const struct neighbour *n, const void *pkey)
263{
264 const u32 *n32 = (const u32 *)n->primary_key;
265 const u32 *p32 = pkey;
266
267 return ((n32[0] ^ p32[0]) | (n32[1] ^ p32[1]) |
268 (n32[2] ^ p32[2]) | (n32[3] ^ p32[3])) == 0;
269}
270
271static inline struct neighbour *___neigh_lookup_noref(
272 struct neigh_table *tbl,
273 bool (*key_eq)(const struct neighbour *n, const void *pkey),
274 __u32 (*hash)(const void *pkey,
275 const struct net_device *dev,
276 __u32 *hash_rnd),
277 const void *pkey,
278 struct net_device *dev)
279{
280 struct neigh_hash_table *nht = rcu_dereference_bh(tbl->nht);
281 struct neighbour *n;
282 u32 hash_val;
283
284 hash_val = hash(pkey, dev, nht->hash_rnd) >> (32 - nht->hash_shift);
285 for (n = rcu_dereference_bh(nht->hash_buckets[hash_val]);
286 n != NULL;
287 n = rcu_dereference_bh(n->next)) {
288 if (n->dev == dev && key_eq(n, pkey))
289 return n;
290 }
291
292 return NULL;
293}
294
295static inline struct neighbour *__neigh_lookup_noref(struct neigh_table *tbl,
296 const void *pkey,
297 struct net_device *dev)
298{
299 return ___neigh_lookup_noref(tbl, tbl->key_eq, tbl->hash, pkey, dev);
300}
301
250void neigh_table_init(int index, struct neigh_table *tbl); 302void neigh_table_init(int index, struct neigh_table *tbl);
251int neigh_table_clear(int index, struct neigh_table *tbl); 303int neigh_table_clear(int index, struct neigh_table *tbl);
252struct neighbour *neigh_lookup(struct neigh_table *tbl, const void *pkey, 304struct neighbour *neigh_lookup(struct neigh_table *tbl, const void *pkey,
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 0f48ea3affed..fe3c6eac5805 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -397,25 +397,15 @@ struct neighbour *neigh_lookup(struct neigh_table *tbl, const void *pkey,
397 struct net_device *dev) 397 struct net_device *dev)
398{ 398{
399 struct neighbour *n; 399 struct neighbour *n;
400 int key_len = tbl->key_len;
401 u32 hash_val;
402 struct neigh_hash_table *nht;
403 400
404 NEIGH_CACHE_STAT_INC(tbl, lookups); 401 NEIGH_CACHE_STAT_INC(tbl, lookups);
405 402
406 rcu_read_lock_bh(); 403 rcu_read_lock_bh();
407 nht = rcu_dereference_bh(tbl->nht); 404 n = __neigh_lookup_noref(tbl, pkey, dev);
408 hash_val = tbl->hash(pkey, dev, nht->hash_rnd) >> (32 - nht->hash_shift); 405 if (n) {
409 406 if (!atomic_inc_not_zero(&n->refcnt))
410 for (n = rcu_dereference_bh(nht->hash_buckets[hash_val]); 407 n = NULL;
411 n != NULL; 408 NEIGH_CACHE_STAT_INC(tbl, hits);
412 n = rcu_dereference_bh(n->next)) {
413 if (dev == n->dev && !memcmp(n->primary_key, pkey, key_len)) {
414 if (!atomic_inc_not_zero(&n->refcnt))
415 n = NULL;
416 NEIGH_CACHE_STAT_INC(tbl, hits);
417 break;
418 }
419 } 409 }
420 410
421 rcu_read_unlock_bh(); 411 rcu_read_unlock_bh();
diff --git a/net/decnet/dn_neigh.c b/net/decnet/dn_neigh.c
index f123c6c6748c..ee7d1cef0027 100644
--- a/net/decnet/dn_neigh.c
+++ b/net/decnet/dn_neigh.c
@@ -93,12 +93,18 @@ static u32 dn_neigh_hash(const void *pkey,
93 return jhash_2words(*(__u16 *)pkey, 0, hash_rnd[0]); 93 return jhash_2words(*(__u16 *)pkey, 0, hash_rnd[0]);
94} 94}
95 95
96static bool dn_key_eq(const struct neighbour *neigh, const void *pkey)
97{
98 return neigh_key_eq16(neigh, pkey);
99}
100
96struct neigh_table dn_neigh_table = { 101struct neigh_table dn_neigh_table = {
97 .family = PF_DECnet, 102 .family = PF_DECnet,
98 .entry_size = NEIGH_ENTRY_SIZE(sizeof(struct dn_neigh)), 103 .entry_size = NEIGH_ENTRY_SIZE(sizeof(struct dn_neigh)),
99 .key_len = sizeof(__le16), 104 .key_len = sizeof(__le16),
100 .protocol = cpu_to_be16(ETH_P_DNA_RT), 105 .protocol = cpu_to_be16(ETH_P_DNA_RT),
101 .hash = dn_neigh_hash, 106 .hash = dn_neigh_hash,
107 .key_eq = dn_key_eq,
102 .constructor = dn_neigh_construct, 108 .constructor = dn_neigh_construct,
103 .id = "dn_neigh_cache", 109 .id = "dn_neigh_cache",
104 .parms ={ 110 .parms ={
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
index 6b8aad6a0d7d..5f5c674e130a 100644
--- a/net/ipv4/arp.c
+++ b/net/ipv4/arp.c
@@ -122,6 +122,7 @@
122 * Interface to generic neighbour cache. 122 * Interface to generic neighbour cache.
123 */ 123 */
124static u32 arp_hash(const void *pkey, const struct net_device *dev, __u32 *hash_rnd); 124static u32 arp_hash(const void *pkey, const struct net_device *dev, __u32 *hash_rnd);
125static bool arp_key_eq(const struct neighbour *n, const void *pkey);
125static int arp_constructor(struct neighbour *neigh); 126static int arp_constructor(struct neighbour *neigh);
126static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb); 127static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb);
127static void arp_error_report(struct neighbour *neigh, struct sk_buff *skb); 128static void arp_error_report(struct neighbour *neigh, struct sk_buff *skb);
@@ -154,6 +155,7 @@ struct neigh_table arp_tbl = {
154 .key_len = 4, 155 .key_len = 4,
155 .protocol = cpu_to_be16(ETH_P_IP), 156 .protocol = cpu_to_be16(ETH_P_IP),
156 .hash = arp_hash, 157 .hash = arp_hash,
158 .key_eq = arp_key_eq,
157 .constructor = arp_constructor, 159 .constructor = arp_constructor,
158 .proxy_redo = parp_redo, 160 .proxy_redo = parp_redo,
159 .id = "arp_cache", 161 .id = "arp_cache",
@@ -209,7 +211,12 @@ static u32 arp_hash(const void *pkey,
209 const struct net_device *dev, 211 const struct net_device *dev,
210 __u32 *hash_rnd) 212 __u32 *hash_rnd)
211{ 213{
212 return arp_hashfn(*(u32 *)pkey, dev, *hash_rnd); 214 return arp_hashfn(pkey, dev, hash_rnd);
215}
216
217static bool arp_key_eq(const struct neighbour *neigh, const void *pkey)
218{
219 return neigh_key_eq32(neigh, pkey);
213} 220}
214 221
215static int arp_constructor(struct neighbour *neigh) 222static int arp_constructor(struct neighbour *neigh)
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index e363bbc2420d..247ad7c298f7 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -84,6 +84,7 @@ do { \
84static u32 ndisc_hash(const void *pkey, 84static u32 ndisc_hash(const void *pkey,
85 const struct net_device *dev, 85 const struct net_device *dev,
86 __u32 *hash_rnd); 86 __u32 *hash_rnd);
87static bool ndisc_key_eq(const struct neighbour *neigh, const void *pkey);
87static int ndisc_constructor(struct neighbour *neigh); 88static int ndisc_constructor(struct neighbour *neigh);
88static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb); 89static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb);
89static void ndisc_error_report(struct neighbour *neigh, struct sk_buff *skb); 90static void ndisc_error_report(struct neighbour *neigh, struct sk_buff *skb);
@@ -119,6 +120,7 @@ struct neigh_table nd_tbl = {
119 .key_len = sizeof(struct in6_addr), 120 .key_len = sizeof(struct in6_addr),
120 .protocol = cpu_to_be16(ETH_P_IPV6), 121 .protocol = cpu_to_be16(ETH_P_IPV6),
121 .hash = ndisc_hash, 122 .hash = ndisc_hash,
123 .key_eq = ndisc_key_eq,
122 .constructor = ndisc_constructor, 124 .constructor = ndisc_constructor,
123 .pconstructor = pndisc_constructor, 125 .pconstructor = pndisc_constructor,
124 .pdestructor = pndisc_destructor, 126 .pdestructor = pndisc_destructor,
@@ -295,6 +297,11 @@ static u32 ndisc_hash(const void *pkey,
295 return ndisc_hashfn(pkey, dev, hash_rnd); 297 return ndisc_hashfn(pkey, dev, hash_rnd);
296} 298}
297 299
300static bool ndisc_key_eq(const struct neighbour *n, const void *pkey)
301{
302 return neigh_key_eq128(n, pkey);
303}
304
298static int ndisc_constructor(struct neighbour *neigh) 305static int ndisc_constructor(struct neighbour *neigh)
299{ 306{
300 struct in6_addr *addr = (struct in6_addr *)&neigh->primary_key; 307 struct in6_addr *addr = (struct in6_addr *)&neigh->primary_key;