ipv4: Make output route lookup return rtable directly.
Instead of on the stack. Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
					parent
					
						
							
								452edd598f
							
						
					
				
			
			
				commit
				
					
						b23dd4fe42
					
				
			
		
					 36 changed files with 267 additions and 224 deletions
				
			
		|  | @ -193,10 +193,11 @@ static int addr4_resolve(struct sockaddr_in *src_in, | ||||||
| 	fl.nl_u.ip4_u.saddr = src_ip; | 	fl.nl_u.ip4_u.saddr = src_ip; | ||||||
| 	fl.oif = addr->bound_dev_if; | 	fl.oif = addr->bound_dev_if; | ||||||
| 
 | 
 | ||||||
| 	ret = ip_route_output_key(&init_net, &rt, &fl); | 	rt = ip_route_output_key(&init_net, &fl); | ||||||
| 	if (ret) | 	if (IS_ERR(rt)) { | ||||||
|  | 		ret = PTR_ERR(rt); | ||||||
| 		goto out; | 		goto out; | ||||||
| 
 | 	} | ||||||
| 	src_in->sin_family = AF_INET; | 	src_in->sin_family = AF_INET; | ||||||
| 	src_in->sin_addr.s_addr = rt->rt_src; | 	src_in->sin_addr.s_addr = rt->rt_src; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -354,7 +354,8 @@ static struct rtable *find_route(struct t3cdev *dev, __be32 local_ip, | ||||||
| 			  } | 			  } | ||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
| 	if (ip_route_output_flow(&init_net, &rt, &fl, NULL)) | 	rt = ip_route_output_flow(&init_net, &fl, NULL); | ||||||
|  | 	if (IS_ERR(rt)) | ||||||
| 		return NULL; | 		return NULL; | ||||||
| 	return rt; | 	return rt; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -331,7 +331,8 @@ static struct rtable *find_route(struct c4iw_dev *dev, __be32 local_ip, | ||||||
| 			  } | 			  } | ||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
| 	if (ip_route_output_flow(&init_net, &rt, &fl, NULL)) | 	rt = ip_route_output_flow(&init_net, &fl, NULL); | ||||||
|  | 	if (IS_ERR(rt)) | ||||||
| 		return NULL; | 		return NULL; | ||||||
| 	return rt; | 	return rt; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1112,7 +1112,8 @@ static int nes_addr_resolve_neigh(struct nes_vnic *nesvnic, u32 dst_ip, int arpi | ||||||
| 
 | 
 | ||||||
| 	memset(&fl, 0, sizeof fl); | 	memset(&fl, 0, sizeof fl); | ||||||
| 	fl.nl_u.ip4_u.daddr = htonl(dst_ip); | 	fl.nl_u.ip4_u.daddr = htonl(dst_ip); | ||||||
| 	if (ip_route_output_key(&init_net, &rt, &fl)) { | 	rt = ip_route_output_key(&init_net, &fl); | ||||||
|  | 	if (IS_ERR(rt)) { | ||||||
| 		printk(KERN_ERR "%s: ip_route_output_key failed for 0x%08X\n", | 		printk(KERN_ERR "%s: ip_route_output_key failed for 0x%08X\n", | ||||||
| 				__func__, dst_ip); | 				__func__, dst_ip); | ||||||
| 		return rc; | 		return rc; | ||||||
|  |  | ||||||
|  | @ -2681,7 +2681,7 @@ static void bond_arp_send(struct net_device *slave_dev, int arp_op, __be32 dest_ | ||||||
| 
 | 
 | ||||||
| static void bond_arp_send_all(struct bonding *bond, struct slave *slave) | static void bond_arp_send_all(struct bonding *bond, struct slave *slave) | ||||||
| { | { | ||||||
| 	int i, vlan_id, rv; | 	int i, vlan_id; | ||||||
| 	__be32 *targets = bond->params.arp_targets; | 	__be32 *targets = bond->params.arp_targets; | ||||||
| 	struct vlan_entry *vlan; | 	struct vlan_entry *vlan; | ||||||
| 	struct net_device *vlan_dev; | 	struct net_device *vlan_dev; | ||||||
|  | @ -2708,8 +2708,8 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave) | ||||||
| 		fl.fl4_dst = targets[i]; | 		fl.fl4_dst = targets[i]; | ||||||
| 		fl.fl4_tos = RTO_ONLINK; | 		fl.fl4_tos = RTO_ONLINK; | ||||||
| 
 | 
 | ||||||
| 		rv = ip_route_output_key(dev_net(bond->dev), &rt, &fl); | 		rt = ip_route_output_key(dev_net(bond->dev), &fl); | ||||||
| 		if (rv) { | 		if (IS_ERR(rt)) { | ||||||
| 			if (net_ratelimit()) { | 			if (net_ratelimit()) { | ||||||
| 				pr_warning("%s: no route to arp_ip_target %pI4\n", | 				pr_warning("%s: no route to arp_ip_target %pI4\n", | ||||||
| 					   bond->dev->name, &fl.fl4_dst); | 					   bond->dev->name, &fl.fl4_dst); | ||||||
|  |  | ||||||
|  | @ -3397,9 +3397,12 @@ static int cnic_get_v4_route(struct sockaddr_in *dst_addr, | ||||||
| 	memset(&fl, 0, sizeof(fl)); | 	memset(&fl, 0, sizeof(fl)); | ||||||
| 	fl.nl_u.ip4_u.daddr = dst_addr->sin_addr.s_addr; | 	fl.nl_u.ip4_u.daddr = dst_addr->sin_addr.s_addr; | ||||||
| 
 | 
 | ||||||
| 	err = ip_route_output_key(&init_net, &rt, &fl); | 	rt = ip_route_output_key(&init_net, &fl); | ||||||
| 	if (!err) | 	err = 0; | ||||||
|  | 	if (!IS_ERR(rt)) | ||||||
| 		*dst = &rt->dst; | 		*dst = &rt->dst; | ||||||
|  | 	else | ||||||
|  | 		err = PTR_ERR(rt); | ||||||
| 	return err; | 	return err; | ||||||
| #else | #else | ||||||
| 	return -ENETUNREACH; | 	return -ENETUNREACH; | ||||||
|  |  | ||||||
|  | @ -175,7 +175,6 @@ static int pptp_xmit(struct ppp_channel *chan, struct sk_buff *skb) | ||||||
| 	struct pptp_opt *opt = &po->proto.pptp; | 	struct pptp_opt *opt = &po->proto.pptp; | ||||||
| 	struct pptp_gre_header *hdr; | 	struct pptp_gre_header *hdr; | ||||||
| 	unsigned int header_len = sizeof(*hdr); | 	unsigned int header_len = sizeof(*hdr); | ||||||
| 	int err = 0; |  | ||||||
| 	int islcp; | 	int islcp; | ||||||
| 	int len; | 	int len; | ||||||
| 	unsigned char *data; | 	unsigned char *data; | ||||||
|  | @ -198,8 +197,8 @@ static int pptp_xmit(struct ppp_channel *chan, struct sk_buff *skb) | ||||||
| 					.saddr = opt->src_addr.sin_addr.s_addr, | 					.saddr = opt->src_addr.sin_addr.s_addr, | ||||||
| 					.tos = RT_TOS(0) } }, | 					.tos = RT_TOS(0) } }, | ||||||
| 			.proto = IPPROTO_GRE }; | 			.proto = IPPROTO_GRE }; | ||||||
| 		err = ip_route_output_key(&init_net, &rt, &fl); | 		rt = ip_route_output_key(&init_net, &fl); | ||||||
| 		if (err) | 		if (IS_ERR(rt)) | ||||||
| 			goto tx_error; | 			goto tx_error; | ||||||
| 	} | 	} | ||||||
| 	tdev = rt->dst.dev; | 	tdev = rt->dst.dev; | ||||||
|  | @ -477,7 +476,8 @@ static int pptp_connect(struct socket *sock, struct sockaddr *uservaddr, | ||||||
| 					.tos = RT_CONN_FLAGS(sk) } }, | 					.tos = RT_CONN_FLAGS(sk) } }, | ||||||
| 			.proto = IPPROTO_GRE }; | 			.proto = IPPROTO_GRE }; | ||||||
| 		security_sk_classify_flow(sk, &fl); | 		security_sk_classify_flow(sk, &fl); | ||||||
| 		if (ip_route_output_key(&init_net, &rt, &fl)) { | 		rt = ip_route_output_key(&init_net, &fl); | ||||||
|  | 		if (IS_ERR(rt)) { | ||||||
| 			error = -EHOSTUNREACH; | 			error = -EHOSTUNREACH; | ||||||
| 			goto end; | 			goto end; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | @ -470,7 +470,8 @@ static struct rtable *find_route_ipv4(__be32 saddr, __be32 daddr, | ||||||
| 			} | 			} | ||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
| 	if (ip_route_output_flow(&init_net, &rt, &fl, NULL)) | 	rt = ip_route_output_flow(&init_net, &fl, NULL); | ||||||
|  | 	if (IS_ERR(rt)) | ||||||
| 		return NULL; | 		return NULL; | ||||||
| 
 | 
 | ||||||
| 	return rt; | 	return rt; | ||||||
|  |  | ||||||
|  | @ -118,9 +118,10 @@ extern void		ip_rt_redirect(__be32 old_gw, __be32 dst, __be32 new_gw, | ||||||
| 				       __be32 src, struct net_device *dev); | 				       __be32 src, struct net_device *dev); | ||||||
| extern void		rt_cache_flush(struct net *net, int how); | extern void		rt_cache_flush(struct net *net, int how); | ||||||
| extern void		rt_cache_flush_batch(struct net *net); | extern void		rt_cache_flush_batch(struct net *net); | ||||||
| extern int		__ip_route_output_key(struct net *, struct rtable **, const struct flowi *flp); | extern struct rtable *__ip_route_output_key(struct net *, const struct flowi *flp); | ||||||
| extern int		ip_route_output_key(struct net *, struct rtable **, struct flowi *flp); | extern struct rtable *ip_route_output_key(struct net *, struct flowi *flp); | ||||||
| extern int		ip_route_output_flow(struct net *, struct rtable **rp, struct flowi *flp, struct sock *sk); | extern struct rtable *ip_route_output_flow(struct net *, struct flowi *flp, | ||||||
|  | 					   struct sock *sk); | ||||||
| extern struct dst_entry *ipv4_blackhole_route(struct net *net, struct dst_entry *dst_orig); | 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, | ||||||
|  | @ -166,10 +167,10 @@ static inline char rt_tos2priority(u8 tos) | ||||||
| 	return ip_tos2prio[IPTOS_TOS(tos)>>1]; | 	return ip_tos2prio[IPTOS_TOS(tos)>>1]; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static inline int ip_route_connect(struct rtable **rp, __be32 dst, | static inline struct rtable *ip_route_connect(__be32 dst, __be32 src, u32 tos, | ||||||
| 				   __be32 src, u32 tos, int oif, u8 protocol, | 					      int oif, u8 protocol, | ||||||
| 				   __be16 sport, __be16 dport, struct sock *sk, | 					      __be16 sport, __be16 dport, | ||||||
| 				   bool can_sleep) | 					      struct sock *sk, bool can_sleep) | ||||||
| { | { | ||||||
| 	struct flowi fl = { .oif = oif, | 	struct flowi fl = { .oif = oif, | ||||||
| 			    .mark = sk->sk_mark, | 			    .mark = sk->sk_mark, | ||||||
|  | @ -179,8 +180,8 @@ static inline int ip_route_connect(struct rtable **rp, __be32 dst, | ||||||
| 			    .proto = protocol, | 			    .proto = protocol, | ||||||
| 			    .fl_ip_sport = sport, | 			    .fl_ip_sport = sport, | ||||||
| 			    .fl_ip_dport = dport }; | 			    .fl_ip_dport = dport }; | ||||||
| 	int err; |  | ||||||
| 	struct net *net = sock_net(sk); | 	struct net *net = sock_net(sk); | ||||||
|  | 	struct rtable *rt; | ||||||
| 
 | 
 | ||||||
| 	if (inet_sk(sk)->transparent) | 	if (inet_sk(sk)->transparent) | ||||||
| 		fl.flags |= FLOWI_FLAG_ANYSRC; | 		fl.flags |= FLOWI_FLAG_ANYSRC; | ||||||
|  | @ -190,29 +191,29 @@ static inline int ip_route_connect(struct rtable **rp, __be32 dst, | ||||||
| 		fl.flags |= FLOWI_FLAG_CAN_SLEEP; | 		fl.flags |= FLOWI_FLAG_CAN_SLEEP; | ||||||
| 
 | 
 | ||||||
| 	if (!dst || !src) { | 	if (!dst || !src) { | ||||||
| 		err = __ip_route_output_key(net, rp, &fl); | 		rt = __ip_route_output_key(net, &fl); | ||||||
| 		if (err) | 		if (IS_ERR(rt)) | ||||||
| 			return err; | 			return rt; | ||||||
| 		fl.fl4_dst = (*rp)->rt_dst; | 		fl.fl4_dst = rt->rt_dst; | ||||||
| 		fl.fl4_src = (*rp)->rt_src; | 		fl.fl4_src = rt->rt_src; | ||||||
| 		ip_rt_put(*rp); | 		ip_rt_put(rt); | ||||||
| 		*rp = NULL; |  | ||||||
| 	} | 	} | ||||||
| 	security_sk_classify_flow(sk, &fl); | 	security_sk_classify_flow(sk, &fl); | ||||||
| 	return ip_route_output_flow(net, rp, &fl, sk); | 	return ip_route_output_flow(net, &fl, sk); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static inline int ip_route_newports(struct rtable **rp, u8 protocol, | static inline struct rtable *ip_route_newports(struct rtable *rt, | ||||||
| 				    __be16 orig_sport, __be16 orig_dport, | 					       u8 protocol, __be16 orig_sport, | ||||||
| 				    __be16 sport, __be16 dport, struct sock *sk) | 					       __be16 orig_dport, __be16 sport, | ||||||
|  | 					       __be16 dport, struct sock *sk) | ||||||
| { | { | ||||||
| 	if (sport != orig_sport || dport != orig_dport) { | 	if (sport != orig_sport || dport != orig_dport) { | ||||||
| 		struct flowi fl = { .oif = (*rp)->fl.oif, | 		struct flowi fl = { .oif = rt->fl.oif, | ||||||
| 				    .mark = (*rp)->fl.mark, | 				    .mark = rt->fl.mark, | ||||||
| 				    .fl4_dst = (*rp)->fl.fl4_dst, | 				    .fl4_dst = rt->fl.fl4_dst, | ||||||
| 				    .fl4_src = (*rp)->fl.fl4_src, | 				    .fl4_src = rt->fl.fl4_src, | ||||||
| 				    .fl4_tos = (*rp)->fl.fl4_tos, | 				    .fl4_tos = rt->fl.fl4_tos, | ||||||
| 				    .proto = (*rp)->fl.proto, | 				    .proto = rt->fl.proto, | ||||||
| 				    .fl_ip_sport = sport, | 				    .fl_ip_sport = sport, | ||||||
| 				    .fl_ip_dport = dport }; | 				    .fl_ip_dport = dport }; | ||||||
| 
 | 
 | ||||||
|  | @ -220,12 +221,11 @@ static inline int ip_route_newports(struct rtable **rp, u8 protocol, | ||||||
| 			fl.flags |= FLOWI_FLAG_ANYSRC; | 			fl.flags |= FLOWI_FLAG_ANYSRC; | ||||||
| 		if (protocol == IPPROTO_TCP) | 		if (protocol == IPPROTO_TCP) | ||||||
| 			fl.flags |= FLOWI_FLAG_PRECOW_METRICS; | 			fl.flags |= FLOWI_FLAG_PRECOW_METRICS; | ||||||
| 		ip_rt_put(*rp); | 		ip_rt_put(rt); | ||||||
| 		*rp = NULL; |  | ||||||
| 		security_sk_classify_flow(sk, &fl); | 		security_sk_classify_flow(sk, &fl); | ||||||
| 		return ip_route_output_flow(sock_net(sk), rp, &fl, sk); | 		return ip_route_output_flow(sock_net(sk), &fl, sk); | ||||||
| 	} | 	} | ||||||
| 	return 0; | 	return rt; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| extern void rt_bind_peer(struct rtable *rt, int create); | extern void rt_bind_peer(struct rtable *rt, int create); | ||||||
|  |  | ||||||
|  | @ -520,9 +520,9 @@ static int clip_setentry(struct atm_vcc *vcc, __be32 ip) | ||||||
| 		unlink_clip_vcc(clip_vcc); | 		unlink_clip_vcc(clip_vcc); | ||||||
| 		return 0; | 		return 0; | ||||||
| 	} | 	} | ||||||
| 	error = ip_route_output_key(&init_net, &rt, &fl); | 	rt = ip_route_output_key(&init_net, &fl); | ||||||
| 	if (error) | 	if (IS_ERR(rt)) | ||||||
| 		return error; | 		return PTR_ERR(rt); | ||||||
| 	neigh = __neigh_lookup(&clip_tbl, &ip, rt->dst.dev, 1); | 	neigh = __neigh_lookup(&clip_tbl, &ip, rt->dst.dev, 1); | ||||||
| 	ip_rt_put(rt); | 	ip_rt_put(rt); | ||||||
| 	if (!neigh) | 	if (!neigh) | ||||||
|  |  | ||||||
|  | @ -428,14 +428,15 @@ static int br_nf_pre_routing_finish(struct sk_buff *skb) | ||||||
| 			if (err != -EHOSTUNREACH || !in_dev || IN_DEV_FORWARD(in_dev)) | 			if (err != -EHOSTUNREACH || !in_dev || IN_DEV_FORWARD(in_dev)) | ||||||
| 				goto free_skb; | 				goto free_skb; | ||||||
| 
 | 
 | ||||||
| 			if (!ip_route_output_key(dev_net(dev), &rt, &fl)) { | 			rt = ip_route_output_key(dev_net(dev), &fl); | ||||||
|  | 			if (!IS_ERR(rt)) { | ||||||
| 				/* - Bridged-and-DNAT'ed traffic doesn't
 | 				/* - Bridged-and-DNAT'ed traffic doesn't
 | ||||||
| 				 *   require ip_forwarding. */ | 				 *   require ip_forwarding. */ | ||||||
| 				if (((struct dst_entry *)rt)->dev == dev) { | 				if (rt->dst.dev == dev) { | ||||||
| 					skb_dst_set(skb, (struct dst_entry *)rt); | 					skb_dst_set(skb, &rt->dst); | ||||||
| 					goto bridged_dnat; | 					goto bridged_dnat; | ||||||
| 				} | 				} | ||||||
| 				dst_release((struct dst_entry *)rt); | 				ip_rt_put(rt); | ||||||
| 			} | 			} | ||||||
| free_skb: | free_skb: | ||||||
| 			kfree_skb(skb); | 			kfree_skb(skb); | ||||||
|  |  | ||||||
|  | @ -46,7 +46,6 @@ int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) | ||||||
| 	__be16 orig_sport, orig_dport; | 	__be16 orig_sport, orig_dport; | ||||||
| 	struct rtable *rt; | 	struct rtable *rt; | ||||||
| 	__be32 daddr, nexthop; | 	__be32 daddr, nexthop; | ||||||
| 	int tmp; |  | ||||||
| 	int err; | 	int err; | ||||||
| 
 | 
 | ||||||
| 	dp->dccps_role = DCCP_ROLE_CLIENT; | 	dp->dccps_role = DCCP_ROLE_CLIENT; | ||||||
|  | @ -66,12 +65,12 @@ int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) | ||||||
| 
 | 
 | ||||||
| 	orig_sport = inet->inet_sport; | 	orig_sport = inet->inet_sport; | ||||||
| 	orig_dport = usin->sin_port; | 	orig_dport = usin->sin_port; | ||||||
| 	tmp = ip_route_connect(&rt, nexthop, inet->inet_saddr, | 	rt = ip_route_connect(nexthop, inet->inet_saddr, | ||||||
| 			      RT_CONN_FLAGS(sk), sk->sk_bound_dev_if, | 			      RT_CONN_FLAGS(sk), sk->sk_bound_dev_if, | ||||||
| 			      IPPROTO_DCCP, | 			      IPPROTO_DCCP, | ||||||
| 			      orig_sport, orig_dport, sk, true); | 			      orig_sport, orig_dport, sk, true); | ||||||
| 	if (tmp < 0) | 	if (IS_ERR(rt)) | ||||||
| 		return tmp; | 		return PTR_ERR(rt); | ||||||
| 
 | 
 | ||||||
| 	if (rt->rt_flags & (RTCF_MULTICAST | RTCF_BROADCAST)) { | 	if (rt->rt_flags & (RTCF_MULTICAST | RTCF_BROADCAST)) { | ||||||
| 		ip_rt_put(rt); | 		ip_rt_put(rt); | ||||||
|  | @ -102,12 +101,13 @@ int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) | ||||||
| 	if (err != 0) | 	if (err != 0) | ||||||
| 		goto failure; | 		goto failure; | ||||||
| 
 | 
 | ||||||
| 	err = ip_route_newports(&rt, IPPROTO_DCCP, | 	rt = ip_route_newports(rt, IPPROTO_DCCP, | ||||||
| 			       orig_sport, orig_dport, | 			       orig_sport, orig_dport, | ||||||
| 			       inet->inet_sport, inet->inet_dport, sk); | 			       inet->inet_sport, inet->inet_dport, sk); | ||||||
| 	if (err != 0) | 	if (IS_ERR(rt)) { | ||||||
|  | 		rt = NULL; | ||||||
| 		goto failure; | 		goto failure; | ||||||
| 
 | 	} | ||||||
| 	/* OK, now commit destination to socket.  */ | 	/* OK, now commit destination to socket.  */ | ||||||
| 	sk_setup_caps(sk, &rt->dst); | 	sk_setup_caps(sk, &rt->dst); | ||||||
| 
 | 
 | ||||||
|  | @ -475,7 +475,8 @@ static struct dst_entry* dccp_v4_route_skb(struct net *net, struct sock *sk, | ||||||
| 			  }; | 			  }; | ||||||
| 
 | 
 | ||||||
| 	security_skb_classify_flow(skb, &fl); | 	security_skb_classify_flow(skb, &fl); | ||||||
| 	if (ip_route_output_flow(net, &rt, &fl, sk)) { | 	rt = ip_route_output_flow(net, &fl, sk); | ||||||
|  | 	if (IS_ERR(rt)) { | ||||||
| 		IP_INC_STATS_BH(net, IPSTATS_MIB_OUTNOROUTES); | 		IP_INC_STATS_BH(net, IPSTATS_MIB_OUTNOROUTES); | ||||||
| 		return NULL; | 		return NULL; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -1101,23 +1101,20 @@ int sysctl_ip_dynaddr __read_mostly; | ||||||
| static int inet_sk_reselect_saddr(struct sock *sk) | static int inet_sk_reselect_saddr(struct sock *sk) | ||||||
| { | { | ||||||
| 	struct inet_sock *inet = inet_sk(sk); | 	struct inet_sock *inet = inet_sk(sk); | ||||||
| 	int err; |  | ||||||
| 	struct rtable *rt; |  | ||||||
| 	__be32 old_saddr = inet->inet_saddr; | 	__be32 old_saddr = inet->inet_saddr; | ||||||
| 	__be32 new_saddr; |  | ||||||
| 	__be32 daddr = inet->inet_daddr; | 	__be32 daddr = inet->inet_daddr; | ||||||
|  | 	struct rtable *rt; | ||||||
|  | 	__be32 new_saddr; | ||||||
| 
 | 
 | ||||||
| 	if (inet->opt && inet->opt->srr) | 	if (inet->opt && inet->opt->srr) | ||||||
| 		daddr = inet->opt->faddr; | 		daddr = inet->opt->faddr; | ||||||
| 
 | 
 | ||||||
| 	/* Query new route. */ | 	/* Query new route. */ | ||||||
| 	err = ip_route_connect(&rt, daddr, 0, | 	rt = ip_route_connect(daddr, 0, RT_CONN_FLAGS(sk), | ||||||
| 			       RT_CONN_FLAGS(sk), | 			      sk->sk_bound_dev_if, sk->sk_protocol, | ||||||
| 			       sk->sk_bound_dev_if, |  | ||||||
| 			       sk->sk_protocol, |  | ||||||
| 			      inet->inet_sport, inet->inet_dport, sk, false); | 			      inet->inet_sport, inet->inet_dport, sk, false); | ||||||
| 	if (err) | 	if (IS_ERR(rt)) | ||||||
| 		return err; | 		return PTR_ERR(rt); | ||||||
| 
 | 
 | ||||||
| 	sk_setup_caps(sk, &rt->dst); | 	sk_setup_caps(sk, &rt->dst); | ||||||
| 
 | 
 | ||||||
|  | @ -1160,7 +1157,7 @@ int inet_sk_rebuild_header(struct sock *sk) | ||||||
| 	daddr = inet->inet_daddr; | 	daddr = inet->inet_daddr; | ||||||
| 	if (inet->opt && inet->opt->srr) | 	if (inet->opt && inet->opt->srr) | ||||||
| 		daddr = inet->opt->faddr; | 		daddr = inet->opt->faddr; | ||||||
| { | 	{ | ||||||
| 	struct flowi fl = { | 	struct flowi fl = { | ||||||
| 		.oif = sk->sk_bound_dev_if, | 		.oif = sk->sk_bound_dev_if, | ||||||
| 		.mark = sk->sk_mark, | 		.mark = sk->sk_mark, | ||||||
|  | @ -1174,11 +1171,14 @@ int inet_sk_rebuild_header(struct sock *sk) | ||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
| 	security_sk_classify_flow(sk, &fl); | 	security_sk_classify_flow(sk, &fl); | ||||||
| 	err = ip_route_output_flow(sock_net(sk), &rt, &fl, sk); | 	rt = ip_route_output_flow(sock_net(sk), &fl, sk); | ||||||
| } | 	} | ||||||
| 	if (!err) | 	if (!IS_ERR(rt)) { | ||||||
|  | 		err = 0; | ||||||
| 		sk_setup_caps(sk, &rt->dst); | 		sk_setup_caps(sk, &rt->dst); | ||||||
| 	else { | 	} else { | ||||||
|  | 		err = PTR_ERR(rt); | ||||||
|  | 
 | ||||||
| 		/* Routing failed... */ | 		/* Routing failed... */ | ||||||
| 		sk->sk_route_caps = 0; | 		sk->sk_route_caps = 0; | ||||||
| 		/*
 | 		/*
 | ||||||
|  |  | ||||||
|  | @ -440,7 +440,8 @@ static int arp_filter(__be32 sip, __be32 tip, struct net_device *dev) | ||||||
| 	/*unsigned long now; */ | 	/*unsigned long now; */ | ||||||
| 	struct net *net = dev_net(dev); | 	struct net *net = dev_net(dev); | ||||||
| 
 | 
 | ||||||
| 	if (ip_route_output_key(net, &rt, &fl) < 0) | 	rt = ip_route_output_key(net, &fl); | ||||||
|  | 	if (IS_ERR(rt)) | ||||||
| 		return 1; | 		return 1; | ||||||
| 	if (rt->dst.dev != dev) { | 	if (rt->dst.dev != dev) { | ||||||
| 		NET_INC_STATS_BH(net, LINUX_MIB_ARPFILTER); | 		NET_INC_STATS_BH(net, LINUX_MIB_ARPFILTER); | ||||||
|  | @ -1063,10 +1064,10 @@ static int arp_req_set(struct net *net, struct arpreq *r, | ||||||
| 	if (dev == NULL) { | 	if (dev == NULL) { | ||||||
| 		struct flowi fl = { .fl4_dst = ip, | 		struct flowi fl = { .fl4_dst = ip, | ||||||
| 				    .fl4_tos = RTO_ONLINK }; | 				    .fl4_tos = RTO_ONLINK }; | ||||||
| 		struct rtable *rt; | 		struct rtable *rt = ip_route_output_key(net, &fl); | ||||||
| 		err = ip_route_output_key(net, &rt, &fl); | 
 | ||||||
| 		if (err != 0) | 		if (IS_ERR(rt)) | ||||||
| 			return err; | 			return PTR_ERR(rt); | ||||||
| 		dev = rt->dst.dev; | 		dev = rt->dst.dev; | ||||||
| 		ip_rt_put(rt); | 		ip_rt_put(rt); | ||||||
| 		if (!dev) | 		if (!dev) | ||||||
|  | @ -1177,7 +1178,6 @@ static int arp_req_delete_public(struct net *net, struct arpreq *r, | ||||||
| static int arp_req_delete(struct net *net, struct arpreq *r, | static int arp_req_delete(struct net *net, struct arpreq *r, | ||||||
| 			  struct net_device *dev) | 			  struct net_device *dev) | ||||||
| { | { | ||||||
| 	int err; |  | ||||||
| 	__be32 ip; | 	__be32 ip; | ||||||
| 
 | 
 | ||||||
| 	if (r->arp_flags & ATF_PUBL) | 	if (r->arp_flags & ATF_PUBL) | ||||||
|  | @ -1187,10 +1187,9 @@ static int arp_req_delete(struct net *net, struct arpreq *r, | ||||||
| 	if (dev == NULL) { | 	if (dev == NULL) { | ||||||
| 		struct flowi fl = { .fl4_dst = ip, | 		struct flowi fl = { .fl4_dst = ip, | ||||||
| 				    .fl4_tos = RTO_ONLINK }; | 				    .fl4_tos = RTO_ONLINK }; | ||||||
| 		struct rtable *rt; | 		struct rtable *rt = ip_route_output_key(net, &fl); | ||||||
| 		err = ip_route_output_key(net, &rt, &fl); | 		if (IS_ERR(rt)) | ||||||
| 		if (err != 0) | 			return PTR_ERR(rt); | ||||||
| 			return err; |  | ||||||
| 		dev = rt->dst.dev; | 		dev = rt->dst.dev; | ||||||
| 		ip_rt_put(rt); | 		ip_rt_put(rt); | ||||||
| 		if (!dev) | 		if (!dev) | ||||||
|  |  | ||||||
|  | @ -46,11 +46,12 @@ int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) | ||||||
| 		if (!saddr) | 		if (!saddr) | ||||||
| 			saddr = inet->mc_addr; | 			saddr = inet->mc_addr; | ||||||
| 	} | 	} | ||||||
| 	err = ip_route_connect(&rt, usin->sin_addr.s_addr, saddr, | 	rt = ip_route_connect(usin->sin_addr.s_addr, saddr, | ||||||
| 			      RT_CONN_FLAGS(sk), oif, | 			      RT_CONN_FLAGS(sk), oif, | ||||||
| 			      sk->sk_protocol, | 			      sk->sk_protocol, | ||||||
| 			      inet->inet_sport, usin->sin_port, sk, true); | 			      inet->inet_sport, usin->sin_port, sk, true); | ||||||
| 	if (err) { | 	if (IS_ERR(rt)) { | ||||||
|  | 		err = PTR_ERR(rt); | ||||||
| 		if (err == -ENETUNREACH) | 		if (err == -ENETUNREACH) | ||||||
| 			IP_INC_STATS_BH(sock_net(sk), IPSTATS_MIB_OUTNOROUTES); | 			IP_INC_STATS_BH(sock_net(sk), IPSTATS_MIB_OUTNOROUTES); | ||||||
| 		return err; | 		return err; | ||||||
|  |  | ||||||
|  | @ -358,7 +358,8 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb) | ||||||
| 				    .fl4_tos = RT_TOS(ip_hdr(skb)->tos), | 				    .fl4_tos = RT_TOS(ip_hdr(skb)->tos), | ||||||
| 				    .proto = IPPROTO_ICMP }; | 				    .proto = IPPROTO_ICMP }; | ||||||
| 		security_skb_classify_flow(skb, &fl); | 		security_skb_classify_flow(skb, &fl); | ||||||
| 		if (ip_route_output_key(net, &rt, &fl)) | 		rt = ip_route_output_key(net, &fl); | ||||||
|  | 		if (IS_ERR(rt)) | ||||||
| 			goto out_unlock; | 			goto out_unlock; | ||||||
| 	} | 	} | ||||||
| 	if (icmpv4_xrlim_allow(net, rt, icmp_param->data.icmph.type, | 	if (icmpv4_xrlim_allow(net, rt, icmp_param->data.icmph.type, | ||||||
|  | @ -388,9 +389,9 @@ static struct rtable *icmp_route_lookup(struct net *net, struct sk_buff *skb_in, | ||||||
| 	int err; | 	int err; | ||||||
| 
 | 
 | ||||||
| 	security_skb_classify_flow(skb_in, &fl); | 	security_skb_classify_flow(skb_in, &fl); | ||||||
| 	err = __ip_route_output_key(net, &rt, &fl); | 	rt = __ip_route_output_key(net, &fl); | ||||||
| 	if (err) | 	if (IS_ERR(rt)) | ||||||
| 		return ERR_PTR(err); | 		return rt; | ||||||
| 
 | 
 | ||||||
| 	/* No need to clone since we're just using its address. */ | 	/* No need to clone since we're just using its address. */ | ||||||
| 	rt2 = rt; | 	rt2 = rt; | ||||||
|  | @ -412,15 +413,19 @@ static struct rtable *icmp_route_lookup(struct net *net, struct sk_buff *skb_in, | ||||||
| 		goto relookup_failed; | 		goto relookup_failed; | ||||||
| 
 | 
 | ||||||
| 	if (inet_addr_type(net, fl.fl4_src) == RTN_LOCAL) { | 	if (inet_addr_type(net, fl.fl4_src) == RTN_LOCAL) { | ||||||
| 		err = __ip_route_output_key(net, &rt2, &fl); | 		rt2 = __ip_route_output_key(net, &fl); | ||||||
|  | 		if (IS_ERR(rt2)) | ||||||
|  | 			err = PTR_ERR(rt2); | ||||||
| 	} else { | 	} else { | ||||||
| 		struct flowi fl2 = {}; | 		struct flowi fl2 = {}; | ||||||
| 		unsigned long orefdst; | 		unsigned long orefdst; | ||||||
| 
 | 
 | ||||||
| 		fl2.fl4_dst = fl.fl4_src; | 		fl2.fl4_dst = fl.fl4_src; | ||||||
| 		err = ip_route_output_key(net, &rt2, &fl2); | 		rt2 = ip_route_output_key(net, &fl2); | ||||||
| 		if (err) | 		if (IS_ERR(rt2)) { | ||||||
|  | 			err = PTR_ERR(rt2); | ||||||
| 			goto relookup_failed; | 			goto relookup_failed; | ||||||
|  | 		} | ||||||
| 		/* Ugh! */ | 		/* Ugh! */ | ||||||
| 		orefdst = skb_in->_skb_refdst; /* save old refdst */ | 		orefdst = skb_in->_skb_refdst; /* save old refdst */ | ||||||
| 		err = ip_route_input(skb_in, fl.fl4_dst, fl.fl4_src, | 		err = ip_route_input(skb_in, fl.fl4_dst, fl.fl4_src, | ||||||
|  |  | ||||||
|  | @ -325,7 +325,8 @@ static struct sk_buff *igmpv3_newpack(struct net_device *dev, int size) | ||||||
| 		struct flowi fl = { .oif = dev->ifindex, | 		struct flowi fl = { .oif = dev->ifindex, | ||||||
| 				    .fl4_dst = IGMPV3_ALL_MCR, | 				    .fl4_dst = IGMPV3_ALL_MCR, | ||||||
| 				    .proto = IPPROTO_IGMP }; | 				    .proto = IPPROTO_IGMP }; | ||||||
| 		if (ip_route_output_key(net, &rt, &fl)) { | 		rt = ip_route_output_key(net, &fl); | ||||||
|  | 		if (IS_ERR(rt)) { | ||||||
| 			kfree_skb(skb); | 			kfree_skb(skb); | ||||||
| 			return NULL; | 			return NULL; | ||||||
| 		} | 		} | ||||||
|  | @ -670,7 +671,8 @@ static int igmp_send_report(struct in_device *in_dev, struct ip_mc_list *pmc, | ||||||
| 		struct flowi fl = { .oif = dev->ifindex, | 		struct flowi fl = { .oif = dev->ifindex, | ||||||
| 				    .fl4_dst = dst, | 				    .fl4_dst = dst, | ||||||
| 				    .proto = IPPROTO_IGMP }; | 				    .proto = IPPROTO_IGMP }; | ||||||
| 		if (ip_route_output_key(net, &rt, &fl)) | 		rt = ip_route_output_key(net, &fl); | ||||||
|  | 		if (IS_ERR(rt)) | ||||||
| 			return -1; | 			return -1; | ||||||
| 	} | 	} | ||||||
| 	if (rt->rt_src == 0) { | 	if (rt->rt_src == 0) { | ||||||
|  | @ -1440,7 +1442,6 @@ void ip_mc_destroy_dev(struct in_device *in_dev) | ||||||
| static struct in_device *ip_mc_find_dev(struct net *net, struct ip_mreqn *imr) | static struct in_device *ip_mc_find_dev(struct net *net, struct ip_mreqn *imr) | ||||||
| { | { | ||||||
| 	struct flowi fl = { .fl4_dst = imr->imr_multiaddr.s_addr }; | 	struct flowi fl = { .fl4_dst = imr->imr_multiaddr.s_addr }; | ||||||
| 	struct rtable *rt; |  | ||||||
| 	struct net_device *dev = NULL; | 	struct net_device *dev = NULL; | ||||||
| 	struct in_device *idev = NULL; | 	struct in_device *idev = NULL; | ||||||
| 
 | 
 | ||||||
|  | @ -1454,10 +1455,13 @@ static struct in_device *ip_mc_find_dev(struct net *net, struct ip_mreqn *imr) | ||||||
| 			return NULL; | 			return NULL; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (!dev && !ip_route_output_key(net, &rt, &fl)) { | 	if (!dev) { | ||||||
|  | 		struct rtable *rt = ip_route_output_key(net, &fl); | ||||||
|  | 		if (!IS_ERR(rt)) { | ||||||
| 			dev = rt->dst.dev; | 			dev = rt->dst.dev; | ||||||
| 			ip_rt_put(rt); | 			ip_rt_put(rt); | ||||||
| 		} | 		} | ||||||
|  | 	} | ||||||
| 	if (dev) { | 	if (dev) { | ||||||
| 		imr->imr_ifindex = dev->ifindex; | 		imr->imr_ifindex = dev->ifindex; | ||||||
| 		idev = __in_dev_get_rtnl(dev); | 		idev = __in_dev_get_rtnl(dev); | ||||||
|  |  | ||||||
|  | @ -369,7 +369,8 @@ struct dst_entry *inet_csk_route_req(struct sock *sk, | ||||||
| 	struct net *net = sock_net(sk); | 	struct net *net = sock_net(sk); | ||||||
| 
 | 
 | ||||||
| 	security_req_classify_flow(req, &fl); | 	security_req_classify_flow(req, &fl); | ||||||
| 	if (ip_route_output_flow(net, &rt, &fl, sk)) | 	rt = ip_route_output_flow(net, &fl, sk); | ||||||
|  | 	if (IS_ERR(rt)) | ||||||
| 		goto no_route; | 		goto no_route; | ||||||
| 	if (opt && opt->is_strictroute && rt->rt_dst != rt->rt_gateway) | 	if (opt && opt->is_strictroute && rt->rt_dst != rt->rt_gateway) | ||||||
| 		goto route_err; | 		goto route_err; | ||||||
|  |  | ||||||
|  | @ -778,7 +778,8 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev | ||||||
| 			.proto = IPPROTO_GRE, | 			.proto = IPPROTO_GRE, | ||||||
| 			.fl_gre_key = tunnel->parms.o_key | 			.fl_gre_key = tunnel->parms.o_key | ||||||
| 		}; | 		}; | ||||||
| 		if (ip_route_output_key(dev_net(dev), &rt, &fl)) { | 		rt = ip_route_output_key(dev_net(dev), &fl); | ||||||
|  | 		if (IS_ERR(rt)) { | ||||||
| 			dev->stats.tx_carrier_errors++; | 			dev->stats.tx_carrier_errors++; | ||||||
| 			goto tx_error; | 			goto tx_error; | ||||||
| 		} | 		} | ||||||
|  | @ -953,9 +954,9 @@ static int ipgre_tunnel_bind_dev(struct net_device *dev) | ||||||
| 			.proto = IPPROTO_GRE, | 			.proto = IPPROTO_GRE, | ||||||
| 			.fl_gre_key = tunnel->parms.o_key | 			.fl_gre_key = tunnel->parms.o_key | ||||||
| 		}; | 		}; | ||||||
| 		struct rtable *rt; | 		struct rtable *rt = ip_route_output_key(dev_net(dev), &fl); | ||||||
| 
 | 
 | ||||||
| 		if (!ip_route_output_key(dev_net(dev), &rt, &fl)) { | 		if (!IS_ERR(rt)) { | ||||||
| 			tdev = rt->dst.dev; | 			tdev = rt->dst.dev; | ||||||
| 			ip_rt_put(rt); | 			ip_rt_put(rt); | ||||||
| 		} | 		} | ||||||
|  | @ -1215,9 +1216,9 @@ static int ipgre_open(struct net_device *dev) | ||||||
| 			.proto = IPPROTO_GRE, | 			.proto = IPPROTO_GRE, | ||||||
| 			.fl_gre_key = t->parms.o_key | 			.fl_gre_key = t->parms.o_key | ||||||
| 		}; | 		}; | ||||||
| 		struct rtable *rt; | 		struct rtable *rt = ip_route_output_key(dev_net(dev), &fl); | ||||||
| 
 | 
 | ||||||
| 		if (ip_route_output_key(dev_net(dev), &rt, &fl)) | 		if (IS_ERR(rt)) | ||||||
| 			return -EADDRNOTAVAIL; | 			return -EADDRNOTAVAIL; | ||||||
| 		dev = rt->dst.dev; | 		dev = rt->dst.dev; | ||||||
| 		ip_rt_put(rt); | 		ip_rt_put(rt); | ||||||
|  |  | ||||||
|  | @ -355,7 +355,8 @@ int ip_queue_xmit(struct sk_buff *skb) | ||||||
| 			 * itself out. | 			 * itself out. | ||||||
| 			 */ | 			 */ | ||||||
| 			security_sk_classify_flow(sk, &fl); | 			security_sk_classify_flow(sk, &fl); | ||||||
| 			if (ip_route_output_flow(sock_net(sk), &rt, &fl, sk)) | 			rt = ip_route_output_flow(sock_net(sk), &fl, sk); | ||||||
|  | 			if (IS_ERR(rt)) | ||||||
| 				goto no_route; | 				goto no_route; | ||||||
| 		} | 		} | ||||||
| 		sk_setup_caps(sk, &rt->dst); | 		sk_setup_caps(sk, &rt->dst); | ||||||
|  | @ -1489,7 +1490,8 @@ void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *ar | ||||||
| 				    .proto = sk->sk_protocol, | 				    .proto = sk->sk_protocol, | ||||||
| 				    .flags = ip_reply_arg_flowi_flags(arg) }; | 				    .flags = ip_reply_arg_flowi_flags(arg) }; | ||||||
| 		security_skb_classify_flow(skb, &fl); | 		security_skb_classify_flow(skb, &fl); | ||||||
| 		if (ip_route_output_key(sock_net(sk), &rt, &fl)) | 		rt = ip_route_output_key(sock_net(sk), &fl); | ||||||
|  | 		if (IS_ERR(rt)) | ||||||
| 			return; | 			return; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -469,7 +469,8 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) | ||||||
| 			.proto = IPPROTO_IPIP | 			.proto = IPPROTO_IPIP | ||||||
| 		}; | 		}; | ||||||
| 
 | 
 | ||||||
| 		if (ip_route_output_key(dev_net(dev), &rt, &fl)) { | 		rt = ip_route_output_key(dev_net(dev), &fl); | ||||||
|  | 		if (IS_ERR(rt)) { | ||||||
| 			dev->stats.tx_carrier_errors++; | 			dev->stats.tx_carrier_errors++; | ||||||
| 			goto tx_error_icmp; | 			goto tx_error_icmp; | ||||||
| 		} | 		} | ||||||
|  | @ -590,9 +591,9 @@ static void ipip_tunnel_bind_dev(struct net_device *dev) | ||||||
| 			.fl4_tos = RT_TOS(iph->tos), | 			.fl4_tos = RT_TOS(iph->tos), | ||||||
| 			.proto = IPPROTO_IPIP | 			.proto = IPPROTO_IPIP | ||||||
| 		}; | 		}; | ||||||
| 		struct rtable *rt; | 		struct rtable *rt = ip_route_output_key(dev_net(dev), &fl); | ||||||
| 
 | 
 | ||||||
| 		if (!ip_route_output_key(dev_net(dev), &rt, &fl)) { | 		if (!IS_ERR(rt)) { | ||||||
| 			tdev = rt->dst.dev; | 			tdev = rt->dst.dev; | ||||||
| 			ip_rt_put(rt); | 			ip_rt_put(rt); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | @ -1618,8 +1618,8 @@ static void ipmr_queue_xmit(struct net *net, struct mr_table *mrt, | ||||||
| 			.fl4_tos = RT_TOS(iph->tos), | 			.fl4_tos = RT_TOS(iph->tos), | ||||||
| 			.proto = IPPROTO_IPIP | 			.proto = IPPROTO_IPIP | ||||||
| 		}; | 		}; | ||||||
| 
 | 		rt = ip_route_output_key(net, &fl); | ||||||
| 		if (ip_route_output_key(net, &rt, &fl)) | 		if (IS_ERR(rt)) | ||||||
| 			goto out_free; | 			goto out_free; | ||||||
| 		encap = sizeof(struct iphdr); | 		encap = sizeof(struct iphdr); | ||||||
| 	} else { | 	} else { | ||||||
|  | @ -1629,8 +1629,8 @@ static void ipmr_queue_xmit(struct net *net, struct mr_table *mrt, | ||||||
| 			.fl4_tos = RT_TOS(iph->tos), | 			.fl4_tos = RT_TOS(iph->tos), | ||||||
| 			.proto = IPPROTO_IPIP | 			.proto = IPPROTO_IPIP | ||||||
| 		}; | 		}; | ||||||
| 
 | 		rt = ip_route_output_key(net, &fl); | ||||||
| 		if (ip_route_output_key(net, &rt, &fl)) | 		if (IS_ERR(rt)) | ||||||
| 			goto out_free; | 			goto out_free; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -38,7 +38,8 @@ int ip_route_me_harder(struct sk_buff *skb, unsigned addr_type) | ||||||
| 		fl.oif = skb->sk ? skb->sk->sk_bound_dev_if : 0; | 		fl.oif = skb->sk ? skb->sk->sk_bound_dev_if : 0; | ||||||
| 		fl.mark = skb->mark; | 		fl.mark = skb->mark; | ||||||
| 		fl.flags = skb->sk ? inet_sk_flowi_flags(skb->sk) : 0; | 		fl.flags = skb->sk ? inet_sk_flowi_flags(skb->sk) : 0; | ||||||
| 		if (ip_route_output_key(net, &rt, &fl) != 0) | 		rt = ip_route_output_key(net, &fl); | ||||||
|  | 		if (IS_ERR(rt)) | ||||||
| 			return -1; | 			return -1; | ||||||
| 
 | 
 | ||||||
| 		/* Drop old route. */ | 		/* Drop old route. */ | ||||||
|  | @ -48,7 +49,8 @@ int ip_route_me_harder(struct sk_buff *skb, unsigned addr_type) | ||||||
| 		/* non-local src, find valid iif to satisfy
 | 		/* non-local src, find valid iif to satisfy
 | ||||||
| 		 * rp-filter when calling ip_route_input. */ | 		 * rp-filter when calling ip_route_input. */ | ||||||
| 		fl.fl4_dst = iph->saddr; | 		fl.fl4_dst = iph->saddr; | ||||||
| 		if (ip_route_output_key(net, &rt, &fl) != 0) | 		rt = ip_route_output_key(net, &fl); | ||||||
|  | 		if (IS_ERR(rt)) | ||||||
| 			return -1; | 			return -1; | ||||||
| 
 | 
 | ||||||
| 		orefdst = skb->_skb_refdst; | 		orefdst = skb->_skb_refdst; | ||||||
|  | @ -221,7 +223,11 @@ static __sum16 nf_ip_checksum_partial(struct sk_buff *skb, unsigned int hook, | ||||||
| 
 | 
 | ||||||
| static int nf_ip_route(struct dst_entry **dst, struct flowi *fl) | static int nf_ip_route(struct dst_entry **dst, struct flowi *fl) | ||||||
| { | { | ||||||
| 	return ip_route_output_key(&init_net, (struct rtable **)dst, fl); | 	struct rtable *rt = ip_route_output_key(&init_net, fl); | ||||||
|  | 	if (IS_ERR(rt)) | ||||||
|  | 		return PTR_ERR(rt); | ||||||
|  | 	*dst = &rt->dst; | ||||||
|  | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static const struct nf_afinfo nf_ip_afinfo = { | static const struct nf_afinfo nf_ip_afinfo = { | ||||||
|  |  | ||||||
|  | @ -564,10 +564,12 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		security_sk_classify_flow(sk, &fl); | 		security_sk_classify_flow(sk, &fl); | ||||||
| 		err = ip_route_output_flow(sock_net(sk), &rt, &fl, sk); | 		rt = ip_route_output_flow(sock_net(sk), &fl, sk); | ||||||
| 	} | 		if (IS_ERR(rt)) { | ||||||
| 	if (err) | 			err = PTR_ERR(rt); | ||||||
| 			goto done; | 			goto done; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	err = -EACCES; | 	err = -EACCES; | ||||||
| 	if (rt->rt_flags & RTCF_BROADCAST && !sock_flag(sk, SOCK_BROADCAST)) | 	if (rt->rt_flags & RTCF_BROADCAST && !sock_flag(sk, SOCK_BROADCAST)) | ||||||
|  |  | ||||||
|  | @ -1014,8 +1014,8 @@ static int slow_chain_length(const struct rtable *head) | ||||||
| 	return length >> FRACT_BITS; | 	return length >> FRACT_BITS; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int rt_intern_hash(unsigned hash, struct rtable *rt, | static struct rtable *rt_intern_hash(unsigned hash, struct rtable *rt, | ||||||
| 			  struct rtable **rp, struct sk_buff *skb, int ifindex) | 				     struct sk_buff *skb, int ifindex) | ||||||
| { | { | ||||||
| 	struct rtable	*rth, *cand; | 	struct rtable	*rth, *cand; | ||||||
| 	struct rtable __rcu **rthp, **candp; | 	struct rtable __rcu **rthp, **candp; | ||||||
|  | @ -1056,7 +1056,7 @@ restart: | ||||||
| 					printk(KERN_WARNING | 					printk(KERN_WARNING | ||||||
| 					    "Neighbour table failure & not caching routes.\n"); | 					    "Neighbour table failure & not caching routes.\n"); | ||||||
| 				ip_rt_put(rt); | 				ip_rt_put(rt); | ||||||
| 				return err; | 				return ERR_PTR(err); | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | @ -1093,11 +1093,9 @@ restart: | ||||||
| 			spin_unlock_bh(rt_hash_lock_addr(hash)); | 			spin_unlock_bh(rt_hash_lock_addr(hash)); | ||||||
| 
 | 
 | ||||||
| 			rt_drop(rt); | 			rt_drop(rt); | ||||||
| 			if (rp) | 			if (skb) | ||||||
| 				*rp = rth; |  | ||||||
| 			else |  | ||||||
| 				skb_dst_set(skb, &rth->dst); | 				skb_dst_set(skb, &rth->dst); | ||||||
| 			return 0; | 			return rth; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if (!atomic_read(&rth->dst.__refcnt)) { | 		if (!atomic_read(&rth->dst.__refcnt)) { | ||||||
|  | @ -1154,7 +1152,7 @@ restart: | ||||||
| 
 | 
 | ||||||
| 			if (err != -ENOBUFS) { | 			if (err != -ENOBUFS) { | ||||||
| 				rt_drop(rt); | 				rt_drop(rt); | ||||||
| 				return err; | 				return ERR_PTR(err); | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			/* Neighbour tables are full and nothing
 | 			/* Neighbour tables are full and nothing
 | ||||||
|  | @ -1175,7 +1173,7 @@ restart: | ||||||
| 			if (net_ratelimit()) | 			if (net_ratelimit()) | ||||||
| 				printk(KERN_WARNING "ipv4: Neighbour table overflow.\n"); | 				printk(KERN_WARNING "ipv4: Neighbour table overflow.\n"); | ||||||
| 			rt_drop(rt); | 			rt_drop(rt); | ||||||
| 			return -ENOBUFS; | 			return ERR_PTR(-ENOBUFS); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -1201,11 +1199,9 @@ restart: | ||||||
| 	spin_unlock_bh(rt_hash_lock_addr(hash)); | 	spin_unlock_bh(rt_hash_lock_addr(hash)); | ||||||
| 
 | 
 | ||||||
| skip_hashing: | skip_hashing: | ||||||
| 	if (rp) | 	if (skb) | ||||||
| 		*rp = rt; |  | ||||||
| 	else |  | ||||||
| 		skb_dst_set(skb, &rt->dst); | 		skb_dst_set(skb, &rt->dst); | ||||||
| 	return 0; | 	return rt; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static atomic_t __rt_peer_genid = ATOMIC_INIT(0); | static atomic_t __rt_peer_genid = ATOMIC_INIT(0); | ||||||
|  | @ -1896,7 +1892,10 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr, | ||||||
| 	RT_CACHE_STAT_INC(in_slow_mc); | 	RT_CACHE_STAT_INC(in_slow_mc); | ||||||
| 
 | 
 | ||||||
| 	hash = rt_hash(daddr, saddr, dev->ifindex, rt_genid(dev_net(dev))); | 	hash = rt_hash(daddr, saddr, dev->ifindex, rt_genid(dev_net(dev))); | ||||||
| 	return rt_intern_hash(hash, rth, NULL, skb, dev->ifindex); | 	rth = rt_intern_hash(hash, rth, skb, dev->ifindex); | ||||||
|  | 	err = 0; | ||||||
|  | 	if (IS_ERR(rth)) | ||||||
|  | 		err = PTR_ERR(rth); | ||||||
| 
 | 
 | ||||||
| e_nobufs: | e_nobufs: | ||||||
| 	return -ENOBUFS; | 	return -ENOBUFS; | ||||||
|  | @ -2051,7 +2050,10 @@ static int ip_mkroute_input(struct sk_buff *skb, | ||||||
| 	/* put it into the cache */ | 	/* put it into the cache */ | ||||||
| 	hash = rt_hash(daddr, saddr, fl->iif, | 	hash = rt_hash(daddr, saddr, fl->iif, | ||||||
| 		       rt_genid(dev_net(rth->dst.dev))); | 		       rt_genid(dev_net(rth->dst.dev))); | ||||||
| 	return rt_intern_hash(hash, rth, NULL, skb, fl->iif); | 	rth = rt_intern_hash(hash, rth, skb, fl->iif); | ||||||
|  | 	if (IS_ERR(rth)) | ||||||
|  | 		return PTR_ERR(rth); | ||||||
|  | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  | @ -2194,7 +2196,10 @@ local_input: | ||||||
| 	} | 	} | ||||||
| 	rth->rt_type	= res.type; | 	rth->rt_type	= res.type; | ||||||
| 	hash = rt_hash(daddr, saddr, fl.iif, rt_genid(net)); | 	hash = rt_hash(daddr, saddr, fl.iif, rt_genid(net)); | ||||||
| 	err = rt_intern_hash(hash, rth, NULL, skb, fl.iif); | 	rth = rt_intern_hash(hash, rth, skb, fl.iif); | ||||||
|  | 	err = 0; | ||||||
|  | 	if (IS_ERR(rth)) | ||||||
|  | 		err = PTR_ERR(rth); | ||||||
| 	goto out; | 	goto out; | ||||||
| 
 | 
 | ||||||
| no_route: | no_route: | ||||||
|  | @ -2422,7 +2427,7 @@ static struct rtable *__mkroute_output(const struct fib_result *res, | ||||||
|  * called with rcu_read_lock(); |  * called with rcu_read_lock(); | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| static int ip_route_output_slow(struct net *net, struct rtable **rp, | static struct rtable *ip_route_output_slow(struct net *net, | ||||||
| 					   const struct flowi *oldflp) | 					   const struct flowi *oldflp) | ||||||
| { | { | ||||||
| 	u32 tos	= RT_FL_TOS(oldflp); | 	u32 tos	= RT_FL_TOS(oldflp); | ||||||
|  | @ -2438,8 +2443,6 @@ static int ip_route_output_slow(struct net *net, struct rtable **rp, | ||||||
| 	unsigned int flags = 0; | 	unsigned int flags = 0; | ||||||
| 	struct net_device *dev_out = NULL; | 	struct net_device *dev_out = NULL; | ||||||
| 	struct rtable *rth; | 	struct rtable *rth; | ||||||
| 	int err; |  | ||||||
| 
 |  | ||||||
| 
 | 
 | ||||||
| 	res.fi		= NULL; | 	res.fi		= NULL; | ||||||
| #ifdef CONFIG_IP_MULTIPLE_TABLES | #ifdef CONFIG_IP_MULTIPLE_TABLES | ||||||
|  | @ -2448,7 +2451,7 @@ static int ip_route_output_slow(struct net *net, struct rtable **rp, | ||||||
| 
 | 
 | ||||||
| 	rcu_read_lock(); | 	rcu_read_lock(); | ||||||
| 	if (oldflp->fl4_src) { | 	if (oldflp->fl4_src) { | ||||||
| 		err = -EINVAL; | 		rth = ERR_PTR(-EINVAL); | ||||||
| 		if (ipv4_is_multicast(oldflp->fl4_src) || | 		if (ipv4_is_multicast(oldflp->fl4_src) || | ||||||
| 		    ipv4_is_lbcast(oldflp->fl4_src) || | 		    ipv4_is_lbcast(oldflp->fl4_src) || | ||||||
| 		    ipv4_is_zeronet(oldflp->fl4_src)) | 		    ipv4_is_zeronet(oldflp->fl4_src)) | ||||||
|  | @ -2499,13 +2502,13 @@ static int ip_route_output_slow(struct net *net, struct rtable **rp, | ||||||
| 
 | 
 | ||||||
| 	if (oldflp->oif) { | 	if (oldflp->oif) { | ||||||
| 		dev_out = dev_get_by_index_rcu(net, oldflp->oif); | 		dev_out = dev_get_by_index_rcu(net, oldflp->oif); | ||||||
| 		err = -ENODEV; | 		rth = ERR_PTR(-ENODEV); | ||||||
| 		if (dev_out == NULL) | 		if (dev_out == NULL) | ||||||
| 			goto out; | 			goto out; | ||||||
| 
 | 
 | ||||||
| 		/* RACE: Check return value of inet_select_addr instead. */ | 		/* RACE: Check return value of inet_select_addr instead. */ | ||||||
| 		if (!(dev_out->flags & IFF_UP) || !__in_dev_get_rcu(dev_out)) { | 		if (!(dev_out->flags & IFF_UP) || !__in_dev_get_rcu(dev_out)) { | ||||||
| 			err = -ENETUNREACH; | 			rth = ERR_PTR(-ENETUNREACH); | ||||||
| 			goto out; | 			goto out; | ||||||
| 		} | 		} | ||||||
| 		if (ipv4_is_local_multicast(oldflp->fl4_dst) || | 		if (ipv4_is_local_multicast(oldflp->fl4_dst) || | ||||||
|  | @ -2563,7 +2566,7 @@ static int ip_route_output_slow(struct net *net, struct rtable **rp, | ||||||
| 			res.type = RTN_UNICAST; | 			res.type = RTN_UNICAST; | ||||||
| 			goto make_route; | 			goto make_route; | ||||||
| 		} | 		} | ||||||
| 		err = -ENETUNREACH; | 		rth = ERR_PTR(-ENETUNREACH); | ||||||
| 		goto out; | 		goto out; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -2598,23 +2601,20 @@ static int ip_route_output_slow(struct net *net, struct rtable **rp, | ||||||
| 
 | 
 | ||||||
| make_route: | make_route: | ||||||
| 	rth = __mkroute_output(&res, &fl, oldflp, dev_out, flags); | 	rth = __mkroute_output(&res, &fl, oldflp, dev_out, flags); | ||||||
| 	if (IS_ERR(rth)) | 	if (!IS_ERR(rth)) { | ||||||
| 		err = PTR_ERR(rth); |  | ||||||
| 	else { |  | ||||||
| 		unsigned int hash; | 		unsigned int hash; | ||||||
| 
 | 
 | ||||||
| 		hash = rt_hash(oldflp->fl4_dst, oldflp->fl4_src, oldflp->oif, | 		hash = rt_hash(oldflp->fl4_dst, oldflp->fl4_src, oldflp->oif, | ||||||
| 			       rt_genid(dev_net(dev_out))); | 			       rt_genid(dev_net(dev_out))); | ||||||
| 		err = rt_intern_hash(hash, rth, rp, NULL, oldflp->oif); | 		rth = rt_intern_hash(hash, rth, NULL, oldflp->oif); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| out: | out: | ||||||
| 	rcu_read_unlock(); | 	rcu_read_unlock(); | ||||||
| 	return err; | 	return rth; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int __ip_route_output_key(struct net *net, struct rtable **rp, | struct rtable *__ip_route_output_key(struct net *net, const struct flowi *flp) | ||||||
| 			  const struct flowi *flp) |  | ||||||
| { | { | ||||||
| 	struct rtable *rth; | 	struct rtable *rth; | ||||||
| 	unsigned int hash; | 	unsigned int hash; | ||||||
|  | @ -2639,15 +2639,14 @@ int __ip_route_output_key(struct net *net, struct rtable **rp, | ||||||
| 			dst_use(&rth->dst, jiffies); | 			dst_use(&rth->dst, jiffies); | ||||||
| 			RT_CACHE_STAT_INC(out_hit); | 			RT_CACHE_STAT_INC(out_hit); | ||||||
| 			rcu_read_unlock_bh(); | 			rcu_read_unlock_bh(); | ||||||
| 			*rp = rth; | 			return rth; | ||||||
| 			return 0; |  | ||||||
| 		} | 		} | ||||||
| 		RT_CACHE_STAT_INC(out_hlist_search); | 		RT_CACHE_STAT_INC(out_hlist_search); | ||||||
| 	} | 	} | ||||||
| 	rcu_read_unlock_bh(); | 	rcu_read_unlock_bh(); | ||||||
| 
 | 
 | ||||||
| slow_output: | slow_output: | ||||||
| 	return ip_route_output_slow(net, rp, flp); | 	return ip_route_output_slow(net, flp); | ||||||
| } | } | ||||||
| EXPORT_SYMBOL_GPL(__ip_route_output_key); | EXPORT_SYMBOL_GPL(__ip_route_output_key); | ||||||
| 
 | 
 | ||||||
|  | @ -2717,34 +2716,29 @@ struct dst_entry *ipv4_blackhole_route(struct net *net, struct dst_entry *dst_or | ||||||
| 	return rt ? &rt->dst : ERR_PTR(-ENOMEM); | 	return rt ? &rt->dst : ERR_PTR(-ENOMEM); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int ip_route_output_flow(struct net *net, struct rtable **rp, struct flowi *flp, | struct rtable *ip_route_output_flow(struct net *net, struct flowi *flp, | ||||||
| 				    struct sock *sk) | 				    struct sock *sk) | ||||||
| { | { | ||||||
| 	int err; | 	struct rtable *rt = __ip_route_output_key(net, flp); | ||||||
| 
 | 
 | ||||||
| 	if ((err = __ip_route_output_key(net, rp, flp)) != 0) | 	if (IS_ERR(rt)) | ||||||
| 		return err; | 		return rt; | ||||||
| 
 | 
 | ||||||
| 	if (flp->proto) { | 	if (flp->proto) { | ||||||
| 		if (!flp->fl4_src) | 		if (!flp->fl4_src) | ||||||
| 			flp->fl4_src = (*rp)->rt_src; | 			flp->fl4_src = rt->rt_src; | ||||||
| 		if (!flp->fl4_dst) | 		if (!flp->fl4_dst) | ||||||
| 			flp->fl4_dst = (*rp)->rt_dst; | 			flp->fl4_dst = rt->rt_dst; | ||||||
| 		*rp = (struct rtable *) xfrm_lookup(net, &(*rp)->dst, flp, sk, 0); | 		rt = (struct rtable *) xfrm_lookup(net, &rt->dst, flp, sk, 0); | ||||||
| 		if (IS_ERR(*rp)) { |  | ||||||
| 			err = PTR_ERR(*rp); |  | ||||||
| 			*rp = NULL; |  | ||||||
| 			return err; |  | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return rt; | ||||||
| } | } | ||||||
| EXPORT_SYMBOL_GPL(ip_route_output_flow); | EXPORT_SYMBOL_GPL(ip_route_output_flow); | ||||||
| 
 | 
 | ||||||
| int ip_route_output_key(struct net *net, struct rtable **rp, struct flowi *flp) | struct rtable *ip_route_output_key(struct net *net, struct flowi *flp) | ||||||
| { | { | ||||||
| 	return ip_route_output_flow(net, rp, flp, NULL); | 	return ip_route_output_flow(net, flp, NULL); | ||||||
| } | } | ||||||
| EXPORT_SYMBOL(ip_route_output_key); | EXPORT_SYMBOL(ip_route_output_key); | ||||||
| 
 | 
 | ||||||
|  | @ -2915,7 +2909,11 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void | ||||||
| 			.oif = tb[RTA_OIF] ? nla_get_u32(tb[RTA_OIF]) : 0, | 			.oif = tb[RTA_OIF] ? nla_get_u32(tb[RTA_OIF]) : 0, | ||||||
| 			.mark = mark, | 			.mark = mark, | ||||||
| 		}; | 		}; | ||||||
| 		err = ip_route_output_key(net, &rt, &fl); | 		rt = ip_route_output_key(net, &fl); | ||||||
|  | 
 | ||||||
|  | 		err = 0; | ||||||
|  | 		if (IS_ERR(rt)) | ||||||
|  | 			err = PTR_ERR(rt); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (err) | 	if (err) | ||||||
|  |  | ||||||
|  | @ -355,7 +355,8 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, | ||||||
| 				    .fl_ip_sport = th->dest, | 				    .fl_ip_sport = th->dest, | ||||||
| 				    .fl_ip_dport = th->source }; | 				    .fl_ip_dport = th->source }; | ||||||
| 		security_req_classify_flow(req, &fl); | 		security_req_classify_flow(req, &fl); | ||||||
| 		if (ip_route_output_key(sock_net(sk), &rt, &fl)) { | 		rt = ip_route_output_key(sock_net(sk), &fl); | ||||||
|  | 		if (IS_ERR(rt)) { | ||||||
| 			reqsk_free(req); | 			reqsk_free(req); | ||||||
| 			goto out; | 			goto out; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | @ -152,7 +152,6 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) | ||||||
| 	__be16 orig_sport, orig_dport; | 	__be16 orig_sport, orig_dport; | ||||||
| 	struct rtable *rt; | 	struct rtable *rt; | ||||||
| 	__be32 daddr, nexthop; | 	__be32 daddr, nexthop; | ||||||
| 	int tmp; |  | ||||||
| 	int err; | 	int err; | ||||||
| 
 | 
 | ||||||
| 	if (addr_len < sizeof(struct sockaddr_in)) | 	if (addr_len < sizeof(struct sockaddr_in)) | ||||||
|  | @ -170,14 +169,15 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) | ||||||
| 
 | 
 | ||||||
| 	orig_sport = inet->inet_sport; | 	orig_sport = inet->inet_sport; | ||||||
| 	orig_dport = usin->sin_port; | 	orig_dport = usin->sin_port; | ||||||
| 	tmp = ip_route_connect(&rt, nexthop, inet->inet_saddr, | 	rt = ip_route_connect(nexthop, inet->inet_saddr, | ||||||
| 			      RT_CONN_FLAGS(sk), sk->sk_bound_dev_if, | 			      RT_CONN_FLAGS(sk), sk->sk_bound_dev_if, | ||||||
| 			      IPPROTO_TCP, | 			      IPPROTO_TCP, | ||||||
| 			      orig_sport, orig_dport, sk, true); | 			      orig_sport, orig_dport, sk, true); | ||||||
| 	if (tmp < 0) { | 	if (IS_ERR(rt)) { | ||||||
| 		if (tmp == -ENETUNREACH) | 		err = PTR_ERR(rt); | ||||||
|  | 		if (err == -ENETUNREACH) | ||||||
| 			IP_INC_STATS_BH(sock_net(sk), IPSTATS_MIB_OUTNOROUTES); | 			IP_INC_STATS_BH(sock_net(sk), IPSTATS_MIB_OUTNOROUTES); | ||||||
| 		return tmp; | 		return err; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (rt->rt_flags & (RTCF_MULTICAST | RTCF_BROADCAST)) { | 	if (rt->rt_flags & (RTCF_MULTICAST | RTCF_BROADCAST)) { | ||||||
|  | @ -236,12 +236,14 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) | ||||||
| 	if (err) | 	if (err) | ||||||
| 		goto failure; | 		goto failure; | ||||||
| 
 | 
 | ||||||
| 	err = ip_route_newports(&rt, IPPROTO_TCP, | 	rt = ip_route_newports(rt, IPPROTO_TCP, | ||||||
| 			       orig_sport, orig_dport, | 			       orig_sport, orig_dport, | ||||||
| 			       inet->inet_sport, inet->inet_dport, sk); | 			       inet->inet_sport, inet->inet_dport, sk); | ||||||
| 	if (err) | 	if (IS_ERR(rt)) { | ||||||
|  | 		err = PTR_ERR(rt); | ||||||
|  | 		rt = NULL; | ||||||
| 		goto failure; | 		goto failure; | ||||||
| 
 | 	} | ||||||
| 	/* OK, now commit destination to socket.  */ | 	/* OK, now commit destination to socket.  */ | ||||||
| 	sk->sk_gso_type = SKB_GSO_TCPV4; | 	sk->sk_gso_type = SKB_GSO_TCPV4; | ||||||
| 	sk_setup_caps(sk, &rt->dst); | 	sk_setup_caps(sk, &rt->dst); | ||||||
|  |  | ||||||
|  | @ -922,8 +922,9 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | ||||||
| 		struct net *net = sock_net(sk); | 		struct net *net = sock_net(sk); | ||||||
| 
 | 
 | ||||||
| 		security_sk_classify_flow(sk, &fl); | 		security_sk_classify_flow(sk, &fl); | ||||||
| 		err = ip_route_output_flow(net, &rt, &fl, sk); | 		rt = ip_route_output_flow(net, &fl, sk); | ||||||
| 		if (err) { | 		if (IS_ERR(rt)) { | ||||||
|  | 			err = PTR_ERR(rt); | ||||||
| 			if (err == -ENETUNREACH) | 			if (err == -ENETUNREACH) | ||||||
| 				IP_INC_STATS_BH(net, IPSTATS_MIB_OUTNOROUTES); | 				IP_INC_STATS_BH(net, IPSTATS_MIB_OUTNOROUTES); | ||||||
| 			goto out; | 			goto out; | ||||||
|  |  | ||||||
|  | @ -26,18 +26,16 @@ static struct dst_entry *xfrm4_dst_lookup(struct net *net, int tos, | ||||||
| 		.fl4_dst = daddr->a4, | 		.fl4_dst = daddr->a4, | ||||||
| 		.fl4_tos = tos, | 		.fl4_tos = tos, | ||||||
| 	}; | 	}; | ||||||
| 	struct dst_entry *dst; |  | ||||||
| 	struct rtable *rt; | 	struct rtable *rt; | ||||||
| 	int err; |  | ||||||
| 
 | 
 | ||||||
| 	if (saddr) | 	if (saddr) | ||||||
| 		fl.fl4_src = saddr->a4; | 		fl.fl4_src = saddr->a4; | ||||||
| 
 | 
 | ||||||
| 	err = __ip_route_output_key(net, &rt, &fl); | 	rt = __ip_route_output_key(net, &fl); | ||||||
| 	dst = &rt->dst; | 	if (!IS_ERR(rt)) | ||||||
| 	if (err) | 		return &rt->dst; | ||||||
| 		dst = ERR_PTR(err); | 
 | ||||||
| 	return dst; | 	return ERR_CAST(rt); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int xfrm4_get_saddr(struct net *net, | static int xfrm4_get_saddr(struct net *net, | ||||||
|  |  | ||||||
|  | @ -581,7 +581,8 @@ ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | ||||||
| 	fl.fl4_dst = eiph->saddr; | 	fl.fl4_dst = eiph->saddr; | ||||||
| 	fl.fl4_tos = RT_TOS(eiph->tos); | 	fl.fl4_tos = RT_TOS(eiph->tos); | ||||||
| 	fl.proto = IPPROTO_IPIP; | 	fl.proto = IPPROTO_IPIP; | ||||||
| 	if (ip_route_output_key(dev_net(skb->dev), &rt, &fl)) | 	rt = ip_route_output_key(dev_net(skb->dev), &fl); | ||||||
|  | 	if (IS_ERR(rt)) | ||||||
| 		goto out; | 		goto out; | ||||||
| 
 | 
 | ||||||
| 	skb2->dev = rt->dst.dev; | 	skb2->dev = rt->dst.dev; | ||||||
|  | @ -593,12 +594,14 @@ ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | ||||||
| 		fl.fl4_dst = eiph->daddr; | 		fl.fl4_dst = eiph->daddr; | ||||||
| 		fl.fl4_src = eiph->saddr; | 		fl.fl4_src = eiph->saddr; | ||||||
| 		fl.fl4_tos = eiph->tos; | 		fl.fl4_tos = eiph->tos; | ||||||
| 		if (ip_route_output_key(dev_net(skb->dev), &rt, &fl) || | 		rt = ip_route_output_key(dev_net(skb->dev), &fl); | ||||||
|  | 		if (IS_ERR(rt) || | ||||||
| 		    rt->dst.dev->type != ARPHRD_TUNNEL) { | 		    rt->dst.dev->type != ARPHRD_TUNNEL) { | ||||||
|  | 			if (!IS_ERR(rt)) | ||||||
| 				ip_rt_put(rt); | 				ip_rt_put(rt); | ||||||
| 			goto out; | 			goto out; | ||||||
| 		} | 		} | ||||||
| 		skb_dst_set(skb2, (struct dst_entry *)rt); | 		skb_dst_set(skb2, &rt->dst); | ||||||
| 	} else { | 	} else { | ||||||
| 		ip_rt_put(rt); | 		ip_rt_put(rt); | ||||||
| 		if (ip_route_input(skb2, eiph->daddr, eiph->saddr, eiph->tos, | 		if (ip_route_input(skb2, eiph->daddr, eiph->saddr, eiph->tos, | ||||||
|  |  | ||||||
|  | @ -738,7 +738,8 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, | ||||||
| 				    .fl4_tos = RT_TOS(tos), | 				    .fl4_tos = RT_TOS(tos), | ||||||
| 				    .oif = tunnel->parms.link, | 				    .oif = tunnel->parms.link, | ||||||
| 				    .proto = IPPROTO_IPV6 }; | 				    .proto = IPPROTO_IPV6 }; | ||||||
| 		if (ip_route_output_key(dev_net(dev), &rt, &fl)) { | 		rt = ip_route_output_key(dev_net(dev), &fl); | ||||||
|  | 		if (IS_ERR(rt)) { | ||||||
| 			dev->stats.tx_carrier_errors++; | 			dev->stats.tx_carrier_errors++; | ||||||
| 			goto tx_error_icmp; | 			goto tx_error_icmp; | ||||||
| 		} | 		} | ||||||
|  | @ -862,8 +863,9 @@ static void ipip6_tunnel_bind_dev(struct net_device *dev) | ||||||
| 				    .fl4_tos = RT_TOS(iph->tos), | 				    .fl4_tos = RT_TOS(iph->tos), | ||||||
| 				    .oif = tunnel->parms.link, | 				    .oif = tunnel->parms.link, | ||||||
| 				    .proto = IPPROTO_IPV6 }; | 				    .proto = IPPROTO_IPV6 }; | ||||||
| 		struct rtable *rt; | 		struct rtable *rt = ip_route_output_key(dev_net(dev), &fl); | ||||||
| 		if (!ip_route_output_key(dev_net(dev), &rt, &fl)) { | 
 | ||||||
|  | 		if (!IS_ERR(rt)) { | ||||||
| 			tdev = rt->dst.dev; | 			tdev = rt->dst.dev; | ||||||
| 			ip_rt_put(rt); | 			ip_rt_put(rt); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | @ -320,11 +320,12 @@ static int l2tp_ip_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len | ||||||
| 	if (ipv4_is_multicast(lsa->l2tp_addr.s_addr)) | 	if (ipv4_is_multicast(lsa->l2tp_addr.s_addr)) | ||||||
| 		goto out; | 		goto out; | ||||||
| 
 | 
 | ||||||
| 	rc = ip_route_connect(&rt, lsa->l2tp_addr.s_addr, saddr, | 	rt = ip_route_connect(lsa->l2tp_addr.s_addr, saddr, | ||||||
| 			      RT_CONN_FLAGS(sk), oif, | 			      RT_CONN_FLAGS(sk), oif, | ||||||
| 			      IPPROTO_L2TP, | 			      IPPROTO_L2TP, | ||||||
| 			      0, 0, sk, true); | 			      0, 0, sk, true); | ||||||
| 	if (rc) { | 	if (IS_ERR(rt)) { | ||||||
|  | 		rc = PTR_ERR(rt); | ||||||
| 		if (rc == -ENETUNREACH) | 		if (rc == -ENETUNREACH) | ||||||
| 			IP_INC_STATS_BH(&init_net, IPSTATS_MIB_OUTNOROUTES); | 			IP_INC_STATS_BH(&init_net, IPSTATS_MIB_OUTNOROUTES); | ||||||
| 		goto out; | 		goto out; | ||||||
|  | @ -489,7 +490,8 @@ static int l2tp_ip_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *m | ||||||
| 			 * itself out. | 			 * itself out. | ||||||
| 			 */ | 			 */ | ||||||
| 			security_sk_classify_flow(sk, &fl); | 			security_sk_classify_flow(sk, &fl); | ||||||
| 			if (ip_route_output_flow(sock_net(sk), &rt, &fl, sk)) | 			rt = ip_route_output_flow(sock_net(sk), &fl, sk); | ||||||
|  | 			if (IS_ERR(rt)) | ||||||
| 				goto no_route; | 				goto no_route; | ||||||
| 		} | 		} | ||||||
| 		sk_setup_caps(sk, &rt->dst); | 		sk_setup_caps(sk, &rt->dst); | ||||||
|  |  | ||||||
|  | @ -103,7 +103,8 @@ __ip_vs_get_out_rt(struct sk_buff *skb, struct ip_vs_dest *dest, | ||||||
| 				.fl4_tos = rtos, | 				.fl4_tos = rtos, | ||||||
| 			}; | 			}; | ||||||
| 
 | 
 | ||||||
| 			if (ip_route_output_key(net, &rt, &fl)) { | 			rt = ip_route_output_key(net, &fl); | ||||||
|  | 			if (IS_ERR(rt)) { | ||||||
| 				spin_unlock(&dest->dst_lock); | 				spin_unlock(&dest->dst_lock); | ||||||
| 				IP_VS_DBG_RL("ip_route_output error, dest: %pI4\n", | 				IP_VS_DBG_RL("ip_route_output error, dest: %pI4\n", | ||||||
| 					     &dest->addr.ip); | 					     &dest->addr.ip); | ||||||
|  | @ -121,7 +122,8 @@ __ip_vs_get_out_rt(struct sk_buff *skb, struct ip_vs_dest *dest, | ||||||
| 			.fl4_tos = rtos, | 			.fl4_tos = rtos, | ||||||
| 		}; | 		}; | ||||||
| 
 | 
 | ||||||
| 		if (ip_route_output_key(net, &rt, &fl)) { | 		rt = ip_route_output_key(net, &fl); | ||||||
|  | 		if (IS_ERR(rt)) { | ||||||
| 			IP_VS_DBG_RL("ip_route_output error, dest: %pI4\n", | 			IP_VS_DBG_RL("ip_route_output error, dest: %pI4\n", | ||||||
| 				     &daddr); | 				     &daddr); | ||||||
| 			return NULL; | 			return NULL; | ||||||
|  | @ -180,7 +182,8 @@ __ip_vs_reroute_locally(struct sk_buff *skb) | ||||||
| 			.mark = skb->mark, | 			.mark = skb->mark, | ||||||
| 		}; | 		}; | ||||||
| 
 | 
 | ||||||
| 		if (ip_route_output_key(net, &rt, &fl)) | 		rt = ip_route_output_key(net, &fl); | ||||||
|  | 		if (IS_ERR(rt)) | ||||||
| 			return 0; | 			return 0; | ||||||
| 		if (!(rt->rt_flags & RTCF_LOCAL)) { | 		if (!(rt->rt_flags & RTCF_LOCAL)) { | ||||||
| 			ip_rt_put(rt); | 			ip_rt_put(rt); | ||||||
|  |  | ||||||
|  | @ -73,7 +73,8 @@ tee_tg_route4(struct sk_buff *skb, const struct xt_tee_tginfo *info) | ||||||
| 	fl.fl4_dst = info->gw.ip; | 	fl.fl4_dst = info->gw.ip; | ||||||
| 	fl.fl4_tos = RT_TOS(iph->tos); | 	fl.fl4_tos = RT_TOS(iph->tos); | ||||||
| 	fl.fl4_scope = RT_SCOPE_UNIVERSE; | 	fl.fl4_scope = RT_SCOPE_UNIVERSE; | ||||||
| 	if (ip_route_output_key(net, &rt, &fl) != 0) | 	rt = ip_route_output_key(net, &fl); | ||||||
|  | 	if (IS_ERR(rt)) | ||||||
| 		return false; | 		return false; | ||||||
| 
 | 
 | ||||||
| 	skb_dst_drop(skb); | 	skb_dst_drop(skb); | ||||||
|  |  | ||||||
|  | @ -37,7 +37,6 @@ static void rxrpc_assess_MTU_size(struct rxrpc_peer *peer) | ||||||
| { | { | ||||||
| 	struct rtable *rt; | 	struct rtable *rt; | ||||||
| 	struct flowi fl; | 	struct flowi fl; | ||||||
| 	int ret; |  | ||||||
| 
 | 
 | ||||||
| 	peer->if_mtu = 1500; | 	peer->if_mtu = 1500; | ||||||
| 
 | 
 | ||||||
|  | @ -58,9 +57,9 @@ static void rxrpc_assess_MTU_size(struct rxrpc_peer *peer) | ||||||
| 		BUG(); | 		BUG(); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	ret = ip_route_output_key(&init_net, &rt, &fl); | 	rt = ip_route_output_key(&init_net, &fl); | ||||||
| 	if (ret < 0) { | 	if (IS_ERR(rt)) { | ||||||
| 		_leave(" [route err %d]", ret); | 		_leave(" [route err %ld]", PTR_ERR(rt)); | ||||||
| 		return; | 		return; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -491,9 +491,9 @@ static struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc, | ||||||
| 	SCTP_DEBUG_PRINTK("%s: DST:%pI4, SRC:%pI4 - ", | 	SCTP_DEBUG_PRINTK("%s: DST:%pI4, SRC:%pI4 - ", | ||||||
| 			  __func__, &fl.fl4_dst, &fl.fl4_src); | 			  __func__, &fl.fl4_dst, &fl.fl4_src); | ||||||
| 
 | 
 | ||||||
| 	if (!ip_route_output_key(&init_net, &rt, &fl)) { | 	rt = ip_route_output_key(&init_net, &fl); | ||||||
|  | 	if (!IS_ERR(rt)) | ||||||
| 		dst = &rt->dst; | 		dst = &rt->dst; | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
| 	/* If there is no association or if a source address is passed, no
 | 	/* If there is no association or if a source address is passed, no
 | ||||||
| 	 * more validation is required. | 	 * more validation is required. | ||||||
|  | @ -535,7 +535,8 @@ static struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc, | ||||||
| 		    (AF_INET == laddr->a.sa.sa_family)) { | 		    (AF_INET == laddr->a.sa.sa_family)) { | ||||||
| 			fl.fl4_src = laddr->a.v4.sin_addr.s_addr; | 			fl.fl4_src = laddr->a.v4.sin_addr.s_addr; | ||||||
| 			fl.fl_ip_sport = laddr->a.v4.sin_port; | 			fl.fl_ip_sport = laddr->a.v4.sin_port; | ||||||
| 			if (!ip_route_output_key(&init_net, &rt, &fl)) { | 			rt = ip_route_output_key(&init_net, &fl); | ||||||
|  | 			if (!IS_ERR(rt)) { | ||||||
| 				dst = &rt->dst; | 				dst = &rt->dst; | ||||||
| 				goto out_unlock; | 				goto out_unlock; | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 David S. Miller
				David S. Miller