Commit ce9c0dba authored by David Wragg's avatar David Wragg Committed by Greg Kroah-Hartman

vxlan, gre, geneve: Set a large MTU on ovs-created tunnel devices

[ Upstream commit 7e059158 ]

Prior to 4.3, openvswitch tunnel vports (vxlan, gre and geneve) could
transmit vxlan packets of any size, constrained only by the ability to
send out the resulting packets.  4.3 introduced netdevs corresponding
to tunnel vports.  These netdevs have an MTU, which limits the size of
a packet that can be successfully encapsulated.  The default MTU
values are low (1500 or less), which is awkwardly small in the context
of physical networks supporting jumbo frames, and leads to a
conspicuous change in behaviour for userspace.

Instead, set the MTU on openvswitch-created netdevs to be the relevant
maximum (i.e. the maximum IP packet size minus any relevant overhead),
effectively restoring the behaviour prior to 4.3.
Signed-off-by: default avatarDavid Wragg <david@weave.works>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 51d7c394
...@@ -1356,11 +1356,21 @@ struct net_device *geneve_dev_create_fb(struct net *net, const char *name, ...@@ -1356,11 +1356,21 @@ struct net_device *geneve_dev_create_fb(struct net *net, const char *name,
err = geneve_configure(net, dev, &geneve_remote_unspec, err = geneve_configure(net, dev, &geneve_remote_unspec,
0, 0, 0, htons(dst_port), true); 0, 0, 0, htons(dst_port), true);
if (err) { if (err)
free_netdev(dev); goto err;
return ERR_PTR(err);
} /* openvswitch users expect packet sizes to be unrestricted,
* so set the largest MTU we can.
*/
err = geneve_change_mtu(dev, IP_MAX_MTU);
if (err)
goto err;
return dev; return dev;
err:
free_netdev(dev);
return ERR_PTR(err);
} }
EXPORT_SYMBOL_GPL(geneve_dev_create_fb); EXPORT_SYMBOL_GPL(geneve_dev_create_fb);
......
...@@ -2776,6 +2776,7 @@ static int vxlan_dev_configure(struct net *src_net, struct net_device *dev, ...@@ -2776,6 +2776,7 @@ static int vxlan_dev_configure(struct net *src_net, struct net_device *dev,
int err; int err;
bool use_ipv6 = false; bool use_ipv6 = false;
__be16 default_port = vxlan->cfg.dst_port; __be16 default_port = vxlan->cfg.dst_port;
struct net_device *lowerdev = NULL;
vxlan->net = src_net; vxlan->net = src_net;
...@@ -2796,9 +2797,7 @@ static int vxlan_dev_configure(struct net *src_net, struct net_device *dev, ...@@ -2796,9 +2797,7 @@ static int vxlan_dev_configure(struct net *src_net, struct net_device *dev,
} }
if (conf->remote_ifindex) { if (conf->remote_ifindex) {
struct net_device *lowerdev lowerdev = __dev_get_by_index(src_net, conf->remote_ifindex);
= __dev_get_by_index(src_net, conf->remote_ifindex);
dst->remote_ifindex = conf->remote_ifindex; dst->remote_ifindex = conf->remote_ifindex;
if (!lowerdev) { if (!lowerdev) {
...@@ -2822,6 +2821,12 @@ static int vxlan_dev_configure(struct net *src_net, struct net_device *dev, ...@@ -2822,6 +2821,12 @@ static int vxlan_dev_configure(struct net *src_net, struct net_device *dev,
needed_headroom = lowerdev->hard_header_len; 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) if (use_ipv6 || conf->flags & VXLAN_F_COLLECT_METADATA)
needed_headroom += VXLAN6_HEADROOM; needed_headroom += VXLAN6_HEADROOM;
else else
......
...@@ -230,6 +230,7 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev, ...@@ -230,6 +230,7 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
int ip_tunnel_ioctl(struct net_device *dev, struct ip_tunnel_parm *p, int cmd); int ip_tunnel_ioctl(struct net_device *dev, struct ip_tunnel_parm *p, int cmd);
int ip_tunnel_encap(struct sk_buff *skb, struct ip_tunnel *t, int ip_tunnel_encap(struct sk_buff *skb, struct ip_tunnel *t,
u8 *protocol, struct flowi4 *fl4); u8 *protocol, struct flowi4 *fl4);
int __ip_tunnel_change_mtu(struct net_device *dev, int new_mtu, bool strict);
int ip_tunnel_change_mtu(struct net_device *dev, int new_mtu); int ip_tunnel_change_mtu(struct net_device *dev, int new_mtu);
struct rtnl_link_stats64 *ip_tunnel_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *ip_tunnel_get_stats64(struct net_device *dev,
......
...@@ -1247,6 +1247,14 @@ struct net_device *gretap_fb_dev_create(struct net *net, const char *name, ...@@ -1247,6 +1247,14 @@ struct net_device *gretap_fb_dev_create(struct net *net, const char *name,
err = ipgre_newlink(net, dev, tb, NULL); err = ipgre_newlink(net, dev, tb, NULL);
if (err < 0) if (err < 0)
goto out; goto out;
/* openvswitch users expect packet sizes to be unrestricted,
* so set the largest MTU we can.
*/
err = __ip_tunnel_change_mtu(dev, IP_MAX_MTU, false);
if (err)
goto out;
return dev; return dev;
out: out:
free_netdev(dev); free_netdev(dev);
......
...@@ -948,17 +948,31 @@ int ip_tunnel_ioctl(struct net_device *dev, struct ip_tunnel_parm *p, int cmd) ...@@ -948,17 +948,31 @@ int ip_tunnel_ioctl(struct net_device *dev, struct ip_tunnel_parm *p, int cmd)
} }
EXPORT_SYMBOL_GPL(ip_tunnel_ioctl); EXPORT_SYMBOL_GPL(ip_tunnel_ioctl);
int ip_tunnel_change_mtu(struct net_device *dev, int new_mtu) int __ip_tunnel_change_mtu(struct net_device *dev, int new_mtu, bool strict)
{ {
struct ip_tunnel *tunnel = netdev_priv(dev); struct ip_tunnel *tunnel = netdev_priv(dev);
int t_hlen = tunnel->hlen + sizeof(struct iphdr); int t_hlen = tunnel->hlen + sizeof(struct iphdr);
int max_mtu = 0xFFF8 - dev->hard_header_len - t_hlen;
if (new_mtu < 68 || if (new_mtu < 68)
new_mtu > 0xFFF8 - dev->hard_header_len - t_hlen)
return -EINVAL; return -EINVAL;
if (new_mtu > max_mtu) {
if (strict)
return -EINVAL;
new_mtu = max_mtu;
}
dev->mtu = new_mtu; dev->mtu = new_mtu;
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(__ip_tunnel_change_mtu);
int ip_tunnel_change_mtu(struct net_device *dev, int new_mtu)
{
return __ip_tunnel_change_mtu(dev, new_mtu, true);
}
EXPORT_SYMBOL_GPL(ip_tunnel_change_mtu); EXPORT_SYMBOL_GPL(ip_tunnel_change_mtu);
static void ip_tunnel_dev_free(struct net_device *dev) static void ip_tunnel_dev_free(struct net_device *dev)
......
...@@ -91,6 +91,8 @@ static struct vport *vxlan_tnl_create(const struct vport_parms *parms) ...@@ -91,6 +91,8 @@ static struct vport *vxlan_tnl_create(const struct vport_parms *parms)
struct vxlan_config conf = { struct vxlan_config conf = {
.no_share = true, .no_share = true,
.flags = VXLAN_F_COLLECT_METADATA | VXLAN_F_UDP_ZERO_CSUM6_RX, .flags = VXLAN_F_COLLECT_METADATA | VXLAN_F_UDP_ZERO_CSUM6_RX,
/* Don't restrict the packets that can be sent by MTU */
.mtu = IP_MAX_MTU,
}; };
if (!options) { if (!options) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment