diff options
author | David S. Miller <davem@davemloft.net> | 2011-12-28 15:06:58 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-12-28 15:06:58 -0500 |
commit | 2c2aba6c561ac425602f4a0be61422224cb87151 (patch) | |
tree | 30b5f2c40b823ca61e2e0930d5e98a89a83222bb | |
parent | 32288eb4d940b10e40c6d4178fe3a40d1437d2f8 (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.h | 2 | ||||
-rw-r--r-- | include/net/ndisc.h | 9 | ||||
-rw-r--r-- | include/net/neighbour.h | 6 | ||||
-rw-r--r-- | net/core/neighbour.c | 13 | ||||
-rw-r--r-- | net/decnet/dn_neigh.c | 4 | ||||
-rw-r--r-- | net/ipv4/arp.c | 6 | ||||
-rw-r--r-- | net/ipv6/ndisc.c | 13 |
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 | ||
82 | static 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 | ||
83 | extern int ndisc_init(void); | 92 | extern 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 | |||
142 | struct neigh_hash_table { | 144 | struct 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 | ||
325 | static void neigh_get_hash_rnd(u32 *x) | ||
326 | { | ||
327 | get_random_bytes(x, sizeof(*x)); | ||
328 | *x |= 1; | ||
329 | } | ||
330 | |||
325 | static struct neigh_hash_table *neigh_hash_alloc(unsigned int shift) | 331 | static 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 | ||
89 | static u32 dn_neigh_hash(const void *pkey, | 89 | static 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 | ||
96 | struct neigh_table dn_neigh_table = { | 96 | struct 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 | */ |
124 | static u32 arp_hash(const void *pkey, const struct net_device *dev, __u32 rnd); | 124 | static u32 arp_hash(const void *pkey, const struct net_device *dev, __u32 *hash_rnd); |
125 | static int arp_constructor(struct neighbour *neigh); | 125 | static int arp_constructor(struct neighbour *neigh); |
126 | static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb); | 126 | static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb); |
127 | static void arp_error_report(struct neighbour *neigh, struct sk_buff *skb); | 127 | static 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 | ||
216 | static u32 arp_hash(const void *pkey, | 216 | static 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 | ||
223 | static int arp_constructor(struct neighbour *neigh) | 223 | static 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 | ||
94 | static u32 ndisc_hash(const void *pkey, | 94 | static 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); |
97 | static int ndisc_constructor(struct neighbour *neigh); | 97 | static int ndisc_constructor(struct neighbour *neigh); |
98 | static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb); | 98 | static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb); |
99 | static void ndisc_error_report(struct neighbour *neigh, struct sk_buff *skb); | 99 | static void ndisc_error_report(struct neighbour *neigh, struct sk_buff *skb); |
@@ -349,16 +349,9 @@ EXPORT_SYMBOL(ndisc_mc_map); | |||
349 | 349 | ||
350 | static u32 ndisc_hash(const void *pkey, | 350 | static 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 | ||
364 | static int ndisc_constructor(struct neighbour *neigh) | 357 | static int ndisc_constructor(struct neighbour *neigh) |