* [PATCH bpf-next v2 3/4] bpf: Add BPF_FIB_LOOKUP_VLAN_INPUT flag to bpf_fib_lookup() helper
From: Avinash Duduskar @ 2026-06-16 22:34 UTC (permalink / raw)
To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko
Cc: Eduard Zingerman, Kumar Kartikeya Dwivedi, Martin KaFai Lau,
Song Liu, Yonghong Song, Jiri Olsa, Emil Tsalapatis,
John Fastabend, Stanislav Fomichev, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, David Ahern,
Shuah Khan, Jesper Dangaard Brouer, Mykyta Yatsenko, Leon Hwang,
KP Singh, Anton Protopopov, Amery Hung, Eyal Birger, Rong Tao,
Toke Høiland-Jørgensen, bpf, netdev, linux-kselftest,
linux-kernel
In-Reply-To: <20260616223426.3568080-1-avinash.duduskar@gmail.com>
BPF_FIB_LOOKUP_VLAN resolves a VLAN egress. The reverse is also
useful: an XDP program receiving a VLAN-tagged frame on a physical
device wants the lookup to behave as if the packet had arrived on the
corresponding VLAN subinterface, so iif-based policy routing and VRF
table selection use the right ingress.
Add BPF_FIB_LOOKUP_VLAN_INPUT. When set, params->h_vlan_proto and
params->h_vlan_TCI are read as an input VLAN tag and the matching VLAN
device of params->ifindex is resolved with __vlan_find_dev_deep_rcu().
The device must be up and in the same network namespace as
params->ifindex (a VLAN device can be moved to another netns while
registered on its parent; receive would deliver into that other
namespace, which a lookup here cannot represent). If params->ifindex
is itself a VLAN device, its inner (QinQ) subinterface is matched.
For a bond or team, a tag on a port matches no device and returns
NOT_FWDED; pass the master's ifindex.
The lookup then runs with the resolved device as the ingress;
params->ifindex itself is not modified on the input side. When the
resolved device is enslaved to a VRF, both the full lookup (via the
l3mdev rule) and BPF_FIB_LOOKUP_DIRECT (via l3mdev_fib_table_rcu())
select the VRF's table from the resolved ingress. That follows from
feeding the resolved device to the flow as the ingress
(fl4.flowi4_iif = dev->ifindex), which is what makes l3mdev resolve
the VRF master from the subinterface rather than from
params->ifindex.
The two failure classes get different treatment on purpose. A
h_vlan_proto other than 802.1Q/802.1ad is API misuse and returns
-EINVAL, since it would otherwise reach the WARN in vlan_proto_idx()
with a program-controlled value. An unmatched VID, a device that is
down, or one in another namespace is a data outcome and returns
BPF_FIB_LKUP_RET_NOT_FWDED, matching the DIRECT path when
fib_get_table() finds no table and mirroring real ingress, where the
receive path drops such frames. A VID of 0 (a priority tag) is looked
up literally and normally fails the same way; receive instead
processes such frames untagged, so callers should not set the flag for
priority tags. Proceeding on the physical device for any of these
would be fail-open for the policy-routing cases above.
The h_vlan fields share a union with tbid, so the flag cannot be
combined with BPF_FIB_LOOKUP_TBID. It describes ingress, so it also
cannot be combined with BPF_FIB_LOOKUP_OUTPUT. Both combinations
return -EINVAL; restricting now keeps a later relaxation backward
compatible. Combining with BPF_FIB_LOOKUP_VLAN is allowed: the tag is
consumed on the ingress side and the egress tag is written on
success.
Under !CONFIG_VLAN_8021Q the __vlan_find_dev_deep_rcu() stub returns
NULL, so every lookup with the flag returns NOT_FWDED, which is
correct since no VLAN device can exist.
Suggested-by: Toke Høiland-Jørgensen <toke@redhat.com>
Signed-off-by: Avinash Duduskar <avinash.duduskar@gmail.com>
---
include/uapi/linux/bpf.h | 34 ++++++++++++++-
net/core/filter.c | 80 +++++++++++++++++++++++++++++++---
tools/include/uapi/linux/bpf.h | 34 ++++++++++++++-
3 files changed, 141 insertions(+), 7 deletions(-)
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index f77aa9472bf1..57e28da3336a 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -3552,6 +3552,35 @@ union bpf_attr {
* reports the route mtu in *params*->mtu_result, and on
* the tc path without tot_len the mtu check runs after
* the swap, against the parent device.
+ * **BPF_FIB_LOOKUP_VLAN_INPUT**
+ * Treat *params*->h_vlan_proto and *params*->h_vlan_TCI
+ * as an input VLAN tag (e.g. parsed from the packet) and
+ * run the lookup as if ingress had happened on the VLAN
+ * subinterface carrying that tag for *params*->ifindex,
+ * rather than on *params*->ifindex itself. The VID is the
+ * low 12 bits of *params*->h_vlan_TCI;
+ * *params*->h_vlan_proto must be ETH_P_8021Q or
+ * ETH_P_8021AD in network byte order (any other value
+ * returns **-EINVAL**). The
+ * subinterface is the one configured for that tag on
+ * *params*->ifindex; if *params*->ifindex is itself a
+ * VLAN device, its inner (QinQ) subinterface is matched.
+ * For a bond or team, a tag on a port matches no
+ * device and returns NOT_FWDED; pass the master's
+ * ifindex.
+ * If no matching subinterface exists, or it is not up,
+ * or it was moved to another network namespace, the
+ * lookup returns **BPF_FIB_LKUP_RET_NOT_FWDED**,
+ * mirroring real ingress, which drops a frame whose tag
+ * is unconfigured or whose VLAN device is down. A VID of
+ * 0 (a priority-tagged frame) is looked up literally like
+ * any other VID; receive instead processes such frames
+ * untagged on the device itself, so do not set this flag
+ * for priority tags.
+ * Cannot be combined with **BPF_FIB_LOOKUP_TBID** (both
+ * use the same input fields) or **BPF_FIB_LOOKUP_OUTPUT**
+ * (this flag is ingress-only); doing so returns
+ * **-EINVAL**.
*
* *ctx* is either **struct xdp_md** for XDP programs or
* **struct sk_buff** tc cls_act programs.
@@ -7348,6 +7377,7 @@ enum {
BPF_FIB_LOOKUP_SRC = (1U << 4),
BPF_FIB_LOOKUP_MARK = (1U << 5),
BPF_FIB_LOOKUP_VLAN = (1U << 6),
+ BPF_FIB_LOOKUP_VLAN_INPUT = (1U << 7),
};
enum {
@@ -7416,7 +7446,9 @@ struct bpf_fib_lookup {
struct {
/* output with BPF_FIB_LOOKUP_VLAN: set from the
* resolved egress VLAN device (see the flag); zeroed
- * on other successful lookups.
+ * on other successful lookups. input with
+ * BPF_FIB_LOOKUP_VLAN_INPUT: the VLAN tag to scope
+ * the lookup by.
*/
__be16 h_vlan_proto;
__be16 h_vlan_TCI;
diff --git a/net/core/filter.c b/net/core/filter.c
index b37a12321fba..cfbdd842ce61 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -6158,6 +6158,41 @@ static int bpf_fib_set_fwd_params(struct net_device *dev,
return 0;
}
+
+/* With BPF_FIB_LOOKUP_VLAN_INPUT the caller passes the packet's VLAN tag in
+ * params->h_vlan_proto and params->h_vlan_TCI; the lookup is done as if
+ * ingress had happened on the matching VLAN subinterface of *dev. Resolve
+ * it and store it in *dev. params is not modified.
+ *
+ * A protocol other than 802.1Q/802.1AD is API misuse (it would otherwise
+ * reach the WARN in vlan_proto_idx()), so it is rejected with -EINVAL. An
+ * unmatched VID, a matching device that is down, or one that was moved
+ * to another netns (receive would deliver into that netns' stack, which
+ * a lookup here cannot represent) is a data outcome, reported as
+ * NOT_FWDED, the same way the DIRECT path reports a missing table. Under
+ * !CONFIG_VLAN_8021Q __vlan_find_dev_deep_rcu() returns NULL, so every
+ * call returns NOT_FWDED, which is correct since no subinterface can
+ * exist.
+ */
+static int bpf_fib_vlan_input_dev(struct net_device **dev,
+ const struct bpf_fib_lookup *params)
+{
+ __be16 proto = params->h_vlan_proto;
+ struct net_device *vlan_dev;
+ u16 vid;
+
+ if (proto != htons(ETH_P_8021Q) && proto != htons(ETH_P_8021AD))
+ return -EINVAL;
+
+ vid = ntohs(params->h_vlan_TCI) & VLAN_VID_MASK;
+ vlan_dev = __vlan_find_dev_deep_rcu(*dev, proto, vid);
+ if (!vlan_dev || !(vlan_dev->flags & IFF_UP) ||
+ !net_eq(dev_net(vlan_dev), dev_net(*dev)))
+ return BPF_FIB_LKUP_RET_NOT_FWDED;
+
+ *dev = vlan_dev;
+ return 0;
+}
#endif
#if IS_ENABLED(CONFIG_INET)
@@ -6177,6 +6212,12 @@ static int bpf_ipv4_fib_lookup(struct net *net, struct bpf_fib_lookup *params,
if (unlikely(!dev))
return -ENODEV;
+ if (flags & BPF_FIB_LOOKUP_VLAN_INPUT) {
+ err = bpf_fib_vlan_input_dev(&dev, params);
+ if (err)
+ return err;
+ }
+
/* verify forwarding is enabled on this interface */
in_dev = __in_dev_get_rcu(dev);
if (unlikely(!in_dev || !IN_DEV_FORWARD(in_dev)))
@@ -6186,7 +6227,10 @@ static int bpf_ipv4_fib_lookup(struct net *net, struct bpf_fib_lookup *params,
fl4.flowi4_iif = 1;
fl4.flowi4_oif = params->ifindex;
} else {
- fl4.flowi4_iif = params->ifindex;
+ /* dev->ifindex, not params->ifindex: VLAN_INPUT may have
+ * resolved dev to a subinterface above.
+ */
+ fl4.flowi4_iif = dev->ifindex;
fl4.flowi4_oif = 0;
}
fl4.flowi4_dscp = inet_dsfield_to_dscp(params->tos);
@@ -6323,6 +6367,12 @@ static int bpf_ipv6_fib_lookup(struct net *net, struct bpf_fib_lookup *params,
if (unlikely(!dev))
return -ENODEV;
+ if (flags & BPF_FIB_LOOKUP_VLAN_INPUT) {
+ err = bpf_fib_vlan_input_dev(&dev, params);
+ if (err)
+ return err;
+ }
+
idev = __in6_dev_get_safely(dev);
if (unlikely(!idev || !READ_ONCE(idev->cnf.forwarding)))
return BPF_FIB_LKUP_RET_FWD_DISABLED;
@@ -6331,7 +6381,11 @@ static int bpf_ipv6_fib_lookup(struct net *net, struct bpf_fib_lookup *params,
fl6.flowi6_iif = 1;
oif = fl6.flowi6_oif = params->ifindex;
} else {
- oif = fl6.flowi6_iif = params->ifindex;
+ /* dev->ifindex, not params->ifindex: VLAN_INPUT may have
+ * resolved dev to a subinterface above.
+ */
+ oif = dev->ifindex;
+ fl6.flowi6_iif = oif;
fl6.flowi6_oif = 0;
strict = RT6_LOOKUP_F_HAS_SADDR;
}
@@ -6443,7 +6497,23 @@ static int bpf_ipv6_fib_lookup(struct net *net, struct bpf_fib_lookup *params,
#define BPF_FIB_LOOKUP_MASK (BPF_FIB_LOOKUP_DIRECT | BPF_FIB_LOOKUP_OUTPUT | \
BPF_FIB_LOOKUP_SKIP_NEIGH | BPF_FIB_LOOKUP_TBID | \
BPF_FIB_LOOKUP_SRC | BPF_FIB_LOOKUP_MARK | \
- BPF_FIB_LOOKUP_VLAN)
+ BPF_FIB_LOOKUP_VLAN | BPF_FIB_LOOKUP_VLAN_INPUT)
+
+static bool bpf_fib_lookup_flags_ok(u32 flags)
+{
+ if (flags & ~BPF_FIB_LOOKUP_MASK)
+ return false;
+
+ /* VLAN_INPUT reads h_vlan_proto/h_vlan_TCI, which alias tbid, so it
+ * cannot be combined with TBID. It is also ingress-only, so it
+ * cannot be combined with the egress-perspective OUTPUT flag.
+ */
+ if ((flags & BPF_FIB_LOOKUP_VLAN_INPUT) &&
+ (flags & (BPF_FIB_LOOKUP_TBID | BPF_FIB_LOOKUP_OUTPUT)))
+ return false;
+
+ return true;
+}
BPF_CALL_4(bpf_xdp_fib_lookup, struct xdp_buff *, ctx,
struct bpf_fib_lookup *, params, int, plen, u32, flags)
@@ -6451,7 +6521,7 @@ BPF_CALL_4(bpf_xdp_fib_lookup, struct xdp_buff *, ctx,
if (plen < sizeof(*params))
return -EINVAL;
- if (flags & ~BPF_FIB_LOOKUP_MASK)
+ if (!bpf_fib_lookup_flags_ok(flags))
return -EINVAL;
switch (params->family) {
@@ -6489,7 +6559,7 @@ BPF_CALL_4(bpf_skb_fib_lookup, struct sk_buff *, skb,
if (plen < sizeof(*params))
return -EINVAL;
- if (flags & ~BPF_FIB_LOOKUP_MASK)
+ if (!bpf_fib_lookup_flags_ok(flags))
return -EINVAL;
if (params->tot_len)
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
index f77aa9472bf1..57e28da3336a 100644
--- a/tools/include/uapi/linux/bpf.h
+++ b/tools/include/uapi/linux/bpf.h
@@ -3552,6 +3552,35 @@ union bpf_attr {
* reports the route mtu in *params*->mtu_result, and on
* the tc path without tot_len the mtu check runs after
* the swap, against the parent device.
+ * **BPF_FIB_LOOKUP_VLAN_INPUT**
+ * Treat *params*->h_vlan_proto and *params*->h_vlan_TCI
+ * as an input VLAN tag (e.g. parsed from the packet) and
+ * run the lookup as if ingress had happened on the VLAN
+ * subinterface carrying that tag for *params*->ifindex,
+ * rather than on *params*->ifindex itself. The VID is the
+ * low 12 bits of *params*->h_vlan_TCI;
+ * *params*->h_vlan_proto must be ETH_P_8021Q or
+ * ETH_P_8021AD in network byte order (any other value
+ * returns **-EINVAL**). The
+ * subinterface is the one configured for that tag on
+ * *params*->ifindex; if *params*->ifindex is itself a
+ * VLAN device, its inner (QinQ) subinterface is matched.
+ * For a bond or team, a tag on a port matches no
+ * device and returns NOT_FWDED; pass the master's
+ * ifindex.
+ * If no matching subinterface exists, or it is not up,
+ * or it was moved to another network namespace, the
+ * lookup returns **BPF_FIB_LKUP_RET_NOT_FWDED**,
+ * mirroring real ingress, which drops a frame whose tag
+ * is unconfigured or whose VLAN device is down. A VID of
+ * 0 (a priority-tagged frame) is looked up literally like
+ * any other VID; receive instead processes such frames
+ * untagged on the device itself, so do not set this flag
+ * for priority tags.
+ * Cannot be combined with **BPF_FIB_LOOKUP_TBID** (both
+ * use the same input fields) or **BPF_FIB_LOOKUP_OUTPUT**
+ * (this flag is ingress-only); doing so returns
+ * **-EINVAL**.
*
* *ctx* is either **struct xdp_md** for XDP programs or
* **struct sk_buff** tc cls_act programs.
@@ -7348,6 +7377,7 @@ enum {
BPF_FIB_LOOKUP_SRC = (1U << 4),
BPF_FIB_LOOKUP_MARK = (1U << 5),
BPF_FIB_LOOKUP_VLAN = (1U << 6),
+ BPF_FIB_LOOKUP_VLAN_INPUT = (1U << 7),
};
enum {
@@ -7416,7 +7446,9 @@ struct bpf_fib_lookup {
struct {
/* output with BPF_FIB_LOOKUP_VLAN: set from the
* resolved egress VLAN device (see the flag); zeroed
- * on other successful lookups.
+ * on other successful lookups. input with
+ * BPF_FIB_LOOKUP_VLAN_INPUT: the VLAN tag to scope
+ * the lookup by.
*/
__be16 h_vlan_proto;
__be16 h_vlan_TCI;
--
2.54.0
^ permalink raw reply related
* [PATCH bpf-next v2 2/4] bpf: Add BPF_FIB_LOOKUP_VLAN flag to bpf_fib_lookup() helper
From: Avinash Duduskar @ 2026-06-16 22:34 UTC (permalink / raw)
To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko
Cc: Eduard Zingerman, Kumar Kartikeya Dwivedi, Martin KaFai Lau,
Song Liu, Yonghong Song, Jiri Olsa, Emil Tsalapatis,
John Fastabend, Stanislav Fomichev, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, David Ahern,
Shuah Khan, Jesper Dangaard Brouer, Mykyta Yatsenko, Leon Hwang,
KP Singh, Anton Protopopov, Amery Hung, Eyal Birger, Rong Tao,
Toke Høiland-Jørgensen, bpf, netdev, linux-kselftest,
linux-kernel
In-Reply-To: <20260616223426.3568080-1-avinash.duduskar@gmail.com>
bpf_fib_lookup() returns the FIB-resolved egress ifindex straight
from the fib result. When the egress is a VLAN device, the returned
ifindex is the VLAN netdev's, which has no XDP xmit handler; XDP
programs that want to forward the frame (e.g. xdp-forward) must
instead target the underlying physical device and push the VLAN tag
themselves. Today the program has no way to learn either the
underlying ifindex or the VLAN tag without maintaining its own
VLAN-to-ifindex map in userspace and refreshing it on netlink
events.
Add BPF_FIB_LOOKUP_VLAN. When the caller sets this flag and the fib
result is a VLAN device whose immediate parent is a real (non-VLAN)
device in the same network namespace, populate the existing output
fields params->h_vlan_proto and params->h_vlan_TCI from the VLAN
device and replace params->ifindex with the parent's ifindex.
params->h_vlan_TCI carries the VID only, with PCP and DEI bits zero; a
consumer wanting to set egress priority writes PCP itself.
params->smac is the VLAN device's own address, which can differ from
the parent's.
Only the immediate parent is resolved, via vlan_dev_priv(dev)->real_dev
and not vlan_dev_real_dev(), which walks to the bottom of a stack. For a
stacked VLAN (QinQ) the immediate parent is itself a VLAN device; since
one h_vlan_proto/h_vlan_TCI pair cannot describe two tags, ifindex is
left unchanged and the vlan fields remain zero in that case. The swap
is also skipped when the parent lives in another network namespace (a
VLAN device can be moved while its parent stays), since its ifindex
would be meaningless or match an unrelated device in the caller's
namespace. The swap and the vlan fields are written only on success;
other output fields keep their existing behaviour, so a frag-needed
result still reports the route mtu in params->mtu_result. When the
flag is not set, behaviour is unchanged: h_vlan_proto and h_vlan_TCI
are zeroed and ifindex is left at the FIB result.
The new block is compiled only under CONFIG_VLAN_8021Q since
vlan_dev_priv() is not defined otherwise; without that config
is_vlan_dev() is constant false and the flag is accepted but never
acts.
This lets an XDP redirect target the physical device and learn the
tag to push in a single lookup, which xdp-forward's optional VLAN
mode (xdp-project/xdp-tools#504) wants from the kernel side.
The helper's input semantics are unchanged; the reverse direction
(supplying a tag as lookup input) is added in the following patch.
Suggested-by: Toke Høiland-Jørgensen <toke@redhat.com>
Signed-off-by: Avinash Duduskar <avinash.duduskar@gmail.com>
---
include/uapi/linux/bpf.h | 31 ++++++++++++++++++++++++++-
net/core/filter.c | 39 ++++++++++++++++++++++++++++++----
tools/include/uapi/linux/bpf.h | 31 ++++++++++++++++++++++++++-
3 files changed, 95 insertions(+), 6 deletions(-)
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 11dd610fa5fa..f77aa9472bf1 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -3527,6 +3527,31 @@ union bpf_attr {
* Use the mark present in *params*->mark for the fib lookup.
* This option should not be used with BPF_FIB_LOOKUP_DIRECT,
* as it only has meaning for full lookups.
+ * **BPF_FIB_LOOKUP_VLAN**
+ * If the fib lookup resolves to a VLAN device whose
+ * parent is a real (non-VLAN) device, set
+ * *params*->h_vlan_proto and *params*->h_vlan_TCI from
+ * the VLAN device and replace *params*->ifindex with the
+ * parent's ifindex. This lets XDP programs that target
+ * the underlying physical device (VLAN devices have no
+ * XDP xmit) discover both the real egress ifindex and
+ * the VLAN tag to push in one call. *params*->h_vlan_TCI
+ * carries the VID only, with PCP and DEI bits zero; a
+ * consumer wanting to set egress priority writes PCP
+ * itself. *params*->smac is the VLAN device's own
+ * address, which can differ from the parent's. Only the
+ * immediate parent is resolved: for a stacked VLAN (QinQ)
+ * the parent is itself a VLAN device, and since one tag
+ * pair cannot describe two tags, *params*->ifindex is
+ * left unchanged and the vlan fields remain zero. The
+ * same applies when the parent is in another network
+ * namespace, where its ifindex would be meaningless.
+ * The swap and the vlan fields are written only on
+ * success; other output fields keep the helper's
+ * existing behaviour, so a frag-needed result still
+ * reports the route mtu in *params*->mtu_result, and on
+ * the tc path without tot_len the mtu check runs after
+ * the swap, against the parent device.
*
* *ctx* is either **struct xdp_md** for XDP programs or
* **struct sk_buff** tc cls_act programs.
@@ -7322,6 +7347,7 @@ enum {
BPF_FIB_LOOKUP_TBID = (1U << 3),
BPF_FIB_LOOKUP_SRC = (1U << 4),
BPF_FIB_LOOKUP_MARK = (1U << 5),
+ BPF_FIB_LOOKUP_VLAN = (1U << 6),
};
enum {
@@ -7388,7 +7414,10 @@ struct bpf_fib_lookup {
union {
struct {
- /* output */
+ /* output with BPF_FIB_LOOKUP_VLAN: set from the
+ * resolved egress VLAN device (see the flag); zeroed
+ * on other successful lookups.
+ */
__be16 h_vlan_proto;
__be16 h_vlan_TCI;
};
diff --git a/net/core/filter.c b/net/core/filter.c
index 6fa172cb1348..b37a12321fba 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -6119,10 +6119,40 @@ static const struct bpf_func_proto bpf_skb_get_xfrm_state_proto = {
#endif
#if IS_ENABLED(CONFIG_INET) || IS_ENABLED(CONFIG_IPV6)
-static int bpf_fib_set_fwd_params(struct bpf_fib_lookup *params, u32 mtu)
+static int bpf_fib_set_fwd_params(struct net_device *dev,
+ struct bpf_fib_lookup *params,
+ u32 flags, u32 mtu)
{
params->h_vlan_TCI = 0;
params->h_vlan_proto = 0;
+
+#if IS_ENABLED(CONFIG_VLAN_8021Q)
+ /* vlan_dev_priv() is only defined when 8021q is built in or as a
+ * module; under !CONFIG_VLAN_8021Q is_vlan_dev() is constant false
+ * so this would be dead, but it still has to compile.
+ */
+ if ((flags & BPF_FIB_LOOKUP_VLAN) && is_vlan_dev(dev)) {
+ struct net_device *real_dev = vlan_dev_priv(dev)->real_dev;
+
+ /* Resolve the immediate parent only. For a stacked VLAN
+ * (QinQ) the parent is itself a VLAN device, and a single
+ * h_vlan_proto/h_vlan_TCI pair cannot describe both tags;
+ * leave ifindex and the vlan fields untouched in that case
+ * rather than report the lower device with only one tag.
+ * The same applies when the parent lives in another netns
+ * (a VLAN device can be moved while its parent stays):
+ * its ifindex would be meaningless, or match an unrelated
+ * device, in the caller's namespace.
+ */
+ if (!is_vlan_dev(real_dev) &&
+ net_eq(dev_net(real_dev), dev_net(dev))) {
+ params->h_vlan_proto = vlan_dev_vlan_proto(dev);
+ params->h_vlan_TCI = htons(vlan_dev_vlan_id(dev));
+ params->ifindex = real_dev->ifindex;
+ }
+ }
+#endif
+
if (mtu)
params->mtu_result = mtu; /* union with tot_len */
@@ -6266,7 +6296,7 @@ static int bpf_ipv4_fib_lookup(struct net *net, struct bpf_fib_lookup *params,
memcpy(params->smac, dev->dev_addr, ETH_ALEN);
set_fwd_params:
- return bpf_fib_set_fwd_params(params, mtu);
+ return bpf_fib_set_fwd_params(dev, params, flags, mtu);
}
#endif
@@ -6406,13 +6436,14 @@ static int bpf_ipv6_fib_lookup(struct net *net, struct bpf_fib_lookup *params,
memcpy(params->smac, dev->dev_addr, ETH_ALEN);
set_fwd_params:
- return bpf_fib_set_fwd_params(params, mtu);
+ return bpf_fib_set_fwd_params(dev, params, flags, mtu);
}
#endif
#define BPF_FIB_LOOKUP_MASK (BPF_FIB_LOOKUP_DIRECT | BPF_FIB_LOOKUP_OUTPUT | \
BPF_FIB_LOOKUP_SKIP_NEIGH | BPF_FIB_LOOKUP_TBID | \
- BPF_FIB_LOOKUP_SRC | BPF_FIB_LOOKUP_MARK)
+ BPF_FIB_LOOKUP_SRC | BPF_FIB_LOOKUP_MARK | \
+ BPF_FIB_LOOKUP_VLAN)
BPF_CALL_4(bpf_xdp_fib_lookup, struct xdp_buff *, ctx,
struct bpf_fib_lookup *, params, int, plen, u32, flags)
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
index 11dd610fa5fa..f77aa9472bf1 100644
--- a/tools/include/uapi/linux/bpf.h
+++ b/tools/include/uapi/linux/bpf.h
@@ -3527,6 +3527,31 @@ union bpf_attr {
* Use the mark present in *params*->mark for the fib lookup.
* This option should not be used with BPF_FIB_LOOKUP_DIRECT,
* as it only has meaning for full lookups.
+ * **BPF_FIB_LOOKUP_VLAN**
+ * If the fib lookup resolves to a VLAN device whose
+ * parent is a real (non-VLAN) device, set
+ * *params*->h_vlan_proto and *params*->h_vlan_TCI from
+ * the VLAN device and replace *params*->ifindex with the
+ * parent's ifindex. This lets XDP programs that target
+ * the underlying physical device (VLAN devices have no
+ * XDP xmit) discover both the real egress ifindex and
+ * the VLAN tag to push in one call. *params*->h_vlan_TCI
+ * carries the VID only, with PCP and DEI bits zero; a
+ * consumer wanting to set egress priority writes PCP
+ * itself. *params*->smac is the VLAN device's own
+ * address, which can differ from the parent's. Only the
+ * immediate parent is resolved: for a stacked VLAN (QinQ)
+ * the parent is itself a VLAN device, and since one tag
+ * pair cannot describe two tags, *params*->ifindex is
+ * left unchanged and the vlan fields remain zero. The
+ * same applies when the parent is in another network
+ * namespace, where its ifindex would be meaningless.
+ * The swap and the vlan fields are written only on
+ * success; other output fields keep the helper's
+ * existing behaviour, so a frag-needed result still
+ * reports the route mtu in *params*->mtu_result, and on
+ * the tc path without tot_len the mtu check runs after
+ * the swap, against the parent device.
*
* *ctx* is either **struct xdp_md** for XDP programs or
* **struct sk_buff** tc cls_act programs.
@@ -7322,6 +7347,7 @@ enum {
BPF_FIB_LOOKUP_TBID = (1U << 3),
BPF_FIB_LOOKUP_SRC = (1U << 4),
BPF_FIB_LOOKUP_MARK = (1U << 5),
+ BPF_FIB_LOOKUP_VLAN = (1U << 6),
};
enum {
@@ -7388,7 +7414,10 @@ struct bpf_fib_lookup {
union {
struct {
- /* output */
+ /* output with BPF_FIB_LOOKUP_VLAN: set from the
+ * resolved egress VLAN device (see the flag); zeroed
+ * on other successful lookups.
+ */
__be16 h_vlan_proto;
__be16 h_vlan_TCI;
};
--
2.54.0
^ permalink raw reply related
* [PATCH bpf-next v2 1/4] bpf: Initialize the l3mdev field for the fib lookup flow
From: Avinash Duduskar @ 2026-06-16 22:34 UTC (permalink / raw)
To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko
Cc: Eduard Zingerman, Kumar Kartikeya Dwivedi, Martin KaFai Lau,
Song Liu, Yonghong Song, Jiri Olsa, Emil Tsalapatis,
John Fastabend, Stanislav Fomichev, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, David Ahern,
Shuah Khan, Jesper Dangaard Brouer, Mykyta Yatsenko, Leon Hwang,
KP Singh, Anton Protopopov, Amery Hung, Eyal Birger, Rong Tao,
Toke Høiland-Jørgensen, bpf, netdev, linux-kselftest,
linux-kernel
In-Reply-To: <20260616223426.3568080-1-avinash.duduskar@gmail.com>
bpf_ipv4_fib_lookup() and bpf_ipv6_fib_lookup() build the flow key on
the stack with a bare "struct flowi4 fl4;" / "struct flowi6 fl6;" and
fill it field by field, but never set flowi4_l3mdev / flowi6_l3mdev.
On the non-DIRECT path the lookup goes through the fib rules whenever the
netns has custom rules, which a VRF installs:
bpf_ipv4_fib_lookup() -> fib_lookup() -> __fib_lookup()
-> l3mdev_update_flow() reads !fl->flowi_l3mdev
-> fib_rules_lookup() -> fib_rule_match()
-> l3mdev_fib_rule_match() uses fl->flowi_l3mdev
l3mdev_update_flow() resolves the l3mdev master from the ingress device
only while the field is still zero:
if (fl->flowi_iif > LOOPBACK_IFINDEX && !fl->flowi_l3mdev) {
dev = dev_get_by_index_rcu(net, fl->flowi_iif);
if (dev)
fl->flowi_l3mdev = l3mdev_master_ifindex_rcu(dev);
}
Left at a nonzero stack value the resolution is skipped, and
l3mdev_fib_rule_match() then tests that value as an ifindex, so the VRF
master is not resolved and the rule fails to match: an ingress enslaved
to a VRF can fail to select its table. The same value is also read just
before that, by FIB rules matching on an L3 master device
(l3mdev_fib_rule_iif_match()/_oif_match()), so an "ip rule iif/oif <vrf>"
mismatches the same way.
The helper already initializes the other flow fields the rules path
consumes (flowi4_mark, flowi4_tun_key.tun_id, flowi4_uid and the v6
counterparts); flowi*_l3mdev was added to that set afterwards and this
helper was never updated to match. ip_route_input_slow() likewise zeroes
the field before its input lookup. Do the same here.
CONFIG_INIT_STACK_ALL_ZERO masks this by default, but it depends on
compiler support (CC_HAS_AUTO_VAR_INIT_ZERO), so INIT_STACK_NONE builds,
including older toolchains that fall back to it, are exposed. Built with
INIT_STACK_ALL_PATTERN, a plain bpf_fib_lookup (no VLAN, no DIRECT) over a
VRF slave whose destination is routed only in the VRF table returns
BPF_FIB_LKUP_RET_NOT_FWDED, and resolves with this patch; reverting these
two lines flips it back. The series' VRF selftests pass on the default
config either way, so they do not exercise this fix.
Fixes: 40867d74c374 ("net: Add l3mdev index to flow struct and avoid oif reset for port devices")
Signed-off-by: Avinash Duduskar <avinash.duduskar@gmail.com>
---
net/core/filter.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/net/core/filter.c b/net/core/filter.c
index 9590877b0714..6fa172cb1348 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -6162,6 +6162,7 @@ static int bpf_ipv4_fib_lookup(struct net *net, struct bpf_fib_lookup *params,
fl4.flowi4_dscp = inet_dsfield_to_dscp(params->tos);
fl4.flowi4_scope = RT_SCOPE_UNIVERSE;
fl4.flowi4_flags = 0;
+ fl4.flowi4_l3mdev = 0;
fl4.flowi4_proto = params->l4_protocol;
fl4.daddr = params->ipv4_dst;
@@ -6307,6 +6308,7 @@ static int bpf_ipv6_fib_lookup(struct net *net, struct bpf_fib_lookup *params,
fl6.flowlabel = params->flowinfo;
fl6.flowi6_scope = 0;
fl6.flowi6_flags = 0;
+ fl6.flowi6_l3mdev = 0;
fl6.mp_hash = 0;
fl6.flowi6_proto = params->l4_protocol;
base-commit: 140fa23df957b51385aa847986d44ad7f59b0563
--
2.54.0
^ permalink raw reply related
* [PATCH bpf-next v2 0/4] bpf: bidirectional VLAN support for bpf_fib_lookup()
From: Avinash Duduskar @ 2026-06-16 22:34 UTC (permalink / raw)
To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko
Cc: Eduard Zingerman, Kumar Kartikeya Dwivedi, Martin KaFai Lau,
Song Liu, Yonghong Song, Jiri Olsa, Emil Tsalapatis,
John Fastabend, Stanislav Fomichev, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, David Ahern,
Shuah Khan, Jesper Dangaard Brouer, Mykyta Yatsenko, Leon Hwang,
KP Singh, Anton Protopopov, Amery Hung, Eyal Birger, Rong Tao,
Toke Høiland-Jørgensen, bpf, netdev, linux-kselftest,
linux-kernel
v1 added a single flag, BPF_FIB_LOOKUP_VLAN, to resolve a VLAN egress to
its underlying real device plus the VLAN tag. v2 fixes a QinQ bug the bpf
ci bot found, adds the input direction Toke asked for, adds selftests,
and prepends a fix for a pre-existing l3mdev/VRF lookup bug in the helper.
Patch 1 is an independent fix: bpf_fib_lookup() never initialized the
flow's flowi_l3mdev field, so on the fib-rules path it is read before it
is written. The VRF master is then not resolved and the l3mdev rule fails
to match, so a slave ingress can fail to select its VRF table, today,
with no part of this series. The helper already initializes every other
rules-path flow field (mark, tun_key, uid); l3mdev was added to that set
later and this one was missed. CONFIG_INIT_STACK_ALL_ZERO (the default)
masks it, which is why the VRF selftests in patch 4 pass with or without
it; built with CONFIG_INIT_STACK_ALL_PATTERN a plain bpf_fib_lookup over a
VRF slave returns NOT_FWDED without the patch and resolves with it. It is
first so the VRF behaviour the later patches document and test is well
defined. If you would rather take it through bpf or net on its own, I am
happy to send it separately. It will not apply cleanly before v6.18,
where the flowi4_dscp context line reads flowi4_tos, so a stable backport
needs a trivial context fixup.
Changes v1 -> v2:
- Fix QinQ handling (found by the bpf ci bot): resolve the immediate
parent with vlan_dev_priv(dev)->real_dev instead of
vlan_dev_real_dev() (which walks to the bottom of a stack), and only
swap when that parent is a real device; stacked VLANs are left
unchanged. The egress block is guarded with CONFIG_VLAN_8021Q.
- Add BPF_FIB_LOOKUP_VLAN_INPUT for the input direction (requested by
Toke): supply the packet tag, run the lookup on the matching VLAN
subinterface. Exclusive with BPF_FIB_LOOKUP_TBID (shared union) and
BPF_FIB_LOOKUP_OUTPUT (ingress-only); both return -EINVAL. Taking the
tag as lookup input follows the approach David Ahern suggested in the
2021 fwmark discussion:
https://lore.kernel.org/bpf/6248c547-ad64-04d6-fcec-374893cc1ef2@gmail.com/
- Both directions are network-namespace aware: a VLAN device can be
moved to another netns while registered on its parent, so the egress
swap is skipped (foreign parent ifindex is meaningless) and the input
resolution fails closed for a device in another netns.
- Add 36 selftest cases plus a cross-netns subtest in
prog_tests/fib_lookup.c, covering both directions, the neighbour path,
OUTPUT and DIRECT|TBID, VRF (rule and DIRECT), resolution semantics
(802.1ad, PCP/DEI, QinQ-inner, bond master and port), the frag-needed
mtu_result, the error returns on both families, and the netns boundary
in both directions.
- Document both flags and the now-bidirectional h_vlan_proto/h_vlan_TCI
fields.
Open questions (defaults chosen, noted here in case a maintainer prefers
otherwise):
1. An unmatched, down, or foreign-netns tag returns
BPF_FIB_LKUP_RET_NOT_FWDED, matching the DIRECT path when
fib_get_table() finds no table, rather than a new return code.
2. BPF_FIB_LOOKUP_OUTPUT | BPF_FIB_LOOKUP_VLAN_INPUT is rejected with
-EINVAL; restricting now keeps relaxing later backward-compatible.
3. The name BPF_FIB_LOOKUP_VLAN_INPUT reads oddly next to
BPF_FIB_LOOKUP_OUTPUT. A pair like _VLAN_EGRESS/_VLAN_INGRESS is an
option while nothing is merged.
4. With BPF_FIB_LOOKUP_VLAN, the tc-path mtu check that runs when
tot_len is not set follows params->ifindex, so after a swap it
checks against the parent device rather than the VLAN device (the
route-mtu path via tot_len is unaffected). Checking against the
VLAN device would preserve the pre-flag semantics if that is
preferred.
On the bot's comment-style note: the new comments keep the form that
prevails in net/core/filter.c, and checkpatch --strict is clean.
v1: https://lore.kernel.org/all/20260609172052.81613-1-avinash.duduskar@gmail.com/
Avinash Duduskar (4):
bpf: Initialize the l3mdev field for the fib lookup flow
bpf: Add BPF_FIB_LOOKUP_VLAN flag to bpf_fib_lookup() helper
bpf: Add BPF_FIB_LOOKUP_VLAN_INPUT flag to bpf_fib_lookup() helper
selftests/bpf: Add bpf_fib_lookup() VLAN flag tests
include/uapi/linux/bpf.h | 63 ++-
net/core/filter.c | 119 ++++-
tools/include/uapi/linux/bpf.h | 63 ++-
.../selftests/bpf/prog_tests/fib_lookup.c | 494 +++++++++++++++++-
4 files changed, 726 insertions(+), 13 deletions(-)
base-commit: 140fa23df957b51385aa847986d44ad7f59b0563
--
2.54.0
^ permalink raw reply
* Re: [PATCH bpf-next 2/2] selftests/bpf: Cover small conntrack opts error writes
From: Emil Tsalapatis @ 2026-06-16 22:34 UTC (permalink / raw)
To: Yiyang Chen, bpf, netfilter-devel
Cc: pablo, fw, phil, davem, edumazet, kuba, pabeni, horms, andrii,
eddyz87, ast, daniel, memxor, martin.lau, song, yonghong.song,
jolsa, emil, shuah, kartikey406, coreteam, netdev, linux-kernel,
linux-kselftest
In-Reply-To: <c4c898dd23181b676ebf6b6b4d9c54f51bb69c75.1781586477.git.chenyy23@mails.tsinghua.edu.cn>
On Tue Jun 16, 2026 at 1:42 AM EDT, Yiyang Chen wrote:
> Add a conntrack kfunc regression check for opts__sz values that do not
> cover opts->error. The BPF program initializes opts->error with a guard
> value, calls the lookup and allocation kfuncs with opts__sz set to
> sizeof(opts->netns_id), and verifies that the guard is still intact
> after the kfunc returns NULL.
>
> Without the conntrack wrapper guard, the kfunc error path overwrites
> that guard with -EINVAL even though the verifier checked only the first
> four bytes of the options object.
>
> Signed-off-by: Yiyang Chen <chenyy23@mails.tsinghua.edu.cn>
Reviewed-by: Emil Tsalapatis <emil@etsalapatis.com>
> ---
> .../testing/selftests/bpf/prog_tests/bpf_nf.c | 6 +++++
> .../testing/selftests/bpf/progs/test_bpf_nf.c | 26 +++++++++++++++++++
> 2 files changed, 32 insertions(+)
>
> diff --git a/tools/testing/selftests/bpf/prog_tests/bpf_nf.c b/tools/testing/selftests/bpf/prog_tests/bpf_nf.c
> index b33dba4b126e2..14d4c1793aed5 100644
> --- a/tools/testing/selftests/bpf/prog_tests/bpf_nf.c
> +++ b/tools/testing/selftests/bpf/prog_tests/bpf_nf.c
> @@ -5,6 +5,8 @@
> #include "test_bpf_nf.skel.h"
> #include "test_bpf_nf_fail.skel.h"
>
> +#define CT_OPTS_ERROR_GUARD 0x12345678
> +
> static char log_buf[1024 * 1024];
>
> struct {
> @@ -119,6 +121,10 @@ static void test_bpf_nf_ct(int mode)
> ASSERT_EQ(skel->bss->test_einval_reserved_new, -EINVAL, "Test EINVAL for reserved in new struct not set to 0");
> ASSERT_EQ(skel->bss->test_einval_netns_id, -EINVAL, "Test EINVAL for netns_id < -1");
> ASSERT_EQ(skel->bss->test_einval_len_opts, -EINVAL, "Test EINVAL for len__opts != NF_BPF_CT_OPTS_SZ");
> + ASSERT_EQ(skel->bss->test_einval_len_opts_small_lookup, CT_OPTS_ERROR_GUARD,
> + "Test no error write for lookup opts__sz before error field");
> + ASSERT_EQ(skel->bss->test_einval_len_opts_small_alloc, CT_OPTS_ERROR_GUARD,
> + "Test no error write for alloc opts__sz before error field");
> ASSERT_EQ(skel->bss->test_eproto_l4proto, -EPROTO, "Test EPROTO for l4proto != TCP or UDP");
> ASSERT_EQ(skel->bss->test_enonet_netns_id, -ENONET, "Test ENONET for bad but valid netns_id");
> ASSERT_EQ(skel->bss->test_enoent_lookup, -ENOENT, "Test ENOENT for failed lookup");
> diff --git a/tools/testing/selftests/bpf/progs/test_bpf_nf.c b/tools/testing/selftests/bpf/progs/test_bpf_nf.c
> index 076fbf03a1268..df43649ecb785 100644
> --- a/tools/testing/selftests/bpf/progs/test_bpf_nf.c
> +++ b/tools/testing/selftests/bpf/progs/test_bpf_nf.c
> @@ -10,6 +10,8 @@
> #define EINVAL 22
> #define ENOENT 2
>
> +#define CT_OPTS_ERROR_GUARD 0x12345678
> +
> #define NF_CT_ZONE_DIR_ORIG (1 << IP_CT_DIR_ORIGINAL)
> #define NF_CT_ZONE_DIR_REPL (1 << IP_CT_DIR_REPLY)
>
> @@ -19,6 +21,8 @@ int test_einval_reserved = 0;
> int test_einval_reserved_new = 0;
> int test_einval_netns_id = 0;
> int test_einval_len_opts = 0;
> +int test_einval_len_opts_small_lookup = 0;
> +int test_einval_len_opts_small_alloc = 0;
> int test_eproto_l4proto = 0;
> int test_enonet_netns_id = 0;
> int test_enoent_lookup = 0;
> @@ -124,6 +128,28 @@ nf_ct_test(struct nf_conn *(*lookup_fn)(void *, struct bpf_sock_tuple *, u32,
> else
> test_einval_len_opts = opts_def.error;
>
> + opts_def.error = CT_OPTS_ERROR_GUARD;
> + ct = lookup_fn(ctx, &bpf_tuple, sizeof(bpf_tuple.ipv4), &opts_def,
> + sizeof(opts_def.netns_id));
> + if (ct) {
> + bpf_ct_release(ct);
> + test_einval_len_opts_small_lookup = -EINVAL;
> + } else {
> + test_einval_len_opts_small_lookup = opts_def.error;
> + }
> +
> + opts_def.error = CT_OPTS_ERROR_GUARD;
> + ct = alloc_fn(ctx, &bpf_tuple, sizeof(bpf_tuple.ipv4), &opts_def,
> + sizeof(opts_def.netns_id));
> + if (ct) {
> + ct = bpf_ct_insert_entry(ct);
> + if (ct)
> + bpf_ct_release(ct);
> + test_einval_len_opts_small_alloc = -EINVAL;
> + } else {
> + test_einval_len_opts_small_alloc = opts_def.error;
> + }
> +
> opts_def.l4proto = IPPROTO_ICMP;
> ct = lookup_fn(ctx, &bpf_tuple, sizeof(bpf_tuple.ipv4), &opts_def,
> sizeof(opts_def));
^ permalink raw reply
* [PATCH] netdevsim: Fix deadlock in del_device_store() and nsim_bus_exit()
From: Moksh Panicker @ 2026-06-16 22:26 UTC (permalink / raw)
To: kuba
Cc: andrew+netdev, davem, edumazet, pabeni, netdev, linux-kernel,
skhan, Moksh Panicker, syzbot+1cf303af03cf30b1275a
del_device_store() and nsim_bus_exit() both hold nsim_bus_dev_list_lock
while calling nsim_bus_dev_del(), which calls device_unregister() which
internally acquires the device lock. If another thread already holds
the device lock and tries to acquire nsim_bus_dev_list_lock, a deadlock
occurs:
INFO: task hung in nsim_bus_dev_del
Fix this by releasing nsim_bus_dev_list_lock before calling
nsim_bus_dev_del() in both locations, after the devices have already
been removed from the list with list_del().
Reported-by: syzbot+1cf303af03cf30b1275a@syzkaller.appspot.com
Closes: https://syzkaller.appspot.com/bug?extid=1cf303af03cf30b1275a
Signed-off-by: Moksh Panicker <mokshpanicker.7@gmail.com>
---
drivers/net/netdevsim/bus.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/drivers/net/netdevsim/bus.c b/drivers/net/netdevsim/bus.c
index 41483e371..0f02ff8ad 100644
--- a/drivers/net/netdevsim/bus.c
+++ b/drivers/net/netdevsim/bus.c
@@ -241,11 +241,12 @@ del_device_store(const struct bus_type *bus, const char *buf, size_t count)
if (nsim_bus_dev->dev.id != id)
continue;
list_del(&nsim_bus_dev->list);
- nsim_bus_dev_del(nsim_bus_dev);
err = 0;
break;
}
mutex_unlock(&nsim_bus_dev_list_lock);
+ if (!err)
+ nsim_bus_dev_del(nsim_bus_dev);
return !err ? count : err;
}
static BUS_ATTR_WO(del_device);
@@ -527,11 +528,11 @@ void nsim_bus_exit(void)
complete(&nsim_bus_devs_released);
mutex_lock(&nsim_bus_dev_list_lock);
- list_for_each_entry_safe(nsim_bus_dev, tmp, &nsim_bus_dev_list, list) {
+ list_for_each_entry_safe(nsim_bus_dev, tmp, &nsim_bus_dev_list, list)
list_del(&nsim_bus_dev->list);
- nsim_bus_dev_del(nsim_bus_dev);
- }
mutex_unlock(&nsim_bus_dev_list_lock);
+ list_for_each_entry_safe(nsim_bus_dev, tmp, &nsim_bus_dev_list, list)
+ nsim_bus_dev_del(nsim_bus_dev);
wait_for_completion(&nsim_bus_devs_released);
--
2.34.1
^ permalink raw reply related
* Re: [PATCH v2] [net] net: airoha: Fix QoS counter configuration for Tx-fwd channels
From: patchwork-bot+netdevbpf @ 2026-06-16 22:11 UTC (permalink / raw)
To: Wayen Yan
Cc: netdev, lorenzo, horms, pabeni, kuba, edumazet, andrew+netdev,
angelogioacchino.delregno, matthias.bgg, linux-arm-kernel,
linux-mediatek
In-Reply-To: <178161132384.2164449.18407700117859190327@gmail.com>
Hello:
This patch was applied to netdev/net-next.git (main)
by Jakub Kicinski <kuba@kernel.org>:
On Tue, 16 Jun 2026 18:50:29 +0800 you wrote:
> In airoha_qdma_init_qos_stats(), the Tx-fwd counter was incorrectly
> using register index (i << 1) instead of ((i << 1) + 1). This caused
> the Tx-fwd configuration to overwrite the Tx-cpu configuration for
> each QoS channel, resulting in incorrect QoS statistics.
>
> Fix by using the correct register index ((i << 1) + 1) for Tx-fwd
> counter configuration.
>
> [...]
Here is the summary with links:
- [v2,net] net: airoha: Fix QoS counter configuration for Tx-fwd channels
https://git.kernel.org/netdev/net-next/c/1402ecccf563
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: airoha: Fix QoS counter configuration for Tx-fwd channels
From: patchwork-bot+netdevbpf @ 2026-06-16 22:11 UTC (permalink / raw)
To: Wayen Yan
Cc: netdev, lorenzo, horms, pabeni, kuba, edumazet, andrew+netdev,
angelogioacchino.delregno, matthias.bgg, linux-arm-kernel,
linux-mediatek
In-Reply-To: <178160712947.2156222.3765685889775458986@gmail.com>
Hello:
This patch was applied to netdev/net-next.git (main)
by Jakub Kicinski <kuba@kernel.org>:
On Tue, 16 Jun 2026 18:50:29 +0800 you wrote:
> In airoha_qdma_init_qos_stats(), the Tx-fwd counter was incorrectly
> using register index (i << 1) instead of ((i << 1) + 1). This caused
> the Tx-fwd configuration to overwrite the Tx-cpu configuration for
> each QoS channel, resulting in incorrect QoS statistics.
>
> Fix by using the correct register index ((i << 1) + 1) for Tx-fwd
> counter configuration.
>
> [...]
Here is the summary with links:
- net: airoha: Fix QoS counter configuration for Tx-fwd channels
https://git.kernel.org/netdev/net-next/c/1402ecccf563
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* [PATCH v2] ice: retry reading NVM if admin queue returns EBUSY
From: Robert Malz @ 2026-06-16 22:08 UTC (permalink / raw)
To: anthony.l.nguyen, przemyslaw.kitszel; +Cc: intel-wired-lan, netdev
When the admin queue command to read NVM returns EBUSY, the driver
currently treats it as a fatal error and aborts the entire read
operation. This can cause spurious NVM read failures during periods of
high firmware activity.
Add retry logic to ice_read_flat_nvm() that handles EBUSY responses
from the admin queue. When an EBUSY error is encountered, release the
NVM resource lock, wait for ICE_SQ_SEND_DELAY_TIME_MS, re-acquire it,
and retry the failed read. The retry is attempted up to
ICE_SQ_SEND_MAX_EXECUTE times before giving up.
Code was extracted from OOT ice driver 1.15.4 release. Additional
change was made to reset last_cmd in case of retry to make sure that
all commands are retried properly.
Fixes: e94509906d6b ("ice: create function to read a section of the NVM and Shadow RAM")
Signed-off-by: Robert Malz <robert.malz@canonical.com>
---
Changes in v2:
- change ICE_AQ_RC_EBUSY -> LIBIE_AQ_RC_EBUSY
drivers/net/ethernet/intel/ice/ice_nvm.c | 25 +++++++++++++++++++-----
1 file changed, 20 insertions(+), 5 deletions(-)
diff --git a/drivers/net/ethernet/intel/ice/ice_nvm.c b/drivers/net/ethernet/intel/ice/ice_nvm.c
index 7e187a804dfa..b3120605d66f 100644
--- a/drivers/net/ethernet/intel/ice/ice_nvm.c
+++ b/drivers/net/ethernet/intel/ice/ice_nvm.c
@@ -67,6 +67,7 @@ ice_read_flat_nvm(struct ice_hw *hw, u32 offset, u32 *length, u8 *data,
{
u32 inlen = *length;
u32 bytes_read = 0;
+ int retry_cnt = 0;
bool last_cmd;
int status;
@@ -96,11 +97,25 @@ ice_read_flat_nvm(struct ice_hw *hw, u32 offset, u32 *length, u8 *data,
offset, read_size,
data + bytes_read, last_cmd,
read_shadow_ram, NULL);
- if (status)
- break;
-
- bytes_read += read_size;
- offset += read_size;
+ if (status) {
+ if (hw->adminq.sq_last_status != LIBIE_AQ_RC_EBUSY ||
+ retry_cnt > ICE_SQ_SEND_MAX_EXECUTE)
+ break;
+ ice_debug(hw, ICE_DBG_NVM,
+ "NVM read EBUSY error, retry %d\n",
+ retry_cnt + 1);
+ last_cmd = false;
+ ice_release_nvm(hw);
+ msleep(ICE_SQ_SEND_DELAY_TIME_MS);
+ status = ice_acquire_nvm(hw, ICE_RES_READ);
+ if (status)
+ break;
+ retry_cnt++;
+ } else {
+ bytes_read += read_size;
+ offset += read_size;
+ retry_cnt = 0;
+ }
} while (!last_cmd);
*length = bytes_read;
--
2.34.1
^ permalink raw reply related
* Re: [PATCH v1 bpf-next 0/2] bpf: bpf_redirect_peer egress redirection
From: Paul Chaignon @ 2026-06-16 22:06 UTC (permalink / raw)
To: Jordan Rife
Cc: bpf, netdev, Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Martin KaFai Lau, Stanislav Fomichev
In-Reply-To: <CABi4-ogYKX9T_gWcXsKSs5-y=3GA_WqwfyjobmCxexTtQ_H86w@mail.gmail.com>
On Tue, Jun 16, 2026 at 01:49:26PM -0700, Jordan Rife wrote:
> > IMO, calling it BPF_F_EGRESS would be less confusing. It's a shame we
> > can't have the same flag API between bpf_redirect() and
> > bpf_redirect_peer(), but this is creating inconsistent semantics for
> > the terms egress/ingress across the two helpers.
>
> Yeah, one annoying thing about BPF_F_EGRESS is that it would only
> apply to bpf_redirect_peer, so you still have inconsistencies across
Yes, that's what I meant by "we can't have the same flag API" :)
Alternatively, we could define BPF_F_EGRESS as 1ULL << 1, for both
helpers, but I'm not sure it's worth it. Maybe Daniel will have another
idea?
> helpers. Perhaps this is less weird than having BPF_F_INGRESS perform
> an egress redirection though.
>
> Jordan
^ permalink raw reply
* [PATCH] net/sched: dualpi2: fix GSO backlog accounting
From: Xingquan Liu @ 2026-06-16 22:02 UTC (permalink / raw)
To: netdev; +Cc: Jamal Hadi Salim, Jiri Pirko, Victor Nogueira, Xingquan Liu,
stable
When DualPI2 splits a GSO skb into N segments, it propagates N
additional packets to its parent before returning NET_XMIT_SUCCESS.
The parent then accounts for the original skb once more, leaving its
qlen one larger than the number of packets actually queued.
With QFQ as the parent, after all real packets are dequeued, QFQ still
has a non-zero qlen while its in-service aggregate has no active
classes. qfq_choose_next_agg() returns NULL and qfq_dequeue() passes
the result to qfq_peek_skb(), causing a NULL pointer dereference.
Count only successfully queued segments and propagate the difference
between the original skb and those segments. Return success whenever
at least one segment was queued.
Fixes: 8f9516daedd6 ("sched: Add enqueue/dequeue of dualpi2 qdisc")
Cc: stable@vger.kernel.org
Signed-off-by: Xingquan Liu <b1n@b1n.io>
---
net/sched/sch_dualpi2.c | 11 +++++------
1 file changed, 5 insertions(+), 6 deletions(-)
diff --git a/net/sched/sch_dualpi2.c b/net/sched/sch_dualpi2.c
index dfec3c99eb45..37d6a8960310 100644
--- a/net/sched/sch_dualpi2.c
+++ b/net/sched/sch_dualpi2.c
@@ -461,7 +461,7 @@ static int dualpi2_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch,
if (IS_ERR_OR_NULL(nskb))
return qdisc_drop(skb, sch, to_free);
- cnt = 1;
+ cnt = 0;
byte_len = 0;
orig_len = qdisc_pkt_len(skb);
skb_list_walk_safe(nskb, nskb, next) {
@@ -488,16 +488,15 @@ static int dualpi2_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch,
byte_len += nskb->len;
}
}
- if (cnt > 1) {
+ if (cnt > 0) {
/* The caller will add the original skb stats to its
* backlog, compensate this if any nskb is enqueued.
*/
- --cnt;
- byte_len -= orig_len;
+ qdisc_tree_reduce_backlog(sch, 1 - cnt,
+ orig_len - byte_len);
}
- qdisc_tree_reduce_backlog(sch, -cnt, -byte_len);
consume_skb(skb);
- return err;
+ return cnt > 0 ? NET_XMIT_SUCCESS : err;
}
return dualpi2_enqueue_skb(skb, sch, to_free);
}
base-commit: fbc6a80cb5d3fd4ac4b56e8c9d791dd17be890c4
--
Xingquan Liu
^ permalink raw reply related
* Re: [PATCH net-next 0/2] appletalk: move the protocol out of tree
From: patchwork-bot+netdevbpf @ 2026-06-16 22:00 UTC (permalink / raw)
To: Jakub Kicinski
Cc: davem, netdev, edumazet, pabeni, andrew+netdev, horms, geert,
chleroy, npiggin, mpe, maddy, linux-mips, linux-m68k,
linuxppc-dev
In-Reply-To: <20260615222935.947233-1-kuba@kernel.org>
Hello:
This series was applied to netdev/net-next.git (main)
by Jakub Kicinski <kuba@kernel.org>:
On Mon, 15 Jun 2026 15:29:33 -0700 you wrote:
> This tiny series moves appletalk out of tree, to:
>
> https://github.com/linux-netdev/mod-orphan
>
> Core maintainainers are unable to keep up with the rate of security
> bug reports and fixes. Nobody seems to care about appletalk enough
> to review the patches.
>
> [...]
Here is the summary with links:
- [net-next,1/2] appletalk: stop storing per-interface state in struct net_device
https://git.kernel.org/netdev/net-next/c/023f9b0f2f4f
- [net-next,2/2] appletalk: move the protocol out of tree
https://git.kernel.org/netdev/net-next/c/8a398a0c189e
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 v2] net: skmsg: preserve sg.copy across SG transforms
From: patchwork-bot+netdevbpf @ 2026-06-16 22:00 UTC (permalink / raw)
To: Yiming Qian
Cc: security, john.fastabend, jakub, kuba, sd, davem, edumazet,
pabeni, horms, keenanat2000, netdev, bpf, linux-kernel, stable
In-Reply-To: <20260610062137.49075-1-yimingqian591@gmail.com>
Hello:
This patch was applied to netdev/net.git (main)
by Jakub Kicinski <kuba@kernel.org>:
On Wed, 10 Jun 2026 06:21:36 +0000 you wrote:
> The sk_msg sg.copy bitmap is part of the scatterlist entry ownership
> state. A set bit tells sk_msg_compute_data_pointers() not to expose the
> entry through writable BPF ctx->data. This protects entries backed by
> pages that are not private to the sk_msg, such as splice-backed file
> page-cache pages.
>
> Several sk_msg transform paths move, copy, split, or compact
> msg->sg.data[] entries without moving the matching sg.copy bit. This can
> make an externally backed entry arrive at a new slot with a clear copy
> bit. A later SK_MSG verdict can then expose sg_virt(sge) as writable
> ctx->data and BPF stores can modify the original page cache.
>
> [...]
Here is the summary with links:
- [net,v2] net: skmsg: preserve sg.copy across SG transforms
https://git.kernel.org/netdev/net/c/406e8a651a7b
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* Re: [Intel-wired-lan] e1000e: Report link down after "Detected Hardware Unit Hang" ?
From: Andrew Lunn @ 2026-06-16 21:59 UTC (permalink / raw)
To: Ruinskiy, Dima
Cc: Helge Deller, Helge Deller, Tony Nguyen, Przemek Kitszel,
intel-wired-lan, netdev
In-Reply-To: <51828156-e859-44db-9926-c076796d0f75@intel.com>
> This does not seem like the right direction to me.
>
> The "Detected Hardware Unit Hang" print does not indicate that the interface
> is dead, but that the transmitter is stalled.
>
> This can be due to an unusually high load, or a HW fault / race condition
> with another component, etc.
>
> When a hang is detected, the transmitter is stopped with netif_stop_queue()
> and eventually ndo_tx_timeout triggers a full reset to the device, which in
> many cases recovers it from the hang.
Does a full reset cause the link to be negotiated again? If so, there
is no harm in setting the carrier down. If the reset is successful,
the carrier will be restored. However, if the reset does not recover
the system, does the carrier say down?
Andrew
^ permalink raw reply
* Re: [PATCH net-next v2 2/4] udmabuf: emit one sg entry per pinned folio
From: Bobby Eshleman @ 2026-06-16 21:59 UTC (permalink / raw)
To: Kasireddy, Vivek
Cc: Donald Hunter, Jakub Kicinski, David S. Miller, Eric Dumazet,
Paolo Abeni, Simon Horman, Andrew Lunn, Gerd Hoffmann,
Sumit Semwal, Christian König, Shuah Khan, Jason Gunthorpe,
netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
dri-devel@lists.freedesktop.org, linux-media@vger.kernel.org,
linaro-mm-sig@lists.linaro.org, linux-kselftest@vger.kernel.org,
sdf@fomichev.me, razor@blackwall.org, daniel@iogearbox.net,
almasrymina@google.com, matttbe@kernel.org, skhawaja@google.com,
dw@davidwei.uk, Bobby Eshleman
In-Reply-To: <ajG4zaK9zu7qZT1+@devvm29614.prn0.facebook.com>
On Tue, Jun 16, 2026 at 01:57:49PM -0700, Bobby Eshleman wrote:
> On Tue, Jun 16, 2026 at 06:04:03AM +0000, Kasireddy, Vivek wrote:
> > Adding Jason to this discussion.
> >
> > Hi Bobby,
> >
> > > Subject: [PATCH net-next v2 2/4] udmabuf: emit one sg entry per pinned
> > > folio
> > >
> > > From: Bobby Eshleman <bobbyeshleman@meta.com>
> > >
> > > get_sg_table() emitted one PAGE_SIZE sg entry per page even when the
> > > underlying folio was larger.
> > >
> > > Instead, walk folios[] and emit one sg entry per folio. When folios
> > We have recently merged a patch (that will make it into 7.2) from Jason that
> > replaced sg_set_folio() with sg_alloc_table_from_pages() in udmabuf driver:
> > https://gitlab.freedesktop.org/drm/tip/-/commit/5bf888673e0dda5a53220fa0c4956271a46c353c
> >
> > Since you are relying on sg_set_folio(), the core argument against its usage
> > in udmabuf is that it doesn't work well with offsets > PAGE_SIZE, resulting
> > in a malformed scatterlist. Not sure if this can be fixed easily.
> >
> > > represent large pages (as is for MFD_HUGETLB), each sg entry is a large
> > > page. Normal PAGE_SIZE sg tables are unchanged.
> > >
> > > This is helpful for importers like net/core/devmem that expect dmabuf sg
> > IMO, udmabuf needs to detect whether importers can handle segments that
> > are > PAGE_SIZE and set the entries appropriately. Please look into how the
> > GPU drivers and other dmabuf exporters/importers handle this situation, so
> > that we can adopt best practices to address this issue.
> >
> > Thanks,
> > Vivek
>
> Hey Vivek,
>
> It sounds looks like that patch might solve my problem. I'll apply and
> troubleshoot from there.
>
> Thanks!
>
> Best,
> Bobby
Good news for me, that patch solves the problem. Thanks for bringing
that up! I can drop my udmabuf patch when I respin the series.
Best,
Bobby
^ permalink raw reply
* Re: [PATCH] e1000: Remove redundant else after return
From: Andrew Lunn @ 2026-06-16 21:51 UTC (permalink / raw)
To: Lovekesh Solanki
Cc: anthony.l.nguyen, przemyslaw.kitszel, andrew+netdev, davem,
edumazet, kuba, pabeni, netdev
In-Reply-To: <20260616210008.109635-1-lovekeshsolanki00@gmail.com>
On Wed, Jun 17, 2026 at 02:30:08AM +0530, Lovekesh Solanki wrote:
> The else branch is needless because the preceding branch
> unconditionally returns -ENOMEM
>
> Reduce nesting by removing unnecessary else
>
> Signed-off-by: Lovekesh Solanki <lovekeshsolanki00@gmail.com>
> ---
> drivers/net/ethernet/intel/e1000/e1000_main.c | 3 +--
> 1 file changed, 1 insertion(+), 2 deletions(-)
>
> diff --git a/drivers/net/ethernet/intel/e1000/e1000_main.c b/drivers/net/ethernet/intel/e1000/e1000_main.c
> index 9b09eb144b81..3d97e952c916 100644
> --- a/drivers/net/ethernet/intel/e1000/e1000_main.c
> +++ b/drivers/net/ethernet/intel/e1000/e1000_main.c
> @@ -1546,11 +1546,10 @@ static int e1000_setup_tx_resources(struct e1000_adapter *adapter,
> "for the transmit descriptor ring\n");
> vfree(txdr->buffer_info);
> return -ENOMEM;
> - } else {
> + }
> /* Free old allocation, new allocation was successful */
> dma_free_coherent(&pdev->dev, txdr->size, olddesc,
> olddma);
> - }
Hi Lovekesh
Please review this patch yourself and tell us what is wrong with it.
Also, please read
https://www.kernel.org/doc/html/latest/process/maintainer-netdev.html
Andrew
---
pw-bot: cr
^ permalink raw reply
* Re: [syzbot] [net?] WARNING in tls_err_abort
From: Sabrina Dubroca @ 2026-06-16 21:46 UTC (permalink / raw)
To: Jakub Kicinski
Cc: syzbot, davem, edumazet, horms, john.fastabend, linux-kernel,
netdev, pabeni, syzkaller-bugs
In-Reply-To: <20260616142359.43300727@kernel.org>
2026-06-16, 14:23:59 -0700, Jakub Kicinski wrote:
> On Tue, 16 Jun 2026 23:00:54 +0200 Sabrina Dubroca wrote:
> > 2026-06-16, 08:28:16 -0700, Jakub Kicinski wrote:
> > > On Tue, 16 Jun 2026 17:19:22 +0200 Sabrina Dubroca wrote:
> > > > I suspect err==0, and sock_error() consumed sk_err in between (the
> > > > alternative would be err > 0).
> > > >
> > > > Something like this?
> > >
> > > Makes sense, but what's eating sk_err?
> >
> > The 2 remaining sock_error() in tls_rx_rec_wait()? [1]
>
> How did that elude my grep..
:)
> > > Don't we depend on it being set
> > > to avoid further state transitions once we hit a crypto error?
> >
> > I kind of thought so too.
>
> In which case the question is whether we should try to remove
> the sock_error() instead? (stating the obvious I guess)
That would make sense, but we can't prevent sock_error() being called
from some helper.
The only relevant one for ktls at the moment seems to be
sk_stream_error(), and I think via sk_stream_wait_memory() we can hit
that EPIPE.
tls_sw_sendmsg_locked has
...
end:
ret = sk_stream_error(sk, msg->msg_flags, ret);
return copied > 0 ? copied : ret;
int sk_stream_error(struct sock *sk, int flags, int err)
{
if (err == -EPIPE)
err = sock_error(sk) ? : -EPIPE;
...
--
Sabrina
^ permalink raw reply
* Re: [PATCH net] net: serialize netif_running() check in enqueue_to_backlog()
From: Kuniyuki Iwashima @ 2026-06-16 21:39 UTC (permalink / raw)
To: Eric Dumazet
Cc: David S . Miller, Jakub Kicinski, Paolo Abeni, Simon Horman,
netdev, eric.dumazet, syzbot+965506b59a2de0b6905c,
Julian Anastasov
In-Reply-To: <20260616141317.407791-1-edumazet@google.com>
On Tue, Jun 16, 2026 at 7:13 AM Eric Dumazet <edumazet@google.com> wrote:
>
> Syzbot reported a KASAN slab-use-after-free in fib_rules_lookup().
>
> The root cause is a race condition where packets can escape the backlog
> flushing during device unregistration (e.g., during netns exit).
>
> Commit e9e4dd3267d0 ("net: do not process device backlog during unregistration")
> introduced a lockless netif_running() check in enqueue_to_backlog() to
> prevent queuing packets to an unregistering device.
>
> However, this creates a TOCTOU race window.
>
> A lockless transmitter (like veth_xmit) can pass
> the check before dev_close() clears IFF_UP. If the transmitter is then
> delayed, flush_all_backlogs() can run and finish before the transmitter
> grabs the backlog lock and queues the packet. The packet then escapes
> the flush and triggers UAF later when processed.
>
> Fix this by moving the netif_running() check inside the backlog lock.
> This serializes the check with the flush work (which also grabs the lock).
> We then either queue the packet before the flush runs (so it gets flushed),
> or check netif_running() after the flush/close completes (so it gets dropped).
>
> Fixes: e9e4dd3267d0 ("net: do not process device backlog during unregistration")
> Reported-by: syzbot+965506b59a2de0b6905c@syzkaller.appspotmail.com
> Closes: https://lore.kernel.org/netdev/6a315824.b0403584.28d0ff.0000.GAE@google.com/T/#u
> Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
Thanks for catching this !
^ permalink raw reply
* Re: [PATCH net-next v2] net: dsa: Fix skb ownership in taggers
From: Vladimir Oltean @ 2026-06-16 21:37 UTC (permalink / raw)
To: Linus Walleij
Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, Florian Fainelli, Jonas Gorski,
Hauke Mehrtens, Kurt Kanzenbach, Woojung Huh, UNGLinuxDriver,
Chester A. Unal, Daniel Golle, Matthias Brugger,
AngeloGioacchino Del Regno, Wei Fang, Clark Wang,
Clément Léger, George McCollister, David Yang, netdev,
Sashiko AI Review
In-Reply-To: <20260616-dsa-fix-free-skb-v2-1-9dbda6a19e97@kernel.org>
On Tue, Jun 16, 2026 at 11:36:22AM +0200, Linus Walleij wrote:
> The tag_8021q.c tagger calls vlan_insert_tag() in dsa_8021q_xmit().
> vlan_insert_tag() will consume the skb with kfree_skb() on failure
> and return NULL.
>
> When NULL is returned as error code to ->xmit() in dsa_user_xmit()
> it will free the same skb again leading to a double-free.
>
> The idea of dsa_user_xmit() and dsa_switch_rcv() dropping the skb
> they held before the call to ->xmit() and ->rcv() is conceptually
> wrong: the pattern elsewhere in the networking code is that consumers
> drop their skb:s on failure.
>
> Modify the ->xmit() and ->rcv() call sites to not drop the SKB if
> the taggers return NULL from any of these calls. Move those drops into
> the taggers so every callback error path that retains ownership consumes
> the skb before returning NULL.
>
> Keep the existing helper ownership rules: VLAN insertion helpers already
> free on failure (this is the case in tag_8021q.c), while deferred
> transmit paths either transfer the skb reference to worker context or
> hold a worker reference with skb_get() and drop the caller's reference.
>
> For SJA1105 meta RX, transfer the buffered stampable skb under the meta
> lock and return NULL while the skb is waiting for its meta frame: the
> skb is not dropped in this case.
>
> Reported-by: Sashiko AI Review <sashiko-bot@kernel.org>
> Closes: https://lore.kernel.org/r/20260610153952.1685895-1-kuba@kernel.org/
> Suggested-by: Jakub Kicinski <kuba@kernel.org>
> Assisted-by: Codex:gpt-5-5
> Acked-by: David Yang <mmyangfl@gmail.com> # yt921x
> Acked-by: Kurt Kanzenbach <kurt@linutronix.de> # hellcreek
> Signed-off-by: Linus Walleij <linusw@kernel.org>
> ---
> Changes in v2:
> - In some instances __skb_pad() and __skb_put_padto() followed by a
> kfree_skb() could be simplified to just call skb_pad() and
> skb_put_padto() which will free the skb on failure.
> - Use a label and goto for the kfree_skb(); return NULL; in
> the netc_rcv() callback in tag_netc.c as requested.
> - Collect ACKs.
> - Retag for net-next.
> - Link to v1: https://patch.msgid.link/20260616-dsa-fix-free-skb-v1-1-fd30b35dcf66@kernel.org
> ---
From my perspective, the tradeoff between pros and cons is not so well
explained. Consider the following not mentioned in the commit message:
- Changing the kfree_skb() convention, without any mechanical obstacle
preventing the backporting of patches that are written assuming one
convention down to trees expecting the other (obstacle like a failure
to compile, for example, which would warn people of their otherwise
silent incompatibility), is an avoidable experience (at best) from a
maintainance perspective.
- Has anyone proven that a real problem exists? Because dsa_user_xmit()
-> skb_ensure_writable_head_tail() has run successfully at this stage,
so we know that dev->needed_headroom bytes are available for writing.
Because DSA uses VLAN as a tag, dsa_user_setup_tagger() will increase
dev->needed_headroom by VLAN_HLEN for the tag_8021q protocols, so
vlan_insert_tag() should not fail. I've looked at this function at it
seems not to be coded up to fail for any other reason.
Otherwise, sure, it seems cleaner this way, but the way I see it, it
risks introducing more issues than it fixes. If maintainers feel
different about this please go ahead, but given the fact that I don't
really have a lot of time to do proper review during this period, I'm
more on the pragmatic side on this one.
^ permalink raw reply
* Re: [syzbot] [net?] WARNING in tls_err_abort
From: Jakub Kicinski @ 2026-06-16 21:23 UTC (permalink / raw)
To: Sabrina Dubroca
Cc: syzbot, davem, edumazet, horms, john.fastabend, linux-kernel,
netdev, pabeni, syzkaller-bugs
In-Reply-To: <ajG5hg9oJvyxPplG@krikkit>
On Tue, 16 Jun 2026 23:00:54 +0200 Sabrina Dubroca wrote:
> 2026-06-16, 08:28:16 -0700, Jakub Kicinski wrote:
> > On Tue, 16 Jun 2026 17:19:22 +0200 Sabrina Dubroca wrote:
> > > I suspect err==0, and sock_error() consumed sk_err in between (the
> > > alternative would be err > 0).
> > >
> > > Something like this?
> >
> > Makes sense, but what's eating sk_err?
>
> The 2 remaining sock_error() in tls_rx_rec_wait()? [1]
How did that elude my grep..
> > Don't we depend on it being set
> > to avoid further state transitions once we hit a crypto error?
>
> I kind of thought so too.
In which case the question is whether we should try to remove
the sock_error() instead? (stating the obvious I guess)
> > I thought that's why we don't consume sk_err in recvmsg and sendmsg in
> > the first place (we are not calling sock_error() anywhere)
>
> Umm...
> [1] https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git/tree/net/tls/tls_sw.c#n1095
>
^ permalink raw reply
* Re: [PATCH] net: faraday: ftmac100: convert to devm resource management
From: Jakub Kicinski @ 2026-06-16 21:21 UTC (permalink / raw)
To: Jack Lee; +Cc: davem, andrew+netdev, edumazet, pabeni, netdev, linux-kernel
In-Reply-To: <20260616203233.55234-1-skunkolee@gmail.com>
On Tue, 16 Jun 2026 13:32:33 -0700 Jack Lee wrote:
> Replace manual resource management with device-managed alternatives:
> - alloc_etherdev() -> devm_alloc_etherdev()
> - request_mem_region() + ioremap() -> devm_platform_ioremap_resource()
>
> This simplifies error handling by removing manual cleanup in error
> paths and the remove function, and eliminates the risk of resource
> leaks.
net-next is closed right now. Also:
Quoting documentation:
Clean-up patches
~~~~~~~~~~~~~~~~
Netdev discourages patches which perform simple clean-ups, which are not in
the context of other work. For example:
* Addressing ``checkpatch.pl``, and other trivial coding style warnings
* Addressing :ref:`Local variable ordering<rcs>` issues
* Conversions to device-managed APIs (``devm_`` helpers)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This is because it is felt that the churn that such changes produce comes
at a greater cost than the value of such clean-ups.
Conversely, spelling and grammar fixes are not discouraged.
See: https://www.kernel.org/doc/html/next/process/maintainer-netdev.html#clean-up-patches
--
pw-bot: reject
^ permalink raw reply
* Re: [PATCH net] netpoll: run NAPI poll in softirq context to avoid rq->lock self-deadlock
From: Jakub Kicinski @ 2026-06-16 21:17 UTC (permalink / raw)
To: Peter Zijlstra
Cc: Sebastian Andrzej Siewior, Petr Mladek, John Ogness,
Sergey Senozhatsky, Vlad Poenaru, Thomas Gleixner, netdev,
David S . Miller, Eric Dumazet, Paolo Abeni, Simon Horman,
Breno Leitao, Clark Williams, Steven Rostedt, linux-rt-devel,
linux-kernel, stable, Frederic Weisbecker, Ingo Molnar,
Vincent Guittot, Dietmar Eggemann, K Prateek Nayak
In-Reply-To: <20260616170257.GH49951@noisy.programming.kicks-ass.net>
On Tue, 16 Jun 2026 19:02:57 +0200 Peter Zijlstra wrote:
> > So this is not an issue since commit 7eab73b18630e ("netconsole: convert
> > to NBCON console infrastructure"). Because from here now on writes are
> > deferred to the nbcon thread. So this purely about -stable in this case.
>
> Hmm, I thought netconsole had some reserved skbs and could to writes
> 'atomic' like? That said, it was 2.6 era the last time I looked at
> netconsole.
Yes, that part is fine. The problem is that netconsole tries
to reap Tx completions if the Tx queue is full. We can't call
skb destructor in irq context so we put the completed skbs on
a queue and try to arm softirq to get to them later.
Arming softirq causes a ksoftirq wake up.
We already skip the completion polling if we detect getting called
from the same networking driver. It's best effort, anyway.
Networking-side fix would be to toss another OR condition into
the skip. But we don't have one that'd work cleanly :S
^ permalink raw reply
* Re: [PATCH net-next V3 2/7] netdevsim: Register devlink after device init
From: Jakub Kicinski @ 2026-06-16 21:05 UTC (permalink / raw)
To: Mark Bloch
Cc: Jiri Pirko, Eric Dumazet, Paolo Abeni, Andrew Lunn,
David S. Miller, Jonathan Corbet, Shuah Khan, Simon Horman,
Sunil Goutham, Linu Cherian, Geetha sowjanya, hariprasad,
Subbaraya Sundeep, Bharat Bhushan, Saeed Mahameed,
Leon Romanovsky, Tariq Toukan, Ethan Nelson-Moore, linux-doc,
netdev, linux-rdma
In-Reply-To: <7635d50c-1c82-4090-8907-53a72444fc04@nvidia.com>
On Tue, 16 Jun 2026 20:29:25 +0300 Mark Bloch wrote:
> I think the explicit helper is the cleanest option here, without any
> workqueue fallback inside devlink. It avoids depending on devl_register()
> ordering, and makes the support explicit per driver.
>
> Does that sound like an acceptable direction?
I'd much rather have the workqueue with the purely theoretical race
with user space than a bunch of drivers that don't act on the cmdline
params.
^ permalink raw reply
* [PATCH] e1000: Remove redundant else after return
From: Lovekesh Solanki @ 2026-06-16 21:00 UTC (permalink / raw)
To: anthony.l.nguyen
Cc: przemyslaw.kitszel, andrew+netdev, davem, edumazet, kuba, pabeni,
netdev, Lovekesh Solanki
The else branch is needless because the preceding branch
unconditionally returns -ENOMEM
Reduce nesting by removing unnecessary else
Signed-off-by: Lovekesh Solanki <lovekeshsolanki00@gmail.com>
---
drivers/net/ethernet/intel/e1000/e1000_main.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/intel/e1000/e1000_main.c b/drivers/net/ethernet/intel/e1000/e1000_main.c
index 9b09eb144b81..3d97e952c916 100644
--- a/drivers/net/ethernet/intel/e1000/e1000_main.c
+++ b/drivers/net/ethernet/intel/e1000/e1000_main.c
@@ -1546,11 +1546,10 @@ static int e1000_setup_tx_resources(struct e1000_adapter *adapter,
"for the transmit descriptor ring\n");
vfree(txdr->buffer_info);
return -ENOMEM;
- } else {
+ }
/* Free old allocation, new allocation was successful */
dma_free_coherent(&pdev->dev, txdr->size, olddesc,
olddma);
- }
}
memset(txdr->desc, 0, txdr->size);
--
2.54.0
^ permalink raw reply related
* Re: [syzbot] [net?] WARNING in tls_err_abort
From: Sabrina Dubroca @ 2026-06-16 21:00 UTC (permalink / raw)
To: Jakub Kicinski
Cc: syzbot, davem, edumazet, horms, john.fastabend, linux-kernel,
netdev, pabeni, syzkaller-bugs
In-Reply-To: <20260616082816.4dd0f035@kernel.org>
2026-06-16, 08:28:16 -0700, Jakub Kicinski wrote:
> On Tue, 16 Jun 2026 17:19:22 +0200 Sabrina Dubroca wrote:
> > I suspect err==0, and sock_error() consumed sk_err in between (the
> > alternative would be err > 0).
> >
> > Something like this?
>
> Makes sense, but what's eating sk_err?
The 2 remaining sock_error() in tls_rx_rec_wait()? [1]
> Don't we depend on it being set
> to avoid further state transitions once we hit a crypto error?
I kind of thought so too.
> I thought that's why we don't consume sk_err in recvmsg and sendmsg in
> the first place (we are not calling sock_error() anywhere)
Umm...
[1] https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git/tree/net/tls/tls_sw.c#n1095
--
Sabrina
^ 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