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>
This commit is contained in:
parent
32288eb4d9
commit
2c2aba6c56
|
@ -23,7 +23,7 @@ static inline struct neighbour *__ipv4_neigh_lookup(struct neigh_table *tbl, str
|
||||||
|
|
||||||
rcu_read_lock_bh();
|
rcu_read_lock_bh();
|
||||||
nht = rcu_dereference_bh(tbl->nht);
|
nht = rcu_dereference_bh(tbl->nht);
|
||||||
hash_val = arp_hashfn(key, dev, nht->hash_rnd) >> (32 - nht->hash_shift);
|
hash_val = arp_hashfn(key, dev, nht->hash_rnd[0]) >> (32 - nht->hash_shift);
|
||||||
for (n = rcu_dereference_bh(nht->hash_buckets[hash_val]);
|
for (n = rcu_dereference_bh(nht->hash_buckets[hash_val]);
|
||||||
n != NULL;
|
n != NULL;
|
||||||
n = rcu_dereference_bh(n->next)) {
|
n = rcu_dereference_bh(n->next)) {
|
||||||
|
|
|
@ -79,6 +79,15 @@ struct nd_opt_hdr {
|
||||||
__u8 nd_opt_len;
|
__u8 nd_opt_len;
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
|
static inline u32 ndisc_hashfn(const void *pkey, const struct net_device *dev, __u32 *hash_rnd)
|
||||||
|
{
|
||||||
|
const u32 *p32 = pkey;
|
||||||
|
|
||||||
|
return (((p32[0] ^ dev->ifindex) * hash_rnd[0]) +
|
||||||
|
(p32[1] * hash_rnd[1]) +
|
||||||
|
(p32[2] * hash_rnd[2]) +
|
||||||
|
(p32[3] * hash_rnd[3]));
|
||||||
|
}
|
||||||
|
|
||||||
extern int ndisc_init(void);
|
extern int ndisc_init(void);
|
||||||
|
|
||||||
|
|
|
@ -139,10 +139,12 @@ struct pneigh_entry {
|
||||||
* neighbour table manipulation
|
* neighbour table manipulation
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define NEIGH_NUM_HASH_RND 4
|
||||||
|
|
||||||
struct neigh_hash_table {
|
struct neigh_hash_table {
|
||||||
struct neighbour __rcu **hash_buckets;
|
struct neighbour __rcu **hash_buckets;
|
||||||
unsigned int hash_shift;
|
unsigned int hash_shift;
|
||||||
__u32 hash_rnd;
|
__u32 hash_rnd[NEIGH_NUM_HASH_RND];
|
||||||
struct rcu_head rcu;
|
struct rcu_head rcu;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -154,7 +156,7 @@ struct neigh_table {
|
||||||
int key_len;
|
int key_len;
|
||||||
__u32 (*hash)(const void *pkey,
|
__u32 (*hash)(const void *pkey,
|
||||||
const struct net_device *dev,
|
const struct net_device *dev,
|
||||||
__u32 hash_rnd);
|
__u32 *hash_rnd);
|
||||||
int (*constructor)(struct neighbour *);
|
int (*constructor)(struct neighbour *);
|
||||||
int (*pconstructor)(struct pneigh_entry *);
|
int (*pconstructor)(struct pneigh_entry *);
|
||||||
void (*pdestructor)(struct pneigh_entry *);
|
void (*pdestructor)(struct pneigh_entry *);
|
||||||
|
|
|
@ -322,11 +322,18 @@ out_entries:
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void neigh_get_hash_rnd(u32 *x)
|
||||||
|
{
|
||||||
|
get_random_bytes(x, sizeof(*x));
|
||||||
|
*x |= 1;
|
||||||
|
}
|
||||||
|
|
||||||
static struct neigh_hash_table *neigh_hash_alloc(unsigned int shift)
|
static struct neigh_hash_table *neigh_hash_alloc(unsigned int shift)
|
||||||
{
|
{
|
||||||
size_t size = (1 << shift) * sizeof(struct neighbour *);
|
size_t size = (1 << shift) * sizeof(struct neighbour *);
|
||||||
struct neigh_hash_table *ret;
|
struct neigh_hash_table *ret;
|
||||||
struct neighbour __rcu **buckets;
|
struct neighbour __rcu **buckets;
|
||||||
|
int i;
|
||||||
|
|
||||||
ret = kmalloc(sizeof(*ret), GFP_ATOMIC);
|
ret = kmalloc(sizeof(*ret), GFP_ATOMIC);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
|
@ -343,8 +350,8 @@ static struct neigh_hash_table *neigh_hash_alloc(unsigned int shift)
|
||||||
}
|
}
|
||||||
ret->hash_buckets = buckets;
|
ret->hash_buckets = buckets;
|
||||||
ret->hash_shift = shift;
|
ret->hash_shift = shift;
|
||||||
get_random_bytes(&ret->hash_rnd, sizeof(ret->hash_rnd));
|
for (i = 0; i < NEIGH_NUM_HASH_RND; i++)
|
||||||
ret->hash_rnd |= 1;
|
neigh_get_hash_rnd(&ret->hash_rnd[i]);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1828,7 +1835,7 @@ static int neightbl_fill_info(struct sk_buff *skb, struct neigh_table *tbl,
|
||||||
|
|
||||||
rcu_read_lock_bh();
|
rcu_read_lock_bh();
|
||||||
nht = rcu_dereference_bh(tbl->nht);
|
nht = rcu_dereference_bh(tbl->nht);
|
||||||
ndc.ndtc_hash_rnd = nht->hash_rnd;
|
ndc.ndtc_hash_rnd = nht->hash_rnd[0];
|
||||||
ndc.ndtc_hash_mask = ((1 << nht->hash_shift) - 1);
|
ndc.ndtc_hash_mask = ((1 << nht->hash_shift) - 1);
|
||||||
rcu_read_unlock_bh();
|
rcu_read_unlock_bh();
|
||||||
|
|
||||||
|
|
|
@ -88,9 +88,9 @@ static const struct neigh_ops dn_phase3_ops = {
|
||||||
|
|
||||||
static u32 dn_neigh_hash(const void *pkey,
|
static u32 dn_neigh_hash(const void *pkey,
|
||||||
const struct net_device *dev,
|
const struct net_device *dev,
|
||||||
__u32 hash_rnd)
|
__u32 *hash_rnd)
|
||||||
{
|
{
|
||||||
return jhash_2words(*(__u16 *)pkey, 0, hash_rnd);
|
return jhash_2words(*(__u16 *)pkey, 0, hash_rnd[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct neigh_table dn_neigh_table = {
|
struct neigh_table dn_neigh_table = {
|
||||||
|
|
|
@ -121,7 +121,7 @@
|
||||||
/*
|
/*
|
||||||
* Interface to generic neighbour cache.
|
* Interface to generic neighbour cache.
|
||||||
*/
|
*/
|
||||||
static u32 arp_hash(const void *pkey, const struct net_device *dev, __u32 rnd);
|
static u32 arp_hash(const void *pkey, const struct net_device *dev, __u32 *hash_rnd);
|
||||||
static int arp_constructor(struct neighbour *neigh);
|
static int arp_constructor(struct neighbour *neigh);
|
||||||
static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb);
|
static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb);
|
||||||
static void arp_error_report(struct neighbour *neigh, struct sk_buff *skb);
|
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)
|
||||||
|
|
||||||
static u32 arp_hash(const void *pkey,
|
static u32 arp_hash(const void *pkey,
|
||||||
const struct net_device *dev,
|
const struct net_device *dev,
|
||||||
__u32 hash_rnd)
|
__u32 *hash_rnd)
|
||||||
{
|
{
|
||||||
return arp_hashfn(*(u32 *)pkey, dev, hash_rnd);
|
return arp_hashfn(*(u32 *)pkey, dev, *hash_rnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int arp_constructor(struct neighbour *neigh)
|
static int arp_constructor(struct neighbour *neigh)
|
||||||
|
|
|
@ -93,7 +93,7 @@
|
||||||
|
|
||||||
static u32 ndisc_hash(const void *pkey,
|
static u32 ndisc_hash(const void *pkey,
|
||||||
const struct net_device *dev,
|
const struct net_device *dev,
|
||||||
__u32 rnd);
|
__u32 *hash_rnd);
|
||||||
static int ndisc_constructor(struct neighbour *neigh);
|
static int ndisc_constructor(struct neighbour *neigh);
|
||||||
static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb);
|
static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb);
|
||||||
static void ndisc_error_report(struct neighbour *neigh, struct sk_buff *skb);
|
static void ndisc_error_report(struct neighbour *neigh, struct sk_buff *skb);
|
||||||
|
@ -349,16 +349,9 @@ EXPORT_SYMBOL(ndisc_mc_map);
|
||||||
|
|
||||||
static u32 ndisc_hash(const void *pkey,
|
static u32 ndisc_hash(const void *pkey,
|
||||||
const struct net_device *dev,
|
const struct net_device *dev,
|
||||||
__u32 hash_rnd)
|
__u32 *hash_rnd)
|
||||||
{
|
{
|
||||||
const u32 *p32 = pkey;
|
return ndisc_hashfn(pkey, dev, hash_rnd);
|
||||||
u32 addr_hash, i;
|
|
||||||
|
|
||||||
addr_hash = 0;
|
|
||||||
for (i = 0; i < (sizeof(struct in6_addr) / sizeof(u32)); i++)
|
|
||||||
addr_hash ^= *p32++;
|
|
||||||
|
|
||||||
return jhash_2words(addr_hash, dev->ifindex, hash_rnd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ndisc_constructor(struct neighbour *neigh)
|
static int ndisc_constructor(struct neighbour *neigh)
|
||||||
|
|
Loading…
Reference in a new issue