From: Maayan Kashani <mkashani@nvidia.com>
To: <dev@dpdk.org>
Cc: <aman.deep.singh@intel.com>, <haijie1@huawei.com>,
<rasland@nvidia.com>, Maayan Kashani <mkashani@nvidia.com>,
<stable@dpdk.org>
Subject: [PATCH] app/testpmd: fix VXLAN-GPE and GENEVE custom port parsing
Date: Thu, 5 Nov 2026 09:31:10 +0200 [thread overview]
Message-ID: <20261105073110.3643780-1-mkashani@nvidia.com> (raw)
The csum forwarding engine parses packets with rte_net_get_ptype(),
which recognizes VXLAN-GPE and GENEVE tunnels only on their default UDP
ports. Since the switch to that API, --vxlan-gpe-port and
--geneve-parsed-port no longer take effect: a packet whose outer UDP
destination port matches a configured non-default port is not detected
as a tunnel, so tunnel Tx flags, outer checksum handling and tunnel TSO
are skipped.
When parse-tunnel is enabled and the outer UDP port matches one of those
options, temporarily present the corresponding default port to
rte_net_get_ptype() and restore the original port afterwards. This reuses
the existing parser without a new library API. Plain VXLAN is unchanged:
the csum engine has always recognized it only on RTE_VXLAN_DEFAULT_PORT,
and rx_vxlan_port configures the device filter rather than this parser.
Only process inner checksums when the parser identified an inner IP
header and all declared inner headers fit in the packet. This preserves
tunnel forwarding for valid non-IP payloads and avoids accessing
truncated inner headers on both default and configured tunnel ports.
Fixes: 76730c7b9b5a ("app/testpmd: use packet type parsing API")
Cc: stable@dpdk.org
Signed-off-by: Maayan Kashani <mkashani@nvidia.com>
---
app/test-pmd/csumonly.c | 84 ++++++++++++++++++++++++++++++++++++++---
1 file changed, 79 insertions(+), 5 deletions(-)
diff --git a/app/test-pmd/csumonly.c b/app/test-pmd/csumonly.c
index c841651756d..e0ce91fed80 100644
--- a/app/test-pmd/csumonly.c
+++ b/app/test-pmd/csumonly.c
@@ -573,6 +573,69 @@ parse_l4_proto(const struct rte_mbuf *m, uint32_t off, uint32_t ptype, bool in_t
return 0;
}
+/*
+ * rte_net_get_ptype() recognizes VXLAN-GPE and GENEVE only on their default
+ * UDP ports. --vxlan-gpe-port and --geneve-parsed-port select other ports.
+ * When one of those matches, present the default port to the existing parser
+ * and restore the original port afterwards. Plain VXLAN stays on
+ * RTE_VXLAN_DEFAULT_PORT: the csum engine has no equivalent option for it.
+ * If a configured port overlaps a tunnel port already recognized by
+ * rte_net_get_ptype(), keep the library's classification.
+ */
+static uint32_t
+parse_tunnel_udp_custom_port(struct rte_mbuf *m, uint32_t ptype,
+ struct rte_net_hdr_lens *hdr_lens)
+{
+ uint32_t off = hdr_lens->l2_len + hdr_lens->l3_len;
+ struct rte_net_hdr_lens parsed = {0};
+ struct rte_udp_hdr *uh;
+ uint16_t default_port;
+ rte_be16_t saved_port;
+ uint16_t dst_port;
+ uint32_t new_ptype;
+
+ if (rte_pktmbuf_data_len(m) < off + sizeof(*uh))
+ return ptype;
+
+ uh = rte_pktmbuf_mtod_offset(m, struct rte_udp_hdr *, off);
+ dst_port = rte_be_to_cpu_16(uh->dst_port);
+ if (vxlan_gpe_udp_port != RTE_VXLAN_GPE_DEFAULT_PORT &&
+ dst_port == vxlan_gpe_udp_port)
+ default_port = RTE_VXLAN_GPE_DEFAULT_PORT;
+ else if (geneve_udp_port != RTE_GENEVE_DEFAULT_PORT &&
+ dst_port == geneve_udp_port)
+ default_port = RTE_GENEVE_DEFAULT_PORT;
+ else
+ return ptype;
+
+ saved_port = uh->dst_port;
+ uh->dst_port = rte_cpu_to_be_16(default_port);
+ new_ptype = rte_net_get_ptype(m, &parsed, RTE_PTYPE_ALL_MASK);
+ uh->dst_port = saved_port;
+
+ if (RTE_ETH_IS_TUNNEL_PKT(new_ptype) == 0)
+ return ptype;
+
+ *hdr_lens = parsed;
+ return new_ptype;
+}
+
+static bool
+can_process_inner_headers(const struct rte_mbuf *m, uint32_t ptype,
+ const struct rte_net_hdr_lens *hdr_lens)
+{
+ uint32_t headers_len;
+
+ if ((ptype & RTE_PTYPE_INNER_L3_MASK) == 0)
+ return false;
+
+ headers_len = hdr_lens->l2_len + hdr_lens->l3_len +
+ hdr_lens->inner_l2_len + hdr_lens->inner_l3_len +
+ hdr_lens->inner_l4_len;
+
+ return rte_pktmbuf_pkt_len(m) >= headers_len;
+}
+
/*
* Receive a burst of packets, and for each packet:
* - parse packet, and try to recognize a supported packet type (1)
@@ -669,6 +732,7 @@ pkt_burst_checksum_forward(struct fwd_stream *fs)
for (i = 0; i < nb_rx; i++) {
struct rte_net_hdr_lens hdr_lens = {0};
+ bool process_inner = false;
if (likely(i < nb_rx - 1))
rte_prefetch0(rte_pktmbuf_mtod(pkts_burst[i + 1],
@@ -703,6 +767,9 @@ pkt_burst_checksum_forward(struct fwd_stream *fs)
}
ptype = rte_net_get_ptype(m, &hdr_lens, RTE_PTYPE_ALL_MASK);
+ if (txp->parse_tunnel && RTE_ETH_IS_TUNNEL_PKT(ptype) == 0 &&
+ (ptype & RTE_PTYPE_L4_MASK) == RTE_PTYPE_L4_UDP)
+ ptype = parse_tunnel_udp_custom_port(m, ptype, &hdr_lens);
info.l2_len = hdr_lens.l2_len;
info.l3_len = hdr_lens.l3_len;
info.l4_len = hdr_lens.l4_len;
@@ -718,10 +785,16 @@ pkt_burst_checksum_forward(struct fwd_stream *fs)
info.l2_len = hdr_lens.inner_l2_len;
info.l3_len = hdr_lens.inner_l3_len;
info.l4_len = hdr_lens.inner_l4_len;
- eth_hdr = (struct rte_ether_hdr *)((char *)l3_hdr +
- hdr_lens.l3_len + hdr_lens.l4_len + hdr_lens.tunnel_len);
- info.ethertype = get_ethertype_by_ptype(eth_hdr,
- ptype & RTE_PTYPE_INNER_L3_MASK);
+ process_inner = can_process_inner_headers(m, ptype, &hdr_lens);
+ if (process_inner) {
+ eth_hdr = (struct rte_ether_hdr *)((char *)l3_hdr +
+ hdr_lens.l3_len + hdr_lens.l4_len +
+ hdr_lens.tunnel_len);
+ info.ethertype = get_ethertype_by_ptype(eth_hdr,
+ ptype & RTE_PTYPE_INNER_L3_MASK);
+ } else {
+ info.ethertype = 0;
+ }
tx_ol_flags |= get_tunnel_ol_flags_by_ptype(ptype);
}
/* update l3_hdr and outer_l3_hdr if a tunnel was parsed */
@@ -730,7 +803,8 @@ pkt_burst_checksum_forward(struct fwd_stream *fs)
outer_l3_hdr = l3_hdr;
l3_hdr = (char *)l3_hdr + info.outer_l3_len + info.l2_len;
- info.l4_proto = parse_l4_proto(m, l3_off, ptype, true);
+ if (process_inner)
+ info.l4_proto = parse_l4_proto(m, l3_off, ptype, true);
}
/* step 2: depending on user command line configuration,
* recompute checksum either in software or flag the
--
2.25.1
next reply other threads:[~2026-11-05 7:31 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-05 7:31 Maayan Kashani [this message]
2026-11-09 18:36 ` [PATCH] app/testpmd: fix VXLAN-GPE and GENEVE custom port parsing Stephen Hemminger
2026-11-10 7:41 ` [PATCH v2] " Maayan Kashani
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=20261105073110.3643780-1-mkashani@nvidia.com \
--to=mkashani@nvidia.com \
--cc=aman.deep.singh@intel.com \
--cc=dev@dpdk.org \
--cc=haijie1@huawei.com \
--cc=rasland@nvidia.com \
--cc=stable@dpdk.org \
/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