]> git.baikalelectronics.ru Git - kernel.git/commitdiff
net: lwtunnel: handle MTU calculation in forwading
authorVadim Fedorenko <vfedorenko@novek.ru>
Fri, 25 Jun 2021 16:21:39 +0000 (19:21 +0300)
committerDavid S. Miller <davem@davemloft.net>
Mon, 28 Jun 2021 19:42:14 +0000 (12:42 -0700)
Commit 151d694f5891 ("net: lwtunnel: Handle fragmentation") moved
fragmentation logic away from lwtunnel by carry encap headroom and
use it in output MTU calculation. But the forwarding part was not
covered and created difference in MTU for output and forwarding and
further to silent drops on ipv4 forwarding path. Fix it by taking
into account lwtunnel encap headroom.

The same commit also introduced difference in how to treat RTAX_MTU
in IPv4 and IPv6 where latter explicitly removes lwtunnel encap
headroom from route MTU. Make IPv4 version do the same.

Fixes: 151d694f5891 ("net: lwtunnel: Handle fragmentation")
Suggested-by: David Ahern <dsahern@gmail.com>
Signed-off-by: Vadim Fedorenko <vfedorenko@novek.ru>
Reviewed-by: David Ahern <dsahern@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/ip.h
include/net/ip6_route.h
net/ipv4/route.c

index e20874059f826eb0f9e899aed556bfbc9c9d71e8..d9683bef86840eb8e614d4bffcc7115a20446361 100644 (file)
@@ -31,6 +31,7 @@
 #include <net/flow.h>
 #include <net/flow_dissector.h>
 #include <net/netns/hash.h>
+#include <net/lwtunnel.h>
 
 #define IPV4_MAX_PMTU          65535U          /* RFC 2675, Section 5.1 */
 #define IPV4_MIN_MTU           68                      /* RFC 791 */
@@ -445,22 +446,25 @@ static inline unsigned int ip_dst_mtu_maybe_forward(const struct dst_entry *dst,
 
        /* 'forwarding = true' case should always honour route mtu */
        mtu = dst_metric_raw(dst, RTAX_MTU);
-       if (mtu)
-               return mtu;
+       if (!mtu)
+               mtu = min(READ_ONCE(dst->dev->mtu), IP_MAX_MTU);
 
-       return min(READ_ONCE(dst->dev->mtu), IP_MAX_MTU);
+       return mtu - lwtunnel_headroom(dst->lwtstate, mtu);
 }
 
 static inline unsigned int ip_skb_dst_mtu(struct sock *sk,
                                          const struct sk_buff *skb)
 {
+       unsigned int mtu;
+
        if (!sk || !sk_fullsock(sk) || ip_sk_use_pmtu(sk)) {
                bool forwarding = IPCB(skb)->flags & IPSKB_FORWARDED;
 
                return ip_dst_mtu_maybe_forward(skb_dst(skb), forwarding);
        }
 
-       return min(READ_ONCE(skb_dst(skb)->dev->mtu), IP_MAX_MTU);
+       mtu = min(READ_ONCE(skb_dst(skb)->dev->mtu), IP_MAX_MTU);
+       return mtu - lwtunnel_headroom(skb_dst(skb)->lwtstate, mtu);
 }
 
 struct dst_metrics *ip_fib_metrics_init(struct net *net, struct nlattr *fc_mx,
index f51a118bfce8b0c8f120338381081a39010a6dc4..f14149df5a654d70c14e6587da826ff7d5e0d491 100644 (file)
@@ -265,11 +265,18 @@ int ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb,
 
 static inline int ip6_skb_dst_mtu(struct sk_buff *skb)
 {
+       int mtu;
+
        struct ipv6_pinfo *np = skb->sk && !dev_recursion_level() ?
                                inet6_sk(skb->sk) : NULL;
 
-       return (np && np->pmtudisc >= IPV6_PMTUDISC_PROBE) ?
-              skb_dst(skb)->dev->mtu : dst_mtu(skb_dst(skb));
+       if (np && np->pmtudisc >= IPV6_PMTUDISC_PROBE) {
+               mtu = READ_ONCE(skb_dst(skb)->dev->mtu);
+               mtu -= lwtunnel_headroom(skb_dst(skb)->lwtstate, mtu);
+       } else
+               mtu = dst_mtu(skb_dst(skb));
+
+       return mtu;
 }
 
 static inline bool ip6_sk_accept_pmtu(const struct sock *sk)
@@ -317,7 +324,7 @@ static inline unsigned int ip6_dst_mtu_forward(const struct dst_entry *dst)
        if (dst_metric_locked(dst, RTAX_MTU)) {
                mtu = dst_metric_raw(dst, RTAX_MTU);
                if (mtu)
-                       return mtu;
+                       goto out;
        }
 
        mtu = IPV6_MIN_MTU;
@@ -327,7 +334,8 @@ static inline unsigned int ip6_dst_mtu_forward(const struct dst_entry *dst)
                mtu = idev->cnf.mtu6;
        rcu_read_unlock();
 
-       return mtu;
+out:
+       return mtu - lwtunnel_headroom(dst->lwtstate, mtu);
 }
 
 u32 ip6_mtu_from_fib6(const struct fib6_result *res,
index 6a36ac98476fa2f379b5edb1f0318eed72586c55..78d1e5afc45206e2de8e2e228265e5ab55d7cbb6 100644 (file)
@@ -1306,7 +1306,7 @@ INDIRECT_CALLABLE_SCOPE unsigned int ipv4_mtu(const struct dst_entry *dst)
                mtu = dst_metric_raw(dst, RTAX_MTU);
 
        if (mtu)
-               return mtu;
+               goto out;
 
        mtu = READ_ONCE(dst->dev->mtu);
 
@@ -1315,6 +1315,7 @@ INDIRECT_CALLABLE_SCOPE unsigned int ipv4_mtu(const struct dst_entry *dst)
                        mtu = 576;
        }
 
+out:
        mtu = min_t(unsigned int, mtu, IP_MAX_MTU);
 
        return mtu - lwtunnel_headroom(dst->lwtstate, mtu);