* [PATCH net-next 10/15] i40e: prepare for XDP metadata ops support
[not found] <20260805213541.2281287-1-anthony.l.nguyen@intel.com>
@ 2026-08-05 21:35 ` Tony Nguyen
2026-08-06 21:36 ` sashiko-bot
2026-08-05 21:35 ` [PATCH net-next 11/15] i40e: add support for bpf_xdp_metadata_rx_hash() Tony Nguyen
2026-08-05 21:35 ` [PATCH net-next 12/15] i40e: add support for bpf_xdp_metadata_rx_vlan_tag() Tony Nguyen
2 siblings, 1 reply; 5+ messages in thread
From: Tony Nguyen @ 2026-08-05 21:35 UTC (permalink / raw)
To: davem, kuba, pabeni, edumazet, andrew+netdev, netdev
Cc: Kohei Enju, anthony.l.nguyen, kohei.enju, przemyslaw.kitszel,
maciej.fijalkowski, magnus.karlsson, ast, daniel, hawk,
john.fastabend, sdf, bpf, Aleksandr Loktionov, Patryk Holda
From: Kohei Enju <kohei@enjuk.jp>
Prepare 'struct i40e_xdp_buff' that contains an xdp_buff and a pointer
to i40e_rx_desc in order to pass the RX descriptor to the XDP kfuncs.
Also in ZC path, use XSK_CHECK_PRIV_TYPE() to ensure i40e_xdp_buff
doesn't exceed the offset of cb in xdp_buff_xsk.
No functional changes.
Signed-off-by: Kohei Enju <kohei@enjuk.jp>
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Tested-by: Patryk Holda <patryk.holda@intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
---
drivers/net/ethernet/intel/i40e/i40e_main.c | 2 +-
drivers/net/ethernet/intel/i40e/i40e_txrx.c | 5 ++++-
drivers/net/ethernet/intel/i40e/i40e_txrx.h | 7 ++++++-
drivers/net/ethernet/intel/i40e/i40e_xsk.c | 12 ++++++++++++
4 files changed, 23 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c
index 0cd0e5597c90..4b11ae9ed8d5 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_main.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
@@ -3622,7 +3622,7 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
}
skip:
- xdp_init_buff(&ring->xdp, xdp_frame_sz, &ring->xdp_rxq);
+ xdp_init_buff(&ring->xdp_ctx.xdp, xdp_frame_sz, &ring->xdp_rxq);
rx_ctx.dbuff = DIV_ROUND_UP(ring->rx_buf_len,
BIT_ULL(I40E_RXQ_CTX_DBUFF_SHIFT));
diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c
index ef5e657816f0..7f68adb5109b 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c
@@ -2438,10 +2438,11 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget,
unsigned int *rx_cleaned)
{
unsigned int total_rx_bytes = 0, total_rx_packets = 0;
+ struct i40e_xdp_buff *xdp_ctx = &rx_ring->xdp_ctx;
u16 cleaned_count = I40E_DESC_UNUSED(rx_ring);
u16 clean_threshold = rx_ring->count / 2;
unsigned int offset = rx_ring->rx_offset;
- struct xdp_buff *xdp = &rx_ring->xdp;
+ struct xdp_buff *xdp = &xdp_ctx->xdp;
unsigned int xdp_xmit = 0;
struct bpf_prog *xdp_prog;
bool failure = false;
@@ -2530,6 +2531,8 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget,
if (neop)
continue;
+ xdp_ctx->desc = rx_desc;
+
xdp_res = i40e_run_xdp(rx_ring, xdp, xdp_prog);
if (xdp_res) {
diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.h b/drivers/net/ethernet/intel/i40e/i40e_txrx.h
index 1e5fd63d47f4..bb741ff3e5f2 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_txrx.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.h
@@ -283,6 +283,11 @@ struct i40e_rx_buffer {
__u32 page_count;
};
+struct i40e_xdp_buff {
+ struct xdp_buff xdp;
+ const union i40e_rx_desc *desc;
+};
+
struct i40e_queue_stats {
u64 packets;
u64 bytes;
@@ -345,7 +350,7 @@ struct i40e_ring {
* and to resume packet building for this ring in the next call to
* i40e_clean_rx_ring_irq().
*/
- struct xdp_buff xdp;
+ struct i40e_xdp_buff xdp_ctx;
/* Next descriptor to be processed; next_to_clean is updated only on
* processing EOP descriptor
diff --git a/drivers/net/ethernet/intel/i40e/i40e_xsk.c b/drivers/net/ethernet/intel/i40e/i40e_xsk.c
index 9f47388eaba5..51a05ce4c7ce 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_xsk.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_xsk.c
@@ -246,6 +246,8 @@ bool i40e_alloc_rx_buffers_zc(struct i40e_ring *rx_ring, u16 count)
u32 nb_buffs, i;
dma_addr_t dma;
+ XSK_CHECK_PRIV_TYPE(struct i40e_xdp_buff);
+
rx_desc = I40E_RX_DESC(rx_ring, ntu);
xdp = i40e_rx_bi(rx_ring, ntu);
@@ -396,6 +398,14 @@ static void i40e_handle_xdp_result_zc(struct i40e_ring *rx_ring,
WARN_ON_ONCE(1);
}
+static struct i40e_xdp_buff *xsk_buff_to_i40e_ctx(struct xdp_buff *xdp)
+{
+ /* xdp_buff pointer used by ZC code path is allocated as xdp_buff_xsk.
+ * i40e_xdp_buff private fields overlap with xdp_buff_xsk->cb.
+ */
+ return (struct i40e_xdp_buff *)xdp;
+}
+
/**
* i40e_clean_rx_irq_zc - Consumes Rx packets from the hardware ring
* @rx_ring: Rx ring
@@ -472,6 +482,8 @@ int i40e_clean_rx_irq_zc(struct i40e_ring *rx_ring, int budget)
if (i40e_is_non_eop(rx_ring, rx_desc))
continue;
+ xsk_buff_to_i40e_ctx(first)->desc = rx_desc;
+
xdp_res = i40e_run_xdp_zc(rx_ring, first, xdp_prog);
i40e_handle_xdp_result_zc(rx_ring, first, rx_desc, &rx_packets,
&rx_bytes, xdp_res, &failure);
--
2.47.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH net-next 11/15] i40e: add support for bpf_xdp_metadata_rx_hash()
[not found] <20260805213541.2281287-1-anthony.l.nguyen@intel.com>
2026-08-05 21:35 ` [PATCH net-next 10/15] i40e: prepare for XDP metadata ops support Tony Nguyen
@ 2026-08-05 21:35 ` Tony Nguyen
2026-08-05 21:35 ` [PATCH net-next 12/15] i40e: add support for bpf_xdp_metadata_rx_vlan_tag() Tony Nguyen
2 siblings, 0 replies; 5+ messages in thread
From: Tony Nguyen @ 2026-08-05 21:35 UTC (permalink / raw)
To: davem, kuba, pabeni, edumazet, andrew+netdev, netdev
Cc: Kohei Enju, anthony.l.nguyen, kohei.enju, przemyslaw.kitszel,
maciej.fijalkowski, magnus.karlsson, ast, daniel, hawk,
john.fastabend, sdf, bpf, Aleksandr Loktionov, Patryk Holda
From: Kohei Enju <kohei@enjuk.jp>
Introduce i40e_xdp_rx_hash() which takes the same approach as
i40e_rx_hash() to extract the hash from RX descriptors.
Tested with X710 adapter using xdp_hw_metadata, and verified hash
consistency between bpf_xdp_metadata_rx_hash() and skb->hash.
Signed-off-by: Kohei Enju <kohei@enjuk.jp>
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Tested-by: Patryk Holda <patryk.holda@intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
---
drivers/net/ethernet/intel/i40e/i40e_main.c | 30 +++++++++++++++++++++
drivers/net/ethernet/intel/i40e/i40e_type.h | 5 ++++
2 files changed, 35 insertions(+)
diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c
index 4b11ae9ed8d5..e487d697a634 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_main.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
@@ -4,6 +4,7 @@
#include <generated/utsrelease.h>
#include <linux/crash_dump.h>
#include <linux/net/intel/libie/pctype.h>
+#include <linux/net/intel/libie/rx.h>
#include <linux/if_bridge.h>
#include <linux/if_macvlan.h>
#include <linux/module.h>
@@ -13582,6 +13583,34 @@ static int i40e_xdp(struct net_device *dev,
}
}
+static int i40e_xdp_rx_hash(const struct xdp_md *_ctx, u32 *hash,
+ enum xdp_rss_hash_type *rss_type)
+{
+ const struct i40e_xdp_buff *ctx = (const void *)_ctx;
+ const union i40e_rx_desc *desc = ctx->desc;
+ struct libeth_rx_pt rx_ptype;
+ u8 raw_rx_ptype;
+ u64 status;
+
+ status = le64_to_cpu(desc->wb.qword1.status_error_len);
+ raw_rx_ptype = FIELD_GET(I40E_RXD_QW1_PTYPE_MASK, status);
+ rx_ptype = libie_rx_pt_parse(raw_rx_ptype);
+
+ if (!libeth_rx_pt_has_hash(ctx->xdp.rxq->dev, rx_ptype) ||
+ FIELD_GET(I40E_RX_DESC_STATUS_FLTSTAT_MASK, status) !=
+ I40E_RX_DESC_FLTSTAT_RSS_HASH)
+ return -ENODATA;
+
+ *hash = le32_to_cpu(desc->wb.qword0.hi_dword.rss);
+ *rss_type = rx_ptype.hash_type;
+
+ return 0;
+}
+
+static const struct xdp_metadata_ops i40e_xdp_metadata_ops = {
+ .xmo_rx_hash = i40e_xdp_rx_hash,
+};
+
static const struct net_device_ops i40e_netdev_ops = {
.ndo_open = i40e_open,
.ndo_stop = i40e_close,
@@ -13784,6 +13813,7 @@ static int i40e_config_netdev(struct i40e_vsi *vsi)
i40e_vsi_config_netdev_tc(vsi, vsi->tc_config.enabled_tc);
netdev->netdev_ops = &i40e_netdev_ops;
+ netdev->xdp_metadata_ops = &i40e_xdp_metadata_ops;
netdev->watchdog_timeo = 5 * HZ;
i40e_set_ethtool_ops(netdev);
diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h
index ed8bbdb586da..16a65c6e5153 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_type.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_type.h
@@ -4,6 +4,7 @@
#ifndef _I40E_TYPE_H_
#define _I40E_TYPE_H_
+#include <linux/bits.h>
#include <uapi/linux/if_ether.h>
#include "i40e_adminq.h"
#include "i40e_hmc.h"
@@ -699,6 +700,10 @@ enum i40e_rx_desc_status_bits {
I40E_RX_DESC_STATUS_LAST /* this entry must be last!!! */
};
+#define I40E_RX_DESC_STATUS_FLTSTAT_MASK \
+ GENMASK_ULL(I40E_RX_DESC_STATUS_FLTSTAT_SHIFT + 1, \
+ I40E_RX_DESC_STATUS_FLTSTAT_SHIFT)
+
#define I40E_RXD_QW1_STATUS_SHIFT 0
#define I40E_RXD_QW1_STATUS_MASK ((BIT(I40E_RX_DESC_STATUS_LAST) - 1) \
<< I40E_RXD_QW1_STATUS_SHIFT)
--
2.47.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH net-next 12/15] i40e: add support for bpf_xdp_metadata_rx_vlan_tag()
[not found] <20260805213541.2281287-1-anthony.l.nguyen@intel.com>
2026-08-05 21:35 ` [PATCH net-next 10/15] i40e: prepare for XDP metadata ops support Tony Nguyen
2026-08-05 21:35 ` [PATCH net-next 11/15] i40e: add support for bpf_xdp_metadata_rx_hash() Tony Nguyen
@ 2026-08-05 21:35 ` Tony Nguyen
2 siblings, 0 replies; 5+ messages in thread
From: Tony Nguyen @ 2026-08-05 21:35 UTC (permalink / raw)
To: davem, kuba, pabeni, edumazet, andrew+netdev, netdev
Cc: Kohei Enju, anthony.l.nguyen, kohei.enju, przemyslaw.kitszel,
maciej.fijalkowski, magnus.karlsson, ast, daniel, hawk,
john.fastabend, sdf, bpf, Aleksandr Loktionov, Patryk Holda
From: Kohei Enju <kohei@enjuk.jp>
Introduce i40e_xdp_rx_vlan_tag() which takes the same approach as
i40e_process_skb_fields() to extract the VLAN tag from the RX
descriptor.
Tested with X710 adapter using xdp_hw_metadata, and confirmed that VLAN
tags match between bpf_xdp_metadata_rx_vlan_tag() and
skb->vlan_proto/vlan_tci.
Signed-off-by: Kohei Enju <kohei@enjuk.jp>
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Tested-by: Patryk Holda <patryk.holda@intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
---
drivers/net/ethernet/intel/i40e/i40e_main.c | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c
index e487d697a634..719f45b5cb40 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_main.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
@@ -13607,8 +13607,27 @@ static int i40e_xdp_rx_hash(const struct xdp_md *_ctx, u32 *hash,
return 0;
}
+static int i40e_xdp_rx_vlan_tag(const struct xdp_md *_ctx, __be16 *vlan_proto,
+ u16 *vlan_tci)
+{
+ const struct i40e_xdp_buff *ctx = (const void *)_ctx;
+ const union i40e_rx_desc *desc = ctx->desc;
+ u64 status;
+
+ status = le64_to_cpu(desc->wb.qword1.status_error_len);
+
+ if (!(status & BIT(I40E_RX_DESC_STATUS_L2TAG1P_SHIFT)))
+ return -ENODATA;
+
+ *vlan_proto = cpu_to_be16(ETH_P_8021Q);
+ *vlan_tci = le16_to_cpu(desc->wb.qword0.lo_dword.l2tag1);
+
+ return 0;
+}
+
static const struct xdp_metadata_ops i40e_xdp_metadata_ops = {
.xmo_rx_hash = i40e_xdp_rx_hash,
+ .xmo_rx_vlan_tag = i40e_xdp_rx_vlan_tag,
};
static const struct net_device_ops i40e_netdev_ops = {
--
2.47.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH net-next 10/15] i40e: prepare for XDP metadata ops support
2026-08-05 21:35 ` [PATCH net-next 10/15] i40e: prepare for XDP metadata ops support Tony Nguyen
@ 2026-08-06 21:36 ` sashiko-bot
2026-08-07 19:00 ` Kohei Enju
0 siblings, 1 reply; 5+ messages in thread
From: sashiko-bot @ 2026-08-06 21:36 UTC (permalink / raw)
To: Tony Nguyen; +Cc: bpf
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [Critical] Use-After-Free in the AF_XDP Zero-Copy receive path due to stagnant index variable on error.
--
--- Patch [10]: [PATCH net-next 10/15] i40e: prepare for XDP metadata ops support ---
commit cf380b8d06da010c94723db1eb6af6df8fb0fdc8
Author: Kohei Enju <kohei@enjuk.jp>
i40e: prepare for XDP metadata ops support
This commit introduces struct i40e_xdp_buff to wrap an xdp_buff alongside
a pointer to an i40e_rx_desc. It passes the RX descriptor to XDP kfuncs
and adds bounds checking in the AF_XDP Zero-Copy path using
XSK_CHECK_PRIV_TYPE.
> diff --git a/drivers/net/ethernet/intel/i40e/i40e_xsk.c b/drivers/net/ethernet/intel/i40e/i40e_xsk.c
> index 9f47388eaba53..51a05ce4c7ce8 100644
> --- a/drivers/net/ethernet/intel/i40e/i40e_xsk.c
> +++ b/drivers/net/ethernet/intel/i40e/i40e_xsk.c
[ ... ]
> @@ -472,6 +482,8 @@ int i40e_clean_rx_irq_zc(struct i40e_ring *rx_ring, int budget)
> if (i40e_is_non_eop(rx_ring, rx_desc))
> continue;
>
> + xsk_buff_to_i40e_ctx(first)->desc = rx_desc;
> +
[Severity: Critical]
This is a pre-existing issue, but does this function have a use-after-free
in its error handling path?
If xsk_buff_add_frag() fails earlier in the loop, it calls
xsk_buff_free(first) and breaks out of the loop without advancing
next_to_clean:
if (!first)
first = bi;
else if (!xsk_buff_add_frag(first, bi)) {
xsk_buff_free(first);
break;
}
On the subsequent NAPI poll, because next_to_process != next_to_clean,
the code loads the freed buffer pointer from the stale next_to_clean
index:
if (next_to_process != next_to_clean)
first = *i40e_rx_bi(rx_ring, next_to_clean);
Could this cause the next packet to be built using a freed buffer?
> xdp_res = i40e_run_xdp_zc(rx_ring, first, xdp_prog);
> i40e_handle_xdp_result_zc(rx_ring, first, rx_desc, &rx_packets,
> &rx_bytes, xdp_res, &failure);
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260805213541.2281287-1-anthony.l.nguyen@intel.com?part=10
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH net-next 10/15] i40e: prepare for XDP metadata ops support
2026-08-06 21:36 ` sashiko-bot
@ 2026-08-07 19:00 ` Kohei Enju
0 siblings, 0 replies; 5+ messages in thread
From: Kohei Enju @ 2026-08-07 19:00 UTC (permalink / raw)
To: sashiko-reviews; +Cc: Tony Nguyen, bpf
On 08/06 21:36, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
>
> Pre-existing issues:
> - [Critical] Use-After-Free in the AF_XDP Zero-Copy receive path due to stagnant index variable on error.
> --
>
> --- Patch [10]: [PATCH net-next 10/15] i40e: prepare for XDP metadata ops support ---
> commit cf380b8d06da010c94723db1eb6af6df8fb0fdc8
> Author: Kohei Enju <kohei@enjuk.jp>
>
> i40e: prepare for XDP metadata ops support
>
> This commit introduces struct i40e_xdp_buff to wrap an xdp_buff alongside
> a pointer to an i40e_rx_desc. It passes the RX descriptor to XDP kfuncs
> and adds bounds checking in the AF_XDP Zero-Copy path using
> XSK_CHECK_PRIV_TYPE.
>
> > diff --git a/drivers/net/ethernet/intel/i40e/i40e_xsk.c b/drivers/net/ethernet/intel/i40e/i40e_xsk.c
> > index 9f47388eaba53..51a05ce4c7ce8 100644
> > --- a/drivers/net/ethernet/intel/i40e/i40e_xsk.c
> > +++ b/drivers/net/ethernet/intel/i40e/i40e_xsk.c
>
> [ ... ]
>
> > @@ -472,6 +482,8 @@ int i40e_clean_rx_irq_zc(struct i40e_ring *rx_ring, int budget)
> > if (i40e_is_non_eop(rx_ring, rx_desc))
> > continue;
> >
> > + xsk_buff_to_i40e_ctx(first)->desc = rx_desc;
> > +
>
> [Severity: Critical]
> This is a pre-existing issue, but does this function have a use-after-free
> in its error handling path?
>
> If xsk_buff_add_frag() fails earlier in the loop, it calls
IIUC, I40E_MAX_CHAINED_RX_BUFFERS (5) limits a packet to one head and at
most four frags. Since xsk_buff_add_frag() fails only when nr_frags ==
MAX_SKB_FRAGS, which is at least 17, this path is unreachable for a
valid i40e RX chain.
However, the UAF scenario looks valid if it does fail, so the
pre-existing error may still be worth fixing.
> xsk_buff_free(first) and breaks out of the loop without advancing
> next_to_clean:
>
> if (!first)
> first = bi;
> else if (!xsk_buff_add_frag(first, bi)) {
> xsk_buff_free(first);
> break;
> }
>
> On the subsequent NAPI poll, because next_to_process != next_to_clean,
> the code loads the freed buffer pointer from the stale next_to_clean
> index:
>
> if (next_to_process != next_to_clean)
> first = *i40e_rx_bi(rx_ring, next_to_clean);
>
> Could this cause the next packet to be built using a freed buffer?
>
> > xdp_res = i40e_run_xdp_zc(rx_ring, first, xdp_prog);
> > i40e_handle_xdp_result_zc(rx_ring, first, rx_desc, &rx_packets,
> > &rx_bytes, xdp_res, &failure);
>
> --
> Sashiko AI review · https://sashiko.dev/#/patchset/20260805213541.2281287-1-anthony.l.nguyen@intel.com?part=10
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-08-07 19:01 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <20260805213541.2281287-1-anthony.l.nguyen@intel.com>
2026-08-05 21:35 ` [PATCH net-next 10/15] i40e: prepare for XDP metadata ops support Tony Nguyen
2026-08-06 21:36 ` sashiko-bot
2026-08-07 19:00 ` Kohei Enju
2026-08-05 21:35 ` [PATCH net-next 11/15] i40e: add support for bpf_xdp_metadata_rx_hash() Tony Nguyen
2026-08-05 21:35 ` [PATCH net-next 12/15] i40e: add support for bpf_xdp_metadata_rx_vlan_tag() Tony Nguyen
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox