diff options
Diffstat (limited to 'drivers/net/vxlan.c')
| -rw-r--r-- | drivers/net/vxlan.c | 34 | 
1 files changed, 20 insertions, 14 deletions
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index da4e3d6632f6..c0dda6fc0921 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -1811,7 +1811,7 @@ static struct rtable *vxlan_get_route(struct vxlan_dev *vxlan,  	fl4.flowi4_mark = skb->mark;  	fl4.flowi4_proto = IPPROTO_UDP;  	fl4.daddr = daddr; -	fl4.saddr = vxlan->cfg.saddr.sin.sin_addr.s_addr; +	fl4.saddr = *saddr;  	rt = ip_route_output_key(vxlan->net, &fl4);  	if (!IS_ERR(rt)) { @@ -1847,7 +1847,7 @@ static struct dst_entry *vxlan6_get_route(struct vxlan_dev *vxlan,  	memset(&fl6, 0, sizeof(fl6));  	fl6.flowi6_oif = oif;  	fl6.daddr = *daddr; -	fl6.saddr = vxlan->cfg.saddr.sin6.sin6_addr; +	fl6.saddr = *saddr;  	fl6.flowlabel = ip6_make_flowinfo(RT_TOS(tos), label);  	fl6.flowi6_mark = skb->mark;  	fl6.flowi6_proto = IPPROTO_UDP; @@ -1920,7 +1920,8 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,  	struct rtable *rt = NULL;  	const struct iphdr *old_iph;  	union vxlan_addr *dst; -	union vxlan_addr remote_ip; +	union vxlan_addr remote_ip, local_ip; +	union vxlan_addr *src;  	struct vxlan_metadata _md;  	struct vxlan_metadata *md = &_md;  	__be16 src_port = 0, dst_port; @@ -1938,6 +1939,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,  		dst_port = rdst->remote_port ? rdst->remote_port : vxlan->cfg.dst_port;  		vni = rdst->remote_vni;  		dst = &rdst->remote_ip; +		src = &vxlan->cfg.saddr;  		dst_cache = &rdst->dst_cache;  	} else {  		if (!info) { @@ -1948,11 +1950,15 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,  		dst_port = info->key.tp_dst ? : vxlan->cfg.dst_port;  		vni = vxlan_tun_id_to_vni(info->key.tun_id);  		remote_ip.sa.sa_family = ip_tunnel_info_af(info); -		if (remote_ip.sa.sa_family == AF_INET) +		if (remote_ip.sa.sa_family == AF_INET) {  			remote_ip.sin.sin_addr.s_addr = info->key.u.ipv4.dst; -		else +			local_ip.sin.sin_addr.s_addr = info->key.u.ipv4.src; +		} else {  			remote_ip.sin6.sin6_addr = info->key.u.ipv6.dst; +			local_ip.sin6.sin6_addr = info->key.u.ipv6.src; +		}  		dst = &remote_ip; +		src = &local_ip;  		dst_cache = &info->dst_cache;  	} @@ -1992,15 +1998,14 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,  	}  	if (dst->sa.sa_family == AF_INET) { -		__be32 saddr; -  		if (!vxlan->vn4_sock)  			goto drop;  		sk = vxlan->vn4_sock->sock->sk;  		rt = vxlan_get_route(vxlan, skb,  				     rdst ? rdst->remote_ifindex : 0, tos, -				     dst->sin.sin_addr.s_addr, &saddr, +				     dst->sin.sin_addr.s_addr, +				     &src->sin.sin_addr.s_addr,  				     dst_cache, info);  		if (IS_ERR(rt)) {  			netdev_dbg(dev, "no route to %pI4\n", @@ -2017,7 +2022,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,  		}  		/* Bypass encapsulation if the destination is local */ -		if (rt->rt_flags & RTCF_LOCAL && +		if (!info && rt->rt_flags & RTCF_LOCAL &&  		    !(rt->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))) {  			struct vxlan_dev *dst_vxlan; @@ -2043,13 +2048,12 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,  		if (err < 0)  			goto xmit_tx_error; -		udp_tunnel_xmit_skb(rt, sk, skb, saddr, +		udp_tunnel_xmit_skb(rt, sk, skb, src->sin.sin_addr.s_addr,  				    dst->sin.sin_addr.s_addr, tos, ttl, df,  				    src_port, dst_port, xnet, !udp_sum);  #if IS_ENABLED(CONFIG_IPV6)  	} else {  		struct dst_entry *ndst; -		struct in6_addr saddr;  		u32 rt6i_flags;  		if (!vxlan->vn6_sock) @@ -2058,7 +2062,8 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,  		ndst = vxlan6_get_route(vxlan, skb,  					rdst ? rdst->remote_ifindex : 0, tos, -					label, &dst->sin6.sin6_addr, &saddr, +					label, &dst->sin6.sin6_addr, +					&src->sin6.sin6_addr,  					dst_cache, info);  		if (IS_ERR(ndst)) {  			netdev_dbg(dev, "no route to %pI6\n", @@ -2077,7 +2082,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,  		/* Bypass encapsulation if the destination is local */  		rt6i_flags = ((struct rt6_info *)ndst)->rt6i_flags; -		if (rt6i_flags & RTF_LOCAL && +		if (!info && rt6i_flags & RTF_LOCAL &&  		    !(rt6i_flags & (RTCF_BROADCAST | RTCF_MULTICAST))) {  			struct vxlan_dev *dst_vxlan; @@ -2104,7 +2109,8 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,  			return;  		}  		udp_tunnel6_xmit_skb(ndst, sk, skb, dev, -				     &saddr, &dst->sin6.sin6_addr, tos, ttl, +				     &src->sin6.sin6_addr, +				     &dst->sin6.sin6_addr, tos, ttl,  				     label, src_port, dst_port, !udp_sum);  #endif  	}  |