Skip to content

Commit

Permalink
datapath: Set a large MTU on tunnel devices.
Browse files Browse the repository at this point in the history
Upstream commit:
    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: David Wragg <david@weave.works>
    Signed-off-by: David S. Miller <davem@davemloft.net>

Upstream: 7e059158d57b ("vxlan, gre, geneve: Set a large MTU on ovs-created
tunnel devices")
Signed-off-by: Joe Stringer <joe@ovn.org>
Acked-by: Jesse Gross <jesse@kernel.org>
  • Loading branch information
dpw authored and joestringer committed Feb 19, 2016
1 parent ef1d4fc commit 06f1a61
Show file tree
Hide file tree
Showing 7 changed files with 55 additions and 10 deletions.
1 change: 1 addition & 0 deletions acinclude.m4
Expand Up @@ -354,6 +354,7 @@ AC_DEFUN([OVS_CHECK_LINUX_COMPAT], [
OVS_GREP_IFELSE([$KSRC/include/net/ip.h], [IPSKB_FRAG_PMTU],
[OVS_DEFINE([HAVE_CORRECT_MRU_HANDLING])])
OVS_GREP_IFELSE([$KSRC/include/net/ip_tunnels.h], [__ip_tunnel_change_mtu])
OVS_GREP_IFELSE([$KSRC/include/net/inet_frag.h], [hashfn.*const],
[OVS_DEFINE([HAVE_INET_FRAGS_CONST])])
OVS_GREP_IFELSE([$KSRC/include/net/inet_frag.h], [last_in],
Expand Down
18 changes: 14 additions & 4 deletions datapath/linux/compat/geneve.c
Expand Up @@ -1039,11 +1039,21 @@ struct net_device *rpl_geneve_dev_create_fb(struct net *net, const char *name,
return dev;

err = geneve_configure(net, dev, 0, 0, 0, 0, htons(dst_port), true);
if (err) {
free_netdev(dev);
return ERR_PTR(err);
}
if (err)
goto 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;

err:
free_netdev(dev);
return ERR_PTR(err);
}
EXPORT_SYMBOL_GPL(rpl_geneve_dev_create_fb);

Expand Down
6 changes: 6 additions & 0 deletions datapath/linux/compat/include/net/ip_tunnels.h
Expand Up @@ -327,4 +327,10 @@ int rpl_ip_tunnel_get_iflink(const struct net_device *dev);
#define ip_tunnel_get_link_net rpl_ip_tunnel_get_link_net
struct net *rpl_ip_tunnel_get_link_net(const struct net_device *dev);
#endif /* HAVE_METADATA_DST */

#ifndef HAVE___IP_TUNNEL_CHANGE_MTU
#define __ip_tunnel_change_mtu rpl___ip_tunnel_change_mtu
int rpl___ip_tunnel_change_mtu(struct net_device *dev, int new_mtu, bool strict);
#endif

#endif /* __NET_IP_TUNNELS_H */
8 changes: 8 additions & 0 deletions datapath/linux/compat/ip_gre.c
Expand Up @@ -613,6 +613,14 @@ struct net_device *rpl_gretap_fb_dev_create(struct net *net, const char *name,
#endif
if (err < 0)
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;
out:
free_netdev(dev);
Expand Down
19 changes: 16 additions & 3 deletions datapath/linux/compat/ip_tunnel.c
Expand Up @@ -137,18 +137,31 @@ static int ip_tunnel_bind_dev(struct net_device *dev)
return mtu;
}

int rpl_ip_tunnel_change_mtu(struct net_device *dev, int new_mtu)
int rpl___ip_tunnel_change_mtu(struct net_device *dev, int new_mtu, bool strict)
{
struct ip_tunnel *tunnel = netdev_priv(dev);
int t_hlen = tunnel->hlen + sizeof(struct iphdr);
int max_mtu = 0xFFF8 - dev->hard_header_len - t_hlen;

if (new_mtu < 68 ||
new_mtu > 0xFFF8 - dev->hard_header_len - t_hlen)
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;
}

int rpl_ip_tunnel_change_mtu(struct net_device *dev, int new_mtu)
{
return rpl___ip_tunnel_change_mtu(dev, new_mtu, true);
}

static void ip_tunnel_dev_free(struct net_device *dev)
{
#ifdef HAVE_DEV_TSTATS
Expand Down
11 changes: 8 additions & 3 deletions datapath/linux/compat/vxlan.c
Expand Up @@ -1905,6 +1905,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;

Expand All @@ -1924,9 +1925,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) {
Expand Down Expand Up @@ -1957,6 +1956,12 @@ static int vxlan_dev_configure(struct net *src_net, struct net_device *dev,
dev->needed_headroom = ETH_HLEN + VXLAN_HEADROOM;
}

if (conf->mtu) {
err = __vxlan_change_mtu(dev, lowerdev, dst, conf->mtu, false);
if (err)
return err;
}

memcpy(&vxlan->cfg, conf, sizeof(*conf));
if (!vxlan->cfg.dst_port)
vxlan->cfg.dst_port = default_port;
Expand Down
2 changes: 2 additions & 0 deletions datapath/vport-vxlan.c
Expand Up @@ -91,6 +91,8 @@ static struct vport *vxlan_tnl_create(const struct vport_parms *parms)
struct vxlan_config conf = {
.no_share = true,
.flags = VXLAN_F_COLLECT_METADATA,
/* Don't restrict the packets that can be sent by MTU */
.mtu = IP_MAX_MTU,
};

if (!options) {
Expand Down

0 comments on commit 06f1a61

Please sign in to comment.