aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2011-12-28 15:06:58 -0500
committerDavid S. Miller <davem@davemloft.net>2011-12-28 15:06:58 -0500
commit2c2aba6c561ac425602f4a0be61422224cb87151 (patch)
tree30b5f2c40b823ca61e2e0930d5e98a89a83222bb
parent32288eb4d940b10e40c6d4178fe3a40d1437d2f8 (diff)
ipv6: Use universal hash for NDISC.
In order to perform a proper universal hash on a vector of integers, we have to use different universal hashes on each vector element. Which means we need 4 different hash randoms for ipv6. Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/arp.h2
-rw-r--r--include/net/ndisc.h9
-rw-r--r--include/net/neighbour.h6
-rw-r--r--net/core/neighbour.c13
-rw-r--r--net/decnet/dn_neigh.c4
-rw-r--r--net/ipv4/arp.c6
-rw-r--r--net/ipv6/ndisc.c13
7 files changed, 32 insertions, 21 deletions
diff --git a/include/net/arp.h b/include/net/arp.h
index 4979af8b1559..0013dc87940b 100644
--- a/include/net/arp.h
+++ b/include/net/arp.h
@@ -23,7 +23,7 @@ static inline struct neighbour *__ipv4_neigh_lookup(struct neigh_table *tbl, str
23 23
24 rcu_read_lock_bh(); 24 rcu_read_lock_bh();
25 nht = rcu_dereference_bh(tbl->nht); 25 nht = rcu_dereference_bh(tbl->nht);
26 hash_val = arp_hashfn(key, dev, nht->hash_rnd) >> (32 - nht->hash_shift); 26 hash_val = arp_hashfn(key, dev, nht->hash_rnd[0]) >> (32 - nht->hash_shift);
27 for (n = rcu_dereference_bh(nht->hash_buckets[hash_val]); 27 for (n = rcu_dereference_bh(nht->hash_buckets[hash_val]);
28 n != NULL; 28 n != NULL;
29 n = rcu_dereference_bh(n->next)) { 29 n = rcu_dereference_bh(n->next)) {
diff --git a/include/net/ndisc.h b/include/net/ndisc.h
index c977c377c015..e9c30023b784 100644
--- a/include/net/ndisc.h
+++ b/include/net/ndisc.h
@@ -79,6 +79,15 @@ struct nd_opt_hdr {
79 __u8 nd_opt_len; 79 __u8 nd_opt_len;
80} __packed; 80} __packed;
81 81
82static inline u32 ndisc_hashfn(const void *pkey, const struct net_device *dev, __u32 *hash_rnd)
83{
84 const u32 *p32 = pkey;
85
86 return (((p32[0] ^ dev->ifindex) * hash_rnd[0]) +
87 (p32[1] * hash_rnd[1]) +
88 (p32[2] * hash_rnd[2]) +
89 (p32[3] * hash_rnd[3]));
90}
82 91
83extern int ndisc_init(void); 92extern int ndisc_init(void);
84 93
diff --git a/include/net/neighbour.h b/include/net/neighbour.h
index e31f0a86f9b7..34c996f46181 100644
--- a/include/net/neighbour.h
+++ b/include/net/neighbour.h
@@ -139,10 +139,12 @@ struct pneigh_entry {
139 * neighbour table manipulation 139 * neighbour table manipulation
140 */ 140 */
141 141
142#define NEIGH_NUM_HASH_RND 4
143
142struct neigh_hash_table { 144struct neigh_hash_table {
143 struct neighbour __rcu **hash_buckets; 145 struct neighbour __rcu **hash_buckets;
144 unsigned int hash_shift; 146 unsigned int hash_shift;
145 __u32 hash_rnd; 147 __u32 hash_rnd[NEIGH_NUM_HASH_RND];
146 struct rcu_head rcu; 148 struct rcu_head rcu;
147}; 149};
148 150
@@ -154,7 +156,7 @@ struct neigh_table {
154 int key_len; 156 int key_len;
155 __u32 (*hash)(const void *pkey, 157 __u32 (*hash)(const void *pkey,
156 const struct net_device *dev, 158 const struct net_device *dev,
157 __u32 hash_rnd); 159 __u32 *hash_rnd);
158 int (*constructor)(struct neighbour *); 160 int (*constructor)(struct neighbour *);
159 int (*pconstructor)(struct pneigh_entry *); 161 int (*pconstructor)(struct pneigh_entry *);
160 void (*pdestructor)(struct pneigh_entry *); 162 void (*pdestructor)(struct pneigh_entry *);
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 4af151e1bf5d..e287346e0934 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -322,11 +322,18 @@ out_entries:
322 goto out; 322 goto out;
323} 323}
324 324
325static void neigh_get_hash_rnd(u32 *x)
326{
327 get_random_bytes(x, sizeof(*x));
328 *x |= 1;
329}
330
325static struct neigh_hash_table *neigh_hash_alloc(unsigned int shift) 331static struct neigh_hash_table *neigh_hash_alloc(unsigned int shift)
326{ 332{
327 size_t size = (1 << shift) * sizeof(struct neighbour *); 333 size_t size = (1 << shift) * sizeof(struct neighbour *);
328 struct neigh_hash_table *ret; 334 struct neigh_hash_table *ret;
329 struct neighbour __rcu **buckets; 335 struct neighbour __rcu **buckets;
336 int i;
330 337
331 ret = kmalloc(sizeof(*ret), GFP_ATOMIC); 338 ret = kmalloc(sizeof(*ret), GFP_ATOMIC);
332 if (!ret) 339 if (!ret)
@@ -343,8 +350,8 @@ static struct neigh_hash_table *neigh_hash_alloc(unsigned int shift)
343 } 350 }
344 ret->hash_buckets = buckets; 351 ret->hash_buckets = buckets;
345 ret->hash_shift = shift; 352 ret->hash_shift = shift;
346 get_random_bytes(&ret->hash_rnd, sizeof(ret->hash_rnd)); 353 for (i = 0; i < NEIGH_NUM_HASH_RND; i++)
347 ret->hash_rnd |= 1; 354 neigh_get_hash_rnd(&ret->hash_rnd[i]);
348 return ret; 355 return ret;
349} 356}
350 357
@@ -1828,7 +1835,7 @@ static int neightbl_fill_info(struct sk_buff *skb, struct neigh_table *tbl,
1828 1835
1829 rcu_read_lock_bh(); 1836 rcu_read_lock_bh();
1830 nht = rcu_dereference_bh(tbl->nht); 1837 nht = rcu_dereference_bh(tbl->nht);
1831 ndc.ndtc_hash_rnd = nht->hash_rnd; 1838 ndc.ndtc_hash_rnd = nht->hash_rnd[0];
1832 ndc.ndtc_hash_mask = ((1 << nht->hash_shift) - 1); 1839 ndc.ndtc_hash_mask = ((1 << nht->hash_shift) - 1);
1833 rcu_read_unlock_bh(); 1840 rcu_read_unlock_bh();
1834 1841
diff --git a/net/decnet/dn_neigh.c b/net/decnet/dn_neigh.c
index 7d2fff29380f..befe426491ba 100644
--- a/net/decnet/dn_neigh.c
+++ b/net/decnet/dn_neigh.c
@@ -88,9 +88,9 @@ static const struct neigh_ops dn_phase3_ops = {
88 88
89static u32 dn_neigh_hash(const void *pkey, 89static u32 dn_neigh_hash(const void *pkey,
90 const struct net_device *dev, 90 const struct net_device *dev,
91 __u32 hash_rnd) 91 __u32 *hash_rnd)
92{ 92{
93 return jhash_2words(*(__u16 *)pkey, 0, hash_rnd); 93 return jhash_2words(*(__u16 *)pkey, 0, hash_rnd[0]);
94} 94}
95 95
96struct neigh_table dn_neigh_table = { 96struct neigh_table dn_neigh_table = {
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
index 381a0876c363..59402be133f0 100644
--- a/net/ipv4/arp.c
+++ b/net/ipv4/arp.c
@@ -121,7 +121,7 @@
121/* 121/*
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 rnd); 124static u32 arp_hash(const void *pkey, const struct net_device *dev, __u32 *hash_rnd);
125static int arp_constructor(struct neighbour *neigh); 125static int arp_constructor(struct neighbour *neigh);
126static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb); 126static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb);
127static void arp_error_report(struct neighbour *neigh, struct sk_buff *skb); 127static void arp_error_report(struct neighbour *neigh, struct sk_buff *skb);
@@ -215,9 +215,9 @@ int arp_mc_map(__be32 addr, u8 *haddr, struct net_device *dev, int dir)
215 215
216static u32 arp_hash(const void *pkey, 216static u32 arp_hash(const void *pkey,
217 const struct net_device *dev, 217 const struct net_device *dev,
218 __u32 hash_rnd) 218 __u32 *hash_rnd)
219{ 219{
220 return arp_hashfn(*(u32 *)pkey, dev, hash_rnd); 220 return arp_hashfn(*(u32 *)pkey, dev, *hash_rnd);
221} 221}
222 222
223static int arp_constructor(struct neighbour *neigh) 223static int arp_constructor(struct neighbour *neigh)
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index f3e50c29add4..538a61960a24 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -93,7 +93,7 @@
93 93
94static u32 ndisc_hash(const void *pkey, 94static u32 ndisc_hash(const void *pkey,
95 const struct net_device *dev, 95 const struct net_device *dev,
96 __u32 rnd); 96 __u32 *hash_rnd);
97static int ndisc_constructor(struct neighbour *neigh); 97static int ndisc_constructor(struct neighbour *neigh);
98static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb); 98static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb);
99static void ndisc_error_report(struct neighbour *neigh, struct sk_buff *skb); 99static void ndisc_error_report(struct neighbour *neigh, struct sk_buff *skb);
@@ -349,16 +349,9 @@ EXPORT_SYMBOL(ndisc_mc_map);
349 349
350static u32 ndisc_hash(const void *pkey, 350static u32 ndisc_hash(const void *pkey,
351 const struct net_device *dev, 351 const struct net_device *dev,
352 __u32 hash_rnd) 352 __u32 *hash_rnd)
353{ 353{
354 const u32 *p32 = pkey; 354 return ndisc_hashfn(pkey, dev, hash_rnd);
355 u32 addr_hash, i;
356
357 addr_hash = 0;
358 for (i = 0; i < (sizeof(struct in6_addr) / sizeof(u32)); i++)
359 addr_hash ^= *p32++;
360
361 return jhash_2words(addr_hash, dev->ifindex, hash_rnd);
362} 355}
363 356
364static int ndisc_constructor(struct neighbour *neigh) 357static int ndisc_constructor(struct neighbour *neigh)