* RE: [Intel-wired-lan] [PATCH] ice: fix ICE_AQ_LINK_SPEED_M for 200G
From: Mekala, SunithaX D @ 2026-04-13 19:55 UTC (permalink / raw)
To: Loktionov, Aleksandr, intel-wired-lan@lists.osuosl.org,
Nguyen, Anthony L, Loktionov, Aleksandr
Cc: netdev@vger.kernel.org, Greenwalt, Paul
In-Reply-To: <20260320050537.422528-1-aleksandr.loktionov@intel.com>
> -----Original Message-----
> From: Intel-wired-lan <intel-wired-lan-bounces@osuosl.org> On Behalf Of Aleksandr Loktionov
> Sent: Thursday, March 19, 2026 10:06 PM
> To: intel-wired-lan@lists.osuosl.org; Nguyen, Anthony L <anthony.l.nguyen@intel.com>; Loktionov, Aleksandr <aleksandr.loktionov@intel.com>
> Cc: netdev@vger.kernel.org; Greenwalt, Paul <paul.greenwalt@intel.com>
> Subject: [Intel-wired-lan] [PATCH] ice: fix ICE_AQ_LINK_SPEED_M for 200G
>
> From: Paul Greenwalt <paul.greenwalt@intel.com>
>
> When setting PHY configuration during driver initialization, 200G link
> speed is not being advertised even when the PHY is capable. This is
> because the get PHY capabilities link speed response is being masked by
> ICE_AQ_LINK_SPEED_M, which does not include the 200G link speed bit.
>
> ICE_AQ_LINK_SPEED_200GB is defined as BIT(11), but the mask 0x7FF only
> covers bits 0-10. Fix ICE_AQ_LINK_SPEED_M to use GENMASK(11, 0) so
> that it covers all defined link speed bits including 200G.
>
> Fixes: 24407a01e57c ("ice: Add 200G speed/phy type use")
> Signed-off-by: Paul Greenwalt <paul.greenwalt@intel.com>
> Signed-off-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
> ---
> drivers/net/ethernet/intel/ice/ice_adminq_cmd.h | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
Tested-by: Sunitha Mekala <sunithax.d.mekala@intel.com> (A Contingent worker at Intel)
^ permalink raw reply
* Re: [GIT PULL] bluetooth-next 2026-04-10
From: Luiz Augusto von Dentz @ 2026-04-13 20:07 UTC (permalink / raw)
To: Jakub Kicinski; +Cc: davem, linux-bluetooth, netdev
In-Reply-To: <20260412091614.1786af4e@kernel.org>
Hi Jakub
On Sun, Apr 12, 2026 at 12:16 PM Jakub Kicinski <kuba@kernel.org> wrote:
>
> On Fri, 10 Apr 2026 13:22:06 -0400 Luiz Augusto von Dentz wrote:
> > bluetooth-next pull request for net-next:
> >
> > core:
> > - hci_core: Rate limit the logging of invalid ISO handle
> > - hci_sync: make hci_cmd_sync_run_once return -EEXIST if exists
> > - hci_event: fix locking in hci_conn_request_evt() with HCI_PROTO_DEFER
> > - hci_event: fix potential UAF in SSP passkey handlers
> > - HCI: Avoid a couple -Wflex-array-member-not-at-end warnings
> > - L2CAP: CoC: Disconnect if received packet size exceeds MPS
> > - L2CAP: Add missing chan lock in l2cap_ecred_reconf_rsp
> > - L2CAP: Fix printing wrong information if SDU length exceeds MTU
> > - SCO: check for codecs->num_codecs == 1 before assigning to sco_pi(sk)->codec
> >
> > drivers:
> > - btusb: MT7922: Add VID/PID 0489/e174
> > - btusb: Add Lite-On 04ca:3807 for MediaTek MT7921
> > - btusb: Add MT7927 IDs ASUS ROG Crosshair X870E Hero, Lenovo Legion Pro 7
> > 16ARX9, Gigabyte Z790 AORUS MASTER X, MSI X870E Ace Max, TP-Link
> > Archer TBE550E, ASUS X870E / ProArt X870E-Creator.
> > - btusb: Add MT7902 IDs 13d3/3579, 13d3/3580, 13d3/3594, 13d3/3596, 0e8d/1ede
> > - btusb: MediaTek MT7922: Add VID 0489 & PID e11d
> > - btintel: Add support for Scorpious Peak2 support
> > - btintel: Add support for Scorpious Peak2F support
> > - btintel_pcie: Add device id of Scorpius Peak2, Nova Lake-PCD-H
> > - btintel_pcie: Add device id of Scorpious2, Nova Lake-PCD-S
> > - btmtk: Add reset mechanism if downloading firmware failed
> > - btmtk: Add MT6639 (MT7927) Bluetooth support
> > - btmtk: fix ISO interface setup for single alt setting
> > - btmtk: add MT7902 SDIO support
> > - Bluetooth: btmtk: add MT7902 MCU support
> > - btbcm: Add entry for BCM4343A2 UART Bluetooth
> > - qca: enable pwrseq support for wcn39xx devices
> > - hci_qca: Fix BT not getting powered-off on rmmod
> > - hci_qca: disable power control for WCN7850 when bt_en is not defined
> > - hci_qca: Fix missing wakeup during SSR memdump handling
> > - hci_ldisc: Clear HCI_UART_PROTO_INIT on error
> > - mmc: sdio: add MediaTek MT7902 SDIO device ID
> > - hci_ll: Enable BROKEN_ENHANCED_SETUP_SYNC_CONN for WL183x
>
> Two fixes tags are messed up here:
>
> Commit: 802446198014 ("Bluetooth: btmtk: hide unused btmtk_mt6639_devs[] array")
> Fixes tag: Fixes: 4cdd001ff03f ("Bluetooth: btmtk: Add MT6639 (MT7927) Bluetooth support")
> Has these problem(s):
> - Target SHA1 does not exist
>
> Commit: 28c9cc700e30 ("Bluetooth: L2CAP: Fix printing wrong information if SDU length exceeds MTU")
> Fixes tag: Fixes: fa768fce4aae ("Bluetooth: LE L2CAP: Disconnect if received packet's SDU exceeds IMTU")
> Has these problem(s):
> - Target SHA1 does not exist
Would you be able to pull the for-net-next-2026-04-13?
--
Luiz Augusto von Dentz
^ permalink raw reply
* Re: [PATCH net-next v2] net: check qdisc_pkt_len_segs_init() return value on ingress
From: Eric Dumazet @ 2026-04-13 20:09 UTC (permalink / raw)
To: David Carlier
Cc: Jakub Kicinski, David S . Miller, Paolo Abeni, Simon Horman,
Stanislav Fomichev, Kuniyuki Iwashima, Samiullah Khawaja,
Hangbin Liu, Krishna Kumar, netdev, linux-kernel
In-Reply-To: <20260413182225.10683-1-devnexen@gmail.com>
On Mon, Apr 13, 2026 at 11:22 AM David Carlier <devnexen@gmail.com> wrote:
>
> Commit 7fb4c1967011 ("net: pull headers in qdisc_pkt_len_segs_init()")
> changed qdisc_pkt_len_segs_init() to return an skb drop reason when
> it detects malicious GSO packets. The egress path in __dev_queue_xmit()
> checks this return value and drops bad packets, but the ingress path in
> sch_handle_ingress() ignores it.
>
> This means malformed GSO packets entering via TC ingress are not dropped
> and could be redirected to another interface or cause incorrect qdisc
> accounting.
>
> Check the return value and drop the packet when a bad GSO is detected.
>
> Fixes: 7fb4c1967011 ("net: pull headers in qdisc_pkt_len_segs_init()")
> Signed-off-by: David Carlier <devnexen@gmail.com>
> ---
>
> v1 -> v2: reorder variable declarations for reverse xmas tree
> v1: https://lore.kernel.org/netdev/20260408172307.46498-1-devnexen@gmail.com/
> net/core/dev.c | 12 ++++++++++--
> 1 file changed, 10 insertions(+), 2 deletions(-)
NACK. This is is not needed.
I will not even bother, this is an obvious LLM based patch.
^ permalink raw reply
* Re: [PATCH net-next] mlx4: correct error reporting in mlx4_master_process_vhcr()
From: Tariq Toukan @ 2026-04-13 20:13 UTC (permalink / raw)
To: Alok Tiwari, tariqt, andrew+netdev, kuba, davem, edumazet, pabeni,
horms, netdev
Cc: alok.a.tiwarilinux
In-Reply-To: <20260409092754.508880-1-alok.a.tiwari@oracle.com>
On 09/04/2026 12:27, Alok Tiwari wrote:
> mlx4_master_process_vhcr() logs vhcr->errno on failures, but this field
> is never populated by the PF path. As a result, all failures are reported
> with errno 0 and err print in status case which is misleading.
>
> Use the actual return value (err) instead, translate it to FW status
> before logging, and report both values.
>
> Signed-off-by: Alok Tiwari <alok.a.tiwari@oracle.com>
> ---
> drivers/net/ethernet/mellanox/mlx4/cmd.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/net/ethernet/mellanox/mlx4/cmd.c b/drivers/net/ethernet/mellanox/mlx4/cmd.c
> index de0193d82ec1..bdaf152e6712 100644
> --- a/drivers/net/ethernet/mellanox/mlx4/cmd.c
> +++ b/drivers/net/ethernet/mellanox/mlx4/cmd.c
> @@ -1782,6 +1782,7 @@ static int mlx4_master_process_vhcr(struct mlx4_dev *dev, int slave,
> }
>
> if (err) {
> + vhcr_cmd->status = mlx4_errno_to_status(err);
> if (!(dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR)) {
> if (vhcr->op == MLX4_CMD_ALLOC_RES &&
> (vhcr->in_modifier & 0xff) == RES_COUNTER &&
> @@ -1791,9 +1792,8 @@ static int mlx4_master_process_vhcr(struct mlx4_dev *dev, int slave,
> slave, err);
> else
> mlx4_warn(dev, "vhcr command:0x%x slave:%d failed with error:%d, status %d\n",
> - vhcr->op, slave, vhcr->errno, err);
> + vhcr->op, slave, err, vhcr_cmd->status);
> }
> - vhcr_cmd->status = mlx4_errno_to_status(err);
> goto out_status;
> }
>
Reviewed-by: Tariq Toukan <tariqt@nvidia.com>
Thanks.
^ permalink raw reply
* Re: [PATCH net-next v2] net: check qdisc_pkt_len_segs_init() return value on ingress
From: David CARLIER @ 2026-04-13 20:34 UTC (permalink / raw)
To: Eric Dumazet
Cc: Jakub Kicinski, David S . Miller, Paolo Abeni, Simon Horman,
Stanislav Fomichev, Kuniyuki Iwashima, Samiullah Khawaja,
Hangbin Liu, Krishna Kumar, netdev, linux-kernel
In-Reply-To: <CANn89iLE4k=N62i9hs+GumpP5v7CU7L+Qj644=4Zk74_P0zDxw@mail.gmail.com>
Hi Eric,
You're right on both counts. An LLM was used for the initial
bug-finding /
pre-analysis on this one, and clearly it wasn't deep enough.
Daniel's
question made me go back and trace the redirect paths properly — the
premise was wrong, __dev_queue_xmit() already catches them. I should
have
re-read your 7fb4c1967011 commit message before sending.
Dropping it. Sorry for the noise.
Cheers,
On Mon, 13 Apr 2026 at 21:09, Eric Dumazet <edumazet@google.com> wrote:
>
> On Mon, Apr 13, 2026 at 11:22 AM David Carlier <devnexen@gmail.com> wrote:
> >
> > Commit 7fb4c1967011 ("net: pull headers in qdisc_pkt_len_segs_init()")
> > changed qdisc_pkt_len_segs_init() to return an skb drop reason when
> > it detects malicious GSO packets. The egress path in __dev_queue_xmit()
> > checks this return value and drops bad packets, but the ingress path in
> > sch_handle_ingress() ignores it.
> >
> > This means malformed GSO packets entering via TC ingress are not dropped
> > and could be redirected to another interface or cause incorrect qdisc
> > accounting.
> >
> > Check the return value and drop the packet when a bad GSO is detected.
> >
> > Fixes: 7fb4c1967011 ("net: pull headers in qdisc_pkt_len_segs_init()")
> > Signed-off-by: David Carlier <devnexen@gmail.com>
> > ---
> >
> > v1 -> v2: reorder variable declarations for reverse xmas tree
> > v1: https://lore.kernel.org/netdev/20260408172307.46498-1-devnexen@gmail.com/
> > net/core/dev.c | 12 ++++++++++--
> > 1 file changed, 10 insertions(+), 2 deletions(-)
>
> NACK. This is is not needed.
>
> I will not even bother, this is an obvious LLM based patch.
^ permalink raw reply
* Re: [GIT PULL] bluetooth-next 2026-04-10
From: Jakub Kicinski @ 2026-04-13 20:44 UTC (permalink / raw)
To: Luiz Augusto von Dentz; +Cc: davem, linux-bluetooth, netdev
In-Reply-To: <CABBYNZLg_Dz9ieQ+ioXf2+Oa+vdL8BMbnt=qOfkONOpNsUZ5qw@mail.gmail.com>
On Mon, 13 Apr 2026 16:07:55 -0400 Luiz Augusto von Dentz wrote:
> > Two fixes tags are messed up here:
> >
> > Commit: 802446198014 ("Bluetooth: btmtk: hide unused btmtk_mt6639_devs[] array")
> > Fixes tag: Fixes: 4cdd001ff03f ("Bluetooth: btmtk: Add MT6639 (MT7927) Bluetooth support")
> > Has these problem(s):
> > - Target SHA1 does not exist
> >
> > Commit: 28c9cc700e30 ("Bluetooth: L2CAP: Fix printing wrong information if SDU length exceeds MTU")
> > Fixes tag: Fixes: fa768fce4aae ("Bluetooth: LE L2CAP: Disconnect if received packet's SDU exceeds IMTU")
> > Has these problem(s):
> > - Target SHA1 does not exist
>
> Would you be able to pull the for-net-next-2026-04-13?
I think so.
^ permalink raw reply
* [PATCH v4 net] net: ax25: fix integer overflow in ax25_rx_fragment()
From: Mashiro Chen @ 2026-04-13 20:49 UTC (permalink / raw)
To: netdev; +Cc: linux-hams, kuba, horms, davem, pabeni, edumazet, Mashiro Chen
In-Reply-To: <20260409025026.24575-1-mashiro.chen@mailbox.org>
ax25_rx_fragment() accumulates fragment lengths into ax25_cb->fraglen,
which is an unsigned short. When the total exceeds 65535, fraglen wraps
around to a small value. The subsequent alloc_skb(fraglen) allocates a
too-small buffer, and skb_put() in the copy loop triggers skb_over_panic().
Add pskb_may_pull(skb, 1) at function entry to ensure the segmentation
header byte is in the linear data area before dereferencing skb->data.
This also rejects zero-length skbs, which the original code did not
check for.
Two issues in the overflow error path are also fixed:
First, the current skb, after skb_pull(skb, 1), is neither enqueued
nor freed before returning 1, leaking it. Add kfree_skb(skb) before
the return.
Second, ax25->fraglen is not reset after skb_queue_purge(). Add
ax25->fraglen = 0 to restore a consistent state.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Signed-off-by: Mashiro Chen <mashiro.chen@mailbox.org>
---
net/ax25/ax25_in.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/net/ax25/ax25_in.c b/net/ax25/ax25_in.c
index d75b3e9ed93de8..e1834e11bb0b6a 100644
--- a/net/ax25/ax25_in.c
+++ b/net/ax25/ax25_in.c
@@ -35,12 +35,22 @@ static int ax25_rx_fragment(ax25_cb *ax25, struct sk_buff *skb)
{
struct sk_buff *skbn, *skbo;
+ if (!pskb_may_pull(skb, 1))
+ return 0;
+
if (ax25->fragno != 0) {
if (!(*skb->data & AX25_SEG_FIRST)) {
if ((ax25->fragno - 1) == (*skb->data & AX25_SEG_REM)) {
/* Enqueue fragment */
ax25->fragno = *skb->data & AX25_SEG_REM;
skb_pull(skb, 1); /* skip fragno */
+ if (ax25->fraglen + skb->len > USHRT_MAX) {
+ kfree_skb(skb);
+ skb_queue_purge(&ax25->frag_queue);
+ ax25->fragno = 0;
+ ax25->fraglen = 0;
+ return 1;
+ }
ax25->fraglen += skb->len;
skb_queue_tail(&ax25->frag_queue, skb);
--
2.53.0
^ permalink raw reply related
* Re: [PATCH net-next] net: stmmac: enable RPS and RBU interrupts
From: Jakub Kicinski @ 2026-04-13 20:50 UTC (permalink / raw)
To: Russell King (Oracle)
Cc: Andrew Lunn, Alexandre Torgue, Andrew Lunn, David S. Miller,
Eric Dumazet, linux-arm-kernel, linux-stm32, netdev, Paolo Abeni,
Sam Edwards
In-Reply-To: <ad06yiZZbLC9k3jY@shell.armlinux.org.uk>
On Mon, 13 Apr 2026 19:49:46 +0100 Russell King (Oracle) wrote:
> > Firing interrupts when Rx fill ring runs dry (which IIUC this patches
> > dies?) is not a good idea.
>
> Well, I'm thinking that at least on some platforms, such as the Jetson
> Xavier NX, unless a different solution can be found, we need the RBU
> interrupt to fire off a reset of the stmmac IP when this happens to
> reduce the PAUSE frame flood on the network.
>
> If we can't do that, then I think stmmac on these platforms needs to be
> marked with CONFIG_BROKEN because right now there doesn't seem to be any
> other viable solution.
>
> My intention with this patch is merely to start collecting the already
> existing statistics so other users can start seeing whether they are
> hitting the same or similar problem. If we're not prepared to do that,
> then we should delete the useless statistics from ethtool -S, but I
> suspect they're now part of the UAPI, even though without this patch
> they will remain stedfastly stuck at zero.
Understood, thanks for the extra context. And the statistic we are
talking about is rx_buf_unav_irq ?
^ permalink raw reply
* Re: [PATCH net-next 2/3] rose: clear neighbour pointer after rose_neigh_put() in state machines
From: Jakub Kicinski @ 2026-04-13 20:53 UTC (permalink / raw)
To: f6bvp; +Cc: linux-hams, netdev, edumazet, pabeni
In-Reply-To: <20260413174238.112418-2-bernard.f6bvp@gmail.com>
On Mon, 13 Apr 2026 19:42:37 +0200 f6bvp wrote:
> Signed-off-by: f6bvp <bernard.f6bvp@gmail.com>
Human name is required when authoring patches.
Please do not post patches in reply to existing threads. See:
https://www.kernel.org/doc/html/next/process/maintainer-netdev.html
--
pw-bot: cr
^ permalink raw reply
* Re: [PATCH net-next] net: stmmac: enable RPS and RBU interrupts
From: Russell King (Oracle) @ 2026-04-13 20:53 UTC (permalink / raw)
To: Jakub Kicinski
Cc: Andrew Lunn, Alexandre Torgue, Andrew Lunn, David S. Miller,
Eric Dumazet, linux-arm-kernel, linux-stm32, netdev, Paolo Abeni,
Sam Edwards
In-Reply-To: <20260413135018.59fbd3a1@kernel.org>
On Mon, Apr 13, 2026 at 01:50:18PM -0700, Jakub Kicinski wrote:
> On Mon, 13 Apr 2026 19:49:46 +0100 Russell King (Oracle) wrote:
> > > Firing interrupts when Rx fill ring runs dry (which IIUC this patches
> > > dies?) is not a good idea.
> >
> > Well, I'm thinking that at least on some platforms, such as the Jetson
> > Xavier NX, unless a different solution can be found, we need the RBU
> > interrupt to fire off a reset of the stmmac IP when this happens to
> > reduce the PAUSE frame flood on the network.
> >
> > If we can't do that, then I think stmmac on these platforms needs to be
> > marked with CONFIG_BROKEN because right now there doesn't seem to be any
> > other viable solution.
> >
> > My intention with this patch is merely to start collecting the already
> > existing statistics so other users can start seeing whether they are
> > hitting the same or similar problem. If we're not prepared to do that,
> > then we should delete the useless statistics from ethtool -S, but I
> > suspect they're now part of the UAPI, even though without this patch
> > they will remain stedfastly stuck at zero.
>
> Understood, thanks for the extra context. And the statistic we are
> talking about is rx_buf_unav_irq ?
Yes, correct.
--
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!
^ permalink raw reply
* Re: [PATCH net-next 1/3] rose: fix race between loopback timer and module removal
From: Andrew Lunn @ 2026-04-13 21:21 UTC (permalink / raw)
To: f6bvp; +Cc: linux-hams, netdev, edumazet, pabeni
In-Reply-To: <20260413174238.112418-1-bernard.f6bvp@gmail.com>
On Mon, Apr 13, 2026 at 07:42:36PM +0200, f6bvp wrote:
> rose_loopback_clear() used timer_delete() which returns immediately
> without waiting for any running callback to complete. If the timer
> fired concurrently with module removal, rose_loopback_timer() would
> access rose_loopback_neigh after it was freed, causing a use-after-free.
>
> Three changes fix the race:
>
> 1. Add a loopback_stopping atomic flag. rose_loopback_timer() checks
> this at entry and mid-loop; when set it drains the queue and bails
> out without re-arming the timer.
>
> 2. Switch rose_loopback_clear() to timer_delete_sync() so it blocks
> until any in-flight callback has returned.
>
> 3. Wrap the timer body with rose_neigh_hold()/rose_neigh_put() so the
> loopback neighbour cannot be freed while the callback is running.
>
> Also fix a pre-existing bug: dev_put(dev) was only called on the
> failure path of rose_rx_call_request(); it is now called unconditionally
> so the device reference is always released.
Hi Barnard
Thanks for the patches.
A few process points.
We prefer lots of small patches, with good commit messages, which are
obviously correct. When i see a list like this, it makes me think the
patch can be split up into smaller patches.
When you have a patch series, please include a patch 0/X which
explains the big picture.
net-next is current closed for the merge window. You can post patches
as RFC, but don't post anything expecting it to be merged.
There is more information here:
https://www.kernel.org/doc/html/latest/process/maintainer-netdev.html
Andrew
^ permalink raw reply
* Re: [PATCH net-next] mlx4: correct error reporting in mlx4_master_process_vhcr()
From: patchwork-bot+netdevbpf @ 2026-04-13 21:30 UTC (permalink / raw)
To: Alok Tiwari
Cc: tariqt, andrew+netdev, kuba, davem, edumazet, pabeni, horms,
netdev, alok.a.tiwarilinux
In-Reply-To: <20260409092754.508880-1-alok.a.tiwari@oracle.com>
Hello:
This patch was applied to netdev/net-next.git (main)
by Jakub Kicinski <kuba@kernel.org>:
On Thu, 9 Apr 2026 02:27:47 -0700 you wrote:
> mlx4_master_process_vhcr() logs vhcr->errno on failures, but this field
> is never populated by the PF path. As a result, all failures are reported
> with errno 0 and err print in status case which is misleading.
>
> Use the actual return value (err) instead, translate it to FW status
> before logging, and report both values.
>
> [...]
Here is the summary with links:
- [net-next] mlx4: correct error reporting in mlx4_master_process_vhcr()
https://git.kernel.org/netdev/net-next/c/bc174d054986
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* Re: [GIT PULL] bluetooth-next 2026-04-13
From: patchwork-bot+netdevbpf @ 2026-04-13 21:30 UTC (permalink / raw)
To: Luiz Augusto von Dentz; +Cc: davem, kuba, linux-bluetooth, netdev
In-Reply-To: <20260413132247.320961-1-luiz.dentz@gmail.com>
Hello:
This pull request was applied to netdev/net-next.git (main)
by Jakub Kicinski <kuba@kernel.org>:
On Mon, 13 Apr 2026 09:22:47 -0400 you wrote:
> The following changes since commit 42f9b4c6ef19e71d2c7d9bfd3c5037d4fe434ad7:
>
> tools: ynl: tests: fix leading space on Makefile target (2026-04-09 20:41:40 -0700)
>
> are available in the Git repository at:
>
> git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git tags/for-net-next-2026-04-13
>
> [...]
Here is the summary with links:
- [GIT,PULL] bluetooth-next 2026-04-13
https://git.kernel.org/netdev/net-next/c/e9dc62f25ba6
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* Re: [Intel-wired-lan] [PATCH iwl-net] ice: fix infinite recursion in ice_cfg_tx_topo via ice_init_dev_hw
From: Paul Menzel @ 2026-04-13 21:30 UTC (permalink / raw)
To: Petr Oros
Cc: netdev, Michal Swiatkowski, Paul Greenwalt, Daniel Zahka,
Przemek Kitszel, Nikolay Aleksandrov, Eric Dumazet, linux-kernel,
Aleksandr Loktionov, Andrew Lunn, Tony Nguyen, Dave Ertman,
jacob.e.keller, Jakub Kicinski, Paolo Abeni, David S. Miller,
intel-wired-lan
In-Reply-To: <20260413191420.3524013-1-poros@redhat.com>
Dear Petr,
Thank you very much for your patch.
Am 13.04.26 um 21:14 schrieb Petr Oros:
> On certain E810 configurations where firmware supports Tx scheduler
> topology switching (tx_sched_topo_comp_mode_en), ice_cfg_tx_topo()
> may need to apply a new 5-layer or 9-layer topology from the DDP
> package. If the AQ command to set the topology fails (e.g. due to
> invalid DDP data or firmware limitations), the global configuration
> lock must still be cleared via a CORER reset.
>
> Commit 86aae43f21cf ("ice: don't leave device non-functional if Tx
> scheduler config fails") correctly fixed this by refactoring
> ice_cfg_tx_topo() to always trigger CORER after acquiring the global
> lock and re-initialize hardware via ice_init_hw() afterwards.
>
> However, commit 8a37f9e2ff40 ("ice: move ice_deinit_dev() to the end
> of deinit paths") later moved ice_init_dev_hw() into ice_init_hw(),
> breaking the reinit path introduced by 86aae43f21cf. This creates an
> infinite recursive call chain:
>
> ice_init_hw()
> ice_init_dev_hw()
> ice_cfg_tx_topo() # topology change needed
> ice_deinit_hw()
> ice_init_hw() # reinit after CORER
> ice_init_dev_hw() # recurse
> ice_cfg_tx_topo()
> ... # stack overflow
>
> Fix by moving ice_init_dev_hw() back out of ice_init_hw() and calling
> it explicitly from ice_probe() and ice_devlink_reinit_up(). The third
> caller, ice_cfg_tx_topo(), intentionally does not need ice_init_dev_hw()
> during its reinit, it only needs the core HW reinitialization. This
> breaks the recursion cleanly without adding flags or guards.
>
> The deinit ordering changes from commit 8a37f9e2ff40 ("ice: move
> ice_deinit_dev() to the end of deinit paths") which fixed slow rmmod
> are preserved, only the init-side placement of ice_init_dev_hw() is
> reverted.
>
> Fixes: 8a37f9e2ff40 ("ice: move ice_deinit_dev() to the end of deinit paths")
> Signed-off-by: Petr Oros <poros@redhat.com>
> ---
> drivers/net/ethernet/intel/ice/devlink/devlink.c | 2 ++
> drivers/net/ethernet/intel/ice/ice_common.c | 2 --
> drivers/net/ethernet/intel/ice/ice_main.c | 2 ++
> 3 files changed, 4 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/net/ethernet/intel/ice/devlink/devlink.c b/drivers/net/ethernet/intel/ice/devlink/devlink.c
> index 6144cee8034d77..641d6e289d5ce6 100644
> --- a/drivers/net/ethernet/intel/ice/devlink/devlink.c
> +++ b/drivers/net/ethernet/intel/ice/devlink/devlink.c
> @@ -1245,6 +1245,8 @@ static int ice_devlink_reinit_up(struct ice_pf *pf)
> return err;
> }
>
> + ice_init_dev_hw(pf);
> +
> /* load MSI-X values */
> ice_set_min_max_msix(pf);
>
> diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c
> index ce11fea122d03e..b617a6bff89134 100644
> --- a/drivers/net/ethernet/intel/ice/ice_common.c
> +++ b/drivers/net/ethernet/intel/ice/ice_common.c
> @@ -1126,8 +1126,6 @@ int ice_init_hw(struct ice_hw *hw)
> if (status)
> goto err_unroll_fltr_mgmt_struct;
>
> - ice_init_dev_hw(hw->back);
> -
> mutex_init(&hw->tnl_lock);
> ice_init_chk_recipe_reuse_support(hw);
>
> diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c
> index e2a5534819d194..a27be29f9bbbfc 100644
> --- a/drivers/net/ethernet/intel/ice/ice_main.c
> +++ b/drivers/net/ethernet/intel/ice/ice_main.c
> @@ -5314,6 +5314,8 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)
> return err;
> }
>
> + ice_init_dev_hw(pf);
> +
> adapter = ice_adapter_get(pdev);
> if (IS_ERR(adapter)) {
> err = PTR_ERR(adapter);
Reviewed-by: Paul Menzel <pmenzel@molgen.mpg.de>
Kind regards,
Paul
^ permalink raw reply
* Re: [PATCH net-next 0/3] Follow-ups to nk_qlease net selftests
From: Jakub Kicinski @ 2026-04-13 21:32 UTC (permalink / raw)
To: Daniel Borkmann; +Cc: pabeni, dw, razor, netdev
In-Reply-To: <47b7d67b-2240-4815-87c8-368413c9ddee@iogearbox.net>
On Mon, 13 Apr 2026 15:02:22 +0200 Daniel Borkmann wrote:
> I'm planning to address these in a v2 of the series, but as per netdev rule
> will wait 24h before resend unless you'd like me to explicitly resend earlier
> (given merge win timing).
Please go ahead with v2 as soon as it's ready.
^ permalink raw reply
* Re: [PATCH net-next 1/3] rose: fix race between loopback timer and module removal
From: Jakub Kicinski @ 2026-04-13 21:34 UTC (permalink / raw)
To: Andrew Lunn, f6bvp; +Cc: linux-hams, netdev, edumazet, pabeni
In-Reply-To: <8e76226b-c861-45f5-9d18-8affa0c80525@lunn.ch>
On Mon, 13 Apr 2026 23:21:16 +0200 Andrew Lunn wrote:
> net-next is current closed for the merge window. You can post patches
> as RFC, but don't post anything expecting it to be merged.
FWIW I assumed this were fixes, in which case the closing of the trees
would not apply, the patches should be marked as "PATCH net" and have
a Fixes tag.
^ permalink raw reply
* Re: [PATCH net-next] net: shaper: Reject zero weight in shaper config
From: Jakub Kicinski @ 2026-04-13 21:50 UTC (permalink / raw)
To: Mohsin Bashir
Cc: netdev, ast, chuck.lever, davem, donald.hunter, edumazet, horms,
linux-kernel, matttbe, pabeni
In-Reply-To: <20260410225123.2341672-1-mohsin.bashr@gmail.com>
On Fri, 10 Apr 2026 15:51:23 -0700 Mohsin Bashir wrote:
> A zero weight is meaningless for DWRR scheduling and can cause
> starvation of the affected node. Add a min-value constraint to
> the weight attribute in the net_shaper netlink spec so that zero
> is rejected at the netlink policy level.
>
> Found while prototyping a new driver, existing drivers are not
> affected.
AI review points out that if the netlink attr is not present core will
leave the DWRR weight as 0 in the struct. I guess we need to think this
thru a little more carefully. What should the "default" weight be?
What if user specifies weights only for subset of leaves?
This part of the uAPI seems under-defined.
Maybe a better adjustment would be to make core set the weight to 1
automatically if the user has not defined it? Only when sending it to
the driver tho, because we'd still want it to not be reported back to
user space. Not sure how hairy it'd get code-wise.
^ permalink raw reply
* Re: [PATCH net-next] net: stmmac: enable RPS and RBU interrupts
From: Sam Edwards @ 2026-04-13 21:54 UTC (permalink / raw)
To: Russell King (Oracle)
Cc: Jakub Kicinski, Andrew Lunn, Alexandre Torgue, Andrew Lunn,
David S. Miller, Eric Dumazet,
moderated list:BROADCOM BCM2711/BCM2835 ARM ARCHITECTURE,
linux-stm32, Linux Network Development Mailing List, Paolo Abeni
In-Reply-To: <ad06yiZZbLC9k3jY@shell.armlinux.org.uk>
On Mon, Apr 13, 2026, 11:49 Russell King (Oracle) <linux@armlinux.org.uk> wrote:
>
> On Mon, Apr 13, 2026 at 11:02:22AM -0700, Jakub Kicinski wrote:
> > On Fri, 10 Apr 2026 14:07:51 +0100 Russell King (Oracle) wrote:
> > > Since we are seeing receive buffer exhaustion on several platforms,
> > > let's enable the interrupts so the statistics we publish via ethtool -S
> > > actually work to aid diagnosis. I've been in two minds about whether
> > > to send this patch, but given the problems with stmmac at the moment,
> > > I think it should be merged.
> >
> > Sorry for a under-research response but wasn't there are person trying
> > to fix the OOM starvation issue? Who was supposed to add a timer?
> > Is your problem also OOM related or do you suspect something else?
>
> It is not OOM related. I have this patch applied:
>
> diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> index 131ea887bedc..614d0e10e3e6 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> @@ -5095,14 +5095,18 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv, u32 queue)
>
> if (!buf->page) {
> buf->page = page_pool_alloc_pages(rx_q->page_pool, gfp);
> - if (!buf->page)
> + if (!buf->page) {
> + netdev_err(priv->dev, "q%u: no buffer 1\n", queue);
> break;
> + }
> }
>
> if (priv->sph_active && !buf->sec_page) {
> buf->sec_page = page_pool_alloc_pages(rx_q->page_pool, gfp);
> - if (!buf->sec_page)
> + if (!buf->sec_page) {
> + netdev_err(priv->dev, "q%u: no buffer 2\n", queue);
> break;
> + }
>
> buf->sec_addr = page_pool_get_dma_addr(buf->sec_page);
> }
>
> and it is silent, so we are not suffering starvation of buffers.
>
> However, the hardware hangs during iperf3, and because it triggers the
> MAC to stream PAUSE frames, and my network uses Netgear GS108 and GS116
> unmanaged switches that always use flow-control between them (there's no
> way not to) it takes down the entire network - as we've discussed
> before. So, this problem is pretty fatal to the *entire* network.
>
> With this patch, the existing statistical counters for this condition
> are incremented, and thus users can use ethtool -S to see what happened
> and report whether they are seeing the same issue.
>
> Without this patch applied, there are no diagnostics from stmmac that
> report what the state is. ethtool -d doesn't list the appropriate
> registers (as I suspect part of the problem is the number of queues
> is somewhat dynamic - userspace can change that configuration through
> ethtool).
>
> Thus, one has to resort to using devmem2 to find out what's happened.
> That's not user friendly.
>
> For me, devmem2 shows:
>
> Channel 0 status register:
> Value at address 0x02491160: 0x00000484
> bit 10: ETI early transmit interrupt - set
> bit 9 : RWT receive watchdog - clear
> bit 8 : RPS receieve process stopped - clear
> bit 7 : RBU receive buffer unavailable - set
> bit 6 : RI receive interrupt - clear
> bit 2 : TBU transmit buffer unavailable - set
> bit 1 : TPS transmit process stopped - clear
> bit 0 : TI transmit interrupt - clear
>
> Debug status register:
> Value at address 0x0249100c: 0x00006300
> TPS[3:0] = 6 = Suspended, Tx descriptor unavailable or Tx buffer
> underflow
> RPS[3:0] = 3 = Running, waiting for Rx packet
>
> Metal Queue 0 debug register:
> Value at address 0x02490d38: 0x002e0020
> PRXQ[13:0] = 0x2e = 46 packets in receive queue
> RXQSTS[1:0] = 2 = Rx queue fill-level above flow-control activate
> threshold
> RRCSTS[1:0] = 0 = Rx Queue Read Controller State = Idle
>
> > Firing interrupts when Rx fill ring runs dry (which IIUC this patches
> > dies?) is not a good idea.
>
> Well, I'm thinking that at least on some platforms, such as the Jetson
> Xavier NX, unless a different solution can be found, we need the RBU
> interrupt to fire off a reset of the stmmac IP when this happens to
> reduce the PAUSE frame flood on the network.
Hi Russell,
Should that reset trigger be RPS, not RBU? My understanding of these
status bits is RBU is just "RxDMA has failed to take a frame from the
RxFIFO" while RPS is "the RxFIFO is full." That would make RBU our
critical threshold to start proactively refilling, and RPS the "too
late, we lose" threshold.
Thinking aloud: Do you suppose the RxDMA waits for a wakeup signal
sent whenever a frame is added to RxFIFO? That might explain why the
former never recovers once the latter is full: a manual wakeup needs
to be sent whenever we resolve RBU. Does the .enable_dma_reception()
op need to be implemented for dwmac5, or have you tried that already?
>
> If we can't do that, then I think stmmac on these platforms needs to be
> marked with CONFIG_BROKEN because right now there doesn't seem to be any
> other viable solution.
>
> My intention with this patch is merely to start collecting the already
> existing statistics so other users can start seeing whether they are
> hitting the same or similar problem. If we're not prepared to do that,
> then we should delete the useless statistics from ethtool -S, but I
> suspect they're now part of the UAPI, even though without this patch
> they will remain stedfastly stuck at zero.
>
> --
> RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
> FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!
^ permalink raw reply
* Re: [PATCH net] net: phy: qcom: at803x: Use the correct bit to disable extended next page
From: patchwork-bot+netdevbpf @ 2026-04-13 22:00 UTC (permalink / raw)
To: Maxime Chevallier
Cc: andrew, kuba, davem, edumazet, pabeni, horms, linux,
thomas.petazzoni, netdev, linux-kernel, linux-arm-msm
In-Reply-To: <20260410171021.1277138-1-maxime.chevallier@bootlin.com>
Hello:
This patch was applied to netdev/net.git (main)
by Jakub Kicinski <kuba@kernel.org>:
On Fri, 10 Apr 2026 19:10:20 +0200 you wrote:
> As noted in the blamed commit, the AR8035 and other PHYs from this
> family advertise the Extended Next Page support by default, which may be
> understood by some partners as this PHY being multi-gig capable.
>
> The fix is to disable XNP advertising, which is done by setting bit 12
> of the Auto-Negotiation Advertisement Register (MII_ADVERTISE).
>
> [...]
Here is the summary with links:
- [net] net: phy: qcom: at803x: Use the correct bit to disable extended next page
https://git.kernel.org/netdev/net/c/e7a62edd34b1
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* Re: [PATCH net-next] net: stmmac: enable RPS and RBU interrupts
From: patchwork-bot+netdevbpf @ 2026-04-13 22:00 UTC (permalink / raw)
To: Russell King
Cc: andrew, alexandre.torgue, andrew+netdev, davem, edumazet, kuba,
linux-arm-kernel, linux-stm32, netdev, pabeni, cfsworks
In-Reply-To: <E1wBBaR-0000000GZHR-1dbM@rmk-PC.armlinux.org.uk>
Hello:
This patch was applied to netdev/net-next.git (main)
by Jakub Kicinski <kuba@kernel.org>:
On Fri, 10 Apr 2026 14:07:51 +0100 you wrote:
> Enable receive process stopped and receive buffer unavailable
> interrupts, so that the statistic counters can be updated.
>
> Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
> ---
> Since we are seeing receive buffer exhaustion on several platforms,
> let's enable the interrupts so the statistics we publish via ethtool -S
> actually work to aid diagnosis. I've been in two minds about whether
> to send this patch, but given the problems with stmmac at the moment,
> I think it should be merged.
>
> [...]
Here is the summary with links:
- [net-next] net: stmmac: enable RPS and RBU interrupts
https://git.kernel.org/netdev/net-next/c/1b9707e6f1a9
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* [PATCH net-next v2 1/3] tools/ynl: Make YnlFamily closeable as a context manager
From: Daniel Borkmann @ 2026-04-13 22:08 UTC (permalink / raw)
To: netdev; +Cc: kuba, dw, pabeni, razor
In-Reply-To: <20260413220809.604592-1-daniel@iogearbox.net>
YnlFamily opens an AF_NETLINK socket in __init__ but has no way
to release it other than leaving it to the GC. YnlFamily holds a
self reference cycle through SpecFamily's self.family = self
in its super().__init__() call, so refcount GC cannot reclaim
it and the socket stays open until the cyclic GC runs.
If a test creates a guest netns, instantiates a YnlFamily inside
it via NetNSEnter(), performs some test case work via Ynl, and
then deletes the netns, then the 'ip netns del' only drops the
mount binding and cleanup_net in the kernel never runs, so any
subsequent test case assertions that objects got cleaned up would
fail given this only gets triggered later via cyclic GC run.
Add an explicit close() that closes the netlink socket and wire
up the __enter__/__exit__ so callers can scope the instance
deterministically via 'with YnlFamily(...) as ynl: ...'.
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
---
tools/net/ynl/pyynl/lib/ynl.py | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/tools/net/ynl/pyynl/lib/ynl.py b/tools/net/ynl/pyynl/lib/ynl.py
index 9c078599cea0..f63c6f828735 100644
--- a/tools/net/ynl/pyynl/lib/ynl.py
+++ b/tools/net/ynl/pyynl/lib/ynl.py
@@ -731,6 +731,16 @@ class YnlFamily(SpecFamily):
bound_f = functools.partial(self._op, op_name)
setattr(self, op.ident_name, bound_f)
+ def close(self):
+ if self.sock is not None:
+ self.sock.close()
+ self.sock = None
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, exc_type, exc, tb):
+ self.close()
def ntf_subscribe(self, mcast_name):
mcast_id = self.nlproto.get_mcast_id(mcast_name, self.mcast_groups)
--
2.43.0
^ permalink raw reply related
* [PATCH net-next v2 0/3] Follow-ups to nk_qlease net selftests
From: Daniel Borkmann @ 2026-04-13 22:08 UTC (permalink / raw)
To: netdev; +Cc: kuba, dw, pabeni, razor
This is a set of follow-ups addressing [0]:
- Split netdevsim tests from HW tests in nk_qlease and move the SW
tests under selftests/net/
- Remove multiple ksft_run()s to fix the recently enforced hard-fail
- Move all the setup inside the test cases for the ones under
selftests/net/ (I'll defer the HW ones to David)
- Add more test coverage related to queue leasing behavior and corner
cases, so now we have 45 tests in nk_qlease.py with netdevsim
which does not need special HW
[0] https://lore.kernel.org/netdev/20260409181950.7e099b6c@kernel.org
v1->v2:
- Fixed ruff ambiguous variable name
- Fixed https://sashiko.dev/#/patchset/20260413114011.588162-1-daniel%40iogearbox.net
findings except the one in patch 1 since if something goes wrong
there, then the test fails and socket gets cleaned up via cyclic
GC run anyway
Daniel Borkmann (3):
tools/ynl: Make YnlFamily closeable as a context manager
selftests/net: Split netdevsim tests from HW tests in nk_qlease
selftests/net: Add additional test coverage in nk_qlease
tools/net/ynl/pyynl/lib/ynl.py | 10 +
.../selftests/drivers/net/hw/nk_qlease.py | 1142 ---------
tools/testing/selftests/net/Makefile | 1 +
tools/testing/selftests/net/nk_qlease.py | 2109 +++++++++++++++++
4 files changed, 2120 insertions(+), 1142 deletions(-)
create mode 100755 tools/testing/selftests/net/nk_qlease.py
--
2.43.0
^ permalink raw reply
* [PATCH net-next v2 2/3] selftests/net: Split netdevsim tests from HW tests in nk_qlease
From: Daniel Borkmann @ 2026-04-13 22:08 UTC (permalink / raw)
To: netdev; +Cc: kuba, dw, pabeni, razor
In-Reply-To: <20260413220809.604592-1-daniel@iogearbox.net>
As pointed out in 3d2c3d2eea9a ("selftests: net: py: explicitly forbid
multiple ksft_run() calls"), ksft_run() cannot be called multiple times.
Move the netdevsim-based queue lease tests to selftests/net/ so that
each file has exactly one ksft_run() call.
The HW tests (io_uring ZC RX, queue attrs, XDP with MP, destroy) remain
in selftests/drivers/net/hw/.
Fixes: 65d657d80684 ("selftests/net: Add queue leasing tests with netkit")
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Link: https://lore.kernel.org/netdev/20260409181950.7e099b6c@kernel.org
---
.../selftests/drivers/net/hw/nk_qlease.py | 1142 ----------------
tools/testing/selftests/net/Makefile | 1 +
tools/testing/selftests/net/nk_qlease.py | 1168 +++++++++++++++++
3 files changed, 1169 insertions(+), 1142 deletions(-)
create mode 100755 tools/testing/selftests/net/nk_qlease.py
diff --git a/tools/testing/selftests/drivers/net/hw/nk_qlease.py b/tools/testing/selftests/drivers/net/hw/nk_qlease.py
index 2bc5ffe96c7d..aa83dc321328 100755
--- a/tools/testing/selftests/drivers/net/hw/nk_qlease.py
+++ b/tools/testing/selftests/drivers/net/hw/nk_qlease.py
@@ -1,7 +1,6 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0
-import errno
import re
import time
import threading
@@ -10,23 +9,17 @@ from lib.py import (
ksft_run,
ksft_exit,
ksft_eq,
- ksft_ne,
ksft_in,
ksft_not_in,
ksft_raises,
)
from lib.py import (
NetDrvContEnv,
- NetNS,
NetNSEnter,
EthtoolFamily,
NetdevFamily,
- RtnlFamily,
- NetdevSimDev,
)
from lib.py import (
- NlError,
- Netlink,
bkg,
cmd,
defer,
@@ -46,1100 +39,6 @@ def set_flow_rule(cfg):
return int(values)
-def create_netkit(rxqueues):
- all_links = ip("-d link show", json=True)
- old_idxs = {
- link["ifindex"]
- for link in all_links
- if link.get("linkinfo", {}).get("info_kind") == "netkit"
- }
-
- rtnl = RtnlFamily()
- rtnl.newlink(
- {
- "linkinfo": {
- "kind": "netkit",
- "data": {
- "mode": "l2",
- "policy": "forward",
- "peer-policy": "forward",
- },
- },
- "num-rx-queues": rxqueues,
- },
- flags=[Netlink.NLM_F_CREATE, Netlink.NLM_F_EXCL],
- )
-
- all_links = ip("-d link show", json=True)
- nk_links = [
- link
- for link in all_links
- if link.get("linkinfo", {}).get("info_kind") == "netkit"
- and link["ifindex"] not in old_idxs
- ]
- nk_links.sort(key=lambda x: x["ifindex"])
- return (
- nk_links[1]["ifname"],
- nk_links[1]["ifindex"],
- nk_links[0]["ifname"],
- nk_links[0]["ifindex"],
- )
-
-
-def create_netkit_single(rxqueues):
- rtnl = RtnlFamily()
- rtnl.newlink(
- {
- "linkinfo": {
- "kind": "netkit",
- "data": {
- "mode": "l2",
- "pairing": "single",
- },
- },
- "num-rx-queues": rxqueues,
- },
- flags=[Netlink.NLM_F_CREATE, Netlink.NLM_F_EXCL],
- )
-
- all_links = ip("-d link show", json=True)
- nk_links = [
- link
- for link in all_links
- if link.get("linkinfo", {}).get("info_kind") == "netkit"
- and "UP" not in link.get("flags", [])
- ]
- return nk_links[0]["ifname"], nk_links[0]["ifindex"]
-
-
-def test_remove_phys(netns) -> None:
- nsimdev = NetdevSimDev(port_count=1, queue_count=2)
- defer(nsimdev.remove)
- nsim = nsimdev.nsims[0]
- ip(f"link set dev {nsim.ifname} up")
-
- nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
- defer(cmd, f"ip link del dev {nk_host}", fail=False)
-
- ip(f"link set dev {nk_guest} netns {netns.name}")
- ip(f"link set dev {nk_host} up")
- ip(f"link set dev {nk_guest} up", ns=netns)
-
- src_queue = 1
- with NetNSEnter(str(netns)):
- netdevnl = NetdevFamily()
- result = netdevnl.queue_create(
- {
- "ifindex": nk_guest_idx,
- "type": "rx",
- "lease": {
- "ifindex": nsim.ifindex,
- "queue": {"id": src_queue, "type": "rx"},
- "netns-id": 0,
- },
- }
- )
- nk_queue_id = result["id"]
-
- netdevnl = NetdevFamily()
- queue_info = netdevnl.queue_get(
- {"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
- )
- ksft_in("lease", queue_info)
- ksft_eq(queue_info["lease"]["ifindex"], nk_guest_idx)
- ksft_eq(queue_info["lease"]["queue"]["id"], nk_queue_id)
-
- nsimdev.remove()
- time.sleep(0.1)
- ret = cmd(f"ip link show dev {nk_host}", fail=False)
- ksft_ne(ret.ret, 0)
-
-
-def test_double_lease(netns) -> None:
- nsimdev = NetdevSimDev(port_count=1, queue_count=2)
- defer(nsimdev.remove)
- nsim = nsimdev.nsims[0]
- ip(f"link set dev {nsim.ifname} up")
-
- nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=3)
- defer(cmd, f"ip link del dev {nk_host}")
-
- ip(f"link set dev {nk_guest} netns {netns.name}")
- ip(f"link set dev {nk_host} up")
- ip(f"link set dev {nk_guest} up", ns=netns)
-
- src_queue = 1
- with NetNSEnter(str(netns)):
- netdevnl = NetdevFamily()
- result = netdevnl.queue_create(
- {
- "ifindex": nk_guest_idx,
- "type": "rx",
- "lease": {
- "ifindex": nsim.ifindex,
- "queue": {"id": src_queue, "type": "rx"},
- "netns-id": 0,
- },
- }
- )
- ksft_eq(result["id"], 1)
-
- with ksft_raises(NlError) as e:
- netdevnl.queue_create(
- {
- "ifindex": nk_guest_idx,
- "type": "rx",
- "lease": {
- "ifindex": nsim.ifindex,
- "queue": {"id": src_queue, "type": "rx"},
- "netns-id": 0,
- },
- }
- )
- ksft_eq(e.exception.nl_msg.error, -errno.EBUSY)
-
-
-def test_virtual_lessor(netns) -> None:
- nk_host_a, _, nk_guest_a, nk_guest_a_idx = create_netkit(rxqueues=2)
- defer(cmd, f"ip link del dev {nk_host_a}")
- ip(f"link set dev {nk_host_a} up")
- ip(f"link set dev {nk_guest_a} up")
-
- nk_host_b, _, nk_guest_b, nk_guest_b_idx = create_netkit(rxqueues=2)
- defer(cmd, f"ip link del dev {nk_host_b}")
-
- ip(f"link set dev {nk_guest_b} netns {netns.name}")
- ip(f"link set dev {nk_host_b} up")
- ip(f"link set dev {nk_guest_b} up", ns=netns)
-
- with NetNSEnter(str(netns)):
- netdevnl = NetdevFamily()
- with ksft_raises(NlError) as e:
- netdevnl.queue_create(
- {
- "ifindex": nk_guest_b_idx,
- "type": "rx",
- "lease": {
- "ifindex": nk_guest_a_idx,
- "queue": {"id": 0, "type": "rx"},
- "netns-id": 0,
- },
- }
- )
- ksft_eq(e.exception.nl_msg.error, -errno.EINVAL)
-
-
-def test_phys_lessee(_netns) -> None:
- nsimdev_a = NetdevSimDev(port_count=1, queue_count=2)
- defer(nsimdev_a.remove)
- nsim_a = nsimdev_a.nsims[0]
- ip(f"link set dev {nsim_a.ifname} up")
-
- nsimdev_b = NetdevSimDev(port_count=1, queue_count=2)
- defer(nsimdev_b.remove)
- nsim_b = nsimdev_b.nsims[0]
- ip(f"link set dev {nsim_b.ifname} up")
-
- netdevnl = NetdevFamily()
- with ksft_raises(NlError) as e:
- netdevnl.queue_create(
- {
- "ifindex": nsim_a.ifindex,
- "type": "rx",
- "lease": {
- "ifindex": nsim_b.ifindex,
- "queue": {"id": 0, "type": "rx"},
- },
- }
- )
- ksft_eq(e.exception.nl_msg.error, -errno.EINVAL)
-
-
-def test_different_lessors(netns) -> None:
- nsimdev_a = NetdevSimDev(port_count=1, queue_count=2)
- defer(nsimdev_a.remove)
- nsim_a = nsimdev_a.nsims[0]
- ip(f"link set dev {nsim_a.ifname} up")
-
- nsimdev_b = NetdevSimDev(port_count=1, queue_count=2)
- defer(nsimdev_b.remove)
- nsim_b = nsimdev_b.nsims[0]
- ip(f"link set dev {nsim_b.ifname} up")
-
- nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=3)
- defer(cmd, f"ip link del dev {nk_host}", fail=False)
-
- ip(f"link set dev {nk_guest} netns {netns.name}")
- ip(f"link set dev {nk_host} up")
- ip(f"link set dev {nk_guest} up", ns=netns)
-
- with NetNSEnter(str(netns)):
- netdevnl = NetdevFamily()
- netdevnl.queue_create(
- {
- "ifindex": nk_guest_idx,
- "type": "rx",
- "lease": {
- "ifindex": nsim_a.ifindex,
- "queue": {"id": 1, "type": "rx"},
- "netns-id": 0,
- },
- }
- )
-
- with ksft_raises(NlError) as e:
- netdevnl.queue_create(
- {
- "ifindex": nk_guest_idx,
- "type": "rx",
- "lease": {
- "ifindex": nsim_b.ifindex,
- "queue": {"id": 1, "type": "rx"},
- "netns-id": 0,
- },
- }
- )
- ksft_eq(e.exception.nl_msg.error, -errno.EOPNOTSUPP)
-
-
-def test_queue_out_of_range(netns) -> None:
- nsimdev = NetdevSimDev(port_count=1, queue_count=2)
- defer(nsimdev.remove)
- nsim = nsimdev.nsims[0]
- ip(f"link set dev {nsim.ifname} up")
-
- nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
- defer(cmd, f"ip link del dev {nk_host}", fail=False)
-
- ip(f"link set dev {nk_guest} netns {netns.name}")
- ip(f"link set dev {nk_host} up")
- ip(f"link set dev {nk_guest} up", ns=netns)
-
- with NetNSEnter(str(netns)):
- netdevnl = NetdevFamily()
- with ksft_raises(NlError) as e:
- netdevnl.queue_create(
- {
- "ifindex": nk_guest_idx,
- "type": "rx",
- "lease": {
- "ifindex": nsim.ifindex,
- "queue": {"id": 2, "type": "rx"},
- "netns-id": 0,
- },
- }
- )
- ksft_eq(e.exception.nl_msg.error, -errno.ERANGE)
-
-
-def test_resize_leased(netns) -> None:
- nsimdev = NetdevSimDev(port_count=1, queue_count=2)
- defer(nsimdev.remove)
- nsim = nsimdev.nsims[0]
- ip(f"link set dev {nsim.ifname} up")
-
- nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
- defer(cmd, f"ip link del dev {nk_host}", fail=False)
-
- ip(f"link set dev {nk_guest} netns {netns.name}")
- ip(f"link set dev {nk_host} up")
- ip(f"link set dev {nk_guest} up", ns=netns)
-
- with NetNSEnter(str(netns)):
- netdevnl = NetdevFamily()
- netdevnl.queue_create(
- {
- "ifindex": nk_guest_idx,
- "type": "rx",
- "lease": {
- "ifindex": nsim.ifindex,
- "queue": {"id": 1, "type": "rx"},
- "netns-id": 0,
- },
- }
- )
-
- ethnl = EthtoolFamily()
- with ksft_raises(NlError) as e:
- ethnl.channels_set({"header": {"dev-index": nsim.ifindex}, "combined-count": 1})
- ksft_eq(e.exception.nl_msg.error, -errno.EINVAL)
-
-
-def test_self_lease(_netns) -> None:
- nk_host, _, _, nk_guest_idx = create_netkit(rxqueues=2)
- defer(cmd, f"ip link del dev {nk_host}", fail=False)
-
- netdevnl = NetdevFamily()
- with ksft_raises(NlError) as e:
- netdevnl.queue_create(
- {
- "ifindex": nk_guest_idx,
- "type": "rx",
- "lease": {
- "ifindex": nk_guest_idx,
- "queue": {"id": 0, "type": "rx"},
- },
- }
- )
- ksft_eq(e.exception.nl_msg.error, -errno.EINVAL)
-
-
-def test_veth_queue_create(netns) -> None:
- nsimdev = NetdevSimDev(port_count=1, queue_count=2)
- defer(nsimdev.remove)
- nsim = nsimdev.nsims[0]
- ip(f"link set dev {nsim.ifname} up")
-
- ip("link add veth0 type veth peer name veth1")
- defer(cmd, "ip link del dev veth0", fail=False)
-
- all_links = ip("-d link show", json=True)
- veth_peer = [
- link
- for link in all_links
- if link.get("ifname") == "veth1"
- ]
- veth_peer_idx = veth_peer[0]["ifindex"]
-
- ip(f"link set dev veth1 netns {netns.name}")
- ip("link set dev veth0 up")
- ip("link set dev veth1 up", ns=netns)
-
- with NetNSEnter(str(netns)):
- netdevnl = NetdevFamily()
- with ksft_raises(NlError) as e:
- netdevnl.queue_create(
- {
- "ifindex": veth_peer_idx,
- "type": "rx",
- "lease": {
- "ifindex": nsim.ifindex,
- "queue": {"id": 1, "type": "rx"},
- "netns-id": 0,
- },
- }
- )
- ksft_eq(e.exception.nl_msg.error, -errno.EINVAL)
-
-
-def test_create_tx_type(netns) -> None:
- nsimdev = NetdevSimDev(port_count=1, queue_count=2)
- defer(nsimdev.remove)
- nsim = nsimdev.nsims[0]
- ip(f"link set dev {nsim.ifname} up")
-
- nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
- defer(cmd, f"ip link del dev {nk_host}", fail=False)
-
- ip(f"link set dev {nk_guest} netns {netns.name}")
- ip(f"link set dev {nk_host} up")
- ip(f"link set dev {nk_guest} up", ns=netns)
-
- with NetNSEnter(str(netns)):
- netdevnl = NetdevFamily()
- with ksft_raises(NlError) as e:
- netdevnl.queue_create(
- {
- "ifindex": nk_guest_idx,
- "type": "tx",
- "lease": {
- "ifindex": nsim.ifindex,
- "queue": {"id": 1, "type": "rx"},
- "netns-id": 0,
- },
- }
- )
- ksft_eq(e.exception.nl_msg.error, -errno.EINVAL)
-
-
-def test_create_primary(_netns) -> None:
- nsimdev = NetdevSimDev(port_count=1, queue_count=2)
- defer(nsimdev.remove)
- nsim = nsimdev.nsims[0]
- ip(f"link set dev {nsim.ifname} up")
-
- nk_host, nk_host_idx, _, _ = create_netkit(rxqueues=2)
- defer(cmd, f"ip link del dev {nk_host}", fail=False)
-
- ip(f"link set dev {nk_host} up")
-
- netdevnl = NetdevFamily()
- with ksft_raises(NlError) as e:
- netdevnl.queue_create(
- {
- "ifindex": nk_host_idx,
- "type": "rx",
- "lease": {
- "ifindex": nsim.ifindex,
- "queue": {"id": 1, "type": "rx"},
- },
- }
- )
- ksft_eq(e.exception.nl_msg.error, -errno.EOPNOTSUPP)
-
-
-def test_create_limit(netns) -> None:
- nsimdev = NetdevSimDev(port_count=1, queue_count=2)
- defer(nsimdev.remove)
- nsim = nsimdev.nsims[0]
- ip(f"link set dev {nsim.ifname} up")
-
- nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=1)
- defer(cmd, f"ip link del dev {nk_host}", fail=False)
-
- ip(f"link set dev {nk_guest} netns {netns.name}")
- ip(f"link set dev {nk_host} up")
- ip(f"link set dev {nk_guest} up", ns=netns)
-
- with NetNSEnter(str(netns)):
- netdevnl = NetdevFamily()
- with ksft_raises(NlError) as e:
- netdevnl.queue_create(
- {
- "ifindex": nk_guest_idx,
- "type": "rx",
- "lease": {
- "ifindex": nsim.ifindex,
- "queue": {"id": 1, "type": "rx"},
- "netns-id": 0,
- },
- }
- )
- ksft_eq(e.exception.nl_msg.error, -errno.EINVAL)
-
-
-def test_link_flap_phys(netns) -> None:
- nsimdev = NetdevSimDev(port_count=1, queue_count=2)
- defer(nsimdev.remove)
- nsim = nsimdev.nsims[0]
- ip(f"link set dev {nsim.ifname} up")
-
- nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
- defer(cmd, f"ip link del dev {nk_host}")
-
- ip(f"link set dev {nk_guest} netns {netns.name}")
- ip(f"link set dev {nk_host} up")
- ip(f"link set dev {nk_guest} up", ns=netns)
-
- src_queue = 1
- with NetNSEnter(str(netns)):
- netdevnl = NetdevFamily()
- result = netdevnl.queue_create(
- {
- "ifindex": nk_guest_idx,
- "type": "rx",
- "lease": {
- "ifindex": nsim.ifindex,
- "queue": {"id": src_queue, "type": "rx"},
- "netns-id": 0,
- },
- }
- )
- nk_queue_id = result["id"]
-
- netdevnl = NetdevFamily()
- queue_info = netdevnl.queue_get(
- {"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
- )
- ksft_in("lease", queue_info)
- ksft_eq(queue_info["lease"]["queue"]["id"], nk_queue_id)
-
- # Link flap the physical device
- ip(f"link set dev {nsim.ifname} down")
- ip(f"link set dev {nsim.ifname} up")
-
- # Verify lease survives the flap
- queue_info = netdevnl.queue_get(
- {"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
- )
- ksft_in("lease", queue_info)
- ksft_eq(queue_info["lease"]["queue"]["id"], nk_queue_id)
-
-
-def test_queue_get_virtual(netns) -> None:
- nsimdev = NetdevSimDev(port_count=1, queue_count=2)
- defer(nsimdev.remove)
- nsim = nsimdev.nsims[0]
- ip(f"link set dev {nsim.ifname} up")
-
- nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
- defer(cmd, f"ip link del dev {nk_host}")
-
- ip(f"link set dev {nk_guest} netns {netns.name}")
- ip(f"link set dev {nk_host} up")
- ip(f"link set dev {nk_guest} up", ns=netns)
-
- src_queue = 1
- with NetNSEnter(str(netns)):
- netdevnl = NetdevFamily()
- result = netdevnl.queue_create(
- {
- "ifindex": nk_guest_idx,
- "type": "rx",
- "lease": {
- "ifindex": nsim.ifindex,
- "queue": {"id": src_queue, "type": "rx"},
- "netns-id": 0,
- },
- }
- )
- nk_queue_id = result["id"]
-
- # queue-get on virtual device's leased queue should not show lease
- # info (lease info is only shown from the physical device's side)
- queue_info = netdevnl.queue_get(
- {"ifindex": nk_guest_idx, "id": nk_queue_id, "type": "rx"}
- )
- ksft_eq(queue_info["id"], nk_queue_id)
- ksft_eq(queue_info["ifindex"], nk_guest_idx)
- ksft_not_in("lease", queue_info)
-
- # Default queue (not leased) also has no lease info
- queue_info = netdevnl.queue_get(
- {"ifindex": nk_guest_idx, "id": 0, "type": "rx"}
- )
- ksft_not_in("lease", queue_info)
-
-
-def test_remove_virt_first(netns) -> None:
- nsimdev = NetdevSimDev(port_count=1, queue_count=2)
- defer(nsimdev.remove)
- nsim = nsimdev.nsims[0]
- ip(f"link set dev {nsim.ifname} up")
-
- nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
-
- ip(f"link set dev {nk_guest} netns {netns.name}")
- ip(f"link set dev {nk_host} up")
- ip(f"link set dev {nk_guest} up", ns=netns)
-
- src_queue = 1
- with NetNSEnter(str(netns)):
- netdevnl = NetdevFamily()
- result = netdevnl.queue_create(
- {
- "ifindex": nk_guest_idx,
- "type": "rx",
- "lease": {
- "ifindex": nsim.ifindex,
- "queue": {"id": src_queue, "type": "rx"},
- "netns-id": 0,
- },
- }
- )
- ksft_eq(result["id"], 1)
-
- netdevnl = NetdevFamily()
- queue_info = netdevnl.queue_get(
- {"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
- )
- ksft_in("lease", queue_info)
- ksft_eq(queue_info["lease"]["queue"]["id"], result["id"])
-
- # Delete netkit (virtual device removed first, physical stays)
- cmd(f"ip link del dev {nk_host}")
-
- # Verify lease is cleaned up on physical device
- queue_info = netdevnl.queue_get(
- {"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
- )
- ksft_not_in("lease", queue_info)
-
-
-def test_multiple_leases(netns) -> None:
- nsimdev = NetdevSimDev(port_count=1, queue_count=3)
- defer(nsimdev.remove)
- nsim = nsimdev.nsims[0]
- ip(f"link set dev {nsim.ifname} up")
-
- nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=4)
- defer(cmd, f"ip link del dev {nk_host}", fail=False)
-
- ip(f"link set dev {nk_guest} netns {netns.name}")
- ip(f"link set dev {nk_host} up")
- ip(f"link set dev {nk_guest} up", ns=netns)
-
- with NetNSEnter(str(netns)):
- netdevnl = NetdevFamily()
- r1 = netdevnl.queue_create(
- {
- "ifindex": nk_guest_idx,
- "type": "rx",
- "lease": {
- "ifindex": nsim.ifindex,
- "queue": {"id": 1, "type": "rx"},
- "netns-id": 0,
- },
- }
- )
- r2 = netdevnl.queue_create(
- {
- "ifindex": nk_guest_idx,
- "type": "rx",
- "lease": {
- "ifindex": nsim.ifindex,
- "queue": {"id": 2, "type": "rx"},
- "netns-id": 0,
- },
- }
- )
-
- ksft_eq(r1["id"], 1)
- ksft_eq(r2["id"], 2)
-
- # Verify both leases visible on physical device
- netdevnl = NetdevFamily()
- q1 = netdevnl.queue_get(
- {"ifindex": nsim.ifindex, "id": 1, "type": "rx"}
- )
- q2 = netdevnl.queue_get(
- {"ifindex": nsim.ifindex, "id": 2, "type": "rx"}
- )
- ksft_in("lease", q1)
- ksft_in("lease", q2)
- ksft_eq(q1["lease"]["ifindex"], nk_guest_idx)
- ksft_eq(q2["lease"]["ifindex"], nk_guest_idx)
- ksft_eq(q1["lease"]["queue"]["id"], r1["id"])
- ksft_eq(q2["lease"]["queue"]["id"], r2["id"])
-
-
-def test_lease_queue_tx_type(netns) -> None:
- nsimdev = NetdevSimDev(port_count=1, queue_count=2)
- defer(nsimdev.remove)
- nsim = nsimdev.nsims[0]
- ip(f"link set dev {nsim.ifname} up")
-
- nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
- defer(cmd, f"ip link del dev {nk_host}", fail=False)
-
- ip(f"link set dev {nk_guest} netns {netns.name}")
- ip(f"link set dev {nk_host} up")
- ip(f"link set dev {nk_guest} up", ns=netns)
-
- with NetNSEnter(str(netns)):
- netdevnl = NetdevFamily()
- with ksft_raises(NlError) as e:
- netdevnl.queue_create(
- {
- "ifindex": nk_guest_idx,
- "type": "rx",
- "lease": {
- "ifindex": nsim.ifindex,
- "queue": {"id": 1, "type": "tx"},
- "netns-id": 0,
- },
- }
- )
- ksft_eq(e.exception.nl_msg.error, -errno.EINVAL)
-
-
-def test_invalid_netns(netns) -> None:
- nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
- defer(cmd, f"ip link del dev {nk_host}", fail=False)
-
- ip(f"link set dev {nk_guest} netns {netns.name}")
- ip(f"link set dev {nk_host} up")
- ip(f"link set dev {nk_guest} up", ns=netns)
-
- with NetNSEnter(str(netns)):
- netdevnl = NetdevFamily()
- with ksft_raises(NlError) as e:
- netdevnl.queue_create(
- {
- "ifindex": nk_guest_idx,
- "type": "rx",
- "lease": {
- "ifindex": 1,
- "queue": {"id": 0, "type": "rx"},
- "netns-id": 999,
- },
- }
- )
- ksft_eq(e.exception.nl_msg.error, -errno.ENONET)
-
-
-def test_invalid_phys_ifindex(netns) -> None:
- nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
- defer(cmd, f"ip link del dev {nk_host}", fail=False)
-
- ip(f"link set dev {nk_guest} netns {netns.name}")
- ip(f"link set dev {nk_host} up")
- ip(f"link set dev {nk_guest} up", ns=netns)
-
- with NetNSEnter(str(netns)):
- netdevnl = NetdevFamily()
- with ksft_raises(NlError) as e:
- netdevnl.queue_create(
- {
- "ifindex": nk_guest_idx,
- "type": "rx",
- "lease": {
- "ifindex": 99999,
- "queue": {"id": 0, "type": "rx"},
- "netns-id": 0,
- },
- }
- )
- ksft_eq(e.exception.nl_msg.error, -errno.ENODEV)
-
-
-def test_multi_netkit_remove_phys(netns) -> None:
- nsimdev = NetdevSimDev(port_count=1, queue_count=3)
- defer(nsimdev.remove)
- nsim = nsimdev.nsims[0]
- ip(f"link set dev {nsim.ifname} up")
-
- # Create two netkit pairs, each leasing a different physical queue
- nk_host_a, _, nk_guest_a, nk_guest_a_idx = create_netkit(rxqueues=2)
- defer(cmd, f"ip link del dev {nk_host_a}", fail=False)
-
- nk_host_b, _, nk_guest_b, nk_guest_b_idx = create_netkit(rxqueues=2)
- defer(cmd, f"ip link del dev {nk_host_b}", fail=False)
-
- ip(f"link set dev {nk_guest_a} netns {netns.name}")
- ip(f"link set dev {nk_host_a} up")
- ip(f"link set dev {nk_guest_a} up", ns=netns)
-
- ip(f"link set dev {nk_guest_b} netns {netns.name}")
- ip(f"link set dev {nk_host_b} up")
- ip(f"link set dev {nk_guest_b} up", ns=netns)
-
- with NetNSEnter(str(netns)):
- netdevnl = NetdevFamily()
- netdevnl.queue_create(
- {
- "ifindex": nk_guest_a_idx,
- "type": "rx",
- "lease": {
- "ifindex": nsim.ifindex,
- "queue": {"id": 1, "type": "rx"},
- "netns-id": 0,
- },
- }
- )
- netdevnl.queue_create(
- {
- "ifindex": nk_guest_b_idx,
- "type": "rx",
- "lease": {
- "ifindex": nsim.ifindex,
- "queue": {"id": 2, "type": "rx"},
- "netns-id": 0,
- },
- }
- )
-
- # Removing the physical device should take down both netkit pairs
- nsimdev.remove()
- time.sleep(0.1)
- ret = cmd(f"ip link show dev {nk_host_a}", fail=False)
- ksft_ne(ret.ret, 0)
- ret = cmd(f"ip link show dev {nk_host_b}", fail=False)
- ksft_ne(ret.ret, 0)
-
-
-def test_single_remove_phys(_netns) -> None:
- nsimdev = NetdevSimDev(port_count=1, queue_count=2)
- defer(nsimdev.remove)
- nsim = nsimdev.nsims[0]
- ip(f"link set dev {nsim.ifname} up")
-
- nk_name, nk_idx = create_netkit_single(rxqueues=2)
- defer(cmd, f"ip link del dev {nk_name}", fail=False)
-
- ip(f"link set dev {nk_name} up")
-
- netdevnl = NetdevFamily()
- netdevnl.queue_create(
- {
- "ifindex": nk_idx,
- "type": "rx",
- "lease": {
- "ifindex": nsim.ifindex,
- "queue": {"id": 1, "type": "rx"},
- },
- }
- )
-
- # Removing the physical device should take down the single netkit device
- nsimdev.remove()
- time.sleep(0.1)
- ret = cmd(f"ip link show dev {nk_name}", fail=False)
- ksft_ne(ret.ret, 0)
-
-
-def test_link_flap_virt(netns) -> None:
- nsimdev = NetdevSimDev(port_count=1, queue_count=2)
- defer(nsimdev.remove)
- nsim = nsimdev.nsims[0]
- ip(f"link set dev {nsim.ifname} up")
-
- nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
- defer(cmd, f"ip link del dev {nk_host}")
-
- ip(f"link set dev {nk_guest} netns {netns.name}")
- ip(f"link set dev {nk_host} up")
- ip(f"link set dev {nk_guest} up", ns=netns)
-
- src_queue = 1
- with NetNSEnter(str(netns)):
- netdevnl = NetdevFamily()
- result = netdevnl.queue_create(
- {
- "ifindex": nk_guest_idx,
- "type": "rx",
- "lease": {
- "ifindex": nsim.ifindex,
- "queue": {"id": src_queue, "type": "rx"},
- "netns-id": 0,
- },
- }
- )
- nk_queue_id = result["id"]
-
- netdevnl = NetdevFamily()
- queue_info = netdevnl.queue_get(
- {"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
- )
- ksft_in("lease", queue_info)
- ksft_eq(queue_info["lease"]["queue"]["id"], nk_queue_id)
-
- # Link flap the virtual (netkit) device
- ip(f"link set dev {nk_guest} down", ns=netns)
- ip(f"link set dev {nk_guest} up", ns=netns)
-
- # Verify lease survives the virtual device flap
- queue_info = netdevnl.queue_get(
- {"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
- )
- ksft_in("lease", queue_info)
- ksft_eq(queue_info["lease"]["queue"]["id"], nk_queue_id)
-
-
-def test_phys_queue_no_lease(netns) -> None:
- nsimdev = NetdevSimDev(port_count=1, queue_count=2)
- defer(nsimdev.remove)
- nsim = nsimdev.nsims[0]
- ip(f"link set dev {nsim.ifname} up")
-
- nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
- defer(cmd, f"ip link del dev {nk_host}")
-
- ip(f"link set dev {nk_guest} netns {netns.name}")
- ip(f"link set dev {nk_host} up")
- ip(f"link set dev {nk_guest} up", ns=netns)
-
- with NetNSEnter(str(netns)):
- netdevnl = NetdevFamily()
- netdevnl.queue_create(
- {
- "ifindex": nk_guest_idx,
- "type": "rx",
- "lease": {
- "ifindex": nsim.ifindex,
- "queue": {"id": 1, "type": "rx"},
- "netns-id": 0,
- },
- }
- )
-
- # Physical queue 0 (not leased) should have no lease info
- netdevnl = NetdevFamily()
- queue_info = netdevnl.queue_get(
- {"ifindex": nsim.ifindex, "id": 0, "type": "rx"}
- )
- ksft_not_in("lease", queue_info)
-
- # Physical queue 1 (leased) should have lease info
- queue_info = netdevnl.queue_get(
- {"ifindex": nsim.ifindex, "id": 1, "type": "rx"}
- )
- ksft_in("lease", queue_info)
-
-
-def test_same_ns_lease(_netns) -> None:
- nsimdev = NetdevSimDev(port_count=1, queue_count=2)
- defer(nsimdev.remove)
- nsim = nsimdev.nsims[0]
- ip(f"link set dev {nsim.ifname} up")
-
- nk_name, nk_idx = create_netkit_single(rxqueues=2)
- defer(cmd, f"ip link del dev {nk_name}", fail=False)
-
- ip(f"link set dev {nk_name} up")
-
- netdevnl = NetdevFamily()
- result = netdevnl.queue_create(
- {
- "ifindex": nk_idx,
- "type": "rx",
- "lease": {
- "ifindex": nsim.ifindex,
- "queue": {"id": 1, "type": "rx"},
- },
- }
- )
- ksft_eq(result["id"], 1)
-
- # Same namespace: lease info should NOT have netns-id
- queue_info = netdevnl.queue_get(
- {"ifindex": nsim.ifindex, "id": 1, "type": "rx"}
- )
- ksft_in("lease", queue_info)
- ksft_eq(queue_info["lease"]["ifindex"], nk_idx)
- ksft_eq(queue_info["lease"]["queue"]["id"], result["id"])
- ksft_not_in("netns-id", queue_info["lease"])
-
-
-def test_resize_after_unlease(netns) -> None:
- nsimdev = NetdevSimDev(port_count=1, queue_count=2)
- defer(nsimdev.remove)
- nsim = nsimdev.nsims[0]
- ip(f"link set dev {nsim.ifname} up")
-
- nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
-
- ip(f"link set dev {nk_guest} netns {netns.name}")
- ip(f"link set dev {nk_host} up")
- ip(f"link set dev {nk_guest} up", ns=netns)
-
- with NetNSEnter(str(netns)):
- netdevnl = NetdevFamily()
- netdevnl.queue_create(
- {
- "ifindex": nk_guest_idx,
- "type": "rx",
- "lease": {
- "ifindex": nsim.ifindex,
- "queue": {"id": 1, "type": "rx"},
- "netns-id": 0,
- },
- }
- )
-
- # Resize should fail while lease is active
- ethnl = EthtoolFamily()
- with ksft_raises(NlError) as e:
- ethnl.channels_set({"header": {"dev-index": nsim.ifindex}, "combined-count": 1})
- ksft_eq(e.exception.nl_msg.error, -errno.EINVAL)
-
- # Delete netkit, clearing the lease
- cmd(f"ip link del dev {nk_host}")
-
- # Resize should now succeed
- ethnl.channels_set({"header": {"dev-index": nsim.ifindex}, "combined-count": 1})
-
-
-def test_lease_queue_zero(netns) -> None:
- nsimdev = NetdevSimDev(port_count=1, queue_count=2)
- defer(nsimdev.remove)
- nsim = nsimdev.nsims[0]
- ip(f"link set dev {nsim.ifname} up")
-
- nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
- defer(cmd, f"ip link del dev {nk_host}", fail=False)
-
- ip(f"link set dev {nk_guest} netns {netns.name}")
- ip(f"link set dev {nk_host} up")
- ip(f"link set dev {nk_guest} up", ns=netns)
-
- with NetNSEnter(str(netns)):
- netdevnl = NetdevFamily()
- result = netdevnl.queue_create(
- {
- "ifindex": nk_guest_idx,
- "type": "rx",
- "lease": {
- "ifindex": nsim.ifindex,
- "queue": {"id": 0, "type": "rx"},
- "netns-id": 0,
- },
- }
- )
- ksft_eq(result["id"], 1)
-
- netdevnl = NetdevFamily()
- queue_info = netdevnl.queue_get(
- {"ifindex": nsim.ifindex, "id": 0, "type": "rx"}
- )
- ksft_in("lease", queue_info)
- ksft_eq(queue_info["lease"]["queue"]["id"], result["id"])
-
-
-def test_release_and_reuse(netns) -> None:
- nsimdev = NetdevSimDev(port_count=1, queue_count=2)
- defer(nsimdev.remove)
- nsim = nsimdev.nsims[0]
- ip(f"link set dev {nsim.ifname} up")
-
- src_queue = 1
-
- # First lease
- nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
-
- ip(f"link set dev {nk_guest} netns {netns.name}")
- ip(f"link set dev {nk_host} up")
- ip(f"link set dev {nk_guest} up", ns=netns)
-
- with NetNSEnter(str(netns)):
- netdevnl = NetdevFamily()
- netdevnl.queue_create(
- {
- "ifindex": nk_guest_idx,
- "type": "rx",
- "lease": {
- "ifindex": nsim.ifindex,
- "queue": {"id": src_queue, "type": "rx"},
- "netns-id": 0,
- },
- }
- )
-
- netdevnl = NetdevFamily()
- queue_info = netdevnl.queue_get(
- {"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
- )
- ksft_in("lease", queue_info)
-
- # Delete netkit, freeing the lease
- cmd(f"ip link del dev {nk_host}")
-
- queue_info = netdevnl.queue_get(
- {"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
- )
- ksft_not_in("lease", queue_info)
-
- # Re-create netkit and lease the same physical queue again
- nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
- defer(cmd, f"ip link del dev {nk_host}", fail=False)
-
- ip(f"link set dev {nk_guest} netns {netns.name}")
- ip(f"link set dev {nk_host} up")
- ip(f"link set dev {nk_guest} up", ns=netns)
-
- with NetNSEnter(str(netns)):
- netdevnl = NetdevFamily()
- result = netdevnl.queue_create(
- {
- "ifindex": nk_guest_idx,
- "type": "rx",
- "lease": {
- "ifindex": nsim.ifindex,
- "queue": {"id": src_queue, "type": "rx"},
- "netns-id": 0,
- },
- }
- )
- ksft_eq(result["id"], 1)
-
- netdevnl = NetdevFamily()
- queue_info = netdevnl.queue_get(
- {"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
- )
- ksft_in("lease", queue_info)
- ksft_eq(queue_info["lease"]["queue"]["id"], result["id"])
-
-
def test_iou_zcrx(cfg) -> None:
cfg.require_ipver("6")
ethnl = EthtoolFamily()
@@ -1324,47 +223,6 @@ def test_destroy(cfg) -> None:
def main() -> None:
- netns = NetNS()
- cmd("ip netns attach init 1")
- ip("netns set init 0", ns=netns)
- ip("link set lo up", ns=netns)
-
- ksft_run(
- [
- test_remove_phys,
- test_double_lease,
- test_virtual_lessor,
- test_phys_lessee,
- test_different_lessors,
- test_queue_out_of_range,
- test_resize_leased,
- test_self_lease,
- test_create_tx_type,
- test_create_primary,
- test_create_limit,
- test_link_flap_phys,
- test_queue_get_virtual,
- test_remove_virt_first,
- test_multiple_leases,
- test_lease_queue_tx_type,
- test_invalid_netns,
- test_invalid_phys_ifindex,
- test_multi_netkit_remove_phys,
- test_single_remove_phys,
- test_link_flap_virt,
- test_phys_queue_no_lease,
- test_same_ns_lease,
- test_resize_after_unlease,
- test_lease_queue_zero,
- test_release_and_reuse,
- test_veth_queue_create,
- ],
- args=(netns,),
- )
-
- cmd("ip netns del init", fail=False)
- del netns
-
with NetDrvContEnv(__file__, rxqueues=2) as cfg:
cfg.bin_local = path.abspath(
path.dirname(__file__) + "/../../../drivers/net/hw/iou-zcrx"
diff --git a/tools/testing/selftests/net/Makefile b/tools/testing/selftests/net/Makefile
index 231245a95879..a275ed584026 100644
--- a/tools/testing/selftests/net/Makefile
+++ b/tools/testing/selftests/net/Makefile
@@ -65,6 +65,7 @@ TEST_PROGS := \
netdevice.sh \
netns-name.sh \
netns-sysctl.sh \
+ nk_qlease.py \
nl_netdev.py \
nl_nlctrl.py \
pmtu.sh \
diff --git a/tools/testing/selftests/net/nk_qlease.py b/tools/testing/selftests/net/nk_qlease.py
new file mode 100755
index 000000000000..6ed4fb5e90f6
--- /dev/null
+++ b/tools/testing/selftests/net/nk_qlease.py
@@ -0,0 +1,1168 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0
+
+import errno
+import time
+from lib.py import (
+ ksft_run,
+ ksft_exit,
+ ksft_eq,
+ ksft_ne,
+ ksft_in,
+ ksft_not_in,
+ ksft_raises,
+)
+from lib.py import (
+ NetNS,
+ NetNSEnter,
+ EthtoolFamily,
+ NetdevFamily,
+ RtnlFamily,
+ NetdevSimDev,
+)
+from lib.py import (
+ NlError,
+ Netlink,
+ cmd,
+ defer,
+ ip,
+)
+
+def create_netkit(rxqueues):
+ all_links = ip("-d link show", json=True)
+ old_idxs = {
+ link["ifindex"]
+ for link in all_links
+ if link.get("linkinfo", {}).get("info_kind") == "netkit"
+ }
+
+ rtnl = RtnlFamily()
+ rtnl.newlink(
+ {
+ "linkinfo": {
+ "kind": "netkit",
+ "data": {
+ "mode": "l2",
+ "policy": "forward",
+ "peer-policy": "forward",
+ },
+ },
+ "num-rx-queues": rxqueues,
+ },
+ flags=[Netlink.NLM_F_CREATE, Netlink.NLM_F_EXCL],
+ )
+
+ all_links = ip("-d link show", json=True)
+ nk_links = [
+ link
+ for link in all_links
+ if link.get("linkinfo", {}).get("info_kind") == "netkit"
+ and link["ifindex"] not in old_idxs
+ ]
+ nk_links.sort(key=lambda x: x["ifindex"])
+ return (
+ nk_links[1]["ifname"],
+ nk_links[1]["ifindex"],
+ nk_links[0]["ifname"],
+ nk_links[0]["ifindex"],
+ )
+
+
+def create_netkit_single(rxqueues):
+ rtnl = RtnlFamily()
+ rtnl.newlink(
+ {
+ "linkinfo": {
+ "kind": "netkit",
+ "data": {
+ "mode": "l2",
+ "pairing": "single",
+ },
+ },
+ "num-rx-queues": rxqueues,
+ },
+ flags=[Netlink.NLM_F_CREATE, Netlink.NLM_F_EXCL],
+ )
+
+ all_links = ip("-d link show", json=True)
+ nk_links = [
+ link
+ for link in all_links
+ if link.get("linkinfo", {}).get("info_kind") == "netkit"
+ and "UP" not in link.get("flags", [])
+ ]
+ return nk_links[0]["ifname"], nk_links[0]["ifindex"]
+
+def test_remove_phys(netns) -> None:
+ nsimdev = NetdevSimDev(port_count=1, queue_count=2)
+ defer(nsimdev.remove)
+ nsim = nsimdev.nsims[0]
+ ip(f"link set dev {nsim.ifname} up")
+
+ nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
+ defer(cmd, f"ip link del dev {nk_host}", fail=False)
+
+ ip(f"link set dev {nk_guest} netns {netns.name}")
+ ip(f"link set dev {nk_host} up")
+ ip(f"link set dev {nk_guest} up", ns=netns)
+
+ src_queue = 1
+ with NetNSEnter(str(netns)):
+ netdevnl = NetdevFamily()
+ result = netdevnl.queue_create(
+ {
+ "ifindex": nk_guest_idx,
+ "type": "rx",
+ "lease": {
+ "ifindex": nsim.ifindex,
+ "queue": {"id": src_queue, "type": "rx"},
+ "netns-id": 0,
+ },
+ }
+ )
+ nk_queue_id = result["id"]
+
+ netdevnl = NetdevFamily()
+ queue_info = netdevnl.queue_get(
+ {"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
+ )
+ ksft_in("lease", queue_info)
+ ksft_eq(queue_info["lease"]["ifindex"], nk_guest_idx)
+ ksft_eq(queue_info["lease"]["queue"]["id"], nk_queue_id)
+
+ nsimdev.remove()
+ time.sleep(0.1)
+ ret = cmd(f"ip link show dev {nk_host}", fail=False)
+ ksft_ne(ret.ret, 0)
+
+
+def test_double_lease(netns) -> None:
+ nsimdev = NetdevSimDev(port_count=1, queue_count=2)
+ defer(nsimdev.remove)
+ nsim = nsimdev.nsims[0]
+ ip(f"link set dev {nsim.ifname} up")
+
+ nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=3)
+ defer(cmd, f"ip link del dev {nk_host}")
+
+ ip(f"link set dev {nk_guest} netns {netns.name}")
+ ip(f"link set dev {nk_host} up")
+ ip(f"link set dev {nk_guest} up", ns=netns)
+
+ src_queue = 1
+ with NetNSEnter(str(netns)):
+ netdevnl = NetdevFamily()
+ result = netdevnl.queue_create(
+ {
+ "ifindex": nk_guest_idx,
+ "type": "rx",
+ "lease": {
+ "ifindex": nsim.ifindex,
+ "queue": {"id": src_queue, "type": "rx"},
+ "netns-id": 0,
+ },
+ }
+ )
+ ksft_eq(result["id"], 1)
+
+ with ksft_raises(NlError) as e:
+ netdevnl.queue_create(
+ {
+ "ifindex": nk_guest_idx,
+ "type": "rx",
+ "lease": {
+ "ifindex": nsim.ifindex,
+ "queue": {"id": src_queue, "type": "rx"},
+ "netns-id": 0,
+ },
+ }
+ )
+ ksft_eq(e.exception.nl_msg.error, -errno.EBUSY)
+
+
+def test_virtual_lessor(netns) -> None:
+ nk_host_a, _, nk_guest_a, nk_guest_a_idx = create_netkit(rxqueues=2)
+ defer(cmd, f"ip link del dev {nk_host_a}")
+ ip(f"link set dev {nk_host_a} up")
+ ip(f"link set dev {nk_guest_a} up")
+
+ nk_host_b, _, nk_guest_b, nk_guest_b_idx = create_netkit(rxqueues=2)
+ defer(cmd, f"ip link del dev {nk_host_b}")
+
+ ip(f"link set dev {nk_guest_b} netns {netns.name}")
+ ip(f"link set dev {nk_host_b} up")
+ ip(f"link set dev {nk_guest_b} up", ns=netns)
+
+ with NetNSEnter(str(netns)):
+ netdevnl = NetdevFamily()
+ with ksft_raises(NlError) as e:
+ netdevnl.queue_create(
+ {
+ "ifindex": nk_guest_b_idx,
+ "type": "rx",
+ "lease": {
+ "ifindex": nk_guest_a_idx,
+ "queue": {"id": 0, "type": "rx"},
+ "netns-id": 0,
+ },
+ }
+ )
+ ksft_eq(e.exception.nl_msg.error, -errno.EINVAL)
+
+
+def test_phys_lessee(_netns) -> None:
+ nsimdev_a = NetdevSimDev(port_count=1, queue_count=2)
+ defer(nsimdev_a.remove)
+ nsim_a = nsimdev_a.nsims[0]
+ ip(f"link set dev {nsim_a.ifname} up")
+
+ nsimdev_b = NetdevSimDev(port_count=1, queue_count=2)
+ defer(nsimdev_b.remove)
+ nsim_b = nsimdev_b.nsims[0]
+ ip(f"link set dev {nsim_b.ifname} up")
+
+ netdevnl = NetdevFamily()
+ with ksft_raises(NlError) as e:
+ netdevnl.queue_create(
+ {
+ "ifindex": nsim_a.ifindex,
+ "type": "rx",
+ "lease": {
+ "ifindex": nsim_b.ifindex,
+ "queue": {"id": 0, "type": "rx"},
+ },
+ }
+ )
+ ksft_eq(e.exception.nl_msg.error, -errno.EINVAL)
+
+
+def test_different_lessors(netns) -> None:
+ nsimdev_a = NetdevSimDev(port_count=1, queue_count=2)
+ defer(nsimdev_a.remove)
+ nsim_a = nsimdev_a.nsims[0]
+ ip(f"link set dev {nsim_a.ifname} up")
+
+ nsimdev_b = NetdevSimDev(port_count=1, queue_count=2)
+ defer(nsimdev_b.remove)
+ nsim_b = nsimdev_b.nsims[0]
+ ip(f"link set dev {nsim_b.ifname} up")
+
+ nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=3)
+ defer(cmd, f"ip link del dev {nk_host}", fail=False)
+
+ ip(f"link set dev {nk_guest} netns {netns.name}")
+ ip(f"link set dev {nk_host} up")
+ ip(f"link set dev {nk_guest} up", ns=netns)
+
+ with NetNSEnter(str(netns)):
+ netdevnl = NetdevFamily()
+ netdevnl.queue_create(
+ {
+ "ifindex": nk_guest_idx,
+ "type": "rx",
+ "lease": {
+ "ifindex": nsim_a.ifindex,
+ "queue": {"id": 1, "type": "rx"},
+ "netns-id": 0,
+ },
+ }
+ )
+
+ with ksft_raises(NlError) as e:
+ netdevnl.queue_create(
+ {
+ "ifindex": nk_guest_idx,
+ "type": "rx",
+ "lease": {
+ "ifindex": nsim_b.ifindex,
+ "queue": {"id": 1, "type": "rx"},
+ "netns-id": 0,
+ },
+ }
+ )
+ ksft_eq(e.exception.nl_msg.error, -errno.EOPNOTSUPP)
+
+
+def test_queue_out_of_range(netns) -> None:
+ nsimdev = NetdevSimDev(port_count=1, queue_count=2)
+ defer(nsimdev.remove)
+ nsim = nsimdev.nsims[0]
+ ip(f"link set dev {nsim.ifname} up")
+
+ nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
+ defer(cmd, f"ip link del dev {nk_host}", fail=False)
+
+ ip(f"link set dev {nk_guest} netns {netns.name}")
+ ip(f"link set dev {nk_host} up")
+ ip(f"link set dev {nk_guest} up", ns=netns)
+
+ with NetNSEnter(str(netns)):
+ netdevnl = NetdevFamily()
+ with ksft_raises(NlError) as e:
+ netdevnl.queue_create(
+ {
+ "ifindex": nk_guest_idx,
+ "type": "rx",
+ "lease": {
+ "ifindex": nsim.ifindex,
+ "queue": {"id": 2, "type": "rx"},
+ "netns-id": 0,
+ },
+ }
+ )
+ ksft_eq(e.exception.nl_msg.error, -errno.ERANGE)
+
+
+def test_resize_leased(netns) -> None:
+ nsimdev = NetdevSimDev(port_count=1, queue_count=2)
+ defer(nsimdev.remove)
+ nsim = nsimdev.nsims[0]
+ ip(f"link set dev {nsim.ifname} up")
+
+ nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
+ defer(cmd, f"ip link del dev {nk_host}", fail=False)
+
+ ip(f"link set dev {nk_guest} netns {netns.name}")
+ ip(f"link set dev {nk_host} up")
+ ip(f"link set dev {nk_guest} up", ns=netns)
+
+ with NetNSEnter(str(netns)):
+ netdevnl = NetdevFamily()
+ netdevnl.queue_create(
+ {
+ "ifindex": nk_guest_idx,
+ "type": "rx",
+ "lease": {
+ "ifindex": nsim.ifindex,
+ "queue": {"id": 1, "type": "rx"},
+ "netns-id": 0,
+ },
+ }
+ )
+
+ ethnl = EthtoolFamily()
+ with ksft_raises(NlError) as e:
+ ethnl.channels_set({"header": {"dev-index": nsim.ifindex}, "combined-count": 1})
+ ksft_eq(e.exception.nl_msg.error, -errno.EINVAL)
+
+
+def test_self_lease(_netns) -> None:
+ nk_host, _, _, nk_guest_idx = create_netkit(rxqueues=2)
+ defer(cmd, f"ip link del dev {nk_host}", fail=False)
+
+ netdevnl = NetdevFamily()
+ with ksft_raises(NlError) as e:
+ netdevnl.queue_create(
+ {
+ "ifindex": nk_guest_idx,
+ "type": "rx",
+ "lease": {
+ "ifindex": nk_guest_idx,
+ "queue": {"id": 0, "type": "rx"},
+ },
+ }
+ )
+ ksft_eq(e.exception.nl_msg.error, -errno.EINVAL)
+
+
+def test_veth_queue_create(netns) -> None:
+ nsimdev = NetdevSimDev(port_count=1, queue_count=2)
+ defer(nsimdev.remove)
+ nsim = nsimdev.nsims[0]
+ ip(f"link set dev {nsim.ifname} up")
+
+ ip("link add veth0 type veth peer name veth1")
+ defer(cmd, "ip link del dev veth0", fail=False)
+
+ all_links = ip("-d link show", json=True)
+ veth_peer = [
+ link
+ for link in all_links
+ if link.get("ifname") == "veth1"
+ ]
+ veth_peer_idx = veth_peer[0]["ifindex"]
+
+ ip(f"link set dev veth1 netns {netns.name}")
+ ip("link set dev veth0 up")
+ ip("link set dev veth1 up", ns=netns)
+
+ with NetNSEnter(str(netns)):
+ netdevnl = NetdevFamily()
+ with ksft_raises(NlError) as e:
+ netdevnl.queue_create(
+ {
+ "ifindex": veth_peer_idx,
+ "type": "rx",
+ "lease": {
+ "ifindex": nsim.ifindex,
+ "queue": {"id": 1, "type": "rx"},
+ "netns-id": 0,
+ },
+ }
+ )
+ ksft_eq(e.exception.nl_msg.error, -errno.EINVAL)
+
+
+def test_create_tx_type(netns) -> None:
+ nsimdev = NetdevSimDev(port_count=1, queue_count=2)
+ defer(nsimdev.remove)
+ nsim = nsimdev.nsims[0]
+ ip(f"link set dev {nsim.ifname} up")
+
+ nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
+ defer(cmd, f"ip link del dev {nk_host}", fail=False)
+
+ ip(f"link set dev {nk_guest} netns {netns.name}")
+ ip(f"link set dev {nk_host} up")
+ ip(f"link set dev {nk_guest} up", ns=netns)
+
+ with NetNSEnter(str(netns)):
+ netdevnl = NetdevFamily()
+ with ksft_raises(NlError) as e:
+ netdevnl.queue_create(
+ {
+ "ifindex": nk_guest_idx,
+ "type": "tx",
+ "lease": {
+ "ifindex": nsim.ifindex,
+ "queue": {"id": 1, "type": "rx"},
+ "netns-id": 0,
+ },
+ }
+ )
+ ksft_eq(e.exception.nl_msg.error, -errno.EINVAL)
+
+
+def test_create_primary(_netns) -> None:
+ nsimdev = NetdevSimDev(port_count=1, queue_count=2)
+ defer(nsimdev.remove)
+ nsim = nsimdev.nsims[0]
+ ip(f"link set dev {nsim.ifname} up")
+
+ nk_host, nk_host_idx, _, _ = create_netkit(rxqueues=2)
+ defer(cmd, f"ip link del dev {nk_host}", fail=False)
+
+ ip(f"link set dev {nk_host} up")
+
+ netdevnl = NetdevFamily()
+ with ksft_raises(NlError) as e:
+ netdevnl.queue_create(
+ {
+ "ifindex": nk_host_idx,
+ "type": "rx",
+ "lease": {
+ "ifindex": nsim.ifindex,
+ "queue": {"id": 1, "type": "rx"},
+ },
+ }
+ )
+ ksft_eq(e.exception.nl_msg.error, -errno.EOPNOTSUPP)
+
+
+def test_create_limit(netns) -> None:
+ nsimdev = NetdevSimDev(port_count=1, queue_count=2)
+ defer(nsimdev.remove)
+ nsim = nsimdev.nsims[0]
+ ip(f"link set dev {nsim.ifname} up")
+
+ nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=1)
+ defer(cmd, f"ip link del dev {nk_host}", fail=False)
+
+ ip(f"link set dev {nk_guest} netns {netns.name}")
+ ip(f"link set dev {nk_host} up")
+ ip(f"link set dev {nk_guest} up", ns=netns)
+
+ with NetNSEnter(str(netns)):
+ netdevnl = NetdevFamily()
+ with ksft_raises(NlError) as e:
+ netdevnl.queue_create(
+ {
+ "ifindex": nk_guest_idx,
+ "type": "rx",
+ "lease": {
+ "ifindex": nsim.ifindex,
+ "queue": {"id": 1, "type": "rx"},
+ "netns-id": 0,
+ },
+ }
+ )
+ ksft_eq(e.exception.nl_msg.error, -errno.EINVAL)
+
+
+def test_link_flap_phys(netns) -> None:
+ nsimdev = NetdevSimDev(port_count=1, queue_count=2)
+ defer(nsimdev.remove)
+ nsim = nsimdev.nsims[0]
+ ip(f"link set dev {nsim.ifname} up")
+
+ nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
+ defer(cmd, f"ip link del dev {nk_host}")
+
+ ip(f"link set dev {nk_guest} netns {netns.name}")
+ ip(f"link set dev {nk_host} up")
+ ip(f"link set dev {nk_guest} up", ns=netns)
+
+ src_queue = 1
+ with NetNSEnter(str(netns)):
+ netdevnl = NetdevFamily()
+ result = netdevnl.queue_create(
+ {
+ "ifindex": nk_guest_idx,
+ "type": "rx",
+ "lease": {
+ "ifindex": nsim.ifindex,
+ "queue": {"id": src_queue, "type": "rx"},
+ "netns-id": 0,
+ },
+ }
+ )
+ nk_queue_id = result["id"]
+
+ netdevnl = NetdevFamily()
+ queue_info = netdevnl.queue_get(
+ {"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
+ )
+ ksft_in("lease", queue_info)
+ ksft_eq(queue_info["lease"]["queue"]["id"], nk_queue_id)
+
+ # Link flap the physical device
+ ip(f"link set dev {nsim.ifname} down")
+ ip(f"link set dev {nsim.ifname} up")
+
+ # Verify lease survives the flap
+ queue_info = netdevnl.queue_get(
+ {"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
+ )
+ ksft_in("lease", queue_info)
+ ksft_eq(queue_info["lease"]["queue"]["id"], nk_queue_id)
+
+
+def test_queue_get_virtual(netns) -> None:
+ nsimdev = NetdevSimDev(port_count=1, queue_count=2)
+ defer(nsimdev.remove)
+ nsim = nsimdev.nsims[0]
+ ip(f"link set dev {nsim.ifname} up")
+
+ nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
+ defer(cmd, f"ip link del dev {nk_host}")
+
+ ip(f"link set dev {nk_guest} netns {netns.name}")
+ ip(f"link set dev {nk_host} up")
+ ip(f"link set dev {nk_guest} up", ns=netns)
+
+ src_queue = 1
+ with NetNSEnter(str(netns)):
+ netdevnl = NetdevFamily()
+ result = netdevnl.queue_create(
+ {
+ "ifindex": nk_guest_idx,
+ "type": "rx",
+ "lease": {
+ "ifindex": nsim.ifindex,
+ "queue": {"id": src_queue, "type": "rx"},
+ "netns-id": 0,
+ },
+ }
+ )
+ nk_queue_id = result["id"]
+
+ # queue-get on virtual device's leased queue should not show lease
+ # info (lease info is only shown from the physical device's side)
+ queue_info = netdevnl.queue_get(
+ {"ifindex": nk_guest_idx, "id": nk_queue_id, "type": "rx"}
+ )
+ ksft_eq(queue_info["id"], nk_queue_id)
+ ksft_eq(queue_info["ifindex"], nk_guest_idx)
+ ksft_not_in("lease", queue_info)
+
+ # Default queue (not leased) also has no lease info
+ queue_info = netdevnl.queue_get(
+ {"ifindex": nk_guest_idx, "id": 0, "type": "rx"}
+ )
+ ksft_not_in("lease", queue_info)
+
+
+def test_remove_virt_first(netns) -> None:
+ nsimdev = NetdevSimDev(port_count=1, queue_count=2)
+ defer(nsimdev.remove)
+ nsim = nsimdev.nsims[0]
+ ip(f"link set dev {nsim.ifname} up")
+
+ nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
+
+ ip(f"link set dev {nk_guest} netns {netns.name}")
+ ip(f"link set dev {nk_host} up")
+ ip(f"link set dev {nk_guest} up", ns=netns)
+
+ src_queue = 1
+ with NetNSEnter(str(netns)):
+ netdevnl = NetdevFamily()
+ result = netdevnl.queue_create(
+ {
+ "ifindex": nk_guest_idx,
+ "type": "rx",
+ "lease": {
+ "ifindex": nsim.ifindex,
+ "queue": {"id": src_queue, "type": "rx"},
+ "netns-id": 0,
+ },
+ }
+ )
+ ksft_eq(result["id"], 1)
+
+ netdevnl = NetdevFamily()
+ queue_info = netdevnl.queue_get(
+ {"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
+ )
+ ksft_in("lease", queue_info)
+ ksft_eq(queue_info["lease"]["queue"]["id"], result["id"])
+
+ # Delete netkit (virtual device removed first, physical stays)
+ cmd(f"ip link del dev {nk_host}")
+
+ # Verify lease is cleaned up on physical device
+ queue_info = netdevnl.queue_get(
+ {"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
+ )
+ ksft_not_in("lease", queue_info)
+
+
+def test_multiple_leases(netns) -> None:
+ nsimdev = NetdevSimDev(port_count=1, queue_count=3)
+ defer(nsimdev.remove)
+ nsim = nsimdev.nsims[0]
+ ip(f"link set dev {nsim.ifname} up")
+
+ nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=4)
+ defer(cmd, f"ip link del dev {nk_host}", fail=False)
+
+ ip(f"link set dev {nk_guest} netns {netns.name}")
+ ip(f"link set dev {nk_host} up")
+ ip(f"link set dev {nk_guest} up", ns=netns)
+
+ with NetNSEnter(str(netns)):
+ netdevnl = NetdevFamily()
+ r1 = netdevnl.queue_create(
+ {
+ "ifindex": nk_guest_idx,
+ "type": "rx",
+ "lease": {
+ "ifindex": nsim.ifindex,
+ "queue": {"id": 1, "type": "rx"},
+ "netns-id": 0,
+ },
+ }
+ )
+ r2 = netdevnl.queue_create(
+ {
+ "ifindex": nk_guest_idx,
+ "type": "rx",
+ "lease": {
+ "ifindex": nsim.ifindex,
+ "queue": {"id": 2, "type": "rx"},
+ "netns-id": 0,
+ },
+ }
+ )
+
+ ksft_eq(r1["id"], 1)
+ ksft_eq(r2["id"], 2)
+
+ # Verify both leases visible on physical device
+ netdevnl = NetdevFamily()
+ q1 = netdevnl.queue_get(
+ {"ifindex": nsim.ifindex, "id": 1, "type": "rx"}
+ )
+ q2 = netdevnl.queue_get(
+ {"ifindex": nsim.ifindex, "id": 2, "type": "rx"}
+ )
+ ksft_in("lease", q1)
+ ksft_in("lease", q2)
+ ksft_eq(q1["lease"]["ifindex"], nk_guest_idx)
+ ksft_eq(q2["lease"]["ifindex"], nk_guest_idx)
+ ksft_eq(q1["lease"]["queue"]["id"], r1["id"])
+ ksft_eq(q2["lease"]["queue"]["id"], r2["id"])
+
+
+def test_lease_queue_tx_type(netns) -> None:
+ nsimdev = NetdevSimDev(port_count=1, queue_count=2)
+ defer(nsimdev.remove)
+ nsim = nsimdev.nsims[0]
+ ip(f"link set dev {nsim.ifname} up")
+
+ nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
+ defer(cmd, f"ip link del dev {nk_host}", fail=False)
+
+ ip(f"link set dev {nk_guest} netns {netns.name}")
+ ip(f"link set dev {nk_host} up")
+ ip(f"link set dev {nk_guest} up", ns=netns)
+
+ with NetNSEnter(str(netns)):
+ netdevnl = NetdevFamily()
+ with ksft_raises(NlError) as e:
+ netdevnl.queue_create(
+ {
+ "ifindex": nk_guest_idx,
+ "type": "rx",
+ "lease": {
+ "ifindex": nsim.ifindex,
+ "queue": {"id": 1, "type": "tx"},
+ "netns-id": 0,
+ },
+ }
+ )
+ ksft_eq(e.exception.nl_msg.error, -errno.EINVAL)
+
+
+def test_invalid_netns(netns) -> None:
+ nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
+ defer(cmd, f"ip link del dev {nk_host}", fail=False)
+
+ ip(f"link set dev {nk_guest} netns {netns.name}")
+ ip(f"link set dev {nk_host} up")
+ ip(f"link set dev {nk_guest} up", ns=netns)
+
+ with NetNSEnter(str(netns)):
+ netdevnl = NetdevFamily()
+ with ksft_raises(NlError) as e:
+ netdevnl.queue_create(
+ {
+ "ifindex": nk_guest_idx,
+ "type": "rx",
+ "lease": {
+ "ifindex": 1,
+ "queue": {"id": 0, "type": "rx"},
+ "netns-id": 999,
+ },
+ }
+ )
+ ksft_eq(e.exception.nl_msg.error, -errno.ENONET)
+
+
+def test_invalid_phys_ifindex(netns) -> None:
+ nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
+ defer(cmd, f"ip link del dev {nk_host}", fail=False)
+
+ ip(f"link set dev {nk_guest} netns {netns.name}")
+ ip(f"link set dev {nk_host} up")
+ ip(f"link set dev {nk_guest} up", ns=netns)
+
+ with NetNSEnter(str(netns)):
+ netdevnl = NetdevFamily()
+ with ksft_raises(NlError) as e:
+ netdevnl.queue_create(
+ {
+ "ifindex": nk_guest_idx,
+ "type": "rx",
+ "lease": {
+ "ifindex": 99999,
+ "queue": {"id": 0, "type": "rx"},
+ "netns-id": 0,
+ },
+ }
+ )
+ ksft_eq(e.exception.nl_msg.error, -errno.ENODEV)
+
+
+def test_multi_netkit_remove_phys(netns) -> None:
+ nsimdev = NetdevSimDev(port_count=1, queue_count=3)
+ defer(nsimdev.remove)
+ nsim = nsimdev.nsims[0]
+ ip(f"link set dev {nsim.ifname} up")
+
+ # Create two netkit pairs, each leasing a different physical queue
+ nk_host_a, _, nk_guest_a, nk_guest_a_idx = create_netkit(rxqueues=2)
+ defer(cmd, f"ip link del dev {nk_host_a}", fail=False)
+
+ nk_host_b, _, nk_guest_b, nk_guest_b_idx = create_netkit(rxqueues=2)
+ defer(cmd, f"ip link del dev {nk_host_b}", fail=False)
+
+ ip(f"link set dev {nk_guest_a} netns {netns.name}")
+ ip(f"link set dev {nk_host_a} up")
+ ip(f"link set dev {nk_guest_a} up", ns=netns)
+
+ ip(f"link set dev {nk_guest_b} netns {netns.name}")
+ ip(f"link set dev {nk_host_b} up")
+ ip(f"link set dev {nk_guest_b} up", ns=netns)
+
+ with NetNSEnter(str(netns)):
+ netdevnl = NetdevFamily()
+ netdevnl.queue_create(
+ {
+ "ifindex": nk_guest_a_idx,
+ "type": "rx",
+ "lease": {
+ "ifindex": nsim.ifindex,
+ "queue": {"id": 1, "type": "rx"},
+ "netns-id": 0,
+ },
+ }
+ )
+ netdevnl.queue_create(
+ {
+ "ifindex": nk_guest_b_idx,
+ "type": "rx",
+ "lease": {
+ "ifindex": nsim.ifindex,
+ "queue": {"id": 2, "type": "rx"},
+ "netns-id": 0,
+ },
+ }
+ )
+
+ # Removing the physical device should take down both netkit pairs
+ nsimdev.remove()
+ time.sleep(0.1)
+ ret = cmd(f"ip link show dev {nk_host_a}", fail=False)
+ ksft_ne(ret.ret, 0)
+ ret = cmd(f"ip link show dev {nk_host_b}", fail=False)
+ ksft_ne(ret.ret, 0)
+
+
+def test_single_remove_phys(_netns) -> None:
+ nsimdev = NetdevSimDev(port_count=1, queue_count=2)
+ defer(nsimdev.remove)
+ nsim = nsimdev.nsims[0]
+ ip(f"link set dev {nsim.ifname} up")
+
+ nk_name, nk_idx = create_netkit_single(rxqueues=2)
+ defer(cmd, f"ip link del dev {nk_name}", fail=False)
+
+ ip(f"link set dev {nk_name} up")
+
+ netdevnl = NetdevFamily()
+ netdevnl.queue_create(
+ {
+ "ifindex": nk_idx,
+ "type": "rx",
+ "lease": {
+ "ifindex": nsim.ifindex,
+ "queue": {"id": 1, "type": "rx"},
+ },
+ }
+ )
+
+ # Removing the physical device should take down the single netkit device
+ nsimdev.remove()
+ time.sleep(0.1)
+ ret = cmd(f"ip link show dev {nk_name}", fail=False)
+ ksft_ne(ret.ret, 0)
+
+
+def test_link_flap_virt(netns) -> None:
+ nsimdev = NetdevSimDev(port_count=1, queue_count=2)
+ defer(nsimdev.remove)
+ nsim = nsimdev.nsims[0]
+ ip(f"link set dev {nsim.ifname} up")
+
+ nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
+ defer(cmd, f"ip link del dev {nk_host}")
+
+ ip(f"link set dev {nk_guest} netns {netns.name}")
+ ip(f"link set dev {nk_host} up")
+ ip(f"link set dev {nk_guest} up", ns=netns)
+
+ src_queue = 1
+ with NetNSEnter(str(netns)):
+ netdevnl = NetdevFamily()
+ result = netdevnl.queue_create(
+ {
+ "ifindex": nk_guest_idx,
+ "type": "rx",
+ "lease": {
+ "ifindex": nsim.ifindex,
+ "queue": {"id": src_queue, "type": "rx"},
+ "netns-id": 0,
+ },
+ }
+ )
+ nk_queue_id = result["id"]
+
+ netdevnl = NetdevFamily()
+ queue_info = netdevnl.queue_get(
+ {"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
+ )
+ ksft_in("lease", queue_info)
+ ksft_eq(queue_info["lease"]["queue"]["id"], nk_queue_id)
+
+ # Link flap the virtual (netkit) device
+ ip(f"link set dev {nk_guest} down", ns=netns)
+ ip(f"link set dev {nk_guest} up", ns=netns)
+
+ # Verify lease survives the virtual device flap
+ queue_info = netdevnl.queue_get(
+ {"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
+ )
+ ksft_in("lease", queue_info)
+ ksft_eq(queue_info["lease"]["queue"]["id"], nk_queue_id)
+
+
+def test_phys_queue_no_lease(netns) -> None:
+ nsimdev = NetdevSimDev(port_count=1, queue_count=2)
+ defer(nsimdev.remove)
+ nsim = nsimdev.nsims[0]
+ ip(f"link set dev {nsim.ifname} up")
+
+ nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
+ defer(cmd, f"ip link del dev {nk_host}")
+
+ ip(f"link set dev {nk_guest} netns {netns.name}")
+ ip(f"link set dev {nk_host} up")
+ ip(f"link set dev {nk_guest} up", ns=netns)
+
+ with NetNSEnter(str(netns)):
+ netdevnl = NetdevFamily()
+ netdevnl.queue_create(
+ {
+ "ifindex": nk_guest_idx,
+ "type": "rx",
+ "lease": {
+ "ifindex": nsim.ifindex,
+ "queue": {"id": 1, "type": "rx"},
+ "netns-id": 0,
+ },
+ }
+ )
+
+ # Physical queue 0 (not leased) should have no lease info
+ netdevnl = NetdevFamily()
+ queue_info = netdevnl.queue_get(
+ {"ifindex": nsim.ifindex, "id": 0, "type": "rx"}
+ )
+ ksft_not_in("lease", queue_info)
+
+ # Physical queue 1 (leased) should have lease info
+ queue_info = netdevnl.queue_get(
+ {"ifindex": nsim.ifindex, "id": 1, "type": "rx"}
+ )
+ ksft_in("lease", queue_info)
+
+
+def test_same_ns_lease(_netns) -> None:
+ nsimdev = NetdevSimDev(port_count=1, queue_count=2)
+ defer(nsimdev.remove)
+ nsim = nsimdev.nsims[0]
+ ip(f"link set dev {nsim.ifname} up")
+
+ nk_name, nk_idx = create_netkit_single(rxqueues=2)
+ defer(cmd, f"ip link del dev {nk_name}", fail=False)
+
+ ip(f"link set dev {nk_name} up")
+
+ netdevnl = NetdevFamily()
+ result = netdevnl.queue_create(
+ {
+ "ifindex": nk_idx,
+ "type": "rx",
+ "lease": {
+ "ifindex": nsim.ifindex,
+ "queue": {"id": 1, "type": "rx"},
+ },
+ }
+ )
+ ksft_eq(result["id"], 1)
+
+ # Same namespace: lease info should NOT have netns-id
+ queue_info = netdevnl.queue_get(
+ {"ifindex": nsim.ifindex, "id": 1, "type": "rx"}
+ )
+ ksft_in("lease", queue_info)
+ ksft_eq(queue_info["lease"]["ifindex"], nk_idx)
+ ksft_eq(queue_info["lease"]["queue"]["id"], result["id"])
+ ksft_not_in("netns-id", queue_info["lease"])
+
+
+def test_resize_after_unlease(netns) -> None:
+ nsimdev = NetdevSimDev(port_count=1, queue_count=2)
+ defer(nsimdev.remove)
+ nsim = nsimdev.nsims[0]
+ ip(f"link set dev {nsim.ifname} up")
+
+ nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
+
+ ip(f"link set dev {nk_guest} netns {netns.name}")
+ ip(f"link set dev {nk_host} up")
+ ip(f"link set dev {nk_guest} up", ns=netns)
+
+ with NetNSEnter(str(netns)):
+ netdevnl = NetdevFamily()
+ netdevnl.queue_create(
+ {
+ "ifindex": nk_guest_idx,
+ "type": "rx",
+ "lease": {
+ "ifindex": nsim.ifindex,
+ "queue": {"id": 1, "type": "rx"},
+ "netns-id": 0,
+ },
+ }
+ )
+
+ # Resize should fail while lease is active
+ ethnl = EthtoolFamily()
+ with ksft_raises(NlError) as e:
+ ethnl.channels_set({"header": {"dev-index": nsim.ifindex}, "combined-count": 1})
+ ksft_eq(e.exception.nl_msg.error, -errno.EINVAL)
+
+ # Delete netkit, clearing the lease
+ cmd(f"ip link del dev {nk_host}")
+
+ # Resize should now succeed
+ ethnl.channels_set({"header": {"dev-index": nsim.ifindex}, "combined-count": 1})
+
+
+def test_lease_queue_zero(netns) -> None:
+ nsimdev = NetdevSimDev(port_count=1, queue_count=2)
+ defer(nsimdev.remove)
+ nsim = nsimdev.nsims[0]
+ ip(f"link set dev {nsim.ifname} up")
+
+ nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
+ defer(cmd, f"ip link del dev {nk_host}", fail=False)
+
+ ip(f"link set dev {nk_guest} netns {netns.name}")
+ ip(f"link set dev {nk_host} up")
+ ip(f"link set dev {nk_guest} up", ns=netns)
+
+ with NetNSEnter(str(netns)):
+ netdevnl = NetdevFamily()
+ result = netdevnl.queue_create(
+ {
+ "ifindex": nk_guest_idx,
+ "type": "rx",
+ "lease": {
+ "ifindex": nsim.ifindex,
+ "queue": {"id": 0, "type": "rx"},
+ "netns-id": 0,
+ },
+ }
+ )
+ ksft_eq(result["id"], 1)
+
+ netdevnl = NetdevFamily()
+ queue_info = netdevnl.queue_get(
+ {"ifindex": nsim.ifindex, "id": 0, "type": "rx"}
+ )
+ ksft_in("lease", queue_info)
+ ksft_eq(queue_info["lease"]["queue"]["id"], result["id"])
+
+
+def test_release_and_reuse(netns) -> None:
+ nsimdev = NetdevSimDev(port_count=1, queue_count=2)
+ defer(nsimdev.remove)
+ nsim = nsimdev.nsims[0]
+ ip(f"link set dev {nsim.ifname} up")
+
+ src_queue = 1
+
+ # First lease
+ nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
+
+ ip(f"link set dev {nk_guest} netns {netns.name}")
+ ip(f"link set dev {nk_host} up")
+ ip(f"link set dev {nk_guest} up", ns=netns)
+
+ with NetNSEnter(str(netns)):
+ netdevnl = NetdevFamily()
+ netdevnl.queue_create(
+ {
+ "ifindex": nk_guest_idx,
+ "type": "rx",
+ "lease": {
+ "ifindex": nsim.ifindex,
+ "queue": {"id": src_queue, "type": "rx"},
+ "netns-id": 0,
+ },
+ }
+ )
+
+ netdevnl = NetdevFamily()
+ queue_info = netdevnl.queue_get(
+ {"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
+ )
+ ksft_in("lease", queue_info)
+
+ # Delete netkit, freeing the lease
+ cmd(f"ip link del dev {nk_host}")
+
+ queue_info = netdevnl.queue_get(
+ {"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
+ )
+ ksft_not_in("lease", queue_info)
+
+ # Re-create netkit and lease the same physical queue again
+ nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
+ defer(cmd, f"ip link del dev {nk_host}", fail=False)
+
+ ip(f"link set dev {nk_guest} netns {netns.name}")
+ ip(f"link set dev {nk_host} up")
+ ip(f"link set dev {nk_guest} up", ns=netns)
+
+ with NetNSEnter(str(netns)):
+ netdevnl = NetdevFamily()
+ result = netdevnl.queue_create(
+ {
+ "ifindex": nk_guest_idx,
+ "type": "rx",
+ "lease": {
+ "ifindex": nsim.ifindex,
+ "queue": {"id": src_queue, "type": "rx"},
+ "netns-id": 0,
+ },
+ }
+ )
+ ksft_eq(result["id"], 1)
+
+ netdevnl = NetdevFamily()
+ queue_info = netdevnl.queue_get(
+ {"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
+ )
+ ksft_in("lease", queue_info)
+ ksft_eq(queue_info["lease"]["queue"]["id"], result["id"])
+
+
+def main() -> None:
+ netns = NetNS()
+ cmd("ip netns attach init 1")
+ ip("netns set init 0", ns=netns)
+ ip("link set lo up", ns=netns)
+
+ ksft_run(
+ [
+ test_remove_phys,
+ test_double_lease,
+ test_virtual_lessor,
+ test_phys_lessee,
+ test_different_lessors,
+ test_queue_out_of_range,
+ test_resize_leased,
+ test_self_lease,
+ test_create_tx_type,
+ test_create_primary,
+ test_create_limit,
+ test_link_flap_phys,
+ test_queue_get_virtual,
+ test_remove_virt_first,
+ test_multiple_leases,
+ test_lease_queue_tx_type,
+ test_invalid_netns,
+ test_invalid_phys_ifindex,
+ test_multi_netkit_remove_phys,
+ test_single_remove_phys,
+ test_link_flap_virt,
+ test_phys_queue_no_lease,
+ test_same_ns_lease,
+ test_resize_after_unlease,
+ test_lease_queue_zero,
+ test_release_and_reuse,
+ test_veth_queue_create,
+ ],
+ args=(netns,),
+ )
+
+ cmd("ip netns del init", fail=False)
+ ksft_exit()
+
+
+if __name__ == "__main__":
+ main()
--
2.43.0
^ permalink raw reply related
* [PATCH net-next v2 3/3] selftests/net: Add additional test coverage in nk_qlease
From: Daniel Borkmann @ 2026-04-13 22:08 UTC (permalink / raw)
To: netdev; +Cc: kuba, dw, pabeni, razor
In-Reply-To: <20260413220809.604592-1-daniel@iogearbox.net>
Add further netkit queue-lease coverage for netns lifecycle of the guest
and physical halves, channel resize across active leases, single-device
and multi-lessee scenarios, L3 mode operation, lease capacity exhaustion,
and corner-cases of e.g. queue-create rejection paths. Also make the tests
more robust by removing the time.sleep(0.1) after netns deletion and turn
them into a wait loop.
Full test run:
# ./nk_qlease.py
TAP version 13
1..45
ok 1 nk_qlease.test_remove_phys
ok 2 nk_qlease.test_double_lease
ok 3 nk_qlease.test_virtual_lessor
ok 4 nk_qlease.test_phys_lessee
ok 5 nk_qlease.test_different_lessors
ok 6 nk_qlease.test_queue_out_of_range
ok 7 nk_qlease.test_resize_leased
ok 8 nk_qlease.test_self_lease
ok 9 nk_qlease.test_create_tx_type
ok 10 nk_qlease.test_create_primary
ok 11 nk_qlease.test_create_limit
ok 12 nk_qlease.test_link_flap_phys
ok 13 nk_qlease.test_queue_get_virtual
ok 14 nk_qlease.test_remove_virt_first
ok 15 nk_qlease.test_multiple_leases
ok 16 nk_qlease.test_lease_queue_tx_type
ok 17 nk_qlease.test_invalid_netns
ok 18 nk_qlease.test_invalid_phys_ifindex
ok 19 nk_qlease.test_multi_netkit_remove_phys
ok 20 nk_qlease.test_single_remove_phys
ok 21 nk_qlease.test_link_flap_virt
ok 22 nk_qlease.test_phys_queue_no_lease
ok 23 nk_qlease.test_same_ns_lease
ok 24 nk_qlease.test_resize_after_unlease
ok 25 nk_qlease.test_lease_queue_zero
ok 26 nk_qlease.test_release_and_reuse
ok 27 nk_qlease.test_veth_queue_create
ok 28 nk_qlease.test_two_netkits_same_queue
ok 29 nk_qlease.test_l3_mode_lease
ok 30 nk_qlease.test_single_double_lease
ok 31 nk_qlease.test_single_different_lessors
ok 32 nk_qlease.test_cross_ns_netns_id
ok 33 nk_qlease.test_delete_guest_netns
ok 34 nk_qlease.test_move_guest_netns
ok 35 nk_qlease.test_resize_phys_no_reduction
ok 36 nk_qlease.test_delete_one_netkit_of_two
ok 37 nk_qlease.test_bind_rx_leased_phys_queue
ok 38 nk_qlease.test_resize_phys_shrink_past_leased
ok 39 nk_qlease.test_resize_virt_not_supported
ok 40 nk_qlease.test_lease_devices_down
ok 41 nk_qlease.test_lease_capacity_exhaustion
ok 42 nk_qlease.test_resize_phys_up
ok 43 nk_qlease.test_multi_ns_lease
ok 44 nk_qlease.test_multi_ns_delete_one
ok 45 nk_qlease.test_move_phys_netns
# Totals: pass:45 fail:0 xfail:0 xpass:0 skip:0 error:0
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
---
tools/testing/selftests/net/nk_qlease.py | 951 ++++++++++++++++++++++-
1 file changed, 946 insertions(+), 5 deletions(-)
diff --git a/tools/testing/selftests/net/nk_qlease.py b/tools/testing/selftests/net/nk_qlease.py
index 6ed4fb5e90f6..a84a73ff4eda 100755
--- a/tools/testing/selftests/net/nk_qlease.py
+++ b/tools/testing/selftests/net/nk_qlease.py
@@ -28,7 +28,16 @@ from lib.py import (
ip,
)
-def create_netkit(rxqueues):
+
+def wait_until(cond, timeout=2.0, interval=0.05):
+ deadline = time.monotonic() + timeout
+ while not cond():
+ if time.monotonic() >= deadline:
+ return
+ time.sleep(interval)
+
+
+def create_netkit(rxqueues, mode="l2"):
all_links = ip("-d link show", json=True)
old_idxs = {
link["ifindex"]
@@ -42,7 +51,7 @@ def create_netkit(rxqueues):
"linkinfo": {
"kind": "netkit",
"data": {
- "mode": "l2",
+ "mode": mode,
"policy": "forward",
"peer-policy": "forward",
},
@@ -93,6 +102,7 @@ def create_netkit_single(rxqueues):
]
return nk_links[0]["ifname"], nk_links[0]["ifindex"]
+
def test_remove_phys(netns) -> None:
nsimdev = NetdevSimDev(port_count=1, queue_count=2)
defer(nsimdev.remove)
@@ -131,7 +141,7 @@ def test_remove_phys(netns) -> None:
ksft_eq(queue_info["lease"]["queue"]["id"], nk_queue_id)
nsimdev.remove()
- time.sleep(0.1)
+ wait_until(lambda: cmd(f"ip link show dev {nk_host}", fail=False).ret != 0)
ret = cmd(f"ip link show dev {nk_host}", fail=False)
ksft_ne(ret.ret, 0)
@@ -812,7 +822,8 @@ def test_multi_netkit_remove_phys(netns) -> None:
# Removing the physical device should take down both netkit pairs
nsimdev.remove()
- time.sleep(0.1)
+ wait_until(lambda: cmd(f"ip link show dev {nk_host_a}", fail=False).ret != 0
+ and cmd(f"ip link show dev {nk_host_b}", fail=False).ret != 0)
ret = cmd(f"ip link show dev {nk_host_a}", fail=False)
ksft_ne(ret.ret, 0)
ret = cmd(f"ip link show dev {nk_host_b}", fail=False)
@@ -844,7 +855,7 @@ def test_single_remove_phys(_netns) -> None:
# Removing the physical device should take down the single netkit device
nsimdev.remove()
- time.sleep(0.1)
+ wait_until(lambda: cmd(f"ip link show dev {nk_name}", fail=False).ret != 0)
ret = cmd(f"ip link show dev {nk_name}", fail=False)
ksft_ne(ret.ret, 0)
@@ -1121,6 +1132,918 @@ def test_release_and_reuse(netns) -> None:
ksft_eq(queue_info["lease"]["queue"]["id"], result["id"])
+def test_two_netkits_same_queue(netns) -> None:
+ nsimdev = NetdevSimDev(port_count=1, queue_count=2)
+ defer(nsimdev.remove)
+ nsim = nsimdev.nsims[0]
+ ip(f"link set dev {nsim.ifname} up")
+
+ nk_host_a, _, nk_guest_a, nk_guest_a_idx = create_netkit(rxqueues=2)
+ defer(cmd, f"ip link del dev {nk_host_a}", fail=False)
+
+ nk_host_b, _, nk_guest_b, nk_guest_b_idx = create_netkit(rxqueues=2)
+ defer(cmd, f"ip link del dev {nk_host_b}", fail=False)
+
+ ip(f"link set dev {nk_guest_a} netns {netns.name}")
+ ip(f"link set dev {nk_host_a} up")
+ ip(f"link set dev {nk_guest_a} up", ns=netns)
+
+ ip(f"link set dev {nk_guest_b} netns {netns.name}")
+ ip(f"link set dev {nk_host_b} up")
+ ip(f"link set dev {nk_guest_b} up", ns=netns)
+
+ src_queue = 1
+ with NetNSEnter(str(netns)), NetdevFamily() as netdevnl_ns:
+ netdevnl_ns.queue_create(
+ {
+ "ifindex": nk_guest_a_idx,
+ "type": "rx",
+ "lease": {
+ "ifindex": nsim.ifindex,
+ "queue": {"id": src_queue, "type": "rx"},
+ "netns-id": 0,
+ },
+ }
+ )
+
+ with ksft_raises(NlError) as e:
+ netdevnl_ns.queue_create(
+ {
+ "ifindex": nk_guest_b_idx,
+ "type": "rx",
+ "lease": {
+ "ifindex": nsim.ifindex,
+ "queue": {"id": src_queue, "type": "rx"},
+ "netns-id": 0,
+ },
+ }
+ )
+ ksft_eq(e.exception.nl_msg.error, -errno.EBUSY)
+
+
+def test_l3_mode_lease(netns) -> None:
+ nsimdev = NetdevSimDev(port_count=1, queue_count=2)
+ defer(nsimdev.remove)
+ nsim = nsimdev.nsims[0]
+ ip(f"link set dev {nsim.ifname} up")
+
+ nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2, mode="l3")
+ defer(cmd, f"ip link del dev {nk_host}", fail=False)
+
+ ip(f"link set dev {nk_guest} netns {netns.name}")
+ ip(f"link set dev {nk_host} up")
+ ip(f"link set dev {nk_guest} up", ns=netns)
+
+ src_queue = 1
+ with NetNSEnter(str(netns)), NetdevFamily() as netdevnl_ns:
+ result = netdevnl_ns.queue_create(
+ {
+ "ifindex": nk_guest_idx,
+ "type": "rx",
+ "lease": {
+ "ifindex": nsim.ifindex,
+ "queue": {"id": src_queue, "type": "rx"},
+ "netns-id": 0,
+ },
+ }
+ )
+ ksft_eq(result["id"], 1)
+
+ netdevnl = NetdevFamily()
+ queue_info = netdevnl.queue_get(
+ {"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
+ )
+ ksft_in("lease", queue_info)
+ ksft_eq(queue_info["lease"]["ifindex"], nk_guest_idx)
+ ksft_eq(queue_info["lease"]["queue"]["id"], result["id"])
+
+
+def test_single_double_lease(_netns) -> None:
+ nsimdev = NetdevSimDev(port_count=1, queue_count=2)
+ defer(nsimdev.remove)
+ nsim = nsimdev.nsims[0]
+ ip(f"link set dev {nsim.ifname} up")
+
+ nk_name, nk_idx = create_netkit_single(rxqueues=3)
+ defer(cmd, f"ip link del dev {nk_name}", fail=False)
+
+ ip(f"link set dev {nk_name} up")
+
+ netdevnl = NetdevFamily()
+ result = netdevnl.queue_create(
+ {
+ "ifindex": nk_idx,
+ "type": "rx",
+ "lease": {
+ "ifindex": nsim.ifindex,
+ "queue": {"id": 1, "type": "rx"},
+ },
+ }
+ )
+ ksft_eq(result["id"], 1)
+
+ with ksft_raises(NlError) as e:
+ netdevnl.queue_create(
+ {
+ "ifindex": nk_idx,
+ "type": "rx",
+ "lease": {
+ "ifindex": nsim.ifindex,
+ "queue": {"id": 1, "type": "rx"},
+ },
+ }
+ )
+ ksft_eq(e.exception.nl_msg.error, -errno.EBUSY)
+
+
+def test_single_different_lessors(_netns) -> None:
+ nsimdev_a = NetdevSimDev(port_count=1, queue_count=2)
+ defer(nsimdev_a.remove)
+ nsim_a = nsimdev_a.nsims[0]
+ ip(f"link set dev {nsim_a.ifname} up")
+
+ nsimdev_b = NetdevSimDev(port_count=1, queue_count=2)
+ defer(nsimdev_b.remove)
+ nsim_b = nsimdev_b.nsims[0]
+ ip(f"link set dev {nsim_b.ifname} up")
+
+ nk_name, nk_idx = create_netkit_single(rxqueues=3)
+ defer(cmd, f"ip link del dev {nk_name}", fail=False)
+
+ ip(f"link set dev {nk_name} up")
+
+ netdevnl = NetdevFamily()
+ netdevnl.queue_create(
+ {
+ "ifindex": nk_idx,
+ "type": "rx",
+ "lease": {
+ "ifindex": nsim_a.ifindex,
+ "queue": {"id": 1, "type": "rx"},
+ },
+ }
+ )
+
+ with ksft_raises(NlError) as e:
+ netdevnl.queue_create(
+ {
+ "ifindex": nk_idx,
+ "type": "rx",
+ "lease": {
+ "ifindex": nsim_b.ifindex,
+ "queue": {"id": 1, "type": "rx"},
+ },
+ }
+ )
+ ksft_eq(e.exception.nl_msg.error, -errno.EOPNOTSUPP)
+
+
+def test_cross_ns_netns_id(netns) -> None:
+ nsimdev = NetdevSimDev(port_count=1, queue_count=2)
+ defer(nsimdev.remove)
+ nsim = nsimdev.nsims[0]
+ ip(f"link set dev {nsim.ifname} up")
+
+ nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
+ defer(cmd, f"ip link del dev {nk_host}", fail=False)
+
+ ip(f"link set dev {nk_guest} netns {netns.name}")
+ ip(f"link set dev {nk_host} up")
+ ip(f"link set dev {nk_guest} up", ns=netns)
+
+ src_queue = 1
+ with NetNSEnter(str(netns)), NetdevFamily() as netdevnl_ns:
+ netdevnl_ns.queue_create(
+ {
+ "ifindex": nk_guest_idx,
+ "type": "rx",
+ "lease": {
+ "ifindex": nsim.ifindex,
+ "queue": {"id": src_queue, "type": "rx"},
+ "netns-id": 0,
+ },
+ }
+ )
+
+ netdevnl = NetdevFamily()
+ queue_info = netdevnl.queue_get(
+ {"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
+ )
+ ksft_in("lease", queue_info)
+ ksft_in("netns-id", queue_info["lease"])
+
+
+def test_delete_guest_netns(_netns) -> None:
+ nsimdev = NetdevSimDev(port_count=1, queue_count=2)
+ defer(nsimdev.remove)
+ nsim = nsimdev.nsims[0]
+ ip(f"link set dev {nsim.ifname} up")
+
+ test_ns = NetNS()
+ ip("netns set init 0", ns=test_ns)
+ ip("link set lo up", ns=test_ns)
+
+ nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
+ defer(cmd, f"ip link del dev {nk_host}", fail=False)
+
+ ip(f"link set dev {nk_guest} netns {test_ns.name}")
+ ip(f"link set dev {nk_host} up")
+ ip(f"link set dev {nk_guest} up", ns=test_ns)
+
+ src_queue = 1
+ with NetNSEnter(str(test_ns)), NetdevFamily() as netdevnl_ns:
+ netdevnl_ns.queue_create(
+ {
+ "ifindex": nk_guest_idx,
+ "type": "rx",
+ "lease": {
+ "ifindex": nsim.ifindex,
+ "queue": {"id": src_queue, "type": "rx"},
+ "netns-id": 0,
+ },
+ }
+ )
+
+ netdevnl = NetdevFamily()
+ queue_info = netdevnl.queue_get(
+ {"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
+ )
+ ksft_in("lease", queue_info)
+
+ del test_ns
+ wait_until(lambda: "lease" not in netdevnl.queue_get(
+ {"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}))
+
+ queue_info = netdevnl.queue_get(
+ {"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
+ )
+ ksft_not_in("lease", queue_info)
+
+ ret = cmd(f"ip link show dev {nk_host}", fail=False)
+ ksft_ne(ret.ret, 0)
+
+
+def test_move_guest_netns(netns) -> None:
+ nsimdev = NetdevSimDev(port_count=1, queue_count=2)
+ defer(nsimdev.remove)
+ nsim = nsimdev.nsims[0]
+ ip(f"link set dev {nsim.ifname} up")
+
+ nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
+ defer(cmd, f"ip link del dev {nk_host}", fail=False)
+
+ ip(f"link set dev {nk_guest} netns {netns.name}")
+ ip(f"link set dev {nk_host} up")
+ ip(f"link set dev {nk_guest} up", ns=netns)
+
+ src_queue = 1
+ with NetNSEnter(str(netns)), NetdevFamily() as netdevnl_ns:
+ result = netdevnl_ns.queue_create(
+ {
+ "ifindex": nk_guest_idx,
+ "type": "rx",
+ "lease": {
+ "ifindex": nsim.ifindex,
+ "queue": {"id": src_queue, "type": "rx"},
+ "netns-id": 0,
+ },
+ }
+ )
+ nk_queue_id = result["id"]
+
+ netdevnl = NetdevFamily()
+ queue_info = netdevnl.queue_get(
+ {"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
+ )
+ ksft_in("lease", queue_info)
+ ksft_eq(queue_info["lease"]["queue"]["id"], nk_queue_id)
+
+ new_ns = NetNS()
+ defer(new_ns.__del__)
+ ip(f"link set dev {nk_guest} netns {new_ns.name}", ns=netns)
+
+ queue_info = netdevnl.queue_get(
+ {"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
+ )
+ ksft_in("lease", queue_info)
+ ksft_eq(queue_info["lease"]["queue"]["id"], nk_queue_id)
+
+
+def test_resize_phys_no_reduction(netns) -> None:
+ nsimdev = NetdevSimDev(port_count=1, queue_count=2)
+ defer(nsimdev.remove)
+ nsim = nsimdev.nsims[0]
+ ip(f"link set dev {nsim.ifname} up")
+
+ nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
+ defer(cmd, f"ip link del dev {nk_host}", fail=False)
+
+ ip(f"link set dev {nk_guest} netns {netns.name}")
+ ip(f"link set dev {nk_host} up")
+ ip(f"link set dev {nk_guest} up", ns=netns)
+
+ with NetNSEnter(str(netns)), NetdevFamily() as netdevnl_ns:
+ netdevnl_ns.queue_create(
+ {
+ "ifindex": nk_guest_idx,
+ "type": "rx",
+ "lease": {
+ "ifindex": nsim.ifindex,
+ "queue": {"id": 1, "type": "rx"},
+ "netns-id": 0,
+ },
+ }
+ )
+
+ ethnl = EthtoolFamily()
+ ethnl.channels_set(
+ {"header": {"dev-index": nsim.ifindex}, "combined-count": 2}
+ )
+
+ netdevnl = NetdevFamily()
+ queue_info = netdevnl.queue_get(
+ {"ifindex": nsim.ifindex, "id": 1, "type": "rx"}
+ )
+ ksft_in("lease", queue_info)
+
+
+def test_delete_one_netkit_of_two(netns) -> None:
+ nsimdev = NetdevSimDev(port_count=1, queue_count=3)
+ defer(nsimdev.remove)
+ nsim = nsimdev.nsims[0]
+ ip(f"link set dev {nsim.ifname} up")
+
+ nk_host_a, _, nk_guest_a, nk_guest_a_idx = create_netkit(rxqueues=2)
+ defer(cmd, f"ip link del dev {nk_host_a}", fail=False)
+
+ nk_host_b, _, nk_guest_b, nk_guest_b_idx = create_netkit(rxqueues=2)
+ defer(cmd, f"ip link del dev {nk_host_b}", fail=False)
+
+ ip(f"link set dev {nk_guest_a} netns {netns.name}")
+ ip(f"link set dev {nk_host_a} up")
+ ip(f"link set dev {nk_guest_a} up", ns=netns)
+
+ ip(f"link set dev {nk_guest_b} netns {netns.name}")
+ ip(f"link set dev {nk_host_b} up")
+ ip(f"link set dev {nk_guest_b} up", ns=netns)
+
+ with NetNSEnter(str(netns)), NetdevFamily() as netdevnl_ns:
+ netdevnl_ns.queue_create(
+ {
+ "ifindex": nk_guest_a_idx,
+ "type": "rx",
+ "lease": {
+ "ifindex": nsim.ifindex,
+ "queue": {"id": 1, "type": "rx"},
+ "netns-id": 0,
+ },
+ }
+ )
+ netdevnl_ns.queue_create(
+ {
+ "ifindex": nk_guest_b_idx,
+ "type": "rx",
+ "lease": {
+ "ifindex": nsim.ifindex,
+ "queue": {"id": 2, "type": "rx"},
+ "netns-id": 0,
+ },
+ }
+ )
+
+ netdevnl = NetdevFamily()
+ q1 = netdevnl.queue_get(
+ {"ifindex": nsim.ifindex, "id": 1, "type": "rx"}
+ )
+ q2 = netdevnl.queue_get(
+ {"ifindex": nsim.ifindex, "id": 2, "type": "rx"}
+ )
+ ksft_in("lease", q1)
+ ksft_in("lease", q2)
+
+ cmd(f"ip link del dev {nk_host_a}")
+
+ q1 = netdevnl.queue_get(
+ {"ifindex": nsim.ifindex, "id": 1, "type": "rx"}
+ )
+ q2 = netdevnl.queue_get(
+ {"ifindex": nsim.ifindex, "id": 2, "type": "rx"}
+ )
+ ksft_not_in("lease", q1)
+ ksft_in("lease", q2)
+
+
+def test_bind_rx_leased_phys_queue(netns) -> None:
+ nsimdev = NetdevSimDev(port_count=1, queue_count=2)
+ defer(nsimdev.remove)
+ nsim = nsimdev.nsims[0]
+ ip(f"link set dev {nsim.ifname} up")
+
+ nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
+ defer(cmd, f"ip link del dev {nk_host}", fail=False)
+
+ ip(f"link set dev {nk_guest} netns {netns.name}")
+ ip(f"link set dev {nk_host} up")
+ ip(f"link set dev {nk_guest} up", ns=netns)
+
+ with NetNSEnter(str(netns)), NetdevFamily() as netdevnl_ns:
+ netdevnl_ns.queue_create(
+ {
+ "ifindex": nk_guest_idx,
+ "type": "rx",
+ "lease": {
+ "ifindex": nsim.ifindex,
+ "queue": {"id": 1, "type": "rx"},
+ "netns-id": 0,
+ },
+ }
+ )
+
+ netdevnl = NetdevFamily()
+ with ksft_raises(NlError) as e:
+ netdevnl.bind_rx(
+ {
+ "ifindex": nsim.ifindex,
+ "fd": 0,
+ "queues": [
+ {"id": 0, "type": "rx"},
+ {"id": 1, "type": "rx"},
+ ],
+ }
+ )
+ ksft_eq(e.exception.nl_msg.error, -errno.EOPNOTSUPP)
+
+
+def test_resize_phys_shrink_past_leased(netns) -> None:
+ nsimdev = NetdevSimDev(port_count=1, queue_count=4)
+ defer(nsimdev.remove)
+ nsim = nsimdev.nsims[0]
+ ip(f"link set dev {nsim.ifname} up")
+
+ nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
+ defer(cmd, f"ip link del dev {nk_host}", fail=False)
+
+ ip(f"link set dev {nk_guest} netns {netns.name}")
+ ip(f"link set dev {nk_host} up")
+ ip(f"link set dev {nk_guest} up", ns=netns)
+
+ with NetNSEnter(str(netns)), NetdevFamily() as netdevnl_ns:
+ netdevnl_ns.queue_create(
+ {
+ "ifindex": nk_guest_idx,
+ "type": "rx",
+ "lease": {
+ "ifindex": nsim.ifindex,
+ "queue": {"id": 1, "type": "rx"},
+ "netns-id": 0,
+ },
+ }
+ )
+
+ ethnl = EthtoolFamily()
+
+ # Shrink past the leased queue — only queue 3 removed, queue 1 untouched
+ ethnl.channels_set(
+ {"header": {"dev-index": nsim.ifindex}, "combined-count": 3}
+ )
+
+ netdevnl = NetdevFamily()
+ queue_info = netdevnl.queue_get(
+ {"ifindex": nsim.ifindex, "id": 1, "type": "rx"}
+ )
+ ksft_in("lease", queue_info)
+
+ # Shrink further — queue 2 removed, queue 1 still untouched
+ ethnl.channels_set(
+ {"header": {"dev-index": nsim.ifindex}, "combined-count": 2}
+ )
+
+ queue_info = netdevnl.queue_get(
+ {"ifindex": nsim.ifindex, "id": 1, "type": "rx"}
+ )
+ ksft_in("lease", queue_info)
+
+ # Shrink into the leased queue — queue 1 is busy, must fail
+ with ksft_raises(NlError) as e:
+ ethnl.channels_set(
+ {"header": {"dev-index": nsim.ifindex}, "combined-count": 1}
+ )
+ ksft_eq(e.exception.nl_msg.error, -errno.EINVAL)
+
+
+def test_resize_virt_not_supported(netns) -> None:
+ nsimdev = NetdevSimDev(port_count=1, queue_count=2)
+ defer(nsimdev.remove)
+ nsim = nsimdev.nsims[0]
+ ip(f"link set dev {nsim.ifname} up")
+
+ nk_host, nk_host_idx, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
+ defer(cmd, f"ip link del dev {nk_host}", fail=False)
+
+ ip(f"link set dev {nk_guest} netns {netns.name}")
+ ip(f"link set dev {nk_host} up")
+ ip(f"link set dev {nk_guest} up", ns=netns)
+
+ with NetNSEnter(str(netns)), NetdevFamily() as netdevnl_ns:
+ netdevnl_ns.queue_create(
+ {
+ "ifindex": nk_guest_idx,
+ "type": "rx",
+ "lease": {
+ "ifindex": nsim.ifindex,
+ "queue": {"id": 1, "type": "rx"},
+ "netns-id": 0,
+ },
+ }
+ )
+
+ # Channel resize on the netkit host must fail — not supported
+ ethnl = EthtoolFamily()
+ with ksft_raises(NlError) as e:
+ ethnl.channels_set(
+ {"header": {"dev-index": nk_host_idx}, "combined-count": 1}
+ )
+ ksft_eq(e.exception.nl_msg.error, -errno.EOPNOTSUPP)
+
+ # Lease must be intact
+ netdevnl = NetdevFamily()
+ queue_info = netdevnl.queue_get(
+ {"ifindex": nsim.ifindex, "id": 1, "type": "rx"}
+ )
+ ksft_in("lease", queue_info)
+
+
+def test_lease_devices_down(netns) -> None:
+ nsimdev = NetdevSimDev(port_count=1, queue_count=2)
+ defer(nsimdev.remove)
+ nsim = nsimdev.nsims[0]
+
+ nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
+ defer(cmd, f"ip link del dev {nk_host}", fail=False)
+
+ ip(f"link set dev {nk_guest} netns {netns.name}")
+
+ # Create lease while both physical and virtual devices are down
+ src_queue = 1
+ with NetNSEnter(str(netns)), NetdevFamily() as netdevnl_ns:
+ result = netdevnl_ns.queue_create(
+ {
+ "ifindex": nk_guest_idx,
+ "type": "rx",
+ "lease": {
+ "ifindex": nsim.ifindex,
+ "queue": {"id": src_queue, "type": "rx"},
+ "netns-id": 0,
+ },
+ }
+ )
+ ksft_eq(result["id"], 1)
+
+ # Bring devices up before queue_get: netdevsim only instantiates NAPIs in
+ # ndo_open, and netdev-genl queue_get returns -ENOENT without a NAPI.
+ ip(f"link set dev {nsim.ifname} up")
+ ip(f"link set dev {nk_host} up")
+ ip(f"link set dev {nk_guest} up", ns=netns)
+
+ netdevnl = NetdevFamily()
+ queue_info = netdevnl.queue_get(
+ {"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
+ )
+ ksft_in("lease", queue_info)
+ ksft_eq(queue_info["lease"]["queue"]["id"], result["id"])
+
+
+def test_lease_capacity_exhaustion(netns) -> None:
+ nsimdev = NetdevSimDev(port_count=1, queue_count=4)
+ defer(nsimdev.remove)
+ nsim = nsimdev.nsims[0]
+ ip(f"link set dev {nsim.ifname} up")
+
+ # rxqueues=3 means num_rx_queues=3, real_num_rx_queues starts at 1.
+ # Can create 2 leased queues (real goes 1->2->3) but not a 3rd (3->4 > 3).
+ nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=3)
+ defer(cmd, f"ip link del dev {nk_host}", fail=False)
+
+ ip(f"link set dev {nk_guest} netns {netns.name}")
+ ip(f"link set dev {nk_host} up")
+ ip(f"link set dev {nk_guest} up", ns=netns)
+
+ with NetNSEnter(str(netns)), NetdevFamily() as netdevnl_ns:
+ r1 = netdevnl_ns.queue_create(
+ {
+ "ifindex": nk_guest_idx,
+ "type": "rx",
+ "lease": {
+ "ifindex": nsim.ifindex,
+ "queue": {"id": 1, "type": "rx"},
+ "netns-id": 0,
+ },
+ }
+ )
+ ksft_eq(r1["id"], 1)
+
+ r2 = netdevnl_ns.queue_create(
+ {
+ "ifindex": nk_guest_idx,
+ "type": "rx",
+ "lease": {
+ "ifindex": nsim.ifindex,
+ "queue": {"id": 2, "type": "rx"},
+ "netns-id": 0,
+ },
+ }
+ )
+ ksft_eq(r2["id"], 2)
+
+ # Third lease fails — netkit queue capacity exhausted
+ with ksft_raises(NlError) as e:
+ netdevnl_ns.queue_create(
+ {
+ "ifindex": nk_guest_idx,
+ "type": "rx",
+ "lease": {
+ "ifindex": nsim.ifindex,
+ "queue": {"id": 3, "type": "rx"},
+ "netns-id": 0,
+ },
+ }
+ )
+ ksft_eq(e.exception.nl_msg.error, -errno.EINVAL)
+
+ # Verify the two successful leases are intact
+ netdevnl = NetdevFamily()
+ q1 = netdevnl.queue_get(
+ {"ifindex": nsim.ifindex, "id": 1, "type": "rx"}
+ )
+ q2 = netdevnl.queue_get(
+ {"ifindex": nsim.ifindex, "id": 2, "type": "rx"}
+ )
+ ksft_in("lease", q1)
+ ksft_in("lease", q2)
+
+
+def test_resize_phys_up(netns) -> None:
+ nsimdev = NetdevSimDev(port_count=1, queue_count=3)
+ defer(nsimdev.remove)
+ nsim = nsimdev.nsims[0]
+ ip(f"link set dev {nsim.ifname} up")
+
+ nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
+ defer(cmd, f"ip link del dev {nk_host}", fail=False)
+
+ ip(f"link set dev {nk_guest} netns {netns.name}")
+ ip(f"link set dev {nk_host} up")
+ ip(f"link set dev {nk_guest} up", ns=netns)
+
+ # Shrink nsim first so we have room to grow
+ ethnl = EthtoolFamily()
+ ethnl.channels_set(
+ {"header": {"dev-index": nsim.ifindex}, "combined-count": 2}
+ )
+
+ with NetNSEnter(str(netns)), NetdevFamily() as netdevnl_ns:
+ netdevnl_ns.queue_create(
+ {
+ "ifindex": nk_guest_idx,
+ "type": "rx",
+ "lease": {
+ "ifindex": nsim.ifindex,
+ "queue": {"id": 1, "type": "rx"},
+ "netns-id": 0,
+ },
+ }
+ )
+
+ # Grow channels — should succeed since leased queue is not removed
+ ethnl.channels_set(
+ {"header": {"dev-index": nsim.ifindex}, "combined-count": 3}
+ )
+
+ netdevnl = NetdevFamily()
+ queue_info = netdevnl.queue_get(
+ {"ifindex": nsim.ifindex, "id": 1, "type": "rx"}
+ )
+ ksft_in("lease", queue_info)
+
+ # New queue 2 should exist without a lease
+ queue_info = netdevnl.queue_get(
+ {"ifindex": nsim.ifindex, "id": 2, "type": "rx"}
+ )
+ ksft_not_in("lease", queue_info)
+
+
+def test_multi_ns_lease(netns) -> None:
+ nsimdev = NetdevSimDev(port_count=1, queue_count=3)
+ defer(nsimdev.remove)
+ nsim = nsimdev.nsims[0]
+ ip(f"link set dev {nsim.ifname} up")
+
+ ns_b = NetNS()
+ defer(ns_b.__del__)
+ ip("netns set init 0", ns=ns_b)
+ ip("link set lo up", ns=ns_b)
+
+ # First netkit pair, guest in netns
+ nk_host_a, _, nk_guest_a, nk_guest_a_idx = create_netkit(rxqueues=2)
+ defer(cmd, f"ip link del dev {nk_host_a}", fail=False)
+ ip(f"link set dev {nk_guest_a} netns {netns.name}")
+ ip(f"link set dev {nk_host_a} up")
+ ip(f"link set dev {nk_guest_a} up", ns=netns)
+
+ # Second netkit pair, guest in ns_b
+ nk_host_b, _, nk_guest_b, nk_guest_b_idx = create_netkit(rxqueues=2)
+ defer(cmd, f"ip link del dev {nk_host_b}", fail=False)
+ ip(f"link set dev {nk_guest_b} netns {ns_b.name}")
+ ip(f"link set dev {nk_host_b} up")
+ ip(f"link set dev {nk_guest_b} up", ns=ns_b)
+
+ # Lease from netns
+ with NetNSEnter(str(netns)), NetdevFamily() as netdevnl_ns:
+ result = netdevnl_ns.queue_create(
+ {
+ "ifindex": nk_guest_a_idx,
+ "type": "rx",
+ "lease": {
+ "ifindex": nsim.ifindex,
+ "queue": {"id": 1, "type": "rx"},
+ "netns-id": 0,
+ },
+ }
+ )
+ ksft_eq(result["id"], 1)
+
+ # Lease from ns_b (different namespace, same physical device)
+ with NetNSEnter(str(ns_b)), NetdevFamily() as netdevnl_ns:
+ result = netdevnl_ns.queue_create(
+ {
+ "ifindex": nk_guest_b_idx,
+ "type": "rx",
+ "lease": {
+ "ifindex": nsim.ifindex,
+ "queue": {"id": 2, "type": "rx"},
+ "netns-id": 0,
+ },
+ }
+ )
+ ksft_eq(result["id"], 1)
+
+ # Verify both leases from the physical side
+ netdevnl = NetdevFamily()
+ q1 = netdevnl.queue_get(
+ {"ifindex": nsim.ifindex, "id": 1, "type": "rx"}
+ )
+ q2 = netdevnl.queue_get(
+ {"ifindex": nsim.ifindex, "id": 2, "type": "rx"}
+ )
+ ksft_in("lease", q1)
+ ksft_in("lease", q2)
+ ksft_eq(q1["lease"]["ifindex"], nk_guest_a_idx)
+ ksft_eq(q2["lease"]["ifindex"], nk_guest_b_idx)
+
+
+def test_multi_ns_delete_one(netns) -> None:
+ nsimdev = NetdevSimDev(port_count=1, queue_count=3)
+ defer(nsimdev.remove)
+ nsim = nsimdev.nsims[0]
+ ip(f"link set dev {nsim.ifname} up")
+
+ ns_b = NetNS()
+ ip("netns set init 0", ns=ns_b)
+ ip("link set lo up", ns=ns_b)
+
+ # First netkit pair, guest in netns (ns_a)
+ nk_host_a, _, nk_guest_a, nk_guest_a_idx = create_netkit(rxqueues=2)
+ defer(cmd, f"ip link del dev {nk_host_a}", fail=False)
+ ip(f"link set dev {nk_guest_a} netns {netns.name}")
+ ip(f"link set dev {nk_host_a} up")
+ ip(f"link set dev {nk_guest_a} up", ns=netns)
+
+ # Second netkit pair, guest in ns_b
+ nk_host_b, _, nk_guest_b, nk_guest_b_idx = create_netkit(rxqueues=2)
+ defer(cmd, f"ip link del dev {nk_host_b}", fail=False)
+
+ ip(f"link set dev {nk_guest_b} netns {ns_b.name}")
+ ip(f"link set dev {nk_host_b} up")
+ ip(f"link set dev {nk_guest_b} up", ns=ns_b)
+
+ with NetNSEnter(str(netns)), NetdevFamily() as netdevnl_ns:
+ netdevnl_ns.queue_create(
+ {
+ "ifindex": nk_guest_a_idx,
+ "type": "rx",
+ "lease": {
+ "ifindex": nsim.ifindex,
+ "queue": {"id": 1, "type": "rx"},
+ "netns-id": 0,
+ },
+ }
+ )
+
+ with NetNSEnter(str(ns_b)), NetdevFamily() as netdevnl_ns:
+ netdevnl_ns.queue_create(
+ {
+ "ifindex": nk_guest_b_idx,
+ "type": "rx",
+ "lease": {
+ "ifindex": nsim.ifindex,
+ "queue": {"id": 2, "type": "rx"},
+ "netns-id": 0,
+ },
+ }
+ )
+
+ netdevnl = NetdevFamily()
+ q1 = netdevnl.queue_get(
+ {"ifindex": nsim.ifindex, "id": 1, "type": "rx"}
+ )
+ q2 = netdevnl.queue_get(
+ {"ifindex": nsim.ifindex, "id": 2, "type": "rx"}
+ )
+ ksft_in("lease", q1)
+ ksft_in("lease", q2)
+
+ # Delete ns_b — destroys nk_guest_b, triggers unlease of queue 2
+ del ns_b
+ wait_until(lambda: "lease" not in netdevnl.queue_get(
+ {"ifindex": nsim.ifindex, "id": 2, "type": "rx"}))
+
+ # ns_a's lease on queue 1 must survive
+ q1 = netdevnl.queue_get(
+ {"ifindex": nsim.ifindex, "id": 1, "type": "rx"}
+ )
+ ksft_in("lease", q1)
+ ksft_eq(q1["lease"]["ifindex"], nk_guest_a_idx)
+
+ # ns_b's lease on queue 2 must be gone
+ q2 = netdevnl.queue_get(
+ {"ifindex": nsim.ifindex, "id": 2, "type": "rx"}
+ )
+ ksft_not_in("lease", q2)
+
+ # nk_host_b should be gone too (phys removal cascades to netkit pair)
+ ret = cmd(f"ip link show dev {nk_host_b}", fail=False)
+ ksft_ne(ret.ret, 0)
+
+
+def test_move_phys_netns(netns) -> None:
+ nsimdev = NetdevSimDev(port_count=1, queue_count=2)
+ defer(nsimdev.remove)
+ nsim = nsimdev.nsims[0]
+ ip(f"link set dev {nsim.ifname} up")
+
+ nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
+ defer(cmd, f"ip link del dev {nk_host}", fail=False)
+
+ ip(f"link set dev {nk_guest} netns {netns.name}")
+ ip(f"link set dev {nk_host} up")
+ ip(f"link set dev {nk_guest} up", ns=netns)
+
+ src_queue = 1
+ with NetNSEnter(str(netns)), NetdevFamily() as netdevnl_ns:
+ nk_queue_id = netdevnl_ns.queue_create(
+ {
+ "ifindex": nk_guest_idx,
+ "type": "rx",
+ "lease": {
+ "ifindex": nsim.ifindex,
+ "queue": {"id": src_queue, "type": "rx"},
+ "netns-id": 0,
+ },
+ }
+ )["id"]
+
+ netdevnl = NetdevFamily()
+ queue_info = netdevnl.queue_get(
+ {"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
+ )
+ ksft_in("lease", queue_info)
+
+ # Move the physical device to a new namespace. Move it back to init_net
+ # on cleanup before the other defers fire (new_ns deletion, nsimdev.remove)
+ # so nsim lives in a stable namespace when they run.
+ new_ns = NetNS()
+ defer(new_ns.__del__)
+ ip(f"link set dev {nsim.ifname} netns {new_ns.name}")
+ defer(ip, f"link set dev {nsim.ifname} netns init", ns=new_ns)
+
+ # Physical device is now in new_ns — find its ifindex there
+ all_links = ip("-d link show", json=True, ns=new_ns)
+ nsim_in_new = [lnk for lnk in all_links if lnk.get("ifname") == nsim.ifname]
+ new_ifindex = nsim_in_new[0]["ifindex"]
+
+ # Moving a device across netns brings it admin-down; bring it back up so
+ # netdevsim re-creates the NAPI (netdev-genl queue_get needs it).
+ ip(f"link set dev {nsim.ifname} up", ns=new_ns)
+
+ # Verify lease survived the namespace move
+ with NetNSEnter(str(new_ns)), NetdevFamily() as netdevnl_ns:
+ queue_info = netdevnl_ns.queue_get(
+ {"ifindex": new_ifindex, "id": src_queue, "type": "rx"}
+ )
+ ksft_in("lease", queue_info)
+ ksft_eq(queue_info["lease"]["queue"]["id"], nk_queue_id)
+
+
def main() -> None:
netns = NetNS()
cmd("ip netns attach init 1")
@@ -1156,6 +2079,24 @@ def main() -> None:
test_lease_queue_zero,
test_release_and_reuse,
test_veth_queue_create,
+ test_two_netkits_same_queue,
+ test_l3_mode_lease,
+ test_single_double_lease,
+ test_single_different_lessors,
+ test_cross_ns_netns_id,
+ test_delete_guest_netns,
+ test_move_guest_netns,
+ test_resize_phys_no_reduction,
+ test_delete_one_netkit_of_two,
+ test_bind_rx_leased_phys_queue,
+ test_resize_phys_shrink_past_leased,
+ test_resize_virt_not_supported,
+ test_lease_devices_down,
+ test_lease_capacity_exhaustion,
+ test_resize_phys_up,
+ test_multi_ns_lease,
+ test_multi_ns_delete_one,
+ test_move_phys_netns,
],
args=(netns,),
)
--
2.43.0
^ permalink raw reply related
* Re: [PATCH RFC bpf-next 1/8] kasan: expose generic kasan helpers
From: Andrey Konovalov @ 2026-04-13 22:19 UTC (permalink / raw)
To: Alexis Lothoré (eBPF Foundation)
Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Martin KaFai Lau, Eduard Zingerman, Kumar Kartikeya Dwivedi,
Song Liu, Yonghong Song, Jiri Olsa, John Fastabend,
David S. Miller, David Ahern, Thomas Gleixner, Ingo Molnar,
Borislav Petkov, Dave Hansen, x86, H. Peter Anvin, Shuah Khan,
Maxime Coquelin, Alexandre Torgue, Andrey Ryabinin,
Alexander Potapenko, Dmitry Vyukov, Vincenzo Frascino,
Andrew Morton, ebpf, Bastien Curutchet, Thomas Petazzoni,
Xu Kuohai, bpf, linux-kernel, netdev, linux-kselftest,
linux-stm32, linux-arm-kernel, kasan-dev, linux-mm
In-Reply-To: <20260413-kasan-v1-1-1a5831230821@bootlin.com>
On Mon, Apr 13, 2026 at 8:29 PM Alexis Lothoré (eBPF Foundation)
<alexis.lothore@bootlin.com> wrote:
>
> In order to prepare KASAN helpers to be called from the eBPF subsystem
> (to add KASAN instrumentation at runtime when JITing eBPF programs),
> expose the __asan_{load,store}X functions in linux/kasan.h
>
> Signed-off-by: Alexis Lothoré (eBPF Foundation) <alexis.lothore@bootlin.com>
> ---
> include/linux/kasan.h | 13 +++++++++++++
> mm/kasan/kasan.h | 10 ----------
> 2 files changed, 13 insertions(+), 10 deletions(-)
>
> diff --git a/include/linux/kasan.h b/include/linux/kasan.h
> index 338a1921a50a..6f580d4a39e4 100644
> --- a/include/linux/kasan.h
> +++ b/include/linux/kasan.h
> @@ -710,4 +710,17 @@ void kasan_non_canonical_hook(unsigned long addr);
> static inline void kasan_non_canonical_hook(unsigned long addr) { }
> #endif /* CONFIG_KASAN_GENERIC || CONFIG_KASAN_SW_TAGS */
>
> +#ifdef CONFIG_KASAN_GENERIC
> +void __asan_load1(void *p);
> +void __asan_store1(void *p);
> +void __asan_load2(void *p);
> +void __asan_store2(void *p);
> +void __asan_load4(void *p);
> +void __asan_store4(void *p);
> +void __asan_load8(void *p);
> +void __asan_store8(void *p);
> +void __asan_load16(void *p);
> +void __asan_store16(void *p);
> +#endif /* CONFIG_KASAN_GENERIC */
This looks ugly, let's not do this unless it's really required.
You can just use kasan_check_read/write() instead - these are public
wrappers around the same shadow memory checking functions. And they
also work with the SW_TAGS mode, in case the BPF would want to use
that mode at some point. (For HW_TAGS, we only have kasan_check_byte()
that checks a single byte, but it can be extended in the future if
required to be used by BPF.)
> +
> #endif /* LINUX_KASAN_H */
> diff --git a/mm/kasan/kasan.h b/mm/kasan/kasan.h
> index fc9169a54766..3bfce8eb3135 100644
> --- a/mm/kasan/kasan.h
> +++ b/mm/kasan/kasan.h
> @@ -594,16 +594,6 @@ void __asan_handle_no_return(void);
> void __asan_alloca_poison(void *, ssize_t size);
> void __asan_allocas_unpoison(void *stack_top, ssize_t stack_bottom);
>
> -void __asan_load1(void *);
> -void __asan_store1(void *);
> -void __asan_load2(void *);
> -void __asan_store2(void *);
> -void __asan_load4(void *);
> -void __asan_store4(void *);
> -void __asan_load8(void *);
> -void __asan_store8(void *);
> -void __asan_load16(void *);
> -void __asan_store16(void *);
> void __asan_loadN(void *, ssize_t size);
> void __asan_storeN(void *, ssize_t size);
>
>
> --
> 2.53.0
>
^ permalink raw reply
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