* Re: [PATCH 0/4] net: bridge: mcast: add multicast exponential field encoding
From: Nikolay Aleksandrov @ 2026-03-27 11:31 UTC (permalink / raw)
To: Ujjal Roy, David S . Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, Ido Schimmel, David Ahern
Cc: Ujjal Roy, bridge, netdev, linux-kernel
In-Reply-To: <0e8a01b0-9b83-405f-a0ad-7b335135962f@blackwall.org>
On 27/03/2026 08:41, Nikolay Aleksandrov wrote:
> On 26/03/2026 17:07, Ujjal Roy wrote:
>> Description:
>> This series addresses a mismatch in how multicast query
>> intervals and response codes are handled across IPv4 (IGMPv3)
>> and IPv6 (MLDv2). While decoding logic currently exists,
>> the corresponding encoding logic is missing during query
>> packet generation. This leads to incorrect intervals being
>> transmitted when values exceed their linear thresholds.
>>
>> The patches introduce a unified floating-point encoding
>> approach based on RFC3376 and RFC3810, ensuring that large
>> intervals are correctly represented in QQIC and MRC fields
>> using the exponent-mantissa format.
>>
>> Key Changes:
>> * ipv4: igmp: get rid of IGMPV3_{QQIC,MRC} and simplify calculation
>> Removes legacy macros in favor of a cleaner, unified
>> calculation for retrieving intervals from encoded fields,
>> improving code maintainability.
>>
>> * ipv6: mld: rename mldv2_mrc() and add mldv2_qqi()
>> Standardizes MLDv2 terminology by renaming mldv2_mrc()
>> to mldv2_mrd() (Maximum Response Delay) and introducing
>> a new API mldv2_qqi for QQI calculation, improving code
>> readability.
>>
>> * ipv4: igmp: encode multicast exponential fields
>> Introduces the logic to dynamically calculate the exponent
>> and mantissa using bit-scan (fls). This ensures QQIC and
>> MRC fields (8-bit) are properly encoded when transmitting
>> query packets with intervals that exceed their respective
>> linear threshold value of 128 (for QQI/MRT).
>>
>> * ipv6: mld: encode multicast exponential fields
>> Applies similar encoding logic for MLDv2. This ensures
>> QQIC (8-bit) and MRC (16-bit) fields are properly encoded
>> when transmitting query packets with intervals that exceed
>> their respective linear thresholds (128 for QQI; 32768
>> for MRD).
>>
>> Impact:
>> These changes ensure that multicast queriers and listeners
>> stay synchronized on timing intervals, preventing protocol
>> timeouts or premature group membership expiration caused
>> by incorrectly formatted packet headers.
>>
>
> Can you add selftests which cover these cases?
>
>
Forgot to mention - for improvements and new features please target net-next.
Cheers,
Nik
^ permalink raw reply
* Re: [PATCH net-next 1/4] dt-bindings: net: dsa: add MT7628 ESW
From: Daniel Golle @ 2026-03-27 11:32 UTC (permalink / raw)
To: Joris Vaisvila
Cc: netdev, horms, pabeni, kuba, edumazet, davem, olteanv,
Andrew Lunn, devicetree, Rob Herring, Krzysztof Kozlowski,
Conor Dooley
In-Reply-To: <acYZOEksxcc-uHcT@archlinux>
On Fri, Mar 27, 2026 at 08:00:51AM +0200, Joris Vaisvila wrote:
> Hi Daniel, thanks for the feedback
>
> On Thu, Mar 26, 2026 at 11:11:23PM +0000, Daniel Golle wrote:
> > > [...]
> > > + port@6 {
> > > + reg = <6>;
> > > + ethernet = <ðernet>;
> > > + phy-mode = "rgmii";
> >
> > Is this actually RGMII internally? Or some unknown internal way to
> > wire the switch CPU port to the CPU MAC? In this case, "internal"
> > should be used here as well.
>
> I don't know how to find this out for sure.
>
> In the MT7628 doc (https://vonger.cn/upload/MT7628_Full.pdf) port 6 is
> refered to as RGMII port 1 (RGMII port 0 being the non-existent port 5),
> but there are no clock registers to be seen.
> In RT3050 docs there are RGMII clock registers for port 5, but nothing
> for port 6, so maybe the CPU port is really using some mystery internal
> connection and only uses "RGMII" as a way to say it's a Gigabit port?
>
> On the hardware I'm testing on, it works fine with the port set to
> "internal" or "rgmii". Would it make more sense to set "internal" then?
"internal" then. It's a single-die SoC, the switch sharing the same
memory space, clocking domain, ... with all the rest of the SoC makes
it very unlikely that RGMII would be used as an on-die connection
type. (unlike eg. MT7621 or MT7623A which are using multiple dies in
the same package, and actually RGMII or TRGMII to connect the
MDIO-managed switch part to the main SoC, see "MCM" / "multi-chip
module" in the mt7530 driver...)
^ permalink raw reply
* Re: [PATCH net] bridge: mrp: reject zero test interval to avoid OOM panic
From: Simon Horman @ 2026-03-27 11:34 UTC (permalink / raw)
To: Xiang Mei
Cc: netdev, bridge, razor, idosch, davem, edumazet, pabeni, bestswngs
In-Reply-To: <20260326032438.3307549-1-xmei5@asu.edu>
On Wed, Mar 25, 2026 at 08:24:38PM -0700, Xiang Mei wrote:
> br_mrp_start_test() and br_mrp_start_in_test() accept the user-supplied
> interval value from netlink without validation. When interval is 0,
> usecs_to_jiffies(0) yields 0, causing the delayed work
> (br_mrp_test_work_expired / br_mrp_in_test_work_expired) to reschedule
> itself with zero delay. This creates a tight loop on system_percpu_wq
> that allocates and transmits MRP test frames at maximum rate, exhausting
> all system memory and causing a kernel panic via OOM deadlock.
I would suspect the primary outcome of this problem is high CPU consumption
rather than memory exhaustion. Is there a reason to expect that
the transmitted fames can't be consumed as fast as they are created?
>
> The same zero-interval issue applies to br_mrp_start_in_test_parse()
> for interconnect test frames.
>
> Use NLA_POLICY_MIN(NLA_U32, 1) in the nla_policy tables for both
> IFLA_BRIDGE_MRP_START_TEST_INTERVAL and
> IFLA_BRIDGE_MRP_START_IN_TEST_INTERVAL, so zero is rejected at the
> netlink attribute parsing layer before the value ever reaches the
> workqueue scheduling code. This is consistent with how other bridge
> subsystems (br_fdb, br_mst) enforce range constraints on netlink
> attributes.
>
> Fixes: 7ab1748e4ce6 ("bridge: mrp: Extend MRP netlink interface for configuring MRP interconnect")
I think you also want
Fixes: 20f6a05ef635 ("bridge: mrp: Rework the MRP netlink interface")
As highlighted by AI review.
> Reported-by: Weiming Shi <bestswngs@gmail.com>
> Signed-off-by: Xiang Mei <xmei5@asu.edu>
...
^ permalink raw reply
* Re: [PATCHv2] atm: nicstar: simplify allocation
From: Simon Horman @ 2026-03-27 11:38 UTC (permalink / raw)
To: Rosen Penev
Cc: linux-atm-general, Chas Williams, Kees Cook, Gustavo A. R. Silva,
open list:ATM, open list,
open list:KERNEL HARDENING (not covered by other areas):Keyword:b__counted_by(_le|_be)?b
In-Reply-To: <20260326053539.336831-1-rosenp@gmail.com>
On Wed, Mar 25, 2026 at 10:35:39PM -0700, Rosen Penev wrote:
> Use a flexible array member with kzalloc_flex to combine allocations
> into one.
>
> Add __counted_by for extra runtime analysis. Move counting variable
> assignment to right after allocation as required by __counted_by.
>
> Signed-off-by: Rosen Penev <rosenp@gmail.com>
> ---
> v2: use kzalloc_flex
> drivers/atm/nicstar.c | 17 +++++------------
> drivers/atm/nicstar.h | 4 ++--
> 2 files changed, 7 insertions(+), 14 deletions(-)
>
> diff --git a/drivers/atm/nicstar.c b/drivers/atm/nicstar.c
> index 24e51343df15..b01c6cfdcc87 100644
> --- a/drivers/atm/nicstar.c
> +++ b/drivers/atm/nicstar.c
> @@ -867,23 +867,17 @@ static scq_info *get_scq(ns_dev *card, int size, u32 scd)
> if (size != VBR_SCQSIZE && size != CBR_SCQSIZE)
> return NULL;
>
> - scq = kmalloc_obj(*scq);
> + scq = kzalloc_flex(*scq, skb, size / NS_SCQE_SIZE);
> if (!scq)
> return NULL;
> - scq->org = dma_alloc_coherent(&card->pcidev->dev,
> - 2 * size, &scq->dma, GFP_KERNEL);
> +
> + scq->num_entries = size / NS_SCQE_SIZE;
> +
> + scq->org = dma_alloc_coherent(&card->pcidev->dev, 2 * size, &scq->dma, GFP_KERNEL);
Networking still prefers code that is 80 columns wide or less:
scq->org = dma_alloc_coherent(&card->pcidev->dev,
2 * size, &scq->dma, GFP_KERNEL);
But maybe just leave this line as it was?
...
> diff --git a/drivers/atm/nicstar.h b/drivers/atm/nicstar.h
> index 1b7f1dfc1735..ba45be53d40e 100644
> --- a/drivers/atm/nicstar.h
> +++ b/drivers/atm/nicstar.h
> @@ -667,14 +667,14 @@ typedef struct scq_info {
> ns_scqe *next;
> volatile ns_scqe *tail; /* Not related to the nicstar register */
> unsigned num_entries;
> - struct sk_buff **skb; /* Pointer to an array of pointers
> - to the sk_buffs used for tx */
> u32 scd; /* SRAM address of the corresponding
> SCD */
> int tbd_count; /* Only meaningful on variable rate */
> wait_queue_head_t scqfull_waitq;
> volatile char full; /* SCQ full indicator */
> spinlock_t lock; /* SCQ spinlock */
> + struct sk_buff *skb[] __counted_by(num_entries); /* Pointer to an array of pointers
> + to the sk_buffs used for tx */
Likewise, 80 columns wide here too.
> } scq_info;
>
> typedef struct rsq_info {
--
pw-bot: cr
^ permalink raw reply
* Re: [PATCH v6] riscv: dts: spacemit: Add ethernet device for K3
From: Yixun Lan @ 2026-03-27 11:38 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Richard Cochran,
Inochi Amaoto
Cc: Yixun Lan, devicetree, linux-riscv, spacemit, linux-kernel,
netdev, Longbin Li
In-Reply-To: <20260326014617.1011732-1-inochiama@gmail.com>
On Thu, 26 Mar 2026 09:46:17 +0800, Inochi Amaoto wrote:
> Add all ethernet device nodes for K3 SoC.
>
>
Applied, thanks!
[1/1] riscv: dts: spacemit: Add ethernet device for K3
https://github.com/spacemit-com/linux/commit/74657a376960252e248089e518cfaaf813906989
Best regards,
--
Yixun Lan <dlan@kernel.org>
^ permalink raw reply
* Re: [PATCH v2 2/4] iwlegacy: 3945-mac: Fixup allocation failure log
From: Stanislaw Gruszka @ 2026-03-27 11:45 UTC (permalink / raw)
To: Brendan Jackman
Cc: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Alexander Potapenko, Marco Elver, Dmitry Vyukov,
Andrew Morton, Allison Henderson, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, dri-devel,
linux-kernel, linux-wireless, kasan-dev, linux-mm, netdev,
linux-rdma, rds-devel
In-Reply-To: <20260326-gfp64-v2-2-d916021cecdf@google.com>
Hi,
On Thu, Mar 26, 2026 at 12:31:58PM +0000, Brendan Jackman wrote:
> Fix 2 issues spotted by AI[0]:
>
> 1. Missing space after the full stop.
>
> 2. Wrong GFP flags are printed.
We should also initialize gfp_mask = priority inside the loop.
But this can be done as separate patch.
> And also switch to %pGg for the GFP flags. This produces nice readable
> output and decouples the format string from the size of gfp_t.
>
> [0] https://sashiko.dev/#/patchset/20260319-gfp64-v1-0-2c73b8d42b7f%40google.com
>
> Signed-off-by: Brendan Jackman <jackmanb@google.com>
Acked-by: Stanislaw Gruszka <stf_xl@wp.pl>
> ---
> drivers/net/wireless/intel/iwlegacy/3945-mac.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/net/wireless/intel/iwlegacy/3945-mac.c b/drivers/net/wireless/intel/iwlegacy/3945-mac.c
> index c148654aa9533..88b31e0b9568c 100644
> --- a/drivers/net/wireless/intel/iwlegacy/3945-mac.c
> +++ b/drivers/net/wireless/intel/iwlegacy/3945-mac.c
> @@ -1002,9 +1002,9 @@ il3945_rx_allocate(struct il_priv *il, gfp_t priority)
> D_INFO("Failed to allocate SKB buffer.\n");
> if (rxq->free_count <= RX_LOW_WATERMARK &&
> net_ratelimit())
> - IL_ERR("Failed to allocate SKB buffer with %0x."
> + IL_ERR("Failed to allocate SKB buffer with %pGg. "
> "Only %u free buffers remaining.\n",
> - priority, rxq->free_count);
> + &gfp_mask, rxq->free_count);
> /* We don't reschedule replenish work here -- we will
> * call the restock method and if it still needs
> * more buffers it will schedule replenish */
>
> --
> 2.51.2
>
^ permalink raw reply
* RE: [Intel-wired-lan] [PATCH v4 net-next 8/8] ice: add TX reference clock (tx_clk) control for E825 devices
From: Loktionov, Aleksandr @ 2026-03-27 11:46 UTC (permalink / raw)
To: Nitka, Grzegorz, netdev@vger.kernel.org
Cc: Vecera, Ivan, vadim.fedorenko@linux.dev, kuba@kernel.org,
jiri@resnulli.us, edumazet@google.com, Kitszel, Przemyslaw,
richardcochran@gmail.com, donald.hunter@gmail.com,
linux-kernel@vger.kernel.org, Kubalewski, Arkadiusz,
andrew+netdev@lunn.ch, intel-wired-lan@lists.osuosl.org,
horms@kernel.org, Prathosh.Satish@microchip.com,
Nguyen, Anthony L, pabeni@redhat.com, davem@davemloft.net
In-Reply-To: <20260326162832.3135857-9-grzegorz.nitka@intel.com>
> -----Original Message-----
> From: Intel-wired-lan <intel-wired-lan-bounces@osuosl.org> On Behalf
> Of Grzegorz Nitka
> Sent: Thursday, March 26, 2026 5:29 PM
> To: netdev@vger.kernel.org
> Cc: Vecera, Ivan <ivecera@redhat.com>; vadim.fedorenko@linux.dev;
> kuba@kernel.org; jiri@resnulli.us; edumazet@google.com; Kitszel,
> Przemyslaw <przemyslaw.kitszel@intel.com>; richardcochran@gmail.com;
> donald.hunter@gmail.com; linux-kernel@vger.kernel.org; Kubalewski,
> Arkadiusz <arkadiusz.kubalewski@intel.com>; andrew+netdev@lunn.ch;
> intel-wired-lan@lists.osuosl.org; horms@kernel.org;
> Prathosh.Satish@microchip.com; Nguyen, Anthony L
> <anthony.l.nguyen@intel.com>; pabeni@redhat.com; davem@davemloft.net
> Subject: [Intel-wired-lan] [PATCH v4 net-next 8/8] ice: add TX
> reference clock (tx_clk) control for E825 devices
>
> Add full support for selecting and controlling the TX SERDES
> reference clock on E825C hardware. E825C devicede supports selecting
> among multiple SERDES transmit reference clock sources (ENET, SyncE,
> EREF0), but imposes several routing constraints: on some paths a
> reference must be enabled on both PHY complexes, and ports sharing a
> PHY must coordinate usage so that a reference is not disabled while
> still in active use. Until now the driver did not expose this domain
> through the DPLL API, nor did it provide a coherent control layer
> for enabling, switching, or tracking TX reference clocks.
>
> This patch implements full TX reference clock management for E825
> devices. Compared to previous iterations, the logic is now separated
> into a dedicated module (ice_txclk.c) which encapsulates all clock-
> selection rules, cross‑PHY dependencies, and the bookkeeping needed
> to ensure safe transitions. This allows the DPLL layer and the PTP
> code to remain focused on their respective roles.
>
> Key additions:
>
> * A new txclk control module (`ice_txclk.c`) implementing:
> - software usage tracking for each reference clock per PHY,
> - peer‑PHY enable rules (SyncE required on both PHYs when used
> on
> PHY0, EREF0 required on both when used on PHY1),
> - safe disabling of unused reference clocks after switching,
> - a single, driver‑internal entry point for clock changes.
>
> * Integration with the DPLL pin ops:
> - pin‑set now calls into `ice_txclk_set_clk()` to request a
> hardware switch,
> - pin‑get reports the current SERDES reference by reading back
> the
> active selector (`ice_get_serdes_ref_sel_e825c()`).
>
> * Wiring the requested reference clock into Auto‑Negotiation
> restart
> through the already‑extended `ice_aq_set_link_restart_an()`.
>
> * After each link-up the driver verifies the effective hardware
> state
> (`ice_txclk_verify()`) and updates its per‑PHY usage bitmaps,
> correcting the requested/active state if the FW or AN flow
> applied a
> different reference.
>
> * PTP PF initialization now seeds the ENET reference clock as
> enabled
> by default for its port.
>
> All reference clock transitions are serialized through the DPLL
> lock, and usage information is shared across all PFs belonging to
> the same E825C controller PF. This ensures that concurrent changes
> are coordinated and that shared PHYs never see an unexpected
> disable.
>
> With this patch, E825 devices gain full userspace‑driven TXC
> reference clock selection via the DPLL subsystem, enabling complete
> SyncE support, precise multi‑clock setups, and predictable clock
> routing behavior.
>
> Reviewed-by: Arkadiusz Kubalewski <arkadiusz.kubalewski@intel.com>
> Signed-off-by: Grzegorz Nitka <grzegorz.nitka@intel.com>
> ---
> drivers/net/ethernet/intel/ice/Makefile | 2 +-
> drivers/net/ethernet/intel/ice/ice.h | 12 +
> drivers/net/ethernet/intel/ice/ice_dpll.c | 53 +++-
> drivers/net/ethernet/intel/ice/ice_ptp.c | 27 ++-
> drivers/net/ethernet/intel/ice/ice_ptp.h | 7 +
> drivers/net/ethernet/intel/ice/ice_ptp_hw.c | 37 +++
> drivers/net/ethernet/intel/ice/ice_ptp_hw.h | 27 +++
> drivers/net/ethernet/intel/ice/ice_txclk.c | 256
> ++++++++++++++++++++ drivers/net/ethernet/intel/ice/ice_txclk.h |
> 41 ++++
> 9 files changed, 445 insertions(+), 17 deletions(-) create mode
> 100644 drivers/net/ethernet/intel/ice/ice_txclk.c
> create mode 100644 drivers/net/ethernet/intel/ice/ice_txclk.h
>
> diff --git a/drivers/net/ethernet/intel/ice/Makefile
> b/drivers/net/ethernet/intel/ice/Makefile
> index 38db476ab2ec..95fd0c49800f 100644
> --- a/drivers/net/ethernet/intel/ice/Makefile
> +++ b/drivers/net/ethernet/intel/ice/Makefile
> @@ -54,7 +54,7 @@ ice-$(CONFIG_PCI_IOV) += \
> ice_vf_mbx.o \
> ice_vf_vsi_vlan_ops.o \
> ice_vf_lib.o
> -ice-$(CONFIG_PTP_1588_CLOCK) += ice_ptp.o ice_ptp_hw.o ice_dpll.o
> ice_tspll.o ice_cpi.o
...
> static const struct dpll_pin_ops ice_dpll_rclk_ops = { diff --git
> a/drivers/net/ethernet/intel/ice/ice_ptp.c
> b/drivers/net/ethernet/intel/ice/ice_ptp.c
> index 094e96219f45..a75a1380097b 100644
> --- a/drivers/net/ethernet/intel/ice/ice_ptp.c
> +++ b/drivers/net/ethernet/intel/ice/ice_ptp.c
> @@ -4,6 +4,7 @@
> #include "ice.h"
> #include "ice_lib.h"
> #include "ice_trace.h"
> +#include "ice_txclk.h"
>
> static const char ice_pin_names[][64] = {
> "SDP0",
> @@ -54,11 +55,6 @@ static const struct ice_ptp_pin_desc
> ice_pin_desc_dpll[] = {
> { SDP3, { 3, -1 }, { 0, 0 }},
> };
>
> -static struct ice_pf *ice_get_ctrl_pf(struct ice_pf *pf) -{
> - return !pf->adapter ? NULL : pf->adapter->ctrl_pf;
> -}
> -
> static struct ice_ptp *ice_get_ctrl_ptp(struct ice_pf *pf) {
> struct ice_pf *ctrl_pf = ice_get_ctrl_pf(pf); @@ -1325,6
> +1321,10 @@ void ice_ptp_link_change(struct ice_pf *pf, bool linkup)
> return;
> }
> }
> +
> + if (linkup)
> + ice_txclk_verify(pf);
msleep() under mutex smels badly... /* ice_cpi_wait_req0_ack0() and ice_cpi_wait_ack() */
pf->dplls.lock can be held ~2seconds blocking ice_dpll_periodic_work().
Can CPI handshake happen outside the lock?
> +
> mutex_unlock(&pf->dplls.lock);
> }
>
...
> */
> --
> 2.39.3
^ permalink raw reply
* Re: [PATCH net] bridge: mrp: reject zero test interval to avoid OOM panic
From: Nikolay Aleksandrov @ 2026-03-27 11:46 UTC (permalink / raw)
To: Simon Horman, Xiang Mei
Cc: netdev, bridge, idosch, davem, edumazet, pabeni, bestswngs
In-Reply-To: <20260327113412.GD567789@horms.kernel.org>
On 27/03/2026 13:34, Simon Horman wrote:
> On Wed, Mar 25, 2026 at 08:24:38PM -0700, Xiang Mei wrote:
>> br_mrp_start_test() and br_mrp_start_in_test() accept the user-supplied
>> interval value from netlink without validation. When interval is 0,
>> usecs_to_jiffies(0) yields 0, causing the delayed work
>> (br_mrp_test_work_expired / br_mrp_in_test_work_expired) to reschedule
>> itself with zero delay. This creates a tight loop on system_percpu_wq
>> that allocates and transmits MRP test frames at maximum rate, exhausting
>> all system memory and causing a kernel panic via OOM deadlock.
>
> I would suspect the primary outcome of this problem is high CPU consumption
> rather than memory exhaustion. Is there a reason to expect that
> the transmitted fames can't be consumed as fast as they are created?
>
+1
More so with CAP_NET_ADMIN you can cause all sorts of OOM and high-cpu usage
conditions. This is a configuration error and OOM doesn't lead to panic unless
instructed to. I don't think this is worth changing at all.
>>
>> The same zero-interval issue applies to br_mrp_start_in_test_parse()
>> for interconnect test frames.
>>
>> Use NLA_POLICY_MIN(NLA_U32, 1) in the nla_policy tables for both
>> IFLA_BRIDGE_MRP_START_TEST_INTERVAL and
>> IFLA_BRIDGE_MRP_START_IN_TEST_INTERVAL, so zero is rejected at the
>> netlink attribute parsing layer before the value ever reaches the
>> workqueue scheduling code. This is consistent with how other bridge
>> subsystems (br_fdb, br_mst) enforce range constraints on netlink
>> attributes.
>>
>> Fixes: 7ab1748e4ce6 ("bridge: mrp: Extend MRP netlink interface for configuring MRP interconnect")
>
> I think you also want
>
> Fixes: 20f6a05ef635 ("bridge: mrp: Rework the MRP netlink interface")
>
> As highlighted by AI review.
>
>> Reported-by: Weiming Shi <bestswngs@gmail.com>
>> Signed-off-by: Xiang Mei <xmei5@asu.edu>
>
> ...
^ permalink raw reply
* Re: [PATCH net-next 2/4] net: phy: mediatek: add phy driver for MT7628 built-in Fast Ethernet PHYs
From: Andrew Lunn @ 2026-03-27 11:48 UTC (permalink / raw)
To: Joris Vaisvila
Cc: netdev, horms, pabeni, kuba, edumazet, davem, olteanv, devicetree,
Rob Herring, Krzysztof Kozlowski, Conor Dooley
In-Reply-To: <20260326204413.3317584-3-joey@tinyisr.com>
On Thu, Mar 26, 2026 at 10:44:11PM +0200, Joris Vaisvila wrote:
> The Fast Ethernet PHYs present in the MT7628 SoCs require an
> undocumented bit to be set before they can establish 100mbps links.
>
> This commit adds the Kconfig option MEDIATEK_FE_SOC_PHY and the
> corresponding driver mtk-fe-soc.c.
>
> Signed-off-by: Joris Vaisvila <joey@tinyisr.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Andrew
^ permalink raw reply
* Re: [PATCH net-next v2 2/4] net: hsr: fix VLAN add unwind on slave errors
From: Felix Maurer @ 2026-03-27 11:52 UTC (permalink / raw)
To: luka.gejak
Cc: davem, edumazet, kuba, pabeni, netdev, horms, liuhangbin,
linux-kernel
In-Reply-To: <20260326154715.38405-3-luka.gejak@linux.dev>
Thank you for updating this patch!
On Thu, Mar 26, 2026 at 04:47:13PM +0100, luka.gejak@linux.dev wrote:
> From: Luka Gejak <luka.gejak@linux.dev>
>
> When vlan_vid_add() fails for a secondary slave, the error path calls
> vlan_vid_del() on the failing port instead of the peer slave that had
> already succeeded. This results in asymmetric VLAN state across the HSR
> pair.
>
> Fix this by switching to a centralized unwind path that removes the VID
> from any slave device that was already programmed.
>
> Signed-off-by: Luka Gejak <luka.gejak@linux.dev>
> ---
> net/hsr/hsr_device.c | 46 ++++++++++++++++++++++++++------------------
> 1 file changed, 27 insertions(+), 19 deletions(-)
>
> diff --git a/net/hsr/hsr_device.c b/net/hsr/hsr_device.c
> index 5c3eca2235ce..75c491279df8 100644
> --- a/net/hsr/hsr_device.c
> +++ b/net/hsr/hsr_device.c
> @@ -532,8 +532,8 @@ static void hsr_change_rx_flags(struct net_device *dev, int change)
> static int hsr_ndo_vlan_rx_add_vid(struct net_device *dev,
> __be16 proto, u16 vid)
> {
> - bool is_slave_a_added = false;
> - bool is_slave_b_added = false;
> + struct net_device *slave_a_dev = NULL;
> + struct net_device *slave_b_dev = NULL;
> struct hsr_port *port;
> struct hsr_priv *hsr;
> int ret = 0;
> @@ -546,29 +546,28 @@ static int hsr_ndo_vlan_rx_add_vid(struct net_device *dev,
> continue;
>
> ret = vlan_vid_add(port->dev, proto, vid);
> - switch (port->type) {
> - case HSR_PT_SLAVE_A:
> - if (ret) {
> - /* clean up Slave-B */
> + if (ret) {
> + switch (port->type) {
> + case HSR_PT_SLAVE_A:
> netdev_err(dev, "add vid failed for Slave-A\n");
> - if (is_slave_b_added)
> - vlan_vid_del(port->dev, proto, vid);
> - return ret;
> + break;
> + case HSR_PT_SLAVE_B:
> + netdev_err(dev, "add vid failed for Slave-B\n");
> + break;
> + default:
> + break;
> }
>
> - is_slave_a_added = true;
> + goto unwind;
> + }
> +
> + switch (port->type) {
> + case HSR_PT_SLAVE_A:
> + slave_a_dev = port->dev;
> break;
>
nit: superflous empty line (it's inconsistent with the other case
blocks)
> case HSR_PT_SLAVE_B:
> - if (ret) {
> - /* clean up Slave-A */
> - netdev_err(dev, "add vid failed for Slave-B\n");
> - if (is_slave_a_added)
> - vlan_vid_del(port->dev, proto, vid);
> - return ret;
> - }
> -
> - is_slave_b_added = true;
> + slave_b_dev = port->dev;
> break;
> default:
> break;
I think this would look cleaner with the good and the bad paths in the
same switch-case, but that may be a matter of (my) taste. What do you
think?
Thanks,
Felix
^ permalink raw reply
* Re: [PATCH v2 0/4] treewide: fixup gfp_t printks
From: Stanislaw Gruszka @ 2026-03-27 11:57 UTC (permalink / raw)
To: Brendan Jackman
Cc: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Alexander Potapenko, Marco Elver, Dmitry Vyukov,
Andrew Morton, Allison Henderson, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, dri-devel,
linux-kernel, linux-wireless, kasan-dev, linux-mm, netdev,
linux-rdma, rds-devel
In-Reply-To: <20260326-gfp64-v2-0-d916021cecdf@google.com>
On Thu, Mar 26, 2026 at 12:31:56PM +0000, Brendan Jackman wrote:
> This patchset used to be about switching gfp_t to unsigned long. That is
> probably not gonna happen any more but while writing it I found these
> cleanups that seem worthwhile regardless.
For the record, these patches are independent and could be sent separately
to the appropriate maintainers. Doing so would avoid unnecessarily large CC
lists for people not interested about the changes in other subsystems.
Regards
Stanislaw
> Signed-off-by: Brendan Jackman <jackmanb@google.com>
> ---
> Changes in v2:
> - Drop gfp_t changes
> - Add correct CCs
> - Add minor fixups to preexisting code spotted by AI review
> - Link to v1: https://lore.kernel.org/r/20260319-gfp64-v1-0-2c73b8d42b7f@google.com
>
> ---
> Brendan Jackman (4):
> drm/managed: Use special gfp_t format specifier
> iwlegacy: 3945-mac: Fixup allocation failure log
> mm/kfence: Use special gfp_t format specifier
> net/rds: Use special gfp_t format specifier
>
> drivers/gpu/drm/drm_managed.c | 4 ++--
> drivers/net/wireless/intel/iwlegacy/3945-mac.c | 4 ++--
> mm/kfence/kfence_test.c | 2 +-
> net/rds/tcp_recv.c | 2 +-
> 4 files changed, 6 insertions(+), 6 deletions(-)
> ---
> base-commit: c369299895a591d96745d6492d4888259b004a9e
> change-id: 20260319-gfp64-7a970a80ba4e
>
> Best regards,
> --
> Brendan Jackman <jackmanb@google.com>
>
^ permalink raw reply
* Re: [PATCH net-next v2 0/2] net: hsr: subsystem cleanups and modernization
From: Felix Maurer @ 2026-03-27 12:01 UTC (permalink / raw)
To: luka.gejak
Cc: davem, edumazet, kuba, pabeni, netdev, horms, liuhangbin,
linux-kernel
In-Reply-To: <20260326174600.136232-1-luka.gejak@linux.dev>
On Thu, Mar 26, 2026 at 06:45:58PM +0100, luka.gejak@linux.dev wrote:
> From: Luka Gejak <luka.gejak@linux.dev>
>
> Changes in v2:
> - dropped trivial cleanup-only patches per netdev clean-up policy
> - added AI attribution for cover-letter/commit-message wording only
> - dropped fallthrough/BIT conversion patches per review
Thank you for updating (and limiting) the series.
> This series contains two focused HSR cleanups with practical benefit.
> It constifies protocol operation tables and replaces a hardcoded
> function name with __func__ to keep diagnostics correct across
> refactoring.
> Assisted-by: Copilot:gpt-5.3-codex (cover-letter/commit-message wording
> only)
>
> Luka Gejak (2):
> net: hsr: constify hsr_ops and prp_ops protocol operation structures
> net: hsr: use __func__ instead of hardcoded function name
The patches look good to me, so for the series:
Reviewed-by: Felix Maurer <fmaurer@redhat.com>
Thanks,
Felix
^ permalink raw reply
* [PATCH 1/2 net-next v2] ipv4: centralize devconf sysctl handling
From: Fernando Fernandez Mancera @ 2026-03-27 12:02 UTC (permalink / raw)
To: netdev
Cc: horms, pabeni, kuba, edumazet, dsahern, davem,
Fernando Fernandez Mancera
The logic for handling IPv4 devconf sysctls is scattered. Notification
and cache flushes are managed in devinet_conf_proc(), while a separate
ipv4_doint_and_flush() function and DEVINET_SYSCTL_FLUSHING_ENTRY macro
is used for properties that solely require a cache flush.
This patch refactors the sysctl handling by introducing a centralized
helper, devinet_conf_post_set(). This new function evaluates the changed
attribute and handles all necessary operations like triggering netlink
notifications. It returns a boolean indicating whether a routing cache
flush is required.
Note that the boolean is necessary as this function will be re-used for
netlink IPv4 devconf handling where the cache flushing must wait until
all the attributes have been processed.
Finally, this is introducing a small change in behavior for
IPV4_DEVCONF_ROUTE_LOCALNET. As commit d0daebc3d622 ("ipv4: Add
interface option to enable routing of 127.0.0.0/8") intended, the cache
flush should only be performed when ROUTE_LOCALNET changes from 1 to 0.
Unfortunately, this was not true because while implementing it the
DEVINET_SYSCTL_FLUSHING_ENTRY was used for the attribute, making the
code related to it on devinet_conf_proc() dead.
IPV4_DEVCONF_FORWARDING is still being handled separately as it requires
more operations.
Signed-off-by: Fernando Fernandez Mancera <fmancera@suse.de>
---
v2: no changes
---
net/ipv4/devinet.c | 127 ++++++++++++++++++++++++---------------------
1 file changed, 68 insertions(+), 59 deletions(-)
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index 58fe7cb69545..8300516fb38f 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -2128,6 +2128,46 @@ static int inet_validate_link_af(const struct net_device *dev,
return 0;
}
+static bool devinet_conf_post_set(struct net *net, struct ipv4_devconf *cnf,
+ int attr, int new, int old, int ifindex)
+{
+ if (new == old)
+ return false;
+
+ switch (attr) {
+ case IPV4_DEVCONF_ROUTE_LOCALNET:
+ case IPV4_DEVCONF_ACCEPT_LOCAL:
+ if (new == 0)
+ return true;
+ break;
+ case IPV4_DEVCONF_NOXFRM:
+ case IPV4_DEVCONF_NOPOLICY:
+ case IPV4_DEVCONF_PROMOTE_SECONDARIES:
+ case IPV4_DEVCONF_DROP_UNICAST_IN_L2_MULTICAST:
+ case IPV4_DEVCONF_BC_FORWARDING:
+ return true;
+ case IPV4_DEVCONF_RP_FILTER:
+ inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
+ NETCONFA_RP_FILTER,
+ ifindex, cnf);
+ break;
+ case IPV4_DEVCONF_PROXY_ARP:
+ inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
+ NETCONFA_PROXY_NEIGH,
+ ifindex, cnf);
+ break;
+ case IPV4_DEVCONF_IGNORE_ROUTES_WITH_LINKDOWN:
+ inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
+ NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN,
+ ifindex, cnf);
+ break;
+ default:
+ break;
+ }
+
+ return false;
+}
+
static int inet_set_link_af(struct net_device *dev, const struct nlattr *nla,
struct netlink_ext_ack *extack)
{
@@ -2509,44 +2549,31 @@ static int devinet_conf_proc(const struct ctl_table *ctl, int write,
if (write) {
struct ipv4_devconf *cnf = ctl->extra1;
- struct net *net = ctl->extra2;
int i = (int *)ctl->data - cnf->data;
+ struct net *net = ctl->extra2;
int ifindex;
- set_bit(i, cnf->state);
-
- if (cnf == net->ipv4.devconf_dflt)
- devinet_copy_dflt_conf(net, i);
- if (i == IPV4_DEVCONF_ACCEPT_LOCAL - 1 ||
- i == IPV4_DEVCONF_ROUTE_LOCALNET - 1)
- if ((new_value == 0) && (old_value != 0))
- rt_cache_flush(net);
+ /* These attributes are bypassing the tracking state,
+ * for the rest track the state and propagate the changes
+ * to default config
+ */
+ switch (i + 1) {
+ case IPV4_DEVCONF_NOXFRM:
+ case IPV4_DEVCONF_NOPOLICY:
+ case IPV4_DEVCONF_PROMOTE_SECONDARIES:
+ case IPV4_DEVCONF_DROP_UNICAST_IN_L2_MULTICAST:
+ break;
+ default:
+ set_bit(i, cnf->state);
+ if (cnf == net->ipv4.devconf_dflt)
+ devinet_copy_dflt_conf(net, i);
+ break;
+ }
- if (i == IPV4_DEVCONF_BC_FORWARDING - 1 &&
- new_value != old_value)
+ ifindex = devinet_conf_ifindex(net, cnf);
+ if (devinet_conf_post_set(net, cnf, i + 1, new_value,
+ old_value, ifindex))
rt_cache_flush(net);
-
- if (i == IPV4_DEVCONF_RP_FILTER - 1 &&
- new_value != old_value) {
- ifindex = devinet_conf_ifindex(net, cnf);
- inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
- NETCONFA_RP_FILTER,
- ifindex, cnf);
- }
- if (i == IPV4_DEVCONF_PROXY_ARP - 1 &&
- new_value != old_value) {
- ifindex = devinet_conf_ifindex(net, cnf);
- inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
- NETCONFA_PROXY_NEIGH,
- ifindex, cnf);
- }
- if (i == IPV4_DEVCONF_IGNORE_ROUTES_WITH_LINKDOWN - 1 &&
- new_value != old_value) {
- ifindex = devinet_conf_ifindex(net, cnf);
- inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
- NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN,
- ifindex, cnf);
- }
}
return ret;
@@ -2599,20 +2626,6 @@ static int devinet_sysctl_forward(const struct ctl_table *ctl, int write,
return ret;
}
-static int ipv4_doint_and_flush(const struct ctl_table *ctl, int write,
- void *buffer, size_t *lenp, loff_t *ppos)
-{
- int *valp = ctl->data;
- int val = *valp;
- int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
- struct net *net = ctl->extra2;
-
- if (write && *valp != val)
- rt_cache_flush(net);
-
- return ret;
-}
-
#define DEVINET_SYSCTL_ENTRY(attr, name, mval, proc) \
{ \
.procname = name, \
@@ -2633,9 +2646,6 @@ static int ipv4_doint_and_flush(const struct ctl_table *ctl, int write,
#define DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, proc) \
DEVINET_SYSCTL_ENTRY(attr, name, 0644, proc)
-#define DEVINET_SYSCTL_FLUSHING_ENTRY(attr, name) \
- DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, ipv4_doint_and_flush)
-
static struct devinet_sysctl_table {
struct ctl_table_header *sysctl_header;
struct ctl_table devinet_vars[IPV4_DEVCONF_MAX];
@@ -2678,15 +2688,14 @@ static struct devinet_sysctl_table {
"ignore_routes_with_linkdown"),
DEVINET_SYSCTL_RW_ENTRY(DROP_GRATUITOUS_ARP,
"drop_gratuitous_arp"),
-
- DEVINET_SYSCTL_FLUSHING_ENTRY(NOXFRM, "disable_xfrm"),
- DEVINET_SYSCTL_FLUSHING_ENTRY(NOPOLICY, "disable_policy"),
- DEVINET_SYSCTL_FLUSHING_ENTRY(PROMOTE_SECONDARIES,
- "promote_secondaries"),
- DEVINET_SYSCTL_FLUSHING_ENTRY(ROUTE_LOCALNET,
- "route_localnet"),
- DEVINET_SYSCTL_FLUSHING_ENTRY(DROP_UNICAST_IN_L2_MULTICAST,
- "drop_unicast_in_l2_multicast"),
+ DEVINET_SYSCTL_RW_ENTRY(NOXFRM, "disable_xfrm"),
+ DEVINET_SYSCTL_RW_ENTRY(NOPOLICY, "disable_policy"),
+ DEVINET_SYSCTL_RW_ENTRY(PROMOTE_SECONDARIES,
+ "promote_secondaries"),
+ DEVINET_SYSCTL_RW_ENTRY(ROUTE_LOCALNET,
+ "route_localnet"),
+ DEVINET_SYSCTL_RW_ENTRY(DROP_UNICAST_IN_L2_MULTICAST,
+ "drop_unicast_in_l2_multicast"),
},
};
--
2.53.0
^ permalink raw reply related
* [PATCH 2/2 net-next v2] ipv4: handle devconf post-set actions on netlink updates
From: Fernando Fernandez Mancera @ 2026-03-27 12:02 UTC (permalink / raw)
To: netdev
Cc: horms, pabeni, kuba, edumazet, dsahern, davem,
Fernando Fernandez Mancera
In-Reply-To: <20260327120202.4761-1-fmancera@suse.de>
When IPv4 device configuration parameters are updated via netlink, the
kernel currently only updates the value. This bypasses several
post-modification actions that occur when these same parameters are
updated via sysctl, such as flushing the routing cache or emitting
RTM_NEWNETCONF notifications.
This patch addresses the inconsistency by calling the
devinet_conf_post_set() helper inside inet_set_link_af(). If a flush is
required, we defer it until the netlink attribute parsing loop
completes.
This ensures consistent behavior and side-effects for devconf changes,
regardless of whether they are initiated via sysctl or netlink.
Signed-off-by: Fernando Fernandez Mancera <fmancera@suse.de>
---
v2: handled forwarding notification and disabling LRO
---
net/ipv4/devinet.c | 29 +++++++++++++++++++++++++++--
1 file changed, 27 insertions(+), 2 deletions(-)
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index 8300516fb38f..a35b72662e43 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -2161,6 +2161,20 @@ static bool devinet_conf_post_set(struct net *net, struct ipv4_devconf *cnf,
NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN,
ifindex, cnf);
break;
+ case IPV4_DEVCONF_FORWARDING:
+ if (new == 1) {
+ /* it is safe to use container_of() because forwarding case
+ * is only used by the netlink path
+ */
+ struct in_device *idev = container_of(cnf, struct in_device, cnf);
+
+ netif_disable_lro(idev->dev);
+ }
+
+ inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
+ NETCONFA_FORWARDING,
+ ifindex, cnf);
+ return true;
default:
break;
}
@@ -2173,6 +2187,8 @@ static int inet_set_link_af(struct net_device *dev, const struct nlattr *nla,
{
struct in_device *in_dev = __in_dev_get_rtnl(dev);
struct nlattr *a, *tb[IFLA_INET_MAX+1];
+ struct net *net = dev_net(dev);
+ bool flush_cache = false;
int rem;
if (!in_dev)
@@ -2182,8 +2198,17 @@ static int inet_set_link_af(struct net_device *dev, const struct nlattr *nla,
return -EINVAL;
if (tb[IFLA_INET_CONF]) {
- nla_for_each_nested(a, tb[IFLA_INET_CONF], rem)
- ipv4_devconf_set(in_dev, nla_type(a), nla_get_u32(a));
+ nla_for_each_nested(a, tb[IFLA_INET_CONF], rem) {
+ int old_value = ipv4_devconf_get(in_dev, nla_type(a));
+ int new_value = nla_get_u32(a);
+
+ ipv4_devconf_set(in_dev, nla_type(a), new_value);
+ if (devinet_conf_post_set(net, &in_dev->cnf, nla_type(a), new_value,
+ old_value, dev->ifindex))
+ flush_cache = true;
+ }
+ if (flush_cache)
+ rt_cache_flush(net);
}
return 0;
--
2.53.0
^ permalink raw reply related
* Re: [PATCH net-next 4/4] net: dsa: initial support for MT7628 embedded switch
From: Andrew Lunn @ 2026-03-27 12:07 UTC (permalink / raw)
To: Joris Vaisvila
Cc: netdev, horms, pabeni, kuba, edumazet, davem, olteanv, devicetree,
Rob Herring, Krzysztof Kozlowski, Conor Dooley
In-Reply-To: <20260326204413.3317584-5-joey@tinyisr.com>
> diff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig
> index 39fb8ead16b5..d07fc8dfe228 100644
> --- a/drivers/net/dsa/Kconfig
> +++ b/drivers/net/dsa/Kconfig
> @@ -70,6 +70,13 @@ config NET_DSA_MV88E6060
> This enables support for the Marvell 88E6060 ethernet switch
> chip.
>
> +config NET_DSA_MT7628
> + tristate "MT7628 Embedded ethernet switch support"
Please could you make this fit the pattern other devices have.
MediaTek MT7628 Embedded ethernet switch support
would be better. And please put it before MT7530. The sorting in
drivers/net/dsa/Kconfig is not great, but we should not make it worse.
> diff --git a/drivers/net/dsa/Makefile b/drivers/net/dsa/Makefile
> index f5a463b87ec2..22da6b680f29 100644
> --- a/drivers/net/dsa/Makefile
> +++ b/drivers/net/dsa/Makefile
> @@ -15,6 +15,7 @@ obj-$(CONFIG_NET_DSA_VITESSE_VSC73XX) += vitesse-vsc73xx-core.o
> obj-$(CONFIG_NET_DSA_VITESSE_VSC73XX_PLATFORM) += vitesse-vsc73xx-platform.o
> obj-$(CONFIG_NET_DSA_VITESSE_VSC73XX_SPI) += vitesse-vsc73xx-spi.o
> obj-$(CONFIG_NET_DSA_YT921X) += yt921x.o
> +obj-$(CONFIG_NET_DSA_MT7628) += mt7628.o
This is also sorted, so should be inserted earlier.
> +static int mt7628_mii_read(struct mii_bus *bus, int port, int regnum)
> +{
> + struct mt7628_esw *esw = bus->priv;
> + int ret;
> + u32 val;
> +
> + ret = regmap_read_poll_timeout(esw->regmap, MT7628_ESW_REG_PCR1, val,
> + !(val & MT7628_ESW_PCR1_RD_DONE), 10,
> + 5000);
> + if (ret)
> + goto out;
> +
> + ret = regmap_write(esw->regmap, MT7628_ESW_REG_PCR0,
> + FIELD_PREP(MT7628_ESW_PCR0_CPU_PHY_REG,
> + regnum) |
> + FIELD_PREP(MT7628_ESW_PCR0_CPU_PHY_ADDR,
> + port) | MT7628_ESW_PCR0_RD_PHY_CMD);
> + if (ret)
> + goto out;
> +
> + ret = regmap_read_poll_timeout(esw->regmap, MT7628_ESW_REG_PCR1, val,
> + (val & MT7628_ESW_PCR1_RD_DONE), 10,
> + 5000);
> +out:
> + if (ret) {
> + dev_err(&bus->dev, "read failed. MDIO timeout?\n");
> + return -ETIMEDOUT;
Return the error code regmap_read_poll_timeout() or regmap_write()
returned.
> +static int mt7628_mii_write(struct mii_bus *bus, int port, int regnum, u16 dat)
> +{
> + struct mt7628_esw *esw = bus->priv;
> + u32 val;
> + int ret;
> +
> + ret = regmap_read_poll_timeout(esw->regmap, MT7628_ESW_REG_PCR1, val,
> + !(val & MT7628_ESW_PCR1_WT_DONE), 10,
> + 5000);
> + if (ret)
> + goto out;
> +
> + ret = regmap_write(esw->regmap, MT7628_ESW_REG_PCR0,
> + FIELD_PREP(MT7628_ESW_PCR0_WT_NWAY_DATA, dat) |
> + FIELD_PREP(MT7628_ESW_PCR0_CPU_PHY_REG,
> + regnum) |
> + FIELD_PREP(MT7628_ESW_PCR0_CPU_PHY_ADDR,
> + port) | MT7628_ESW_PCR0_WT_PHY_CMD);
> + if (ret)
> + goto out;
> +
> + ret = regmap_read_poll_timeout(esw->regmap, MT7628_ESW_REG_PCR1, val,
> + (val & MT7628_ESW_PCR1_WT_DONE), 10,
> + 5000);
> +out:
> + if (ret) {
> + dev_err(&bus->dev, "write failed. MDIO timeout?\n");
> + return -ETIMEDOUT;
Same here. And in general, always return the error code, if there is
one, don't make one up.
> +static int mt7628_setup_internal_mdio(struct dsa_switch *ds)
> +{
> + struct mt7628_esw *esw = ds->priv;
> + struct device_node *mdio;
> + struct mii_bus *bus;
> + int ret = 0;
> +
> + mdio = of_get_child_by_name(ds->dev->of_node, "mdio");
> + if (mdio && !of_device_is_available(mdio))
> + goto out_put_node;
of_get_available_child_by_name() ?
Andrew
^ permalink raw reply
* Re: [PATCH] net: ti: icssg-prueth: fix missing data copy and wrong recycle in ZC RX dispatch
From: patchwork-bot+netdevbpf @ 2026-03-27 12:10 UTC (permalink / raw)
To: David CARLIER
Cc: danishanwar, rogerq, andrew+netdev, davem, edumazet, kuba, pabeni,
m-malladi, jacob.e.keller, horms, linux-arm-kernel, netdev,
linux-kernel
In-Reply-To: <20260325125131.53399-1-devnexen@gmail.com>
Hello:
This patch was applied to netdev/net.git (main)
by David S. Miller <davem@davemloft.net>:
On Wed, 25 Mar 2026 12:51:30 +0000 you wrote:
> emac_dispatch_skb_zc() allocates a new skb via napi_alloc_skb() but
> never copies the packet data from the XDP buffer into it. The skb is
> passed up the stack containing uninitialized heap memory instead of
> the actual received packet, leaking kernel heap contents to userspace.
>
> Copy the received packet data from the XDP buffer into the skb using
> skb_copy_to_linear_data().
>
> [...]
Here is the summary with links:
- net: ti: icssg-prueth: fix missing data copy and wrong recycle in ZC RX dispatch
https://git.kernel.org/netdev/net/c/5597dd284ff8
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/ipv6: ioam6: prevent schema length wraparound in trace fill
From: patchwork-bot+netdevbpf @ 2026-03-27 12:10 UTC (permalink / raw)
To: Pengpeng Hou
Cc: justin.iurman, davem, dsahern, edumazet, kuba, pabeni, horms,
netdev, linux-kernel
In-Reply-To: <20260325074152.17064-1-pengpeng@iscas.ac.cn>
Hello:
This patch was applied to netdev/net.git (main)
by David S. Miller <davem@davemloft.net>:
On Wed, 25 Mar 2026 15:41:52 +0800 you wrote:
> ioam6_fill_trace_data() stores the schema contribution to the trace
> length in a u8. With bit 22 enabled and the largest schema payload,
> sclen becomes 1 + 1020 / 4, wraps from 256 to 0, and bypasses the
> remaining-space check. __ioam6_fill_trace_data() then positions the
> write cursor without reserving the schema area but still copies the
> 4-byte schema header and the full schema payload, overrunning the trace
> buffer.
>
> [...]
Here is the summary with links:
- net/ipv6: ioam6: prevent schema length wraparound in trace fill
https://git.kernel.org/netdev/net/c/5e67ba9bb531
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] tg3: Fix race for querying speed/duplex
From: patchwork-bot+netdevbpf @ 2026-03-27 12:10 UTC (permalink / raw)
To: Thomas Bogendoerfer
Cc: pavan.chebbi, mchan, andrew+netdev, davem, edumazet, kuba, pabeni,
nsujir, netdev, linux-kernel
In-Reply-To: <20260325112054.108988-1-tbogendoerfer@suse.de>
Hello:
This patch was applied to netdev/net.git (main)
by David S. Miller <davem@davemloft.net>:
On Wed, 25 Mar 2026 12:20:53 +0100 you wrote:
> When driver signals carrier up via netif_carrier_on() its internal
> link_up state isn't updated immediately. This leads to inconsistent
> speed/duplex in /proc/net/bonding/bondX where the speed and duplex
> is shown as unknown while ethtool shows correct values. Fix this by
> using netif_carrier_ok() for link checking in get_ksettings function.
>
> Fixes: 84421b99cedc ("tg3: Update link_up flag for phylib devices")
> Signed-off-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
>
> [...]
Here is the summary with links:
- [net] tg3: Fix race for querying speed/duplex
https://git.kernel.org/netdev/net/c/bb417456c781
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 v2 03/15] firmware: qcom_scm: Migrate to generic PAS service
From: Harshal Dev @ 2026-03-27 12:10 UTC (permalink / raw)
To: Sumit Garg, linux-arm-msm, devicetree, dri-devel, freedreno,
linux-media, netdev, linux-wireless, ath12k, linux-remoteproc
Cc: andersson, konradybcio, robh, krzk+dt, conor+dt, robin.clark,
sean, akhilpo, lumag, abhinav.kumar, jesszhan0024, marijn.suijten,
airlied, simona, vikash.garodia, dikshita.agarwal, bod, mchehab,
elder, andrew+netdev, davem, edumazet, kuba, pabeni, jjohnson,
mathieu.poirier, trilokkumar.soni, mukesh.ojha, pavan.kondeti,
jorge.ramirez, tonyh, vignesh.viswanathan, srinivas.kandagatla,
amirreza.zarrabi, jens.wiklander, op-tee, apurupa, skare,
linux-kernel, Sumit Garg
In-Reply-To: <20260312062756.694390-4-sumit.garg@kernel.org>
On 3/12/2026 11:57 AM, Sumit Garg wrote:
> From: Sumit Garg <sumit.garg@oss.qualcomm.com>
>
> With the availability of generic PAS service, let's add SCM calls as
> a backend to keep supporting legacy QTEE interfaces. The exported
> qcom_scm* wrappers will get dropped once all the client drivers get
> migrated as part of future patches.
>
> Signed-off-by: Sumit Garg <sumit.garg@oss.qualcomm.com>
> ---
> drivers/firmware/qcom/Kconfig | 1 +
> drivers/firmware/qcom/qcom_scm.c | 336 ++++++++++++++-----------------
> 2 files changed, 156 insertions(+), 181 deletions(-)
>
[..]
> diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c
> index 8fbc96693a55..2d7937ae7c8f 100644
> --- a/drivers/firmware/qcom/qcom_scm.c
> +++ b/drivers/firmware/qcom/qcom_scm.c
> @@ -13,6 +13,7 @@
> #include <linux/dma-mapping.h>
[..]
>
> -/**
> - * devm_qcom_scm_pas_context_alloc() - Allocate peripheral authentication service
> - * context for a given peripheral
> - *
> - * PAS context is device-resource managed, so the caller does not need
> - * to worry about freeing the context memory.
> - *
> - * @dev: PAS firmware device
> - * @pas_id: peripheral authentication service id
> - * @mem_phys: Subsystem reserve memory start address
> - * @mem_size: Subsystem reserve memory size
> - *
> - * Returns: The new PAS context, or ERR_PTR() on failure.
> - */
Shouldn't we drop the documentation for the exported functions in this file as part of
patch 14/15? After this patch is applied, the devm_qcom_scm_pas_context_alloc() function
still remains exported and available.
Regards,
Harshal
^ permalink raw reply
* [PATCH net-next v10 04/14] net, ethtool: Disallow leased real rxqs to be resized
From: Daniel Borkmann @ 2026-03-27 12:10 UTC (permalink / raw)
To: netdev
Cc: bpf, kuba, davem, razor, pabeni, willemb, sdf, john.fastabend,
martin.lau, jordan, maciej.fijalkowski, magnus.karlsson, dw, toke,
yangzhenze, wangdongdong.6
In-Reply-To: <20260327121049.334562-1-daniel@iogearbox.net>
Similar to AF_XDP, do not allow queues in a physical netdev to be
resized by ethtool -L when they are leased. Cover channel resize
paths (both netlink and ioctl) to reject resizing when the queues
would be affected.
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Co-developed-by: David Wei <dw@davidwei.uk>
Signed-off-by: David Wei <dw@davidwei.uk>
---
net/ethtool/channels.c | 17 ++++++++++++-----
net/ethtool/ioctl.c | 16 +++++++++++-----
2 files changed, 23 insertions(+), 10 deletions(-)
diff --git a/net/ethtool/channels.c b/net/ethtool/channels.c
index 45232cf1c144..63ed5ebf19a8 100644
--- a/net/ethtool/channels.c
+++ b/net/ethtool/channels.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
-#include <net/xdp_sock_drv.h>
+#include <net/netdev_queues.h>
#include "common.h"
#include "netlink.h"
@@ -169,14 +169,21 @@ ethnl_set_channels(struct ethnl_req_info *req_info, struct genl_info *info)
if (ret)
return ret;
- /* Disabling channels, query zero-copy AF_XDP sockets */
+ /* ensure channels are not busy at the moment */
from_channel = channels.combined_count +
min(channels.rx_count, channels.tx_count);
- for (i = from_channel; i < old_total; i++)
- if (xsk_get_pool_from_qid(dev, i)) {
- GENL_SET_ERR_MSG(info, "requested channel counts are too low for existing zerocopy AF_XDP sockets");
+ for (i = from_channel; i < old_total; i++) {
+ bool losing_rx = i >= channels.combined_count +
+ channels.rx_count;
+
+ if (netdev_queue_busy(dev, i,
+ losing_rx ? NETDEV_QUEUE_TYPE_RX :
+ NETDEV_QUEUE_TYPE_TX, NULL)) {
+ GENL_SET_ERR_MSG(info,
+ "requested channel counts are too low due to busy queues (AF_XDP or queue leasing)");
return -EINVAL;
}
+ }
ret = dev->ethtool_ops->set_channels(dev, &channels);
return ret < 0 ? ret : 1;
diff --git a/net/ethtool/ioctl.c b/net/ethtool/ioctl.c
index 3c713a91ad0d..f7288bc6cae4 100644
--- a/net/ethtool/ioctl.c
+++ b/net/ethtool/ioctl.c
@@ -27,12 +27,12 @@
#include <linux/net.h>
#include <linux/pm_runtime.h>
#include <linux/utsname.h>
+#include <linux/ethtool_netlink.h>
#include <net/devlink.h>
#include <net/ipv6.h>
-#include <net/xdp_sock_drv.h>
#include <net/flow_offload.h>
#include <net/netdev_lock.h>
-#include <linux/ethtool_netlink.h>
+#include <net/netdev_queues.h>
#include "common.h"
@@ -2284,13 +2284,19 @@ static noinline_for_stack int ethtool_set_channels(struct net_device *dev,
if (ret)
return ret;
- /* Disabling channels, query zero-copy AF_XDP sockets */
+ /* Disabling channels, query busy queues (AF_XDP, queue leasing) */
from_channel = channels.combined_count +
min(channels.rx_count, channels.tx_count);
to_channel = curr.combined_count + max(curr.rx_count, curr.tx_count);
- for (i = from_channel; i < to_channel; i++)
- if (xsk_get_pool_from_qid(dev, i))
+ for (i = from_channel; i < to_channel; i++) {
+ bool losing_rx = i >= channels.combined_count +
+ channels.rx_count;
+
+ if (netdev_queue_busy(dev, i,
+ losing_rx ? NETDEV_QUEUE_TYPE_RX :
+ NETDEV_QUEUE_TYPE_TX, NULL))
return -EINVAL;
+ }
ret = dev->ethtool_ops->set_channels(dev, &channels);
if (!ret)
--
2.43.0
^ permalink raw reply related
* [PATCH net-next v10 07/14] net: Proxy netdev_queue_get_dma_dev for leased queues
From: Daniel Borkmann @ 2026-03-27 12:10 UTC (permalink / raw)
To: netdev
Cc: bpf, kuba, davem, razor, pabeni, willemb, sdf, john.fastabend,
martin.lau, jordan, maciej.fijalkowski, magnus.karlsson, dw, toke,
yangzhenze, wangdongdong.6
In-Reply-To: <20260327121049.334562-1-daniel@iogearbox.net>
From: David Wei <dw@davidwei.uk>
Extend netdev_queue_get_dma_dev to return the physical device of the
real rxq for DMA in case the queue was leased. This allows memory
providers like io_uring zero-copy or devmem to bind to the physically
leased rxq via virtual devices such as netkit.
Signed-off-by: David Wei <dw@davidwei.uk>
Co-developed-by: Daniel Borkmann <daniel@iogearbox.net>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
---
include/net/netdev_queues.h | 3 ++-
net/core/netdev_queues.c | 36 ++++++++++++++++++++++++++++--------
2 files changed, 30 insertions(+), 9 deletions(-)
diff --git a/include/net/netdev_queues.h b/include/net/netdev_queues.h
index 748b70552ed1..d14a45a13b40 100644
--- a/include/net/netdev_queues.h
+++ b/include/net/netdev_queues.h
@@ -380,7 +380,8 @@ static inline unsigned int netif_xmit_timeout_ms(struct netdev_queue *txq)
get_desc, start_thrs); \
})
-struct device *netdev_queue_get_dma_dev(struct net_device *dev, int idx);
+struct device *netdev_queue_get_dma_dev(struct net_device *dev,
+ unsigned int idx);
bool netdev_can_create_queue(const struct net_device *dev,
struct netlink_ext_ack *extack);
bool netdev_can_lease_queue(const struct net_device *dev,
diff --git a/net/core/netdev_queues.c b/net/core/netdev_queues.c
index 177401828e79..9a945d74c3a7 100644
--- a/net/core/netdev_queues.c
+++ b/net/core/netdev_queues.c
@@ -6,27 +6,47 @@
#include "dev.h"
+static struct device *
+__netdev_queue_get_dma_dev(struct net_device *dev, unsigned int idx)
+{
+ const struct netdev_queue_mgmt_ops *queue_ops = dev->queue_mgmt_ops;
+ struct device *dma_dev;
+
+ if (queue_ops && queue_ops->ndo_queue_get_dma_dev)
+ dma_dev = queue_ops->ndo_queue_get_dma_dev(dev, idx);
+ else
+ dma_dev = dev->dev.parent;
+
+ return dma_dev && dma_dev->dma_mask ? dma_dev : NULL;
+}
+
/**
* netdev_queue_get_dma_dev() - get dma device for zero-copy operations
* @dev: net_device
* @idx: queue index
*
- * Get dma device for zero-copy operations to be used for this queue.
+ * Get dma device for zero-copy operations to be used for this queue. If the
+ * queue is leased from a physical queue, we retrieve the physical queue's
+ * dma device.
* When such device is not available or valid, the function will return NULL.
*
* Return: Device or NULL on error
*/
-struct device *netdev_queue_get_dma_dev(struct net_device *dev, int idx)
+struct device *netdev_queue_get_dma_dev(struct net_device *dev,
+ unsigned int idx)
{
- const struct netdev_queue_mgmt_ops *queue_ops = dev->queue_mgmt_ops;
+ struct net_device *orig_dev = dev;
struct device *dma_dev;
- if (queue_ops && queue_ops->ndo_queue_get_dma_dev)
- dma_dev = queue_ops->ndo_queue_get_dma_dev(dev, idx);
- else
- dma_dev = dev->dev.parent;
+ if (!netif_rxq_is_leased(dev, idx))
+ return __netdev_queue_get_dma_dev(dev, idx);
- return dma_dev && dma_dev->dma_mask ? dma_dev : NULL;
+ if (!netif_get_rx_queue_lease_locked(&dev, &idx))
+ return NULL;
+
+ dma_dev = __netdev_queue_get_dma_dev(dev, idx);
+ netif_put_rx_queue_lease_locked(orig_dev, dev);
+ return dma_dev;
}
bool netdev_can_create_queue(const struct net_device *dev,
--
2.43.0
^ permalink raw reply related
* [PATCH net-next v10 02/14] net: Implement netdev_nl_queue_create_doit
From: Daniel Borkmann @ 2026-03-27 12:10 UTC (permalink / raw)
To: netdev
Cc: bpf, kuba, davem, razor, pabeni, willemb, sdf, john.fastabend,
martin.lau, jordan, maciej.fijalkowski, magnus.karlsson, dw, toke,
yangzhenze, wangdongdong.6
In-Reply-To: <20260327121049.334562-1-daniel@iogearbox.net>
Implement netdev_nl_queue_create_doit which creates a new rx queue in a
virtual netdev and then leases it to a rx queue in a physical netdev.
Example with ynl client:
# ynl --family netdev --output-json --do queue-create \
--json '{"ifindex": 8, "type": "rx", "lease": {"ifindex": 4, "queue": {"type": "rx", "id": 15}}}'
{'id': 1}
Note that the netdevice locking order is always from the virtual to
the physical device.
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Co-developed-by: David Wei <dw@davidwei.uk>
Signed-off-by: David Wei <dw@davidwei.uk>
---
Documentation/networking/netdevices.rst | 6 +
include/linux/netdevice.h | 9 +-
include/net/netdev_queues.h | 19 ++-
include/net/netdev_rx_queue.h | 15 ++-
include/net/xdp_sock_drv.h | 2 +-
net/core/dev.c | 8 ++
net/core/dev.h | 5 +
net/core/netdev-genl.c | 164 +++++++++++++++++++++++-
net/core/netdev_queues.c | 62 +++++++++
net/core/netdev_rx_queue.c | 46 ++++++-
net/xdp/xsk.c | 2 +-
11 files changed, 325 insertions(+), 13 deletions(-)
diff --git a/Documentation/networking/netdevices.rst b/Documentation/networking/netdevices.rst
index 35704d115312..83e28b96884f 100644
--- a/Documentation/networking/netdevices.rst
+++ b/Documentation/networking/netdevices.rst
@@ -329,6 +329,12 @@ by setting ``request_ops_lock`` to true. Code comments and docs refer
to drivers which have ops called under the instance lock as "ops locked".
See also the documentation of the ``lock`` member of struct net_device.
+There is also a case of taking two per-netdev locks in sequence when netdev
+queues are leased, that is, the netdev-scope lock is taken for both the
+virtual and the physical device. To prevent deadlocks, the virtual device's
+lock must always be acquired before the physical device's (see
+``netdev_nl_queue_create_doit``).
+
In the future, there will be an option for individual
drivers to opt out of using ``rtnl_lock`` and instead perform their control
operations directly under the netdev instance lock.
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index e15367373f7c..e8aa9cc4075d 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -2561,7 +2561,14 @@ struct net_device {
* Also protects some fields in:
* struct napi_struct, struct netdev_queue, struct netdev_rx_queue
*
- * Ordering: take after rtnl_lock.
+ * Ordering:
+ *
+ * - take after rtnl_lock
+ *
+ * - for the case of netdev queue leasing, the netdev-scope lock is
+ * taken for both the virtual and the physical device; to prevent
+ * deadlocks, the virtual device's lock must always be acquired
+ * before the physical device's (see netdev_nl_queue_create_doit)
*/
struct mutex lock;
diff --git a/include/net/netdev_queues.h b/include/net/netdev_queues.h
index 95ed28212f4e..748b70552ed1 100644
--- a/include/net/netdev_queues.h
+++ b/include/net/netdev_queues.h
@@ -150,6 +150,11 @@ enum {
* When NIC-wide config is changed the callback will
* be invoked for all queues.
*
+ * @ndo_queue_create: Create a new RX queue on a virtual device that will
+ * be paired with a physical device's queue via leasing.
+ * Return the new queue id on success, negative error
+ * on failure.
+ *
* @supported_params: Bitmask of supported parameters, see QCFG_*.
*
* Note that @ndo_queue_mem_alloc and @ndo_queue_mem_free may be called while
@@ -178,6 +183,8 @@ struct netdev_queue_mgmt_ops {
struct netlink_ext_ack *extack);
struct device * (*ndo_queue_get_dma_dev)(struct net_device *dev,
int idx);
+ int (*ndo_queue_create)(struct net_device *dev,
+ struct netlink_ext_ack *extack);
unsigned int supported_params;
};
@@ -185,7 +192,7 @@ struct netdev_queue_mgmt_ops {
void netdev_queue_config(struct net_device *dev, int rxq,
struct netdev_queue_config *qcfg);
-bool netif_rxq_has_unreadable_mp(struct net_device *dev, int idx);
+bool netif_rxq_has_unreadable_mp(struct net_device *dev, unsigned int rxq_idx);
/**
* DOC: Lockless queue stopping / waking helpers.
@@ -374,5 +381,11 @@ static inline unsigned int netif_xmit_timeout_ms(struct netdev_queue *txq)
})
struct device *netdev_queue_get_dma_dev(struct net_device *dev, int idx);
-
-#endif
+bool netdev_can_create_queue(const struct net_device *dev,
+ struct netlink_ext_ack *extack);
+bool netdev_can_lease_queue(const struct net_device *dev,
+ struct netlink_ext_ack *extack);
+bool netdev_queue_busy(struct net_device *dev, unsigned int idx,
+ enum netdev_queue_type type,
+ struct netlink_ext_ack *extack);
+#endif /* _LINUX_NET_QUEUES_H */
diff --git a/include/net/netdev_rx_queue.h b/include/net/netdev_rx_queue.h
index 08f81329fc11..1d41c253f0a3 100644
--- a/include/net/netdev_rx_queue.h
+++ b/include/net/netdev_rx_queue.h
@@ -31,6 +31,14 @@ struct netdev_rx_queue {
struct napi_struct *napi;
struct netdev_queue_config qcfg;
struct pp_memory_provider_params mp_params;
+
+ /* If a queue is leased, then the lease pointer is always
+ * valid. From the physical device it points to the virtual
+ * queue, and from the virtual device it points to the
+ * physical queue.
+ */
+ struct netdev_rx_queue *lease;
+ netdevice_tracker lease_tracker;
} ____cacheline_aligned_in_smp;
/*
@@ -60,5 +68,8 @@ get_netdev_rx_queue_index(struct netdev_rx_queue *queue)
}
int netdev_rx_queue_restart(struct net_device *dev, unsigned int rxq);
-
-#endif
+void netdev_rx_queue_lease(struct netdev_rx_queue *rxq_dst,
+ struct netdev_rx_queue *rxq_src);
+void netdev_rx_queue_unlease(struct netdev_rx_queue *rxq_dst,
+ struct netdev_rx_queue *rxq_src);
+#endif /* _LINUX_NETDEV_RX_QUEUE_H */
diff --git a/include/net/xdp_sock_drv.h b/include/net/xdp_sock_drv.h
index 6b9ebae2dc95..06d4609b6ebd 100644
--- a/include/net/xdp_sock_drv.h
+++ b/include/net/xdp_sock_drv.h
@@ -28,7 +28,7 @@ void xsk_tx_completed(struct xsk_buff_pool *pool, u32 nb_entries);
bool xsk_tx_peek_desc(struct xsk_buff_pool *pool, struct xdp_desc *desc);
u32 xsk_tx_peek_release_desc_batch(struct xsk_buff_pool *pool, u32 max);
void xsk_tx_release(struct xsk_buff_pool *pool);
-struct xsk_buff_pool *xsk_get_pool_from_qid(struct net_device *dev,
+struct xsk_buff_pool *xsk_get_pool_from_qid(const struct net_device *dev,
u16 queue_id);
void xsk_set_rx_need_wakeup(struct xsk_buff_pool *pool);
void xsk_set_tx_need_wakeup(struct xsk_buff_pool *pool);
diff --git a/net/core/dev.c b/net/core/dev.c
index ae8fe706c486..59b7b86bb171 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1121,6 +1121,14 @@ netdev_get_by_index_lock_ops_compat(struct net *net, int ifindex)
return __netdev_put_lock_ops_compat(dev, net);
}
+struct net_device *
+netdev_put_lock(struct net_device *dev, struct net *net,
+ netdevice_tracker *tracker)
+{
+ netdev_tracker_free(dev, tracker);
+ return __netdev_put_lock(dev, net);
+}
+
struct net_device *
netdev_xa_find_lock(struct net *net, struct net_device *dev,
unsigned long *index)
diff --git a/net/core/dev.h b/net/core/dev.h
index 781619e76b3e..6516ce2b5517 100644
--- a/net/core/dev.h
+++ b/net/core/dev.h
@@ -31,6 +31,8 @@ netdev_napi_by_id_lock(struct net *net, unsigned int napi_id);
struct net_device *dev_get_by_napi_id(unsigned int napi_id);
struct net_device *__netdev_put_lock(struct net_device *dev, struct net *net);
+struct net_device *netdev_put_lock(struct net_device *dev, struct net *net,
+ netdevice_tracker *tracker);
struct net_device *
netdev_xa_find_lock(struct net *net, struct net_device *dev,
unsigned long *index);
@@ -96,6 +98,9 @@ int netdev_queue_config_validate(struct net_device *dev, int rxq_idx,
struct netdev_queue_config *qcfg,
struct netlink_ext_ack *extack);
+bool netif_rxq_has_mp(struct net_device *dev, unsigned int rxq_idx);
+bool netif_rxq_is_leased(struct net_device *dev, unsigned int rxq_idx);
+
/* netdev management, shared between various uAPI entry points */
struct netdev_name_node {
struct hlist_node hlist;
diff --git a/net/core/netdev-genl.c b/net/core/netdev-genl.c
index aae75431858d..5d5e5b9a8af0 100644
--- a/net/core/netdev-genl.c
+++ b/net/core/netdev-genl.c
@@ -1122,7 +1122,169 @@ int netdev_nl_bind_tx_doit(struct sk_buff *skb, struct genl_info *info)
int netdev_nl_queue_create_doit(struct sk_buff *skb, struct genl_info *info)
{
- return -EOPNOTSUPP;
+ const int qmaxtype = ARRAY_SIZE(netdev_queue_id_nl_policy) - 1;
+ const int lmaxtype = ARRAY_SIZE(netdev_lease_nl_policy) - 1;
+ int err, ifindex, ifindex_lease, queue_id, queue_id_lease;
+ struct nlattr *qtb[ARRAY_SIZE(netdev_queue_id_nl_policy)];
+ struct nlattr *ltb[ARRAY_SIZE(netdev_lease_nl_policy)];
+ struct netdev_rx_queue *rxq, *rxq_lease;
+ struct net_device *dev, *dev_lease;
+ netdevice_tracker dev_tracker;
+ s32 netns_lease = -1;
+ struct nlattr *nest;
+ struct sk_buff *rsp;
+ struct net *net;
+ void *hdr;
+
+ if (GENL_REQ_ATTR_CHECK(info, NETDEV_A_QUEUE_IFINDEX) ||
+ GENL_REQ_ATTR_CHECK(info, NETDEV_A_QUEUE_TYPE) ||
+ GENL_REQ_ATTR_CHECK(info, NETDEV_A_QUEUE_LEASE))
+ return -EINVAL;
+ if (nla_get_u32(info->attrs[NETDEV_A_QUEUE_TYPE]) !=
+ NETDEV_QUEUE_TYPE_RX) {
+ NL_SET_BAD_ATTR(info->extack, info->attrs[NETDEV_A_QUEUE_TYPE]);
+ return -EINVAL;
+ }
+
+ ifindex = nla_get_u32(info->attrs[NETDEV_A_QUEUE_IFINDEX]);
+
+ nest = info->attrs[NETDEV_A_QUEUE_LEASE];
+ err = nla_parse_nested(ltb, lmaxtype, nest,
+ netdev_lease_nl_policy, info->extack);
+ if (err < 0)
+ return err;
+ if (NL_REQ_ATTR_CHECK(info->extack, nest, ltb, NETDEV_A_LEASE_IFINDEX) ||
+ NL_REQ_ATTR_CHECK(info->extack, nest, ltb, NETDEV_A_LEASE_QUEUE))
+ return -EINVAL;
+ if (ltb[NETDEV_A_LEASE_NETNS_ID]) {
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ netns_lease = nla_get_s32(ltb[NETDEV_A_LEASE_NETNS_ID]);
+ }
+
+ ifindex_lease = nla_get_u32(ltb[NETDEV_A_LEASE_IFINDEX]);
+
+ nest = ltb[NETDEV_A_LEASE_QUEUE];
+ err = nla_parse_nested(qtb, qmaxtype, nest,
+ netdev_queue_id_nl_policy, info->extack);
+ if (err < 0)
+ return err;
+ if (NL_REQ_ATTR_CHECK(info->extack, nest, qtb, NETDEV_A_QUEUE_ID) ||
+ NL_REQ_ATTR_CHECK(info->extack, nest, qtb, NETDEV_A_QUEUE_TYPE))
+ return -EINVAL;
+ if (nla_get_u32(qtb[NETDEV_A_QUEUE_TYPE]) != NETDEV_QUEUE_TYPE_RX) {
+ NL_SET_BAD_ATTR(info->extack, qtb[NETDEV_A_QUEUE_TYPE]);
+ return -EINVAL;
+ }
+
+ queue_id_lease = nla_get_u32(qtb[NETDEV_A_QUEUE_ID]);
+
+ rsp = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
+ if (!rsp)
+ return -ENOMEM;
+
+ hdr = genlmsg_iput(rsp, info);
+ if (!hdr) {
+ err = -EMSGSIZE;
+ goto err_genlmsg_free;
+ }
+
+ /* Locking order is always from the virtual to the physical device
+ * since this is also the same order when applications open the
+ * memory provider later on.
+ */
+ dev = netdev_get_by_index_lock(genl_info_net(info), ifindex);
+ if (!dev) {
+ err = -ENODEV;
+ goto err_genlmsg_free;
+ }
+ if (!netdev_can_create_queue(dev, info->extack)) {
+ err = -EINVAL;
+ goto err_unlock_dev;
+ }
+
+ net = genl_info_net(info);
+ if (netns_lease >= 0) {
+ net = get_net_ns_by_id(net, netns_lease);
+ if (!net) {
+ err = -ENONET;
+ goto err_unlock_dev;
+ }
+ }
+
+ dev_lease = netdev_get_by_index(net, ifindex_lease, &dev_tracker,
+ GFP_KERNEL);
+ if (!dev_lease) {
+ err = -ENODEV;
+ goto err_put_netns;
+ }
+ if (!netdev_can_lease_queue(dev_lease, info->extack)) {
+ netdev_put(dev_lease, &dev_tracker);
+ err = -EINVAL;
+ goto err_put_netns;
+ }
+
+ dev_lease = netdev_put_lock(dev_lease, net, &dev_tracker);
+ if (!dev_lease) {
+ err = -ENODEV;
+ goto err_put_netns;
+ }
+ if (queue_id_lease >= dev_lease->real_num_rx_queues) {
+ err = -ERANGE;
+ NL_SET_BAD_ATTR(info->extack, qtb[NETDEV_A_QUEUE_ID]);
+ goto err_unlock_dev_lease;
+ }
+ if (netdev_queue_busy(dev_lease, queue_id_lease, NETDEV_QUEUE_TYPE_RX,
+ info->extack)) {
+ err = -EBUSY;
+ goto err_unlock_dev_lease;
+ }
+
+ rxq_lease = __netif_get_rx_queue(dev_lease, queue_id_lease);
+ rxq = __netif_get_rx_queue(dev, dev->real_num_rx_queues - 1);
+
+ /* Leasing queues from different physical devices is currently
+ * not supported. Capabilities such as XDP features and DMA
+ * device may differ between physical devices, and computing
+ * a correct intersection for the virtual device is not yet
+ * implemented.
+ */
+ if (rxq->lease && rxq->lease->dev != dev_lease) {
+ err = -EOPNOTSUPP;
+ NL_SET_ERR_MSG(info->extack,
+ "Leasing queues from different devices not supported");
+ goto err_unlock_dev_lease;
+ }
+
+ queue_id = dev->queue_mgmt_ops->ndo_queue_create(dev, info->extack);
+ if (queue_id < 0) {
+ err = queue_id;
+ goto err_unlock_dev_lease;
+ }
+ rxq = __netif_get_rx_queue(dev, queue_id);
+
+ netdev_rx_queue_lease(rxq, rxq_lease);
+
+ nla_put_u32(rsp, NETDEV_A_QUEUE_ID, queue_id);
+ genlmsg_end(rsp, hdr);
+
+ netdev_unlock(dev_lease);
+ netdev_unlock(dev);
+ if (netns_lease >= 0)
+ put_net(net);
+
+ return genlmsg_reply(rsp, info);
+
+err_unlock_dev_lease:
+ netdev_unlock(dev_lease);
+err_put_netns:
+ if (netns_lease >= 0)
+ put_net(net);
+err_unlock_dev:
+ netdev_unlock(dev);
+err_genlmsg_free:
+ nlmsg_free(rsp);
+ return err;
}
void netdev_nl_sock_priv_init(struct netdev_nl_sock *priv)
diff --git a/net/core/netdev_queues.c b/net/core/netdev_queues.c
index 251f27a8307f..177401828e79 100644
--- a/net/core/netdev_queues.c
+++ b/net/core/netdev_queues.c
@@ -1,6 +1,10 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include <net/netdev_queues.h>
+#include <net/netdev_rx_queue.h>
+#include <net/xdp_sock_drv.h>
+
+#include "dev.h"
/**
* netdev_queue_get_dma_dev() - get dma device for zero-copy operations
@@ -25,3 +29,61 @@ struct device *netdev_queue_get_dma_dev(struct net_device *dev, int idx)
return dma_dev && dma_dev->dma_mask ? dma_dev : NULL;
}
+bool netdev_can_create_queue(const struct net_device *dev,
+ struct netlink_ext_ack *extack)
+{
+ if (dev->dev.parent) {
+ NL_SET_ERR_MSG(extack, "Device is not a virtual device");
+ return false;
+ }
+ if (!dev->queue_mgmt_ops ||
+ !dev->queue_mgmt_ops->ndo_queue_create) {
+ NL_SET_ERR_MSG(extack, "Device does not support queue creation");
+ return false;
+ }
+ if (dev->real_num_rx_queues < 1 ||
+ dev->real_num_tx_queues < 1) {
+ NL_SET_ERR_MSG(extack, "Device must have at least one real queue");
+ return false;
+ }
+ return true;
+}
+
+bool netdev_can_lease_queue(const struct net_device *dev,
+ struct netlink_ext_ack *extack)
+{
+ if (!dev->dev.parent) {
+ NL_SET_ERR_MSG(extack, "Lease device is a virtual device");
+ return false;
+ }
+ if (!netif_device_present(dev)) {
+ NL_SET_ERR_MSG(extack, "Lease device has been removed from the system");
+ return false;
+ }
+ if (!dev->queue_mgmt_ops) {
+ NL_SET_ERR_MSG(extack, "Lease device does not support queue management operations");
+ return false;
+ }
+ return true;
+}
+
+bool netdev_queue_busy(struct net_device *dev, unsigned int idx,
+ enum netdev_queue_type type,
+ struct netlink_ext_ack *extack)
+{
+ if (xsk_get_pool_from_qid(dev, idx)) {
+ NL_SET_ERR_MSG(extack, "Device queue in use by AF_XDP");
+ return true;
+ }
+ if (type == NETDEV_QUEUE_TYPE_TX)
+ return false;
+ if (netif_rxq_is_leased(dev, idx)) {
+ NL_SET_ERR_MSG(extack, "Device queue in use due to queue leasing");
+ return true;
+ }
+ if (netif_rxq_has_mp(dev, idx)) {
+ NL_SET_ERR_MSG(extack, "Device queue in use by memory provider");
+ return true;
+ }
+ return false;
+}
diff --git a/net/core/netdev_rx_queue.c b/net/core/netdev_rx_queue.c
index 668a90658f25..a1f23c2c96d4 100644
--- a/net/core/netdev_rx_queue.c
+++ b/net/core/netdev_rx_queue.c
@@ -10,15 +10,53 @@
#include "dev.h"
#include "page_pool_priv.h"
-/* See also page_pool_is_unreadable() */
-bool netif_rxq_has_unreadable_mp(struct net_device *dev, int idx)
+void netdev_rx_queue_lease(struct netdev_rx_queue *rxq_dst,
+ struct netdev_rx_queue *rxq_src)
{
- struct netdev_rx_queue *rxq = __netif_get_rx_queue(dev, idx);
+ netdev_assert_locked(rxq_src->dev);
+ netdev_assert_locked(rxq_dst->dev);
+
+ netdev_hold(rxq_src->dev, &rxq_src->lease_tracker, GFP_KERNEL);
- return !!rxq->mp_params.mp_ops;
+ WRITE_ONCE(rxq_src->lease, rxq_dst);
+ WRITE_ONCE(rxq_dst->lease, rxq_src);
+}
+
+void netdev_rx_queue_unlease(struct netdev_rx_queue *rxq_dst,
+ struct netdev_rx_queue *rxq_src)
+{
+ netdev_assert_locked(rxq_dst->dev);
+ netdev_assert_locked(rxq_src->dev);
+
+ WRITE_ONCE(rxq_src->lease, NULL);
+ WRITE_ONCE(rxq_dst->lease, NULL);
+
+ netdev_put(rxq_src->dev, &rxq_src->lease_tracker);
+}
+
+bool netif_rxq_is_leased(struct net_device *dev, unsigned int rxq_idx)
+{
+ if (rxq_idx < dev->real_num_rx_queues)
+ return READ_ONCE(__netif_get_rx_queue(dev, rxq_idx)->lease);
+ return false;
+}
+
+/* See also page_pool_is_unreadable() */
+bool netif_rxq_has_unreadable_mp(struct net_device *dev, unsigned int rxq_idx)
+{
+ if (rxq_idx < dev->real_num_rx_queues)
+ return __netif_get_rx_queue(dev, rxq_idx)->mp_params.mp_ops;
+ return false;
}
EXPORT_SYMBOL(netif_rxq_has_unreadable_mp);
+bool netif_rxq_has_mp(struct net_device *dev, unsigned int rxq_idx)
+{
+ if (rxq_idx < dev->real_num_rx_queues)
+ return __netif_get_rx_queue(dev, rxq_idx)->mp_params.mp_priv;
+ return false;
+}
+
static int netdev_rx_queue_reconfig(struct net_device *dev,
unsigned int rxq_idx,
struct netdev_queue_config *qcfg_old,
diff --git a/net/xdp/xsk.c b/net/xdp/xsk.c
index 6149f6a79897..79f31705276f 100644
--- a/net/xdp/xsk.c
+++ b/net/xdp/xsk.c
@@ -103,7 +103,7 @@ bool xsk_uses_need_wakeup(struct xsk_buff_pool *pool)
}
EXPORT_SYMBOL(xsk_uses_need_wakeup);
-struct xsk_buff_pool *xsk_get_pool_from_qid(struct net_device *dev,
+struct xsk_buff_pool *xsk_get_pool_from_qid(const struct net_device *dev,
u16 queue_id)
{
if (queue_id < dev->real_num_rx_queues)
--
2.43.0
^ permalink raw reply related
* [PATCH net-next v10 09/14] xsk: Proxy pool management for leased queues
From: Daniel Borkmann @ 2026-03-27 12:10 UTC (permalink / raw)
To: netdev
Cc: bpf, kuba, davem, razor, pabeni, willemb, sdf, john.fastabend,
martin.lau, jordan, maciej.fijalkowski, magnus.karlsson, dw, toke,
yangzhenze, wangdongdong.6
In-Reply-To: <20260327121049.334562-1-daniel@iogearbox.net>
Similarly to the netif_mp_{open,close}_rxq handling for leased queues, proxy
the xsk_{reg,clear}_pool_at_qid via netif_get_rx_queue_lease_locked such
that in case a virtual netdev picked a leased rxq, the request gets through
to the real rxq in the physical netdev. The proxying is only relevant for
queue_id < dev->real_num_rx_queues since right now it's only supported for
rxqs.
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Co-developed-by: David Wei <dw@davidwei.uk>
Signed-off-by: David Wei <dw@davidwei.uk>
Acked-by: Stanislav Fomichev <sdf@fomichev.me>
Reviewed-by: Nikolay Aleksandrov <razor@blackwall.org>
---
net/xdp/xsk.c | 47 +++++++++++++++++++++++++++++++++++------------
1 file changed, 35 insertions(+), 12 deletions(-)
diff --git a/net/xdp/xsk.c b/net/xdp/xsk.c
index 3fab551eeaf7..f4b048f3c123 100644
--- a/net/xdp/xsk.c
+++ b/net/xdp/xsk.c
@@ -23,6 +23,8 @@
#include <linux/netdevice.h>
#include <linux/rculist.h>
#include <linux/vmalloc.h>
+
+#include <net/netdev_queues.h>
#include <net/xdp_sock_drv.h>
#include <net/busy_poll.h>
#include <net/netdev_lock.h>
@@ -117,10 +119,18 @@ EXPORT_SYMBOL(xsk_get_pool_from_qid);
void xsk_clear_pool_at_qid(struct net_device *dev, u16 queue_id)
{
- if (queue_id < dev->num_rx_queues)
- dev->_rx[queue_id].pool = NULL;
- if (queue_id < dev->num_tx_queues)
- dev->_tx[queue_id].pool = NULL;
+ struct net_device *orig_dev = dev;
+ unsigned int id = queue_id;
+
+ if (id < dev->real_num_rx_queues)
+ WARN_ON_ONCE(!netif_get_rx_queue_lease_locked(&dev, &id));
+
+ if (id < dev->num_rx_queues)
+ dev->_rx[id].pool = NULL;
+ if (id < dev->num_tx_queues)
+ dev->_tx[id].pool = NULL;
+
+ netif_put_rx_queue_lease_locked(orig_dev, dev);
}
/* The buffer pool is stored both in the _rx struct and the _tx struct as we do
@@ -130,17 +140,30 @@ void xsk_clear_pool_at_qid(struct net_device *dev, u16 queue_id)
int xsk_reg_pool_at_qid(struct net_device *dev, struct xsk_buff_pool *pool,
u16 queue_id)
{
- if (queue_id >= max_t(unsigned int,
- dev->real_num_rx_queues,
- dev->real_num_tx_queues))
+ struct net_device *orig_dev = dev;
+ unsigned int id = queue_id;
+ int ret = 0;
+
+ if (id >= max(dev->real_num_rx_queues,
+ dev->real_num_tx_queues))
return -EINVAL;
- if (queue_id < dev->real_num_rx_queues)
- dev->_rx[queue_id].pool = pool;
- if (queue_id < dev->real_num_tx_queues)
- dev->_tx[queue_id].pool = pool;
+ if (id < dev->real_num_rx_queues) {
+ if (!netif_get_rx_queue_lease_locked(&dev, &id))
+ return -EBUSY;
+ if (xsk_get_pool_from_qid(dev, id)) {
+ ret = -EBUSY;
+ goto out;
+ }
+ }
- return 0;
+ if (id < dev->real_num_rx_queues)
+ dev->_rx[id].pool = pool;
+ if (id < dev->real_num_tx_queues)
+ dev->_tx[id].pool = pool;
+out:
+ netif_put_rx_queue_lease_locked(orig_dev, dev);
+ return ret;
}
static int __xsk_rcv_zc(struct xdp_sock *xs, struct xdp_buff_xsk *xskb, u32 len,
--
2.43.0
^ permalink raw reply related
* [PATCH net-next v10 00/14] netkit: Support for io_uring zero-copy and AF_XDP
From: Daniel Borkmann @ 2026-03-27 12:10 UTC (permalink / raw)
To: netdev
Cc: bpf, kuba, davem, razor, pabeni, willemb, sdf, john.fastabend,
martin.lau, jordan, maciej.fijalkowski, magnus.karlsson, dw, toke,
yangzhenze, wangdongdong.6
Containers use virtual netdevs to route traffic from a physical netdev
in the host namespace. They do not have access to the physical netdev
in the host and thus can't use memory providers or AF_XDP that require
reconfiguring/restarting queues in the physical netdev.
This patchset adds the concept of queue leasing to virtual netdevs that
allow containers to use memory providers and AF_XDP at native speed.
Leased queues are bound to a real queue in a physical netdev and act
as a proxy.
Memory providers and AF_XDP operations take an ifindex and queue id,
so containers would pass in an ifindex for a virtual netdev and a queue
id of a leased queue, which then gets proxied to the underlying real
queue.
We have implemented support for this concept in netkit and tested the
latter against Nvidia ConnectX-6 (mlx5) as well as Broadcom BCM957504
(bnxt_en) 100G NICs. For more details see the individual patches.
v9->v10:
- Fix netkit selftest ruff checks (Jakub)
- Pass in net arg in netdev_put_lock (Gemini)
- Make the ethtool channel busy checks direction-aware (Gemini)
- Fix list corruption in netkit_check_lease_unregister (Gemini)
- Fix netkit_set_headroom in single device mode (Gemini)
- Fix xsk_clear_pool_at_qid bounds to use num_{rx,tx}_queues (Gemini)
- Fix netkit xsk teardown state checks (Gemini)
- The remainder of the Gemini findings were non-issues
- Rebase and retested everything with mlx5 + bnxt_en
v8->v9:
- Use ynl --family netdev in commit desc (Jakub)
- Update docs and comments about locking (Jakub)
- Propagate extack to the driver in ndo_queue_create (Jakub)
- Move function to net/core/dev.h core where possible (Jakub)
- Add comment about lease in netdev_rx_queue struct (Jakub)
- Add min: 0 check to netns id in policy (Jakub)
- Drop ifindex == ifindex_lease test in netdev_nl_queue_create_doit (Jakub)
- Detailed extack errors in netkit's ndo_queue_create (Jakub)
- Refactor lease dump into own function in netdev_nl_queue_fill_one (Jakub)
- Dump mp and xsk info for both queues in netdev_nl_queue_fill_one (Jakub)
- Replace the net_ prefix with netif_ for net_mp_{open,close}_rxq (Jakub)
- Remove ifq_idx naming cleanup from net_mp_{open,close}_rxq (Jakub)
- Rework the mp entry points to have explicit code that deals with
the lease (Jakub)
- Fix locking in netdev_queue_get_dma_dev (Jakub)
- Remove unneeded carrier flap in netkit_queue_create (Jakub)
- Drop base net selftests that were already merged
- Add more nekit queue leasing coverage of base functionality (Jakub)
- Remove any mp leftovers upon unlease found via test cases
- Rebase and retested everything with mlx5 + bnxt_en
v7->v8:
- Rework and refactor net_mp_{open,close}_rxq patch (Jakub)
- Moved queue lease netlink command from env into test (Jakub)
- Support netns_id also in queue create call and not only dump
- Rebase and retested everything with mlx5 + bnxt_en
v6->v7:
- Add xsk_dev_queue_valid real_num_rx_queues check given bound
xs->queue_id could be from a TX queue (Claude)
- Fix up exception path in queue leasing selftest (Claude)
- Rebase and retested everything with mlx5 + bnxt_en
v5->v6:
- Fix nest_queue test in netdev_nl_queue_fill_one (Jakub/Claude)
- Fix netdev notifier locking leak (Jakub/Claude)
- Drop NETREG_UNREGISTERING WARN_ON_ONCE to avoid confusion (Stan)
- Remove slipped-in .gitignore cruft in net selftest (Stan)
- Fix Pylint warnings in net selftest (Jakub)
- Rebase and retested everything with mlx5 + bnxt_en
v4->v5:
- Rework of the core API into queue-create op (Jakub)
- Rename from queue peering to queue leasing (Jakub)
- Add net selftests for queue leasing (Stan, Jakub)
- Move netkit_queue_get_dma_dev into core (Jakub)
- Dropped netkit_get_channels (Jakub)
- Moved ndo_queue_create back to return index or error (Jakub)
- Inline __netdev_rx_queue_{peer,unpeer} helpers (Jakub)
- Adding helpers in patches where they are used (Jakub)
- Undo inline for netdev_put_lock (Jakub)
- Factoring out checks whether device can lease (Jakub)
- Fix up return codes in netdev_nl_bind_queue_doit (Jakub)
- Reject when AF_XDP or mp already bound (Jakub)
- Switch some error cases to NL_SET_BAD_ATTR() (Jakub)
- Rebase and retested everything with mlx5 + bnxt_en
v3->v4:
- ndo_queue_create store dst queue via arg (Nikolay)
- Small nits like a spelling issue + rev xmas (Nikolay)
- admin-perm flag in bind-queue spec (Jakub)
- Fix potential ABBA deadlock situation in bind (Jakub, Paolo, Stan)
- Add a peer dev_tracker to not reuse the sysfs one (Jakub)
- New patch (12/14) to handle the underlying device going away (Jakub)
- Improve commit message on queue-get (Jakub)
- Do not expose phys dev info from container on queue-get (Jakub)
- Add netif_put_rx_queue_peer_locked to simplify code (Stan)
- Rework xsk handling to simplify the code and drop a few patches
- Rebase and retested everything with mlx5 + bnxt_en
v2->v3:
- Use netdev_ops_assert_locked instead of netdev_assert_locked (syzbot)
- Add missing netdev_lockdep_set_classes in netkit
v1->v2:
- Removed bind sample ynl code (Stan)
- Reworked netdev locking to have consistent order (Stan, Kuba)
- Return 'not supported' in API patch (Stan)
- Improved ynl documentation (Kuba)
- Added 'max: s32-max' in ynl spec for ifindex (Kuba)
- Added also queue type in ynl to have user specify rx to make
it obvious (Kuba)
- Use of netdev_hold (Kuba)
- Avoid static inlines from another header (Kuba)
- Squashed some commits (Kuba, Stan)
- Removed ndo_{peer,unpeer}_queues callback and simplified
code (Kuba)
- Improved commit messages (Toke, Kuba, Stan, zf)
- Got rid of locking genl_sk_priv_get (Stan)
- Removed af_xdp cleanup churn (Maciej)
- Added netdev locking asserts (Stan)
- Reject ethtool ioctl path queue resizing (Kuba)
- Added kdoc for ndo_queue_create (Stan)
- Uninvert logic in netkit single dev mode (Jordan)
- Added binding support for multiple queues
Daniel Borkmann (10):
net: Add queue-create operation
net: Implement netdev_nl_queue_create_doit
net: Add lease info to queue-get response
net, ethtool: Disallow leased real rxqs to be resized
net: Slightly simplify net_mp_{open,close}_rxq
xsk: Extend xsk_rcv_check validation
xsk: Proxy pool management for leased queues
netkit: Add single device mode for netkit
netkit: Add netkit notifier to check for unregistering devices
netkit: Add xsk support for af_xdp applications
David Wei (4):
net: Proxy netif_mp_{open,close}_rxq for leased queues
net: Proxy netdev_queue_get_dma_dev for leased queues
netkit: Implement rtnl_link_ops->alloc and ndo_queue_create
selftests/net: Add queue leasing tests with netkit
Documentation/netlink/specs/netdev.yaml | 46 ++
Documentation/networking/netdevices.rst | 6 +
drivers/net/netkit.c | 410 ++++++++++--
include/linux/netdevice.h | 11 +-
include/net/netdev_queues.h | 22 +-
include/net/netdev_rx_queue.h | 29 +-
include/net/page_pool/memory_provider.h | 8 +-
include/net/xdp_sock_drv.h | 2 +-
include/uapi/linux/if_link.h | 6 +
include/uapi/linux/netdev.h | 11 +
io_uring/zcrx.c | 9 +-
net/core/dev.c | 14 +
net/core/dev.h | 7 +
net/core/devmem.c | 6 +-
net/core/netdev-genl-gen.c | 20 +
net/core/netdev-genl-gen.h | 2 +
net/core/netdev-genl.c | 233 ++++++-
net/core/netdev_queues.c | 98 ++-
net/core/netdev_rx_queue.c | 194 +++++-
net/ethtool/channels.c | 17 +-
net/ethtool/ioctl.c | 16 +-
net/xdp/xsk.c | 78 ++-
tools/include/uapi/linux/netdev.h | 11 +
.../testing/selftests/drivers/net/hw/Makefile | 1 +
.../drivers/net/hw/lib/py/__init__.py | 4 +-
.../selftests/drivers/net/hw/nk_qlease.py | 597 ++++++++++++++++++
26 files changed, 1703 insertions(+), 155 deletions(-)
create mode 100755 tools/testing/selftests/drivers/net/hw/nk_qlease.py
--
2.43.0
^ permalink raw reply
* [PATCH net-next v10 11/14] netkit: Implement rtnl_link_ops->alloc and ndo_queue_create
From: Daniel Borkmann @ 2026-03-27 12:10 UTC (permalink / raw)
To: netdev
Cc: bpf, kuba, davem, razor, pabeni, willemb, sdf, john.fastabend,
martin.lau, jordan, maciej.fijalkowski, magnus.karlsson, dw, toke,
yangzhenze, wangdongdong.6
In-Reply-To: <20260327121049.334562-1-daniel@iogearbox.net>
From: David Wei <dw@davidwei.uk>
Implement rtnl_link_ops->alloc that allows the number of rx queues to be
set when netkit is created. By default, netkit has only a single rxq (and
single txq). The number of queues is deliberately not allowed to be changed
via ethtool -L and is fixed for the lifetime of a netkit instance.
For netkit device creation, numrxqueues with larger than one rxq can be
specified. These rxqs are leasable to real rxqs in physical netdevs:
ip link add type netkit peer numrxqueues 64 # for device pair
ip link add numrxqueues 64 type netkit single # for single device
The limit of numrxqueues for netkit is currently set to 1024, which allows
leasing multiple real rxqs from physical netdevs.
The implementation of ndo_queue_create() adds a new rxq during the queue
lease operation. We allow to create queues either in single device mode
or for the case of dual device mode for the netkit peer device which gets
placed into the target network namespace. For dual device mode the lease
against the primary device does not make sense for the targeted use cases,
and therefore gets rejected.
We also need to add a lockdep class for netkit, such that lockdep does
not trip over us, similarly done as in commit 0bef512012b1 ("net: add
netdev_lockdep_set_classes() to virtual drivers").
This is also the last missing bit to netkit for supporting io_uring with
zero-copy mode [0]. Up until this point it was not possible to consume the
latter out of containers or Kubernetes Pods where applications are in their
own network namespace.
io_uring example with eth0 being a physical device with 16 queues where
netkit is bound to the last queue, iou-zcrx.c is binary from selftests.
Flow steering to that queue is based on the service VIP:port of the
server utilizing io_uring:
# ethtool -X eth0 start 0 equal 15
# ethtool -X eth0 start 15 equal 1 context new
# ethtool --config-ntuple eth0 flow-type tcp4 dst-ip 1.2.3.4 dst-port 5000 action 15
# ip netns add foo
# ip link add type netkit peer numrxqueues 2
# ynl --family netdev --output-json --do queue-create \
--json "{"ifindex": $(ifindex nk0), "type": "rx", \
"lease": { "ifindex": $(ifindex eth0), \
"queue": { "type": "rx", "id": 15 } } }"
{'id': 1}
# ip link set nk0 netns foo
# ip link set nk1 up
# ip netns exec foo ip link set lo up
# ip netns exec foo ip link set nk0 up
# ip netns exec foo ip addr add 1.2.3.4/32 dev nk0
[ ... setup routing etc to get external traffic into the netns ... ]
# ip netns exec foo ./iou-zcrx -s -p 5000 -i nk0 -q 1
Remote io_uring client:
# ./iou-zcrx -c -h 1.2.3.4 -p 5000 -l 12840 -z 65536
We have tested the above against a Broadcom BCM957504 (bnxt_en) 100G NIC,
supporting TCP header/data split.
Similarly, this also works for devmem which we tested using ncdevmem:
# ip netns exec foo ./ncdevmem -s 1.2.3.4 -l -p 5000 -f nk0 -t 1 -q 1
And on the remote client:
# ./ncdevmem -s 1.2.3.4 -p 5000 -f eth0
For Cilium, the plan is to open up support for the various memory providers
for regular Kubernetes Pods when Cilium is configured with netkit datapath
mode.
Signed-off-by: David Wei <dw@davidwei.uk>
Co-developed-by: Daniel Borkmann <daniel@iogearbox.net>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Reviewed-by: Nikolay Aleksandrov <razor@blackwall.org>
Link: https://kernel-recipes.org/en/2024/schedule/efficient-zero-copy-networking-using-io_uring [0]
---
drivers/net/netkit.c | 126 ++++++++++++++++++++++++++++++++++++++-----
1 file changed, 114 insertions(+), 12 deletions(-)
diff --git a/drivers/net/netkit.c b/drivers/net/netkit.c
index 1260c2ea88ca..a96fa81b098b 100644
--- a/drivers/net/netkit.c
+++ b/drivers/net/netkit.c
@@ -9,11 +9,20 @@
#include <linux/bpf_mprog.h>
#include <linux/indirect_call_wrapper.h>
+#include <net/netdev_lock.h>
+#include <net/netdev_queues.h>
+#include <net/netdev_rx_queue.h>
#include <net/netkit.h>
#include <net/dst.h>
#include <net/tcx.h>
-#define DRV_NAME "netkit"
+#define NETKIT_DRV_NAME "netkit"
+
+#define NETKIT_NUM_RX_QUEUES_MAX 1024
+#define NETKIT_NUM_TX_QUEUES_MAX 1
+
+#define NETKIT_NUM_RX_QUEUES_REAL 1
+#define NETKIT_NUM_TX_QUEUES_REAL 1
struct netkit {
__cacheline_group_begin(netkit_fastpath);
@@ -37,6 +46,8 @@ struct netkit_link {
struct net_device *dev;
};
+static struct rtnl_link_ops netkit_link_ops;
+
static __always_inline int
netkit_run(const struct bpf_mprog_entry *entry, struct sk_buff *skb,
enum netkit_action ret)
@@ -225,9 +236,16 @@ static void netkit_get_stats(struct net_device *dev,
stats->tx_dropped = DEV_STATS_READ(dev, tx_dropped);
}
+static int netkit_init(struct net_device *dev)
+{
+ netdev_lockdep_set_classes(dev);
+ return 0;
+}
+
static void netkit_uninit(struct net_device *dev);
static const struct net_device_ops netkit_netdev_ops = {
+ .ndo_init = netkit_init,
.ndo_open = netkit_open,
.ndo_stop = netkit_close,
.ndo_start_xmit = netkit_xmit,
@@ -244,13 +262,96 @@ static const struct net_device_ops netkit_netdev_ops = {
static void netkit_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
- strscpy(info->driver, DRV_NAME, sizeof(info->driver));
+ strscpy(info->driver, NETKIT_DRV_NAME, sizeof(info->driver));
}
static const struct ethtool_ops netkit_ethtool_ops = {
.get_drvinfo = netkit_get_drvinfo,
};
+static int netkit_queue_create(struct net_device *dev,
+ struct netlink_ext_ack *extack)
+{
+ struct netkit *nk = netkit_priv(dev);
+ u32 rxq_count_old, rxq_count_new;
+ int err;
+
+ rxq_count_old = dev->real_num_rx_queues;
+ rxq_count_new = rxq_count_old + 1;
+
+ /* In paired mode, only the non-primary (peer) device can
+ * create leased queues since the primary is the management
+ * side. In single device mode, leasing is always allowed.
+ */
+ if (nk->pair == NETKIT_DEVICE_PAIR && nk->primary) {
+ NL_SET_ERR_MSG(extack,
+ "netkit can only lease against the peer device");
+ return -EOPNOTSUPP;
+ }
+
+ err = netif_set_real_num_rx_queues(dev, rxq_count_new);
+ if (err) {
+ if (rxq_count_new > dev->num_rx_queues)
+ NL_SET_ERR_MSG(extack,
+ "netkit maximum queue limit reached");
+ else
+ NL_SET_ERR_MSG_FMT(extack,
+ "netkit cannot create more queues err=%d", err);
+ return err;
+ }
+
+ return rxq_count_old;
+}
+
+static const struct netdev_queue_mgmt_ops netkit_queue_mgmt_ops = {
+ .ndo_queue_create = netkit_queue_create,
+};
+
+static struct net_device *netkit_alloc(struct nlattr *tb[],
+ const char *ifname,
+ unsigned char name_assign_type,
+ unsigned int num_tx_queues,
+ unsigned int num_rx_queues)
+{
+ const struct rtnl_link_ops *ops = &netkit_link_ops;
+ struct net_device *dev;
+
+ if (num_tx_queues > NETKIT_NUM_TX_QUEUES_MAX ||
+ num_rx_queues > NETKIT_NUM_RX_QUEUES_MAX)
+ return ERR_PTR(-EOPNOTSUPP);
+
+ dev = alloc_netdev_mqs(ops->priv_size, ifname,
+ name_assign_type, ops->setup,
+ num_tx_queues, num_rx_queues);
+ if (dev) {
+ dev->real_num_tx_queues = NETKIT_NUM_TX_QUEUES_REAL;
+ dev->real_num_rx_queues = NETKIT_NUM_RX_QUEUES_REAL;
+ }
+ return dev;
+}
+
+static void netkit_queue_unlease(struct net_device *dev)
+{
+ struct netdev_rx_queue *rxq, *rxq_lease;
+ struct net_device *dev_lease;
+ int i;
+
+ if (dev->real_num_rx_queues == 1)
+ return;
+
+ netdev_lock(dev);
+ for (i = 1; i < dev->real_num_rx_queues; i++) {
+ rxq = __netif_get_rx_queue(dev, i);
+ rxq_lease = rxq->lease;
+ dev_lease = rxq_lease->dev;
+
+ netdev_lock(dev_lease);
+ netdev_rx_queue_unlease(rxq, rxq_lease);
+ netdev_unlock(dev_lease);
+ }
+ netdev_unlock(dev);
+}
+
static void netkit_setup(struct net_device *dev)
{
static const netdev_features_t netkit_features_hw_vlan =
@@ -281,8 +382,9 @@ static void netkit_setup(struct net_device *dev)
dev->priv_flags |= IFF_DISABLE_NETPOLL;
dev->lltx = true;
- dev->ethtool_ops = &netkit_ethtool_ops;
- dev->netdev_ops = &netkit_netdev_ops;
+ dev->netdev_ops = &netkit_netdev_ops;
+ dev->ethtool_ops = &netkit_ethtool_ops;
+ dev->queue_mgmt_ops = &netkit_queue_mgmt_ops;
dev->features |= netkit_features;
dev->hw_features = netkit_features;
@@ -331,8 +433,6 @@ static int netkit_validate(struct nlattr *tb[], struct nlattr *data[],
return 0;
}
-static struct rtnl_link_ops netkit_link_ops;
-
static int netkit_new_link(struct net_device *dev,
struct rtnl_newlink_params *params,
struct netlink_ext_ack *extack)
@@ -868,6 +968,7 @@ static void netkit_release_all(struct net_device *dev)
static void netkit_uninit(struct net_device *dev)
{
netkit_release_all(dev);
+ netkit_queue_unlease(dev);
}
static void netkit_del_link(struct net_device *dev, struct list_head *head)
@@ -1008,8 +1109,9 @@ static const struct nla_policy netkit_policy[IFLA_NETKIT_MAX + 1] = {
};
static struct rtnl_link_ops netkit_link_ops = {
- .kind = DRV_NAME,
+ .kind = NETKIT_DRV_NAME,
.priv_size = sizeof(struct netkit),
+ .alloc = netkit_alloc,
.setup = netkit_setup,
.newlink = netkit_new_link,
.dellink = netkit_del_link,
@@ -1023,7 +1125,7 @@ static struct rtnl_link_ops netkit_link_ops = {
.maxtype = IFLA_NETKIT_MAX,
};
-static __init int netkit_init(void)
+static __init int netkit_mod_init(void)
{
BUILD_BUG_ON((int)NETKIT_NEXT != (int)TCX_NEXT ||
(int)NETKIT_PASS != (int)TCX_PASS ||
@@ -1033,16 +1135,16 @@ static __init int netkit_init(void)
return rtnl_link_register(&netkit_link_ops);
}
-static __exit void netkit_exit(void)
+static __exit void netkit_mod_exit(void)
{
rtnl_link_unregister(&netkit_link_ops);
}
-module_init(netkit_init);
-module_exit(netkit_exit);
+module_init(netkit_mod_init);
+module_exit(netkit_mod_exit);
MODULE_DESCRIPTION("BPF-programmable network device");
MODULE_AUTHOR("Daniel Borkmann <daniel@iogearbox.net>");
MODULE_AUTHOR("Nikolay Aleksandrov <razor@blackwall.org>");
MODULE_LICENSE("GPL");
-MODULE_ALIAS_RTNL_LINK(DRV_NAME);
+MODULE_ALIAS_RTNL_LINK(NETKIT_DRV_NAME);
--
2.43.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox