[ovs-dev,branch-2.7,08/25] datapath: use core MTU range checking in core net infra

Message ID 1489620689-122370-9-git-send-email-jarno@ovn.org
State Superseded
Headers show

Commit Message

Jarno Rajahalme March 15, 2017, 11:31 p.m.
From: Jarod Wilson <jarod@redhat.com>

Upstream commit:
    commit 61e84623ace35ce48975e8f90bbbac7557c43d61
    Author: Jarod Wilson <jarod@redhat.com>
    Date:   Fri Oct 7 22:04:33 2016 -0400

    net: centralize net_device min/max MTU checking

    While looking into an MTU issue with sfc, I started noticing that almost
    every NIC driver with an ndo_change_mtu function implemented almost
    exactly the same range checks, and in many cases, that was the only
    practical thing their ndo_change_mtu function was doing. Quite a few
    drivers have either 68, 64, 60 or 46 as their minimum MTU value checked,
    and then various sizes from 1500 to 65535 for their maximum MTU value. We
    can remove a whole lot of redundant code here if we simple store min_mtu
    and max_mtu in net_device, and check against those in net/core/dev.c's

    In theory, there should be zero functional change with this patch, it just
    puts the infrastructure in place. Subsequent patches will attempt to start
    using said infrastructure, with theoretically zero change in

    CC: netdev@vger.kernel.org
    Signed-off-by: Jarod Wilson <jarod@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

Upstream commit:
    commit 91572088e3fdbf4fe31cf397926d8b890fdb3237
    Author: Jarod Wilson <jarod@redhat.com>
    Date:   Thu Oct 20 13:55:20 2016 -0400

    net: use core MTU range checking in core net infra


    - set min/max_mtu, remove internal_dev_change_mtu
    - note: max_mtu wasn't checked previously, it's been set to 65535, which
      is the largest possible size supported


    Signed-off-by: Jarod Wilson <jarod@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>
    Signed-off-by: Jarno Rajahalme <jarno@ovn.org>

Upstream commit:
    commit 425df17ce3a26d98f76e2b6b0af2acf4aeb0b026
    Author: Jarno Rajahalme <jarno@ovn.org>
    Date:   Tue Feb 14 21:16:28 2017 -0800

    openvswitch: Set internal device max mtu to ETH_MAX_MTU.

    Commit 91572088e3fd ("net: use core MTU range checking in core net
    infra") changed the openvswitch internal device to use the core net
    infra for controlling the MTU range, but failed to actually set the
    max_mtu as described in the commit message, which now defaults to

    This patch fixes this by setting max_mtu to ETH_MAX_MTU after
    ether_setup() call.

    Fixes: 91572088e3fd ("net: use core MTU range checking in core net infra")
    Signed-off-by: Jarno Rajahalme <jarno@ovn.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

This backport detects the new max_mtu field in the struct netdevice
and uses the upstream code if it exists, and local backport code if
not.  The latter case is amended with bounds checks with new upstream
macros ETH_MIN_MTU and ETH_MAX_MTU and the corresponding error
messages from the upstream commit.

Signed-off-by: Jarno Rajahalme <jarno@ovn.org>
Signed-off-by: Joe Stringer <joe@ovn.org>
 acinclude.m4                                   |  2 ++
 datapath/linux/compat/include/linux/if_ether.h |  8 ++++++++
 datapath/vport-internal_dev.c                  | 22 +++++++++++++++++++---
 3 files changed, 29 insertions(+), 3 deletions(-)


diff --git a/acinclude.m4 b/acinclude.m4
index e8b64b5..052a18f 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -510,6 +510,8 @@  AC_DEFUN([OVS_CHECK_LINUX_COMPAT], [
                         [netdev_master_upper_dev_link], [upper_priv],
+  OVS_FIND_FIELD_IFELSE([$KSRC/include/linux/netdevice.h], [net_device],
+                        [max_mtu])
   OVS_GREP_IFELSE([$KSRC/include/linux/netfilter.h], [nf_hook_state])
   OVS_GREP_IFELSE([$KSRC/include/linux/netfilter.h], [nf_register_net_hook])
diff --git a/datapath/linux/compat/include/linux/if_ether.h b/datapath/linux/compat/include/linux/if_ether.h
index ac0f1ed..5eb99bc 100644
--- a/datapath/linux/compat/include/linux/if_ether.h
+++ b/datapath/linux/compat/include/linux/if_ether.h
@@ -3,6 +3,14 @@ 
 #include_next <linux/if_ether.h>
+#ifndef ETH_MIN_MTU
+#define ETH_MIN_MTU	68		/* Min IPv4 MTU per RFC791	*/
+#ifndef ETH_MAX_MTU
+#define ETH_MAX_MTU	0xFFFFU		/* 65535, same as IP_MAX_MTU	*/
 #ifndef ETH_P_802_3_MIN
 #define ETH_P_802_3_MIN        0x0600
diff --git a/datapath/vport-internal_dev.c b/datapath/vport-internal_dev.c
index f0542a5..2988e8c 100644
--- a/datapath/vport-internal_dev.c
+++ b/datapath/vport-internal_dev.c
@@ -89,14 +89,25 @@  static const struct ethtool_ops internal_dev_ethtool_ops = {
 	.get_link	= ethtool_op_get_link,
-static int internal_dev_change_mtu(struct net_device *netdev, int new_mtu)
+static int internal_dev_change_mtu(struct net_device *dev, int new_mtu)
-	if (new_mtu < 68)
+	if (new_mtu < ETH_MIN_MTU) {
+		net_err_ratelimited("%s: Invalid MTU %d requested, hw min %d\n",
+				    dev->name, new_mtu, ETH_MIN_MTU);
 		return -EINVAL;
+	}
+	if (new_mtu > ETH_MAX_MTU) {
+		net_err_ratelimited("%s: Invalid MTU %d requested, hw max %d\n",
+				    dev->name, new_mtu, ETH_MAX_MTU);
+		return -EINVAL;
+	}
-	netdev->mtu = new_mtu;
+	dev->mtu = new_mtu;
 	return 0;
 static void internal_dev_destructor(struct net_device *dev)
@@ -150,7 +161,9 @@  static const struct net_device_ops internal_dev_netdev_ops = {
 	.ndo_stop = internal_dev_stop,
 	.ndo_start_xmit = internal_dev_xmit,
 	.ndo_set_mac_address = eth_mac_addr,
 	.ndo_change_mtu = internal_dev_change_mtu,
 	.ndo_get_stats64 = internal_get_stats,
@@ -169,6 +182,9 @@  static void do_setup(struct net_device *netdev)
+	netdev->max_mtu = ETH_MAX_MTU;
 	netdev->netdev_ops = &internal_dev_netdev_ops;
 	netdev->priv_flags &= ~IFF_TX_SKB_SHARING;