neigh: Factor out ___neigh_lookup_noref
authorEric W. Biederman <ebiederm@xmission.com>
Tue, 3 Mar 2015 23:10:44 +0000 (17:10 -0600)
committerDavid S. Miller <davem@davemloft.net>
Wed, 4 Mar 2015 05:23:23 +0000 (00:23 -0500)
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>
include/net/arp.h
include/net/ndisc.h
include/net/neighbour.h
net/core/neighbour.c
net/decnet/dn_neigh.c
net/ipv4/arp.c
net/ipv6/ndisc.c

index 21ee1860abbc7109006ebc5d625ac25d41d3f6bc..5e0f891d476c299d91fde14ce9cdeedc9a7e26c6 100644 (file)
@@ -9,28 +9,17 @@
 
 extern struct neigh_table arp_tbl;
 
-static inline u32 arp_hashfn(u32 key, const struct net_device *dev, u32 hash_rnd)
+static inline u32 arp_hashfn(const void *pkey, const struct net_device *dev, u32 *hash_rnd)
 {
+       u32 key = *(const u32 *)pkey;
        u32 val = key ^ hash32_ptr(dev);
 
-       return val * hash_rnd;
+       return val * hash_rnd[0];
 }
 
 static inline struct neighbour *__ipv4_neigh_lookup_noref(struct net_device *dev, u32 key)
 {
-       struct neigh_hash_table *nht = rcu_dereference_bh(arp_tbl.nht);
-       struct neighbour *n;
-       u32 hash_val;
-
-       hash_val = arp_hashfn(key, dev, nht->hash_rnd[0]) >> (32 - nht->hash_shift);
-       for (n = rcu_dereference_bh(nht->hash_buckets[hash_val]);
-            n != NULL;
-            n = rcu_dereference_bh(n->next)) {
-               if (n->dev == dev && *(u32 *)n->primary_key == key)
-                       return n;
-       }
-
-       return NULL;
+       return ___neigh_lookup_noref(&arp_tbl, neigh_key_eq32, arp_hashfn, &key, dev);
 }
 
 static inline struct neighbour *__ipv4_neigh_lookup(struct net_device *dev, u32 key)
index 6bbda34d5e59d030a1e2d69e93cda754d06ae5c0..b3a7751251b4cb9ce1a7fcb1d3999a63f4ff5074 100644 (file)
@@ -156,24 +156,7 @@ static inline u32 ndisc_hashfn(const void *pkey, const struct net_device *dev, _
 
 static inline struct neighbour *__ipv6_neigh_lookup_noref(struct net_device *dev, const void *pkey)
 {
-       struct neigh_hash_table *nht;
-       const u32 *p32 = pkey;
-       struct neighbour *n;
-       u32 hash_val;
-
-       nht = rcu_dereference_bh(nd_tbl.nht);
-       hash_val = ndisc_hashfn(pkey, dev, nht->hash_rnd) >> (32 - nht->hash_shift);
-       for (n = rcu_dereference_bh(nht->hash_buckets[hash_val]);
-            n != NULL;
-            n = rcu_dereference_bh(n->next)) {
-               u32 *n32 = (u32 *) n->primary_key;
-               if (n->dev == dev &&
-                   ((n32[0] ^ p32[0]) | (n32[1] ^ p32[1]) |
-                    (n32[2] ^ p32[2]) | (n32[3] ^ p32[3])) == 0)
-                       return n;
-       }
-
-       return NULL;
+       return ___neigh_lookup_noref(&nd_tbl, neigh_key_eq128, ndisc_hashfn, pkey, dev);
 }
 
 static inline struct neighbour *__ipv6_neigh_lookup(struct net_device *dev, const void *pkey)
index 9f912e4d4232d1b5a5ec1ab3f7ef51d0cac730e5..14e3f017966b2654862decf88ad2835aa338dd22 100644 (file)
@@ -197,6 +197,7 @@ struct neigh_table {
        __u32                   (*hash)(const void *pkey,
                                        const struct net_device *dev,
                                        __u32 *hash_rnd);
+       bool                    (*key_eq)(const struct neighbour *, const void *pkey);
        int                     (*constructor)(struct neighbour *);
        int                     (*pconstructor)(struct pneigh_entry *);
        void                    (*pdestructor)(struct pneigh_entry *);
@@ -247,6 +248,57 @@ static inline void *neighbour_priv(const struct neighbour *n)
 #define NEIGH_UPDATE_F_ISROUTER                        0x40000000
 #define NEIGH_UPDATE_F_ADMIN                   0x80000000
 
+
+static inline bool neigh_key_eq16(const struct neighbour *n, const void *pkey)
+{
+       return *(const u16 *)n->primary_key == *(const u16 *)pkey;
+}
+
+static inline bool neigh_key_eq32(const struct neighbour *n, const void *pkey)
+{
+       return *(const u32 *)n->primary_key == *(const u32 *)pkey;
+}
+
+static inline bool neigh_key_eq128(const struct neighbour *n, const void *pkey)
+{
+       const u32 *n32 = (const u32 *)n->primary_key;
+       const u32 *p32 = pkey;
+
+       return ((n32[0] ^ p32[0]) | (n32[1] ^ p32[1]) |
+               (n32[2] ^ p32[2]) | (n32[3] ^ p32[3])) == 0;
+}
+
+static inline struct neighbour *___neigh_lookup_noref(
+       struct neigh_table *tbl,
+       bool (*key_eq)(const struct neighbour *n, const void *pkey),
+       __u32 (*hash)(const void *pkey,
+                     const struct net_device *dev,
+                     __u32 *hash_rnd),
+       const void *pkey,
+       struct net_device *dev)
+{
+       struct neigh_hash_table *nht = rcu_dereference_bh(tbl->nht);
+       struct neighbour *n;
+       u32 hash_val;
+
+       hash_val = hash(pkey, dev, nht->hash_rnd) >> (32 - nht->hash_shift);
+       for (n = rcu_dereference_bh(nht->hash_buckets[hash_val]);
+            n != NULL;
+            n = rcu_dereference_bh(n->next)) {
+               if (n->dev == dev && key_eq(n, pkey))
+                       return n;
+       }
+
+       return NULL;
+}
+
+static inline struct neighbour *__neigh_lookup_noref(struct neigh_table *tbl,
+                                                    const void *pkey,
+                                                    struct net_device *dev)
+{
+       return ___neigh_lookup_noref(tbl, tbl->key_eq, tbl->hash, pkey, dev);
+}
+
 void neigh_table_init(int index, struct neigh_table *tbl);
 int neigh_table_clear(int index, struct neigh_table *tbl);
 struct neighbour *neigh_lookup(struct neigh_table *tbl, const void *pkey,
index 0f48ea3affed3f53871a2ab01972b32a01c6ed31..fe3c6eac5805788be5c1e1bda1375afff24c4126 100644 (file)
@@ -397,25 +397,15 @@ struct neighbour *neigh_lookup(struct neigh_table *tbl, const void *pkey,
                               struct net_device *dev)
 {
        struct neighbour *n;
-       int key_len = tbl->key_len;
-       u32 hash_val;
-       struct neigh_hash_table *nht;
 
        NEIGH_CACHE_STAT_INC(tbl, lookups);
 
        rcu_read_lock_bh();
-       nht = rcu_dereference_bh(tbl->nht);
-       hash_val = tbl->hash(pkey, dev, nht->hash_rnd) >> (32 - nht->hash_shift);
-
-       for (n = rcu_dereference_bh(nht->hash_buckets[hash_val]);
-            n != NULL;
-            n = rcu_dereference_bh(n->next)) {
-               if (dev == n->dev && !memcmp(n->primary_key, pkey, key_len)) {
-                       if (!atomic_inc_not_zero(&n->refcnt))
-                               n = NULL;
-                       NEIGH_CACHE_STAT_INC(tbl, hits);
-                       break;
-               }
+       n = __neigh_lookup_noref(tbl, pkey, dev);
+       if (n) {
+               if (!atomic_inc_not_zero(&n->refcnt))
+                       n = NULL;
+               NEIGH_CACHE_STAT_INC(tbl, hits);
        }
 
        rcu_read_unlock_bh();
index f123c6c6748c10b98e7e7500c108936dc634a128..ee7d1cef002743b7972071e662c48c01db889a52 100644 (file)
@@ -93,12 +93,18 @@ static u32 dn_neigh_hash(const void *pkey,
        return jhash_2words(*(__u16 *)pkey, 0, hash_rnd[0]);
 }
 
+static bool dn_key_eq(const struct neighbour *neigh, const void *pkey)
+{
+       return neigh_key_eq16(neigh, pkey);
+}
+
 struct neigh_table dn_neigh_table = {
        .family =                       PF_DECnet,
        .entry_size =                   NEIGH_ENTRY_SIZE(sizeof(struct dn_neigh)),
        .key_len =                      sizeof(__le16),
        .protocol =                     cpu_to_be16(ETH_P_DNA_RT),
        .hash =                         dn_neigh_hash,
+       .key_eq =                       dn_key_eq,
        .constructor =                  dn_neigh_construct,
        .id =                           "dn_neigh_cache",
        .parms ={
index 6b8aad6a0d7dd2b28c6d52d16b3357136a73241b..5f5c674e130ab438881745a9049ff028f900b6eb 100644 (file)
  *     Interface to generic neighbour cache.
  */
 static u32 arp_hash(const void *pkey, const struct net_device *dev, __u32 *hash_rnd);
+static bool arp_key_eq(const struct neighbour *n, const void *pkey);
 static int arp_constructor(struct neighbour *neigh);
 static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb);
 static void arp_error_report(struct neighbour *neigh, struct sk_buff *skb);
@@ -154,6 +155,7 @@ struct neigh_table arp_tbl = {
        .key_len        = 4,
        .protocol       = cpu_to_be16(ETH_P_IP),
        .hash           = arp_hash,
+       .key_eq         = arp_key_eq,
        .constructor    = arp_constructor,
        .proxy_redo     = parp_redo,
        .id             = "arp_cache",
@@ -209,7 +211,12 @@ static u32 arp_hash(const void *pkey,
                    const struct net_device *dev,
                    __u32 *hash_rnd)
 {
-       return arp_hashfn(*(u32 *)pkey, dev, *hash_rnd);
+       return arp_hashfn(pkey, dev, hash_rnd);
+}
+
+static bool arp_key_eq(const struct neighbour *neigh, const void *pkey)
+{
+       return neigh_key_eq32(neigh, pkey);
 }
 
 static int arp_constructor(struct neighbour *neigh)
index e363bbc2420d8dec7e4d3c4626ac089513d0a04e..247ad7c298f73e38a0169f0df299f9ba96de3271 100644 (file)
@@ -84,6 +84,7 @@ do {                                                          \
 static u32 ndisc_hash(const void *pkey,
                      const struct net_device *dev,
                      __u32 *hash_rnd);
+static bool ndisc_key_eq(const struct neighbour *neigh, const void *pkey);
 static int ndisc_constructor(struct neighbour *neigh);
 static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb);
 static void ndisc_error_report(struct neighbour *neigh, struct sk_buff *skb);
@@ -119,6 +120,7 @@ struct neigh_table nd_tbl = {
        .key_len =      sizeof(struct in6_addr),
        .protocol =     cpu_to_be16(ETH_P_IPV6),
        .hash =         ndisc_hash,
+       .key_eq =       ndisc_key_eq,
        .constructor =  ndisc_constructor,
        .pconstructor = pndisc_constructor,
        .pdestructor =  pndisc_destructor,
@@ -295,6 +297,11 @@ static u32 ndisc_hash(const void *pkey,
        return ndisc_hashfn(pkey, dev, hash_rnd);
 }
 
+static bool ndisc_key_eq(const struct neighbour *n, const void *pkey)
+{
+       return neigh_key_eq128(n, pkey);
+}
+
 static int ndisc_constructor(struct neighbour *neigh)
 {
        struct in6_addr *addr = (struct in6_addr *)&neigh->primary_key;