* [PATCH net-next 1/4] i40e: prepare for XDP metadata ops support
2026-09-01 21:17 [PATCH net-next 0/4][pull request] Intel Wired LAN Driver Updates 2026-09-01 (i40e) Tony Nguyen
@ 2026-09-01 21:17 ` Tony Nguyen
2026-09-01 21:17 ` [PATCH net-next 2/4] i40e: add support for bpf_xdp_metadata_rx_hash() Tony Nguyen
` (2 subsequent siblings)
3 siblings, 0 replies; 8+ messages in thread
From: Tony Nguyen @ 2026-09-01 21:17 UTC (permalink / raw)
To: davem, kuba, pabeni, edumazet, andrew+netdev, netdev
Cc: Kohei Enju, anthony.l.nguyen, kohei.enju, enjuk, chris.packham,
przemyslaw.kitszel, blair.steven, carl.smith, horms,
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] 8+ messages in thread* [PATCH net-next 2/4] i40e: add support for bpf_xdp_metadata_rx_hash()
2026-09-01 21:17 [PATCH net-next 0/4][pull request] Intel Wired LAN Driver Updates 2026-09-01 (i40e) Tony Nguyen
2026-09-01 21:17 ` [PATCH net-next 1/4] i40e: prepare for XDP metadata ops support Tony Nguyen
@ 2026-09-01 21:17 ` Tony Nguyen
2026-09-04 9:19 ` netdev-bot+sashiko
2026-09-01 21:17 ` [PATCH net-next 3/4] i40e: add support for bpf_xdp_metadata_rx_vlan_tag() Tony Nguyen
2026-09-01 21:17 ` [PATCH net-next 4/4] i40e: Avoid repeating RX filter warning Tony Nguyen
3 siblings, 1 reply; 8+ messages in thread
From: Tony Nguyen @ 2026-09-01 21:17 UTC (permalink / raw)
To: davem, kuba, pabeni, edumazet, andrew+netdev, netdev
Cc: Kohei Enju, anthony.l.nguyen, kohei.enju, enjuk, chris.packham,
przemyslaw.kitszel, blair.steven, carl.smith, horms,
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] 8+ messages in thread* Re: [PATCH net-next 2/4] i40e: add support for bpf_xdp_metadata_rx_hash()
2026-09-01 21:17 ` [PATCH net-next 2/4] i40e: add support for bpf_xdp_metadata_rx_hash() Tony Nguyen
@ 2026-09-04 9:19 ` netdev-bot+sashiko
0 siblings, 0 replies; 8+ messages in thread
From: netdev-bot+sashiko @ 2026-09-04 9:19 UTC (permalink / raw)
To: anthony.l.nguyen
Cc: davem, kuba, pabeni, edumazet, andrew+netdev, netdev,
chris.packham, kohei.enju, enjuk, przemyslaw.kitszel,
blair.steven, carl.smith, horms, maciej.fijalkowski,
magnus.karlsson, ast, daniel, hawk, john.fastabend, sdf, bpf,
aleksandr.loktionov, sx.rinitha
Thank you for your contribution! Sashiko AI review found 1 potential
issue(s) to consider:
Critical: 0 · High: 0 · Medium: 1 · Low: 0
- [Medium] i40e_config_netdev() sets `netdev->xdp_metadata_ops =
&i40e_xdp_metadata_ops;` unconditionally…
--
i40e: add support for bpf_xdp_metadata_rx_hash()
This adds i40e_xdp_rx_hash() as an xdp_metadata_ops callback, extracting
the RSS hash and hash type from the RX descriptor the same way
i40e_rx_hash() does. A new I40E_RX_DESC_STATUS_FLTSTAT_MASK helper is
added to i40e_type.h and the ops struct is installed on the netdev.
> diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c
> index 4b11ae9ed8d53..e487d697a634f 100644
> --- a/drivers/net/ethernet/intel/i40e/i40e_main.c
> +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
[ ... ]
> @@ -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;
[Severity: Medium]
Should this assignment live inside the I40E_VSI_MAIN branch, next to where
the rest of the XDP capability state is set?
Earlier in i40e_config_netdev() the XDP capabilities are set only for the
main VSI:
if (vsi->type == I40E_VSI_MAIN) {
...
netdev->xdp_features = NETDEV_XDP_ACT_BASIC |
NETDEV_XDP_ACT_REDIRECT |
NETDEV_XDP_ACT_XSK_ZEROCOPY |
NETDEV_XDP_ACT_RX_SG;
netdev->xdp_zc_max_segs = I40E_MAX_BUFFER_TXD;
} else {
/* Relate the VSI_VMDQ name to the VSI_MAIN name ... */
but i40e_config_netdev() also runs for VMDQ2 netdevs, via i40e_vsi_setup():
switch (vsi->type) {
/* setup the netdev if needed */
case I40E_VSI_MAIN:
case I40E_VSI_VMDQ2:
ret = i40e_config_netdev(vsi);
Those macvlan-offload "<pf>v%d" netdevs get xdp_features == 0, and
i40e_xdp() rejects every ndo_bpf command on them:
if (vsi->type != I40E_VSI_MAIN)
return -EINVAL;
So no native XDP program can be attached there, and xmo_rx_hash can never
be reached on such a netdev.
Does this make the netlink capability report inconsistent? netdev_nl_dev_fill()
derives the xdp-rx-metadata-features bits purely from the presence of the
callback, with no cross-check against dev->xdp_features:
net/core/netdev-genl.c:netdev_nl_dev_fill() {
...
#define XDP_METADATA_KFUNC(_, flag, __, xmo) \
if (netdev->xdp_metadata_ops && netdev->xdp_metadata_ops->xmo) \
xdp_rx_meta |= flag;
...
}
which means a VMDQ2 netdev advertises NETDEV_XDP_RX_METADATA_HASH ("Device is
capable of exposing receive packet hash via bpf_xdp_metadata_rx_hash()") while
rejecting XDP entirely.
The follow-up patch adding bpf_xdp_metadata_rx_vlan_tag() extends the same
unconditional assignment, so NETDEV_XDP_RX_METADATA_VLAN_TAG ends up reported
on those netdevs too; the assignment is still unconditional at the end of the
series.
> netdev->watchdog_timeo = 5 * HZ;
> i40e_set_ethtool_ops(netdev);
>
--
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260901211752.1922993-1-anthony.l.nguyen%40intel.com
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH net-next 3/4] i40e: add support for bpf_xdp_metadata_rx_vlan_tag()
2026-09-01 21:17 [PATCH net-next 0/4][pull request] Intel Wired LAN Driver Updates 2026-09-01 (i40e) Tony Nguyen
2026-09-01 21:17 ` [PATCH net-next 1/4] i40e: prepare for XDP metadata ops support Tony Nguyen
2026-09-01 21:17 ` [PATCH net-next 2/4] i40e: add support for bpf_xdp_metadata_rx_hash() Tony Nguyen
@ 2026-09-01 21:17 ` Tony Nguyen
2026-09-01 21:17 ` [PATCH net-next 4/4] i40e: Avoid repeating RX filter warning Tony Nguyen
3 siblings, 0 replies; 8+ messages in thread
From: Tony Nguyen @ 2026-09-01 21:17 UTC (permalink / raw)
To: davem, kuba, pabeni, edumazet, andrew+netdev, netdev
Cc: Kohei Enju, anthony.l.nguyen, kohei.enju, enjuk, chris.packham,
przemyslaw.kitszel, blair.steven, carl.smith, horms,
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] 8+ messages in thread* [PATCH net-next 4/4] i40e: Avoid repeating RX filter warning
2026-09-01 21:17 [PATCH net-next 0/4][pull request] Intel Wired LAN Driver Updates 2026-09-01 (i40e) Tony Nguyen
` (2 preceding siblings ...)
2026-09-01 21:17 ` [PATCH net-next 3/4] i40e: add support for bpf_xdp_metadata_rx_vlan_tag() Tony Nguyen
@ 2026-09-01 21:17 ` Tony Nguyen
2026-09-02 21:18 ` sashiko-bot
2026-09-04 9:19 ` netdev-bot+sashiko
3 siblings, 2 replies; 8+ messages in thread
From: Tony Nguyen @ 2026-09-01 21:17 UTC (permalink / raw)
To: davem, kuba, pabeni, edumazet, andrew+netdev, netdev
Cc: Chris Packham, anthony.l.nguyen, kohei.enju, enjuk,
przemyslaw.kitszel, blair.steven, carl.smith, horms,
maciej.fijalkowski, magnus.karlsson, ast, daniel, hawk,
john.fastabend, sdf, bpf, Aleksandr Loktionov, Rinitha S
From: Chris Packham <chris.packham@alliedtelesis.co.nz>
When the i40e runs out of space for RX filters the driver switches to
promiscuous mode and warns that it has done so. In scenarios with a
large number of these filters this can generate a lot of warnings. For
example:
$ dmesg -c > /dev/null
$ ip link add dev br0 type bridge vlan_filtering 1 vlan_default_pvid 1
$ ip link set dev eth7 master br0
$ bridge vlan add vid 1 dev eth7 pvid untagged self
$ bridge vlan add vid 2-4094 dev eth7 tagged
$ dmesg
[ 25.601705] i40e 0000:01:00.1: Error LIBIE_AQ_RC_ENOSPC, forcing overflow promiscuous on PF
[ 25.601833] i40e 0000:01:00.1: Error LIBIE_AQ_RC_ENOSPC, forcing overflow promiscuous on PF
[ 25.601961] i40e 0000:01:00.1: Error LIBIE_AQ_RC_ENOSPC, forcing overflow promiscuous on PF
[ 25.602088] i40e 0000:01:00.1: Error LIBIE_AQ_RC_ENOSPC, forcing overflow promiscuous on PF
[ 25.602216] i40e 0000:01:00.1: Error LIBIE_AQ_RC_ENOSPC, forcing overflow promiscuous on PF
[ 25.602344] i40e 0000:01:00.1: Error LIBIE_AQ_RC_ENOSPC, forcing overflow promiscuous on PF
...
Use test_and_set_bit() so that the warning is only issued when the
driver enables promiscuous mode and not on the addition of subsequent RX
filters.
Signed-off-by: Chris Packham <chris.packham@alliedtelesis.co.nz>
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Tested-by: Rinitha S <sx.rinitha@intel.com> (A Contingent worker at Intel)
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
---
drivers/net/ethernet/intel/i40e/i40e_main.c | 19 +++++++++++--------
1 file changed, 11 insertions(+), 8 deletions(-)
diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c
index 719f45b5cb40..abbc71e815ae 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_main.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
@@ -2412,10 +2412,12 @@ void i40e_aqc_add_filters(struct i40e_vsi *vsi, const char *vsi_name,
if (fcnt != num_add) {
if (vsi->type == I40E_VSI_MAIN) {
- set_bit(__I40E_VSI_OVERFLOW_PROMISC, vsi->state);
- dev_warn(&vsi->back->pdev->dev,
- "Error %s adding RX filters on %s, promiscuous mode forced on\n",
- libie_aq_str(aq_status), vsi_name);
+ if (!test_and_set_bit(__I40E_VSI_OVERFLOW_PROMISC,
+ vsi->state)) {
+ dev_warn(&vsi->back->pdev->dev,
+ "Error %s adding RX filters on %s, promiscuous mode forced on\n",
+ libie_aq_str(aq_status), vsi_name);
+ }
} else if (vsi->type == I40E_VSI_SRIOV ||
vsi->type == I40E_VSI_VMDQ1 ||
vsi->type == I40E_VSI_VMDQ2) {
@@ -2465,10 +2467,11 @@ i40e_aqc_broadcast_filter(struct i40e_vsi *vsi, const char *vsi_name,
}
if (aq_ret) {
- set_bit(__I40E_VSI_OVERFLOW_PROMISC, vsi->state);
- dev_warn(&vsi->back->pdev->dev,
- "Error %s, forcing overflow promiscuous on %s\n",
- libie_aq_str(hw->aq.asq_last_status), vsi_name);
+ if (!test_and_set_bit(__I40E_VSI_OVERFLOW_PROMISC, vsi->state)) {
+ dev_warn(&vsi->back->pdev->dev,
+ "Error %s, forcing overflow promiscuous on %s\n",
+ libie_aq_str(hw->aq.asq_last_status), vsi_name);
+ }
}
return aq_ret;
--
2.47.1
^ permalink raw reply related [flat|nested] 8+ messages in thread* Re: [PATCH net-next 4/4] i40e: Avoid repeating RX filter warning
2026-09-01 21:17 ` [PATCH net-next 4/4] i40e: Avoid repeating RX filter warning Tony Nguyen
@ 2026-09-02 21:18 ` sashiko-bot
2026-09-04 9:19 ` netdev-bot+sashiko
1 sibling, 0 replies; 8+ messages in thread
From: sashiko-bot @ 2026-09-02 21:18 UTC (permalink / raw)
To: Tony Nguyen; +Cc: bpf
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
New issues:
- [High] The fix for repeating RX filter warnings is incomplete and leaves SRIOV/VMDQ VSIs vulnerable to log spam, exacerbated by unconditional state clearing for untrusted VFs.
Pre-existing issues:
- [High] The function `i40e_sync_vsi_filters` implements an ad-hoc sleeping spinlock using a bit flag (`__I40E_VSI_SYNCING_FILTERS`), violating subsystem locking guidelines.
--
commit e12ee63ee282f8dda3570d0ba1ab6d4fc31ab63e
Author: Chris Packham <chris.packham@alliedtelesis.co.nz>
Subject: i40e: Avoid repeating RX filter warning
This patch introduces a test_and_set_bit check on the overflow promiscuous
state flag to suppress repetitive log messages when the driver forces
overflow promiscuous mode due to a lack of space for RX filters. It updates
the warning logic in both i40e_aqc_add_filters and i40e_aqc_broadcast_filter.
> diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c
> index 719f45b5cb409..abbc71e815ae3 100644
> --- a/drivers/net/ethernet/intel/i40e/i40e_main.c
> +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
[ ... ]
> @@ -2412,10 +2412,12 @@ void i40e_aqc_add_filters(struct i40e_vsi *vsi, const char *vsi_name,
>
> if (fcnt != num_add) {
> if (vsi->type == I40E_VSI_MAIN) {
> - set_bit(__I40E_VSI_OVERFLOW_PROMISC, vsi->state);
> - dev_warn(&vsi->back->pdev->dev,
> - "Error %s adding RX filters on %s, promiscuous mode forced on\n",
> - libie_aq_str(aq_status), vsi_name);
> + if (!test_and_set_bit(__I40E_VSI_OVERFLOW_PROMISC,
> + vsi->state)) {
> + dev_warn(&vsi->back->pdev->dev,
> + "Error %s adding RX filters on %s, promiscuous mode forced on\n",
> + libie_aq_str(aq_status), vsi_name);
> + }
> } else if (vsi->type == I40E_VSI_SRIOV ||
> vsi->type == I40E_VSI_VMDQ1 ||
> vsi->type == I40E_VSI_VMDQ2) {
[Severity: High]
Does this logic leave virtual function and vmdq VSIs vulnerable to log spam?
The patch suppresses the warning for the main VSI by checking
test_and_set_bit, but the else if branch for the other VSI types immediately
below it does not use a state check.
Should the state-based warning suppression be enforced equally across all VSI
types?
This regression seems exacerbated by the unconditional state clearing for
untrusted virtual functions in i40e_sync_vsi_filters:
drivers/net/ethernet/intel/i40e/i40e_main.c:i40e_sync_vsi_filters() {
...
/* if the VF is not trusted do not do promisc */
if (vsi->type == I40E_VSI_SRIOV && pf->vf &&
!pf->vf[vsi->vf_id].trusted) {
clear_bit(__I40E_VSI_OVERFLOW_PROMISC, vsi->state);
goto out;
}
...
}
Does this unconditional state clearing destroy the warning suppression logic
for untrusted virtual functions, potentially leading to a denial of service
via log spam?
[Severity: High]
This is a pre-existing issue, but while reviewing the synchronization of
these filters I noticed the following pattern in i40e_sync_vsi_filters:
drivers/net/ethernet/intel/i40e/i40e_main.c:i40e_sync_vsi_filters() {
...
while (test_and_set_bit(__I40E_VSI_SYNCING_FILTERS, vsi->state))
usleep_range(1000, 2000);
...
out:
...
clear_bit(__I40E_VSI_SYNCING_FILTERS, vsi->state);
return retval;
...
}
Does this implement an ad-hoc sleeping spinlock using a bit flag, violating
the subsystem guidelines for synchronization?
Would it be better to directly replace this custom polling loop with a
standard mutex to ensure strict lockdep tracking and memory ordering?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260901211752.1922993-1-anthony.l.nguyen@intel.com?part=4
^ permalink raw reply [flat|nested] 8+ messages in thread* Re: [PATCH net-next 4/4] i40e: Avoid repeating RX filter warning
2026-09-01 21:17 ` [PATCH net-next 4/4] i40e: Avoid repeating RX filter warning Tony Nguyen
2026-09-02 21:18 ` sashiko-bot
@ 2026-09-04 9:19 ` netdev-bot+sashiko
1 sibling, 0 replies; 8+ messages in thread
From: netdev-bot+sashiko @ 2026-09-04 9:19 UTC (permalink / raw)
To: anthony.l.nguyen
Cc: davem, kuba, pabeni, edumazet, andrew+netdev, netdev,
chris.packham, kohei.enju, enjuk, przemyslaw.kitszel,
blair.steven, carl.smith, horms, maciej.fijalkowski,
magnus.karlsson, ast, daniel, hawk, john.fastabend, sdf, bpf,
aleksandr.loktionov, sx.rinitha
Thank you for your contribution! Sashiko AI review found 1 potential
issue(s) to consider:
Critical: 0 · High: 0 · Medium: 0 (1) · Low: 1
- [Low] Two diagnostics that report different failure classes are now
gated on one shared single-shot bit.
Pre-existing issues:
- [Medium] The overflow-promiscuous bit that the patch now also uses as a
log-once latch lives in `vsi->state`, which is protected only by an…
--
i40e: Avoid repeating RX filter warning
The patch converts the two set_bit(__I40E_VSI_OVERFLOW_PROMISC, vsi->state)
call sites in i40e_aqc_add_filters() and i40e_aqc_broadcast_filter() to
test_and_set_bit(), so the "forcing overflow promiscuous" warning is only
emitted on the transition into overflow promiscuous mode.
> diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c
> index 719f45b5cb409..abbc71e815ae3 100644
> --- a/drivers/net/ethernet/intel/i40e/i40e_main.c
> +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
> @@ -2412,10 +2412,12 @@ void i40e_aqc_add_filters(struct i40e_vsi *vsi, const char *vsi_name,
>
> if (fcnt != num_add) {
> if (vsi->type == I40E_VSI_MAIN) {
> - set_bit(__I40E_VSI_OVERFLOW_PROMISC, vsi->state);
> - dev_warn(&vsi->back->pdev->dev,
> - "Error %s adding RX filters on %s, promiscuous mode forced on\n",
> - libie_aq_str(aq_status), vsi_name);
> + if (!test_and_set_bit(__I40E_VSI_OVERFLOW_PROMISC,
> + vsi->state)) {
> + dev_warn(&vsi->back->pdev->dev,
> + "Error %s adding RX filters on %s, promiscuous mode forced on\n",
> + libie_aq_str(aq_status), vsi_name);
> + }
[Severity: Medium]
This isn't a bug introduced by this patch, but the warning is now latched on
a bit whose lifetime is managed by an ad-hoc flag-as-lock scheme, so is the
latch reliable?
i40e_sync_vsi_filters() serializes its whole sleeping section with an
open-coded acquire loop:
while (test_and_set_bit(__I40E_VSI_SYNCING_FILTERS, vsi->state))
usleep_range(1000, 2000);
pf = vsi->back;
old_overflow = test_bit(__I40E_VSI_OVERFLOW_PROMISC, vsi->state);
and releases it with a plain clear_bit(__I40E_VSI_SYNCING_FILTERS,
vsi->state) on both the out: and err_no_memory: paths.
i40e_add_vsi(), reached from i40e_rebuild() and i40e_vsi_setup(), clears the
bit without participating in that gate at all:
spin_unlock_bh(&vsi->mac_filter_hash_lock);
clear_bit(__I40E_VSI_OVERFLOW_PROMISC, vsi->state);
If that clear lands while i40e_sync_vsi_filters() is between its
old_overflow snapshot and the new_overflow / promisc_threshold decision, can
the warning re-fire, or the opposite, can the state read as non-overflowing
while filter programming keeps failing?
> } else if (vsi->type == I40E_VSI_SRIOV ||
> vsi->type == I40E_VSI_VMDQ1 ||
> vsi->type == I40E_VSI_VMDQ2) {
> @@ -2465,10 +2467,11 @@ i40e_aqc_broadcast_filter(struct i40e_vsi *vsi, const char *vsi_name,
> }
>
> if (aq_ret) {
> - set_bit(__I40E_VSI_OVERFLOW_PROMISC, vsi->state);
> - dev_warn(&vsi->back->pdev->dev,
> - "Error %s, forcing overflow promiscuous on %s\n",
> - libie_aq_str(hw->aq.asq_last_status), vsi_name);
> + if (!test_and_set_bit(__I40E_VSI_OVERFLOW_PROMISC, vsi->state)) {
> + dev_warn(&vsi->back->pdev->dev,
> + "Error %s, forcing overflow promiscuous on %s\n",
> + libie_aq_str(hw->aq.asq_last_status), vsi_name);
> + }
> }
[Severity: Low]
Two different failure classes now share one single-shot bit. Is that
intended?
i40e_aqc_add_filters() warns when MAC/VLAN filter space is exhausted
(fcnt != num_add, typically LIBIE_AQ_RC_ENOSPC), while
i40e_aqc_broadcast_filter() warns on any AdminQ error returned by
i40e_aq_set_vsi_broadcast() or i40e_aq_set_vsi_bc_promisc_on_vlan(),
including errors that are not ENOSPC, and prints its own
libie_aq_str(hw->aq.asq_last_status) text.
In the scenario from the commit message (bridge vlan add vid 2-4094) the add
path sets __I40E_VSI_OVERFLOW_PROMISC first, so a later
i40e_aqc_broadcast_filter() failure of an unrelated class prints nothing
until the bit is cleared again.
For the delete path in i40e_sync_vsi_filters() the return value is
discarded:
if (is_broadcast_ether_addr(f->macaddr)) {
i40e_aqc_broadcast_filter(vsi, vsi_name, f);
hlist_del(&f->hlist);
kfree(f);
continue;
}
so with the warning suppressed, is that failure reported anywhere at all?
Would a per-site dev_warn_once() style latch, or a separate condition flag
per message, keep both diagnostics?
--
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260901211752.1922993-1-anthony.l.nguyen%40intel.com
^ permalink raw reply [flat|nested] 8+ messages in thread