|
@@ -30,6 +30,9 @@
|
|
|
#include <net/xfrm.h>
|
|
|
#include <net/net_namespace.h>
|
|
|
#include <net/netns/generic.h>
|
|
|
+#include <linux/ip.h>
|
|
|
+#include <linux/ipv6.h>
|
|
|
+#include <linux/udp.h>
|
|
|
|
|
|
#include "l2tp_core.h"
|
|
|
|
|
@@ -204,6 +207,53 @@ static void l2tp_eth_show(struct seq_file *m, void *arg)
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
+static void l2tp_eth_adjust_mtu(struct l2tp_tunnel *tunnel,
|
|
|
+ struct l2tp_session *session,
|
|
|
+ struct net_device *dev)
|
|
|
+{
|
|
|
+ unsigned int overhead = 0;
|
|
|
+ struct dst_entry *dst;
|
|
|
+ u32 l3_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 (session->mtu != 0) {
|
|
|
+ dev->mtu = session->mtu;
|
|
|
+ dev->needed_headroom += session->hdr_len;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ l3_overhead = kernel_sock_ip_overhead(tunnel->sock);
|
|
|
+ if (l3_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.
|
|
|
+ */
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ /* 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 PMTU discovery was enabled, use discovered MTU on L2TP device */
|
|
|
+ dst = sk_dst_get(tunnel->sock);
|
|
|
+ if (dst) {
|
|
|
+ /* dst_mtu will use PMTU if found, else fallback to intf MTU */
|
|
|
+ u32 pmtu = dst_mtu(dst);
|
|
|
+
|
|
|
+ if (pmtu != 0)
|
|
|
+ dev->mtu = pmtu;
|
|
|
+ dst_release(dst);
|
|
|
+ }
|
|
|
+ session->mtu = dev->mtu - overhead;
|
|
|
+ dev->mtu = session->mtu;
|
|
|
+ dev->needed_headroom += session->hdr_len;
|
|
|
+}
|
|
|
+
|
|
|
static int l2tp_eth_create(struct net *net, u32 tunnel_id, u32 session_id, u32 peer_session_id, struct l2tp_session_cfg *cfg)
|
|
|
{
|
|
|
struct net_device *dev;
|
|
@@ -247,12 +297,9 @@ static int l2tp_eth_create(struct net *net, u32 tunnel_id, u32 session_id, u32 p
|
|
|
}
|
|
|
|
|
|
dev_net_set(dev, net);
|
|
|
- if (session->mtu == 0)
|
|
|
- session->mtu = dev->mtu - session->hdr_len;
|
|
|
- dev->mtu = session->mtu;
|
|
|
- dev->needed_headroom += session->hdr_len;
|
|
|
dev->min_mtu = 0;
|
|
|
dev->max_mtu = ETH_MAX_MTU;
|
|
|
+ l2tp_eth_adjust_mtu(tunnel, session, dev);
|
|
|
|
|
|
priv = netdev_priv(dev);
|
|
|
priv->dev = dev;
|