Netdev List
 help / color / mirror / Atom feed
* Re: [PATCH net-next v2 2/2] net: phy: add DAPU Telecom DAP8210R(I) Gigabit Ethernet PHY driver
From: Maxime Chevallier @ 2026-07-16 13:01 UTC (permalink / raw)
  To: Artem Shimko, netdev, Andrew Lunn, Heiner Kallweit, Russell King,
	David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: linux-kernel, devicetree
In-Reply-To: <20260716113805.593215-3-a.shimko.dev@gmail.com>

Hi,

On 7/16/26 13:38, Artem Shimko wrote:
> Add a new PHY driver for the DAPU Telecom DAP8211R(I) Gigabit
> Ethernet PHY, which is commonly used in enterprise and industrial
> networking applications.
> 
> The driver implements extended register access via indirect addressing
> through corresponding registers, and provides comprehensive device tree
> support for RGMII delay configuration. The rx-internal-delay-ps and
> tx-internal-delay-ps properties allow precise tuning of clock delays in
> 150 ps steps from 0 to 2250 ps. Additionally, the optional
> dapu,tx-inverted-clk flag enables 180-degree TX clock phase shift for
> boards where signal integrity or MAC requirements necessitate clock
> inversion.
> 
> Signed-off-by: Artem Shimko <a.shimko.dev@gmail.com>
> ---
>  drivers/net/phy/Kconfig    |  10 ++
>  drivers/net/phy/Makefile   |   1 +
>  drivers/net/phy/dap8211r.c | 281 +++++++++++++++++++++++++++++++++++++
>  3 files changed, 292 insertions(+)
>  create mode 100644 drivers/net/phy/dap8211r.c
> 
> diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
> index 099f25dceabb..4576f707ac94 100644
> --- a/drivers/net/phy/Kconfig
> +++ b/drivers/net/phy/Kconfig
> @@ -237,6 +237,16 @@ config DAVICOM_PHY
>  	help
>  	  Currently supports dm9161e and dm9131
>  
> +config DAP8211R_PHY
> +	tristate "DAPU Telecom DAP8211R(I) Gigabit Ethernet PHY"
> +	depends on OF
> +	help
> +	  Support for the DAPU Telecom DAP8211R(I) Gigabit Ethernet PHY.
> +	  This PHY is designed for enterprise and industrial networking
> +	  applications, supporting 10/100/1000 Mbps operation.
> +	  RGMII with: configurable TX/RX clock delays, optional flag to enable
> +	  180-degree TX clock phase shift and internal packet generator.
> +
>  config ICPLUS_PHY
>  	tristate "ICPlus PHYs"
>  	help
> diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
> index de660ae94945..ad35733eb4bb 100644
> --- a/drivers/net/phy/Makefile
> +++ b/drivers/net/phy/Makefile
> @@ -53,6 +53,7 @@ obj-$(CONFIG_BROADCOM_PHY)	+= broadcom.o
>  obj-$(CONFIG_CICADA_PHY)	+= cicada.o
>  obj-$(CONFIG_CORTINA_PHY)	+= cortina.o
>  obj-$(CONFIG_DAVICOM_PHY)	+= davicom.o
> +obj-$(CONFIG_DAP8211R_PHY)	+= dap8211r.o
>  obj-$(CONFIG_DP83640_PHY)	+= dp83640.o
>  obj-$(CONFIG_DP83822_PHY)	+= dp83822.o
>  obj-$(CONFIG_DP83848_PHY)	+= dp83848.o
> diff --git a/drivers/net/phy/dap8211r.c b/drivers/net/phy/dap8211r.c
> new file mode 100644
> index 000000000000..e1e6a322ef0c
> --- /dev/null
> +++ b/drivers/net/phy/dap8211r.c
> @@ -0,0 +1,281 @@
> +// SPDX-License-Identifier: GPL
> +/*
> + * Driver for the DAPU Telecom DAP8211R(I) Gigabit Ethernet PHY.
> + *
> + * Specifications:
> + *   - IEEE 802.3 10BASE-Te, 100BASE-TX, 1000BASE-T
> + *   - IEEE 802.3az-2010 Energy Efficient Ethernet
> + *   - IEEE 1588 SyncE support
> + *   - RGMII
> + *
> + * Author: Artem Shimko <a.shimko.dev@gmail.com>
> + */
> +
> +#include <linux/bitfield.h>
> +#include <linux/errno.h>
> +#include <linux/ethtool.h>
> +#include <linux/kernel.h>
> +#include <linux/mii.h>
> +#include <linux/module.h>
> +#include <linux/netdevice.h>
> +#include <linux/of.h>
> +#include <linux/phy.h>
> +
> +#define DAP8211R_PHY_ID			0x0008011B
> +#define DAP8211R_PHY_ID_MASK		0xFFFFFFFF
> +
> +#define DAP8211R_EXT_ADD		0x1E
> +#define DAP8211R_EXT_DATA		0x1F
> +
> +#define DAP8211R_PHY_CON		0xA001
> +#define DAP8211R_PHY_SW_RST		BIT(15)
> +
> +#define DAP8211R_RGMII_CON		0xA003
> +#define DAP8211R_RGMII_TX_DEL_MASK	GENMASK(3, 0)
> +#define DAP8211R_RGMII_RX_DEL_MASK	GENMASK(13, 10)
> +#define DAP8211R_RGMII_CLK_INVERT	BIT(14)
> +
> +/* Default RGMII delay: 13 * 150 == 1.95ns */
> +#define DAP8211R_DEFAULT_DELAY_SEL	0xD
> +
> +struct dap8211r_delay_config {
> +	u32 ps;
> +	u8 sel;
> +};
> +
> +static const struct dap8211r_delay_config delay_config[] = {
> +	{   0, 0},
> +	{ 150, 1},
> +	{ 300, 2},
> +	{ 450, 3},
> +	{ 600, 4},
> +	{ 750, 5},
> +	{ 900, 6},
> +	{1050, 7},
> +	{1200, 8},
> +	{1350, 9},
> +	{1500, 10},
> +	{1650, 11},
> +	{1800, 12},
> +	{1950, 13},
> +	{2100, 14},
> +	{2250, 15},
> +};
> +
> +#define DAP8211R_DELAY_COUNT	ARRAY_SIZE(delay_config)
> +
> +/**
> + * dap8211r_delay_ps_to_sel() - Convert ps to register value (exact match only)
> + * @ps: Delay in picoseconds
> + *
> + * Converts a delay value in picoseconds to the corresponding register value
> + * for RGMII delay configuration. The PHY supports specific values from
> + * 0 to 2250 ps in 150 ps steps.
> + *
> + * Return: Register value (0-15) on success, -EINVAL if @ps is not supported.
> + */
> +
> +static int dap8211r_delay_ps_to_sel(u32 ps)
> +{
> +	for (int i = 0; i < DAP8211R_DELAY_COUNT; i++)
> +		if (ps == delay_config[i].ps)
> +			return delay_config[i].sel;
> +
> +	return -EINVAL;
> +}
> +
> +/**
> + * dap8211r_read_ext() - Read extended register
> + * @phydev: PHY device structure
> + * @reg: Extended register address
> + *
> + * Reads a PHY extended register using the indirect access method.
> + * The caller must hold the MDIO bus lock.
> + *
> + * Return: Register value on success, or negative error code
> + */
> +static int dap8211r_read_ext(struct phy_device *phydev, u16 reg)
> +{
> +	int ret;
> +
> +	phy_lock_mdio_bus(phydev);
> +	ret = __phy_write(phydev, DAP8211R_EXT_ADD, reg);
> +	if (ret < 0)
> +		goto out;
> +
> +	ret = __phy_read(phydev, DAP8211R_EXT_DATA);
> +out:
> +	phy_unlock_mdio_bus(phydev);
> +	return ret;
> +}
> +
> +/**
> + * dap8211r_modify_ext() - Modify extended register bits
> + * @phydev: PHY device structure
> + * @reg: Extended register address
> + * @mask: Bit mask of bits to clear
> + * @set: Bit mask of bits to set
> + *
> + * Modifies a PHY extended register using the indirect access method.
> + * New value = (old value & ~mask) | set.
> + * The caller must hold the MDIO bus lock.
> + *
> + * Return: 0 on success, or negative error code
> + */
> +static int dap8211r_modify_ext(struct phy_device *phydev, u16 reg, u16 mask, u16 set)
> +{
> +	int ret;
> +
> +	phy_lock_mdio_bus(phydev);
> +	ret = __phy_write(phydev, DAP8211R_EXT_ADD, reg);
> +	if (ret < 0)
> +		goto out;
> +
> +	ret = __phy_modify(phydev, DAP8211R_EXT_DATA, mask, set);
> +out:
> +	phy_unlock_mdio_bus(phydev);
> +	return ret;
> +}
> +
> +/**
> + * dap8211r_get_rgmii_delay() - Get RGMII delay from DT
> + * @phydev: PHY device
> + * @prop_name: DT property name
> + * @is_id: If phy mode is PHY_INTERFACE_MODE_RGMII_[TXID,RXID,ID]
> + *
> + * Reads the RGMII delay from the device tree. If the property is not
> + * specified, the default delay (1950ps) is used.
> + *
> + * Return: Register value (0-15) on success, negative error code on failure.
> + *	   -EINVAL: Property not specified and is_id is false.
> + */
> +static int dap8211r_get_rgmii_delay(struct phy_device *phydev, const char *prop_name, bool is_id)
> +{
> +	struct device_node *np = phydev->mdio.dev.of_node;
> +	u32 ps = 0;
> +	int ret;
> +
> +	ret = of_property_read_u32(np, prop_name, &ps);
> +	if (ret == -EINVAL)
> +		return (is_id) ? DAP8211R_DEFAULT_DELAY_SEL : ret;
> +	if (ret < 0)
> +		return ret;
> +
> +	return dap8211r_delay_ps_to_sel(ps);
> +}
> +
> +/**
> + * dap8211r_config_init() - Initialize PHY
> + * @phydev: PHY device structure
> + *
> + * Configures the PHY during initialization:
> + * - RGMII delays based on interface mode
> + * - TX clock invertion
> + * - Software reset to apply settings (low active, self clear)
> + *
> + * Return: 0 on success, or negative error code
> + */
> +static int dap8211r_config_init(struct phy_device *phydev)
> +{
> +	struct device_node *phydev_node = phydev->mdio.dev.of_node;
> +	u16 mask = 0, set = 0;
> +	int ret, retries = 10;
> +
> +	switch (phydev->interface) {
> +	case PHY_INTERFACE_MODE_RGMII:
> +		ret = dap8211r_get_rgmii_delay(phydev, "rx-internal-delay-ps", false);
> +		if (ret >= 0) {
> +			set = FIELD_PREP(DAP8211R_RGMII_RX_DEL_MASK, ret);
> +			mask = DAP8211R_RGMII_RX_DEL_MASK;
> +		} else if ((ret < 0) && (ret != -EINVAL)) {
> +			return ret;
> +		}
> +
> +		ret = dap8211r_get_rgmii_delay(phydev, "tx-internal-delay-ps", false);
> +		if (ret >= 0) {
> +			set |= FIELD_PREP(DAP8211R_RGMII_TX_DEL_MASK, ret);
> +			mask |= DAP8211R_RGMII_TX_DEL_MASK;
> +		} else if ((ret < 0) && (ret != -EINVAL)) {
> +			return ret;
> +		}
> +		break;
> +	case PHY_INTERFACE_MODE_RGMII_RXID:
> +		ret = dap8211r_get_rgmii_delay(phydev, "rx-internal-delay-ps", true);
> +		if (ret < 0)
> +			return ret;
> +
> +		set = FIELD_PREP(DAP8211R_RGMII_RX_DEL_MASK, ret);
> +		mask = DAP8211R_RGMII_RX_DEL_MASK;
> +		break;
> +	case PHY_INTERFACE_MODE_RGMII_ID:
> +		ret = dap8211r_get_rgmii_delay(phydev, "rx-internal-delay-ps", true);
> +		if (ret < 0)
> +			return ret;
> +
> +		set = FIELD_PREP(DAP8211R_RGMII_RX_DEL_MASK, ret);
> +		mask = DAP8211R_RGMII_RX_DEL_MASK;
> +		fallthrough;
> +	case PHY_INTERFACE_MODE_RGMII_TXID:
> +		ret = dap8211r_get_rgmii_delay(phydev, "tx-internal-delay-ps", true);
> +		if (ret < 0)
> +			return ret;
> +
> +		set |= FIELD_PREP(DAP8211R_RGMII_TX_DEL_MASK, ret);
> +		mask |= DAP8211R_RGMII_TX_DEL_MASK;
> +		break;
> +	default:
> +		phydev_err(phydev, "Unsupported interface: %d\n",
> +			   phydev->interface);
> +		return -EINVAL;
> +	}

You can simplify the whole delay parsing a log by using phy_get_internal_delay().
It will give you the index of the delay from the delay table you have :)

https://elixir.bootlin.com/linux/v7.1.3/source/drivers/net/phy/phy_device.c#L3085

You can take a look at the few drivers that use it (mscc, dp83869) for reference

Maxime

^ permalink raw reply

* [PATCH net-next 5/7] phonet: pep: convert getsockopt to sockopt_t
From: Breno Leitao @ 2026-07-16 13:00 UTC (permalink / raw)
  To: sdf, David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Alexander Aring, Stefan Schmidt, Miquel Raynal,
	Remi Denis-Courmont, Rémi Denis-Courmont, John Fastabend,
	Sabrina Dubroca, Shuah Khan
  Cc: netdev, linux-kernel, linux-wpan, linux-kselftest, Breno Leitao,
	kernel-team
In-Reply-To: <20260716-getsockopt_phase4-v1-0-4f45cb12dce7@debian.org>

Continue converting the proto-layer getsockopt callbacks to the
sockopt_t interface, splitting pep_getsockopt() into a
do_pep_getsockopt() helper that takes a sockopt_t.

The thin pep_getsockopt() wrapper keeps its __user signature for now:
it builds a user-backed sockopt_t with sockopt_init_user(), calls the
helper, and writes the returned length back to optlen. The helper uses
copy_to_iter() instead of copy_to_user(). No functional change.

Signed-off-by: Breno Leitao <leitao@debian.org>
---
 net/phonet/pep.c | 36 ++++++++++++++++++++++++++----------
 1 file changed, 26 insertions(+), 10 deletions(-)

diff --git a/net/phonet/pep.c b/net/phonet/pep.c
index 60d1a5375725b..c7f4ce894af56 100644
--- a/net/phonet/pep.c
+++ b/net/phonet/pep.c
@@ -1078,17 +1078,11 @@ static int pep_setsockopt(struct sock *sk, int level, int optname,
 	return err;
 }
 
-static int pep_getsockopt(struct sock *sk, int level, int optname,
-				char __user *optval, int __user *optlen)
+static int do_pep_getsockopt(struct sock *sk, int optname, sockopt_t *opt)
 {
 	struct pep_sock *pn = pep_sk(sk);
 	int len, val;
 
-	if (level != SOL_PNPIPE)
-		return -ENOPROTOOPT;
-	if (get_user(len, optlen))
-		return -EFAULT;
-
 	switch (optname) {
 	case PNPIPE_ENCAP:
 		val = pn->ifindex ? PNPIPE_ENCAP_IP : PNPIPE_ENCAP_NONE;
@@ -1112,11 +1106,33 @@ static int pep_getsockopt(struct sock *sk, int level, int optname,
 		return -ENOPROTOOPT;
 	}
 
-	len = min_t(unsigned int, sizeof(int), len);
-	if (put_user(len, optlen))
+	len = min_t(unsigned int, sizeof(int), opt->optlen);
+	opt->optlen = len;
+	if (copy_to_iter(&val, len, &opt->iter_out) != len)
 		return -EFAULT;
-	if (copy_to_user(optval, &val, len))
+	return 0;
+}
+
+static int pep_getsockopt(struct sock *sk, int level, int optname,
+			  char __user *optval, int __user *optlen)
+{
+	sockopt_t opt;
+	int err;
+
+	if (level != SOL_PNPIPE)
+		return -ENOPROTOOPT;
+
+	err = sockopt_init_user(&opt, optval, optlen);
+	if (err)
+		return err;
+
+	err = do_pep_getsockopt(sk, optname, &opt);
+	if (err)
+		return err;
+
+	if (put_user(opt.optlen, optlen))
 		return -EFAULT;
+
 	return 0;
 }
 

-- 
2.53.0-Meta


^ permalink raw reply related

* [PATCH net-next 4/7] phonet: pep: do not write beyond optlen in getsockopt
From: Breno Leitao @ 2026-07-16 13:00 UTC (permalink / raw)
  To: sdf, David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Alexander Aring, Stefan Schmidt, Miquel Raynal,
	Remi Denis-Courmont, Rémi Denis-Courmont, John Fastabend,
	Sabrina Dubroca, Shuah Khan
  Cc: netdev, linux-kernel, linux-wpan, linux-kselftest, Breno Leitao,
	kernel-team
In-Reply-To: <20260716-getsockopt_phase4-v1-0-4f45cb12dce7@debian.org>

pep_getsockopt() clamps the reported length to the caller's buffer with
min_t(), but then stores the value with put_user(val, (int __user *)
optval), which always writes sizeof(int) bytes. A getsockopt() call with
an optlen smaller than sizeof(int) thus reports the clamped length yet
writes a full int, one to three bytes past the user buffer.

Write the value with copy_to_user() bounded by len, so at most optlen
bytes are copied, matching the length reported back to userspace.

Fixes: 02a47617cdce ("Phonet: implement GPRS virtual interface over PEP socket")
Signed-off-by: Breno Leitao <leitao@debian.org>
---
 net/phonet/pep.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/phonet/pep.c b/net/phonet/pep.c
index 7069271393933..60d1a5375725b 100644
--- a/net/phonet/pep.c
+++ b/net/phonet/pep.c
@@ -1115,7 +1115,7 @@ static int pep_getsockopt(struct sock *sk, int level, int optname,
 	len = min_t(unsigned int, sizeof(int), len);
 	if (put_user(len, optlen))
 		return -EFAULT;
-	if (put_user(val, (int __user *) optval))
+	if (copy_to_user(optval, &val, len))
 		return -EFAULT;
 	return 0;
 }

-- 
2.53.0-Meta


^ permalink raw reply related

* [PATCH net-next 3/7] ieee802154: convert dgram getsockopt to sockopt_t
From: Breno Leitao @ 2026-07-16 13:00 UTC (permalink / raw)
  To: sdf, David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Alexander Aring, Stefan Schmidt, Miquel Raynal,
	Remi Denis-Courmont, Rémi Denis-Courmont, John Fastabend,
	Sabrina Dubroca, Shuah Khan
  Cc: netdev, linux-kernel, linux-wpan, linux-kselftest, Breno Leitao,
	kernel-team
In-Reply-To: <20260716-getsockopt_phase4-v1-0-4f45cb12dce7@debian.org>

Continue converting the proto-layer getsockopt callbacks to the sockopt_t
interface, splitting dgram_getsockopt() into a do_dgram_getsockopt() helper
that takes a sockopt_t.

No functional change.

Signed-off-by: Breno Leitao <leitao@debian.org>
---
 net/ieee802154/socket.c | 38 ++++++++++++++++++++++++++------------
 1 file changed, 26 insertions(+), 12 deletions(-)

diff --git a/net/ieee802154/socket.c b/net/ieee802154/socket.c
index 85dce296d7513..763f63e48afe4 100644
--- a/net/ieee802154/socket.c
+++ b/net/ieee802154/socket.c
@@ -831,20 +831,12 @@ static int ieee802154_dgram_deliver(struct net_device *dev, struct sk_buff *skb)
 	return ret;
 }
 
-static int dgram_getsockopt(struct sock *sk, int level, int optname,
-			    char __user *optval, int __user *optlen)
+static int do_dgram_getsockopt(struct sock *sk, int optname, sockopt_t *opt)
 {
 	struct dgram_sock *ro = dgram_sk(sk);
-
 	int val, len;
 
-	if (level != SOL_IEEE802154)
-		return -EOPNOTSUPP;
-
-	if (get_user(len, optlen))
-		return -EFAULT;
-
-	len = min_t(unsigned int, len, sizeof(int));
+	len = min_t(unsigned int, opt->optlen, sizeof(int));
 
 	switch (optname) {
 	case WPAN_WANTACK:
@@ -871,10 +863,32 @@ static int dgram_getsockopt(struct sock *sk, int level, int optname,
 		return -ENOPROTOOPT;
 	}
 
-	if (put_user(len, optlen))
+	opt->optlen = len;
+	if (copy_to_iter(&val, len, &opt->iter_out) != len)
 		return -EFAULT;
-	if (copy_to_user(optval, &val, len))
+	return 0;
+}
+
+static int dgram_getsockopt(struct sock *sk, int level, int optname,
+			    char __user *optval, int __user *optlen)
+{
+	sockopt_t opt;
+	int err;
+
+	if (level != SOL_IEEE802154)
+		return -EOPNOTSUPP;
+
+	err = sockopt_init_user(&opt, optval, optlen);
+	if (err)
+		return err;
+
+	err = do_dgram_getsockopt(sk, optname, &opt);
+	if (err)
+		return err;
+
+	if (put_user(opt.optlen, optlen))
 		return -EFAULT;
+
 	return 0;
 }
 

-- 
2.53.0-Meta


^ permalink raw reply related

* [PATCH net-next 2/7] ipv6: raw: convert do_rawv6_getsockopt to sockopt_t
From: Breno Leitao @ 2026-07-16 13:00 UTC (permalink / raw)
  To: sdf, David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Alexander Aring, Stefan Schmidt, Miquel Raynal,
	Remi Denis-Courmont, Rémi Denis-Courmont, John Fastabend,
	Sabrina Dubroca, Shuah Khan
  Cc: netdev, linux-kernel, linux-wpan, linux-kselftest, Breno Leitao,
	kernel-team
In-Reply-To: <20260716-getsockopt_phase4-v1-0-4f45cb12dce7@debian.org>

Convert do_rawv6_getsockopt to the new sockopt_t model, mirroring what
we have in ipv4. The overall goal is to move these callbacks gradually
from __user points to use sockopt_t, and this part touches
do_rawv6_getsockopt.

No functional change.

Signed-off-by: Breno Leitao <leitao@debian.org>
---
 net/ipv6/raw.c | 27 +++++++++++++++++++--------
 1 file changed, 19 insertions(+), 8 deletions(-)

diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index 99eec36796fb9..1f15942d14163 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -1051,14 +1051,12 @@ static int rawv6_setsockopt(struct sock *sk, int level, int optname,
 	return do_rawv6_setsockopt(sk, level, optname, optval, optlen);
 }
 
-static int do_rawv6_getsockopt(struct sock *sk, int optname,
-			       char __user *optval, int __user *optlen)
+static int do_rawv6_getsockopt(struct sock *sk, int optname, sockopt_t *opt)
 {
 	struct raw6_sock *rp = raw6_sk(sk);
 	int val, len;
 
-	if (get_user(len, optlen))
-		return -EFAULT;
+	len = opt->optlen;
 
 	switch (optname) {
 	case IPV6_HDRINCL:
@@ -1082,9 +1080,8 @@ static int do_rawv6_getsockopt(struct sock *sk, int optname,
 
 	len = min_t(unsigned int, sizeof(int), len);
 
-	if (put_user(len, optlen))
-		return -EFAULT;
-	if (copy_to_user(optval, &val, len))
+	opt->optlen = len;
+	if (copy_to_iter(&val, len, &opt->iter_out) != len)
 		return -EFAULT;
 	return 0;
 }
@@ -1092,6 +1089,9 @@ static int do_rawv6_getsockopt(struct sock *sk, int optname,
 static int rawv6_getsockopt(struct sock *sk, int level, int optname,
 			  char __user *optval, int __user *optlen)
 {
+	sockopt_t opt;
+	int err;
+
 	switch (level) {
 	case SOL_RAW:
 		break;
@@ -1109,7 +1109,18 @@ static int rawv6_getsockopt(struct sock *sk, int level, int optname,
 		return ipv6_getsockopt(sk, level, optname, optval, optlen);
 	}
 
-	return do_rawv6_getsockopt(sk, optname, optval, optlen);
+	err = sockopt_init_user(&opt, optval, optlen);
+	if (err)
+		return err;
+
+	err = do_rawv6_getsockopt(sk, optname, &opt);
+	if (err)
+		return err;
+
+	if (put_user(opt.optlen, optlen))
+		return -EFAULT;
+
+	return 0;
 }
 
 static int rawv6_ioctl(struct sock *sk, int cmd, int *karg)

-- 
2.53.0-Meta


^ permalink raw reply related

* [PATCH net-next 1/7] ipv6: raw: drop unused level argument from do_rawv6_getsockopt
From: Breno Leitao @ 2026-07-16 12:59 UTC (permalink / raw)
  To: sdf, David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Alexander Aring, Stefan Schmidt, Miquel Raynal,
	Remi Denis-Courmont, Rémi Denis-Courmont, John Fastabend,
	Sabrina Dubroca, Shuah Khan
  Cc: netdev, linux-kernel, linux-wpan, linux-kselftest, Breno Leitao,
	kernel-team
In-Reply-To: <20260716-getsockopt_phase4-v1-0-4f45cb12dce7@debian.org>

do_rawv6_getsockopt() takes a level argument but never uses it; the
level dispatch is handled by the caller, rawv6_getsockopt(). Drop it,
matching ipv4's do_raw_getsockopt().

No functional change.

Signed-off-by: Breno Leitao <leitao@debian.org>
---
 net/ipv6/raw.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index 3cc58698cbbd3..99eec36796fb9 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -1051,8 +1051,8 @@ static int rawv6_setsockopt(struct sock *sk, int level, int optname,
 	return do_rawv6_setsockopt(sk, level, optname, optval, optlen);
 }
 
-static int do_rawv6_getsockopt(struct sock *sk, int level, int optname,
-			    char __user *optval, int __user *optlen)
+static int do_rawv6_getsockopt(struct sock *sk, int optname,
+			       char __user *optval, int __user *optlen)
 {
 	struct raw6_sock *rp = raw6_sk(sk);
 	int val, len;
@@ -1109,7 +1109,7 @@ static int rawv6_getsockopt(struct sock *sk, int level, int optname,
 		return ipv6_getsockopt(sk, level, optname, optval, optlen);
 	}
 
-	return do_rawv6_getsockopt(sk, level, optname, optval, optlen);
+	return do_rawv6_getsockopt(sk, optname, optval, optlen);
 }
 
 static int rawv6_ioctl(struct sock *sk, int cmd, int *karg)

-- 
2.53.0-Meta


^ permalink raw reply related

* [PATCH net-next 0/7] net: convert rawv6, ieee802154, phonet and tls getsockopt to sockopt_t
From: Breno Leitao @ 2026-07-16 12:59 UTC (permalink / raw)
  To: sdf, David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Alexander Aring, Stefan Schmidt, Miquel Raynal,
	Remi Denis-Courmont, Rémi Denis-Courmont, John Fastabend,
	Sabrina Dubroca, Shuah Khan
  Cc: netdev, linux-kernel, linux-wpan, linux-kselftest, Breno Leitao,
	kernel-team

Now that sockopt_init_user() was already merged, builds a user-backed
sockopt_t from the __user pair. A getsockopt leaf can then take
a sockopt_t behind a thin __user wrapper: the wrapper builds it, calls
the leaf, and writes the length back to optlen. The leaf copies with
copy_to_iter() instead of copy_to_user().

Convert four more leaves the way udp and raw already were: ipv6 raw
(do_rawv6_getsockopt), ieee802154 dgram, phonet pep, and tls
(do_tls_getsockopt and its per-option helpers). 

Converting phonet surfaced a pre-existing bug: pep_getsockopt() clamps the
length it reports but writes a full int with put_user(), overrunning an
optval buffer shorter than sizeof(int). It is fixed in its own patch, with
a Fixes: tag, before the phonet conversion, so it can be backported alone.

The last patch adds getsockopt_iter selftest fixtures for rawv6,
ieee802154, phonet and tls, checking the returned length and errno across
exact, oversized and short buffers, an unknown optname and a bad level.

For full motivation about these changes, please check the initial thread
at link
https://lore.kernel.org/all/20260401-getsockopt-v2-0-611df6771aff@debian.org/#t

Signed-off-by: Breno Leitao <leitao@debian.org>
---
Breno Leitao (7):
      ipv6: raw: drop unused level argument from do_rawv6_getsockopt
      ipv6: raw: convert do_rawv6_getsockopt to sockopt_t
      ieee802154: convert dgram getsockopt to sockopt_t
      phonet: pep: do not write beyond optlen in getsockopt
      phonet: pep: convert getsockopt to sockopt_t
      tls: convert getsockopt to sockopt_t
      selftests: net: getsockopt_iter: cover rawv6, ieee802154, phonet and tls

 net/ieee802154/socket.c                       |  38 ++-
 net/ipv6/raw.c                                |  27 +-
 net/phonet/pep.c                              |  36 ++-
 net/tls/tls_main.c                            |  80 +++--
 tools/testing/selftests/net/getsockopt_iter.c | 424 ++++++++++++++++++++++++++
 5 files changed, 533 insertions(+), 72 deletions(-)
---
base-commit: f6f3b36c15ed44de1fbb44e645e4fae8c4a4453e
change-id: 20260715-getsockopt_phase4-180209cfc60a

Best regards,
--  
Breno Leitao <leitao@debian.org>


^ permalink raw reply

* Re: [PATCH v4 net-next 3/7] selftests/ptp: Add testptp support for attributes ioctls
From: saeed bishara @ 2026-07-16 13:00 UTC (permalink / raw)
  To: Arthur Kiyanovski
  Cc: David Miller, Jakub Kicinski, netdev, Richard Cochran,
	Eric Dumazet, Paolo Abeni, David Woodhouse, Thomas Gleixner,
	Miroslav Lichvar, Andrew Lunn, Wen Gu, Xuan Zhuo, David Woodhouse,
	Yonatan Sarna, Zorik Machulsky, Alexander Matushevsky,
	Saeed Bshara, Matt Wilson, Anthony Liguori, Nafea Bshara,
	Evgeny Schmeilin, Netanel Belgazal, Ali Saidi,
	Benjamin Herrenschmidt, Noam Dagan, David Arinzon,
	Evgeny Ostrovsky, Ofir Tabachnik, Amit Bernstein, linux-kselftest,
	linux-doc, shuah, Jonathan Corbet, Shuah Khan, Simon Horman,
	vadim.fedorenko
In-Reply-To: <20260714020340.25014-4-akiyano@amazon.com>

>                 " -t val     shift the ptp clock time by 'val' seconds\n"
>                 " -T val     set the ptp clock time to 'val' seconds\n"
>                 " -x val     get an extended ptp clock time with the desired number of samples (up to %d)\n"
> +               " -a val     get extended timestamps with attributes (error_bound,\n"
timestamps -> ptp clock to be consistent
also, have you considered making the "-a" additional flag to -x and -A
instead of an exclusive option?


> +               printf("sample #%2d: unknown clock %d %s: %lld.%09u\n",
> +                      sample_num, clockid, when, sec, nsec);
In the case of an unknown clock, will the additional parameters
(when/sec/..) be useful?

>                 break;
>         }
>  }
> @@ -188,6 +193,7 @@ int main(int argc, char *argv[])
>         struct ptp_sys_offset *sysoff;
>         struct ptp_sys_offset_extended *soe;
>         struct ptp_sys_offset_precise *xts;
> +       struct ptp_sys_offset_attrs *attrs_data;
>
>         char *progname;
>         unsigned int i;
> @@ -208,7 +214,9 @@ int main(int argc, char *argv[])
>         int list_pins = 0;
>         int pct_offset = 0;
>         int getextended = 0;
> +       int getextendedattrs = 0;
>         int getcross = 0;
> +       int getcrossattrs = 0;
>         int n_samples = 0;
>         int pin_index = -1, pin_func;
>         int pps = -1;
> @@ -226,7 +234,8 @@ int main(int argc, char *argv[])
>
>         progname = strrchr(argv[0], '/');
>         progname = progname ? 1+progname : argv[0];
> -       while (EOF != (c = getopt(argc, argv, "cd:e:E:f:F:ghH:i:k:lL:n:o:p:P:rsSt:T:w:x:Xy:z"))) {
> +       while (EOF != (c = getopt(argc, argv,
> +                                 "a:Acd:e:E:f:F:ghH:i:k:lL:n:o:p:P:rsSt:T:w:x:Xy:z"))) {
>                 switch (c) {
>                 case 'c':
>                         capabilities = 1;
> @@ -311,9 +320,22 @@ int main(int argc, char *argv[])
>                                 return -1;
>                         }
>                         break;
> +               case 'a':
> +                       getextendedattrs = atoi(optarg);
> +                       if (getextendedattrs < 1 ||
> +                           getextendedattrs > PTP_MAX_SAMPLES) {
> +                               fprintf(stderr,
> +                                       "number of extended attrs timestamp samples must be between 1 and %d; was asked for %d\n",
> +                                       PTP_MAX_SAMPLES, getextendedattrs);
> +                               return -1;
> +                       }
> +                       break;
>                 case 'X':
>                         getcross = 1;
>                         break;
> +               case 'A':
> +                       getcrossattrs = 1;
> +                       break;
>                 case 'y':
>                         if (!strcasecmp(optarg, "realtime"))
>                                 ext_clockid = CLOCK_REALTIME;
> @@ -367,6 +389,8 @@ int main(int argc, char *argv[])
>                                "  %d programmable pins\n"
>                                "  %d cross timestamping\n"
>                                "  %d adjust_phase\n"
> +                              "  %d extended_attrs\n"
> +                              "  %d precise_attrs\n"
>                                "  %d maximum phase adjustment (ns)\n",
>                                caps.max_adj,
>                                caps.n_alarm,
> @@ -376,6 +400,8 @@ int main(int argc, char *argv[])
>                                caps.n_pins,
>                                caps.cross_timestamping,
>                                caps.adjust_phase,
> +                              caps.extended_attrs,
> +                              caps.precise_attrs,
>                                caps.max_phase_adj);
>                 }
>         }
> @@ -648,6 +674,49 @@ int main(int argc, char *argv[])
>                 free(soe);
>         }
>
> +       if (getextendedattrs) {
> +               attrs_data = calloc(1, sizeof(*attrs_data) +
> +                                   getextendedattrs * sizeof(struct ptp_timestamp));
> +               if (!attrs_data) {
> +                       perror("calloc");
> +                       return -1;
> +               }
> +
> +               attrs_data->request.num_samples = getextendedattrs;
> +               attrs_data->request.clock_id = ext_clockid;
> +
> +               if (ioctl(fd, PTP_SYS_OFFSET_EXTENDED_ATTRS, attrs_data)) {
> +                       perror("PTP_SYS_OFFSET_EXTENDED_ATTRS");
> +               } else {
> +                       printf("extended attrs timestamp request returned %d samples\n",
> +                              getextendedattrs);
> +
> +                       for (i = 0; i < getextendedattrs; i++) {
> +                               struct ptp_timestamp *ts = &attrs_data->timestamps[i];
> +
> +                               printf("  sample #%u:\n", i);
> +                               printf("    sys before: %lld ns\n",
> +                                      (long long)ts->pre_systime.sys_time);
> +                               printf("    phc time:   %lld.%09u\n",
> +                                      ts->devtime.device_time.sec,
> +                                      ts->devtime.device_time.nsec);
> +                               if (ts->devtime.attrs.valid & PTP_ATTRS_VALID_ERROR_BOUND)
> +                                       printf("    error_bound: %u ns\n",
> +                                              ts->devtime.attrs.error_bound);
in case device doesn't report error bound, I think it's better to
print explicit message

^ permalink raw reply

* Re: [PATCH RFC net-next 3/6] bpf: Allow skb extensions to survive packet scrubbing
From: Jakub Sitnicki @ 2026-07-16 12:59 UTC (permalink / raw)
  To: Stanislav Fomichev, Daniel Borkmann, John Fastabend
  Cc: netdev, bpf, kernel-team, Jakub Kicinski, Kuniyuki Iwashima
In-Reply-To: <aljKKt6nCB3fjFVA@devvm7509.cco0.facebook.com>

On Thu, Jul 16, 2026 at 05:11 AM -07, Stanislav Fomichev wrote:
> On 07/14, Jakub Sitnicki wrote:
>> skb_scrub_packet() drops all skb extensions unconditionally via
>> skb_ext_reset(). It runs on tunnel encap/decap (ip_tunnel_rcv,
>> vxlan_rcv, etc.) and cross-netns forwarding (dev_forward_skb).
>> 
>> This makes it impossible for a BPF program to pass metadata via
>> bpf_skb_ext through a tunnel or across a netns boundary. The extension
>> is always lost at the scrub point.
>> 
>> Introduce skb_ext_scrub() which consults each active extension before
>> discarding it. Extensions that request preservation are kept while the
>> rest are torn down. When the extension slab is shared with clones, COW
>> ensures isolation. Replace the skb_ext_reset() call in
>> skb_scrub_packet() with skb_ext_scrub().
>> 
>> Expose the opt-in mechanism to BPF via the BPF_SKB_EXT_F_NO_SCRUB flag
>> for bpf_dynptr_from_skb_ext(). A program that sets this flag when
>> creating the extension signals that its metadata should survive
>> scrubbing.
>> 
>> Signed-off-by: Jakub Sitnicki <jakub@cloudflare.com>
>> ---
>>  include/linux/bpf.h      |  1 +
>>  include/linux/skbuff.h   |  2 ++
>>  include/uapi/linux/bpf.h |  3 +-
>>  net/core/filter.c        | 11 +++++--
>>  net/core/skbuff.c        | 82 ++++++++++++++++++++++++++++++++++++++++++------
>>  net/ipv4/udp.c           |  2 +-
>>  6 files changed, 86 insertions(+), 15 deletions(-)
>> 
>> diff --git a/include/linux/bpf.h b/include/linux/bpf.h
>> index 6b918a5b61bf..a46ca53c5b27 100644
>> --- a/include/linux/bpf.h
>> +++ b/include/linux/bpf.h
>> @@ -4214,6 +4214,7 @@ static inline int bpf_map_check_op_flags(struct bpf_map *map, u64 flags, u64 all
>>  #ifdef CONFIG_BPF_SKB_EXT
>>  
>>  struct bpf_skb_ext {
>> +	u64 flags;
>>  	u8 buf[CONFIG_BPF_SKB_EXT_SIZE] __aligned(8);
>>  };
>>  
>> diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
>> index 584d8440d352..66afa5489007 100644
>> --- a/include/linux/skbuff.h
>> +++ b/include/linux/skbuff.h
>> @@ -5063,6 +5063,7 @@ void *__skb_ext_set(struct sk_buff *skb, enum skb_ext_id id,
>>  void *skb_ext_add(struct sk_buff *skb, enum skb_ext_id id);
>>  void __skb_ext_del(struct sk_buff *skb, enum skb_ext_id id);
>>  void __skb_ext_put(struct skb_ext *ext);
>> +void skb_ext_scrub(struct sk_buff *skb);
>>  
>>  static inline void skb_ext_put(struct sk_buff *skb)
>>  {
>> @@ -5132,6 +5133,7 @@ static inline bool skb_has_extensions(struct sk_buff *skb)
>>  static inline void __skb_ext_put(struct skb_ext *ext) {}
>>  static inline void skb_ext_put(struct sk_buff *skb) {}
>>  static inline void skb_ext_reset(struct sk_buff *skb) {}
>> +static inline void skb_ext_scrub(struct sk_buff *skb) {}
>>  static inline void skb_ext_del(struct sk_buff *skb, int unused) {}
>>  static inline void __skb_ext_copy(struct sk_buff *d, const struct sk_buff *s) {}
>>  static inline void skb_ext_copy(struct sk_buff *dst, const struct sk_buff *s) {}
>> diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
>> index 3eee4467422d..02da170205de 100644
>> --- a/include/uapi/linux/bpf.h
>> +++ b/include/uapi/linux/bpf.h
>> @@ -7734,7 +7734,8 @@ struct bpf_insn_array_value {
>>  
>>  /* Flags to control bpf_dynptr_from_skb_ext() behavior. */
>>  enum {
>> -	BPF_SKB_EXT_F_CREATE = (1ULL << 0),
>> +	BPF_SKB_EXT_F_CREATE	= (1ULL << 0),
>> +	BPF_SKB_EXT_F_NO_SCRUB	= (1ULL << 1),
>
> Do I understand correctly that you do prefer the NO_SCRUB mode? Any reason
> we need to have scrub mode? If it's all produced/consumed by bpf, maybe
> we can just carry this data unconditionally instead of having a SCRUB/NO_SCRUB
> option?

Yes, that's correct. We definitely need NO_SCRUB but I don't have a use
case that relies on metadata scrubbing. I believe Kuniyuki also would
like the no-scrub to be the only/default behavior for Google's egress
use case.

I've made it an opt-out mostly because that the existing metadata
(skb->mark, skb->data_meta) gets scrubbed. Although as Jakub K has
pointed out to me - you can circumvent it by using bpf_redirect into the
target netns. So I guess we have a precendent?

I could use input from folks operating in K8S-like environments, if
no-scrub-only mode would be acceptable there? Daniel, John, any opinion?


^ permalink raw reply

* Re: [BUG] vlan: skb_under_panic when toggling NETIF_F_HW_VLAN_CTAG_TX on lower device
From: Eric Dumazet @ 2026-07-16 12:53 UTC (permalink / raw)
  To: xietangxin
  Cc: David S . Miller, Jakub Kicinski, Paolo Abeni, Simon Horman,
	netdev, linux-kernel, John Fastabend, Jesse Gross, gaoxingwang1,
	huyizhen
In-Reply-To: <99d678ae-c7b2-4b44-b534-b8320679deb3@h-partners.com>

On Thu, Jul 16, 2026 at 2:20 PM xietangxin <xietangxin@h-partners.com> wrote:
>
> [BUG] vlan: skb_under_panic when toggling NETIF_F_HW_VLAN_CTAG_TX on lower device
>
> Hi all,
>
> We encountered a skb_under_panic triggered by toggling
> NETIF_F_HW_VLAN_CTAG_TX on the lower device while a VLAN device is
> up and sending traffic.
>
> Call trace
> ==========
>
>  skbuff: skb_under_panic: text:ffffc0d2900283d8 len:74 put:14
>   head:ffff334820249c00 data:ffff334820249bfe tail:0x48 end:0xc0 dev:vlan4
>  ------------[ cut here ]------------
>  kernel BUG at net/core/skbuff.c:116!
>  Internal error: Oops - BUG: 00000000f2000800 [#1] SMP
>  Call trace:
>   skb_panic+0xcc/0xd0
>   __skb_checksum+0x0/0x480
>   eth_header+0x48/0x1a0
>   vlan_dev_hard_header+0xd0/0x284
>   neigh_connected_output+0x16c/0x20c
>   ip6_finish_output2+0x4b4/0xd74
>   __ip6_finish_output.part.0+0x1ac/0x3b0
>   ip6_finish_output+0x160/0x200
>   ip6_output+0x13c/0x294
>   ndisc_send_skb+0x41c/0x6f0
>   ndisc_send_rs+0xac/0x3b0
>   addrconf_rs_timer+0x42c/0x660
>   call_timer_fn+0x54/0x290
>   expire_timers+0x26c/0x420
>
> Reproducer
> ==========
>
>  # Create veth pair (NETIF_F_HW_VLAN_CTAG_TX is ON by default)
>  ip link add veth0 type veth peer name veth1
>  ip link set veth0 up
>  ip link set veth1 up
>
>  # Turn off HW VLAN TX offload on lower device
>  ethtool -K veth0 tx-vlan-hw-insert off
>
>  # Create VLAN device on veth0
>  # At this point: header_ops = &vlan_header_ops, hard_header_len = 18
>  ip link add link veth0 name veth0.10 type vlan id 10 reorder_hdr off
>  ip addr add 192.168.10.1/24 dev veth0.10
>  ip link set veth0.10 up
>
>  # Turn HW VLAN TX offload back ON on lower device
>  # This triggers NETDEV_FEAT_CHANGE -> vlan_transfer_features()
>  # hard_header_len changes from 18 to 14, but header_ops is NOT updated
>  ethtool -K veth0 tx-vlan-hw-insert on
>
>  # When a packet is sent through veth0.10
>  # - skb is allocated based on hard_header_len=14 -> ~16 bytes
>  # - vlan_dev_hard_header() pushes VLAN_HLEN(4) + ETH_HLEN(14) = 18 bytes
>  # - skb_under_panic!
>
>
> Any feedback or guidance would be greatly appreciated.

This rings a bell, I thought we already fixed this issue long ago :/

I would suggest we always add VLAN_HLEN even if not (yet) needed.

diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
index 2b74ed56eb166d52c3351768d9dfedc7b2c8ec2d..d7f90b3b2bb3aadb2c466891720a7f407d0bc34b
100644
--- a/net/8021q/vlan.c
+++ b/net/8021q/vlan.c
@@ -323,10 +323,7 @@ static void vlan_transfer_features(struct net_device *dev,

        netif_inherit_tso_max(vlandev, dev);

-       if (vlan_hw_offload_capable(dev->features, vlan->vlan_proto))
-               vlandev->hard_header_len = dev->hard_header_len;
-       else
-               vlandev->hard_header_len = dev->hard_header_len + VLAN_HLEN;
+       vlandev->hard_header_len = dev->hard_header_len + VLAN_HLEN;

 #if IS_ENABLED(CONFIG_FCOE)
        vlandev->fcoe_ddp_xid = dev->fcoe_ddp_xid;

A kind-of-similar change is needed in net/8021q/vlan_dev.c

^ permalink raw reply

* Re: [PATCH net] mac802154: flush rx_mac_cmd_list before freeing sdata
From: Simon Horman @ 2026-07-16 12:49 UTC (permalink / raw)
  To: security
  Cc: Simon Horman, alex.aring, stefan, miquel.raynal, davem, edumazet,
	kuba, pabeni, linux-wpan, netdev, linux-kernel, stable
In-Reply-To: <20260710111353.12138-1-security@auditcode.ai>

This is an AI-generated review of your patch. The human sending this
email has considered the AI review valid, or at least plausible.
https://netdev-ai.bots.linux.dev/sashiko/
---
mac802154: flush rx_mac_cmd_list before freeing sdata

This patch adds mac802154_flush_queued_mac_cmds() and calls it from
ieee802154_if_remove() and ieee802154_unregister_hw() to drain
local->rx_mac_cmd_list before sdata is freed, aiming to close a KASAN
use-after-free in mac802154_rx_mac_cmd_worker().

> diff --git a/net/mac802154/iface.c b/net/mac802154/iface.c
> index b823720630e7..59a045cccfe9 100644
> --- a/net/mac802154/iface.c
> +++ b/net/mac802154/iface.c
> @@ -694,6 +694,16 @@ void ieee802154_if_remove(struct ieee802154_sub_if_data *sdata)
>  	mutex_unlock(&sdata->local->iflist_mtx);
>  
>  	synchronize_rcu();
> +
> +	/*
> +	 * Drop any rx_mac_cmd_list entry still pointing at this sdata
> +	 * before it is freed below: mac802154_rx_mac_cmd_worker() runs
> +	 * asynchronously on local->mac_wq and derefs mac_pkt->sdata with
> +	 * no liveness check of its own (see mac802154_flush_queued_mac_cmds()
> +	 * for details).
> +	 */
> +	mac802154_flush_queued_mac_cmds(sdata->local, sdata);
> +
>  	unregister_netdevice(sdata->dev);
>  }

[High]
When ieee802154_if_remove() runs to delete one interface, does anything
stop RX softirq on sibling interfaces of the same phy from concurrently
enqueueing into local->rx_mac_cmd_list while the flush is walking it?

The producer path is ieee802154_subif_frame(), reached from the RX
tasklet under rcu_read_lock only, and it unconditionally does:

    mac_pkt->sdata = sdata;
    list_add_tail(&mac_pkt->node, &sdata->local->rx_mac_cmd_list);
    queue_work(sdata->local->mac_wq, &sdata->local->rx_mac_cmd_work);

with no lock on rx_mac_cmd_list. list_del_rcu() + synchronize_rcu()
above only quiesces the sdata being removed; other sdata on the same
local remain in local->interfaces and can keep receiving MAC-command
frames on other CPUs throughout the flush.

> diff --git a/net/mac802154/main.c b/net/mac802154/main.c
> index ea1efef3572a..2f8c57e78db1 100644
> --- a/net/mac802154/main.c
> +++ b/net/mac802154/main.c
> @@ -277,6 +277,17 @@ void ieee802154_unregister_hw(struct ieee802154_hw *hw)
>  	tasklet_kill(&local->tasklet);
>  	flush_workqueue(local->workqueue);
>  
> +	/*
> +	 * tasklet_kill() above stops any further frame reaching
> +	 * ieee802154_subif_frame(), but mac802154_rx_mac_cmd_worker() may
> +	 * still be queued/running on local->mac_wq and derefs the sdata of
> +	 * every interface ieee802154_remove_interfaces() is about to free
> +	 * below. flush_workqueue(local->workqueue) does not cover it --
> +	 * that is the DATA workqueue, not local->mac_wq -- so drain it
> +	 * explicitly first.
> +	 */
> +	mac802154_flush_queued_mac_cmds(local, NULL);
> +
>  	rtnl_lock();
>  
>  	ieee802154_remove_interfaces(local);

[High]
Does tasklet_kill() actually stop any further frame from reaching
ieee802154_subif_frame() here?

tasklet_kill() clears TASKLET_STATE_SCHED and waits for a running
instance to finish, but it does not prevent a subsequent
tasklet_schedule() from a driver's ieee802154_rx_irqsafe() path. If a
driver interrupt fires between mac802154_flush_queued_mac_cmds(local,
NULL) and destroy_workqueue(local->mac_wq) further down, a new
mac_pkt would be added to rx_mac_cmd_list, the worker would be queued
on local->mac_wq, and it would then run against sdatas already freed
by ieee802154_remove_interfaces().

Note this call site also runs before rtnl_lock() a few lines below,
which is relevant to the kernel-doc comment quoted further down.

> diff --git a/net/mac802154/rx.c b/net/mac802154/rx.c
> index cd8f2a11920d..0b167f76cb23 100644
> --- a/net/mac802154/rx.c
> +++ b/net/mac802154/rx.c
> @@ -128,6 +128,48 @@ void mac802154_rx_mac_cmd_worker(struct work_struct *work)
>  	kfree(mac_pkt);
>  }
>  
> +/**
> + * mac802154_flush_queued_mac_cmds - drop pending rx_mac_cmd_list work
> + * @local: the mac802154 device the queue belongs to
> + * @sdata: interface being torn down, or %NULL to flush unconditionally
> + *
> + * Every queued &struct cfg802154_mac_pkt stashes a raw pointer to the
> + * interface it was received on (see ieee802154_subif_frame() below) which
> + * mac802154_rx_mac_cmd_worker() dereferences without ever checking whether
> + * that interface is still alive. Callers must invoke this before freeing
> + * @sdata -- or every interface on @local, when @sdata is %NULL -- so the
> + * worker can never run against freed memory:
> + *
> + *  - cancel_work_sync() waits out a run already in flight. That is still
> + *    safe to let finish because nothing has been freed yet, and it blocks
> + *    any new run from starting for as long as we hold the RTNL.

[Low]
Is this description of cancel_work_sync() accurate?

cancel_work_sync() only guarantees the work is not pending or executing
by the time it returns, and does not itself block future queue_work()
calls. RTNL is not held at the ieee802154_unregister_hw() call site
(the flush is invoked before rtnl_lock() there), and at the
ieee802154_if_remove() site RTNL is a plain mutex that does not disable
BH and does not serialize with the RX softirq path
ieee802154_tasklet_handler() -> ieee802154_rx() ->
__ieee802154_rx_handle_packet() -> ieee802154_subif_frame(), which is
what enqueues into rx_mac_cmd_list and re-arms rx_mac_cmd_work via
queue_work(local->mac_wq, ...).

Could this comment be reworded to describe an invariant the code
actually provides?

> + *  - every list entry pointing at @sdata (all of them, if @sdata is NULL)
> + *    is then dropped so no future run of the worker can see it.
> + *
> + * Mirrors mac802154_flush_queued_beacons() in scan.c, which does not need
> + * the cancel_work_sync() step because its worker never dereferences sdata.
> + */
> +void mac802154_flush_queued_mac_cmds(struct ieee802154_local *local,
> +				     struct ieee802154_sub_if_data *sdata)
> +{
> +	struct cfg802154_mac_pkt *mac_pkt, *tmp;
> +
> +	cancel_work_sync(&local->rx_mac_cmd_work);
> +
> +	list_for_each_entry_safe(mac_pkt, tmp, &local->rx_mac_cmd_list, node) {
> +		if (sdata && mac_pkt->sdata != sdata)
> +			continue;
> +
> +		list_del(&mac_pkt->node);
> +		kfree_skb(mac_pkt->skb);
> +		kfree(mac_pkt);
> +	}
> +
> +	/* Other interfaces on @local may still have entries pending. */
> +	if (!list_empty(&local->rx_mac_cmd_list))
> +		queue_work(local->mac_wq, &local->rx_mac_cmd_work);
> +}

[High]
Given that ieee802154_subif_frame() can still be entered from softirq on
sibling interfaces after cancel_work_sync() returns, what protects
rx_mac_cmd_list during this iteration?

The producer does:

    list_add_tail(&mac_pkt->node, &sdata->local->rx_mac_cmd_list);
    queue_work(sdata->local->mac_wq, &sdata->local->rx_mac_cmd_work);

with no lock. cancel_work_sync() does not block a subsequent
queue_work(), so mac802154_rx_mac_cmd_worker() can start on another CPU
while this function is still iterating. The worker does
list_first_entry_or_null() + list_del() on the same list, and the
iterator here pre-loads tmp = list_next_entry(pos) each round.

Under that shape, could a concurrent list_del() from the worker on the
head entry (a) target the same entry the flush is about to delete
(double kfree() of mac_pkt), (b) free the entry that tmp points at
(use-after-free inside the flush loop), or (c) race with a
list_add_tail() from the producer softirq and leave neighbour pointers
inconsistent?

The trailing:

    if (!list_empty(&local->rx_mac_cmd_list))
        queue_work(local->mac_wq, &local->rx_mac_cmd_work);

also reads list state and re-arms the worker without any lock, which is
a TOCTOU against a softirq list_add_tail() on the same list.

Would either a spin_lock_bh() around every rx_mac_cmd_list mutation
plus the queue_work() (matching the softirq producer), or preventing
new enqueues for the sdata being torn down in ieee802154_subif_frame()
before the flush runs, close this window?

Also, in the multi-interface case ieee802154_if_remove() only quiesces
the sdata being removed with synchronize_rcu(); does this fix actually
address the scenario the commit message describes, where MAC_CMD
traffic is arriving on a sibling interface of the same phy during
NL802154_CMD_DEL_INTERFACE?

^ permalink raw reply

* [PATCH net-next V2] net: axienet: Clear stale AXI DMA TX/RX status before re-enabling interrupts
From: Kusuma Vasana @ 2026-07-16 12:48 UTC (permalink / raw)
  To: radhey.shyam.pandey, andrew+netdev, davem, edumazet, kuba, pabeni,
	michal.simek, Kusuma.Vasana
  Cc: git, linux-arm-kernel, linux-kernel, netdev

The AXI DMA interrupt line is level-sensitive: it asserts whenever
the IOC (XAXIDMA_IRQ_IOC_MASK) or DELAY (XAXIDMA_IRQ_DELAY_MASK) bits
in the status register (XAXIDMA_TX_SR_OFFSET / XAXIDMA_RX_SR_OFFSET)
are set and their corresponding enable bits in the control register
are active.

During TX/RX, interrupts are disabled in the control register while
NAPI runs. Completions arriving in this window cause hardware to latch
IOC/DELAY into the status register regardless of the control register
mask state. After NAPI completion, re-enabling interrupts immediately
re-asserts the IRQ line due to these stale status register bits, even
when no new work is pending.

This results in a stale interrupt and redundant NAPI poll cycle with
no new work pending, causing unnecessary CPU processing.

In the initial driver, the status register was cleared after polling
all packets, which naturally consumed any status accumulated during
processing. When the driver was converted to NAPI, status register
clearing was moved to the ISR before polling begins, leaving no
mechanism to clear status bits that arrive during the NAPI poll window.

Fix this by unconditionally clearing interrupt status bits before
re-enabling interrupts in the NAPI poll handlers.

Signed-off-by: Kusuma Vasana <kusuma.vasana@amd.com>
Reviewed-by: Radhey Shyam Pandey <radhey.shyam.pandey@amd.com>
---
Changes in V2 :

-Added net-next prefix in the subject
-Updated the commit description

---
 drivers/net/ethernet/xilinx/xilinx_axienet_main.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
index fcf517069d16..29050c8d04e2 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
@@ -1018,6 +1018,13 @@ static int axienet_tx_poll(struct napi_struct *napi, int budget)
 			netif_wake_queue(ndev);
 	}
 
+	/* Clear stale IOC/DELAY bits that may have latched during the
+	 * poll window to prevent a stale interrupt when there is no
+	 * work pending.
+	 */
+	axienet_dma_out32(lp, XAXIDMA_TX_SR_OFFSET,
+			  XAXIDMA_IRQ_IOC_MASK | XAXIDMA_IRQ_DELAY_MASK);
+
 	if (packets < budget && napi_complete_done(napi, packets)) {
 		/* Re-enable TX completion interrupts. This should
 		 * cause an immediate interrupt if any TX packets are
@@ -1293,6 +1300,13 @@ static int axienet_rx_poll(struct napi_struct *napi, int budget)
 		cur_p = &lp->rx_bd_v[lp->rx_bd_ci];
 	}
 
+	/* Clear stale IOC/DELAY bits that may have latched during the
+	 * poll window to prevent a stale interrupt when there is no
+	 * work pending.
+	 */
+	axienet_dma_out32(lp, XAXIDMA_RX_SR_OFFSET,
+			  XAXIDMA_IRQ_IOC_MASK | XAXIDMA_IRQ_DELAY_MASK);
+
 	u64_stats_update_begin(&lp->rx_stat_sync);
 	u64_stats_add(&lp->rx_packets, packets);
 	u64_stats_add(&lp->rx_bytes, size);
-- 
2.43.0


^ permalink raw reply related

* Re: Please apply 736b380e28d0 and eca856950f7c down to 6.1.y
From: Salvatore Bonaccorso @ 2026-07-16 12:46 UTC (permalink / raw)
  To: Wongi Lee, Greg Kroah-Hartman
  Cc: stable, Sasha Levin, netdev, David Ahern, Ido Schimmel,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Jungwoo Lee
In-Reply-To: <akJ9gzZrhXMUomcg@eldamar.lan>

Hi Greg,

On Mon, Jun 29, 2026 at 04:13:23PM +0200, Salvatore Bonaccorso wrote:
> Hi Greg,
> 
> On Wed, Jun 24, 2026 at 06:44:00PM +0900, Wongi Lee wrote:
> > On Wed, Jun 24, 2026 at 11:37:29AM +0200, Greg Kroah-Hartman wrote:
> > > On Wed, Jun 24, 2026 at 06:30:03PM +0900, Wongi Lee wrote:
> > > > On Wed, Jun 24, 2026 at 11:00:45AM +0200, Greg Kroah-Hartman wrote:
> > > > > On Wed, Jun 24, 2026 at 05:14:38PM +0900, Wongi Lee wrote:
> > > > > > Hi,
> > > > > > 
> > > > > > Could the following upstream commits be queued for the active stable
> > > > > > trees?
> > > > > > 
> > > > > >   commit 736b380e28d0480c7bc3e022f1950f31fe53a7c5
> > > > > >   ("ipv6: account for fraggap on the paged allocation path")
> > > > > 
> > > > > I do not see that commit id in Linus's tree, are you sure it is correct?
> > > > > 
> > > > > >   commit eca856950f7cb1a221e02b99d758409f2c5cec42
> > > > > >   ("ipv4: account for fraggap on the paged allocation path")
> > > > > 
> > > > > Same here, no id of that one in Linus's tree that I can see.
> > > > > 
> > > > > thanks,
> > > > > 
> > > > > greg k-h
> > > > 
> > > > 
> > > > Hi Greg,
> > > > 
> > > > First, sorry for confusing you.
> > > > 
> > > > The commit IDs are from netdev/net.git:
> > > > 
> > > >   736b380e28d0480c7bc3e022f1950f31fe53a7c5
> > > >   https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net.git/commit/?id=736b380e28d0
> > > > 
> > > >   eca856950f7cb1a221e02b99d758409f2c5cec42
> > > >   https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net.git/commit/?id=eca856950f7c
> > > > 
> > > > They were applied to netdev without Cc: stable@vger.kernel.org, so I
> > > > wanted to flag them for stable handling but I send it too fast (before
> > > > merge).
> > > > 
> > > > I will resend the request with the Linus tree commit ID.
> > > 
> > > They have to be in Linus's tree, before we can take them in a stable
> > > release, right?
> > > 
> > > And why were they not originally tagged with the cc: stable?  That would
> > > save you time in the future as it would all just happen automatically.
> > > 
> > > thanks,
> > > 
> > > greg k-h
> > 
> > Right, my fault.
> > 
> > Also I just forgot cc'ing stable when sending it. I'll apply it next time.
> 
> Small heads-up: Both commits are now in Linus' tree and included in
> v7.2-rc1:
> 
> $ git describe --contains 736b380e28d0480c7bc3e022f1950f31fe53a7c5
> v7.2-rc1~29^2~66^2
> $ git describe --contains eca856950f7cb1a221e02b99d758409f2c5cec42
> v7.2-rc1~29^2~66^2~1
> 
> Can you queue those as needed down to the 6.1.y stable series?

Can you still pick this as well for 6.1.y? The upstream commit
eca856950f7cb1a221e02b99d758409f2c5cec42 does not apply cleanly to
6.1.y but this is just because it deletes a comment (the second hunk),
which was never added to 6.1.y.

Regards,
Salvatore

^ permalink raw reply

* Re: [PATCH RFC net-next 1/6] bpf: Introduce per-packet metadata storage for BPF programs
From: Jakub Sitnicki @ 2026-07-16 12:35 UTC (permalink / raw)
  To: Stanislav Fomichev; +Cc: netdev, bpf, kernel-team
In-Reply-To: <aljJ1u-_1CBBF8Ha@devvm7509.cco0.facebook.com>

On Thu, Jul 16, 2026 at 05:10 AM -07, Stanislav Fomichev wrote:
> On 07/14, Jakub Sitnicki wrote:
>> BPF programs attached at different points in the network stack have no way
>> to pass data between each other on a per-packet basis, other than by
>> stashing it into a shared BPF map. xdp/skb->data_meta works for XDP-to-TC
>> handoff, but is not available to programs running at later hooks like
>> cgroup/skb, sock_ops, socket filters, tracing or LSM.
>> 
>> Add a new skb extension (struct bpf_skb_ext) that provides up to 256 bytes
>> of per-packet storage. Size is configurable at build time though the
>> CONFIG_BPF_SKB_EXT_SIZE option. The storage is embedded inside the
>> extension chunk itself.
>> 
>> Expose the storage to BPF programs via bpf_dynptr_from_skb_ext() kfunc.
>> The caller passes BPF_SKB_EXT_F_CREATE to allocate or COW (unshare) the
>> extension and get a read-write dynptr. Without the flag, it gets a
>> read-only dynptr to the existing extension, or -ENOENT if none exists.
>> 
>> Guard the feature behind a new CONFIG_BPF_SKB_EXT option.
>> 
>> Signed-off-by: Jakub Sitnicki <jakub@cloudflare.com>
>> ---
>>  include/linux/bpf.h      |  10 ++++
>>  include/linux/filter.h   |  26 ++++++++++
>>  include/linux/skbuff.h   |   3 ++
>>  include/uapi/linux/bpf.h |   5 ++
>>  kernel/bpf/helpers.c     |   7 +++
>>  kernel/bpf/log.c         |   2 +
>>  kernel/bpf/verifier.c    |  10 +++-
>>  net/Kconfig              |  20 ++++++++
>>  net/core/filter.c        | 129 +++++++++++++++++++++++++++++++++++++++++++++++
>>  net/core/skbuff.c        |   3 ++
>>  10 files changed, 214 insertions(+), 1 deletion(-)
>> 
>> diff --git a/include/linux/bpf.h b/include/linux/bpf.h
>> index 7719f6528445..6b918a5b61bf 100644
>> --- a/include/linux/bpf.h
>> +++ b/include/linux/bpf.h
>> @@ -1484,6 +1484,8 @@ enum bpf_dynptr_type {
>>  	BPF_DYNPTR_TYPE_SKB_META,
>>  	/* Underlying data is a file */
>>  	BPF_DYNPTR_TYPE_FILE,
>> +	/* Underlying data is a bpf_skb_ext chunk */
>> +	BPF_DYNPTR_TYPE_SKB_EXT,
>>  };
>>  
>>  int bpf_dynptr_check_size(u64 size);
>> @@ -4209,4 +4211,12 @@ static inline int bpf_map_check_op_flags(struct bpf_map *map, u64 flags, u64 all
>>  	return 0;
>>  }
>>  
>> +#ifdef CONFIG_BPF_SKB_EXT
>> +
>> +struct bpf_skb_ext {
>> +	u8 buf[CONFIG_BPF_SKB_EXT_SIZE] __aligned(8);
>> +};
>
> Can we do a dynamic size from the start? Say, some sysfs knob, 0 by
> default. Once written, it's locks in the size and can't be changed.
> Then your new 'flags' field can be used to indicate whether the area
> actually has been allocated or not?

Thanks for feedback. Dynamic size would be ideal.

We're limited by skb extensions implementation here, which needs to know
the (maximum) size of each skb extension chunk at init time [1].

That said, there's been hallway discussion at Netdev, that we should
look into making skb_ext allocate memory just for activated extensions
and realloc as needed, as extensions are gaining more users.

Current implementation (allocate space for every available extension) is
wasteful, as you have extension combos which are not possible (won't be
active at the same time), like IPsec and MPTCP and CAN.

IOW, build-time config is what is doable today. Having a sysctl knob
doesn't buy us much. But we have a path to lift that constraint later
(if we don't mess up the BPF API).

[1] https://elixir.bootlin.com/linux/v7.2-rc3/source/net/core/skbuff.c#L5171

^ permalink raw reply

* Re: [PATCH bpf-next v5 8/8] selftests: net: add test for XDP_PASS skb checksum invalidation
From: Stanislav Fomichev @ 2026-07-16 12:30 UTC (permalink / raw)
  To: Lorenzo Bianconi
  Cc: Donald Hunter, Jakub Kicinski, David S. Miller, Eric Dumazet,
	Paolo Abeni, Simon Horman, Alexei Starovoitov, Daniel Borkmann,
	Jesper Dangaard Brouer, John Fastabend, Stanislav Fomichev,
	Andrew Lunn, Tony Nguyen, Przemek Kitszel, Alexander Lobakin,
	Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman, Song Liu,
	Yonghong Song, KP Singh, Hao Luo, Jiri Olsa, Shuah Khan,
	Maciej Fijalkowski, Jonathan Corbet, Shuah Khan,
	Kumar Kartikeya Dwivedi, Emil Tsalapatis, Vladimir Vdovin,
	Jakub Sitnicki, netdev, bpf, intel-wired-lan, linux-kselftest,
	linux-doc
In-Reply-To: <20260715-bpf-xdp-meta-rxcksum-v5-8-623d5c0d0ab7@kernel.org>

On 07/15, Lorenzo Bianconi wrote:
> Add a test that verifies skb->ip_summed is set to CHECKSUM_NONE
> when a device running in XDP mode creates an skb from a xdp_buff
> if the attached ebpf program returns an XDP_PASS.
> The test attaches an XDP program returning XDP_PASS, and a TC
> ingress program that runs the bpf_skb_rx_checksum() kfunc to
> inspect the resulting skb. After XDP_PASS the driver must invalidate
> any previously computed hardware RX checksum since XDP may have
> modified the packet data.
> The BPF program counts packets per checksum type in a map, and the
> test runner verifies that after sending traffic the CHECKSUM_NONE
> counter is non-zero while CHECKSUM_UNNECESSARY and CHECKSUM_COMPLETE
> counters are zero.
> 
> Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
> ---
>  Documentation/networking/xdp-rx-metadata.rst       |  5 ++
>  .../selftests/drivers/net/hw/xdp_metadata.py       | 55 +++++++++++++++-
>  .../selftests/net/lib/skb_metadata_csum.bpf.c      | 73 ++++++++++++++++++++++
>  3 files changed, 132 insertions(+), 1 deletion(-)
> 
> diff --git a/Documentation/networking/xdp-rx-metadata.rst b/Documentation/networking/xdp-rx-metadata.rst
> index 93918b3769a3..7434ac98242a 100644
> --- a/Documentation/networking/xdp-rx-metadata.rst
> +++ b/Documentation/networking/xdp-rx-metadata.rst
> @@ -90,6 +90,11 @@ conversion, and the XDP metadata is not used by the kernel when building
>  ``skbs``. However, TC-BPF programs can access the XDP metadata area using
>  the ``data_meta`` pointer.

[..]

> +If a driver is running in XDP mode, any existing hardware RX checksum
> +(``CHECKSUM_UNNECESSARY`` or ``CHECKSUM_COMPLETE``) must be invalidated
> +by setting ``skb->ip_summed`` to ``CHECKSUM_NONE`` before passing the
> +skb to the kernel, since XDP may have modified the packet data.
> +
>  In the future, we'd like to support a case where an XDP program
>  can override some of the metadata used for building ``skbs``.

Sorry for keeping nitpicking on this, but I'm still not convinced that
it is what we currently do. From my previous reply:

> > Looking at a few drivers:
> > - bnxt (bnxt_rx_pkt) does UNNECESSARY - ok
> > - mlx5 (mlx5e_handle_csum) does UNNECESSARY and skips COMPLETE if there is
> >   bpf prog attached
> > - fbnic (fbnic_rx_csum) - can do COMPLETE even with xdp attached?
> > - gve (gve_rx) - can do COMPLETE even with xdp attached?

(although for gve I might be wrong, there is also gve_rx_skb_csum that only
does UNNECESSARY).

I'd wait for Jakub to chime in, but it feels like we should just document
what we currently do as a recommended approach: for the drivers
that support COMPLETE, do not report it when the bpf program is attached.
Both NONE and UNNECESSARY are ok.

Also, did you run this test on real HW? NIPA now has HW tests, maybe it
makes sense to route this series via net-next to get the real coverage?

^ permalink raw reply

* Re: ipv4: icmp: icmp_route_lookup() relookups pick wrong netdev with policy routing + strict rp_filter
From: Eric Dumazet @ 2026-07-16 12:29 UTC (permalink / raw)
  To: Muhammad Ziad
  Cc: netdev, David Ahern, Jakub Kicinski, Paolo Abeni, David S. Miller,
	linux-kernel
In-Reply-To: <CANn89iJ+M_r-c3iGK1o7_pLBTVF-s5_R-8MjL3=Q0Aj=1a4deQ@mail.gmail.com>

On Thu, Jul 16, 2026 at 1:22 PM Eric Dumazet <edumazet@google.com> wrote:
>
> On Thu, Jul 16, 2026 at 12:40 PM Muhammad Ziad <muhzi100@gmail.com> wrote:
> >
> > Thank you for the fix, Eric. Applying the other selectors from skb_in
> > makes sense to me, but I'm not sure if instead we should copy them
> > from fl4_dec?
> >
> > The mark param e.g. is gated by IP4_REPLY_MARK() on fwmark_reflect,
> > which could be different from skb_in->mark.
> >
>
> Yes, sashiko had some remarks.
>
> I have been playing with:
>
> diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
> index 23e921d313b36b00d8ae5e14846527220c9db32b..b0eb4f8ff9867499dc3a96c92a414440b2d3a115
> 100644
> --- a/net/ipv4/icmp.c
> +++ b/net/ipv4/icmp.c
> @@ -548,10 +548,12 @@ static struct rtable *icmp_route_lookup(struct
> net *net, struct flowi4 *fl4,
>                 if (IS_ERR(rt2))
>                         err = PTR_ERR(rt2);
>         } else {
> -               struct flowi4 fl4_2 = {};
> +               struct flowi4 fl4_2 = fl4_dec;
>                 unsigned long orefdst;
>
>                 fl4_2.daddr = fl4_dec.saddr;
> +               fl4_2.saddr = fl4_dec.daddr;
> +               fl4_2.flowi4_oif = l3mdev_master_ifindex(route_lookup_dev);
>                 rt2 = ip_route_output_key(net, &fl4_2);
>                 if (IS_ERR(rt2)) {
>                         err = PTR_ERR(rt2);
>
>

Or even better:

diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index 23e921d313b36b00d8ae5e14846527220c9db32b..aaaa0e347702c4412ff515a9d0589c79c69c62d1
100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -548,10 +548,13 @@ static struct rtable *icmp_route_lookup(struct
net *net, struct flowi4 *fl4,
                if (IS_ERR(rt2))
                        err = PTR_ERR(rt2);
        } else {
-               struct flowi4 fl4_2 = {};
+               struct flowi4 fl4_2 = fl4_dec;
                unsigned long orefdst;

-               fl4_2.daddr = fl4_dec.saddr;
+               swap(fl4_2.daddr, fl4_2.saddr);
+               swap(fl4_2.fl4_sport, fl4_2.fl4_dport);
+
+               fl4_2.flowi4_oif = l3mdev_master_ifindex(route_lookup_dev);
                rt2 = ip_route_output_key(net, &fl4_2);
                if (IS_ERR(rt2)) {
                        err = PTR_ERR(rt2);

^ permalink raw reply

* [BUG] vlan: skb_under_panic when toggling NETIF_F_HW_VLAN_CTAG_TX on lower device
From: xietangxin @ 2026-07-16 12:20 UTC (permalink / raw)
  To: David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni
  Cc: Simon Horman, netdev, linux-kernel, John Fastabend, Jesse Gross,
	gaoxingwang1, huyizhen

[BUG] vlan: skb_under_panic when toggling NETIF_F_HW_VLAN_CTAG_TX on lower device

Hi all,

We encountered a skb_under_panic triggered by toggling
NETIF_F_HW_VLAN_CTAG_TX on the lower device while a VLAN device is
up and sending traffic.

Call trace
==========

 skbuff: skb_under_panic: text:ffffc0d2900283d8 len:74 put:14
  head:ffff334820249c00 data:ffff334820249bfe tail:0x48 end:0xc0 dev:vlan4
 ------------[ cut here ]------------
 kernel BUG at net/core/skbuff.c:116!
 Internal error: Oops - BUG: 00000000f2000800 [#1] SMP
 Call trace:
  skb_panic+0xcc/0xd0
  __skb_checksum+0x0/0x480
  eth_header+0x48/0x1a0
  vlan_dev_hard_header+0xd0/0x284
  neigh_connected_output+0x16c/0x20c
  ip6_finish_output2+0x4b4/0xd74
  __ip6_finish_output.part.0+0x1ac/0x3b0
  ip6_finish_output+0x160/0x200
  ip6_output+0x13c/0x294
  ndisc_send_skb+0x41c/0x6f0
  ndisc_send_rs+0xac/0x3b0
  addrconf_rs_timer+0x42c/0x660
  call_timer_fn+0x54/0x290
  expire_timers+0x26c/0x420

Reproducer
==========

 # Create veth pair (NETIF_F_HW_VLAN_CTAG_TX is ON by default)
 ip link add veth0 type veth peer name veth1
 ip link set veth0 up
 ip link set veth1 up

 # Turn off HW VLAN TX offload on lower device
 ethtool -K veth0 tx-vlan-hw-insert off

 # Create VLAN device on veth0
 # At this point: header_ops = &vlan_header_ops, hard_header_len = 18
 ip link add link veth0 name veth0.10 type vlan id 10 reorder_hdr off
 ip addr add 192.168.10.1/24 dev veth0.10
 ip link set veth0.10 up

 # Turn HW VLAN TX offload back ON on lower device
 # This triggers NETDEV_FEAT_CHANGE -> vlan_transfer_features()
 # hard_header_len changes from 18 to 14, but header_ops is NOT updated
 ethtool -K veth0 tx-vlan-hw-insert on

 # When a packet is sent through veth0.10
 # - skb is allocated based on hard_header_len=14 -> ~16 bytes
 # - vlan_dev_hard_header() pushes VLAN_HLEN(4) + ETH_HLEN(14) = 18 bytes
 # - skb_under_panic!


Any feedback or guidance would be greatly appreciated.

-- 
Best regards,
Tangxin Xie


^ permalink raw reply

* Re: [PATCH v3 net 1/6] xsk: fix buffer leak in xsk_drop_skb() for AF_XDP multi-buffer Tx
From: Jason Xing @ 2026-07-16 12:15 UTC (permalink / raw)
  To: Maciej Fijalkowski
  Cc: netdev, bpf, magnus.karlsson, stfomichev, kuba, pabeni, horms,
	bjorn, Jason Xing
In-Reply-To: <aljF91Tx804Lcwyx@boxer>

On Thu, Jul 16, 2026 at 1:52 PM Maciej Fijalkowski
<maciej.fijalkowski@intel.com> wrote:
>
> On Thu, Jul 16, 2026 at 01:42:28PM +0200, Jason Xing wrote:
> > On Thu, Jul 16, 2026 at 1:25 PM Maciej Fijalkowski
> > <maciej.fijalkowski@intel.com> wrote:
> > >
> > > On Thu, Jul 16, 2026 at 01:22:24PM +0200, Jason Xing wrote:
> > > > On Tue, Jul 14, 2026 at 4:08 PM Maciej Fijalkowski
> > > > <maciej.fijalkowski@intel.com> wrote:
> > > > >
> > > > > From: Jason Xing <kernelxing@tencent.com>
> > > > >
> > > > > This patch is inspired by the check[1] from sashiko. It says when
> > > > > overflow happens, the address of cq to be published is invalid.
> > > > > Actually the severer thing is the whole process of publishing the
> > > > > address of cq in this particular case is not right: it should truely
> > > > > publish the address and advance the cached_prod in cq as long as it
> > > > > reads descriptors from txq.
> > > > >
> > > > > The following is the full analysis.
> > > > > xsk_drop_skb() is called in three places, which all discard a partially
> > > > > built multi-buffer skb:
> > > > > 1) xsk_build_skb() -EOVERFLOW error path: packet exceeds MAX_SKB_FRAGS
> > > > > 2) __xsk_generic_xmit() post-loop cleanup: an invalid descriptor in
> > > > >    the TX ring prevents the partial packet from completing
> > > > > 3) xsk_release(): socket close while xs->skb holds an incomplete packet
> > > > >
> > > > > In all three cases, the TX descriptors for the already-processed frags
> > > > > have been consumed from the TX ring (xskq_cons_release), and CQ slots
> > > > > have been reserved. However, xsk_drop_skb() calls xsk_consume_skb()
> > > > > which cancels the CQ reservations via xsk_cq_cancel_locked(). Since
> > > > > the buffer addresses never appear in the completion queue, userspace
> > > > > permanently loses track of these buffers.
> > > > >
> > > > > Fix this by letting consume_skb() trigger the existing xsk_destruct_skb
> > > > > destructor, which already submits buffer addresses to the CQ via
> > > > > xsk_cq_submit_addr_locked().
> > > > >
> > > > > Note that cancelling the descriptors back to the TX ring (via
> > > > > xskq_cons_cancel_n) is not a appropriate option because an oversized
> > > > > packet that always exceeds MAX_SKB_FRAGS would be retried indefinitely,
> > > > > which is an obviously deadlock bug in the TX path.
> > > > >
> > > > > Also move the desc->addr assignment in xsk_build_skb() above the
> > > > > overflow check so that the current descriptor's address is recorded
> > > > > before a potential -EOVERFLOW jump to free_err, consistent with the
> > > > > zerocopy path in xsk_build_skb_zerocopy().
> > > > >
> > > > > [1]: https://lore.kernel.org/all/20260425041726.85FB3C2BCB2@smtp.kernel.org/
> > > > >
> > > > > Fixes: cf24f5a5feea ("xsk: add support for AF_XDP multi-buffer on Tx path")
> > > > > Signed-off-by: Jason Xing <kernelxing@tencent.com>
> > > >
> > > > Maciej, maybe your tag is missing here?
> > >
> > > IIRC this has been taken as-is from your patchset. The next one has been
> > > touched in few ways and I included my co-developed tag there.
> >
> > Yep, I mean maybe you can simply drop your reviewed-by or acked-by tag
> > here if you approve.
>
> I see. I am not sure what are principles for such cases, I could assume
> that if I include this as a sender then it implies my ack on such change.
> Anyways I can just:
>
> Acked-by: Maciej Fijalkowski <maciej.fijalkowski@intel.com>

Thanks.

>
> BTW now I reminded myself I dropped Stan's tags in whole set. I think it
> was of changes on 4/6, otherwise I don't have other excuse.
>
> So Jason if you bump at Stan somewhere in the netdevconf's hallway could
> you ask him to re-ack it if it still works for him?

No problem, but I don't see him appearing in netdev today. But yes, I
would if I saw him.

Thanks,
Jason

>
> >
> > Thanks,
> > Jason
> >
> > >
> > > >
> > > > Thanks,
> > > > Jason

^ permalink raw reply

* Re: [PATCH RFC net-next 3/6] bpf: Allow skb extensions to survive packet scrubbing
From: Stanislav Fomichev @ 2026-07-16 12:11 UTC (permalink / raw)
  To: Jakub Sitnicki; +Cc: netdev, bpf, kernel-team
In-Reply-To: <20260714-bpf-meta-inside-skb-ext-v1-3-5871c07a8dd6@cloudflare.com>

On 07/14, Jakub Sitnicki wrote:
> skb_scrub_packet() drops all skb extensions unconditionally via
> skb_ext_reset(). It runs on tunnel encap/decap (ip_tunnel_rcv,
> vxlan_rcv, etc.) and cross-netns forwarding (dev_forward_skb).
> 
> This makes it impossible for a BPF program to pass metadata via
> bpf_skb_ext through a tunnel or across a netns boundary. The extension
> is always lost at the scrub point.
> 
> Introduce skb_ext_scrub() which consults each active extension before
> discarding it. Extensions that request preservation are kept while the
> rest are torn down. When the extension slab is shared with clones, COW
> ensures isolation. Replace the skb_ext_reset() call in
> skb_scrub_packet() with skb_ext_scrub().
> 
> Expose the opt-in mechanism to BPF via the BPF_SKB_EXT_F_NO_SCRUB flag
> for bpf_dynptr_from_skb_ext(). A program that sets this flag when
> creating the extension signals that its metadata should survive
> scrubbing.
> 
> Signed-off-by: Jakub Sitnicki <jakub@cloudflare.com>
> ---
>  include/linux/bpf.h      |  1 +
>  include/linux/skbuff.h   |  2 ++
>  include/uapi/linux/bpf.h |  3 +-
>  net/core/filter.c        | 11 +++++--
>  net/core/skbuff.c        | 82 ++++++++++++++++++++++++++++++++++++++++++------
>  net/ipv4/udp.c           |  2 +-
>  6 files changed, 86 insertions(+), 15 deletions(-)
> 
> diff --git a/include/linux/bpf.h b/include/linux/bpf.h
> index 6b918a5b61bf..a46ca53c5b27 100644
> --- a/include/linux/bpf.h
> +++ b/include/linux/bpf.h
> @@ -4214,6 +4214,7 @@ static inline int bpf_map_check_op_flags(struct bpf_map *map, u64 flags, u64 all
>  #ifdef CONFIG_BPF_SKB_EXT
>  
>  struct bpf_skb_ext {
> +	u64 flags;
>  	u8 buf[CONFIG_BPF_SKB_EXT_SIZE] __aligned(8);
>  };
>  
> diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
> index 584d8440d352..66afa5489007 100644
> --- a/include/linux/skbuff.h
> +++ b/include/linux/skbuff.h
> @@ -5063,6 +5063,7 @@ void *__skb_ext_set(struct sk_buff *skb, enum skb_ext_id id,
>  void *skb_ext_add(struct sk_buff *skb, enum skb_ext_id id);
>  void __skb_ext_del(struct sk_buff *skb, enum skb_ext_id id);
>  void __skb_ext_put(struct skb_ext *ext);
> +void skb_ext_scrub(struct sk_buff *skb);
>  
>  static inline void skb_ext_put(struct sk_buff *skb)
>  {
> @@ -5132,6 +5133,7 @@ static inline bool skb_has_extensions(struct sk_buff *skb)
>  static inline void __skb_ext_put(struct skb_ext *ext) {}
>  static inline void skb_ext_put(struct sk_buff *skb) {}
>  static inline void skb_ext_reset(struct sk_buff *skb) {}
> +static inline void skb_ext_scrub(struct sk_buff *skb) {}
>  static inline void skb_ext_del(struct sk_buff *skb, int unused) {}
>  static inline void __skb_ext_copy(struct sk_buff *d, const struct sk_buff *s) {}
>  static inline void skb_ext_copy(struct sk_buff *dst, const struct sk_buff *s) {}
> diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
> index 3eee4467422d..02da170205de 100644
> --- a/include/uapi/linux/bpf.h
> +++ b/include/uapi/linux/bpf.h
> @@ -7734,7 +7734,8 @@ struct bpf_insn_array_value {
>  
>  /* Flags to control bpf_dynptr_from_skb_ext() behavior. */
>  enum {
> -	BPF_SKB_EXT_F_CREATE = (1ULL << 0),
> +	BPF_SKB_EXT_F_CREATE	= (1ULL << 0),
> +	BPF_SKB_EXT_F_NO_SCRUB	= (1ULL << 1),

Do I understand correctly that you do prefer the NO_SCRUB mode? Any reason
we need to have scrub mode? If it's all produced/consumed by bpf, maybe
we can just carry this data unconditionally instead of having a SCRUB/NO_SCRUB
option?

^ permalink raw reply

* Re: [PATCH RFC net-next 1/6] bpf: Introduce per-packet metadata storage for BPF programs
From: Stanislav Fomichev @ 2026-07-16 12:10 UTC (permalink / raw)
  To: Jakub Sitnicki; +Cc: netdev, bpf, kernel-team
In-Reply-To: <20260714-bpf-meta-inside-skb-ext-v1-1-5871c07a8dd6@cloudflare.com>

On 07/14, Jakub Sitnicki wrote:
> BPF programs attached at different points in the network stack have no way
> to pass data between each other on a per-packet basis, other than by
> stashing it into a shared BPF map. xdp/skb->data_meta works for XDP-to-TC
> handoff, but is not available to programs running at later hooks like
> cgroup/skb, sock_ops, socket filters, tracing or LSM.
> 
> Add a new skb extension (struct bpf_skb_ext) that provides up to 256 bytes
> of per-packet storage. Size is configurable at build time though the
> CONFIG_BPF_SKB_EXT_SIZE option. The storage is embedded inside the
> extension chunk itself.
> 
> Expose the storage to BPF programs via bpf_dynptr_from_skb_ext() kfunc.
> The caller passes BPF_SKB_EXT_F_CREATE to allocate or COW (unshare) the
> extension and get a read-write dynptr. Without the flag, it gets a
> read-only dynptr to the existing extension, or -ENOENT if none exists.
> 
> Guard the feature behind a new CONFIG_BPF_SKB_EXT option.
> 
> Signed-off-by: Jakub Sitnicki <jakub@cloudflare.com>
> ---
>  include/linux/bpf.h      |  10 ++++
>  include/linux/filter.h   |  26 ++++++++++
>  include/linux/skbuff.h   |   3 ++
>  include/uapi/linux/bpf.h |   5 ++
>  kernel/bpf/helpers.c     |   7 +++
>  kernel/bpf/log.c         |   2 +
>  kernel/bpf/verifier.c    |  10 +++-
>  net/Kconfig              |  20 ++++++++
>  net/core/filter.c        | 129 +++++++++++++++++++++++++++++++++++++++++++++++
>  net/core/skbuff.c        |   3 ++
>  10 files changed, 214 insertions(+), 1 deletion(-)
> 
> diff --git a/include/linux/bpf.h b/include/linux/bpf.h
> index 7719f6528445..6b918a5b61bf 100644
> --- a/include/linux/bpf.h
> +++ b/include/linux/bpf.h
> @@ -1484,6 +1484,8 @@ enum bpf_dynptr_type {
>  	BPF_DYNPTR_TYPE_SKB_META,
>  	/* Underlying data is a file */
>  	BPF_DYNPTR_TYPE_FILE,
> +	/* Underlying data is a bpf_skb_ext chunk */
> +	BPF_DYNPTR_TYPE_SKB_EXT,
>  };
>  
>  int bpf_dynptr_check_size(u64 size);
> @@ -4209,4 +4211,12 @@ static inline int bpf_map_check_op_flags(struct bpf_map *map, u64 flags, u64 all
>  	return 0;
>  }
>  
> +#ifdef CONFIG_BPF_SKB_EXT
> +
> +struct bpf_skb_ext {
> +	u8 buf[CONFIG_BPF_SKB_EXT_SIZE] __aligned(8);
> +};

Can we do a dynamic size from the start? Say, some sysfs knob, 0 by
default. Once written, it's locks in the size and can't be changed.
Then your new 'flags' field can be used to indicate whether the area
actually has been allocated or not?

^ permalink raw reply

* Re: [PATCH net-next v2 0/4] net: hsr: PRP RedBox (PRP-SAN) support
From: Fernando Fernandez Mancera @ 2026-07-16 12:04 UTC (permalink / raw)
  To: Fernando Fernandez Mancera
  Cc: Xin Xie, netdev, David S . Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Shuah Khan, Sebastian Andrzej Siewior,
	Felix Maurer, Luka Gejak, linux-kselftest, linux-kernel
In-Reply-To: <178420323080.16062.15477610308661322679.b4-review@b4>

On 2026-07-16 14:00 +0200, Fernando Fernandez Mancera wrote:
> On Mon, 06 Jul 2026 13:41:27 +0000, Xin Xie <xiexinet@gmail.com> wrote:
> > This series adds PRP RedBox support to the hsr driver: a PRP node that
> > proxies one or more SANs sitting behind an interlink port (IEC 62439-3,
> > PRP-SAN). HSR-SAN has been supported since commit 5055cccfc2d1 ("net: hsr:
> > Provide RedBox support (HSR-SAN)"); this extends the equivalent capability
> > to PRP, reusing the existing protocol-neutral proxy machinery
> > (proxy_node_db, hsr_proxy_announce(), hsr_prune_proxy_nodes()).
> > 
> > A SAN behind the interlink does bidirectional unicast with peers on the PRP
> > network, its source MAC is preserved on the wire, the PRP RCT is correct,
> > and the RedBox announces each proxied SAN with the RedBox-MAC TLV (Type 30)
> > in its supervision frames.
> > 
> > The series is bisect-safe: the datapath, duplicate discard and supervision
> > support are added first; the rtnetlink rejection of "type hsr ... interlink
> > <dev> proto 1" is removed only in patch 3, once the feature is complete.
> > 
> > Design notes:
> > 
> >  - prp_drop_frame() does not walk the node tables. The destination
> >    classification (PRP-network node vs proxied SAN) is resolved once per
> >    frame in fill_frame_info() and cached in struct hsr_frame_info, so the
> >    per egress-port drop decision is O(1) in the softIRQ path. The
> >    classification is gated on PRP RedBox devices (prot_version == PRP_V1 &&
> >    hsr->redbox), so HSR RedBox traffic is not affected.
> > 
> >  - The LAN A/B duplicate test is factored into prp_is_lan_dup() so the new
> >    PRP interlink rules in prp_drop_frame() do not change hsr_drop_frame()
> >    behaviour, including the NETIF_F_HW_HSR_FWD path. This is software PRP
> >    RedBox only; it adds no new hardware-offload contract.
> > 
> >  - The supervision emitter uses pre-reserved tailroom (hsr_init_skb() +
> >    skb_put()) on the existing GFP_ATOMIC path; no skb_linearize() or
> >    pskb_expand_head(). The RedBox-MAC TLV is followed by an explicit EOT
> >    (Type 0, Length 0); padding via skb_put_padto(ETH_ZLEN) and the 6-byte
> >    PRP RCT remain at the absolute tail of the egress frame.
> > 
> >  - The hsr_get_node() hsr_ethhdr length guard is relaxed only for PRP
> >    supervision frames (prot_version == PRP_V1 && ETH_P_PRP && is_sup), which
> >    are untagged with mac_len == ETH_HLEN. HSR (ETH_P_HSR) supervision is
> >    front-tagged and keeps the original length requirement, so HSR
> >    malformed-frame filtering is unchanged.
> > 
> > Testing (on a net-next v7.2-rc1 kernel built from this base, x86-64):
> >  - checkpatch.pl --strict: patches 1-3 clean; patch 4 reports only the
> >    expected "added file(s), does MAINTAINERS need updating?" note, which is
> >    ignorable here -- MAINTAINERS already lists
> >    tools/testing/selftests/net/hsr/ under HSR NETWORK PROTOCOL.
> >  - git diff --check clean; the series git-am's onto the base commit.
> >  - tools/testing/selftests/net/hsr/hsr_prp_redbox.sh: PASS on the patched
> >    kernel (bidirectional unicast, SAN MAC preservation, RedBox-MAC TLV +
> >    EOT in the proxy-announce).
> >  - HSR regression on the same kernel: hsr_redbox.sh (HSR-SAN/RedBox),
> >    hsr_ping.sh and prp_ping.sh all PASS, confirming the PRP changes do not
> >    regress the existing HSR/PRP paths.
> >  - netns checks: peer<->SAN 0% loss with no duplicates and a valid PRP RCT
> >    on the wire; a silent SAN is pruned from the announce; zero driver
> >    WARN/BUG/Oops/RCU-stall during the run.
> > 
> > Beyond the in-tree selftest, this exact series (applied to this base and
> > running as the net-next kernel on x86-64 hardware) was also validated with an
> > out-of-tree IEC 62439-3 conformance harness (supervision TLV chain, duplicate
> > discard, cross-LAN rejection, seqnr rollover, VLAN/multicast/GOOSE frame types
> > with the RCT verified at the absolute frame tail), and interoperability-tested
> > against a commercial PRP RedBox (Siemens SCALANCE X204RNA) over 100 Mbit/s
> > Fast Ethernet with NIC hardware (PTP) timestamping: a mid-stream single-LAN
> > outage of ~2 s at 10 kpps was bridged with zero lost and zero duplicate frames
> > (seamless PRP failover), and the duplicate-discard window held zero lost /
> > zero duplicates under netem asymmetric delay up to 100 ms (~1000 sequence
> > numbers in flight), 25% reorder, and 5% single-LAN loss. The failover and
> > impairment matrix was additionally repeated on a KASAN + lockdep + kmemleak
> > instrumented build of this kernel, including a 72-carrier-event link
> > flap-storm with deliberate double-LAN cuts: zero KASAN, lockdep, or kmemleak
> > findings. This out-of-tree testing is supplementary and not required to
> > evaluate the series.
> > 
> 
> The series looks good to me, I just found a couple of nits.
> 
> Thank you!

Oh I just realized you posted a v3 - anyway, as there were no changes my
comments also apply there.

Thanks,
Fernando.


^ permalink raw reply

* Re: [PATCH net-next v2 0/4] net: hsr: PRP RedBox (PRP-SAN) support
From: Fernando Fernandez Mancera @ 2026-07-16 12:00 UTC (permalink / raw)
  To: Xin Xie
  Cc: netdev, David S . Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Shuah Khan, Sebastian Andrzej Siewior,
	Felix Maurer, Luka Gejak, Fernando Fernandez Mancera,
	linux-kselftest, linux-kernel
In-Reply-To: <20260706134131.61659-1-xiexinet@gmail.com>

On Mon, 06 Jul 2026 13:41:27 +0000, Xin Xie <xiexinet@gmail.com> wrote:
> This series adds PRP RedBox support to the hsr driver: a PRP node that
> proxies one or more SANs sitting behind an interlink port (IEC 62439-3,
> PRP-SAN). HSR-SAN has been supported since commit 5055cccfc2d1 ("net: hsr:
> Provide RedBox support (HSR-SAN)"); this extends the equivalent capability
> to PRP, reusing the existing protocol-neutral proxy machinery
> (proxy_node_db, hsr_proxy_announce(), hsr_prune_proxy_nodes()).
> 
> A SAN behind the interlink does bidirectional unicast with peers on the PRP
> network, its source MAC is preserved on the wire, the PRP RCT is correct,
> and the RedBox announces each proxied SAN with the RedBox-MAC TLV (Type 30)
> in its supervision frames.
> 
> The series is bisect-safe: the datapath, duplicate discard and supervision
> support are added first; the rtnetlink rejection of "type hsr ... interlink
> <dev> proto 1" is removed only in patch 3, once the feature is complete.
> 
> Design notes:
> 
>  - prp_drop_frame() does not walk the node tables. The destination
>    classification (PRP-network node vs proxied SAN) is resolved once per
>    frame in fill_frame_info() and cached in struct hsr_frame_info, so the
>    per egress-port drop decision is O(1) in the softIRQ path. The
>    classification is gated on PRP RedBox devices (prot_version == PRP_V1 &&
>    hsr->redbox), so HSR RedBox traffic is not affected.
> 
>  - The LAN A/B duplicate test is factored into prp_is_lan_dup() so the new
>    PRP interlink rules in prp_drop_frame() do not change hsr_drop_frame()
>    behaviour, including the NETIF_F_HW_HSR_FWD path. This is software PRP
>    RedBox only; it adds no new hardware-offload contract.
> 
>  - The supervision emitter uses pre-reserved tailroom (hsr_init_skb() +
>    skb_put()) on the existing GFP_ATOMIC path; no skb_linearize() or
>    pskb_expand_head(). The RedBox-MAC TLV is followed by an explicit EOT
>    (Type 0, Length 0); padding via skb_put_padto(ETH_ZLEN) and the 6-byte
>    PRP RCT remain at the absolute tail of the egress frame.
> 
>  - The hsr_get_node() hsr_ethhdr length guard is relaxed only for PRP
>    supervision frames (prot_version == PRP_V1 && ETH_P_PRP && is_sup), which
>    are untagged with mac_len == ETH_HLEN. HSR (ETH_P_HSR) supervision is
>    front-tagged and keeps the original length requirement, so HSR
>    malformed-frame filtering is unchanged.
> 
> Testing (on a net-next v7.2-rc1 kernel built from this base, x86-64):
>  - checkpatch.pl --strict: patches 1-3 clean; patch 4 reports only the
>    expected "added file(s), does MAINTAINERS need updating?" note, which is
>    ignorable here -- MAINTAINERS already lists
>    tools/testing/selftests/net/hsr/ under HSR NETWORK PROTOCOL.
>  - git diff --check clean; the series git-am's onto the base commit.
>  - tools/testing/selftests/net/hsr/hsr_prp_redbox.sh: PASS on the patched
>    kernel (bidirectional unicast, SAN MAC preservation, RedBox-MAC TLV +
>    EOT in the proxy-announce).
>  - HSR regression on the same kernel: hsr_redbox.sh (HSR-SAN/RedBox),
>    hsr_ping.sh and prp_ping.sh all PASS, confirming the PRP changes do not
>    regress the existing HSR/PRP paths.
>  - netns checks: peer<->SAN 0% loss with no duplicates and a valid PRP RCT
>    on the wire; a silent SAN is pruned from the announce; zero driver
>    WARN/BUG/Oops/RCU-stall during the run.
> 
> Beyond the in-tree selftest, this exact series (applied to this base and
> running as the net-next kernel on x86-64 hardware) was also validated with an
> out-of-tree IEC 62439-3 conformance harness (supervision TLV chain, duplicate
> discard, cross-LAN rejection, seqnr rollover, VLAN/multicast/GOOSE frame types
> with the RCT verified at the absolute frame tail), and interoperability-tested
> against a commercial PRP RedBox (Siemens SCALANCE X204RNA) over 100 Mbit/s
> Fast Ethernet with NIC hardware (PTP) timestamping: a mid-stream single-LAN
> outage of ~2 s at 10 kpps was bridged with zero lost and zero duplicate frames
> (seamless PRP failover), and the duplicate-discard window held zero lost /
> zero duplicates under netem asymmetric delay up to 100 ms (~1000 sequence
> numbers in flight), 25% reorder, and 5% single-LAN loss. The failover and
> impairment matrix was additionally repeated on a KASAN + lockdep + kmemleak
> instrumented build of this kernel, including a 72-carrier-event link
> flap-storm with deliberate double-LAN cuts: zero KASAN, lockdep, or kmemleak
> findings. This out-of-tree testing is supplementary and not required to
> evaluate the series.
> 

The series looks good to me, I just found a couple of nits.

Thank you!

^ permalink raw reply

* Re: [PATCH net-next v2 2/4] net: hsr: emit RedBox-MAC TLV in PRP RedBox supervision frames
From: Fernando Fernandez Mancera @ 2026-07-16 12:00 UTC (permalink / raw)
  To: Xin Xie
  Cc: netdev, David S . Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Shuah Khan, Sebastian Andrzej Siewior,
	Felix Maurer, Luka Gejak, Fernando Fernandez Mancera,
	linux-kselftest, linux-kernel
In-Reply-To: <20260706134131.61659-3-xiexinet@gmail.com>

On Mon, 06 Jul 2026 13:41:29 +0000, Xin Xie <xiexinet@gmail.com> wrote:
> A PRP RedBox must announce the SANs it proxies so peers populate their
> proxy node tables. The proxy-announce machinery (hsr_proxy_announce(),
> armed via hsr->redbox) already iterates proxy_node_db under RCU and calls
> send_sv_frame() once per SAN, but the PRP sender emitted neither the
> announced SAN MAC nor the RedBox-MAC TLV that IEC 62439-3 requires.
> 
> Extend send_prp_supervision_frame() so that, for a proxy-announce
> (identified by the interlink port, an O(1) test), the frame carries the
> proxied SAN MAC as MacAddressA followed by the RedBox-MAC TLV (Type 30)
> and an explicit End-of-TLV marker before padding.
> 
> hsr_get_node() must also accept the reinjected proxy-announce: a PRP
> supervision frame is an untagged ETH_P_PRP frame (mac_len == ETH_HLEN, the
> RCT is appended only on egress) sourced from macaddress_redbox, which is
> never learned from data. Exempt only PRP supervision frames from the
> hsr_ethhdr length guard; HSR (ETH_P_HSR) supervision is front-tagged and
> keeps the original guard, so HSR malformed-frame filtering is unchanged.
> 
> Also align macaddress_redbox so that ether_addr_copy() and
> ether_addr_equal() on it are safe on architectures without efficient
> unaligned access.
> 
> Signed-off-by: Xin Xie <xiexinet@gmail.com>
>
> diff --git a/net/hsr/hsr_device.c b/net/hsr/hsr_device.c
> index 5af491ed2b72..0973f9a94f4d 100644
> --- a/net/hsr/hsr_device.c
> +++ b/net/hsr/hsr_device.c
> @@ -372,10 +372,21 @@ static void send_prp_supervision_frame(struct hsr_port *master,
>  {
>  	struct hsr_priv *hsr = master->hsr;
>  	struct hsr_sup_payload *hsr_sp;
> +	struct hsr_sup_tlv *hsr_stlv;
>  	struct hsr_sup_tag *hsr_stag;
>  	struct sk_buff *skb;
> +	bool redbox_proxy;
> +	int extra = 0;
> +
> +	redbox_proxy = hsr->redbox && master->type == HSR_PT_INTERLINK;
> +
> +	/* A proxy-announce carries a RedBox-MAC TLV and an EOT marker. */
> +	if (redbox_proxy)
> +		extra = sizeof(struct hsr_sup_tlv) +
> +			sizeof(struct hsr_sup_payload) +
> +			sizeof(struct hsr_sup_tlv);
>  
> -	skb = hsr_init_skb(master, 0);
> +	skb = hsr_init_skb(master, extra);
>  	if (!skb) {
>  		netdev_warn_once(master->dev, "PRP: Could not send supervision frame\n");
>  		return;
> @@ -393,9 +404,25 @@ static void send_prp_supervision_frame(struct hsr_port *master,
>  	hsr_stag->tlv.HSR_TLV_type = PRP_TLV_LIFE_CHECK_DD;
>  	hsr_stag->tlv.HSR_TLV_length = sizeof(struct hsr_sup_payload);
>  
> -	/* Payload: MacAddressA */
> +	/* Payload: MacAddressA, the announced node. */
>  	hsr_sp = skb_put(skb, sizeof(struct hsr_sup_payload));
> -	ether_addr_copy(hsr_sp->macaddress_A, master->dev->dev_addr);
> +	ether_addr_copy(hsr_sp->macaddress_A, addr);
> +
> +	/* Proxy-announce: append the RedBox-MAC TLV (Type 30) and an explicit
> +	 * EOT to terminate the TLV chain before zero padding.
> +	 */
> +	if (redbox_proxy) {
> +		hsr_stlv = skb_put(skb, sizeof(struct hsr_sup_tlv));
> +		hsr_stlv->HSR_TLV_type = PRP_TLV_REDBOX_MAC;
> +		hsr_stlv->HSR_TLV_length = sizeof(struct hsr_sup_payload);
> +
> +		hsr_sp = skb_put(skb, sizeof(struct hsr_sup_payload));
> +		ether_addr_copy(hsr_sp->macaddress_A, hsr->macaddress_redbox);
> +
> +		hsr_stlv = skb_put(skb, sizeof(struct hsr_sup_tlv));
> +		hsr_stlv->HSR_TLV_type = HSR_TLV_EOT;
> +		hsr_stlv->HSR_TLV_length = 0;
> +	}
>  
>  	if (skb_put_padto(skb, ETH_ZLEN)) {
>  		spin_unlock_bh(&hsr->seqnr_lock);
> diff --git a/net/hsr/hsr_framereg.c b/net/hsr/hsr_framereg.c
> index 8f708b6e6c33..b3b106be692e 100644
> --- a/net/hsr/hsr_framereg.c
> +++ b/net/hsr/hsr_framereg.c
> @@ -293,8 +293,17 @@ struct hsr_node *hsr_get_node(struct hsr_port *port, struct list_head *node_db,
>  	 */
>  	if (ethhdr->h_proto == htons(ETH_P_PRP) ||
>  	    ethhdr->h_proto == htons(ETH_P_HSR)) {
> -		/* Check if skb contains hsr_ethhdr */
> -		if (skb->mac_len < sizeof(struct hsr_ethhdr))
> +		bool prp_sup;
> +
> +		/* A PRP supervision frame is an untagged ETH_P_PRP frame
> +		 * (mac_len == ETH_HLEN); its RCT is appended only on egress.
> +		 * HSR (ETH_P_HSR) supervision is front-tagged and still must
> +		 * contain a struct hsr_ethhdr.
> +		 */
> +		prp_sup = hsr->prot_version == PRP_V1 &&
> +			  ethhdr->h_proto == htons(ETH_P_PRP) && is_sup;
> +
> +		if (!prp_sup && skb->mac_len < sizeof(struct hsr_ethhdr))
>  			return NULL;
>  	} else {
>  		rct = skb_get_PRP_rct(skb);
> diff --git a/net/hsr/hsr_main.h b/net/hsr/hsr_main.h
> index 134e4f3fff60..c27cfdd9ca3f 100644
> --- a/net/hsr/hsr_main.h
> +++ b/net/hsr/hsr_main.h
> @@ -211,7 +211,7 @@ struct hsr_priv {
>  				 */
>  	bool fwd_offloaded;	/* Forwarding offloaded to HW */
>  	bool redbox;            /* Device supports HSR RedBox */
> -	unsigned char		macaddress_redbox[ETH_ALEN];
> +	unsigned char	macaddress_redbox[ETH_ALEN] __aligned(sizeof(u16));

The indentation is wrong here, could you keep at the same level it was
before?

^ permalink raw reply

* Re: [PATCH net-next v2 1/4] net: hsr: add PRP interlink (RedBox) datapath and duplicate discard
From: Fernando Fernandez Mancera @ 2026-07-16 12:00 UTC (permalink / raw)
  To: Xin Xie
  Cc: netdev, David S . Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Shuah Khan, Sebastian Andrzej Siewior,
	Felix Maurer, Luka Gejak, Fernando Fernandez Mancera,
	linux-kselftest, linux-kernel
In-Reply-To: <20260706134131.61659-2-xiexinet@gmail.com>

On Mon, 06 Jul 2026 13:41:28 +0000, Xin Xie <xiexinet@gmail.com> wrote:
> A PRP RedBox proxies SANs that sit behind an interlink port: their frames
> must reach the PRP network with the SAN source MAC preserved, and PRP
> unicast must be steered between the LAN and the SAN segment correctly.
> 
> Add the PRP interlink forwarding rules to prp_drop_frame() and give RedBox
> nodes a second duplicate-discard slot so the two LAN copies of a frame
> destined to a SAN collapse to a single delivery out the interlink.
> 
> The destination classification (is the unicast DA a PRP-network node or a
> proxied SAN) is resolved once per frame in fill_frame_info(), gated to PRP
> RedBox devices, and cached in struct hsr_frame_info, so prp_drop_frame()
> stays O(1) and does not walk the node tables for every candidate egress
> port in the softIRQ path. HSR RedBox frame classification is untouched.
> 
> Factor the LAN A/B duplicate test into prp_is_lan_dup() so the new PRP
> interlink rules do not change hsr_drop_frame() behaviour, including the
> NETIF_F_HW_HSR_FWD path which keeps using the LAN-duplicate test only.
> 
> Publish the RedBox state before the first hsr_add_port(): the slave and
> interlink rx handlers are live from hsr_add_port() on and rtnl does not
> stop softirq processing, so a frame could otherwise be handled while
> hsr->redbox is still false. hsr_add_node() sizes each node's per-port
> sequence state from hsr->redbox; a node learned in that window would get
> a single-port sequence block, breaking the interlink duplicate discard
> (WARN_ON_ONCE plus duplicate delivery to the SAN) and letting the
> supervision sequence-block merge read beyond the source node's allocated
> sequence bitmap. Publishing the flag before any port exists makes the
> per-node sizing uniform by construction. This is safe: the proxy
> announce timer is only armed from hsr_check_announce() once the master
> is running, the packet-path readers of hsr->redbox tolerate an empty
> proxy node database and an absent interlink port, and the
> prune_proxy_timer is still armed only after the interlink port has been
> attached successfully.
> 
> Additionally bound the supervision sequence-block merge by the smaller
> of the two nodes' seq_port_cnt as defense in depth against mismatched
> node sizes.
> 
> Signed-off-by: Xin Xie <xiexinet@gmail.com>
>
> diff --git a/net/hsr/hsr_device.c b/net/hsr/hsr_device.c
> index 5555b71ab19b..5af491ed2b72 100644
> --- a/net/hsr/hsr_device.c
> +++ b/net/hsr/hsr_device.c
> @@ -768,6 +768,15 @@ int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2],
>  	/* Make sure the 1st call to netif_carrier_on() gets through */
>  	netif_carrier_off(hsr_dev);
>  
> +	/* Publish the RedBox state before any port is attached: the rx
> +	 * handlers are live from hsr_add_port() on, and hsr_add_node()
> +	 * sizes each node's per-port sequence state from hsr->redbox.
> +	 */
> +	if (interlink) {
> +		hsr->redbox = true;
> +		ether_addr_copy(hsr->macaddress_redbox, interlink->dev_addr);
> +	}
> +
>  	res = hsr_add_port(hsr, hsr_dev, HSR_PT_MASTER, extack);
>  	if (res)
>  		goto err_add_master;
> @@ -805,8 +814,6 @@ int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2],
>  		if (res)
>  			goto err_unregister;
>  
> -		hsr->redbox = true;
> -		ether_addr_copy(hsr->macaddress_redbox, interlink->dev_addr);
>  		mod_timer(&hsr->prune_proxy_timer,
>  			  jiffies + msecs_to_jiffies(PRUNE_PROXY_PERIOD));
>  	}
> diff --git a/net/hsr/hsr_forward.c b/net/hsr/hsr_forward.c
> index 0774981a65c1..efcd0acef38c 100644
> --- a/net/hsr/hsr_forward.c
> +++ b/net/hsr/hsr_forward.c
> @@ -440,12 +440,37 @@ static int hsr_xmit(struct sk_buff *skb, struct hsr_port *port,
>  	return dev_queue_xmit(skb);
>  }
>  
> +static bool prp_is_lan_dup(struct hsr_frame_info *frame,
> +			   struct hsr_port *port)
> +{
> +	enum hsr_port_type rx = frame->port_rcv->type;
> +
> +	return (rx == HSR_PT_SLAVE_A && port->type == HSR_PT_SLAVE_B) ||
> +	       (rx == HSR_PT_SLAVE_B && port->type == HSR_PT_SLAVE_A);
> +}
> +
>  bool prp_drop_frame(struct hsr_frame_info *frame, struct hsr_port *port)
>  {
> -	return ((frame->port_rcv->type == HSR_PT_SLAVE_A &&
> -		 port->type == HSR_PT_SLAVE_B) ||
> -		(frame->port_rcv->type == HSR_PT_SLAVE_B &&
> -		 port->type == HSR_PT_SLAVE_A));
> +	enum hsr_port_type rx = frame->port_rcv->type;
> +
> +	/* Supervision frames are not delivered to a SAN on the interlink. */
> +	if (frame->is_supervision && port->type == HSR_PT_INTERLINK)
> +		return true;
> +
> +	if (prp_is_lan_dup(frame, port))
> +		return true;

Since we already have rx (enum hsr_port_type) here, can we pass this
directly to prp_is_lan_dup() function instead of passing frame?

> +
> +	/* LAN to interlink: keep PRP-network unicast off the SAN segment. */
> +	if ((rx == HSR_PT_SLAVE_A || rx == HSR_PT_SLAVE_B) &&
> +	    port->type == HSR_PT_INTERLINK)
> +		return frame->dst_in_node_db;
> +
> +	/* Interlink to LAN: keep SAN-to-SAN unicast local. */
> +	if ((port->type == HSR_PT_SLAVE_A || port->type == HSR_PT_SLAVE_B) &&
> +	    rx == HSR_PT_INTERLINK)
> +		return frame->dst_in_proxy_node_db;
> +
> +	return false;
>  }
>  
>  bool hsr_drop_frame(struct hsr_frame_info *frame, struct hsr_port *port)
> @@ -453,7 +478,7 @@ bool hsr_drop_frame(struct hsr_frame_info *frame, struct hsr_port *port)
>  	struct sk_buff *skb;
>  
>  	if (port->dev->features & NETIF_F_HW_HSR_FWD)
> -		return prp_drop_frame(frame, port);
> +		return prp_is_lan_dup(frame, port);
>  

Of course these calls will need to pass rx too.

^ permalink raw reply

* Re: [PATCH net v1 0/3] net: fix stale TX skb pointers on DMA map failure
From: Simon Horman @ 2026-07-16 12:00 UTC (permalink / raw)
  To: xuanqiang.luo
  Cc: netdev, Xuanqiang Luo, Rasesh Mody, Sudarsana Kalluru,
	GR-Linux-NIC-Dev, Fan Gong, Xin Guo, Gur Stavi, Jijie Shao,
	Jian Shen, Andrew Lunn, David S . Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Ivan Vecera, linux-kernel
In-Reply-To: <20260710090527.58354-1-xuanqiang.luo@linux.dev>

On Fri, Jul 10, 2026 at 05:05:21PM +0800, xuanqiang.luo@linux.dev wrote:
> From: Xuanqiang Luo <luoxuanqiang@kylinos.cn>
> 
> While I was backporting commit 1a303baa715e6 ("ice: fix double-free of
> tx_buf skb"), an AI-assisted scan identified several suspected TX error
> paths. I reviewed the results and found this issue in the three drivers
> fixed here.
> 
> The drivers differ, but the bug is the same. On a DMA mapping failure, the
> TX path frees an skb while its ring entry still points to it. A later
> transmission normally overwrites the entry. If the interface is stopped
> first, teardown can instead access or free the skb again.
> 
> I do not have these adapters, so I have not tested the drivers on hardware.
> I checked the error and teardown paths by inspection. Still, these small
> fixes seem worth posting for review. They are independent, but are sent as
> one series because they address the same issue.
> 
> Xuanqiang Luo (3):
>   bna: fix use-after-free on DMA mapping failure
>   hinic3: fix use-after-free on DMA mapping failure
>   net: hibmcge: fix double-free of tx skb on DMA mapping failure

For the series:

Reviewed-by: Simon Horman <horms@kernel.org>

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox