mirror of
				git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
				synced 2025-11-01 09:13:37 +00:00 
			
		
		
		
	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
					
				
					 7 changed files with 32 additions and 21 deletions
				
			
		| 
						 | 
				
			
			@ -23,7 +23,7 @@ static inline struct neighbour *__ipv4_neigh_lookup(struct neigh_table *tbl, str
 | 
			
		|||
 | 
			
		||||
	rcu_read_lock_bh();
 | 
			
		||||
	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]);
 | 
			
		||||
	     n != NULL;
 | 
			
		||||
	     n = rcu_dereference_bh(n->next)) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -79,6 +79,15 @@ struct nd_opt_hdr {
 | 
			
		|||
	__u8		nd_opt_len;
 | 
			
		||||
} __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);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -139,10 +139,12 @@ struct pneigh_entry {
 | 
			
		|||
 *	neighbour table manipulation
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define NEIGH_NUM_HASH_RND	4
 | 
			
		||||
 | 
			
		||||
struct neigh_hash_table {
 | 
			
		||||
	struct neighbour __rcu	**hash_buckets;
 | 
			
		||||
	unsigned int		hash_shift;
 | 
			
		||||
	__u32			hash_rnd;
 | 
			
		||||
	__u32			hash_rnd[NEIGH_NUM_HASH_RND];
 | 
			
		||||
	struct rcu_head		rcu;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -154,7 +156,7 @@ struct neigh_table {
 | 
			
		|||
	int			key_len;
 | 
			
		||||
	__u32			(*hash)(const void *pkey,
 | 
			
		||||
					const struct net_device *dev,
 | 
			
		||||
					__u32 hash_rnd);
 | 
			
		||||
					__u32 *hash_rnd);
 | 
			
		||||
	int			(*constructor)(struct neighbour *);
 | 
			
		||||
	int			(*pconstructor)(struct pneigh_entry *);
 | 
			
		||||
	void			(*pdestructor)(struct pneigh_entry *);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -322,11 +322,18 @@ out_entries:
 | 
			
		|||
	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)
 | 
			
		||||
{
 | 
			
		||||
	size_t size = (1 << shift) * sizeof(struct neighbour *);
 | 
			
		||||
	struct neigh_hash_table *ret;
 | 
			
		||||
	struct neighbour __rcu **buckets;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	ret = kmalloc(sizeof(*ret), GFP_ATOMIC);
 | 
			
		||||
	if (!ret)
 | 
			
		||||
| 
						 | 
				
			
			@ -343,8 +350,8 @@ static struct neigh_hash_table *neigh_hash_alloc(unsigned int shift)
 | 
			
		|||
	}
 | 
			
		||||
	ret->hash_buckets = buckets;
 | 
			
		||||
	ret->hash_shift = shift;
 | 
			
		||||
	get_random_bytes(&ret->hash_rnd, sizeof(ret->hash_rnd));
 | 
			
		||||
	ret->hash_rnd |= 1;
 | 
			
		||||
	for (i = 0; i < NEIGH_NUM_HASH_RND; i++)
 | 
			
		||||
		neigh_get_hash_rnd(&ret->hash_rnd[i]);
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1828,7 +1835,7 @@ static int neightbl_fill_info(struct sk_buff *skb, struct neigh_table *tbl,
 | 
			
		|||
 | 
			
		||||
		rcu_read_lock_bh();
 | 
			
		||||
		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);
 | 
			
		||||
		rcu_read_unlock_bh();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -88,9 +88,9 @@ static const struct neigh_ops dn_phase3_ops = {
 | 
			
		|||
 | 
			
		||||
static u32 dn_neigh_hash(const void *pkey,
 | 
			
		||||
			 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 = {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -121,7 +121,7 @@
 | 
			
		|||
/*
 | 
			
		||||
 *	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 void arp_solicit(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,
 | 
			
		||||
		    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)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -93,7 +93,7 @@
 | 
			
		|||
 | 
			
		||||
static u32 ndisc_hash(const void *pkey,
 | 
			
		||||
		      const struct net_device *dev,
 | 
			
		||||
		      __u32 rnd);
 | 
			
		||||
		      __u32 *hash_rnd);
 | 
			
		||||
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);
 | 
			
		||||
| 
						 | 
				
			
			@ -349,16 +349,9 @@ EXPORT_SYMBOL(ndisc_mc_map);
 | 
			
		|||
 | 
			
		||||
static u32 ndisc_hash(const void *pkey,
 | 
			
		||||
		      const struct net_device *dev,
 | 
			
		||||
		      __u32 hash_rnd)
 | 
			
		||||
		      __u32 *hash_rnd)
 | 
			
		||||
{
 | 
			
		||||
	const u32 *p32 = pkey;
 | 
			
		||||
	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);
 | 
			
		||||
	return ndisc_hashfn(pkey, dev, hash_rnd);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int ndisc_constructor(struct neighbour *neigh)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue