* Re: [GIT PULL] wireless-next-2026-05-06
From: patchwork-bot+netdevbpf @ 2026-05-06 14:41 UTC (permalink / raw)
To: Johannes Berg; +Cc: netdev, linux-wireless
In-Reply-To: <20260506111147.224296-3-johannes@sipsolutions.net>
Hello:
This pull request was applied to netdev/net-next.git (main)
by Jakub Kicinski <kuba@kernel.org>:
On Wed, 6 May 2026 13:10:53 +0200 you wrote:
> Hi,
>
> More content for next, as below. I'm sending this now
> in hopes that we'll get net merged into net-next after
> it all lands, because I'm annoyed by the use-after-free
> issue that somehow we never noticed and now hits all
> the time.
>
> [...]
Here is the summary with links:
- [GIT,PULL] wireless-next-2026-05-06
https://git.kernel.org/netdev/net-next/c/2281958e6007
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* Re: [PATCH] crypto: af_alg - Document the deprecation of AF_ALG
From: Jeff Barnes @ 2026-05-06 14:42 UTC (permalink / raw)
To: Andy Lutomirski
Cc: Eric Biggers, linux-crypto@vger.kernel.org, Herbert Xu,
linux-doc@vger.kernel.org, linux-api@vger.kernel.org,
linux-kernel@vger.kernel.org, netdev@vger.kernel.org,
Linus Torvalds
In-Reply-To: <CALCETrVqG+1yErRJjkxvJrf=A+Vu84HTR4Bx1Pcd8G1C0PJcMA@mail.gmail.com>
Hi,
On May 5 2026, at 7:17 pm, Andy Lutomirski <luto@amacapital.net> wrote:
>> On Apr 29, 2026, at 6:19 PM, Eric Biggers <ebiggers@kernel.org> wrote:
>>
>> AF_ALG is almost completely unnecessary, and it exposes a massive attack
>> surface that hasn't been standing up to modern vulnerability discovery
>> tools. The latest one even has its own website, providing a small
>> Python script that reliably roots most Linux distros: https://copy.fail/
>
> How about adding a configuration option, defaulted on, that requires
> capable(CAP_SYS_ADMIN) to create the socket (and maybe also to bind /
> connect it). And a sysctl to allow the administrator to override this
> in the unlikely event that it’s needed.
>
> IIRC cryptsetup used to and maybe even still does require these
> sockets sometimes and this would let it keep working. And there's all
> the FIPS stuff downthread.
Apologize in advance for the long-winded answer.
The "FIPS stuff" centers on using sha512hmac -> libkcapi -> AF_ALG for
verifying integrity. The early‑boot sha512hmac check that some
distributions use (typically from initramfs) sits at an awkward
intersection of multiple standards, and it may help to clarify where it
actually fits and where it doesn't.
From a standards perspective, FIPS 140‑3 requires a cryptographic module
to perform self‑integrity verification using an approved algorithm and
to prevent the module from entering an operational state on failure. In
the Linux kernel, the cryptographic module is the kernel crypto
subsystem, and these requirements are met by the kernel’s internal
power‑up self‑tests (KATs, etc.) on the crypto code and critical data as
loaded into memory.
FIPS 199 / SP 800‑53 (e.g., SI‑7) impose system‑level integrity
requirements (for Moderate impact systems), i.e., that unauthorized
modification of critical components is prevented or detected and that
failures result in a protective action. These controls are explicitly
technology‑agnostic and are not limited to cryptographic‑module self‑tests.
The sha512hmac check is not the FIPS 140‑3 cryptographic‑module
self‑integrity test. Instead, it has historically been used as a system
integrity control that provides auditors with assurance that the kernel
image containing the cryptographic module has not been modified prior to
execution, and that a failure will halt the boot.
Although FIPS 140‑3 does not mandate an HMAC over the kernel image, the
early‑boot HMAC became an accepted evidence pattern for satisfying
system‑integrity expectations (FIPS 199 / SI‑7) alongside a kernel
crypto validation. This is why it is often perceived as “required” for
FIPS submissions, even though it is not normatively required by
FIPS 140‑3 itself.
With the deprecation/removal of AF_ALG for this use case, there is no
longer a supported way to perform an early‑boot, userspace‑driven HMAC
using validated kernel crypto without introducing circular dependencies
(e.g., relying on userspace crypto before crypto self‑tests complete).
As a result, there is no drop‑in replacement for sha512hmac that
preserves all of its historical properties.
This is a new development that challenges a long‑standing assumption:
that system‑integrity evidence and cryptographic‑module self‑integrity
can be cleanly separated while still being demonstrated by a single
early‑boot mechanism. That assumption no longer holds given proposed
kernel interfaces.
A more accurate decomposition (and one that aligns with the intent of
the standards) is to separate integrity enforcement by system phase.
1. Secure Boot (or equivalent platform verification) ensures that a
modified kernel image is not executed at all. This satisfies the
requirement that critical components are not loaded in a modified state
and that integrity failure results in a protective action (boot prevention).
2. IMA (with appraisal and enforcement) ensures that modified
executables, modules, or firmware cannot be loaded or executed once the
kernel is running.
3. Kernel crypto self‑tests continue to satisfy FIPS 140‑3
self‑integrity requirements independently of the above.
Taken together, Secure Boot + IMA provide continuous system‑integrity
enforcement without re‑introducing early‑boot HMACs or AF_ALG
dependencies, while keeping cryptographic‑module self‑integrity
correctly scoped to the kernel crypto subsystem.
The transition away from sha512hmac is therefore not a removal of
integrity enforcement, but a shift from a single, early‑boot mechanism
to a phased integrity model that better reflects the separation of
concerns already present in the standards — even though this separation
was previously masked by the hacky HMAC approach.
This change will require updated documentation and auditor education,
but it reflects the current technical reality and avoids perpetuating an
interface that no longer has a sustainable implementation path.
>
>
>>
>> This isn't sustainable, especially as LLMs have accelerated the rate the
>> vulnerabilities are coming in. The effort that is being put into this
>> thing is vastly disproportional to the few programs that actually use
>> it, and those programs would be better served by userspace code anyway.
>>
>> These issues have been noted in many mailing list discussions already.
>> But until now they haven't been reflected in the documentation or
>> kconfig menu itself, and the vulnerabilities are still coming in.
>>
>> Let's go ahead and document the deprecation.
>>
>> This isn't intended to change anything overnight. After all, most Linux
>> distros won't be able to disable the kconfig options quite yet, mainly
>> because of iwd. But this should create a bit more impetus for these
>> userspace programs to be fixed, and the documentation update should also
>> help prevent more users from appearing.
>>
>> Signed-off-by: Eric Biggers <ebiggers@kernel.org>
>> ---
>>
>> This patch is targeting crypto/master
>>
>> Documentation/crypto/userspace-if.rst | 82 ++++++++++++++++++++-------
>> crypto/Kconfig | 69 ++++++++++++++++------
>> 2 files changed, 113 insertions(+), 38 deletions(-)
>>
>> diff --git a/Documentation/crypto/userspace-if.rst b/Documentation/crypto/userspace-if.rst
>> index 021759198fe7..c39f5c79a5b7 100644
>> --- a/Documentation/crypto/userspace-if.rst
>> +++ b/Documentation/crypto/userspace-if.rst
>> @@ -2,30 +2,72 @@ User Space Interface
>> ====================
>>
>> Introduction
>> ------------
>>
>> -The concepts of the kernel crypto API visible to kernel space is fully
>> -applicable to the user space interface as well. Therefore, the kernel
>> -crypto API high level discussion for the in-kernel use cases applies
>> -here as well.
>> -
>> -The major difference, however, is that user space can only act as a
>> -consumer and never as a provider of a transformation or cipher
>> -algorithm.
>> -
>> -The following covers the user space interface exported by the kernel
>> -crypto API. A working example of this description is libkcapi that can
>> -be obtained from [1]. That library can be used by user space
>> -applications that require cryptographic services from the kernel.
>> -
>> -Some details of the in-kernel kernel crypto API aspects do not apply to
>> -user space, however. This includes the difference between synchronous
>> -and asynchronous invocations. The user space API call is fully
>> -synchronous.
>> -
>> -[1] https://www.chronox.de/libkcapi/index.html
>> +AF_ALG provides unprivileged userspace programs access to arbitrary hash,
>> +symmetric cipher, AEAD, and RNG algorithms that are implemented in kernel-mode
>> +code.
>> +
>> +AF_ALG is insecure and is deprecated. Originally added to the kernel
>> in 2010,
>> +most kernel developers now consider it to be a mistake.
>> +
>> +AF_ALG continues to be supported only for backwards compatibility.
>> On systems
>> +where no programs using AF_ALG remain, the support for it should be
>> disabled by
>> +disabling ``CONFIG_CRYPTO_USER_API_*``.
>> +
>> +Deprecation
>> +-----------
>> +
>> +AF_ALG was originally intended to provide userspace programs access
>> to crypto
>> +accelerators that they wouldn't otherwise have access to.
>> +
>> +However, that capability turned out to not be useful on very many
>> systems. More
>> +significantly, the actual implementation exposes a vastly greater
>> amount of
>> +functionality than that. It actually provides access to all software algorithms.
>> +
>> +This includes arbitrary compositions of different algorithms created
>> via a
>> +complex template system, as well as algorithms that only make sense
>> as internal
>> +implementation details of other algorithms. It also includes full zero-copy
>> +support, which is difficult for the kernel to implement securely.
>> +
>> +Ultimately, these algorithms are just math computations. They use
>> the same
>> +instructions that userspace programs already have access to, just
>> accessed in a
>> +much more convoluted and less efficient way.
>> +
>> +Indeed, userspace code is nearly always what is being used anyway.
>> These same
>> +algorithms are widely implemented in userspace crypto libraries.
>> +
>> +Meanwhile, AF_ALG hasn't been withstanding modern vulnerability
>> discovery tools
>> +such as syzbot and large language models. It receives a steady
>> stream of CVEs.
>> +Some of the examples include:
>> +
>> +- CVE-2026-31677
>> +- CVE-2026-31431 (https://copy.fail)
>> +- CVE-2025-38079
>> +- CVE-2025-37808
>> +- CVE-2024-26824
>> +- CVE-2022-48781
>> +- CVE-2019-8912
>> +- CVE-2018-14619
>> +- CVE-2017-18075
>> +- CVE-2017-17806
>> +- CVE-2017-17805
>> +- CVE-2016-10147
>> +- CVE-2015-8970
>> +- CVE-2015-3331
>> +- CVE-2014-9644
>> +- CVE-2013-7421
>> +- CVE-2011-4081
>> +
>> +It is recommended that, whenever possible, userspace programs be
>> migrated to
>> +userspace crypto code (which again, is what is normally used anyway) and
>> +``CONFIG_CRYPTO_USER_API_*`` be disabled. On systems that use
>> SELinux, SELinux
>> +can also be used to restrict the use of AF_ALG to trusted programs.
>> +
>> +The remainder of this documentation provides the historical
>> documentation for
>> +the deprecated AF_ALG interface.
>>
>> User Space API General Remarks
>> ------------------------------
>>
>> The kernel crypto API is accessible from user space. Currently, the
>> diff --git a/crypto/Kconfig b/crypto/Kconfig
>> index 103d1f58cb7c..6cd1c478d4be 100644
>> --- a/crypto/Kconfig
>> +++ b/crypto/Kconfig
>> @@ -1278,48 +1278,72 @@ config CRYPTO_DF80090A
>> tristate
>> select CRYPTO_AES
>> select CRYPTO_CTR
>>
>> endmenu
>> -menu "Userspace interface"
>> +menu "Userspace interface (deprecated)"
>>
>> config CRYPTO_USER_API
>> tristate
>>
>> config CRYPTO_USER_API_HASH
>> - tristate "Hash algorithms"
>> + tristate "Hash algorithms (deprecated)"
>> depends on NET
>> select CRYPTO_HASH
>> select CRYPTO_USER_API
>> help
>> - Enable the userspace interface for hash algorithms.
>> + Enable the AF_ALG userspace interface for hash algorithms. This
>> + provides unprivileged userspace programs access to arbitrary hash
>> + algorithms implemented in the kernel's privileged execution context.
>>
>> - See Documentation/crypto/userspace-if.rst and
>> - https://www.chronox.de/libkcapi/html/index.html
>> + This interface is deprecated and is supported only for backwards
>> + compatibility. It regularly has vulnerabilities, and the capabilities
>> + it provides are redundant with userspace crypto libraries.
>> +
>> + Enable this only if needed for support for a program that
>> hasn't yet
>> + been converted to userspace crypto, for example iwd.
>> +
>> + See also Documentation/crypto/userspace-if.rst
>>
>> config CRYPTO_USER_API_SKCIPHER
>> - tristate "Symmetric key cipher algorithms"
>> + tristate "Symmetric key cipher algorithms (deprecated)"
>> depends on NET
>> select CRYPTO_SKCIPHER
>> select CRYPTO_USER_API
>> help
>> - Enable the userspace interface for symmetric key cipher algorithms.
>> + Enable the AF_ALG userspace interface for symmetric key algorithms.
>> + This provides unprivileged userspace programs access to arbitrary
>> + symmetric key algorithms implemented in the kernel's privileged
>> + execution context.
>> +
>> + This interface is deprecated and is supported only for backwards
>> + compatibility. It regularly has vulnerabilities, and the capabilities
>> + it provides are redundant with userspace crypto libraries.
>> +
>> + Enable this only if needed for support for a program that
>> hasn't yet
>> + been converted to userspace crypto, for example iwd, or cryptsetup
>> + with certain algorithms.
>>
>> - See Documentation/crypto/userspace-if.rst and
>> - https://www.chronox.de/libkcapi/html/index.html
>> + See also Documentation/crypto/userspace-if.rst
>>
>> config CRYPTO_USER_API_RNG
>> - tristate "RNG (random number generator) algorithms"
>> + tristate "Random number generation algorithms (deprecated)"
>> depends on NET
>> select CRYPTO_RNG
>> select CRYPTO_USER_API
>> help
>> - Enable the userspace interface for RNG (random number generator)
>> - algorithms.
>> + Enable the AF_ALG userspace interface for random number generation
>> + (RNG) algorithms. This provides unprivileged userspace programs
>> + access to arbitrary RNG algorithms implemented in the kernel's
>> + privileged execution context.
>>
>> - See Documentation/crypto/userspace-if.rst and
>> - https://www.chronox.de/libkcapi/html/index.html
>> + This interface is deprecated and is supported only for backwards
>> + compatibility. It regularly has vulnerabilities, and the capabilities
>> + it provides are redundant with userspace crypto libraries as
>> well as
>> + the normal kernel RNG (e.g., /dev/urandom and getrandom(2)).
>> +
>> + See also Documentation/crypto/userspace-if.rst
>>
>> config CRYPTO_USER_API_RNG_CAVP
>> bool "Enable CAVP testing of DRBG"
>> depends on CRYPTO_USER_API_RNG && CRYPTO_DRBG
>> help
>> @@ -1330,20 +1354,29 @@ config CRYPTO_USER_API_RNG_CAVP
>>
>> This should only be enabled for CAVP testing. You should say
>> no unless you know what this is.
>>
>> config CRYPTO_USER_API_AEAD
>> - tristate "AEAD cipher algorithms"
>> + tristate "AEAD cipher algorithms (deprecated)"
>> depends on NET
>> select CRYPTO_AEAD
>> select CRYPTO_SKCIPHER
>> select CRYPTO_USER_API
>> help
>> - Enable the userspace interface for AEAD cipher algorithms.
>> + Enable the AF_ALG userspace interface for authenticated encryption
>> + with associated data (AEAD) algorithms. This provides unprivileged
>> + userspace programs access to arbitrary AEAD algorithms
>> implemented in
>> + the kernel's privileged execution context.
>> +
>> + This interface is deprecated and is supported only for backwards
>> + compatibility. It regularly has vulnerabilities, and the capabilities
>> + it provides are redundant with userspace crypto libraries.
>> +
>> + Enable this only if needed for support for a program that
>> hasn't yet
>> + been converted to userspace crypto, for example iwd.
>>
>> - See Documentation/crypto/userspace-if.rst and
>> - https://www.chronox.de/libkcapi/html/index.html
>> + See also Documentation/crypto/userspace-if.rst
>>
>> config CRYPTO_USER_API_ENABLE_OBSOLETE
>> bool "Obsolete cryptographic algorithms"
>> depends on CRYPTO_USER_API
>> default y
>>
>> base-commit: 57b8e2d666a31fa201432d58f5fe3469a0dd83ba
>> --
>> 2.54.0
>>
>>
>
^ permalink raw reply
* Re: [PATCH net-next 10/12] net: stmmac: tc956x: add TC956x/QPS615 support
From: Andrew Lunn @ 2026-05-06 14:45 UTC (permalink / raw)
To: Xilin Wu
Cc: Alex Elder, andrew+netdev, davem, edumazet, kuba, pabeni,
maxime.chevallier, rmk+kernel, andersson, konradybcio, robh,
krzk+dt, conor+dt, linusw, brgl, arnd, gregkh, Daniel Thompson,
mohd.anwar, a0987203069, alexandre.torgue, ast, boon.khai.ng,
chenchuangyu, chenhuacai, daniel, hawk, hkallweit1, inochiama,
john.fastabend, julianbraha, livelycarpet87, matthew.gerlach,
mcoquelin.stm32, me, prabhakar.mahadev-lad.rj, richardcochran,
rohan.g.thomas, sdf, siyanteng, weishangjuan, wens, netdev, bpf,
linux-arm-msm, devicetree, linux-gpio, linux-stm32,
linux-arm-kernel, linux-kernel
In-Reply-To: <4C0D95BC59F1A4ED+53f3be85-2cdd-4058-8950-57970027d481@radxa.com>
> Hi Andrew,
>
> Yes, the PHY is doing the WoL. And I guess this makes sense as it allows the
> MAC to power down during suspend to save power.
>
> The INTN pin of QCA8081 is connected to the ETH_0_INT_N of QPS615. And the
> INTN_WOL pin is connected to a SoC GPIO.
>
> Without this change, I can't get WoL to work. I have a working branch for
> our board here:
> https://github.com/strongtz/linux-radxa-qcom/commits/v7.0.2-8280-wip/
Please take a look at commit
commit 6911308d7d111a9c367293b52f2dc265819f2b60
Author: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
Date: Thu Oct 23 10:16:50 2025 +0100
net: stmmac: convert to phylink-managed Wake-on-Lan
In particular:
When STMMAC_FLAG_USE_PHY_WOL is not set, we provide the MAC's WoL
capabilities to phylink, which then allows phylink to choose between
the PHY and MAC for WoL depending on their individual capabilities
as described in the phylink commit. This only augments the WoL
functionality with PHYs that declare to the driver model that they are
wake-up capable. Currently, very few PHY drivers support this.
Could you actually patch the PHY driver to make it list its
capabilities. That is the direction we want to go in the long term,
and not use STMMAC_FLAG_USE_PHY_WOL.
Andrew
^ permalink raw reply
* Re: [PATCH v1 net] ipmr: Call ipmr_fib_lookup() under RCU.
From: Ido Schimmel @ 2026-05-06 14:50 UTC (permalink / raw)
To: Kuniyuki Iwashima
Cc: David Ahern, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, Kuniyuki Iwashima, netdev, syzkaller,
Yi Lai
In-Reply-To: <20260506065955.1695753-1-kuniyu@google.com>
On Wed, May 06, 2026 at 06:59:53AM +0000, Kuniyuki Iwashima wrote:
> Yi Lai reported RCU splat in reg_vif_xmit() below. [0]
>
> When CONFIG_IP_MROUTE_MULTIPLE_TABLES=n, ipmr_fib_lookup()
> uses rcu_dereference() without explicit rcu_read_lock().
>
> Although rcu_read_lock_bh() is already held by the caller
> __dev_queue_xmit(), lockdep requires explicit rcu_read_lock()
> for rcu_dereference().
>
> Let's move up rcu_read_lock() in reg_vif_xmit() to
> cover ipmr_fib_lookup().
[...]
> Fixes: b3b6babf4751 ("ipmr: Free mr_table after RCU grace period.")
> Reported-by: syzkaller <syzkaller@googlegroups.com>
> Reported-by: Yi Lai <yi1.lai@intel.com>
> Closes: https://lore.kernel.org/netdev/afrY34dLXNUboevf@ly-workstation/
> Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
^ permalink raw reply
* Re: [PATCH net] vsock/virtio: fix potential unbounded skb queue
From: Michael S. Tsirkin @ 2026-05-06 15:15 UTC (permalink / raw)
To: Eric Dumazet
Cc: Stefano Garzarella, David S . Miller, Jakub Kicinski, Paolo Abeni,
Simon Horman, netdev, eric.dumazet, Arseniy Krasnov,
Stefan Hajnoczi, Jason Wang, Xuan Zhuo, Eugenio Pérez, kvm,
virtualization
In-Reply-To: <CANn89iLs8DOWJwDpf_ARoMrV+6b2tbhEJ=VVzeC8gCm5dRGaig@mail.gmail.com>
On Tue, May 05, 2026 at 07:14:36AM -0700, Eric Dumazet wrote:
> There is always a discrepancy between skb->len and skb->truesize.
> You will not be able to announce a 1MB window, and accept one milliion
> skb of 1-byte each.
We can if we copy.
> This kind of contract is broken.
^ permalink raw reply
* [PATCH net-next 00/13] dpaa2-switch: add support for LAG offload
From: Ioana Ciornei @ 2026-05-06 15:15 UTC (permalink / raw)
To: andrew+netdev, davem, edumazet, kuba, pabeni, netdev; +Cc: linux-kernel
This patch set adds support in dpaa2-switch for offloading upper bond
devices.
The first patch adds the necessary new APIs for the LAG configuration
while the second patch uses them, both in the prechangeupper phase and
the changeupper one. Which ports can be part of the same LAG group is
configurable at boot time, thus we use the prechangeupper callback in
order to validate that a requested configuration can be offloaded or
not.
Patches 3 and 4 are updating the logic around choosing the FDB that
should be used on a switch port. This is necessary since with the
addition of the LAG offload, we need to take into account all ports
which are under the same bridge, even though not directly.
This set also extends the handling of FDBs and port objects so that they
are handled by the driver even on an offloaded bond device.
Ioana Ciornei (13):
dpaa2-switch: add LAG configuration API
dpaa2-switch: add support for LAG offload
dpaa2-switch: change dpaa2_switch_port_set_fdb() function prototype
dpaa2-switch: extend dpaa2_switch_port_set_fdb() to cover bond
scenarios
dpaa2-switch: add dpaa2_switch_port_to_bridge_port() helper
dpaa2-switch: create a separate dpaa2_switch_port_fdb_event() function
dpaa2-switch: check early if an FDB entry should be added
dpaa2-switch: consolidate unicast and multicast management
dpaa2-switch: offload FDBs added on an upper bond device
dpaa2-switch: offload port objects on an upper bond device
dpaa2-switch: trap all link local reserved addresses to the CPU
dpaa2-switch: add support for imprecise source port
dpaa2-switch: do not error out when the same VLAN is installed
multiple times
.../ethernet/freescale/dpaa2/dpaa2-switch.c | 866 +++++++++++++++---
.../ethernet/freescale/dpaa2/dpaa2-switch.h | 39 +-
.../net/ethernet/freescale/dpaa2/dpsw-cmd.h | 18 +-
drivers/net/ethernet/freescale/dpaa2/dpsw.c | 57 ++
drivers/net/ethernet/freescale/dpaa2/dpsw.h | 20 +
5 files changed, 886 insertions(+), 114 deletions(-)
--
2.25.1
^ permalink raw reply
* [PATCH net-next 01/13] dpaa2-switch: add LAG configuration API
From: Ioana Ciornei @ 2026-05-06 15:15 UTC (permalink / raw)
To: andrew+netdev, davem, edumazet, kuba, pabeni, netdev; +Cc: linux-kernel
In-Reply-To: <20260506151540.1242997-1-ioana.ciornei@nxp.com>
Add the necessary APIs to configure and control the LAG support on the
DPAA2 switch object.
- The dpsw_lag_set() function will be used to either verify that a LAG
configuration can be support or to actually apply it in HW.
- The dpsw_if_set_lag_state() will get used in the next patches to
change the per port LAG state of a specific DPSW interface.
Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
---
.../net/ethernet/freescale/dpaa2/dpsw-cmd.h | 18 +++++-
drivers/net/ethernet/freescale/dpaa2/dpsw.c | 57 +++++++++++++++++++
drivers/net/ethernet/freescale/dpaa2/dpsw.h | 20 +++++++
3 files changed, 94 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/freescale/dpaa2/dpsw-cmd.h b/drivers/net/ethernet/freescale/dpaa2/dpsw-cmd.h
index 397d55f2bd99..9a2055c64983 100644
--- a/drivers/net/ethernet/freescale/dpaa2/dpsw-cmd.h
+++ b/drivers/net/ethernet/freescale/dpaa2/dpsw-cmd.h
@@ -12,7 +12,7 @@
/* DPSW Version */
#define DPSW_VER_MAJOR 8
-#define DPSW_VER_MINOR 9
+#define DPSW_VER_MINOR 13
#define DPSW_CMD_BASE_VERSION 1
#define DPSW_CMD_VERSION_2 2
@@ -92,11 +92,14 @@
#define DPSW_CMDID_CTRL_IF_SET_POOLS DPSW_CMD_ID(0x0A1)
#define DPSW_CMDID_CTRL_IF_ENABLE DPSW_CMD_ID(0x0A2)
#define DPSW_CMDID_CTRL_IF_DISABLE DPSW_CMD_ID(0x0A3)
+#define DPSW_CMDID_SET_LAG DPSW_CMD_V2(0x0A4)
#define DPSW_CMDID_CTRL_IF_SET_QUEUE DPSW_CMD_ID(0x0A6)
#define DPSW_CMDID_SET_EGRESS_FLOOD DPSW_CMD_ID(0x0AC)
#define DPSW_CMDID_IF_SET_LEARNING_MODE DPSW_CMD_ID(0x0AD)
+#define DPSW_CMDID_IF_SET_LAG_STATE DPSW_CMD_ID(0x0B0)
+
/* Macros for accessing command fields smaller than 1byte */
#define DPSW_MASK(field) \
GENMASK(DPSW_##field##_SHIFT + DPSW_##field##_SIZE - 1, \
@@ -552,5 +555,18 @@ struct dpsw_cmd_if_reflection {
/* only 2 bits from the LSB */
u8 filter;
};
+
+struct dpsw_cmd_lag {
+ u8 group_id;
+ u8 num_ifs;
+ u8 pad[6];
+ u8 if_id[DPSW_MAX_LAG_IFS];
+ u8 phase;
+};
+
+struct dpsw_cmd_if_set_lag_state {
+ __le16 if_id;
+ u8 tx_enabled;
+};
#pragma pack(pop)
#endif /* __FSL_DPSW_CMD_H */
diff --git a/drivers/net/ethernet/freescale/dpaa2/dpsw.c b/drivers/net/ethernet/freescale/dpaa2/dpsw.c
index ab921d75deb2..c3951a9d6e0e 100644
--- a/drivers/net/ethernet/freescale/dpaa2/dpsw.c
+++ b/drivers/net/ethernet/freescale/dpaa2/dpsw.c
@@ -1659,3 +1659,60 @@ int dpsw_if_remove_reflection(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
return mc_send_command(mc_io, &cmd);
}
+
+/**
+ * dpsw_lag_set() - Set LAG configuration
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPSW object
+ * @cfg: pointer to LAG configuration
+ *
+ * Return: '0' on Success; Error code otherwise.
+ */
+int dpsw_lag_set(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
+ const struct dpsw_lag_cfg *cfg)
+{
+ struct fsl_mc_command cmd = { 0 };
+ struct dpsw_cmd_lag *cmd_params;
+ int i = 0;
+
+ cmd.header = mc_encode_cmd_header(DPSW_CMDID_SET_LAG, cmd_flags, token);
+
+ cmd_params = (struct dpsw_cmd_lag *)cmd.params;
+ cmd_params->group_id = cfg->group_id;
+ cmd_params->num_ifs = cfg->num_ifs;
+ cmd_params->phase = cfg->phase;
+
+ for (i = 0; i < cfg->num_ifs; i++)
+ cmd_params->if_id[i] = cfg->if_id[i];
+
+ return mc_send_command(mc_io, &cmd);
+}
+
+/**
+ * dpsw_if_set_lag_state() - Change per port LAG state
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPSW object
+ * @if_id: ID of the switch interface
+ * @tx_enabled: Value of the per port LAG state
+ * - 0 if the interface will not be active as part of the LAG group
+ * - 1 if the interface will be active in the LAG group
+ *
+ * Return: '0' on Success; Error code otherwise.
+ */
+int dpsw_if_set_lag_state(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
+ u16 if_id, u8 tx_enabled)
+{
+ struct dpsw_cmd_if_set_lag_state *cmd_params;
+ struct fsl_mc_command cmd = { 0 };
+
+ cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_SET_LAG_STATE,
+ cmd_flags, token);
+
+ cmd_params = (struct dpsw_cmd_if_set_lag_state *)cmd.params;
+ cmd_params->if_id = cpu_to_le16(if_id);
+ cmd_params->tx_enabled = tx_enabled;
+
+ return mc_send_command(mc_io, &cmd);
+}
diff --git a/drivers/net/ethernet/freescale/dpaa2/dpsw.h b/drivers/net/ethernet/freescale/dpaa2/dpsw.h
index b90bd363f47a..d79021ef3474 100644
--- a/drivers/net/ethernet/freescale/dpaa2/dpsw.h
+++ b/drivers/net/ethernet/freescale/dpaa2/dpsw.h
@@ -20,6 +20,8 @@ struct fsl_mc_io;
#define DPSW_MAX_IF 64
+#define DPSW_MAX_LAG_IFS 8
+
int dpsw_open(struct fsl_mc_io *mc_io, u32 cmd_flags, int dpsw_id, u16 *token);
int dpsw_close(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token);
@@ -788,4 +790,22 @@ int dpsw_if_add_reflection(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
int dpsw_if_remove_reflection(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
u16 if_id, const struct dpsw_reflection_cfg *cfg);
+
+/* Link Aggregation Group configuration */
+
+#define DPSW_LAG_SET_PHASE_APPLY 0
+#define DPSW_LAG_SET_PHASE_CHECK 1
+
+struct dpsw_lag_cfg {
+ u8 group_id;
+ u8 num_ifs;
+ u8 if_id[DPSW_MAX_LAG_IFS];
+ u8 phase;
+};
+
+int dpsw_lag_set(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
+ const struct dpsw_lag_cfg *cfg);
+
+int dpsw_if_set_lag_state(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
+ u16 if_id, u8 tx_enabled);
#endif /* __FSL_DPSW_H */
--
2.25.1
^ permalink raw reply related
* [PATCH net-next 02/13] dpaa2-switch: add support for LAG offload
From: Ioana Ciornei @ 2026-05-06 15:15 UTC (permalink / raw)
To: andrew+netdev, davem, edumazet, kuba, pabeni, netdev; +Cc: linux-kernel
In-Reply-To: <20260506151540.1242997-1-ioana.ciornei@nxp.com>
This patch adds the bulk of the changes needed in order to support
offloading of an upper bond device.
First of all, handling of the NETDEV_CHANGEUPPER and
NETDEV_PRECHANGEUPPER events is extended so that the driver is capable
to handle joining or leaving an upper bond device.
All the restrictions around the LAG offload support are added in the
newly added dpaa2_switch_pre_lag_join() function.
The same events are extended to also detect if one of our upper bond
devices changes its own upper device. In this case, on each lower device
that is DPAA2 the corresponding dpaa2_switch_port_[pre]changeupper()
function will be called. This will start the process of joining the same
FDB as the one used by the bridge device.
Setting the 'offload_fwd_mark' field on the skbs is also extended to be
setup not only when the port is under a bridge but also under a bond
device that is offloaded.
Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
---
.../ethernet/freescale/dpaa2/dpaa2-switch.c | 390 +++++++++++++++++-
.../ethernet/freescale/dpaa2/dpaa2-switch.h | 14 +-
2 files changed, 402 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
index 52c1cb9cb7e0..6367873401c0 100644
--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
+++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
@@ -51,6 +51,17 @@ dpaa2_switch_filter_block_get_unused(struct ethsw_core *ethsw)
return NULL;
}
+static struct dpaa2_switch_lag *
+dpaa2_switch_lag_get_unused(struct ethsw_core *ethsw)
+{
+ int i;
+
+ for (i = 0; i < ethsw->sw_attr.num_ifs; i++)
+ if (!ethsw->lags[i].in_use)
+ return ðsw->lags[i];
+ return NULL;
+}
+
static u16 dpaa2_switch_port_set_fdb(struct ethsw_port_priv *port_priv,
struct net_device *bridge_dev)
{
@@ -2195,6 +2206,266 @@ dpaa2_switch_prechangeupper_sanity_checks(struct net_device *netdev,
return 0;
}
+static int dpaa2_switch_pre_lag_join(struct net_device *netdev,
+ struct net_device *upper_dev,
+ struct netdev_lag_upper_info *info,
+ struct netlink_ext_ack *extack)
+{
+ struct ethsw_port_priv *port_priv = netdev_priv(netdev);
+ struct ethsw_core *ethsw = port_priv->ethsw_data;
+ struct ethsw_port_priv *other_port_priv;
+ struct dpaa2_switch_lag *lag = NULL;
+ struct dpsw_lag_cfg cfg = {0};
+ struct net_device *other_dev;
+ int i, num_ifs = 0, err;
+ struct list_head *iter;
+
+ if (!(ethsw->features & ETHSW_FEATURE_LAG_OFFLOAD)) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "LAG offload is supported only for DPSW >= v8.13");
+ return -EOPNOTSUPP;
+ }
+
+ if (info->tx_type != NETDEV_LAG_TX_TYPE_HASH) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Can only offload LAG using hash TX type");
+ return -EOPNOTSUPP;
+ }
+
+ if (info->hash_type != NETDEV_LAG_HASH_L23) {
+ NL_SET_ERR_MSG_MOD(extack, "Can only offload L2+L3 Tx hash");
+ return -EOPNOTSUPP;
+ }
+
+ if (!dpaa2_switch_port_has_mac(port_priv)) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Only switch interfaces connected to MACs can be under a LAG");
+ return -EINVAL;
+ }
+
+ if (vlan_uses_dev(upper_dev)) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Cannot join a LAG upper that has a VLAN");
+ return -EOPNOTSUPP;
+ }
+
+ for (i = 0; i < ethsw->sw_attr.num_ifs; i++) {
+ if (!ethsw->lags[i].in_use)
+ continue;
+ if (ethsw->lags[i].bond_dev != upper_dev)
+ continue;
+ lag = ðsw->lags[i];
+ break;
+ }
+
+ netdev_for_each_lower_dev(upper_dev, other_dev, iter) {
+ if (!dpaa2_switch_port_dev_check(other_dev))
+ continue;
+
+ other_port_priv = netdev_priv(other_dev);
+ if (other_port_priv->ethsw_data != port_priv->ethsw_data) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Interface from a different DPSW is in the bond already");
+ return -EINVAL;
+ }
+
+ cfg.if_id[num_ifs++] = other_port_priv->idx;
+
+ if (num_ifs >= DPSW_MAX_LAG_IFS) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Cannot add more than 8 DPAA2 switch ports under the same bond");
+ return -EINVAL;
+ }
+ }
+
+ if (lag) {
+ cfg.group_id = lag->id;
+ cfg.if_id[num_ifs++] = port_priv->idx;
+ cfg.num_ifs = num_ifs;
+ cfg.phase = DPSW_LAG_SET_PHASE_CHECK;
+
+ err = dpsw_lag_set(ethsw->mc_io, 0, ethsw->dpsw_handle, &cfg);
+ if (err) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Cannot offload LAG configuration");
+ return -EOPNOTSUPP;
+ }
+ }
+
+ return 0;
+}
+
+static void dpaa2_switch_port_set_lag_group(struct ethsw_port_priv *port_priv,
+ struct net_device *bond_dev)
+{
+ struct ethsw_core *ethsw = port_priv->ethsw_data;
+ struct ethsw_port_priv *other_port_priv = NULL;
+ struct dpaa2_switch_lag *lag = NULL;
+ struct net_device *other_dev;
+ struct list_head *iter;
+
+ netdev_for_each_lower_dev(bond_dev, other_dev, iter) {
+ if (!dpaa2_switch_port_dev_check(other_dev))
+ continue;
+
+ other_port_priv = netdev_priv(other_dev);
+ if (!other_port_priv->lag)
+ continue;
+
+ if (other_port_priv->lag->bond_dev == bond_dev) {
+ port_priv->lag = other_port_priv->lag;
+ return;
+ }
+ }
+
+ /* This is the first interface to be added under a bond device. Find an
+ * unused LAG group. No need to check for NULL since there are the same
+ * amount of DPSW ports as LAG groups, meaning that each port can have
+ * its own LAG group.
+ */
+ lag = dpaa2_switch_lag_get_unused(ethsw);
+ lag->in_use = true;
+ lag->bond_dev = bond_dev;
+ port_priv->lag = lag;
+}
+
+static int dpaa2_switch_set_lag_cfg(struct net_device *bond_dev, u8 lag_id,
+ struct ethsw_core *ethsw)
+{
+ struct dpaa2_switch_lag *lag = ðsw->lags[lag_id - 1];
+ struct ethsw_port_priv *other_port_priv = NULL;
+ struct dpsw_lag_cfg cfg = {0};
+ u8 num_ifs = 0;
+ int i;
+
+ cfg.group_id = lag_id;
+ for (i = 0; i < ethsw->sw_attr.num_ifs; i++) {
+ other_port_priv = ethsw->ports[i];
+
+ if (!other_port_priv)
+ continue;
+ if (!other_port_priv->lag)
+ continue;
+ if (other_port_priv->lag->bond_dev != bond_dev)
+ continue;
+
+ /* No need to check against DPSW_MAX_LAG_IFS since this
+ * was done in the prechangeupper stage. The flow will
+ * not reach this point in case there are more DPAA2
+ * switch ports under the same bond than we can accept.
+ */
+ cfg.if_id[num_ifs++] = other_port_priv->idx;
+ }
+
+ cfg.num_ifs = num_ifs;
+
+ /* No more interfaces under this LAG group, mark it as not in use */
+ if (!num_ifs) {
+ lag->bond_dev = NULL;
+ lag->in_use = false;
+ }
+
+ return dpsw_lag_set(ethsw->mc_io, 0, ethsw->dpsw_handle, &cfg);
+}
+
+static int dpaa2_switch_port_bond_join(struct net_device *netdev,
+ struct net_device *bond_dev,
+ struct netdev_lag_upper_info *info,
+ struct netlink_ext_ack *extack)
+{
+ struct ethsw_port_priv *port_priv = netdev_priv(netdev);
+ struct ethsw_core *ethsw = port_priv->ethsw_data;
+ struct dpaa2_switch_fdb *old_fdb = port_priv->fdb;
+ struct net_device *bridge_dev;
+ int err = 0;
+ u8 lag_id;
+
+ /* Setup the egress flood policy (broadcast, unknown unicast) */
+ dpaa2_switch_port_set_fdb(port_priv, bond_dev);
+ err = dpaa2_switch_fdb_set_egress_flood(ethsw, port_priv->fdb->fdb_id);
+ if (err)
+ goto err_egress_flood;
+
+ /* Recreate the egress flood domain of the FDB that we just left. */
+ err = dpaa2_switch_fdb_set_egress_flood(ethsw, old_fdb->fdb_id);
+ if (err)
+ goto err_egress_flood;
+
+ /* Setup the port_priv->lag pointer for this switch port */
+ dpaa2_switch_port_set_lag_group(port_priv, bond_dev);
+
+ /* Create the LAG configuration and apply it in MC */
+ lag_id = port_priv->lag->id;
+ err = dpaa2_switch_set_lag_cfg(bond_dev, lag_id, ethsw);
+ if (err)
+ goto err_lag_cfg;
+
+ /* If the bond device is a switch port, then join the bridge as well */
+ bridge_dev = netdev_master_upper_dev_get(bond_dev);
+ if (!bridge_dev || !netif_is_bridge_master(bridge_dev))
+ return 0;
+
+ err = dpaa2_switch_port_bridge_join(netdev, bridge_dev, extack);
+ if (err)
+ goto err_bridge_join;
+
+ return err;
+
+err_bridge_join:
+err_lag_cfg:
+ port_priv->lag = NULL;
+ dpaa2_switch_set_lag_cfg(bond_dev, lag_id, ethsw);
+err_egress_flood:
+ dpaa2_switch_port_set_fdb(port_priv, NULL);
+ return err;
+}
+
+static int dpaa2_switch_port_bond_leave(struct net_device *netdev,
+ struct net_device *bond_dev)
+{
+ struct ethsw_port_priv *port_priv = netdev_priv(netdev);
+ struct dpaa2_switch_fdb *old_fdb = port_priv->fdb;
+ struct ethsw_core *ethsw = port_priv->ethsw_data;
+ struct dpaa2_switch_lag *lag = port_priv->lag;
+ int err = 0;
+
+ /* Delete the default VLAN, we might change our FDB in this operation */
+ err = dpaa2_switch_port_del_vlan(port_priv, DEFAULT_VLAN_ID);
+ if (err)
+ return err;
+
+ /* Setup the FDB for this port which is now standalone */
+ dpaa2_switch_port_set_fdb(port_priv, NULL);
+
+ /* Setup the egress flood policy (broadcast, unknown unicast).
+ * When the port is not under a bond, only the CTRL interface is part
+ * of the flooding domain besides the actual port.
+ */
+ err = dpaa2_switch_fdb_set_egress_flood(ethsw, port_priv->fdb->fdb_id);
+ if (err)
+ return err;
+
+ /* Recreate the egress flood domain of the FDB that we just left. */
+ err = dpaa2_switch_fdb_set_egress_flood(ethsw, old_fdb->fdb_id);
+ if (err)
+ return err;
+
+ /* Add the VLAN 1 as PVID when not under a bond. We need this since
+ * the dpaa2 switch interfaces are not capable to be VLAN unaware
+ */
+ err = dpaa2_switch_port_add_vlan(port_priv, DEFAULT_VLAN_ID,
+ BRIDGE_VLAN_INFO_UNTAGGED |
+ BRIDGE_VLAN_INFO_PVID);
+ if (err)
+ return err;
+
+ /* Recreate the LAG configuration for the LAG group that we left */
+ port_priv->lag = NULL;
+ dpaa2_switch_set_lag_cfg(bond_dev, lag->id, ethsw);
+
+ return 0;
+}
+
static int dpaa2_switch_port_prechangeupper(struct net_device *netdev,
struct netdev_notifier_changeupper_info *info)
{
@@ -2216,6 +2487,9 @@ static int dpaa2_switch_port_prechangeupper(struct net_device *netdev,
if (!info->linking)
dpaa2_switch_port_pre_bridge_leave(netdev);
+ } else if (netif_is_lag_master(upper_dev) && info->linking) {
+ return dpaa2_switch_pre_lag_join(netdev, upper_dev,
+ info->upper_info, extack);
}
return 0;
@@ -2240,6 +2514,80 @@ static int dpaa2_switch_port_changeupper(struct net_device *netdev,
extack);
else
return dpaa2_switch_port_bridge_leave(netdev);
+ } else if (netif_is_lag_master(upper_dev)) {
+ if (info->linking)
+ return dpaa2_switch_port_bond_join(netdev, upper_dev,
+ info->upper_info,
+ extack);
+ else
+ return dpaa2_switch_port_bond_leave(netdev, upper_dev);
+ }
+
+ return 0;
+}
+
+static int
+dpaa2_switch_lag_prechangeupper(struct net_device *netdev,
+ struct netdev_notifier_changeupper_info *info)
+{
+ struct net_device *lower;
+ struct list_head *iter;
+ int err = 0;
+
+ if (!netif_is_lag_master(netdev))
+ return 0;
+
+ netdev_for_each_lower_dev(netdev, lower, iter) {
+ if (!dpaa2_switch_port_dev_check(lower))
+ continue;
+
+ err = dpaa2_switch_port_prechangeupper(lower, info);
+ if (err)
+ return err;
+ }
+
+ return err;
+}
+
+static int
+dpaa2_switch_lag_changeupper(struct net_device *netdev,
+ struct netdev_notifier_changeupper_info *info)
+{
+ struct net_device *lower;
+ struct list_head *iter;
+ int err = 0;
+
+ if (!netif_is_lag_master(netdev))
+ return 0;
+
+ netdev_for_each_lower_dev(netdev, lower, iter) {
+ if (!dpaa2_switch_port_dev_check(lower))
+ continue;
+
+ err = dpaa2_switch_port_changeupper(lower, info);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static int
+dpaa2_switch_port_changelowerstate(struct net_device *netdev,
+ struct netdev_lag_lower_state_info *linfo)
+{
+ struct ethsw_port_priv *port_priv = netdev_priv(netdev);
+ struct ethsw_core *ethsw = port_priv->ethsw_data;
+ int err;
+
+ if (!port_priv->lag)
+ return 0;
+
+ err = dpsw_if_set_lag_state(ethsw->mc_io, 0, ethsw->dpsw_handle,
+ port_priv->idx, linfo->tx_enabled ? 1 : 0);
+ if (err) {
+ netdev_err(netdev, "dpsw_if_set_lag_state() = %d\n", err);
+ return err;
}
return 0;
@@ -2249,6 +2597,7 @@ static int dpaa2_switch_port_netdevice_event(struct notifier_block *nb,
unsigned long event, void *ptr)
{
struct net_device *netdev = netdev_notifier_info_to_dev(ptr);
+ struct netdev_notifier_changelowerstate_info *info;
int err = 0;
switch (event) {
@@ -2257,13 +2606,29 @@ static int dpaa2_switch_port_netdevice_event(struct notifier_block *nb,
if (err)
return notifier_from_errno(err);
+ err = dpaa2_switch_lag_prechangeupper(netdev, ptr);
+ if (err)
+ return notifier_from_errno(err);
+
break;
case NETDEV_CHANGEUPPER:
err = dpaa2_switch_port_changeupper(netdev, ptr);
if (err)
return notifier_from_errno(err);
+ err = dpaa2_switch_lag_changeupper(netdev, ptr);
+ if (err)
+ return notifier_from_errno(err);
+
break;
+ case NETDEV_CHANGELOWERSTATE:
+ info = ptr;
+ if (!dpaa2_switch_port_dev_check(netdev))
+ break;
+
+ err = dpaa2_switch_port_changelowerstate(netdev,
+ info->lower_state_info);
+ return notifier_from_errno(err);
}
return NOTIFY_DONE;
@@ -2500,8 +2865,11 @@ static void dpaa2_switch_rx(struct dpaa2_switch_fq *fq,
skb->dev = netdev;
skb->protocol = eth_type_trans(skb, skb->dev);
- /* Setup the offload_fwd_mark only if the port is under a bridge */
+ /* Setup the offload_fwd_mark only if the port is under a bridge
+ * or under a bond device that is offloaded.
+ */
skb->offload_fwd_mark = !!(port_priv->fdb->bridge_dev);
+ skb->offload_fwd_mark |= !!(port_priv->lag);
netif_receive_skb(skb);
@@ -2517,6 +2885,9 @@ static void dpaa2_switch_detect_features(struct ethsw_core *ethsw)
if (ethsw->major > 8 || (ethsw->major == 8 && ethsw->minor >= 6))
ethsw->features |= ETHSW_FEATURE_MAC_ADDR;
+
+ if (ethsw->major > 8 || (ethsw->major == 8 && ethsw->minor >= 13))
+ ethsw->features |= ETHSW_FEATURE_LAG_OFFLOAD;
}
static int dpaa2_switch_setup_fqs(struct ethsw_core *ethsw)
@@ -3301,6 +3672,7 @@ static void dpaa2_switch_remove(struct fsl_mc_device *sw_dev)
kfree(ethsw->fdbs);
kfree(ethsw->filter_blocks);
kfree(ethsw->ports);
+ kfree(ethsw->lags);
dpaa2_switch_teardown(sw_dev);
@@ -3328,6 +3700,7 @@ static int dpaa2_switch_probe_port(struct ethsw_core *ethsw,
port_priv = netdev_priv(port_netdev);
port_priv->netdev = port_netdev;
port_priv->ethsw_data = ethsw;
+ port_priv->lag = NULL;
mutex_init(&port_priv->mac_lock);
@@ -3435,6 +3808,19 @@ static int dpaa2_switch_probe(struct fsl_mc_device *sw_dev)
goto err_free_fdbs;
}
+ ethsw->lags = kcalloc(ethsw->sw_attr.num_ifs, sizeof(*ethsw->lags),
+ GFP_KERNEL);
+ if (!ethsw->lags) {
+ err = -ENOMEM;
+ goto err_free_filter;
+ }
+ for (i = 0; i < ethsw->sw_attr.num_ifs; i++) {
+ ethsw->lags[i].bond_dev = NULL;
+ ethsw->lags[i].ethsw = ethsw;
+ ethsw->lags[i].id = i + 1;
+ ethsw->lags[i].in_use = 0;
+ }
+
for (i = 0; i < ethsw->sw_attr.num_ifs; i++) {
err = dpaa2_switch_probe_port(ethsw, i);
if (err)
@@ -3481,6 +3867,8 @@ static int dpaa2_switch_probe(struct fsl_mc_device *sw_dev)
err_free_netdev:
for (i--; i >= 0; i--)
dpaa2_switch_remove_port(ethsw, i);
+ kfree(ethsw->lags);
+err_free_filter:
kfree(ethsw->filter_blocks);
err_free_fdbs:
kfree(ethsw->fdbs);
diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.h b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.h
index 42b3ca73f55d..56debbdefd13 100644
--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.h
+++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.h
@@ -41,7 +41,8 @@
#define ETHSW_MAX_FRAME_LENGTH (DPAA2_MFL - VLAN_ETH_HLEN - ETH_FCS_LEN)
#define ETHSW_L2_MAX_FRM(mtu) ((mtu) + VLAN_ETH_HLEN + ETH_FCS_LEN)
-#define ETHSW_FEATURE_MAC_ADDR BIT(0)
+#define ETHSW_FEATURE_MAC_ADDR BIT(0)
+#define ETHSW_FEATURE_LAG_OFFLOAD BIT(1)
/* Number of receive queues (one RX and one TX_CONF) */
#define DPAA2_SWITCH_RX_NUM_FQS 2
@@ -105,6 +106,13 @@ struct dpaa2_switch_fdb {
bool in_use;
};
+struct dpaa2_switch_lag {
+ struct ethsw_core *ethsw;
+ struct net_device *bond_dev;
+ bool in_use;
+ u8 id;
+};
+
struct dpaa2_switch_acl_entry {
struct list_head list;
u16 prio;
@@ -163,6 +171,8 @@ struct ethsw_port_priv {
struct dpaa2_mac *mac;
/* Protects against changes to port_priv->mac */
struct mutex mac_lock;
+
+ struct dpaa2_switch_lag *lag;
};
/* Switch data */
@@ -190,6 +200,8 @@ struct ethsw_core {
struct dpaa2_switch_fdb *fdbs;
struct dpaa2_switch_filter_block *filter_blocks;
u16 mirror_port;
+
+ struct dpaa2_switch_lag *lags;
};
static inline int dpaa2_switch_get_index(struct ethsw_core *ethsw,
--
2.25.1
^ permalink raw reply related
* [PATCH net-next 03/13] dpaa2-switch: change dpaa2_switch_port_set_fdb() function prototype
From: Ioana Ciornei @ 2026-05-06 15:15 UTC (permalink / raw)
To: andrew+netdev, davem, edumazet, kuba, pabeni, netdev; +Cc: linux-kernel
In-Reply-To: <20260506151540.1242997-1-ioana.ciornei@nxp.com>
Since there dpaa2_switch_port_set_fdb() never fails and its return value
was never checked, change its prototype to return void.
Also, instead of determining if the DPAA2 port is joining or leaving an
upper based on the value of the 'bridge_dev' parameter, add the
'linking' parameter to explicitly specify the action. This will enable
us to pass the upper device that we are joining/leaving in all possible
cases. This will get used in the next patches to determine what kind of
device the upper is: a bridge or a bond.
Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
---
.../ethernet/freescale/dpaa2/dpaa2-switch.c | 33 +++++++++----------
1 file changed, 15 insertions(+), 18 deletions(-)
diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
index 6367873401c0..f1b4c24b8a47 100644
--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
+++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
@@ -62,18 +62,17 @@ dpaa2_switch_lag_get_unused(struct ethsw_core *ethsw)
return NULL;
}
-static u16 dpaa2_switch_port_set_fdb(struct ethsw_port_priv *port_priv,
- struct net_device *bridge_dev)
+static void dpaa2_switch_port_set_fdb(struct ethsw_port_priv *port_priv,
+ struct net_device *upper_dev,
+ bool linking)
{
struct ethsw_port_priv *other_port_priv = NULL;
struct dpaa2_switch_fdb *fdb;
struct net_device *other_dev;
struct list_head *iter;
- /* If we leave a bridge (bridge_dev is NULL), find an unused
- * FDB and use that.
- */
- if (!bridge_dev) {
+ /* If we leave a bridge, find an unused FDB and use that. */
+ if (!linking) {
fdb = dpaa2_switch_fdb_get_unused(port_priv->ethsw_data);
/* If there is no unused FDB, we must be the last port that
@@ -83,13 +82,13 @@ static u16 dpaa2_switch_port_set_fdb(struct ethsw_port_priv *port_priv,
if (!fdb) {
port_priv->fdb->bridge_dev = NULL;
- return 0;
+ return;
}
port_priv->fdb = fdb;
port_priv->fdb->in_use = true;
port_priv->fdb->bridge_dev = NULL;
- return 0;
+ return;
}
/* The below call to netdev_for_each_lower_dev() demands the RTNL lock
@@ -101,7 +100,7 @@ static u16 dpaa2_switch_port_set_fdb(struct ethsw_port_priv *port_priv,
/* If part of a bridge, use the FDB of the first dpaa2 switch interface
* to be present in that bridge
*/
- netdev_for_each_lower_dev(bridge_dev, other_dev, iter) {
+ netdev_for_each_lower_dev(upper_dev, other_dev, iter) {
if (!dpaa2_switch_port_dev_check(other_dev))
continue;
@@ -127,9 +126,7 @@ static u16 dpaa2_switch_port_set_fdb(struct ethsw_port_priv *port_priv,
}
/* Keep track of the new upper bridge device */
- port_priv->fdb->bridge_dev = bridge_dev;
-
- return 0;
+ port_priv->fdb->bridge_dev = upper_dev;
}
static void dpaa2_switch_fdb_get_flood_cfg(struct ethsw_core *ethsw, u16 fdb_id,
@@ -2040,7 +2037,7 @@ static int dpaa2_switch_port_bridge_join(struct net_device *netdev,
if (err)
return err;
- dpaa2_switch_port_set_fdb(port_priv, upper_dev);
+ dpaa2_switch_port_set_fdb(port_priv, upper_dev, true);
/* Inherit the initial bridge port learning state */
learn_ena = br_port_flag_is_set(netdev, BR_LEARNING);
@@ -2066,7 +2063,7 @@ static int dpaa2_switch_port_bridge_join(struct net_device *netdev,
err_switchdev_offload:
err_egress_flood:
- dpaa2_switch_port_set_fdb(port_priv, NULL);
+ dpaa2_switch_port_set_fdb(port_priv, upper_dev, false);
return err;
}
@@ -2113,7 +2110,7 @@ static int dpaa2_switch_port_bridge_leave(struct net_device *netdev)
if (err)
netdev_err(netdev, "Unable to clear RX VLANs from old FDB table, err (%d)\n", err);
- dpaa2_switch_port_set_fdb(port_priv, NULL);
+ dpaa2_switch_port_set_fdb(port_priv, port_priv->fdb->bridge_dev, false);
/* Restore all RX VLANs into the new FDB table that we just joined */
err = vlan_for_each(netdev, dpaa2_switch_port_restore_rxvlan, netdev);
@@ -2381,7 +2378,7 @@ static int dpaa2_switch_port_bond_join(struct net_device *netdev,
u8 lag_id;
/* Setup the egress flood policy (broadcast, unknown unicast) */
- dpaa2_switch_port_set_fdb(port_priv, bond_dev);
+ dpaa2_switch_port_set_fdb(port_priv, bond_dev, true);
err = dpaa2_switch_fdb_set_egress_flood(ethsw, port_priv->fdb->fdb_id);
if (err)
goto err_egress_flood;
@@ -2416,7 +2413,7 @@ static int dpaa2_switch_port_bond_join(struct net_device *netdev,
port_priv->lag = NULL;
dpaa2_switch_set_lag_cfg(bond_dev, lag_id, ethsw);
err_egress_flood:
- dpaa2_switch_port_set_fdb(port_priv, NULL);
+ dpaa2_switch_port_set_fdb(port_priv, bond_dev, false);
return err;
}
@@ -2435,7 +2432,7 @@ static int dpaa2_switch_port_bond_leave(struct net_device *netdev,
return err;
/* Setup the FDB for this port which is now standalone */
- dpaa2_switch_port_set_fdb(port_priv, NULL);
+ dpaa2_switch_port_set_fdb(port_priv, bond_dev, false);
/* Setup the egress flood policy (broadcast, unknown unicast).
* When the port is not under a bond, only the CTRL interface is part
--
2.25.1
^ permalink raw reply related
* [PATCH net-next 07/13] dpaa2-switch: check early if an FDB entry should be added
From: Ioana Ciornei @ 2026-05-06 15:15 UTC (permalink / raw)
To: andrew+netdev, davem, edumazet, kuba, pabeni, netdev; +Cc: linux-kernel
In-Reply-To: <20260506151540.1242997-1-ioana.ciornei@nxp.com>
Instead of waiting until the last moment to check if an FDB entry should
be added to HW, move the check earlier (before even scheduling the work
item) so that we don't just waste time.
Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
---
drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
index 476ee8b46921..a057fd85bd27 100644
--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
+++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
@@ -2725,8 +2725,6 @@ static void dpaa2_switch_event_work(struct work_struct *work)
switch (switchdev_work->event) {
case SWITCHDEV_FDB_ADD_TO_DEVICE:
- if (!fdb_info->added_by_user || fdb_info->is_local)
- break;
if (is_unicast_ether_addr(fdb_info->addr))
err = dpaa2_switch_port_fdb_add_uc(netdev_priv(dev),
fdb_info->addr);
@@ -2740,8 +2738,6 @@ static void dpaa2_switch_event_work(struct work_struct *work)
&fdb_info->info, NULL);
break;
case SWITCHDEV_FDB_DEL_TO_DEVICE:
- if (!fdb_info->added_by_user || fdb_info->is_local)
- break;
if (is_unicast_ether_addr(fdb_info->addr))
dpaa2_switch_port_fdb_del_uc(netdev_priv(dev), fdb_info->addr);
else
@@ -2767,6 +2763,9 @@ static int dpaa2_switch_port_fdb_event(struct notifier_block *nb,
if (!dpaa2_switch_port_dev_check(dev))
return NOTIFY_DONE;
+ if (!fdb_info->added_by_user || fdb_info->is_local)
+ return NOTIFY_DONE;
+
switchdev_work = kzalloc_obj(*switchdev_work, GFP_ATOMIC);
if (!switchdev_work)
return NOTIFY_BAD;
--
2.25.1
^ permalink raw reply related
* [PATCH net-next 04/13] dpaa2-switch: extend dpaa2_switch_port_set_fdb() to cover bond scenarios
From: Ioana Ciornei @ 2026-05-06 15:15 UTC (permalink / raw)
To: andrew+netdev, davem, edumazet, kuba, pabeni, netdev; +Cc: linux-kernel
In-Reply-To: <20260506151540.1242997-1-ioana.ciornei@nxp.com>
The dpaa2_switch_port_set_fdb() function is responsible with determining
what FDB should be used by a port as a consequence of changing its upper
device. This patch extends the function to also cover the circumstances
in which a DPAA2 switch port offloads a bond device.
This will allow us, for example, to setup the same FDB on all DPAA2
switch ports which are under the same bridge, even though not directly
but rather through an upper bond device which is bridged. How the
function does this is by first determining a DPAA2 port is already under
the same bridge and if so, choosing its FDB. To cover the entire
hierarchy in depth, we add an extra walk through all the lowers of a
bridged bond device.
When leaving an upper device, the DPAA2 switch port must find a new FDB
to use. If before it just searched for an unused FDB to go along with
its new standalone status, now it first checks if the port is still part
of a LAG and then uses the FDB of any port that already left the same
bridge.
Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
---
.../ethernet/freescale/dpaa2/dpaa2-switch.c | 102 +++++++++++++-----
1 file changed, 78 insertions(+), 24 deletions(-)
diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
index f1b4c24b8a47..9d3a0aef1568 100644
--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
+++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
@@ -66,28 +66,59 @@ static void dpaa2_switch_port_set_fdb(struct ethsw_port_priv *port_priv,
struct net_device *upper_dev,
bool linking)
{
+ struct ethsw_core *ethsw = port_priv->ethsw_data;
struct ethsw_port_priv *other_port_priv = NULL;
- struct dpaa2_switch_fdb *fdb;
- struct net_device *other_dev;
- struct list_head *iter;
+ struct net_device *other_dev, *other_dev2;
+ u16 fdb_id_old = port_priv->fdb->fdb_id;
+ struct dpaa2_switch_fdb *fdb = NULL;
+ struct list_head *iter, *iter2;
+ int i;
- /* If we leave a bridge, find an unused FDB and use that. */
+ /* If we leave a an upper device, be it a bond or a bridge, find an
+ * unused FDB and use that.
+ */
if (!linking) {
- fdb = dpaa2_switch_fdb_get_unused(port_priv->ethsw_data);
-
- /* If there is no unused FDB, we must be the last port that
- * leaves the last bridge, all the others are standalone. We
- * can just keep the FDB that we already have.
+ /* This port leaves a bridge, but it's still under a bond.
+ * Search for the first port under the same bond which already
+ * left the bridge.
*/
+ if (netif_is_bridge_master(upper_dev) && port_priv->lag) {
+ for (i = 0; i < ethsw->sw_attr.num_ifs; i++) {
+ other_port_priv = ethsw->ports[i];
+ if (!other_port_priv)
+ continue;
+
+ if (other_port_priv == port_priv)
+ continue;
+
+ /* Found a port which is under the same bond
+ * device but already left the bridge. Use
+ * this port's FDB.
+ */
+ if (other_port_priv->lag == port_priv->lag &&
+ other_port_priv->fdb->fdb_id != fdb_id_old) {
+ fdb = other_port_priv->fdb;
+ break;
+ }
+ }
+ }
- if (!fdb) {
- port_priv->fdb->bridge_dev = NULL;
- return;
+ /* Try to get hold of an unused FDB to use */
+ if (!fdb)
+ fdb = dpaa2_switch_fdb_get_unused(port_priv->ethsw_data);
+
+ if (fdb) {
+ port_priv->fdb = fdb;
+ port_priv->fdb->in_use = true;
}
- port_priv->fdb = fdb;
- port_priv->fdb->in_use = true;
- port_priv->fdb->bridge_dev = NULL;
+ if (netif_is_bridge_master(upper_dev))
+ port_priv->fdb->bridge_dev = NULL;
+
+ /* In case all FDBs are already in use, we must be the last
+ * port that becomes standalone. We can just keep the FDB that
+ * we already have. Nothing more to do in this case.
+ */
return;
}
@@ -97,18 +128,40 @@ static void dpaa2_switch_port_set_fdb(struct ethsw_port_priv *port_priv,
*/
ASSERT_RTNL();
- /* If part of a bridge, use the FDB of the first dpaa2 switch interface
- * to be present in that bridge
+ /* In case we are joining an upper device, be it a bridge device or a
+ * bond device, we will use the FDB of the first DPAA2 switch interface
+ * that is already present under the same upper device. For this to
+ * happen we have to extend our search so that we can find any DPAA2
+ * interface that is a lower of a bond bridged port
*/
+ other_port_priv = NULL;
netdev_for_each_lower_dev(upper_dev, other_dev, iter) {
- if (!dpaa2_switch_port_dev_check(other_dev))
- continue;
+ if (netif_is_lag_master(other_dev)) {
+ /* Search through all the lowers of the bridged lag */
+ netdev_for_each_lower_dev(other_dev, other_dev2, iter2) {
+ if (!dpaa2_switch_port_dev_check(other_dev2))
+ continue;
+ if (other_dev2 == port_priv->netdev)
+ continue;
+
+ /* Skip the port if it's the same upper */
+ other_port_priv = netdev_priv(other_dev2);
+ if (other_port_priv->lag == port_priv->lag) {
+ other_port_priv = NULL;
+ continue;
+ }
+ break;
+ }
- if (other_dev == port_priv->netdev)
- continue;
+ if (other_port_priv)
+ break;
+ } else if (dpaa2_switch_port_dev_check(other_dev)) {
+ if (other_dev == port_priv->netdev)
+ continue;
- other_port_priv = netdev_priv(other_dev);
- break;
+ other_port_priv = netdev_priv(other_dev);
+ break;
+ }
}
/* The current port is about to change its FDB to the one used by the
@@ -126,7 +179,8 @@ static void dpaa2_switch_port_set_fdb(struct ethsw_port_priv *port_priv,
}
/* Keep track of the new upper bridge device */
- port_priv->fdb->bridge_dev = upper_dev;
+ if (netif_is_bridge_master(upper_dev))
+ port_priv->fdb->bridge_dev = upper_dev;
}
static void dpaa2_switch_fdb_get_flood_cfg(struct ethsw_core *ethsw, u16 fdb_id,
--
2.25.1
^ permalink raw reply related
* [PATCH net-next 08/13] dpaa2-switch: consolidate unicast and multicast management
From: Ioana Ciornei @ 2026-05-06 15:15 UTC (permalink / raw)
To: andrew+netdev, davem, edumazet, kuba, pabeni, netdev; +Cc: linux-kernel
In-Reply-To: <20260506151540.1242997-1-ioana.ciornei@nxp.com>
This patch consolidates the unicast and multicast management by creating
two new functions - dpaa2_switch_port_fdb_[add|del]() - which can be
used for either uc or mc addresses. Having this common entrypoint for
both types of addresses will help us in the next patches to streamline
the same addresses but on LAG ports.
Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
---
.../ethernet/freescale/dpaa2/dpaa2-switch.c | 39 +++++++++++++------
1 file changed, 27 insertions(+), 12 deletions(-)
diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
index a057fd85bd27..bced37335a9e 100644
--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
+++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
@@ -551,6 +551,28 @@ static int dpaa2_switch_port_fdb_del_mc(struct ethsw_port_priv *port_priv,
return err;
}
+static int dpaa2_switch_port_fdb_add(struct ethsw_port_priv *port_priv,
+ const unsigned char *addr)
+{
+ int err;
+
+ if (is_unicast_ether_addr(addr))
+ err = dpaa2_switch_port_fdb_add_uc(port_priv, addr);
+ else
+ err = dpaa2_switch_port_fdb_add_mc(port_priv, addr);
+
+ return err;
+}
+
+static int dpaa2_switch_port_fdb_del(struct ethsw_port_priv *port_priv,
+ const unsigned char *addr)
+{
+ if (is_unicast_ether_addr(addr))
+ return dpaa2_switch_port_fdb_del_uc(port_priv, addr);
+ else
+ return dpaa2_switch_port_fdb_del_mc(port_priv, addr);
+}
+
static void dpaa2_switch_port_get_stats(struct net_device *netdev,
struct rtnl_link_stats64 *stats)
{
@@ -1915,7 +1937,7 @@ static int dpaa2_switch_port_mdb_add(struct net_device *netdev,
if (dpaa2_switch_port_lookup_address(netdev, 0, mdb->addr))
return -EEXIST;
- err = dpaa2_switch_port_fdb_add_mc(port_priv, mdb->addr);
+ err = dpaa2_switch_port_fdb_add(port_priv, mdb->addr);
if (err)
return err;
@@ -2033,7 +2055,7 @@ static int dpaa2_switch_port_mdb_del(struct net_device *netdev,
if (!dpaa2_switch_port_lookup_address(netdev, 0, mdb->addr))
return -ENOENT;
- err = dpaa2_switch_port_fdb_del_mc(port_priv, mdb->addr);
+ err = dpaa2_switch_port_fdb_del(port_priv, mdb->addr);
if (err)
return err;
@@ -2725,12 +2747,8 @@ static void dpaa2_switch_event_work(struct work_struct *work)
switch (switchdev_work->event) {
case SWITCHDEV_FDB_ADD_TO_DEVICE:
- if (is_unicast_ether_addr(fdb_info->addr))
- err = dpaa2_switch_port_fdb_add_uc(netdev_priv(dev),
- fdb_info->addr);
- else
- err = dpaa2_switch_port_fdb_add_mc(netdev_priv(dev),
- fdb_info->addr);
+ err = dpaa2_switch_port_fdb_add(netdev_priv(dev),
+ fdb_info->addr);
if (err)
break;
fdb_info->offloaded = true;
@@ -2738,10 +2756,7 @@ static void dpaa2_switch_event_work(struct work_struct *work)
&fdb_info->info, NULL);
break;
case SWITCHDEV_FDB_DEL_TO_DEVICE:
- if (is_unicast_ether_addr(fdb_info->addr))
- dpaa2_switch_port_fdb_del_uc(netdev_priv(dev), fdb_info->addr);
- else
- dpaa2_switch_port_fdb_del_mc(netdev_priv(dev), fdb_info->addr);
+ dpaa2_switch_port_fdb_del(netdev_priv(dev), fdb_info->addr);
break;
}
--
2.25.1
^ permalink raw reply related
* [PATCH net-next 05/13] dpaa2-switch: add dpaa2_switch_port_to_bridge_port() helper
From: Ioana Ciornei @ 2026-05-06 15:15 UTC (permalink / raw)
To: andrew+netdev, davem, edumazet, kuba, pabeni, netdev; +Cc: linux-kernel
In-Reply-To: <20260506151540.1242997-1-ioana.ciornei@nxp.com>
With the addition of offloading support for upper bond devices we have
to let the switchdev framework know if a specific bridge port is
offloaded or not, even if that port is bond device.
For this to happen, create the dpaa2_switch_port_to_bridge_port function
which will determine the bridge port corresponding to a particulat DPAA2
switch interface and use it in the switchdev_bridge_port_offload call.
Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
---
.../ethernet/freescale/dpaa2/dpaa2-switch.c | 26 ++++++++++++++++---
1 file changed, 23 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
index 9d3a0aef1568..aaa22dc15038 100644
--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
+++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
@@ -2076,6 +2076,18 @@ static int dpaa2_switch_port_attr_set_event(struct net_device *netdev,
return notifier_from_errno(err);
}
+static struct net_device *
+dpaa2_switch_port_to_bridge_port(struct ethsw_port_priv *port_priv)
+{
+ if (!port_priv->fdb->bridge_dev)
+ return NULL;
+
+ if (port_priv->lag)
+ return port_priv->lag->bond_dev;
+
+ return port_priv->netdev;
+}
+
static int dpaa2_switch_port_bridge_join(struct net_device *netdev,
struct net_device *upper_dev,
struct netlink_ext_ack *extack)
@@ -2083,6 +2095,7 @@ static int dpaa2_switch_port_bridge_join(struct net_device *netdev,
struct ethsw_port_priv *port_priv = netdev_priv(netdev);
struct dpaa2_switch_fdb *old_fdb = port_priv->fdb;
struct ethsw_core *ethsw = port_priv->ethsw_data;
+ struct net_device *brport_dev;
bool learn_ena;
int err;
@@ -2094,7 +2107,8 @@ static int dpaa2_switch_port_bridge_join(struct net_device *netdev,
dpaa2_switch_port_set_fdb(port_priv, upper_dev, true);
/* Inherit the initial bridge port learning state */
- learn_ena = br_port_flag_is_set(netdev, BR_LEARNING);
+ brport_dev = dpaa2_switch_port_to_bridge_port(port_priv);
+ learn_ena = br_port_flag_is_set(brport_dev, BR_LEARNING);
err = dpaa2_switch_port_set_learning(port_priv, learn_ena);
port_priv->learn_ena = learn_ena;
@@ -2108,7 +2122,8 @@ static int dpaa2_switch_port_bridge_join(struct net_device *netdev,
if (err)
goto err_egress_flood;
- err = switchdev_bridge_port_offload(netdev, netdev, NULL,
+ brport_dev = dpaa2_switch_port_to_bridge_port(port_priv);
+ err = switchdev_bridge_port_offload(brport_dev, netdev, NULL,
NULL, NULL, false, extack);
if (err)
goto err_switchdev_offload;
@@ -2143,7 +2158,12 @@ static int dpaa2_switch_port_restore_rxvlan(struct net_device *vdev, int vid, vo
static void dpaa2_switch_port_pre_bridge_leave(struct net_device *netdev)
{
- switchdev_bridge_port_unoffload(netdev, NULL, NULL, NULL);
+ struct ethsw_port_priv *port_priv = netdev_priv(netdev);
+ struct net_device *brport_dev;
+
+ brport_dev = dpaa2_switch_port_to_bridge_port(port_priv);
+
+ switchdev_bridge_port_unoffload(brport_dev, NULL, NULL, NULL);
}
static int dpaa2_switch_port_bridge_leave(struct net_device *netdev)
--
2.25.1
^ permalink raw reply related
* [PATCH net-next 09/13] dpaa2-switch: offload FDBs added on an upper bond device
From: Ioana Ciornei @ 2026-05-06 15:15 UTC (permalink / raw)
To: andrew+netdev, davem, edumazet, kuba, pabeni, netdev; +Cc: linux-kernel
In-Reply-To: <20260506151540.1242997-1-ioana.ciornei@nxp.com>
This patch adds support for offloading FDB entries added on upper bond
devices.
First of all, the call to switchdev_bridge_port_offload() is updated so
that the notifier blocks needed for FDB events replay are available to
the bridge core.
Using switchdev_handle_*() helpers is also necessary because each FDB
event needs to be fanned out to any DPAA2 switch lower device. This
triggers another change in the return type used by the
dpaa2_switch_port_fdb_event() - from notifier types to regular errno
types.
Handling of the SWITCHDEV_FDB_ADD_TO_DEVICE/SWITCHDEV_FDB_DEL_TO_DEVICE
events is updated so that the newly dpaa2_switch_lag_fdb_add() /
dpaa2_switch_lag_fdb_del() functions are called anytime a port is under
a bond device. This will allow us to manage refcounting on FDB entries
which are added on the upper bond devices.
The DPAA2 switch uses shared-VLAN learning which means that the vid
parameter is not used when adding an FDB entry to HW. The current
behavior when dealing with FDB entries with the same MAC address but
different VLANs is to add the entry to HW every time while removal will
get done on the first 'bridge fdb del' command issued by the user.
The same behavior is kept also for FDBs added on bond devices by keeping
the refcount on the {vid, addr} pair while the HW operation disregards
entirely the vid parameter.
Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
---
.../ethernet/freescale/dpaa2/dpaa2-switch.c | 190 ++++++++++++++++--
.../ethernet/freescale/dpaa2/dpaa2-switch.h | 22 ++
2 files changed, 193 insertions(+), 19 deletions(-)
diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
index bced37335a9e..cce0af47ca07 100644
--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
+++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
@@ -25,6 +25,9 @@
#define DEFAULT_VLAN_ID 1
+static struct notifier_block dpaa2_switch_port_switchdev_nb;
+static struct notifier_block dpaa2_switch_port_switchdev_blocking_nb;
+
static u16 dpaa2_switch_port_get_fdb_id(struct ethsw_port_priv *port_priv)
{
return port_priv->fdb->fdb_id;
@@ -62,6 +65,25 @@ dpaa2_switch_lag_get_unused(struct ethsw_core *ethsw)
return NULL;
}
+static struct ethsw_port_priv *
+dpaa2_switch_lag_get_primary(struct dpaa2_switch_lag *lag)
+{
+ struct ethsw_core *ethsw = lag->ethsw;
+ struct ethsw_port_priv *port_priv;
+ int i;
+
+ for (i = 0; i < ethsw->sw_attr.num_ifs; i++) {
+ port_priv = ethsw->ports[i];
+ if (!port_priv)
+ continue;
+
+ if (port_priv->lag == lag)
+ return port_priv;
+ }
+
+ return NULL;
+}
+
static void dpaa2_switch_port_set_fdb(struct ethsw_port_priv *port_priv,
struct net_device *upper_dev,
bool linking)
@@ -573,6 +595,91 @@ static int dpaa2_switch_port_fdb_del(struct ethsw_port_priv *port_priv,
return dpaa2_switch_port_fdb_del_mc(port_priv, addr);
}
+static struct dpaa2_mac_addr *
+dpaa2_switch_mac_addr_find(struct list_head *addr_list,
+ const unsigned char *addr, u16 vid)
+{
+ struct dpaa2_mac_addr *a;
+
+ list_for_each_entry(a, addr_list, list)
+ if (ether_addr_equal(a->addr, addr) && a->vid == vid)
+ return a;
+
+ return NULL;
+}
+
+static int dpaa2_switch_lag_fdb_add(struct dpaa2_switch_lag *lag,
+ const unsigned char *addr, u16 vid)
+{
+ struct ethsw_port_priv *port_priv;
+ struct dpaa2_mac_addr *a;
+ int err = 0;
+
+ mutex_lock(&lag->fdb_lock);
+
+ a = dpaa2_switch_mac_addr_find(&lag->fdbs, addr, vid);
+ if (a) {
+ refcount_inc(&a->refcount);
+ goto out;
+ }
+
+ port_priv = dpaa2_switch_lag_get_primary(lag);
+ if (!port_priv) {
+ err = -ENOENT;
+ goto out;
+ }
+
+ a = kzalloc(sizeof(*a), GFP_KERNEL);
+ if (!a) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ err = dpaa2_switch_port_fdb_add(port_priv, addr);
+ if (err) {
+ kfree(a);
+ goto out;
+ }
+
+ ether_addr_copy(a->addr, addr);
+ a->vid = vid;
+ refcount_set(&a->refcount, 1);
+ list_add_tail(&a->list, &lag->fdbs);
+
+out:
+ mutex_unlock(&lag->fdb_lock);
+
+ return err;
+}
+
+static void dpaa2_switch_lag_fdb_del(struct dpaa2_switch_lag *lag,
+ const unsigned char *addr, u16 vid)
+{
+ struct ethsw_port_priv *port_priv;
+ struct dpaa2_mac_addr *a;
+
+ mutex_lock(&lag->fdb_lock);
+
+ a = dpaa2_switch_mac_addr_find(&lag->fdbs, addr, vid);
+ if (!a)
+ goto out;
+
+ port_priv = dpaa2_switch_lag_get_primary(lag);
+ if (!port_priv)
+ goto out;
+
+ if (!refcount_dec_and_test(&a->refcount))
+ goto out;
+
+ dpaa2_switch_port_fdb_del(port_priv, addr);
+
+ list_del(&a->list);
+ kfree(a);
+
+out:
+ mutex_unlock(&lag->fdb_lock);
+}
+
static void dpaa2_switch_port_get_stats(struct net_device *netdev,
struct rtnl_link_stats64 *stats)
{
@@ -1520,6 +1627,22 @@ bool dpaa2_switch_port_dev_check(const struct net_device *netdev)
return netdev->netdev_ops == &dpaa2_switch_port_ops;
}
+static bool dpaa2_switch_foreign_dev_check(const struct net_device *dev,
+ const struct net_device *foreign_dev)
+{
+ struct ethsw_port_priv *port_priv = netdev_priv(dev);
+
+ if (netif_is_bridge_master(foreign_dev))
+ if (port_priv->fdb->bridge_dev == foreign_dev)
+ return false;
+
+ if (netif_is_bridge_port(foreign_dev))
+ return !dpaa2_switch_port_offloads_bridge_port(port_priv,
+ foreign_dev);
+
+ return true;
+}
+
static int dpaa2_switch_port_connect_mac(struct ethsw_port_priv *port_priv)
{
struct fsl_mc_device *dpsw_port_dev, *dpmac_dev;
@@ -2145,8 +2268,10 @@ static int dpaa2_switch_port_bridge_join(struct net_device *netdev,
goto err_egress_flood;
brport_dev = dpaa2_switch_port_to_bridge_port(port_priv);
- err = switchdev_bridge_port_offload(brport_dev, netdev, NULL,
- NULL, NULL, false, extack);
+ err = switchdev_bridge_port_offload(brport_dev, netdev, port_priv,
+ &dpaa2_switch_port_switchdev_nb,
+ &dpaa2_switch_port_switchdev_blocking_nb,
+ false, extack);
if (err)
goto err_switchdev_offload;
@@ -2731,7 +2856,9 @@ struct ethsw_switchdev_event_work {
struct work_struct work;
struct switchdev_notifier_fdb_info fdb_info;
struct net_device *dev;
+ struct net_device *orig_dev;
unsigned long event;
+ u16 vid;
};
static void dpaa2_switch_event_work(struct work_struct *work)
@@ -2739,6 +2866,7 @@ static void dpaa2_switch_event_work(struct work_struct *work)
struct ethsw_switchdev_event_work *switchdev_work =
container_of(work, struct ethsw_switchdev_event_work, work);
struct net_device *dev = switchdev_work->dev;
+ struct ethsw_port_priv *port_priv = netdev_priv(dev);
struct switchdev_notifier_fdb_info *fdb_info;
int err;
@@ -2747,16 +2875,26 @@ static void dpaa2_switch_event_work(struct work_struct *work)
switch (switchdev_work->event) {
case SWITCHDEV_FDB_ADD_TO_DEVICE:
- err = dpaa2_switch_port_fdb_add(netdev_priv(dev),
- fdb_info->addr);
+ if (port_priv->lag)
+ err = dpaa2_switch_lag_fdb_add(port_priv->lag,
+ fdb_info->addr,
+ switchdev_work->vid);
+ else
+ err = dpaa2_switch_port_fdb_add(netdev_priv(dev),
+ fdb_info->addr);
if (err)
break;
fdb_info->offloaded = true;
- call_switchdev_notifiers(SWITCHDEV_FDB_OFFLOADED, dev,
+ call_switchdev_notifiers(SWITCHDEV_FDB_OFFLOADED,
+ switchdev_work->orig_dev,
&fdb_info->info, NULL);
break;
case SWITCHDEV_FDB_DEL_TO_DEVICE:
- dpaa2_switch_port_fdb_del(netdev_priv(dev), fdb_info->addr);
+ if (port_priv->lag)
+ dpaa2_switch_lag_fdb_del(port_priv->lag, fdb_info->addr,
+ switchdev_work->vid);
+ else
+ dpaa2_switch_port_fdb_del(port_priv, fdb_info->addr);
break;
}
@@ -2766,33 +2904,40 @@ static void dpaa2_switch_event_work(struct work_struct *work)
dev_put(dev);
}
-static int dpaa2_switch_port_fdb_event(struct notifier_block *nb,
- unsigned long event, void *ptr)
+static int
+dpaa2_switch_port_fdb_event(struct net_device *dev,
+ struct net_device *orig_dev,
+ unsigned long event, const void *ctx,
+ const struct switchdev_notifier_fdb_info *fdb_info)
{
- struct net_device *dev = switchdev_notifier_info_to_dev(ptr);
struct ethsw_port_priv *port_priv = netdev_priv(dev);
struct ethsw_switchdev_event_work *switchdev_work;
- struct switchdev_notifier_fdb_info *fdb_info = ptr;
struct ethsw_core *ethsw = port_priv->ethsw_data;
- if (!dpaa2_switch_port_dev_check(dev))
- return NOTIFY_DONE;
+ if (ctx && ctx != port_priv)
+ return 0;
+
+ /* For the moment, do nothing with entries towards foreign devices */
+ if (dpaa2_switch_foreign_dev_check(dev, orig_dev))
+ return 0;
if (!fdb_info->added_by_user || fdb_info->is_local)
- return NOTIFY_DONE;
+ return 0;
switchdev_work = kzalloc_obj(*switchdev_work, GFP_ATOMIC);
if (!switchdev_work)
- return NOTIFY_BAD;
+ return -ENOMEM;
INIT_WORK(&switchdev_work->work, dpaa2_switch_event_work);
switchdev_work->dev = dev;
switchdev_work->event = event;
+ switchdev_work->orig_dev = orig_dev;
+ switchdev_work->vid = fdb_info->vid;
switch (event) {
case SWITCHDEV_FDB_ADD_TO_DEVICE:
case SWITCHDEV_FDB_DEL_TO_DEVICE:
- memcpy(&switchdev_work->fdb_info, ptr,
+ memcpy(&switchdev_work->fdb_info, fdb_info,
sizeof(switchdev_work->fdb_info));
switchdev_work->fdb_info.addr = kzalloc(ETH_ALEN, GFP_ATOMIC);
if (!switchdev_work->fdb_info.addr)
@@ -2806,16 +2951,16 @@ static int dpaa2_switch_port_fdb_event(struct notifier_block *nb,
break;
default:
kfree(switchdev_work);
- return NOTIFY_DONE;
+ return 0;
}
queue_work(ethsw->workqueue, &switchdev_work->work);
- return NOTIFY_DONE;
+ return 0;
err_addr_alloc:
kfree(switchdev_work);
- return NOTIFY_BAD;
+ return -ENOMEM;
}
/* Called under rcu_read_lock() */
@@ -2823,13 +2968,18 @@ static int dpaa2_switch_port_event(struct notifier_block *nb,
unsigned long event, void *ptr)
{
struct net_device *dev = switchdev_notifier_info_to_dev(ptr);
+ int err;
switch (event) {
case SWITCHDEV_PORT_ATTR_SET:
return dpaa2_switch_port_attr_set_event(dev, ptr);
case SWITCHDEV_FDB_ADD_TO_DEVICE:
case SWITCHDEV_FDB_DEL_TO_DEVICE:
- return dpaa2_switch_port_fdb_event(nb, event, ptr);
+ err = switchdev_handle_fdb_event_to_device(dev, event, ptr,
+ dpaa2_switch_port_dev_check,
+ dpaa2_switch_foreign_dev_check,
+ dpaa2_switch_port_fdb_event);
+ return notifier_from_errno(err);
default:
return NOTIFY_DONE;
}
@@ -3917,6 +4067,8 @@ static int dpaa2_switch_probe(struct fsl_mc_device *sw_dev)
ethsw->lags[i].ethsw = ethsw;
ethsw->lags[i].id = i + 1;
ethsw->lags[i].in_use = 0;
+ mutex_init(ðsw->lags[i].fdb_lock);
+ INIT_LIST_HEAD(ðsw->lags[i].fdbs);
}
for (i = 0; i < ethsw->sw_attr.num_ifs; i++) {
diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.h b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.h
index 56debbdefd13..96d780980d77 100644
--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.h
+++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.h
@@ -100,6 +100,13 @@ struct dpaa2_switch_fq {
u32 fqid;
};
+struct dpaa2_mac_addr {
+ unsigned char addr[ETH_ALEN];
+ u16 vid;
+ refcount_t refcount;
+ struct list_head list;
+};
+
struct dpaa2_switch_fdb {
struct net_device *bridge_dev;
u16 fdb_id;
@@ -111,6 +118,9 @@ struct dpaa2_switch_lag {
struct net_device *bond_dev;
bool in_use;
u8 id;
+ /* Protects the list of fdbs installed on this LAG */
+ struct mutex fdb_lock;
+ struct list_head fdbs;
};
struct dpaa2_switch_acl_entry {
@@ -286,4 +296,16 @@ int dpaa2_switch_block_offload_mirror(struct dpaa2_switch_filter_block *block,
int dpaa2_switch_block_unoffload_mirror(struct dpaa2_switch_filter_block *block,
struct ethsw_port_priv *port_priv);
+
+static inline bool
+dpaa2_switch_port_offloads_bridge_port(struct ethsw_port_priv *port_priv,
+ const struct net_device *dev)
+{
+ if (port_priv->lag && port_priv->lag->bond_dev == dev)
+ return true;
+ if (port_priv->netdev == dev)
+ return true;
+ return false;
+}
+
#endif /* __ETHSW_H */
--
2.25.1
^ permalink raw reply related
* [PATCH net-next 06/13] dpaa2-switch: create a separate dpaa2_switch_port_fdb_event() function
From: Ioana Ciornei @ 2026-05-06 15:15 UTC (permalink / raw)
To: andrew+netdev, davem, edumazet, kuba, pabeni, netdev; +Cc: linux-kernel
In-Reply-To: <20260506151540.1242997-1-ioana.ciornei@nxp.com>
Create a separate dpaa2_switch_port_fdb_event() function that will only
handle the FDB related events. With this change, the
dpaa2_switch_port_event() notifier handler can be written in a way that
it's easier to follow.
Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
---
.../ethernet/freescale/dpaa2/dpaa2-switch.c | 25 ++++++++++++++-----
1 file changed, 19 insertions(+), 6 deletions(-)
diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
index aaa22dc15038..476ee8b46921 100644
--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
+++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
@@ -2755,9 +2755,8 @@ static void dpaa2_switch_event_work(struct work_struct *work)
dev_put(dev);
}
-/* Called under rcu_read_lock() */
-static int dpaa2_switch_port_event(struct notifier_block *nb,
- unsigned long event, void *ptr)
+static int dpaa2_switch_port_fdb_event(struct notifier_block *nb,
+ unsigned long event, void *ptr)
{
struct net_device *dev = switchdev_notifier_info_to_dev(ptr);
struct ethsw_port_priv *port_priv = netdev_priv(dev);
@@ -2765,9 +2764,6 @@ static int dpaa2_switch_port_event(struct notifier_block *nb,
struct switchdev_notifier_fdb_info *fdb_info = ptr;
struct ethsw_core *ethsw = port_priv->ethsw_data;
- if (event == SWITCHDEV_PORT_ATTR_SET)
- return dpaa2_switch_port_attr_set_event(dev, ptr);
-
if (!dpaa2_switch_port_dev_check(dev))
return NOTIFY_DONE;
@@ -2808,6 +2804,23 @@ static int dpaa2_switch_port_event(struct notifier_block *nb,
return NOTIFY_BAD;
}
+/* Called under rcu_read_lock() */
+static int dpaa2_switch_port_event(struct notifier_block *nb,
+ unsigned long event, void *ptr)
+{
+ struct net_device *dev = switchdev_notifier_info_to_dev(ptr);
+
+ switch (event) {
+ case SWITCHDEV_PORT_ATTR_SET:
+ return dpaa2_switch_port_attr_set_event(dev, ptr);
+ case SWITCHDEV_FDB_ADD_TO_DEVICE:
+ case SWITCHDEV_FDB_DEL_TO_DEVICE:
+ return dpaa2_switch_port_fdb_event(nb, event, ptr);
+ default:
+ return NOTIFY_DONE;
+ }
+}
+
static int dpaa2_switch_port_obj_event(unsigned long event,
struct net_device *netdev,
struct switchdev_notifier_port_obj_info *port_obj_info)
--
2.25.1
^ permalink raw reply related
* [PATCH net-next 10/13] dpaa2-switch: offload port objects on an upper bond device
From: Ioana Ciornei @ 2026-05-06 15:15 UTC (permalink / raw)
To: andrew+netdev, davem, edumazet, kuba, pabeni, netdev; +Cc: linux-kernel
In-Reply-To: <20260506151540.1242997-1-ioana.ciornei@nxp.com>
This patch adds support for offloading port objects, VLANs and MDBs,
added on upper bond devices.
First of all, the use of the switchdev_handle_*() replication helpers
is introduced for the SWITCHDEV_PORT_OBJ_ADD/SWITCHDEV_PORT_OBJ_DEL
events. With this change, setting up the 'port_obj_info->handled = true'
is not needed anymore since it's now handled by the new helpers.
In the DPAA2 architecture, there is no difference in adding a FDB or MDB
which points towards a LAG port. Unlike other architectures, we do not
need to populate all the possible destinations which are under the LAG,
we only have to specify a single queueing destination (QDID) which
represents the LAG. This all means that handling of MDBs in bond devices
needs to have refcount mechanism as with the FDBs.
This mechanism is triggered by calling the dpaa2_switch_lag_fdb_add() /
dpaa2_switch_lag_fdb_del() functions which were added in the previous
patch.
Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
---
.../ethernet/freescale/dpaa2/dpaa2-switch.c | 66 ++++++++++---------
1 file changed, 36 insertions(+), 30 deletions(-)
diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
index cce0af47ca07..17a7a64064b5 100644
--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
+++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
@@ -2060,7 +2060,11 @@ static int dpaa2_switch_port_mdb_add(struct net_device *netdev,
if (dpaa2_switch_port_lookup_address(netdev, 0, mdb->addr))
return -EEXIST;
- err = dpaa2_switch_port_fdb_add(port_priv, mdb->addr);
+ if (port_priv->lag)
+ err = dpaa2_switch_lag_fdb_add(port_priv->lag, mdb->addr,
+ mdb->vid);
+ else
+ err = dpaa2_switch_port_fdb_add(port_priv, mdb->addr);
if (err)
return err;
@@ -2073,11 +2077,19 @@ static int dpaa2_switch_port_mdb_add(struct net_device *netdev,
return err;
}
-static int dpaa2_switch_port_obj_add(struct net_device *netdev,
- const struct switchdev_obj *obj)
+static int dpaa2_switch_port_obj_add(struct net_device *netdev, const void *ctx,
+ const struct switchdev_obj *obj,
+ struct netlink_ext_ack *extack)
{
+ struct ethsw_port_priv *port_priv = netdev_priv(netdev);
int err;
+ if (ctx && ctx != port_priv)
+ return 0;
+
+ if (!dpaa2_switch_port_offloads_bridge_port(port_priv, obj->orig_dev))
+ return -EOPNOTSUPP;
+
switch (obj->id) {
case SWITCHDEV_OBJ_ID_PORT_VLAN:
err = dpaa2_switch_port_vlans_add(netdev,
@@ -2178,9 +2190,10 @@ static int dpaa2_switch_port_mdb_del(struct net_device *netdev,
if (!dpaa2_switch_port_lookup_address(netdev, 0, mdb->addr))
return -ENOENT;
- err = dpaa2_switch_port_fdb_del(port_priv, mdb->addr);
- if (err)
- return err;
+ if (port_priv->lag)
+ dpaa2_switch_lag_fdb_del(port_priv->lag, mdb->addr, mdb->vid);
+ else
+ dpaa2_switch_port_fdb_del(port_priv, mdb->addr);
err = dev_mc_del(netdev, mdb->addr);
if (err) {
@@ -2191,11 +2204,18 @@ static int dpaa2_switch_port_mdb_del(struct net_device *netdev,
return err;
}
-static int dpaa2_switch_port_obj_del(struct net_device *netdev,
+static int dpaa2_switch_port_obj_del(struct net_device *netdev, const void *ctx,
const struct switchdev_obj *obj)
{
+ struct ethsw_port_priv *port_priv = netdev_priv(netdev);
int err;
+ if (ctx && ctx != port_priv)
+ return 0;
+
+ if (!dpaa2_switch_port_offloads_bridge_port(port_priv, obj->orig_dev))
+ return -EOPNOTSUPP;
+
switch (obj->id) {
case SWITCHDEV_OBJ_ID_PORT_VLAN:
err = dpaa2_switch_port_vlans_del(netdev, SWITCHDEV_OBJ_PORT_VLAN(obj));
@@ -2985,37 +3005,23 @@ static int dpaa2_switch_port_event(struct notifier_block *nb,
}
}
-static int dpaa2_switch_port_obj_event(unsigned long event,
- struct net_device *netdev,
- struct switchdev_notifier_port_obj_info *port_obj_info)
-{
- int err = -EOPNOTSUPP;
-
- if (!dpaa2_switch_port_dev_check(netdev))
- return NOTIFY_DONE;
-
- switch (event) {
- case SWITCHDEV_PORT_OBJ_ADD:
- err = dpaa2_switch_port_obj_add(netdev, port_obj_info->obj);
- break;
- case SWITCHDEV_PORT_OBJ_DEL:
- err = dpaa2_switch_port_obj_del(netdev, port_obj_info->obj);
- break;
- }
-
- port_obj_info->handled = true;
- return notifier_from_errno(err);
-}
-
static int dpaa2_switch_port_blocking_event(struct notifier_block *nb,
unsigned long event, void *ptr)
{
struct net_device *dev = switchdev_notifier_info_to_dev(ptr);
+ int err;
switch (event) {
case SWITCHDEV_PORT_OBJ_ADD:
+ err = switchdev_handle_port_obj_add(dev, ptr,
+ dpaa2_switch_port_dev_check,
+ dpaa2_switch_port_obj_add);
+ return notifier_from_errno(err);
case SWITCHDEV_PORT_OBJ_DEL:
- return dpaa2_switch_port_obj_event(event, dev, ptr);
+ err = switchdev_handle_port_obj_del(dev, ptr,
+ dpaa2_switch_port_dev_check,
+ dpaa2_switch_port_obj_del);
+ return notifier_from_errno(err);
case SWITCHDEV_PORT_ATTR_SET:
return dpaa2_switch_port_attr_set_event(dev, ptr);
}
--
2.25.1
^ permalink raw reply related
* [PATCH net-next 11/13] dpaa2-switch: trap all link local reserved addresses to the CPU
From: Ioana Ciornei @ 2026-05-06 15:15 UTC (permalink / raw)
To: andrew+netdev, davem, edumazet, kuba, pabeni, netdev; +Cc: linux-kernel
In-Reply-To: <20260506151540.1242997-1-ioana.ciornei@nxp.com>
Do not trap only STP frames to the control interface but rather trap all
link local reserved addresses. This will still be done by looking at the
destination MAC address but keeping in mind to not take into account the
last byte.
This change will benefit LACP frames which now will reach the control
interface.
While at it, change the prototype of the
dpaa2_switch_port_trap_mac_addr() function so that we directly pass a
'const u8 *' so that it matches the ether_addr_copy() used.
Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
---
drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c | 13 ++++++-------
1 file changed, 6 insertions(+), 7 deletions(-)
diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
index 17a7a64064b5..59ed06ed7ef6 100644
--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
+++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
@@ -3776,17 +3776,15 @@ static int dpaa2_switch_init(struct fsl_mc_device *sw_dev)
return err;
}
-/* Add an ACL to redirect frames with specific destination MAC address to
- * control interface
- */
+/* Add an ACL to redirect frames to control interface based on the dst MAC */
static int dpaa2_switch_port_trap_mac_addr(struct ethsw_port_priv *port_priv,
- const char *mac)
+ const u8 *mac, const u8 *mask)
{
struct dpaa2_switch_acl_entry acl_entry = {0};
/* Match on the destination MAC address */
ether_addr_copy(acl_entry.key.match.l2_dest_mac, mac);
- eth_broadcast_addr(acl_entry.key.mask.l2_dest_mac);
+ ether_addr_copy(acl_entry.key.mask.l2_dest_mac, mask);
/* Trap to CPU */
acl_entry.cfg.precedence = 0;
@@ -3797,7 +3795,8 @@ static int dpaa2_switch_port_trap_mac_addr(struct ethsw_port_priv *port_priv,
static int dpaa2_switch_port_init(struct ethsw_port_priv *port_priv, u16 port)
{
- const char stpa[ETH_ALEN] = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x00};
+ const u8 ll_mac[ETH_ALEN] = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x00};
+ const u8 ll_mask[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0x00};
struct switchdev_obj_port_vlan vlan = {
.obj.id = SWITCHDEV_OBJ_ID_PORT_VLAN,
.vid = DEFAULT_VLAN_ID,
@@ -3872,7 +3871,7 @@ static int dpaa2_switch_port_init(struct ethsw_port_priv *port_priv, u16 port)
if (err)
return err;
- err = dpaa2_switch_port_trap_mac_addr(port_priv, stpa);
+ err = dpaa2_switch_port_trap_mac_addr(port_priv, ll_mac, ll_mask);
if (err)
return err;
--
2.25.1
^ permalink raw reply related
* [PATCH net-next 12/13] dpaa2-switch: add support for imprecise source port
From: Ioana Ciornei @ 2026-05-06 15:15 UTC (permalink / raw)
To: andrew+netdev, davem, edumazet, kuba, pabeni, netdev; +Cc: linux-kernel
In-Reply-To: <20260506151540.1242997-1-ioana.ciornei@nxp.com>
Switch ports configured as part of a LAG group are not able to provide
a precise source port for all packets which reach the control interface.
The only frames which will have a precise source port are those that are
explicitly trapped, for example STP and LCAP frames. For any other
frames (for example, those which are flooded) we can only know the
ingress LAG group.
Take into account the DPAA2_ETHSW_FLC_IMPRECISE_IF_ID bit and based on
its value target the bond device or the specific source netdevice.
Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
---
drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c | 10 ++++++++--
drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.h | 3 +++
2 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
index 59ed06ed7ef6..8353d2230c72 100644
--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
+++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
@@ -3075,9 +3075,12 @@ static void dpaa2_switch_rx(struct dpaa2_switch_fq *fq,
struct sk_buff *skb;
u16 vlan_tci, vid;
int if_id, err;
+ u64 flc;
+
+ flc = dpaa2_fd_get_flc(fd);
/* get switch ingress interface ID */
- if_id = upper_32_bits(dpaa2_fd_get_flc(fd)) & 0x0000FFFF;
+ if_id = DPAA2_ETHSW_FLC_IF_ID(flc);
if (if_id >= ethsw->sw_attr.num_ifs) {
dev_err(ethsw->dev, "Frame received from unknown interface!\n");
@@ -3116,7 +3119,10 @@ static void dpaa2_switch_rx(struct dpaa2_switch_fq *fq,
}
}
- skb->dev = netdev;
+ if (DPAA2_ETHSW_FLC_IMPRECISE_IF_ID(flc) && port_priv->lag)
+ skb->dev = port_priv->lag->bond_dev;
+ else
+ skb->dev = netdev;
skb->protocol = eth_type_trans(skb, skb->dev);
/* Setup the offload_fwd_mark only if the port is under a bridge
diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.h b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.h
index 96d780980d77..6d7a503f9be7 100644
--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.h
+++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.h
@@ -87,6 +87,9 @@
#define DPAA2_ETHSW_PORT_ACL_CMD_BUF_SIZE 256
+#define DPAA2_ETHSW_FLC_IF_ID(flc) (((flc) >> 32) & GENMASK(15, 0))
+#define DPAA2_ETHSW_FLC_IMPRECISE_IF_ID(flc) ((flc) & BIT(63))
+
extern const struct ethtool_ops dpaa2_switch_port_ethtool_ops;
struct ethsw_core;
--
2.25.1
^ permalink raw reply related
* Re: [PATCH net 0/8] IPVS fixes for net
From: Pablo Neira Ayuso @ 2026-05-06 15:16 UTC (permalink / raw)
To: Julian Anastasov
Cc: netfilter-devel, davem, netdev, kuba, pabeni, edumazet, fw, horms,
longman, lvs-devel, Anna-Maria Behnsen, Frederic Weisbecker,
Ingo Molnar, Thomas Gleixner
In-Reply-To: <bce80830-1e2d-43ad-ba7f-055cb352b348@ssi.bg>
Hi Julian,
Cc'ing Waiman Long and NOHZ maintainers (apologies if this is dragging
more people that I should into this issue).
On Wed, May 06, 2026 at 11:56:05AM +0300, Julian Anastasov wrote:
[...]
> Here are some comments after the last review from
> Sashiko:
>
> https://sashiko.dev/#/patchset/20260505001648.360569-1-pablo%40netfilter.org
>
> Patch 1:
> - while ip_vs_dst_event() should loop and ensure all dev
> references are released, single change of svc_table_changes
> does not indicate the old references are dropped by ip_vs_flush() or
> ip_vs_del_service(). I'll post new change to abort the loop
> when we are sure the services are at least once released.
>
> Patch 5:
> - after executing ip_vs_est_calc_phase(), data can
> remain only for kt0 because all estimators are stopped,
> unlinked and the kt data structures for kt > 0 are empty
> and as result freed and the kthread tasks stopped (which
> happens early). After this, kt 0 calls
> ip_vs_est_drain_temp_list() as part of its loop,
> so it will eventually call ip_vs_est_add_kthread()
> and ip_vs_est_reload_start() to request kthread tasks
> to be started if data for new kthreads are created.
> So, I don't see problem here.
>
> Patch 6:
> - we will add conn_max sysctl soon
OK, just follow up on these for 1 and 6, thanks.
> Patch 7 and 8:
> - I can not decide how valid are the concerns in the review.
Placing here links for convenience:
https://sashiko.dev/#/message/20260505001648.360569-8-pablo%40netfilter.org
https://sashiko.dev/#/message/20260505001648.360569-9-pablo%40netfilter.org
This is away from my limited scope of knowledged.
^ permalink raw reply
* [PATCH net-next 13/13] dpaa2-switch: do not error out when the same VLAN is installed multiple times
From: Ioana Ciornei @ 2026-05-06 15:15 UTC (permalink / raw)
To: andrew+netdev, davem, edumazet, kuba, pabeni, netdev; +Cc: linux-kernel
In-Reply-To: <20260506151540.1242997-1-ioana.ciornei@nxp.com>
With the addition of the LAG offload support it has become apparent that
depending on the order in which a bridged bond setup is created, the
driver could be requested to add the same VLAN twice, once through the
802.1q filters and then through switchdev.
This is because any VLANs already installed on the bond device when the
bond_enslave() operation happens will also be installed on the switch
port through the .ndo_vlan_rx_add_vid() callback. Once the bond device
becomes offloaded, the same VLANs will get replayed and installed
through switchdev.
$ ip link set dev eth4 master bond1
[ 165.008131] fsl_dpaa2_switch dpsw.0 eth4: configuring for inband/usxgmii link mode
[ 165.021020] 8021q: adding VLAN 0 to HW filter on device eth4
[ 165.083351] fsl_dpaa2_switch dpsw.0 eth4: VLAN 100 already configured
RTNETLINK answers: File exists
Avoid this by not erroring out when the same VLAN is installed or
removed multiple times so that we avoid the above issue. Also remove the
netdev_err() since there isn't anything that the user can do to prevent
this behavior.
Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
---
.../net/ethernet/freescale/dpaa2/dpaa2-switch.c | 17 +++++------------
1 file changed, 5 insertions(+), 12 deletions(-)
diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
index 8353d2230c72..644f720a7ec7 100644
--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
+++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
@@ -372,10 +372,8 @@ static int dpaa2_switch_port_add_vlan(struct ethsw_port_priv *port_priv,
struct dpsw_vlan_if_cfg vcfg = {0};
int err;
- if (port_priv->vlans[vid]) {
- netdev_err(netdev, "VLAN %d already configured\n", vid);
- return -EEXIST;
- }
+ if (port_priv->vlans[vid])
+ return 0;
/* If hit, this VLAN rule will lead the packet into the FDB table
* specified in the vlan configuration below
@@ -1993,13 +1991,8 @@ int dpaa2_switch_port_vlans_add(struct net_device *netdev,
struct dpsw_attr *attr = ðsw->sw_attr;
int err = 0;
- /* Make sure that the VLAN is not already configured
- * on the switch port
- */
- if (port_priv->vlans[vlan->vid] & ETHSW_VLAN_MEMBER) {
- netdev_err(netdev, "VLAN %d already configured\n", vlan->vid);
- return -EEXIST;
- }
+ if (port_priv->vlans[vlan->vid] & ETHSW_VLAN_MEMBER)
+ return 0;
/* Check if there is space for a new VLAN */
err = dpsw_get_attributes(ethsw->mc_io, 0, ethsw->dpsw_handle,
@@ -2115,7 +2108,7 @@ static int dpaa2_switch_port_del_vlan(struct ethsw_port_priv *port_priv, u16 vid
int i, err;
if (!port_priv->vlans[vid])
- return -ENOENT;
+ return 0;
if (port_priv->vlans[vid] & ETHSW_VLAN_PVID) {
/* If we are deleting the PVID of a port, use VLAN 4095 instead
--
2.25.1
^ permalink raw reply related
* Re: [syzbot] [rdma] general protection fault in kernel_sock_shutdown (4)
From: Kuniyuki Iwashima @ 2026-05-06 15:19 UTC (permalink / raw)
To: Zhu Yanjun
Cc: syzbot, akpm, arjan, davem, dsahern, edumazet, horms, jgg, kuba,
kuni1840, leon, linux-kernel, linux-rdma, netdev, pabeni,
syzkaller-bugs, zyjzyj2000
In-Reply-To: <78183562-ff83-4b7a-9c7b-b3cb92676ee8@linux.dev>
On Wed, May 6, 2026 at 7:28 AM Zhu Yanjun <yanjun.zhu@linux.dev> wrote:
>
>
> 在 2026/5/6 6:48, syzbot 写道:
> > syzbot has found a reproducer for the following issue on:
> >
> > HEAD commit: 74fe02ce122a Merge tag 'wq-for-7.1-rc2-fixes' of git://git..
> > git tree: upstream
> > console output: https://syzkaller.appspot.com/x/log.txt?x=16e895ce580000
> > kernel config: https://syzkaller.appspot.com/x/.config?x=59da38148f3a3d24
> > dashboard link: https://syzkaller.appspot.com/bug?extid=d8f76778263ab65c2b21
> > compiler: gcc (Debian 14.2.0-19) 14.2.0, GNU ld (GNU Binutils for Debian) 2.44
> > syz repro: https://syzkaller.appspot.com/x/repro.syz?x=13a613ba580000
> >
> > Downloadable assets:
> > disk image (non-bootable): https://storage.googleapis.com/syzbot-assets/d900f083ada3/non_bootable_disk-74fe02ce.raw.xz
> > vmlinux: https://storage.googleapis.com/syzbot-assets/c0a591d96864/vmlinux-74fe02ce.xz
> > kernel image: https://storage.googleapis.com/syzbot-assets/9f94fb623cd1/bzImage-74fe02ce.xz
> >
> > IMPORTANT: if you fix the issue, please add the following tag to the commit:
> > Reported-by: syzbot+d8f76778263ab65c2b21@syzkaller.appspotmail.com
> >
> > Oops: general protection fault, probably for non-canonical address 0xdffffc000000000d: 0000 [#1] SMP KASAN NOPTI
> > KASAN: null-ptr-deref in range [0x0000000000000068-0x000000000000006f]
>
> Thanks a lot. IIRC, this problem is in process. The link is
> https://patchwork.kernel.org/project/linux-rdma/patch/20260424013759.728288-1-kuniyu@google.com/
>
> Hi, Kuniyuki Iwashima
>
> I think you are fixing this problem. I hope that we can see your commit
> very soon.
Yes, I was sidetracked but will respin v3 this week.
^ permalink raw reply
* Re: [RFC net-next 0/4] devlink: Add boot-time defaults
From: Jiri Pirko @ 2026-05-06 15:22 UTC (permalink / raw)
To: Mark Bloch
Cc: Eric Dumazet, Jakub Kicinski, Paolo Abeni, Andrew Lunn,
David S. Miller, Jonathan Corbet, Shuah Khan, Simon Horman,
Saeed Mahameed, Leon Romanovsky, Tariq Toukan, Andrew Morton,
Borislav Petkov (AMD), Randy Dunlap, Dave Hansen,
Christian Brauner, Petr Mladek, Peter Zijlstra (Intel),
Thomas Gleixner, Pawan Gupta, Dapeng Mi, Kees Cook, Marco Elver,
Eric Biggers, Li RongQing, Paul E. McKenney, linux-doc,
linux-kernel, netdev, linux-rdma
In-Reply-To: <20260506123739.1959770-1-mbloch@nvidia.com>
Wed, May 06, 2026 at 02:37:35PM +0200, mbloch@nvidia.com wrote:
>This series adds a devlink= kernel command line parameter for applying
>selected devlink settings during device initialization.
>
>Following a discussion with Jakub[1], I am sending this RFC to get the
>conversation moving. I started from Jakub's example/request and extended
>it to cover requirements from production systems and configurations that
>customers use.
>
>One important caveat is that the parsing logic in this RFC was written
>with AI assistance. I am also not sure whether the resulting syntax and
>parser are too complex for a kernel command line interface. This is part
>of why I am sending it as an RFC: to understand what direction and level
>of complexity would be acceptable to people.
>
>The implementation is intended to support the following properties:
>
>- A system may have multiple devlink devices that usually need the same
> configuration. For a configuration such as eswitch mode switchdev, a
> user should be able to specify multiple devices to which that
> configuration applies.
>
>- There may be ordering dependencies between options. For example, in
> mlx5, flow_steering_mode should be set before moving to switchdev.
> With this in mind, defaults are applied per device in the left-to-right
> order in which they appear on the command line.
>
>The intent is to let deployments set devlink defaults before normal
>userspace orchestration runs, while still using devlink concepts and
"defaults before normal userspace orchestrarion". I read it as config
before config, which eventually could be skipped.
>driver callbacks rather than adding driver-specific module parameters.
>A default is scoped to one or more devlink handles, for example:
>
> devlink=[pci/0000:08:00.0]:esw:mode:switchdev
> devlink=[pci/0000:08:00.0]:param:flow_steering_mode:smfs
> devlink=[pci/0000:08:00.0,pci/0000:08:00.1]:param:flow_steering_mode:hmfs,[pci/0000:08:00.0,pci/0000:08:00.1]:esw:mode:switchdev
I don't like this. What you do, you are basically introducing user
configuration tool on kernel cmdline.
The same you would achieve with a proper userspace tool/daemon.
I did try to come up with it and push it here:
https://github.com/systemd/systemd/pull/37393
That didn't get merged for unknown reason, but the idea is sound. You
provide configuration files for devlink object and systemd-devlinkd
will apply when they appear. Wouldn't this help your case?
[..]
^ permalink raw reply
* Re: [PATCH net 04/12] net: shaper: try to avoid violating RCU
From: Paolo Abeni @ 2026-05-06 15:22 UTC (permalink / raw)
To: Jakub Kicinski, davem
Cc: netdev, edumazet, andrew+netdev, horms, shuah, linux-kselftest
In-Reply-To: <20260506000628.1501691-5-kuba@kernel.org>
On 5/6/26 2:06 AM, Jakub Kicinski wrote:
> net_shaper_commit() overrides nodes which may be concurrently read
> under RCU. This is not a huge deal since the entries only contain
> config, worst case user will see inconsistent config params. But
> we should try to avoid this obvious RCU violation. Try to allocate
> a new node. Since commit() can't fail fall back to overriding.
>
> Full fix is probably not worth the complexity, struct net_shaper
> is around 80B, and the allocation is with GFP_KERNEL.
I'm not sure if even this variant is worthy?!? The scheduler tree dump
could be still inconsistent, as the dump is not atomic. IMHO e.g.
inconsistent weights in the same WRR group would be as bad as
inconsistent values inside the single shaper.
/P
^ permalink raw reply
* [PATCH net-next] net: usb: pegasus: replace simple_strtoul with kstrtouint
From: Sajal Gupta @ 2026-05-06 15:26 UTC (permalink / raw)
To: petkan
Cc: andrew+netdev, davem, edumazet, kuba, pabeni, linux-usb, netdev,
linux-kernel, Sajal Gupta
simple_strtoul() is deprecated as it has no error checking. Replace it
with kstrtouint() which returns an error code on invalid input, and add
appropriate error handling.
Also add a NULL check before parsing flags, since strsep() can set id
to NULL if the input has fewer tokens than expected.
Signed-off-by: Sajal Gupta <sajal2005gupta@gmail.com>
---
drivers/net/usb/pegasus.c | 26 ++++++++++++++++++++------
1 file changed, 20 insertions(+), 6 deletions(-)
diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c
index db85f40734d7..d45f08f8f22e 100644
--- a/drivers/net/usb/pegasus.c
+++ b/drivers/net/usb/pegasus.c
@@ -1327,15 +1327,29 @@ static void __init parse_id(char *id)
{
unsigned int vendor_id = 0, device_id = 0, flags = 0, i = 0;
char *token, *name = NULL;
+ int err;
- if ((token = strsep(&id, ":")) != NULL)
+ token = strsep(&id, ":");
+ if (token)
name = token;
/* name now points to a null terminated string*/
- if ((token = strsep(&id, ":")) != NULL)
- vendor_id = simple_strtoul(token, NULL, 16);
- if ((token = strsep(&id, ":")) != NULL)
- device_id = simple_strtoul(token, NULL, 16);
- flags = simple_strtoul(id, NULL, 16);
+ token = strsep(&id, ":");
+ if (token) {
+ err = kstrtouint(token, 16, &vendor_id);
+ if (err)
+ return;
+ }
+ token = strsep(&id, ":");
+ if (token) {
+ err = kstrtouint(token, 16, &device_id);
+ if (err)
+ return;
+ }
+ if (id) {
+ err = kstrtouint(id, 16, &flags);
+ if (err)
+ return;
+ }
pr_info("%s: new device %s, vendor ID 0x%04x, device ID 0x%04x, flags: 0x%x\n",
driver_name, name, vendor_id, device_id, flags);
--
2.54.0
^ permalink raw reply related
* Re: [PATCH bpf-next v4 02/12] bpf: Unify dynptr handling in the verifier
From: bot+bpf-ci @ 2026-05-06 15:27 UTC (permalink / raw)
To: ameryhung, bpf
Cc: netdev, alexei.starovoitov, andrii, daniel, eddyz87, memxor,
martin.lau, mykyta.yatsenko5, ameryhung, kernel-team, ast, andrii,
daniel, martin.lau, eddyz87, yonghong.song, clm, ihor.solodrai
In-Reply-To: <20260506142709.2298255-3-ameryhung@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 1091 bytes --]
> diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h
> index 976e2b2f40e8..f330e9cf297e 100644
> --- a/include/linux/bpf_verifier.h
> +++ b/include/linux/bpf_verifier.h
> @@ -1376,6 +1376,13 @@ struct bpf_map_desc {
> int uid;
> };
>
> +/* The last initialized dynptr; Populated by process_dynptr_func() */
> +struct bpf_dynptr_desc {
> + enum bpf_dynptr_type type;
> + u32 id;
> + u32 ref_obj_id;
> +};
> +
A review comment from Mykyta Yatsenko requested that a comment be added
to the ref_obj_id field explaining what it's for:
https://lore.kernel.org/bpf/87ikb2tkta.fsf@gmail.com/
The author mentioned in v3 that comments for id, ref_obj_id, and parent_id
would be added in a later refactor patch. However, should this struct have
inline documentation now for clarity, particularly for the ref_obj_id field?
[ ... ]
---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md
CI run summary: https://github.com/kernel-patches/bpf/actions/runs/25442456702
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox