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; | ||||
| }  | ||||
| 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 | ||||
| extern int xfrm_lookup(struct net *net, struct dst_entry **dst_p, | ||||
| 		       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 | ||||
| 
 | ||||
|  |  | |||
|  | @ -520,8 +520,8 @@ extern struct dst_entry *	ip6_sk_dst_lookup_flow(struct sock *sk, | |||
| 						       struct flowi *fl, | ||||
| 						       const struct in6_addr *final_dst, | ||||
| 						       bool can_sleep); | ||||
| extern struct dst_entry *	ip6_dst_blackhole(struct net *net, | ||||
| 						  struct dst_entry *orig_dst); | ||||
| extern struct dst_entry *	ip6_blackhole_route(struct net *net, | ||||
| 						    struct dst_entry *orig_dst); | ||||
| 
 | ||||
| /*
 | ||||
|  *	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 **, struct flowi *flp); | ||||
| 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, | ||||
| 				 u8 tos, struct net_device *devin, bool noref); | ||||
|  |  | |||
|  | @ -280,6 +280,7 @@ struct xfrm_policy_afinfo { | |||
| 	int			(*fill_dst)(struct xfrm_dst *xdst, | ||||
| 					    struct net_device *dev, | ||||
| 					    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); | ||||
|  |  | |||
|  | @ -2675,12 +2675,10 @@ static struct dst_ops ipv4_dst_blackhole_ops = { | |||
| 	.update_pmtu		=	ipv4_rt_blackhole_update_pmtu, | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| static int ipv4_dst_blackhole(struct net *net, struct rtable **rp, struct flowi *flp) | ||||
| struct dst_entry *ipv4_blackhole_route(struct net *net, struct dst_entry *dst_orig) | ||||
| { | ||||
| 	struct rtable *ort = *rp; | ||||
| 	struct rtable *rt = (struct rtable *) | ||||
| 		dst_alloc(&ipv4_dst_blackhole_ops, 1); | ||||
| 	struct rtable *rt = dst_alloc(&ipv4_dst_blackhole_ops, 1); | ||||
| 	struct rtable *ort = (struct rtable *) dst_orig; | ||||
| 
 | ||||
| 	if (rt) { | ||||
| 		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_release(&(*rp)->dst); | ||||
| 	*rp = rt; | ||||
| 	return rt ? 0 : -ENOMEM; | ||||
| 	dst_release(dst_orig); | ||||
| 
 | ||||
| 	return rt ? &rt->dst : ERR_PTR(-ENOMEM); | ||||
| } | ||||
| 
 | ||||
| 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; | ||||
| 		if (!flp->fl4_dst) | ||||
| 			flp->fl4_dst = (*rp)->rt_dst; | ||||
| 		err = __xfrm_lookup(net, (struct dst_entry **)rp, flp, sk, 0); | ||||
| 		if (err == -EREMOTE) | ||||
| 			err = ipv4_dst_blackhole(net, rp, flp); | ||||
| 
 | ||||
| 		return err; | ||||
| 		return xfrm_lookup(net, (struct dst_entry **)rp, flp, sk, 0); | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
|  |  | |||
|  | @ -234,6 +234,7 @@ static struct xfrm_policy_afinfo xfrm4_policy_afinfo = { | |||
| 	.get_tos =		xfrm4_get_tos, | ||||
| 	.init_path =		xfrm4_init_path, | ||||
| 	.fill_dst =		xfrm4_fill_dst, | ||||
| 	.blackhole_route =	ipv4_blackhole_route, | ||||
| }; | ||||
| 
 | ||||
| #ifdef CONFIG_SYSCTL | ||||
|  |  | |||
|  | @ -1025,18 +1025,12 @@ struct dst_entry *ip6_dst_lookup_flow(struct sock *sk, struct flowi *fl, | |||
| 		return ERR_PTR(err); | ||||
| 	if (final_dst) | ||||
| 		ipv6_addr_copy(&fl->fl6_dst, final_dst); | ||||
| 	if (can_sleep) { | ||||
| 	if (can_sleep) | ||||
| 		fl->flags |= FLOWI_FLAG_CAN_SLEEP; | ||||
| 		err = __xfrm_lookup(sock_net(sk), &dst, fl, sk, 0); | ||||
| 		if (err == -EREMOTE) | ||||
| 			return ip6_dst_blackhole(sock_net(sk), dst); | ||||
| 		if (err) | ||||
| 			return ERR_PTR(err); | ||||
| 	} else { | ||||
| 		err = xfrm_lookup(sock_net(sk), &dst, fl, sk, 0); | ||||
| 		if (err) | ||||
| 			return ERR_PTR(err); | ||||
| 	} | ||||
| 
 | ||||
| 	err = xfrm_lookup(sock_net(sk), &dst, fl, sk, 0); | ||||
| 	if (err) | ||||
| 		return ERR_PTR(err); | ||||
| 	return dst; | ||||
| } | ||||
| 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); | ||||
| 	if (final_dst) | ||||
| 		ipv6_addr_copy(&fl->fl6_dst, final_dst); | ||||
| 	if (can_sleep) { | ||||
| 	if (can_sleep) | ||||
| 		fl->flags |= FLOWI_FLAG_CAN_SLEEP; | ||||
| 		err = __xfrm_lookup(sock_net(sk), &dst, fl, sk, 0); | ||||
| 		if (err == -EREMOTE) | ||||
| 			return ip6_dst_blackhole(sock_net(sk), dst); | ||||
| 		if (err) | ||||
| 			return ERR_PTR(err); | ||||
| 	} else { | ||||
| 		err = xfrm_lookup(sock_net(sk), &dst, fl, sk, 0); | ||||
| 		if (err) | ||||
| 			return ERR_PTR(err); | ||||
| 	} | ||||
| 
 | ||||
| 	err = xfrm_lookup(sock_net(sk), &dst, fl, sk, 0); | ||||
| 	if (err) | ||||
| 		return ERR_PTR(err); | ||||
| 	return dst; | ||||
| } | ||||
| 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); | ||||
| 
 | ||||
| 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 *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); | ||||
| 	return new ? new : ERR_PTR(-ENOMEM); | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(ip6_dst_blackhole); | ||||
| 
 | ||||
| /*
 | ||||
|  *	Destination cache support functions | ||||
|  |  | |||
|  | @ -274,6 +274,7 @@ static struct xfrm_policy_afinfo xfrm6_policy_afinfo = { | |||
| 	.get_tos =		xfrm6_get_tos, | ||||
| 	.init_path =		xfrm6_init_path, | ||||
| 	.fill_dst =		xfrm6_fill_dst, | ||||
| 	.blackhole_route =	ip6_blackhole_route, | ||||
| }; | ||||
| 
 | ||||
| static int __init xfrm6_policy_init(void) | ||||
|  |  | |||
|  | @ -1735,14 +1735,31 @@ error: | |||
| 	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.
 | ||||
|  * | ||||
|  * At the moment we eat a raw IP route. Mostly to speed up lookups | ||||
|  * on interfaces with disabled IPsec. | ||||
|  */ | ||||
| int __xfrm_lookup(struct net *net, struct dst_entry **dst_p, | ||||
| 		  const struct flowi *fl, | ||||
| 		  struct sock *sk, int flags) | ||||
| int xfrm_lookup(struct net *net, struct dst_entry **dst_p, | ||||
| 		const struct flowi *fl, | ||||
| 		struct sock *sk, int flags) | ||||
| { | ||||
| 	struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX]; | ||||
| 	struct flow_cache_object *flo; | ||||
|  | @ -1829,7 +1846,12 @@ restart: | |||
| 			dst_release(dst); | ||||
| 			xfrm_pols_put(pols, drop_pols); | ||||
| 			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) { | ||||
| 			DECLARE_WAITQUEUE(wait, current); | ||||
|  | @ -1895,22 +1917,6 @@ dropdst: | |||
| 	xfrm_pols_put(pols, drop_pols); | ||||
| 	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); | ||||
| 
 | ||||
| static inline int | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 David S. Miller
				David S. Miller