* Re: [PATCH v2] net/intel: Replace manual array size calculation with ARRAY_SIZE
From: Dan Carpenter @ 2026-04-22 13:24 UTC (permalink / raw)
To: Jakub Raczynski
Cc: netdev, kuba, przemyslaw.kitszel, anthony.l.nguyen,
kernel-janitors
In-Reply-To: <20260422105710.268003-1-j.raczynski@samsung.com>
On Wed, Apr 22, 2026 at 12:57:12PM +0200, Jakub Raczynski wrote:
> There are still places in the code where manual calculation of array size
> exist, but it is good to enforce usage of single macro through the whole
> code as it makes code bit more readable.
> While at it, beautify condition surrounding it by reversing check and remove
> unnecessary casting.
>
> Signed-off-by: Jakub Raczynski <j.raczynski@samsung.com>
> ---
Thanks.
Reviewed-by: Dan Carpenter <error27@gmail.com>
regards,
dan carpenter
^ permalink raw reply
* [PATCH] m68k: mvme147: Make me the maintainer
From: Daniel Palmer @ 2026-04-22 13:27 UTC (permalink / raw)
To: andrew+netdev
Cc: geert, James.Bottomley, martin.petersen, davem, edumazet, kuba,
pabeni, linux-m68k, linux-scsi, netdev, linux-kernel,
Daniel Palmer
I'm actively using mainline + patches on this board as a bootloader
for another VME board and as a terminal server using a multiport
serial board in the same VME backplane. I even have mainline u-boot
on real EPROMs.
Make me the maintainer of its ethernet, scsi and arch code so I get
an email before one or more of them get deleted.
Signed-off-by: Daniel Palmer <daniel@thingy.jp>
---
MAINTAINERS | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index d25342ca8aa1..9949b5528bcf 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -15311,6 +15311,13 @@ S: Maintained
W: http://www.tazenda.demon.co.uk/phil/linux-hp
F: arch/m68k/hp300/
+M68K ON MVME147
+M: Daniel Palmer <daniel@thingy.jp>
+S: Maintained
+F: arch/m68k/mvme147/
+F: drivers/net/ethernet/amd/mvme147.c
+F: drivers/scsi/mvme147.*
+
M88DS3103 MEDIA DRIVER
L: linux-media@vger.kernel.org
S: Orphan
--
2.53.0
^ permalink raw reply related
* Re: [net-next v2 0/3] Add motorcomm 8531s set ds func and 8522 driver
From: Andrew Lunn @ 2026-04-22 13:27 UTC (permalink / raw)
To: Minda Chen
Cc: Frank, Andrew Lunn, Heiner Kallweit, David S . Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, netdev, linux-kernel
In-Reply-To: <20260422083255.29692-1-minda.chen@starfivetech.com>
On Wed, Apr 22, 2026 at 04:32:52PM +0800, Minda Chen wrote:
> This patch is for Starfive JHB100 EVB board. JHB100 contain
> 1 RGMII/RMII and 1 RMII synopsys GMAC cores. In the EVB board, RGMII
> interface connect with YT8531s Ethernet PHY. RMII interface connect
> with YT8522 ethernet PHY. So patch 1-2 is for RGMII interface
> patch 3 is RMII is for RMII interface.
>
> JHB100 is a Starfive new RISC-V SoC for datacenter BMC (BaseBoard
> Managent Controller). Similar with Aspeed 27x0.
>
> The JHB100 minimal system upstream is in progress:
> https://patchwork.kernel.org/project/linux-riscv/cover/20260403054945.467700-1-changhuang.liang@starfivetech.com/
Please take a read of sections 1.3 and 1.4 of:
https://www.kernel.org/doc/html/latest/process/maintainer-netdev.html
Andrew
---
pw-bot: cr
^ permalink raw reply
* Re: [PATCH RFC net-next v2 2/2] af_packet: Add port specific handling for HSR
From: Sebastian Andrzej Siewior @ 2026-04-22 13:27 UTC (permalink / raw)
To: Willem de Bruijn
Cc: netdev, (JC), Jayachandran, David S. Miller, Andrew Lunn,
Chintan Vankar, Danish Anwar, Daolin Qiu, Eric Dumazet,
Felix Maurer, Jakub Kicinski, Paolo Abeni, Richard Cochran,
Simon Horman, Raghavendra, Vignesh, Bajjuri, Praneeth,
TK, Pratheesh Gangadhar, Muralidharan, Neelima
In-Reply-To: <willemdebruijn.kernel.270fa204f615f@gmail.com>
On 2026-04-21 03:41:52 [-0400], Willem de Bruijn wrote:
> Sebastian Andrzej Siewior wrote:
Hi Willem,
> > I understand your concern. I tried to make as self contained as
> > possible and little runtime overhead as possible.
> >
> > > One perhaps interesting Rx only option I had missed before is
> > > SOF_TIMESTAMPING_OPT_PKTINFO. Would that give you the original
> > > device ifindex today?
> >
> > The upper logic expects to poll() on the fd. If I need to filter the
> > device based on this then breaks the expectations.
> > I need also to receive packets without a timestamp so I don't think this
> > works.
>
> I don't follow this. My suggestion is to optionally receive this
> additional metadata along with the data. Not as a filter.
Yes. Just ignore that part.
> > cb[] is limited to one layer. I do have a skb_ext variant working but
> > this requires cmsg to set it. Do you think about generic skb_ext which
> > is set from af_packet? But I don't think it brings much value if I can't
> > filter on the RX side before returning the packet to userland.
> >
> > > But at this point I see enough options that do not require changes
> > > to packet sockets.
> > >
> > > To get back to the simplest approach: skb->mark. Is there any
> > > concrete risk that on this path that would conflict with other
> > > uses of that field? If packet sockets inject directly into this
> > > driver (possibly even with PACKET_QDISC_BYPASS)?
> >
> > So I have a skb->mark variant working. I do read on the ethX interface
>
> When reading on both ethX interfaces, that gives you all the info you
> need on Rx, right? Or alternatively by attaching to hsr0 with
> SOF_TIMESTAMPING_OPT_PKTINFO.
>
> So skb->mark is only relevant to the Tx side, right? There might be
> yet another way to identify in the hsr ndo_start_xmit that a packet
> arrived from a PF_PACKET socket. E.g., by checking skb->sk->sk_family.
> As alternative or complement to skb->protocol.
>
> Btw, on receive the inverse could also be true: insert a synthetic
> header and pop that in userspace, e.g., a VLAN tag.
So I made this:
I open hsr0 for TX with a custom header. The header is expected if the
ether-type is set to PTP. This extra header holds the HSR-header
information and port request.
I open eth0 for RX. I set PACKET_IGNORE_OUTGOING to avoid the feedback
from hsr0 writes. This is part is crucial ;)
I use skb_ext to pass the information from the inline-header to
the network driver since the data pointer of the skb is forwarded after
that header. In the end I have no idea if the network driver supports HW
offloading and needs this information or not and sends the packet as-is.
HW offloading becomes a bit tricky but relying on skb_ext (for HSR) and
checking otherwise for the ether type vs PTP (in the PRP case) does the
trick.
So it is slightly more complicated but seems to work.
Let me wait until after the merge window and then I present what I have.
Sebastian
^ permalink raw reply
* Re: [PATCH] mptcp: do not drop partial packets
From: Paolo Abeni @ 2026-04-22 13:51 UTC (permalink / raw)
To: Shardul Bankar, matttbe, martineau
Cc: geliang, davem, edumazet, kuba, horms, netdev, mptcp,
linux-kernel, janak, kalpan.jani, Shardul Bankar
In-Reply-To: <20260422120954.8877-1-shardul.b@mpiricsoftware.com>
On 4/22/26 2:09 PM, Shardul Bankar wrote:
> diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
> index 614c3f583ca0..6858e6e283e3 100644
> --- a/net/mptcp/protocol.c
> +++ b/net/mptcp/protocol.c
> @@ -397,12 +397,27 @@ static bool __mptcp_move_skb(struct sock *sk, struct sk_buff *skb)
> return false;
> }
>
> - /* old data, keep it simple and drop the whole pkt, sender
> - * will retransmit as needed, if needed.
> + /* Completely old data? */
> + if (!after64(MPTCP_SKB_CB(skb)->end_seq, msk->ack_seq)) {
> + MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_DUPDATA);
> + mptcp_drop(sk, skb);
> + return false;
> + }
> +
> + /* Partial packet: map_seq < ack_seq < end_seq.
> + * Skip the already-acked bytes and enqueue the new data.
> */
> - MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_DUPDATA);
> - mptcp_drop(sk, skb);
> - return false;
> + copy_len = MPTCP_SKB_CB(skb)->end_seq - msk->ack_seq;
> + MPTCP_SKB_CB(skb)->offset += msk->ack_seq - MPTCP_SKB_CB(skb)->map_seq;
here MPTCP_SKB_CB(skb)->offset is always != 0 ...
> + msk->bytes_received += copy_len;
> + WRITE_ONCE(msk->ack_seq, msk->ack_seq + copy_len);
> + tail = skb_peek_tail(&sk->sk_receive_queue);
> + if (tail && mptcp_try_coalesce(sk, tail, skb))
... so mptcp_try_coalesce() will always fail.
/P
^ permalink raw reply
* Re: [PATCH net-next v2 13/14] net: macb: use context swapping in .set_ringparam()
From: Théo Lebrun @ 2026-04-22 14:00 UTC (permalink / raw)
To: Jakub Kicinski, Alexandre Belloni
Cc: nicolas.ferre, claudiu.beznea, andrew+netdev, davem, edumazet,
pabeni, richardcochran, linux, pvalerio, conor, nb,
vladimir.kondratiev, gregory.clement, benoit.monin, tawfik.bayouk,
thomas.petazzoni, maxime.chevallier, netdev, linux-kernel
In-Reply-To: <20260414005654.3766959-1-kuba@kernel.org>
On Tue Apr 14, 2026 at 2:56 AM CEST, Jakub Kicinski wrote:
> This is an AI-generated review of your patch. The human sending this
> email has considered the AI review valid, or at least plausible.
> ---
> net: macb: use context swapping in .set_ringparam()
>
> This patch modifies the ethtool set_ringparam implementation to use a
> context swapping mechanism. Instead of closing and reopening the interface,
> it allocates new buffers, stops the interface temporarily, swaps the active
> context, and then frees the old one.
>
>> diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c
>> index 3deab87c565b5..d1536cb1e40bb 100644
>> --- a/drivers/net/ethernet/cadence/macb_main.c
>> +++ b/drivers/net/ethernet/cadence/macb_main.c
>> @@ -3081,6 +3081,89 @@ static void macb_configure_dma(struct macb *bp)
> [ ... ]
>> +static void macb_context_swap_start(struct macb *bp)
>> +{
> [ ... ]
>> + for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) {
>> + napi_disable(&queue->napi_rx);
>> + napi_disable(&queue->napi_tx);
>
> This isn't a regression from this patch, but does calling napi_disable()
> unconditionally crash on EMAC devices?
>
> EMAC devices appear to not initialize NAPI, which leaves the NAPI struct
> zero-initialized (n->dev is NULL), potentially causing a NULL pointer
> dereference in napi_disable(). Additionally, does this path also blindly
> call bp->macbgem_ops.mog_init_rings() which is NULL on EMAC?
So the LLM is correct in that queue->napi_{rx,tx} fields are never
initialised on at91 platforms [0]. Then we use the fields from many
places without checking.
Most are safe because at91 uses its own netdev_ops.
Functions that get called on at91 and do NAPI calls are:
- macb_suspend() & macb_resume() => system-wide suspend => ignored
- macb_{close,open}() called by macb_set_ringparam()
The codepaths for at91 are so different, context swap support for at91
sounds unrelevant. I'll update both change_mtu and set_ringparam to
return -EOPNOTSUPP if netif_running() && IS_EMAC.
[0]: NAPI fields are initialised in macb_init_dflt() which is either
used as the default config->init() or called by some of those init
functions. at91ether_init() doesn't.
>
>> + netdev_tx_reset_queue(netdev_get_tx_queue(bp->netdev, q));
>> + cancel_work_sync(&queue->tx_error_task);
>> + }
> [ ... ]
>> +static void macb_context_swap_end(struct macb *bp,
>> + struct macb_context *new_ctx)
>> +{
> [ ... ]
>> + /* Swap contexts & give buffer pointers to HW. */
>> +
>> + old_ctx = bp->ctx;
>> + bp->ctx = new_ctx;
>> + macb_init_buffers(bp);
>
> Since the new context swap doesn't call phylink_stop(), could a concurrent
> macb_mac_link_up() execution set the RE and TE bits in NCR during the window
> where bp->lock is dropped?
>
> If so, macb_init_buffers() would write new DMA ring base addresses to RBQP
> and TBQP while the MAC is actively enabled, which violates hardware
> specifications and could cause DMA corruption.
Again this is correct. We can have a race inbetween the swap and phylink
callbacks. However running phylink_stop() would partially ruin the idea
behind context swapping.
bp->lock is not the solution. We need either to disable phylink
operations for the swap duration or to synchronise with them. We cannot
grab bp->lock for the whole swap timespan because some calls might want
to sleep.
Both .mac_link_{up,down}() get called by phylink_resolve() which
acquires phydev->mutex [1]. Getting this mutex for the swap operation
sounds like the solution. PHY status updates will be delayed until the
end of our context swap operation (or the opposite).
Accessible from bp->netdev->phydev->lock. A few drivers already grab
that lock, but no one is for context swapping. Looked at fbnic for
example and there is no sync inbetween phylink ops and set_ringparam.
See fbnic_set_ringparam(), fbnic_phylink_mac_link_down
(), fbnic_mac_link_down_asic(). Maybe the sequence has been crafted to
work fine with concurrent accesses?
⟩ git grep -l 'mutex_lock.*phydev' drivers/net/ethernet/
drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
drivers/net/ethernet/broadcom/genet/bcmmii.c
drivers/net/ethernet/cadence/macb_main.c
drivers/net/ethernet/faraday/ftgmac100.c
drivers/net/ethernet/realtek/r8169_main.c
drivers/net/ethernet/ti/icssg/icssg_prueth.c
[1]: https://elixir.bootlin.com/linux/v7.0/source/drivers/net/phy/phylink.c#L1620
>> + if (!(bp->caps & MACB_CAPS_MACB_IS_EMAC)) {
>> + for (q = 0, queue = bp->queues; q < bp->num_queues;
>> + ++q, ++queue) {
>> + queue_writel(queue, IER,
>> + bp->rx_intr_mask |
>> + MACB_TX_INT_FLAGS |
>> + MACB_BIT(HRESP));
>> + }
>> + }
>
> Hardware interrupts are disabled unconditionally for all devices in
> macb_context_swap_start() by writing -1 to IDR.
>
> Will this explicit check prevent EMAC devices from having their interrupts
> re-enabled?
>
> Since EMAC devices do not use NAPI and rely on hardware interrupts, leaving
> them masked might silently halt all network traffic after a ring parameter
> change.
The check will be dropped. As said above, context swapping won't support
at91 platforms.
>> + ctrl = macb_readl(bp, NCR);
>> + macb_writel(bp, NCR, ctrl | MACB_BIT(RE) | MACB_BIT(TE));
>
> Can this unprotected read-modify-write of the NCR register race with phylink
> state changes?
>
> If an asynchronous phylink callback like macb_mac_config() modifies NCR
> while holding bp->lock, this unlocked write could overwrite and drop those
> concurrent updates.
The phydev->lock will help here as well.
macb_mac_config() == phylink_mac_ops::mac_config()
<- phylink_mac_config()
<- phylink_major_config()
<- phylink_resolve() (OR phylink_mac_initial_config())
both grab phydev->lock
>
>> +
>> + netif_tx_start_all_queues(bp->netdev);
>> +
>> + /* Free old context. */
>> +
>> + macb_free_consistent(old_ctx);
>
> This isn't a regression from this patch, but does this context swap leak
> pending TX packets and their DMA mappings?
>
> When freeing the old context, macb_free_consistent() appears to only free
> the pointer array. If it doesn't iterate from txq->tail to txq->head to
> unmap the active DMA mappings and free the sk_buff structs, repeatedly
> modifying ring parameters could cause a memory and DMA mapping leak.
Yes it does. I already have a patch pending. This bug has been present
since forever. :-)
Thanks,
--
Théo Lebrun, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply
* [PATCH ipsec 0/3] xfrm: Don't clobber inner headers when already set
From: Cosmin Ratiu @ 2026-04-22 14:06 UTC (permalink / raw)
To: netdev
Cc: Steffen Klassert, Herbert Xu, David S . Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Andrew Lunn,
Shuah Khan, Cosmin Ratiu, Nimrod Oren, Carolina Jubran,
Gal Pressman, linux-kselftest
Commit [1] exposed an existing issue in xfrm which broke tunneling
protocols over IPsec (e.g. VXLAN over IPsec).
This series fixes that and adds a test which exercises VXLAN over IPsec.
For details please see the individual patches.
[1] commit 7fb4c1967011 ("net: pull headers in qdisc_pkt_len_segs_init()")
Cosmin Ratiu (3):
tools/selftests: Use a sensible timeout value for iperf3 client
tools/selftests: Add a VXLAN+IPsec traffic test
xfrm: Don't clobber inner headers when already set
net/xfrm/xfrm_output.c | 20 +-
.../testing/selftests/drivers/net/hw/Makefile | 1 +
tools/testing/selftests/drivers/net/hw/config | 5 +
.../selftests/drivers/net/hw/ipsec_vxlan.py | 204 ++++++++++++++++++
.../selftests/drivers/net/lib/py/load.py | 5 +-
5 files changed, 228 insertions(+), 7 deletions(-)
create mode 100755 tools/testing/selftests/drivers/net/hw/ipsec_vxlan.py
--
2.53.0
^ permalink raw reply
* [PATCH net v2] net: usb: rtl8150: fix use-after-free in rtl8150_start_xmit()
From: Morduan Zang @ 2026-04-22 14:07 UTC (permalink / raw)
To: michal.pecio
Cc: andrew+netdev, davem, edumazet, kuba, linux-kernel, linux-usb,
netdev, pabeni, petkan, syzbot+3f46c095ac0ca048cb71,
syzkaller-bugs, zhangdandan, zhanjun, Andrew Lunn
In-Reply-To: <20260421220547.2f7f9d85.michal.pecio@gmail.com>
From: Zhan Jun <zhanjun@uniontech.com>
syzbot reported a KASAN slab-use-after-free read in rtl8150_start_xmit()
when accessing skb->len for tx statistics after usb_submit_urb() has
been called:
BUG: KASAN: slab-use-after-free in rtl8150_start_xmit+0x71f/0x760
drivers/net/usb/rtl8150.c:712
Read of size 4 at addr ffff88810eb7a930 by task kworker/0:4/5226
The URB completion handler write_bulk_callback() frees the skb via
dev_kfree_skb_irq(dev->tx_skb). The URB may complete on another CPU
in softirq context before usb_submit_urb() returns in the submitter,
so by the time the submitter reads skb->len the skb has already been
queued to the per-CPU completion_queue and freed by net_tx_action():
CPU A (xmit) CPU B (USB completion softirq)
------------ ------------------------------
dev->tx_skb = skb;
usb_submit_urb() --+
|-------> write_bulk_callback()
| dev_kfree_skb_irq(dev->tx_skb)
| net_tx_action()
| napi_skb_cache_put() <-- free
netdev->stats.tx_bytes |
+= skb->len; <-- UAF read
Fix it by caching skb->len before submitting the URB and using the
cached value when updating the tx_bytes counter.
The pre-existing tx_bytes semantics are preserved: the counter tracks
the original frame length (skb->len), not the ETH_ZLEN/USB-alignment
padded "count" value that is handed to the device. Changing that
would be a user-visible accounting change and is out of scope for
this UAF fix.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Reported-by: syzbot+3f46c095ac0ca048cb71@syzkaller.appspotmail.com
Closes: https://lore.kernel.org/all/69e69ee7.050a0220.24bfd3.002b.GAE@google.com/
Closes: https://syzkaller.appspot.com/bug?extid=3f46c095ac0ca048cb71
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Zhan Jun <zhanjun@uniontech.com>
---
Changes in v2:
- Drop the vague "This mirrors the fix pattern used by other USB
network drivers." claim from the changelog (Michal Pecio).
- Clarify that the patch intentionally preserves the existing
tx_bytes semantics (no ETH_ZLEN/USB padding accounted), and that
adjusting that is out of scope for this UAF fix (Michal Pecio).
- Use the correct "[PATCH net]" subject prefix per
Documentation/process/maintainer-netdev.rst (Andrew Lunn).
- Add Reviewed-by: Andrew Lunn.
- No functional changes; code diff is identical to v1.
v1: https://lore.kernel.org/all/73ACB7391A6DE033+20260421110412.14795-1-zhangdandan@uniontech.com/
---
drivers/net/usb/rtl8150.c | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c
index 4cda0643afb6..6fc6be0cced6 100644
--- a/drivers/net/usb/rtl8150.c
+++ b/drivers/net/usb/rtl8150.c
@@ -683,6 +683,7 @@ static netdev_tx_t rtl8150_start_xmit(struct sk_buff *skb,
struct net_device *netdev)
{
rtl8150_t *dev = netdev_priv(netdev);
+ unsigned int skb_len;
int count, res;
/* pad the frame and ensure terminating USB packet, datasheet 9.2.3 */
@@ -694,6 +695,14 @@ static netdev_tx_t rtl8150_start_xmit(struct sk_buff *skb,
return NETDEV_TX_OK;
}
+ /*
+ * Cache skb->len before submitting the URB: the URB completion
+ * handler (write_bulk_callback) frees the skb, and it may run
+ * on another CPU before usb_submit_urb() returns, which would
+ * leave skb dangling here.
+ */
+ skb_len = skb->len;
+
netif_stop_queue(netdev);
dev->tx_skb = skb;
usb_fill_bulk_urb(dev->tx_urb, dev->udev, usb_sndbulkpipe(dev->udev, 2),
@@ -709,7 +718,7 @@ static netdev_tx_t rtl8150_start_xmit(struct sk_buff *skb,
}
} else {
netdev->stats.tx_packets++;
- netdev->stats.tx_bytes += skb->len;
+ netdev->stats.tx_bytes += skb_len;
netif_trans_update(netdev);
}
--
2.51.0
^ permalink raw reply related
* [PATCH ipsec 3/3] xfrm: Don't clobber inner headers when already set
From: Cosmin Ratiu @ 2026-04-22 14:06 UTC (permalink / raw)
To: netdev
Cc: Steffen Klassert, Herbert Xu, David S . Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Andrew Lunn,
Shuah Khan, Cosmin Ratiu, Nimrod Oren, Carolina Jubran,
Gal Pressman, linux-kselftest
In-Reply-To: <20260422140648.3877129-1-cratiu@nvidia.com>
On VXLAN over IPsec egress, xfrm{4,6}_transport_output() blindly
overwrite inner_transport_header (== the inner TCP header saved in VXLAN
iptunnel_handle_offloads() -> skb_reset_inner_headers()) with the
current transport_header (== the VXLAN outer UDP header set by
udp_tunnel_xmit_skb()).
This was a latent bug, harmless until commit [1] added a doff validation
check in qdisc_pkt_len_segs_init() for encapsulated GSO packets. With
the wrong inner_transport_header set by xfrm, qdisc_pkt_len_segs_init()
interprets inner_transport_header as a TCP header, reads doff=0 from the
upper byte of the VNI and drops the packet with DROP_REASON_SKB_BAD_GSO.
Besides the use in GSO to determine the header size of segmented
packets, inner_transport_header might be used by drivers to set up
inner checksum offloading by pointing the HW to the inner transport
header. A quick browse through available drivers shows that mlx5 uses
skb->csum_start specifically for this scenario, while others either
don't support VXLAN over IPsec crypto offload (ixgbe) or the HW is
capable of parsing the packets itself (nfp, Chelsio).
But in all cases, it is more correct to let the inner_transport_header
point to the innermost header instead of overwriting it in xfrm.
So fix this by guarding all four inner header save sites in
xfrm_output.c (xfrm{4,6}_transport_output, xfrm{4,6}_tunnel_encap_add)
with a check for skb->inner_protocol. When inner_protocol is set, a
tunnel layer (VXLAN, Geneve, GRE, etc.) has already saved the correct
inner header offsets and they must not be overwritten. When
inner_protocol is zero, no prior tunnel encapsulation exists and xfrm
must save the inner headers itself. The tunnel mode checks are only
added for completion, since they aren't strictly required, as
xfrm_output() forces software GSO in tunnel mode before encap.
This makes the previously added test pass:
# ./tools/testing/selftests/drivers/net/hw/ipsec_vxlan.py
TAP version 13
1..4
ok 1 ipsec_vxlan.test_vxlan_ipsec_crypto_offload.outer_v4_inner_v4
ok 2 ipsec_vxlan.test_vxlan_ipsec_crypto_offload.outer_v4_inner_v6
ok 3 ipsec_vxlan.test_vxlan_ipsec_crypto_offload.outer_v6_inner_v4
ok 4 ipsec_vxlan.test_vxlan_ipsec_crypto_offload.outer_v6_inner_v6
# Totals: pass:4 fail:0 xfail:0 xpass:0 skip:0 error:0
[1] commit 7fb4c1967011 ("net: pull headers in qdisc_pkt_len_segs_init()")
Fixes: f1bd7d659ef0 ("xfrm: Add encapsulation header offsets while SKB is not encrypted")
Signed-off-by: Cosmin Ratiu <cratiu@nvidia.com>
---
net/xfrm/xfrm_output.c | 20 ++++++++++++++------
1 file changed, 14 insertions(+), 6 deletions(-)
diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c
index a9652b422f51..cc35c2fcbbe0 100644
--- a/net/xfrm/xfrm_output.c
+++ b/net/xfrm/xfrm_output.c
@@ -66,7 +66,9 @@ static int xfrm4_transport_output(struct xfrm_state *x, struct sk_buff *skb)
struct iphdr *iph = ip_hdr(skb);
int ihl = iph->ihl * 4;
- skb_set_inner_transport_header(skb, skb_transport_offset(skb));
+ if (!skb->inner_protocol)
+ skb_set_inner_transport_header(skb,
+ skb_transport_offset(skb));
skb_set_network_header(skb, -x->props.header_len);
skb->mac_header = skb->network_header +
@@ -167,7 +169,9 @@ static int xfrm6_transport_output(struct xfrm_state *x, struct sk_buff *skb)
int hdr_len;
iph = ipv6_hdr(skb);
- skb_set_inner_transport_header(skb, skb_transport_offset(skb));
+ if (!skb->inner_protocol)
+ skb_set_inner_transport_header(skb,
+ skb_transport_offset(skb));
hdr_len = xfrm6_hdr_offset(x, skb, &prevhdr);
if (hdr_len < 0)
@@ -276,8 +280,10 @@ static int xfrm4_tunnel_encap_add(struct xfrm_state *x, struct sk_buff *skb)
struct iphdr *top_iph;
int flags;
- skb_set_inner_network_header(skb, skb_network_offset(skb));
- skb_set_inner_transport_header(skb, skb_transport_offset(skb));
+ if (!skb->inner_protocol) {
+ skb_set_inner_network_header(skb, skb_network_offset(skb));
+ skb_set_inner_transport_header(skb, skb_transport_offset(skb));
+ }
skb_set_network_header(skb, -x->props.header_len);
skb->mac_header = skb->network_header +
@@ -321,8 +327,10 @@ static int xfrm6_tunnel_encap_add(struct xfrm_state *x, struct sk_buff *skb)
struct ipv6hdr *top_iph;
int dsfield;
- skb_set_inner_network_header(skb, skb_network_offset(skb));
- skb_set_inner_transport_header(skb, skb_transport_offset(skb));
+ if (!skb->inner_protocol) {
+ skb_set_inner_network_header(skb, skb_network_offset(skb));
+ skb_set_inner_transport_header(skb, skb_transport_offset(skb));
+ }
skb_set_network_header(skb, -x->props.header_len);
skb->mac_header = skb->network_header +
--
2.53.0
^ permalink raw reply related
* [PATCH ipsec 1/3] tools/selftests: Use a sensible timeout value for iperf3 client
From: Cosmin Ratiu @ 2026-04-22 14:06 UTC (permalink / raw)
To: netdev
Cc: Steffen Klassert, Herbert Xu, David S . Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Andrew Lunn,
Shuah Khan, Cosmin Ratiu, Nimrod Oren, Carolina Jubran,
Gal Pressman, linux-kselftest
In-Reply-To: <20260422140648.3877129-1-cratiu@nvidia.com>
The default timeout of cmd() is 5 seconds and Iperf3Runner requests the
iperf3 client to run for 10 seconds, which clearly doesn't work since
commit [1] enforced the timeout parameter.
Use a value derived from duration as timeout (+5 seconds for
startup/teardown/various other overhead).
[1] commit f0bd19316663 ("selftests: net: fix timeout passed as positional argument to communicate()")
Signed-off-by: Cosmin Ratiu <cratiu@nvidia.com>
---
tools/testing/selftests/drivers/net/lib/py/load.py | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/tools/testing/selftests/drivers/net/lib/py/load.py b/tools/testing/selftests/drivers/net/lib/py/load.py
index f181fa2d38fc..e24660e5c27f 100644
--- a/tools/testing/selftests/drivers/net/lib/py/load.py
+++ b/tools/testing/selftests/drivers/net/lib/py/load.py
@@ -48,7 +48,10 @@ class Iperf3Runner:
Starts the iperf3 client with the configured options.
"""
cmdline = self._build_client(streams, duration, reverse)
- return cmd(cmdline, background=background, host=self.env.remote)
+ kwargs = {"background": background, "host": self.env.remote}
+ if not background:
+ kwargs["timeout"] = duration + 5
+ return cmd(cmdline, **kwargs)
def measure_bandwidth(self, reverse=False):
"""
--
2.53.0
^ permalink raw reply related
* [PATCH ipsec 2/3] tools/selftests: Add a VXLAN+IPsec traffic test
From: Cosmin Ratiu @ 2026-04-22 14:06 UTC (permalink / raw)
To: netdev
Cc: Steffen Klassert, Herbert Xu, David S . Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Andrew Lunn,
Shuah Khan, Cosmin Ratiu, Nimrod Oren, Carolina Jubran,
Gal Pressman, linux-kselftest
In-Reply-To: <20260422140648.3877129-1-cratiu@nvidia.com>
There are VXLAN tests and IPsec tests, but there is no test that
combines the two protocols and exercises the tunnel-over-ipsec code
paths. Fix that by adding a traffic test with VXLAN and IPsec using
crypto offload. This is runnable on HW which supports ESP offload (so no
nsim unfortunately).
Traffic is done with iperf3 and the test validates that there are no
packet drops and iperf3 can get to at least 100 Mbps (a very
conservative value on today's crypto offload HW, as it can typically
reach multi-Gbps rates).
Ran right now, the test fails due to a recently exposed bug in xfrm,
which will be fixed in the next patch:
# ./tools/testing/selftests/drivers/net/hw/ipsec_vxlan.py
TAP version 13
1..4
# Check| At ./tools/testing/selftests/drivers/net/hw/ipsec_vxlan.py,
# line 161, in test_vxlan_ipsec_crypto_offload:
# Check| ksft_eq(drops_after - drops_before, 0,
# Check failed 189 != 0 TX drops during VXLAN+IPsec
# Check| At ./tools/testing/selftests/drivers/net/hw/ipsec_vxlan.py,
# line 163, in test_vxlan_ipsec_crypto_offload:
# Check| ksft_ge(bw_gbps, 0.1,
# Check failed 0.0015058278404812596 < 0.1 Minimum 100Mbps over
# VXLAN+IPsec
not ok 1 ipsec_vxlan.test_vxlan_ipsec_crypto_offload.outer_v4_inner_v4
...
Signed-off-by: Cosmin Ratiu <cratiu@nvidia.com>
---
.../testing/selftests/drivers/net/hw/Makefile | 1 +
tools/testing/selftests/drivers/net/hw/config | 5 +
.../selftests/drivers/net/hw/ipsec_vxlan.py | 204 ++++++++++++++++++
3 files changed, 210 insertions(+)
create mode 100755 tools/testing/selftests/drivers/net/hw/ipsec_vxlan.py
diff --git a/tools/testing/selftests/drivers/net/hw/Makefile b/tools/testing/selftests/drivers/net/hw/Makefile
index 85ca4d1ecf9e..3b6ff4708005 100644
--- a/tools/testing/selftests/drivers/net/hw/Makefile
+++ b/tools/testing/selftests/drivers/net/hw/Makefile
@@ -30,6 +30,7 @@ TEST_PROGS = \
gro_hw.py \
hw_stats_l3.sh \
hw_stats_l3_gre.sh \
+ ipsec_vxlan.py \
iou-zcrx.py \
irq.py \
loopback.sh \
diff --git a/tools/testing/selftests/drivers/net/hw/config b/tools/testing/selftests/drivers/net/hw/config
index dd50cb8a7911..ae0168c2bbe6 100644
--- a/tools/testing/selftests/drivers/net/hw/config
+++ b/tools/testing/selftests/drivers/net/hw/config
@@ -12,5 +12,10 @@ CONFIG_NET_IPGRE=y
CONFIG_NET_IPGRE_DEMUX=y
CONFIG_NETKIT=y
CONFIG_NET_SCH_INGRESS=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_ESP_OFFLOAD=y
+CONFIG_INET_ESP=y
+CONFIG_INET_ESP_OFFLOAD=y
CONFIG_UDMABUF=y
CONFIG_VXLAN=y
+CONFIG_XFRM_USER=y
diff --git a/tools/testing/selftests/drivers/net/hw/ipsec_vxlan.py b/tools/testing/selftests/drivers/net/hw/ipsec_vxlan.py
new file mode 100755
index 000000000000..0740a4d85240
--- /dev/null
+++ b/tools/testing/selftests/drivers/net/hw/ipsec_vxlan.py
@@ -0,0 +1,204 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0
+"""Traffic test for VXLAN + IPsec crypto-offload."""
+
+import os
+
+from lib.py import ksft_run, ksft_exit, ksft_eq, ksft_ge
+from lib.py import ksft_variants, KsftNamedVariant, KsftSkipEx
+from lib.py import CmdExitFailure, NetDrvEpEnv, cmd, defer, ethtool, ip
+from lib.py import Iperf3Runner
+
+# Inner tunnel addresses - TEST-NET-2 (RFC 5737) / doc prefix (RFC 3849)
+INNER_V4_LOCAL = "198.51.100.1"
+INNER_V4_REMOTE = "198.51.100.2"
+INNER_V6_LOCAL = "2001:db8:100::1"
+INNER_V6_REMOTE = "2001:db8:100::2"
+
+# ESP parameters
+SPI_OUT = "0x1000"
+SPI_IN = "0x1001"
+# 128-bit key + 32-bit salt = 20 bytes hex, 128-bit ICV
+ESP_AEAD = "aead 'rfc4106(gcm(aes))' 0x" + "01" * 20 + " 128"
+
+
+def xfrm(args, host=None):
+ """Runs 'ip xfrm' via shell to preserve parentheses in algo names."""
+ cmd(f"ip xfrm {args}", shell=True, host=host)
+
+
+def check_xfrm_offload_support():
+ """Skips if iproute2 lacks xfrm offload support."""
+ out = cmd("ip xfrm state help", fail=False)
+ if "offload" not in out.stdout + out.stderr:
+ raise KsftSkipEx("iproute2 too old, missing xfrm offload")
+
+
+def check_esp_hw_offload(cfg):
+ """Skips if device lacks esp-hw-offload support."""
+ check_xfrm_offload_support()
+ 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("esp-hw-offload", {}).get("active"):
+ raise KsftSkipEx("Device does not support esp-hw-offload")
+
+
+def get_tx_drops(cfg):
+ """Returns TX dropped counter from the physical device."""
+ stats = ip("-s -s link show dev " + cfg.ifname, json=True)[0]
+ return stats["stats64"]["tx"]["dropped"]
+
+
+def setup_vxlan_ipsec(cfg, outer_ipver, inner_ipver):
+ """Sets up VXLAN tunnel with IPsec transport-mode crypto-offload."""
+ vxlan_name = f"vx{os.getpid()}"
+ local_addr = cfg.addr_v[outer_ipver]
+ remote_addr = cfg.remote_addr_v[outer_ipver]
+
+ if inner_ipver == "4":
+ inner_local = f"{INNER_V4_LOCAL}/24"
+ inner_remote = f"{INNER_V4_REMOTE}/24"
+ addr_extra = ""
+ else:
+ inner_local = f"{INNER_V6_LOCAL}/64"
+ inner_remote = f"{INNER_V6_REMOTE}/64"
+ addr_extra = " nodad"
+
+ if outer_ipver == "6":
+ vxlan_opts = "udp6zerocsumtx udp6zerocsumrx"
+ else:
+ vxlan_opts = "noudpcsum"
+
+ # VXLAN tunnel - local side
+ ip(f"link add {vxlan_name} type vxlan id 100 dstport 4789 {vxlan_opts} "
+ f"local {local_addr} remote {remote_addr} dev {cfg.ifname}")
+ defer(ip, f"link del {vxlan_name}")
+ ip(f"addr add {inner_local} dev {vxlan_name}{addr_extra}")
+ ip(f"link set {vxlan_name} up")
+
+ # VXLAN tunnel - remote side
+ ip(f"link add {vxlan_name} type vxlan id 100 dstport 4789 {vxlan_opts} "
+ f"local {remote_addr} remote {local_addr} dev {cfg.remote_ifname}",
+ host=cfg.remote)
+ defer(ip, f"link del {vxlan_name}", host=cfg.remote)
+ ip(f"addr add {inner_remote} dev {vxlan_name}{addr_extra}",
+ host=cfg.remote)
+ ip(f"link set {vxlan_name} up", host=cfg.remote)
+
+ # xfrm state - local outbound SA
+ xfrm(f"state add src {local_addr} dst {remote_addr} "
+ f"proto esp spi {SPI_OUT} "
+ f"{ESP_AEAD} "
+ f"mode transport offload crypto dev {cfg.ifname} dir out")
+ defer(xfrm, f"state del src {local_addr} dst {remote_addr} "
+ f"proto esp spi {SPI_OUT}")
+
+ # xfrm state - local inbound SA
+ xfrm(f"state add src {remote_addr} dst {local_addr} "
+ f"proto esp spi {SPI_IN} "
+ f"{ESP_AEAD} "
+ f"mode transport offload crypto dev {cfg.ifname} dir in")
+ defer(xfrm, f"state del src {remote_addr} dst {local_addr} "
+ f"proto esp spi {SPI_IN}")
+
+ # xfrm state - remote outbound SA (mirror, software crypto)
+ xfrm(f"state add src {remote_addr} dst {local_addr} "
+ f"proto esp spi {SPI_IN} "
+ f"{ESP_AEAD} "
+ f"mode transport",
+ host=cfg.remote)
+ defer(xfrm, f"state del src {remote_addr} dst {local_addr} "
+ f"proto esp spi {SPI_IN}", host=cfg.remote)
+
+ # xfrm state - remote inbound SA (mirror, software crypto)
+ xfrm(f"state add src {local_addr} dst {remote_addr} "
+ f"proto esp spi {SPI_OUT} "
+ f"{ESP_AEAD} "
+ f"mode transport",
+ host=cfg.remote)
+ defer(xfrm, f"state del src {local_addr} dst {remote_addr} "
+ f"proto esp spi {SPI_OUT}", host=cfg.remote)
+
+ # xfrm policy - local out
+ xfrm(f"policy add src {local_addr} dst {remote_addr} "
+ f"proto udp dport 4789 dir out "
+ f"tmpl src {local_addr} dst {remote_addr} proto esp mode transport")
+ defer(xfrm, f"policy del src {local_addr} dst {remote_addr} "
+ f"proto udp dport 4789 dir out")
+
+ # xfrm policy - local in
+ xfrm(f"policy add src {remote_addr} dst {local_addr} "
+ f"proto udp dport 4789 dir in "
+ f"tmpl src {remote_addr} dst {local_addr} proto esp mode transport")
+ defer(xfrm, f"policy del src {remote_addr} dst {local_addr} "
+ f"proto udp dport 4789 dir in")
+
+ # xfrm policy - remote out
+ xfrm(f"policy add src {remote_addr} dst {local_addr} "
+ f"proto udp dport 4789 dir out "
+ f"tmpl src {remote_addr} dst {local_addr} proto esp mode transport",
+ host=cfg.remote)
+ defer(xfrm, f"policy del src {remote_addr} dst {local_addr} "
+ f"proto udp dport 4789 dir out", host=cfg.remote)
+
+ # xfrm policy - remote in
+ xfrm(f"policy add src {local_addr} dst {remote_addr} "
+ f"proto udp dport 4789 dir in "
+ f"tmpl src {local_addr} dst {remote_addr} proto esp mode transport",
+ host=cfg.remote)
+ defer(xfrm, f"policy del src {local_addr} dst {remote_addr} "
+ f"proto udp dport 4789 dir in", host=cfg.remote)
+
+
+def _vxlan_ipsec_variants():
+ """Generates outer/inner IP version variants."""
+ for outer in ["4", "6"]:
+ for inner in ["4", "6"]:
+ yield KsftNamedVariant(f"outer_v{outer}_inner_v{inner}", outer, inner)
+
+
+@ksft_variants(_vxlan_ipsec_variants())
+def test_vxlan_ipsec_crypto_offload(cfg, outer_ipver, inner_ipver):
+ """Tests VXLAN+IPsec crypto-offload has no TX drops."""
+ cfg.require_ipver(outer_ipver)
+ check_esp_hw_offload(cfg)
+
+ setup_vxlan_ipsec(cfg, outer_ipver, inner_ipver)
+
+ if inner_ipver == "4":
+ inner_local = INNER_V4_LOCAL
+ inner_remote = INNER_V4_REMOTE
+ ping = "ping"
+ else:
+ inner_local = INNER_V6_LOCAL
+ inner_remote = INNER_V6_REMOTE
+ ping = "ping -6"
+
+ cmd(f"{ping} -c 1 -W 2 {inner_remote}")
+
+ drops_before = get_tx_drops(cfg)
+
+ runner = Iperf3Runner(cfg, server_ip=inner_local,
+ client_ip=inner_remote)
+ bw_gbps = runner.measure_bandwidth(reverse=True)
+
+ cfg.wait_hw_stats_settle()
+ drops_after = get_tx_drops(cfg)
+
+ ksft_eq(drops_after - drops_before, 0,
+ comment="TX drops during VXLAN+IPsec")
+ ksft_ge(bw_gbps, 0.1,
+ comment="Minimum 100Mbps over VXLAN+IPsec")
+
+
+def main():
+ """Runs VXLAN+IPsec crypto-offload GSO selftest."""
+ with NetDrvEpEnv(__file__, nsim_test=False) as cfg:
+ ksft_run([test_vxlan_ipsec_crypto_offload], args=(cfg,))
+ ksft_exit()
+
+
+if __name__ == "__main__":
+ main()
--
2.53.0
^ permalink raw reply related
* Re: [PATCH] net/stmmac: Fix typos: 'tx_undeflow_irq' -> 'tx_underflow_irq'
From: Jakub Raczynski @ 2026-04-22 14:15 UTC (permalink / raw)
To: Andrew Lunn
Cc: netdev, linux-kernel, kuba, davem, andrew+netdev, kernel-janitors,
linux-arm-kernel, linux-stm32
In-Reply-To: <f1d51362-ca8f-481a-b9c1-400ab6422686@lunn.ch>
[-- Attachment #1: Type: text/plain, Size: 1403 bytes --]
On Wed, Apr 22, 2026 at 02:47:38PM +0200, Andrew Lunn wrote:
> > I don't see anything wrong with it?
> > - naming is correct, same as stmmac_extra_stats from common.h, as it
> > wouldn't compile otherwise
> > - string length is ok, as max name length is ETH_GSTRING_LEN=32 and it is
> > not close
> > - ethtool just polls data from driver and in my tests it is ok
> > - all instances of 'undeflow' are changed
> > - 'underflow' semantic is ok, 'undeflow' is just not correct
> >
> > Please correct me if I am wrong, but imo no issues with this patch.
>
> ABI
>
> This name is published as part of the kAPI. You are changing its
> name. User space could be looking for this name, even thought it has a
> typo in it.
>
> Andrew
>
I don't think it is? This part of extra stats (struct stmmac_extra_stats) and
is not part of standard ABI from
Documentation/ABI/testing/sysfs-class-net-statistics
nor is mentioned in
Documentation/networking/device_drivers/ethernet/stmicro/stmmac.rst
These extra stats are specific to stmmac driver and most of these are more
than standard
https://www.kernel.org/doc/html/v7.0/networking/statistics.html#c.rtnl_link_stats64
This name does not exist outside stmmac driver, so while some application may
expect this (stmmac specific app), question is should this typo stick?
This type of typo is even mentioned in scripts/spelling.txt.
Regards
Jakub Raczynski
[-- Attachment #2: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply
* Re: [PATCH bpf-next] selftests/bpf: drop xdping tool
From: Alan Maguire @ 2026-04-22 14:30 UTC (permalink / raw)
To: Alexis Lothoré (eBPF Foundation), Andrii Nakryiko,
Eduard Zingerman, Alexei Starovoitov, Daniel Borkmann,
Martin KaFai Lau, Kumar Kartikeya Dwivedi, Song Liu,
Yonghong Song, Jiri Olsa, Shuah Khan, David S. Miller,
Jakub Kicinski, Jesper Dangaard Brouer, John Fastabend,
Stanislav Fomichev
Cc: ebpf, Bastien Curutchet, Thomas Petazzoni, linux-kernel, bpf,
linux-kselftest, netdev
In-Reply-To: <20260417-xdping-v1-1-9b0ce0e7adf8@bootlin.com>
On 17/04/2026 16:33, Alexis Lothoré (eBPF Foundation) wrote:
> As part of a larger cleanup effort in the bpf selftests directory,
> tests and scripts are either being converted to the test_progs framework
> (so they are executed automatically in bpf CI), or removed if not
> relevant for such integration.
>
> The test_xdping.sh script (with the associated xdping.c) acts as a RTT
> measurement tool, by attaching two small xdp programs to two interfaces.
> Converting this test to test_progs may not make much sense:
> - RTT measurement does not really fit in the scope of a functional test,
> this is rather about measuring some performance level.
> - there are other existing tests in test_progs that actively validate
> XDP features like program attachment, return value processing, packet
> modification, etc
>
> Drop test_xdping.sh and the corresponding xdping.c userspace part. Keep
> the ebpf part (xdping_kern.c), as it is used by another test integrated
> in test_progs (btf_dump)
>
> Signed-off-by: Alexis Lothoré (eBPF Foundation) <alexis.lothore@bootlin.com>
Reviewed-by: Alan Maguire <alan.maguire@oracle.com>
as discussed, switching to loading xdp_dummy.bpf.o in prog_tests/btf_dump.c
would be good too (feel free to retain the Reviewed-by: with that v2 change).
Thanks!
> ---
> tools/testing/selftests/bpf/.gitignore | 1 -
> tools/testing/selftests/bpf/Makefile | 3 -
> tools/testing/selftests/bpf/test_xdping.sh | 103 ------------
> tools/testing/selftests/bpf/xdping.c | 254 -----------------------------
> 4 files changed, 361 deletions(-)
>
> diff --git a/tools/testing/selftests/bpf/.gitignore b/tools/testing/selftests/bpf/.gitignore
> index bfdc5518ecc8..986a6389186b 100644
> --- a/tools/testing/selftests/bpf/.gitignore
> +++ b/tools/testing/selftests/bpf/.gitignore
> @@ -21,7 +21,6 @@ test_lirc_mode2_user
> flow_dissector_load
> test_tcpnotify_user
> test_libbpf
> -xdping
> test_cpp
> *.d
> *.subskel.h
> diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
> index 78e60040811e..00a986a7d088 100644
> --- a/tools/testing/selftests/bpf/Makefile
> +++ b/tools/testing/selftests/bpf/Makefile
> @@ -111,7 +111,6 @@ TEST_FILES = xsk_prereqs.sh $(wildcard progs/btf_dump_test_case_*.c)
> # Order correspond to 'make run_tests' order
> TEST_PROGS := test_kmod.sh \
> test_lirc_mode2.sh \
> - test_xdping.sh \
> test_bpftool_build.sh \
> test_doc_build.sh \
> test_xsk.sh \
> @@ -134,7 +133,6 @@ TEST_GEN_PROGS_EXTENDED = \
> xdp_features \
> xdp_hw_metadata \
> xdp_synproxy \
> - xdping \
> xskxceiver
>
> TEST_GEN_FILES += $(TEST_KMODS) liburandom_read.so urandom_read sign-file uprobe_multi
> @@ -320,7 +318,6 @@ $(OUTPUT)/test_tcpnotify_user: $(CGROUP_HELPERS) $(TESTING_HELPERS) $(TRACE_HELP
> $(OUTPUT)/test_sock_fields: $(CGROUP_HELPERS) $(TESTING_HELPERS)
> $(OUTPUT)/test_tag: $(TESTING_HELPERS)
> $(OUTPUT)/test_lirc_mode2_user: $(TESTING_HELPERS)
> -$(OUTPUT)/xdping: $(TESTING_HELPERS)
> $(OUTPUT)/flow_dissector_load: $(TESTING_HELPERS)
> $(OUTPUT)/test_maps: $(TESTING_HELPERS)
> $(OUTPUT)/test_verifier: $(TESTING_HELPERS) $(CAP_HELPERS) $(UNPRIV_HELPERS)
> diff --git a/tools/testing/selftests/bpf/test_xdping.sh b/tools/testing/selftests/bpf/test_xdping.sh
> deleted file mode 100755
> index c3d82e0a7378..000000000000
> --- a/tools/testing/selftests/bpf/test_xdping.sh
> +++ /dev/null
> @@ -1,103 +0,0 @@
> -#!/bin/bash
> -# SPDX-License-Identifier: GPL-2.0
> -
> -# xdping tests
> -# Here we setup and teardown configuration required to run
> -# xdping, exercising its options.
> -#
> -# Setup is similar to test_tunnel tests but without the tunnel.
> -#
> -# Topology:
> -# ---------
> -# root namespace | tc_ns0 namespace
> -# |
> -# ---------- | ----------
> -# | veth1 | --------- | veth0 |
> -# ---------- peer ----------
> -#
> -# Device Configuration
> -# --------------------
> -# Root namespace with BPF
> -# Device names and addresses:
> -# veth1 IP: 10.1.1.200
> -# xdp added to veth1, xdpings originate from here.
> -#
> -# Namespace tc_ns0 with BPF
> -# Device names and addresses:
> -# veth0 IPv4: 10.1.1.100
> -# For some tests xdping run in server mode here.
> -#
> -
> -readonly TARGET_IP="10.1.1.100"
> -readonly TARGET_NS="xdp_ns0"
> -
> -readonly LOCAL_IP="10.1.1.200"
> -
> -setup()
> -{
> - ip netns add $TARGET_NS
> - ip link add veth0 type veth peer name veth1
> - ip link set veth0 netns $TARGET_NS
> - ip netns exec $TARGET_NS ip addr add ${TARGET_IP}/24 dev veth0
> - ip addr add ${LOCAL_IP}/24 dev veth1
> - ip netns exec $TARGET_NS ip link set veth0 up
> - ip link set veth1 up
> -}
> -
> -cleanup()
> -{
> - set +e
> - ip netns delete $TARGET_NS 2>/dev/null
> - ip link del veth1 2>/dev/null
> - if [[ $server_pid -ne 0 ]]; then
> - kill -TERM $server_pid
> - fi
> -}
> -
> -test()
> -{
> - client_args="$1"
> - server_args="$2"
> -
> - echo "Test client args '$client_args'; server args '$server_args'"
> -
> - server_pid=0
> - if [[ -n "$server_args" ]]; then
> - ip netns exec $TARGET_NS ./xdping $server_args &
> - server_pid=$!
> - sleep 10
> - fi
> - ./xdping $client_args $TARGET_IP
> -
> - if [[ $server_pid -ne 0 ]]; then
> - kill -TERM $server_pid
> - server_pid=0
> - fi
> -
> - echo "Test client args '$client_args'; server args '$server_args': PASS"
> -}
> -
> -set -e
> -
> -server_pid=0
> -
> -trap cleanup EXIT
> -
> -setup
> -
> -for server_args in "" "-I veth0 -s -S" ; do
> - # client in skb mode
> - client_args="-I veth1 -S"
> - test "$client_args" "$server_args"
> -
> - # client with count of 10 RTT measurements.
> - client_args="-I veth1 -S -c 10"
> - test "$client_args" "$server_args"
> -done
> -
> -# Test drv mode
> -test "-I veth1 -N" "-I veth0 -s -N"
> -test "-I veth1 -N -c 10" "-I veth0 -s -N"
> -
> -echo "OK. All tests passed"
> -exit 0
> diff --git a/tools/testing/selftests/bpf/xdping.c b/tools/testing/selftests/bpf/xdping.c
> deleted file mode 100644
> index 9ed8c796645d..000000000000
> --- a/tools/testing/selftests/bpf/xdping.c
> +++ /dev/null
> @@ -1,254 +0,0 @@
> -// SPDX-License-Identifier: GPL-2.0
> -/* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. */
> -
> -#include <linux/bpf.h>
> -#include <linux/if_link.h>
> -#include <arpa/inet.h>
> -#include <assert.h>
> -#include <errno.h>
> -#include <signal.h>
> -#include <stdio.h>
> -#include <stdlib.h>
> -#include <string.h>
> -#include <unistd.h>
> -#include <libgen.h>
> -#include <net/if.h>
> -#include <sys/types.h>
> -#include <sys/socket.h>
> -#include <netdb.h>
> -
> -#include "bpf/bpf.h"
> -#include "bpf/libbpf.h"
> -
> -#include "xdping.h"
> -#include "testing_helpers.h"
> -
> -static int ifindex;
> -static __u32 xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST;
> -
> -static void cleanup(int sig)
> -{
> - bpf_xdp_detach(ifindex, xdp_flags, NULL);
> - if (sig)
> - exit(1);
> -}
> -
> -static int get_stats(int fd, __u16 count, __u32 raddr)
> -{
> - struct pinginfo pinginfo = { 0 };
> - char inaddrbuf[INET_ADDRSTRLEN];
> - struct in_addr inaddr;
> - __u16 i;
> -
> - inaddr.s_addr = raddr;
> -
> - printf("\nXDP RTT data:\n");
> -
> - if (bpf_map_lookup_elem(fd, &raddr, &pinginfo)) {
> - perror("bpf_map_lookup elem");
> - return 1;
> - }
> -
> - for (i = 0; i < count; i++) {
> - if (pinginfo.times[i] == 0)
> - break;
> -
> - printf("64 bytes from %s: icmp_seq=%d ttl=64 time=%#.5f ms\n",
> - inet_ntop(AF_INET, &inaddr, inaddrbuf,
> - sizeof(inaddrbuf)),
> - count + i + 1,
> - (double)pinginfo.times[i]/1000000);
> - }
> -
> - if (i < count) {
> - fprintf(stderr, "Expected %d samples, got %d.\n", count, i);
> - return 1;
> - }
> -
> - bpf_map_delete_elem(fd, &raddr);
> -
> - return 0;
> -}
> -
> -static void show_usage(const char *prog)
> -{
> - fprintf(stderr,
> - "usage: %s [OPTS] -I interface destination\n\n"
> - "OPTS:\n"
> - " -c count Stop after sending count requests\n"
> - " (default %d, max %d)\n"
> - " -I interface interface name\n"
> - " -N Run in driver mode\n"
> - " -s Server mode\n"
> - " -S Run in skb mode\n",
> - prog, XDPING_DEFAULT_COUNT, XDPING_MAX_COUNT);
> -}
> -
> -int main(int argc, char **argv)
> -{
> - __u32 mode_flags = XDP_FLAGS_DRV_MODE | XDP_FLAGS_SKB_MODE;
> - struct addrinfo *a, hints = { .ai_family = AF_INET };
> - __u16 count = XDPING_DEFAULT_COUNT;
> - struct pinginfo pinginfo = { 0 };
> - const char *optstr = "c:I:NsS";
> - struct bpf_program *main_prog;
> - int prog_fd = -1, map_fd = -1;
> - struct sockaddr_in rin;
> - struct bpf_object *obj;
> - struct bpf_map *map;
> - char *ifname = NULL;
> - char filename[256];
> - int opt, ret = 1;
> - __u32 raddr = 0;
> - int server = 0;
> - char cmd[256];
> -
> - while ((opt = getopt(argc, argv, optstr)) != -1) {
> - switch (opt) {
> - case 'c':
> - count = atoi(optarg);
> - if (count < 1 || count > XDPING_MAX_COUNT) {
> - fprintf(stderr,
> - "min count is 1, max count is %d\n",
> - XDPING_MAX_COUNT);
> - return 1;
> - }
> - break;
> - case 'I':
> - ifname = optarg;
> - ifindex = if_nametoindex(ifname);
> - if (!ifindex) {
> - fprintf(stderr, "Could not get interface %s\n",
> - ifname);
> - return 1;
> - }
> - break;
> - case 'N':
> - xdp_flags |= XDP_FLAGS_DRV_MODE;
> - break;
> - case 's':
> - /* use server program */
> - server = 1;
> - break;
> - case 'S':
> - xdp_flags |= XDP_FLAGS_SKB_MODE;
> - break;
> - default:
> - show_usage(basename(argv[0]));
> - return 1;
> - }
> - }
> -
> - if (!ifname) {
> - show_usage(basename(argv[0]));
> - return 1;
> - }
> - if (!server && optind == argc) {
> - show_usage(basename(argv[0]));
> - return 1;
> - }
> -
> - if ((xdp_flags & mode_flags) == mode_flags) {
> - fprintf(stderr, "-N or -S can be specified, not both.\n");
> - show_usage(basename(argv[0]));
> - return 1;
> - }
> -
> - if (!server) {
> - /* Only supports IPv4; see hints initialization above. */
> - if (getaddrinfo(argv[optind], NULL, &hints, &a) || !a) {
> - fprintf(stderr, "Could not resolve %s\n", argv[optind]);
> - return 1;
> - }
> - memcpy(&rin, a->ai_addr, sizeof(rin));
> - raddr = rin.sin_addr.s_addr;
> - freeaddrinfo(a);
> - }
> -
> - /* Use libbpf 1.0 API mode */
> - libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
> -
> - snprintf(filename, sizeof(filename), "%s_kern.bpf.o", argv[0]);
> -
> - if (bpf_prog_test_load(filename, BPF_PROG_TYPE_XDP, &obj, &prog_fd)) {
> - fprintf(stderr, "load of %s failed\n", filename);
> - return 1;
> - }
> -
> - main_prog = bpf_object__find_program_by_name(obj,
> - server ? "xdping_server" : "xdping_client");
> - if (main_prog)
> - prog_fd = bpf_program__fd(main_prog);
> - if (!main_prog || prog_fd < 0) {
> - fprintf(stderr, "could not find xdping program");
> - return 1;
> - }
> -
> - map = bpf_object__next_map(obj, NULL);
> - if (map)
> - map_fd = bpf_map__fd(map);
> - if (!map || map_fd < 0) {
> - fprintf(stderr, "Could not find ping map");
> - goto done;
> - }
> -
> - signal(SIGINT, cleanup);
> - signal(SIGTERM, cleanup);
> -
> - printf("Setting up XDP for %s, please wait...\n", ifname);
> -
> - printf("XDP setup disrupts network connectivity, hit Ctrl+C to quit\n");
> -
> - if (bpf_xdp_attach(ifindex, prog_fd, xdp_flags, NULL) < 0) {
> - fprintf(stderr, "Link set xdp fd failed for %s\n", ifname);
> - goto done;
> - }
> -
> - if (server) {
> - close(prog_fd);
> - close(map_fd);
> - printf("Running server on %s; press Ctrl+C to exit...\n",
> - ifname);
> - do { } while (1);
> - }
> -
> - /* Start xdping-ing from last regular ping reply, e.g. for a count
> - * of 10 ICMP requests, we start xdping-ing using reply with seq number
> - * 10. The reason the last "real" ping RTT is much higher is that
> - * the ping program sees the ICMP reply associated with the last
> - * XDP-generated packet, so ping doesn't get a reply until XDP is done.
> - */
> - pinginfo.seq = htons(count);
> - pinginfo.count = count;
> -
> - if (bpf_map_update_elem(map_fd, &raddr, &pinginfo, BPF_ANY)) {
> - fprintf(stderr, "could not communicate with BPF map: %s\n",
> - strerror(errno));
> - cleanup(0);
> - goto done;
> - }
> -
> - /* We need to wait for XDP setup to complete. */
> - sleep(10);
> -
> - snprintf(cmd, sizeof(cmd), "ping -c %d -I %s %s",
> - count, ifname, argv[optind]);
> -
> - printf("\nNormal ping RTT data\n");
> - printf("[Ignore final RTT; it is distorted by XDP using the reply]\n");
> -
> - ret = system(cmd);
> -
> - if (!ret)
> - ret = get_stats(map_fd, count, raddr);
> -
> - cleanup(0);
> -
> -done:
> - if (prog_fd > 0)
> - close(prog_fd);
> - if (map_fd > 0)
> - close(map_fd);
> -
> - return ret;
> -}
>
> ---
> base-commit: b7fb68124aa80db90394236a9a4a6add12f4425d
> change-id: 20260417-xdping-5c2ef5a63899
>
> Best regards,
> --
> Alexis Lothoré (eBPF Foundation) <alexis.lothore@bootlin.com>
>
^ permalink raw reply
* Re: [PATCH net-next v2 14/14] net: macb: use context swapping in .ndo_change_mtu()
From: Théo Lebrun @ 2026-04-22 14:35 UTC (permalink / raw)
To: Jakub Kicinski
Cc: nicolas.ferre, claudiu.beznea, andrew+netdev, davem, edumazet,
pabeni, richardcochran, linux, pvalerio, conor, nb,
vladimir.kondratiev, gregory.clement, benoit.monin, tawfik.bayouk,
thomas.petazzoni, maxime.chevallier, netdev, linux-kernel
In-Reply-To: <20260414005657.3767049-1-kuba@kernel.org>
Hello Jakub,
On Tue Apr 14, 2026 at 2:56 AM CEST, Jakub Kicinski wrote:
> This is an AI-generated review of your patch. The human sending this
> email has considered the AI review valid, or at least plausible.
> ---
> net: macb: use context swapping in .ndo_change_mtu()
>
> This commit introduces a mechanism to perform context swapping when changing
> the MTU while the interface is running. It allocates a new context,
> reconfigures the hardware via a start and end swap process, and then frees
> the old context to avoid PHY reinitialization and gracefully handle memory
> pressure.
>
>> diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c
>> index d1536cb1e40bb..79371718f8392 100644
>> --- a/drivers/net/ethernet/cadence/macb_main.c
>> +++ b/drivers/net/ethernet/cadence/macb_main.c
>> @@ -3430,11 +3430,25 @@ static int macb_close(struct net_device *netdev)
>>
>> static int macb_change_mtu(struct net_device *netdev, int new_mtu)
>> {
>> - if (netif_running(netdev))
>> - return -EBUSY;
>> + struct macb *bp = netdev_priv(netdev);
>> + bool running = netif_running(netdev);
>> + struct macb_context *new_ctx;
>> +
>> + if (running) {
>> + new_ctx = macb_context_alloc(bp, new_mtu,
>> + bp->configured_rx_ring_size,
>> + bp->configured_tx_ring_size);
>> + if (IS_ERR(new_ctx))
>> + return PTR_ERR(new_ctx);
>> +
>> + macb_context_swap_start(bp);
>
> Does macb_context_swap_start() gracefully halt the transmitter before the
> context is freed?
>
> It appears to attempt disabling the hardware transmitter by clearing the
> TE and RE bits in the NCR register, but does not poll the hardware to ensure
> it has reached an idle state.
>
> Immediately after, macb_context_swap_end() frees the descriptor rings and data
> buffers via macb_free_consistent().
>
> If the MAC DMA engine is still mid-transfer, could it read or write to kernel
> memory that has already been freed or reallocated?
Yes and we already have the solution in macb_halt_tx(), used by
macb_tx_error_task(). Close and swap should also use it. Will fix.
Though from the manual's description of TE it sounds super unlikely.
Rx isn't an issue, modifying RE in NCR is the way to go.
> Can this code cause an AB-BA deadlock between napi_disable() and
> cancel_work_sync()?
>
> In macb_context_swap_start(), the code calls napi_disable() for all queues,
> and then immediately calls cancel_work_sync() on the error tasks.
>
> Both of these work items internally invoke napi_disable().
>
> If either error task runs concurrently, it will block forever inside its
> napi_disable() waiting for the NAPI state bits (which were already set by the
> first call in macb_context_swap_start()) to clear.
>
> Consequently, could cancel_work_sync() hang indefinitely waiting for the
> blocked work task to finish?
Wrong because napi_disable() grabs the netdev->lock mutex.
>> }
>>
>> WRITE_ONCE(netdev->mtu, new_mtu);
>>
>> + if (running)
>> + macb_context_swap_end(bp, new_ctx);
>
> Does macb_context_swap_end() leak pending TX buffers and their DMA mappings?
> When changing the MTU while the interface is running, macb_context_swap_end()
> calls macb_free_consistent() to free the old DMA context. While RX buffers are
> properly freed, for the TX queues it appears to only free the tracking array
> pointer without iterating through the ring to unmap the DMA mappings and free
> the actual buffers.
>
> Any packets queued in the hardware ring at the moment of the MTU swap might
> be permanently leaked, which could lead to memory and IOMMU space exhaustion
> under active traffic.
Yes, I have a pending patch for this. Will send soon. It is a bugfix
fixing the close codepath and we'll reuse the code in the swap
operation.
> Will MTU changes on EMAC devices permanently disable hardware interrupts?
>
> macb_context_swap_start() disables all interrupts unconditionally by writing
> -1 to the IDR register.
>
> However, macb_context_swap_end() restores interrupts via the IER register
> inside an explicit check:
>
> if (!(bp->caps & MACB_CAPS_MACB_IS_EMAC)) {
> ...
> }
>
> Since there is no else branch to re-enable interrupts for EMAC devices,
> could changing the MTU on these devices leave interrupts permanently masked
> and cause the network interface to silently stall?
Ignoring because we will refuse swap for EMAC devices. Their state is
too different; they have different ndo callbacks for everything and
don't use NAPI.
> Is there a missing spinlock when modifying the IER and NCR registers in
> macb_context_swap_end()?
>
> Modifications to the NCR and interrupt registers in macb_context_swap_start()
> are protected by the spinlock. However, macb_context_swap_end() performs
> lockless read-modify-write operations on both IER and NCR:
>
> ctrl = macb_readl(bp, NCR);
> macb_writel(bp, NCR, ctrl | MACB_BIT(RE) | MACB_BIT(TE));
>
> If concurrent hardware events or background tasks take the lock and modify
> NCR during this window, could their updates be silently overwritten?
Yes swap_end needs to wrap its access in the bp->lock spinlock to have
the read-modify-write operation be atomic.
Thanks,
--
Théo Lebrun, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply
* [PATCH v2] mptcp: do not drop partial packets
From: Shardul Bankar @ 2026-04-22 14:39 UTC (permalink / raw)
To: pabeni, matttbe, martineau
Cc: geliang, davem, edumazet, kuba, horms, netdev, mptcp,
linux-kernel, janak, kalpan.jani, shardulsb08, Shardul Bankar
When a packet arrives with map_seq < ack_seq < end_seq, the beginning
of the packet has already been acknowledged but the end contains new
data. Currently the entire packet is dropped as "old data," forcing
the sender to retransmit.
Instead, skip the already-acked bytes by adjusting the skb offset and
enqueue only the new portion. Update bytes_received and ack_seq to
reflect the new data consumed.
A previous attempt at this fix (commit 1d2ce718811a ("mptcp: do not
drop partial packets"), reverted in commit bf39160c4218 ("Revert
"mptcp: do not drop partial packets"")) also added a zero-window
check and changed rcv_wnd_sent initialization, which caused test
regressions. This version addresses only the partial packet handling
without modifying receive window accounting.
Fixes: ab174ad8ef76 ("mptcp: move ooo skbs into msk out of order queue.")
Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/600
Signed-off-by: Shardul Bankar <shardul.b@mpiricsoftware.com>
---
v2: Drop the mptcp_try_coalesce() attempt for partial packets, since
non-zero offset always prevents coalescing (Paolo).
net/mptcp/protocol.c | 22 +++++++++++++++++-----
1 file changed, 17 insertions(+), 5 deletions(-)
diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
index 614c3f583ca0..73ec6563ab2b 100644
--- a/net/mptcp/protocol.c
+++ b/net/mptcp/protocol.c
@@ -397,12 +397,24 @@ static bool __mptcp_move_skb(struct sock *sk, struct sk_buff *skb)
return false;
}
- /* old data, keep it simple and drop the whole pkt, sender
- * will retransmit as needed, if needed.
+ /* Completely old data? */
+ if (!after64(MPTCP_SKB_CB(skb)->end_seq, msk->ack_seq)) {
+ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_DUPDATA);
+ mptcp_drop(sk, skb);
+ return false;
+ }
+
+ /* Partial packet: map_seq < ack_seq < end_seq.
+ * Skip the already-acked bytes and enqueue the new data.
*/
- MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_DUPDATA);
- mptcp_drop(sk, skb);
- return false;
+ copy_len = MPTCP_SKB_CB(skb)->end_seq - msk->ack_seq;
+ MPTCP_SKB_CB(skb)->offset += msk->ack_seq - MPTCP_SKB_CB(skb)->map_seq;
+ msk->bytes_received += copy_len;
+ WRITE_ONCE(msk->ack_seq, msk->ack_seq + copy_len);
+
+ skb_set_owner_r(skb, sk);
+ __skb_queue_tail(&sk->sk_receive_queue, skb);
+ return true;
}
static void mptcp_stop_rtx_timer(struct sock *sk)
--
2.34.1
^ permalink raw reply related
* Re: [PATCH] mptcp: do not drop partial packets
From: Shardul Bankar @ 2026-04-22 14:40 UTC (permalink / raw)
To: Paolo Abeni, matttbe, martineau
Cc: geliang, davem, edumazet, kuba, horms, netdev, mptcp,
linux-kernel, janak, kalpan.jani
In-Reply-To: <fc2ca10a-1fa8-48f8-b140-6c59595fc08b@redhat.com>
On Wed, 2026-04-22 at 15:51 +0200, Paolo Abeni wrote:
> On 4/22/26 2:09 PM, Shardul Bankar wrote:
> > +
> > + /* Partial packet: map_seq < ack_seq < end_seq.
> > + * Skip the already-acked bytes and enqueue the new data.
> > */
> > - MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_DUPDATA);
> > - mptcp_drop(sk, skb);
> > - return false;
> > + copy_len = MPTCP_SKB_CB(skb)->end_seq - msk->ack_seq;
> > + MPTCP_SKB_CB(skb)->offset += msk->ack_seq -
> > MPTCP_SKB_CB(skb)->map_seq;
>
> here MPTCP_SKB_CB(skb)->offset is always != 0 ...
>
> > + msk->bytes_received += copy_len;
> > + WRITE_ONCE(msk->ack_seq, msk->ack_seq + copy_len);
> > + tail = skb_peek_tail(&sk->sk_receive_queue);
> > + if (tail && mptcp_try_coalesce(sk, tail, skb))
>
> ... so mptcp_try_coalesce() will always fail.
Thanks, good catch. Fixed in v2.
Regards,
Shardul
^ permalink raw reply
* Re: [PATCH] smb: smbdirect: move fs/smb/common/smbdirect/ to fs/smb/smbdirect/
From: Steve French @ 2026-04-22 14:49 UTC (permalink / raw)
To: Stefan Metzmacher
Cc: Christoph Hellwig, linux-cifs, linux-rdma, netdev,
samba-technical, Tom Talpey, Linus Torvalds, Namjae Jeon
In-Reply-To: <9cb0901c-18c5-4858-941c-3b37ee112af9@samba.org>
On Wed, Apr 22, 2026 at 3:16 AM Stefan Metzmacher <metze@samba.org> wrote:
>
> Hi Christoph,
>
> >> diff --git a/fs/smb/Makefile b/fs/smb/Makefile
> >> index 9a1bf59a1a65..353b1c2eefc4 100644
> >> --- a/fs/smb/Makefile
> >> +++ b/fs/smb/Makefile
> >> @@ -1,5 +1,6 @@
> >> # SPDX-License-Identifier: GPL-2.0
> >>
> >> obj-$(CONFIG_SMBFS) += common/
> >> +obj-$(CONFIG_SMBDIRECT) += smbdirect/
> >
> > Why is this not in net/smbdirect/ or driver/infiniband/ulp/smdirect?
>
> Yes, I also thought about net/smbdirect.
I would prefer to leave it in fs/smb for the time being, since it makes it
easier to track since fs/smb/server and fs/smb/client have dependencies
on it. In the long run, I don't mind moving it, if it starts being
used outside
of smb client and server.
> As IPPROTO_SMBDIRECT or PF_SMBDIRECT will be the next step,
> see the open discussion here:
> https://lore.kernel.org/linux-cifs/cover.1775571957.git.metze@samba.org/
> (I'll follow with that discussion soon)
>
> I was just unsure about the consequences, e.g. would
> the maintainer/pull request flow have to change in that case?
> Or would Steve be able to take the changes via his trees?
> Any I also didn't want to offend anybody, so I just took
> what Linus proposed.
>
> Using driver/infiniband/ulp/smdirect would also work,
> if everybody prefer that.
>
> > As far as I can tell there is zero file system logic in this code.
> >
> >> -#include "../common/smbdirect/smbdirect_public.h"
> >> +#include "../smbdirect/public.h"
> >
> > And all these relative includes suggest you really want a
> > include/linux/smdirect/ instead.
>
> Yes, that's my also my goal in the next steps.
>
> > While we're at it: __SMBDIRECT_EXPORT_SYMBOL__ is really odd.
> > One thing is the __ pre- and postfix that make it look weird.
>
> Yes, the __SMBDIRECT_EXPORT_SYMBOL__ was mainly a temporary
> thing, now it's useless and I'll remove it.
>
> > The other is that EXPORT_SYMBOL_FOR_MODULES is for very specific
> > symbols that really should not exported. What this warrants instead
> > is a normal EXPORT_SYMBOL_NS_GPL.
>
> I want the exported functions be minimal, as most of
> of should go via the socket layer instead.
>
> If EXPORT_SYMBOL_NS_GPL(func, "smbdirect") is better than
> EXPORT_SYMBOL_FOR_MODULES() I can change that.
>
> It means cifs.ko and ksmbd.ko would need MODULE_IMPORT_NS("smbdirect"), correct?
>
> Thanks!
> metze
--
Thanks,
Steve
^ permalink raw reply
* [PATCH net 1/1] net: rds: fix MR cleanup on copy error
From: Ren Wei @ 2026-04-22 14:52 UTC (permalink / raw)
To: netdev, linux-rdma, rds-devel
Cc: achender, davem, edumazet, kuba, pabeni, horms, leon,
santosh.shilimkar, jhubbard, yuantan098, yifanwucs, tomapufckgml,
bird, draw51280, n05ec
In-Reply-To: <cover.1776764247.git.draw51280@163.com>
From: Ao Zhou <draw51280@163.com>
__rds_rdma_map() hands sg/pages ownership to the transport after
get_mr() succeeds. If copying the generated cookie back to user space
fails after that point, the error path must not free those resources
again before dropping the MR reference.
Remove the duplicate unpin/free from the put_user() failure branch so
that MR teardown is handled only through the existing final cleanup
path.
Fixes: 0d4597c8c5ab ("net/rds: Track user mapped pages through special API")
Cc: stable@kernel.org
Reported-by: Yuan Tan <yuantan098@gmail.com>
Reported-by: Yifan Wu <yifanwucs@gmail.com>
Reported-by: Juefei Pu <tomapufckgml@gmail.com>
Reported-by: Xin Liu <bird@lzu.edu.cn>
Signed-off-by: Ao Zhou <draw51280@163.com>
Signed-off-by: Ren Wei <n05ec@lzu.edu.cn>
---
net/rds/rdma.c | 4 ----
1 file changed, 4 deletions(-)
diff --git a/net/rds/rdma.c b/net/rds/rdma.c
index aa6465dc742c..61fb6e45281b 100644
--- a/net/rds/rdma.c
+++ b/net/rds/rdma.c
@@ -326,10 +326,6 @@ static int __rds_rdma_map(struct rds_sock *rs, struct rds_get_mr_args *args,
if (args->cookie_addr &&
put_user(cookie, (u64 __user *)(unsigned long)args->cookie_addr)) {
- if (!need_odp) {
- unpin_user_pages(pages, nr_pages);
- kfree(sg);
- }
ret = -EFAULT;
goto out;
}
--
2.43.0
^ permalink raw reply related
* Re: [PATCH] ipv6: udp: fix memory leak in udpv6_sendmsg error path
From: Jakub Kicinski @ 2026-04-22 15:04 UTC (permalink / raw)
To: Mingyu Wang
Cc: willemdebruijn.kernel, davem, dsahern, edumazet, pabeni, horms,
netdev, linux-kernel
In-Reply-To: <20260422105802.486216-1-25181214217@stu.xidian.edu.cn>
On Wed, 22 Apr 2026 18:58:02 +0800 Mingyu Wang wrote:
> During fuzzing with failslab enabled, a memory leak was observed in the
> IPv6 UDP send path.
>
> When sending via the lockless fast path (!corkreq), udpv6_sendmsg()
> calls ip6_make_skb() and assumes that the routing entry (dst_entry)
> reference has been stolen by the callee. However, if ip6_make_skb()
> fails early (e.g., due to an ENOMEM from memory allocation failure),
> it returns an error pointer without consuming the dst reference.
>
> Since udpv6_sendmsg() unconditionally jumps to the 'out_no_dst' label,
> the unconsumed dst_entry is never released, resulting in a memory leak.
>
> Fix this by explicitly calling dst_release(dst) when ip6_make_skb()
> returns an error.
Test this with cmsg_ip.sh on a debug-enabled kernel before you repost.
I think it causes crashes there.
--
pw-bot: cr
^ permalink raw reply
* Re: [PATCH net 1/2] net/mlx5e: psp: Fix invalid access on PSP dev registration fail
From: Cosmin Ratiu @ 2026-04-22 15:13 UTC (permalink / raw)
To: kuba@kernel.org
Cc: Boris Pismenny, willemdebruijn.kernel@gmail.com,
andrew+netdev@lunn.ch, daniel.zahka@gmail.com,
davem@davemloft.net, leon@kernel.org,
linux-kernel@vger.kernel.org, edumazet@google.com,
linux-rdma@vger.kernel.org, Rahul Rameshbabu, Raed Salem,
Dragos Tatulea, kees@kernel.org, Mark Bloch, pabeni@redhat.com,
Tariq Toukan, Saeed Mahameed, netdev@vger.kernel.org,
Gal Pressman
In-Reply-To: <e9d10b11f73c0ff212a5dee0b08d9ca90eca5407.camel@nvidia.com>
On Wed, 2026-04-22 at 09:25 +0000, Cosmin Ratiu wrote:
> On Tue, 2026-04-21 at 11:32 -0700, Jakub Kicinski wrote:
> > On Tue, 21 Apr 2026 17:34:32 +0000 Cosmin Ratiu wrote:
> > > > No, the normal thing to do is to propagate errors.
> > > > If you want to diverge from that _you_ should have a reason,
> > > > a better reason than a vague "kernel can fail".
> > > > I'd prefer for the driver to fail in an obvious way.
> > > > Which will be immediately spotted by the operator, not 2 weeks
> > > > later when 10% of the fleet is upgraded already.
> > > > The only exception I'd make is to keep devlink registered in
> > > > case the fix is to flash a different FW.
> > >
> > > In this case, PSP not working would be spotted on the next PSP
> > > dev-
> > > get
> > > op which produces zilch instead of working devices.
> >
> > When you have X vendors times Y device generations times Z FW
> > versions
> > in your fleet dev-get returning nothing is not a failure. It just
> > means
> > you're running on a machine that's not capable. Best you can do to
> > spot a buggy kernel is to notice that the fraction of PSP traffic
> > is
> > decreasing over time. After significant portion of the fleet is
> > already
> > on the bad kernel.
> >
> > > But I understand what you want. You'd like the netdevice to
> > > either
> > > be
> > > fully initialized with all supported+configured protocols or fail
> > > the
> > > open operation. No intermediate/partial states. This is a non-
> > > trivial
> > > refactor for mlx5, because mlx5_nic_enable() returns nothing.
> > > Refactoring seems possible though, its only caller is
> > > mlx5e_attach_netdev(), which returns errors. It's certainly not
> > > something that should be done for a net fix though.
> > >
> > > I have a series pending for net-next where the PSP configuration
> > > is
> > > hooked to mlx5e_psp_set_config(). I will look into implementing
> > > what
> > > you propose there and propagate errors.
> > >
> > > Meanwhile, do you want to take these fixes (1 and 2) or maybe
> > > just
> > > 2
> > > for net or not?
> >
> > Can you call mlx5e_psp_cleanup() when register fails for now?
>
> Done for the next version, currently undergoing testing.
There's a snag: priv->psp may be accessed concurrently from
mlx5e_get_stats() -> mlx5e_fold_sw_stats64() so we'd need to play
tricks with RCU and that goes beyond what a net fix should be: It's a
redesign of how priv->psp is handled in the driver. There's a risk we
are missing things, or it becomes more intrusive that what a fix should
be.
I would like to ask you: let's please not do this redesign of priv->psp
in a rush, and leave it for the net-next series I mentioned...
To reiterate, would you like to take patch 2?
Cosmin.
^ permalink raw reply
* Re: [PATCH net-next 1/3] net/ethernet: add ZTE network driver support
From: Junyang Han @ 2026-04-22 14:46 UTC (permalink / raw)
To: andrew+netdev
Cc: davem, netdev, edumazet, kuba, pabeni, han.junyang, ran.ming,
han.chengfei, zhang.yanze
In-Reply-To: <20260415015334.2018453-1-han.junyang@zte.com.cn>
[-- Attachment #1.1.1: Type: text/plain, Size: 4071 bytes --]
Hi Andrew,
Thank you for your detailed review. Please see my responses below.
> Please always include a patch 0/X in a patch set, explaining the big
> picture.
Cover letter (patch 0/X) has been added in v2 explaining the big picture.
> + * ZTE DingHai Ethernet driver
> + * Copyright (c) 2022-2024, ZTE Corporation.
> And the last two years?
Copyright year updated to 2022-2026.
> +#define DRV_VERSION "1.0-1"
> Driver versions are generally useless. What does this actually mean
> for the given very limited driver? Are you going to change the version
> with each patchset?
Removed. Driver version is not needed for upstream submission.
> +#define DRV_SUMMARY "ZTE(R) zxdh-net driver"
> +
> +const char zxdh_pf_driver_version[] = DRV_VERSION;
> +static const char zxdh_pf_driver_string[] = DRV_SUMMARY;
> +static const char zxdh_pf_copyright[] = "Copyright (c)
> 2022-2024, ZTE Corporation.";
> You don't need this, you have the copyright above.
Removed all these. The copyright in the file header is sufficient.
> +MODULE_AUTHOR("ZTE");
> Author is a person, with an email address.
Fixed. Now using:
MODULE_AUTHOR("Junyang Han <han.junyang@zte.com.cn>");
> +MODULE_DESCRIPTION(DRV_SUMMARY);
> Please just put the string here, not #define.
Fixed. Now using:
MODULE_DESCRIPTION("ZTE Corporation network adapters (DingHai series) Ethernet driver");
> +MODULE_VERSION(DRV_VERSION);
> +MODULE_LICENSE("GPL");
> +static int dh_pf_pci_init(struct dh_core_dev *dev)
> +{
> + int ret = 0;
> + struct zxdh_pf_device *pf_dev = NULL;
> Reverse Christmas tree. This applies everywhere for a netdev driver.
Fixed. Function variable declarations now follow reverse Christmas tree.
> +static int dh_pf_probe(struct pci_dev *pdev, const struct pci_device_id *id)
> +{
> +err_cfg_init:
> + mutex_destroy(&pf_dev->irq_lock);
> + mutex_destroy(&dh_dev->lock);
> + devlink_free(devlink);
> + pf_dev = NULL;
> Since this is a probe function, do you really need to set pf_dev to
> NULL? How is it going to keep a value over EPROBE_DEFER cycles?
Removed. pf_dev doesn't need to be set to NULL.
> +static void dh_pf_remove(struct pci_dev *pdev)
> +{
> + struct dh_core_dev *dh_dev = pci_get_drvdata(pdev);
> + struct devlink *devlink = priv_to_devlink(dh_dev);
> + struct zxdh_pf_device *pf_dev = dh_core_priv(dh_dev);
> +
> + if (!dh_dev)
> + return;
> How does that happen?
Removed the NULL check.
> + dh_pf_pci_close(dh_dev);
> + mutex_destroy(&pf_dev->irq_lock);
> + mutex_destroy(&dh_dev->lock);
> + devlink_free(devlink);
> + pci_set_drvdata(pdev, NULL);
> +}
> +static int dh_pf_suspend(struct pci_dev *pdev, pm_message_t state)
> +{
> + return 0;
> +}
> +
> +static int dh_pf_resume(struct pci_dev *pdev)
> +{
> + return 0;
> +}
> If they do nothing, don't provide them. You can add them when you add
> suspend/resume support.
Removed. Suspend/resume will be added when needed.
> +static int __init dh_pf_pci_init_module(void)
> +{
> + return pci_register_driver(&dh_pf_driver);
> +}
> +
> +static void __exit dh_pf_pci_exit_module(void)
> +{
> + pci_unregister_driver(&dh_pf_driver);
> +}
> +
> +module_init(dh_pf_pci_init_module);
> +module_exit(dh_pf_pci_exit_module);
> The PCI subsystem offers a wrapper to do this.
Fixed. Now using module_pci_driver(dh_pf_driver).
> +struct dh_core_dev {
> + struct device *device;
> + enum dh_coredev_type coredev_type;
> + struct pci_dev *pdev;
> + struct devlink *devlink;
> + struct mutex lock; /* Protects device configuration */
> + char priv[] __aligned(32);
> That is unusual. priv is usually a void * and allocated. If you want
> an actual array, you might want to have a second member indicate the
> size of the array, look at all the work done recently on flexible
> arrays.
Fixed. Changed to void *priv, allocated dynamically with kzalloc().
Best regards,
Junyang Han
[-- Attachment #1.1.2: Type: text/html , Size: 7872 bytes --]
^ permalink raw reply
* Re: [PATCH] smb: smbdirect: move fs/smb/common/smbdirect/ to fs/smb/smbdirect/
From: Paulo Alcantara @ 2026-04-22 15:16 UTC (permalink / raw)
To: Steve French, Stefan Metzmacher
Cc: Christoph Hellwig, linux-cifs, linux-rdma, netdev,
samba-technical, Tom Talpey, Linus Torvalds, Namjae Jeon
In-Reply-To: <CAH2r5msb3-HiPSv+HgBknEwDXGsv0xU=TGCxHdmc-VCLKzYCmw@mail.gmail.com>
Steve French <smfrench@gmail.com> writes:
> On Wed, Apr 22, 2026 at 3:16 AM Stefan Metzmacher <metze@samba.org> wrote:
>>
>> Hi Christoph,
>>
>> >> diff --git a/fs/smb/Makefile b/fs/smb/Makefile
>> >> index 9a1bf59a1a65..353b1c2eefc4 100644
>> >> --- a/fs/smb/Makefile
>> >> +++ b/fs/smb/Makefile
>> >> @@ -1,5 +1,6 @@
>> >> # SPDX-License-Identifier: GPL-2.0
>> >>
>> >> obj-$(CONFIG_SMBFS) += common/
>> >> +obj-$(CONFIG_SMBDIRECT) += smbdirect/
>> >
>> > Why is this not in net/smbdirect/ or driver/infiniband/ulp/smdirect?
>>
>> Yes, I also thought about net/smbdirect.
>
> I would prefer to leave it in fs/smb for the time being, since it makes it
> easier to track since fs/smb/server and fs/smb/client have dependencies
> on it. In the long run, I don't mind moving it, if it starts being
> used outside
> of smb client and server.
Please let's not break backporting any further. Decide where it will
end up at once. We don't want the "fs/cifs -> fs/smb/client" history
all over again.
Won't samba be using it? If so, you could consider an user outside
fs/smb/{client,server} and then leave it in net/ instead, as hch
suggested.
^ permalink raw reply
* Re: [PATCH net-next 3/3] net/ethernet/zte/dinghai: add hardware register access and PCI capability scanning
From: Junyang Han @ 2026-04-22 14:47 UTC (permalink / raw)
To: andrew+netdev
Cc: davem, netdev, edumazet, kuba, pabeni, han.junyang, ran.ming,
han.chengfei, zhang.yanze
In-Reply-To: <20260415015334.2018453-3-han.junyang@zte.com.cn>
[-- Attachment #1.1.1: Type: text/plain, Size: 4596 bytes --]
Hi Andrew,
Thank you for reviewing patch 3/3. Please see my responses below.
> +int32_t zxdh_pf_pci_find_capability(struct pci_dev *pdev, uint8_t cfg_type,
> + uint32_t ioresource_types, int32_t *bars)
> +{
> + int32_t pos = 0;
> + uint8_t type = 0;
> + uint8_t bar = 0;
> +
> + for (pos = pci_find_capability(pdev, PCI_CAP_ID_VNDR); pos > 0;
> + pos = pci_find_next_capability(pdev, pos, PCI_CAP_ID_VNDR)) {
> + pci_read_config_byte(pdev, pos + offsetof
> (struct zxdh_pf_pci_cap, cfg_type), &type);
> + pci_read_config_byte(pdev, pos + offsetof
> (struct zxdh_pf_pci_cap, bar), &bar);
> Something odd going on with indentation? Has the mailer corrupted it?
The indentation in the original patch was correct (4-space). The mailer
appears to have corrupted the formatting in the display. Code is properly
indented in the actual patch.
> +
> + /* ignore structures with reserved BAR values */
> + if (bar > ZXDH_PF_MAX_BAR_VAL)
> + continue;
> +
> + if (type == cfg_type) {
> + if (pci_resource_len(pdev, bar) &&
> + pci_resource_flags(pdev, bar) & ioresource_types) {
> + *bars |= (1 << bar);
> + return pos;
> + }
> + }
> + }
> +
> + return 0;
> +}
> +
> +void __iomem *zxdh_pf_map_capability(struct dh_core_dev *dh_dev, int32_t off,
> + size_t minlen, uint32_t align,
> + uint32_t start, uint32_t size,
> + size_t *len, resource_size_t *pa,
> + uint32_t *bar_off)
> + p = pci_iomap_range(pdev, bar, offset, length);
> + if (unlikely(!p)) {
> Is this hot path? Please only use unlikely() when dealing with frames
> in the hot path.
Removed unlikely(). It's not in a hot path.
> +int32_t zxdh_pf_common_cfg_init(struct dh_core_dev *dh_dev)
> +{
> + int32_t common = 0;
> + struct zxdh_pf_device *pf_dev = dh_core_priv(dh_dev);
> + struct pci_dev *pdev = dh_dev->pdev;
> +
> + /* check for a common config: if not, use legacy mode (bar 0). */
> + common = zxdh_pf_pci_find_capability(pdev, ZXDH_PCI_CAP_COMMON_CFG,
> + IORESOURCE_IO | IORESOURCE_MEM,
> + &pf_dev->modern_bars);
> + if (common == 0) {
> + LOG_ERR("missing capabilities %i, leaving for legacy driver\
> n", common);
> + return -ENODEV;
> + }
> +
> + pf_dev->common = zxdh_pf_map_capability(dh_dev, common,
> + sizeof(struct zxdh_pf_pci_common_cfg),
> + ZXDH_PF_ALIGN4, 0,
> + sizeof(struct zxdh_pf_pci_common_cfg),
> + NULL, NULL, NULL);
> + if (unlikely(!pf_dev->common)) {
> + LOG_ERR("pf_dev->common is null\n");
> + return -EINVAL;
> + }
> +
> + return 0;
> +}
> +int32_t zxdh_pf_notify_cfg_init(struct dh_core_dev *dh_dev)
> +{
> + /* We don't know how many VQs we'll map, ahead of the time.
> + * If notify length is small, map it all now. Otherwise, map each VQ individually later.
> + */
> + if ((uint64_t)notify_length + (notify_offset % PAGE_SIZE) <= PAGE_SIZE) {
> Please try to avoid casts. They suggest the types are wrong. You will
> probably have better code if you don't need the cast.
Fixed. Changed notify_length and notify_offset to size_t type.
The cast is no longer needed:
if (notify_length + (notify_offset % PAGE_SIZE) <= PAGE_SIZE)
> +int32_t zxdh_pf_modern_cfg_init(struct dh_core_dev *dh_dev)
> +{
> + int32_t ret = 0;
> + struct zxdh_pf_device *pf_dev = dh_core_priv(dh_dev);
> + struct pci_dev *pdev = dh_dev->pdev;
> +
> + ret = zxdh_pf_common_cfg_init(dh_dev);
> + if (ret != 0) {
> if (ret)
> would be more normal.
Fixed. Changed to "if (ret)".
> +void zxdh_pf_get_vf_mac
> (struct dh_core_dev *dh_dev, uint8_t *mac, int32_t vf_id)
> +{
> + uint32_t DEV_MAC_L = 0;
> + uint16_t DEV_MAC_H = 0;
> + struct zxdh_pf_device *pf_dev = dh_core_priv(dh_dev);
> +
> + if (pf_dev->pf_sriov_cap_base) {
> + DEV_MAC_L = ioread32((void __iomem *)(pf_dev->pf_sriov_cap_base +
> + (pf_dev->sriov_bar_size) * vf_id +
> + pf_dev->dev_cfg_bar_off));
> Is the cast needed? pf_dev->pf_sriov_cap_base should already be void *
> __iomem.
Fixed. Removed the cast. pf_sriov_cap_base is already void __iomem *.
Best regards,
Junyang Han
[-- Attachment #1.1.2: Type: text/html , Size: 10913 bytes --]
^ permalink raw reply
* [PATCH net-next v2 0/3] Add ZTE DingHai Ethernet PF driver
From: Junyang Han @ 2026-04-22 14:48 UTC (permalink / raw)
To: netdev
Cc: davem, andrew+netdev, edumazet, kuba, pabeni, han.junyang,
ran.ming, han.chengfei, zhang.yanze
[-- Attachment #1.1.1: Type: text/plain, Size: 2712 bytes --]
This series adds initial support for the ZTE DingHai Ethernet controller,
a high-performance PCIe Ethernet device supporting SR-IOV, hardware
offloading, and advanced virtualization features.
Changes from v1 (addressing feedback from AndrewLunn):
- Update copyright years to 2022-2026
- Remove DRV_VERSION, MODULE_VERSION and related boilerplate
- Fix MODULE_AUTHOR to use person with email address
- Use module_pci_driver() instead of manual init/exit
- Remove empty suspend/resume callbacks
- Replace char priv[] flexible array with void *priv + kzalloc
- Switch logging from printk wrappers to dev_*() based macros
- Remove dh_helper.h and dh_log.c, simplify to dh_log.h only
- Fix variable declaration ordering (reverse Christmas tree)
- Remove unnecessary NULL check in remove and pf_dev=NULL in probe
- Fix indentation and remove unnecessary type casts
- Use kernel idiomatic "if (ret)" style
This patch series is organized as follows:
- Patch 1: Add basic driver framework (Kconfig/Makefile, probe/remove skeleton)
- Patch 2: Add logging infrastructure using kernel standard dev_* macros
- Patch 3: Add hardware register access and PCI capability scanning
This is the initial submission and only includes the PF (Physical Function)
driver. The VF (Virtual Function) driver will be submitted separately.
Junyang Han (3):
net/ethernet: add ZTE network driver support
net/ethernet/zte/dinghai: add logging infrastructure
net/ethernet/zte/dinghai: add hardware register access and PCI
capability scanning
MAINTAINERS | 6 +
drivers/net/ethernet/Kconfig | 1 +
drivers/net/ethernet/Makefile | 1 +
drivers/net/ethernet/zte/Kconfig | 20 +
drivers/net/ethernet/zte/Makefile | 6 +
drivers/net/ethernet/zte/dinghai/Kconfig | 34 ++
drivers/net/ethernet/zte/dinghai/Makefile | 10 +
drivers/net/ethernet/zte/dinghai/dh_log.h | 60 ++
drivers/net/ethernet/zte/dinghai/dh_queue.h | 71 +++
drivers/net/ethernet/zte/dinghai/en_pf.c | 605 ++++++++++++++++++++
drivers/net/ethernet/zte/dinghai/en_pf.h | 100 ++++
11 files changed, 914 insertions(+)
create mode 100644 drivers/net/ethernet/zte/Kconfig
create mode 100644 drivers/net/ethernet/zte/Makefile
create mode 100644 drivers/net/ethernet/zte/dinghai/Kconfig
create mode 100644 drivers/net/ethernet/zte/dinghai/Makefile
create mode 100644 drivers/net/ethernet/zte/dinghai/dh_log.h
create mode 100644 drivers/net/ethernet/zte/dinghai/dh_queue.h
create mode 100644 drivers/net/ethernet/zte/dinghai/en_pf.c
create mode 100644 drivers/net/ethernet/zte/dinghai/en_pf.h
--
2.27.0
[-- Attachment #1.1.2: Type: text/html , Size: 4876 bytes --]
^ permalink raw reply
* [PATCH net-next v2 1/3] net/ethernet: add ZTE network driver support
From: Junyang Han @ 2026-04-22 14:48 UTC (permalink / raw)
To: netdev
Cc: davem, andrew+netdev, edumazet, kuba, pabeni, han.junyang,
ran.ming, han.chengfei, zhang.yanze
In-Reply-To: <20260422144901.2403456-1-han.junyang@zte.com.cn>
[-- Attachment #1.1.1: Type: text/plain, Size: 11298 bytes --]
Add basic framework for ZTE DingHai ethernet PF driver, including
Kconfig/Makefile build support and PCIe device probe/remove skeleton.
Signed-off-by: Junyang Han <han.junyang@zte.com.cn>
---
MAINTAINERS | 6 +
drivers/net/ethernet/Kconfig | 1 +
drivers/net/ethernet/Makefile | 1 +
drivers/net/ethernet/zte/Kconfig | 20 +++
drivers/net/ethernet/zte/Makefile | 6 +
drivers/net/ethernet/zte/dinghai/Kconfig | 34 +++++
drivers/net/ethernet/zte/dinghai/Makefile | 10 ++
drivers/net/ethernet/zte/dinghai/en_pf.c | 162 ++++++++++++++++++++++
drivers/net/ethernet/zte/dinghai/en_pf.h | 62 +++++++++
9 files changed, 302 insertions(+)
create mode 100644 drivers/net/ethernet/zte/Kconfig
create mode 100644 drivers/net/ethernet/zte/Makefile
create mode 100644 drivers/net/ethernet/zte/dinghai/Kconfig
create mode 100644 drivers/net/ethernet/zte/dinghai/Makefile
create mode 100644 drivers/net/ethernet/zte/dinghai/en_pf.c
create mode 100644 drivers/net/ethernet/zte/dinghai/en_pf.h
diff --git a/MAINTAINERS b/MAINTAINERS
index 65902b97f5df..92ddac4bb310 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -29210,6 +29210,12 @@ S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
F: sound/hda/codecs/senarytech.c
+ZTE DINGHAI ETHERNET DRIVER
+M: Junyang Han <han.junyang@zte.com.cn>
+L: netdev@vger.kernel.org
+S: Maintained
+F: drivers/net/ethernet/zte/
+
THE REST
M: Linus Torvalds <torvalds@linux-foundation.org>
L: linux-kernel@vger.kernel.org
diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig
index bdc29d143160..ecc6fbb01510 100644
--- a/drivers/net/ethernet/Kconfig
+++ b/drivers/net/ethernet/Kconfig
@@ -190,5 +190,6 @@ source "drivers/net/ethernet/wangxun/Kconfig"
source "drivers/net/ethernet/wiznet/Kconfig"
source "drivers/net/ethernet/xilinx/Kconfig"
source "drivers/net/ethernet/xircom/Kconfig"
+source "drivers/net/ethernet/zte/Kconfig"
endif # ETHERNET
diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile
index 6bffb60ba644..7476af77d6c8 100644
--- a/drivers/net/ethernet/Makefile
+++ b/drivers/net/ethernet/Makefile
@@ -106,3 +106,4 @@ obj-$(CONFIG_NET_VENDOR_XIRCOM) += xircom/
obj-$(CONFIG_NET_VENDOR_SYNOPSYS) += synopsys/
obj-$(CONFIG_NET_VENDOR_PENSANDO) += pensando/
obj-$(CONFIG_OA_TC6) += oa_tc6.o
+obj-$(CONFIG_NET_VENDOR_ZTE) += zte/
diff --git a/drivers/net/ethernet/zte/Kconfig b/drivers/net/ethernet/zte/Kconfig
new file mode 100644
index 000000000000..b95c2fc7db77
--- /dev/null
+++ b/drivers/net/ethernet/zte/Kconfig
@@ -0,0 +1,20 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# ZTE driver configuration
+#
+
+config NET_VENDOR_ZTE
+ bool "ZTE devices"
+ default y
+ help
+ If you have a network (Ethernet) card belonging to this class, say Y.
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about Zte cards. If you say Y, you will be asked
+ for your specific card in the following questions.
+
+if NET_VENDOR_ZTE
+
+source "drivers/net/ethernet/zte/dinghai/Kconfig"
+
+endif # NET_VENDOR_ZTE
diff --git a/drivers/net/ethernet/zte/Makefile b/drivers/net/ethernet/zte/Makefile
new file mode 100644
index 000000000000..cd9929b61559
--- /dev/null
+++ b/drivers/net/ethernet/zte/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Makefile for the ZTE device drivers
+#
+
+obj-$(CONFIG_DINGHAI) += dinghai/
diff --git a/drivers/net/ethernet/zte/dinghai/Kconfig b/drivers/net/ethernet/zte/dinghai/Kconfig
new file mode 100644
index 000000000000..94b5bd9b3c50
--- /dev/null
+++ b/drivers/net/ethernet/zte/dinghai/Kconfig
@@ -0,0 +1,34 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# ZTE DingHai Ethernet driver configuration
+#
+
+config DINGHAI
+ bool "ZTE DingHai Ethernet driver"
+ depends on NET_VENDOR_ZTE && PCI
+ select NET_DEVLINK
+ help
+ This driver supports ZTE DingHai Ethernet devices.
+
+ DingHai is a high-performance Ethernet controller that supports
+ multiple features including hardware offloading, SR-IOV, and
+ advanced virtualization capabilities.
+
+ If you say Y here, you can select specific driver variants below.
+
+ If unsure, say N.
+
+if DINGHAI
+
+config DINGHAI_PF
+ tristate "ZTE DingHai PF (Physical Function) driver"
+ help
+ This driver supports ZTE DingHai PCI Express Ethernet
+ adapters (PF).
+
+ To compile this driver as a module, choose M here. The module
+ will be named dinghai10e.
+
+ If unsure, say N.
+
+endif # DINGHAI
diff --git a/drivers/net/ethernet/zte/dinghai/Makefile b/drivers/net/ethernet/zte/dinghai/Makefile
new file mode 100644
index 000000000000..f55a8de518be
--- /dev/null
+++ b/drivers/net/ethernet/zte/dinghai/Makefile
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Makefile for ZTE DingHai Ethernet driver
+#
+
+ccflags-y += -I$(src)
+
+obj-$(CONFIG_DINGHAI_PF) += dinghai10e.o
+dinghai10e-y := en_pf.o
+
diff --git a/drivers/net/ethernet/zte/dinghai/en_pf.c b/drivers/net/ethernet/zte/dinghai/en_pf.c
new file mode 100644
index 000000000000..5e13a8c24a28
--- /dev/null
+++ b/drivers/net/ethernet/zte/dinghai/en_pf.c
@@ -0,0 +1,162 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * ZTE DingHai Ethernet driver
+ * Copyright (c) 2022-2026, ZTE Corporation.
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <net/devlink.h>
+#include "en_pf.h"
+
+MODULE_AUTHOR("Junyang Han <han.junyang@zte.com.cn>");
+MODULE_DESCRIPTION("ZTE Corporation network adapters (DingHai series) Ethernet driver");
+MODULE_LICENSE("GPL");
+
+static const struct devlink_ops dh_pf_devlink_ops = {};
+
+const struct pci_device_id dh_pf_pci_table[] = {
+ { PCI_DEVICE(ZXDH_PF_VENDOR_ID, ZXDH_PF_DEVICE_ID), 0 },
+ { PCI_DEVICE(ZXDH_PF_VENDOR_ID, ZXDH_VF_DEVICE_ID), 0 },
+ { 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, dh_pf_pci_table);
+
+static int dh_pf_pci_init(struct dh_core_dev *dev)
+{
+ struct zxdh_pf_device *pf_dev = NULL;
+ int ret = 0;
+
+ pci_set_drvdata(dev->pdev, dev);
+
+ ret = pci_enable_device(dev->pdev);
+ if (ret)
+ return -ENOMEM;
+
+ ret = dma_set_mask_and_coherent(dev->device, DMA_BIT_MASK(64));
+ if (ret) {
+ ret = dma_set_mask_and_coherent(dev->device, DMA_BIT_MASK(32));
+ if (ret)
+ goto err_pci;
+ }
+
+ ret = pci_request_selected_regions(dev->pdev,
+ pci_select_bars(dev->pdev, IORESOURCE_MEM),
+ "dh-pf");
+ if (ret)
+ goto err_pci;
+
+ pci_set_master(dev->pdev);
+ ret = pci_save_state(dev->pdev);
+ if (ret)
+ goto err_pci_save_state;
+
+ pf_dev = dev->priv;
+ pf_dev->pci_ioremap_addr[0] =
+ (uint64_t)ioremap(pci_resource_start(dev->pdev, 0),
+ pci_resource_len(dev->pdev, 0));
+ if (!pf_dev->pci_ioremap_addr[0]) {
+ ret = -ENOMEM;
+ goto err_pci_save_state;
+ }
+
+ return 0;
+
+err_pci_save_state:
+ pci_release_selected_regions(dev->pdev, pci_select_bars(dev->pdev, IORESOURCE_MEM));
+err_pci:
+ pci_disable_device(dev->pdev);
+ return ret;
+}
+
+void dh_pf_pci_close(struct dh_core_dev *dev)
+{
+ struct zxdh_pf_device *pf_dev = NULL;
+
+ pf_dev = dev->priv;
+ iounmap((void *)pf_dev->pci_ioremap_addr[0]);
+ pci_release_selected_regions(dev->pdev, pci_select_bars(dev->pdev, IORESOURCE_MEM));
+ pci_disable_device(dev->pdev);
+}
+
+static int dh_pf_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ struct dh_core_dev *dh_dev = NULL;
+ struct zxdh_pf_device *pf_dev = NULL;
+ struct devlink *devlink = NULL;
+ int ret = 0;
+
+ devlink = devlink_alloc(&dh_pf_devlink_ops, sizeof(struct dh_core_dev),
+ &pdev->dev);
+ if (!devlink)
+ return -ENOMEM;
+
+ dh_dev = devlink_priv(devlink);
+ dh_dev->device = &pdev->dev;
+ dh_dev->pdev = pdev;
+ dh_dev->devlink = devlink;
+
+ pf_dev = dh_core_alloc_priv(dh_dev, sizeof(*pf_dev));
+ if (!pf_dev)
+ return -ENOMEM;
+
+ pf_dev->bar_chan_valid = false;
+ pf_dev->vepa = false;
+ mutex_init(&dh_dev->lock);
+ mutex_init(&pf_dev->irq_lock);
+
+ dh_dev->coredev_type = GET_COREDEV_TYPE(pdev);
+
+ ret = dh_pf_pci_init(dh_dev);
+ if (ret)
+ goto err_cfg_init;
+
+ return 0;
+
+err_cfg_init:
+ mutex_destroy(&pf_dev->irq_lock);
+ mutex_destroy(&dh_dev->lock);
+ dh_core_free_priv(dh_dev);
+ devlink_free(devlink);
+ return -EPERM;
+}
+
+static void dh_pf_remove(struct pci_dev *pdev)
+{
+ struct dh_core_dev *dh_dev = pci_get_drvdata(pdev);
+ struct devlink *devlink = priv_to_devlink(dh_dev);
+ struct zxdh_pf_device *pf_dev = dh_dev->priv;
+
+ dh_pf_pci_close(dh_dev);
+ mutex_destroy(&pf_dev->irq_lock);
+ mutex_destroy(&dh_dev->lock);
+ dh_core_free_priv(dh_dev);
+ devlink_free(devlink);
+ pci_set_drvdata(pdev, NULL);
+}
+
+static void dh_pf_shutdown(struct pci_dev *pdev)
+{
+ struct dh_core_dev *dh_dev = pci_get_drvdata(pdev);
+ struct devlink *devlink = priv_to_devlink(dh_dev);
+ struct zxdh_pf_device *pf_dev = dh_dev->priv;
+
+ dh_pf_pci_close(dh_dev);
+ mutex_destroy(&pf_dev->irq_lock);
+ mutex_destroy(&dh_dev->lock);
+ dh_core_free_priv(dh_dev);
+ devlink_free(devlink);
+
+ pci_set_drvdata(pdev, NULL);
+}
+
+static struct pci_driver dh_pf_driver = {
+ .name = "dinghai10e",
+ .id_table = dh_pf_pci_table,
+ .probe = dh_pf_probe,
+ .remove = dh_pf_remove,
+ .shutdown = dh_pf_shutdown,
+};
+
+module_pci_driver(dh_pf_driver);
diff --git a/drivers/net/ethernet/zte/dinghai/en_pf.h b/drivers/net/ethernet/zte/dinghai/en_pf.h
new file mode 100644
index 000000000000..a8b324adb948
--- /dev/null
+++ b/drivers/net/ethernet/zte/dinghai/en_pf.h
@@ -0,0 +1,62 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * ZTE DingHai Ethernet driver - PF header
+ * Copyright (c) 2022-2026, ZTE Corporation.
+ */
+
+#ifndef __ZXDH_EN_PF_H__
+#define __ZXDH_EN_PF_H__
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/mutex.h>
+
+#define ZXDH_PF_VENDOR_ID 0x1cf2
+#define ZXDH_PF_DEVICE_ID 0x8040
+#define ZXDH_VF_DEVICE_ID 0x8041
+
+enum dh_coredev_type {
+ DH_COREDEV_PF,
+ DH_COREDEV_VF,
+ DH_COREDEV_SF,
+ DH_COREDEV_MPF
+};
+
+struct devlink;
+
+struct dh_core_dev {
+ struct device *device;
+ enum dh_coredev_type coredev_type;
+ struct pci_dev *pdev;
+ struct devlink *devlink;
+ struct mutex lock; /* Protects device configuration */
+ void *priv;
+};
+
+struct zxdh_pf_device {
+ uint64_t pci_ioremap_addr[6];
+ bool bar_chan_valid;
+ bool vepa;
+ struct mutex irq_lock; /* Protects IRQ operations */
+};
+
+static inline void *dh_core_alloc_priv(struct dh_core_dev *dh_dev, size_t size)
+{
+ void *priv = kzalloc(size, GFP_KERNEL);
+
+ if (priv)
+ dh_dev->priv = priv;
+ return priv;
+}
+
+static inline void dh_core_free_priv(struct dh_core_dev *dh_dev)
+{
+ kfree(dh_dev->priv);
+ dh_dev->priv = NULL;
+}
+
+#define GET_COREDEV_TYPE(pdev) \
+ ((pdev)->device == ZXDH_VF_DEVICE_ID ? DH_COREDEV_VF : DH_COREDEV_PF)
+
+#endif
+
--
2.27.0
[-- Attachment #1.1.2: Type: text/html , Size: 21496 bytes --]
^ 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