* Re: [PATCH net-next v2 0/5] Reimplement TCP-AO using crypto library
From: Jakub Kicinski @ 2026-04-27 22:55 UTC (permalink / raw)
To: Dmitry Safonov
Cc: Eric Biggers, netdev, linux-crypto, linux-kernel, Eric Dumazet,
Neal Cardwell, Kuniyuki Iwashima, David S . Miller, David Ahern,
Paolo Abeni, Simon Horman, Ard Biesheuvel, Jason A . Donenfeld,
Herbert Xu, Dmitry Safonov
In-Reply-To: <CAJwJo6Z9oJSMMBUL_pbYWN6ha3n4MRpKV_aVut8E+af3JUDFkw@mail.gmail.com>
On Mon, 27 Apr 2026 20:09:05 +0100 Dmitry Safonov wrote:
> I do like these numbers quite much! Yet, as I mentioned in version 1,
> removing a fallback for other algorithms' support does not sound good
> to me. There are two reasons:
> - Ronald P. Bonica (the original RFC5925 author), together with Tony
> Li do have an active RFC draft to support the additional algorithms
> [1], potentially in addition to TCP Extended Options [2]
> - There is at least one open-source BGP implementation (BIRD) that
> allows using the algorithms that you are removing [3]. Without a
> deprecation period and communication with at least known open source
> users, it implies intentionally breaking them, which I can't agree
> with.
>
> I don't feel like Naking as we don't have any customers using anything
> other than the 3 algorithms above (and BGP implementation is
> [unfortunately] closed-source, so that would not feel appropriate even
> if we had such customers), yet I do feel like it's worth and
> appropriate to express my thoughts/concerns.
What do you want to happen? You are the maintainer of this code,
you don't get so say "i don't want to nack it but also no" :)
Like Eric says if there are no real users code can be deleted.
Adding deprecation warnings upstream is quite slow, IDK if injecting
deprecation warnings to stable has been discussed..
^ permalink raw reply
* [PATCH] net: lwt_bpf: replace name-based BPF program comparison with digest
From: Matan Cohen @ 2026-04-27 22:51 UTC (permalink / raw)
To: netdev; +Cc: davem, edumazet, kuba, pabeni, daniel, linux-kernel, Matan Cohen
bpf_lwt_prog_cmp() used strcmp() on program names as a workaround
because delete requests rebuild the LWT state, creating a new
bpf_prog instance for the same program.
Name comparison is unreliable: programs with the same name but
different instructions compare equal, while instruction-identical
programs with different names compare unequal.
Replace it with a two-step approach:
- Pointer equality as a cheap fast path.
- SHA256 digest comparison as the fallback. bpf_prog_calc_tag()
computes the digest (instructions with map fds zeroed) at the
end of bpf_check(), so it is valid for every successfully
loaded BPF program.
Signed-off-by: Matan Cohen <matan@matanco.space>
---
net/core/lwt_bpf.c | 15 +++++++++------
1 file changed, 9 insertions(+), 6 deletions(-)
diff --git a/net/core/lwt_bpf.c b/net/core/lwt_bpf.c
index f71ef82a5f3d3..6999da98b6b97 100644
--- a/net/core/lwt_bpf.c
+++ b/net/core/lwt_bpf.c
@@ -494,17 +494,20 @@ static int bpf_encap_nlsize(struct lwtunnel_state *lwtstate)
static int bpf_lwt_prog_cmp(struct bpf_lwt_prog *a, struct bpf_lwt_prog *b)
{
- /* FIXME:
- * The LWT state is currently rebuilt for delete requests which
- * results in a new bpf_prog instance. Comparing names for now.
+ /* Delete requests rebuild the LWT state, so pointer equality is
+ * not sufficient. Compare by digest (SHA256 of instructions with
+ * map fds zeroed by bpf_prog_calc_tag()) as a reliable fallback.
*/
- if (!a->name && !b->name)
+ if (!a->prog && !b->prog)
return 0;
- if (!a->name || !b->name)
+ if (!a->prog || !b->prog)
return 1;
- return strcmp(a->name, b->name);
+ if (a->prog == b->prog)
+ return 0;
+
+ return memcmp(a->prog->digest, b->prog->digest, SHA256_DIGEST_SIZE);
}
static int bpf_encap_cmp(struct lwtunnel_state *a, struct lwtunnel_state *b)
--
2.43.0
^ permalink raw reply related
* Re: [PATCH net-next v5 0/3] selftests: drv-net: convert so_txtime to drv-net
From: Jakub Kicinski @ 2026-04-27 22:48 UTC (permalink / raw)
To: Willem de Bruijn
Cc: netdev, davem, edumazet, pabeni, horms, linux-kselftest, shuah,
Willem de Bruijn
In-Reply-To: <20260427201640.294694-1-willemdebruijn.kernel@gmail.com>
On Mon, 27 Apr 2026 16:14:32 -0400 Willem de Bruijn wrote:
> Subject: [PATCH net-next v5 0/3] selftests: drv-net: convert so_txtime to drv-net
net-next wasn't open yet, when you posted.
Please resubmit in a couple of days.
--
pw-bot: defer
^ permalink raw reply
* [ANN] net-next is OPEN
From: Jakub Kicinski @ 2026-04-27 22:47 UTC (permalink / raw)
To: netdev
Hi!
net-next is now open, and accepting v7.2 patches.
I was hoping to get a single clean run out of the CI before
the announcement but it's still a bit wonky. So let's open
net-next and I'll try to somehow mend it as we go.
^ permalink raw reply
* Re: [RFC PATCH net-next] net: mana: Force single RX buffer per page under SWIOTLB bounce modes
From: Jakub Kicinski @ 2026-04-27 22:44 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, dipayanroy, leitao, kees,
john.fastabend, hawk, bpf, daniel, ast, sdf, yury.norov
In-Reply-To: <ae91hyrLf4n23XE6@linuxonhyperv3.guj3yctzbm1etfxqx2vob5hsef.xx.internal.cloudapp.net>
On Mon, 27 Apr 2026 07:41:11 -0700 Dipayaan Roy wrote:
> In both cases, sub-page RX buffer fragments allocated via page_pool may
> not be compatible with bounce buffering in this mode, leading to failures
> in the RX path.
What does it mean to not be compatible with swiotlb?
Normally that indicates that DMA API is mis-used.
^ permalink raw reply
* [PATCH net v1 2/2] selftest: net: Add test for TCP flow failover with ECMP routes.
From: Sagarika Sharma @ 2026-04-27 22:42 UTC (permalink / raw)
To: David S . Miller, David Ahern, Eric Dumazet, Jakub Kicinski,
Paolo Abeni
Cc: Shuah Khan, Simon Horman, Kuniyuki Iwashima, netdev,
linux-kselftest, Sagarika Sharma
In-Reply-To: <20260427224243.3499162-1-sharmasagarika@google.com>
From: Kuniyuki Iwashima <kuniyu@google.com>
Without the previous commit, TCP failed to switch to alternative
IPv6 routes immediately upon carrier loss.
It would persist with the dead route until reaching the threshold
net.ipv4.tcp_retries1, leading to unnecessary delays in failover.
Let's add a selftest for this scenario to ensure TCP fails over
immediately upon a carrier loss event.
Before:
TEST: TCP IPv4 failover [ OK ]
TEST: TCP IPv6 failover [FAIL]
After:
TEST: TCP IPv4 failover [ OK ]
TEST: TCP IPv6 failover [ OK ]
Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
Signed-off-by: Sagarika Sharma <sharmasagarika@google.com>
---
tools/testing/selftests/net/Makefile | 1 +
.../selftests/net/tcp_ecmp_failover.sh | 209 ++++++++++++++++++
2 files changed, 210 insertions(+)
create mode 100755 tools/testing/selftests/net/tcp_ecmp_failover.sh
diff --git a/tools/testing/selftests/net/Makefile b/tools/testing/selftests/net/Makefile
index a275ed584026..f3da38c54d27 100644
--- a/tools/testing/selftests/net/Makefile
+++ b/tools/testing/selftests/net/Makefile
@@ -96,6 +96,7 @@ TEST_PROGS := \
srv6_hl2encap_red_l2vpn_test.sh \
srv6_iptunnel_cache.sh \
stress_reuseport_listen.sh \
+ tcp_ecmp_failover.sh \
tcp_fastopen_backup_key.sh \
test_bpf.sh \
test_bridge_backup_port.sh \
diff --git a/tools/testing/selftests/net/tcp_ecmp_failover.sh b/tools/testing/selftests/net/tcp_ecmp_failover.sh
new file mode 100755
index 000000000000..f857d5db84d8
--- /dev/null
+++ b/tools/testing/selftests/net/tcp_ecmp_failover.sh
@@ -0,0 +1,209 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+#
+# Copyright 2026 Google LLC.
+#
+# This test verifies TCP flow failover between ECMP routes
+# upon carrier loss on the active device.
+#
+# socat -----------------------------> socat
+# |
+# .-- veth-c1 -|- veth-s1 --.
+# dummy0 -| | |-- dummy0
+# '-- veth-c2 -|- veth-s2 --'
+# |
+#
+
+REQUIRE_JQ=no
+REQUIRE_MZ=no
+NUM_NETIFS=0
+
+source forwarding/lib.sh
+
+CLIENT_IP="10.0.59.1"
+SERVER_IP="10.0.92.1"
+CLIENT_IP6="2001:db8:5a9a::1"
+SERVER_IP6="2001:db8:9292::1"
+
+setup_server()
+{
+ IP="ip -n $server"
+ NS_EXEC="ip netns exec $server"
+
+ $IP link add dummy0 type dummy
+ $IP link set dummy0 up
+
+ $IP -4 addr add $SERVER_IP/32 dev dummy0
+ $IP -6 addr add $SERVER_IP6/128 dev dummy0 nodad
+
+ $IP link set veth-s1 up
+ $IP link set veth-s2 up
+
+ $IP -4 addr add 192.168.1.2/24 dev veth-s1
+ $IP -4 addr add 192.168.2.2/24 dev veth-s2
+
+ $IP -4 route add $CLIENT_IP/32 \
+ nexthop via 192.168.1.1 dev veth-s1 weight 1 \
+ nexthop via 192.168.2.1 dev veth-s2 weight 1
+
+ $IP -6 addr add 2001:db8:1::2/64 dev veth-s1 nodad
+ $IP -6 addr add 2001:db8:2::2/64 dev veth-s2 nodad
+
+ $IP -6 route add $CLIENT_IP6/128 \
+ nexthop via 2001:db8:1::1 dev veth-s1 weight 1 \
+ nexthop via 2001:db8:2::1 dev veth-s2 weight 1
+}
+
+setup_client()
+{
+ IP="ip -n $client"
+ NS_EXEC="ip netns exec $client"
+
+ $IP link add dummy0 type dummy
+ $IP link set dummy0 up
+
+ $IP -4 addr add $CLIENT_IP/32 dev dummy0
+ $IP -6 addr add $CLIENT_IP6/128 dev dummy0 nodad
+
+ $IP link set veth-c1 up
+ $IP link set veth-c2 up
+
+ $IP -4 addr add 192.168.1.1/24 dev veth-c1
+ $IP -4 addr add 192.168.2.1/24 dev veth-c2
+
+ $IP -4 route add $SERVER_IP/32 \
+ nexthop via 192.168.1.2 dev veth-c1 weight 1 \
+ nexthop via 192.168.2.2 dev veth-c2 weight 1
+
+ $IP -6 addr add 2001:db8:1::1/64 dev veth-c1 nodad
+ $IP -6 addr add 2001:db8:2::1/64 dev veth-c2 nodad
+
+ $IP -6 route add $SERVER_IP6/128 \
+ nexthop via 2001:db8:1::2 dev veth-c1 weight 1 \
+ nexthop via 2001:db8:2::2 dev veth-c2 weight 1
+
+ # By default, tcp_retries1=3 triggers a route refresh
+ # after 3 retransmits (~5s). Ensure this never occurs
+ # for test stability.
+ $NS_EXEC sysctl -qw net.ipv4.tcp_retries1=100
+
+ # When NETDEV_CHANGE is issued for a dev tied to an ECMP
+ # route, RTNH_F_LINKDOWN is flagged and the sernum is
+ # bumped to invalidate the route via sk_dst_check().
+ #
+ # Without ignore_routes_with_linkdown=1, subsequent
+ # lookups may still select the same RTNH_F_LINKDOWN route.
+ $NS_EXEC sysctl -qw net.ipv4.conf.veth-c1.ignore_routes_with_linkdown=1
+ $NS_EXEC sysctl -qw net.ipv4.conf.veth-c2.ignore_routes_with_linkdown=1
+
+ $NS_EXEC sysctl -qw net.ipv6.conf.veth-c1.ignore_routes_with_linkdown=1
+ $NS_EXEC sysctl -qw net.ipv6.conf.veth-c2.ignore_routes_with_linkdown=1
+}
+
+setup()
+{
+ setup_ns client server
+
+ ip -n $client link add veth-c1 type veth peer veth-s1 netns $server
+ ip -n $client link add veth-c2 type veth peer veth-s2 netns $server
+
+ setup_server
+ setup_client
+}
+
+cleanup()
+{
+ cleanup_all_ns
+}
+
+tcp_ecmp_failover()
+{
+ local pf=$1; shift
+ local server_ip=$1; shift
+ local client_ip=$1; shift
+
+ RET=0
+
+ tcpdump_start veth-s1 $server
+ tcpdump_start veth-s2 $server
+
+ ip netns exec $server \
+ socat -u TCP-LISTEN:8080,pf=$pf,bind=$server_ip,reuseaddr /dev/null &
+ server_pid=$!
+
+ # Wait for server to start listening.
+ # Sometimes client fails without this sleep.
+ sleep 1
+
+ ip netns exec $client \
+ socat -u /dev/zero TCP:$server_ip:8080,pf=$pf,bind=$client_ip &
+ client_pid=$!
+
+ # To capture enough packets.
+ sleep 3
+
+ tcpdump_stop veth-s1
+ tcpdump_stop veth-s2
+
+ pkts_s1=$(tcpdump_show veth-s1 | wc -l)
+ pkts_s2=$(tcpdump_show veth-s2 | wc -l)
+
+ tcpdump_cleanup veth-s1
+ tcpdump_cleanup veth-s2
+
+ # Detect the device chosen by the client
+ if [ $pkts_s1 -gt $pkts_s2 ]; then
+ veth_down=veth-s1
+ veth_up=veth-s2
+ else
+ veth_down=veth-s2
+ veth_up=veth-s1
+ fi
+
+ # Taking down $veth_down causes its peer to lose carrier,
+ # triggering NETDEV_CHANGE. This flags RTNH_F_LINKDOWN
+ # and bumps the sernum for the route associated with that
+ # peer, invalidating the cached dst in the TCP socket.
+ #
+ # Consequently, sk_dst_check() fails, forcing the subsequent
+ # lookup to select the remaining healthy route via $veth_up.
+ ip -n $server link set $veth_down down
+
+ tcpdump_start $veth_up $server
+
+ # To capture enough packets.
+ sleep 3
+
+ tcpdump_stop $veth_up
+
+ kill -9 $client_pid 2>&1 > /dev/null
+ kill -9 $server_pid 2>&1 > /dev/null
+ wait 2> /dev/null
+
+ pkts=$(tcpdump_show $veth_up | wc -l)
+
+ tcpdump_cleanup $veth_up
+
+ if [ $pkts -lt 10000 ]; then
+ RET=$ksft_fail
+ fi
+}
+
+test_ipv4()
+{
+ setup
+ tcp_ecmp_failover IPv4 $SERVER_IP $CLIENT_IP
+ log_test "TCP IPv4 failover"
+ cleanup
+}
+
+test_ipv6()
+{
+ setup
+ tcp_ecmp_failover IPv6 "[$SERVER_IP6]" "[$CLIENT_IP6]"
+ log_test "TCP IPv6 failover"
+ cleanup
+}
+
+test_ipv4
+test_ipv6
--
2.54.0.545.g6539524ca2-goog
^ permalink raw reply related
* [PATCH net v1 1/2] ipv6: update route serial number on NETDEV_CHANGE
From: Sagarika Sharma @ 2026-04-27 22:42 UTC (permalink / raw)
To: David S . Miller, David Ahern, Eric Dumazet, Jakub Kicinski,
Paolo Abeni
Cc: Shuah Khan, Simon Horman, Kuniyuki Iwashima, netdev,
linux-kselftest, Sagarika Sharma
In-Reply-To: <20260427224243.3499162-1-sharmasagarika@google.com>
When using IPv6 ECMP routes, if a netdev listed as a nexthop experiences
a carrier change event (e.g., a bond device generating a NETDEV_CHANGE
event after its slaves go linkdown), established connections utilizing
that nexthop fail to fail over to other available nexthops. Instead,
these connections stall or drop.
This happens because the IPv6 FIB code does not invalidate the socket's
cached destination when a NETDEV_CHANGE event occurs. While
fib6_ifdown() correctly marks the nexthop with RTNH_F_LINKDOWN, it
leaves the route's serial number unchanged. As a result, sockets with a
previously cached dst do not realize the route is no longer viable and
continue to try using the non-functional nexthop.
This behavior contrasts with IPv4, which actively flushes cached
destinations on a NETDEV_CHANGE event (see fib_netdev_event() in
net/ipv4/fib_frontend.c).
Fix this by updating the route serial number in fib6_ifdown() when
setting RTNH_F_LINKDOWN. This invalidates stale cached destinations,
forcing sockets to perform a new route lookup and fail over to a
functioning nexthop.
Fixes: 51ebd3181572 ("ipv6: add support of equal cost multipath (ECMP)")
Signed-off-by: Sagarika Sharma <sharmasagarika@google.com>
Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
---
net/ipv6/route.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 19eb6b702227..0dc0316530ca 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -4995,6 +4995,7 @@ static int fib6_ifdown(struct fib6_info *rt, void *p_arg)
rt->fib6_flags & (RTF_LOCAL | RTF_ANYCAST))
break;
rt->fib6_nh->fib_nh_flags |= RTNH_F_LINKDOWN;
+ fib6_update_sernum(net, rt);
rt6_multipath_rebalance(rt);
break;
}
--
2.54.0.545.g6539524ca2-goog
^ permalink raw reply related
* [PATCH net v1 0/2] ipv6: fix ECMP route failover on carrier loss
From: Sagarika Sharma @ 2026-04-27 22:42 UTC (permalink / raw)
To: David S . Miller, David Ahern, Eric Dumazet, Jakub Kicinski,
Paolo Abeni
Cc: Shuah Khan, Simon Horman, Kuniyuki Iwashima, netdev,
linux-kselftest, Sagarika Sharma
This patchset resolves an issue where established IPv6 connections are
unable to transition to alternative ECMP nexthops upon carrier loss.
Unlike IPv4, the IPv6 routing subsystem does not actively invalidate
cached destinations during a NETDEV_CHANGE event. Sockets persist
with dead routes, leading to stalled traffic or connection drops.
This series introduces a fix to trigger route invalidation by
updating the route serial number on link carrier loss and provides
a corresponding selftest to validate the failover behavior for IPv4
and IPv6.
Kuniyuki Iwashima (1):
selftest: net: Add test for TCP flow failover with ECMP routes.
Sagarika Sharma (1):
ipv6: update route serial number on NETDEV_CHANGE
net/ipv6/route.c | 1 +
tools/testing/selftests/net/Makefile | 1 +
.../selftests/net/tcp_ecmp_failover.sh | 209 ++++++++++++++++++
3 files changed, 211 insertions(+)
create mode 100755 tools/testing/selftests/net/tcp_ecmp_failover.sh
--
2.54.0.545.g6539524ca2-goog
^ permalink raw reply
* Re: [PATCH v5 2/6] bpf: refactor masks for ADJ_ROOM flags and encap validation
From: Martin KaFai Lau @ 2026-04-27 22:40 UTC (permalink / raw)
To: Nick Hudson
Cc: bpf, netdev, Willem de Bruijn, Max Tottenham, Anna Glasgall,
Daniel Borkmann, Alexei Starovoitov, Andrii Nakryiko,
Eduard Zingerman, Kumar Kartikeya Dwivedi, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, linux-kernel
In-Reply-To: <20260420104051.1528843-3-nhudson@akamai.com>
On Mon, Apr 20, 2026 at 11:40:47AM +0100, Nick Hudson wrote:
> @@ -3618,8 +3623,8 @@ static int bpf_skb_net_shrink(struct sk_buff *skb, u32 off, u32 len_diff,
> {
> int ret;
>
> - if (unlikely(flags & ~(BPF_F_ADJ_ROOM_FIXED_GSO |
> - BPF_F_ADJ_ROOM_DECAP_L3_MASK |
> + if (unlikely(flags & ~(BPF_F_ADJ_ROOM_DECAP_MASK |
> + BPF_F_ADJ_ROOM_FIXED_GSO |
> BPF_F_ADJ_ROOM_NO_CSUM_RESET)))
It has conflict with a recent change. Please rebase with bpf-next/net.
pw-bot: cr
^ permalink raw reply
* Re: [syzbot] [lvs?] UBSAN: shift-out-of-bounds in ip_vs_rht_desired_size
From: Julian Anastasov @ 2026-04-27 22:37 UTC (permalink / raw)
To: syzbot
Cc: coreteam, davem, edumazet, fw, horms, kuba, linux-kernel,
lvs-devel, netdev, netfilter-devel, pabeni, pablo, phil,
syzkaller-bugs
In-Reply-To: <69ef9c80.050a0220.18b4f.0005.GAE@google.com>
Hello,
On Mon, 27 Apr 2026, syzbot wrote:
> Hello,
>
> syzbot found the following issue on:
>
> HEAD commit: e728258debd5 Merge tag 'net-7.1-rc1' of git://git.kernel.o..
> git tree: net-next
> console output: https://syzkaller.appspot.com/x/log.txt?x=169022ce580000
> kernel config: https://syzkaller.appspot.com/x/.config?x=ca77bfc4078c8193
> dashboard link: https://syzkaller.appspot.com/bug?extid=217f1db9c791e27fe54a
> compiler: Debian clang version 21.1.8 (++20251221033036+2078da43e25a-1~exp1~20251221153213.50), Debian LLD 21.1.8
>
> Unfortunately, I don't have any reproducer for this issue yet.
>
> Downloadable assets:
> disk image: https://storage.googleapis.com/syzbot-assets/24195bde5d1d/disk-e728258d.raw.xz
> vmlinux: https://storage.googleapis.com/syzbot-assets/78131d1b0e14/vmlinux-e728258d.xz
> kernel image: https://storage.googleapis.com/syzbot-assets/836d0dd78c10/bzImage-e728258d.xz
>
> IMPORTANT: if you fix the issue, please add the following tag to the commit:
> Reported-by: syzbot+217f1db9c791e27fe54a@syzkaller.appspotmail.com
>
> wlan0: No active IBSS STAs - trying to scan for other IBSS networks with same SSID (merge)
> ------------[ cut here ]------------
> UBSAN: shift-out-of-bounds in ./include/linux/log2.h:57:13
> shift exponent 64 is too large for 64-bit type 'unsigned long'
> CPU: 1 UID: 0 PID: 77 Comm: kworker/u8:4 Not tainted syzkaller #0 PREEMPT(full)
> Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 04/18/2026
> Workqueue: events_unbound conn_resize_work_handler
> Call Trace:
> <TASK>
> dump_stack_lvl+0xe8/0x150 lib/dump_stack.c:120
> ubsan_epilogue+0xa/0x30 lib/ubsan.c:233
> __ubsan_handle_shift_out_of_bounds+0x385/0x410 lib/ubsan.c:494
> __roundup_pow_of_two include/linux/log2.h:57 [inline]
Looks like roundup_pow_of_two() is called for 0.
Will provide fix for this...
> ip_vs_rht_desired_size+0x2cf/0x410 net/netfilter/ipvs/ip_vs_core.c:240
> ip_vs_conn_desired_size net/netfilter/ipvs/ip_vs_conn.c:765 [inline]
> conn_resize_work_handler+0x1b6/0x14c0 net/netfilter/ipvs/ip_vs_conn.c:822
> process_one_work kernel/workqueue.c:3302 [inline]
> process_scheduled_works+0xb5d/0x1860 kernel/workqueue.c:3385
> worker_thread+0xa53/0xfc0 kernel/workqueue.c:3466
> kthread+0x388/0x470 kernel/kthread.c:436
> ret_from_fork+0x514/0xb70 arch/x86/kernel/process.c:158
> ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245
> </TASK>
> ---[ end trace ]---
> Kernel panic - not syncing: UBSAN: panic_on_warn set ...
> CPU: 1 UID: 0 PID: 77 Comm: kworker/u8:4 Not tainted syzkaller #0 PREEMPT(full)
> Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 04/18/2026
> Workqueue: events_unbound conn_resize_work_handler
> Call Trace:
> <TASK>
> vpanic+0x56c/0xa60 kernel/panic.c:650
> panic+0xc5/0xd0 kernel/panic.c:787
> check_panic_on_warn+0x89/0xb0 kernel/panic.c:524
> __ubsan_handle_shift_out_of_bounds+0x385/0x410 lib/ubsan.c:494
> __roundup_pow_of_two include/linux/log2.h:57 [inline]
> ip_vs_rht_desired_size+0x2cf/0x410 net/netfilter/ipvs/ip_vs_core.c:240
> ip_vs_conn_desired_size net/netfilter/ipvs/ip_vs_conn.c:765 [inline]
> conn_resize_work_handler+0x1b6/0x14c0 net/netfilter/ipvs/ip_vs_conn.c:822
> process_one_work kernel/workqueue.c:3302 [inline]
> process_scheduled_works+0xb5d/0x1860 kernel/workqueue.c:3385
> worker_thread+0xa53/0xfc0 kernel/workqueue.c:3466
> kthread+0x388/0x470 kernel/kthread.c:436
> ret_from_fork+0x514/0xb70 arch/x86/kernel/process.c:158
> ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245
> </TASK>
> Kernel Offset: disabled
> Rebooting in 86400 seconds..
Regards
--
Julian Anastasov <ja@ssi.bg>
^ permalink raw reply
* Re: [PATCH v5 6/6] selftests/bpf: tc_tunnel validate decap GSO state
From: Martin KaFai Lau @ 2026-04-27 22:36 UTC (permalink / raw)
To: nhudson
Cc: bot+bpf-ci, bpf, netdev, willemb, ast, daniel, andrii, eddyz87,
memxor, shuah, linux-kselftest, linux-kernel, martin.lau,
yonghong.song, clm, ihor.solodrai
In-Reply-To: <2ea5cc41fd138e94dc34b1d4073833118b93ae48d802aabe480e355e27417b62@mail.kernel.org>
On Mon, Apr 20, 2026 at 11:19:30AM +0000, bot+bpf-ci@kernel.org wrote:
> > + if (!shinfo->gso_size)
> > + return TC_ACT_OK;
> > +
> > + if ((flags & BPF_F_ADJ_ROOM_DECAP_L4_UDP) &&
> > + (shinfo->gso_type & SKB_GSO_UDP_TUNNEL_MASK))
> > + return TC_ACT_SHOT;
> > +
> > + if ((flags & BPF_F_ADJ_ROOM_DECAP_L4_GRE) &&
> > + (shinfo->gso_type & (SKB_GSO_GRE | SKB_GSO_GRE_CSUM)))
> > + return TC_ACT_SHOT;
> > +
> > + if ((flags & BPF_F_ADJ_ROOM_DECAP_IPXIP4) &&
> > + (shinfo->gso_type & SKB_GSO_IPXIP4))
> > + return TC_ACT_SHOT;
> > +
> > + if ((flags & BPF_F_ADJ_ROOM_DECAP_IPXIP6) &&
> > + (shinfo->gso_type & SKB_GSO_IPXIP6))
> > + return TC_ACT_SHOT;
>
> Are these IPXIP4 and IPXIP6 checks reachable?
>
> Looking earlier in decap_internal(), for IPPROTO_IPIP and IPPROTO_IPV6
> cases, the function only sets BPF_F_ADJ_ROOM_DECAP_L3_IPV4 and
> BPF_F_ADJ_ROOM_DECAP_L3_IPV6 on the flags variable (around the protocol
> switch statement).
>
> Because BPF_F_ADJ_ROOM_DECAP_IPXIP4 and BPF_F_ADJ_ROOM_DECAP_IPXIP6 are
> never added to flags, wouldn't these validation checks always be skipped?
>
> Ref: https://lore.kernel.org/bpf/20260416124324.B0CE6C2BCAF@smtp.kernel.org/
This comment has been mentioned again. It seems legit. Please don't ignore
the review comment. Otherwise, it will be assumed that the solutions are
being worked on and patchwork will eventually archive the patches after
some time.
Also, there is a 'SYS(fail_close_ns_client, "ethtool -K veth1 tso off");'
in prog_tests/test_tc_tunnel.c. Is the shinfo->gso_type ever set?
What will break if tso is kept on?
^ permalink raw reply
* [Intel-wired-lan][PATCH net v3] idpf: fix xdp crash in soft reset error path
From: Joshua Hay @ 2026-04-27 22:44 UTC (permalink / raw)
To: intel-wired-lan
Cc: emil.s.tantilov, willemb, decot, anthony.l.nguyen,
przemyslaw.kitszel, aleksander.lobakin, netdev, kuba, stable,
Joshua Hay, Aleksandr Loktionov
From: Emil Tantilov <emil.s.tantilov@intel.com>
NULL pointer dereference is reported in cases where idpf_vport_open()
fails during soft reset:
./xdpsock -i <inf> -q -r -N
[ 3179.186687] idpf 0000:83:00.0: Failed to initialize queue ids for vport 0: -12
[ 3179.276739] BUG: kernel NULL pointer dereference, address: 0000000000000010
[ 3179.277636] #PF: supervisor read access in kernel mode
[ 3179.278470] #PF: error_code(0x0000) - not-present page
[ 3179.279285] PGD 0
[ 3179.280083] Oops: Oops: 0000 [#1] SMP NOPTI
...
[ 3179.283997] Workqueue: events xp_release_deferred
[ 3179.284770] RIP: 0010:idpf_find_rxq_vec+0x17/0x30 [idpf]
...
[ 3179.291937] Call Trace:
[ 3179.292392] <TASK>
[ 3179.292843] idpf_qp_switch+0x25/0x820 [idpf]
[ 3179.293325] idpf_xsk_pool_setup+0x7c/0x520 [idpf]
[ 3179.293803] idpf_xdp+0x59/0x240 [idpf]
[ 3179.294275] xp_disable_drv_zc+0x62/0xb0
[ 3179.294743] xp_clear_dev+0x40/0xb0
[ 3179.295198] xp_release_deferred+0x1f/0xa0
[ 3179.295648] process_one_work+0x226/0x730
[ 3179.296106] worker_thread+0x19e/0x340
[ 3179.296557] ? __pfx_worker_thread+0x10/0x10
[ 3179.297009] kthread+0xf4/0x130
[ 3179.297459] ? __pfx_kthread+0x10/0x10
[ 3179.297910] ret_from_fork+0x32c/0x410
[ 3179.298361] ? __pfx_kthread+0x10/0x10
[ 3179.298702] ret_from_fork_asm+0x1a/0x30
Fix the error handling of the soft reset in idpf_xdp_setup_prog() by
restoring the vport->xdp_prog to the old value. This avoids referencing
the orphaned prog that was copied to vport->xdp_prog in the soft reset
and prevents subsequent false positive by idpf_xdp_enabled(). Roll back
the number of queues as well. Also only call put on the program if the
soft reset was successful. Returning an error will trigger the core XDP
stack to handle the put otherwise.
Update the restart check in idpf_xsk_pool_setup() to use IDPF_VPORT_UP bit
instead of netif_running(). The idpf_vport_stop/start() calls will not
update the __LINK_STATE_START bit, making this test a false positive
should the soft reset fail.
Fixes: 3d57b2c00f09 ("idpf: add XSk pool initialization")
Cc: stable@vger.kernel.org
Signed-off-by: Emil Tantilov <emil.s.tantilov@intel.com>
Signed-off-by: Joshua Hay <joshua.a.hay@intel.com>
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
---
v3:
- call idpf_vport_adjust_qs in case of XDP soft reset failure to restore
previous queue configuration, including data queue config
- change idpf_vport_adjust_qs and idpf_vport_calc_total_qs return types
to void since they cannot fail
- only call bpf_prog_put if soft reset succeeds
---
drivers/net/ethernet/intel/idpf/idpf_lib.c | 4 +---
drivers/net/ethernet/intel/idpf/idpf_txrx.c | 12 ++++--------
drivers/net/ethernet/intel/idpf/idpf_txrx.h | 6 +++---
.../net/ethernet/intel/idpf/idpf_virtchnl.c | 19 ++++---------------
.../net/ethernet/intel/idpf/idpf_virtchnl.h | 4 ++--
drivers/net/ethernet/intel/idpf/xdp.c | 8 +++++---
drivers/net/ethernet/intel/idpf/xsk.c | 4 +++-
7 files changed, 22 insertions(+), 35 deletions(-)
diff --git a/drivers/net/ethernet/intel/idpf/idpf_lib.c b/drivers/net/ethernet/intel/idpf/idpf_lib.c
index cf966fe6c759..56198b417c97 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_lib.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_lib.c
@@ -2042,9 +2042,7 @@ int idpf_initiate_soft_reset(struct idpf_vport *vport,
/* Adjust resource parameters prior to reallocating resources */
switch (reset_cause) {
case IDPF_SR_Q_CHANGE:
- err = idpf_vport_adjust_qs(new_vport, new_rsrc);
- if (err)
- goto free_vport;
+ idpf_vport_adjust_qs(new_vport, new_rsrc);
break;
case IDPF_SR_Q_DESC_CHANGE:
/* Update queue parameters before allocating resources */
diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.c b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
index 4fc0bb14c5b1..4e0d31023123 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_txrx.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
@@ -1568,12 +1568,10 @@ void idpf_vport_calc_num_q_desc(struct idpf_vport *vport,
* @vport_idx: vport idx to retrieve vport pointer
* @vport_msg: message to fill with data
* @max_q: vport max queue info
- *
- * Return: 0 on success, error value on failure.
*/
-int idpf_vport_calc_total_qs(struct idpf_adapter *adapter, u16 vport_idx,
- struct virtchnl2_create_vport *vport_msg,
- struct idpf_vport_max_q *max_q)
+void idpf_vport_calc_total_qs(struct idpf_adapter *adapter, u16 vport_idx,
+ struct virtchnl2_create_vport *vport_msg,
+ struct idpf_vport_max_q *max_q)
{
int dflt_splitq_txq_grps = 0, dflt_singleq_txqs = 0;
int dflt_splitq_rxq_grps = 0, dflt_singleq_rxqs = 0;
@@ -1624,7 +1622,7 @@ int idpf_vport_calc_total_qs(struct idpf_adapter *adapter, u16 vport_idx,
}
if (!vport_config)
- return 0;
+ return;
user = &vport_config->user_config;
user->num_req_rx_qs = le16_to_cpu(vport_msg->num_rx_q);
@@ -1640,8 +1638,6 @@ int idpf_vport_calc_total_qs(struct idpf_adapter *adapter, u16 vport_idx,
vport_msg->num_tx_q = cpu_to_le16(user->num_req_tx_qs + num_xdpsq);
if (idpf_is_queue_model_split(le16_to_cpu(vport_msg->txq_model)))
vport_msg->num_tx_complq = vport_msg->num_tx_q;
-
- return 0;
}
/**
diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.h b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
index b6836e38f449..22c647d6dd5c 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_txrx.h
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
@@ -1084,9 +1084,9 @@ void idpf_vport_init_num_qs(struct idpf_vport *vport,
struct idpf_q_vec_rsrc *rsrc);
void idpf_vport_calc_num_q_desc(struct idpf_vport *vport,
struct idpf_q_vec_rsrc *rsrc);
-int idpf_vport_calc_total_qs(struct idpf_adapter *adapter, u16 vport_index,
- struct virtchnl2_create_vport *vport_msg,
- struct idpf_vport_max_q *max_q);
+void idpf_vport_calc_total_qs(struct idpf_adapter *adapter, u16 vport_index,
+ struct virtchnl2_create_vport *vport_msg,
+ struct idpf_vport_max_q *max_q);
void idpf_vport_calc_num_q_groups(struct idpf_q_vec_rsrc *rsrc);
int idpf_vport_queues_alloc(struct idpf_vport *vport,
struct idpf_q_vec_rsrc *rsrc);
diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
index be66f9b2e101..91af4f298475 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
@@ -1578,12 +1578,7 @@ int idpf_send_create_vport_msg(struct idpf_adapter *adapter,
else
vport_msg->rxq_model = cpu_to_le16(VIRTCHNL2_QUEUE_MODEL_SINGLE);
- err = idpf_vport_calc_total_qs(adapter, idx, vport_msg, max_q);
- if (err) {
- dev_err(&adapter->pdev->dev, "Enough queues are not available");
-
- return err;
- }
+ idpf_vport_calc_total_qs(adapter, idx, vport_msg, max_q);
if (!adapter->vport_params_recvd[idx]) {
adapter->vport_params_recvd[idx] = kzalloc(IDPF_CTLQ_MAX_BUF_LEN,
@@ -4065,24 +4060,18 @@ int idpf_vport_queue_ids_init(struct idpf_vport *vport,
* @vport: virtual port data struct
* @rsrc: pointer to queue and vector resources
*
- * Renegotiate queues. Returns 0 on success, negative on failure.
+ * Renegotiate queues.
*/
-int idpf_vport_adjust_qs(struct idpf_vport *vport, struct idpf_q_vec_rsrc *rsrc)
+void idpf_vport_adjust_qs(struct idpf_vport *vport, struct idpf_q_vec_rsrc *rsrc)
{
struct virtchnl2_create_vport vport_msg;
- int err;
vport_msg.txq_model = cpu_to_le16(rsrc->txq_model);
vport_msg.rxq_model = cpu_to_le16(rsrc->rxq_model);
- err = idpf_vport_calc_total_qs(vport->adapter, vport->idx, &vport_msg,
- NULL);
- if (err)
- return err;
+ idpf_vport_calc_total_qs(vport->adapter, vport->idx, &vport_msg, NULL);
idpf_vport_init_num_qs(vport, &vport_msg, rsrc);
idpf_vport_calc_num_q_groups(rsrc);
-
- return 0;
}
/**
diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h
index 6876e3ed9d1b..76d238fc660c 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h
+++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h
@@ -169,8 +169,8 @@ int idpf_send_destroy_vport_msg(struct idpf_adapter *adapter, u32 vport_id);
int idpf_send_enable_vport_msg(struct idpf_adapter *adapter, u32 vport_id);
int idpf_send_disable_vport_msg(struct idpf_adapter *adapter, u32 vport_id);
-int idpf_vport_adjust_qs(struct idpf_vport *vport,
- struct idpf_q_vec_rsrc *rsrc);
+void idpf_vport_adjust_qs(struct idpf_vport *vport,
+ struct idpf_q_vec_rsrc *rsrc);
int idpf_vport_alloc_max_qs(struct idpf_adapter *adapter,
struct idpf_vport_max_q *max_q);
void idpf_vport_dealloc_max_qs(struct idpf_adapter *adapter,
diff --git a/drivers/net/ethernet/intel/idpf/xdp.c b/drivers/net/ethernet/intel/idpf/xdp.c
index dcd867517a5f..f6e6b72169fd 100644
--- a/drivers/net/ethernet/intel/idpf/xdp.c
+++ b/drivers/net/ethernet/intel/idpf/xdp.c
@@ -488,11 +488,13 @@ static int idpf_xdp_setup_prog(struct idpf_vport *vport,
"Could not reopen the vport after XDP setup");
cfg->user_config.xdp_prog = old;
- old = prog;
- }
+ vport->xdp_prog = old;
- if (old)
+ /* Restore previous queue config */
+ idpf_vport_adjust_qs(vport, &vport->dflt_qv_rsrc);
+ } else if (old) {
bpf_prog_put(old);
+ }
libeth_xdp_set_redirect(vport->netdev, vport->xdp_prog);
diff --git a/drivers/net/ethernet/intel/idpf/xsk.c b/drivers/net/ethernet/intel/idpf/xsk.c
index d95d3efdfd36..3d8c430efd2b 100644
--- a/drivers/net/ethernet/intel/idpf/xsk.c
+++ b/drivers/net/ethernet/intel/idpf/xsk.c
@@ -553,6 +553,7 @@ int idpf_xskrq_poll(struct idpf_rx_queue *rxq, u32 budget)
int idpf_xsk_pool_setup(struct idpf_vport *vport, struct netdev_bpf *bpf)
{
+ const struct idpf_netdev_priv *np = netdev_priv(vport->netdev);
struct xsk_buff_pool *pool = bpf->xsk.pool;
u32 qid = bpf->xsk.queue_id;
bool restart;
@@ -568,7 +569,8 @@ int idpf_xsk_pool_setup(struct idpf_vport *vport, struct netdev_bpf *bpf)
return -EINVAL;
}
- restart = idpf_xdp_enabled(vport) && netif_running(vport->netdev);
+ restart = idpf_xdp_enabled(vport) &&
+ test_bit(IDPF_VPORT_UP, np->state);
if (!restart)
goto pool;
--
2.39.2
^ permalink raw reply related
* Re: [RFC PATCH v1 7/9] x86: Add unsafe_copy_from_user()
From: Yury Norov @ 2026-04-27 22:30 UTC (permalink / raw)
To: Linus Torvalds
Cc: Christophe Leroy (CS GROUP), Andrew Morton, David Laight,
Thomas Gleixner, linux-alpha, Yury Norov, linux-kernel,
linux-snps-arc, linux-arm-kernel, linux-mips, linuxppc-dev, kvm,
linux-riscv, linux-s390, sparclinux, linux-um, dmaengine,
linux-efi, linux-fsi, amd-gfx, dri-devel, intel-gfx, linux-wpan,
netdev, linux-wireless, linux-spi, linux-media, linux-staging,
linux-serial, linux-usb, xen-devel, linux-fsdevel, ocfs2-devel,
bpf, kasan-dev, linux-mm, linux-x25, rust-for-linux, linux-sound,
sound-open-firmware, linux-csky, linux-hexagon, loongarch,
linux-m68k, linux-openrisc, linux-parisc, linux-sh, linux-arch
In-Reply-To: <CAHk-=wgPrLy0FR3sEWBYQuNAac1axDASYMnTuPuxEU0WytzL7w@mail.gmail.com>
On Mon, Apr 27, 2026 at 02:52:05PM -0700, Linus Torvalds wrote:
> On Mon, 27 Apr 2026 at 12:19, Yury Norov <ynorov@nvidia.com> wrote:
> >
> > This is what Linus said when added x86 implementation for copy_from_user()
> > in c512c69187197:
>
> Note that some things have happily changed in the six+ years since...
>
> > That's partly because we have no current users of it, but also partly
> > because the copy_from_user() case is slightly different and cannot
> > efficiently be implemented in terms of a unsafe_get_user() loop (because
> > gcc can't do asm goto with outputs).
>
> now everybody can do asm goto with outputs.
>
> Yes, it's disabled on older versions, so it's not *always* available,
> but all modern versions do it. And if you care about performance, you
> won't be using an old compiler.
The minimal GCC version is 8.1, and asm goto with outputs is supported
since GCC-11. That would brake the build, if we just switch to using it
without "CC_IS_GCC && (GCC_VERSION >= 110100)" guard.
Is it worth to maintain 2 version of the function? I don't know...
Thanks,
Yury
^ permalink raw reply
* Re: [BUG] net: tcp: SO_LINGER with l_linger=0 leaks memory when closing sockets with pending send data
From: Ahmed, Aaron @ 2026-04-27 22:26 UTC (permalink / raw)
To: Kuniyuki Iwashima
Cc: stable@vger.kernel.org, netdev@vger.kernel.org,
ncardwell@google.com, edumazet@google.com
In-Reply-To: <CAAVpQUCfMsWBpPpywbwBLRCdHUqWqFBoDK=17dwDkG6T0dQxzw@mail.gmail.com>
Hi Kuniyuki!
Thanks for taking a look! To clarify the issue: the problem shows up on long-running servers
with many concurrent connections. The original reproducer exits
right after closing the sockets, so the memory gets cleaned up at
process exit. In production the server never exits, so the memory
just keeps growing. Is this expected behavior?
I've written an updated reproducer that models a persistent
server. You can pass 0 or 1 as an argument to set the l_linger value.
This outputs the following:
When l_linger=0:
TCP: inuse 7 orphan 0 tw 2 alloc 100009 mem 197259
When l_linger=1:
TCP: inuse 50008 orphan 0 tw 5 alloc 50009 mem 14426
With l_linger=0, only 7 sockets are in use but ~770 MB of TCP
memory has no owner. With l_linger=1, 50,008 sockets are in use
but only ~56 MB of memory.
Updated reproducer:
Build: gcc -O2 -pthread -o tcp_linger_memleak tcp_linger_memleak.c
Run: ulimit -n 100000
sudo sysctl -w net.core.wmem_max=4194304
sudo sysctl -w net.ipv4.tcp_rmem="4096 8192 16384"
./tcp_linger_memleak 0
./tcp_linger_memleak 1
---8<---
/* tcp_linger_memleak.c - SO_LINGER(0) TCP memory leak reproducer
*
* Build: gcc -O2 -pthread -o tcp_linger_memleak tcp_linger_memleak.c
* Run: ulimit -n 100000
* sudo sysctl -w net.core.wmem_max=4194304
* sudo sysctl -w net.ipv4.tcp_rmem="4096 8192 16384"
* ./tcp_linger_memleak [linger_sec]
* linger_sec=0 (default) -> leaks memory
* linger_sec=1 -> no leak
*
* Monitor: watch -n5 'cat /proc/net/sockstat; echo ---; free -m'
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <pthread.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#define PORT 6666
#define NUM_THREADS 8
#define MAX_CLIENTS 4096
#define NUM_CONNS 25000
#define WRITE_INTERVAL_MS 200
#define MSG_SIZE_MIN 128
#define MSG_SIZE_MAX 2046
#define CLIENT_RDBUF 10240
static int g_linger_sec = 0;
struct worker {
pthread_mutex_t lock;
int fds[MAX_CLIENTS];
int bufsz[MAX_CLIENTS];
int count;
int pipe_rd;
int pipe_wr;
};
static struct worker workers[NUM_THREADS];
static void *worker_thread(void *arg)
{
struct worker *w = (struct worker *)arg;
char buf[MSG_SIZE_MAX];
memset(buf, 'A', sizeof(buf));
while (1) {
char dummy;
if (read(w->pipe_rd, &dummy, 1) <= 0)
break;
pthread_mutex_lock(&w->lock);
int i = 0;
while (i < w->count) {
ssize_t n = send(w->fds[i], buf, w->bufsz[i],
MSG_NOSIGNAL);
if (n < 0) {
struct linger lg = {
.l_onoff = 1,
.l_linger = g_linger_sec
};
setsockopt(w->fds[i], SOL_SOCKET,
SO_LINGER, &lg, sizeof(lg));
close(w->fds[i]);
w->fds[i] = w->fds[w->count - 1];
w->bufsz[i] = w->bufsz[w->count - 1];
w->count--;
continue;
}
i++;
}
pthread_mutex_unlock(&w->lock);
}
return NULL;
}
static void *tick_thread(void *arg)
{
(void)arg;
while (1) {
usleep(WRITE_INTERVAL_MS * 1000);
for (int t = 0; t < NUM_THREADS; t++) {
char c = 1;
write(workers[t].pipe_wr, &c, 1);
}
}
return NULL;
}
static void run_client(void)
{
struct sockaddr_in addr = {
.sin_family = AF_INET,
.sin_port = htons(PORT),
};
int fds[NUM_CONNS];
char rdbuf[CLIENT_RDBUF];
inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr);
for (int i = 0; i < NUM_CONNS; i++) {
fds[i] = socket(AF_INET, SOCK_STREAM, 0);
if (fds[i] < 0) {
usleep(1000);
i--;
continue;
}
if (connect(fds[i], (struct sockaddr *)&addr,
sizeof(addr)) < 0) {
close(fds[i]);
usleep(1000);
i--;
continue;
}
int opt = 1;
setsockopt(fds[i], IPPROTO_TCP, TCP_NODELAY,
&opt, sizeof(opt));
if (i % 1000 == 0)
printf("Client: %d connections established\n", i);
usleep(100);
}
printf("Client: all %d connections established, reading slowly...\n",
NUM_CONNS);
while (1) {
for (int i = 0; i < NUM_CONNS; i++) {
if (fds[i] < 0)
continue;
ssize_t n = recv(fds[i], rdbuf, sizeof(rdbuf),
MSG_DONTWAIT);
if (n == 0 || (n < 0 && errno != EAGAIN &&
errno != EWOULDBLOCK)) {
close(fds[i]);
fds[i] = -1;
}
}
usleep(50000);
}
}
int main(int argc, char *argv[])
{
g_linger_sec = (argc > 1) ? atoi(argv[1]) : 0;
printf("SO_LINGER l_linger=%d\n", g_linger_sec);
printf("Monitor: watch -n5 'cat /proc/net/sockstat'\n\n");
signal(SIGPIPE, SIG_IGN);
for (int t = 0; t < NUM_THREADS; t++) {
int pfd[2];
pthread_t tid;
pthread_mutex_init(&workers[t].lock, NULL);
workers[t].count = 0;
pipe(pfd);
workers[t].pipe_rd = pfd[0];
workers[t].pipe_wr = pfd[1];
pthread_create(&tid, NULL, worker_thread, &workers[t]);
pthread_detach(tid);
}
pthread_t tick_tid;
pthread_create(&tick_tid, NULL, tick_thread, NULL);
pthread_detach(tick_tid);
pid_t child = fork();
if (child == 0) {
run_client();
_exit(0);
}
struct sockaddr_in addr = {
.sin_family = AF_INET,
.sin_port = htons(PORT),
.sin_addr.s_addr = htonl(INADDR_ANY)
};
int opt = 1;
int lsn = socket(AF_INET, SOCK_STREAM, 0);
setsockopt(lsn, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
bind(lsn, (struct sockaddr *)&addr, sizeof(addr));
listen(lsn, 4096);
int thread_idx = 0;
unsigned long accepted = 0;
while (1) {
int fd = accept(lsn, NULL, NULL);
if (fd < 0)
continue;
opt = 1;
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
&opt, sizeof(opt));
int flags = fcntl(fd, F_GETFL, 0);
fcntl(fd, F_SETFL, flags | O_NONBLOCK);
int sndbuf = 4 * 1024 * 1024;
setsockopt(fd, SOL_SOCKET, SO_SNDBUF,
&sndbuf, sizeof(sndbuf));
struct worker *w = &workers[thread_idx % NUM_THREADS];
pthread_mutex_lock(&w->lock);
if (w->count < MAX_CLIENTS) {
w->fds[w->count] = fd;
w->bufsz[w->count] = MSG_SIZE_MIN +
(rand() % (MSG_SIZE_MAX - MSG_SIZE_MIN));
w->count++;
} else {
close(fd);
}
pthread_mutex_unlock(&w->lock);
thread_idx++;
accepted++;
if (accepted % 5000 == 0)
printf("Server: accepted %lu connections\n",
accepted);
}
}
---8<---
Thanks,
Aaron
On 4/17/26, 5:45 PM, "Kuniyuki Iwashima" <kuniyu@google.com <mailto:kuniyu@google.com>> wrote:
CAUTION: This email originated from outside of the organization. Do not click links or open attachments unless you can confirm the sender and know the content is safe.
Hi Aaron :)
Thanks for the report.
On Fri, Apr 17, 2026 at 5:20 PM Ahmed, Aaron <aarnahmd@amazon.com <mailto:aarnahmd@amazon.com>> wrote:
>
> Hi,
>
> We have identified a TCP memory leak issue on Amazon Linux with kernel versions 5.15.168 through 6.18.20 that occurs when closing sockets with SO_LINGER set to l_onoff=1, l_linger=0, on servers handling many persistent connections with full write buffers.
>
> Overview:
>
> The issue was discovered on a public-facing non-blocking TCP server that maintains many persistent connections and streams data to clients. When a client cannot read fast enough, the TCP write socket buffer on the server side fills up and send() returns EAGAIN. At that point, the server application disconnects the slow client by setting SO_LINGER to l_onoff=1, l_linger=0 and calling close(). This is intended to immediately reset the connection and release all associated kernel resources. However, while the socket disappears from netstat and sockstat (TCP inuse drops), the write buffer memory is not properly reclaimed. /proc/net/sockstat shows TCP mem pages accumulating with no owning sockets, causing the leaked memory to grow past the tcp_mem limits. Setting SO_LINGER to l_onoff=1, l_linger=1 instead does not leak. With l_linger=1, the connection goes through FIN_WAIT1 → FIN_WAIT2 → CLOSE (confirmed with BPF tcpstates), and all memory is freed properly. With l_linger=0, the connection transitions directly from ESTABLISHED → CLOSE via RST, bypassing the FIN states entirely.
>
> Reproducer:
> ```
> /* tcp_linger_memleak.c - SO_LINGER(0) TCP memory leak reproducer
> *
> * Build: gcc -O2 -o tcp_linger_memleak tcp_linger_memleak.c
> * Run: sudo sysctl -w net.core.wmem_max=4194304
> * sudo sysctl -w net.ipv4.tcp_rmem="4096 8192 16384"
> * ./tcp_linger_memleak
> */
> #include <stdio.h>
> #include <stdlib.h>
> #include <string.h>
> #include <unistd.h>
> #include <errno.h>
> #include <fcntl.h>
> #include <signal.h>
> #include <sys/socket.h>
> #include <sys/wait.h>
> #include <netinet/in.h>
>
> #define NUM_CONNS 5000
> #define PORT 6666
>
> static void print_mem(const char *label) {
> FILE *f;
> char line[256];
> f = fopen("/proc/meminfo", "r");
> while (fgets(line, sizeof(line), f))
> if (strncmp(line, "MemAvailable:", 13) == 0)
> printf("%s: %s", label, line);
> fclose(f);
> f = fopen("/proc/net/sockstat", "r");
> while (fgets(line, sizeof(line), f))
> if (strncmp(line, "TCP:", 4) == 0)
> printf("%s: %s", label, line);
> fclose(f);
> }
>
> int main(void) {
> struct sockaddr_in addr = {
> .sin_family = AF_INET,
> .sin_port = htons(PORT),
> .sin_addr.s_addr = htonl(INADDR_LOOPBACK)
> };
> int opt = 1;
> signal(SIGPIPE, SIG_IGN);
>
> int lsn = socket(AF_INET, SOCK_STREAM, 0);
> setsockopt(lsn, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
> bind(lsn, (struct sockaddr *)&addr, sizeof(addr));
> listen(lsn, NUM_CONNS);
>
> /* Fork client: connect N times, never read */
> pid_t child = fork();
> if (child == 0) {
> int fds[NUM_CONNS];
> for (int i = 0; i < NUM_CONNS; i++) {
> fds[i] = socket(AF_INET, SOCK_STREAM, 0);
> connect(fds[i], (struct sockaddr *)&addr, sizeof(addr));
> }
> pause(); /* sit forever, never read */
> _exit(0);
> }
>
> /* Accept all connections */
> int clients[NUM_CONNS];
> for (int i = 0; i < NUM_CONNS; i++)
> clients[i] = accept(lsn, NULL, NULL);
>
> /* Freeze client so it stops reading */
> kill(child, SIGSTOP);
> printf("=== %d connections established, client frozen ===\n", NUM_CONNS);
> print_mem("BEFORE");
>
> /* Fill buffers and close with SO_LINGER(1,0) */
> char buf[2048];
> memset(buf, 'A', sizeof(buf));
> for (int i = 0; i < NUM_CONNS; i++) {
> int flags = fcntl(clients[i], F_GETFL, 0);
> fcntl(clients[i], F_SETFL, flags | O_NONBLOCK);
> while (send(clients[i], buf, sizeof(buf), MSG_NOSIGNAL) > 0);
> struct linger lg = { .l_onoff = 1, .l_linger = 0 };
> setsockopt(clients[i], SOL_SOCKET, SO_LINGER, &lg, sizeof(lg));
> close(clients[i]);
> }
>
> sleep(2);
> printf("\n=== All sockets closed with SO_LINGER(1,0) ===\n");
> print_mem("AFTER");
> kill(child, SIGKILL);
> waitpid(child, NULL, 0);
> close(lsn);
> return 0;
> }
> ```
> Output (Tested on 6.18.20):
> ```
> === 5000 connections established, client frozen ===
> BEFORE: MemAvailable: 95491288 kB
> BEFORE: TCP: inuse 10005 orphan 0 tw 5 alloc 10006 mem 0
>
> === All sockets closed with SO_LINGER(1,0) ===
> AFTER: MemAvailable: 95321800 kB
> AFTER: TCP: inuse 5 orphan 0 tw 5 alloc 5006 mem 8300
> ```
Unfortunately, it dies immediately on my end.
=== 5000 connections established, client frozen ===
Segmentation fault (core dumped) ./linux/tcp_linger
Did you see actual memory leak with kmemleak or is it
just the tcp_mem counter that is really leaked ?
# echo clear > /sys/kernel/debug/kmemleak
~ run repro ~
# echo scan > /sys/kernel/debug/kmemleak
^ permalink raw reply
* Re: [PATCH] dsa: b53: hide legacy gpiolib usage on non-mips
From: Florian Fainelli @ 2026-04-27 22:23 UTC (permalink / raw)
To: Arnd Bergmann, Florian Fainelli, Jonas Gorski, Andrew Lunn,
Vladimir Oltean, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Linus Walleij, Bartosz Golaszewski
Cc: Arnd Bergmann, Álvaro Fernández Rojas, Kyle Hendry,
netdev, linux-kernel, linux-gpio
In-Reply-To: <20260427143020.2800317-1-arnd@kernel.org>
On 4/27/26 07:30, Arnd Bergmann wrote:
> From: Arnd Bergmann <arnd@arndb.de>
>
> The MIPS bcm53xx platform still uses the legacy gpiolib interfaces based
> on gpio numbers, but other platforms do not.
>
> Hide these interfaces inside of the existing #ifdef block and use the
> modern interfaces in the common parts of the driver to allow building
> it when the gpio_set_value() is left out of the kernel.
>
> Reviewed-by: Jonas Gorski <jonas.gorski@gmail.com>
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Reviewed-by: Florian Fainelli <florian.fainelli@broadcom.com>
Small nit: subject should be prefix with "net: ", and a target tree,
like net-next. Since net-next is currently closed, you will have to
resubmit.
--
Florian
^ permalink raw reply
* Re: [PATCH v5 5/6] bpf: clear decap tunnel GSO state in skb_adjust_room
From: Martin KaFai Lau @ 2026-04-27 22:19 UTC (permalink / raw)
To: nhudson
Cc: bot+bpf-ci, bpf, netdev, willemb, mtottenh, aglasgal, ast, daniel,
andrii, eddyz87, memxor, davem, edumazet, kuba, pabeni,
linux-kernel, martin.lau, yonghong.song, clm, ihor.solodrai
In-Reply-To: <82df2b6834553e3f2da26e5ee1f1b880f8a1af073e6fd88894a4839c66b7b121@mail.kernel.org>
On Mon, Apr 20, 2026 at 11:19:31AM +0000, bot+bpf-ci@kernel.org wrote:
> > + if ((flags & BPF_F_ADJ_ROOM_DECAP_L4_UDP) &&
> > + (shinfo->gso_type & (SKB_GSO_UDP_TUNNEL |
> > + SKB_GSO_UDP_TUNNEL_CSUM)))
> > + shinfo->gso_type &= ~(SKB_GSO_UDP_TUNNEL |
> > + SKB_GSO_UDP_TUNNEL_CSUM);
> > + if ((flags & BPF_F_ADJ_ROOM_DECAP_L4_GRE) &&
> > + (shinfo->gso_type & (SKB_GSO_GRE | SKB_GSO_GRE_CSUM)))
> > + shinfo->gso_type &= ~(SKB_GSO_GRE |
> > + SKB_GSO_GRE_CSUM);
> > + if ((flags & BPF_F_ADJ_ROOM_DECAP_IPXIP4) &&
> > + (shinfo->gso_type & SKB_GSO_IPXIP4))
> > + shinfo->gso_type &= ~SKB_GSO_IPXIP4;
> > + if ((flags & BPF_F_ADJ_ROOM_DECAP_IPXIP6) &&
> > + (shinfo->gso_type & SKB_GSO_IPXIP6))
> > + shinfo->gso_type &= ~SKB_GSO_IPXIP6;
> > +
> > + /* Clear encapsulation flag only when no tunnel GSO flags remain */
> > + if (flags & (BPF_F_ADJ_ROOM_DECAP_L4_MASK |
> > + BPF_F_ADJ_ROOM_DECAP_IPXIP_MASK)) {
> > + if (!(shinfo->gso_type & (SKB_GSO_UDP_TUNNEL |
> > + SKB_GSO_UDP_TUNNEL_CSUM |
> > + SKB_GSO_GRE |
> > + SKB_GSO_GRE_CSUM |
> > + SKB_GSO_IPXIP4 |
> > + SKB_GSO_IPXIP6 |
> > + SKB_GSO_ESP)))
> > + if (skb->encapsulation)
> > + skb->encapsulation = 0;
> > + }
>
> All of this new GSO flag clearing logic is added inside the if (skb_is_gso(skb))
> block in bpf_skb_net_shrink(). Does this mean non-GSO packets bypass the
> decapsulation state clearing?
>
> BPF programs can call bpf_skb_adjust_room() to decapsulate non-GSO packets
> as well. If a non-GSO packet undergoes decapsulation with the tunnel headers
> stripped, but skb->encapsulation remains set, could this cause downstream
> network stack components to misinterpret the packet as still being
> encapsulated?
It has been asked multiple times by different AI review agents but has been
ignored afaik. Please reply/address it so they won't reiterate. From
a quick look, bpf_skb_net_grow() sets the encapsulation regardless
of skb_is_gso.
^ permalink raw reply
* Re: [PATCH iproute2] remove hamradio protocols
From: patchwork-bot+netdevbpf @ 2026-04-27 22:01 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: netdev
In-Reply-To: <20260424232427.792249-1-stephen@networkplumber.org>
Hello:
This patch was applied to iproute2/iproute2.git (main)
by Stephen Hemminger <stephen@networkplumber.org>:
On Fri, 24 Apr 2026 16:24:27 -0700 you wrote:
> The ax25, rose, and netrom have been removed upstream.
> Drop support for those protocols from iproute2.
>
> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
> ---
> Makefile | 9 ---
> include/uapi/linux/ax25.h | 117 --------------------------------------
> include/uapi/linux/rose.h | 91 -----------------------------
> include/utils.h | 6 --
> lib/ax25_ntop.c | 82 --------------------------
> lib/ll_addr.c | 6 --
> lib/netrom_ntop.c | 23 --------
> lib/rose_ntop.c | 56 ------------------
> 8 files changed, 390 deletions(-)
> delete mode 100644 include/uapi/linux/ax25.h
> delete mode 100644 include/uapi/linux/rose.h
> delete mode 100644 lib/ax25_ntop.c
> delete mode 100644 lib/netrom_ntop.c
> delete mode 100644 lib/rose_ntop.c
Here is the summary with links:
- [iproute2] remove hamradio protocols
https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/commit/?id=f46186fd0332
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* Re: [RFC PATCH v1 7/9] x86: Add unsafe_copy_from_user()
From: Linus Torvalds @ 2026-04-27 21:52 UTC (permalink / raw)
To: Yury Norov
Cc: Christophe Leroy (CS GROUP), Andrew Morton, David Laight,
Thomas Gleixner, linux-alpha, Yury Norov, linux-kernel,
linux-snps-arc, linux-arm-kernel, linux-mips, linuxppc-dev, kvm,
linux-riscv, linux-s390, sparclinux, linux-um, dmaengine,
linux-efi, linux-fsi, amd-gfx, dri-devel, intel-gfx, linux-wpan,
netdev, linux-wireless, linux-spi, linux-media, linux-staging,
linux-serial, linux-usb, xen-devel, linux-fsdevel, ocfs2-devel,
bpf, kasan-dev, linux-mm, linux-x25, rust-for-linux, linux-sound,
sound-open-firmware, linux-csky, linux-hexagon, loongarch,
linux-m68k, linux-openrisc, linux-parisc, linux-sh, linux-arch
In-Reply-To: <ae-2yLWSGnfeTvh1@yury>
On Mon, 27 Apr 2026 at 12:19, Yury Norov <ynorov@nvidia.com> wrote:
>
> This is what Linus said when added x86 implementation for copy_from_user()
> in c512c69187197:
Note that some things have happily changed in the six+ years since...
> That's partly because we have no current users of it, but also partly
> because the copy_from_user() case is slightly different and cannot
> efficiently be implemented in terms of a unsafe_get_user() loop (because
> gcc can't do asm goto with outputs).
now everybody can do asm goto with outputs.
Yes, it's disabled on older versions, so it's not *always* available,
but all modern versions do it. And if you care about performance, you
won't be using an old compiler.
Linus
^ permalink raw reply
* Re: [PATCH net-next v2] r8169: expose software counters through netdev qstats
From: Eric Joyner @ 2026-04-27 21:45 UTC (permalink / raw)
To: Gustavo Arantes, Heiner Kallweit, nic_swsd
Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Javen Xu, netdev, linux-kernel
In-Reply-To: <20260427205931.5884-1-dev.gustavoa@gmail.com>
On 4/27/2026 1:59 PM, Gustavo Arantes wrote:
> r8169 maintains synchronized per-CPU software counters for packet and
> byte accounting and exposes them through ndo_get_stats64(), but
> userspace using the structured netdev qstats API cannot retrieve them from
> this driver.
>
> Expose the same counters through netdev_stat_ops. r8169 has a single Rx
> and Tx queue, so report the accumulated counters on queue 0. Use zero
> base stats so device-scope qstats are derived from the queue counters
> and match the packet and byte values reported through RTNL.
>
> This does not add new accounting and does not touch the data path. It
> only makes the existing counters available through the common qstats
> interface, which lets generic userspace tooling query r8169 the same way
> it queries other drivers with qstats support.
>
> Signed-off-by: Gustavo Arantes <dev.gustavoa@gmail.com>
> ---
> v2:
> - Submit again now that net-next has reopened.
> - Expand commit message to explain the qstats userspace benefit.
>
> Tested on a Realtek RTL8111/8168/8211/8411 PCIe Gigabit Ethernet
> controller using the r8169 driver.
>
> v1: https://lore.kernel.org/netdev/20260418021232.5425-1-dev.gustavoa@gmail.com/
>
> drivers/net/ethernet/realtek/r8169_main.c | 70 +++++++++++++++++++++++
> 1 file changed, 70 insertions(+)
>
> diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c
> index 791277e750ba..9d833b446383 100644
> --- a/drivers/net/ethernet/realtek/r8169_main.c
> +++ b/drivers/net/ethernet/realtek/r8169_main.c
> @@ -5175,6 +5175,75 @@ rtl8169_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
> pm_runtime_put_noidle(&pdev->dev);
> }
>
> +static void rtl8169_fetch_sw_stats(struct net_device *dev,
> + struct netdev_queue_stats_rx *rx,
> + struct netdev_queue_stats_tx *tx)
> +{
> + const struct pcpu_sw_netstats *stats;
> + unsigned int start;
> + int cpu;
> +
> + for_each_possible_cpu(cpu) {
> + u64 rx_packets, rx_bytes, tx_packets, tx_bytes;
> +
> + stats = per_cpu_ptr(dev->tstats, cpu);
> + do {
> + start = u64_stats_fetch_begin(&stats->syncp);
> + rx_packets = u64_stats_read(&stats->rx_packets);
> + rx_bytes = u64_stats_read(&stats->rx_bytes);
> + tx_packets = u64_stats_read(&stats->tx_packets);
> + tx_bytes = u64_stats_read(&stats->tx_bytes);
> + } while (u64_stats_fetch_retry(&stats->syncp, start));
> +
> + rx->packets += rx_packets;
> + rx->bytes += rx_bytes;
> + tx->packets += tx_packets;
> + tx->bytes += tx_bytes;
> + }
> +}
> +
> +static void rtl8169_get_queue_stats_rx(struct net_device *dev, int idx,
> + struct netdev_queue_stats_rx *rx)
> +{
> + struct netdev_queue_stats_tx tx = {};
> +
> + if (idx)
> + return;
> +
> + rx->packets = 0;
> + rx->bytes = 0;
> + rtl8169_fetch_sw_stats(dev, rx, &tx);
> +}
> +
> +static void rtl8169_get_queue_stats_tx(struct net_device *dev, int idx,
> + struct netdev_queue_stats_tx *tx)
> +{
> + struct netdev_queue_stats_rx rx = {};
> +
> + if (idx)
> + return;
> +
> + tx->packets = 0;
> + tx->bytes = 0;
> + rtl8169_fetch_sw_stats(dev, &rx, tx);
> +}
> +
> +static void rtl8169_get_base_stats(struct net_device *dev,
> + struct netdev_queue_stats_rx *rx,
> + struct netdev_queue_stats_tx *tx)
> +{
> + rx->packets = 0;
> + rx->bytes = 0;
> + tx->packets = 0;
> + tx->bytes = 0;
> +}
> +
> +static const struct netdev_stat_ops rtl8169_stat_ops = {
> + .get_queue_stats_rx = rtl8169_get_queue_stats_rx,
> + .get_queue_stats_tx = rtl8169_get_queue_stats_tx,
> + .get_base_stats = rtl8169_get_base_stats,
> +};
> +
> static void rtl8169_net_suspend(struct rtl8169_private *tp)
> {
> netif_device_detach(tp->dev);
> @@ -5615,6 +5684,7 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
>
> SET_NETDEV_DEV(dev, &pdev->dev);
> dev->netdev_ops = &rtl_netdev_ops;
> + dev->stat_ops = &rtl8169_stat_ops;
> tp = netdev_priv(dev);
> tp->dev = dev;
> tp->pci_dev = pdev;
> --
> 2.54.0
>
The comment for struct netdev_stat_ops says:
> * Device drivers are encouraged to reset the per-queue statistics when
> * number of queues change. This is because the primary use case for
> * per-queue statistics is currently to detect traffic imbalance.
But the commit message says there's only one Tx/Rx queue. Then that makes
this patch nonsensical? What is this actually for?
- Eric
^ permalink raw reply
* [PATCH v2 9/9] ptp: switch to using FIELD_GET_SIGNED()
From: Yury Norov @ 2026-04-27 21:41 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
H. Peter Anvin, Andy Lutomirski, Peter Zijlstra, Jonathan Cameron,
David Lechner, Johannes Berg, David Laight, Nuno Sá,
Andy Shevchenko, Ping-Ke Shih, Richard Cochran, Andrew Lunn,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Alexandre Belloni, Yury Norov, Rasmus Villemoes, Hans de Goede,
Linus Walleij, Sakari Ailus, Salah Triki, Achim Gratz,
Ben Collins, x86, linux-kernel, linux-iio, linux-wireless, netdev,
linux-rtc
Cc: Yury Norov
In-Reply-To: <20260427214127.406067-1-ynorov@nvidia.com>
Switch from sign_extend32(FIELD_GET()) to the dedicated
FIELD_GET_SIGNED() and don't calculate the fields length explicitly.
Signed-off-by: Yury Norov <ynorov@nvidia.com>
---
drivers/ptp/ptp_fc3.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/ptp/ptp_fc3.c b/drivers/ptp/ptp_fc3.c
index 70002500170e..f0e000428a3f 100644
--- a/drivers/ptp/ptp_fc3.c
+++ b/drivers/ptp/ptp_fc3.c
@@ -55,8 +55,8 @@ static s64 tdc_meas2offset(struct idtfc3 *idtfc3, u64 meas_read)
{
s64 coarse, fine;
- fine = sign_extend64(FIELD_GET(FINE_MEAS_MASK, meas_read), 12);
- coarse = sign_extend64(FIELD_GET(COARSE_MEAS_MASK, meas_read), (39 - 13));
+ fine = FIELD_GET_SIGNED(FINE_MEAS_MASK, meas_read);
+ coarse = FIELD_GET_SIGNED(COARSE_MEAS_MASK, meas_read);
fine = div64_s64(fine * NSEC_PER_SEC, idtfc3->tdc_apll_freq * 62LL);
coarse = div64_s64(coarse * NSEC_PER_SEC, idtfc3->time_ref_freq);
--
2.51.0
^ permalink raw reply related
* [PATCH v2 8/9] rtc: rv3032: switch to using FIELD_GET_SIGNED()
From: Yury Norov @ 2026-04-27 21:41 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
H. Peter Anvin, Andy Lutomirski, Peter Zijlstra, Jonathan Cameron,
David Lechner, Johannes Berg, David Laight, Nuno Sá,
Andy Shevchenko, Ping-Ke Shih, Richard Cochran, Andrew Lunn,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Alexandre Belloni, Yury Norov, Rasmus Villemoes, Hans de Goede,
Linus Walleij, Sakari Ailus, Salah Triki, Achim Gratz,
Ben Collins, x86, linux-kernel, linux-iio, linux-wireless, netdev,
linux-rtc
Cc: Yury Norov
In-Reply-To: <20260427214127.406067-1-ynorov@nvidia.com>
Switch from sign_extend32(FIELD_GET()) to the dedicated
FIELD_GET_SIGNED() and don't calculate the fields length explicitly.
Signed-off-by: Yury Norov <ynorov@nvidia.com>
---
drivers/rtc/rtc-rv3032.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/rtc/rtc-rv3032.c b/drivers/rtc/rtc-rv3032.c
index 6c09da7738e1..6bafdec637ae 100644
--- a/drivers/rtc/rtc-rv3032.c
+++ b/drivers/rtc/rtc-rv3032.c
@@ -376,7 +376,7 @@ static int rv3032_read_offset(struct device *dev, long *offset)
if (ret < 0)
return ret;
- steps = sign_extend32(FIELD_GET(RV3032_OFFSET_MSK, value), 5);
+ steps = FIELD_GET_SIGNED(RV3032_OFFSET_MSK, value);
*offset = DIV_ROUND_CLOSEST(steps * OFFSET_STEP_PPT, 1000);
--
2.51.0
^ permalink raw reply related
* [PATCH v2 7/9] wifi: rtw89: switch to using FIELD_GET_SIGNED()
From: Yury Norov @ 2026-04-27 21:41 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
H. Peter Anvin, Andy Lutomirski, Peter Zijlstra, Jonathan Cameron,
David Lechner, Johannes Berg, David Laight, Nuno Sá,
Andy Shevchenko, Ping-Ke Shih, Richard Cochran, Andrew Lunn,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Alexandre Belloni, Yury Norov, Rasmus Villemoes, Hans de Goede,
Linus Walleij, Sakari Ailus, Salah Triki, Achim Gratz,
Ben Collins, x86, linux-kernel, linux-iio, linux-wireless, netdev,
linux-rtc
Cc: Yury Norov
In-Reply-To: <20260427214127.406067-1-ynorov@nvidia.com>
Switch from sign_extend32(FIELD_GET()) to the dedicated
FIELD_GET_SIGNED() and don't calculate the fields length explicitly.
Signed-off-by: Yury Norov <ynorov@nvidia.com>
---
drivers/net/wireless/realtek/rtw89/rtw8852a_rfk.c | 4 ++--
drivers/net/wireless/realtek/rtw89/rtw8852b_common.c | 4 ++--
drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.c | 4 ++--
drivers/net/wireless/realtek/rtw89/rtw8852c.c | 4 ++--
4 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8852a_rfk.c
index 463399413318..8679b21fd3fd 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852a_rfk.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852a_rfk.c
@@ -334,8 +334,8 @@ static void _check_addc(struct rtw89_dev *rtwdev, enum rtw89_rf_path path)
for (i = 0; i < ADDC_T_AVG; i++) {
tmp = rtw89_phy_read32_mask(rtwdev, R_DBG32_D, MASKDWORD);
- dc_re += sign_extend32(FIELD_GET(0xfff000, tmp), 11);
- dc_im += sign_extend32(FIELD_GET(0xfff, tmp), 11);
+ dc_re += FIELD_GET_SIGNED(0xfff000, tmp);
+ dc_im += FIELD_GET_SIGNED(0xfff, tmp);
}
dc_re /= ADDC_T_AVG;
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c b/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c
index 65b839323e3e..df5fbae50ff5 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c
@@ -206,9 +206,9 @@ static void rtw8852bx_efuse_parsing_tssi(struct rtw89_dev *rtwdev,
static bool _decode_efuse_gain(u8 data, s8 *high, s8 *low)
{
if (high)
- *high = sign_extend32(FIELD_GET(GENMASK(7, 4), data), 3);
+ *high = FIELD_GET_SIGNED(GENMASK(7, 4), data);
if (low)
- *low = sign_extend32(FIELD_GET(GENMASK(3, 0), data), 3);
+ *low = FIELD_GET_SIGNED(GENMASK(3, 0), data);
return data != 0xff;
}
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.c
index 70b1515c00fa..8db6ea475128 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.c
@@ -497,8 +497,8 @@ static void _check_addc(struct rtw89_dev *rtwdev, enum rtw89_rf_path path)
for (i = 0; i < ADDC_T_AVG; i++) {
tmp = rtw89_phy_read32_mask(rtwdev, R_DBG32_D, MASKDWORD);
- dc_re += sign_extend32(FIELD_GET(0xfff000, tmp), 11);
- dc_im += sign_extend32(FIELD_GET(0xfff, tmp), 11);
+ dc_re += FIELD_GET_SIGNED(0xfff000, tmp);
+ dc_im += FIELD_GET_SIGNED(0xfff, tmp);
}
dc_re /= ADDC_T_AVG;
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c
index 40db7e3c0d97..32eecd184b7c 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c
@@ -517,9 +517,9 @@ static void rtw8852c_efuse_parsing_tssi(struct rtw89_dev *rtwdev,
static bool _decode_efuse_gain(u8 data, s8 *high, s8 *low)
{
if (high)
- *high = sign_extend32(FIELD_GET(GENMASK(7, 4), data), 3);
+ *high = FIELD_GET_SIGNED(GENMASK(7, 4), data);
if (low)
- *low = sign_extend32(FIELD_GET(GENMASK(3, 0), data), 3);
+ *low = FIELD_GET_SIGNED(GENMASK(3, 0), data);
return data != 0xff;
}
--
2.51.0
^ permalink raw reply related
* [PATCH v2 6/9] iio: mcp9600: switch to using FIELD_GET_SIGNED()
From: Yury Norov @ 2026-04-27 21:41 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
H. Peter Anvin, Andy Lutomirski, Peter Zijlstra, Jonathan Cameron,
David Lechner, Johannes Berg, David Laight, Nuno Sá,
Andy Shevchenko, Ping-Ke Shih, Richard Cochran, Andrew Lunn,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Alexandre Belloni, Yury Norov, Rasmus Villemoes, Hans de Goede,
Linus Walleij, Sakari Ailus, Salah Triki, Achim Gratz,
Ben Collins, x86, linux-kernel, linux-iio, linux-wireless, netdev,
linux-rtc
Cc: Yury Norov
In-Reply-To: <20260427214127.406067-1-ynorov@nvidia.com>
Switch from sign_extend32(FIELD_GET()) to the dedicated
FIELD_GET_SIGNED() and don't calculate the fields length explicitly.
Acked-by: Jonathan Cameron <jic23@kernel.org>
Signed-off-by: Yury Norov <ynorov@nvidia.com>
---
drivers/iio/temperature/mcp9600.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/iio/temperature/mcp9600.c b/drivers/iio/temperature/mcp9600.c
index aa42c2b1a369..69baf654c9c0 100644
--- a/drivers/iio/temperature/mcp9600.c
+++ b/drivers/iio/temperature/mcp9600.c
@@ -297,7 +297,7 @@ static int mcp9600_read_thresh(struct iio_dev *indio_dev,
* Temperature is stored in two’s complement format in
* bits(15:2), LSB is 0.25 degree celsius.
*/
- *val = sign_extend32(FIELD_GET(MCP9600_ALERT_LIMIT_MASK, ret), 13);
+ *val = FIELD_GET_SIGNED(MCP9600_ALERT_LIMIT_MASK, ret);
*val2 = 4;
return IIO_VAL_FRACTIONAL;
case IIO_EV_INFO_HYSTERESIS:
--
2.51.0
^ permalink raw reply related
* [PATCH v2 5/9] iio: pressure: bmp280: switch to using FIELD_GET_SIGNED()
From: Yury Norov @ 2026-04-27 21:41 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
H. Peter Anvin, Andy Lutomirski, Peter Zijlstra, Jonathan Cameron,
David Lechner, Johannes Berg, David Laight, Nuno Sá,
Andy Shevchenko, Ping-Ke Shih, Richard Cochran, Andrew Lunn,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Alexandre Belloni, Yury Norov, Rasmus Villemoes, Hans de Goede,
Linus Walleij, Sakari Ailus, Salah Triki, Achim Gratz,
Ben Collins, x86, linux-kernel, linux-iio, linux-wireless, netdev,
linux-rtc
Cc: Yury Norov
In-Reply-To: <20260427214127.406067-1-ynorov@nvidia.com>
Switch from sign_extend32(FIELD_GET()) to the dedicated
FIELD_GET_SIGNED() and don't calculate the fields length explicitly.
Acked-by: Jonathan Cameron <jic23@kernel.org>
Signed-off-by: Yury Norov <ynorov@nvidia.com>
---
drivers/iio/pressure/bmp280-core.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c
index d983ce9c0b99..f722aea16e0e 100644
--- a/drivers/iio/pressure/bmp280-core.c
+++ b/drivers/iio/pressure/bmp280-core.c
@@ -392,7 +392,7 @@ static int bme280_read_calib(struct bmp280_data *data)
h4_lower = FIELD_GET(BME280_COMP_H4_MASK_LOW, tmp_1);
calib->H4 = sign_extend32(h4_upper | h4_lower, 11);
tmp_3 = get_unaligned_le16(&data->bme280_humid_cal_buf[H5]);
- calib->H5 = sign_extend32(FIELD_GET(BME280_COMP_H5_MASK, tmp_3), 11);
+ calib->H5 = FIELD_GET_SIGNED(BME280_COMP_H5_MASK, tmp_3);
calib->H6 = data->bme280_humid_cal_buf[H6];
return 0;
--
2.51.0
^ permalink raw reply related
* [PATCH v2 4/9] iio: magnetometer: yas530: switch to using FIELD_GET_SIGNED()
From: Yury Norov @ 2026-04-27 21:41 UTC (permalink / raw)
To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
H. Peter Anvin, Andy Lutomirski, Peter Zijlstra, Jonathan Cameron,
David Lechner, Johannes Berg, David Laight, Nuno Sá,
Andy Shevchenko, Ping-Ke Shih, Richard Cochran, Andrew Lunn,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Alexandre Belloni, Yury Norov, Rasmus Villemoes, Hans de Goede,
Linus Walleij, Sakari Ailus, Salah Triki, Achim Gratz,
Ben Collins, x86, linux-kernel, linux-iio, linux-wireless, netdev,
linux-rtc
Cc: Yury Norov
In-Reply-To: <20260427214127.406067-1-ynorov@nvidia.com>
Switch from sign_extend32(FIELD_GET()) to the dedicated
FIELD_GET_SIGNED() and don't calculate the fields length explicitly.
Reviewed-by: Linus Walleij <linusw@kernel.org>
Acked-by: Jonathan Cameron <jic23@kernel.org>
Signed-off-by: Yury Norov <ynorov@nvidia.com>
---
drivers/iio/magnetometer/yamaha-yas530.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/iio/magnetometer/yamaha-yas530.c b/drivers/iio/magnetometer/yamaha-yas530.c
index d49e37edcbed..6a80042602c6 100644
--- a/drivers/iio/magnetometer/yamaha-yas530.c
+++ b/drivers/iio/magnetometer/yamaha-yas530.c
@@ -859,9 +859,9 @@ static int yas530_get_calibration_data(struct yas5xx *yas5xx)
c->f[0] = FIELD_GET(GENMASK(22, 21), val);
c->f[1] = FIELD_GET(GENMASK(14, 13), val);
c->f[2] = FIELD_GET(GENMASK(6, 5), val);
- c->r[0] = sign_extend32(FIELD_GET(GENMASK(28, 23), val), 5);
- c->r[1] = sign_extend32(FIELD_GET(GENMASK(20, 15), val), 5);
- c->r[2] = sign_extend32(FIELD_GET(GENMASK(12, 7), val), 5);
+ c->r[0] = FIELD_GET_SIGNED(GENMASK(28, 23), val);
+ c->r[1] = FIELD_GET_SIGNED(GENMASK(20, 15), val);
+ c->r[2] = FIELD_GET_SIGNED(GENMASK(12, 7), val);
return 0;
}
@@ -914,9 +914,9 @@ static int yas532_get_calibration_data(struct yas5xx *yas5xx)
c->f[0] = FIELD_GET(GENMASK(24, 23), val);
c->f[1] = FIELD_GET(GENMASK(16, 15), val);
c->f[2] = FIELD_GET(GENMASK(8, 7), val);
- c->r[0] = sign_extend32(FIELD_GET(GENMASK(30, 25), val), 5);
- c->r[1] = sign_extend32(FIELD_GET(GENMASK(22, 17), val), 5);
- c->r[2] = sign_extend32(FIELD_GET(GENMASK(14, 7), val), 5);
+ c->r[0] = FIELD_GET_SIGNED(GENMASK(30, 25), val);
+ c->r[1] = FIELD_GET_SIGNED(GENMASK(22, 17), val);
+ c->r[2] = FIELD_GET_SIGNED(GENMASK(14, 7), val);
return 0;
}
--
2.51.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