From: Pablo Neira Ayuso <pablo@netfilter.org>
To: Zhixing Chen <running910@gmail.com>
Cc: Harald Welte <laforge@gnumonks.org>,
Andrew Lunn <andrew+netdev@lunn.ch>,
"David S . Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@google.com>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
osmocom-net-gprs@lists.osmocom.org, netdev@vger.kernel.org
Subject: Re: [PATCH net] gtp: parse extension headers before reading inner protocol
Date: Fri, 3 Jul 2026 10:54:08 +0200 [thread overview]
Message-ID: <akd4sLY7qR0597Si@chamomile> (raw)
In-Reply-To: <20260703084244.59077-1-running910@gmail.com>
On Fri, Jul 03, 2026 at 04:42:44PM +0800, Zhixing Chen wrote:
> GTPv1-U packets may carry a chain of extension headers before the inner
> IP packet. The receive path already parses and skips these extension
> headers, but it currently reads the inner protocol before doing so.
>
> As a result, the first extension header byte is interpreted as the inner
> IP version. Packets with extension headers are then dropped before PDP
> lookup.
>
> Parse the extension header chain before calling gtp_inner_proto(), so the
> inner protocol is read from the actual inner IP header.
Missing Fixes: tag.
> Signed-off-by: Zhixing Chen <running910@gmail.com>
> ---
>
> I noticed this while running a few GTP tunnel tests with a veth pair and a
> peer network namespace.
>
> The commands below only set up a small GTPv1-U demo and verify that the
> plain tunnel works as expected:
>
> ip link add vroot type veth peer name vpeer
> ip a a 172.0.0.1/24 dev vroot
> ip link set vroot up
> ip a a 172.99.0.1/32 dev lo
> gtp-link add gtp0 ip 172.0.0.1 &
> gtp-tunnel add gtp0 v1 200 100 172.99.0.2 172.0.0.2
> ip r a 172.99.0.2/32 dev gtp0
> ip link set gtp0 mtu 1500
>
> ip netns add nspeer
> ip link set vpeer netns nspeer
> ip netns exec nspeer ip a a 172.0.0.2/24 dev vpeer
> ip netns exec nspeer ip link set vpeer up
> ip netns exec nspeer ip a a 172.99.0.2/32 dev lo
> ip netns exec nspeer ip link set lo up
>
> ip netns exec nspeer gtp-link add gtp1 ip 172.0.0.2 &
> ip netns exec nspeer gtp-tunnel add gtp1 v1 100 200 172.99.0.1 172.0.0.1
> ip netns exec nspeer ip r a 172.99.0.1/32 dev gtp1
> ip netns exec nspeer ip link set gtp1 mtu 1500
>
> With this setup, plain traffic between 172.99.0.1 and 172.99.0.2 goes
> through the GTP tunnel.
>
> After that, I used a small sender in the peer namespace to build two
> UDP/2152 packets for the root namespace GTP endpoint. Both packets use TEID
> 200 and carry an inner UDP packet from 172.99.0.2:12345 to
> 172.99.0.1:9999. The first packet is a plain GTPv1-U T-PDU. The second
> packet carries the same inner UDP packet after a GTP extension header.
>
> Before this fix, a receiver bound to 172.99.0.1:9999 only receives the
> plain packet:
>
> root@vm:/# python gtp_nsroot_recv.py
> listening on 172.99.0.1:9999
> received #1 from ('172.99.0.2', 12345): b'plain'
>
> After this fix, it receives both packets:
>
> root@vm:/# python gtp_nsroot_recv.py
> listening on 172.99.0.1:9999
> received #1 from ('172.99.0.2', 12345): b'plain'
> received #2 from ('172.99.0.2', 12345): b'extension'
>
> ---
> drivers/net/gtp.c | 8 ++++----
> 1 file changed, 4 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
> index a60ef32b35b8..4a8b00548673 100644
> --- a/drivers/net/gtp.c
> +++ b/drivers/net/gtp.c
> @@ -826,6 +826,10 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb)
> if (!pskb_may_pull(skb, hdrlen))
> return -1;
>
> + if (gtp1->flags & GTP1_F_EXTHDR &&
> + gtp_parse_exthdrs(skb, &hdrlen) < 0)
> + return -1;
> +
> if (gtp_inner_proto(skb, hdrlen, &inner_proto) < 0) {
> netdev_dbg(gtp->dev, "GTP packet does not encapsulate an IP packet\n");
> return -1;
> @@ -840,10 +844,6 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb)
> return 1;
> }
>
> - if (gtp1->flags & GTP1_F_EXTHDR &&
> - gtp_parse_exthdrs(skb, &hdrlen) < 0)
> - return -1;
> -
> return gtp_rx(pctx, skb, hdrlen, gtp->role, inner_proto);
> }
>
> --
> 2.34.1
>
next prev parent reply other threads:[~2026-07-03 8:54 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-03 8:42 [PATCH net] gtp: parse extension headers before reading inner protocol Zhixing Chen
2026-07-03 8:54 ` Pablo Neira Ayuso [this message]
2026-07-03 9:49 ` Zhixing Chen
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=akd4sLY7qR0597Si@chamomile \
--to=pablo@netfilter.org \
--cc=andrew+netdev@lunn.ch \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=kuba@kernel.org \
--cc=laforge@gnumonks.org \
--cc=netdev@vger.kernel.org \
--cc=osmocom-net-gprs@lists.osmocom.org \
--cc=pabeni@redhat.com \
--cc=running910@gmail.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.