forked from mirrors/linux
		
	ipv4: Make neigh lookups directly in output packet path.
Do not use the dst cached neigh, we'll be getting rid of that. Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									11604721a3
								
							
						
					
					
						commit
						a263b30936
					
				
					 5 changed files with 44 additions and 25 deletions
				
			
		|  | @ -15,24 +15,34 @@ static inline u32 arp_hashfn(u32 key, const struct net_device *dev, u32 hash_rnd | ||||||
| 	return val * hash_rnd; | 	return val * hash_rnd; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static inline struct neighbour *__ipv4_neigh_lookup(struct net_device *dev, u32 key) | static inline struct neighbour *__ipv4_neigh_lookup_noref(struct net_device *dev, u32 key) | ||||||
| { | { | ||||||
| 	struct neigh_hash_table *nht; | 	struct neigh_hash_table *nht = rcu_dereference_bh(arp_tbl.nht); | ||||||
| 	struct neighbour *n; | 	struct neighbour *n; | ||||||
| 	u32 hash_val; | 	u32 hash_val; | ||||||
| 
 | 
 | ||||||
| 	rcu_read_lock_bh(); | 	if (dev->flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) | ||||||
| 	nht = rcu_dereference_bh(arp_tbl.nht); | 		key = 0; | ||||||
|  | 
 | ||||||
| 	hash_val = arp_hashfn(key, dev, nht->hash_rnd[0]) >> (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)) { | ||||||
| 		if (n->dev == dev && *(u32 *)n->primary_key == key) { | 		if (n->dev == dev && *(u32 *)n->primary_key == key) | ||||||
| 			if (!atomic_inc_not_zero(&n->refcnt)) | 			return n; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return NULL; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static inline struct neighbour *__ipv4_neigh_lookup(struct net_device *dev, u32 key) | ||||||
|  | { | ||||||
|  | 	struct neighbour *n; | ||||||
|  | 
 | ||||||
|  | 	rcu_read_lock_bh(); | ||||||
|  | 	n = __ipv4_neigh_lookup_noref(dev, key); | ||||||
|  | 	if (n && !atomic_inc_not_zero(&n->refcnt)) | ||||||
| 		n = NULL; | 		n = NULL; | ||||||
| 			break; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	rcu_read_unlock_bh(); | 	rcu_read_unlock_bh(); | ||||||
| 
 | 
 | ||||||
| 	return n; | 	return n; | ||||||
|  |  | ||||||
|  | @ -202,9 +202,16 @@ extern struct neighbour *	neigh_lookup(struct neigh_table *tbl, | ||||||
| extern struct neighbour *	neigh_lookup_nodev(struct neigh_table *tbl, | extern struct neighbour *	neigh_lookup_nodev(struct neigh_table *tbl, | ||||||
| 						   struct net *net, | 						   struct net *net, | ||||||
| 						   const void *pkey); | 						   const void *pkey); | ||||||
| extern struct neighbour *	neigh_create(struct neigh_table *tbl, | extern struct neighbour *	__neigh_create(struct neigh_table *tbl, | ||||||
| 					       const void *pkey, | 					       const void *pkey, | ||||||
| 					     struct net_device *dev); | 					       struct net_device *dev, | ||||||
|  | 					       bool want_ref); | ||||||
|  | static inline struct neighbour *neigh_create(struct neigh_table *tbl, | ||||||
|  | 					     const void *pkey, | ||||||
|  | 					     struct net_device *dev) | ||||||
|  | { | ||||||
|  | 	return __neigh_create(tbl, pkey, dev, true); | ||||||
|  | } | ||||||
| extern void			neigh_destroy(struct neighbour *neigh); | extern void			neigh_destroy(struct neighbour *neigh); | ||||||
| extern int			__neigh_event_send(struct neighbour *neigh, struct sk_buff *skb); | extern int			__neigh_event_send(struct neighbour *neigh, struct sk_buff *skb); | ||||||
| extern int			neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new,  | extern int			neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new,  | ||||||
|  |  | ||||||
|  | @ -474,8 +474,8 @@ struct neighbour *neigh_lookup_nodev(struct neigh_table *tbl, struct net *net, | ||||||
| } | } | ||||||
| EXPORT_SYMBOL(neigh_lookup_nodev); | EXPORT_SYMBOL(neigh_lookup_nodev); | ||||||
| 
 | 
 | ||||||
| struct neighbour *neigh_create(struct neigh_table *tbl, const void *pkey, | struct neighbour *__neigh_create(struct neigh_table *tbl, const void *pkey, | ||||||
| 			       struct net_device *dev) | 				 struct net_device *dev, bool want_ref) | ||||||
| { | { | ||||||
| 	u32 hash_val; | 	u32 hash_val; | ||||||
| 	int key_len = tbl->key_len; | 	int key_len = tbl->key_len; | ||||||
|  | @ -535,6 +535,7 @@ struct neighbour *neigh_create(struct neigh_table *tbl, const void *pkey, | ||||||
| 	     n1 = rcu_dereference_protected(n1->next, | 	     n1 = rcu_dereference_protected(n1->next, | ||||||
| 			lockdep_is_held(&tbl->lock))) { | 			lockdep_is_held(&tbl->lock))) { | ||||||
| 		if (dev == n1->dev && !memcmp(n1->primary_key, pkey, key_len)) { | 		if (dev == n1->dev && !memcmp(n1->primary_key, pkey, key_len)) { | ||||||
|  | 			if (want_ref) | ||||||
| 				neigh_hold(n1); | 				neigh_hold(n1); | ||||||
| 			rc = n1; | 			rc = n1; | ||||||
| 			goto out_tbl_unlock; | 			goto out_tbl_unlock; | ||||||
|  | @ -542,6 +543,7 @@ struct neighbour *neigh_create(struct neigh_table *tbl, const void *pkey, | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	n->dead = 0; | 	n->dead = 0; | ||||||
|  | 	if (want_ref) | ||||||
| 		neigh_hold(n); | 		neigh_hold(n); | ||||||
| 	rcu_assign_pointer(n->next, | 	rcu_assign_pointer(n->next, | ||||||
| 			   rcu_dereference_protected(nht->hash_buckets[hash_val], | 			   rcu_dereference_protected(nht->hash_buckets[hash_val], | ||||||
|  | @ -558,7 +560,7 @@ struct neighbour *neigh_create(struct neigh_table *tbl, const void *pkey, | ||||||
| 	neigh_release(n); | 	neigh_release(n); | ||||||
| 	goto out; | 	goto out; | ||||||
| } | } | ||||||
| EXPORT_SYMBOL(neigh_create); | EXPORT_SYMBOL(__neigh_create); | ||||||
| 
 | 
 | ||||||
| static u32 pneigh_hash(const void *pkey, int key_len) | static u32 pneigh_hash(const void *pkey, int key_len) | ||||||
| { | { | ||||||
|  |  | ||||||
|  | @ -170,6 +170,7 @@ static inline int ip_finish_output2(struct sk_buff *skb) | ||||||
| 	struct net_device *dev = dst->dev; | 	struct net_device *dev = dst->dev; | ||||||
| 	unsigned int hh_len = LL_RESERVED_SPACE(dev); | 	unsigned int hh_len = LL_RESERVED_SPACE(dev); | ||||||
| 	struct neighbour *neigh; | 	struct neighbour *neigh; | ||||||
|  | 	u32 nexthop; | ||||||
| 
 | 
 | ||||||
| 	if (rt->rt_type == RTN_MULTICAST) { | 	if (rt->rt_type == RTN_MULTICAST) { | ||||||
| 		IP_UPD_PO_STATS(dev_net(dev), IPSTATS_MIB_OUTMCAST, skb->len); | 		IP_UPD_PO_STATS(dev_net(dev), IPSTATS_MIB_OUTMCAST, skb->len); | ||||||
|  | @ -191,15 +192,18 @@ static inline int ip_finish_output2(struct sk_buff *skb) | ||||||
| 		skb = skb2; | 		skb = skb2; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	rcu_read_lock(); | 	rcu_read_lock_bh(); | ||||||
| 	neigh = dst_get_neighbour_noref(dst); | 	nexthop = rt->rt_gateway ? rt->rt_gateway : ip_hdr(skb)->daddr; | ||||||
|  | 	neigh = __ipv4_neigh_lookup_noref(dev, nexthop); | ||||||
|  | 	if (unlikely(!neigh)) | ||||||
|  | 		neigh = __neigh_create(&arp_tbl, &nexthop, dev, false); | ||||||
| 	if (neigh) { | 	if (neigh) { | ||||||
| 		int res = neigh_output(neigh, skb); | 		int res = neigh_output(neigh, skb); | ||||||
| 
 | 
 | ||||||
| 		rcu_read_unlock(); | 		rcu_read_unlock_bh(); | ||||||
| 		return res; | 		return res; | ||||||
| 	} | 	} | ||||||
| 	rcu_read_unlock(); | 	rcu_read_unlock_bh(); | ||||||
| 
 | 
 | ||||||
| 	net_dbg_ratelimited("%s: No header cache and no neighbour!\n", | 	net_dbg_ratelimited("%s: No header cache and no neighbour!\n", | ||||||
| 			    __func__); | 			    __func__); | ||||||
|  |  | ||||||
|  | @ -1098,17 +1098,13 @@ static int slow_chain_length(const struct rtable *head) | ||||||
| 
 | 
 | ||||||
| static struct neighbour *ipv4_neigh_lookup(const struct dst_entry *dst, const void *daddr) | static struct neighbour *ipv4_neigh_lookup(const struct dst_entry *dst, const void *daddr) | ||||||
| { | { | ||||||
| 	static const __be32 inaddr_any = 0; |  | ||||||
| 	struct net_device *dev = dst->dev; | 	struct net_device *dev = dst->dev; | ||||||
| 	const __be32 *pkey = daddr; | 	const __be32 *pkey = daddr; | ||||||
| 	const struct rtable *rt; | 	const struct rtable *rt; | ||||||
| 	struct neighbour *n; | 	struct neighbour *n; | ||||||
| 
 | 
 | ||||||
| 	rt = (const struct rtable *) dst; | 	rt = (const struct rtable *) dst; | ||||||
| 
 | 	if (rt->rt_gateway) | ||||||
| 	if (dev->flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) |  | ||||||
| 		pkey = &inaddr_any; |  | ||||||
| 	else if (rt->rt_gateway) |  | ||||||
| 		pkey = (const __be32 *) &rt->rt_gateway; | 		pkey = (const __be32 *) &rt->rt_gateway; | ||||||
| 
 | 
 | ||||||
| 	n = __ipv4_neigh_lookup(dev, *(__force u32 *)pkey); | 	n = __ipv4_neigh_lookup(dev, *(__force u32 *)pkey); | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 David S. Miller
						David S. Miller