* Re: [PATCH bpf v2 2/2] selftests/bpf: Add tests for sock_ops ctx access with same src/dst register
From: sun jian @ 2026-04-06 16:47 UTC (permalink / raw)
To: Jiayuan Chen
Cc: bpf, Martin KaFai Lau, Daniel Borkmann, John Fastabend,
Stanislav Fomichev, Alexei Starovoitov, Andrii Nakryiko,
Eduard Zingerman, Kumar Kartikeya Dwivedi, Song Liu,
Yonghong Song, Jiri Olsa, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Shuah Khan,
linux-kernel, netdev, linux-kselftest
In-Reply-To: <20260406031330.187630-2-jiayuan.chen@linux.dev>
On Mon, Apr 6, 2026 at 11:15 AM Jiayuan Chen <jiayuan.chen@linux.dev> wrote:
>
> Add selftests to verify SOCK_OPS_GET_SK() and SOCK_OPS_GET_FIELD()
> correctly return NULL/zero when dst_reg == src_reg and is_fullsock == 0.
>
> Three subtests are included:
> - get_sk: ctx->sk with same src/dst register (SOCK_OPS_GET_SK)
> - get_field: ctx->snd_cwnd with same src/dst register (SOCK_OPS_GET_FIELD)
> - get_sk_diff_reg: ctx->sk with different src/dst register (baseline)
>
> Each BPF program uses inline asm (__naked) to force specific register
> allocation, reads is_fullsock first, then loads the field using the same
> (or different) register. The test triggers TCP_NEW_SYN_RECV via a TCP
> handshake and checks that the result is NULL/zero when is_fullsock == 0.
>
> Test:
> ./test_progs -a sock_ops_get_sk -v
> test_sock_ops_get_sk:PASS:join_cgroup 0 nsec
> test_sock_ops_get_sk:PASS:skel_open_load 0 nsec
> run_sock_ops_test:PASS:prog_attach 0 nsec
> run_sock_ops_test:PASS:start_server 0 nsec
> run_sock_ops_test:PASS:connect_to_fd 0 nsec
> test_sock_ops_get_sk:PASS:null_seen 0 nsec
> test_sock_ops_get_sk:PASS:bug_not_detected 0 nsec
> #419/1 sock_ops_get_sk/get_sk:OK
> run_sock_ops_test:PASS:prog_attach 0 nsec
> run_sock_ops_test:PASS:start_server 0 nsec
> run_sock_ops_test:PASS:connect_to_fd 0 nsec
> test_sock_ops_get_sk:PASS:field_null_seen 0 nsec
> test_sock_ops_get_sk:PASS:field_bug_not_detected 0 nsec
> #419/2 sock_ops_get_sk/get_field:OK
> run_sock_ops_test:PASS:prog_attach 0 nsec
> run_sock_ops_test:PASS:start_server 0 nsec
> run_sock_ops_test:PASS:connect_to_fd 0 nsec
> test_sock_ops_get_sk:PASS:diff_reg_null_seen 0 nsec
> test_sock_ops_get_sk:PASS:diff_reg_bug_not_detected 0 nsec
> #419/3 sock_ops_get_sk/get_sk_diff_reg:OK
> #419 sock_ops_get_sk:OK
> Summary: 1/3 PASSED, 0 SKIPPED, 0 FAILED
>
> Signed-off-by: Jiayuan Chen <jiayuan.chen@linux.dev>
> ---
> .../bpf/prog_tests/sock_ops_get_sk.c | 77 ++++++++++++
> .../selftests/bpf/progs/sock_ops_get_sk.c | 117 ++++++++++++++++++
> 2 files changed, 194 insertions(+)
> create mode 100644 tools/testing/selftests/bpf/prog_tests/sock_ops_get_sk.c
> create mode 100644 tools/testing/selftests/bpf/progs/sock_ops_get_sk.c
>
> diff --git a/tools/testing/selftests/bpf/prog_tests/sock_ops_get_sk.c b/tools/testing/selftests/bpf/prog_tests/sock_ops_get_sk.c
> new file mode 100644
> index 0000000000000..e086f7abb197e
> --- /dev/null
> +++ b/tools/testing/selftests/bpf/prog_tests/sock_ops_get_sk.c
> @@ -0,0 +1,77 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +#include <test_progs.h>
> +#include "cgroup_helpers.h"
> +#include "network_helpers.h"
> +#include "sock_ops_get_sk.skel.h"
> +
> +/* See progs/sock_ops_get_sk.c for the bug description. */
> +static void run_sock_ops_test(struct sock_ops_get_sk *skel, int cgroup_fd,
> + int prog_fd)
> +{
> + int server_fd, client_fd, err;
> +
> + err = bpf_prog_attach(prog_fd, cgroup_fd, BPF_CGROUP_SOCK_OPS, 0);
> + if (!ASSERT_OK(err, "prog_attach"))
> + return;
> +
> + server_fd = start_server(AF_INET, SOCK_STREAM, NULL, 0, 0);
> + if (!ASSERT_GE(server_fd, 0, "start_server"))
> + goto detach;
> +
> + /* Trigger TCP handshake which causes TCP_NEW_SYN_RECV state where
> + * is_fullsock == 0 and is_locked_tcp_sock == 0.
> + */
> + client_fd = connect_to_fd(server_fd, 0);
> + if (!ASSERT_GE(client_fd, 0, "connect_to_fd"))
> + goto close_server;
> +
> + close(client_fd);
> +
> +close_server:
> + close(server_fd);
> +detach:
> + bpf_prog_detach(cgroup_fd, BPF_CGROUP_SOCK_OPS);
> +}
> +
> +void test_sock_ops_get_sk(void)
> +{
> + struct sock_ops_get_sk *skel;
> + int cgroup_fd;
> +
> + cgroup_fd = test__join_cgroup("/sock_ops_get_sk");
> + if (!ASSERT_GE(cgroup_fd, 0, "join_cgroup"))
> + return;
> +
> + skel = sock_ops_get_sk__open_and_load();
> + if (!ASSERT_OK_PTR(skel, "skel_open_load"))
> + goto close_cgroup;
> +
> + /* Test SOCK_OPS_GET_SK with same src/dst register */
> + if (test__start_subtest("get_sk")) {
> + run_sock_ops_test(skel, cgroup_fd,
> + bpf_program__fd(skel->progs.sock_ops_get_sk_same_reg));
> + ASSERT_EQ(skel->bss->null_seen, 1, "null_seen");
> + ASSERT_EQ(skel->bss->bug_detected, 0, "bug_not_detected");
> + }
> +
> + /* Test SOCK_OPS_GET_FIELD with same src/dst register */
> + if (test__start_subtest("get_field")) {
> + run_sock_ops_test(skel, cgroup_fd,
> + bpf_program__fd(skel->progs.sock_ops_get_field_same_reg));
> + ASSERT_EQ(skel->bss->field_null_seen, 1, "field_null_seen");
> + ASSERT_EQ(skel->bss->field_bug_detected, 0, "field_bug_not_detected");
> + }
> +
> + /* Test SOCK_OPS_GET_SK with different src/dst register */
> + if (test__start_subtest("get_sk_diff_reg")) {
> + run_sock_ops_test(skel, cgroup_fd,
> + bpf_program__fd(skel->progs.sock_ops_get_sk_diff_reg));
> + ASSERT_EQ(skel->bss->diff_reg_null_seen, 1, "diff_reg_null_seen");
> + ASSERT_EQ(skel->bss->diff_reg_bug_detected, 0, "diff_reg_bug_not_detected");
> + }
> +
> + sock_ops_get_sk__destroy(skel);
> +close_cgroup:
> + close(cgroup_fd);
> +}
> diff --git a/tools/testing/selftests/bpf/progs/sock_ops_get_sk.c b/tools/testing/selftests/bpf/progs/sock_ops_get_sk.c
> new file mode 100644
> index 0000000000000..3a0689f8ce7ca
> --- /dev/null
> +++ b/tools/testing/selftests/bpf/progs/sock_ops_get_sk.c
> @@ -0,0 +1,117 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +#include "vmlinux.h"
> +#include <bpf/bpf_helpers.h>
> +#include "bpf_misc.h"
> +
> +/*
> + * Test the SOCK_OPS_GET_SK() and SOCK_OPS_GET_FIELD() macros in
> + * sock_ops_convert_ctx_access() when dst_reg == src_reg.
> + *
> + * When dst_reg == src_reg, the macros borrow a temporary register to load
> + * is_fullsock / is_locked_tcp_sock, because dst_reg holds the ctx pointer
> + * and cannot be clobbered before ctx->sk / ctx->field is read. If
> + * is_fullsock == 0 (e.g., TCP_NEW_SYN_RECV with a request_sock), the macro
> + * must still zero dst_reg so the verifier's PTR_TO_SOCKET_OR_NULL /
> + * SCALAR_VALUE type is correct at runtime. A missing clear leaves a stale
> + * ctx pointer in dst_reg that passes NULL checks (GET_SK) or leaks a kernel
> + * address as a scalar (GET_FIELD).
> + *
> + * When dst_reg != src_reg, dst_reg itself is used to load is_fullsock, so
> + * the JEQ (dst_reg == 0) naturally leaves it zeroed on the !fullsock path.
> + */
> +
> +int bug_detected;
> +int null_seen;
> +
> +SEC("sockops")
> +__naked void sock_ops_get_sk_same_reg(void)
> +{
> + asm volatile (
> + "r7 = *(u32 *)(r1 + %[is_fullsock_off]);"
> + "r1 = *(u64 *)(r1 + %[sk_off]);"
> + "if r7 != 0 goto 2f;"
> + "if r1 == 0 goto 1f;"
> + "r1 = %[bug_detected] ll;"
> + "r2 = 1;"
> + "*(u32 *)(r1 + 0) = r2;"
> + "goto 2f;"
> + "1:"
> + "r1 = %[null_seen] ll;"
> + "r2 = 1;"
> + "*(u32 *)(r1 + 0) = r2;"
> + "2:"
> + "r0 = 1;"
> + "exit;"
> + :
> + : __imm_const(is_fullsock_off, offsetof(struct bpf_sock_ops, is_fullsock)),
> + __imm_const(sk_off, offsetof(struct bpf_sock_ops, sk)),
> + __imm_addr(bug_detected),
> + __imm_addr(null_seen)
> + : __clobber_all);
> +}
> +
> +/* SOCK_OPS_GET_FIELD: same-register, is_locked_tcp_sock == 0 path. */
> +int field_bug_detected;
> +int field_null_seen;
> +
> +SEC("sockops")
> +__naked void sock_ops_get_field_same_reg(void)
> +{
> + asm volatile (
> + "r7 = *(u32 *)(r1 + %[is_fullsock_off]);"
> + "r1 = *(u32 *)(r1 + %[snd_cwnd_off]);"
> + "if r7 != 0 goto 2f;"
> + "if r1 == 0 goto 1f;"
> + "r1 = %[field_bug_detected] ll;"
> + "r2 = 1;"
> + "*(u32 *)(r1 + 0) = r2;"
> + "goto 2f;"
> + "1:"
> + "r1 = %[field_null_seen] ll;"
> + "r2 = 1;"
> + "*(u32 *)(r1 + 0) = r2;"
> + "2:"
> + "r0 = 1;"
> + "exit;"
> + :
> + : __imm_const(is_fullsock_off, offsetof(struct bpf_sock_ops, is_fullsock)),
> + __imm_const(snd_cwnd_off, offsetof(struct bpf_sock_ops, snd_cwnd)),
> + __imm_addr(field_bug_detected),
> + __imm_addr(field_null_seen)
> + : __clobber_all);
> +}
> +
> +/* SOCK_OPS_GET_SK: different-register, is_fullsock == 0 path. */
> +int diff_reg_bug_detected;
> +int diff_reg_null_seen;
> +
> +SEC("sockops")
> +__naked void sock_ops_get_sk_diff_reg(void)
> +{
> + asm volatile (
> + "r7 = r1;"
> + "r6 = *(u32 *)(r7 + %[is_fullsock_off]);"
> + "r2 = *(u64 *)(r7 + %[sk_off]);"
> + "if r6 != 0 goto 2f;"
> + "if r2 == 0 goto 1f;"
> + "r1 = %[diff_reg_bug_detected] ll;"
> + "r3 = 1;"
> + "*(u32 *)(r1 + 0) = r3;"
> + "goto 2f;"
> + "1:"
> + "r1 = %[diff_reg_null_seen] ll;"
> + "r3 = 1;"
> + "*(u32 *)(r1 + 0) = r3;"
> + "2:"
> + "r0 = 1;"
> + "exit;"
> + :
> + : __imm_const(is_fullsock_off, offsetof(struct bpf_sock_ops, is_fullsock)),
> + __imm_const(sk_off, offsetof(struct bpf_sock_ops, sk)),
> + __imm_addr(diff_reg_bug_detected),
> + __imm_addr(diff_reg_null_seen)
> + : __clobber_all);
> +}
> +
> +char _license[] SEC("license") = "GPL";
> --
> 2.43.0
>
>
Reviewed-by: Sun Jian <sun.jian.kdev@gmail.com>
^ permalink raw reply
* Re: [PATCH net-next 2/3] net: phy: broadcom: implement .disable_autonomous_eee for BCM54xx
From: Florian Fainelli @ 2026-04-06 16:54 UTC (permalink / raw)
To: Nicolai Buchwitz, Andrew Lunn, Heiner Kallweit, Russell King,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Florian Fainelli, Broadcom internal kernel review list
Cc: netdev, linux-kernel
In-Reply-To: <20260406-devel-autonomous-eee-v1-2-b335e7143711@tipi-net.de>
On 4/6/26 00:13, Nicolai Buchwitz wrote:
> Implement the .disable_autonomous_eee callback for the BCM54210E.
>
> In AutogrEEEn mode the PHY manages EEE autonomously. Clearing the
> AutogrEEEn enable bit in MII_BUF_CNTL_0 switches the PHY to Native
> EEE mode.
>
> Signed-off-by: Nicolai Buchwitz <nb@tipi-net.de>
Reviewed-by: Florian Fainelli <florian.fainelli@broadcom.com>
--
Florian
^ permalink raw reply
* Re: [PATCH net-next v2] selftests/net: convert so_txtime to drv-net
From: Willem de Bruijn @ 2026-04-06 16:55 UTC (permalink / raw)
To: Jakub Kicinski, Willem de Bruijn
Cc: netdev, davem, edumazet, pabeni, horms, Willem de Bruijn
In-Reply-To: <20260406090231.63df3fac@kernel.org>
Jakub Kicinski wrote:
> On Sat, 04 Apr 2026 22:20:15 -0400 Willem de Bruijn wrote:
> > > +YNL_GEN_FILES := \
> > > + psp_responder \
> > > + so_txtime
> >
> > This should just go under TEST_GEN_FILES (sashiko)
> >
> > I don't quite understand the check_selftest check_new_files_makefile
> > failure.
>
> Glancing at the code you were missing the
>
> # end of YNL_GEN_FILES
>
> trailer.
>
> Those checkers are equally annoying and easy to run locally, they
> take a path to the modified file and say "good" / "bad".
Thanks. Indeed, I only learned about this yesterday. Ran it before v3.
Was super easy. Sharing for anyone else new to this:
git format-patch -1
mkdir /tmp/patches
mv 000* /tmp/patches
cd /tmp
git clone https://github.com/linux-netdev/nipa.git
cd nipa
./ingest_mdir.py --mdir /tmp/patches --tree ~/src/kernel/netdev/nn -t patch/check_selftest
--- output
Saving output and logs to: /tmp/tmp7zb9n8ka
Tree name unknown
[1] selftests/net: convert so_txtime to drv-net
Series level tests:
Patch level tests:
check_selftest OKAY Good format (5); New files in Makefile checked (1)
^ permalink raw reply
* Re: [net-next v2 3/3] selftests/net: Test PACKET_AUXDATA
From: Joe Damato @ 2026-04-06 17:01 UTC (permalink / raw)
To: Willem de Bruijn
Cc: netdev, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, Shuah Khan, dalias, andrew+netdev,
linux-kernel, willemb, linux-kselftest
In-Reply-To: <willemdebruijn.kernel.14a8e29bbdc9a@gmail.com>
On Sat, Apr 04, 2026 at 11:30:09PM -0400, Willem de Bruijn wrote:
> Willem de Bruijn wrote:
> > Joe Damato wrote:
[...]
> > > -static void do_rx(int fd, int expected_len, char *expected)
> > > +static void check_aux_data(struct cmsghdr *cmsg, int expected_len)
> > > {
> > > + struct tpacket_auxdata *adata;
> > > +
> > > + if (!cmsg)
> > > + error(1, 0, "auxdata null");
> > > +
> > > + if (cmsg->cmsg_level != SOL_PACKET)
> > > + error(1, 0, "cmsg_level != SOL_PACKET");
> > > +
> > > + if (cmsg->cmsg_type != PACKET_AUXDATA)
> > > + error(1, 0, "cmsg_type != PACKET_AUXDATA");
> > > +
> > > + adata = (struct tpacket_auxdata *)CMSG_DATA(cmsg);
> >
> > Sashiko had another interesting observation that this access may be
> > unaligned, as cmsg_buf[1024] has 1-byte alignment.
> >
> > That is not new in this patch. Indeed most tests in this dir just
> > deference msg_control as struct cmsghdr * and CMSG_DATA as whatever
> > domain specific type.
> >
> > The man page also warns about this and suggests using memcpy to
> > access CMSG_DATA. Not sure why it does not warn about the other
> > cmsg_.. fields.
>
> The commit that introduced that has more context
>
> https://git.kernel.org/pub/scm/docs/man-pages/man-pages.git/commit/man/man3/cmsg.3?id=36d25246b4333513fefdbec7f78f29d193cf5d9a
>
> It points out 32-bit platforms where cmsghdr is 12 bytes.
>
> At least one example given, ptpd, uses a union to ensure alignment
>
> union {
> struct cmsghdr cm;
> char control[256];
> } cmsg_un;
>
> But at least one other example, ssmping, does not. So I think not even
> the 4B (on 32-bit archs) of cmsghdr fields can be depended on.
I'm fine with adding an "__attribute__((aligned(8)))" to be safe, but FWIW, I
think the key point from the commit message linked above is:
shows access to int payload via *(int *)CMSG_DATA(cmsg) (of course
int is safe because its alignment is <= header alignment, but this
is not mentioned).
struct tpacket_auxdata only has u32 and u16, so 4 byte alignment seems fine
and I don't think the issue applies in this particular case. But, as I said
above, I am fine with adding the attribute to be defensive.
^ permalink raw reply
* [PATCH net v3] net: rose: defer rose_neigh cleanup to workqueue to fix UAF
From: Mashiro Chen @ 2026-04-06 17:01 UTC (permalink / raw)
To: netdev
Cc: linux-hams, davem, edumazet, kuba, pabeni, horms, linux-kernel,
syzbot+abd2b69348e2d9b107a1, Mashiro Chen
In-Reply-To: <20260405125830.89251-1-mashiro.chen@mailbox.org>
rose_neigh_put() frees the rose_neigh object when the reference count
reaches zero, but does not stop the t0timer and ftimer beforehand.
If a timer has been scheduled and fires after the object is freed,
the callback will access already-freed memory, leading to a
use-after-free.
The UAF can be triggered through the following sequence:
1. rose_add_node() creates a rose_neigh with refcount=2
(initial neigh_list reference plus one held by the new node entry)
2. A socket connects via rose_get_neigh(), rose_neigh_hold() raises
refcount to 3; rose_transmit_link() arms t0timer on the neigh
3. The routing entry is deleted: rose_del_node() drops the node
reference (3->2), calls rose_remove_neigh() which stops both
timers, then drops the neigh_list reference (2->1); the socket
now holds the only reference with t0timer stopped
4. T1 expires in ROSE_STATE_1: rose_timer_expiry() sends
CLEAR_REQUEST via rose_transmit_link(), which sees
neigh->restarted=0 and !rose_t0timer_running, and re-arms
t0timer on the neigh (refcount still 1)
5. T3 expires in ROSE_STATE_2: rose_timer_expiry() calls
rose_neigh_put(), refcount drops to 0, kfree(neigh)
6. t0timer fires, rose_t0timer_expiry() accesses freed neigh -> UAF
Calling timer_delete_sync() directly in rose_neigh_put() would fix
the UAF but is unsafe: rose_neigh_put() can be called while holding
spinlocks (e.g. rose_route_frame() holds rose_neigh_list_lock and
rose_route_list_lock), and timer_delete_sync() may block waiting for
a running callback, which is illegal in atomic context.
Fix this by deferring the final cleanup to a workqueue. When the
refcount drops to zero, schedule rose_neigh_free_work() instead of
freeing inline. The work function runs in process context where it
is safe to call timer_shutdown_sync() before freeing the object.
timer_shutdown_sync() is used instead of timer_delete_sync() to
permanently prevent the self-rearming t0timer from firing again
after the work function starts.
Fixes: d860d1faa6b2 ("net: rose: convert 'use' field to refcount_t")
Reported-by: syzbot+abd2b69348e2d9b107a1@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=abd2b69348e2d9b107a1
Signed-off-by: Mashiro Chen <mashiro.chen@mailbox.org>
---
Changes in v3:
- Replaced timer_delete_sync() in rose_neigh_put() with a workqueue
to avoid calling a blocking function in atomic context
- Added rose_neigh_free_work() to handle cleanup in process context
- Added struct work_struct free_work to struct rose_neigh
- Used timer_shutdown_sync() to prevent the self-rearming t0timer
from firing again after cleanup begins
Changes in v2:
- Stop t0timer and ftimer before freeing the object
include/net/rose.h | 10 ++++------
net/rose/rose_route.c | 16 ++++++++++++++++
2 files changed, 20 insertions(+), 6 deletions(-)
diff --git a/include/net/rose.h b/include/net/rose.h
index 2b5491bbf39ab..704214e38ef1d 100644
--- a/include/net/rose.h
+++ b/include/net/rose.h
@@ -9,6 +9,7 @@
#define _ROSE_H
#include <linux/refcount.h>
+#include <linux/workqueue.h>
#include <linux/rose.h>
#include <net/ax25.h>
#include <net/sock.h>
@@ -105,6 +106,7 @@ struct rose_neigh {
struct sk_buff_head queue;
struct timer_list t0timer;
struct timer_list ftimer;
+ struct work_struct free_work;
};
struct rose_node {
@@ -159,12 +161,8 @@ static inline void rose_neigh_hold(struct rose_neigh *rose_neigh)
static inline void rose_neigh_put(struct rose_neigh *rose_neigh)
{
- if (refcount_dec_and_test(&rose_neigh->use)) {
- if (rose_neigh->ax25)
- ax25_cb_put(rose_neigh->ax25);
- kfree(rose_neigh->digipeat);
- kfree(rose_neigh);
- }
+ if (refcount_dec_and_test(&rose_neigh->use))
+ schedule_work(&rose_neigh->free_work);
}
/* af_rose.c */
diff --git a/net/rose/rose_route.c b/net/rose/rose_route.c
index e31842e6b3c8b..8c8e09793d442 100644
--- a/net/rose/rose_route.c
+++ b/net/rose/rose_route.c
@@ -28,6 +28,7 @@
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/notifier.h>
+#include <linux/workqueue.h>
#include <linux/init.h>
#include <net/rose.h>
#include <linux/seq_file.h>
@@ -44,6 +45,19 @@ static DEFINE_SPINLOCK(rose_route_list_lock);
struct rose_neigh *rose_loopback_neigh;
+static void rose_neigh_free_work(struct work_struct *work)
+{
+ struct rose_neigh *rose_neigh =
+ container_of(work, struct rose_neigh, free_work);
+
+ timer_shutdown_sync(&rose_neigh->t0timer);
+ timer_shutdown_sync(&rose_neigh->ftimer);
+ if (rose_neigh->ax25)
+ ax25_cb_put(rose_neigh->ax25);
+ kfree(rose_neigh->digipeat);
+ kfree(rose_neigh);
+}
+
/*
* Add a new route to a node, and in the process add the node and the
* neighbour if it is new.
@@ -103,6 +117,7 @@ static int __must_check rose_add_node(struct rose_route_struct *rose_route,
timer_setup(&rose_neigh->ftimer, NULL, 0);
timer_setup(&rose_neigh->t0timer, NULL, 0);
+ INIT_WORK(&rose_neigh->free_work, rose_neigh_free_work);
if (rose_route->ndigis != 0) {
rose_neigh->digipeat =
@@ -388,6 +403,7 @@ void rose_add_loopback_neigh(void)
timer_setup(&sn->ftimer, NULL, 0);
timer_setup(&sn->t0timer, NULL, 0);
+ INIT_WORK(&sn->free_work, rose_neigh_free_work);
spin_lock_bh(&rose_neigh_list_lock);
sn->next = rose_neigh_list;
--
2.53.0
^ permalink raw reply related
* Re: [PATCH net-next 0/3] net: phy: add support for disabling autonomous EEE
From: Russell King (Oracle) @ 2026-04-06 17:10 UTC (permalink / raw)
To: Florian Fainelli
Cc: Andrew Lunn, Nicolai Buchwitz, Heiner Kallweit, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Broadcom internal kernel review list, netdev, linux-kernel
In-Reply-To: <cdef227e-9dfe-4860-aca3-5ce1f60cb838@broadcom.com>
On Mon, Apr 06, 2026 at 09:43:55AM -0700, Florian Fainelli wrote:
> That is almost a guarantee given, there will be a broken MAC
Well, it already exists. modern i.MX platforms use stmmac, and some
bright spark wired lpi_intr_o together with the main stmmac interrupt
which causes interrupt storms when the receive path exits LPI. This
makes stmmac LPI unusable on this platform.
So, if i.MX is paired with a PHY that can do its own EEE, then we
have this exact scenaro.
--
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!
^ permalink raw reply
* Re: [PATCH net-next v6 1/7] net: bcmgenet: convert RX path to page_pool
From: Florian Fainelli @ 2026-04-06 17:10 UTC (permalink / raw)
To: Nicolai Buchwitz, netdev
Cc: Justin Chen, Simon Horman, Mohsin Bashir, Doug Berger,
Broadcom internal kernel review list, Andrew Lunn, Eric Dumazet,
Paolo Abeni, David S. Miller, Jakub Kicinski, Vikas Gupta,
Bhargava Marreddy, Rajashekar Hudumula, Arnd Bergmann,
Fernando Fernandez Mancera, Markus Blöchl, linux-kernel
In-Reply-To: <20260406083536.839517-2-nb@tipi-net.de>
On 4/6/26 01:35, Nicolai Buchwitz wrote:
> Replace the per-packet __netdev_alloc_skb() + dma_map_single() in the
> RX path with page_pool, which provides efficient page recycling and
> DMA mapping management. This is a prerequisite for XDP support (which
> requires stable page-backed buffers rather than SKB linear data).
>
> Key changes:
> - Create a page_pool per RX ring (PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV)
> - bcmgenet_rx_refill() allocates pages via page_pool_alloc_pages()
> - bcmgenet_desc_rx() builds SKBs from pages via napi_build_skb() with
> skb_mark_for_recycle() for automatic page_pool return
> - Buffer layout reserves XDP_PACKET_HEADROOM (256 bytes) before the HW
> RSB (64 bytes) + alignment pad (2 bytes) for future XDP headroom
>
> Signed-off-by: Nicolai Buchwitz <nb@tipi-net.de>
Reviewed-by: Florian Fainelli <florian.fainelli@broadcom.com>
Tested-by: Florian Fainelli <florian.fainelli@broadcom.com>
--
Florian
^ permalink raw reply
* Re: [PATCH net v3 4/7] net/sched: netem: restructure dequeue to avoid re-entrancy with child qdisc
From: Stephen Hemminger @ 2026-04-06 17:12 UTC (permalink / raw)
To: Jakub Kicinski
Cc: Simon Horman, netdev, Jamal Hadi Salim, Jiri Pirko,
David S. Miller, Eric Dumazet, Paolo Abeni, open list
In-Reply-To: <20260406084133.47bcfc8f@kernel.org>
On Mon, 6 Apr 2026 08:41:33 -0700
Jakub Kicinski <kuba@kernel.org> wrote:
> On Sat, 4 Apr 2026 10:49:46 +0100 Simon Horman wrote:
> > On Thu, Apr 02, 2026 at 01:19:32PM -0700, Stephen Hemminger wrote:
> > > netem_dequeue() enqueues packets into its child qdisc while being
> > > called from the parent's dequeue path. This causes two problems:
> > >
> > > - HFSC tracks class active/inactive state on qlen transitions.
> > > A child enqueue during dequeue causes double-insertion into
> > > the eltree (CVE-2025-37890, CVE-2025-38001).
> > >
> > > - Non-work-conserving children like TBF may refuse to dequeue
> > > packets just enqueued, causing netem to return NULL despite
> > > having backlog. Parents like DRR then incorrectly deactivate
> > > the class.
> > >
> > > Split the dequeue into helpers:
> > >
> > > netem_pull_tfifo() - remove head packet from tfifo
> > > netem_slot_account() - update slot pacing counters
> > > netem_dequeue_child() - batch-transfer ready packets to the
> > > child, then dequeue from the child
> > > netem_dequeue_direct()- dequeue from tfifo when no child
> > >
> > > When a child qdisc is present, all time-ready packets are moved
> > > into the child before calling its dequeue. This separates the
> > > enqueue and dequeue phases so the parent sees consistent qlen
> > > transitions.
> > >
> > > Fixes: 50612537e9ab ("netem: fix classful handling")
> > > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
> > > ---
> > > net/sched/sch_netem.c | 201 +++++++++++++++++++++++++++---------------
> > > 1 file changed, 128 insertions(+), 73 deletions(-)
> >
> > Hi Stephen,
> >
> > As a fix this is a large and complex patch.
> > Could it be split up somehow to aid review?
>
> +1, FWIW it's perfectly fine to have refactoring patch in a net series
> (without a Fixes tag) if it makes the fix a lot easier to review.
I split it into refactoring followed by fix for next version
The fix alone just gets really confusing to look at;
I got more confused the pre-existing spaghetti code here..
^ permalink raw reply
* Re: [PATCH net-next v6 7/7] net: bcmgenet: reject MTU changes incompatible with XDP
From: Florian Fainelli @ 2026-04-06 17:19 UTC (permalink / raw)
To: Nicolai Buchwitz, netdev
Cc: Justin Chen, Simon Horman, Mohsin Bashir, Doug Berger,
Florian Fainelli, Broadcom internal kernel review list,
Andrew Lunn, Eric Dumazet, Paolo Abeni, David S. Miller,
Jakub Kicinski, Alexei Starovoitov, Daniel Borkmann,
Jesper Dangaard Brouer, John Fastabend, Stanislav Fomichev,
linux-kernel, bpf
In-Reply-To: <20260406083536.839517-8-nb@tipi-net.de>
On 4/6/26 01:35, Nicolai Buchwitz wrote:
> Add a minimal ndo_change_mtu that rejects MTU values too large for
> single-page XDP buffers when an XDP program is attached. Without this,
> users could change the MTU at runtime and break the XDP buffer layout.
>
> When no XDP program is attached, any MTU change is accepted, matching
> the existing behavior without ndo_change_mtu.
>
> Signed-off-by: Nicolai Buchwitz <nb@tipi-net.de>
Reviewed-by: Florian Fainelli <florian.fainelli@broadcom.com>
--
Florian
^ permalink raw reply
* Re: [PATCH net-next v6 6/7] net: bcmgenet: add XDP statistics counters
From: Florian Fainelli @ 2026-04-06 17:20 UTC (permalink / raw)
To: Nicolai Buchwitz, netdev
Cc: Justin Chen, Simon Horman, Mohsin Bashir, Doug Berger,
Broadcom internal kernel review list, Andrew Lunn, Eric Dumazet,
Paolo Abeni, David S. Miller, Jakub Kicinski, Alexei Starovoitov,
Daniel Borkmann, Jesper Dangaard Brouer, John Fastabend,
Stanislav Fomichev, linux-kernel, bpf
In-Reply-To: <20260406083536.839517-7-nb@tipi-net.de>
On 4/6/26 01:35, Nicolai Buchwitz wrote:
> Expose per-action XDP counters via ethtool -S: xdp_pass, xdp_drop,
> xdp_tx, xdp_tx_err, xdp_redirect, and xdp_redirect_err.
>
> These use the existing soft MIB infrastructure and are incremented in
> bcmgenet_run_xdp() alongside the existing driver statistics.
>
> Signed-off-by: Nicolai Buchwitz <nb@tipi-net.de>
Reviewed-by: Florian Fainelli <florian.fainelli@broadcom.com>
--
Florian
^ permalink raw reply
* Re: [PATCH net-next v6 2/7] net: bcmgenet: register xdp_rxq_info for each RX ring
From: Florian Fainelli @ 2026-04-06 17:22 UTC (permalink / raw)
To: Nicolai Buchwitz, netdev
Cc: Justin Chen, Simon Horman, Mohsin Bashir, Doug Berger,
Broadcom internal kernel review list, Andrew Lunn, Eric Dumazet,
Paolo Abeni, David S. Miller, Jakub Kicinski, Alexei Starovoitov,
Daniel Borkmann, Jesper Dangaard Brouer, John Fastabend,
Stanislav Fomichev, linux-kernel, bpf
In-Reply-To: <20260406083536.839517-3-nb@tipi-net.de>
On 4/6/26 01:35, Nicolai Buchwitz wrote:
> Register an xdp_rxq_info per RX ring and associate it with the ring's
> page_pool via MEM_TYPE_PAGE_POOL. This is required infrastructure for
> XDP program execution: the XDP framework needs to know the memory model
> backing each RX queue for correct page lifecycle management.
>
> No functional change - XDP programs are not yet attached or executed.
>
> Signed-off-by: Nicolai Buchwitz <nb@tipi-net.de>
Reviewed-by: Florian Fainelli <florian.fainelli@broadcom.com>
--
Florian
^ permalink raw reply
* [PATCH net v4 0/8] net/sched: netem bug fixes
From: Stephen Hemminger @ 2026-04-06 17:25 UTC (permalink / raw)
To: netdev; +Cc: Stephen Hemminger
These bugs were identified while using AI-assisted code review of
sch_netem.c to analyze the packet duplication re-entrancy problem
(CVE-2025-37890, CVE-2025-38001), which are addressed in a separate
series.
The review uncovered several additional issues:
- probability gaps in the 4-state Markov loss model where
boundary values produce no state transition
- queue limit check not accounting for reordered packets
- PRNG reseeded on every tc change, breaking reproducibility
- the core dequeue re-entrancy issue with child qdiscs
causing HFSC eltree corruption and DRR class stalls
- missing NULL termination on the tfifo linear list tail
- slot delay configuration not validated for inverted ranges
- slot delay arithmetic overflow for ranges above ~2.1 seconds
v4 - split refactoring and fix for dequeue into two patches
Stephen Hemminger (8):
net/sched: netem: fix probability gaps in 4-state loss model
net/sched: netem: fix queue limit check to include reordered packets
net/sched: netem: only reseed PRNG when seed is explicitly provided
net/sched: netem: refactor dequeue into helper functions
net/sched: netem: batch-transfer ready packets to avoid child
re-entrancy
net/sched: netem: null-terminate tfifo linear queue tail
net/sched: netem: check for invalid slot range
net/sched: netem: fix slot delay calculation overflow
net/sched/sch_netem.c | 245 +++++++++++++++++++++++++++---------------
1 file changed, 160 insertions(+), 85 deletions(-)
--
2.53.0
^ permalink raw reply
* [PATCH net v4 1/8] net/sched: netem: fix probability gaps in 4-state loss model
From: Stephen Hemminger @ 2026-04-06 17:25 UTC (permalink / raw)
To: netdev
Cc: Stephen Hemminger, Simon Horman, Jamal Hadi Salim, Jiri Pirko,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
open list
In-Reply-To: <20260406172627.210894-1-stephen@networkplumber.org>
The 4-state Markov chain in loss_4state() has gaps at the boundaries
between transition probability ranges. The comparisons use:
if (rnd < a4)
else if (a4 < rnd && rnd < a1 + a4)
When rnd equals a boundary value exactly, neither branch matches and
no state transition occurs. The redundant lower-bound check (a4 < rnd)
is already implied by being in the else branch.
Remove the unnecessary lower-bound comparisons so the ranges are
contiguous and every random value produces a transition, matching
the GI (General and Intuitive) loss model specification.
This bug goes back to original implementation of this model.
Fixes: 661b79725fea ("netem: revised correlated loss generator")
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
Reviewed-by: Simon Horman <horms@kernel.org>
---
net/sched/sch_netem.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c
index 20df1c08b1e9..8ee72cac1faf 100644
--- a/net/sched/sch_netem.c
+++ b/net/sched/sch_netem.c
@@ -227,10 +227,10 @@ static bool loss_4state(struct netem_sched_data *q)
if (rnd < clg->a4) {
clg->state = LOST_IN_GAP_PERIOD;
return true;
- } else if (clg->a4 < rnd && rnd < clg->a1 + clg->a4) {
+ } else if (rnd < clg->a1 + clg->a4) {
clg->state = LOST_IN_BURST_PERIOD;
return true;
- } else if (clg->a1 + clg->a4 < rnd) {
+ } else {
clg->state = TX_IN_GAP_PERIOD;
}
@@ -247,9 +247,9 @@ static bool loss_4state(struct netem_sched_data *q)
case LOST_IN_BURST_PERIOD:
if (rnd < clg->a3)
clg->state = TX_IN_BURST_PERIOD;
- else if (clg->a3 < rnd && rnd < clg->a2 + clg->a3) {
+ else if (rnd < clg->a2 + clg->a3) {
clg->state = TX_IN_GAP_PERIOD;
- } else if (clg->a2 + clg->a3 < rnd) {
+ } else {
clg->state = LOST_IN_BURST_PERIOD;
return true;
}
--
2.53.0
^ permalink raw reply related
* [PATCH net v4 2/8] net/sched: netem: fix queue limit check to include reordered packets
From: Stephen Hemminger @ 2026-04-06 17:25 UTC (permalink / raw)
To: netdev
Cc: Stephen Hemminger, Simon Horman, Jamal Hadi Salim, Jiri Pirko,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
open list
In-Reply-To: <20260406172627.210894-1-stephen@networkplumber.org>
The queue limit check in netem_enqueue() uses q->t_len which only
counts packets in the internal tfifo. Packets placed in sch->q by
the reorder path (__qdisc_enqueue_head) are not counted, allowing
the total queue occupancy to exceed sch->limit under reordering.
Include sch->q.qlen in the limit check.
Fixes: 50612537e9ab ("netem: fix classful handling")
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
Reviewed-by: Simon Horman <horms@kernel.org>
---
net/sched/sch_netem.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c
index 8ee72cac1faf..d400a730eadd 100644
--- a/net/sched/sch_netem.c
+++ b/net/sched/sch_netem.c
@@ -524,7 +524,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch,
1 << get_random_u32_below(8);
}
- if (unlikely(q->t_len >= sch->limit)) {
+ if (unlikely(sch->q.qlen >= sch->limit)) {
/* re-link segs, so that qdisc_drop_all() frees them all */
skb->next = segs;
qdisc_drop_all(skb, sch, to_free);
--
2.53.0
^ permalink raw reply related
* [PATCH net v4 3/8] net/sched: netem: only reseed PRNG when seed is explicitly provided
From: Stephen Hemminger @ 2026-04-06 17:25 UTC (permalink / raw)
To: netdev
Cc: Stephen Hemminger, Simon Horman, Jamal Hadi Salim, Jiri Pirko,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
François Michel, open list
In-Reply-To: <20260406172627.210894-1-stephen@networkplumber.org>
netem_change() unconditionally reseeds the PRNG on every tc change
command. If TCA_NETEM_PRNG_SEED is not specified, a new random seed
is generated, destroying reproducibility for users who set a
deterministic seed on a previous change.
Move the initial random seed generation to netem_init() and only
reseed in netem_change() when TCA_NETEM_PRNG_SEED is explicitly
provided by the user.
Fixes: 4072d97ddc44 ("netem: add prng attribute to netem_sched_data")
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
Reviewed-by: Simon Horman <horms@kernel.org>
---
net/sched/sch_netem.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c
index d400a730eadd..556f9747f0e7 100644
--- a/net/sched/sch_netem.c
+++ b/net/sched/sch_netem.c
@@ -1112,11 +1112,10 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt,
/* capping jitter to the range acceptable by tabledist() */
q->jitter = min_t(s64, abs(q->jitter), INT_MAX);
- if (tb[TCA_NETEM_PRNG_SEED])
+ if (tb[TCA_NETEM_PRNG_SEED]) {
q->prng.seed = nla_get_u64(tb[TCA_NETEM_PRNG_SEED]);
- else
- q->prng.seed = get_random_u64();
- prandom_seed_state(&q->prng.prng_state, q->prng.seed);
+ prandom_seed_state(&q->prng.prng_state, q->prng.seed);
+ }
unlock:
sch_tree_unlock(sch);
@@ -1139,6 +1138,9 @@ static int netem_init(struct Qdisc *sch, struct nlattr *opt,
return -EINVAL;
q->loss_model = CLG_RANDOM;
+ q->prng.seed = get_random_u64();
+ prandom_seed_state(&q->prng.prng_state, q->prng.seed);
+
ret = netem_change(sch, opt, extack);
if (ret)
pr_info("netem: change failed\n");
--
2.53.0
^ permalink raw reply related
* [PATCH net v4 4/8] net/sched: netem: refactor dequeue into helper functions
From: Stephen Hemminger @ 2026-04-06 17:25 UTC (permalink / raw)
To: netdev
Cc: Stephen Hemminger, Jamal Hadi Salim, Jiri Pirko, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman,
open list
In-Reply-To: <20260406172627.210894-1-stephen@networkplumber.org>
Extract the tfifo removal, slot accounting, and child/direct dequeue
paths from the monolithic netem_dequeue() into separate helpers:
netem_pull_tfifo() - remove head packet from tfifo
netem_slot_account() - update slot pacing counters
netem_dequeue_child() - enqueue to child, then dequeue from child
netem_dequeue_direct()- dequeue from tfifo when no child
This replaces the goto-based control flow with straightforward function
calls, making the code easier to follow and modify.
No functional change intended.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
net/sched/sch_netem.c | 190 +++++++++++++++++++++++++++---------------
1 file changed, 123 insertions(+), 67 deletions(-)
diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c
index 556f9747f0e7..e264f7aefb97 100644
--- a/net/sched/sch_netem.c
+++ b/net/sched/sch_netem.c
@@ -689,99 +689,155 @@ static struct sk_buff *netem_peek(struct netem_sched_data *q)
return q->t_head;
}
-static void netem_erase_head(struct netem_sched_data *q, struct sk_buff *skb)
+/*
+ * Pop the head packet from the tfifo and prepare it for delivery.
+ * skb->dev shares the rbnode area and must be restored after removal.
+ */
+static struct sk_buff *netem_pull_tfifo(struct netem_sched_data *q,
+ struct Qdisc *sch)
{
- if (skb == q->t_head) {
+ struct sk_buff *skb;
+
+ if (q->t_head) {
+ skb = q->t_head;
q->t_head = skb->next;
if (!q->t_head)
q->t_tail = NULL;
} else {
- rb_erase(&skb->rbnode, &q->t_root);
+ struct rb_node *p = rb_first(&q->t_root);
+
+ if (!p)
+ return NULL;
+ skb = rb_to_skb(p);
+ rb_erase(p, &q->t_root);
}
+
+ q->t_len--;
+ skb->next = NULL;
+ skb->prev = NULL;
+ skb->dev = qdisc_dev(sch);
+
+ return skb;
}
-static struct sk_buff *netem_dequeue(struct Qdisc *sch)
+/* Update slot pacing counters after releasing a packet */
+static void netem_slot_account(struct netem_sched_data *q,
+ const struct sk_buff *skb, u64 now)
+{
+ if (!q->slot.slot_next)
+ return;
+
+ q->slot.packets_left--;
+ q->slot.bytes_left -= qdisc_pkt_len(skb);
+ if (q->slot.packets_left <= 0 || q->slot.bytes_left <= 0)
+ get_slot_next(q, now);
+}
+
+/*
+ * Transfer time-ready packets from the tfifo into the child qdisc,
+ * then dequeue from the child.
+ */
+static struct sk_buff *netem_dequeue_child(struct Qdisc *sch)
{
struct netem_sched_data *q = qdisc_priv(sch);
+ u64 now = ktime_get_ns();
struct sk_buff *skb;
-tfifo_dequeue:
- skb = __qdisc_dequeue_head(&sch->q);
- if (skb) {
-deliver:
- qdisc_qstats_backlog_dec(sch, skb);
- qdisc_bstats_update(sch, skb);
- return skb;
- }
skb = netem_peek(q);
if (skb) {
- u64 time_to_send;
- u64 now = ktime_get_ns();
+ u64 time_to_send = netem_skb_cb(skb)->time_to_send;
- /* if more time remaining? */
- time_to_send = netem_skb_cb(skb)->time_to_send;
if (q->slot.slot_next && q->slot.slot_next < time_to_send)
get_slot_next(q, now);
if (time_to_send <= now && q->slot.slot_next <= now) {
- netem_erase_head(q, skb);
- q->t_len--;
- skb->next = NULL;
- skb->prev = NULL;
- /* skb->dev shares skb->rbnode area,
- * we need to restore its value.
- */
- skb->dev = qdisc_dev(sch);
-
- if (q->slot.slot_next) {
- q->slot.packets_left--;
- q->slot.bytes_left -= qdisc_pkt_len(skb);
- if (q->slot.packets_left <= 0 ||
- q->slot.bytes_left <= 0)
- get_slot_next(q, now);
- }
-
- if (q->qdisc) {
- unsigned int pkt_len = qdisc_pkt_len(skb);
- struct sk_buff *to_free = NULL;
- int err;
-
- err = qdisc_enqueue(skb, q->qdisc, &to_free);
- kfree_skb_list(to_free);
- if (err != NET_XMIT_SUCCESS) {
- if (net_xmit_drop_count(err))
- qdisc_qstats_drop(sch);
- sch->qstats.backlog -= pkt_len;
- sch->q.qlen--;
- qdisc_tree_reduce_backlog(sch, 1, pkt_len);
- }
- goto tfifo_dequeue;
- }
- sch->q.qlen--;
- goto deliver;
- }
-
- if (q->qdisc) {
- skb = q->qdisc->ops->dequeue(q->qdisc);
- if (skb) {
+ struct sk_buff *to_free = NULL;
+ unsigned int pkt_len;
+ int err;
+
+ skb = netem_pull_tfifo(q, sch);
+ netem_slot_account(q, skb, now);
+
+ pkt_len = qdisc_pkt_len(skb);
+ err = qdisc_enqueue(skb, q->qdisc, &to_free);
+ kfree_skb_list(to_free);
+ if (err != NET_XMIT_SUCCESS) {
+ if (net_xmit_drop_count(err))
+ qdisc_qstats_drop(sch);
+ sch->qstats.backlog -= pkt_len;
sch->q.qlen--;
- goto deliver;
+ qdisc_tree_reduce_backlog(sch, 1, pkt_len);
}
}
-
- qdisc_watchdog_schedule_ns(&q->watchdog,
- max(time_to_send,
- q->slot.slot_next));
}
- if (q->qdisc) {
- skb = q->qdisc->ops->dequeue(q->qdisc);
- if (skb) {
- sch->q.qlen--;
- goto deliver;
- }
+ skb = q->qdisc->ops->dequeue(q->qdisc);
+ if (skb)
+ sch->q.qlen--;
+
+ return skb;
+}
+
+/* Dequeue directly from the tfifo when no child qdisc is configured. */
+static struct sk_buff *netem_dequeue_direct(struct Qdisc *sch)
+{
+ struct netem_sched_data *q = qdisc_priv(sch);
+ struct sk_buff *skb;
+ u64 time_to_send;
+ u64 now;
+
+ skb = netem_peek(q);
+ if (!skb)
+ return NULL;
+
+ now = ktime_get_ns();
+ time_to_send = netem_skb_cb(skb)->time_to_send;
+
+ if (q->slot.slot_next && q->slot.slot_next < time_to_send)
+ get_slot_next(q, now);
+
+ if (time_to_send > now || q->slot.slot_next > now)
+ return NULL;
+
+ skb = netem_pull_tfifo(q, sch);
+ netem_slot_account(q, skb, now);
+ sch->q.qlen--;
+
+ return skb;
+}
+
+static struct sk_buff *netem_dequeue(struct Qdisc *sch)
+{
+ struct netem_sched_data *q = qdisc_priv(sch);
+ struct sk_buff *skb;
+
+ /* First check the reorder queue */
+ skb = __qdisc_dequeue_head(&sch->q);
+ if (skb)
+ goto deliver;
+
+ if (q->qdisc)
+ skb = netem_dequeue_child(sch);
+ else
+ skb = netem_dequeue_direct(sch);
+
+ if (skb)
+ goto deliver;
+
+ /* Nothing ready — schedule watchdog for next packet */
+ skb = netem_peek(q);
+ if (skb) {
+ u64 time_to_send = netem_skb_cb(skb)->time_to_send;
+
+ qdisc_watchdog_schedule_ns(&q->watchdog,
+ max(time_to_send, q->slot.slot_next));
}
return NULL;
+
+deliver:
+ qdisc_qstats_backlog_dec(sch, skb);
+ qdisc_bstats_update(sch, skb);
+ return skb;
}
static void netem_reset(struct Qdisc *sch)
--
2.53.0
^ permalink raw reply related
* [PATCH net v4 5/8] net/sched: netem: batch-transfer ready packets to avoid child re-entrancy
From: Stephen Hemminger @ 2026-04-06 17:25 UTC (permalink / raw)
To: netdev
Cc: Stephen Hemminger, Jamal Hadi Salim, Jiri Pirko, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman,
open list
In-Reply-To: <20260406172627.210894-1-stephen@networkplumber.org>
netem_dequeue_child() previously transferred one packet from the tfifo
to the child qdisc per dequeue call. Parents like HFSC that track
class active/inactive state on qlen transitions could see an enqueue
during dequeue, causing double-insertion into the eltree
(CVE-2025-37890, CVE-2025-38001). Non-work-conserving children like
TBF could also refuse to return a just-enqueued packet, making netem
return NULL despite having backlog, which causes parents like DRR to
incorrectly deactivate the class.
Move all time-ready packets into the child before calling its dequeue.
This separates the enqueue and dequeue phases so the parent sees
consistent qlen transitions.
Fixes: 50612537e9ab ("netem: fix classful handling")
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
net/sched/sch_netem.c | 49 +++++++++++++++++++++----------------------
1 file changed, 24 insertions(+), 25 deletions(-)
diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c
index e264f7aefb97..b93f0e886a2b 100644
--- a/net/sched/sch_netem.c
+++ b/net/sched/sch_netem.c
@@ -734,8 +734,10 @@ static void netem_slot_account(struct netem_sched_data *q,
}
/*
- * Transfer time-ready packets from the tfifo into the child qdisc,
- * then dequeue from the child.
+ * Transfer all time-ready packets from the tfifo into the child qdisc,
+ * then dequeue from the child. Batching the transfers avoids calling
+ * qdisc_enqueue() inside the parent's dequeue path, which confuses
+ * parents that track active/inactive state on qlen transitions (HFSC).
*/
static struct sk_buff *netem_dequeue_child(struct Qdisc *sch)
{
@@ -743,31 +745,28 @@ static struct sk_buff *netem_dequeue_child(struct Qdisc *sch)
u64 now = ktime_get_ns();
struct sk_buff *skb;
- skb = netem_peek(q);
- if (skb) {
- u64 time_to_send = netem_skb_cb(skb)->time_to_send;
-
- if (q->slot.slot_next && q->slot.slot_next < time_to_send)
- get_slot_next(q, now);
-
- if (time_to_send <= now && q->slot.slot_next <= now) {
- struct sk_buff *to_free = NULL;
- unsigned int pkt_len;
- int err;
+ while ((skb = netem_peek(q)) != NULL) {
+ struct sk_buff *to_free = NULL;
+ unsigned int pkt_len;
+ int err;
- skb = netem_pull_tfifo(q, sch);
- netem_slot_account(q, skb, now);
+ if (netem_skb_cb(skb)->time_to_send > now)
+ break;
+ if (q->slot.slot_next && q->slot.slot_next > now)
+ break;
- pkt_len = qdisc_pkt_len(skb);
- err = qdisc_enqueue(skb, q->qdisc, &to_free);
- kfree_skb_list(to_free);
- if (err != NET_XMIT_SUCCESS) {
- if (net_xmit_drop_count(err))
- qdisc_qstats_drop(sch);
- sch->qstats.backlog -= pkt_len;
- sch->q.qlen--;
- qdisc_tree_reduce_backlog(sch, 1, pkt_len);
- }
+ skb = netem_pull_tfifo(q, sch);
+ netem_slot_account(q, skb, now);
+
+ pkt_len = qdisc_pkt_len(skb);
+ err = qdisc_enqueue(skb, q->qdisc, &to_free);
+ kfree_skb_list(to_free);
+ if (unlikely(err != NET_XMIT_SUCCESS)) {
+ if (net_xmit_drop_count(err))
+ qdisc_qstats_drop(sch);
+ sch->qstats.backlog -= pkt_len;
+ sch->q.qlen--;
+ qdisc_tree_reduce_backlog(sch, 1, pkt_len);
}
}
--
2.53.0
^ permalink raw reply related
* [PATCH net v4 6/8] net/sched: netem: null-terminate tfifo linear queue tail
From: Stephen Hemminger @ 2026-04-06 17:25 UTC (permalink / raw)
To: netdev
Cc: Stephen Hemminger, Simon Horman, Jamal Hadi Salim, Jiri Pirko,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Peter Oskolkov, open list
In-Reply-To: <20260406172627.210894-1-stephen@networkplumber.org>
When tfifo_enqueue() appends a packet to the linear queue tail,
nskb->next is never set to NULL. The list terminates correctly
only by accident if the skb arrived with next already NULL.
Explicitly null-terminate the tail to prevent list corruption.
Fixes: d66280b12bd7 ("net: netem: use a list in addition to rbtree")
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
Reviewed-by: Simon Horman <horms@kernel.org>
---
net/sched/sch_netem.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c
index b93f0e886a2b..e405bf862163 100644
--- a/net/sched/sch_netem.c
+++ b/net/sched/sch_netem.c
@@ -398,6 +398,7 @@ static void tfifo_enqueue(struct sk_buff *nskb, struct Qdisc *sch)
q->t_tail->next = nskb;
else
q->t_head = nskb;
+ nskb->next = NULL;
q->t_tail = nskb;
} else {
struct rb_node **p = &q->t_root.rb_node, *parent = NULL;
--
2.53.0
^ permalink raw reply related
* [PATCH net v4 7/8] net/sched: netem: check for invalid slot range
From: Stephen Hemminger @ 2026-04-06 17:25 UTC (permalink / raw)
To: netdev
Cc: Stephen Hemminger, Simon Horman, Jamal Hadi Salim, Jiri Pirko,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Neal Cardwell, Yousuk Seung, open list
In-Reply-To: <20260406172627.210894-1-stephen@networkplumber.org>
Reject slot configuration where min_delay exceeds max_delay.
The delay range computation in get_slot_next() underflows in
this case, producing bogus results.
Fixes: 0a9fe5c375b5 ("netem: slotting with non-uniform distribution")
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
Reviewed-by: Simon Horman <horms@kernel.org>
---
net/sched/sch_netem.c | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c
index e405bf862163..c82f76af41aa 100644
--- a/net/sched/sch_netem.c
+++ b/net/sched/sch_netem.c
@@ -883,6 +883,18 @@ static int get_dist_table(struct disttable **tbl, const struct nlattr *attr)
return 0;
}
+static int validate_slot(const struct nlattr *attr,
+ struct netlink_ext_ack *extack)
+{
+ const struct tc_netem_slot *c = nla_data(attr);
+
+ if (c->min_delay > c->max_delay) {
+ NL_SET_ERR_MSG(extack, "slot min delay greater than max delay");
+ return -EINVAL;
+ }
+ return 0;
+}
+
static void get_slot(struct netem_sched_data *q, const struct nlattr *attr)
{
const struct tc_netem_slot *c = nla_data(attr);
@@ -1096,6 +1108,12 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt,
goto table_free;
}
+ if (tb[TCA_NETEM_SLOT]) {
+ ret = validate_slot(tb[TCA_NETEM_SLOT], extack);
+ if (ret)
+ goto table_free;
+ }
+
sch_tree_lock(sch);
/* backup q->clg and q->loss_model */
old_clg = q->clg;
--
2.53.0
^ permalink raw reply related
* [PATCH net v4 8/8] net/sched: netem: fix slot delay calculation overflow
From: Stephen Hemminger @ 2026-04-06 17:25 UTC (permalink / raw)
To: netdev
Cc: Stephen Hemminger, Simon Horman, Jamal Hadi Salim, Jiri Pirko,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Yousuk Seung, Neal Cardwell, open list
In-Reply-To: <20260406172627.210894-1-stephen@networkplumber.org>
get_slot_next() computes a random delay between min_delay and
max_delay using:
get_random_u32() * (max_delay - min_delay) >> 32
This overflows signed 64-bit arithmetic when the delay range exceeds
approximately 2.1 seconds (2^31 nanoseconds), producing a negative
result that effectively disables slot-based pacing. This is a
realistic configuration for WAN emulation (e.g., slot 1s 5s).
Use mul_u64_u32_shr() which handles the widening multiply without
overflow.
Fixes: 0a9fe5c375b5 ("netem: slotting with non-uniform distribution")
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
Reviewed-by: Simon Horman <horms@kernel.org>
---
net/sched/sch_netem.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c
index c82f76af41aa..d47e1b0d7942 100644
--- a/net/sched/sch_netem.c
+++ b/net/sched/sch_netem.c
@@ -660,9 +660,8 @@ static void get_slot_next(struct netem_sched_data *q, u64 now)
if (!q->slot_dist)
next_delay = q->slot_config.min_delay +
- (get_random_u32() *
- (q->slot_config.max_delay -
- q->slot_config.min_delay) >> 32);
+ mul_u64_u32_shr(q->slot_config.max_delay - q->slot_config.min_delay,
+ get_random_u32(), 32);
else
next_delay = tabledist(q->slot_config.dist_delay,
(s32)(q->slot_config.dist_jitter),
--
2.53.0
^ permalink raw reply related
* Re: [PATCH v2] mm/vmpressure: skip socket pressure for costly order reclaim
From: JP Kobryn (Meta) @ 2026-04-06 17:34 UTC (permalink / raw)
To: Shakeel Butt
Cc: linux-mm, willy, hannes, akpm, david, ljs, Liam.Howlett, vbabka,
rppt, surenb, mhocko, kasong, qi.zheng, baohua, axelrasmussen,
yuanchu, weixugc, riel, kuba, edumazet, netdev, linux-kernel,
kernel-team
In-Reply-To: <ac8DEuZhb_aQA4ez@linux.dev>
On 4/2/26 6:03 PM, Shakeel Butt wrote:
> On Thu, Apr 02, 2026 at 04:25:11PM -0700, JP Kobryn (Meta) wrote:
>> When kswapd reclaims at high order due to fragmentation,
>
> * kswapd is woken up for the higher order reclaim request
>
> But this can be direct reclaim as well.
Good call.
>
>> vmpressure() can
>> report poor reclaim efficiency even though the system has plenty of free
>> memory. This is because kswapd scans many pages but finds little to reclaim
>> - the pages are actively in use and don't need to be freed. The resulting
>> scan:reclaim ratio triggers socket pressure, throttling TCP throughput
>> unnecessarily.
>>
>> Net allocations do not exceed order 3 (PAGE_ALLOC_COSTLY_ORDER),
>
> Net not doing costly order allocations is irrelevant here. IIUC you want all
> costly order allocations (like THPs) to not raise vmpressure as those don't
> necessarily represents the memory pressure.
The supporting context I included was based on the investigation that
led to the patch. But as you and Rik both noted, the patch has
greater implications.
>
>> so high
>> order reclaim difficulty should not trigger socket pressure. The kernel
>> already treats this order as the boundary where reclaim is no longer
>> expected to succeed and compaction may take over.
>>
>> Make vmpressure() order-aware through an additional parameter sourced from
>> scan_control at existing call sites. Socket pressure is now only asserted
>> when order <= PAGE_ALLOC_COSTLY_ORDER.
>>
>> Memcg reclaim is unaffected since try_to_free_mem_cgroup_pages() always
>> uses order 0, which passes the filter unconditionally. Similarly,
>> vmpressure_prio() now passes order 0 internally when calling vmpressure(),
>> ensuring critical pressure from low reclaim priority is not suppressed by
>> the order filter.
>>
>> Signed-off-by: JP Kobryn (Meta) <jp.kobryn@linux.dev>
>
> The patch looks good. I think we can ask Andrew to just adjust the commit
> message and then you don't need to resend.
It's no problem for me. I'll send a v3 with an updated commit message.
^ permalink raw reply
* Re: [PATCH net] xfrm_user: fix info leak in build_mapping()
From: Jakub Kicinski @ 2026-04-06 17:38 UTC (permalink / raw)
To: Greg Kroah-Hartman
Cc: netdev, linux-kernel, Steffen Klassert, Herbert Xu,
David S. Miller, Eric Dumazet, Paolo Abeni, Simon Horman
In-Reply-To: <2026040634-deodorant-shakiness-a64e@gregkh>
On Mon, 6 Apr 2026 18:08:27 +0200 Greg Kroah-Hartman wrote:
> On Mon, Apr 06, 2026 at 08:58:59AM -0700, Jakub Kicinski wrote:
> > On Mon, 6 Apr 2026 08:54:49 -0700 Jakub Kicinski wrote:
> > > You're right, skb owner is responsible for clearing after put.
> > > Tho, Netlink is not as perf critical as real networking, I wish
> > > we at least had a helper which reserves the space and clears it :/
> > > This is not the first or the second time we hit this sort of a bug.
> >
> > We could make nlmsg_append() do that. Mostly because I don't have
> > a better idea for a name and nlmsg_append is only used once ;)
>
> As shown in my other patch:
> https://lore.kernel.org/r/2026040621-poison-gristle-aaa3@gregkh
> we need this in at least 2 places, don't know if it's worth doing it for
> all messages?
I was thinking -- add the helper so that we can use it in places we're
touching anyway. No need to mess with correct existing code.
> I guess nlmsg_append() would work? It tries to do some zeroing out for
> alignment for some reason...
>
> Want me to do that? I don't have a way to test any of this, I just
> found it using some static code analysis tools that looked at holes in
> structures.
Do you have any more Netlink leaks in the queue? If you do let's do it,
if you don't we can wait until the next victi^w patch to arrive.
^ permalink raw reply
* [PATCH v3] mm/vmpressure: skip socket pressure for costly order reclaim
From: JP Kobryn (Meta) @ 2026-04-06 17:44 UTC (permalink / raw)
To: linux-mm, willy, hannes, akpm, david, ljs, Liam.Howlett, vbabka,
rppt, surenb, mhocko, kasong, qi.zheng, shakeel.butt, baohua,
axelrasmussen, yuanchu, weixugc, riel, kuba, edumazet
Cc: netdev, linux-kernel, kernel-team
When reclaim is triggered by high order allocations on a fragmented system,
vmpressure() can report poor reclaim efficiency even though the system has
plenty of free memory. This is because many pages are scanned, but few are
found to actually reclaim - the pages are actively in use and don't need to
be freed. The resulting scan:reclaim ratio causes vmpressure() to assert
socket pressure, throttling TCP throughput unnecessarily.
Costly order allocations (above PAGE_ALLOC_COSTLY_ORDER) rely heavily on
compaction to succeed, so poor reclaim efficiency at these orders does not
necessarily indicate memory pressure. The kernel already treats this order
as the boundary where reclaim is no longer expected to succeed and
compaction may take over.
Make vmpressure() order-aware through an additional parameter sourced from
scan_control at existing call sites. Socket pressure is now only asserted
when order <= PAGE_ALLOC_COSTLY_ORDER.
Memcg reclaim is unaffected since try_to_free_mem_cgroup_pages() always
uses order 0, which passes the filter unconditionally. Similarly,
vmpressure_prio() now passes order 0 internally when calling vmpressure(),
ensuring critical pressure from low reclaim priority is not suppressed by
the order filter.
Signed-off-by: JP Kobryn (Meta) <jp.kobryn@linux.dev>
Reviewed-by: Rik van Riel <riel@surriel.com>
Acked-by: Johannes Weiner <hannes@cmpxchg.org>
Acked-by: Shakeel Butt <shakeel.butt@linux.dev>
Acked-by: Jakub Kicinski <kuba@kernel.org>
---
v3
- update changelog to justify patch beyond just networking
- update changelog to expand scope of vmpressure beyond kswapd
v2
- dropped extern specifier from vmpressure decl
- added comment to explain rationale of adjusted conditional
v1: https://lore.kernel.org/all/20260401203752.643259-1-jp.kobryn@linux.dev/
include/linux/vmpressure.h | 9 +++++----
mm/vmpressure.c | 15 ++++++++++++---
mm/vmscan.c | 8 ++++----
3 files changed, 21 insertions(+), 11 deletions(-)
diff --git a/include/linux/vmpressure.h b/include/linux/vmpressure.h
index 6a2f51ebbfd35..faecd55224017 100644
--- a/include/linux/vmpressure.h
+++ b/include/linux/vmpressure.h
@@ -30,8 +30,8 @@ struct vmpressure {
struct mem_cgroup;
#ifdef CONFIG_MEMCG
-extern void vmpressure(gfp_t gfp, struct mem_cgroup *memcg, bool tree,
- unsigned long scanned, unsigned long reclaimed);
+void vmpressure(gfp_t gfp, int order, struct mem_cgroup *memcg, bool tree,
+ unsigned long scanned, unsigned long reclaimed);
extern void vmpressure_prio(gfp_t gfp, struct mem_cgroup *memcg, int prio);
extern void vmpressure_init(struct vmpressure *vmpr);
@@ -44,8 +44,9 @@ extern int vmpressure_register_event(struct mem_cgroup *memcg,
extern void vmpressure_unregister_event(struct mem_cgroup *memcg,
struct eventfd_ctx *eventfd);
#else
-static inline void vmpressure(gfp_t gfp, struct mem_cgroup *memcg, bool tree,
- unsigned long scanned, unsigned long reclaimed) {}
+static inline void vmpressure(gfp_t gfp, int order, struct mem_cgroup *memcg,
+ bool tree, unsigned long scanned,
+ unsigned long reclaimed) {}
static inline void vmpressure_prio(gfp_t gfp, struct mem_cgroup *memcg,
int prio) {}
#endif /* CONFIG_MEMCG */
diff --git a/mm/vmpressure.c b/mm/vmpressure.c
index 3fbb86996c4d2..f053554e58264 100644
--- a/mm/vmpressure.c
+++ b/mm/vmpressure.c
@@ -218,6 +218,7 @@ static void vmpressure_work_fn(struct work_struct *work)
/**
* vmpressure() - Account memory pressure through scanned/reclaimed ratio
* @gfp: reclaimer's gfp mask
+ * @order: allocation order being reclaimed for
* @memcg: cgroup memory controller handle
* @tree: legacy subtree mode
* @scanned: number of pages scanned
@@ -236,7 +237,7 @@ static void vmpressure_work_fn(struct work_struct *work)
*
* This function does not return any value.
*/
-void vmpressure(gfp_t gfp, struct mem_cgroup *memcg, bool tree,
+void vmpressure(gfp_t gfp, int order, struct mem_cgroup *memcg, bool tree,
unsigned long scanned, unsigned long reclaimed)
{
struct vmpressure *vmpr;
@@ -307,7 +308,15 @@ void vmpressure(gfp_t gfp, struct mem_cgroup *memcg, bool tree,
level = vmpressure_calc_level(scanned, reclaimed);
- if (level > VMPRESSURE_LOW) {
+ /*
+ * Once we go above COSTLY_ORDER, reclaim relies heavily on
+ * compaction to make progress. Reclaim efficiency was never a
+ * great proxy for pressure to begin with, but it's outright
+ * misleading with these high orders. Don't throttle sockets
+ * because somebody is attempting something crazy like an order-7
+ * and predictably struggling.
+ */
+ if (level > VMPRESSURE_LOW && order <= PAGE_ALLOC_COSTLY_ORDER) {
/*
* Let the socket buffer allocator know that
* we are having trouble reclaiming LRU pages.
@@ -348,7 +357,7 @@ void vmpressure_prio(gfp_t gfp, struct mem_cgroup *memcg, int prio)
* to the vmpressure() basically means that we signal 'critical'
* level.
*/
- vmpressure(gfp, memcg, true, vmpressure_win, 0);
+ vmpressure(gfp, 0, memcg, true, vmpressure_win, 0);
}
#define MAX_VMPRESSURE_ARGS_LEN (strlen("critical") + strlen("hierarchy") + 2)
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 5a8c8fcccbfc9..1342323a0b41f 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -5071,8 +5071,8 @@ static int shrink_one(struct lruvec *lruvec, struct scan_control *sc)
shrink_slab(sc->gfp_mask, pgdat->node_id, memcg, sc->priority);
if (!sc->proactive)
- vmpressure(sc->gfp_mask, memcg, false, sc->nr_scanned - scanned,
- sc->nr_reclaimed - reclaimed);
+ vmpressure(sc->gfp_mask, sc->order, memcg, false,
+ sc->nr_scanned - scanned, sc->nr_reclaimed - reclaimed);
flush_reclaim_state(sc);
@@ -6175,7 +6175,7 @@ static void shrink_node_memcgs(pg_data_t *pgdat, struct scan_control *sc)
/* Record the group's reclaim efficiency */
if (!sc->proactive)
- vmpressure(sc->gfp_mask, memcg, false,
+ vmpressure(sc->gfp_mask, sc->order, memcg, false,
sc->nr_scanned - scanned,
sc->nr_reclaimed - reclaimed);
@@ -6220,7 +6220,7 @@ static void shrink_node(pg_data_t *pgdat, struct scan_control *sc)
/* Record the subtree's reclaim efficiency */
if (!sc->proactive)
- vmpressure(sc->gfp_mask, sc->target_mem_cgroup, true,
+ vmpressure(sc->gfp_mask, sc->order, sc->target_mem_cgroup, true,
sc->nr_scanned - nr_scanned, nr_node_reclaimed);
if (nr_node_reclaimed)
--
2.52.0
^ permalink raw reply related
* Re: [PATCH net-next,v4] net: mana: Force full-page RX buffers via ethtool private flag
From: Jakub Kicinski @ 2026-04-06 17:51 UTC (permalink / raw)
To: Dipayaan Roy
Cc: kys, haiyangz, wei.liu, decui, andrew+netdev, davem, edumazet,
pabeni, leon, longli, kotaranov, horms, shradhagupta, ssengar,
ernis, shirazsaleem, linux-hyperv, netdev, linux-kernel,
linux-rdma, stephen, jacob.e.keller, leitao, kees, dipayanroy
In-Reply-To: <adHTm2SvjDrezEdv@linuxonhyperv3.guj3yctzbm1etfxqx2vob5hsef.xx.internal.cloudapp.net>
On Sat, 4 Apr 2026 20:14:35 -0700 Dipayaan Roy wrote:
> Function Fragment Full-page Delta
> ─---------------------------- ─------- --------- -----
> napi_pp_put_page 3.93% 0.85% +3.08%
> page_pool_alloc_frag_netmem 1.93% — +1.93%
> Total page_pool overhead 5.86% 0.85% +5.01%
Thanks for the analysis, and presumably recycling the full page is
cheaper because page_pool_put_unrefed_netmem() hits the fastpath
because page_pool_napi_local() returns true?
^ permalink raw reply
* [PATCH net-next] docs: netdev: improve wording of reviewer guidance
From: Jakub Kicinski @ 2026-04-06 17:53 UTC (permalink / raw)
To: davem
Cc: netdev, edumazet, pabeni, andrew+netdev, horms, Jakub Kicinski,
corbet, skhan, workflows, linux-doc
Reword the reviewer guidance based on behavior we see on the list.
Steer folks:
- towards sending tags
- away from process issues.
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
CC: corbet@lwn.net
CC: skhan@linuxfoundation.org
CC: workflows@vger.kernel.org
CC: linux-doc@vger.kernel.org
---
Documentation/process/maintainer-netdev.rst | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/Documentation/process/maintainer-netdev.rst b/Documentation/process/maintainer-netdev.rst
index 3aa13bc2405d..bda93b459a05 100644
--- a/Documentation/process/maintainer-netdev.rst
+++ b/Documentation/process/maintainer-netdev.rst
@@ -551,10 +551,12 @@ helpful tips please see :ref:`development_advancedtopics_reviews`.
It's safe to assume that netdev maintainers know the community and the level
of expertise of the reviewers. The reviewers should not be concerned about
-their comments impeding or derailing the patch flow.
+their comments impeding or derailing the patch flow. A Reviewed-by tag
+is understood to mean "I have reviewed this code to the best of my ability"
+rather than "I can attest this code is correct".
-Less experienced reviewers are highly encouraged to do more in-depth
-review of submissions and not focus exclusively on trivial or subjective
+Reviewers are highly encouraged to do more in-depth review of submissions
+and not focus exclusively on process issues, trivial or subjective
matters like code formatting, tags etc.
Testimonials / feedback
--
2.53.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox