lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Wed, 27 May 2020 14:25:07 -0700
From:   Edwin Peer <edwin.peer@...adcom.com>
To:     netdev@...r.kernel.org
Cc:     Edwin Peer <edwin.peer@...adcom.com>, edumazet@...gle.com,
        linville@...driver.com, shemminger@...tta.com,
        mirq-linux@...e.qmqm.pl, jesse.brandeburg@...el.com,
        jchapman@...alix.com, david@...ve.works, j.vosburgh@...il.com,
        vfalico@...il.com, andy@...yhouse.net, sridhar.samudrala@...el.com,
        jiri@...lanox.com, geoff@...radead.org, mokuno@...sony.co.jp,
        msink@...monline.ru, mporter@...nel.crashing.org,
        inaky.perez-gonzalez@...el.com, jwi@...ux.ibm.com,
        kgraul@...ux.ibm.com, ubraun@...ux.ibm.com,
        grant.likely@...retlab.ca, hadi@...erus.ca, dsahern@...nel.org,
        shrijeet@...il.com, jon.mason@...el.com, dave.jiang@...el.com,
        saeedm@...lanox.com, hadarh@...lanox.com, ogerlitz@...lanox.com,
        allenbh@...il.com, michael.chan@...adcom.com
Subject: [RFC PATCH net-next 06/11] net: l2tp_eth: constrain upper VLAN MTU using IFF_NO_VLAN_ROOM

Constrain the MTU of upper VLAN devices if the MTU of the L2TP Ethernet
device is configured to its default optimal size, which does not leave
space for a nested VLAN tag without causing fragmentation.

Refactor l2tp_eth_adjust_mtu() so that it can also be used to determine
the optimal size when the L2TP device's MTU is changed. This function
needed to move before the net_device_ops definition in order to avoid a
forward declaration, but instead the definition of net_device_ops is
moved so that the refactoring changes are better represented in the
diff.

Signed-off-by: Edwin Peer <edwin.peer@...adcom.com>
---
 net/l2tp/l2tp_eth.c | 114 ++++++++++++++++++++++++--------------------
 1 file changed, 63 insertions(+), 51 deletions(-)

diff --git a/net/l2tp/l2tp_eth.c b/net/l2tp/l2tp_eth.c
index fd5ac2788e45..6fbb900bc3d1 100644
--- a/net/l2tp/l2tp_eth.c
+++ b/net/l2tp/l2tp_eth.c
@@ -103,28 +103,6 @@ static void l2tp_eth_get_stats64(struct net_device *dev,
 
 }
 
-static const struct net_device_ops l2tp_eth_netdev_ops = {
-	.ndo_init		= l2tp_eth_dev_init,
-	.ndo_uninit		= l2tp_eth_dev_uninit,
-	.ndo_start_xmit		= l2tp_eth_dev_xmit,
-	.ndo_get_stats64	= l2tp_eth_get_stats64,
-	.ndo_set_mac_address	= eth_mac_addr,
-};
-
-static struct device_type l2tpeth_type = {
-	.name = "l2tpeth",
-};
-
-static void l2tp_eth_dev_setup(struct net_device *dev)
-{
-	SET_NETDEV_DEVTYPE(dev, &l2tpeth_type);
-	ether_setup(dev);
-	dev->priv_flags		&= ~IFF_TX_SKB_SHARING;
-	dev->features		|= NETIF_F_LLTX;
-	dev->netdev_ops		= &l2tp_eth_netdev_ops;
-	dev->needs_free_netdev	= true;
-}
-
 static void l2tp_eth_dev_recv(struct l2tp_session *session, struct sk_buff *skb, int data_len)
 {
 	struct l2tp_eth_sess *spriv = l2tp_session_priv(session);
@@ -215,44 +193,73 @@ static void l2tp_eth_show(struct seq_file *m, void *arg)
 	dev_put(dev);
 }
 
-static void l2tp_eth_adjust_mtu(struct l2tp_tunnel *tunnel,
-				struct l2tp_session *session,
-				struct net_device *dev)
+static unsigned int l2tp_eth_best_mtu(struct net_device *dev)
 {
-	unsigned int overhead = 0;
-	u32 l3_overhead = 0;
-	u32 mtu;
+	struct l2tp_eth *priv = netdev_priv(dev);
+	struct l2tp_session *session = priv->session;
+	struct l2tp_tunnel *tunnel = session->tunnel;
+	unsigned int mtu, overhead = 0;
 
-	/* if the encap is UDP, account for UDP header size */
-	if (tunnel->encap == L2TP_ENCAPTYPE_UDP) {
-		overhead += sizeof(struct udphdr);
-		dev->needed_headroom += sizeof(struct udphdr);
+	if (tunnel->sock) {
+		lock_sock(tunnel->sock);
+		overhead = kernel_sock_ip_overhead(tunnel->sock);
+		release_sock(tunnel->sock);
 	}
 
-	lock_sock(tunnel->sock);
-	l3_overhead = kernel_sock_ip_overhead(tunnel->sock);
-	release_sock(tunnel->sock);
-
-	if (l3_overhead == 0) {
+	if (overhead == 0) {
 		/* L3 Overhead couldn't be identified, this could be
 		 * because tunnel->sock was NULL or the socket's
 		 * address family was not IPv4 or IPv6,
-		 * dev mtu stays at 1500.
+		 * assume existing MTU is best
 		 */
-		return;
+		return dev->mtu;
 	}
-	/* Adjust MTU, factor overhead - underlay L3, overlay L2 hdr
-	 * UDP overhead, if any, was already factored in above.
-	 */
-	overhead += session->hdr_len + ETH_HLEN + l3_overhead;
 
+	/* if the encap is UDP, account for UDP header size */
+	if (tunnel->encap == L2TP_ENCAPTYPE_UDP)
+		overhead += sizeof(struct udphdr);
+
+	/* Maximize MTU, factor in overhead - overlay L2 and Geneve header.
+	 * UDP overhead, if any, and underlay L3 already factored in above.
+	 */
+	overhead += session->hdr_len + ETH_HLEN;
 	mtu = l2tp_tunnel_dst_mtu(tunnel) - overhead;
 	if (mtu < dev->min_mtu || mtu > dev->max_mtu)
-		dev->mtu = ETH_DATA_LEN - overhead;
-	else
-		dev->mtu = mtu;
+		mtu = ETH_DATA_LEN - overhead;
 
-	dev->needed_headroom += session->hdr_len;
+	return mtu;
+}
+
+static int l2tp_eth_change_mtu(struct net_device *dev, int new_mtu)
+{
+	unsigned int best_mtu = l2tp_eth_best_mtu(dev);
+
+	dev->mtu = new_mtu;
+	__vlan_constrain_mtu(dev, best_mtu);
+	return 0;
+}
+
+static const struct net_device_ops l2tp_eth_netdev_ops = {
+	.ndo_init		= l2tp_eth_dev_init,
+	.ndo_uninit		= l2tp_eth_dev_uninit,
+	.ndo_start_xmit		= l2tp_eth_dev_xmit,
+	.ndo_get_stats64	= l2tp_eth_get_stats64,
+	.ndo_set_mac_address	= eth_mac_addr,
+	.ndo_change_mtu		= l2tp_eth_change_mtu,
+};
+
+static struct device_type l2tpeth_type = {
+	.name = "l2tpeth",
+};
+
+static void l2tp_eth_dev_setup(struct net_device *dev)
+{
+	SET_NETDEV_DEVTYPE(dev, &l2tpeth_type);
+	ether_setup(dev);
+	dev->priv_flags		&= ~IFF_TX_SKB_SHARING;
+	dev->features		|= NETIF_F_LLTX;
+	dev->netdev_ops		= &l2tp_eth_netdev_ops;
+	dev->needs_free_netdev	= true;
 }
 
 static int l2tp_eth_create(struct net *net, struct l2tp_tunnel *tunnel,
@@ -289,14 +296,19 @@ static int l2tp_eth_create(struct net *net, struct l2tp_tunnel *tunnel,
 		goto err_sess;
 	}
 
-	dev_net_set(dev, net);
-	dev->min_mtu = 0;
-	dev->max_mtu = ETH_MAX_MTU;
-	l2tp_eth_adjust_mtu(tunnel, session, dev);
+	if (tunnel->encap == L2TP_ENCAPTYPE_UDP)
+		dev->needed_headroom += sizeof(struct udphdr);
+	dev->needed_headroom += session->hdr_len;
 
 	priv = netdev_priv(dev);
 	priv->session = session;
 
+	dev_net_set(dev, net);
+	dev->min_mtu = 0;
+	dev->max_mtu = ETH_MAX_MTU;
+	dev->mtu = l2tp_eth_best_mtu(dev);
+	dev->priv_flags |= IFF_NO_VLAN_ROOM;
+
 	session->recv_skb = l2tp_eth_dev_recv;
 	session->session_close = l2tp_eth_delete;
 	if (IS_ENABLED(CONFIG_L2TP_DEBUGFS))
-- 
2.26.2

Powered by blists - more mailing lists