diff options
Diffstat (limited to 'drivers/net/vxlan.c')
| -rw-r--r-- | drivers/net/vxlan.c | 89 | 
1 files changed, 62 insertions, 27 deletions
| diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 2d88c799d2ac..1c32bd104797 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -73,7 +73,7 @@ MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN");  static int vxlan_net_id;  static struct rtnl_link_ops vxlan_link_ops; -static const u8 all_zeros_mac[ETH_ALEN]; +static const u8 all_zeros_mac[ETH_ALEN + 2];  static int vxlan_sock_add(struct vxlan_dev *vxlan); @@ -931,8 +931,10 @@ static int vxlan_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb,  						     cb->nlh->nlmsg_seq,  						     RTM_NEWNEIGH,  						     NLM_F_MULTI, rd); -				if (err < 0) +				if (err < 0) { +					cb->args[1] = err;  					goto out; +				}  skip:  				++idx;  			} @@ -1306,8 +1308,10 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)  		gbp = (struct vxlanhdr_gbp *)vxh;  		md->gbp = ntohs(gbp->policy_id); -		if (tun_dst) +		if (tun_dst) {  			tun_dst->u.tun_info.key.tun_flags |= TUNNEL_VXLAN_OPT; +			tun_dst->u.tun_info.options_len = sizeof(*md); +		}  		if (gbp->dont_learn)  			md->gbp |= VXLAN_GBP_DONT_LEARN; @@ -1985,11 +1989,6 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,  				     vxlan->cfg.port_max, true);  	if (info) { -		if (info->key.tun_flags & TUNNEL_CSUM) -			flags |= VXLAN_F_UDP_CSUM; -		else -			flags &= ~VXLAN_F_UDP_CSUM; -  		ttl = info->key.ttl;  		tos = info->key.tos; @@ -2004,8 +2003,15 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,  			goto drop;  		sk = vxlan->vn4_sock->sock->sk; -		if (info && (info->key.tun_flags & TUNNEL_DONT_FRAGMENT)) -			df = htons(IP_DF); +		if (info) { +			if (info->key.tun_flags & TUNNEL_DONT_FRAGMENT) +				df = htons(IP_DF); + +			if (info->key.tun_flags & TUNNEL_CSUM) +				flags |= VXLAN_F_UDP_CSUM; +			else +				flags &= ~VXLAN_F_UDP_CSUM; +		}  		memset(&fl4, 0, sizeof(fl4));  		fl4.flowi4_oif = rdst ? rdst->remote_ifindex : 0; @@ -2101,6 +2107,13 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,  			return;  		} +		if (info) { +			if (info->key.tun_flags & TUNNEL_CSUM) +				flags &= ~VXLAN_F_UDP_ZERO_CSUM6_TX; +			else +				flags |= VXLAN_F_UDP_ZERO_CSUM6_TX; +		} +  		ttl = ttl ? : ip6_dst_hoplimit(ndst);  		err = vxlan6_xmit_skb(ndst, sk, skb, dev, &saddr, &dst->sin6.sin6_addr,  				      0, ttl, src_port, dst_port, htonl(vni << 8), md, @@ -2162,9 +2175,11 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev)  #endif  	} -	if (vxlan->flags & VXLAN_F_COLLECT_METADATA && -	    info && info->mode & IP_TUNNEL_INFO_TX) { -		vxlan_xmit_one(skb, dev, NULL, false); +	if (vxlan->flags & VXLAN_F_COLLECT_METADATA) { +		if (info && info->mode & IP_TUNNEL_INFO_TX) +			vxlan_xmit_one(skb, dev, NULL, false); +		else +			kfree_skb(skb);  		return NETDEV_TX_OK;  	} @@ -2358,29 +2373,43 @@ static void vxlan_set_multicast_list(struct net_device *dev)  {  } -static int vxlan_change_mtu(struct net_device *dev, int new_mtu) +static int __vxlan_change_mtu(struct net_device *dev, +			      struct net_device *lowerdev, +			      struct vxlan_rdst *dst, int new_mtu, bool strict)  { -	struct vxlan_dev *vxlan = netdev_priv(dev); -	struct vxlan_rdst *dst = &vxlan->default_dst; -	struct net_device *lowerdev; -	int max_mtu; +	int max_mtu = IP_MAX_MTU; -	lowerdev = __dev_get_by_index(vxlan->net, dst->remote_ifindex); -	if (lowerdev == NULL) -		return eth_change_mtu(dev, new_mtu); +	if (lowerdev) +		max_mtu = lowerdev->mtu;  	if (dst->remote_ip.sa.sa_family == AF_INET6) -		max_mtu = lowerdev->mtu - VXLAN6_HEADROOM; +		max_mtu -= VXLAN6_HEADROOM;  	else -		max_mtu = lowerdev->mtu - VXLAN_HEADROOM; +		max_mtu -= VXLAN_HEADROOM; -	if (new_mtu < 68 || new_mtu > max_mtu) +	if (new_mtu < 68)  		return -EINVAL; +	if (new_mtu > max_mtu) { +		if (strict) +			return -EINVAL; + +		new_mtu = max_mtu; +	} +  	dev->mtu = new_mtu;  	return 0;  } +static int vxlan_change_mtu(struct net_device *dev, int new_mtu) +{ +	struct vxlan_dev *vxlan = netdev_priv(dev); +	struct vxlan_rdst *dst = &vxlan->default_dst; +	struct net_device *lowerdev = __dev_get_by_index(vxlan->net, +							 dst->remote_ifindex); +	return __vxlan_change_mtu(dev, lowerdev, dst, new_mtu, true); +} +  static int egress_ipv4_tun_info(struct net_device *dev, struct sk_buff *skb,  				struct ip_tunnel_info *info,  				__be16 sport, __be16 dport) @@ -2514,6 +2543,7 @@ static void vxlan_setup(struct net_device *dev)  	dev->hw_features |= NETIF_F_GSO_SOFTWARE;  	dev->hw_features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_STAG_TX;  	netif_keep_dst(dev); +	dev->priv_flags &= ~IFF_TX_SKB_SHARING;  	dev->priv_flags |= IFF_LIVE_ADDR_CHANGE | IFF_NO_QUEUE;  	INIT_LIST_HEAD(&vxlan->next); @@ -2756,6 +2786,7 @@ static int vxlan_dev_configure(struct net *src_net, struct net_device *dev,  	int err;  	bool use_ipv6 = false;  	__be16 default_port = vxlan->cfg.dst_port; +	struct net_device *lowerdev = NULL;  	vxlan->net = src_net; @@ -2776,9 +2807,7 @@ static int vxlan_dev_configure(struct net *src_net, struct net_device *dev,  	}  	if (conf->remote_ifindex) { -		struct net_device *lowerdev -			 = __dev_get_by_index(src_net, conf->remote_ifindex); - +		lowerdev = __dev_get_by_index(src_net, conf->remote_ifindex);  		dst->remote_ifindex = conf->remote_ifindex;  		if (!lowerdev) { @@ -2802,6 +2831,12 @@ static int vxlan_dev_configure(struct net *src_net, struct net_device *dev,  		needed_headroom = lowerdev->hard_header_len;  	} +	if (conf->mtu) { +		err = __vxlan_change_mtu(dev, lowerdev, dst, conf->mtu, false); +		if (err) +			return err; +	} +  	if (use_ipv6 || conf->flags & VXLAN_F_COLLECT_METADATA)  		needed_headroom += VXLAN6_HEADROOM;  	else | 
