* [PATCH iwl-next 2/2] i40e: keep track of per queue gso counters.
From: Paolo Abeni @ 2026-04-08 11:43 UTC (permalink / raw)
To: intel-wired-lan
Cc: Tony Nguyen, Przemek Kitszel, Andrew Lunn, David S. Miller,
Eric Dumazet, Jakub Kicinski, Alexei Starovoitov, Daniel Borkmann,
Jesper Dangaard Brouer, John Fastabend, Stanislav Fomichev,
netdev
In-Reply-To: <cover.1775648513.git.pabeni@redhat.com>
Track the number of GSO and wire packets transmitted and expose the
counters via the queue stats.
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
---
drivers/net/ethernet/intel/i40e/i40e.h | 2 ++
drivers/net/ethernet/intel/i40e/i40e_main.c | 13 ++++++++++++-
drivers/net/ethernet/intel/i40e/i40e_txrx.c | 8 +++++++-
drivers/net/ethernet/intel/i40e/i40e_txrx.h | 2 ++
drivers/net/ethernet/intel/i40e/i40e_txrx_common.h | 6 +++++-
drivers/net/ethernet/intel/i40e/i40e_xsk.c | 2 +-
6 files changed, 29 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h
index fe642c464e9c..4a88c7d69f61 100644
--- a/drivers/net/ethernet/intel/i40e/i40e.h
+++ b/drivers/net/ethernet/intel/i40e/i40e.h
@@ -845,6 +845,8 @@ struct i40e_vsi {
u64 tx_stopped_base;
u64 tx_bytes;
u64 tx_packets;
+ u64 tx_gso_packets;
+ u64 tx_gso_wire_packets;
u64 rx_buf_failed;
u64 rx_page_failed;
u64 rx_page_reuse;
diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c
index 0d0b3619ec56..7c2af738ccc5 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_main.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
@@ -11695,6 +11695,8 @@ static void i40e_vsi_aggregate_tx_counters(struct i40e_vsi *vsi,
vsi->tx_bytes += tx_ring->stats.bytes;
vsi->tx_packets += tx_ring->stats.packets;
+ vsi->tx_gso_packets += tx_ring->tx_stats.tx_gso_packets;
+ vsi->tx_gso_wire_packets += tx_ring->tx_stats.tx_gso_wire_packets;
}
static void i40e_vsi_aggregate_rx_counters(struct i40e_vsi *vsi,
@@ -13684,6 +13686,8 @@ static void i40e_zero_tx_ring_stats(struct netdev_queue_stats_tx *tx)
{
tx->bytes = 0;
tx->packets = 0;
+ tx->hw_gso_packets = 0;
+ tx->hw_gso_wire_packets = 0;
tx->stop = 0;
tx->wake = 0;
tx->hw_drops = 0;
@@ -13692,17 +13696,21 @@ static void i40e_zero_tx_ring_stats(struct netdev_queue_stats_tx *tx)
static void i40e_add_tx_ring_stats(struct i40e_ring *tx_ring,
struct netdev_queue_stats_tx *tx)
{
- u64 bytes, packets;
+ u64 bytes, packets, gso_packets, gso_wire_packets;
unsigned int start;
do {
start = u64_stats_fetch_begin(&tx_ring->syncp);
bytes = tx_ring->stats.bytes;
packets = tx_ring->stats.packets;
+ gso_packets = tx_ring->tx_stats.tx_gso_packets;
+ gso_wire_packets = tx_ring->tx_stats.tx_gso_wire_packets;
} while (u64_stats_fetch_retry(&tx_ring->syncp, start));
tx->bytes += bytes;
tx->packets += packets;
+ tx->hw_gso_packets += gso_packets;
+ tx->hw_gso_wire_packets += gso_wire_packets;
tx->stop += tx_ring->tx_stats.tx_stopped;
tx->wake += tx_ring->tx_stats.restart_queue;
@@ -13743,6 +13751,9 @@ static void i40e_get_base_stats(struct net_device *dev,
tx->bytes = vsi->tx_bytes;
tx->packets = vsi->tx_packets;
+ tx->hw_gso_packets = vsi->tx_gso_packets;
+ tx->hw_gso_wire_packets = vsi->tx_gso_wire_packets;
+
tx->wake = vsi->tx_restart_base;
tx->stop = vsi->tx_stopped_base;
tx->hw_drops = vsi->tx_busy_base;
diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c
index 894f2d06d39d..ec61cc43ae39 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c
@@ -928,6 +928,7 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
struct i40e_ring *tx_ring, int napi_budget,
unsigned int *tx_cleaned)
{
+ unsigned int total_gso_packets = 0, total_gso_wire_packets = 0;
int i = tx_ring->next_to_clean;
struct i40e_tx_buffer *tx_buf;
struct i40e_tx_desc *tx_head;
@@ -959,6 +960,10 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
/* update the statistics for this packet */
total_bytes += tx_buf->bytecount;
total_packets += tx_buf->gso_segs;
+ if (tx_buf->gso_segs > 1) {
+ total_gso_packets++;
+ total_gso_wire_packets += tx_buf->gso_segs;
+ }
/* free the skb/XDP data */
if (ring_is_xdp(tx_ring))
@@ -1018,7 +1023,8 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
i += tx_ring->count;
tx_ring->next_to_clean = i;
- i40e_update_tx_stats(tx_ring, total_packets, total_bytes);
+ i40e_update_tx_stats(tx_ring, total_packets, total_bytes,
+ total_gso_packets, total_gso_wire_packets);
i40e_arm_wb(tx_ring, vsi, budget);
if (ring_is_xdp(tx_ring))
diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.h b/drivers/net/ethernet/intel/i40e/i40e_txrx.h
index 1e5fd63d47f4..15c608378467 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_txrx.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.h
@@ -295,6 +295,8 @@ struct i40e_tx_queue_stats {
u64 tx_linearize;
u64 tx_force_wb;
u64 tx_stopped;
+ u64 tx_gso_packets;
+ u64 tx_gso_wire_packets;
int prev_pkt_ctr;
};
diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx_common.h b/drivers/net/ethernet/intel/i40e/i40e_txrx_common.h
index e26807fd2123..24220594ff1a 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_txrx_common.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_txrx_common.h
@@ -45,11 +45,15 @@ static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size,
**/
static inline void i40e_update_tx_stats(struct i40e_ring *tx_ring,
unsigned int total_packets,
- unsigned int total_bytes)
+ unsigned int total_bytes,
+ unsigned int total_gso,
+ unsigned int total_gso_wire)
{
u64_stats_update_begin(&tx_ring->syncp);
tx_ring->stats.bytes += total_bytes;
tx_ring->stats.packets += total_packets;
+ tx_ring->tx_stats.tx_gso_packets += total_gso;
+ tx_ring->tx_stats.tx_gso_wire_packets += total_gso_wire;
u64_stats_update_end(&tx_ring->syncp);
tx_ring->q_vector->tx.total_bytes += total_bytes;
tx_ring->q_vector->tx.total_packets += total_packets;
diff --git a/drivers/net/ethernet/intel/i40e/i40e_xsk.c b/drivers/net/ethernet/intel/i40e/i40e_xsk.c
index 9f47388eaba5..c2a465416a33 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_xsk.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_xsk.c
@@ -599,7 +599,7 @@ static bool i40e_xmit_zc(struct i40e_ring *xdp_ring, unsigned int budget)
i40e_set_rs_bit(xdp_ring);
i40e_xdp_ring_update_tail(xdp_ring);
- i40e_update_tx_stats(xdp_ring, nb_pkts, total_bytes);
+ i40e_update_tx_stats(xdp_ring, nb_pkts, total_bytes, 0, 0);
return nb_pkts < budget;
}
--
2.53.0
^ permalink raw reply related
* Re: [PATCH net] net: phy: micrel: Fix MMD register access during SPD in ksz9131_resume()
From: Geert Uytterhoeven @ 2026-04-08 11:45 UTC (permalink / raw)
To: Ovidiu Panait
Cc: andrew, hkallweit1, linux, davem, edumazet, kuba, pabeni,
biju.das.jz, netdev, linux-kernel, linux-renesas-soc,
Niklas Söderlund
In-Reply-To: <20260403111738.37749-1-ovidiu.panait.rb@renesas.com>
Hi Ovidiu,
On Fri, 3 Apr 2026 at 13:18, Ovidiu Panait <ovidiu.panait.rb@renesas.com> wrote:
> During system suspend, phy_suspend() puts the PHY into Software Power-Down
> (SPD) by setting the BMCR_PDOWN bit in MII_BMCR. According to the KSZ9131
> datasheet, MMD register access is restricted during SPD:
>
> - Only access to the standard registers (0 through 31) is supported.
> - Access to MMD address spaces other than MMD address space 1 is
> possible if the spd_clock_gate_override bit is set.
> - Access to MMD address space 1 is not possible.
>
> However, ksz9131_resume() calls ksz9131_config_rgmii_delay() before
> kszphy_resume() clears BMCR_PDOWN. This means MMD registers are accessed
> while the PHY is still in SPD, contrary to the datasheet.
>
> Additionally, on platforms where the PHY loses power during suspend
> (e.g. RZ/G3E), all settings from ksz9131_config_init(), not just the
> RGMII delays, are lost and need to be restored. When the MAC driver
> sets mac_managed_pm (e.g. stmmac), mdio_bus_phy_resume() is skipped,
> so phy_init_hw() (which calls config_init to restore all PHY settings)
> is never invoked during resume.
>
> Fix this by replacing the RGMII delay restoration with a call to
> phy_init_hw(), which takes the PHY out of SPD and performs full
> reinitialization.
>
> Fixes: f25a7eaa897f ("net: phy: micrel: Add ksz9131_resume()")
> Signed-off-by: Ovidiu Panait <ovidiu.panait.rb@renesas.com>
Thanks for your patch!
> --- a/drivers/net/phy/micrel.c
> +++ b/drivers/net/phy/micrel.c
> @@ -6016,8 +6016,13 @@ static int lan8841_suspend(struct phy_device *phydev)
>
> static int ksz9131_resume(struct phy_device *phydev)
> {
> - if (phydev->suspended && phy_interface_is_rgmii(phydev))
> - ksz9131_config_rgmii_delay(phydev);
> + int ret;
> +
> + if (phydev->suspended) {
> + ret = phy_init_hw(phydev);
> + if (ret)
> + return ret;
> + }
>
> return kszphy_resume(phydev);
> }
This function is now no longer KSZ9131-specific.
I am wondering if this should be done for other Micrel PHYs, too,
e.g. by moving the phy_init_hw() call into kszphy_resume()?
Ethernet after resume has always been flaky on Salvator-X with KSZ9031
and R-Car M3-W ES1.0 (this seems to be specific to R-Car M3-W, as
boards with R-Car H3 or M3-N do not seem to suffer from this; don't
ask me why).
I have just tried:
- .resume = kszphy_resume,
+ .resume = ksz9131_resume,
in the KSZ9031 entry, and ... surprise! Ethernet on R-Car M3-W now
works much better after resume!
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply
* Re: [PATCH 3/3] net: dsa: microchip: implement KSZ87xx Module 3 low-loss cable errata
From: Fidelio LAWSON @ 2026-04-08 11:50 UTC (permalink / raw)
To: Andrew Lunn
Cc: Woojung Huh, UNGLinuxDriver, Vladimir Oltean, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Marek Vasut, Maxime Chevallier,
netdev, devicetree, linux-kernel, Fidelio Lawson
In-Reply-To: <c235ee5c-6057-4c10-9960-9c5a3527bf22@lunn.ch>
On 4/4/26 16:45, Andrew Lunn wrote:
> On Fri, Apr 03, 2026 at 11:43:24AM +0200, Fidelio LAWSON wrote:
>> On 3/26/26 13:18, Andrew Lunn wrote:
>>>> + mutex_lock(&dev->alu_mutex);
>>>> +
>>>> + ret = ksz_write8(dev, regs[REG_IND_CTRL_0], 0xA0);
>>>> +
>>>> + if (!ret)
>>>> + ret = ksz_write8(dev, 0x6F, indir_reg);
>>>> +
>>>> + if (!ret)
>>>> + ret = ksz_write8(dev, regs[REG_IND_BYTE], indir_val);
>>>> +
>>>> + mutex_unlock(&dev->alu_mutex);
>>>
>>> What address space are these registers in? Normally workarounds for a
>>> PHY would be in the PHY driver. But that assumes the registers are
>>> accessible from the PHY driver.
>>>
>>> Andrew
>>
>> Hi Andrew,
>> These registers belong to the KSZ87xx switch address space, accessed through
>> the switch’s indirect access mechanism. In particular, the offsets used here
>> correspond to entries within the TABLE_LINK_MD_V indirect table of the
>> KSZ8-family switches.
>
> So this errata is for ksz87xx only?
>
> For this PHY, do all PHY register reads and writes go through
>
> https://elixir.bootlin.com/linux/v6.19.11/source/drivers/net/dsa/microchip/ksz8.c#L957
> ksz8_r_phy()
>
> and
>
> https://elixir.bootlin.com/linux/v6.19.11/source/drivers/net/dsa/microchip/ksz8.c#L1221
> ksz8_w_phy()?
>
> We already have some "interesting" things going on in these
> functions. PHY_REG_LINK_MD and PHY_REG_PHY_CTRL are not standard C22
> PHY registers. They take the values 0x1d and 0x1f. The 802.3 standard
> defines 0x10-0x1f as vendor specific, so this is O.K.
>
> So you could define 2 bits in say register 0x1c to indicate the errata
> mode. You can have a PHY tunable which does reads/writes to these two
> bits, and ksz8_w_phy/ksz8_r_phy which translates them to indirect
> register accesses?
>
> It is not even really violating the layering.
>
> Andrew
Hi Andrew,
Thanks a lot for the feedback, it was very helpful.
Yes, the erratum affects KSZ87xx devices only, and all accesses to the
embedded PHYs indeed go through ksz8_r_phy() / ksz8_w_phy(), as you
pointed out.
I followed your suggestion and reworked the implementation accordingly:
the errata selection is now modeled as a vendor‑specific Clause 22 PHY
register (0x1c), handled entirely in ksz8_r_phy() / ksz8_w_phy(), which
translate reads and writes into the appropriate indirect TABLE_LINK_MD_V
accesses. This keeps the PHY‑facing API clean without breaking the layering.
I’ve dropped the DT approach and adjusted the implementation based on
the review comments. I’m sending a v2 with these changes shortly.
Thanks again for the guidance.
Best regards,
Fidelio
^ permalink raw reply
* Re: [Intel-wired-lan] [PATCH iwl-next 0/2] i40e: implement per-queue stats
From: Paul Menzel @ 2026-04-08 11:50 UTC (permalink / raw)
To: Paolo Abeni
Cc: intel-wired-lan, Tony Nguyen, Przemek Kitszel, Andrew Lunn,
David S. Miller, Eric Dumazet, Jakub Kicinski, Alexei Starovoitov,
Daniel Borkmann, Jesper Dangaard Brouer, John Fastabend,
Stanislav Fomichev, netdev
In-Reply-To: <cover.1775648513.git.pabeni@redhat.com>
Dear Paolo,
Thank you for your patches.
Am 08.04.26 um 13:43 schrieb Paolo Abeni:
> The i40e driver already collects some per queue statistics, but does
> not expose them to the user-space using the standard interface.
>
> Implement the stat_ops callbacks and extends the already collected info
s/extends/extend/
> with basic GSO counters. Overall this allows passing the kernel NIC
> drivers TSO test cases.
It’d be great, if you added the commands to show the stats, and to run
the test cases.
> Paolo Abeni (2):
> i40e: implement basic per-queue stats
> i40e: keep track of per queue gso counters.
No period needed at the end of the summary/title.
>
> drivers/net/ethernet/intel/i40e/i40e.h | 9 ++
> drivers/net/ethernet/intel/i40e/i40e_main.c | 144 ++++++++++++++++++
> drivers/net/ethernet/intel/i40e/i40e_txrx.c | 8 +-
> drivers/net/ethernet/intel/i40e/i40e_txrx.h | 2 +
> .../ethernet/intel/i40e/i40e_txrx_common.h | 6 +-
> drivers/net/ethernet/intel/i40e/i40e_xsk.c | 2 +-
> 6 files changed, 168 insertions(+), 3 deletions(-)
Kind regards,
Paul
^ permalink raw reply
* [PATCH net v8 0/4] macsec: Add support for VLAN filtering in offload mode
From: Cosmin Ratiu @ 2026-04-08 11:52 UTC (permalink / raw)
To: netdev
Cc: Sabrina Dubroca, Andrew Lunn, David S . Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Stanislav Fomichev,
David Wei, Shuah Khan, linux-kselftest, Cosmin Ratiu,
Dragos Tatulea
This short series adds support for VLANs in MACsec devices when offload
mode is enabled. This allows VLAN netdevs on top of MACsec netdevs to
function, which accidentally used to be the case in the past, but was
broken. This series adds back proper support.
As part of this, the existing nsim-only MACsec offload tests were
translated to Python so they can run against real HW and new
traffic-based tests were added for VLAN filter propagation, since
there's currently no uAPI to check VLAN filters.
---
V8:
- Undo filters on failure when enabling macsec offload and fail the op.
- Used a better string from 'ip macsec help' to detect support.
- Dropped unneded '-d' from the MAC address getter.
- Used os.path.join() instead of manual '+'.
V7: https://lore.kernel.org/netdev/ac5Wt4vWxHMTcsae@krikkit/T/
- Added missing ethtool feature checks.
V6: https://lore.kernel.org/netdev/20260330130130.989236-1-cratiu@nvidia.com/T/#u
- Resurrected nsim debugfs file for VLAN filters.
- Switched to WARN_ON_ONCE in nsim, which is always compiled in.
- Tweaked tests to check the nsim VLAN filter file on nsim.
- Disabled ping on nsim in offload mode, data plane doesn't work.
- Added CONFIG_VLAN_8021Q to the test config.
V5: https://lore.kernel.org/netdev/20260323123633.756163-1-cratiu@nvidia.com/T/#u
- Merged tests and macsec lib in a single file.
- Fixed Python linter issues.
- Added CONFIG_MACSEC to tools/testing/selftests/drivers/net/config
V4: https://lore.kernel.org/netdev/20260313105227.1884391-1-cratiu@nvidia.com/T/#u
- Migrated nsim-only macsec tests to Python, usable against real hw.
- Ran these tests against both nsim and mlx5.
- Gave up on nsim patches since the tests no longer use them.
V3: https://lore.kernel.org/netdev/20260306151004.2862198-1-cratiu@nvidia.com/t/#u
- Moved back to net.
- Added proper rollback support for VLAN filters in case of failure.
- Added VLAN as a requirement for the new macsec tests.
V2: https://lore.kernel.org/netdev/20260227090227.1552512-1-cratiu@nvidia.com/
- Sent to net-next instead of net because of apparent complexity.
- Changed VLAN filtering to only function in offload mode.
- Added tests.
V1: https://lore.kernel.org/netdev/20260107104723.2750725-1-cratiu@nvidia.com/
Cosmin Ratiu (4):
selftests: Migrate nsim-only MACsec tests to Python
nsim: Add support for VLAN filters
selftests: Add MACsec VLAN propagation traffic test
macsec: Support VLAN-filtering lower devices
drivers/net/macsec.c | 71 +++-
drivers/net/netdevsim/netdev.c | 65 +++-
drivers/net/netdevsim/netdevsim.h | 8 +
tools/testing/selftests/drivers/net/Makefile | 1 +
tools/testing/selftests/drivers/net/config | 2 +
.../selftests/drivers/net/lib/py/env.py | 9 +
tools/testing/selftests/drivers/net/macsec.py | 343 ++++++++++++++++++
.../selftests/drivers/net/netdevsim/Makefile | 1 -
.../drivers/net/netdevsim/macsec-offload.sh | 117 ------
9 files changed, 489 insertions(+), 128 deletions(-)
create mode 100755 tools/testing/selftests/drivers/net/macsec.py
delete mode 100755 tools/testing/selftests/drivers/net/netdevsim/macsec-offload.sh
--
2.53.0
^ permalink raw reply
* [PATCH net v8 2/4] nsim: Add support for VLAN filters
From: Cosmin Ratiu @ 2026-04-08 11:52 UTC (permalink / raw)
To: netdev
Cc: Sabrina Dubroca, Andrew Lunn, David S . Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Stanislav Fomichev,
David Wei, Shuah Khan, linux-kselftest, Cosmin Ratiu,
Dragos Tatulea
In-Reply-To: <20260408115240.1636047-1-cratiu@nvidia.com>
Add support for storing the list of VLANs in nsim devices, together with
ops for adding/removing them and a debug file to show them.
This will be used in upcoming tests.
Signed-off-by: Cosmin Ratiu <cratiu@nvidia.com>
---
drivers/net/netdevsim/netdev.c | 65 ++++++++++++++++++++++++++++++-
drivers/net/netdevsim/netdevsim.h | 8 ++++
2 files changed, 71 insertions(+), 2 deletions(-)
diff --git a/drivers/net/netdevsim/netdev.c b/drivers/net/netdevsim/netdev.c
index 3645ebde049a..19b0ff183c45 100644
--- a/drivers/net/netdevsim/netdev.c
+++ b/drivers/net/netdevsim/netdev.c
@@ -605,6 +605,36 @@ static int nsim_stop(struct net_device *dev)
return 0;
}
+static int nsim_vlan_rx_add_vid(struct net_device *dev, __be16 proto, u16 vid)
+{
+ struct netdevsim *ns = netdev_priv(dev);
+
+ if (vid >= VLAN_N_VID)
+ return -EINVAL;
+
+ if (proto == htons(ETH_P_8021Q))
+ WARN_ON_ONCE(test_and_set_bit(vid, ns->vlan.ctag));
+ else if (proto == htons(ETH_P_8021AD))
+ WARN_ON_ONCE(test_and_set_bit(vid, ns->vlan.stag));
+
+ return 0;
+}
+
+static int nsim_vlan_rx_kill_vid(struct net_device *dev, __be16 proto, u16 vid)
+{
+ struct netdevsim *ns = netdev_priv(dev);
+
+ if (vid >= VLAN_N_VID)
+ return -EINVAL;
+
+ if (proto == htons(ETH_P_8021Q))
+ WARN_ON_ONCE(!test_and_clear_bit(vid, ns->vlan.ctag));
+ else if (proto == htons(ETH_P_8021AD))
+ WARN_ON_ONCE(!test_and_clear_bit(vid, ns->vlan.stag));
+
+ return 0;
+}
+
static int nsim_shaper_set(struct net_shaper_binding *binding,
const struct net_shaper *shaper,
struct netlink_ext_ack *extack)
@@ -662,6 +692,8 @@ static const struct net_device_ops nsim_netdev_ops = {
.ndo_bpf = nsim_bpf,
.ndo_open = nsim_open,
.ndo_stop = nsim_stop,
+ .ndo_vlan_rx_add_vid = nsim_vlan_rx_add_vid,
+ .ndo_vlan_rx_kill_vid = nsim_vlan_rx_kill_vid,
.net_shaper_ops = &nsim_shaper_ops,
};
@@ -673,6 +705,8 @@ static const struct net_device_ops nsim_vf_netdev_ops = {
.ndo_change_mtu = nsim_change_mtu,
.ndo_setup_tc = nsim_setup_tc,
.ndo_set_features = nsim_set_features,
+ .ndo_vlan_rx_add_vid = nsim_vlan_rx_add_vid,
+ .ndo_vlan_rx_kill_vid = nsim_vlan_rx_kill_vid,
};
/* We don't have true per-queue stats, yet, so do some random fakery here.
@@ -970,6 +1004,20 @@ static const struct file_operations nsim_pp_hold_fops = {
.owner = THIS_MODULE,
};
+static int nsim_vlan_show(struct seq_file *s, void *data)
+{
+ struct netdevsim *ns = s->private;
+ int vid;
+
+ for_each_set_bit(vid, ns->vlan.ctag, VLAN_N_VID)
+ seq_printf(s, "ctag %d\n", vid);
+ for_each_set_bit(vid, ns->vlan.stag, VLAN_N_VID)
+ seq_printf(s, "stag %d\n", vid);
+
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(nsim_vlan);
+
static void nsim_setup(struct net_device *dev)
{
ether_setup(dev);
@@ -982,14 +1030,18 @@ static void nsim_setup(struct net_device *dev)
NETIF_F_FRAGLIST |
NETIF_F_HW_CSUM |
NETIF_F_LRO |
- NETIF_F_TSO;
+ NETIF_F_TSO |
+ NETIF_F_HW_VLAN_CTAG_FILTER |
+ NETIF_F_HW_VLAN_STAG_FILTER;
dev->hw_features |= NETIF_F_HW_TC |
NETIF_F_SG |
NETIF_F_FRAGLIST |
NETIF_F_HW_CSUM |
NETIF_F_LRO |
NETIF_F_TSO |
- NETIF_F_LOOPBACK;
+ NETIF_F_LOOPBACK |
+ NETIF_F_HW_VLAN_CTAG_FILTER |
+ NETIF_F_HW_VLAN_STAG_FILTER;
dev->pcpu_stat_type = NETDEV_PCPU_STAT_DSTATS;
dev->max_mtu = ETH_MAX_MTU;
dev->xdp_features = NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_HW_OFFLOAD;
@@ -1156,6 +1208,8 @@ struct netdevsim *nsim_create(struct nsim_dev *nsim_dev,
ns->qr_dfs = debugfs_create_file("queue_reset", 0200,
nsim_dev_port->ddir, ns,
&nsim_qreset_fops);
+ ns->vlan_dfs = debugfs_create_file("vlan", 0400, nsim_dev_port->ddir,
+ ns, &nsim_vlan_fops);
return ns;
err_free_netdev:
@@ -1167,7 +1221,9 @@ void nsim_destroy(struct netdevsim *ns)
{
struct net_device *dev = ns->netdev;
struct netdevsim *peer;
+ u16 vid;
+ debugfs_remove(ns->vlan_dfs);
debugfs_remove(ns->qr_dfs);
debugfs_remove(ns->pp_dfs);
@@ -1193,6 +1249,11 @@ void nsim_destroy(struct netdevsim *ns)
if (nsim_dev_port_is_pf(ns->nsim_dev_port))
nsim_exit_netdevsim(ns);
+ for_each_set_bit(vid, ns->vlan.ctag, VLAN_N_VID)
+ WARN_ON_ONCE(1);
+ for_each_set_bit(vid, ns->vlan.stag, VLAN_N_VID)
+ WARN_ON_ONCE(1);
+
/* Put this intentionally late to exercise the orphaning path */
if (ns->page) {
page_pool_put_full_page(pp_page_to_nmdesc(ns->page)->pp,
diff --git a/drivers/net/netdevsim/netdevsim.h b/drivers/net/netdevsim/netdevsim.h
index f767fc8a7505..f844c27ca78b 100644
--- a/drivers/net/netdevsim/netdevsim.h
+++ b/drivers/net/netdevsim/netdevsim.h
@@ -18,6 +18,7 @@
#include <linux/ethtool.h>
#include <linux/ethtool_netlink.h>
#include <linux/kernel.h>
+#include <linux/if_vlan.h>
#include <linux/list.h>
#include <linux/netdevice.h>
#include <linux/ptp_mock.h>
@@ -75,6 +76,11 @@ struct nsim_macsec {
u8 nsim_secy_count;
};
+struct nsim_vlan {
+ DECLARE_BITMAP(ctag, VLAN_N_VID);
+ DECLARE_BITMAP(stag, VLAN_N_VID);
+};
+
struct nsim_ethtool_pauseparam {
bool rx;
bool tx;
@@ -135,6 +141,7 @@ struct netdevsim {
bool bpf_map_accept;
struct nsim_ipsec ipsec;
struct nsim_macsec macsec;
+ struct nsim_vlan vlan;
struct {
u32 inject_error;
u32 __ports[2][NSIM_UDP_TUNNEL_N_PORTS];
@@ -146,6 +153,7 @@ struct netdevsim {
struct page *page;
struct dentry *pp_dfs;
struct dentry *qr_dfs;
+ struct dentry *vlan_dfs;
struct nsim_ethtool ethtool;
struct netdevsim __rcu *peer;
--
2.53.0
^ permalink raw reply related
* [PATCH net v8 1/4] selftests: Migrate nsim-only MACsec tests to Python
From: Cosmin Ratiu @ 2026-04-08 11:52 UTC (permalink / raw)
To: netdev
Cc: Sabrina Dubroca, Andrew Lunn, David S . Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Stanislav Fomichev,
David Wei, Shuah Khan, linux-kselftest, Cosmin Ratiu,
Dragos Tatulea
In-Reply-To: <20260408115240.1636047-1-cratiu@nvidia.com>
Move MACsec offload API and ethtool feature tests from
tools/testing/selftests/drivers/net/netdevsim/macsec-offload.sh to
tools/testing/selftests/drivers/net/macsec.py using the NetDrvEnv
framework so tests can run against both netdevsim (default) and real
hardware (NETIF=ethX). As some real hardware requires MACsec to use
encryption, add that to the tests.
Netdevsim-specific limit checks (max SecY, max RX SC) were moved into
separate test cases to avoid failures on real hardware.
Signed-off-by: Cosmin Ratiu <cratiu@nvidia.com>
---
tools/testing/selftests/drivers/net/Makefile | 1 +
tools/testing/selftests/drivers/net/config | 1 +
tools/testing/selftests/drivers/net/macsec.py | 202 ++++++++++++++++++
.../selftests/drivers/net/netdevsim/Makefile | 1 -
.../drivers/net/netdevsim/macsec-offload.sh | 117 ----------
5 files changed, 204 insertions(+), 118 deletions(-)
create mode 100755 tools/testing/selftests/drivers/net/macsec.py
delete mode 100755 tools/testing/selftests/drivers/net/netdevsim/macsec-offload.sh
diff --git a/tools/testing/selftests/drivers/net/Makefile b/tools/testing/selftests/drivers/net/Makefile
index 8154d6d429d3..5e045dde0273 100644
--- a/tools/testing/selftests/drivers/net/Makefile
+++ b/tools/testing/selftests/drivers/net/Makefile
@@ -13,6 +13,7 @@ TEST_GEN_FILES := \
TEST_PROGS := \
gro.py \
hds.py \
+ macsec.py \
napi_id.py \
napi_threaded.py \
netpoll_basic.py \
diff --git a/tools/testing/selftests/drivers/net/config b/tools/testing/selftests/drivers/net/config
index 77ccf83d87e0..d4b31a317c09 100644
--- a/tools/testing/selftests/drivers/net/config
+++ b/tools/testing/selftests/drivers/net/config
@@ -3,6 +3,7 @@ CONFIG_DEBUG_INFO_BTF=y
CONFIG_DEBUG_INFO_BTF_MODULES=n
CONFIG_INET_PSP=y
CONFIG_IPV6=y
+CONFIG_MACSEC=m
CONFIG_NETCONSOLE=m
CONFIG_NETCONSOLE_DYNAMIC=y
CONFIG_NETCONSOLE_EXTENDED_LOG=y
diff --git a/tools/testing/selftests/drivers/net/macsec.py b/tools/testing/selftests/drivers/net/macsec.py
new file mode 100755
index 000000000000..5220c0656c0c
--- /dev/null
+++ b/tools/testing/selftests/drivers/net/macsec.py
@@ -0,0 +1,202 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0
+
+"""MACsec tests."""
+
+import os
+
+from lib.py import ksft_run, ksft_exit, ksft_eq, ksft_raises
+from lib.py import CmdExitFailure, KsftSkipEx
+from lib.py import NetDrvEpEnv
+from lib.py import cmd, ip, defer, ethtool
+
+# Unique prefix per run to avoid collisions in the shared netns.
+# Keep it short: IFNAMSIZ is 16 (incl. NUL), and VLAN names append ".<vid>".
+MACSEC_PFX = f"ms{os.getpid()}_"
+
+
+def _macsec_name(idx=0):
+ return f"{MACSEC_PFX}{idx}"
+
+
+def _get_macsec_offload(dev):
+ """Returns macsec offload mode string from ip -d link show."""
+ info = ip(f"-d link show dev {dev}", json=True)[0]
+ return info.get("linkinfo", {}).get("info_data", {}).get("offload")
+
+
+def _get_features(dev):
+ """Returns ethtool features dict for a device."""
+ return ethtool(f"-k {dev}", json=True)[0]
+
+
+def _require_ip_macsec(cfg):
+ """SKIP if iproute2 on local or remote lacks 'ip macsec' support."""
+ for host in [None, cfg.remote]:
+ out = cmd("ip macsec help", fail=False, host=host)
+ if "Usage" not in out.stdout + out.stderr:
+ where = "remote" if host else "local"
+ raise KsftSkipEx(f"iproute2 too old on {where},"
+ " missing macsec support")
+
+
+def _require_ip_macsec_offload():
+ """SKIP if local iproute2 doesn't understand 'ip macsec offload'."""
+ out = cmd("ip macsec help", fail=False)
+ if "offload" not in out.stdout + out.stderr:
+ raise KsftSkipEx("iproute2 too old, missing macsec offload")
+
+
+def _require_macsec_offload(cfg):
+ """SKIP if local device doesn't support macsec-hw-offload."""
+ _require_ip_macsec_offload()
+ try:
+ feat = ethtool(f"-k {cfg.ifname}", json=True)[0]
+ except (CmdExitFailure, IndexError) as e:
+ raise KsftSkipEx(
+ f"can't query features: {e}") from e
+ if not feat.get("macsec-hw-offload", {}).get("active"):
+ raise KsftSkipEx("macsec-hw-offload not supported")
+
+
+def test_offload_api(cfg) -> None:
+ """MACsec offload API: create SecY, add SA/rx, toggle offload."""
+
+ _require_macsec_offload(cfg)
+ ms0 = _macsec_name(0)
+ ms1 = _macsec_name(1)
+ ms2 = _macsec_name(2)
+
+ # Create 3 SecY with offload
+ ip(f"link add link {cfg.ifname} {ms0} type macsec "
+ f"port 4 encrypt on offload mac")
+ defer(ip, f"link del {ms0}")
+
+ ip(f"link add link {cfg.ifname} {ms1} type macsec "
+ f"address aa:bb:cc:dd:ee:ff port 5 encrypt on offload mac")
+ defer(ip, f"link del {ms1}")
+
+ ip(f"link add link {cfg.ifname} {ms2} type macsec "
+ f"sci abbacdde01020304 encrypt on offload mac")
+ defer(ip, f"link del {ms2}")
+
+ # Add TX SA
+ ip(f"macsec add {ms0} tx sa 0 pn 1024 on "
+ "key 01 12345678901234567890123456789012")
+
+ # Add RX SC + SA
+ ip(f"macsec add {ms0} rx port 1234 address 1c:ed:de:ad:be:ef")
+ ip(f"macsec add {ms0} rx port 1234 address 1c:ed:de:ad:be:ef "
+ "sa 0 pn 1 on key 00 0123456789abcdef0123456789abcdef")
+
+ # Can't disable offload when SAs are configured
+ with ksft_raises(CmdExitFailure):
+ ip(f"link set {ms0} type macsec offload off")
+ with ksft_raises(CmdExitFailure):
+ ip(f"macsec offload {ms0} off")
+
+ # Toggle offload via rtnetlink on SA-free device
+ ip(f"link set {ms2} type macsec offload off")
+ ip(f"link set {ms2} type macsec encrypt on offload mac")
+
+ # Toggle offload via genetlink
+ ip(f"macsec offload {ms2} off")
+ ip(f"macsec offload {ms2} mac")
+
+
+def test_max_secy(cfg) -> None:
+ """nsim-only test for max number of SecYs."""
+
+ cfg.require_nsim()
+ _require_ip_macsec_offload()
+ ms0 = _macsec_name(0)
+ ms1 = _macsec_name(1)
+ ms2 = _macsec_name(2)
+ ms3 = _macsec_name(3)
+
+ ip(f"link add link {cfg.ifname} {ms0} type macsec "
+ f"port 4 encrypt on offload mac")
+ defer(ip, f"link del {ms0}")
+
+ ip(f"link add link {cfg.ifname} {ms1} type macsec "
+ f"address aa:bb:cc:dd:ee:ff port 5 encrypt on offload mac")
+ defer(ip, f"link del {ms1}")
+
+ ip(f"link add link {cfg.ifname} {ms2} type macsec "
+ f"sci abbacdde01020304 encrypt on offload mac")
+ defer(ip, f"link del {ms2}")
+ with ksft_raises(CmdExitFailure):
+ ip(f"link add link {cfg.ifname} {ms3} "
+ f"type macsec port 8 encrypt on offload mac")
+
+
+def test_max_sc(cfg) -> None:
+ """nsim-only test for max number of SCs."""
+
+ cfg.require_nsim()
+ _require_ip_macsec_offload()
+ ms0 = _macsec_name(0)
+
+ ip(f"link add link {cfg.ifname} {ms0} type macsec "
+ f"port 4 encrypt on offload mac")
+ defer(ip, f"link del {ms0}")
+ ip(f"macsec add {ms0} rx port 1234 address 1c:ed:de:ad:be:ef")
+ with ksft_raises(CmdExitFailure):
+ ip(f"macsec add {ms0} rx port 1235 address 1c:ed:de:ad:be:ef")
+
+
+def test_offload_state(cfg) -> None:
+ """Offload state reflects configuration changes."""
+
+ _require_macsec_offload(cfg)
+ ms0 = _macsec_name(0)
+
+ # Create with offload on
+ ip(f"link add link {cfg.ifname} {ms0} type macsec "
+ f"encrypt on offload mac")
+ cleanup = defer(ip, f"link del {ms0}")
+
+ ksft_eq(_get_macsec_offload(ms0), "mac",
+ "created with offload: should be mac")
+ feats_on_1 = _get_features(ms0)
+
+ ip(f"link set {ms0} type macsec offload off")
+ ksft_eq(_get_macsec_offload(ms0), "off",
+ "offload disabled: should be off")
+ feats_off_1 = _get_features(ms0)
+
+ ip(f"link set {ms0} type macsec encrypt on offload mac")
+ ksft_eq(_get_macsec_offload(ms0), "mac",
+ "offload re-enabled: should be mac")
+ ksft_eq(_get_features(ms0), feats_on_1,
+ "features should match first offload-on snapshot")
+
+ # Delete and recreate without offload
+ cleanup.exec()
+ ip(f"link add link {cfg.ifname} {ms0} type macsec")
+ defer(ip, f"link del {ms0}")
+ ksft_eq(_get_macsec_offload(ms0), "off",
+ "created without offload: should be off")
+ ksft_eq(_get_features(ms0), feats_off_1,
+ "features should match first offload-off snapshot")
+
+ ip(f"link set {ms0} type macsec encrypt on offload mac")
+ ksft_eq(_get_macsec_offload(ms0), "mac",
+ "offload enabled after create: should be mac")
+ ksft_eq(_get_features(ms0), feats_on_1,
+ "features should match first offload-on snapshot")
+
+
+def main() -> None:
+ """Main program."""
+ with NetDrvEpEnv(__file__) as cfg:
+ ksft_run([test_offload_api,
+ test_max_secy,
+ test_max_sc,
+ test_offload_state,
+ ], args=(cfg,))
+ ksft_exit()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/tools/testing/selftests/drivers/net/netdevsim/Makefile b/tools/testing/selftests/drivers/net/netdevsim/Makefile
index 1a228c5430f5..9808c2fbae9e 100644
--- a/tools/testing/selftests/drivers/net/netdevsim/Makefile
+++ b/tools/testing/selftests/drivers/net/netdevsim/Makefile
@@ -11,7 +11,6 @@ TEST_PROGS := \
fib.sh \
fib_notifications.sh \
hw_stats_l3.sh \
- macsec-offload.sh \
nexthop.sh \
peer.sh \
psample.sh \
diff --git a/tools/testing/selftests/drivers/net/netdevsim/macsec-offload.sh b/tools/testing/selftests/drivers/net/netdevsim/macsec-offload.sh
deleted file mode 100755
index 98033e6667d2..000000000000
--- a/tools/testing/selftests/drivers/net/netdevsim/macsec-offload.sh
+++ /dev/null
@@ -1,117 +0,0 @@
-#!/bin/bash
-# SPDX-License-Identifier: GPL-2.0-only
-
-source ethtool-common.sh
-
-NSIM_NETDEV=$(make_netdev)
-MACSEC_NETDEV=macsec_nsim
-
-set -o pipefail
-
-if ! ethtool -k $NSIM_NETDEV | grep -q 'macsec-hw-offload: on'; then
- echo "SKIP: netdevsim doesn't support MACsec offload"
- exit 4
-fi
-
-if ! ip link add link $NSIM_NETDEV $MACSEC_NETDEV type macsec offload mac 2>/dev/null; then
- echo "SKIP: couldn't create macsec device"
- exit 4
-fi
-ip link del $MACSEC_NETDEV
-
-#
-# test macsec offload API
-#
-
-ip link add link $NSIM_NETDEV "${MACSEC_NETDEV}" type macsec port 4 offload mac
-check $?
-
-ip link add link $NSIM_NETDEV "${MACSEC_NETDEV}2" type macsec address "aa:bb:cc:dd:ee:ff" port 5 offload mac
-check $?
-
-ip link add link $NSIM_NETDEV "${MACSEC_NETDEV}3" type macsec sci abbacdde01020304 offload mac
-check $?
-
-ip link add link $NSIM_NETDEV "${MACSEC_NETDEV}4" type macsec port 8 offload mac 2> /dev/null
-check $? '' '' 1
-
-ip macsec add "${MACSEC_NETDEV}" tx sa 0 pn 1024 on key 01 12345678901234567890123456789012
-check $?
-
-ip macsec add "${MACSEC_NETDEV}" rx port 1234 address "1c:ed:de:ad:be:ef"
-check $?
-
-ip macsec add "${MACSEC_NETDEV}" rx port 1234 address "1c:ed:de:ad:be:ef" sa 0 pn 1 on \
- key 00 0123456789abcdef0123456789abcdef
-check $?
-
-ip macsec add "${MACSEC_NETDEV}" rx port 1235 address "1c:ed:de:ad:be:ef" 2> /dev/null
-check $? '' '' 1
-
-# can't disable macsec offload when SAs are configured
-ip link set "${MACSEC_NETDEV}" type macsec offload off 2> /dev/null
-check $? '' '' 1
-
-ip macsec offload "${MACSEC_NETDEV}" off 2> /dev/null
-check $? '' '' 1
-
-# toggle macsec offload via rtnetlink
-ip link set "${MACSEC_NETDEV}2" type macsec offload off
-check $?
-
-ip link set "${MACSEC_NETDEV}2" type macsec offload mac
-check $?
-
-# toggle macsec offload via genetlink
-ip macsec offload "${MACSEC_NETDEV}2" off
-check $?
-
-ip macsec offload "${MACSEC_NETDEV}2" mac
-check $?
-
-for dev in ${MACSEC_NETDEV}{,2,3} ; do
- ip link del $dev
- check $?
-done
-
-
-#
-# test ethtool features when toggling offload
-#
-
-ip link add link $NSIM_NETDEV $MACSEC_NETDEV type macsec offload mac
-TMP_FEATS_ON_1="$(ethtool -k $MACSEC_NETDEV)"
-
-ip link set $MACSEC_NETDEV type macsec offload off
-TMP_FEATS_OFF_1="$(ethtool -k $MACSEC_NETDEV)"
-
-ip link set $MACSEC_NETDEV type macsec offload mac
-TMP_FEATS_ON_2="$(ethtool -k $MACSEC_NETDEV)"
-
-[ "$TMP_FEATS_ON_1" = "$TMP_FEATS_ON_2" ]
-check $?
-
-ip link del $MACSEC_NETDEV
-
-ip link add link $NSIM_NETDEV $MACSEC_NETDEV type macsec
-check $?
-
-TMP_FEATS_OFF_2="$(ethtool -k $MACSEC_NETDEV)"
-[ "$TMP_FEATS_OFF_1" = "$TMP_FEATS_OFF_2" ]
-check $?
-
-ip link set $MACSEC_NETDEV type macsec offload mac
-check $?
-
-TMP_FEATS_ON_3="$(ethtool -k $MACSEC_NETDEV)"
-[ "$TMP_FEATS_ON_1" = "$TMP_FEATS_ON_3" ]
-check $?
-
-
-if [ $num_errors -eq 0 ]; then
- echo "PASSED all $((num_passes)) checks"
- exit 0
-else
- echo "FAILED $num_errors/$((num_errors+num_passes)) checks"
- exit 1
-fi
--
2.53.0
^ permalink raw reply related
* [PATCH net v8 3/4] selftests: Add MACsec VLAN propagation traffic test
From: Cosmin Ratiu @ 2026-04-08 11:52 UTC (permalink / raw)
To: netdev
Cc: Sabrina Dubroca, Andrew Lunn, David S . Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Stanislav Fomichev,
David Wei, Shuah Khan, linux-kselftest, Cosmin Ratiu,
Dragos Tatulea
In-Reply-To: <20260408115240.1636047-1-cratiu@nvidia.com>
Add VLAN filter propagation tests through offloaded MACsec devices via
actual traffic.
The tests create MACsec tunnels with matching SAs on both endpoints,
stack VLANs on top, and verify connectivity with ping. Covered:
- Offloaded MACsec with VLAN (filters propagate to HW)
- Software MACsec with VLAN (no HW filter propagation)
- Offload on/off toggle and verifying traffic still works
On netdevsim this makes use of the VLAN filter debugfs file to actually
validate that filters are applied/removed correctly.
On real hardware the traffic should validate actual VLAN filter
propagation.
Signed-off-by: Cosmin Ratiu <cratiu@nvidia.com>
---
tools/testing/selftests/drivers/net/config | 1 +
.../selftests/drivers/net/lib/py/env.py | 9 ++
tools/testing/selftests/drivers/net/macsec.py | 141 ++++++++++++++++++
3 files changed, 151 insertions(+)
diff --git a/tools/testing/selftests/drivers/net/config b/tools/testing/selftests/drivers/net/config
index d4b31a317c09..fd16994366f4 100644
--- a/tools/testing/selftests/drivers/net/config
+++ b/tools/testing/selftests/drivers/net/config
@@ -8,4 +8,5 @@ CONFIG_NETCONSOLE=m
CONFIG_NETCONSOLE_DYNAMIC=y
CONFIG_NETCONSOLE_EXTENDED_LOG=y
CONFIG_NETDEVSIM=m
+CONFIG_VLAN_8021Q=m
CONFIG_XDP_SOCKETS=y
diff --git a/tools/testing/selftests/drivers/net/lib/py/env.py b/tools/testing/selftests/drivers/net/lib/py/env.py
index 41cc248ac848..b80666277e36 100644
--- a/tools/testing/selftests/drivers/net/lib/py/env.py
+++ b/tools/testing/selftests/drivers/net/lib/py/env.py
@@ -255,6 +255,15 @@ class NetDrvEpEnv(NetDrvEnvBase):
if nsim_test is False and self._ns is not None:
raise KsftXfailEx("Test does not work on netdevsim")
+ def get_local_nsim_dev(self):
+ """Returns the local netdevsim device or None.
+ Using this method is discouraged, as it makes tests nsim-specific.
+ Standard interfaces available on all HW should ideally be used.
+ This method is intended for the few cases where nsim-specific
+ assertions need to be verified which cannot be verified otherwise.
+ """
+ return self._ns
+
def _require_cmd(self, comm, key, host=None):
cached = self._required_cmd.get(comm, {})
if cached.get(key) is None:
diff --git a/tools/testing/selftests/drivers/net/macsec.py b/tools/testing/selftests/drivers/net/macsec.py
index 5220c0656c0c..9a83d9542e04 100755
--- a/tools/testing/selftests/drivers/net/macsec.py
+++ b/tools/testing/selftests/drivers/net/macsec.py
@@ -6,10 +6,14 @@
import os
from lib.py import ksft_run, ksft_exit, ksft_eq, ksft_raises
+from lib.py import ksft_variants, KsftNamedVariant
from lib.py import CmdExitFailure, KsftSkipEx
from lib.py import NetDrvEpEnv
from lib.py import cmd, ip, defer, ethtool
+MACSEC_KEY = "12345678901234567890123456789012"
+MACSEC_VLAN_VID = 10
+
# Unique prefix per run to avoid collisions in the shared netns.
# Keep it short: IFNAMSIZ is 16 (incl. NUL), and VLAN names append ".<vid>".
MACSEC_PFX = f"ms{os.getpid()}_"
@@ -59,6 +63,78 @@ def _require_macsec_offload(cfg):
raise KsftSkipEx("macsec-hw-offload not supported")
+def _get_mac(ifname, host=None):
+ """Gets MAC address of an interface."""
+ dev = ip(f"link show dev {ifname}", json=True, host=host)
+ return dev[0]["address"]
+
+
+def _setup_macsec_sa(cfg, name):
+ """Adds matching TX/RX SAs on both ends."""
+ local_mac = _get_mac(name)
+ remote_mac = _get_mac(name, host=cfg.remote)
+
+ ip(f"macsec add {name} tx sa 0 pn 1 on key 01 {MACSEC_KEY}")
+ ip(f"macsec add {name} rx port 1 address {remote_mac}")
+ ip(f"macsec add {name} rx port 1 address {remote_mac} "
+ f"sa 0 pn 1 on key 02 {MACSEC_KEY}")
+
+ ip(f"macsec add {name} tx sa 0 pn 1 on key 02 {MACSEC_KEY}",
+ host=cfg.remote)
+ ip(f"macsec add {name} rx port 1 address {local_mac}", host=cfg.remote)
+ ip(f"macsec add {name} rx port 1 address {local_mac} "
+ f"sa 0 pn 1 on key 01 {MACSEC_KEY}", host=cfg.remote)
+
+
+def _setup_macsec_devs(cfg, name, offload):
+ """Creates macsec devices on both ends.
+
+ Only the local device gets HW offload; the remote always uses software
+ MACsec since it may not support offload at all.
+ """
+ offload_arg = "mac" if offload else "off"
+
+ ip(f"link add link {cfg.ifname} {name} "
+ f"type macsec encrypt on offload {offload_arg}")
+ defer(ip, f"link del {name}")
+ ip(f"link add link {cfg.remote_ifname} {name} "
+ f"type macsec encrypt on", host=cfg.remote)
+ defer(ip, f"link del {name}", host=cfg.remote)
+
+
+def _set_offload(name, offload):
+ """Sets offload on the local macsec device only."""
+ offload_arg = "mac" if offload else "off"
+
+ ip(f"link set {name} type macsec encrypt on offload {offload_arg}")
+
+
+def _setup_vlans(cfg, name, vid):
+ """Adds VLANs on top of existing macsec devs."""
+ vlan_name = f"{name}.{vid}"
+
+ ip(f"link add link {name} {vlan_name} type vlan id {vid}")
+ defer(ip, f"link del {vlan_name}")
+ ip(f"link add link {name} {vlan_name} type vlan id {vid}", host=cfg.remote)
+ defer(ip, f"link del {vlan_name}", host=cfg.remote)
+
+
+def _setup_vlan_ips(cfg, name, vid):
+ """Adds VLANs and IPs and brings up the macsec + VLAN devices."""
+ local_ip = "198.51.100.1"
+ remote_ip = "198.51.100.2"
+ vlan_name = f"{name}.{vid}"
+
+ ip(f"addr add {local_ip}/24 dev {vlan_name}")
+ ip(f"addr add {remote_ip}/24 dev {vlan_name}", host=cfg.remote)
+ ip(f"link set {name} up")
+ ip(f"link set {name} up", host=cfg.remote)
+ ip(f"link set {vlan_name} up")
+ ip(f"link set {vlan_name} up", host=cfg.remote)
+
+ return vlan_name, remote_ip
+
+
def test_offload_api(cfg) -> None:
"""MACsec offload API: create SecY, add SA/rx, toggle offload."""
@@ -187,6 +263,69 @@ def test_offload_state(cfg) -> None:
"features should match first offload-on snapshot")
+def _check_nsim_vid(cfg, vid, expected) -> None:
+ """Checks if a VLAN is present. Only works on netdevsim."""
+
+ nsim = cfg.get_local_nsim_dev()
+ if not nsim:
+ return
+
+ vlan_path = os.path.join(nsim.nsims[0].dfs_dir, "vlan")
+ with open(vlan_path, encoding="utf-8") as f:
+ vids = f.read()
+ found = f"ctag {vid}\n" in vids
+ ksft_eq(found, expected,
+ f"VLAN {vid} {'expected' if expected else 'not expected'}"
+ f" in debugfs")
+
+
+@ksft_variants([
+ KsftNamedVariant("offloaded", True),
+ KsftNamedVariant("software", False),
+])
+def test_vlan(cfg, offload) -> None:
+ """Ping through VLAN-over-macsec."""
+
+ _require_ip_macsec(cfg)
+ if offload:
+ _require_macsec_offload(cfg)
+ else:
+ _require_ip_macsec_offload()
+ name = _macsec_name()
+ _setup_macsec_devs(cfg, name, offload=offload)
+ _setup_macsec_sa(cfg, name)
+ _setup_vlans(cfg, name, MACSEC_VLAN_VID)
+ vlan_name, remote_ip = _setup_vlan_ips(cfg, name, MACSEC_VLAN_VID)
+ _check_nsim_vid(cfg, MACSEC_VLAN_VID, offload)
+ # nsim doesn't handle the data path for offloaded macsec, so skip
+ # the ping when offloaded on nsim.
+ if not offload or not cfg.get_local_nsim_dev():
+ cmd(f"ping -I {vlan_name} -c 1 -W 5 {remote_ip}")
+
+
+@ksft_variants([
+ KsftNamedVariant("on_to_off", True),
+ KsftNamedVariant("off_to_on", False),
+])
+def test_vlan_toggle(cfg, offload) -> None:
+ """Toggle offload: VLAN filters propagate/remove correctly."""
+
+ _require_ip_macsec(cfg)
+ _require_macsec_offload(cfg)
+ name = _macsec_name()
+ _setup_macsec_devs(cfg, name, offload=offload)
+ _setup_vlans(cfg, name, MACSEC_VLAN_VID)
+ _check_nsim_vid(cfg, MACSEC_VLAN_VID, offload)
+ _set_offload(name, offload=not offload)
+ _check_nsim_vid(cfg, MACSEC_VLAN_VID, not offload)
+ vlan_name, remote_ip = _setup_vlan_ips(cfg, name, MACSEC_VLAN_VID)
+ _setup_macsec_sa(cfg, name)
+ # nsim doesn't handle the data path for offloaded macsec, so skip
+ # the ping when the final state is offloaded on nsim.
+ if offload or not cfg.get_local_nsim_dev():
+ cmd(f"ping -I {vlan_name} -c 1 -W 5 {remote_ip}")
+
+
def main() -> None:
"""Main program."""
with NetDrvEpEnv(__file__) as cfg:
@@ -194,6 +333,8 @@ def main() -> None:
test_max_secy,
test_max_sc,
test_offload_state,
+ test_vlan,
+ test_vlan_toggle,
], args=(cfg,))
ksft_exit()
--
2.53.0
^ permalink raw reply related
* [PATCH net v8 4/4] macsec: Support VLAN-filtering lower devices
From: Cosmin Ratiu @ 2026-04-08 11:52 UTC (permalink / raw)
To: netdev
Cc: Sabrina Dubroca, Andrew Lunn, David S . Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Stanislav Fomichev,
David Wei, Shuah Khan, linux-kselftest, Cosmin Ratiu,
Dragos Tatulea
In-Reply-To: <20260408115240.1636047-1-cratiu@nvidia.com>
VLAN-filtering is done through two netdev features
(NETIF_F_HW_VLAN_CTAG_FILTER and NETIF_F_HW_VLAN_STAG_FILTER) and two
netdev ops (ndo_vlan_rx_add_vid and ndo_vlan_rx_kill_vid).
Implement these and advertise the features if the lower device supports
them. This allows proper VLAN filtering to work on top of MACsec
devices, when the lower device is capable of VLAN filtering.
As a concrete example, having this chain of interfaces now works:
vlan_filtering_capable_dev(1) -> macsec_dev(2) -> macsec_vlan_dev(3)
Before the mentioned commit this used to accidentally work because the
MACsec device (and thus the lower device) was put in promiscuous mode
and the VLAN filter was not used. But after commit [1] correctly made
the macsec driver expose the IFF_UNICAST_FLT flag, promiscuous mode was
no longer used and VLAN filters on dev 1 kicked in. Without support in
dev 2 for propagating VLAN filters down, the register_vlan_dev ->
vlan_vid_add -> __vlan_vid_add -> vlan_add_rx_filter_info call from dev
3 is silently eaten (because vlan_hw_filter_capable returns false and
vlan_add_rx_filter_info silently succeeds).
For MACsec, VLAN filters are only relevant for offload, otherwise
the VLANs are encrypted and the lower devices don't care about them. So
VLAN filters are only passed on to lower devices in offload mode.
Flipping between offload modes now needs to offload/unoffload the
filters with vlan_{get,drop}_rx_*_filter_info().
To avoid the back-and-forth filter updating during rollback, the setting
of macsec->offload is moved after the add/del secy ops. This is safe
since none of the code called from those requires macsec->offload.
In case adding the filters fails, the added ones are rolled back and an
error is returned to the operation toggling the offload state.
Fixes: 0349659fd72f ("macsec: set IFF_UNICAST_FLT priv flag")
Signed-off-by: Cosmin Ratiu <cratiu@nvidia.com>
---
drivers/net/macsec.c | 71 +++++++++++++++++++++++++++++++++++++++-----
1 file changed, 63 insertions(+), 8 deletions(-)
diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
index f6cad0746a02..6147ee8b1d78 100644
--- a/drivers/net/macsec.c
+++ b/drivers/net/macsec.c
@@ -2584,7 +2584,9 @@ static void macsec_inherit_tso_max(struct net_device *dev)
netif_inherit_tso_max(dev, macsec->real_dev);
}
-static int macsec_update_offload(struct net_device *dev, enum macsec_offload offload)
+static int macsec_update_offload(struct net_device *dev,
+ enum macsec_offload offload,
+ struct netlink_ext_ack *extack)
{
enum macsec_offload prev_offload;
const struct macsec_ops *ops;
@@ -2616,14 +2618,35 @@ static int macsec_update_offload(struct net_device *dev, enum macsec_offload off
if (!ops)
return -EOPNOTSUPP;
- macsec->offload = offload;
-
ctx.secy = &macsec->secy;
ret = offload == MACSEC_OFFLOAD_OFF ? macsec_offload(ops->mdo_del_secy, &ctx)
: macsec_offload(ops->mdo_add_secy, &ctx);
- if (ret) {
- macsec->offload = prev_offload;
+ if (ret)
return ret;
+
+ /* Remove VLAN filters when disabling offload. */
+ if (offload == MACSEC_OFFLOAD_OFF) {
+ vlan_drop_rx_ctag_filter_info(dev);
+ vlan_drop_rx_stag_filter_info(dev);
+ }
+ macsec->offload = offload;
+ /* Add VLAN filters when enabling offload. */
+ if (prev_offload == MACSEC_OFFLOAD_OFF) {
+ ret = vlan_get_rx_ctag_filter_info(dev);
+ if (ret) {
+ NL_SET_ERR_MSG_FMT(extack,
+ "adding ctag VLAN filters failed, err %d",
+ ret);
+ goto rollback_offload;
+ }
+ ret = vlan_get_rx_stag_filter_info(dev);
+ if (ret) {
+ NL_SET_ERR_MSG_FMT(extack,
+ "adding stag VLAN filters failed, err %d",
+ ret);
+ vlan_drop_rx_ctag_filter_info(dev);
+ goto rollback_offload;
+ }
}
macsec_set_head_tail_room(dev);
@@ -2633,6 +2656,12 @@ static int macsec_update_offload(struct net_device *dev, enum macsec_offload off
netdev_update_features(dev);
+ return 0;
+
+rollback_offload:
+ macsec->offload = prev_offload;
+ macsec_offload(ops->mdo_del_secy, &ctx);
+
return ret;
}
@@ -2673,7 +2702,7 @@ static int macsec_upd_offload(struct sk_buff *skb, struct genl_info *info)
offload = nla_get_u8(tb_offload[MACSEC_OFFLOAD_ATTR_TYPE]);
if (macsec->offload != offload)
- ret = macsec_update_offload(dev, offload);
+ ret = macsec_update_offload(dev, offload, info->extack);
out:
rtnl_unlock();
return ret;
@@ -3486,7 +3515,8 @@ static netdev_tx_t macsec_start_xmit(struct sk_buff *skb,
}
#define MACSEC_FEATURES \
- (NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST)
+ (NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST | \
+ NETIF_F_HW_VLAN_STAG_FILTER | NETIF_F_HW_VLAN_CTAG_FILTER)
#define MACSEC_OFFLOAD_FEATURES \
(MACSEC_FEATURES | NETIF_F_GSO_SOFTWARE | NETIF_F_SOFT_FEATURES | \
@@ -3707,6 +3737,29 @@ static int macsec_set_mac_address(struct net_device *dev, void *p)
return err;
}
+static int macsec_vlan_rx_add_vid(struct net_device *dev,
+ __be16 proto, u16 vid)
+{
+ struct macsec_dev *macsec = netdev_priv(dev);
+
+ if (!macsec_is_offloaded(macsec))
+ return 0;
+
+ return vlan_vid_add(macsec->real_dev, proto, vid);
+}
+
+static int macsec_vlan_rx_kill_vid(struct net_device *dev,
+ __be16 proto, u16 vid)
+{
+ struct macsec_dev *macsec = netdev_priv(dev);
+
+ if (!macsec_is_offloaded(macsec))
+ return 0;
+
+ vlan_vid_del(macsec->real_dev, proto, vid);
+ return 0;
+}
+
static int macsec_change_mtu(struct net_device *dev, int new_mtu)
{
struct macsec_dev *macsec = macsec_priv(dev);
@@ -3748,6 +3801,8 @@ static const struct net_device_ops macsec_netdev_ops = {
.ndo_set_rx_mode = macsec_dev_set_rx_mode,
.ndo_change_rx_flags = macsec_dev_change_rx_flags,
.ndo_set_mac_address = macsec_set_mac_address,
+ .ndo_vlan_rx_add_vid = macsec_vlan_rx_add_vid,
+ .ndo_vlan_rx_kill_vid = macsec_vlan_rx_kill_vid,
.ndo_start_xmit = macsec_start_xmit,
.ndo_get_stats64 = macsec_get_stats64,
.ndo_get_iflink = macsec_get_iflink,
@@ -3912,7 +3967,7 @@ static int macsec_changelink(struct net_device *dev, struct nlattr *tb[],
offload = nla_get_u8(data[IFLA_MACSEC_OFFLOAD]);
if (macsec->offload != offload) {
macsec_offload_state_change = true;
- ret = macsec_update_offload(dev, offload);
+ ret = macsec_update_offload(dev, offload, extack);
if (ret)
goto cleanup;
}
--
2.53.0
^ permalink raw reply related
* [PATCH v2] net: dsa: microchip: implement KSZ87xx Module 3 low-loss cable errata
From: Fidelio Lawson @ 2026-04-08 11:57 UTC (permalink / raw)
To: Woojung Huh, UNGLinuxDriver, Andrew Lunn, Vladimir Oltean,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Marek Vasut,
Maxime Chevallier
Cc: Woojung Huh, netdev, devicetree, linux-kernel, Fidelio Lawson
Implement the "Module 3: Equalizer fix for short cables" erratum from
Microchip document DS80000687C for KSZ87xx switches.
The issue affects short or low-loss cable links (e.g. CAT5e/CAT6),
where the PHY receiver equalizer may amplify high-amplitude signals
excessively, resulting in internal distortion and link establishment
failures.
KSZ87xx devices require a workaround for the Module 3 low-loss cable
condition, controlled through the switch TABLE_LINK_MD_V indirect
registers.
The affected registers are part of the switch address space and are not
directly accessible from the PHY driver. To keep the PHY-facing API
clean and avoid leaking switch-specific details, model this errata
control as vendor-specific Clause 22 PHY registers.
Two vendor-defined bits are introduced in PHY_REG_LOW_LOSS_CTRL,
and ksz8_r_phy() / ksz8_w_phy() translate accesses to these bits
into the appropriate indirect TABLE_LINK_MD_V accesses.
The control register defines the following modes:
bits [1:0]:
00 = workaround disabled
01 = workaround 1 (DSP EQ training adjustment, LinkMD reg 0x3c)
10 = workaround 2 (receiver LPF bandwidth, LinkMD reg 0x4c)
Workaround 1: Adjusts the DSP EQ training behavior via LinkMD register
0x3C. Widens and optimizes the DSP EQ compensation range,
and is expected to solve most short/low-loss cable issues.
Workaround 2: for the cases where Workaround 1 is not sufficient.
This one adjusts the receiver low-pass filter bandwidth, effectively
reducing the high-frequency component of the received signal
The register is accessible through standard PHY read/write operations
(e.g. phytool), without requiring any switch-specific userspace
interface. This allows robust link establishment on short or
low-loss cabling without requiring DTS properties and without
constraining hardware design choices.
The erratum affects the shared PHY analog front-end and therefore
applies globally to the switch.
Signed-off-by: Fidelio Lawson <fidelio.lawson@exotec.com>
---
Hello,
This patch implements the “Module 3: Equalizer fix for short cables” erratum
described in Microchip document DS80000687C for KSZ87xx switches.
According to the erratum, the embedded PHY receiver in KSZ87xx switches is
tuned by default for long, high-loss Ethernet cables. When operating with
short or low-loss cables (for example CAT5e or CAT6), the PHY equalizer may
over-amplify the incoming signal, leading to internal distortion and link
establishment failures.
Microchip provides two workarounds, each requiring a write to a different
indirect PHY register access mechanism.
The workaround requires programming internal PHY/DSP registers located in the
LinkMD table, accessed through the KSZ8 indirect register mechanism. Since these
registers belong to the switch address space and are not directly accessible
from a standalone PHY driver, the erratum control is modeled as a vendor-specific
Clause 22 PHY register, virtualized by the KSZ8 DSA driver.
Reads and writes to this register are intercepted by ksz8_r_phy() /
ksz8_w_phy() and translated into the required TABLE_LINK_MD_V indirect accesses.
The erratum affects the shared PHY analog front-end and therefore applies
globally to the switch.
The register defines three modes:
- 0x0: workaround disabled
- 0x1: workaround 1 (DSP EQ training adjustment)
- 0x2: workaround 2 (receiver low-pass filter bandwidth reduction)
The register can be read and written from userspace via standard Clause 22 PHY
accesses (for example using phytool) on DSA user ports.
This series is based on Linux v7.0-rc1.
---
Changes in v2:
- Dropped the device tree approache based on review feedback
- Modeled the errata control as a vendor-specific Clause 22 PHY register
- Added KSZ87xx-specific guards and replaced magic values with named macros
- Rebased on Linux v7.0-rc1
- Link to v1: https://patch.msgid.link/20260326-ksz87xx_errata_low_loss_connections-v1-0-79a698f43626@exotec.com
---
drivers/net/dsa/microchip/ksz8.c | 33 +++++++++++++++++++++++++++++++++
drivers/net/dsa/microchip/ksz8_reg.h | 20 +++++++++++++++++++-
drivers/net/dsa/microchip/ksz_common.h | 3 +++
3 files changed, 55 insertions(+), 1 deletion(-)
diff --git a/drivers/net/dsa/microchip/ksz8.c b/drivers/net/dsa/microchip/ksz8.c
index c354abdafc1b..d11da6e9ff54 100644
--- a/drivers/net/dsa/microchip/ksz8.c
+++ b/drivers/net/dsa/microchip/ksz8.c
@@ -1058,6 +1058,11 @@ int ksz8_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val)
if (ret)
return ret;
+ break;
+ case PHY_REG_KSZ87XX_LOW_LOSS:
+ if (!ksz_is_ksz87xx(dev))
+ return -EOPNOTSUPP;
+ data = dev->low_loss_wa_mode;
break;
default:
processed = false;
@@ -1271,6 +1276,34 @@ int ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val)
if (ret)
return ret;
break;
+ case PHY_REG_KSZ87XX_LOW_LOSS:
+ if (!ksz_is_ksz87xx(dev))
+ return -EOPNOTSUPP;
+
+ switch (val & PHY_KSZ87XX_LOW_LOSS_MASK) {
+ case PHY_LOW_LOSS_ERRATA_DISABLED:
+ ret = ksz8_ind_write8(dev, TABLE_LINK_MD, KSZ87XX_REG_EQ_TRAIN,
+ KSZ87XX_EQ_TRAIN_DEFAULT);
+ if (!ret)
+ ret = ksz8_ind_write8(dev, TABLE_LINK_MD,
+ KSZ87XX_REG_PHY_LPF,
+ KSZ87XX_PHY_LPF_DEFAULT);
+ break;
+ case KSZ87XX_LOW_LOSS_WA_EQ:
+ ret = ksz8_ind_write8(dev, TABLE_LINK_MD, KSZ87XX_REG_EQ_TRAIN,
+ KSZ87XX_EQ_TRAIN_LOW_LOSS);
+ break;
+ case KSZ87XX_LOW_LOSS_WA_LPF:
+ ret = ksz8_ind_write8(dev, TABLE_LINK_MD, KSZ87XX_REG_PHY_LPF,
+ KSZ87XX_PHY_LPF_62MHZ);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (!ret)
+ dev->low_loss_wa_mode = val & PHY_KSZ87XX_LOW_LOSS_MASK;
+ return ret;
default:
break;
}
diff --git a/drivers/net/dsa/microchip/ksz8_reg.h b/drivers/net/dsa/microchip/ksz8_reg.h
index 332408567b47..cd1092aa0eaf 100644
--- a/drivers/net/dsa/microchip/ksz8_reg.h
+++ b/drivers/net/dsa/microchip/ksz8_reg.h
@@ -202,6 +202,10 @@
#define REG_PORT_3_STATUS_0 0x38
#define REG_PORT_4_STATUS_0 0x48
+/* KSZ87xx LinkMD registers (TABLE_LINK_MD_V) */
+#define KSZ87XX_REG_EQ_TRAIN 0x3C
+#define KSZ87XX_REG_PHY_LPF 0x4C
+
/* For KSZ8765. */
#define PORT_REMOTE_ASYM_PAUSE BIT(5)
#define PORT_REMOTE_SYM_PAUSE BIT(4)
@@ -342,7 +346,7 @@
#define TABLE_EEE (TABLE_EEE_V << TABLE_EXT_SELECT_S)
#define TABLE_ACL (TABLE_ACL_V << TABLE_EXT_SELECT_S)
#define TABLE_PME (TABLE_PME_V << TABLE_EXT_SELECT_S)
-#define TABLE_LINK_MD (TABLE_LINK_MD << TABLE_EXT_SELECT_S)
+#define TABLE_LINK_MD (TABLE_LINK_MD_V << TABLE_EXT_SELECT_S)
#define TABLE_READ BIT(4)
#define TABLE_SELECT_S 2
#define TABLE_STATIC_MAC_V 0
@@ -729,6 +733,20 @@
#define PHY_POWER_SAVING_ENABLE BIT(2)
#define PHY_REMOTE_LOOPBACK BIT(1)
+/* Equalizer low-loss workaround */
+/* bits [1:0]: 00 = disabled, 01 = workaround 1, 10 = workaround 2 */
+#define PHY_REG_KSZ87XX_LOW_LOSS 0x1C
+#define PHY_KSZ87XX_LOW_LOSS_MASK GENMASK(1, 0)
+
+#define PHY_LOW_LOSS_ERRATA_DISABLED 0
+#define KSZ87XX_LOW_LOSS_WA_EQ 1
+#define KSZ87XX_LOW_LOSS_WA_LPF 2
+
+#define KSZ87XX_EQ_TRAIN_DEFAULT 0x0A
+#define KSZ87XX_EQ_TRAIN_LOW_LOSS 0x15
+#define KSZ87XX_PHY_LPF_DEFAULT 0x00
+#define KSZ87XX_PHY_LPF_62MHZ 0x40
+
/* KSZ8463 specific registers. */
#define P1MBCR 0x4C
#define P1MBSR 0x4E
diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h
index 929aff4c55de..729996c7160c 100644
--- a/drivers/net/dsa/microchip/ksz_common.h
+++ b/drivers/net/dsa/microchip/ksz_common.h
@@ -219,6 +219,9 @@ struct ksz_device {
* the switch’s internal PHYs, bypassing the main SPI interface.
*/
struct mii_bus *parent_mdio_bus;
+
+ /* Equalizer low-loss workaround tunable */
+ u8 low_loss_wa_mode; /* bits [1:0]: 00 = disabled, 01 = workaround 1, 10 = workaround 2 */
};
/* List of supported models */
---
base-commit: 2d1373e4246da3b58e1df058374ed6b101804e07
change-id: 20260323-ksz87xx_errata_low_loss_connections-b65e76e2b403
Best regards,
--
Fidelio Lawson <fidelio.lawson@exotec.com>
^ permalink raw reply related
* Re: [Intel-wired-lan] [PATCH iwl-next] igb: use ktime_get_real helpers in igb_ptp_reset()
From: Paul Menzel @ 2026-04-08 11:57 UTC (permalink / raw)
To: Aleksandr Loktionov
Cc: intel-wired-lan, anthony.l.nguyen, netdev, Jacob Keller,
Simon Horman
In-Reply-To: <20260408083521.1620447-1-aleksandr.loktionov@intel.com>
Dear Aleksandr,
Thank you for your patch.
Am 08.04.26 um 10:35 schrieb Aleksandr Loktionov:
> Replace ktime_to_ns(ktime_get_real()) with the direct equivalent
> ktime_get_real_ns() and ktime_to_timespec64(ktime_get_real()) with
> ktime_get_real_ts64() in igb_ptp_reset(). Using the combined helpers
> avoids the unnecessary intermediate ktime_t variable and makes the
> intent clearer.
No intermediate variable is removed in the diff below. What am I missing?
> Suggested-by: Jacob Keller <jacob.e.keller@intel.com>
> Suggested-by: Simon Horman <horms@kernel.org>
> Signed-off-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
> ---
> drivers/net/ethernet/intel/igb/igb_ptp.c | 5 +++--
> 1 file changed, 3 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/net/ethernet/intel/igb/igb_ptp.c b/drivers/net/ethernet/intel/igb/igb_ptp.c
> index bd85d02..638d824 100644
> --- a/drivers/net/ethernet/intel/igb/igb_ptp.c
> +++ b/drivers/net/ethernet/intel/igb/igb_ptp.c
> @@ -1500,12 +1500,13 @@ void igb_ptp_reset(struct igb_adapter *adapter)
>
> /* Re-initialize the timer. */
> if ((hw->mac.type == e1000_i210) || (hw->mac.type == e1000_i211)) {
> - struct timespec64 ts = ktime_to_timespec64(ktime_get_real());
> + struct timespec64 ts;
>
> + ktime_get_real_ts64(&ts);
> igb_ptp_write_i210(adapter, &ts);
> } else {
> timecounter_init(&adapter->tc, &adapter->cc,
> - ktime_to_ns(ktime_get_real()));
> + ktime_get_real_ns());
> }
> out:
> spin_unlock_irqrestore(&adapter->tmreg_lock, flags);
With the commit message clarified, feel free to add:
Reviewed-by: Paul Menzel <pmenzel@molgen.mpg.de>
Kind regards,
Paul
^ permalink raw reply
* RE: [Intel-wired-lan] [PATCH iwl-next 1/2] i40e: implement basic per-queue stats
From: Loktionov, Aleksandr @ 2026-04-08 12:07 UTC (permalink / raw)
To: Paolo Abeni, intel-wired-lan@lists.osuosl.org
Cc: Nguyen, Anthony L, Kitszel, Przemyslaw, Andrew Lunn,
David S. Miller, Eric Dumazet, Jakub Kicinski, Alexei Starovoitov,
Daniel Borkmann, Jesper Dangaard Brouer, John Fastabend,
Stanislav Fomichev, netdev@vger.kernel.org
In-Reply-To: <0815f1eb4b60faa653ea703e420395b724d05216.1775648513.git.pabeni@redhat.com>
> -----Original Message-----
> From: Intel-wired-lan <intel-wired-lan-bounces@osuosl.org> On Behalf
> Of Paolo Abeni
> Sent: Wednesday, April 8, 2026 1:44 PM
> To: intel-wired-lan@lists.osuosl.org
> Cc: Nguyen, Anthony L <anthony.l.nguyen@intel.com>; Kitszel,
> Przemyslaw <przemyslaw.kitszel@intel.com>; Andrew Lunn
> <andrew+netdev@lunn.ch>; David S. Miller <davem@davemloft.net>; Eric
> Dumazet <edumazet@google.com>; Jakub Kicinski <kuba@kernel.org>;
> Alexei Starovoitov <ast@kernel.org>; Daniel Borkmann
> <daniel@iogearbox.net>; Jesper Dangaard Brouer <hawk@kernel.org>; John
> Fastabend <john.fastabend@gmail.com>; Stanislav Fomichev
> <sdf@fomichev.me>; netdev@vger.kernel.org
> Subject: [Intel-wired-lan] [PATCH iwl-next 1/2] i40e: implement basic
> per-queue stats
>
> Only expose the counters currently available (bytes, packets); add
> account for base stats to deal with ring clear.
>
> Signed-off-by: Paolo Abeni <pabeni@redhat.com>
> ---
> drivers/net/ethernet/intel/i40e/i40e.h | 7 ++
> drivers/net/ethernet/intel/i40e/i40e_main.c | 133
> ++++++++++++++++++++
> 2 files changed, 140 insertions(+)
>
> diff --git a/drivers/net/ethernet/intel/i40e/i40e.h
> b/drivers/net/ethernet/intel/i40e/i40e.h
> index dcb50c2e1aa2..fe642c464e9c 100644
> --- a/drivers/net/ethernet/intel/i40e/i40e.h
> +++ b/drivers/net/ethernet/intel/i40e/i40e.h
> @@ -836,16 +836,23 @@ struct i40e_vsi {
> struct i40e_eth_stats eth_stats;
> struct i40e_eth_stats eth_stats_offsets;
> u64 tx_restart;
...
> +static void i40e_zero_tx_ring_stats(struct netdev_queue_stats_tx *tx)
> {
> + tx->bytes = 0;
> + tx->packets = 0;
> + tx->stop = 0;
> + tx->wake = 0;
> + tx->hw_drops = 0;
> +}
> +
> +static void i40e_add_tx_ring_stats(struct i40e_ring *tx_ring,
> + struct netdev_queue_stats_tx *tx) {
> + u64 bytes, packets;
> + unsigned int start;
> +
> + do {
> + start = u64_stats_fetch_begin(&tx_ring->syncp);
> + bytes = tx_ring->stats.bytes;
> + packets = tx_ring->stats.packets;
> + } while (u64_stats_fetch_retry(&tx_ring->syncp, start));
> +
> + tx->bytes += bytes;
> + tx->packets += packets;
> +
> + tx->stop += tx_ring->tx_stats.tx_stopped;
> + tx->wake += tx_ring->tx_stats.restart_queue;
> + tx->hw_drops += tx_ring->tx_stats.tx_busy; }
Why the reads are outside the seqlock region?
On 32-bit kernels, unprotected u64 reads can tear IMHO
> +
> +static void i40e_get_queue_stats_tx(struct net_device *dev, int idx,
> + struct netdev_queue_stats_tx *tx) {
...
> netdev->netdev_ops = &i40e_netdev_ops;
> netdev->watchdog_timeo = 5 * HZ;
> i40e_set_ethtool_ops(netdev);
> --
> 2.53.0
^ permalink raw reply
* RE: [Intel-wired-lan] [PATCH iwl-next 2/2] i40e: keep track of per queue gso counters.
From: Loktionov, Aleksandr @ 2026-04-08 12:08 UTC (permalink / raw)
To: Paolo Abeni, intel-wired-lan@lists.osuosl.org
Cc: Nguyen, Anthony L, Kitszel, Przemyslaw, Andrew Lunn,
David S. Miller, Eric Dumazet, Jakub Kicinski, Alexei Starovoitov,
Daniel Borkmann, Jesper Dangaard Brouer, John Fastabend,
Stanislav Fomichev, netdev@vger.kernel.org
In-Reply-To: <c70f2e9d8cbc4af419356ed022bc60a8c9cfc7d2.1775648513.git.pabeni@redhat.com>
> -----Original Message-----
> From: Intel-wired-lan <intel-wired-lan-bounces@osuosl.org> On Behalf
> Of Paolo Abeni
> Sent: Wednesday, April 8, 2026 1:44 PM
> To: intel-wired-lan@lists.osuosl.org
> Cc: Nguyen, Anthony L <anthony.l.nguyen@intel.com>; Kitszel,
> Przemyslaw <przemyslaw.kitszel@intel.com>; Andrew Lunn
> <andrew+netdev@lunn.ch>; David S. Miller <davem@davemloft.net>; Eric
> Dumazet <edumazet@google.com>; Jakub Kicinski <kuba@kernel.org>;
> Alexei Starovoitov <ast@kernel.org>; Daniel Borkmann
> <daniel@iogearbox.net>; Jesper Dangaard Brouer <hawk@kernel.org>; John
> Fastabend <john.fastabend@gmail.com>; Stanislav Fomichev
> <sdf@fomichev.me>; netdev@vger.kernel.org
> Subject: [Intel-wired-lan] [PATCH iwl-next 2/2] i40e: keep track of
> per queue gso counters.
>
Please remove trailing '.'
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
> Track the number of GSO and wire packets transmitted and expose the
> counters via the queue stats.
>
> Signed-off-by: Paolo Abeni <pabeni@redhat.com>
> ---
> drivers/net/ethernet/intel/i40e/i40e.h | 2 ++
> drivers/net/ethernet/intel/i40e/i40e_main.c | 13 ++++++++++++-
> drivers/net/ethernet/intel/i40e/i40e_txrx.c | 8 +++++++-
> drivers/net/ethernet/intel/i40e/i40e_txrx.h | 2 ++
> drivers/net/ethernet/intel/i40e/i40e_txrx_common.h | 6 +++++-
> drivers/net/ethernet/intel/i40e/i40e_xsk.c | 2 +-
> 6 files changed, 29 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/net/ethernet/intel/i40e/i40e.h
> b/drivers/net/ethernet/intel/i40e/i40e.h
> index fe642c464e9c..4a88c7d69f61 100644
> --- a/drivers/net/ethernet/intel/i40e/i40e.h
> +++ b/drivers/net/ethernet/intel/i40e/i40e.h
> @@ -845,6 +845,8 @@ struct i40e_vsi {
> u64 tx_stopped_base;
> u64 tx_bytes;
> u64 tx_packets;
...
>
> return nb_pkts < budget;
> }
> --
> 2.53.0
^ permalink raw reply
* [PATCH net v5 00/21] rxrpc: Miscellaneous fixes
From: David Howells @ 2026-04-08 12:12 UTC (permalink / raw)
To: netdev
Cc: David Howells, Marc Dionne, Jakub Kicinski, David S. Miller,
Eric Dumazet, Paolo Abeni, linux-afs, linux-kernel
Here are some fixes for rxrpc:
(1) Fix key quota calculation.
(2) Fix a memory leak.
(3) Fix rxrpc_new_client_call_for_sendmsg() to substitute NULL for an
empty key.
Might want to remove this substitution entirely or handle it in
rxrpc_init_client_call_security() instead.
(4) Fix deletion of call->link to be RCU safe.
(5) Fix missing bounds checks when parsing RxGK tickets.
(6) Fix use of wrong skbuff to get challenge serial number. Also actually
substitute the newer response skbuff and release the older one.
(7) Fix unexpected RACK timer warning to report old mode.
(8) Fix call key refcount leak.
(9) Fix the interaction of jumbograms with Tx window space, setting the
request-ack flag when the window space is getting low, typically
because each jumbogram take a big bite out of the window and fewer UDP
packets get traded.
(10) Don't call rxrpc_put_call() with a NULL pointer.
(11) Reject undecryptable rxkad response tickets by checking result of
decryption.
(12) Fix buffer bounds calculation in the RESPONSE authenticator parser.
(13) Fix oversized response length check.
(14) Fix refcount leak on multiple setting of server keyring.
(15) Fix checks made by RXRPC_SECURITY_KEY and RXRPC_SECURITY_KEYRING (both
should be allowed).
(16) Fix lack of result checking on calls to crypto_skcipher_en/decrypt().
(17) Fix token_len limit check in rxgk_verify_response().
(18) Fix rxgk context leak in rxgk_verify_response().
(19) Fix read beyond end of buffer in rxgk_do_verify_authenticator().
(20) Fix parsing of RESPONSE packet on a connection that has already been set
from a prior response.
(21) Fix size of buffers used for rendering addresses into for procfiles.
David
The patches can be found here also:
http://git.kernel.org/cgit/linux/kernel/git/dhowells/linux-fs.git/log/?h=rxrpc-fixes
Changes
=======
ver #5)
- AI review[2]:
- Dropped patch to check rx->securities in rxrpc_setsockopt().
- Changed patch to check rx->securities in rxrpc_server_keyring() to return
error -EINVAL.
- Added patch to check rx->key and rx->securities correctly.
- Added patch to check return of crypto_skcipher_en/decrypt().
- Added patch to check buf len in rxgk_do_verify_authenticator().
- Imported a patch to fix parsing of RESPONSE packet in wrong state.
- Imported a patch to fix size of address buffers in procfiles.
ver #4)
- Got rid of the on_list()/on_list_rcu() patch.
- Removed the list_del_init from rxrpc_destroy_all_calls().
- Made the list_del_rcu() in rxrpc_put_call() unconditional.
- Added four new patches.
ver #3)
- Rename the dwc2's on_list() to dwc2_on_list() to free up the name.
- Added a patch to fix the interaction of jumbograms with window space.
ver #2)
- AI review[1]:
- Added a patch to fix key quota calculation.
- Added a patch to fix a memory leak.
- Added a patch to use NULL instead of an empty key in rxrpc_sengmsg().
- Added a patch to use RCU-safe deletion on call->link.
- Modified the response packet selection patch to select the newer
response when there's an older response - and to release the older
response skbuff.
- Move on_list_rcu() and add on_list().
Link: https://sashiko.dev/#/patchset/20260319150150.4189381-1-dhowells%40redhat.com [1]
Link: https://sashiko.dev/#/patchset/20260401105614.1696001-10-dhowells@redhat.com [2]
Alok Tiwari (2):
rxrpc: Fix use of wrong skb when comparing queued RESP challenge
serial
rxrpc: Fix rack timer warning to report unexpected mode
Anderson Nascimento (1):
rxrpc: Fix key reference count leak from call->key
David Howells (9):
rxrpc: Fix key quota calculation for multitoken keys
rxrpc: Fix key parsing memleak
rxrpc: Fix anonymous key handling
rxrpc: Fix call removal to use RCU safe deletion
rxrpc: Fix key/keyring checks in
setsockopt(RXRPC_SECURITY_KEY/KEYRING)
rxrpc: Fix missing error checks for rxkad encryption/decryption
failure
rxrpc: Fix integer overflow in rxgk_verify_response()
rxrpc: Fix leak of rxgk context in rxgk_verify_response()
rxrpc: Fix buffer overread in rxgk_do_verify_authenticator()
Douya Le (1):
rxrpc: Only put the call ref if one was acquired
Keenan Dong (2):
rxrpc: fix RESPONSE authenticator parser OOB read
rxrpc: fix oversized RESPONSE authenticator length check
Luxiao Xu (1):
rxrpc: fix reference count leak in rxrpc_server_keyring()
Marc Dionne (1):
rxrpc: Fix to request an ack if window is limited
Oleh Konko (1):
rxrpc: Fix RxGK token loading to check bounds
Pengpeng Hou (1):
rxrpc: proc: size address buffers for %pISpc output
Wang Jie (1):
rxrpc: only handle RESPONSE during service challenge
Yuqi Xu (1):
rxrpc: reject undecryptable rxkad response tickets
include/trace/events/rxrpc.h | 4 ++-
net/rxrpc/af_rxrpc.c | 6 ----
net/rxrpc/ar-internal.h | 2 +-
net/rxrpc/call_object.c | 25 ++++++--------
net/rxrpc/conn_event.c | 19 ++++++++---
net/rxrpc/input_rack.c | 2 +-
net/rxrpc/io_thread.c | 3 +-
net/rxrpc/key.c | 40 +++++++++++++----------
net/rxrpc/output.c | 2 ++
net/rxrpc/proc.c | 37 ++++++++++++---------
net/rxrpc/rxgk.c | 19 +++++++----
net/rxrpc/rxkad.c | 63 ++++++++++++++++++++++++------------
net/rxrpc/sendmsg.c | 2 +-
net/rxrpc/server_key.c | 3 ++
14 files changed, 138 insertions(+), 89 deletions(-)
^ permalink raw reply
* [PATCH net v5 01/21] rxrpc: Fix key quota calculation for multitoken keys
From: David Howells @ 2026-04-08 12:12 UTC (permalink / raw)
To: netdev
Cc: David Howells, Marc Dionne, Jakub Kicinski, David S. Miller,
Eric Dumazet, Paolo Abeni, linux-afs, linux-kernel,
Jeffrey Altman, Simon Horman, stable
In-Reply-To: <20260408121252.2249051-1-dhowells@redhat.com>
In the rxrpc key preparsing, every token extracted sets the proposed quota
value, but for multitoken keys, this will overwrite the previous proposed
quota, losing it.
Fix this by adding to the proposed quota instead.
Fixes: 8a7a3eb4ddbe ("KEYS: RxRPC: Use key preparsing")
Closes: https://sashiko.dev/#/patchset/20260319150150.4189381-1-dhowells%40redhat.com
Signed-off-by: David Howells <dhowells@redhat.com>
cc: Marc Dionne <marc.dionne@auristor.com>
cc: Jeffrey Altman <jaltman@auristor.com>
cc: Eric Dumazet <edumazet@google.com>
cc: "David S. Miller" <davem@davemloft.net>
cc: Jakub Kicinski <kuba@kernel.org>
cc: Paolo Abeni <pabeni@redhat.com>
cc: Simon Horman <horms@kernel.org>
cc: linux-afs@lists.infradead.org
cc: netdev@vger.kernel.org
cc: stable@kernel.org
---
net/rxrpc/key.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/net/rxrpc/key.c b/net/rxrpc/key.c
index 85078114b2dd..af403f0ccab5 100644
--- a/net/rxrpc/key.c
+++ b/net/rxrpc/key.c
@@ -72,7 +72,7 @@ static int rxrpc_preparse_xdr_rxkad(struct key_preparsed_payload *prep,
return -EKEYREJECTED;
plen = sizeof(*token) + sizeof(*token->kad) + tktlen;
- prep->quotalen = datalen + plen;
+ prep->quotalen += datalen + plen;
plen -= sizeof(*token);
token = kzalloc_obj(*token);
@@ -199,7 +199,7 @@ static int rxrpc_preparse_xdr_yfs_rxgk(struct key_preparsed_payload *prep,
}
plen = sizeof(*token) + sizeof(*token->rxgk) + tktlen + keylen;
- prep->quotalen = datalen + plen;
+ prep->quotalen += datalen + plen;
plen -= sizeof(*token);
token = kzalloc_obj(*token);
@@ -460,6 +460,7 @@ static int rxrpc_preparse(struct key_preparsed_payload *prep)
memcpy(&kver, prep->data, sizeof(kver));
prep->data += sizeof(kver);
prep->datalen -= sizeof(kver);
+ prep->quotalen = 0;
_debug("KEY I/F VERSION: %u", kver);
@@ -497,7 +498,7 @@ static int rxrpc_preparse(struct key_preparsed_payload *prep)
goto error;
plen = sizeof(*token->kad) + v1->ticket_length;
- prep->quotalen = plen + sizeof(*token);
+ prep->quotalen += plen + sizeof(*token);
ret = -ENOMEM;
token = kzalloc_obj(*token);
^ permalink raw reply related
* [PATCH net v5 02/21] rxrpc: Fix key parsing memleak
From: David Howells @ 2026-04-08 12:12 UTC (permalink / raw)
To: netdev
Cc: David Howells, Marc Dionne, Jakub Kicinski, David S. Miller,
Eric Dumazet, Paolo Abeni, linux-afs, linux-kernel,
Jeffrey Altman, Simon Horman, stable
In-Reply-To: <20260408121252.2249051-1-dhowells@redhat.com>
In rxrpc_preparse_xdr_yfs_rxgk(), the memory attached to token->rxgk can be
leaked in a few error paths after it's allocated.
Fix this by freeing it in the "reject_token:" case.
Fixes: 0ca100ff4df6 ("rxrpc: Add YFS RxGK (GSSAPI) security class")
Closes: https://sashiko.dev/#/patchset/20260319150150.4189381-1-dhowells%40redhat.com
Signed-off-by: David Howells <dhowells@redhat.com>
cc: Marc Dionne <marc.dionne@auristor.com>
cc: Jeffrey Altman <jaltman@auristor.com>
cc: Eric Dumazet <edumazet@google.com>
cc: "David S. Miller" <davem@davemloft.net>
cc: Jakub Kicinski <kuba@kernel.org>
cc: Paolo Abeni <pabeni@redhat.com>
cc: Simon Horman <horms@kernel.org>
cc: linux-afs@lists.infradead.org
cc: netdev@vger.kernel.org
cc: stable@kernel.org
---
net/rxrpc/key.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/net/rxrpc/key.c b/net/rxrpc/key.c
index af403f0ccab5..26d4336a4a02 100644
--- a/net/rxrpc/key.c
+++ b/net/rxrpc/key.c
@@ -274,6 +274,7 @@ static int rxrpc_preparse_xdr_yfs_rxgk(struct key_preparsed_payload *prep,
nomem:
return -ENOMEM;
reject_token:
+ kfree(token->rxgk);
kfree(token);
reject:
return -EKEYREJECTED;
^ permalink raw reply related
* [PATCH net v5 03/21] rxrpc: Fix anonymous key handling
From: David Howells @ 2026-04-08 12:12 UTC (permalink / raw)
To: netdev
Cc: David Howells, Marc Dionne, Jakub Kicinski, David S. Miller,
Eric Dumazet, Paolo Abeni, linux-afs, linux-kernel,
Jeffrey Altman, Simon Horman, stable
In-Reply-To: <20260408121252.2249051-1-dhowells@redhat.com>
In rxrpc_new_client_call_for_sendmsg(), a key with no payload is meant to
be substituted for a NULL key pointer, but the variable this is done with
is subsequently not used.
Fix this by using "key" rather than "rx->key" when filling in the
connection parameters.
Note that this only affects direct use of AF_RXRPC; the kAFS filesystem
doesn't use sendmsg() directly and so bypasses the issue. Further,
AF_RXRPC passes a NULL key in if no key is set, so using an anonymous key
in that manner works. Since this hasn't been noticed to this point, it
might be better just to remove the "key" variable and the code that sets it
- and, arguably, rxrpc_init_client_call_security() would be a better place
to handle it.
Fixes: 19ffa01c9c45 ("rxrpc: Use structs to hold connection params and protocol info")
Closes: https://sashiko.dev/#/patchset/20260319150150.4189381-1-dhowells%40redhat.com
Signed-off-by: David Howells <dhowells@redhat.com>
cc: Marc Dionne <marc.dionne@auristor.com>
cc: Jeffrey Altman <jaltman@auristor.com>
cc: Eric Dumazet <edumazet@google.com>
cc: "David S. Miller" <davem@davemloft.net>
cc: Jakub Kicinski <kuba@kernel.org>
cc: Paolo Abeni <pabeni@redhat.com>
cc: Simon Horman <horms@kernel.org>
cc: linux-afs@lists.infradead.org
cc: netdev@vger.kernel.org
cc: stable@kernel.org
---
net/rxrpc/sendmsg.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/rxrpc/sendmsg.c b/net/rxrpc/sendmsg.c
index 04f9c5f2dc24..c35de4fd75e3 100644
--- a/net/rxrpc/sendmsg.c
+++ b/net/rxrpc/sendmsg.c
@@ -637,7 +637,7 @@ rxrpc_new_client_call_for_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg,
memset(&cp, 0, sizeof(cp));
cp.local = rx->local;
cp.peer = peer;
- cp.key = rx->key;
+ cp.key = key;
cp.security_level = rx->min_sec_level;
cp.exclusive = rx->exclusive | p->exclusive;
cp.upgrade = p->upgrade;
^ permalink raw reply related
* [PATCH net v5 05/21] rxrpc: Fix RxGK token loading to check bounds
From: David Howells @ 2026-04-08 12:12 UTC (permalink / raw)
To: netdev
Cc: David Howells, Marc Dionne, Jakub Kicinski, David S. Miller,
Eric Dumazet, Paolo Abeni, linux-afs, linux-kernel, Oleh Konko,
Jeffrey Altman, Simon Horman, stable
In-Reply-To: <20260408121252.2249051-1-dhowells@redhat.com>
From: Oleh Konko <security@1seal.org>
rxrpc_preparse_xdr_yfs_rxgk() reads the raw key length and ticket length
from the XDR token as u32 values and passes each through round_up(x, 4)
before using the rounded value for validation and allocation. When the raw
length is >= 0xfffffffd, round_up() wraps to 0, so the bounds check and
kzalloc both use 0 while the subsequent memcpy still copies the original
~4 GiB value, producing a heap buffer overflow reachable from an
unprivileged add_key() call.
Fix this by:
(1) Rejecting raw key lengths above AFSTOKEN_GK_KEY_MAX and raw ticket
lengths above AFSTOKEN_GK_TOKEN_MAX before rounding, consistent with
the caps that the RxKAD path already enforces via AFSTOKEN_RK_TIX_MAX.
(2) Sizing the flexible-array allocation from the validated raw key
length via struct_size_t() instead of the rounded value.
(3) Caching the raw lengths so that the later field assignments and
memcpy calls do not re-read from the token, eliminating a class of
TOCTOU re-parse.
The control path (valid token with lengths within bounds) is unaffected.
Fixes: 0ca100ff4df6 ("rxrpc: Add YFS RxGK (GSSAPI) security class")
Signed-off-by: Oleh Konko <security@1seal.org>
Signed-off-by: David Howells <dhowells@redhat.com>
Reviewed-by: Jeffrey Altman <jaltman@auristor.com>
cc: Marc Dionne <marc.dionne@auristor.com>
cc: Eric Dumazet <edumazet@google.com>
cc: "David S. Miller" <davem@davemloft.net>
cc: Jakub Kicinski <kuba@kernel.org>
cc: Paolo Abeni <pabeni@redhat.com>
cc: Simon Horman <horms@kernel.org>
cc: linux-afs@lists.infradead.org
cc: netdev@vger.kernel.org
cc: stable@kernel.org
---
net/rxrpc/key.c | 30 +++++++++++++++++-------------
1 file changed, 17 insertions(+), 13 deletions(-)
diff --git a/net/rxrpc/key.c b/net/rxrpc/key.c
index 26d4336a4a02..77237a82be3b 100644
--- a/net/rxrpc/key.c
+++ b/net/rxrpc/key.c
@@ -13,6 +13,7 @@
#include <crypto/skcipher.h>
#include <linux/module.h>
#include <linux/net.h>
+#include <linux/overflow.h>
#include <linux/skbuff.h>
#include <linux/key-type.h>
#include <linux/ctype.h>
@@ -171,7 +172,7 @@ static int rxrpc_preparse_xdr_yfs_rxgk(struct key_preparsed_payload *prep,
size_t plen;
const __be32 *ticket, *key;
s64 tmp;
- u32 tktlen, keylen;
+ size_t raw_keylen, raw_tktlen, keylen, tktlen;
_enter(",{%x,%x,%x,%x},%x",
ntohl(xdr[0]), ntohl(xdr[1]), ntohl(xdr[2]), ntohl(xdr[3]),
@@ -181,18 +182,22 @@ static int rxrpc_preparse_xdr_yfs_rxgk(struct key_preparsed_payload *prep,
goto reject;
key = xdr + (6 * 2 + 1);
- keylen = ntohl(key[-1]);
- _debug("keylen: %x", keylen);
- keylen = round_up(keylen, 4);
+ raw_keylen = ntohl(key[-1]);
+ _debug("keylen: %zx", raw_keylen);
+ if (raw_keylen > AFSTOKEN_GK_KEY_MAX)
+ goto reject;
+ keylen = round_up(raw_keylen, 4);
if ((6 * 2 + 2) * 4 + keylen > toklen)
goto reject;
ticket = xdr + (6 * 2 + 1 + (keylen / 4) + 1);
- tktlen = ntohl(ticket[-1]);
- _debug("tktlen: %x", tktlen);
- tktlen = round_up(tktlen, 4);
+ raw_tktlen = ntohl(ticket[-1]);
+ _debug("tktlen: %zx", raw_tktlen);
+ if (raw_tktlen > AFSTOKEN_GK_TOKEN_MAX)
+ goto reject;
+ tktlen = round_up(raw_tktlen, 4);
if ((6 * 2 + 2) * 4 + keylen + tktlen != toklen) {
- kleave(" = -EKEYREJECTED [%x!=%x, %x,%x]",
+ kleave(" = -EKEYREJECTED [%zx!=%x, %zx,%zx]",
(6 * 2 + 2) * 4 + keylen + tktlen, toklen,
keylen, tktlen);
goto reject;
@@ -206,7 +211,7 @@ static int rxrpc_preparse_xdr_yfs_rxgk(struct key_preparsed_payload *prep,
if (!token)
goto nomem;
- token->rxgk = kzalloc(sizeof(*token->rxgk) + keylen, GFP_KERNEL);
+ token->rxgk = kzalloc(struct_size_t(struct rxgk_key, _key, raw_keylen), GFP_KERNEL);
if (!token->rxgk)
goto nomem_token;
@@ -221,9 +226,9 @@ static int rxrpc_preparse_xdr_yfs_rxgk(struct key_preparsed_payload *prep,
token->rxgk->enctype = tmp = xdr_dec64(xdr + 5 * 2);
if (tmp < 0 || tmp > UINT_MAX)
goto reject_token;
- token->rxgk->key.len = ntohl(key[-1]);
+ token->rxgk->key.len = raw_keylen;
token->rxgk->key.data = token->rxgk->_key;
- token->rxgk->ticket.len = ntohl(ticket[-1]);
+ token->rxgk->ticket.len = raw_tktlen;
if (token->rxgk->endtime != 0) {
expiry = rxrpc_s64_to_time64(token->rxgk->endtime);
@@ -236,8 +241,7 @@ static int rxrpc_preparse_xdr_yfs_rxgk(struct key_preparsed_payload *prep,
memcpy(token->rxgk->key.data, key, token->rxgk->key.len);
/* Pad the ticket so that we can use it directly in XDR */
- token->rxgk->ticket.data = kzalloc(round_up(token->rxgk->ticket.len, 4),
- GFP_KERNEL);
+ token->rxgk->ticket.data = kzalloc(tktlen, GFP_KERNEL);
if (!token->rxgk->ticket.data)
goto nomem_yrxgk;
memcpy(token->rxgk->ticket.data, ticket, token->rxgk->ticket.len);
^ permalink raw reply related
* [PATCH net v5 06/21] rxrpc: Fix use of wrong skb when comparing queued RESP challenge serial
From: David Howells @ 2026-04-08 12:12 UTC (permalink / raw)
To: netdev
Cc: David Howells, Marc Dionne, Jakub Kicinski, David S. Miller,
Eric Dumazet, Paolo Abeni, linux-afs, linux-kernel, Alok Tiwari,
Jeffrey Altman, Simon Horman, stable
In-Reply-To: <20260408121252.2249051-1-dhowells@redhat.com>
From: Alok Tiwari <alok.a.tiwari@oracle.com>
In rxrpc_post_response(), the code should be comparing the challenge serial
number from the cached response before deciding to switch to a newer
response, but looks at the newer packet private data instead, rendering the
comparison always false.
Fix this by switching to look at the older packet.
Fix further[1] to substitute the new packet in place of the old one if
newer and also to release whichever we don't use.
Fixes: 5800b1cf3fd8 ("rxrpc: Allow CHALLENGEs to the passed to the app for a RESPONSE")
Signed-off-by: Alok Tiwari <alok.a.tiwari@oracle.com>
Signed-off-by: David Howells <dhowells@redhat.com>
Reviewed-by: Jeffrey Altman <jaltman@auristor.com>
cc: Marc Dionne <marc.dionne@auristor.com>
cc: Eric Dumazet <edumazet@google.com>
cc: "David S. Miller" <davem@davemloft.net>
cc: Jakub Kicinski <kuba@kernel.org>
cc: Paolo Abeni <pabeni@redhat.com>
cc: Simon Horman <horms@kernel.org>
cc: linux-afs@lists.infradead.org
cc: netdev@vger.kernel.org
cc: stable@kernel.org
Link: https://sashiko.dev/#/patchset/20260319150150.4189381-1-dhowells%40redhat.com [1]
---
include/trace/events/rxrpc.h | 1 +
net/rxrpc/conn_event.c | 5 +++--
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/include/trace/events/rxrpc.h b/include/trace/events/rxrpc.h
index a826cd80007b..f7f559204b87 100644
--- a/include/trace/events/rxrpc.h
+++ b/include/trace/events/rxrpc.h
@@ -185,6 +185,7 @@
EM(rxrpc_skb_put_input, "PUT input ") \
EM(rxrpc_skb_put_jumbo_subpacket, "PUT jumbo-sub") \
EM(rxrpc_skb_put_oob, "PUT oob ") \
+ EM(rxrpc_skb_put_old_response, "PUT old-resp ") \
EM(rxrpc_skb_put_purge, "PUT purge ") \
EM(rxrpc_skb_put_purge_oob, "PUT purge-oob") \
EM(rxrpc_skb_put_response, "PUT response ") \
diff --git a/net/rxrpc/conn_event.c b/net/rxrpc/conn_event.c
index 98ad9b51ca2c..c50cbfc5a313 100644
--- a/net/rxrpc/conn_event.c
+++ b/net/rxrpc/conn_event.c
@@ -557,11 +557,11 @@ void rxrpc_post_response(struct rxrpc_connection *conn, struct sk_buff *skb)
spin_lock_irq(&local->lock);
old = conn->tx_response;
if (old) {
- struct rxrpc_skb_priv *osp = rxrpc_skb(skb);
+ struct rxrpc_skb_priv *osp = rxrpc_skb(old);
/* Always go with the response to the most recent challenge. */
if (after(sp->resp.challenge_serial, osp->resp.challenge_serial))
- conn->tx_response = old;
+ conn->tx_response = skb;
else
old = skb;
} else {
@@ -569,4 +569,5 @@ void rxrpc_post_response(struct rxrpc_connection *conn, struct sk_buff *skb)
}
spin_unlock_irq(&local->lock);
rxrpc_poke_conn(conn, rxrpc_conn_get_poke_response);
+ rxrpc_free_skb(old, rxrpc_skb_put_old_response);
}
^ permalink raw reply related
* [PATCH net v5 07/21] rxrpc: Fix rack timer warning to report unexpected mode
From: David Howells @ 2026-04-08 12:12 UTC (permalink / raw)
To: netdev
Cc: David Howells, Marc Dionne, Jakub Kicinski, David S. Miller,
Eric Dumazet, Paolo Abeni, linux-afs, linux-kernel, Alok Tiwari,
Simon Horman, Jeffrey Altman, stable
In-Reply-To: <20260408121252.2249051-1-dhowells@redhat.com>
From: Alok Tiwari <alok.a.tiwari@oracle.com>
rxrpc_rack_timer_expired() clears call->rack_timer_mode to OFF before
the switch. The default case warning therefore always prints OFF and
doesn't identify the unexpected timer mode.
Log the saved mode value instead so the warning reports the actual
unexpected rack timer mode.
Fixes: 7c482665931b ("rxrpc: Implement RACK/TLP to deal with transmission stalls [RFC8985]")
Signed-off-by: Alok Tiwari <alok.a.tiwari@oracle.com>
Signed-off-by: David Howells <dhowells@redhat.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Reviewed-by: Jeffrey Altman <jaltman@auristor.com>
cc: Marc Dionne <marc.dionne@auristor.com>
cc: Eric Dumazet <edumazet@google.com>
cc: "David S. Miller" <davem@davemloft.net>
cc: Jakub Kicinski <kuba@kernel.org>
cc: Paolo Abeni <pabeni@redhat.com>
cc: linux-afs@lists.infradead.org
cc: netdev@vger.kernel.org
cc: stable@kernel.org
---
net/rxrpc/input_rack.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/rxrpc/input_rack.c b/net/rxrpc/input_rack.c
index 13c371261e0a..9eb109ffba56 100644
--- a/net/rxrpc/input_rack.c
+++ b/net/rxrpc/input_rack.c
@@ -413,6 +413,6 @@ void rxrpc_rack_timer_expired(struct rxrpc_call *call, ktime_t overran_by)
break;
//case RXRPC_CALL_RACKTIMER_ZEROWIN:
default:
- pr_warn("Unexpected rack timer %u", call->rack_timer_mode);
+ pr_warn("Unexpected rack timer %u", mode);
}
}
^ permalink raw reply related
* [PATCH net v5 08/21] rxrpc: Fix key reference count leak from call->key
From: David Howells @ 2026-04-08 12:12 UTC (permalink / raw)
To: netdev
Cc: David Howells, Marc Dionne, Jakub Kicinski, David S. Miller,
Eric Dumazet, Paolo Abeni, linux-afs, linux-kernel,
Anderson Nascimento, Jeffrey Altman, Simon Horman, stable
In-Reply-To: <20260408121252.2249051-1-dhowells@redhat.com>
From: Anderson Nascimento <anderson@allelesecurity.com>
When creating a client call in rxrpc_alloc_client_call(), the code obtains
a reference to the key. This is never cleaned up and gets leaked when the
call is destroyed.
Fix this by freeing call->key in rxrpc_destroy_call().
Before the patch, it shows the key reference counter elevated:
$ cat /proc/keys | grep afs@54321
1bffe9cd I--Q--i 8053480 4169w 3b010000 1000 1000 rxrpc afs@54321: ka
$
After the patch, the invalidated key is removed when the code exits:
$ cat /proc/keys | grep afs@54321
$
Fixes: f3441d4125fc ("rxrpc: Copy client call parameters into rxrpc_call earlier")
Signed-off-by: Anderson Nascimento <anderson@allelesecurity.com>
Co-developed-by: David Howells <dhowells@redhat.com>
Signed-off-by: David Howells <dhowells@redhat.com>
Reviewed-by: Jeffrey Altman <jaltman@auristor.com>
cc: Marc Dionne <marc.dionne@auristor.com>
cc: Eric Dumazet <edumazet@google.com>
cc: "David S. Miller" <davem@davemloft.net>
cc: Jakub Kicinski <kuba@kernel.org>
cc: Paolo Abeni <pabeni@redhat.com>
cc: Simon Horman <horms@kernel.org>
cc: linux-afs@lists.infradead.org
cc: netdev@vger.kernel.org
cc: stable@kernel.org
---
net/rxrpc/call_object.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/net/rxrpc/call_object.c b/net/rxrpc/call_object.c
index 59329cfe1532..f035f486c139 100644
--- a/net/rxrpc/call_object.c
+++ b/net/rxrpc/call_object.c
@@ -692,6 +692,7 @@ static void rxrpc_destroy_call(struct work_struct *work)
rxrpc_put_bundle(call->bundle, rxrpc_bundle_put_call);
rxrpc_put_peer(call->peer, rxrpc_peer_put_call);
rxrpc_put_local(call->local, rxrpc_local_put_call);
+ key_put(call->key);
call_rcu(&call->rcu, rxrpc_rcu_free_call);
}
^ permalink raw reply related
* [PATCH net v5 04/21] rxrpc: Fix call removal to use RCU safe deletion
From: David Howells @ 2026-04-08 12:12 UTC (permalink / raw)
To: netdev
Cc: David Howells, Marc Dionne, Jakub Kicinski, David S. Miller,
Eric Dumazet, Paolo Abeni, linux-afs, linux-kernel,
Jeffrey Altman, Linus Torvalds, Simon Horman, stable
In-Reply-To: <20260408121252.2249051-1-dhowells@redhat.com>
Fix rxrpc call removal from the rxnet->calls list to use list_del_rcu()
rather than list_del_init() to prevent stuffing up reading
/proc/net/rxrpc/calls from potentially getting into an infinite loop.
This, however, means that list_empty() no longer works on an entry that's
been deleted from the list, making it harder to detect prior deletion. Fix
this by:
Firstly, make rxrpc_destroy_all_calls() only dump the first ten calls that
are unexpectedly still on the list. Limiting the number of steps means
there's no need to call cond_resched() or to remove calls from the list
here, thereby eliminating the need for rxrpc_put_call() to check for that.
rxrpc_put_call() can then be fixed to unconditionally delete the call from
the list as it is the only place that the deletion occurs.
Fixes: 2baec2c3f854 ("rxrpc: Support network namespacing")
Closes: https://sashiko.dev/#/patchset/20260319150150.4189381-1-dhowells%40redhat.com
Signed-off-by: David Howells <dhowells@redhat.com>
cc: Marc Dionne <marc.dionne@auristor.com>
cc: Jeffrey Altman <jaltman@auristor.com>
cc: Linus Torvalds <torvalds@linux-foundation.org>
cc: Eric Dumazet <edumazet@google.com>
cc: "David S. Miller" <davem@davemloft.net>
cc: Jakub Kicinski <kuba@kernel.org>
cc: Paolo Abeni <pabeni@redhat.com>
cc: Simon Horman <horms@kernel.org>
cc: linux-afs@lists.infradead.org
cc: netdev@vger.kernel.org
cc: stable@kernel.org
---
include/trace/events/rxrpc.h | 2 +-
net/rxrpc/call_object.c | 24 +++++++++---------------
2 files changed, 10 insertions(+), 16 deletions(-)
diff --git a/include/trace/events/rxrpc.h b/include/trace/events/rxrpc.h
index 869f97c9bf73..a826cd80007b 100644
--- a/include/trace/events/rxrpc.h
+++ b/include/trace/events/rxrpc.h
@@ -347,7 +347,7 @@
EM(rxrpc_call_see_release, "SEE release ") \
EM(rxrpc_call_see_userid_exists, "SEE u-exists") \
EM(rxrpc_call_see_waiting_call, "SEE q-conn ") \
- E_(rxrpc_call_see_zap, "SEE zap ")
+ E_(rxrpc_call_see_still_live, "SEE !still-l")
#define rxrpc_txqueue_traces \
EM(rxrpc_txqueue_await_reply, "AWR") \
diff --git a/net/rxrpc/call_object.c b/net/rxrpc/call_object.c
index 918f41d97a2f..59329cfe1532 100644
--- a/net/rxrpc/call_object.c
+++ b/net/rxrpc/call_object.c
@@ -654,11 +654,9 @@ void rxrpc_put_call(struct rxrpc_call *call, enum rxrpc_call_trace why)
if (dead) {
ASSERTCMP(__rxrpc_call_state(call), ==, RXRPC_CALL_COMPLETE);
- if (!list_empty(&call->link)) {
- spin_lock(&rxnet->call_lock);
- list_del_init(&call->link);
- spin_unlock(&rxnet->call_lock);
- }
+ spin_lock(&rxnet->call_lock);
+ list_del_rcu(&call->link);
+ spin_unlock(&rxnet->call_lock);
rxrpc_cleanup_call(call);
}
@@ -730,24 +728,20 @@ void rxrpc_destroy_all_calls(struct rxrpc_net *rxnet)
_enter("");
if (!list_empty(&rxnet->calls)) {
- spin_lock(&rxnet->call_lock);
+ int shown = 0;
- while (!list_empty(&rxnet->calls)) {
- call = list_entry(rxnet->calls.next,
- struct rxrpc_call, link);
- _debug("Zapping call %p", call);
+ spin_lock(&rxnet->call_lock);
- rxrpc_see_call(call, rxrpc_call_see_zap);
- list_del_init(&call->link);
+ list_for_each_entry(call, &rxnet->calls, link) {
+ rxrpc_see_call(call, rxrpc_call_see_still_live);
pr_err("Call %p still in use (%d,%s,%lx,%lx)!\n",
call, refcount_read(&call->ref),
rxrpc_call_states[__rxrpc_call_state(call)],
call->flags, call->events);
- spin_unlock(&rxnet->call_lock);
- cond_resched();
- spin_lock(&rxnet->call_lock);
+ if (++shown >= 10)
+ break;
}
spin_unlock(&rxnet->call_lock);
^ permalink raw reply related
* [PATCH net v5 09/21] rxrpc: Fix to request an ack if window is limited
From: David Howells @ 2026-04-08 12:12 UTC (permalink / raw)
To: netdev
Cc: David Howells, Marc Dionne, Jakub Kicinski, David S. Miller,
Eric Dumazet, Paolo Abeni, linux-afs, linux-kernel, Marc Dionne,
Jeffrey Altman, Simon Horman, stable
In-Reply-To: <20260408121252.2249051-1-dhowells@redhat.com>
From: Marc Dionne <marc.c.dionne@gmail.com>
Peers may only send immediate acks for every 2 UDP packets received.
When sending a jumbogram, it is important to check that there is
sufficient window space to send another same sized jumbogram following
the current one, and request an ack if there isn't. Failure to do so may
cause the call to stall waiting for an ack until the resend timer fires.
Where jumbograms are in use this causes a very significant drop in
performance.
Fixes: fe24a5494390 ("rxrpc: Send jumbo DATA packets")
Signed-off-by: Marc Dionne <marc.dionne@auristor.com>
Signed-off-by: David Howells <dhowells@redhat.com>
cc: Jeffrey Altman <jaltman@auristor.com>
cc: Eric Dumazet <edumazet@google.com>
cc: "David S. Miller" <davem@davemloft.net>
cc: Jakub Kicinski <kuba@kernel.org>
cc: Paolo Abeni <pabeni@redhat.com>
cc: Simon Horman <horms@kernel.org>
cc: linux-afs@lists.infradead.org
cc: netdev@vger.kernel.org
cc: stable@kernel.org
---
include/trace/events/rxrpc.h | 1 +
net/rxrpc/ar-internal.h | 2 +-
net/rxrpc/output.c | 2 ++
net/rxrpc/proc.c | 5 +++--
4 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/include/trace/events/rxrpc.h b/include/trace/events/rxrpc.h
index f7f559204b87..578b8038b211 100644
--- a/include/trace/events/rxrpc.h
+++ b/include/trace/events/rxrpc.h
@@ -521,6 +521,7 @@
#define rxrpc_req_ack_traces \
EM(rxrpc_reqack_ack_lost, "ACK-LOST ") \
EM(rxrpc_reqack_app_stall, "APP-STALL ") \
+ EM(rxrpc_reqack_jumbo_win, "JUMBO-WIN ") \
EM(rxrpc_reqack_more_rtt, "MORE-RTT ") \
EM(rxrpc_reqack_no_srv_last, "NO-SRVLAST") \
EM(rxrpc_reqack_old_rtt, "OLD-RTT ") \
diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h
index 36d6ca0d1089..96ecb83c9071 100644
--- a/net/rxrpc/ar-internal.h
+++ b/net/rxrpc/ar-internal.h
@@ -117,7 +117,7 @@ struct rxrpc_net {
atomic_t stat_tx_jumbo[10];
atomic_t stat_rx_jumbo[10];
- atomic_t stat_why_req_ack[8];
+ atomic_t stat_why_req_ack[9];
atomic_t stat_io_loop;
};
diff --git a/net/rxrpc/output.c b/net/rxrpc/output.c
index d70db367e358..870e59bf06af 100644
--- a/net/rxrpc/output.c
+++ b/net/rxrpc/output.c
@@ -479,6 +479,8 @@ static size_t rxrpc_prepare_data_subpacket(struct rxrpc_call *call,
why = rxrpc_reqack_old_rtt;
else if (!last && !after(READ_ONCE(call->send_top), txb->seq))
why = rxrpc_reqack_app_stall;
+ else if (call->tx_winsize <= (2 * req->n) || call->cong_cwnd <= (2 * req->n))
+ why = rxrpc_reqack_jumbo_win;
else
goto dont_set_request_ack;
diff --git a/net/rxrpc/proc.c b/net/rxrpc/proc.c
index 59292f7f9205..7755fca5beb8 100644
--- a/net/rxrpc/proc.c
+++ b/net/rxrpc/proc.c
@@ -518,11 +518,12 @@ int rxrpc_stats_show(struct seq_file *seq, void *v)
atomic_read(&rxnet->stat_rx_acks[RXRPC_ACK_IDLE]),
atomic_read(&rxnet->stat_rx_acks[0]));
seq_printf(seq,
- "Why-Req-A: acklost=%u mrtt=%u ortt=%u stall=%u\n",
+ "Why-Req-A: acklost=%u mrtt=%u ortt=%u stall=%u jwin=%u\n",
atomic_read(&rxnet->stat_why_req_ack[rxrpc_reqack_ack_lost]),
atomic_read(&rxnet->stat_why_req_ack[rxrpc_reqack_more_rtt]),
atomic_read(&rxnet->stat_why_req_ack[rxrpc_reqack_old_rtt]),
- atomic_read(&rxnet->stat_why_req_ack[rxrpc_reqack_app_stall]));
+ atomic_read(&rxnet->stat_why_req_ack[rxrpc_reqack_app_stall]),
+ atomic_read(&rxnet->stat_why_req_ack[rxrpc_reqack_jumbo_win]));
seq_printf(seq,
"Why-Req-A: nolast=%u retx=%u slows=%u smtxw=%u\n",
atomic_read(&rxnet->stat_why_req_ack[rxrpc_reqack_no_srv_last]),
^ permalink raw reply related
* [PATCH net v5 10/21] rxrpc: Only put the call ref if one was acquired
From: David Howells @ 2026-04-08 12:12 UTC (permalink / raw)
To: netdev
Cc: David Howells, Marc Dionne, Jakub Kicinski, David S. Miller,
Eric Dumazet, Paolo Abeni, linux-afs, linux-kernel, Douya Le,
Yifan Wu, Juefei Pu, Yuan Tan, Xin Liu, Ao Zhou, Simon Horman,
stable
In-Reply-To: <20260408121252.2249051-1-dhowells@redhat.com>
From: Douya Le <ldy3087146292@gmail.com>
rxrpc_input_packet_on_conn() can process a to-client packet after the
current client call on the channel has already been torn down. In that
case chan->call is NULL, rxrpc_try_get_call() returns NULL and there is
no reference to drop.
The client-side implicit-end error path does not account for that and
unconditionally calls rxrpc_put_call(). This turns a protocol error
path into a kernel crash instead of rejecting the packet.
Only drop the call reference if one was actually acquired. Keep the
existing protocol error handling unchanged.
Fixes: 5e6ef4f1017c ("rxrpc: Make the I/O thread take over the call and local processor work")
Reported-by: Yifan Wu <yifanwucs@gmail.com>
Reported-by: Juefei Pu <tomapufckgml@gmail.com>
Signed-off-by: Douya Le <ldy3087146292@gmail.com>
Co-developed-by: Yuan Tan <tanyuan98@gmail.com>
Signed-off-by: Yuan Tan <tanyuan98@gmail.com>
Suggested-by: Xin Liu <bird@lzu.edu.cn>
Signed-off-by: Ao Zhou <n05ec@lzu.edu.cn>
Signed-off-by: David Howells <dhowells@redhat.com>
cc: Marc Dionne <marc.dionne@auristor.com>
cc: Eric Dumazet <edumazet@google.com>
cc: "David S. Miller" <davem@davemloft.net>
cc: Jakub Kicinski <kuba@kernel.org>
cc: Paolo Abeni <pabeni@redhat.com>
cc: Simon Horman <horms@kernel.org>
cc: linux-afs@lists.infradead.org
cc: netdev@vger.kernel.org
cc: stable@kernel.org
---
net/rxrpc/io_thread.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/net/rxrpc/io_thread.c b/net/rxrpc/io_thread.c
index e939ecf417c4..697956931925 100644
--- a/net/rxrpc/io_thread.c
+++ b/net/rxrpc/io_thread.c
@@ -419,7 +419,8 @@ static int rxrpc_input_packet_on_conn(struct rxrpc_connection *conn,
if (sp->hdr.callNumber > chan->call_id) {
if (rxrpc_to_client(sp)) {
- rxrpc_put_call(call, rxrpc_call_put_input);
+ if (call)
+ rxrpc_put_call(call, rxrpc_call_put_input);
return rxrpc_protocol_error(skb,
rxrpc_eproto_unexpected_implicit_end);
}
^ permalink raw reply related
* [PATCH net v5 11/21] rxrpc: reject undecryptable rxkad response tickets
From: David Howells @ 2026-04-08 12:12 UTC (permalink / raw)
To: netdev
Cc: David Howells, Marc Dionne, Jakub Kicinski, David S. Miller,
Eric Dumazet, Paolo Abeni, linux-afs, linux-kernel, Yuqi Xu,
Yifan Wu, Juefei Pu, Yuan Tan, Xin Liu, Ren Wei, Ren Wei,
Simon Horman, stable
In-Reply-To: <20260408121252.2249051-1-dhowells@redhat.com>
From: Yuqi Xu <xuyuqiabc@gmail.com>
rxkad_decrypt_ticket() decrypts the RXKAD response ticket and then
parses the buffer as plaintext without checking whether
crypto_skcipher_decrypt() succeeded.
A malformed RESPONSE can therefore use a non-block-aligned ticket
length, make the decrypt operation fail, and still drive the ticket
parser with attacker-controlled bytes.
Check the decrypt result and abort the connection with RXKADBADTICKET
when ticket decryption fails.
Fixes: 17926a79320a ("[AF_RXRPC]: Provide secure RxRPC sockets for use by userspace and kernel both")
Reported-by: Yifan Wu <yifanwucs@gmail.com>
Reported-by: Juefei Pu <tomapufckgml@gmail.com>
Co-developed-by: Yuan Tan <yuantan098@gmail.com>
Signed-off-by: Yuan Tan <yuantan098@gmail.com>
Suggested-by: Xin Liu <bird@lzu.edu.cn>
Tested-by: Ren Wei <enjou1224z@gmail.com>
Signed-off-by: Yuqi Xu <xuyuqiabc@gmail.com>
Signed-off-by: Ren Wei <n05ec@lzu.edu.cn>
Signed-off-by: David Howells <dhowells@redhat.com>
cc: Marc Dionne <marc.dionne@auristor.com>
cc: Eric Dumazet <edumazet@google.com>
cc: "David S. Miller" <davem@davemloft.net>
cc: Jakub Kicinski <kuba@kernel.org>
cc: Paolo Abeni <pabeni@redhat.com>
cc: Simon Horman <horms@kernel.org>
cc: linux-afs@lists.infradead.org
cc: netdev@vger.kernel.org
cc: stable@kernel.org
---
net/rxrpc/rxkad.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/net/rxrpc/rxkad.c b/net/rxrpc/rxkad.c
index e923d6829008..0f79d694cb08 100644
--- a/net/rxrpc/rxkad.c
+++ b/net/rxrpc/rxkad.c
@@ -958,6 +958,7 @@ static int rxkad_decrypt_ticket(struct rxrpc_connection *conn,
struct in_addr addr;
unsigned int life;
time64_t issue, now;
+ int ret;
bool little_endian;
u8 *p, *q, *name, *end;
@@ -977,8 +978,11 @@ static int rxkad_decrypt_ticket(struct rxrpc_connection *conn,
sg_init_one(&sg[0], ticket, ticket_len);
skcipher_request_set_callback(req, 0, NULL, NULL);
skcipher_request_set_crypt(req, sg, sg, ticket_len, iv.x);
- crypto_skcipher_decrypt(req);
+ ret = crypto_skcipher_decrypt(req);
skcipher_request_free(req);
+ if (ret < 0)
+ return rxrpc_abort_conn(conn, skb, RXKADBADTICKET, -EPROTO,
+ rxkad_abort_resp_tkt_short);
p = ticket;
end = p + ticket_len;
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox