forked from mirrors/linux
		
	xfrm: Handle blackhole route creation via afinfo.
That way we don't have to potentially do this in every xfrm_lookup() caller. Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									69ead7afdf
								
							
						
					
					
						commit
						2774c131b1
					
				
					 10 changed files with 50 additions and 67 deletions
				
			
		| 
						 | 
					@ -432,17 +432,9 @@ static inline int xfrm_lookup(struct net *net, struct dst_entry **dst_p,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
} 
 | 
					} 
 | 
				
			||||||
static inline int __xfrm_lookup(struct net *net, struct dst_entry **dst_p,
 | 
					 | 
				
			||||||
				const struct flowi *fl, struct sock *sk,
 | 
					 | 
				
			||||||
				int flags)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
extern int xfrm_lookup(struct net *net, struct dst_entry **dst_p,
 | 
					extern int xfrm_lookup(struct net *net, struct dst_entry **dst_p,
 | 
				
			||||||
		       const struct flowi *fl, struct sock *sk, int flags);
 | 
							       const struct flowi *fl, struct sock *sk, int flags);
 | 
				
			||||||
extern int __xfrm_lookup(struct net *net, struct dst_entry **dst_p,
 | 
					 | 
				
			||||||
			 const struct flowi *fl, struct sock *sk, int flags);
 | 
					 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -520,8 +520,8 @@ extern struct dst_entry *	ip6_sk_dst_lookup_flow(struct sock *sk,
 | 
				
			||||||
						       struct flowi *fl,
 | 
											       struct flowi *fl,
 | 
				
			||||||
						       const struct in6_addr *final_dst,
 | 
											       const struct in6_addr *final_dst,
 | 
				
			||||||
						       bool can_sleep);
 | 
											       bool can_sleep);
 | 
				
			||||||
extern struct dst_entry *	ip6_dst_blackhole(struct net *net,
 | 
					extern struct dst_entry *	ip6_blackhole_route(struct net *net,
 | 
				
			||||||
						  struct dst_entry *orig_dst);
 | 
											    struct dst_entry *orig_dst);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 *	skb processing functions
 | 
					 *	skb processing functions
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -121,6 +121,7 @@ extern void		rt_cache_flush_batch(struct net *net);
 | 
				
			||||||
extern int		__ip_route_output_key(struct net *, struct rtable **, const struct flowi *flp);
 | 
					extern int		__ip_route_output_key(struct net *, struct rtable **, const struct flowi *flp);
 | 
				
			||||||
extern int		ip_route_output_key(struct net *, struct rtable **, struct flowi *flp);
 | 
					extern int		ip_route_output_key(struct net *, struct rtable **, struct flowi *flp);
 | 
				
			||||||
extern int		ip_route_output_flow(struct net *, struct rtable **rp, struct flowi *flp, struct sock *sk);
 | 
					extern int		ip_route_output_flow(struct net *, struct rtable **rp, struct flowi *flp, struct sock *sk);
 | 
				
			||||||
 | 
					extern struct dst_entry *ipv4_blackhole_route(struct net *net, struct dst_entry *dst_orig);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern int ip_route_input_common(struct sk_buff *skb, __be32 dst, __be32 src,
 | 
					extern int ip_route_input_common(struct sk_buff *skb, __be32 dst, __be32 src,
 | 
				
			||||||
				 u8 tos, struct net_device *devin, bool noref);
 | 
									 u8 tos, struct net_device *devin, bool noref);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -280,6 +280,7 @@ struct xfrm_policy_afinfo {
 | 
				
			||||||
	int			(*fill_dst)(struct xfrm_dst *xdst,
 | 
						int			(*fill_dst)(struct xfrm_dst *xdst,
 | 
				
			||||||
					    struct net_device *dev,
 | 
										    struct net_device *dev,
 | 
				
			||||||
					    const struct flowi *fl);
 | 
										    const struct flowi *fl);
 | 
				
			||||||
 | 
						struct dst_entry	*(*blackhole_route)(struct net *net, struct dst_entry *orig);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo);
 | 
					extern int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2675,12 +2675,10 @@ static struct dst_ops ipv4_dst_blackhole_ops = {
 | 
				
			||||||
	.update_pmtu		=	ipv4_rt_blackhole_update_pmtu,
 | 
						.update_pmtu		=	ipv4_rt_blackhole_update_pmtu,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct dst_entry *ipv4_blackhole_route(struct net *net, struct dst_entry *dst_orig)
 | 
				
			||||||
static int ipv4_dst_blackhole(struct net *net, struct rtable **rp, struct flowi *flp)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct rtable *ort = *rp;
 | 
						struct rtable *rt = dst_alloc(&ipv4_dst_blackhole_ops, 1);
 | 
				
			||||||
	struct rtable *rt = (struct rtable *)
 | 
						struct rtable *ort = (struct rtable *) dst_orig;
 | 
				
			||||||
		dst_alloc(&ipv4_dst_blackhole_ops, 1);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (rt) {
 | 
						if (rt) {
 | 
				
			||||||
		struct dst_entry *new = &rt->dst;
 | 
							struct dst_entry *new = &rt->dst;
 | 
				
			||||||
| 
						 | 
					@ -2714,9 +2712,9 @@ static int ipv4_dst_blackhole(struct net *net, struct rtable **rp, struct flowi
 | 
				
			||||||
		dst_free(new);
 | 
							dst_free(new);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dst_release(&(*rp)->dst);
 | 
						dst_release(dst_orig);
 | 
				
			||||||
	*rp = rt;
 | 
					
 | 
				
			||||||
	return rt ? 0 : -ENOMEM;
 | 
						return rt ? &rt->dst : ERR_PTR(-ENOMEM);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int ip_route_output_flow(struct net *net, struct rtable **rp, struct flowi *flp,
 | 
					int ip_route_output_flow(struct net *net, struct rtable **rp, struct flowi *flp,
 | 
				
			||||||
| 
						 | 
					@ -2732,11 +2730,7 @@ int ip_route_output_flow(struct net *net, struct rtable **rp, struct flowi *flp,
 | 
				
			||||||
			flp->fl4_src = (*rp)->rt_src;
 | 
								flp->fl4_src = (*rp)->rt_src;
 | 
				
			||||||
		if (!flp->fl4_dst)
 | 
							if (!flp->fl4_dst)
 | 
				
			||||||
			flp->fl4_dst = (*rp)->rt_dst;
 | 
								flp->fl4_dst = (*rp)->rt_dst;
 | 
				
			||||||
		err = __xfrm_lookup(net, (struct dst_entry **)rp, flp, sk, 0);
 | 
							return xfrm_lookup(net, (struct dst_entry **)rp, flp, sk, 0);
 | 
				
			||||||
		if (err == -EREMOTE)
 | 
					 | 
				
			||||||
			err = ipv4_dst_blackhole(net, rp, flp);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return err;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -234,6 +234,7 @@ static struct xfrm_policy_afinfo xfrm4_policy_afinfo = {
 | 
				
			||||||
	.get_tos =		xfrm4_get_tos,
 | 
						.get_tos =		xfrm4_get_tos,
 | 
				
			||||||
	.init_path =		xfrm4_init_path,
 | 
						.init_path =		xfrm4_init_path,
 | 
				
			||||||
	.fill_dst =		xfrm4_fill_dst,
 | 
						.fill_dst =		xfrm4_fill_dst,
 | 
				
			||||||
 | 
						.blackhole_route =	ipv4_blackhole_route,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_SYSCTL
 | 
					#ifdef CONFIG_SYSCTL
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1025,18 +1025,12 @@ struct dst_entry *ip6_dst_lookup_flow(struct sock *sk, struct flowi *fl,
 | 
				
			||||||
		return ERR_PTR(err);
 | 
							return ERR_PTR(err);
 | 
				
			||||||
	if (final_dst)
 | 
						if (final_dst)
 | 
				
			||||||
		ipv6_addr_copy(&fl->fl6_dst, final_dst);
 | 
							ipv6_addr_copy(&fl->fl6_dst, final_dst);
 | 
				
			||||||
	if (can_sleep) {
 | 
						if (can_sleep)
 | 
				
			||||||
		fl->flags |= FLOWI_FLAG_CAN_SLEEP;
 | 
							fl->flags |= FLOWI_FLAG_CAN_SLEEP;
 | 
				
			||||||
		err = __xfrm_lookup(sock_net(sk), &dst, fl, sk, 0);
 | 
					
 | 
				
			||||||
		if (err == -EREMOTE)
 | 
						err = xfrm_lookup(sock_net(sk), &dst, fl, sk, 0);
 | 
				
			||||||
			return ip6_dst_blackhole(sock_net(sk), dst);
 | 
						if (err)
 | 
				
			||||||
		if (err)
 | 
							return ERR_PTR(err);
 | 
				
			||||||
			return ERR_PTR(err);
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		err = xfrm_lookup(sock_net(sk), &dst, fl, sk, 0);
 | 
					 | 
				
			||||||
		if (err)
 | 
					 | 
				
			||||||
			return ERR_PTR(err);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return dst;
 | 
						return dst;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL_GPL(ip6_dst_lookup_flow);
 | 
					EXPORT_SYMBOL_GPL(ip6_dst_lookup_flow);
 | 
				
			||||||
| 
						 | 
					@ -1070,18 +1064,12 @@ struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi *fl,
 | 
				
			||||||
		return ERR_PTR(err);
 | 
							return ERR_PTR(err);
 | 
				
			||||||
	if (final_dst)
 | 
						if (final_dst)
 | 
				
			||||||
		ipv6_addr_copy(&fl->fl6_dst, final_dst);
 | 
							ipv6_addr_copy(&fl->fl6_dst, final_dst);
 | 
				
			||||||
	if (can_sleep) {
 | 
						if (can_sleep)
 | 
				
			||||||
		fl->flags |= FLOWI_FLAG_CAN_SLEEP;
 | 
							fl->flags |= FLOWI_FLAG_CAN_SLEEP;
 | 
				
			||||||
		err = __xfrm_lookup(sock_net(sk), &dst, fl, sk, 0);
 | 
					
 | 
				
			||||||
		if (err == -EREMOTE)
 | 
						err = xfrm_lookup(sock_net(sk), &dst, fl, sk, 0);
 | 
				
			||||||
			return ip6_dst_blackhole(sock_net(sk), dst);
 | 
						if (err)
 | 
				
			||||||
		if (err)
 | 
							return ERR_PTR(err);
 | 
				
			||||||
			return ERR_PTR(err);
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		err = xfrm_lookup(sock_net(sk), &dst, fl, sk, 0);
 | 
					 | 
				
			||||||
		if (err)
 | 
					 | 
				
			||||||
			return ERR_PTR(err);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return dst;
 | 
						return dst;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL_GPL(ip6_sk_dst_lookup_flow);
 | 
					EXPORT_SYMBOL_GPL(ip6_sk_dst_lookup_flow);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -870,7 +870,7 @@ struct dst_entry * ip6_route_output(struct net *net, struct sock *sk,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
EXPORT_SYMBOL(ip6_route_output);
 | 
					EXPORT_SYMBOL(ip6_route_output);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct dst_entry *ip6_dst_blackhole(struct net *net, struct dst_entry *dst_orig)
 | 
					struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_orig)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct rt6_info *rt = dst_alloc(&ip6_dst_blackhole_ops, 1);
 | 
						struct rt6_info *rt = dst_alloc(&ip6_dst_blackhole_ops, 1);
 | 
				
			||||||
	struct rt6_info *ort = (struct rt6_info *) dst_orig;
 | 
						struct rt6_info *ort = (struct rt6_info *) dst_orig;
 | 
				
			||||||
| 
						 | 
					@ -907,7 +907,6 @@ struct dst_entry *ip6_dst_blackhole(struct net *net, struct dst_entry *dst_orig)
 | 
				
			||||||
	dst_release(dst_orig);
 | 
						dst_release(dst_orig);
 | 
				
			||||||
	return new ? new : ERR_PTR(-ENOMEM);
 | 
						return new ? new : ERR_PTR(-ENOMEM);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL_GPL(ip6_dst_blackhole);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 *	Destination cache support functions
 | 
					 *	Destination cache support functions
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -274,6 +274,7 @@ static struct xfrm_policy_afinfo xfrm6_policy_afinfo = {
 | 
				
			||||||
	.get_tos =		xfrm6_get_tos,
 | 
						.get_tos =		xfrm6_get_tos,
 | 
				
			||||||
	.init_path =		xfrm6_init_path,
 | 
						.init_path =		xfrm6_init_path,
 | 
				
			||||||
	.fill_dst =		xfrm6_fill_dst,
 | 
						.fill_dst =		xfrm6_fill_dst,
 | 
				
			||||||
 | 
						.blackhole_route =	ip6_blackhole_route,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int __init xfrm6_policy_init(void)
 | 
					static int __init xfrm6_policy_init(void)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1735,14 +1735,31 @@ xfrm_bundle_lookup(struct net *net, const struct flowi *fl, u16 family, u8 dir,
 | 
				
			||||||
	return ERR_PTR(err);
 | 
						return ERR_PTR(err);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct dst_entry *make_blackhole(struct net *net, u16 family,
 | 
				
			||||||
 | 
										struct dst_entry *dst_orig)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family);
 | 
				
			||||||
 | 
						struct dst_entry *ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!afinfo) {
 | 
				
			||||||
 | 
							dst_release(dst_orig);
 | 
				
			||||||
 | 
							ret = ERR_PTR(-EINVAL);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							ret = afinfo->blackhole_route(net, dst_orig);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						xfrm_policy_put_afinfo(afinfo);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Main function: finds/creates a bundle for given flow.
 | 
					/* Main function: finds/creates a bundle for given flow.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * At the moment we eat a raw IP route. Mostly to speed up lookups
 | 
					 * At the moment we eat a raw IP route. Mostly to speed up lookups
 | 
				
			||||||
 * on interfaces with disabled IPsec.
 | 
					 * on interfaces with disabled IPsec.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
int __xfrm_lookup(struct net *net, struct dst_entry **dst_p,
 | 
					int xfrm_lookup(struct net *net, struct dst_entry **dst_p,
 | 
				
			||||||
		  const struct flowi *fl,
 | 
							const struct flowi *fl,
 | 
				
			||||||
		  struct sock *sk, int flags)
 | 
							struct sock *sk, int flags)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX];
 | 
						struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX];
 | 
				
			||||||
	struct flow_cache_object *flo;
 | 
						struct flow_cache_object *flo;
 | 
				
			||||||
| 
						 | 
					@ -1829,7 +1846,12 @@ int __xfrm_lookup(struct net *net, struct dst_entry **dst_p,
 | 
				
			||||||
			dst_release(dst);
 | 
								dst_release(dst);
 | 
				
			||||||
			xfrm_pols_put(pols, drop_pols);
 | 
								xfrm_pols_put(pols, drop_pols);
 | 
				
			||||||
			XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTNOSTATES);
 | 
								XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTNOSTATES);
 | 
				
			||||||
			return -EREMOTE;
 | 
					
 | 
				
			||||||
 | 
								dst = make_blackhole(net, family, dst_orig);
 | 
				
			||||||
 | 
								if (IS_ERR(dst))
 | 
				
			||||||
 | 
									return PTR_ERR(dst);
 | 
				
			||||||
 | 
								*dst_p = dst;
 | 
				
			||||||
 | 
								return 0;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (fl->flags & FLOWI_FLAG_CAN_SLEEP) {
 | 
							if (fl->flags & FLOWI_FLAG_CAN_SLEEP) {
 | 
				
			||||||
			DECLARE_WAITQUEUE(wait, current);
 | 
								DECLARE_WAITQUEUE(wait, current);
 | 
				
			||||||
| 
						 | 
					@ -1895,22 +1917,6 @@ int __xfrm_lookup(struct net *net, struct dst_entry **dst_p,
 | 
				
			||||||
	xfrm_pols_put(pols, drop_pols);
 | 
						xfrm_pols_put(pols, drop_pols);
 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL(__xfrm_lookup);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int xfrm_lookup(struct net *net, struct dst_entry **dst_p,
 | 
					 | 
				
			||||||
		const struct flowi *fl,
 | 
					 | 
				
			||||||
		struct sock *sk, int flags)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	int err = __xfrm_lookup(net, dst_p, fl, sk, flags);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (err == -EREMOTE) {
 | 
					 | 
				
			||||||
		dst_release(*dst_p);
 | 
					 | 
				
			||||||
		*dst_p = NULL;
 | 
					 | 
				
			||||||
		err = -EAGAIN;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return err;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
EXPORT_SYMBOL(xfrm_lookup);
 | 
					EXPORT_SYMBOL(xfrm_lookup);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline int
 | 
					static inline int
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue