mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	net: add confirm_neigh method to dst_ops
Add confirm_neigh method to dst_ops and use it from IPv4 and IPv6 to lookup and confirm the neighbour. Its usage via the new helper dst_confirm_neigh() should be restricted to MSG_PROBE users for performance reasons. For XFRM prefer the last tunnel address, if present. With help from Steffen Klassert. Signed-off-by: Julian Anastasov <ja@ssi.bg> Acked-by: Steffen Klassert <steffen.klassert@secunet.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									c3a2e83705
								
							
						
					
					
						commit
						63fca65d08
					
				
					 7 changed files with 96 additions and 0 deletions
				
			
		| 
						 | 
					@ -35,6 +35,22 @@ static inline struct neighbour *__ipv4_neigh_lookup(struct net_device *dev, u32
 | 
				
			||||||
	return n;
 | 
						return n;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void __ipv4_confirm_neigh(struct net_device *dev, u32 key)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct neighbour *n;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rcu_read_lock_bh();
 | 
				
			||||||
 | 
						n = __ipv4_neigh_lookup_noref(dev, key);
 | 
				
			||||||
 | 
						if (n) {
 | 
				
			||||||
 | 
							unsigned long now = jiffies;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* avoid dirtying neighbour */
 | 
				
			||||||
 | 
							if (n->confirmed != now)
 | 
				
			||||||
 | 
								n->confirmed = now;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						rcu_read_unlock_bh();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void arp_init(void);
 | 
					void arp_init(void);
 | 
				
			||||||
int arp_ioctl(struct net *net, unsigned int cmd, void __user *arg);
 | 
					int arp_ioctl(struct net *net, unsigned int cmd, void __user *arg);
 | 
				
			||||||
void arp_send(int type, int ptype, __be32 dest_ip,
 | 
					void arp_send(int type, int ptype, __be32 dest_ip,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -477,6 +477,13 @@ static inline struct neighbour *dst_neigh_lookup_skb(const struct dst_entry *dst
 | 
				
			||||||
	return IS_ERR(n) ? NULL : n;
 | 
						return IS_ERR(n) ? NULL : n;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void dst_confirm_neigh(const struct dst_entry *dst,
 | 
				
			||||||
 | 
									     const void *daddr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (dst->ops->confirm_neigh)
 | 
				
			||||||
 | 
							dst->ops->confirm_neigh(dst, daddr);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline void dst_link_failure(struct sk_buff *skb)
 | 
					static inline void dst_link_failure(struct sk_buff *skb)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct dst_entry *dst = skb_dst(skb);
 | 
						struct dst_entry *dst = skb_dst(skb);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -33,6 +33,8 @@ struct dst_ops {
 | 
				
			||||||
	struct neighbour *	(*neigh_lookup)(const struct dst_entry *dst,
 | 
						struct neighbour *	(*neigh_lookup)(const struct dst_entry *dst,
 | 
				
			||||||
						struct sk_buff *skb,
 | 
											struct sk_buff *skb,
 | 
				
			||||||
						const void *daddr);
 | 
											const void *daddr);
 | 
				
			||||||
 | 
						void			(*confirm_neigh)(const struct dst_entry *dst,
 | 
				
			||||||
 | 
											 const void *daddr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct kmem_cache	*kmem_cachep;
 | 
						struct kmem_cache	*kmem_cachep;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -391,6 +391,23 @@ static inline struct neighbour *__ipv6_neigh_lookup(struct net_device *dev, cons
 | 
				
			||||||
	return n;
 | 
						return n;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void __ipv6_confirm_neigh(struct net_device *dev,
 | 
				
			||||||
 | 
										const void *pkey)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct neighbour *n;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rcu_read_lock_bh();
 | 
				
			||||||
 | 
						n = __ipv6_neigh_lookup_noref(dev, pkey);
 | 
				
			||||||
 | 
						if (n) {
 | 
				
			||||||
 | 
							unsigned long now = jiffies;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* avoid dirtying neighbour */
 | 
				
			||||||
 | 
							if (n->confirmed != now)
 | 
				
			||||||
 | 
								n->confirmed = now;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						rcu_read_unlock_bh();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int ndisc_init(void);
 | 
					int ndisc_init(void);
 | 
				
			||||||
int ndisc_late_init(void);
 | 
					int ndisc_late_init(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -154,6 +154,7 @@ static u32 *ipv4_cow_metrics(struct dst_entry *dst, unsigned long old)
 | 
				
			||||||
static struct neighbour *ipv4_neigh_lookup(const struct dst_entry *dst,
 | 
					static struct neighbour *ipv4_neigh_lookup(const struct dst_entry *dst,
 | 
				
			||||||
					   struct sk_buff *skb,
 | 
										   struct sk_buff *skb,
 | 
				
			||||||
					   const void *daddr);
 | 
										   const void *daddr);
 | 
				
			||||||
 | 
					static void ipv4_confirm_neigh(const struct dst_entry *dst, const void *daddr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct dst_ops ipv4_dst_ops = {
 | 
					static struct dst_ops ipv4_dst_ops = {
 | 
				
			||||||
	.family =		AF_INET,
 | 
						.family =		AF_INET,
 | 
				
			||||||
| 
						 | 
					@ -168,6 +169,7 @@ static struct dst_ops ipv4_dst_ops = {
 | 
				
			||||||
	.redirect =		ip_do_redirect,
 | 
						.redirect =		ip_do_redirect,
 | 
				
			||||||
	.local_out =		__ip_local_out,
 | 
						.local_out =		__ip_local_out,
 | 
				
			||||||
	.neigh_lookup =		ipv4_neigh_lookup,
 | 
						.neigh_lookup =		ipv4_neigh_lookup,
 | 
				
			||||||
 | 
						.confirm_neigh =	ipv4_confirm_neigh,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define ECN_OR_COST(class)	TC_PRIO_##class
 | 
					#define ECN_OR_COST(class)	TC_PRIO_##class
 | 
				
			||||||
| 
						 | 
					@ -461,6 +463,23 @@ static struct neighbour *ipv4_neigh_lookup(const struct dst_entry *dst,
 | 
				
			||||||
	return neigh_create(&arp_tbl, pkey, dev);
 | 
						return neigh_create(&arp_tbl, pkey, dev);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void ipv4_confirm_neigh(const struct dst_entry *dst, const void *daddr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct net_device *dev = dst->dev;
 | 
				
			||||||
 | 
						const __be32 *pkey = daddr;
 | 
				
			||||||
 | 
						const struct rtable *rt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rt = (const struct rtable *)dst;
 | 
				
			||||||
 | 
						if (rt->rt_gateway)
 | 
				
			||||||
 | 
							pkey = (const __be32 *)&rt->rt_gateway;
 | 
				
			||||||
 | 
						else if (!daddr ||
 | 
				
			||||||
 | 
							 (rt->rt_flags &
 | 
				
			||||||
 | 
							  (RTCF_MULTICAST | RTCF_BROADCAST | RTCF_LOCAL)))
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						__ipv4_confirm_neigh(dev, *(__force u32 *)pkey);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define IP_IDENTS_SZ 2048u
 | 
					#define IP_IDENTS_SZ 2048u
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static atomic_t *ip_idents __read_mostly;
 | 
					static atomic_t *ip_idents __read_mostly;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -223,6 +223,21 @@ static struct neighbour *ip6_neigh_lookup(const struct dst_entry *dst,
 | 
				
			||||||
	return neigh_create(&nd_tbl, daddr, dst->dev);
 | 
						return neigh_create(&nd_tbl, daddr, dst->dev);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void ip6_confirm_neigh(const struct dst_entry *dst, const void *daddr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct net_device *dev = dst->dev;
 | 
				
			||||||
 | 
						struct rt6_info *rt = (struct rt6_info *)dst;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						daddr = choose_neigh_daddr(rt, NULL, daddr);
 | 
				
			||||||
 | 
						if (!daddr)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						if (dev->flags & (IFF_NOARP | IFF_LOOPBACK))
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						if (ipv6_addr_is_multicast((const struct in6_addr *)daddr))
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						__ipv6_confirm_neigh(dev, daddr);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct dst_ops ip6_dst_ops_template = {
 | 
					static struct dst_ops ip6_dst_ops_template = {
 | 
				
			||||||
	.family			=	AF_INET6,
 | 
						.family			=	AF_INET6,
 | 
				
			||||||
	.gc			=	ip6_dst_gc,
 | 
						.gc			=	ip6_dst_gc,
 | 
				
			||||||
| 
						 | 
					@ -239,6 +254,7 @@ static struct dst_ops ip6_dst_ops_template = {
 | 
				
			||||||
	.redirect		=	rt6_do_redirect,
 | 
						.redirect		=	rt6_do_redirect,
 | 
				
			||||||
	.local_out		=	__ip6_local_out,
 | 
						.local_out		=	__ip6_local_out,
 | 
				
			||||||
	.neigh_lookup		=	ip6_neigh_lookup,
 | 
						.neigh_lookup		=	ip6_neigh_lookup,
 | 
				
			||||||
 | 
						.confirm_neigh		=	ip6_confirm_neigh,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static unsigned int ip6_blackhole_mtu(const struct dst_entry *dst)
 | 
					static unsigned int ip6_blackhole_mtu(const struct dst_entry *dst)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2856,6 +2856,23 @@ static struct neighbour *xfrm_neigh_lookup(const struct dst_entry *dst,
 | 
				
			||||||
	return dst->path->ops->neigh_lookup(dst, skb, daddr);
 | 
						return dst->path->ops->neigh_lookup(dst, skb, daddr);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void xfrm_confirm_neigh(const struct dst_entry *dst, const void *daddr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const struct dst_entry *path = dst->path;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (; dst != path; dst = dst->child) {
 | 
				
			||||||
 | 
							const struct xfrm_state *xfrm = dst->xfrm;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (xfrm->props.mode == XFRM_MODE_TRANSPORT)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							if (xfrm->type->flags & XFRM_TYPE_REMOTE_COADDR)
 | 
				
			||||||
 | 
								daddr = xfrm->coaddr;
 | 
				
			||||||
 | 
							else if (!(xfrm->type->flags & XFRM_TYPE_LOCAL_COADDR))
 | 
				
			||||||
 | 
								daddr = &xfrm->id.daddr;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						path->ops->confirm_neigh(path, daddr);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo)
 | 
					int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int err = 0;
 | 
						int err = 0;
 | 
				
			||||||
| 
						 | 
					@ -2882,6 +2899,8 @@ int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo)
 | 
				
			||||||
			dst_ops->link_failure = xfrm_link_failure;
 | 
								dst_ops->link_failure = xfrm_link_failure;
 | 
				
			||||||
		if (likely(dst_ops->neigh_lookup == NULL))
 | 
							if (likely(dst_ops->neigh_lookup == NULL))
 | 
				
			||||||
			dst_ops->neigh_lookup = xfrm_neigh_lookup;
 | 
								dst_ops->neigh_lookup = xfrm_neigh_lookup;
 | 
				
			||||||
 | 
							if (likely(!dst_ops->confirm_neigh))
 | 
				
			||||||
 | 
								dst_ops->confirm_neigh = xfrm_confirm_neigh;
 | 
				
			||||||
		if (likely(afinfo->garbage_collect == NULL))
 | 
							if (likely(afinfo->garbage_collect == NULL))
 | 
				
			||||||
			afinfo->garbage_collect = xfrm_garbage_collect_deferred;
 | 
								afinfo->garbage_collect = xfrm_garbage_collect_deferred;
 | 
				
			||||||
		rcu_assign_pointer(xfrm_policy_afinfo[afinfo->family], afinfo);
 | 
							rcu_assign_pointer(xfrm_policy_afinfo[afinfo->family], afinfo);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue