diff options
Diffstat (limited to 'include/net/route.h')
| -rw-r--r-- | include/net/route.h | 163 | 
1 files changed, 82 insertions, 81 deletions
diff --git a/include/net/route.h b/include/net/route.h index 8fce0621cad..db7b3432f07 100644 --- a/include/net/route.h +++ b/include/net/route.h @@ -35,16 +35,8 @@  #include <linux/cache.h>  #include <linux/security.h> -#ifndef __KERNEL__ -#warning This file is not supposed to be used outside of kernel. -#endif -  #define RTO_ONLINK	0x01 -#define RTO_CONN	0 -/* RTO_CONN is not used (being alias for 0), but preserved not to break - * some modules referring to it. */ -  #define RT_CONN_FLAGS(sk)   (RT_TOS(inet_sk(sk)->tos) | sock_flag(sk, SOCK_LOCALROUTE))  struct fib_nh; @@ -60,7 +52,7 @@ struct rtable {  	int			rt_genid;  	unsigned		rt_flags;  	__u16			rt_type; -	__u8			rt_tos; +	__u8			rt_key_tos;  	__be32			rt_dst;	/* Path destination	*/  	__be32			rt_src;	/* Path source		*/ @@ -123,7 +115,7 @@ extern void		ip_rt_redirect(__be32 old_gw, __be32 dst, __be32 new_gw,  				       __be32 src, struct net_device *dev);  extern void		rt_cache_flush(struct net *net, int how);  extern void		rt_cache_flush_batch(struct net *net); -extern struct rtable *__ip_route_output_key(struct net *, const struct flowi4 *flp); +extern struct rtable *__ip_route_output_key(struct net *, struct flowi4 *flp);  extern struct rtable *ip_route_output_flow(struct net *, struct flowi4 *flp,  					   struct sock *sk);  extern struct dst_entry *ipv4_blackhole_route(struct net *net, struct dst_entry *dst_orig); @@ -145,40 +137,33 @@ static inline struct rtable *ip_route_output(struct net *net, __be32 daddr,  	return ip_route_output_key(net, &fl4);  } -static inline struct rtable *ip_route_output_ports(struct net *net, struct sock *sk, +static inline struct rtable *ip_route_output_ports(struct net *net, struct flowi4 *fl4, +						   struct sock *sk,  						   __be32 daddr, __be32 saddr,  						   __be16 dport, __be16 sport,  						   __u8 proto, __u8 tos, int oif)  { -	struct flowi4 fl4 = { -		.flowi4_oif = oif, -		.flowi4_flags = sk ? inet_sk_flowi_flags(sk) : 0, -		.flowi4_mark = sk ? sk->sk_mark : 0, -		.daddr = daddr, -		.saddr = saddr, -		.flowi4_tos = tos, -		.flowi4_proto = proto, -		.fl4_dport = dport, -		.fl4_sport = sport, -	}; +	flowi4_init_output(fl4, oif, sk ? sk->sk_mark : 0, tos, +			   RT_SCOPE_UNIVERSE, proto, +			   sk ? inet_sk_flowi_flags(sk) : 0, +			   daddr, saddr, dport, sport);  	if (sk) -		security_sk_classify_flow(sk, flowi4_to_flowi(&fl4)); -	return ip_route_output_flow(net, &fl4, sk); +		security_sk_classify_flow(sk, flowi4_to_flowi(fl4)); +	return ip_route_output_flow(net, fl4, sk);  } -static inline struct rtable *ip_route_output_gre(struct net *net, +static inline struct rtable *ip_route_output_gre(struct net *net, struct flowi4 *fl4,  						 __be32 daddr, __be32 saddr,  						 __be32 gre_key, __u8 tos, int oif)  { -	struct flowi4 fl4 = { -		.flowi4_oif = oif, -		.daddr = daddr, -		.saddr = saddr, -		.flowi4_tos = tos, -		.flowi4_proto = IPPROTO_GRE, -		.fl4_gre_key = gre_key, -	}; -	return ip_route_output_key(net, &fl4); +	memset(fl4, 0, sizeof(*fl4)); +	fl4->flowi4_oif = oif; +	fl4->daddr = daddr; +	fl4->saddr = saddr; +	fl4->flowi4_tos = tos; +	fl4->flowi4_proto = IPPROTO_GRE; +	fl4->fl4_gre_key = gre_key; +	return ip_route_output_key(net, fl4);  }  extern int ip_route_input_common(struct sk_buff *skb, __be32 dst, __be32 src, @@ -196,14 +181,15 @@ static inline int ip_route_input_noref(struct sk_buff *skb, __be32 dst, __be32 s  	return ip_route_input_common(skb, dst, src, tos, devin, true);  } -extern unsigned short	ip_rt_frag_needed(struct net *net, struct iphdr *iph, unsigned short new_mtu, struct net_device *dev); +extern unsigned short	ip_rt_frag_needed(struct net *net, const struct iphdr *iph, +					  unsigned short new_mtu, struct net_device *dev);  extern void		ip_rt_send_redirect(struct sk_buff *skb);  extern unsigned		inet_addr_type(struct net *net, __be32 addr);  extern unsigned		inet_dev_addr_type(struct net *net, const struct net_device *dev, __be32 addr);  extern void		ip_rt_multicast_event(struct in_device *);  extern int		ip_rt_ioctl(struct net *, unsigned int cmd, void __user *arg); -extern void		ip_rt_get_source(u8 *src, struct rtable *rt); +extern void		ip_rt_get_source(u8 *src, struct sk_buff *skb, struct rtable *rt);  extern int		ip_rt_dump(struct sk_buff *skb,  struct netlink_callback *cb);  struct in_ifaddr; @@ -225,78 +211,93 @@ static inline char rt_tos2priority(u8 tos)  	return ip_tos2prio[IPTOS_TOS(tos)>>1];  } -static inline struct rtable *ip_route_connect(__be32 dst, __be32 src, u32 tos, +/* ip_route_connect() and ip_route_newports() work in tandem whilst + * binding a socket for a new outgoing connection. + * + * In order to use IPSEC properly, we must, in the end, have a + * route that was looked up using all available keys including source + * and destination ports. + * + * However, if a source port needs to be allocated (the user specified + * a wildcard source port) we need to obtain addressing information + * in order to perform that allocation. + * + * So ip_route_connect() looks up a route using wildcarded source and + * destination ports in the key, simply so that we can get a pair of + * addresses to use for port allocation. + * + * Later, once the ports are allocated, ip_route_newports() will make + * another route lookup if needed to make sure we catch any IPSEC + * rules keyed on the port information. + * + * The callers allocate the flow key on their stack, and must pass in + * the same flowi4 object to both the ip_route_connect() and the + * ip_route_newports() calls. + */ + +static inline void ip_route_connect_init(struct flowi4 *fl4, __be32 dst, __be32 src, +					 u32 tos, int oif, u8 protocol, +					 __be16 sport, __be16 dport, +					 struct sock *sk, bool can_sleep) +{ +	__u8 flow_flags = 0; + +	if (inet_sk(sk)->transparent) +		flow_flags |= FLOWI_FLAG_ANYSRC; +	if (protocol == IPPROTO_TCP) +		flow_flags |= FLOWI_FLAG_PRECOW_METRICS; +	if (can_sleep) +		flow_flags |= FLOWI_FLAG_CAN_SLEEP; + +	flowi4_init_output(fl4, oif, sk->sk_mark, tos, RT_SCOPE_UNIVERSE, +			   protocol, flow_flags, dst, src, dport, sport); +} + +static inline struct rtable *ip_route_connect(struct flowi4 *fl4, +					      __be32 dst, __be32 src, u32 tos,  					      int oif, u8 protocol,  					      __be16 sport, __be16 dport,  					      struct sock *sk, bool can_sleep)  { -	struct flowi4 fl4 = { -		.flowi4_oif = oif, -		.flowi4_mark = sk->sk_mark, -		.daddr = dst, -		.saddr = src, -		.flowi4_tos = tos, -		.flowi4_proto = protocol, -		.fl4_sport = sport, -		.fl4_dport = dport, -	};  	struct net *net = sock_net(sk);  	struct rtable *rt; -	if (inet_sk(sk)->transparent) -		fl4.flowi4_flags |= FLOWI_FLAG_ANYSRC; -	if (protocol == IPPROTO_TCP) -		fl4.flowi4_flags |= FLOWI_FLAG_PRECOW_METRICS; -	if (can_sleep) -		fl4.flowi4_flags |= FLOWI_FLAG_CAN_SLEEP; +	ip_route_connect_init(fl4, dst, src, tos, oif, protocol, +			      sport, dport, sk, can_sleep);  	if (!dst || !src) { -		rt = __ip_route_output_key(net, &fl4); +		rt = __ip_route_output_key(net, fl4);  		if (IS_ERR(rt))  			return rt; -		fl4.daddr = rt->rt_dst; -		fl4.saddr = rt->rt_src;  		ip_rt_put(rt);  	} -	security_sk_classify_flow(sk, flowi4_to_flowi(&fl4)); -	return ip_route_output_flow(net, &fl4, sk); +	security_sk_classify_flow(sk, flowi4_to_flowi(fl4)); +	return ip_route_output_flow(net, fl4, sk);  } -static inline struct rtable *ip_route_newports(struct rtable *rt, -					       u8 protocol, __be16 orig_sport, -					       __be16 orig_dport, __be16 sport, -					       __be16 dport, struct sock *sk) +static inline struct rtable *ip_route_newports(struct flowi4 *fl4, struct rtable *rt, +					       __be16 orig_sport, __be16 orig_dport, +					       __be16 sport, __be16 dport, +					       struct sock *sk)  {  	if (sport != orig_sport || dport != orig_dport) { -		struct flowi4 fl4 = { -			.flowi4_oif = rt->rt_oif, -			.flowi4_mark = rt->rt_mark, -			.daddr = rt->rt_dst, -			.saddr = rt->rt_src, -			.flowi4_tos = rt->rt_tos, -			.flowi4_proto = protocol, -			.fl4_sport = sport, -			.fl4_dport = dport -		}; -		if (inet_sk(sk)->transparent) -			fl4.flowi4_flags |= FLOWI_FLAG_ANYSRC; -		if (protocol == IPPROTO_TCP) -			fl4.flowi4_flags |= FLOWI_FLAG_PRECOW_METRICS; +		fl4->fl4_dport = dport; +		fl4->fl4_sport = sport;  		ip_rt_put(rt); -		security_sk_classify_flow(sk, flowi4_to_flowi(&fl4)); -		return ip_route_output_flow(sock_net(sk), &fl4, sk); +		security_sk_classify_flow(sk, flowi4_to_flowi(fl4)); +		return ip_route_output_flow(sock_net(sk), fl4, sk);  	}  	return rt;  } -extern void rt_bind_peer(struct rtable *rt, int create); +extern void rt_bind_peer(struct rtable *rt, __be32 daddr, int create); -static inline struct inet_peer *rt_get_peer(struct rtable *rt) +static inline struct inet_peer *rt_get_peer(struct rtable *rt, __be32 daddr)  {  	if (rt->peer)  		return rt->peer; -	rt_bind_peer(rt, 0); +	rt_bind_peer(rt, daddr, 0);  	return rt->peer;  }  |