* Re: [PATCH net-next 10/11] net: macb: use context swapping in .set_ringparam()
From: Théo Lebrun @ 2026-04-03 9:03 UTC (permalink / raw)
To: Théo Lebrun, Nicolai Buchwitz
Cc: Nicolas Ferre, Claudiu Beznea, Andrew Lunn, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Richard Cochran,
Russell King, Paolo Valerio, Conor Dooley, Vladimir Kondratiev,
Gregory CLEMENT, Benoît Monin, Tawfik Bayouk,
Thomas Petazzoni, Maxime Chevallier, netdev, linux-kernel
In-Reply-To: <DHIT9TPJQJ46.21A89R5UAFXVH@bootlin.com>
On Thu Apr 2, 2026 at 6:31 PM CEST, Théo Lebrun wrote:
> On Thu Apr 2, 2026 at 1:29 PM CEST, Nicolai Buchwitz wrote:
>> On 1.4.2026 18:39, Théo Lebrun wrote:
>>> ethtool_ops.set_ringparam() is implemented using the primitive close /
>>> update ring size / reopen sequence. Under memory pressure this does not
>>> fly: we free our buffers at close and cannot reallocate new ones at
>>> open. Also, it triggers a slow PHY reinit.
>>>
>>> Instead, exploit the new context mechanism and improve our sequence to:
>>> - allocate a new context (including buffers) first
>>> - if it fails, early return without any impact to the interface
>>> - stop interface
>>> - update global state (bp, netdev, etc)
>>> - pass buffer pointers to the hardware
>>> - start interface
>>> - free old context.
>>>
>>> The HW disable sequence is inspired by macb_reset_hw() but avoids
>>> (1) setting NCR bit CLRSTAT and (2) clearing register PBUFRXCUT.
>>>
>>> The HW re-enable sequence is inspired by macb_mac_link_up(), skipping
>>> over register writes which would be redundant (because values have not
>>> changed).
>>>
>>> The generic context swapping parts are isolated into helper functions
>>> macb_context_swap_start|end(), reusable by other operations
>>> (change_mtu,
>>> set_channels, etc).
>>>
>>> Signed-off-by: Théo Lebrun <theo.lebrun@bootlin.com>
>>> ---
>>> drivers/net/ethernet/cadence/macb_main.c | 89
>>> +++++++++++++++++++++++++++++---
>>> 1 file changed, 82 insertions(+), 7 deletions(-)
>>>
>>> diff --git a/drivers/net/ethernet/cadence/macb_main.c
>>> b/drivers/net/ethernet/cadence/macb_main.c
>>> index 42b19b969f3e..543356554c11 100644
>>> --- a/drivers/net/ethernet/cadence/macb_main.c
>>> +++ b/drivers/net/ethernet/cadence/macb_main.c
>>> @@ -2905,6 +2905,76 @@ static struct macb_context
>>> *macb_context_alloc(struct macb *bp,
>>> return ctx;
>>> }
>>>
>>> +static void macb_context_swap_start(struct macb *bp)
>>> +{
>>> + struct macb_queue *queue;
>>> + unsigned int q;
>>> + u32 ctrl;
>>> +
>>> + /* Disable software Tx, disable HW Tx/Rx and disable NAPI. */
>>> +
>>> + netif_tx_disable(bp->netdev);
>>> +
>>> + ctrl = macb_readl(bp, NCR);
>>> + macb_writel(bp, NCR, ctrl & ~(MACB_BIT(RE) | MACB_BIT(TE)));
>>> +
>>> + macb_writel(bp, TSR, -1);
>>> + macb_writel(bp, RSR, -1);
>>> +
>>> + for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) {
>>> + queue_writel(queue, IDR, -1);
>>> + queue_readl(queue, ISR);
>>> + if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
>>> + queue_writel(queue, ISR, -1);
>>> + }
>>> +
>>> + for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) {
>>> + napi_disable(&queue->napi_rx);
>>> + napi_disable(&queue->napi_tx);
>>> + }
>>
>> tx_error_task, hresp_err_bh_work, and tx_lpi_work all dereference
>> bp->ctx and could race with the pointer swap in swap_end.
>> macb_close() cancels at least tx_lpi_work here. Should these be
>> flushed too?
>
> This is a large topic! While trying to find a solution as part of this
> series I am noticing many race conditions. With this context series we
> worsen some (by introducing bp->ctx NULL ptr dereference).
>
> Let's start by identifying all schedule-able contexts involved:
> - #1 any request from userspace, too many callbacks to list
> - #2 NAPI softirq or kthread context, macb_{rx,tx}_poll()
> - #3 bp->hresp_err_bh_work / macb_hresp_error_task()
> - #4 bp->tx_lpi_work / macb_tx_lpi_work_fn()
> - #5 queue->tx_error_task / macb_tx_error_task()
> - #6 IRQ context, macb_interrupt()
>
> Some race conditions:
>
> - #1 macb_close() doesn't cancel & wait upon #3 hresp_err_bh_work.
> They could race, especially as #3 doesn't grab bp->lock. One race
> example: #3 BP HRESP starts the interface after it has been closed
> and buffers freed. RBQP/TBQP are not reset so MACB would occur
> memory corruption on Rx and transmit memory content.
>
> - #1 macb_close() doesn't cancel & wait upon #5 tx_error_task. #5 does
> grab bp->lock but that doesn't make it much safer. One race example:
> same as above, restart of interface with ghost ring buffers.
>
> - #3 hresp_err_bh_work could collide with anything as it does no
> locking, especially #1 (xmit for example) or #2 (NAPI). It is less
> likely to collide with #6 IRQ because it starts by disabling those
> but there is a possibility of the IRQ having already triggered and
> macb_interrupt() already running in parallel of
> macb_hresp_error_task().
>
> - #5 queue->tx_error_task writes to Tx head/tail inside bp->lock.
> #1 macb_start_xmit() modifies those too, but inside
> queue->tx_ptr_lock. Oops. There probably are other places modifying
> head/tail or any other Tx queue value without queue->tx_ptr_lock.
>
> - #5 macb_tx_error_task() tries to gently disable TX but if it
> times-out then it uses the global switch (TE field in NCR
> register). That sounds racy with #2 NAPI that doesn't grab bp->lock
> and would probably break if the interface is shutdown under its
> feet.
>
> I don't see much more. To fix all that, someone ought to exhaustively go
> through all tasks (#1-6 above) & all shared data and reason one by one.
> Who will be that someone? ;-) But that sounds pretty unrelated to the
> series at hand, no?
>
> I'd agree that some locking of bp->lock around the swap operation would
> improve the series, and I'll add that in V2 for sure!
After some sleep, I feel like my message was a bit rough. To clarify
what I plan for V2:
- grab bp->lock on swap to protect us against some of #1 userspace and
all of #6 IRQ.
- disabling #2 NAPI on swap is already done
- disable all three BH features on swap
That will not fix everything listed above.
On top, we should:
- check/revise our locking strategy for almost all codepaths,
- check all BH features are disabled and blocked upon in the right
codepaths,
- in many bp->lock critical section, we should early exit if !bp->ctx.
>
>>
>>> +}
>>> +
>>> +static void macb_context_swap_end(struct macb *bp,
>>> + struct macb_context *new_ctx)
>>> +{
>>> + struct macb_context *old_ctx;
>>> + struct macb_queue *queue;
>>> + unsigned int q;
>>> + u32 ctrl;
>>> +
>>> + /* Swap contexts & give buffer pointers to HW. */
>>> +
>>> + old_ctx = bp->ctx;
>>> + bp->ctx = new_ctx;
>>> + macb_init_buffers(bp);
>>> +
>>> + /* Start NAPI, HW Tx/Rx and software Tx. */
>>> +
>>> + for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) {
>>> + napi_enable(&queue->napi_rx);
>>> + napi_enable(&queue->napi_tx);
>>> + }
>>> +
>>> + if (!(bp->caps & MACB_CAPS_MACB_IS_EMAC)) {
>>> + for (q = 0, queue = bp->queues; q < bp->num_queues;
>>> + ++q, ++queue) {
>>> + queue_writel(queue, IER,
>>> + bp->rx_intr_mask |
>>> + MACB_TX_INT_FLAGS |
>>> + MACB_BIT(HRESP));
>>> + }
>>> + }
>>> +
>>> + ctrl = macb_readl(bp, NCR);
>>> + macb_writel(bp, NCR, ctrl | MACB_BIT(RE) | MACB_BIT(TE));
>>> +
>>> + netif_tx_start_all_queues(bp->netdev);
>>> +
>>> + /* Free old context. */
>>> +
>>> + macb_free_consistent(old_ctx);
>>
>> 1. kfree(old_ctx) is missing. The context struct itself leaks on
>> every swap.
>
> Agreed.
>
>> 2. macb_close() calls netdev_tx_reset_queue() for each queue.
>> Shouldn't the swap do the same? BQL accounting will be stale
>> after switching to a fresh context.
>
> I explicitely left that out as I thought DQL would benefit from keeping
> past context of the traffic. But indeed as we start afresh from a new
> set of buffers we should reset DQL. fbnic, pointed out as an good
> example by Jakub recently, does that.
>
>>
>> 3. macb_configure_dma() is not called after the swap. For
>> set_ringparam this is probably fine since rx_buffer_size
>> does not change, but this becomes a problem in patch 11.
>
> Indeed, I had missed it took bp->ctx->rx_buffer_size as a parameter.
> Will fix.
Thanks,
--
Théo Lebrun, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply
* Re: [PATCH iwl-next] ice: check cross-timestamp timeout bits
From: Simon Horman @ 2026-04-03 9:03 UTC (permalink / raw)
To: Aleksandr Loktionov; +Cc: intel-wired-lan, anthony.l.nguyen, netdev
In-Reply-To: <20260327072236.129802-3-aleksandr.loktionov@intel.com>
On Fri, Mar 27, 2026 at 08:22:34AM +0100, Aleksandr Loktionov wrote:
> From: Karol Kolacinski <karol.kolacinski@intel.com>
>
> Polling for cross-timestamp active bit depends on HW scheduling and
> actual timeout may happen before the driver finishes polling.
>
> Check cross-timestamp timeout bits to ensure that the driver finishes
> the operation earlier when HW indicates timeout.
>
> Fixes: 92456e795ac6 ("ice: Add unified ice_capture_crosststamp")
> Signed-off-by: Karol Kolacinski <karol.kolacinski@intel.com>
> Signed-off-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Reviewed-by: Simon Horman <horms@kernel.org>
^ permalink raw reply
* [PATCH mlx5-next 2/2] net/mlx5: Add icm_mng_function_id_mode cap bit
From: Tariq Toukan @ 2026-04-03 9:00 UTC (permalink / raw)
To: Leon Romanovsky, Jason Gunthorpe, Saeed Mahameed, Tariq Toukan
Cc: Eric Dumazet, Jakub Kicinski, Paolo Abeni, Andrew Lunn,
David S. Miller, Mark Bloch, netdev, linux-rdma, linux-kernel,
Gal Pressman, Dragos Tatulea, Moshe Shemesh, Akiva Goldberger
In-Reply-To: <20260403090028.137783-1-tariqt@nvidia.com>
From: Moshe Shemesh <moshe@nvidia.com>
Introduce the capability bit icm_mng_function_id_mode to indicate that
the device firmware uses vhca_id instead of function_id as the effective
identifier for the firmware commands MANAGE_PAGES, QUERY_PAGES, and page
request event.
Signed-off-by: Moshe Shemesh <moshe@nvidia.com>
Reviewed-by: Akiva Goldberger <agoldberger@nvidia.com>
Reviewed-by: Mark Bloch <mbloch@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
---
include/linux/mlx5/mlx5_ifc.h | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h
index 2400b4c38c77..007f5138db2b 100644
--- a/include/linux/mlx5/mlx5_ifc.h
+++ b/include/linux/mlx5/mlx5_ifc.h
@@ -1654,6 +1654,11 @@ enum {
MLX5_STEERING_FORMAT_CONNECTX_8 = 3,
};
+enum {
+ MLX5_ID_MODE_FUNCTION_INDEX = 0,
+ MLX5_ID_MODE_FUNCTION_VHCA_ID = 1,
+};
+
struct mlx5_ifc_cmd_hca_cap_bits {
u8 reserved_at_0[0x6];
u8 page_request_disable[0x1];
@@ -1916,7 +1921,8 @@ struct mlx5_ifc_cmd_hca_cap_bits {
u8 reserved_at_280[0x10];
u8 max_wqe_sz_sq[0x10];
- u8 reserved_at_2a0[0x7];
+ u8 icm_mng_function_id_mode[0x1];
+ u8 reserved_at_2a1[0x6];
u8 mkey_pcie_tph[0x1];
u8 reserved_at_2a8[0x1];
u8 tis_tir_td_order[0x1];
--
2.44.0
^ permalink raw reply related
* [PATCH mlx5-next 1/2] net/mlx5: Rename MLX5_PF page counter type to MLX5_SELF
From: Tariq Toukan @ 2026-04-03 9:00 UTC (permalink / raw)
To: Leon Romanovsky, Jason Gunthorpe, Saeed Mahameed, Tariq Toukan
Cc: Eric Dumazet, Jakub Kicinski, Paolo Abeni, Andrew Lunn,
David S. Miller, Mark Bloch, netdev, linux-rdma, linux-kernel,
Gal Pressman, Dragos Tatulea, Moshe Shemesh
In-Reply-To: <20260403090028.137783-1-tariqt@nvidia.com>
From: Moshe Shemesh <moshe@nvidia.com>
The MLX5_PF enum value in mlx5_func_type is used to track firmware
page allocations for the page manager function itself, which is either
the ECPF on SmartNIC systems or the host PF when there is no ECPF.
Rename it to MLX5_SELF to accurately reflect that this counter tracks
pages allocated by the manager for its own use, regardless of whether
it is a PF or ECPF.
Signed-off-by: Moshe Shemesh <moshe@nvidia.com>
Reviewed-by: Mark Bloch <mbloch@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
---
drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c | 3 ++-
include/linux/mlx5/driver.h | 2 +-
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c b/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c
index 5ccb3ce98acb..77ffa31cc505 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c
@@ -77,7 +77,8 @@ static u32 get_function(u16 func_id, bool ec_function)
static u16 func_id_to_type(struct mlx5_core_dev *dev, u16 func_id, bool ec_function)
{
if (!func_id)
- return mlx5_core_is_ecpf(dev) && !ec_function ? MLX5_HOST_PF : MLX5_PF;
+ return mlx5_core_is_ecpf(dev) && !ec_function ?
+ MLX5_HOST_PF : MLX5_SELF;
if (func_id <= max(mlx5_core_max_vfs(dev), mlx5_core_max_ec_vfs(dev))) {
if (ec_function)
diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h
index b8b5af78284d..10bc913591d5 100644
--- a/include/linux/mlx5/driver.h
+++ b/include/linux/mlx5/driver.h
@@ -550,7 +550,7 @@ struct mlx5_debugfs_entries {
};
enum mlx5_func_type {
- MLX5_PF,
+ MLX5_SELF,
MLX5_VF,
MLX5_SF,
MLX5_HOST_PF,
--
2.44.0
^ permalink raw reply related
* [PATCH mlx5-next 0/2] mlx5-next updates 2026-04-03
From: Tariq Toukan @ 2026-04-03 9:00 UTC (permalink / raw)
To: Leon Romanovsky, Jason Gunthorpe, Saeed Mahameed, Tariq Toukan
Cc: Eric Dumazet, Jakub Kicinski, Paolo Abeni, Andrew Lunn,
David S. Miller, Mark Bloch, netdev, linux-rdma, linux-kernel,
Gal Pressman, Dragos Tatulea, Moshe Shemesh
Hi,
This series contains mlx5 shared updates as preparation for upcoming
features.
Regards,
Tariq
Moshe Shemesh (2):
net/mlx5: Rename MLX5_PF page counter type to MLX5_SELF
net/mlx5: Add icm_mng_function_id_mode cap bit
drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c | 3 ++-
include/linux/mlx5/driver.h | 2 +-
include/linux/mlx5/mlx5_ifc.h | 8 +++++++-
3 files changed, 10 insertions(+), 3 deletions(-)
base-commit: 26469110c750c8179560637dd813e5d65b8148d2
--
2.44.0
^ permalink raw reply
* Re: [PATCH v5 23/27] clk: mediatek: Add MT8196 disp-ao clock support
From: Jason-JH Lin (林睿祥) @ 2026-04-03 8:54 UTC (permalink / raw)
To: Laura Nao
Cc: Guangjie Song (宋光杰), robh@kernel.org,
kernel@collabora.com, Sirius Wang (王皓昱),
Nancy Lin (林欣螢), AngeloGioacchino Del Regno,
linux-mediatek@lists.infradead.org, conor+dt@kernel.org,
Paul-pl Chen (陳柏霖),
linux-kernel@vger.kernel.org,
Project_Global_Chrome_Upstream_Group, devicetree@vger.kernel.org,
richardcochran@gmail.com, krzk+dt@kernel.org,
mturquette@baylibre.com, Nicolas Prado, p.zabel@pengutronix.de,
Singo Chang (張興國), wenst@chromium.org,
linux-arm-kernel@lists.infradead.org, netdev@vger.kernel.org,
linux-clk@vger.kernel.org, matthias.bgg@gmail.com,
sboyd@kernel.org
In-Reply-To: <20260402100538.27291-1-laura.nao@collabora.com>
[snip]
> > > +static const struct of_device_id of_match_clk_mt8196_vdisp_ao[]
> > > = {
> > > + { .compatible = "mediatek,mt8196-vdisp-ao", .data =
> > > &mm_v_mcd },
> >
> > Hi Laura,
> >
> > We are going to send mtk-mmsys driver for MT8196 recently, but we
> > found
> > the compatible name is used here.
> >
> > As your commit message, vdisp-ao is integrated with the mtk-mmsys
> > driver, which registers the vdisp-ao clock driver via
> > platform_device_register_data().
> >
> > Shouldn't this compatible name belong to mmsys driver for MT8196?
> >
>
> That's right, my fault for missing that! Thanks for the heads up.
>
> I'm aware Angelo is currently restructuring mediatek-drm (including
> mmsys and mutex), and that might affect the way vdisp-ao is loaded
> too.
> So I'm not sure whether it makes sense to send a patch to fix this
> right away.
OK, we'll try to contact Angelo from other places.
Thanks for your confirmation!
Regards,
Jason-JH.Lin
>
> Best,
>
> Laura
>
^ permalink raw reply
* Re:Re: [RFC PATCH 0/6] rust: net: introduce minimal rtnl/netdevice abstractions and nlmon reference driver
From: wenzhaoliao @ 2026-04-03 8:52 UTC (permalink / raw)
To: Andrew Lunn
Cc: rust-for-linux, netdev, linux-kernel, ojeda, boqun, gary,
bjorn3_gh, lossin, a.hindborg, aliceryhl, tmgross, dakr,
andrew+netdev, davem, edumazet, kuba, pabeni
Hi Andrew,
Thank you for the candid feedback. I completely understand and agree with your point. Introducing Rust just for the sake of rewriting existing, perfectly working C code is not the goal here.
To clarify, my primary motivation for submitting the nlmon driver was not to replace the C implementation, but rather to use it as a minimal, isolated testbed to validate the proposed Rust networking abstractions (the first part of the patch series). I wanted to ensure the abstractions were somewhat grounded in a real use case before attempting to write a driver for a completely new device.
Since I am very eager to contribute to the Rust for Linux network infrastructure in the long run, I would highly appreciate it if you (or anyone on the list) could spare a few minutes to briefly review the design of the abstractions and the idiomatic Rust usage in the patch, purely from a technical and architectural perspective. Knowing whether these abstractions are on the right track would be incredibly helpful for me before I apply them to a newly requested driver as you suggested.
If the netdev mailing list is not the appropriate venue for discussing experimental Rust abstractions or seeking design feedback on reference code, could you kindly point me to the right place? Would the Rust-for-Linux Zulip or the rust-for-linux mailing list be a better channel to discuss how to improve these abstractions?
Thank you again for your time and guidance.
Best regards,
Wenzhao Liao
发件人:Andrew Lunn <andrew@lunn.ch>
发送日期:2026-04-03 04:00:28
收件人:Wenzhao Liao <wenzhaoliao@ruc.edu.cn>
抄送人:rust-for-linux@vger.kernel.org,netdev@vger.kernel.org,linux-kernel@vger.kernel.org,ojeda@kernel.org,boqun@kernel.org,gary@garyguo.net,bjorn3_gh@protonmail.com,lossin@kernel.org,a.hindborg@kernel.org,aliceryhl@google.com,tmgross@umich.edu,dakr@kernel.org,andrew+netdev@lunn.ch,davem@davemloft.net,edumazet@google.com,kuba@kernel.org,pabeni@redhat.com
主题:Re: [RFC PATCH 0/6] rust: net: introduce minimal rtnl/netdevice abstractions and nlmon reference driver>On Thu, Apr 02, 2026 at 12:36:34PM -0400, Wenzhao Liao wrote:
>> Hi,
>>
>> This RFC proposes a minimal set of Rust networking abstractions for
>> link-type drivers, together with a Rust implementation of nlmon as a
>> reference driver.
>
>nlmon exists. Why would we want a second implementation in Rust?
>
>It seems like we keep getting Rust submissions for the sake of
>submitting Rust. We never seem to get Rust code adding something new,
>something which does not already exist.
>
>Please, if you want to submit Rust code, find a device which does not
>have a driver and write a driver for it, in Rust. Or find a protocol
>described in an RFC which we don't implement, and write a Rust
>implementation. Or find a new firewall rule which cannot be described
>using the current code, and implement it in Rust.
>
>Unless it is something new, i doubt it will get accepted.
>
> Andrew
>
^ permalink raw reply
* Re: [PATCH 1/2] net: qrtr: ns: Limit the maximum server registration per node
From: Simon Horman @ 2026-04-03 8:52 UTC (permalink / raw)
To: Manivannan Sadhasivam
Cc: Manivannan Sadhasivam, davem, edumazet, kuba, pabeni,
linux-arm-msm, netdev, linux-kernel, andersson, yimingqian591,
chris.lew, stable
In-Reply-To: <20260403083009.GA11973@horms.kernel.org>
On Fri, Apr 03, 2026 at 09:30:09AM +0100, Simon Horman wrote:
> On Fri, Mar 27, 2026 at 03:40:01PM +0530, Manivannan Sadhasivam wrote:
> > On Fri, Mar 27, 2026 at 09:58:32AM +0000, Simon Horman wrote:
> > > On Wed, Mar 25, 2026 at 04:14:14PM +0530, Manivannan Sadhasivam wrote:
> > > > Current code does no bound checking on the number of servers added per
> > > > node. A malicious client can flood NEW_SERVER messages and exhaust memory.
> > > >
> > > > Fix this issue by limiting the maximum number of server registrations to
> > > > 256 per node. If the NEW_SERVER message is received for an old port, then
> > > > don't restrict it as it will get replaced.
> > > >
> > > > Note that the limit of 256 is chosen based on the current platform
> > > > requirements. If requirement changes in the future, this limit can be
> > > > increased.
> > > >
> > > > Cc: stable@vger.kernel.org
> > > > Fixes: 0c2204a4ad71 ("net: qrtr: Migrate nameservice to kernel from userspace")
> > > > Reported-by: Yiming Qian <yimingqian591@gmail.com>
> > > > Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
> > >
> > > Reviewed-by: Simon Horman <horms@kernel.org>
> > >
> > > > ---
> > > > net/qrtr/ns.c | 24 ++++++++++++++++++++----
> > > > 1 file changed, 20 insertions(+), 4 deletions(-)
> > > >
> > > > diff --git a/net/qrtr/ns.c b/net/qrtr/ns.c
> > > > index 3203b2220860..fb4e8a2d370d 100644
> > > > --- a/net/qrtr/ns.c
> > > > +++ b/net/qrtr/ns.c
> > > > @@ -67,8 +67,14 @@ struct qrtr_server {
> > > > struct qrtr_node {
> > > > unsigned int id;
> > > > struct xarray servers;
> > > > + u32 server_count;
> > > > };
> > > >
> > > > +/* Max server limit is chosen based on the current platform requirements. If the
> > > > + * requirement changes in the future, this value can be increased.
> > > > + */
> > > > +#define QRTR_NS_MAX_SERVERS 256
> > > > +
> > > > static struct qrtr_node *node_get(unsigned int node_id)
> > > > {
> > > > struct qrtr_node *node;
> > > > @@ -229,6 +235,17 @@ static struct qrtr_server *server_add(unsigned int service,
> > > > if (!service || !port)
> > > > return NULL;
> > > >
> > > > + node = node_get(node_id);
> > > > + if (!node)
> > > > + return NULL;
> > >
> > > This is not new behaviour added by patch, but If I understand things
> > > correctly, node_get will allocate a new node if one doesn't already exist
> > > for the node_id.
> > >
> >
> > Yes!
> >
> > > I am wondering if any bounds are placed on the number of nodes that can be
> > > created. And, if not, is this a point of concern from a memory exhaustion
> > > perspective?
> > >
> >
> > That's true. I plan to send a followup for that. This series just limits the
> > scope in addressing the reported issue.
>
> Thanks, sounds good to me.
>
> For this patch, feel free to add:
>
> Reviewed-by: Simon Horman <horms@kernel.org>
Sorry, I now see Jakub's comment on this.
So I'll review the revised series, addressing the concern above,
when it becomes available.
Feel free to include my Reviewed-by tags on patches that
don't change in a material way.
^ permalink raw reply
* Re: [PATCH net-next] eth: remove the driver for acenic / tigon1&2
From: Greg KH @ 2026-04-03 8:48 UTC (permalink / raw)
To: Jakub Kicinski
Cc: davem, netdev, edumazet, pabeni, andrew+netdev, horms, jes,
chenhuacai, kernel, tsbogend, James.Bottomley, deller, maddy, mpe,
npiggin, chleroy, hca, gor, agordeev, borntraeger, svens,
bhelgaas, dakr, kwilczynski, ojeda, boqun, gary, bjorn3_gh,
lossin, a.hindborg, aliceryhl, tmgross, ebiggers, ardb, tiwai,
tytso, enelsonmoore, martin.petersen, jirislaby, geert, herbert,
vineethr, lirongqing, kshk, vadim.fedorenko, dong100, wangruikang,
hkallweit1, kees, loongarch, linux-mips, linux-parisc,
linuxppc-dev, linux-s390, linux-pci, rust-for-linux
In-Reply-To: <20260402183029.1236713-1-kuba@kernel.org>
On Thu, Apr 02, 2026 at 11:30:29AM -0700, Jakub Kicinski wrote:
> The entire git history for this driver looks like tree-wide
> and automated cleanups. There's even more coming now with
> AI, so let's try to delete it instead.
>
> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
^ permalink raw reply
* Re: [PATCH v3 net-next] net: advance skb_defer_disable_key check in napi_consume_skb
From: kernel test robot @ 2026-04-03 8:47 UTC (permalink / raw)
To: Jason Xing, davem, edumazet, kuba, pabeni, horms
Cc: llvm, oe-kbuild-all, netdev, Jason Xing
In-Reply-To: <20260401033211.44463-1-kerneljasonxing@gmail.com>
Hi Jason,
kernel test robot noticed the following build errors:
[auto build test ERROR on net-next/main]
url: https://github.com/intel-lab-lkp/linux/commits/Jason-Xing/net-advance-skb_defer_disable_key-check-in-napi_consume_skb/20260403-115110
base: net-next/main
patch link: https://lore.kernel.org/r/20260401033211.44463-1-kerneljasonxing%40gmail.com
patch subject: [PATCH v3 net-next] net: advance skb_defer_disable_key check in napi_consume_skb
config: x86_64-buildonly-randconfig-005-20260403 (https://download.01.org/0day-ci/archive/20260403/202604031607.o753ScQ1-lkp@intel.com/config)
compiler: clang version 20.1.8 (https://github.com/llvm/llvm-project 87f0227cb60147a26a1eeb4fb06e3b505e9c7261)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260403/202604031607.o753ScQ1-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202604031607.o753ScQ1-lkp@intel.com/
All errors (new ones prefixed by >>):
>> net/core/skbuff.c:1522:31: error: use of undeclared identifier 'skb_defer_disable_key'
1522 | if (!static_branch_unlikely(&skb_defer_disable_key) &&
| ^
>> net/core/skbuff.c:1522:31: error: use of undeclared identifier 'skb_defer_disable_key'
>> net/core/skbuff.c:1522:31: error: use of undeclared identifier 'skb_defer_disable_key'
>> net/core/skbuff.c:1522:31: error: use of undeclared identifier 'skb_defer_disable_key'
4 errors generated.
vim +/skb_defer_disable_key +1522 net/core/skbuff.c
1500
1501 /**
1502 * napi_consume_skb() - consume skb in NAPI context, try to feed skb cache
1503 * @skb: buffer to free
1504 * @budget: NAPI budget
1505 *
1506 * Non-zero @budget must come from the @budget argument passed by the core
1507 * to a NAPI poll function. Note that core may pass budget of 0 to NAPI poll
1508 * for example when polling for netpoll / netconsole.
1509 *
1510 * Passing @budget of 0 is safe from any context, it turns this function
1511 * into dev_consume_skb_any().
1512 */
1513 void napi_consume_skb(struct sk_buff *skb, int budget)
1514 {
1515 if (unlikely(!budget || !skb)) {
1516 dev_consume_skb_any(skb);
1517 return;
1518 }
1519
1520 DEBUG_NET_WARN_ON_ONCE(!in_softirq());
1521
> 1522 if (!static_branch_unlikely(&skb_defer_disable_key) &&
1523 skb->alloc_cpu != smp_processor_id() && !skb_shared(skb)) {
1524 skb_release_head_state(skb);
1525 return skb_attempt_defer_free(skb);
1526 }
1527
1528 if (!skb_unref(skb))
1529 return;
1530
1531 /* if reaching here SKB is ready to free */
1532 trace_consume_skb(skb, __builtin_return_address(0));
1533
1534 /* if SKB is a clone, don't handle this case */
1535 if (skb->fclone != SKB_FCLONE_UNAVAILABLE) {
1536 __kfree_skb(skb);
1537 return;
1538 }
1539
1540 skb_release_all(skb, SKB_CONSUMED);
1541 napi_skb_cache_put(skb);
1542 }
1543 EXPORT_SYMBOL(napi_consume_skb);
1544
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* Re: [PATCH v3 net-next] net: advance skb_defer_disable_key check in napi_consume_skb
From: kernel test robot @ 2026-04-03 8:47 UTC (permalink / raw)
To: Jason Xing, davem, edumazet, kuba, pabeni, horms
Cc: oe-kbuild-all, netdev, Jason Xing
In-Reply-To: <20260401033211.44463-1-kerneljasonxing@gmail.com>
Hi Jason,
kernel test robot noticed the following build errors:
[auto build test ERROR on net-next/main]
url: https://github.com/intel-lab-lkp/linux/commits/Jason-Xing/net-advance-skb_defer_disable_key-check-in-napi_consume_skb/20260403-115110
base: net-next/main
patch link: https://lore.kernel.org/r/20260401033211.44463-1-kerneljasonxing%40gmail.com
patch subject: [PATCH v3 net-next] net: advance skb_defer_disable_key check in napi_consume_skb
config: mips-cu1830-neo_defconfig (https://download.01.org/0day-ci/archive/20260403/202604031603.YyNxdorw-lkp@intel.com/config)
compiler: mips-linux-gcc (GCC) 15.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260403/202604031603.YyNxdorw-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202604031603.YyNxdorw-lkp@intel.com/
All errors (new ones prefixed by >>):
In file included from include/linux/build_bug.h:5,
from include/linux/container_of.h:5,
from include/linux/list.h:5,
from include/linux/module.h:12,
from net/core/skbuff.c:37:
net/core/skbuff.c: In function 'napi_consume_skb':
>> net/core/skbuff.c:1522:38: error: 'skb_defer_disable_key' undeclared (first use in this function)
1522 | if (!static_branch_unlikely(&skb_defer_disable_key) &&
| ^~~~~~~~~~~~~~~~~~~~~
include/linux/compiler.h:77:45: note: in definition of macro 'unlikely'
77 | # define unlikely(x) __builtin_expect(!!(x), 0)
| ^
include/linux/jump_label.h:515:41: note: in expansion of macro 'unlikely_notrace'
515 | #define static_branch_unlikely(x) unlikely_notrace(static_key_enabled(&(x)->key))
| ^~~~~~~~~~~~~~~~
include/linux/jump_label.h:515:58: note: in expansion of macro 'static_key_enabled'
515 | #define static_branch_unlikely(x) unlikely_notrace(static_key_enabled(&(x)->key))
| ^~~~~~~~~~~~~~~~~~
net/core/skbuff.c:1522:14: note: in expansion of macro 'static_branch_unlikely'
1522 | if (!static_branch_unlikely(&skb_defer_disable_key) &&
| ^~~~~~~~~~~~~~~~~~~~~~
net/core/skbuff.c:1522:38: note: each undeclared identifier is reported only once for each function it appears in
1522 | if (!static_branch_unlikely(&skb_defer_disable_key) &&
| ^~~~~~~~~~~~~~~~~~~~~
include/linux/compiler.h:77:45: note: in definition of macro 'unlikely'
77 | # define unlikely(x) __builtin_expect(!!(x), 0)
| ^
include/linux/jump_label.h:515:41: note: in expansion of macro 'unlikely_notrace'
515 | #define static_branch_unlikely(x) unlikely_notrace(static_key_enabled(&(x)->key))
| ^~~~~~~~~~~~~~~~
include/linux/jump_label.h:515:58: note: in expansion of macro 'static_key_enabled'
515 | #define static_branch_unlikely(x) unlikely_notrace(static_key_enabled(&(x)->key))
| ^~~~~~~~~~~~~~~~~~
net/core/skbuff.c:1522:14: note: in expansion of macro 'static_branch_unlikely'
1522 | if (!static_branch_unlikely(&skb_defer_disable_key) &&
| ^~~~~~~~~~~~~~~~~~~~~~
vim +/skb_defer_disable_key +1522 net/core/skbuff.c
1500
1501 /**
1502 * napi_consume_skb() - consume skb in NAPI context, try to feed skb cache
1503 * @skb: buffer to free
1504 * @budget: NAPI budget
1505 *
1506 * Non-zero @budget must come from the @budget argument passed by the core
1507 * to a NAPI poll function. Note that core may pass budget of 0 to NAPI poll
1508 * for example when polling for netpoll / netconsole.
1509 *
1510 * Passing @budget of 0 is safe from any context, it turns this function
1511 * into dev_consume_skb_any().
1512 */
1513 void napi_consume_skb(struct sk_buff *skb, int budget)
1514 {
1515 if (unlikely(!budget || !skb)) {
1516 dev_consume_skb_any(skb);
1517 return;
1518 }
1519
1520 DEBUG_NET_WARN_ON_ONCE(!in_softirq());
1521
> 1522 if (!static_branch_unlikely(&skb_defer_disable_key) &&
1523 skb->alloc_cpu != smp_processor_id() && !skb_shared(skb)) {
1524 skb_release_head_state(skb);
1525 return skb_attempt_defer_free(skb);
1526 }
1527
1528 if (!skb_unref(skb))
1529 return;
1530
1531 /* if reaching here SKB is ready to free */
1532 trace_consume_skb(skb, __builtin_return_address(0));
1533
1534 /* if SKB is a clone, don't handle this case */
1535 if (skb->fclone != SKB_FCLONE_UNAVAILABLE) {
1536 __kfree_skb(skb);
1537 return;
1538 }
1539
1540 skb_release_all(skb, SKB_CONSUMED);
1541 napi_skb_cache_put(skb);
1542 }
1543 EXPORT_SYMBOL(napi_consume_skb);
1544
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* Re: [PATCH iwl-next] ixgbe: fix integer overflow and wrong bit position in ixgbe_validate_rtr()
From: Simon Horman @ 2026-04-03 8:41 UTC (permalink / raw)
To: Aleksandr Loktionov; +Cc: intel-wired-lan, anthony.l.nguyen, netdev
In-Reply-To: <20260327073046.134085-10-aleksandr.loktionov@intel.com>
On Fri, Mar 27, 2026 at 08:30:44AM +0100, Aleksandr Loktionov wrote:
> Two bugs in the same loop in ixgbe_validate_rtr():
If these are bugs then they should have a Fixes tag.
If there is more than one bug, possibly split into two patches.
And if these are present in net, then probably they are iwl-net material.
OTOH, if they are not bugs, then please don't describe them as such.
>
> 1. When extracting 3-bit traffic class values from the IXGBE_RTRUP2TC
> register the shifted value was assigned directly to a u8, silently
> truncating any bits above bit 7. Mask with IXGBE_RTRUP2TC_UP_MASK
> before the assignment so only the intended 3 bits are kept.
>
> 2. When clearing an out-of-bounds entry the mask was always shifted by
> the fixed constant IXGBE_RTRUP2TC_UP_SHIFT (== 3), regardless of
> which loop iteration was being processed. This means only the entry
> at bit position 3 was ever cleared; entries at bit positions 0, 6, 9,
> ..., 21 were left unreset. Use i * IXGBE_RTRUP2TC_UP_SHIFT to target
> the correct field for each iteration.
This describes the effect at the register level.
But I think it would be useful to describe the effect that
users will experience.
>
> Also replace the hardcoded 0x7 literal with the IXGBE_RTRUP2TC_UP_MASK
> constant for consistency with other parts of the driver.
>
> Signed-off-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
This does seem ripe for use of FIELD_GET and FIELD_PREP.
But if these are bug fixes, then this minimalist approach looks good to me.
> ---
> drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 5 +++--
> 1 file changed, 3 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
> index 9aec66c..53b82a5 100644
> --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
> +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
> @@ -9798,11 +9798,12 @@ static void ixgbe_validate_rtr(struct ixgbe_adapter *adapter, u8 tc)
> rsave = reg;
>
> for (i = 0; i < MAX_TRAFFIC_CLASS; i++) {
> - u8 up2tc = reg >> (i * IXGBE_RTRUP2TC_UP_SHIFT);
> + u8 up2tc = IXGBE_RTRUP2TC_UP_MASK &
> + (reg >> (i * IXGBE_RTRUP2TC_UP_SHIFT));
>
> /* If up2tc is out of bounds default to zero */
> if (up2tc > tc)
> - reg &= ~(0x7 << IXGBE_RTRUP2TC_UP_SHIFT);
> + reg &= ~(IXGBE_RTRUP2TC_UP_MASK << (i * IXGBE_RTRUP2TC_UP_SHIFT));
> }
>
> if (reg != rsave)
> --
> 2.52.0
>
^ permalink raw reply
* [PATCH net-next] pppoe: drop PFC frames
From: Qingfang Deng @ 2026-04-03 8:39 UTC (permalink / raw)
To: linux-ppp, Michal Ostrowski, Andrew Lunn, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, netdev, linux-kernel
Cc: Paul Mackerras, Jaco Kroon, James Carlson, Wojciech Drewek,
Guillaume Nault, Qingfang Deng
RFC 2516 Section 7 states that Protocol Field Compression (PFC) is NOT
RECOMMENDED for PPPoE. In practice, pppd does not support negotiating
PFC for PPPoE sessions, and the current PPPoE driver assumes an
uncompressed (2-byte) protocol field.
If a peer with a broken implementation or an attacker sends a frame with
a compressed (1-byte) protocol field, the subsequent PPP payload is
shifted by one byte. This causes the network header to be 4-byte
misaligned, which may trigger unaligned access exceptions on some
architectures.
To reduce the attack surface, drop the compressed protocol field frames.
Signed-off-by: Qingfang Deng <qingfang.deng@linux.dev>
---
drivers/net/ppp/pppoe.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c
index 1ac61c273b28..457a83c73293 100644
--- a/drivers/net/ppp/pppoe.c
+++ b/drivers/net/ppp/pppoe.c
@@ -393,7 +393,7 @@ static int pppoe_rcv(struct sk_buff *skb, struct net_device *dev,
if (skb_mac_header_len(skb) < ETH_HLEN)
goto drop;
- if (!pskb_may_pull(skb, sizeof(struct pppoe_hdr)))
+ if (!pskb_may_pull(skb, PPPOE_SES_HLEN))
goto drop;
ph = pppoe_hdr(skb);
@@ -403,6 +403,10 @@ static int pppoe_rcv(struct sk_buff *skb, struct net_device *dev,
if (skb->len < len)
goto drop;
+ /* drop PFC frames */
+ if (unlikely(skb->data[0] & 0x01))
+ goto drop;
+
if (pskb_trim_rcsum(skb, len))
goto drop;
--
2.43.0
^ permalink raw reply related
* Re: [PATCH net] bridge: mrp: reject zero test interval to avoid OOM panic
From: Simon Horman @ 2026-04-03 8:34 UTC (permalink / raw)
To: Nikolay Aleksandrov
Cc: Xiang Mei, netdev, bridge, idosch, davem, edumazet, pabeni,
bestswngs
In-Reply-To: <f7fea291-bde9-4f95-8a59-1b209407ee27@blackwall.org>
On Fri, Mar 27, 2026 at 01:46:39PM +0200, Nikolay Aleksandrov wrote:
> 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.
Right, I was getting to think that too.
...
^ permalink raw reply
* Re: [PATCH 2/2] net: qrtr: ns: Limit the maximum lookups per socket
From: Simon Horman @ 2026-04-03 8:32 UTC (permalink / raw)
To: Manivannan Sadhasivam
Cc: Manivannan Sadhasivam, davem, edumazet, kuba, pabeni,
linux-arm-msm, netdev, linux-kernel, andersson, yimingqian591,
chris.lew, stable
In-Reply-To: <b3i64wszqrmxmpl453z6mpaiqmuespxiioexb3wwbt3bz7mmen@rlewkfc4v25s>
On Fri, Mar 27, 2026 at 03:47:13PM +0530, Manivannan Sadhasivam wrote:
> On Fri, Mar 27, 2026 at 10:07:09AM +0000, Simon Horman wrote:
> > On Wed, Mar 25, 2026 at 04:14:15PM +0530, Manivannan Sadhasivam wrote:
> > > Current code does no bound checking on the number of lookups a client can
> > > perform per socket. Though the code restricts the lookups to local clients,
> > > there is still a possibility of a malicious local client sending a flood of
> > > NEW_LOOKUP messages over the same socket.
> > >
> > > Fix this issue by limiting the maximum number of lookups to 64 per socket.
> > > Note that, limit of 64 is chosen based on the current platform
> > > requirements. If requirement changes in the future, this limit can be
> > > increased.
> > >
> > > Cc: stable@vger.kernel.org
> > > Fixes: 0c2204a4ad71 ("net: qrtr: Migrate nameservice to kernel from userspace")
> > > Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
> > > ---
> > > net/qrtr/ns.c | 18 ++++++++++++++++--
> > > 1 file changed, 16 insertions(+), 2 deletions(-)
> > >
> > > diff --git a/net/qrtr/ns.c b/net/qrtr/ns.c
> > > index fb4e8a2d370d..707fde809939 100644
> > > --- a/net/qrtr/ns.c
> > > +++ b/net/qrtr/ns.c
> > > @@ -70,10 +70,11 @@ struct qrtr_node {
> > > u32 server_count;
> > > };
> > >
> > > -/* Max server limit is chosen based on the current platform requirements. If the
> > > - * requirement changes in the future, this value can be increased.
> > > +/* Max server, lookup limits are chosen based on the current platform requirements.
> > > + * If the requirement changes in the future, these values can be increased.
> > > */
> > > #define QRTR_NS_MAX_SERVERS 256
> > > +#define QRTR_NS_MAX_LOOKUPS 64
> > >
> > > static struct qrtr_node *node_get(unsigned int node_id)
> > > {
> > > @@ -545,11 +546,24 @@ static int ctrl_cmd_new_lookup(struct sockaddr_qrtr *from,
> > > struct qrtr_node *node;
> > > unsigned long node_idx;
> > > unsigned long srv_idx;
> > > + u8 count = 0;
> > >
> > > /* Accept only local observers */
> > > if (from->sq_node != qrtr_ns.local_node)
> > > return -EINVAL;
> > >
> > > + /* Make sure the client performs only maximum allowed lookups */
> > > + list_for_each_entry(lookup, &qrtr_ns.lookups, li) {
> > > + if (lookup->sq.sq_node == from->sq_node &&
> > > + lookup->sq.sq_port == from->sq_port)
> > > + count++;
> >
> > This feels like it could get quite expensive.
> > If many lookups are added, it feels like it may be O(n^2).
> >
>
> Lookups are not something that'll happen very often. A client only registers
> for the lookup once per service that it depends on. That shouldn't be too
> much. And then once lookup is registered, it will be used throughout the
> lifetime of the client.
>
> So there is no overhead associated with this check.
Thanks, and sorry for the delay: I was taking a holiday.
I'm still slightly concerned that this may prove to be a problem.
But we can leave that concern sit in a corner by itself for now.
For this patch feel free to add,
Reviewed-by: Simon Horman <horms@kernel.org>
I notice that this series has been marked as changes requested in patchwork.
So, unless it's being handled by some other means that I can't see at this
moment, I think it would be best to repost this series.
^ permalink raw reply
* Re: [PATCH 1/2] net: qrtr: ns: Limit the maximum server registration per node
From: Simon Horman @ 2026-04-03 8:30 UTC (permalink / raw)
To: Manivannan Sadhasivam
Cc: Manivannan Sadhasivam, davem, edumazet, kuba, pabeni,
linux-arm-msm, netdev, linux-kernel, andersson, yimingqian591,
chris.lew, stable
In-Reply-To: <as3zucfwr4z2x5pxww6ognmqcujkwnhppulm7jquex6fy6sqn5@qa33h5mxxdz7>
On Fri, Mar 27, 2026 at 03:40:01PM +0530, Manivannan Sadhasivam wrote:
> On Fri, Mar 27, 2026 at 09:58:32AM +0000, Simon Horman wrote:
> > On Wed, Mar 25, 2026 at 04:14:14PM +0530, Manivannan Sadhasivam wrote:
> > > Current code does no bound checking on the number of servers added per
> > > node. A malicious client can flood NEW_SERVER messages and exhaust memory.
> > >
> > > Fix this issue by limiting the maximum number of server registrations to
> > > 256 per node. If the NEW_SERVER message is received for an old port, then
> > > don't restrict it as it will get replaced.
> > >
> > > Note that the limit of 256 is chosen based on the current platform
> > > requirements. If requirement changes in the future, this limit can be
> > > increased.
> > >
> > > Cc: stable@vger.kernel.org
> > > Fixes: 0c2204a4ad71 ("net: qrtr: Migrate nameservice to kernel from userspace")
> > > Reported-by: Yiming Qian <yimingqian591@gmail.com>
> > > Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
> >
> > Reviewed-by: Simon Horman <horms@kernel.org>
> >
> > > ---
> > > net/qrtr/ns.c | 24 ++++++++++++++++++++----
> > > 1 file changed, 20 insertions(+), 4 deletions(-)
> > >
> > > diff --git a/net/qrtr/ns.c b/net/qrtr/ns.c
> > > index 3203b2220860..fb4e8a2d370d 100644
> > > --- a/net/qrtr/ns.c
> > > +++ b/net/qrtr/ns.c
> > > @@ -67,8 +67,14 @@ struct qrtr_server {
> > > struct qrtr_node {
> > > unsigned int id;
> > > struct xarray servers;
> > > + u32 server_count;
> > > };
> > >
> > > +/* Max server limit is chosen based on the current platform requirements. If the
> > > + * requirement changes in the future, this value can be increased.
> > > + */
> > > +#define QRTR_NS_MAX_SERVERS 256
> > > +
> > > static struct qrtr_node *node_get(unsigned int node_id)
> > > {
> > > struct qrtr_node *node;
> > > @@ -229,6 +235,17 @@ static struct qrtr_server *server_add(unsigned int service,
> > > if (!service || !port)
> > > return NULL;
> > >
> > > + node = node_get(node_id);
> > > + if (!node)
> > > + return NULL;
> >
> > This is not new behaviour added by patch, but If I understand things
> > correctly, node_get will allocate a new node if one doesn't already exist
> > for the node_id.
> >
>
> Yes!
>
> > I am wondering if any bounds are placed on the number of nodes that can be
> > created. And, if not, is this a point of concern from a memory exhaustion
> > perspective?
> >
>
> That's true. I plan to send a followup for that. This series just limits the
> scope in addressing the reported issue.
Thanks, sounds good to me.
For this patch, feel free to add:
Reviewed-by: Simon Horman <horms@kernel.org>
^ permalink raw reply
* Re: [PATCH 1/3] dt-bindings: dsa: microchip: add KSZ low-loss cable errata properties
From: Fidelio LAWSON @ 2026-04-03 8:28 UTC (permalink / raw)
To: Andrew Lunn
Cc: Woojung Huh, UNGLinuxDriver, Vladimir Oltean, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Marek Vasut, Maxime Chevallier,
netdev, devicetree, linux-kernel, Fidelio Lawson
In-Reply-To: <521cf729-50d2-44c1-8c96-c1fba2127b9d@lunn.ch>
On 3/26/26 13:14, Andrew Lunn wrote:
> On Thu, Mar 26, 2026 at 10:10:21AM +0100, Fidelio Lawson wrote:
>> Microchip KSZ87xx switches are affected by the "Module 3: Equalizer fix
>> for short cables" erratum described in DS80000687C.
>> The embedded PHY receivers are tuned for long, high-loss cables,
>> which may cause signal distortion when operated with short or low-loss
>> cabling such as CAT5e or CAT6. In these cases,
>> the PHY may fail to establish a link due to internal over-amplification.
>>
>> Two workarounds are provided by Microchip, each configuring a different
>> indirect register value to adjust the PHY equalizer settings.
>>
>> This patch introduces two new device tree properties to enable and
>> select the appropriate workaround:
>>
>> - microchip,low-loss-errata-enable: boolean enabling the feature
>> - microchip,low-loss-errata: selects workaround 1 or 2 (default: 1)
>>
>> These properties allow board designers to opt into the errata fix
>> according to the targeted cable characteristics of their platform.
>
> Does the errata give any indication how the two different workarounds
> differ? How would a user decided which to use?
>
> I also question if this should be a DT property. The length of the
> cables is not a property of the board.
>
> A PHY tunable would better reflect the same board can be used with
> different cables, with different lengths/quality.
>
> Andrew
Hi Andrew,
Thanks for the review.
Regarding the difference between the two workarounds:
Microchip’s errata does provide some insight into how they behave and
when each should be used.
Workaround 1 modifies the PHY equalizer settings by adjusting an
indirect register (0x3c).
According to Microchip’s support article:
“The above register change makes the equalizer’s compensation range
wider, and therefore cables with various characteristics can be
tolerated. Adjust equalizer EQ training algorithm to cover a few type of
short cables issue. Also is appropriate for board‑to‑board connection
and port‑to‑port connection with the capacitor AC coupling mode.”
Microchip also explains that although the default value in register 0x3c
handles standard short Ethernet cables (CAT‑5/CAT‑5e), a more optimized
value (0x15) provides better tolerance for corner cases, especially very
short or board‑to‑board links:
“Based on tests, a more optimized equalizer adjustment value 0x15 is
better for all corner cases of the short cable and short distance
connection for port‑to‑port or board‑to‑board cases.”
So Workaround 1 primarily widens and optimizes the DSP equalizer EQ
compensation range, and is expected to solve most short/low‑loss cable
issues.
Workaround 2 is intended for the cases where Workaround 1 is not sufficient.
This one adjusts the receiver low‑pass filter bandwidth, effectively
reducing the high‑frequency component of the received signal:
“Based on the root cause above, adjust the receiver low pass filter to
reduce the high frequency component to keep the receive signal within a
reasonable range when using CAT‑5E and CAT‑6 cable.”
So Workaround 2 is a more aggressive filtering approach, applied only
when the EQ adjustment alone does not stabilize the link on CAT‑5e/CAT‑6
short cable scenarios.
Regarding the question of whether this should be exposed through a PHY
tunable:
I understand your concern. The erratum is indeed linked to cable
characteristics, not the board itself.
Since this patch modifies registers that belong to the DSA switch
itself, and not the PHY driver, I’m not entirely sure it would be
architecturally correct to expose these adjustments as PHY tunables. The
workarounds target internal receiver/equalizer settings inside the
KSZ87xx switch block, accessed via the switch’s indirect register
mechanism, not via a standard phy_device.
Given that, I’m unsure whether mapping these switch‑level registers into
the PHY tunables framework would be appropriate or even feasible.
What do you think?
Best regards,
Fidelio
^ permalink raw reply
* Re: [PATCH v4 net-next 5/5] net: pcs: pcs-mtk-lynxi: deprecate "mediatek,pnswap"
From: Frank Wunderlich @ 2026-04-03 8:23 UTC (permalink / raw)
To: Vladimir Oltean
Cc: netdev, devicetree, linux-kernel, linux-mediatek, Daniel Golle,
Horatiu Vultur, Bj√∏rn Mork, Andrew Lunn,
Heiner Kallweit, Russell King, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
Eric Woudstra, Alexander Couzens, Chester A. Unal, DENG Qingfang,
Sean Wang, Felix Fietkau
In-Reply-To: <20260402095300.hujib22ag6g5wkts@skbuf>
Am 2. April 2026 11:53:00 MESZ schrieb Vladimir Oltean <vladimir.oltean@nxp.com>:
>On Thu, Apr 02, 2026 at 05:50:33AM +0000, Frank Wunderlich wrote:
>> Hi,
>
>Hi,
>
>Please don't top-post :(
Sorry about that. Try to do better future :)
I keep context for now (not removing my findings from early mail),i hope it is ok.
Maybe daniel or mtk can respond if my understanding is wrong.
>> i tried using these properties in sgmiisys0 node (which should be mapped to mac0 and the mt7530 switch) without success [1].
>>
>> it looks like these properties are not read somewhere.
>
>Can you please clarify whether your problem is with the SerDes connected
>to a switch port or to a GMAC?
From my tests it looks like the issue is on switch side.
>Because if to a switch port, mt7531_create_sgmii() doesn't have any
>phandle to the SGMIISYS. That was from existing code.
>
> pcs = mtk_pcs_lynxi_create(priv->dev, NULL, regmap,
> MT7531_PHYA_CTRL_SIGNAL3);
>
>The LynxI PCS will be instantiated without a fwnode and only the
>defaults will apply.
This was a good hint, i had only seen the pcs call for mac.
>> the flow is
>>
>> mtk_probe (eth driver)
>>
>> if (MTK_HAS_CAPS(eth->soc->caps, MTK_SGMII)) {
>> err = mtk_sgmii_init(eth);
>>
>> and there calling mtk_pcs_lynxi_create with the sgmiisys-node (for each mac, so imho mac0=sgmiisys0)
>> but handling the sgmiisys only as syscon, not a "real" pcs node [2].
>>
>> but your new code calls phy_get_tx_polarity and should read out this properties, but from subnode "pcs", so next try was
>>
>> &sgmiisys0 {
>> pcs {
>> rx-polarity = <PHY_POL_NORMAL>;
>> tx-polarity = <PHY_POL_INVERT>;
>> };
>> };
>>
>> which results in completely strange behaviour (looks like sgmiisys1 is mapped to mac0, but based on code in mtk_sgmii_init 0=0 should be right):
>>
>> [ 2.765218] SGMSYS_QPHY_WRAP_CTRL = 0x501, will write 0x500
>> [ 9.143849] SGMSYS_QPHY_WRAP_CTRL = 0x500, will write 0x501
>>
>> but nevertheless i tried changing sgmiisys0 to sgmiisys1 and got the dame result as before
>>
>> [ 2.713644] SGMSYS_QPHY_WRAP_CTRL = 0x501, will write 0x500
>> [ 9.061509] SGMSYS_QPHY_WRAP_CTRL = 0x500, will write 0x500
>>
>> i can only change the second serdes with sgmiisys0, but not the first.
>
>I assume the second SerDes is mapped to a GMAC port which does
>instantiate the LynxI PCS with a fwnode, right? If so, the behaviour is
>consistent with the code. Only mtk-soc-eth uses mediatek,sgmiisys AFAICS.
>
>> mapping between mac and sgmiisys in dts in mt7986a.dtsi [3] are like this:
>>
>> eth: ethernet@15100000 {
>> compatible = "mediatek,mt7986-eth";
>> mediatek,sgmiisys = <&sgmiisys0>, <&sgmiisys1>;
>> ...
>> };
>>
>> ð {
>> status = "okay";
>>
>> gmac0: mac@0 {
>> compatible = "mediatek,eth-mac";
>> ...
>> };
>>
>> gmac1: mac@1 {
>> compatible = "mediatek,eth-mac";
>> ...
>> };
>> };
>>
>> maybe it is time to revive the PCS framework discussion ([4]-[6])?
>>
>> [1] https://github.com/frank-w/BPI-Router-Linux/commit/4846a7bb352fe5911136cba33813f099bac035fd
>> [2] https://elixir.bootlin.com/linux/v7.0-rc4/source/drivers/net/ethernet/mediatek/mtk_eth_soc.c#L5001
>> [3] https://elixir.bootlin.com/linux/v7.0-rc4/source/arch/arm64/boot/dts/mediatek/mt7986a.dtsi#L528
>>
>> [4] * https://patchwork.kernel.org/project/netdevbpf/patch/20250610233134.3588011-4-sean.anderson@linux.dev/ (v6)
>> > pcs-framework itself had not yet got a response from netdev maintainer (only other parts)
>> [5] * https://patchwork.kernel.org/project/netdevbpf/patch/20250511201250.3789083-4-ansuelsmth@gmail.com/ (v4)
>> > discussion: https://lore.kernel.org/netdev/20250511201250.3789083-1-ansuelsmth@gmail.com/
>> [6] * https://patchwork.kernel.org/project/netdevbpf/patch/ba4e359584a6b3bc4b3470822c42186d5b0856f9.1721910728.git.daniel@makrotopia.org/
>> > discussion: https://patchwork.kernel.org/project/netdevbpf/patch/8aa905080bdb6760875d62cb3b2b41258837f80e.1702352117.git.daniel@makrotopia.org/
>
>I'm not exactly sure how device+driver for the PCS devices would help in
>this case though? Because the LynxI PCS driver would just retrieve the
>fwnode on its own, rather than it being passed by the mtk_pcs_lynxi_create()
>caller?
Imho it could be more general and cleaner than calling "external" function in code. If pcs acts
as own device i would see which dtnode is assigned to it...here i guessed both calls were
from mac,but one was from mac and one from switch.
I tried adding prints before the lynxi call,but this does not make it clean from where it comes (i guess because of threading)...but this could be understanding issue on my side.
It looked like this:
root@bpi-r3:~# dmesg | grep 'SGMSYS_QPHY_WRAP_CTRL\|pcs'
[ 2.155221] mtk_soc_eth 15100000.ethernet: create sgmii pcs for mac #0
[ 2.168308] mtk_soc_eth 15100000.ethernet: create sgmii pcs for mac #1
[ 2.699744] mt7530-mdio mdio-bus:1f: add lynxi pcs for switch (port5)
[ 2.706773] mt7530-mdio mdio-bus:1f: add lynxi pcs for switch (port6)
[ 2.707881] SGMSYS_QPHY_WRAP_CTRL = 0x501, will write 0x501
[ 9.081259] SGMSYS_QPHY_WRAP_CTRL = 0x500, will write 0x500
>We need to have a very good model of what happens when the PCS provider
>goes away, especially in multi-port scenarios. It is a similar issue as
>to what happens when a phy_device goes away.
>https://lore.kernel.org/netdev/20260311153421.u454m3e4blkstymt@skbuf/
>
>I'm not saying "let's not do that", but we'd effectively introducing an
>issue that currently does not exist, with the PCS lifetime being managed
>by the consumer.
>
>Do you have any better idea by now why SGMSYS_QPHY_WRAP_CTRL is 0x501
>for SGMIISYS #0? Is that its out-of-reset value?
We guess that switch takes this value somehow from an efuse or similar.
I have 2 ways to fix this broken state:
1) to keep dts backward compatibility and due to undocumented behaviour i prefer this patch:
--- a/drivers/net/pcs/pcs-mtk-lynxi.c
+++ b/drivers/net/pcs/pcs-mtk-lynxi.c
@@ -129,6 +129,9 @@ static int mtk_pcs_config_polarity(struct mtk_pcs_lynxi *mpcs,
unsigned int val = 0, tmp;
int ret;
+ if (!fwnode)
+ return 0;
+
if (fwnode_property_read_bool(fwnode, "mediatek,pnswap"))
default_pol = PHY_POL_INVERT;
2) document pcs polarity (i'm still unsure if this is really correct as i cannot measure in hardware,just from software debugging...but not sure if the SGMSYS_QPHY_WRAP_CTRL offset is valid on switch regmap too) - it looks for me that by default is different between mac and switch side:
<https://github.com/frank-w/BPI-Router-Linux/commit/f693e2ed24287ce1e125d7f6202e14e263cc564d>
And add dts nodes like this:
<https://github.com/frank-w/BPI-Router-Linux/commit/4f7bce943dda614d24431d63adad65f1117a7f6d>
If i set same polarity to mac it is broken (thats why sgmiisys0 is disabled). I guess the pnswap property means "invert the default behaviour" and not "use inverted polarity compared to standard" and mac and switch use the same polarity with different values of the corresponding registers.
Based on my register documentation of mt7531 ("MT7531_Reference_Manual_for_Development_Board.pdf" page 729) i see
000050EC = QPHY_WRAP_CTRL
Bit 0
1'b1 : inversed TX_BIT_POLARITY TX bit polarity control (TX default inversed in MT7531)
Where bit 1 is only defined as "RX bit polarity control"
So my guess is that tx is inverted in hardware,but tx-bit is set in efuse to get the POL_NORMAL.
I did not find the register in my mt7986 register documentation...seems complete networking part is missing.
I do not expect that board changes polarity in hardware...
Regards Frank
^ permalink raw reply
* [PATCH net-next] ip6_tunnel: use generic for_each_ip_tunnel_rcu macro
From: Yue Haibing @ 2026-04-03 8:46 UTC (permalink / raw)
To: davem, dsahern, edumazet, kuba, pabeni, horms
Cc: netdev, linux-kernel, yuehaibing
Remove the locally defined for_each_ip6_tunnel_rcu macro and use
the generic for_each_ip_tunnel_rcu from linux/if_tunnel.h instead.
This eliminates code duplication and ensures consistency across
the kernel tunnel implementations.
Signed-off-by: Yue Haibing <yuehaibing@huawei.com>
---
net/ipv6/ip6_tunnel.c | 9 +++------
1 file changed, 3 insertions(+), 6 deletions(-)
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index 4c29aa94e86e..ace0bb91542f 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -96,9 +96,6 @@ static inline int ip6_tnl_mpls_supported(void)
return IS_ENABLED(CONFIG_MPLS);
}
-#define for_each_ip6_tunnel_rcu(start) \
- for (t = rcu_dereference(start); t; t = rcu_dereference(t->next))
-
/**
* ip6_tnl_lookup - fetch tunnel matching the end-point addresses
* @net: network namespace
@@ -121,7 +118,7 @@ ip6_tnl_lookup(struct net *net, int link,
struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
struct in6_addr any;
- for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) {
+ for_each_ip_tunnel_rcu(t, ip6n->tnls_r_l[hash]) {
if (!ipv6_addr_equal(local, &t->parms.laddr) ||
!ipv6_addr_equal(remote, &t->parms.raddr) ||
!(t->dev->flags & IFF_UP))
@@ -135,7 +132,7 @@ ip6_tnl_lookup(struct net *net, int link,
memset(&any, 0, sizeof(any));
hash = HASH(&any, local);
- for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) {
+ for_each_ip_tunnel_rcu(t, ip6n->tnls_r_l[hash]) {
if (!ipv6_addr_equal(local, &t->parms.laddr) ||
!ipv6_addr_any(&t->parms.raddr) ||
!(t->dev->flags & IFF_UP))
@@ -148,7 +145,7 @@ ip6_tnl_lookup(struct net *net, int link,
}
hash = HASH(remote, &any);
- for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) {
+ for_each_ip_tunnel_rcu(t, ip6n->tnls_r_l[hash]) {
if (!ipv6_addr_equal(remote, &t->parms.raddr) ||
!ipv6_addr_any(&t->parms.laddr) ||
!(t->dev->flags & IFF_UP))
--
2.34.1
^ permalink raw reply related
* [PATCH net-next] ipv6: sit: remove redundant ret = 0 assignment
From: Yue Haibing @ 2026-04-03 8:44 UTC (permalink / raw)
To: davem, dsahern, edumazet, kuba, pabeni, horms, yuehaibing
Cc: netdev, linux-kernel
The variable ret is initialized to 0 when it is defined
and is not modified before copy_to_user().
Signed-off-by: Yue Haibing <yuehaibing@huawei.com>
---
net/ipv6/sit.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index ef2e5111fb3a..09c0a01d44f4 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -359,7 +359,6 @@ static int ipip6_tunnel_get_prl(struct net_device *dev, struct ip_tunnel_prl __u
rcu_read_unlock();
len = sizeof(*kp) * c;
- ret = 0;
if ((len && copy_to_user(a + 1, kp, len)) || put_user(len, &a->datalen))
ret = -EFAULT;
--
2.34.1
^ permalink raw reply related
* Re: [Intel-wired-lan] [PATCH net-next] iavf: fix kernel-doc comment style in ethtool ops
From: Paul Menzel @ 2026-04-03 8:09 UTC (permalink / raw)
To: Aleksandr Loktionov
Cc: intel-wired-lan, anthony.l.nguyen, netdev, Leszek Pepiak
In-Reply-To: <20260403054321.3791392-1-aleksandr.loktionov@intel.com>
Dear Leszek, dear Aleksandr,
Thank you for the patch.
Am 03.04.26 um 07:43 schrieb Aleksandr Loktionov:
> From: Leszek Pepiak <leszek.pepiak@intel.com>
>
> iavf_get_channels() and iavf_set_channels() use the legacy `**/`
> comment terminator and embed the return description in the body text.
> Convert to proper kernel-doc style: single `*/` terminator and an
> explicit `Return:` section.
>
> Signed-off-by: Leszek Pepiak <leszek.pepiak@intel.com>
> Signed-off-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
>
> ---
> drivers/net/ethernet/intel/iavf/iavf_ethtool.c | 13 +++++++------
> 1 file changed, 7 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/net/ethernet/intel/iavf/iavf_ethtool.c b/drivers/net/ethernet/intel/iavf/iavf_ethtool.c
> index 8188dd4..425acbb 100644
> --- a/drivers/net/ethernet/intel/iavf/iavf_ethtool.c
> +++ b/drivers/net/ethernet/intel/iavf/iavf_ethtool.c
> @@ -1846,13 +1846,13 @@ static int iavf_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd,
> return ret;
> }
> /**
> - * iavf_get_channels: get the number of channels supported by the device
> + * iavf_get_channels - get the number of channels supported by the device
> * @netdev: network interface device structure
> * @ch: channel information structure
> *
> * For the purposes of our device, we only use combined channels, i.e. a tx/rx
> * queue pair. Report one extra channel to match our "other" MSI-X vector.
> - **/
> + */
> static void iavf_get_channels(struct net_device *netdev,
> struct ethtool_channels *ch)
> {
> @@ -1873,14 +1873,15 @@ static void iavf_get_channels(struct net_device *netdev,
> }
>
> /**
> - * iavf_set_channels: set the new channel count
> + * iavf_set_channels - set the new channel count
> * @netdev: network interface device structure
> * @ch: channel information structure
> *
> * Negotiate a new number of channels with the PF then do a reset. During
> - * reset we'll realloc queues and fix the RSS table. Returns 0 on success,
> - * negative on failure.
> - **/
> + * reset we'll realloc queues and fix the RSS table.
> + *
> + * Return: 0 on success, negative on failure.
> + */
> static int iavf_set_channels(struct net_device *netdev,
> struct ethtool_channels *ch)
> {
Reviewed-by: Paul Menzel <pmenzel@molgen.mpg.de>
Kind regards,
Paul
^ permalink raw reply
* [PATCH v2 1/1] Bluetooth: serialize accept_q access
From: Ren Wei @ 2026-04-03 8:05 UTC (permalink / raw)
To: linux-bluetooth, netdev
Cc: marcel, luiz.dentz, davem, edumazet, kuba, pabeni, horms,
yifanwucs, tomapufckgml, yuantan098, bird, enjou1224z,
wangjiexun2025, n05ec
In-Reply-To: <cover.1774454568.git.wangjiexun2025@gmail.com>
From: Jiexun Wang <wangjiexun2025@gmail.com>
bt_sock_poll() walks the accept queue without synchronization, while
child teardown can unlink the same socket and drop its last reference.
Protect accept_q with a dedicated lock for queue updates and polling.
Also rework bt_accept_dequeue() to take temporary child references under
the queue lock before dropping it and locking the child socket.
Fixes: 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 ("Linux-2.6.12-rc2")
Reported-by: Yifan Wu <yifanwucs@gmail.com>
Reported-by: Juefei Pu <tomapufckgml@gmail.com>
Co-developed-by: Yuan Tan <yuantan098@gmail.com>
Signed-off-by: Yuan Tan <yuantan098@gmail.com>
Suggested-by: Xin Liu <bird@lzu.edu.cn>
Tested-by: Ren Wei <enjou1224z@gmail.com>
Signed-off-by: Jiexun Wang <wangjiexun2025@gmail.com>
Signed-off-by: Ren Wei <n05ec@lzu.edu.cn>
---
Changes in v2:
- add Tested-by: Ren Wei <enjou1224z@gmail.com>
- resend to the public Bluetooth/netdev lists
include/net/bluetooth/bluetooth.h | 1 +
net/bluetooth/af_bluetooth.c | 85 +++++++++++++++++++++++--------
2 files changed, 66 insertions(+), 20 deletions(-)
diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
index 69eed69f7f26..3faea66b1979 100644
--- a/include/net/bluetooth/bluetooth.h
+++ b/include/net/bluetooth/bluetooth.h
@@ -398,6 +398,7 @@ void baswap(bdaddr_t *dst, const bdaddr_t *src);
struct bt_sock {
struct sock sk;
struct list_head accept_q;
+ spinlock_t accept_q_lock; /* protects accept_q */
struct sock *parent;
unsigned long flags;
void (*skb_msg_name)(struct sk_buff *, void *, int *);
diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c
index 2b94e2077203..f44e1ecc83d8 100644
--- a/net/bluetooth/af_bluetooth.c
+++ b/net/bluetooth/af_bluetooth.c
@@ -154,6 +154,7 @@ struct sock *bt_sock_alloc(struct net *net, struct socket *sock,
sock_init_data(sock, sk);
INIT_LIST_HEAD(&bt_sk(sk)->accept_q);
+ spin_lock_init(&bt_sk(sk)->accept_q_lock);
sock_reset_flag(sk, SOCK_ZAPPED);
@@ -214,6 +215,7 @@ void bt_accept_enqueue(struct sock *parent, struct sock *sk, bool bh)
{
const struct cred *old_cred;
struct pid *old_pid;
+ struct bt_sock *par = bt_sk(parent);
BT_DBG("parent %p, sk %p", parent, sk);
@@ -224,9 +226,12 @@ void bt_accept_enqueue(struct sock *parent, struct sock *sk, bool bh)
else
lock_sock_nested(sk, SINGLE_DEPTH_NESTING);
- list_add_tail(&bt_sk(sk)->accept_q, &bt_sk(parent)->accept_q);
bt_sk(sk)->parent = parent;
+ spin_lock_bh(&par->accept_q_lock);
+ list_add_tail(&bt_sk(sk)->accept_q, &par->accept_q);
+ spin_unlock_bh(&par->accept_q_lock);
+
/* Copy credentials from parent since for incoming connections the
* socket is allocated by the kernel.
*/
@@ -254,45 +259,73 @@ EXPORT_SYMBOL(bt_accept_enqueue);
*/
void bt_accept_unlink(struct sock *sk)
{
+ struct sock *parent = bt_sk(sk)->parent;
+
BT_DBG("sk %p state %d", sk, sk->sk_state);
+ spin_lock_bh(&bt_sk(parent)->accept_q_lock);
list_del_init(&bt_sk(sk)->accept_q);
- sk_acceptq_removed(bt_sk(sk)->parent);
+ spin_unlock_bh(&bt_sk(parent)->accept_q_lock);
+
+ sk_acceptq_removed(parent);
bt_sk(sk)->parent = NULL;
sock_put(sk);
}
EXPORT_SYMBOL(bt_accept_unlink);
+static struct sock *bt_accept_get(struct sock *parent, struct sock *sk)
+{
+ struct bt_sock *bt = bt_sk(parent);
+ struct sock *next = NULL;
+
+ /* accept_q is modified from child teardown paths too, so take a
+ * temporary reference before dropping the queue lock.
+ */
+ spin_lock_bh(&bt->accept_q_lock);
+
+ if (sk) {
+ if (bt_sk(sk)->parent != parent)
+ goto out;
+
+ if (!list_is_last(&bt_sk(sk)->accept_q, &bt->accept_q)) {
+ next = &list_next_entry(bt_sk(sk), accept_q)->sk;
+ sock_hold(next);
+ }
+ } else if (!list_empty(&bt->accept_q)) {
+ next = &list_first_entry(&bt->accept_q,
+ struct bt_sock, accept_q)->sk;
+ sock_hold(next);
+ }
+
+out:
+ spin_unlock_bh(&bt->accept_q_lock);
+ return next;
+}
+
struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock)
{
- struct bt_sock *s, *n;
- struct sock *sk;
+ struct sock *sk, *next;
BT_DBG("parent %p", parent);
restart:
- list_for_each_entry_safe(s, n, &bt_sk(parent)->accept_q, accept_q) {
- sk = (struct sock *)s;
-
+ for (sk = bt_accept_get(parent, NULL); sk; sk = next) {
/* Prevent early freeing of sk due to unlink and sock_kill */
- sock_hold(sk);
lock_sock(sk);
/* Check sk has not already been unlinked via
* bt_accept_unlink() due to serialisation caused by sk locking
*/
- if (!bt_sk(sk)->parent) {
+ if (bt_sk(sk)->parent != parent) {
BT_DBG("sk %p, already unlinked", sk);
release_sock(sk);
sock_put(sk);
- /* Restart the loop as sk is no longer in the list
- * and also avoid a potential infinite loop because
- * list_for_each_entry_safe() is not thread safe.
- */
goto restart;
}
+ next = bt_accept_get(parent, sk);
+
/* sk is safely in the parent list so reduce reference count */
sock_put(sk);
@@ -310,6 +343,8 @@ struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock)
sock_graft(sk, newsock);
release_sock(sk);
+ if (next)
+ sock_put(next);
return sk;
}
@@ -518,18 +553,28 @@ EXPORT_SYMBOL(bt_sock_stream_recvmsg);
static inline __poll_t bt_accept_poll(struct sock *parent)
{
- struct bt_sock *s, *n;
+ struct bt_sock *bt = bt_sk(parent);
+ struct bt_sock *s;
struct sock *sk;
+ __poll_t mask = 0;
+
+ spin_lock_bh(&bt->accept_q_lock);
+ list_for_each_entry(s, &bt->accept_q, accept_q) {
+ int state;
- list_for_each_entry_safe(s, n, &bt_sk(parent)->accept_q, accept_q) {
sk = (struct sock *)s;
- if (sk->sk_state == BT_CONNECTED ||
- (test_bit(BT_SK_DEFER_SETUP, &bt_sk(parent)->flags) &&
- sk->sk_state == BT_CONNECT2))
- return EPOLLIN | EPOLLRDNORM;
+ state = READ_ONCE(sk->sk_state);
+
+ if (state == BT_CONNECTED ||
+ (test_bit(BT_SK_DEFER_SETUP, &bt->flags) &&
+ state == BT_CONNECT2)) {
+ mask = EPOLLIN | EPOLLRDNORM;
+ break;
+ }
}
+ spin_unlock_bh(&bt->accept_q_lock);
- return 0;
+ return mask;
}
__poll_t bt_sock_poll(struct file *file, struct socket *sock,
--
2.34.1
^ permalink raw reply related
* [PATCH OLK-6.6 086/451] bpf, net: validate struct_ops when updating value.
From: Zicheng Qu @ 2026-04-03 7:27 UTC (permalink / raw)
To: kernel
Cc: tanghui20, quzicheng, quzicheng315, Kui-Feng Lee, netdev,
Martin KaFai Lau, Luo Gengkun
In-Reply-To: <20260403073326.3096906-1-quzicheng@huawei.com>
From: Kui-Feng Lee <thinker.li@gmail.com>
mainline inclusion
from mainline-v6.9-rc1
commit 73e4f9e615d7b99f39663d4722dc73e8fa5db5f9
category: feature
bugzilla: https://atomgit.com/openeuler/kernel/issues/8335
CVE: NA
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=73e4f9e615d7b99f39663d4722dc73e8fa5db5f9
----------------------------------------------------------------------
Perform all validations when updating values of struct_ops maps. Doing
validation in st_ops->reg() and st_ops->update() is not necessary anymore.
However, tcp_register_congestion_control() has been called in various
places. It still needs to do validations.
Cc: netdev@vger.kernel.org
Signed-off-by: Kui-Feng Lee <thinker.li@gmail.com>
Link: https://lore.kernel.org/r/20240224223418.526631-2-thinker.li@gmail.com
Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
Signed-off-by: Luo Gengkun <luogengkun2@huawei.com>
---
kernel/bpf/bpf_struct_ops.c | 11 ++++++-----
net/ipv4/tcp_cong.c | 6 +-----
2 files changed, 7 insertions(+), 10 deletions(-)
diff --git a/kernel/bpf/bpf_struct_ops.c b/kernel/bpf/bpf_struct_ops.c
index 0d7be97a2411..c244ed5114fd 100644
--- a/kernel/bpf/bpf_struct_ops.c
+++ b/kernel/bpf/bpf_struct_ops.c
@@ -667,13 +667,14 @@ static long bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key,
*(unsigned long *)(udata + moff) = prog->aux->id;
}
+ if (st_ops->validate) {
+ err = st_ops->validate(kdata);
+ if (err)
+ goto reset_unlock;
+ }
+
if (st_map->map.map_flags & BPF_F_LINK) {
err = 0;
- if (st_ops->validate) {
- err = st_ops->validate(kdata);
- if (err)
- goto reset_unlock;
- }
arch_protect_bpf_trampoline(st_map->image, PAGE_SIZE);
/* Let bpf_link handle registration & unregistration.
*
diff --git a/net/ipv4/tcp_cong.c b/net/ipv4/tcp_cong.c
index 95dbb2799be4..48617d99abb0 100644
--- a/net/ipv4/tcp_cong.c
+++ b/net/ipv4/tcp_cong.c
@@ -145,11 +145,7 @@ EXPORT_SYMBOL_GPL(tcp_unregister_congestion_control);
int tcp_update_congestion_control(struct tcp_congestion_ops *ca, struct tcp_congestion_ops *old_ca)
{
struct tcp_congestion_ops *existing;
- int ret;
-
- ret = tcp_validate_congestion_control(ca);
- if (ret)
- return ret;
+ int ret = 0;
ca->key = jhash(ca->name, sizeof(ca->name), strlen(ca->name));
--
2.34.1
^ permalink raw reply related
* [PATCH OLK-6.6 058/451] bpf, net: switch to dynamic registration
From: Zicheng Qu @ 2026-04-03 7:26 UTC (permalink / raw)
To: kernel
Cc: tanghui20, quzicheng, quzicheng315, Kui-Feng Lee, netdev,
Martin KaFai Lau, Luo Gengkun
In-Reply-To: <20260403073326.3096906-1-quzicheng@huawei.com>
From: Kui-Feng Lee <thinker.li@gmail.com>
mainline inclusion
from mainline-v6.9-rc1
commit f6be98d19985411ca1f3d53413d94d5b7f41c200
category: feature
bugzilla: https://atomgit.com/openeuler/kernel/issues/8335
CVE: NA
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=f6be98d19985411ca1f3d53413d94d5b7f41c200
----------------------------------------------------------------------
Replace the static list of struct_ops types with per-btf struct_ops_tab to
enable dynamic registration.
Both bpf_dummy_ops and bpf_tcp_ca now utilize the registration function
instead of being listed in bpf_struct_ops_types.h.
Cc: netdev@vger.kernel.org
Signed-off-by: Kui-Feng Lee <thinker.li@gmail.com>
Link: https://lore.kernel.org/r/20240119225005.668602-12-thinker.li@gmail.com
Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
Signed-off-by: Luo Gengkun <luogengkun2@huawei.com>
---
include/linux/bpf.h | 27 +++++---
include/linux/btf.h | 12 ++++
kernel/bpf/bpf_struct_ops.c | 100 ++++--------------------------
kernel/bpf/bpf_struct_ops_types.h | 12 ----
kernel/bpf/btf.c | 86 +++++++++++++++++++++++--
net/bpf/bpf_dummy_struct_ops.c | 11 +++-
net/ipv4/bpf_tcp_ca.c | 12 +++-
7 files changed, 142 insertions(+), 118 deletions(-)
delete mode 100644 kernel/bpf/bpf_struct_ops_types.h
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 6eba14c2eb93..0624b33be7a2 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -1827,9 +1827,20 @@ struct bpf_struct_ops_common_value {
};
#if defined(CONFIG_BPF_JIT) && defined(CONFIG_BPF_SYSCALL)
+/* This macro helps developer to register a struct_ops type and generate
+ * type information correctly. Developers should use this macro to register
+ * a struct_ops type instead of calling __register_bpf_struct_ops() directly.
+ */
+#define register_bpf_struct_ops(st_ops, type) \
+ ({ \
+ struct bpf_struct_ops_##type { \
+ struct bpf_struct_ops_common_value common; \
+ struct type data ____cacheline_aligned_in_smp; \
+ }; \
+ BTF_TYPE_EMIT(struct bpf_struct_ops_##type); \
+ __register_bpf_struct_ops(st_ops); \
+ })
#define BPF_MODULE_OWNER ((void *)((0xeB9FUL << 2) + POISON_POINTER_DELTA))
-const struct bpf_struct_ops_desc *bpf_struct_ops_find(struct btf *btf, u32 type_id);
-void bpf_struct_ops_init(struct btf *btf, struct bpf_verifier_log *log);
bool bpf_struct_ops_get(const void *kdata);
void bpf_struct_ops_put(const void *kdata);
int bpf_struct_ops_map_sys_lookup_elem(struct bpf_map *map, void *key,
@@ -1871,16 +1882,12 @@ struct bpf_dummy_ops {
int bpf_struct_ops_test_run(struct bpf_prog *prog, const union bpf_attr *kattr,
union bpf_attr __user *uattr);
#endif
+int bpf_struct_ops_desc_init(struct bpf_struct_ops_desc *st_ops_desc,
+ struct btf *btf,
+ struct bpf_verifier_log *log);
void bpf_map_struct_ops_info_fill(struct bpf_map_info *info, struct bpf_map *map);
#else
-static inline const struct bpf_struct_ops_desc *bpf_struct_ops_find(struct btf *btf, u32 type_id)
-{
- return NULL;
-}
-static inline void bpf_struct_ops_init(struct btf *btf,
- struct bpf_verifier_log *log)
-{
-}
+#define register_bpf_struct_ops(st_ops, type) ({ (void *)(st_ops); 0; })
static inline bool bpf_try_module_get(const void *data, struct module *owner)
{
return try_module_get(owner);
diff --git a/include/linux/btf.h b/include/linux/btf.h
index 1d852dad7473..79f34103ab5d 100644
--- a/include/linux/btf.h
+++ b/include/linux/btf.h
@@ -497,6 +497,18 @@ static inline void *btf_id_set8_contains(const struct btf_id_set8 *set, u32 id)
struct bpf_verifier_log;
+#if defined(CONFIG_BPF_JIT) && defined(CONFIG_BPF_SYSCALL)
+struct bpf_struct_ops;
+int __register_bpf_struct_ops(struct bpf_struct_ops *st_ops);
+const struct bpf_struct_ops_desc *bpf_struct_ops_find_value(struct btf *btf, u32 value_id);
+const struct bpf_struct_ops_desc *bpf_struct_ops_find(struct btf *btf, u32 type_id);
+#else
+static inline const struct bpf_struct_ops_desc *bpf_struct_ops_find(struct btf *btf, u32 type_id)
+{
+ return NULL;
+}
+#endif
+
#ifdef CONFIG_BPF_SYSCALL
const struct btf_type *btf_type_by_id(const struct btf *btf, u32 type_id);
const char *btf_name_by_offset(const struct btf *btf, u32 offset);
diff --git a/kernel/bpf/bpf_struct_ops.c b/kernel/bpf/bpf_struct_ops.c
index 30ab34fab0f8..defc052e4622 100644
--- a/kernel/bpf/bpf_struct_ops.c
+++ b/kernel/bpf/bpf_struct_ops.c
@@ -62,35 +62,6 @@ static DEFINE_MUTEX(update_mutex);
#define VALUE_PREFIX "bpf_struct_ops_"
#define VALUE_PREFIX_LEN (sizeof(VALUE_PREFIX) - 1)
-/* bpf_struct_ops_##_name (e.g. bpf_struct_ops_tcp_congestion_ops) is
- * the map's value exposed to the userspace and its btf-type-id is
- * stored at the map->btf_vmlinux_value_type_id.
- *
- */
-#define BPF_STRUCT_OPS_TYPE(_name) \
-extern struct bpf_struct_ops bpf_##_name; \
- \
-struct bpf_struct_ops_##_name { \
- struct bpf_struct_ops_common_value common; \
- struct _name data ____cacheline_aligned_in_smp; \
-};
-#include "bpf_struct_ops_types.h"
-#undef BPF_STRUCT_OPS_TYPE
-
-enum {
-#define BPF_STRUCT_OPS_TYPE(_name) BPF_STRUCT_OPS_TYPE_##_name,
-#include "bpf_struct_ops_types.h"
-#undef BPF_STRUCT_OPS_TYPE
- __NR_BPF_STRUCT_OPS_TYPE,
-};
-
-static struct bpf_struct_ops_desc bpf_struct_ops[] = {
-#define BPF_STRUCT_OPS_TYPE(_name) \
- [BPF_STRUCT_OPS_TYPE_##_name] = { .st_ops = &bpf_##_name },
-#include "bpf_struct_ops_types.h"
-#undef BPF_STRUCT_OPS_TYPE
-};
-
const struct bpf_verifier_ops bpf_struct_ops_verifier_ops = {
};
@@ -145,9 +116,9 @@ static bool is_valid_value_type(struct btf *btf, s32 value_id,
return true;
}
-static void bpf_struct_ops_desc_init(struct bpf_struct_ops_desc *st_ops_desc,
- struct btf *btf,
- struct bpf_verifier_log *log)
+int bpf_struct_ops_desc_init(struct bpf_struct_ops_desc *st_ops_desc,
+ struct btf *btf,
+ struct bpf_verifier_log *log)
{
struct bpf_struct_ops *st_ops = st_ops_desc->st_ops;
const struct btf_member *member;
@@ -161,7 +132,7 @@ static void bpf_struct_ops_desc_init(struct bpf_struct_ops_desc *st_ops_desc,
sizeof(value_name)) {
pr_warn("struct_ops name %s is too long\n",
st_ops->name);
- return;
+ return -EINVAL;
}
sprintf(value_name, "%s%s", VALUE_PREFIX, st_ops->name);
@@ -170,13 +141,13 @@ static void bpf_struct_ops_desc_init(struct bpf_struct_ops_desc *st_ops_desc,
if (type_id < 0) {
pr_warn("Cannot find struct %s in %s\n",
st_ops->name, btf_get_name(btf));
- return;
+ return -EINVAL;
}
t = btf_type_by_id(btf, type_id);
if (btf_type_vlen(t) > BPF_STRUCT_OPS_MAX_NR_MEMBERS) {
pr_warn("Cannot support #%u members in struct %s\n",
btf_type_vlen(t), st_ops->name);
- return;
+ return -EINVAL;
}
value_id = btf_find_by_name_kind(btf, value_name,
@@ -184,10 +155,10 @@ static void bpf_struct_ops_desc_init(struct bpf_struct_ops_desc *st_ops_desc,
if (value_id < 0) {
pr_warn("Cannot find struct %s in %s\n",
value_name, btf_get_name(btf));
- return;
+ return -EINVAL;
}
if (!is_valid_value_type(btf, value_id, t, value_name))
- return;
+ return -EINVAL;
for_each_member(i, t, member) {
const struct btf_type *func_proto;
@@ -196,13 +167,13 @@ static void bpf_struct_ops_desc_init(struct bpf_struct_ops_desc *st_ops_desc,
if (!*mname) {
pr_warn("anon member in struct %s is not supported\n",
st_ops->name);
- break;
+ return -EOPNOTSUPP;
}
if (__btf_member_bitfield_size(t, member)) {
pr_warn("bit field member %s in struct %s is not supported\n",
mname, st_ops->name);
- break;
+ return -EOPNOTSUPP;
}
func_proto = btf_type_resolve_func_ptr(btf,
@@ -214,7 +185,7 @@ static void bpf_struct_ops_desc_init(struct bpf_struct_ops_desc *st_ops_desc,
&st_ops->func_models[i])) {
pr_warn("Error in parsing func ptr %s in struct %s\n",
mname, st_ops->name);
- break;
+ return -EINVAL;
}
}
@@ -222,6 +193,7 @@ static void bpf_struct_ops_desc_init(struct bpf_struct_ops_desc *st_ops_desc,
if (st_ops->init(btf)) {
pr_warn("Error in init bpf_struct_ops %s\n",
st_ops->name);
+ return -EINVAL;
} else {
st_ops_desc->type_id = type_id;
st_ops_desc->type = t;
@@ -230,54 +202,8 @@ static void bpf_struct_ops_desc_init(struct bpf_struct_ops_desc *st_ops_desc,
value_id);
}
}
-}
-void bpf_struct_ops_init(struct btf *btf, struct bpf_verifier_log *log)
-{
- struct bpf_struct_ops_desc *st_ops_desc;
- u32 i;
-
- /* Ensure BTF type is emitted for "struct bpf_struct_ops_##_name" */
-#define BPF_STRUCT_OPS_TYPE(_name) BTF_TYPE_EMIT(struct bpf_struct_ops_##_name);
-#include "bpf_struct_ops_types.h"
-#undef BPF_STRUCT_OPS_TYPE
-
- for (i = 0; i < ARRAY_SIZE(bpf_struct_ops); i++) {
- st_ops_desc = &bpf_struct_ops[i];
- bpf_struct_ops_desc_init(st_ops_desc, btf, log);
- }
-}
-
-static const struct bpf_struct_ops_desc *
-bpf_struct_ops_find_value(struct btf *btf, u32 value_id)
-{
- unsigned int i;
-
- if (!value_id || !btf)
- return NULL;
-
- for (i = 0; i < ARRAY_SIZE(bpf_struct_ops); i++) {
- if (bpf_struct_ops[i].value_id == value_id)
- return &bpf_struct_ops[i];
- }
-
- return NULL;
-}
-
-const struct bpf_struct_ops_desc *
-bpf_struct_ops_find(struct btf *btf, u32 type_id)
-{
- unsigned int i;
-
- if (!type_id || !btf)
- return NULL;
-
- for (i = 0; i < ARRAY_SIZE(bpf_struct_ops); i++) {
- if (bpf_struct_ops[i].type_id == type_id)
- return &bpf_struct_ops[i];
- }
-
- return NULL;
+ return 0;
}
static int bpf_struct_ops_map_get_next_key(struct bpf_map *map, void *key,
diff --git a/kernel/bpf/bpf_struct_ops_types.h b/kernel/bpf/bpf_struct_ops_types.h
deleted file mode 100644
index 5678a9ddf817..000000000000
--- a/kernel/bpf/bpf_struct_ops_types.h
+++ /dev/null
@@ -1,12 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/* internal file - do not include directly */
-
-#ifdef CONFIG_BPF_JIT
-#ifdef CONFIG_NET
-BPF_STRUCT_OPS_TYPE(bpf_dummy_ops)
-#endif
-#ifdef CONFIG_INET
-#include <net/tcp.h>
-BPF_STRUCT_OPS_TYPE(tcp_congestion_ops)
-#endif
-#endif
diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
index 4ecdd08aec7f..1cd7e8fbcc57 100644
--- a/kernel/bpf/btf.c
+++ b/kernel/bpf/btf.c
@@ -19,6 +19,7 @@
#include <linux/bpf_verifier.h>
#include <linux/btf.h>
#include <linux/btf_ids.h>
+#include <linux/bpf.h>
#include <linux/bpf_lsm.h>
#include <linux/skmsg.h>
#include <linux/perf_event.h>
@@ -5801,8 +5802,6 @@ struct btf *btf_parse_vmlinux(void)
/* btf_parse_vmlinux() runs under bpf_verifier_lock */
bpf_ctx_convert.t = btf_type_by_id(btf, bpf_ctx_convert_btf_id[0]);
- bpf_struct_ops_init(btf, log);
-
refcount_set(&btf->refcnt, 1);
err = btf_alloc_id(btf);
@@ -8895,11 +8894,13 @@ bool btf_type_ids_nocast_alias(struct bpf_verifier_log *log,
return !strncmp(reg_name, arg_name, cmp_len);
}
+#ifdef CONFIG_BPF_JIT
static int
-btf_add_struct_ops(struct btf *btf, struct bpf_struct_ops *st_ops)
+btf_add_struct_ops(struct btf *btf, struct bpf_struct_ops *st_ops,
+ struct bpf_verifier_log *log)
{
struct btf_struct_ops_tab *tab, *new_tab;
- int i;
+ int i, err;
tab = btf->struct_ops_tab;
if (!tab) {
@@ -8929,7 +8930,84 @@ btf_add_struct_ops(struct btf *btf, struct bpf_struct_ops *st_ops)
tab->ops[btf->struct_ops_tab->cnt].st_ops = st_ops;
+ err = bpf_struct_ops_desc_init(&tab->ops[btf->struct_ops_tab->cnt], btf, log);
+ if (err)
+ return err;
+
btf->struct_ops_tab->cnt++;
return 0;
}
+
+const struct bpf_struct_ops_desc *
+bpf_struct_ops_find_value(struct btf *btf, u32 value_id)
+{
+ const struct bpf_struct_ops_desc *st_ops_list;
+ unsigned int i;
+ u32 cnt;
+
+ if (!value_id)
+ return NULL;
+ if (!btf->struct_ops_tab)
+ return NULL;
+
+ cnt = btf->struct_ops_tab->cnt;
+ st_ops_list = btf->struct_ops_tab->ops;
+ for (i = 0; i < cnt; i++) {
+ if (st_ops_list[i].value_id == value_id)
+ return &st_ops_list[i];
+ }
+
+ return NULL;
+}
+
+const struct bpf_struct_ops_desc *
+bpf_struct_ops_find(struct btf *btf, u32 type_id)
+{
+ const struct bpf_struct_ops_desc *st_ops_list;
+ unsigned int i;
+ u32 cnt;
+
+ if (!type_id)
+ return NULL;
+ if (!btf->struct_ops_tab)
+ return NULL;
+
+ cnt = btf->struct_ops_tab->cnt;
+ st_ops_list = btf->struct_ops_tab->ops;
+ for (i = 0; i < cnt; i++) {
+ if (st_ops_list[i].type_id == type_id)
+ return &st_ops_list[i];
+ }
+
+ return NULL;
+}
+
+int __register_bpf_struct_ops(struct bpf_struct_ops *st_ops)
+{
+ struct bpf_verifier_log *log;
+ struct btf *btf;
+ int err = 0;
+
+ btf = btf_get_module_btf(st_ops->owner);
+ if (!btf)
+ return -EINVAL;
+
+ log = kzalloc(sizeof(*log), GFP_KERNEL | __GFP_NOWARN);
+ if (!log) {
+ err = -ENOMEM;
+ goto errout;
+ }
+
+ log->level = BPF_LOG_KERNEL;
+
+ err = btf_add_struct_ops(btf, st_ops, log);
+
+errout:
+ kfree(log);
+ btf_put(btf);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(__register_bpf_struct_ops);
+#endif
diff --git a/net/bpf/bpf_dummy_struct_ops.c b/net/bpf/bpf_dummy_struct_ops.c
index ba2c58dba2da..02de71719aed 100644
--- a/net/bpf/bpf_dummy_struct_ops.c
+++ b/net/bpf/bpf_dummy_struct_ops.c
@@ -7,7 +7,7 @@
#include <linux/bpf.h>
#include <linux/btf.h>
-extern struct bpf_struct_ops bpf_bpf_dummy_ops;
+static struct bpf_struct_ops bpf_bpf_dummy_ops;
/* A common type for test_N with return value in bpf_dummy_ops */
typedef int (*dummy_ops_test_ret_fn)(struct bpf_dummy_ops_state *state, ...);
@@ -256,7 +256,7 @@ static struct bpf_dummy_ops __bpf_bpf_dummy_ops = {
.test_sleepable = bpf_dummy_test_sleepable,
};
-struct bpf_struct_ops bpf_bpf_dummy_ops = {
+static struct bpf_struct_ops bpf_bpf_dummy_ops = {
.verifier_ops = &bpf_dummy_verifier_ops,
.init = bpf_dummy_init,
.check_member = bpf_dummy_ops_check_member,
@@ -265,4 +265,11 @@ struct bpf_struct_ops bpf_bpf_dummy_ops = {
.unreg = bpf_dummy_unreg,
.name = "bpf_dummy_ops",
.cfi_stubs = &__bpf_bpf_dummy_ops,
+ .owner = THIS_MODULE,
};
+
+static int __init bpf_dummy_struct_ops_init(void)
+{
+ return register_bpf_struct_ops(&bpf_bpf_dummy_ops, bpf_dummy_ops);
+}
+late_initcall(bpf_dummy_struct_ops_init);
diff --git a/net/ipv4/bpf_tcp_ca.c b/net/ipv4/bpf_tcp_ca.c
index dffd8828079b..8e7716256d3c 100644
--- a/net/ipv4/bpf_tcp_ca.c
+++ b/net/ipv4/bpf_tcp_ca.c
@@ -12,7 +12,7 @@
#include <net/bpf_sk_storage.h>
/* "extern" is to avoid sparse warning. It is only used in bpf_struct_ops.c. */
-extern struct bpf_struct_ops bpf_tcp_congestion_ops;
+static struct bpf_struct_ops bpf_tcp_congestion_ops;
static u32 unsupported_ops[] = {
offsetof(struct tcp_congestion_ops, get_info),
@@ -345,7 +345,7 @@ static struct tcp_congestion_ops __bpf_ops_tcp_congestion_ops = {
.release = __bpf_tcp_ca_release,
};
-struct bpf_struct_ops bpf_tcp_congestion_ops = {
+static struct bpf_struct_ops bpf_tcp_congestion_ops = {
.verifier_ops = &bpf_tcp_ca_verifier_ops,
.reg = bpf_tcp_ca_reg,
.unreg = bpf_tcp_ca_unreg,
@@ -356,10 +356,16 @@ struct bpf_struct_ops bpf_tcp_congestion_ops = {
.validate = bpf_tcp_ca_validate,
.name = "tcp_congestion_ops",
.cfi_stubs = &__bpf_ops_tcp_congestion_ops,
+ .owner = THIS_MODULE,
};
static int __init bpf_tcp_ca_kfunc_init(void)
{
- return register_btf_kfunc_id_set(BPF_PROG_TYPE_STRUCT_OPS, &bpf_tcp_ca_kfunc_set);
+ int ret;
+
+ ret = register_btf_kfunc_id_set(BPF_PROG_TYPE_STRUCT_OPS, &bpf_tcp_ca_kfunc_set);
+ ret = ret ?: register_bpf_struct_ops(&bpf_tcp_congestion_ops, tcp_congestion_ops);
+
+ return ret;
}
late_initcall(bpf_tcp_ca_kfunc_init);
--
2.34.1
^ permalink raw reply related
* [PATCH OLK-6.6 048/451] bpf, net: introduce bpf_struct_ops_desc.
From: Zicheng Qu @ 2026-04-03 7:26 UTC (permalink / raw)
To: kernel
Cc: tanghui20, quzicheng, quzicheng315, Kui-Feng Lee, netdev,
Martin KaFai Lau, Luo Gengkun
In-Reply-To: <20260403073326.3096906-1-quzicheng@huawei.com>
From: Kui-Feng Lee <thinker.li@gmail.com>
mainline inclusion
from mainline-v6.9-rc1
commit 4c5763ed996a61b51d721d0968d0df957826ea49
category: feature
bugzilla: https://atomgit.com/openeuler/kernel/issues/8335
CVE: NA
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=4c5763ed996a61b51d721d0968d0df957826ea49
----------------------------------------------------------------------
Move some of members of bpf_struct_ops to bpf_struct_ops_desc. type_id is
unavailabe in bpf_struct_ops anymore. Modules should get it from the btf
received by kmod's init function.
Cc: netdev@vger.kernel.org
Signed-off-by: Kui-Feng Lee <thinker.li@gmail.com>
Link: https://lore.kernel.org/r/20240119225005.668602-4-thinker.li@gmail.com
Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
Conflicts:
include/linux/bpf.h
[Fix conflicts because of kabi.]
Signed-off-by: Luo Gengkun <luogengkun2@huawei.com>
---
include/linux/bpf.h | 17 +++++---
kernel/bpf/bpf_struct_ops.c | 80 +++++++++++++++++-----------------
kernel/bpf/verifier.c | 8 ++--
net/bpf/bpf_dummy_struct_ops.c | 11 ++++-
net/ipv4/bpf_tcp_ca.c | 8 +++-
5 files changed, 75 insertions(+), 49 deletions(-)
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 3bb9b329340f..562e52f0f982 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -1792,13 +1792,11 @@ struct bpf_struct_ops {
void (*unreg)(void *kdata);
int (*update)(void *kdata, void *old_kdata);
int (*validate)(void *kdata);
- const struct btf_type *type;
- const struct btf_type *value_type;
+ void *cfi_stubs;
const char *name;
struct btf_func_model func_models[BPF_STRUCT_OPS_MAX_NR_MEMBERS];
u32 type_id;
u32 value_id;
- void *cfi_stubs;
KABI_RESERVE(1)
KABI_RESERVE(2)
@@ -1806,9 +1804,18 @@ struct bpf_struct_ops {
KABI_RESERVE(4)
};
+struct bpf_struct_ops_desc {
+ struct bpf_struct_ops *st_ops;
+
+ const struct btf_type *type;
+ const struct btf_type *value_type;
+ u32 type_id;
+ u32 value_id;
+};
+
#if defined(CONFIG_BPF_JIT) && defined(CONFIG_BPF_SYSCALL)
#define BPF_MODULE_OWNER ((void *)((0xeB9FUL << 2) + POISON_POINTER_DELTA))
-const struct bpf_struct_ops *bpf_struct_ops_find(u32 type_id);
+const struct bpf_struct_ops_desc *bpf_struct_ops_find(u32 type_id);
void bpf_struct_ops_init(struct btf *btf, struct bpf_verifier_log *log);
bool bpf_struct_ops_get(const void *kdata);
void bpf_struct_ops_put(const void *kdata);
@@ -1852,7 +1859,7 @@ int bpf_struct_ops_test_run(struct bpf_prog *prog, const union bpf_attr *kattr,
union bpf_attr __user *uattr);
#endif
#else
-static inline const struct bpf_struct_ops *bpf_struct_ops_find(u32 type_id)
+static inline const struct bpf_struct_ops_desc *bpf_struct_ops_find(u32 type_id)
{
return NULL;
}
diff --git a/kernel/bpf/bpf_struct_ops.c b/kernel/bpf/bpf_struct_ops.c
index 5b3ebcb435d0..9774f7824e8b 100644
--- a/kernel/bpf/bpf_struct_ops.c
+++ b/kernel/bpf/bpf_struct_ops.c
@@ -32,7 +32,7 @@ struct bpf_struct_ops_value {
struct bpf_struct_ops_map {
struct bpf_map map;
struct rcu_head rcu;
- const struct bpf_struct_ops *st_ops;
+ const struct bpf_struct_ops_desc *st_ops_desc;
/* protect map_update */
struct mutex lock;
/* link has all the bpf_links that is populated
@@ -92,9 +92,9 @@ enum {
__NR_BPF_STRUCT_OPS_TYPE,
};
-static struct bpf_struct_ops * const bpf_struct_ops[] = {
+static struct bpf_struct_ops_desc bpf_struct_ops[] = {
#define BPF_STRUCT_OPS_TYPE(_name) \
- [BPF_STRUCT_OPS_TYPE_##_name] = &bpf_##_name,
+ [BPF_STRUCT_OPS_TYPE_##_name] = { .st_ops = &bpf_##_name },
#include "bpf_struct_ops_types.h"
#undef BPF_STRUCT_OPS_TYPE
};
@@ -115,10 +115,11 @@ enum {
IDX_MODULE_ID,
};
-static void bpf_struct_ops_init_one(struct bpf_struct_ops *st_ops,
- struct btf *btf,
- struct bpf_verifier_log *log)
+static void bpf_struct_ops_desc_init(struct bpf_struct_ops_desc *st_ops_desc,
+ struct btf *btf,
+ struct bpf_verifier_log *log)
{
+ struct bpf_struct_ops *st_ops = st_ops_desc->st_ops;
const struct btf_member *member;
const struct btf_type *t;
s32 type_id, value_id;
@@ -190,18 +191,18 @@ static void bpf_struct_ops_init_one(struct bpf_struct_ops *st_ops,
pr_warn("Error in init bpf_struct_ops %s\n",
st_ops->name);
} else {
- st_ops->type_id = type_id;
- st_ops->type = t;
- st_ops->value_id = value_id;
- st_ops->value_type = btf_type_by_id(btf,
- value_id);
+ st_ops_desc->type_id = type_id;
+ st_ops_desc->type = t;
+ st_ops_desc->value_id = value_id;
+ st_ops_desc->value_type = btf_type_by_id(btf,
+ value_id);
}
}
}
void bpf_struct_ops_init(struct btf *btf, struct bpf_verifier_log *log)
{
- struct bpf_struct_ops *st_ops;
+ struct bpf_struct_ops_desc *st_ops_desc;
u32 i;
/* Ensure BTF type is emitted for "struct bpf_struct_ops_##_name" */
@@ -210,14 +211,14 @@ void bpf_struct_ops_init(struct btf *btf, struct bpf_verifier_log *log)
#undef BPF_STRUCT_OPS_TYPE
for (i = 0; i < ARRAY_SIZE(bpf_struct_ops); i++) {
- st_ops = bpf_struct_ops[i];
- bpf_struct_ops_init_one(st_ops, btf, log);
+ st_ops_desc = &bpf_struct_ops[i];
+ bpf_struct_ops_desc_init(st_ops_desc, btf, log);
}
}
extern struct btf *btf_vmlinux;
-static const struct bpf_struct_ops *
+static const struct bpf_struct_ops_desc *
bpf_struct_ops_find_value(u32 value_id)
{
unsigned int i;
@@ -226,14 +227,14 @@ bpf_struct_ops_find_value(u32 value_id)
return NULL;
for (i = 0; i < ARRAY_SIZE(bpf_struct_ops); i++) {
- if (bpf_struct_ops[i]->value_id == value_id)
- return bpf_struct_ops[i];
+ if (bpf_struct_ops[i].value_id == value_id)
+ return &bpf_struct_ops[i];
}
return NULL;
}
-const struct bpf_struct_ops *bpf_struct_ops_find(u32 type_id)
+const struct bpf_struct_ops_desc *bpf_struct_ops_find(u32 type_id)
{
unsigned int i;
@@ -241,8 +242,8 @@ const struct bpf_struct_ops *bpf_struct_ops_find(u32 type_id)
return NULL;
for (i = 0; i < ARRAY_SIZE(bpf_struct_ops); i++) {
- if (bpf_struct_ops[i]->type_id == type_id)
- return bpf_struct_ops[i];
+ if (bpf_struct_ops[i].type_id == type_id)
+ return &bpf_struct_ops[i];
}
return NULL;
@@ -302,7 +303,7 @@ static void *bpf_struct_ops_map_lookup_elem(struct bpf_map *map, void *key)
static void bpf_struct_ops_map_put_progs(struct bpf_struct_ops_map *st_map)
{
- const struct btf_type *t = st_map->st_ops->type;
+ const struct btf_type *t = st_map->st_ops_desc->type;
u32 i;
for (i = 0; i < btf_type_vlen(t); i++) {
@@ -382,11 +383,12 @@ static long bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key,
void *value, u64 flags)
{
struct bpf_struct_ops_map *st_map = (struct bpf_struct_ops_map *)map;
- const struct bpf_struct_ops *st_ops = st_map->st_ops;
+ const struct bpf_struct_ops_desc *st_ops_desc = st_map->st_ops_desc;
+ const struct bpf_struct_ops *st_ops = st_ops_desc->st_ops;
struct bpf_struct_ops_value *uvalue, *kvalue;
const struct btf_type *module_type;
const struct btf_member *member;
- const struct btf_type *t = st_ops->type;
+ const struct btf_type *t = st_ops_desc->type;
struct bpf_tramp_links *tlinks;
void *udata, *kdata;
int prog_fd, err;
@@ -399,7 +401,7 @@ static long bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key,
if (*(u32 *)key != 0)
return -E2BIG;
- err = check_zero_holes(st_ops->value_type, value);
+ err = check_zero_holes(st_ops_desc->value_type, value);
if (err)
return err;
@@ -492,7 +494,7 @@ static long bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key,
}
if (prog->type != BPF_PROG_TYPE_STRUCT_OPS ||
- prog->aux->attach_btf_id != st_ops->type_id ||
+ prog->aux->attach_btf_id != st_ops_desc->type_id ||
prog->expected_attach_type != i) {
bpf_prog_put(prog);
err = -EINVAL;
@@ -588,7 +590,7 @@ static long bpf_struct_ops_map_delete_elem(struct bpf_map *map, void *key)
BPF_STRUCT_OPS_STATE_TOBEFREE);
switch (prev_state) {
case BPF_STRUCT_OPS_STATE_INUSE:
- st_map->st_ops->unreg(&st_map->kvalue.data);
+ st_map->st_ops_desc->st_ops->unreg(&st_map->kvalue.data);
bpf_map_put(map);
return 0;
case BPF_STRUCT_OPS_STATE_TOBEFREE:
@@ -669,22 +671,22 @@ static int bpf_struct_ops_map_alloc_check(union bpf_attr *attr)
static struct bpf_map *bpf_struct_ops_map_alloc(union bpf_attr *attr)
{
- const struct bpf_struct_ops *st_ops;
+ const struct bpf_struct_ops_desc *st_ops_desc;
size_t st_map_size;
struct bpf_struct_ops_map *st_map;
const struct btf_type *t, *vt;
struct bpf_map *map;
int ret;
- st_ops = bpf_struct_ops_find_value(attr->btf_vmlinux_value_type_id);
- if (!st_ops)
+ st_ops_desc = bpf_struct_ops_find_value(attr->btf_vmlinux_value_type_id);
+ if (!st_ops_desc)
return ERR_PTR(-ENOTSUPP);
- vt = st_ops->value_type;
+ vt = st_ops_desc->value_type;
if (attr->value_size != vt->size)
return ERR_PTR(-EINVAL);
- t = st_ops->type;
+ t = st_ops_desc->type;
st_map_size = sizeof(*st_map) +
/* kvalue stores the
@@ -696,7 +698,7 @@ static struct bpf_map *bpf_struct_ops_map_alloc(union bpf_attr *attr)
if (!st_map)
return ERR_PTR(-ENOMEM);
- st_map->st_ops = st_ops;
+ st_map->st_ops_desc = st_ops_desc;
map = &st_map->map;
ret = bpf_jit_charge_modmem(PAGE_SIZE);
@@ -733,8 +735,8 @@ static struct bpf_map *bpf_struct_ops_map_alloc(union bpf_attr *attr)
static u64 bpf_struct_ops_map_mem_usage(const struct bpf_map *map)
{
struct bpf_struct_ops_map *st_map = (struct bpf_struct_ops_map *)map;
- const struct bpf_struct_ops *st_ops = st_map->st_ops;
- const struct btf_type *vt = st_ops->value_type;
+ const struct bpf_struct_ops_desc *st_ops_desc = st_map->st_ops_desc;
+ const struct btf_type *vt = st_ops_desc->value_type;
u64 usage;
usage = sizeof(*st_map) +
@@ -808,7 +810,7 @@ static void bpf_struct_ops_map_link_dealloc(struct bpf_link *link)
/* st_link->map can be NULL if
* bpf_struct_ops_link_create() fails to register.
*/
- st_map->st_ops->unreg(&st_map->kvalue.data);
+ st_map->st_ops_desc->st_ops->unreg(&st_map->kvalue.data);
bpf_map_put(&st_map->map);
}
kfree(st_link);
@@ -855,7 +857,7 @@ static int bpf_struct_ops_map_link_update(struct bpf_link *link, struct bpf_map
if (!bpf_struct_ops_valid_to_reg(new_map))
return -EINVAL;
- if (!st_map->st_ops->update)
+ if (!st_map->st_ops_desc->st_ops->update)
return -EOPNOTSUPP;
mutex_lock(&update_mutex);
@@ -868,12 +870,12 @@ static int bpf_struct_ops_map_link_update(struct bpf_link *link, struct bpf_map
old_st_map = container_of(old_map, struct bpf_struct_ops_map, map);
/* The new and old struct_ops must be the same type. */
- if (st_map->st_ops != old_st_map->st_ops) {
+ if (st_map->st_ops_desc != old_st_map->st_ops_desc) {
err = -EINVAL;
goto err_out;
}
- err = st_map->st_ops->update(st_map->kvalue.data, old_st_map->kvalue.data);
+ err = st_map->st_ops_desc->st_ops->update(st_map->kvalue.data, old_st_map->kvalue.data);
if (err)
goto err_out;
@@ -924,7 +926,7 @@ int bpf_struct_ops_link_create(union bpf_attr *attr)
if (err)
goto err_out;
- err = st_map->st_ops->reg(st_map->kvalue.data);
+ err = st_map->st_ops_desc->st_ops->reg(st_map->kvalue.data);
if (err) {
bpf_link_cleanup(&link_primer);
link = NULL;
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 8c810642d24d..24f05aa247e8 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -20208,6 +20208,7 @@ static void print_verification_stats(struct bpf_verifier_env *env)
static int check_struct_ops_btf_id(struct bpf_verifier_env *env)
{
const struct btf_type *t, *func_proto;
+ const struct bpf_struct_ops_desc *st_ops_desc;
const struct bpf_struct_ops *st_ops;
const struct btf_member *member;
struct bpf_prog *prog = env->prog;
@@ -20220,14 +20221,15 @@ static int check_struct_ops_btf_id(struct bpf_verifier_env *env)
}
btf_id = prog->aux->attach_btf_id;
- st_ops = bpf_struct_ops_find(btf_id);
- if (!st_ops) {
+ st_ops_desc = bpf_struct_ops_find(btf_id);
+ if (!st_ops_desc) {
verbose(env, "attach_btf_id %u is not a supported struct\n",
btf_id);
return -ENOTSUPP;
}
+ st_ops = st_ops_desc->st_ops;
- t = st_ops->type;
+ t = st_ops_desc->type;
member_idx = prog->expected_attach_type;
if (member_idx >= btf_type_vlen(t)) {
verbose(env, "attach to invalid member idx %u of struct %s\n",
diff --git a/net/bpf/bpf_dummy_struct_ops.c b/net/bpf/bpf_dummy_struct_ops.c
index 8906f7bdf4a9..ba2c58dba2da 100644
--- a/net/bpf/bpf_dummy_struct_ops.c
+++ b/net/bpf/bpf_dummy_struct_ops.c
@@ -22,6 +22,8 @@ struct bpf_dummy_ops_test_args {
struct bpf_dummy_ops_state state;
};
+static struct btf *bpf_dummy_ops_btf;
+
static struct bpf_dummy_ops_test_args *
dummy_ops_init_args(const union bpf_attr *kattr, unsigned int nr)
{
@@ -90,9 +92,15 @@ int bpf_struct_ops_test_run(struct bpf_prog *prog, const union bpf_attr *kattr,
void *image = NULL;
unsigned int op_idx;
int prog_ret;
+ s32 type_id;
int err;
- if (prog->aux->attach_btf_id != st_ops->type_id)
+ type_id = btf_find_by_name_kind(bpf_dummy_ops_btf,
+ bpf_bpf_dummy_ops.name,
+ BTF_KIND_STRUCT);
+ if (type_id < 0)
+ return -EINVAL;
+ if (prog->aux->attach_btf_id != type_id)
return -EOPNOTSUPP;
func_proto = prog->aux->attach_func_proto;
@@ -148,6 +156,7 @@ int bpf_struct_ops_test_run(struct bpf_prog *prog, const union bpf_attr *kattr,
static int bpf_dummy_init(struct btf *btf)
{
+ bpf_dummy_ops_btf = btf;
return 0;
}
diff --git a/net/ipv4/bpf_tcp_ca.c b/net/ipv4/bpf_tcp_ca.c
index ae8b15e6896f..dffd8828079b 100644
--- a/net/ipv4/bpf_tcp_ca.c
+++ b/net/ipv4/bpf_tcp_ca.c
@@ -20,6 +20,7 @@ static u32 unsupported_ops[] = {
static const struct btf_type *tcp_sock_type;
static u32 tcp_sock_id, sock_id;
+static const struct btf_type *tcp_congestion_ops_type;
static int bpf_tcp_ca_init(struct btf *btf)
{
@@ -36,6 +37,11 @@ static int bpf_tcp_ca_init(struct btf *btf)
tcp_sock_id = type_id;
tcp_sock_type = btf_type_by_id(btf, tcp_sock_id);
+ type_id = btf_find_by_name_kind(btf, "tcp_congestion_ops", BTF_KIND_STRUCT);
+ if (type_id < 0)
+ return -EINVAL;
+ tcp_congestion_ops_type = btf_type_by_id(btf, type_id);
+
return 0;
}
@@ -149,7 +155,7 @@ static u32 prog_ops_moff(const struct bpf_prog *prog)
u32 midx;
midx = prog->expected_attach_type;
- t = bpf_tcp_congestion_ops.type;
+ t = tcp_congestion_ops_type;
m = &btf_type_member(t)[midx];
return __btf_member_bit_offset(t, m) / 8;
--
2.34.1
^ 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