mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Anton Danilov <littlesmilingcloud@gmail.com>
To: netdev@vger.kernel.org
Cc: "David S . Miller" <davem@davemloft.net>,
	Eric Dumazet <edumazet@google.com>,
	Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
	Simon Horman <horms@kernel.org>, David Ahern <dsahern@kernel.org>,
	Ido Schimmel <idosch@nvidia.com>,
	Andrew Lunn <andrew+netdev@lunn.ch>,
	linux-kernel@vger.kernel.org
Subject: [PATCH net-next v5 13/14] ip6_gre: add drop reasons to the transmit path
Date: Wed, 30 Sep 2026 21:39:09 +0300	[thread overview]
Message-ID: <20260930183910.3151873-14-littlesmilingcloud@gmail.com> (raw)
In-Reply-To: <20260930183910.3151873-1-littlesmilingcloud@gmail.com>

The previous patch made the ip6_gre helpers return the drop reason of
ip6_tnl_xmit() and their own, but ip6gre_tunnel_xmit() and
ip6erspan_tunnel_xmit() still free the packet with a plain kfree_skb().
Free it with the reason instead, and give the drops of the handlers
themselves one, from the same set:

 - the length reason from pskb_inet_may_pull_reason(), as in ip_gre,
 - SKB_DROP_REASON_NO_TX_TARGET for a device without a remote address
   that is not collect_md, every packet of which ip6_tnl_xmit_ctl()
   refuses, as the handlers pass it the addresses of the device;
   ip6_tnl_xmit() reports an NBMA tunnel that found no endpoint the
   same way,
 - SKB_DROP_REASON_DEV_READY for the other refusals of
   ip6_tnl_xmit_ctl(), which, as the previous patch explains, include a
   routing loop,
 - SKB_DROP_REASON_NOMEM for the offload setup, the trim of a packet
   longer than the MTU and the headroom,
 - SKB_DROP_REASON_TUNNEL_TXINFO for the collect_md metadata checks of
   ip6erspan, and for a packet without IPv6 metadata in ip6gre (see
   below),
 - SKB_DROP_REASON_UNHANDLED_PROTO for an ERSPAN version that is not
   implemented,
 - SKB_DROP_REASON_RECURSION_LIMIT and SKB_DROP_REASON_IPV6_BAD_EXTHDR
   for the checks that ip6erspan_tunnel_xmit() does itself, the same as
   in ip6gre_xmit_ipv6().

ip6gre_tunnel_xmit() looks up the metadata of a collect_md device before
it passes the packet to a helper, but leaves the drop of a packet
without usable metadata, missing or not of the IPv6 family, to the
helpers, and ip6gre_xmit_ipv6() checks the source address first. The
raddr of such a device is ::, so such a packet sent from ::, like the
device's own DAD probe, would be reported as
SKB_DROP_REASON_RECURSION_LIMIT, and other such packets as
SKB_DROP_REASON_TUNNEL_TXINFO. Drop it right after the lookup instead,
as SKB_DROP_REASON_TUNNEL_TXINFO, with the test ip6erspan_tunnel_xmit()
uses; the IPv4 handlers also test presence and family together. The
helpers dropped such a packet before ip6_tnl_xmit() in any case, and
tx_err counts it by the result of the lookup, so only the reason
changes; the test in __gre6_xmit() stays as a safeguard. A packet from
:: that carries IPv6 metadata still meets the check in
ip6gre_xmit_ipv6().

Such an ip6gre device is an NBMA tunnel: ip6gre_header() puts the
endpoint of the packet in its outer header, and __gre6_xmit() would
take it from there, but ip6gre_tunnel_xmit() refuses the packet before
that, so the device sends nothing. This patch does not change that; it
reports these drops like those of an ip6gretap or ip6erspan device
without a remote address, which has no endpoint at all.

Assisted-by: LLM
Signed-off-by: Anton Danilov <littlesmilingcloud@gmail.com>
---
 net/ipv6/ip6_gre.c | 73 ++++++++++++++++++++++++++++++++++++----------
 1 file changed, 58 insertions(+), 15 deletions(-)

diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c
index 9e94ea6b6c20..dbca78230815 100644
--- a/net/ipv6/ip6_gre.c
+++ b/net/ipv6/ip6_gre.c
@@ -889,14 +889,28 @@ static netdev_tx_t ip6gre_tunnel_xmit(struct sk_buff *skb,
 	enum skb_drop_reason reason;
 	__be16 payload_protocol;
 
-	if (!pskb_inet_may_pull(skb))
+	reason = pskb_inet_may_pull_reason(skb);
+	if (reason)
 		goto tx_err;
 
-	if (!ip6_tnl_xmit_ctl(t, &t->parms.laddr, &t->parms.raddr))
+	if (!t->parms.collect_md && ipv6_addr_any(&t->parms.raddr)) {
+		reason = SKB_DROP_REASON_NO_TX_TARGET;
 		goto tx_err;
+	}
 
-	if (t->parms.collect_md)
+	if (!ip6_tnl_xmit_ctl(t, &t->parms.laddr, &t->parms.raddr)) {
+		reason = SKB_DROP_REASON_DEV_READY;
+		goto tx_err;
+	}
+
+	if (t->parms.collect_md) {
 		tun_info = skb_tunnel_info_txcheck(skb);
+		if (IS_ERR(tun_info) ||
+		    unlikely(ip_tunnel_info_af(tun_info) != AF_INET6)) {
+			reason = SKB_DROP_REASON_TUNNEL_TXINFO;
+			goto tx_err;
+		}
+	}
 
 	payload_protocol = skb_protocol(skb, true);
 	switch (payload_protocol) {
@@ -917,10 +931,11 @@ static netdev_tx_t ip6gre_tunnel_xmit(struct sk_buff *skb,
 	return NETDEV_TX_OK;
 
 tx_err:
+	reason = reason ?: SKB_DROP_REASON_NOT_SPECIFIED;
 	if (!IS_ERR(tun_info))
 		DEV_STATS_INC(dev, tx_errors);
 	DEV_STATS_INC(dev, tx_dropped);
-	kfree_skb(skb);
+	kfree_skb_reason(skb, reason);
 	return NETDEV_TX_OK;
 }
 
@@ -940,18 +955,30 @@ static netdev_tx_t ip6erspan_tunnel_xmit(struct sk_buff *skb,
 	__u32 mtu;
 	int nhoff;
 
-	if (!pskb_inet_may_pull(skb))
+	reason = pskb_inet_may_pull_reason(skb);
+	if (reason)
 		goto tx_err;
 
-	if (!ip6_tnl_xmit_ctl(t, &t->parms.laddr, &t->parms.raddr))
+	if (!t->parms.collect_md && ipv6_addr_any(&t->parms.raddr)) {
+		reason = SKB_DROP_REASON_NO_TX_TARGET;
 		goto tx_err;
+	}
 
-	if (gre_handle_offloads(skb, false))
+	if (!ip6_tnl_xmit_ctl(t, &t->parms.laddr, &t->parms.raddr)) {
+		reason = SKB_DROP_REASON_DEV_READY;
 		goto tx_err;
+	}
+
+	if (gre_handle_offloads(skb, false)) {
+		reason = SKB_DROP_REASON_NOMEM;
+		goto tx_err;
+	}
 
 	if (skb->len > dev->mtu + dev->hard_header_len) {
-		if (pskb_trim(skb, dev->mtu + dev->hard_header_len))
+		if (pskb_trim(skb, dev->mtu + dev->hard_header_len)) {
+			reason = SKB_DROP_REASON_NOMEM;
 			goto tx_err;
+		}
 		truncate = true;
 	}
 
@@ -971,8 +998,10 @@ static netdev_tx_t ip6erspan_tunnel_xmit(struct sk_buff *skb,
 			truncate = true;
 	}
 
-	if (skb_cow_head(skb, dev->needed_headroom ?: t->hlen))
+	if (skb_cow_head(skb, dev->needed_headroom ?: t->hlen)) {
+		reason = SKB_DROP_REASON_NOMEM;
 		goto tx_err;
+	}
 
 	IPCB(skb)->flags = 0;
 
@@ -986,8 +1015,10 @@ static netdev_tx_t ip6erspan_tunnel_xmit(struct sk_buff *skb,
 
 		tun_info = skb_tunnel_info_txcheck(skb);
 		if (IS_ERR(tun_info) ||
-		    unlikely(ip_tunnel_info_af(tun_info) != AF_INET6))
+		    unlikely(ip_tunnel_info_af(tun_info) != AF_INET6)) {
+			reason = SKB_DROP_REASON_TUNNEL_TXINFO;
 			goto tx_err;
+		}
 
 		key = &tun_info->key;
 		memset(&fl6, 0, sizeof(fl6));
@@ -999,10 +1030,14 @@ static netdev_tx_t ip6erspan_tunnel_xmit(struct sk_buff *skb,
 
 		dsfield = key->tos;
 		if (!test_bit(IP_TUNNEL_ERSPAN_OPT_BIT,
-			      tun_info->key.tun_flags))
+			      tun_info->key.tun_flags)) {
+			reason = SKB_DROP_REASON_TUNNEL_TXINFO;
 			goto tx_err;
-		if (tun_info->options_len < sizeof(*md))
+		}
+		if (tun_info->options_len < sizeof(*md)) {
+			reason = SKB_DROP_REASON_TUNNEL_TXINFO;
 			goto tx_err;
+		}
 		md = ip_tunnel_info_opts(tun_info);
 
 		tun_id = tunnel_id_to_key32(key->tun_id);
@@ -1020,6 +1055,7 @@ static netdev_tx_t ip6erspan_tunnel_xmit(struct sk_buff *skb,
 					       truncate, false);
 			proto = htons(ETH_P_ERSPAN2);
 		} else {
+			reason = SKB_DROP_REASON_UNHANDLED_PROTO;
 			goto tx_err;
 		}
 	} else {
@@ -1030,11 +1066,16 @@ static netdev_tx_t ip6erspan_tunnel_xmit(struct sk_buff *skb,
 						 &dsfield, &encap_limit);
 			break;
 		case htons(ETH_P_IPV6):
-			if (ipv6_addr_equal(&t->parms.raddr, &ipv6_hdr(skb)->saddr))
+			if (ipv6_addr_equal(&t->parms.raddr,
+					    &ipv6_hdr(skb)->saddr)) {
+				reason = SKB_DROP_REASON_RECURSION_LIMIT;
 				goto tx_err;
+			}
 			if (prepare_ip6gre_xmit_ipv6(skb, dev, &fl6,
-						     &dsfield, &encap_limit))
+						     &dsfield, &encap_limit)) {
+				reason = SKB_DROP_REASON_IPV6_BAD_EXTHDR;
 				goto tx_err;
+			}
 			break;
 		default:
 			memcpy(&fl6, &t->fl.u.ip6, sizeof(fl6));
@@ -1053,6 +1094,7 @@ static netdev_tx_t ip6erspan_tunnel_xmit(struct sk_buff *skb,
 					       truncate, false);
 			proto = htons(ETH_P_ERSPAN2);
 		} else {
+			reason = SKB_DROP_REASON_UNHANDLED_PROTO;
 			goto tx_err;
 		}
 
@@ -1087,10 +1129,11 @@ static netdev_tx_t ip6erspan_tunnel_xmit(struct sk_buff *skb,
 	return NETDEV_TX_OK;
 
 tx_err:
+	reason = reason ?: SKB_DROP_REASON_NOT_SPECIFIED;
 	if (!IS_ERR(tun_info))
 		DEV_STATS_INC(dev, tx_errors);
 	DEV_STATS_INC(dev, tx_dropped);
-	kfree_skb(skb);
+	kfree_skb_reason(skb, reason);
 	return NETDEV_TX_OK;
 }
 
-- 
2.47.3


  parent reply	other threads:[~2026-09-30 18:39 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-30 18:38 [PATCH net-next v5 00/14] tunnels: add core and gre drop reasons Anton Danilov
2026-09-30 18:38 ` [PATCH net-next v5 01/14] vxlan: rename the drop reasons for use by other tunnels Anton Danilov
2026-09-30 18:38 ` [PATCH net-next v5 02/14] ip_tunnel: make __iptunnel_pull_header() return a drop reason Anton Danilov
2026-09-30 18:38 ` [PATCH net-next v5 03/14] vxlan: report the drop reason of __iptunnel_pull_header() Anton Danilov
2026-09-30 18:39 ` [PATCH net-next v5 04/14] ip_tunnel: add drop reasons to the generic RX path Anton Danilov
2026-09-30 18:39 ` [PATCH net-next v5 05/14] ip6_tunnel: add drop reasons to the receive path Anton Danilov
2026-09-30 18:39 ` [PATCH net-next v5 06/14] gre: make gre_parse_header() report a drop reason Anton Danilov
2026-09-30 18:39 ` [PATCH net-next v5 07/14] ip_gre: add drop reasons to the RX path Anton Danilov
2026-09-30 18:39 ` [PATCH net-next v5 08/14] ip6_gre: " Anton Danilov
2026-09-30 18:39 ` [PATCH net-next v5 09/14] ip_tunnel: add drop reasons to the transmit path Anton Danilov
2026-09-30 18:39 ` [PATCH net-next v5 10/14] ip_gre: " Anton Danilov
2026-09-30 18:39 ` [PATCH net-next v5 11/14] ip6_gre: make prepare_ip6gre_xmit_other() void Anton Danilov
2026-09-30 18:39 ` [PATCH net-next v5 12/14] ip6_tunnel: make ip6_tnl_xmit() return a drop reason Anton Danilov
2026-09-30 18:39 ` Anton Danilov [this message]
2026-09-30 18:39 ` [PATCH net-next v5 14/14] vxlan: report a circular route as SKB_DROP_REASON_RECURSION_LIMIT Anton Danilov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260930183910.3151873-14-littlesmilingcloud@gmail.com \
    --to=littlesmilingcloud@gmail.com \
    --cc=andrew+netdev@lunn.ch \
    --cc=davem@davemloft.net \
    --cc=dsahern@kernel.org \
    --cc=edumazet@google.com \
    --cc=horms@kernel.org \
    --cc=idosch@nvidia.com \
    --cc=kuba@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®