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

neigh: Factor out ___neigh_lookup_noref

While looking at the mpls code I found myself writing yet another
version of neigh_lookup_noref. We currently have __ipv4_lookup_noref
and __ipv6_lookup_noref.

So to make my work a little easier and to make it a smidge easier to
verify/maintain the mpls code in the future I stopped and wrote
___neigh_lookup_noref. Then I rewote __ipv4_lookup_noref and
__ipv6_lookup_noref in terms of this new function. I tested my new
version by verifying that the same code is generated in
ip_finish_output2 and ip6_finish_output2 where these functions are
inlined.

To get to ___neigh_lookup_noref I added a new neighbour cache table
function key_eq. So that the static size of the key would be
available.

I also added __neigh_lookup_noref for people who want to to lookup
a neighbour table entry quickly but don't know which neibhgour table
they are going to look up.

Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Eric W. Biederman and committed by
David S. Miller
60395a20 2f56f6be

+83 -49
+4 -15
include/net/arp.h
··· 9 9 10 10 extern struct neigh_table arp_tbl; 11 11 12 - static inline u32 arp_hashfn(u32 key, const struct net_device *dev, u32 hash_rnd) 12 + static inline u32 arp_hashfn(const void *pkey, const struct net_device *dev, u32 *hash_rnd) 13 13 { 14 + u32 key = *(const u32 *)pkey; 14 15 u32 val = key ^ hash32_ptr(dev); 15 16 16 - return val * hash_rnd; 17 + return val * hash_rnd[0]; 17 18 } 18 19 19 20 static 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 - 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; 22 + return ___neigh_lookup_noref(&arp_tbl, neigh_key_eq32, arp_hashfn, &key, dev); 34 23 } 35 24 36 25 static inline struct neighbour *__ipv4_neigh_lookup(struct net_device *dev, u32 key)
+1 -18
include/net/ndisc.h
··· 156 156 157 157 static inline struct neighbour *__ipv6_neigh_lookup_noref(struct net_device *dev, const void *pkey) 158 158 { 159 - struct neigh_hash_table *nht; 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; 159 + return ___neigh_lookup_noref(&nd_tbl, neigh_key_eq128, ndisc_hashfn, pkey, dev); 177 160 } 178 161 179 162 static inline struct neighbour *__ipv6_neigh_lookup(struct net_device *dev, const void *pkey)
+52
include/net/neighbour.h
··· 197 197 __u32 (*hash)(const void *pkey, 198 198 const struct net_device *dev, 199 199 __u32 *hash_rnd); 200 + bool (*key_eq)(const struct neighbour *, const void *pkey); 200 201 int (*constructor)(struct neighbour *); 201 202 int (*pconstructor)(struct pneigh_entry *); 202 203 void (*pdestructor)(struct pneigh_entry *); ··· 247 246 #define NEIGH_UPDATE_F_OVERRIDE_ISROUTER 0x00000004 248 247 #define NEIGH_UPDATE_F_ISROUTER 0x40000000 249 248 #define NEIGH_UPDATE_F_ADMIN 0x80000000 249 + 250 + 251 + static inline bool neigh_key_eq16(const struct neighbour *n, const void *pkey) 252 + { 253 + return *(const u16 *)n->primary_key == *(const u16 *)pkey; 254 + } 255 + 256 + static inline bool neigh_key_eq32(const struct neighbour *n, const void *pkey) 257 + { 258 + return *(const u32 *)n->primary_key == *(const u32 *)pkey; 259 + } 260 + 261 + static inline bool neigh_key_eq128(const struct neighbour *n, const void *pkey) 262 + { 263 + const u32 *n32 = (const u32 *)n->primary_key; 264 + const u32 *p32 = pkey; 265 + 266 + return ((n32[0] ^ p32[0]) | (n32[1] ^ p32[1]) | 267 + (n32[2] ^ p32[2]) | (n32[3] ^ p32[3])) == 0; 268 + } 269 + 270 + static inline struct neighbour *___neigh_lookup_noref( 271 + struct neigh_table *tbl, 272 + bool (*key_eq)(const struct neighbour *n, const void *pkey), 273 + __u32 (*hash)(const void *pkey, 274 + const struct net_device *dev, 275 + __u32 *hash_rnd), 276 + const void *pkey, 277 + struct net_device *dev) 278 + { 279 + struct neigh_hash_table *nht = rcu_dereference_bh(tbl->nht); 280 + struct neighbour *n; 281 + u32 hash_val; 282 + 283 + hash_val = hash(pkey, dev, nht->hash_rnd) >> (32 - nht->hash_shift); 284 + for (n = rcu_dereference_bh(nht->hash_buckets[hash_val]); 285 + n != NULL; 286 + n = rcu_dereference_bh(n->next)) { 287 + if (n->dev == dev && key_eq(n, pkey)) 288 + return n; 289 + } 290 + 291 + return NULL; 292 + } 293 + 294 + static inline struct neighbour *__neigh_lookup_noref(struct neigh_table *tbl, 295 + const void *pkey, 296 + struct net_device *dev) 297 + { 298 + return ___neigh_lookup_noref(tbl, tbl->key_eq, tbl->hash, pkey, dev); 299 + } 250 300 251 301 void neigh_table_init(int index, struct neigh_table *tbl); 252 302 int neigh_table_clear(int index, struct neigh_table *tbl);
+5 -15
net/core/neighbour.c
··· 397 397 struct net_device *dev) 398 398 { 399 399 struct neighbour *n; 400 - int key_len = tbl->key_len; 401 - u32 hash_val; 402 - struct neigh_hash_table *nht; 403 400 404 401 NEIGH_CACHE_STAT_INC(tbl, lookups); 405 402 406 403 rcu_read_lock_bh(); 407 - nht = rcu_dereference_bh(tbl->nht); 408 - hash_val = tbl->hash(pkey, dev, nht->hash_rnd) >> (32 - nht->hash_shift); 409 - 410 - for (n = rcu_dereference_bh(nht->hash_buckets[hash_val]); 411 - n != NULL; 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 - } 404 + n = __neigh_lookup_noref(tbl, pkey, dev); 405 + if (n) { 406 + if (!atomic_inc_not_zero(&n->refcnt)) 407 + n = NULL; 408 + NEIGH_CACHE_STAT_INC(tbl, hits); 419 409 } 420 410 421 411 rcu_read_unlock_bh();
+6
net/decnet/dn_neigh.c
··· 93 93 return jhash_2words(*(__u16 *)pkey, 0, hash_rnd[0]); 94 94 } 95 95 96 + static bool dn_key_eq(const struct neighbour *neigh, const void *pkey) 97 + { 98 + return neigh_key_eq16(neigh, pkey); 99 + } 100 + 96 101 struct neigh_table dn_neigh_table = { 97 102 .family = PF_DECnet, 98 103 .entry_size = NEIGH_ENTRY_SIZE(sizeof(struct dn_neigh)), 99 104 .key_len = sizeof(__le16), 100 105 .protocol = cpu_to_be16(ETH_P_DNA_RT), 101 106 .hash = dn_neigh_hash, 107 + .key_eq = dn_key_eq, 102 108 .constructor = dn_neigh_construct, 103 109 .id = "dn_neigh_cache", 104 110 .parms ={
+8 -1
net/ipv4/arp.c
··· 122 122 * Interface to generic neighbour cache. 123 123 */ 124 124 static u32 arp_hash(const void *pkey, const struct net_device *dev, __u32 *hash_rnd); 125 + static bool arp_key_eq(const struct neighbour *n, const void *pkey); 125 126 static int arp_constructor(struct neighbour *neigh); 126 127 static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb); 127 128 static void arp_error_report(struct neighbour *neigh, struct sk_buff *skb); ··· 155 154 .key_len = 4, 156 155 .protocol = cpu_to_be16(ETH_P_IP), 157 156 .hash = arp_hash, 157 + .key_eq = arp_key_eq, 158 158 .constructor = arp_constructor, 159 159 .proxy_redo = parp_redo, 160 160 .id = "arp_cache", ··· 211 209 const struct net_device *dev, 212 210 __u32 *hash_rnd) 213 211 { 214 - return arp_hashfn(*(u32 *)pkey, dev, *hash_rnd); 212 + return arp_hashfn(pkey, dev, hash_rnd); 213 + } 214 + 215 + static bool arp_key_eq(const struct neighbour *neigh, const void *pkey) 216 + { 217 + return neigh_key_eq32(neigh, pkey); 215 218 } 216 219 217 220 static int arp_constructor(struct neighbour *neigh)
+7
net/ipv6/ndisc.c
··· 84 84 static u32 ndisc_hash(const void *pkey, 85 85 const struct net_device *dev, 86 86 __u32 *hash_rnd); 87 + static bool ndisc_key_eq(const struct neighbour *neigh, const void *pkey); 87 88 static int ndisc_constructor(struct neighbour *neigh); 88 89 static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb); 89 90 static void ndisc_error_report(struct neighbour *neigh, struct sk_buff *skb); ··· 120 119 .key_len = sizeof(struct in6_addr), 121 120 .protocol = cpu_to_be16(ETH_P_IPV6), 122 121 .hash = ndisc_hash, 122 + .key_eq = ndisc_key_eq, 123 123 .constructor = ndisc_constructor, 124 124 .pconstructor = pndisc_constructor, 125 125 .pdestructor = pndisc_destructor, ··· 295 293 __u32 *hash_rnd) 296 294 { 297 295 return ndisc_hashfn(pkey, dev, hash_rnd); 296 + } 297 + 298 + static bool ndisc_key_eq(const struct neighbour *n, const void *pkey) 299 + { 300 + return neigh_key_eq128(n, pkey); 298 301 } 299 302 300 303 static int ndisc_constructor(struct neighbour *neigh)