* Re: [BUG] mlx5: VLAN-aware bridge drops all traffic in legacy eswitch mode without promiscuous
From: Dragos Tatulea @ 2026-04-28 11:32 UTC (permalink / raw)
To: bryan, netdev; +Cc: saeedm, tariqt
In-Reply-To: <5d5524e8077bc3f169ab5ce6ea267d344efd3336.camel@gmail.com>
On Mon, Apr 27, 2026 at 04:10:28PM -0500, bryan wrote:
> Here would be one example config (sanitized). The promisc on link is
> what allows traffic to pass - I disable promisc, and traffic stops.
> These are single-port CX4Lx cards. nic0 is the physical interface, no
> VFs configured, SrIOV has been disabled as part of testing and
> troubleshooting, Kernel 6.17 currently:
>
Is this a distro kernel or a self-compiled .deb?
> auto lo
> iface lo inet loopback
>
> auto nic0
> iface nic0 inet manual
> up ip link set nic0 promisc on
> auto vmbr0
> iface vmbr0 inet manual
> bridge-ports nic0
> bridge-stp off
> bridge-fd 0
> bridge-vlan-aware yes
> bridge-vids 2-10 555
>
> auto vmbr0.555
> iface vmbr0.555 inet static
> address 192.168.1.123/24
> gateway 192.168.1.1
>
>
> iface nic3 inet manual
>
> iface nic1 inet manual
>
> iface nic2 inet manual
>
>
> This was ported over to use the new nic# bindings, before this it was
> the standard enps0np0 naming. No difference in behvaiour.
>
I don't have a machine with ifupdown available but I did a similar setup
with iproute2 (note that promisc mode is explicitly set to off):
# Bring PF up
ip link set dev $DEV up
ip link set dev $DEV promisc off
# Create bridge
ip link add name $BR type bridge
ip link set dev $BR type bridge stp_state 0 forward_delay 0
# Make bridge VLAN-aware
ip link set dev $BR type bridge vlan_filtering 1
# Add PF to bridge
ip link set dev $DEV master $BR
# Bring bridge up
ip link set dev $BR up
# Allow VLANs 2-10 and 555 on $DEV bridge port
bridge vlan del dev $DEV vid 1
bridge vlan add dev $DEV vid 2-10
bridge vlan add dev $DEV vid 555
# Also allow VLANs on bridge self port
bridge vlan add dev $BR vid 2-10 self
bridge vlan add dev $BR vid 555 self
# Create VLAN subinterface $BR.555
ip link add link $BR name $BR.555 type vlan id 555
# Assign IP
ip addr add 192.168.1.123/24 dev $BR.555
# Bring VLAN interface up
ip link set dev $BR.555 up
On the peer where $DEV is connected to I have created a vlan interface
for vlan id 555 and I can ping it without issues...
> >Is this even with one vlan? I ran a flow on a CX4LX pair with one vlan
> >and vlan_filtering set and traffic seems to be flowing normally.
>
> I have not checked with literally only one VLAN, as that is not at all
> the use case. I can absolutely test that if it would help! Would you
> like me to remove every VLAN but 555 from the interface, and leave the
> rest of the config as-is?
>
No need.
>
>
> [...]
>
> >eth2 is a PF in legacy switchdev mode.
>
> It was my understanding that Legacy mode and Switchdev mode were two
> independent modes, with Legacy done in-software and Switchdev using the
> eSwitch on the NIC itself. Please excuse my ignorance if that is not
> the case. Would you be able to specify if you used Switchdev mode or
> Legacy mode? because Switchdev mode DOES function as a workaround and
> passes traffic (but in my case results in system instability after a
> time).
>
My bad, sorry. I wanted to say legacy mode.
It would be useful if you could provide a reproduction using only plain
iproute2 commands (ip and bridge) like above.
Also, do you see anyting relevant info in dmesg regarding the interface?
Could you also provide the following:
- ip link
- ip addr
- bridge link
- bridge vlan
- bridge fdb
- ethtool -S nic0
Maybe we can get some info from there.
Thanks,
Dragos
^ permalink raw reply
* Re: [PATCH net v2] net: usb: rtl8150: free skb on usb_submit_urb() failure in xmit
From: Paolo Abeni @ 2026-04-28 11:32 UTC (permalink / raw)
To: Morduan Zang, Jakub Kicinski, Petko Manolov
Cc: Andrew Lunn, David S . Miller, Eric Dumazet, linux-usb, netdev,
linux-kernel, Andrew Lunn
In-Reply-To: <E7D3E1C013C5A859+20260424015517.9574-1-zhangdandan@uniontech.com>
On 4/24/26 3:55 AM, Morduan Zang wrote:
> When rtl8150_start_xmit() fails to submit the tx URB, the URB is never
> handed to the USB core and write_bulk_callback() will not run. The
> driver returns NETDEV_TX_OK, which tells the networking stack that the
> skb has been consumed, but nothing actually frees the skb on this
> error path:
>
> dev->tx_skb = skb;
> ...
> if ((res = usb_submit_urb(dev->tx_urb, GFP_ATOMIC))) {
> ...
> /* no kfree_skb here */
> }
> return NETDEV_TX_OK;
>
> This leaks the skb on every submit failure and also leaves dev->tx_skb
> pointing at memory that the driver itself may later free, which is
> fragile.
>
> Free the skb with dev_kfree_skb_any() in the error path and clear
> dev->tx_skb so no stale pointer is left behind.
>
> Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
> Reviewed-by: Andrew Lunn <andrew@lunn.ch>
> Signed-off-by: Morduan Zang <zhangdandan@uniontech.com>
Applied (by Jakub, AFAICS the bot did not send out the notification for
some reason), thanks!
/P
^ permalink raw reply
* [PATCH net-next v5 3/3] net: dsa: yt921x: Add port police support
From: David Yang @ 2026-04-28 11:26 UTC (permalink / raw)
To: netdev
Cc: David Yang, Andrew Lunn, Vladimir Oltean, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, linux-kernel
In-Reply-To: <20260428112606.1917230-1-mmyangfl@gmail.com>
Enable rate meter ability and support limiting the rate of incoming
traffic.
Signed-off-by: David Yang <mmyangfl@gmail.com>
---
drivers/net/dsa/yt921x.c | 323 ++++++++++++++++++++++++++++++++++++++-
drivers/net/dsa/yt921x.h | 51 +++++++
2 files changed, 373 insertions(+), 1 deletion(-)
diff --git a/drivers/net/dsa/yt921x.c b/drivers/net/dsa/yt921x.c
index 0c07b903fd68..d93674d567d7 100644
--- a/drivers/net/dsa/yt921x.c
+++ b/drivers/net/dsa/yt921x.c
@@ -263,6 +263,14 @@ yt921x_reg_toggle_bits(struct yt921x_priv *priv, u32 reg, u32 mask, bool set)
* eliminate potential issues, although partial reads/writes are also possible.
*/
+static void update_ctrls_unaligned(u32 *lo, u32 *hi, u64 mask, u64 val)
+{
+ *lo &= ~lower_32_bits(mask);
+ *hi &= ~upper_32_bits(mask);
+ *lo |= lower_32_bits(val);
+ *hi |= upper_32_bits(val);
+}
+
static int
yt921x_regs_read(struct yt921x_priv *priv, u32 reg, u32 *vals,
unsigned int num_regs)
@@ -373,6 +381,12 @@ yt921x_reg64_clear_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks)
return yt921x_regs_clear_bits(priv, reg, masks, 2);
}
+static int
+yt921x_reg96_write(struct yt921x_priv *priv, u32 reg, const u32 *vals)
+{
+ return yt921x_regs_write(priv, reg, vals, 3);
+}
+
static int yt921x_reg_mdio_read(void *context, u32 reg, u32 *valp)
{
struct yt921x_reg_mdio *mdio = context;
@@ -1066,6 +1080,13 @@ yt921x_dsa_set_mac_eee(struct dsa_switch *ds, int port, struct ethtool_keee *e)
return res;
}
+static int yt921x_mtu_fetch(struct yt921x_priv *priv, int port)
+{
+ struct dsa_port *dp = dsa_to_port(&priv->ds, port);
+
+ return dp->user ? READ_ONCE(dp->user->mtu) : ETH_DATA_LEN;
+}
+
static int
yt921x_dsa_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
{
@@ -1097,6 +1118,266 @@ static int yt921x_dsa_port_max_mtu(struct dsa_switch *ds, int port)
return YT921X_FRAME_SIZE_MAX - ETH_HLEN - ETH_FCS_LEN - YT921X_TAG_LEN;
}
+/* v * 2^e */
+static u64 ldexpu64(u64 v, int e)
+{
+ return e >= 0 ? v << e : v >> -e;
+}
+
+/* slot (ns) * rate (/s) / 10^9 (ns/s) = 2^C * token * 4^unit */
+static u32 rate2token(u64 rate, unsigned int slot_ns, int unit, int C)
+{
+ int e = 2 * unit + C + YT921X_TOKEN_RATE_C;
+
+ return div_u64(ldexpu64(slot_ns * rate, -e), 1000000000);
+}
+
+static u64 token2rate(u32 token, unsigned int slot_ns, int unit, int C)
+{
+ int e = 2 * unit + C + YT921X_TOKEN_RATE_C;
+
+ return div_u64(ldexpu64(mul_u32_u32(1000000000, token), e), slot_ns);
+}
+
+/* burst = 2^C * token * 4^unit */
+static u32 burst2token(u64 burst, int unit, int C)
+{
+ return ldexpu64(burst, -(2 * unit + C));
+}
+
+static u64 token2burst(u32 token, int unit, int C)
+{
+ return ldexpu64(token, 2 * unit + C);
+}
+
+struct yt921x_marker {
+ u32 cir;
+ u32 cbs;
+ u32 ebs;
+ int unit;
+ bool pkt_mode;
+};
+
+#define YT921X_MARKER_PKT_MODE BIT(0)
+#define YT921X_MARKER_SINGLE_BUCKET BIT(1)
+
+static int
+yt921x_marker_tfm(struct yt921x_marker *marker, u64 rate, u64 burst,
+ unsigned int flags, unsigned int slot_ns, u32 cir_max,
+ u32 cbs_max, int unit_max, struct yt921x_priv *priv, int port,
+ struct netlink_ext_ack *extack)
+{
+ const int C = flags & YT921X_MARKER_PKT_MODE ? YT921X_TOKEN_PKT_C :
+ YT921X_TOKEN_BYTE_C;
+ struct device *dev = to_device(priv);
+ struct yt921x_marker m;
+ u64 burst_est;
+ u64 burst_sug;
+ u64 burst_max;
+ u64 rate_max;
+
+ m.unit = unit_max;
+ rate_max = token2rate(cir_max, slot_ns, m.unit, C);
+ burst_max = token2burst(cbs_max, m.unit, C);
+
+ /* Check for unusual values */
+ if (rate > rate_max || burst > burst_max) {
+ NL_SET_ERR_MSG_MOD(extack, "Unexpected tremendous rate");
+ return -ERANGE;
+ }
+
+ /* Check for matching burst */
+ burst_est = div_u64(slot_ns * rate, 1000000000);
+ burst_sug = burst_est;
+ if (flags & YT921X_MARKER_PKT_MODE)
+ burst_sug++;
+ else
+ burst_sug += ETH_HLEN + yt921x_mtu_fetch(priv, port) +
+ ETH_FCS_LEN;
+ if (burst_sug > burst)
+ NL_SET_ERR_MSG_FMT_MOD(extack,
+ "Consider burst at least %llu to match rate %llu\n",
+ burst_sug, rate);
+
+ /* Select unit */
+ for (; m.unit > 0; m.unit--) {
+ if (rate > (rate_max >> 2) || burst > (burst_max >> 2))
+ break;
+ rate_max >>= 2;
+ burst_max >>= 2;
+ }
+
+ /* Calculate information rate and bucket size */
+ m.cir = rate2token(rate, slot_ns, m.unit, C);
+ if (!m.cir)
+ m.cir = 1;
+ else if (WARN_ON(m.cir > cir_max))
+ m.cir = cir_max;
+ m.cbs = burst2token(burst, m.unit, C);
+ if (!m.cbs)
+ m.cbs = 1;
+ else if (WARN_ON(m.cbs > cbs_max))
+ m.cbs = cbs_max;
+
+ /* Cut EBS */
+ m.ebs = 0;
+ if (!(flags & YT921X_MARKER_SINGLE_BUCKET)) {
+ /* We don't have a chance to adjust rate when MTU is changed */
+ if (flags & YT921X_MARKER_PKT_MODE)
+ burst_est++;
+ else
+ burst_est += YT921X_FRAME_SIZE_MAX;
+
+ if (burst_est < burst) {
+ u32 pbs = m.cbs;
+
+ m.cbs = burst2token(burst_est, m.unit, C);
+ if (!m.cbs)
+ m.cbs = 1;
+ else if (WARN_ON(m.cbs > cbs_max))
+ m.cbs = cbs_max;
+
+ if (pbs > m.cbs)
+ m.ebs = pbs - m.cbs;
+ }
+ }
+
+ dev_dbg(dev,
+ "slot %u ns, rate %llu, burst %llu -> unit %d, cir %u, cbs %u, ebs %u\n",
+ slot_ns, rate, burst, m.unit, m.cir, m.cbs, m.ebs);
+
+ m.pkt_mode = flags & YT921X_MARKER_PKT_MODE;
+ *marker = m;
+ return 0;
+}
+
+static int
+yt921x_marker_tfm_police(struct yt921x_marker *marker,
+ const struct flow_action_police *police,
+ unsigned int flags, struct yt921x_priv *priv, int port,
+ struct netlink_ext_ack *extack)
+{
+ bool pkt_mode = !!police->rate_pkt_ps;
+ u64 burst;
+ u64 rate;
+
+ rate = pkt_mode ? police->rate_pkt_ps : police->rate_bytes_ps;
+ burst = pkt_mode ? police->burst_pkt : police->burst;
+ if (pkt_mode)
+ flags |= YT921X_MARKER_PKT_MODE;
+
+ return yt921x_marker_tfm(marker, rate, burst, flags,
+ priv->meter_slot_ns, YT921X_METER_CIR_MAX,
+ YT921X_METER_CBS_MAX, YT921X_METER_UNIT_MAX,
+ priv, port, extack);
+}
+
+static int
+yt921x_police_validate(const struct flow_action_police *police,
+ const struct flow_action *action,
+ const struct flow_action_entry *act,
+ struct netlink_ext_ack *extack)
+{
+ if (police->exceed.act_id != FLOW_ACTION_DROP) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Offload not supported when exceed action is not drop");
+ return -EOPNOTSUPP;
+ }
+
+ if (police->notexceed.act_id != FLOW_ACTION_PIPE &&
+ police->notexceed.act_id != FLOW_ACTION_ACCEPT) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Offload not supported when conform action is not pipe or ok");
+ return -EOPNOTSUPP;
+ }
+
+ if (police->notexceed.act_id == FLOW_ACTION_ACCEPT && action && act &&
+ !flow_action_is_last_entry(action, act)) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Offload not supported when conform action is ok, but action is not last");
+ return -EOPNOTSUPP;
+ }
+
+ /* mtu defaults to unlimited but we got 2040 here, don't know why */
+ if (police->peakrate_bytes_ps || police->avrate || police->overhead) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Offload not supported when peakrate/avrate/overhead is configured");
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static int
+yt921x_meter_config(struct yt921x_priv *priv, unsigned int id,
+ const struct yt921x_marker *marker)
+{
+ u32 ctrls[3];
+
+ ctrls[0] = 0;
+ ctrls[1] = YT921X_METER_CTRLb_CIR(marker->cir);
+ ctrls[2] = YT921X_METER_CTRLc_UNIT(marker->unit) |
+ YT921X_METER_CTRLc_DROP_R |
+ YT921X_METER_CTRLc_TOKEN_OVERFLOW_EN |
+ YT921X_METER_CTRLc_METER_EN;
+ if (marker->pkt_mode)
+ ctrls[2] |= YT921X_METER_CTRLc_PKT_MODE;
+ update_ctrls_unaligned(&ctrls[0], &ctrls[1],
+ YT921X_METER_CTRLab_EBS_M,
+ YT921X_METER_CTRLab_EBS(marker->ebs));
+ update_ctrls_unaligned(&ctrls[1], &ctrls[2],
+ YT921X_METER_CTRLbc_CBS_M,
+ YT921X_METER_CTRLbc_CBS(marker->cbs));
+
+ return yt921x_reg96_write(priv, YT921X_METERn_CTRL(id), ctrls);
+}
+
+static void yt921x_dsa_port_policer_del(struct dsa_switch *ds, int port)
+{
+ struct yt921x_priv *priv = to_yt921x_priv(ds);
+ struct device *dev = to_device(priv);
+ int res;
+
+ mutex_lock(&priv->reg_lock);
+ res = yt921x_reg_write(priv, YT921X_PORTn_METER(port), 0);
+ mutex_unlock(&priv->reg_lock);
+
+ if (res)
+ dev_err(dev, "Failed to %s port %d: %i\n", "delete policer on",
+ port, res);
+}
+
+static int
+yt921x_dsa_port_policer_add(struct dsa_switch *ds, int port,
+ const struct flow_action_police *police,
+ struct netlink_ext_ack *extack)
+{
+ struct yt921x_priv *priv = to_yt921x_priv(ds);
+ struct yt921x_marker marker;
+ u32 ctrl;
+ int res;
+
+ res = yt921x_police_validate(police, NULL, NULL, extack);
+ if (res)
+ return res;
+
+ res = yt921x_marker_tfm_police(&marker, police, 0, priv, port, extack);
+ if (res)
+ return res;
+
+ mutex_lock(&priv->reg_lock);
+ res = yt921x_meter_config(priv, port + YT921X_METER_NUM, &marker);
+ if (res)
+ goto end;
+
+ ctrl = YT921X_PORT_METER_ID(port) | YT921X_PORT_METER_EN;
+ res = yt921x_reg_write(priv, YT921X_PORTn_METER(port), ctrl);
+end:
+ mutex_unlock(&priv->reg_lock);
+
+ return res;
+}
+
static int
yt921x_mirror_del(struct yt921x_priv *priv, int port, bool ingress)
{
@@ -3052,6 +3333,7 @@ static int yt921x_chip_detect(struct yt921x_priv *priv)
u32 chipid;
u32 major;
u32 mode;
+ u32 val;
int res;
res = yt921x_reg_read(priv, YT921X_CHIP_ID, &chipid);
@@ -3086,12 +3368,27 @@ static int yt921x_chip_detect(struct yt921x_priv *priv)
return -ENODEV;
}
+ res = yt921x_reg_read(priv, YT921X_SYS_CLK, &val);
+ if (res)
+ return res;
+ switch (FIELD_GET(YT921X_SYS_CLK_SEL_M, val)) {
+ case 0:
+ priv->cycle_ns = info->major == YT9215_MAJOR ? 8 : 6;
+ break;
+ case YT921X_SYS_CLK_143M:
+ priv->cycle_ns = 7;
+ break;
+ default:
+ priv->cycle_ns = 8;
+ }
+
/* Print chipid here since we are interested in lower 16 bits */
dev_info(dev,
"Motorcomm %s ethernet switch, chipid: 0x%x, chipmode: 0x%x 0x%x\n",
info->name, chipid, mode, extmode);
priv->info = info;
+
return 0;
}
@@ -3213,6 +3510,23 @@ static int yt921x_chip_setup_dsa(struct yt921x_priv *priv)
return 0;
}
+static int yt921x_chip_setup_tc(struct yt921x_priv *priv)
+{
+ unsigned int op_ns;
+ u32 ctrl;
+ int res;
+
+ op_ns = 8 * priv->cycle_ns;
+
+ ctrl = max(priv->meter_slot_ns / op_ns, YT921X_METER_SLOT_MIN);
+ res = yt921x_reg_write(priv, YT921X_METER_SLOT, ctrl);
+ if (res)
+ return res;
+ priv->meter_slot_ns = ctrl * op_ns;
+
+ return 0;
+}
+
static int __maybe_unused yt921x_chip_setup_qos(struct yt921x_priv *priv)
{
u32 ctrl;
@@ -3259,7 +3573,7 @@ static int yt921x_chip_setup(struct yt921x_priv *priv)
u32 ctrl;
int res;
- ctrl = YT921X_FUNC_MIB;
+ ctrl = YT921X_FUNC_MIB | YT921X_FUNC_METER;
res = yt921x_reg_set_bits(priv, YT921X_FUNC, ctrl);
if (res)
return res;
@@ -3268,6 +3582,10 @@ static int yt921x_chip_setup(struct yt921x_priv *priv)
if (res)
return res;
+ res = yt921x_chip_setup_tc(priv);
+ if (res)
+ return res;
+
#if IS_ENABLED(CONFIG_DCB)
res = yt921x_chip_setup_qos(priv);
if (res)
@@ -3359,6 +3677,9 @@ static const struct dsa_switch_ops yt921x_dsa_switch_ops = {
/* mtu */
.port_change_mtu = yt921x_dsa_port_change_mtu,
.port_max_mtu = yt921x_dsa_port_max_mtu,
+ /* rate */
+ .port_policer_del = yt921x_dsa_port_policer_del,
+ .port_policer_add = yt921x_dsa_port_policer_add,
/* hsr */
.port_hsr_leave = dsa_port_simple_hsr_leave,
.port_hsr_join = dsa_port_simple_hsr_join,
diff --git a/drivers/net/dsa/yt921x.h b/drivers/net/dsa/yt921x.h
index 4989d87c2492..546b12a8994a 100644
--- a/drivers/net/dsa/yt921x.h
+++ b/drivers/net/dsa/yt921x.h
@@ -23,6 +23,7 @@
#define YT921X_RST_HW BIT(31)
#define YT921X_RST_SW BIT(1)
#define YT921X_FUNC 0x80004
+#define YT921X_FUNC_METER BIT(4)
#define YT921X_FUNC_MIB BIT(1)
#define YT921X_CHIP_ID 0x80008
#define YT921X_CHIP_ID_MAJOR GENMASK(31, 16)
@@ -239,6 +240,11 @@
#define YT921X_EDATA_DATA_STATUS_M GENMASK(3, 0)
#define YT921X_EDATA_DATA_STATUS(x) FIELD_PREP(YT921X_EDATA_DATA_STATUS_M, (x))
#define YT921X_EDATA_DATA_IDLE YT921X_EDATA_DATA_STATUS(3)
+#define YT921X_SYS_CLK 0xe0040
+#define YT921X_SYS_CLK_SEL_M GENMASK(1, 0) /* unknown: 167M */
+#define YT9215_SYS_CLK_125M 0
+#define YT9218_SYS_CLK_167M 0
+#define YT921X_SYS_CLK_143M 1
#define YT921X_EXT_MBUS_OP 0x6a000
#define YT921X_INT_MBUS_OP 0xf0000
@@ -465,6 +471,39 @@ enum yt921x_app_selector {
#define YT921X_LAG_HASH_MAC_DA BIT(1)
#define YT921X_LAG_HASH_SRC_PORT BIT(0)
+#define YT921X_PORTn_RATE(port) (0x220000 + 4 * (port))
+#define YT921X_PORT_RATE_GAP_VALUE GENMASK(4, 0) /* default 20 */
+#define YT921X_METER_SLOT 0x220104
+#define YT921X_METER_SLOT_SLOT_M GENMASK(11, 0)
+#define YT921X_PORTn_METER(port) (0x220108 + 4 * (port))
+#define YT921X_PORT_METER_EN BIT(4)
+#define YT921X_PORT_METER_ID_M GENMASK(3, 0)
+#define YT921X_PORT_METER_ID(x) FIELD_PREP(YT921X_PORT_METER_ID_M, (x))
+#define YT921X_METERn_CTRL(x) (0x220800 + 0x10 * (x))
+#define YT921X_METER_CTRLc_METER_EN BIT(14)
+#define YT921X_METER_CTRLc_TOKEN_OVERFLOW_EN BIT(13) /* RFC4115: yellow use unused green bw */
+#define YT921X_METER_CTRLc_DROP_M GENMASK(12, 11)
+#define YT921X_METER_CTRLc_DROP(x) FIELD_PREP(YT921X_METER_CTRLc_DROP_M, (x))
+#define YT921X_METER_CTRLc_DROP_GYR YT921X_METER_CTRLc_DROP(0)
+#define YT921X_METER_CTRLc_DROP_YR YT921X_METER_CTRLc_DROP(1)
+#define YT921X_METER_CTRLc_DROP_R YT921X_METER_CTRLc_DROP(2)
+#define YT921X_METER_CTRLc_DROP_NONE YT921X_METER_CTRLc_DROP(3)
+#define YT921X_METER_CTRLc_COLOR_BLIND BIT(10)
+#define YT921X_METER_CTRLc_UNIT_M GENMASK(9, 7)
+#define YT921X_METER_CTRLc_UNIT(x) FIELD_PREP(YT921X_METER_CTRLc_UNIT_M, (x))
+#define YT921X_METER_CTRLc_BYTE_MODE_INCLUDE_GAP BIT(6) /* +GAP_VALUE bytes each packet */
+#define YT921X_METER_CTRLc_PKT_MODE BIT(5) /* 0: byte rate mode */
+#define YT921X_METER_CTRLc_RFC2698 BIT(4) /* 0: RFC4115 */
+#define YT921X_METER_CTRLbc_CBS_M GENMASK_ULL(35, 20)
+#define YT921X_METER_CTRLbc_CBS(x) FIELD_PREP(YT921X_METER_CTRLbc_CBS_M, (x))
+#define YT921X_METER_CTRLb_CIR_M GENMASK(19, 2)
+#define YT921X_METER_CTRLb_CIR(x) FIELD_PREP(YT921X_METER_CTRLb_CIR_M, (x))
+#define YT921X_METER_CTRLab_EBS_M GENMASK_ULL(33, 18)
+#define YT921X_METER_CTRLab_EBS(x) FIELD_PREP(YT921X_METER_CTRLab_EBS_M, (x))
+#define YT921X_METER_CTRLa_EIR_M GENMASK(17, 0)
+#define YT921X_METER_CTRLa_EIR(x) FIELD_PREP(YT921X_METER_CTRLa_EIR_M, (x))
+#define YT921X_METERn_STAT(x) (0x221000 + 8 * (x))
+
#define YT921X_PORTn_VLAN_CTRL(port) (0x230010 + 4 * (port))
#define YT921X_PORT_VLAN_CTRL_SVLAN_PRIO_EN BIT(31)
#define YT921X_PORT_VLAN_CTRL_CVLAN_PRIO_EN BIT(30)
@@ -508,6 +547,16 @@ enum yt921x_fdb_entry_status {
#define YT921X_MSTI_NUM 16
+#define YT921X_TOKEN_BYTE_C 1 /* 1 token = 2^1 byte */
+#define YT921X_TOKEN_PKT_C -6 /* 1 token = 2^-6 packets */
+#define YT921X_TOKEN_RATE_C -15
+/* Custom meters only, not including dedicated port meters (11) */
+#define YT921X_METER_NUM 64
+#define YT921X_METER_SLOT_MIN 80
+#define YT921X_METER_UNIT_MAX ((1 << 3) - 1)
+#define YT921X_METER_CIR_MAX ((1 << 18) - 1)
+#define YT921X_METER_CBS_MAX ((1 << 16) - 1)
+
#define YT921X_LAG_NUM 2
#define YT921X_LAG_PORT_NUM 4
@@ -602,8 +651,10 @@ struct yt921x_priv {
struct dsa_switch ds;
const struct yt921x_info *info;
+ unsigned int meter_slot_ns;
/* cache of dsa_cpu_ports(ds) */
u16 cpu_ports_mask;
+ unsigned char cycle_ns;
/* protect the access to the switch registers */
struct mutex reg_lock;
--
2.53.0
^ permalink raw reply related
* [PATCH net-next v5 2/3] net: dsa: yt921x: Refactor long register helpers
From: David Yang @ 2026-04-28 11:26 UTC (permalink / raw)
To: netdev
Cc: David Yang, Andrew Lunn, Vladimir Oltean, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, linux-kernel
In-Reply-To: <20260428112606.1917230-1-mmyangfl@gmail.com>
Dealing long registers with u64 is good, until you realize there are
longer 96-bit registers.
Refactor reg64 helpers to use u32 arrays instead of u64 values, in
preparation for 96-bit registers. We do not keep the separate u64
version for reg64 to avoid duplicated wrappers, although it looks better
when dealing with reg64 *only*.
Helpers for reg96 should be added when they are actually used to avoid
function unused warnings.
Signed-off-by: David Yang <mmyangfl@gmail.com>
---
drivers/net/dsa/yt921x.c | 162 +++++++++++++++++++++++++++------------
drivers/net/dsa/yt921x.h | 36 ++++-----
2 files changed, 129 insertions(+), 69 deletions(-)
diff --git a/drivers/net/dsa/yt921x.c b/drivers/net/dsa/yt921x.c
index 87139448bec3..0c07b903fd68 100644
--- a/drivers/net/dsa/yt921x.c
+++ b/drivers/net/dsa/yt921x.c
@@ -255,63 +255,122 @@ yt921x_reg_toggle_bits(struct yt921x_priv *priv, u32 reg, u32 mask, bool set)
return yt921x_reg_update_bits(priv, reg, mask, !set ? 0 : mask);
}
-/* Some registers, like VLANn_CTRL, should always be written in 64-bit, even if
- * you are to write only the lower / upper 32 bits.
+/* Some multi-word registers, like VLANn_CTRL, should be treated as a single
+ * long register. More specifically, writes to parts of its words won't become
+ * visible, until the last word is written.
*
- * There is no such restriction for reading, but we still provide 64-bit read
- * wrappers so that we always handle u64 values.
+ * Here we require full read and write operations over these registers to
+ * eliminate potential issues, although partial reads/writes are also possible.
*/
-static int yt921x_reg64_read(struct yt921x_priv *priv, u32 reg, u64 *valp)
+static int
+yt921x_regs_read(struct yt921x_priv *priv, u32 reg, u32 *vals,
+ unsigned int num_regs)
{
- u32 lo;
- u32 hi;
int res;
- res = yt921x_reg_read(priv, reg, &lo);
- if (res)
- return res;
- res = yt921x_reg_read(priv, reg + 4, &hi);
- if (res)
- return res;
+ for (unsigned int i = 0; i < num_regs; i++) {
+ res = yt921x_reg_read(priv, reg + 4 * i, &vals[i]);
+ if (res)
+ return res;
+ }
+
+ return 0;
+}
+
+static int
+yt921x_regs_write(struct yt921x_priv *priv, u32 reg, const u32 *vals,
+ unsigned int num_regs)
+{
+ int res;
+
+ for (unsigned int i = 0; i < num_regs; i++) {
+ res = yt921x_reg_write(priv, reg + 4 * i, vals[i]);
+ if (res)
+ return res;
+ }
- *valp = ((u64)hi << 32) | lo;
return 0;
}
-static int yt921x_reg64_write(struct yt921x_priv *priv, u32 reg, u64 val)
+static int
+yt921x_regs_update_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks,
+ const u32 *vals, unsigned int num_regs)
{
+ bool changed = false;
+ u32 vs[4];
int res;
- res = yt921x_reg_write(priv, reg, (u32)val);
+ BUILD_BUG_ON(num_regs > ARRAY_SIZE(vs));
+
+ res = yt921x_regs_read(priv, reg, vs, num_regs);
if (res)
return res;
- return yt921x_reg_write(priv, reg + 4, (u32)(val >> 32));
+
+ for (unsigned int i = 0; i < num_regs; i++) {
+ u32 u = vs[i];
+
+ u &= ~masks[i];
+ u |= vals[i];
+ if (u != vs[i])
+ changed = true;
+
+ vs[i] = u;
+ }
+
+ if (!changed)
+ return 0;
+
+ return yt921x_regs_write(priv, reg, vs, num_regs);
}
static int
-yt921x_reg64_update_bits(struct yt921x_priv *priv, u32 reg, u64 mask, u64 val)
+yt921x_regs_clear_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks,
+ unsigned int num_regs)
{
+ bool changed = false;
+ u32 vs[4];
int res;
- u64 v;
- u64 u;
- res = yt921x_reg64_read(priv, reg, &v);
+ BUILD_BUG_ON(num_regs > ARRAY_SIZE(vs));
+
+ res = yt921x_regs_read(priv, reg, vs, num_regs);
if (res)
return res;
- u = v;
- u &= ~mask;
- u |= val;
- if (u == v)
+ for (unsigned int i = 0; i < num_regs; i++) {
+ u32 u = vs[i];
+
+ u &= ~masks[i];
+ if (u != vs[i])
+ changed = true;
+
+ vs[i] = u;
+ }
+
+ if (!changed)
return 0;
- return yt921x_reg64_write(priv, reg, u);
+ return yt921x_regs_write(priv, reg, vs, num_regs);
+}
+
+static int
+yt921x_reg64_write(struct yt921x_priv *priv, u32 reg, const u32 *vals)
+{
+ return yt921x_regs_write(priv, reg, vals, 2);
}
-static int yt921x_reg64_clear_bits(struct yt921x_priv *priv, u32 reg, u64 mask)
+static int
+yt921x_reg64_update_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks,
+ const u32 *vals)
{
- return yt921x_reg64_update_bits(priv, reg, mask, 0);
+ return yt921x_regs_update_bits(priv, reg, masks, vals, 2);
+}
+
+static int
+yt921x_reg64_clear_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks)
+{
+ return yt921x_regs_clear_bits(priv, reg, masks, 2);
}
static int yt921x_reg_mdio_read(void *context, u32 reg, u32 *valp)
@@ -1844,33 +1903,31 @@ yt921x_vlan_filtering(struct yt921x_priv *priv, int port, bool vlan_filtering)
return 0;
}
-static int
-yt921x_vlan_del(struct yt921x_priv *priv, int port, u16 vid)
+static int yt921x_vlan_del(struct yt921x_priv *priv, int port, u16 vid)
{
- u64 mask64;
+ u32 masks[2];
- mask64 = YT921X_VLAN_CTRL_PORTS(port) |
- YT921X_VLAN_CTRL_UNTAG_PORTn(port);
+ masks[0] = YT921X_VLAN_CTRLa_PORTn(port);
+ masks[1] = YT921X_VLAN_CTRLb_UNTAG_PORTn(port);
- return yt921x_reg64_clear_bits(priv, YT921X_VLANn_CTRL(vid), mask64);
+ return yt921x_reg64_clear_bits(priv, YT921X_VLANn_CTRL(vid), masks);
}
static int
yt921x_vlan_add(struct yt921x_priv *priv, int port, u16 vid, bool untagged)
{
- u64 mask64;
- u64 ctrl64;
+ u32 masks[2];
+ u32 ctrls[2];
- mask64 = YT921X_VLAN_CTRL_PORTn(port) |
- YT921X_VLAN_CTRL_PORTS(priv->cpu_ports_mask);
- ctrl64 = mask64;
+ masks[0] = YT921X_VLAN_CTRLa_PORTn(port) |
+ YT921X_VLAN_CTRLa_PORTS(priv->cpu_ports_mask);
+ ctrls[0] = masks[0];
- mask64 |= YT921X_VLAN_CTRL_UNTAG_PORTn(port);
- if (untagged)
- ctrl64 |= YT921X_VLAN_CTRL_UNTAG_PORTn(port);
+ masks[1] = YT921X_VLAN_CTRLb_UNTAG_PORTn(port);
+ ctrls[1] = untagged ? masks[1] : 0;
return yt921x_reg64_update_bits(priv, YT921X_VLANn_CTRL(vid),
- mask64, ctrl64);
+ masks, ctrls);
}
static int
@@ -2318,8 +2375,8 @@ yt921x_dsa_vlan_msti_set(struct dsa_switch *ds, struct dsa_bridge bridge,
const struct switchdev_vlan_msti *msti)
{
struct yt921x_priv *priv = to_yt921x_priv(ds);
- u64 mask64;
- u64 ctrl64;
+ u32 masks[2];
+ u32 ctrls[2];
int res;
if (!msti->vid)
@@ -2327,12 +2384,14 @@ yt921x_dsa_vlan_msti_set(struct dsa_switch *ds, struct dsa_bridge bridge,
if (!msti->msti || msti->msti >= YT921X_MSTI_NUM)
return -EINVAL;
- mask64 = YT921X_VLAN_CTRL_STP_ID_M;
- ctrl64 = YT921X_VLAN_CTRL_STP_ID(msti->msti);
+ masks[0] = 0;
+ ctrls[0] = 0;
+ masks[1] = YT921X_VLAN_CTRLb_STP_ID_M;
+ ctrls[1] = YT921X_VLAN_CTRLb_STP_ID(msti->msti);
mutex_lock(&priv->reg_lock);
res = yt921x_reg64_update_bits(priv, YT921X_VLANn_CTRL(msti->vid),
- mask64, ctrl64);
+ masks, ctrls);
mutex_unlock(&priv->reg_lock);
return res;
@@ -3084,7 +3143,7 @@ static int yt921x_chip_setup_dsa(struct yt921x_priv *priv)
{
struct dsa_switch *ds = &priv->ds;
unsigned long cpu_ports_mask;
- u64 ctrl64;
+ u32 ctrls[2];
u32 ctrl;
int port;
int res;
@@ -3145,8 +3204,9 @@ static int yt921x_chip_setup_dsa(struct yt921x_priv *priv)
/* Tagged VID 0 should be treated as untagged, which confuses the
* hardware a lot
*/
- ctrl64 = YT921X_VLAN_CTRL_LEARN_DIS | YT921X_VLAN_CTRL_PORTS_M;
- res = yt921x_reg64_write(priv, YT921X_VLANn_CTRL(0), ctrl64);
+ ctrls[0] = YT921X_VLAN_CTRLa_LEARN_DIS | YT921X_VLAN_CTRLa_PORTS_M;
+ ctrls[1] = 0;
+ res = yt921x_reg64_write(priv, YT921X_VLANn_CTRL(0), ctrls);
if (res)
return res;
diff --git a/drivers/net/dsa/yt921x.h b/drivers/net/dsa/yt921x.h
index 3f129b8d403f..4989d87c2492 100644
--- a/drivers/net/dsa/yt921x.h
+++ b/drivers/net/dsa/yt921x.h
@@ -429,24 +429,24 @@ enum yt921x_app_selector {
#define YT921X_FDB_HW_FLUSH_ON_LINKDOWN BIT(0)
#define YT921X_VLANn_CTRL(vlan) (0x188000 + 8 * (vlan))
-#define YT921X_VLAN_CTRL_UNTAG_PORTS_M GENMASK_ULL(50, 40)
-#define YT921X_VLAN_CTRL_UNTAG_PORTS(x) FIELD_PREP(YT921X_VLAN_CTRL_UNTAG_PORTS_M, (x))
-#define YT921X_VLAN_CTRL_UNTAG_PORTn(port) BIT_ULL((port) + 40)
-#define YT921X_VLAN_CTRL_STP_ID_M GENMASK_ULL(39, 36)
-#define YT921X_VLAN_CTRL_STP_ID(x) FIELD_PREP(YT921X_VLAN_CTRL_STP_ID_M, (x))
-#define YT921X_VLAN_CTRL_SVLAN_EN BIT_ULL(35)
-#define YT921X_VLAN_CTRL_FID_M GENMASK_ULL(34, 23)
-#define YT921X_VLAN_CTRL_FID(x) FIELD_PREP(YT921X_VLAN_CTRL_FID_M, (x))
-#define YT921X_VLAN_CTRL_LEARN_DIS BIT_ULL(22)
-#define YT921X_VLAN_CTRL_PRIO_EN BIT_ULL(21)
-#define YT921X_VLAN_CTRL_PRIO_M GENMASK_ULL(20, 18)
-#define YT921X_VLAN_CTRL_PRIO(x) FIELD_PREP(YT921X_VLAN_CTRL_PRIO_M, (x))
-#define YT921X_VLAN_CTRL_PORTS_M GENMASK_ULL(17, 7)
-#define YT921X_VLAN_CTRL_PORTS(x) FIELD_PREP(YT921X_VLAN_CTRL_PORTS_M, (x))
-#define YT921X_VLAN_CTRL_PORTn(port) BIT_ULL((port) + 7)
-#define YT921X_VLAN_CTRL_BYPASS_1X_AC BIT_ULL(6)
-#define YT921X_VLAN_CTRL_METER_EN BIT_ULL(5)
-#define YT921X_VLAN_CTRL_METER_ID_M GENMASK_ULL(4, 0)
+#define YT921X_VLAN_CTRLb_UNTAG_PORTS_M GENMASK(18, 8)
+#define YT921X_VLAN_CTRLb_UNTAG_PORTS(x) FIELD_PREP(YT921X_VLAN_CTRLb_UNTAG_PORTS_M, (x))
+#define YT921X_VLAN_CTRLb_UNTAG_PORTn(port) BIT((port) + 8)
+#define YT921X_VLAN_CTRLb_STP_ID_M GENMASK(7, 4)
+#define YT921X_VLAN_CTRLb_STP_ID(x) FIELD_PREP(YT921X_VLAN_CTRLb_STP_ID_M, (x))
+#define YT921X_VLAN_CTRLb_SVLAN_EN BIT(3)
+#define YT921X_VLAN_CTRLab_FID_M GENMASK_ULL(34, 23)
+#define YT921X_VLAN_CTRLab_FID(x) FIELD_PREP(YT921X_VLAN_CTRLab_FID_M, (x))
+#define YT921X_VLAN_CTRLa_LEARN_DIS BIT(22)
+#define YT921X_VLAN_CTRLa_PRIO_EN BIT(21)
+#define YT921X_VLAN_CTRLa_PRIO_M GENMASK(20, 18)
+#define YT921X_VLAN_CTRLa_PRIO(x) FIELD_PREP(YT921X_VLAN_CTRLa_PRIO_M, (x))
+#define YT921X_VLAN_CTRLa_PORTS_M GENMASK(17, 7)
+#define YT921X_VLAN_CTRLa_PORTS(x) FIELD_PREP(YT921X_VLAN_CTRLa_PORTS_M, (x))
+#define YT921X_VLAN_CTRLa_PORTn(port) BIT((port) + 7)
+#define YT921X_VLAN_CTRLa_BYPASS_1X_AC BIT(6)
+#define YT921X_VLAN_CTRLa_METER_EN BIT(5)
+#define YT921X_VLAN_CTRLa_METER_ID_M GENMASK(4, 0)
#define YT921X_TPID_IGRn(x) (0x210000 + 4 * (x)) /* [0, 3] */
#define YT921X_TPID_IGR_TPID_M GENMASK(15, 0)
--
2.53.0
^ permalink raw reply related
* [PATCH net-next v5 1/3] net: dsa: pass extack to dsa_switch_ops :: port_policer_add()
From: David Yang @ 2026-04-28 11:26 UTC (permalink / raw)
To: netdev
Cc: David Yang, Andrew Lunn, Vladimir Oltean, UNGLinuxDriver,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, linux-kernel
In-Reply-To: <20260428112606.1917230-1-mmyangfl@gmail.com>
Drivers might have error messages to propagate to user space. Propagate
the netlink extack so that they can inform user space in a verbal way of
their limitations.
Make the according transformations to the two users (sja1105 and felix).
Signed-off-by: David Yang <mmyangfl@gmail.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
---
drivers/net/dsa/ocelot/felix.c | 3 ++-
drivers/net/dsa/sja1105/sja1105_main.c | 3 ++-
include/net/dsa.h | 3 ++-
net/dsa/user.c | 2 +-
4 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/drivers/net/dsa/ocelot/felix.c b/drivers/net/dsa/ocelot/felix.c
index 84cf8e7fb17a..4272ea6e9ca8 100644
--- a/drivers/net/dsa/ocelot/felix.c
+++ b/drivers/net/dsa/ocelot/felix.c
@@ -2001,7 +2001,8 @@ static int felix_cls_flower_stats(struct dsa_switch *ds, int port,
}
static int felix_port_policer_add(struct dsa_switch *ds, int port,
- const struct flow_action_police *policer)
+ const struct flow_action_police *policer,
+ struct netlink_ext_ack *extack)
{
struct ocelot *ocelot = ds->priv;
struct ocelot_policer pol = {
diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c
index c72c2bfdcffb..dbfa45064747 100644
--- a/drivers/net/dsa/sja1105/sja1105_main.c
+++ b/drivers/net/dsa/sja1105/sja1105_main.c
@@ -2847,7 +2847,8 @@ static void sja1105_mirror_del(struct dsa_switch *ds, int port,
}
static int sja1105_port_policer_add(struct dsa_switch *ds, int port,
- const struct flow_action_police *policer)
+ const struct flow_action_police *policer,
+ struct netlink_ext_ack *extack)
{
struct sja1105_l2_policing_entry *policing;
struct sja1105_private *priv = ds->priv;
diff --git a/include/net/dsa.h b/include/net/dsa.h
index 8b6d34e8a6f0..4cc67469cf2e 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -1122,7 +1122,8 @@ struct dsa_switch_ops {
void (*port_mirror_del)(struct dsa_switch *ds, int port,
struct dsa_mall_mirror_tc_entry *mirror);
int (*port_policer_add)(struct dsa_switch *ds, int port,
- const struct flow_action_police *policer);
+ const struct flow_action_police *policer,
+ struct netlink_ext_ack *extack);
void (*port_policer_del)(struct dsa_switch *ds, int port);
int (*port_setup_tc)(struct dsa_switch *ds, int port,
enum tc_setup_type type, void *type_data);
diff --git a/net/dsa/user.c b/net/dsa/user.c
index c4bd6fe90b45..8704c1a3a5b7 100644
--- a/net/dsa/user.c
+++ b/net/dsa/user.c
@@ -1499,7 +1499,7 @@ dsa_user_add_cls_matchall_police(struct net_device *dev,
policer = &mall_tc_entry->policer;
*policer = act->police;
- err = ds->ops->port_policer_add(ds, dp->index, policer);
+ err = ds->ops->port_policer_add(ds, dp->index, policer, extack);
if (err) {
kfree(mall_tc_entry);
return err;
--
2.53.0
^ permalink raw reply related
* [PATCH net-next v5 0/3] net: dsa: yt921x: Add port police support
From: David Yang @ 2026-04-28 11:26 UTC (permalink / raw)
To: netdev
Cc: David Yang, Vladimir Oltean, UNGLinuxDriver, Andrew Lunn,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, linux-kernel, Vladimir Oltean
v4: https://lore.kernel.org/r/20260409171209.2575583-1-mmyangfl@gmail.com
- split series and drop patch for qdisc tbf
v3: https://lore.kernel.org/r/20260407160559.1747616-1-mmyangfl@gmail.com
- explain long registers more accurately
- fix missing packet mode flag
- rearrange function layout, in preparation for further patches
v2: https://lore.kernel.org/r/20260402223437.109097-1-mmyangfl@gmail.com
- refine commit messages and code styles, no functional changes
v1: https://lore.kernel.org/r/20260225090853.2021140-1-mmyangfl@gmail.com
- pass extack to user tc policers
- keep reg64 helpers along with reg96
- avoid macros in favor of functions
- adjust log messages
David Yang (3):
net: dsa: pass extack to dsa_switch_ops :: port_policer_add()
net: dsa: yt921x: Refactor long register helpers
net: dsa: yt921x: Add port police support
drivers/net/dsa/ocelot/felix.c | 3 +-
drivers/net/dsa/sja1105/sja1105_main.c | 3 +-
drivers/net/dsa/yt921x.c | 485 ++++++++++++++++++++++---
drivers/net/dsa/yt921x.h | 87 ++++-
include/net/dsa.h | 3 +-
net/dsa/user.c | 2 +-
6 files changed, 509 insertions(+), 74 deletions(-)
--
2.53.0
^ permalink raw reply
* Re: [PATCH net v3] ipv6: validate extension header length before copying to cmsg
From: Paolo Abeni @ 2026-04-28 11:24 UTC (permalink / raw)
To: Qi Tang, David S . Miller, David Ahern, Eric Dumazet,
Jakub Kicinski, Simon Horman
Cc: netdev, linux-kernel
In-Reply-To: <20260423103238.3987364-1-tpluszz77@gmail.com>
On 4/23/26 12:32 PM, Qi Tang wrote:
> ip6_datagram_recv_specific_ctl() builds IPV6_{HOPOPTS,DSTOPTS,RTHDR}
> cmsgs (and their IPV6_2292* legacy counterparts) by trusting the
> on-wire hdrlen byte (ptr[1]) when computing the put_cmsg() length.
> The length was validated only at parse time (ipv6_parse_hopopts(),
> etc.). An nftables payload-write expression can rewrite hdrlen after
> parsing and before the skb reaches recvmsg; the write itself is
> in-bounds but put_cmsg() then reads up to ((hdrlen+1) << 3) = 2040
> bytes from an 8-byte header. nftables is reachable from an
> unprivileged user namespace, so this is an unprivileged
> slab-out-of-bounds read:
>
> BUG: KASAN: slab-out-of-bounds in put_cmsg+0x3ac/0x540
> put_cmsg+0x3ac/0x540
> udpv6_recvmsg+0xca0/0x1250
> sock_recvmsg+0xdf/0x190
> ____sys_recvmsg+0x1b1/0x620
>
> Add ipv6_get_exthdr_len() which computes the extension header length
> and validates it against skb_tail_pointer(skb), returning 0 on
> failure. Extension headers are kept in the linear skb area by
> pskb_may_pull() during input, so skb_tail_pointer() is the correct
> bound.
>
> Use ipv6_get_exthdr_len() at all non-AH call sites: the five
> standalone cmsg blocks (HbH, 2292HbH, 2292DSTOPTS x2, 2292RTHDR)
> and the three standard cases in the extension-header walk loop
> (DSTOPTS, ROUTING, default). AH retains an inline bounds check
> because its length formula differs ((ptr[1]+2)<<2).
>
> When the walk loop detects a corrupted header, return from the
> function instead of continuing to process later socket options.
>
> Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
> Signed-off-by: Qi Tang <tpluszz77@gmail.com>
> ---
> Changes v2 -> v3:
> - Resend as new thread (v2 was incorrectly sent as reply to v1)
>
> Changes v1 -> v2 (Paolo Abeni):
> - Factor repeated bounds-check + put_cmsg into ipv6_get_exthdr_len()
> - Return from the function on corrupted walk-loop entry instead of
> goto + empty label
>
> v2: https://lore.kernel.org/netdev/20260423102255.3752004-1-tpluszz77@gmail.com/
> v1: https://lore.kernel.org/netdev/20260419150344.624673-1-tpluszz77@gmail.com/
>
> net/ipv6/datagram.c | 46 +++++++++++++++++++++++++++++++++++++--------
> 1 file changed, 38 insertions(+), 8 deletions(-)
>
> diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
> index 972bf0426d59..0a7b74d5f402 100644
> --- a/net/ipv6/datagram.c
> +++ b/net/ipv6/datagram.c
> @@ -617,6 +617,13 @@ void ip6_datagram_recv_common_ctl(struct sock *sk, struct msghdr *msg,
> }
> }
>
> +static u16 ipv6_get_exthdr_len(const struct sk_buff *skb, const u8 *ptr)
> +{
> + u16 len = (ptr[1] + 1) << 3;
Sashiko notes that you should validate even this offset (1) before
accessing it.
You may also consider switching to pskb_may_pull().
/P
^ permalink raw reply
* [PATCH 1/1] nfc: llcp: fix use-after-free in llcp_sock_release()
From: Lee Jones @ 2026-04-28 11:22 UTC (permalink / raw)
To: lee, David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Kees Cook, netdev, linux-kernel
llcp_sock_release() unconditionally unlinks the socket from the local
sockets list. However, if the socket is still in connecting state, it
is on the connecting list.
Fix this by checking the socket state and unlinking from the correct list.
Signed-off-by: Lee Jones <lee@kernel.org>
---
net/nfc/llcp_sock.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/net/nfc/llcp_sock.c b/net/nfc/llcp_sock.c
index f1be1e84f6653..feab29fc62f44 100644
--- a/net/nfc/llcp_sock.c
+++ b/net/nfc/llcp_sock.c
@@ -633,6 +633,8 @@ static int llcp_sock_release(struct socket *sock)
if (sock->type == SOCK_RAW)
nfc_llcp_sock_unlink(&local->raw_sockets, sk);
+ else if (sk->sk_state == LLCP_CONNECTING)
+ nfc_llcp_sock_unlink(&local->connecting_sockets, sk);
else
nfc_llcp_sock_unlink(&local->sockets, sk);
--
2.54.0.545.g6539524ca2-goog
^ permalink raw reply related
* Re: [PATCH net v1 1/2] ipv6: update route serial number on NETDEV_CHANGE
From: Eric Dumazet @ 2026-04-28 11:21 UTC (permalink / raw)
To: Ido Schimmel
Cc: Sagarika Sharma, David S . Miller, David Ahern, Jakub Kicinski,
Paolo Abeni, Shuah Khan, Simon Horman, Kuniyuki Iwashima, netdev,
linux-kselftest
In-Reply-To: <20260428110708.GA571865@shredder>
On Tue, Apr 28, 2026 at 4:07 AM Ido Schimmel <idosch@nvidia.com> wrote:
>
> On Mon, Apr 27, 2026 at 10:42:22PM +0000, Sagarika Sharma wrote:
> > When using IPv6 ECMP routes, if a netdev listed as a nexthop experiences
> > a carrier change event (e.g., a bond device generating a NETDEV_CHANGE
> > event after its slaves go linkdown), established connections utilizing
> > that nexthop fail to fail over to other available nexthops. Instead,
> > these connections stall or drop.
> >
> > This happens because the IPv6 FIB code does not invalidate the socket's
> > cached destination when a NETDEV_CHANGE event occurs. While
> > fib6_ifdown() correctly marks the nexthop with RTNH_F_LINKDOWN, it
> > leaves the route's serial number unchanged. As a result, sockets with a
> > previously cached dst do not realize the route is no longer viable and
> > continue to try using the non-functional nexthop.
> >
> > This behavior contrasts with IPv4, which actively flushes cached
> > destinations on a NETDEV_CHANGE event (see fib_netdev_event() in
> > net/ipv4/fib_frontend.c).
> >
> > Fix this by updating the route serial number in fib6_ifdown() when
> > setting RTNH_F_LINKDOWN. This invalidates stale cached destinations,
> > forcing sockets to perform a new route lookup and fail over to a
> > functioning nexthop.
> >
> > Fixes: 51ebd3181572 ("ipv6: add support of equal cost multipath (ECMP)")
> > Signed-off-by: Sagarika Sharma <sharmasagarika@google.com>
> > Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
>
> Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Reviewed-by: Eric Dumazet <edumazet@google.com>
Thanks!
^ permalink raw reply
* Re: [RFC PATCH v1 7/9] x86: Add unsafe_copy_from_user()
From: Segher Boessenkool @ 2026-04-28 11:20 UTC (permalink / raw)
To: Yury Norov
Cc: Linus Torvalds, Christophe Leroy (CS GROUP), Andrew Morton,
David Laight, Thomas Gleixner, linux-alpha, Yury Norov,
linux-kernel, linux-snps-arc, linux-arm-kernel, linux-mips,
linuxppc-dev, kvm, linux-riscv, linux-s390, sparclinux, linux-um,
dmaengine, linux-efi, linux-fsi, amd-gfx, dri-devel, intel-gfx,
linux-wpan, netdev, linux-wireless, linux-spi, linux-media,
linux-staging, linux-serial, linux-usb, xen-devel, linux-fsdevel,
ocfs2-devel, bpf, kasan-dev, linux-mm, linux-x25, rust-for-linux,
linux-sound, sound-open-firmware, linux-csky, linux-hexagon,
loongarch, linux-m68k, linux-openrisc, linux-parisc, linux-sh,
linux-arch
In-Reply-To: <ae_jeJLlVWjJ4sOY@yury>
Hi!
On Mon, Apr 27, 2026 at 06:30:16PM -0400, Yury Norov wrote:
> On Mon, Apr 27, 2026 at 02:52:05PM -0700, Linus Torvalds wrote:
> > On Mon, 27 Apr 2026 at 12:19, Yury Norov <ynorov@nvidia.com> wrote:
> > >
> > > This is what Linus said when added x86 implementation for copy_from_user()
> > > in c512c69187197:
> >
> > Note that some things have happily changed in the six+ years since...
> >
> > > That's partly because we have no current users of it, but also partly
> > > because the copy_from_user() case is slightly different and cannot
> > > efficiently be implemented in terms of a unsafe_get_user() loop (because
> > > gcc can't do asm goto with outputs).
> >
> > now everybody can do asm goto with outputs.
> >
> > Yes, it's disabled on older versions, so it's not *always* available,
> > but all modern versions do it. And if you care about performance, you
> > won't be using an old compiler.
>
> The minimal GCC version is 8.1, and asm goto with outputs is supported
> since GCC-11. That would brake the build, if we just switch to using it
> without "CC_IS_GCC && (GCC_VERSION >= 110100)" guard.
>
> Is it worth to maintain 2 version of the function? I don't know...
GCC 11 was released five years and a day ago. The last GCC 11 release
(that of 11.5) is not even two years ago though (but there will be no
more!)
So it would be not conservative at all to require GCC 11 as minimum now,
some people might even call it a bit aggressive. But in a year (or
maybe two) the lay of the land will be rather different.
Segher
^ permalink raw reply
* Re: [PATCH net v2] net: mctp i2c: check length before marking flow active
From: patchwork-bot+netdevbpf @ 2026-04-28 11:20 UTC (permalink / raw)
To: William A. Kennington III
Cc: jk, matt, andrew+netdev, davem, edumazet, kuba, pabeni, wsa,
netdev, linux-kernel
In-Reply-To: <20260423074741.201460-1-william@wkennington.com>
Hello:
This patch was applied to netdev/net.git (main)
by Paolo Abeni <pabeni@redhat.com>:
On Thu, 23 Apr 2026 00:46:52 -0700 you wrote:
> Currently, mctp_i2c_get_tx_flow_state() is called before the packet length
> sanity check. This function marks a new flow as active in the MCTP core.
>
> If the sanity check fails, mctp_i2c_xmit() returns early without calling
> mctp_i2c_lock_nest(). This results in a mismatched locking state: the
> flow is active, but the I2C bus lock was never acquired for it.
>
> [...]
Here is the summary with links:
- [net,v2] net: mctp i2c: check length before marking flow active
https://git.kernel.org/netdev/net/c/4ca07b9239bd
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* Re: [PATCH net v1 2/2] selftest: net: Add test for TCP flow failover with ECMP routes.
From: Ido Schimmel @ 2026-04-28 11:18 UTC (permalink / raw)
To: Sagarika Sharma
Cc: David S . Miller, David Ahern, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Shuah Khan, Simon Horman, Kuniyuki Iwashima, netdev,
linux-kselftest
In-Reply-To: <20260427224243.3499162-3-sharmasagarika@google.com>
On Mon, Apr 27, 2026 at 10:42:23PM +0000, Sagarika Sharma wrote:
> From: Kuniyuki Iwashima <kuniyu@google.com>
>
> Without the previous commit, TCP failed to switch to alternative
> IPv6 routes immediately upon carrier loss.
>
> It would persist with the dead route until reaching the threshold
> net.ipv4.tcp_retries1, leading to unnecessary delays in failover.
>
> Let's add a selftest for this scenario to ensure TCP fails over
> immediately upon a carrier loss event.
>
> Before:
> TEST: TCP IPv4 failover [ OK ]
> TEST: TCP IPv6 failover [FAIL]
>
> After:
> TEST: TCP IPv4 failover [ OK ]
> TEST: TCP IPv6 failover [ OK ]
>
> Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
> Signed-off-by: Sagarika Sharma <sharmasagarika@google.com>
Thanks for the test. LGTM. A couple of nits below.
[...]
> diff --git a/tools/testing/selftests/net/tcp_ecmp_failover.sh b/tools/testing/selftests/net/tcp_ecmp_failover.sh
> new file mode 100755
> index 000000000000..f857d5db84d8
> --- /dev/null
> +++ b/tools/testing/selftests/net/tcp_ecmp_failover.sh
[...]
> +
> +test_ipv4
> +test_ipv6
Maybe squash something like [1]? I ran the test without the first patch
and I get:
# ./tcp_ecmp_failover.sh
TEST: TCP IPv4 failover [ OK ]
TEST: TCP IPv6 failover [FAIL]
# echo $?
0
[1]
diff --git a/tools/testing/selftests/net/tcp_ecmp_failover.sh b/tools/testing/selftests/net/tcp_ecmp_failover.sh
index f857d5db84d8..8b7a2d82c442 100755
--- a/tools/testing/selftests/net/tcp_ecmp_failover.sh
+++ b/tools/testing/selftests/net/tcp_ecmp_failover.sh
@@ -205,5 +205,10 @@ test_ipv6()
cleanup
}
+require_command socat
+require_command tcpdump
+
test_ipv4
test_ipv6
+
+exit "$EXIT_STATUS"
^ permalink raw reply related
* Re: [PATCH net-next 1/2] devlink, mlx5: add init/fini ops for shared devlink
From: Jiri Pirko @ 2026-04-28 11:10 UTC (permalink / raw)
To: Przemek Kitszel
Cc: netdev, Jakub Kicinski, intel-wired-lan, Tony Nguyen,
Jacob Keller, Lukasz Czapnik, Jedrzej Jagielski, Andrew Lunn,
David S. Miller, Eric Dumazet, Paolo Abeni, Saeed Mahameed,
Leon Romanovsky, Tariq Toukan, Mark Bloch, Simon Horman,
Aleksandr Loktionov
In-Reply-To: <20260428090912.3461-2-przemyslaw.kitszel@intel.com>
Tue, Apr 28, 2026 at 11:09:11AM +0200, przemyslaw.kitszel@intel.com wrote:
>Add .shd_init() and .shd_fini() ops, that will be called for the first
>devlink_shd_get() (to initialize driver' priv data) and on the last
>devlink_shd_put() (to allow for the cleanup). Both ops are optional.
>
>.shd_init() could return an error, which will stop creation of shd
>instance. The initializer also gets an additional, optional param,
>that driver could use for any needs.
>
>If any of the callbacks will need to get devlink instance, it could
>be accessed by shd_priv_to_devlink().
>
>Both callbacks are called with devl_lock held and devlink registered.
>
>Next commit will make use of the callbacks, another one will make use also
>of the non-null additional param (outside of this series).
>
>Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
>Signed-off-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
>---
>first discussed at:
>https://lore.kernel.org/netdev/20260325063143.261806-3-przemyslaw.kitszel@intel.com
>
>Sashiko suggested to convert devlink_shd_create() to return ERR_PTR(),
>and propagate that up to the driver. It think it will just make code more
>verbose for not much benefit. And drivers could just store err if they
>want in the passed @init_param.
>
>---
> include/net/devlink.h | 26 +++++++++++++
> .../ethernet/mellanox/mlx5/core/sh_devlink.c | 2 +-
> net/devlink/sh_dev.c | 39 ++++++++++++++++++-
> 3 files changed, 64 insertions(+), 3 deletions(-)
>
>diff --git a/include/net/devlink.h b/include/net/devlink.h
>index bcd31de1f890..5d3a1337bfa1 100644
>--- a/include/net/devlink.h
>+++ b/include/net/devlink.h
>@@ -1586,6 +1586,30 @@ struct devlink_ops {
> struct devlink_rate *parent,
> void *priv_child, void *priv_parent,
> struct netlink_ext_ack *extack);
>+
>+ /**
>+ * shd_init: Shared devlink instance initializer
>+ * @priv: shd_devlink' priv
>+ * @init_param: additional param to pass to driver callback
>+ *
>+ * Called once when the shared instance is first created (by the first
>+ * devlink_shd_get() call).
>+ * Should initialize the driver's private data embedded in the shared
>+ * devlink. May be NULL.
>+ *
>+ * Return: 0 on success, negative to prevent shared instance usage.
>+ */
>+ int (*shd_init)(void *priv, void *init_param);
1. "param" has specific meaning in devlink context
2. You don't use the arg in driver
Care to drop it?
Otherwise, this looks fine to me. Thanks! (small nitpick below)
>+ /**
>+ * shd_fini: Shared devlink instance finalizer
>+ * @priv: shd_devlink' priv
>+ *
>+ * Called once when the last reference is dropped and the shared
>+ * instance is destroyed. Should clean up the driver's private data.
>+ * May be NULL.
>+ */
>+ void (*shd_fini)(void *priv);
>+
> /**
> * selftests_check() - queries if selftest is supported
> * @devlink: devlink instance
>@@ -1651,9 +1675,11 @@ void devlink_free(struct devlink *devlink);
> struct devlink *devlink_shd_get(const char *id,
> const struct devlink_ops *ops,
> size_t priv_size,
>+ void *init_param,
> const struct device_driver *driver);
> void devlink_shd_put(struct devlink *devlink);
> void *devlink_shd_get_priv(struct devlink *devlink);
>+struct devlink *shd_priv_to_devlink(void *priv);
>
> /**
> * struct devlink_port_ops - Port operations
>diff --git a/drivers/net/ethernet/mellanox/mlx5/core/sh_devlink.c b/drivers/net/ethernet/mellanox/mlx5/core/sh_devlink.c
>index b925364765ac..1b8b1ce7e72d 100644
>--- a/drivers/net/ethernet/mellanox/mlx5/core/sh_devlink.c
>+++ b/drivers/net/ethernet/mellanox/mlx5/core/sh_devlink.c
>@@ -43,7 +43,7 @@ int mlx5_shd_init(struct mlx5_core_dev *dev)
> *end = '\0';
>
> /* Get or create shared devlink instance */
>- devlink = devlink_shd_get(sn, &mlx5_shd_ops, 0, pdev->dev.driver);
>+ devlink = devlink_shd_get(sn, &mlx5_shd_ops, 0, NULL, pdev->dev.driver);
> kfree(sn);
> if (!devlink)
> return -ENOMEM;
>diff --git a/net/devlink/sh_dev.c b/net/devlink/sh_dev.c
>index 85acce97e788..048a2a6adc9e 100644
>--- a/net/devlink/sh_dev.c
>+++ b/net/devlink/sh_dev.c
>@@ -34,6 +34,7 @@ static struct devlink_shd *devlink_shd_lookup(const char *id)
> static struct devlink_shd *devlink_shd_create(const char *id,
> const struct devlink_ops *ops,
> size_t priv_size,
>+ void *init_param,
> const struct device_driver *driver)
> {
> struct devlink_shd *shd;
>@@ -49,16 +50,30 @@ static struct devlink_shd *devlink_shd_create(const char *id,
> if (!shd->id)
> goto err_devlink_free;
> shd->priv_size = priv_size;
>- refcount_set(&shd->refcount, 1);
>
> devl_lock(devlink);
> devl_register(devlink);
>+
>+ if (ops->shd_init) {
>+ int err;
>+
>+ err = ops->shd_init(shd->priv, init_param);
>+ if (err)
>+ goto err_unregister;
>+ }
>+
> devl_unlock(devlink);
>
>+ refcount_set(&shd->refcount, 1);
> list_add_tail(&shd->list, &shd_list);
>
> return shd;
>
>+err_unregister:
>+ devl_unregister(devlink);
>+ devl_unlock(devlink);
>+ kfree(shd->id);
>+
> err_devlink_free:
> devlink_free(devlink);
> return NULL;
>@@ -69,7 +84,12 @@ static void devlink_shd_destroy(struct devlink_shd *shd)
> struct devlink *devlink = priv_to_devlink(shd);
>
> list_del(&shd->list);
>+
Not sure why to add empty line here.
> devl_lock(devlink);
>+
>+ if (devlink->ops->shd_fini)
>+ devlink->ops->shd_fini(shd->priv);
>+
> devl_unregister(devlink);
> devl_unlock(devlink);
> kfree(shd->id);
>@@ -81,6 +101,7 @@ static void devlink_shd_destroy(struct devlink_shd *shd)
> * @id: Identifier string (e.g., serial number) for the shared instance
> * @ops: Devlink operations structure
> * @priv_size: Size of private data structure
>+ * @init_param: Passed to .shd_init() callback alongside driver's priv
> * @driver: Driver associated with the shared devlink instance
> *
> * Get an existing shared devlink instance identified by @id, or create
>@@ -96,16 +117,17 @@ static void devlink_shd_destroy(struct devlink_shd *shd)
> struct devlink *devlink_shd_get(const char *id,
> const struct devlink_ops *ops,
> size_t priv_size,
>+ void *init_param,
> const struct device_driver *driver)
> {
> struct devlink *devlink;
> struct devlink_shd *shd;
>
> mutex_lock(&shd_mutex);
>
> shd = devlink_shd_lookup(id);
> if (!shd) {
>- shd = devlink_shd_create(id, ops, priv_size, driver);
>+ shd = devlink_shd_create(id, ops, priv_size, init_param, driver);
> goto unlock;
> }
>
>@@ -159,3 +181,16 @@ void *devlink_shd_get_priv(struct devlink *devlink)
> return shd->priv;
> }
> EXPORT_SYMBOL_GPL(devlink_shd_get_priv);
>+
>+/** shd_priv_to_devlink - Get devlink instance from shd_devlink's priv
>+ * @priv: Driver's priv data
>+ *
>+ * Return: pointer to shared devlink instance the @priv belongs to.
>+ */
>+struct devlink *shd_priv_to_devlink(void *priv)
>+{
>+ struct devlink_shd *shd = container_of(priv, struct devlink_shd, priv);
>+
>+ return priv_to_devlink(shd);
>+}
>+EXPORT_SYMBOL_GPL(shd_priv_to_devlink);
>--
>2.39.3
>
^ permalink raw reply
* [PATCH net 2/2] ip6_gre: Use cached t->net in ip6erspan_changelink().
From: Maoyi Xie @ 2026-04-28 11:07 UTC (permalink / raw)
To: netdev
Cc: kuniyu, shaw.leon, davem, kuba, edumazet, pabeni, dsahern, kuznet,
linux-kernel, stable, security
In-Reply-To: <20260428110713.2550315-1-maoyixie.tju@gmail.com>
From: Maoyi Xie <maoyi.xie@ntu.edu.sg>
After commit 5e72ce3e3980 ("net: ipv6: Use link netns in newlink() of
rtnl_link_ops"), ip6erspan_newlink() correctly resolves the per-netns
ip6gre hash via link_net. ip6erspan_changelink() was not converted in
that series and still uses dev_net(dev), which diverges from the
device's creation netns after IFLA_NET_NS_FD migration.
This re-inserts the tunnel into the wrong per-netns hash, leaving a
stale entry in the original creation netns. When that netns is later
destroyed, ip6gre_exit_rtnl_net() walks the stale entry, producing a
slab-use-after-free reported by KASAN, followed by a kernel BUG at
net/core/dev.c (LIST_POISON1) in unregister_netdevice_many_notify().
Reachable from an unprivileged user namespace ("unshare --user
--map-root-user --net"); cross-tenant scope on container hosts.
Note: ip6gre_changelink() (the non-erspan sibling earlier in the same
file) already uses the cached t->net correctly. The bug is specific
to ip6erspan_changelink() copying the wrong shape.
Fixes: 5e72ce3e3980 ("net: ipv6: Use link netns in newlink() of rtnl_link_ops")
Reported-by: Maoyi Xie <maoyi.xie@ntu.edu.sg>
Cc: stable@vger.kernel.org # v5.15+
Signed-off-by: Maoyi Xie <maoyi.xie@ntu.edu.sg>
---
net/ipv6/ip6_gre.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c
index dafcc0dcd..38ac14cc0 100644
--- a/net/ipv6/ip6_gre.c
+++ b/net/ipv6/ip6_gre.c
@@ -2261,7 +2261,8 @@ static int ip6erspan_changelink(struct net_device *dev, struct nlattr *tb[],
struct nlattr *data[],
struct netlink_ext_ack *extack)
{
- struct ip6gre_net *ign = net_generic(dev_net(dev), ip6gre_net_id);
+ struct ip6_tnl *nt = netdev_priv(dev);
+ struct ip6gre_net *ign = net_generic(nt->net, ip6gre_net_id);
struct __ip6_tnl_parm p;
struct ip6_tnl *t;
--
2.34.1
^ permalink raw reply related
* Re: [PATCH net v1 1/2] ipv6: update route serial number on NETDEV_CHANGE
From: Ido Schimmel @ 2026-04-28 11:07 UTC (permalink / raw)
To: Sagarika Sharma
Cc: David S . Miller, David Ahern, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Shuah Khan, Simon Horman, Kuniyuki Iwashima, netdev,
linux-kselftest
In-Reply-To: <20260427224243.3499162-2-sharmasagarika@google.com>
On Mon, Apr 27, 2026 at 10:42:22PM +0000, Sagarika Sharma wrote:
> When using IPv6 ECMP routes, if a netdev listed as a nexthop experiences
> a carrier change event (e.g., a bond device generating a NETDEV_CHANGE
> event after its slaves go linkdown), established connections utilizing
> that nexthop fail to fail over to other available nexthops. Instead,
> these connections stall or drop.
>
> This happens because the IPv6 FIB code does not invalidate the socket's
> cached destination when a NETDEV_CHANGE event occurs. While
> fib6_ifdown() correctly marks the nexthop with RTNH_F_LINKDOWN, it
> leaves the route's serial number unchanged. As a result, sockets with a
> previously cached dst do not realize the route is no longer viable and
> continue to try using the non-functional nexthop.
>
> This behavior contrasts with IPv4, which actively flushes cached
> destinations on a NETDEV_CHANGE event (see fib_netdev_event() in
> net/ipv4/fib_frontend.c).
>
> Fix this by updating the route serial number in fib6_ifdown() when
> setting RTNH_F_LINKDOWN. This invalidates stale cached destinations,
> forcing sockets to perform a new route lookup and fail over to a
> functioning nexthop.
>
> Fixes: 51ebd3181572 ("ipv6: add support of equal cost multipath (ECMP)")
> Signed-off-by: Sagarika Sharma <sharmasagarika@google.com>
> Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
^ permalink raw reply
* [PATCH net 1/2] ip6: vti: Use ip6_tnl.net in vti6_changelink().
From: Maoyi Xie @ 2026-04-28 11:07 UTC (permalink / raw)
To: netdev
Cc: kuniyu, shaw.leon, davem, kuba, edumazet, pabeni, dsahern, kuznet,
linux-kernel, stable, security
In-Reply-To: <20260428110713.2550315-1-maoyixie.tju@gmail.com>
From: Kuniyuki Iwashima <kuniyu@google.com>
ip netns add ns1
ip netns add ns2
ip -n ns1 link add vti6_test type vti6 remote ::1 local ::2 key 7
ip -n ns1 link set vti6_test netns ns2
ip -n ns2 link set vti6_test type vti6 remote ::3 local ::4 key 9
ip netns del ns2
ip netns del ns1
[ 132.495484] ------------[ cut here ]------------
[ 132.497609] kernel BUG at net/core/dev.c:12376!
After commit 5e72ce3e3980 ("net: ipv6: Use link netns in newlink() of
rtnl_link_ops"), vti6_newlink() correctly resolves the per-netns vti6
hash via link_net. vti6_changelink() and vti6_update() were not
converted in that series and still read dev_net(dev) /
dev_net(t->dev), which diverge from the device's creation netns
after IFLA_NET_NS_FD migration. The result is a stale per-netns hash
entry; cleanup_net() of the original netns then walks freed memory.
Reachable from an unprivileged user namespace ("unshare --user
--map-root-user --net"); cross-tenant scope on container hosts.
Fixes: 5e72ce3e3980 ("net: ipv6: Use link netns in newlink() of rtnl_link_ops")
Reported-by: Maoyi Xie <maoyi.xie@ntu.edu.sg>
Cc: stable@vger.kernel.org # v5.15+
Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
---
net/ipv6/ip6_vti.c | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c
index ad5290be4..dcb257411 100644
--- a/net/ipv6/ip6_vti.c
+++ b/net/ipv6/ip6_vti.c
@@ -722,10 +722,11 @@ vti6_tnl_change(struct ip6_tnl *t, const struct __ip6_tnl_parm *p,
static int vti6_update(struct ip6_tnl *t, struct __ip6_tnl_parm *p,
bool keep_mtu)
{
- struct net *net = dev_net(t->dev);
- struct vti6_net *ip6n = net_generic(net, vti6_net_id);
+ struct net *net = t->net;
+ struct vti6_net *ip6n;
int err;
+ ip6n = net_generic(net, vti6_net_id);
vti6_tnl_unlink(ip6n, t);
synchronize_net();
err = vti6_tnl_change(t, p, keep_mtu);
@@ -1031,11 +1032,12 @@ static int vti6_changelink(struct net_device *dev, struct nlattr *tb[],
struct nlattr *data[],
struct netlink_ext_ack *extack)
{
- struct ip6_tnl *t;
+ struct ip6_tnl *t = netdev_priv(dev);
+ struct net *net = t->net;
struct __ip6_tnl_parm p;
- struct net *net = dev_net(dev);
- struct vti6_net *ip6n = net_generic(net, vti6_net_id);
+ struct vti6_net *ip6n;
+ ip6n = net_generic(net, vti6_net_id);
if (dev == ip6n->fb_tnl_dev)
return -EINVAL;
--
2.34.1
^ permalink raw reply related
* [PATCH net 0/2] ipv6: tunnel changelink: use cached netns pointer
From: Maoyi Xie @ 2026-04-28 11:07 UTC (permalink / raw)
To: netdev
Cc: kuniyu, shaw.leon, davem, kuba, edumazet, pabeni, dsahern, kuznet,
linux-kernel, stable, security
From: Maoyi Xie <maoyi.xie@ntu.edu.sg>
This series addresses two slab-use-after-free reports against the IPv6
tunnel changelink callbacks vti6_changelink() and ip6erspan_changelink(),
both reachable from an unprivileged user namespace and verified on
Linux v7.0 with KASAN.
Both bugs are sibling misses of commit 5e72ce3e3980 ("net: ipv6: Use
link netns in newlink() of rtnl_link_ops"), which migrated the
*_newlink callbacks for vti6, ip6_gre, ip6_tunnel, sit and ip_tunnel
from dev_net() to link_net but did not convert the corresponding
*_changelink callbacks. As a result, after a device is migrated via
IFLA_NET_NS_FD, the changelink path looks up the per-netns hash in the
wrong namespace, leaving a stale hash entry in the original creation
netns. The next cleanup_net() of that netns walks freed memory.
Patch 1/2 was authored by Kuniyuki Iwashima during the security
disclosure thread; it converts vti6_changelink() and vti6_update() to
use the cached t->net.
Patch 2/2 applies the equivalent conversion to ip6erspan_changelink().
The non-erspan sibling ip6gre_changelink() in the same file already
uses the cached t->net correctly.
Both bugs were originally reported on security@kernel.org on
2026-04-26 and triaged with Kuniyuki Iwashima and Xiao Liang. Posting
publicly per standard practice once the technical fix shape is
settled.
The bugs are present on all maintained LTS branches (v5.15, v6.1, v6.6,
v6.12, v6.18) with byte-identical source, hence Cc: stable@.
Tested with KASAN reproducers (unshare --user --map-root-user --net,
RTM_NEWLINK + IFLA_NET_NS_FD migration, RTM_NEWLINK changelink in
the migrated netns, then teardown of the original netns); without the
patches both reports trip within ~2 seconds, with the patches the
reproducers complete cleanly.
Kuniyuki Iwashima (1):
ip6: vti: Use ip6_tnl.net in vti6_changelink().
Maoyi Xie (1):
ip6_gre: Use cached t->net in ip6erspan_changelink().
net/ipv6/ip6_gre.c | 3 ++-
net/ipv6/ip6_vti.c | 12 +++++++-----
2 files changed, 9 insertions(+), 6 deletions(-)
--
2.34.1
^ permalink raw reply
* [PATCH] hv_sock: fix ARM64 support
From: Hamza Mahfooz @ 2026-04-28 11:05 UTC (permalink / raw)
To: netdev
Cc: K. Y. Srinivasan, Haiyang Zhang, Wei Liu, Dexuan Cui, Long Li,
Stefano Garzarella, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, Michael Kelley, Himadri Pandya,
linux-hyperv, virtualization, linux-kernel, Hamza Mahfooz, stable
VMBUS ring buffers must be page aligned. Therefore, the current value of
24K presents a challenge on ARM64 kernels (with 64K pages). So, use
VMBUS_RING_SIZE() to ensure they are always aligned and large enough to
hold all of the relevant data.
Cc: stable@kernel.vger.org
Fixes: 77ffe33363c0 ("hv_sock: use HV_HYP_PAGE_SIZE for Hyper-V communication")
Tested-by: Dexuan Cui <decui@microsoft.com>
Reviewed-by: Dexuan Cui <decui@microsoft.com>
Signed-off-by: Hamza Mahfooz <hamzamahfooz@linux.microsoft.com>
---
net/vmw_vsock/hyperv_transport.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/net/vmw_vsock/hyperv_transport.c b/net/vmw_vsock/hyperv_transport.c
index 069386a74557..40f09b23efa3 100644
--- a/net/vmw_vsock/hyperv_transport.c
+++ b/net/vmw_vsock/hyperv_transport.c
@@ -375,10 +375,10 @@ static void hvs_open_connection(struct vmbus_channel *chan)
} else {
sndbuf = max_t(int, sk->sk_sndbuf, RINGBUFFER_HVS_SND_SIZE);
sndbuf = min_t(int, sndbuf, RINGBUFFER_HVS_MAX_SIZE);
- sndbuf = ALIGN(sndbuf, HV_HYP_PAGE_SIZE);
+ sndbuf = VMBUS_RING_SIZE(sndbuf);
rcvbuf = max_t(int, sk->sk_rcvbuf, RINGBUFFER_HVS_RCV_SIZE);
rcvbuf = min_t(int, rcvbuf, RINGBUFFER_HVS_MAX_SIZE);
- rcvbuf = ALIGN(rcvbuf, HV_HYP_PAGE_SIZE);
+ rcvbuf = VMBUS_RING_SIZE(rcvbuf);
}
chan->max_pkt_size = HVS_MAX_PKT_SIZE;
--
2.54.0
^ permalink raw reply related
* Re: [PATCH net v2] net: mctp i2c: check length before marking flow active
From: Paolo Abeni @ 2026-04-28 11:03 UTC (permalink / raw)
To: William A. Kennington III, Jeremy Kerr, Matt Johnston,
Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Wolfram Sang
Cc: netdev, linux-kernel
In-Reply-To: <20260423074741.201460-1-william@wkennington.com>
On 4/23/26 9:46 AM, William A. Kennington III wrote:
> Currently, mctp_i2c_get_tx_flow_state() is called before the packet length
> sanity check. This function marks a new flow as active in the MCTP core.
>
> If the sanity check fails, mctp_i2c_xmit() returns early without calling
> mctp_i2c_lock_nest(). This results in a mismatched locking state: the
> flow is active, but the I2C bus lock was never acquired for it.
>
> When the flow is later released, mctp_i2c_release_flow() will see the
> active state and queue an unlock marker. The TX thread will then
> decrement midev->i2c_lock_count from 0, causing it to underflow to -1.
>
> This underflow permanently breaks the driver's locking logic, allowing
> future transmissions to occur without holding the I2C bus lock, leading
> to bus collisions and potential hardware hangs.
>
> Move the mctp_i2c_get_tx_flow_state() call to after the length sanity
> check to ensure we only transition the flow state if we are actually
> going to proceed with the transmission and locking.
>
> Fixes: f5b8abf9fc3d ("mctp i2c: MCTP I2C binding driver")
> Signed-off-by: William A. Kennington III <william@wkennington.com>
Note that you should have included Jeremy's ack, and you should have
avoided reposting before the 24h grace period. In this specific case,
you could have avoided a repost entirely
/P
^ permalink raw reply
* Re: [PATCH net] neighbour: neigh_xmit needs to release skb on -EAFNOSUPPORT
From: Pablo Neira Ayuso @ 2026-04-28 11:00 UTC (permalink / raw)
To: netdev; +Cc: netfilter-devel, edumazet, davem, kuba, pabeni, horms
In-Reply-To: <20260428102052.53637-1-pablo@netfilter.org>
On Tue, Apr 28, 2026 at 12:20:52PM +0200, Pablo Neira Ayuso wrote:
> Sashiko reports:
>
> "... if the target neighbor table is NULL (for example, for
> NEIGH_ND_TABLE when IPv6 is disabled), the code takes the out_unlock
> path and bypasses the out_kfree_skb cleanup"
>
> Fix this skb memleak by releasing the skb in case of -EAFNOSUPPORT.
Please, withdraw.
Florian Westphal already posted a similar fix that is already in
net.git
Thanks.
> Fixes: f8f2eb9de69a ("neighbour: add RCU protection to neigh_tables[]")
> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
^ permalink raw reply
* Re: [PATCH net v3] ipv6: addrconf: skip ERRDAD transition when address already DEAD
From: Paolo Abeni @ 2026-04-28 10:59 UTC (permalink / raw)
To: Linmao Li, davem, dsahern, edumazet, kuba
Cc: horms, stephen, netdev, linux-kernel
In-Reply-To: <20260423023216.1221731-1-lilinmao@kylinos.cn>
On 4/23/26 4:32 AM, Linmao Li wrote:
> addrconf_dad_failure() transitions ifp->state from DAD to POSTDAD
> via addrconf_dad_end(), which drops ifp->lock on return. The lock
> is re-acquired after net_info_ratelimited(). A concurrent
> ipv6_del_addr() can take the lock in that window, set ifp->state
> to DEAD and run list_del_rcu(&ifp->if_list).
>
> addrconf_dad_failure() then overwrites DEAD with ERRDAD at errdad:
> and schedules a new dad_work. The work calls ipv6_del_addr()
> again, hitting the already-poisoned list entry:
>
> general protection fault: 0000 [#1] SMP NOPTI
> CPU: 4 PID: 217 Comm: kworker/4:1
> Workqueue: ipv6_addrconf addrconf_dad_work
> RIP: 0010:ipv6_del_addr+0xe9/0x280
> RAX: dead000000000122
> Call Trace:
> addrconf_dad_stop+0x113/0x140
> addrconf_dad_work+0x28c/0x430
> process_one_work+0x1eb/0x3b0
> worker_thread+0x4d/0x400
> kthread+0x104/0x140
> ret_from_fork+0x35/0x40
>
> Fold the addrconf_dad_end() logic into addrconf_dad_failure()
> under a single ifp->lock critical section. The STABLE_PRIVACY
> branch temporarily drops ifp->lock, so keep a state-is-DEAD
> bail-out at errdad: for that remaining window.
>
> Fixes: c15b1ccadb32 ("ipv6: move DAD and addrconf_verify processing to workqueue")
> Signed-off-by: Linmao Li <lilinmao@kylinos.cn>
> ---
> net/ipv6/addrconf.c | 13 ++++++++++---
> 1 file changed, 10 insertions(+), 3 deletions(-)
>
> diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
> index 5476b6536eb7..c9ea0d5042d0 100644
> --- a/net/ipv6/addrconf.c
> +++ b/net/ipv6/addrconf.c
> @@ -2166,16 +2166,18 @@ void addrconf_dad_failure(struct sk_buff *skb, struct inet6_ifaddr *ifp)
> struct net *net = dev_net(idev->dev);
> int max_addresses;
>
> - if (addrconf_dad_end(ifp)) {
> + spin_lock_bh(&ifp->lock);
> +
> + if (ifp->state != INET6_IFADDR_STATE_DAD) {
> + spin_unlock_bh(&ifp->lock);
> in6_ifa_put(ifp);
> return;
> }
> + ifp->state = INET6_IFADDR_STATE_POSTDAD;
>
> net_info_ratelimited("%s: IPv6 duplicate address %pI6c used by %pM detected!\n",
> ifp->idev->dev->name, &ifp->addr, eth_hdr(skb)->h_source);
>
> - spin_lock_bh(&ifp->lock);
> -
> if (ifp->flags & IFA_F_STABLE_PRIVACY) {
> struct in6_addr new_addr;
> struct inet6_ifaddr *ifp2;
> @@ -2227,6 +2229,11 @@ void addrconf_dad_failure(struct sk_buff *skb, struct inet6_ifaddr *ifp)
>
> errdad:
> /* transition from _POSTDAD to _ERRDAD */
> + if (ifp->state == INET6_IFADDR_STATE_DEAD) {
> + spin_unlock_bh(&ifp->lock);
> + in6_ifa_put(ifp);
> + return;
It looks like this check is need only when the ifp->lock is released
again, i.e. just after the `lock_errdad`. Please move it there, to avoid
confusion when looking at this code in the future.
Thanks,
Paolo
^ permalink raw reply
* Re: [PATCH iwl-net v2 0/4] iavf: fix VLAN filter state machine races
From: Petr Oros @ 2026-04-28 10:53 UTC (permalink / raw)
To: Jacob Keller, Simon Horman
Cc: netdev, Tony Nguyen, Przemek Kitszel, Andrew Lunn,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Jesse Brandeburg, Mitch Williams, Aaron Brown,
Przemyslaw Patynowski, Jedrzej Jagielski, intel-wired-lan,
linux-kernel
In-Reply-To: <b2d56951-4776-4d99-bb4a-69ef7da0a502@intel.com>
On 4/23/26 22:48, Jacob Keller wrote:
> On 4/21/2026 2:02 AM, Simon Horman wrote:
>> On Fri, Apr 17, 2026 at 04:29:41PM +0200, Petr Oros wrote:
>>> The iavf VLAN filter state machine has several design issues that lead
>>> to race conditions between userspace add/del calls and the watchdog
>>> task's virtchnl processing. Filters can get lost or leak HW resources,
>>> especially during interface down/up cycles and namespace moves.
>> ...
>>
>> Hi Petr,
>>
>> Sashiko has a bit to say about this patch.
>> I'd appreciate it if you could look over that.
>>
>> In particular, the feedback on patches 2 and 3 may warrant
>> some updates to this patchset, while I think 4 is more
>> in the realm of possible future work.
> @Petr,
>
> Could you please review the Sashiko reports and clarify whether a new
> version will be needed?
>
> The original series posted as a net-next was Tested-by, and it would be
> good to get this moving, but I don't want to queue it up for sending
> until certain it won't simply get rejected due to these unresolved comments.
>
> Thanks,
> Jake
>
Hi Jake,
The Sashiko review identified seven concerns across the four patches.
Five of them describe sub millisecond race windows. Rapid del and re add
of a VLAN in IAVF_VLAN_ADDING state. Pending IAVF_VLAN_ADD lost across
down and up before the watchdog ships the request. REMOVING combined with
user re add and user re del state confusion. The reset path resurrecting
filters that are in REMOVE or REMOVING state. Phantom ACTIVE after the PF
rejects an ADD whose user side del raced through.
The remaining two are deterministic pre existing V1 bugs unrelated to
this series. The V1 ADD_VLAN error path has never called
iavf_vlan_add_reject().
The V2 path got it in 968996c070ef ("iavf: Fix VLAN_V2 addition/rejection")
and V1 was missed. These manifest whenever the PF rejects an ADD on i40e
for example a port VLAN conflict or an untrusted cap reached, and they
belong in a separate fix.
The five race window findings require tight syscall sequencing via ip batch
or sysfs FLR concurrent with del to reach. These patterns do not match how
NetworkManager, systemd-networkd, libvirt or cloud-init configure VLANs.
Those tools add VLANs once on VF setup and do not issue rapid del and
re add or trigger FLR mid operation. The current version keeps the state
machine minimal. Closing these windows requires per filter flag tracking
that adds complexity disproportionate to the user visible benefit on real
workloads.
Two larger problems are worth addressing in follow up work.
The first is num_vlan_filters accounting on V2 under high churn.
Post series, filters in REMOVING state count against
iavf_get_max_vlans_allowed until the PF confirms the deletion.
This can cause a transient EIO on rapid del then add when at the cap.
Pre series this was avoided by immediate kfree. The trade off here is
correctness (no HW resource leak on PF reject) at the cost of a transient
userspace error.
The second is the i40e silent ADD reject. The i40e PF rejects over cap or
untrusted VF VLAN ADDs by returning VIRTCHNL_STATUS_SUCCESS, so iavf cannot
surface the failure to userspace. ip link add ... type vlan reports success
while no filter exists in HW. V2 on ice avoids this via the client side cap.
Closing this gap requires PF and driver ABI coordination.
The series has been tested across documented user workflows on both
ice and i40e PFs in trusted and untrusted modes. The tested scenarios
include interface up and down cycles, namespace migration, VF reset,
VLAN add and remove sequences, parallel VLAN operations across two VFs,
traffic verification via ping under spoofcheck, port VLAN, and multi
VLAN configurations. The workflow scenarios pass on the patched kernel.
The small number of test failures observed were test framework artifacts
(missing IP configuration on probe interfaces, settle time too short for
PF round trip drainage, V1 PF reject classification) and not kernel
regressions.
Regards,
Petr
^ permalink raw reply
* Re: [PATCH v2 2/2] pinctrl: qcom: add the TLMM driver for the Nord platforms
From: Linus Walleij @ 2026-04-28 10:50 UTC (permalink / raw)
To: Bartosz Golaszewski
Cc: Bjorn Andersson, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Richard Cochran, Bartosz Golaszewski, Shawn Guo, Arnd Bergmann,
Dmitry Baryshkov, linux-arm-msm, linux-gpio, devicetree,
linux-kernel, netdev
In-Reply-To: <20260427-nord-tlmm-v2-2-ade8e0f3d803@oss.qualcomm.com>
Hi Bartosz,
thanks for your patch!
On Mon, Apr 27, 2026 at 4:00 PM Bartosz Golaszewski
<bartosz.golaszewski@oss.qualcomm.com> wrote:
> +config PINCTRL_NORD
> + tristate "Qualcomm Technologies Inc NORD (SA8797p) pin controller driver"
Krzysztof just tidied up all of these strings, this should now say:
tristate "Qualcomm NORD (SA8797p) pin controller driver"
or something.
Yours,
Linus Walleij
^ permalink raw reply
* Re: [PATCH net v6] net: stmmac: Prevent NULL deref when RX memory exhausted
From: patchwork-bot+netdevbpf @ 2026-04-28 10:50 UTC (permalink / raw)
To: Sam Edwards
Cc: andrew+netdev, davem, edumazet, kuba, pabeni, mcoquelin.stm32,
alexandre.torgue, rmk+kernel, maxime.chevallier, ovidiu.panait.rb,
vladimir.oltean, baruch, fancer.lancer, peppe.cavallaro, netdev,
linux-stm32, linux-arm-kernel, linux-kernel, CFSworks, stable,
linux
In-Reply-To: <20260422044503.5349-1-CFSworks@gmail.com>
Hello:
This patch was applied to netdev/net.git (main)
by Paolo Abeni <pabeni@redhat.com>:
On Tue, 21 Apr 2026 21:45:03 -0700 you wrote:
> The CPU receives frames from the MAC through conventional DMA: the CPU
> allocates buffers for the MAC, then the MAC fills them and returns
> ownership to the CPU. For each hardware RX queue, the CPU and MAC
> coordinate through a shared ring array of DMA descriptors: one
> descriptor per DMA buffer. Each descriptor includes the buffer's
> physical address and a status flag ("OWN") indicating which side owns
> the buffer: OWN=0 for CPU, OWN=1 for MAC. The CPU is only allowed to set
> the flag and the MAC is only allowed to clear it, and both must move
> through the ring in sequence: thus the ring is used for both
> "submissions" and "completions."
>
> [...]
Here is the summary with links:
- [net,v6] net: stmmac: Prevent NULL deref when RX memory exhausted
https://git.kernel.org/netdev/net/c/0bb05e6adfa9
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* Re: [PATCH v2 7/9] wifi: rtw89: switch to using FIELD_GET_SIGNED()
From: David Laight @ 2026-04-28 10:43 UTC (permalink / raw)
To: Andy Shevchenko
Cc: Yury Norov, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
Dave Hansen, H. Peter Anvin, Andy Lutomirski, Peter Zijlstra,
Jonathan Cameron, David Lechner, Johannes Berg, Nuno Sá,
Andy Shevchenko, Ping-Ke Shih, Richard Cochran, Andrew Lunn,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Alexandre Belloni, Yury Norov, Rasmus Villemoes, Hans de Goede,
Linus Walleij, Sakari Ailus, Salah Triki, Achim Gratz,
Ben Collins, x86, linux-kernel, linux-iio, linux-wireless, netdev,
linux-rtc
In-Reply-To: <afBdXj_9r25Ssnz6@ashevche-desk.local>
On Tue, 28 Apr 2026 10:10:22 +0300
Andy Shevchenko <andriy.shevchenko@intel.com> wrote:
> On Mon, Apr 27, 2026 at 05:41:24PM -0400, Yury Norov wrote:
> > Switch from sign_extend32(FIELD_GET()) to the dedicated
> > FIELD_GET_SIGNED() and don't calculate the fields length explicitly.
>
> ...
>
> > for (i = 0; i < ADDC_T_AVG; i++) {
> > tmp = rtw89_phy_read32_mask(rtwdev, R_DBG32_D, MASKDWORD);
> > - dc_re += sign_extend32(FIELD_GET(0xfff000, tmp), 11);
> > - dc_im += sign_extend32(FIELD_GET(0xfff, tmp), 11);
> > + dc_re += FIELD_GET_SIGNED(0xfff000, tmp);
> > + dc_im += FIELD_GET_SIGNED(0xfff, tmp);
>
> In the same driver the GENMASK() is being used, why not doing it here while at it?
To me those bit masks look more readable than the GENMASK() calls would be.
David
>
> > }
>
> ...
>
> > for (i = 0; i < ADDC_T_AVG; i++) {
> > tmp = rtw89_phy_read32_mask(rtwdev, R_DBG32_D, MASKDWORD);
> > - dc_re += sign_extend32(FIELD_GET(0xfff000, tmp), 11);
> > - dc_im += sign_extend32(FIELD_GET(0xfff, tmp), 11);
> > + dc_re += FIELD_GET_SIGNED(0xfff000, tmp);
> > + dc_im += FIELD_GET_SIGNED(0xfff, tmp);
> > }
>
> Ditto, and it even looks like the same piece repeating twice in different
> compilation units of the same driver...
>
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox