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,7 +520,7 @@ 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); | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  |  | ||||||
|  | @ -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) |  | ||||||
| 			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); | 	err = xfrm_lookup(sock_net(sk), &dst, fl, sk, 0); | ||||||
| 	if (err) | 	if (err) | ||||||
| 		return ERR_PTR(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) |  | ||||||
| 			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); | 	err = xfrm_lookup(sock_net(sk), &dst, fl, sk, 0); | ||||||
| 	if (err) | 	if (err) | ||||||
| 		return ERR_PTR(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,12 +1735,29 @@ error: | ||||||
| 	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) | ||||||
| { | { | ||||||
|  | @ -1829,7 +1846,12 @@ restart: | ||||||
| 			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 @@ dropdst: | ||||||
| 	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…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 David S. Miller
				David S. Miller