[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20200527212512.17901-7-edwin.peer@broadcom.com>
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