* Re: [PATCH net-next 4/5] crypto: fcrypt - Remove support for FCrypt block cipher
From: Geert Uytterhoeven @ 2026-04-28 10:03 UTC (permalink / raw)
To: Eric Biggers
Cc: netdev, linux-afs, David Howells, Marc Dionne, linux-crypto,
linux-kernel, David S . Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman
In-Reply-To: <20260428024400.123337-5-ebiggers@kernel.org>
On Tue, 28 Apr 2026 at 04:49, Eric Biggers <ebiggers@kernel.org> wrote:
> Remove the insecure FCrypt block cipher from the crypto API. Its only
> user was net/rxrpc/, but now net/rxrpc/ implements it locally. The
> crypto API implementation is no longer needed.
>
> For some additional context: FCrypt was designed in 1988 and is
> essentially a weakened version of DES. It has the same 56-bit key size
> as DES, which is easily brute forced. Moreover, it's cryptographically
> weak and doesn't even provide the intended 56-bit security level. Its
> author considers it to be a mistake, as well
> (https://lists.openafs.org/pipermail/openafs-devel/2000-December/005320.html).
>
> But fortunately this 1980s-era homebrew block cipher was never adopted
> outside of net/rxrpc/. So its code can just be kept there.
>
> Signed-off-by: Eric Biggers <ebiggers@kernel.org>
> arch/m68k/configs/amiga_defconfig | 1 -
> arch/m68k/configs/apollo_defconfig | 1 -
> arch/m68k/configs/atari_defconfig | 1 -
> arch/m68k/configs/bvme6000_defconfig | 1 -
> arch/m68k/configs/hp300_defconfig | 1 -
> arch/m68k/configs/mac_defconfig | 1 -
> arch/m68k/configs/multi_defconfig | 1 -
> arch/m68k/configs/mvme147_defconfig | 1 -
> arch/m68k/configs/mvme16x_defconfig | 1 -
> arch/m68k/configs/q40_defconfig | 1 -
> arch/m68k/configs/sun3_defconfig | 1 -
> arch/m68k/configs/sun3x_defconfig | 1 -
Acked-by: Geert Uytterhoeven <geert@linux-m68k.org> # m68k
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply
* Re: [PATCH net] netfilter: nf_nat: avoid invalid nat_net pointer use on failed nf_nat_init()
From: Pablo Neira Ayuso @ 2026-04-28 10:01 UTC (permalink / raw)
To: Mathias Krause; +Cc: netfilter-devel, Florian Westphal, netdev
In-Reply-To: <20260428090917.3851366-1-minipli@grsecurity.net>
On Tue, Apr 28, 2026 at 11:09:17AM +0200, Mathias Krause wrote:
> We ran into below KASAN splat, which is mostly uninteresting, beside
> for having nf_nat_register_fn() in the call chain as a cause for the
> offending access:
>
> ==================================================================
> BUG: KASAN: slab-out-of-bounds in nf_nat_register_fn+0x5f9/0x640
> Read of size 8 at addr ffff890031e54c20 by task iptables/9510
>
> CPU: 0 UID: 0 PID: 9510 Comm: iptables Not tainted 6.18.18-grsec-full-20260320181326 #1 PREEMPT(voluntary)
> Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
> Call Trace:
> <TASK>
> […] dump_stack_lvl+0xee/0x160 ffff88004117eeb8
> […] print_report+0x6e/0x640 ffff88004117eee0
> […] ? __phys_addr+0x8e/0x140 ffff88004117eef0
> […] ? kasan_addr_to_slab+0x51/0xe0 ffff88004117ef08
> […] ? complete_report_info+0xec/0x1c0 ffff88004117ef20
> […] ? nf_nat_register_fn+0x5f9/0x640 ffff88004117ef48
> […] kasan_report+0xbc/0x140 ffff88004117ef50
> […] ? nf_nat_register_fn+0x5f9/0x640 ffff88004117ef90
> […] nf_nat_register_fn+0x5f9/0x640 ffff88004117eff8
> […] ? nf_nat_icmp_reply_translation+0x6e0/0x6e0 ffff88004117f070
> […] nf_tables_register_hook.part.0+0xa0/0x220 ffff88004117f080
> […] nf_tables_addchain.constprop.0+0x1054/0x1fc0 ffff88004117f0b8
> […] ? nft_chain_lookup.part.0+0x4ce/0xac0 ffff88004117f130
> […] ? nf_tables_abort+0x3d80/0x3d80 ffff88004117f190
> […] ? nf_tables_dumpreset_obj+0x100/0x100 ffff88004117f1c8
> […] ? nft_table_lookup.part.0+0x255/0x300 ffff88004117f310
> […] ? nf_tables_newchain+0x21a4/0x2fa0 ffff88004117f358
> […] nf_tables_newchain+0x21a4/0x2fa0 ffff88004117f360
> […] ? nf_tables_addchain.constprop.0+0x1fc0/0x1fc0 ffff88004117f458
> […] ? nla_get_range_signed+0x4a0/0x4a0 ffff88004117f488
> […] ? lock_acquire+0x16f/0x320 ffff88004117f490
> […] ? find_held_lock+0x3b/0xe0 ffff88004117f4b0
> […] ? __nla_parse+0x45/0x80 ffff88004117f500
> […] nfnetlink_rcv_batch+0xbca/0x19a0 ffff88004117f550
> […] ? nfnetlink_net_exit_batch+0x120/0x120 ffff88004117f618
> […] ? __sanitizer_cov_trace_switch+0x63/0xe0 ffff88004117f720
> […] ? gr_acl_handle_mmap+0x1c4/0x320 ffff88004117f7c0
> […] ? nla_get_range_signed+0x4a0/0x4a0 ffff88004117f7e8
> […] ? gr_is_capable+0x6f/0xe0 ffff88004117f830
> […] ? __nla_parse+0x45/0x80 ffff88004117f860
> […] ? skb_pull+0x103/0x1a0 ffff88004117f880
> […] nfnetlink_rcv+0x3db/0x4a0 ffff88004117f8b0
> […] ? nfnetlink_rcv_batch+0x19a0/0x19a0 ffff88004117f8d8
> […] ? netlink_lookup+0xe2/0x240 ffff88004117f900
> […] netlink_unicast+0x74b/0xb00 ffff88004117f930
> […] ? netlink_attachskb+0xb20/0xb20 ffff88004117f980
> […] ? __check_object_size+0x3e/0xaa0 ffff88004117f998
> […] ? security_netlink_send+0x51/0x160 ffff88004117f9c8
> […] netlink_sendmsg+0xa03/0x1200 ffff88004117f9f8
> […] ? netlink_unicast+0xb00/0xb00 ffff88004117fa70
> […] ? netlink_unicast+0xb00/0xb00 ffff88004117fac8
> […] ? ____sys_sendmsg+0xe2a/0x1040 ffff88004117faf8
> […] ____sys_sendmsg+0xe2a/0x1040 ffff88004117fb00
> […] ? kernel_recvmsg+0x300/0x300 ffff88004117fb60
> […] ? reacquire_held_locks+0xe9/0x260 ffff88004117fbc8
> […] ___sys_sendmsg+0x138/0x200 ffff88004117fbf8
> […] ? do_recvmmsg+0x7e0/0x7e0 ffff88004117fc30
> […] ? lockdep_hardirqs_on_prepare+0x101/0x1e0 ffff88004117fc50
> […] ? lock_acquire+0x16f/0x320 ffff88004117fd20
> […] ? lock_acquire+0x16f/0x320 ffff88004117fd58
> […] ? find_held_lock+0x3b/0xe0 ffff88004117fd70
> […] __sys_sendmsg+0x17a/0x260 ffff88004117fdc8
> […] ? __sys_sendmsg_sock+0x80/0x80 ffff88004117fdf0
> […] ? syscall_trace_enter+0x15e/0x2c0 ffff88004117fe98
> […] do_syscall_64+0x7d/0x400 ffff88004117fec8
> […] entry_SYSCALL_64_safe_stack+0x4a/0x60 ffff88004117fef8
> </TASK>
> ==================================================================
>
> The out-of-bounds report, though, is a red herring as it is for an
> access that shouldn't have happened in the first place.
>
> When nf_nat_init() fails to register its BPF kfuncs, it'll unwind and,
> among others, call unregister_pernet_subsys() to deregister its per-net
> ops. This makes the previously allocated net id available for reuse by
> the next caller of register_pernet_subsys(), in our case, synproxy.
> However, 'nat_net_id' will still hold the previously allocated value.
>
> If nf_nat.o gets build as a module, all this doesn't matter. A failed
> initialization routine makes the module fail to load and any dependent
> module won't be able to load either. However, if nf_nat.o is built-in,
> a failing init won't /completely/ make its functionality unavailable to
> dependent modules, namely the code and static data is still there, free
> to be called by modules like nft_chain_nat.ko.
>
> Case in point, nft_chain_nat registers hooks that'll call into nf_nat
> which, in our case, failed to initialize and therefore won't have a
> valid net id nor related net_nat object any more.
>
> Code in nf_nat, namely nf_nat_register_fn() and nf_nat_unregister_fn(),
> still making use of the reallocated net id, lead to a type confusion as
> the call to net_generic() will no longer return memory belonging to an
> object suited to fit 'struct nat_net' but 'struct synproxy_net' instead.
> The latter is only 24 bytes on 64-bit systems, much smaller than struct
> nat_net which is 176 bytes, perfectly explaining the OOB KASAN report.
>
> Detect and handle a failed nf_nat_init() by testing the 'nf_nat_hook'
> pointer which will be reset to NULL on initialization errors to prevent
> the usage of an invalid nat_net pointer.
>
> As this check is only needed when nf_nat.o is built-in, guard it by
> '#ifndef MODULE...'.
>
> Fixes: cbc1dd5b659f ("netfilter: nf_nat: Fix possible memory leak in nf_nat_init()")
> Signed-off-by: Mathias Krause <minipli@grsecurity.net>
> ---
> net/netfilter/nf_nat_core.c | 10 ++++++++++
> 1 file changed, 10 insertions(+)
>
> diff --git a/net/netfilter/nf_nat_core.c b/net/netfilter/nf_nat_core.c
> index 3b5434e4ec9c..76a150b9d418 100644
> --- a/net/netfilter/nf_nat_core.c
> +++ b/net/netfilter/nf_nat_core.c
> @@ -1187,6 +1187,16 @@ int nf_nat_register_fn(struct net *net, u8 pf, const struct nf_hook_ops *ops,
> struct nf_hook_ops *nat_ops;
> int i, ret;
>
> +#ifndef MODULE
> + /* If nf_nat_core is built-in and nf_nat_init() fails, dependent
> + * modules like nft_chain_nat.ko may still call this function.
> + * However, nat_net would be invalid, likely pointing to some other
> + * per-net structure.
Hm, if nf_nat_init() fails, then nft_chain_nat should fail to load.
Maybe there is a different way to validate this dependency?
> + */
> + if (WARN_ON_ONCE(!nf_nat_hook))
> + return -EOPNOTSUPP;
> +#endif
> +
> if (WARN_ON_ONCE(pf >= ARRAY_SIZE(nat_net->nat_proto_net)))
> return -EINVAL;
>
> --
> 2.47.3
>
^ permalink raw reply
* [PATCH net 8/8] netfilter: nf_conntrack_sip: don't use simple_strtoul
From: Pablo Neira Ayuso @ 2026-04-28 9:58 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev, kuba, pabeni, edumazet, fw, horms
In-Reply-To: <20260428095840.51961-1-pablo@netfilter.org>
From: Florian Westphal <fw@strlen.de>
Replace unsafe port parsing in epaddr_len(), ct_sip_parse_header_uri(),
and ct_sip_parse_request() with a new sip_parse_port() helper that
validates each digit against the buffer limit, eliminating the use of
simple_strtoul() which assumes NUL-terminated strings.
The previous code dereferenced pointers without bounds checks after
sip_parse_addr() and relied on simple_strtoul() on non-NUL-terminated
skb data. A port that reaches the buffer limit without a trailing
character is also rejected as malformed.
Also get rid of all simple_strtoul() usage in conntrack, prefer a
stricter version instead. There are intentional changes:
- Bail out if number is > UINT_MAX and indicate a failure, same for
too long sequences.
While we do accept 05535 as port 5535, we will not accept e.g.
'sip:10.0.0.1:005060'. While its syntactically valid under RFC 3261,
we should restrict this to not waste cycles when presented with
malformed packets with 64k '0' characters.
- Force base 10 in ct_sip_parse_numerical_param(). This is used to fetch
'expire=' and 'rports='; both are expected to use base-10.
- In nf_nat_sip.c, only accept the parsed value if its within the 1k-64k
range.
- epaddr_len now returns 0 if the port is invalid, as it already does
for invalid ip addresses. This is intentional. nf_conntrack_sip
performs lots of guesswork to find the right parts of the message
to parse. Being stricter could break existing setups.
Connection tracking helpers are designed to allow traffic to
pass, not to block it.
Based on an earlier patch from Jenny Guanni Qu <qguanni@gmail.com>.
Fixes: 05e3ced297fe ("[NETFILTER]: nf_conntrack_sip: introduce SIP-URI parsing helper")
Reported-by: Klaudia Kloc <klaudia@vidocsecurity.com>
Reported-by: Dawid Moczadło <dawid@vidocsecurity.com>
Reported-by: Jenny Guanni Qu <qguanni@gmail.com>.
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
net/netfilter/nf_conntrack_sip.c | 152 ++++++++++++++++++++++++-------
net/netfilter/nf_nat_sip.c | 1 +
2 files changed, 119 insertions(+), 34 deletions(-)
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
index 182cfb119448..1eb55907d470 100644
--- a/net/netfilter/nf_conntrack_sip.c
+++ b/net/netfilter/nf_conntrack_sip.c
@@ -181,6 +181,57 @@ static int sip_parse_addr(const struct nf_conn *ct, const char *cp,
return 1;
}
+/* Parse optional port number after IP address.
+ * Returns false on malformed input, true otherwise.
+ * If port is non-NULL, stores parsed port in network byte order.
+ * If no port is present, sets *port to default SIP port.
+ */
+static bool sip_parse_port(const char *dptr, const char **endp,
+ const char *limit, __be16 *port)
+{
+ unsigned int p = 0;
+ int len = 0;
+
+ if (dptr >= limit)
+ return false;
+
+ if (*dptr != ':') {
+ if (port)
+ *port = htons(SIP_PORT);
+ if (endp)
+ *endp = dptr;
+ return true;
+ }
+
+ dptr++; /* skip ':' */
+
+ while (dptr < limit && isdigit(*dptr)) {
+ p = p * 10 + (*dptr - '0');
+ dptr++;
+ len++;
+ if (len > 5) /* max "65535" */
+ return false;
+ }
+
+ if (len == 0)
+ return false;
+
+ /* reached limit while parsing port */
+ if (dptr >= limit)
+ return false;
+
+ if (p < 1024 || p > 65535)
+ return false;
+
+ if (port)
+ *port = htons(p);
+
+ if (endp)
+ *endp = dptr;
+
+ return true;
+}
+
/* skip ip address. returns its length. */
static int epaddr_len(const struct nf_conn *ct, const char *dptr,
const char *limit, int *shift)
@@ -193,11 +244,8 @@ static int epaddr_len(const struct nf_conn *ct, const char *dptr,
return 0;
}
- /* Port number */
- if (*dptr == ':') {
- dptr++;
- dptr += digits_len(ct, dptr, limit, shift);
- }
+ if (!sip_parse_port(dptr, &dptr, limit, NULL))
+ return 0;
return dptr - aux;
}
@@ -228,6 +276,51 @@ static int skp_epaddr_len(const struct nf_conn *ct, const char *dptr,
return epaddr_len(ct, dptr, limit, shift);
}
+/* simple_strtoul stops after first non-number character.
+ * But as we're not dealing with c-strings, we can't rely on
+ * hitting \r,\n,\0 etc. before moving past end of buffer.
+ *
+ * This is a variant of simple_strtoul, but doesn't require
+ * a c-string.
+ *
+ * If value exceeds UINT_MAX, 0 is returned.
+ */
+static unsigned int sip_strtouint(const char *cp, unsigned int len, char **endp)
+{
+ const unsigned int max = sizeof("4294967295");
+ unsigned int olen = len;
+ const char *s = cp;
+ u64 result = 0;
+
+ if (len > max)
+ len = max;
+
+ while (olen > 0 && isdigit(*s)) {
+ unsigned int value;
+
+ if (len == 0)
+ goto err;
+
+ value = *s - '0';
+ result = result * 10 + value;
+
+ if (result > UINT_MAX)
+ goto err;
+ s++;
+ len--;
+ olen--;
+ }
+
+ if (endp)
+ *endp = (char *)s;
+
+ return result;
+err:
+ if (endp)
+ *endp = (char *)cp;
+ return 0;
+}
+
/* Parse a SIP request line of the form:
*
* Request-Line = Method SP Request-URI SP SIP-Version CRLF
@@ -241,7 +334,6 @@ int ct_sip_parse_request(const struct nf_conn *ct,
{
const char *start = dptr, *limit = dptr + datalen, *end;
unsigned int mlen;
- unsigned int p;
int shift = 0;
/* Skip method and following whitespace */
@@ -267,14 +359,8 @@ int ct_sip_parse_request(const struct nf_conn *ct,
if (!sip_parse_addr(ct, dptr, &end, addr, limit, true))
return -1;
- if (end < limit && *end == ':') {
- end++;
- p = simple_strtoul(end, (char **)&end, 10);
- if (p < 1024 || p > 65535)
- return -1;
- *port = htons(p);
- } else
- *port = htons(SIP_PORT);
+ if (!sip_parse_port(end, &end, limit, port))
+ return -1;
if (end == dptr)
return 0;
@@ -509,7 +595,6 @@ int ct_sip_parse_header_uri(const struct nf_conn *ct, const char *dptr,
union nf_inet_addr *addr, __be16 *port)
{
const char *c, *limit = dptr + datalen;
- unsigned int p;
int ret;
ret = ct_sip_walk_headers(ct, dptr, dataoff ? *dataoff : 0, datalen,
@@ -520,14 +605,8 @@ int ct_sip_parse_header_uri(const struct nf_conn *ct, const char *dptr,
if (!sip_parse_addr(ct, dptr + *matchoff, &c, addr, limit, true))
return -1;
- if (*c == ':') {
- c++;
- p = simple_strtoul(c, (char **)&c, 10);
- if (p < 1024 || p > 65535)
- return -1;
- *port = htons(p);
- } else
- *port = htons(SIP_PORT);
+ if (!sip_parse_port(c, &c, limit, port))
+ return -1;
if (dataoff)
*dataoff = c - dptr;
@@ -609,7 +688,7 @@ int ct_sip_parse_numerical_param(const struct nf_conn *ct, const char *dptr,
return 0;
start += strlen(name);
- *val = simple_strtoul(start, &end, 0);
+ *val = sip_strtouint(start, limit - start, (char **)&end);
if (start == end)
return -1;
if (matchoff && matchlen) {
@@ -1064,6 +1143,8 @@ static int process_sdp(struct sk_buff *skb, unsigned int protoff,
mediaoff = sdpoff;
for (i = 0; i < ARRAY_SIZE(sdp_media_types); ) {
+ char *end;
+
if (ct_sip_get_sdp_header(ct, *dptr, mediaoff, *datalen,
SDP_HDR_MEDIA, SDP_HDR_UNSPEC,
&mediaoff, &medialen) <= 0)
@@ -1079,8 +1160,8 @@ static int process_sdp(struct sk_buff *skb, unsigned int protoff,
mediaoff += t->len;
medialen -= t->len;
- port = simple_strtoul(*dptr + mediaoff, NULL, 10);
- if (port == 0)
+ port = sip_strtouint(*dptr + mediaoff, *datalen - mediaoff, (char **)&end);
+ if (port == 0 || *dptr + mediaoff == end)
continue;
if (port < 1024 || port > 65535) {
nf_ct_helper_log(skb, ct, "wrong port %u", port);
@@ -1254,7 +1335,7 @@ static int process_register_request(struct sk_buff *skb, unsigned int protoff,
*/
if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_EXPIRES,
&matchoff, &matchlen) > 0)
- expires = simple_strtoul(*dptr + matchoff, NULL, 10);
+ expires = sip_strtouint(*dptr + matchoff, *datalen - matchoff, NULL);
ret = ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen,
SIP_HDR_CONTACT, NULL,
@@ -1358,7 +1439,7 @@ static int process_register_response(struct sk_buff *skb, unsigned int protoff,
if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_EXPIRES,
&matchoff, &matchlen) > 0)
- expires = simple_strtoul(*dptr + matchoff, NULL, 10);
+ expires = sip_strtouint(*dptr + matchoff, *datalen - matchoff, NULL);
while (1) {
unsigned int c_expires = expires;
@@ -1418,10 +1499,12 @@ static int process_sip_response(struct sk_buff *skb, unsigned int protoff,
struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
unsigned int matchoff, matchlen, matchend;
unsigned int code, cseq, i;
+ char *end;
if (*datalen < strlen("SIP/2.0 200"))
return NF_ACCEPT;
- code = simple_strtoul(*dptr + strlen("SIP/2.0 "), NULL, 10);
+ code = sip_strtouint(*dptr + strlen("SIP/2.0 "),
+ *datalen - strlen("SIP/2.0 "), NULL);
if (!code) {
nf_ct_helper_log(skb, ct, "cannot get code");
return NF_DROP;
@@ -1432,8 +1515,8 @@ static int process_sip_response(struct sk_buff *skb, unsigned int protoff,
nf_ct_helper_log(skb, ct, "cannot parse cseq");
return NF_DROP;
}
- cseq = simple_strtoul(*dptr + matchoff, NULL, 10);
- if (!cseq && *(*dptr + matchoff) != '0') {
+ cseq = sip_strtouint(*dptr + matchoff, *datalen - matchoff, (char **)&end);
+ if (*dptr + matchoff == end) {
nf_ct_helper_log(skb, ct, "cannot get cseq");
return NF_DROP;
}
@@ -1482,6 +1565,7 @@ static int process_sip_request(struct sk_buff *skb, unsigned int protoff,
for (i = 0; i < ARRAY_SIZE(sip_handlers); i++) {
const struct sip_handler *handler;
+ char *end;
handler = &sip_handlers[i];
if (handler->request == NULL)
@@ -1498,8 +1582,8 @@ static int process_sip_request(struct sk_buff *skb, unsigned int protoff,
nf_ct_helper_log(skb, ct, "cannot parse cseq");
return NF_DROP;
}
- cseq = simple_strtoul(*dptr + matchoff, NULL, 10);
- if (!cseq && *(*dptr + matchoff) != '0') {
+ cseq = sip_strtouint(*dptr + matchoff, *datalen - matchoff, (char **)&end);
+ if (*dptr + matchoff == end) {
nf_ct_helper_log(skb, ct, "cannot get cseq");
return NF_DROP;
}
@@ -1575,7 +1659,7 @@ static int sip_help_tcp(struct sk_buff *skb, unsigned int protoff,
&matchoff, &matchlen) <= 0)
break;
- clen = simple_strtoul(dptr + matchoff, (char **)&end, 10);
+ clen = sip_strtouint(dptr + matchoff, datalen - matchoff, (char **)&end);
if (dptr + matchoff == end)
break;
diff --git a/net/netfilter/nf_nat_sip.c b/net/netfilter/nf_nat_sip.c
index c845b6d1a2bd..9fbfc6bff0c2 100644
--- a/net/netfilter/nf_nat_sip.c
+++ b/net/netfilter/nf_nat_sip.c
@@ -246,6 +246,7 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff,
if (ct_sip_parse_numerical_param(ct, *dptr, matchend, *datalen,
"rport=", &poff, &plen,
&n) > 0 &&
+ n >= 1024 && n <= 65535 &&
htons(n) == ct->tuplehash[dir].tuple.dst.u.udp.port &&
htons(n) != ct->tuplehash[!dir].tuple.src.u.udp.port) {
__be16 p = ct->tuplehash[!dir].tuple.src.u.udp.port;
--
2.47.3
^ permalink raw reply related
* [PATCH net 7/8] netfilter: reject zero shift in nft_bitwise
From: Pablo Neira Ayuso @ 2026-04-28 9:58 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev, kuba, pabeni, edumazet, fw, horms
In-Reply-To: <20260428095840.51961-1-pablo@netfilter.org>
From: Kai Ma <k4729.23098@gmail.com>
Reject zero shift operands for nft_bitwise left and right shift
expressions during initialization.
The carry propagation logic computes the carry from the adjacent 32-bit
word using BITS_PER_TYPE(u32) - shift. A zero shift operand turns this
into a 32-bit shift, which is undefined behaviour.
Reject zero shift operands in the control plane, alongside the existing
check for values greater than or equal to 32, so malformed rules never
reach the packet path.
Fixes: 567d746b55bc ("netfilter: bitwise: add support for shifts.")
Cc: stable@kernel.org
Reported-by: Yuan Tan <yuantan098@gmail.com>
Reported-by: Yifan Wu <yifanwucs@gmail.com>
Reported-by: Juefei Pu <tomapufckgml@gmail.com>
Reported-by: Xin Liu <bird@lzu.edu.cn>
Signed-off-by: Kai Ma <k4729.23098@gmail.com>
Signed-off-by: Ren Wei <n05ec@lzu.edu.cn>
Reviewed-by: Fernando Fernandez Mancera <fmancera@suse.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
net/netfilter/nft_bitwise.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/net/netfilter/nft_bitwise.c b/net/netfilter/nft_bitwise.c
index 13808e9cd999..94dccdcfa06b 100644
--- a/net/netfilter/nft_bitwise.c
+++ b/net/netfilter/nft_bitwise.c
@@ -196,7 +196,8 @@ static int nft_bitwise_init_shift(struct nft_bitwise *priv,
if (err < 0)
return err;
- if (priv->data.data[0] >= BITS_PER_TYPE(u32)) {
+ if (!priv->data.data[0] ||
+ priv->data.data[0] >= BITS_PER_TYPE(u32)) {
nft_data_release(&priv->data, desc.type);
return -EINVAL;
}
--
2.47.3
^ permalink raw reply related
* [PATCH net 5/8] netfilter: nf_tables: add hook transactions for device deletions
From: Pablo Neira Ayuso @ 2026-04-28 9:58 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev, kuba, pabeni, edumazet, fw, horms
In-Reply-To: <20260428095840.51961-1-pablo@netfilter.org>
Restore the flag that indicates that the hook is going away, ie.
NFT_HOOK_REMOVE, but add a new transaction object to track deletion
of hooks without altering the basechain/flowtable hook_list during
the preparation phase.
The existing approach that moves the hook from the basechain/flowtable
hook_list to transaction hook_list breaks netlink dump path readers
of this RCU-protected list.
It should be possible use an array for nft_trans_hook to store the
deleted hooks to compact the representation but I am not expecting
many hook object, specially now that wildcard support for devices
is in place.
Note that the nft_trans_chain_hooks() list contains a list of struct
nft_trans_hook objects for DELCHAIN and DELFLOWTABLE commands, while
this list stores struct nft_hook objects for NEWCHAIN and NEWFLOWTABLE.
Note that new commands can be updated to use nft_trans_hook for
consistency.
This patch also adapts the event notification path to deal with the list
of hook transactions.
Fixes: 7d937b107108 ("netfilter: nf_tables: support for deleting devices in an existing netdev chain")
Fixes: b6d9014a3335 ("netfilter: nf_tables: delete flowtable hooks via transaction list")
Reported-by: Xiang Mei <xmei5@asu.edu>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
include/net/netfilter/nf_tables.h | 13 ++
net/netfilter/nf_tables_api.c | 264 +++++++++++++++++++++++-------
2 files changed, 217 insertions(+), 60 deletions(-)
diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h
index 2c0173d9309c..cff7b773e972 100644
--- a/include/net/netfilter/nf_tables.h
+++ b/include/net/netfilter/nf_tables.h
@@ -1204,12 +1204,15 @@ struct nft_stats {
struct u64_stats_sync syncp;
};
+#define NFT_HOOK_REMOVE (1 << 0)
+
struct nft_hook {
struct list_head list;
struct list_head ops_list;
struct rcu_head rcu;
char ifname[IFNAMSIZ];
u8 ifnamelen;
+ u8 flags;
};
struct nf_hook_ops *nft_hook_find_ops(const struct nft_hook *hook,
@@ -1664,6 +1667,16 @@ struct nft_trans {
u8 put_net:1;
};
+/**
+ * struct nft_trans_hook - nf_tables hook update in transaction
+ * @list: used internally
+ * @hook: struct nft_hook with the device hook
+ */
+struct nft_trans_hook {
+ struct list_head list;
+ struct nft_hook *hook;
+};
+
/**
* struct nft_trans_binding - nf_tables object with binding support in transaction
* @nft_trans: base structure, MUST be first member
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index ae10116af923..d20ce5c36d31 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -380,6 +380,32 @@ static void nft_netdev_hook_unlink_free_rcu(struct nft_hook *hook)
nft_netdev_hook_free_rcu(hook);
}
+static void nft_trans_hook_destroy(struct nft_trans_hook *trans_hook)
+{
+ list_del(&trans_hook->list);
+ kfree(trans_hook);
+}
+
+static void nft_netdev_unregister_trans_hook(struct net *net,
+ const struct nft_table *table,
+ struct list_head *hook_list)
+{
+ struct nft_trans_hook *trans_hook, *next;
+ struct nf_hook_ops *ops;
+ struct nft_hook *hook;
+
+ list_for_each_entry_safe(trans_hook, next, hook_list, list) {
+ hook = trans_hook->hook;
+
+ if (!(table->flags & NFT_TABLE_F_DORMANT)) {
+ list_for_each_entry(ops, &hook->ops_list, list)
+ nf_unregister_net_hook(net, ops);
+ }
+ nft_netdev_hook_unlink_free_rcu(hook);
+ nft_trans_hook_destroy(trans_hook);
+ }
+}
+
static void nft_netdev_unregister_hooks(struct net *net,
struct list_head *hook_list,
bool release_netdev)
@@ -1946,15 +1972,69 @@ static int nft_nla_put_hook_dev(struct sk_buff *skb, struct nft_hook *hook)
return nla_put_string(skb, attr, hook->ifname);
}
+struct nft_hook_dump_ctx {
+ struct nft_hook *first;
+ int n;
+};
+
+static int nft_dump_basechain_hook_one(struct sk_buff *skb,
+ struct nft_hook *hook,
+ struct nft_hook_dump_ctx *dump_ctx)
+{
+ if (!dump_ctx->first)
+ dump_ctx->first = hook;
+
+ if (nft_nla_put_hook_dev(skb, hook))
+ return -1;
+
+ dump_ctx->n++;
+
+ return 0;
+}
+
+static int nft_dump_basechain_hook_list(struct sk_buff *skb,
+ const struct net *net,
+ const struct list_head *hook_list,
+ struct nft_hook_dump_ctx *dump_ctx)
+{
+ struct nft_hook *hook;
+ int err;
+
+ list_for_each_entry_rcu(hook, hook_list, list,
+ lockdep_commit_lock_is_held(net)) {
+ err = nft_dump_basechain_hook_one(skb, hook, dump_ctx);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+static int nft_dump_basechain_trans_hook_list(struct sk_buff *skb,
+ const struct list_head *trans_hook_list,
+ struct nft_hook_dump_ctx *dump_ctx)
+{
+ struct nft_trans_hook *trans_hook;
+ int err;
+
+ list_for_each_entry(trans_hook, trans_hook_list, list) {
+ err = nft_dump_basechain_hook_one(skb, trans_hook->hook, dump_ctx);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
static int nft_dump_basechain_hook(struct sk_buff *skb,
const struct net *net, int family,
const struct nft_base_chain *basechain,
- const struct list_head *hook_list)
+ const struct list_head *hook_list,
+ const struct list_head *trans_hook_list)
{
const struct nf_hook_ops *ops = &basechain->ops;
- struct nft_hook *hook, *first = NULL;
+ struct nft_hook_dump_ctx dump_hook_ctx = {};
struct nlattr *nest, *nest_devs;
- int n = 0;
nest = nla_nest_start_noflag(skb, NFTA_CHAIN_HOOK);
if (nest == NULL)
@@ -1969,23 +2049,23 @@ static int nft_dump_basechain_hook(struct sk_buff *skb,
if (!nest_devs)
goto nla_put_failure;
- if (!hook_list)
+ if (!hook_list && !trans_hook_list)
hook_list = &basechain->hook_list;
- list_for_each_entry_rcu(hook, hook_list, list,
- lockdep_commit_lock_is_held(net)) {
- if (!first)
- first = hook;
-
- if (nft_nla_put_hook_dev(skb, hook))
- goto nla_put_failure;
- n++;
+ if (hook_list &&
+ nft_dump_basechain_hook_list(skb, net, hook_list, &dump_hook_ctx)) {
+ goto nla_put_failure;
+ } else if (trans_hook_list &&
+ nft_dump_basechain_trans_hook_list(skb, trans_hook_list,
+ &dump_hook_ctx)) {
+ goto nla_put_failure;
}
+
nla_nest_end(skb, nest_devs);
- if (n == 1 &&
- !hook_is_prefix(first) &&
- nla_put_string(skb, NFTA_HOOK_DEV, first->ifname))
+ if (dump_hook_ctx.n == 1 &&
+ !hook_is_prefix(dump_hook_ctx.first) &&
+ nla_put_string(skb, NFTA_HOOK_DEV, dump_hook_ctx.first->ifname))
goto nla_put_failure;
}
nla_nest_end(skb, nest);
@@ -1999,7 +2079,8 @@ static int nf_tables_fill_chain_info(struct sk_buff *skb, struct net *net,
u32 portid, u32 seq, int event, u32 flags,
int family, const struct nft_table *table,
const struct nft_chain *chain,
- const struct list_head *hook_list)
+ const struct list_head *hook_list,
+ const struct list_head *trans_hook_list)
{
struct nlmsghdr *nlh;
@@ -2015,7 +2096,7 @@ static int nf_tables_fill_chain_info(struct sk_buff *skb, struct net *net,
NFTA_CHAIN_PAD))
goto nla_put_failure;
- if (!hook_list &&
+ if (!hook_list && !trans_hook_list &&
(event == NFT_MSG_DELCHAIN ||
event == NFT_MSG_DESTROYCHAIN)) {
nlmsg_end(skb, nlh);
@@ -2026,7 +2107,8 @@ static int nf_tables_fill_chain_info(struct sk_buff *skb, struct net *net,
const struct nft_base_chain *basechain = nft_base_chain(chain);
struct nft_stats __percpu *stats;
- if (nft_dump_basechain_hook(skb, net, family, basechain, hook_list))
+ if (nft_dump_basechain_hook(skb, net, family, basechain,
+ hook_list, trans_hook_list))
goto nla_put_failure;
if (nla_put_be32(skb, NFTA_CHAIN_POLICY,
@@ -2062,7 +2144,8 @@ static int nf_tables_fill_chain_info(struct sk_buff *skb, struct net *net,
}
static void nf_tables_chain_notify(const struct nft_ctx *ctx, int event,
- const struct list_head *hook_list)
+ const struct list_head *hook_list,
+ const struct list_head *trans_hook_list)
{
struct nftables_pernet *nft_net;
struct sk_buff *skb;
@@ -2082,7 +2165,7 @@ static void nf_tables_chain_notify(const struct nft_ctx *ctx, int event,
err = nf_tables_fill_chain_info(skb, ctx->net, ctx->portid, ctx->seq,
event, flags, ctx->family, ctx->table,
- ctx->chain, hook_list);
+ ctx->chain, hook_list, trans_hook_list);
if (err < 0) {
kfree_skb(skb);
goto err;
@@ -2128,7 +2211,7 @@ static int nf_tables_dump_chains(struct sk_buff *skb,
NFT_MSG_NEWCHAIN,
NLM_F_MULTI,
table->family, table,
- chain, NULL) < 0)
+ chain, NULL, NULL) < 0)
goto done;
nl_dump_check_consistent(cb, nlmsg_hdr(skb));
@@ -2182,7 +2265,7 @@ static int nf_tables_getchain(struct sk_buff *skb, const struct nfnl_info *info,
err = nf_tables_fill_chain_info(skb2, net, NETLINK_CB(skb).portid,
info->nlh->nlmsg_seq, NFT_MSG_NEWCHAIN,
- 0, family, table, chain, NULL);
+ 0, family, table, chain, NULL, NULL);
if (err < 0)
goto err_fill_chain_info;
@@ -2345,8 +2428,12 @@ static struct nft_hook *nft_hook_list_find(struct list_head *hook_list,
list_for_each_entry(hook, hook_list, list) {
if (!strncmp(hook->ifname, this->ifname,
- min(hook->ifnamelen, this->ifnamelen)))
+ min(hook->ifnamelen, this->ifnamelen))) {
+ if (hook->flags & NFT_HOOK_REMOVE)
+ continue;
+
return hook;
+ }
}
return NULL;
@@ -3105,6 +3192,32 @@ static int nf_tables_newchain(struct sk_buff *skb, const struct nfnl_info *info,
return nf_tables_addchain(&ctx, family, policy, flags, extack);
}
+static int nft_trans_delhook(struct nft_hook *hook,
+ struct list_head *del_list)
+{
+ struct nft_trans_hook *trans_hook;
+
+ trans_hook = kmalloc_obj(*trans_hook, GFP_KERNEL);
+ if (!trans_hook)
+ return -ENOMEM;
+
+ trans_hook->hook = hook;
+ list_add_tail(&trans_hook->list, del_list);
+ hook->flags |= NFT_HOOK_REMOVE;
+
+ return 0;
+}
+
+static void nft_trans_delhook_abort(struct list_head *del_list)
+{
+ struct nft_trans_hook *trans_hook, *next;
+
+ list_for_each_entry_safe(trans_hook, next, del_list, list) {
+ trans_hook->hook->flags &= ~NFT_HOOK_REMOVE;
+ nft_trans_hook_destroy(trans_hook);
+ }
+}
+
static int nft_delchain_hook(struct nft_ctx *ctx,
struct nft_base_chain *basechain,
struct netlink_ext_ack *extack)
@@ -3131,7 +3244,10 @@ static int nft_delchain_hook(struct nft_ctx *ctx,
err = -ENOENT;
goto err_chain_del_hook;
}
- list_move(&hook->list, &chain_del_list);
+ if (nft_trans_delhook(hook, &chain_del_list) < 0) {
+ err = -ENOMEM;
+ goto err_chain_del_hook;
+ }
}
trans = nft_trans_alloc_chain(ctx, NFT_MSG_DELCHAIN);
@@ -3151,7 +3267,7 @@ static int nft_delchain_hook(struct nft_ctx *ctx,
return 0;
err_chain_del_hook:
- list_splice(&chain_del_list, &basechain->hook_list);
+ nft_trans_delhook_abort(&chain_del_list);
nft_chain_release_hook(&chain_hook);
return err;
@@ -8941,6 +9057,24 @@ static void nft_hooks_destroy(struct list_head *hook_list)
nft_netdev_hook_unlink_free_rcu(hook);
}
+static void nft_flowtable_unregister_trans_hook(struct net *net,
+ struct nft_flowtable *flowtable,
+ struct list_head *hook_list)
+{
+ struct nft_trans_hook *trans_hook, *next;
+ struct nf_hook_ops *ops;
+ struct nft_hook *hook;
+
+ list_for_each_entry_safe(trans_hook, next, hook_list, list) {
+ hook = trans_hook->hook;
+ list_for_each_entry(ops, &hook->ops_list, list)
+ nft_unregister_flowtable_ops(net, flowtable, ops);
+
+ nft_netdev_hook_unlink_free_rcu(hook);
+ nft_trans_hook_destroy(trans_hook);
+ }
+}
+
static int nft_flowtable_update(struct nft_ctx *ctx, const struct nlmsghdr *nlh,
struct nft_flowtable *flowtable,
struct netlink_ext_ack *extack)
@@ -9199,7 +9333,10 @@ static int nft_delflowtable_hook(struct nft_ctx *ctx,
err = -ENOENT;
goto err_flowtable_del_hook;
}
- list_move(&hook->list, &flowtable_del_list);
+ if (nft_trans_delhook(hook, &flowtable_del_list) < 0) {
+ err = -ENOMEM;
+ goto err_flowtable_del_hook;
+ }
}
trans = nft_trans_alloc(ctx, NFT_MSG_DELFLOWTABLE,
@@ -9220,7 +9357,7 @@ static int nft_delflowtable_hook(struct nft_ctx *ctx,
return 0;
err_flowtable_del_hook:
- list_splice(&flowtable_del_list, &flowtable->hook_list);
+ nft_trans_delhook_abort(&flowtable_del_list);
nft_flowtable_hook_release(&flowtable_hook);
return err;
@@ -9285,8 +9422,10 @@ static int nf_tables_fill_flowtable_info(struct sk_buff *skb, struct net *net,
u32 portid, u32 seq, int event,
u32 flags, int family,
struct nft_flowtable *flowtable,
- struct list_head *hook_list)
+ struct list_head *hook_list,
+ struct list_head *trans_hook_list)
{
+ struct nft_trans_hook *trans_hook;
struct nlattr *nest, *nest_devs;
struct nft_hook *hook;
struct nlmsghdr *nlh;
@@ -9303,7 +9442,7 @@ static int nf_tables_fill_flowtable_info(struct sk_buff *skb, struct net *net,
NFTA_FLOWTABLE_PAD))
goto nla_put_failure;
- if (!hook_list &&
+ if (!hook_list && !trans_hook_list &&
(event == NFT_MSG_DELFLOWTABLE ||
event == NFT_MSG_DESTROYFLOWTABLE)) {
nlmsg_end(skb, nlh);
@@ -9325,13 +9464,20 @@ static int nf_tables_fill_flowtable_info(struct sk_buff *skb, struct net *net,
if (!nest_devs)
goto nla_put_failure;
- if (!hook_list)
+ if (!hook_list && !trans_hook_list)
hook_list = &flowtable->hook_list;
- list_for_each_entry_rcu(hook, hook_list, list,
- lockdep_commit_lock_is_held(net)) {
- if (nft_nla_put_hook_dev(skb, hook))
- goto nla_put_failure;
+ if (hook_list) {
+ list_for_each_entry_rcu(hook, hook_list, list,
+ lockdep_commit_lock_is_held(net)) {
+ if (nft_nla_put_hook_dev(skb, hook))
+ goto nla_put_failure;
+ }
+ } else if (trans_hook_list) {
+ list_for_each_entry(trans_hook, trans_hook_list, list) {
+ if (nft_nla_put_hook_dev(skb, trans_hook->hook))
+ goto nla_put_failure;
+ }
}
nla_nest_end(skb, nest_devs);
nla_nest_end(skb, nest);
@@ -9385,7 +9531,7 @@ static int nf_tables_dump_flowtable(struct sk_buff *skb,
NFT_MSG_NEWFLOWTABLE,
NLM_F_MULTI | NLM_F_APPEND,
table->family,
- flowtable, NULL) < 0)
+ flowtable, NULL, NULL) < 0)
goto done;
nl_dump_check_consistent(cb, nlmsg_hdr(skb));
@@ -9485,7 +9631,7 @@ static int nf_tables_getflowtable(struct sk_buff *skb,
err = nf_tables_fill_flowtable_info(skb2, net, NETLINK_CB(skb).portid,
info->nlh->nlmsg_seq,
NFT_MSG_NEWFLOWTABLE, 0, family,
- flowtable, NULL);
+ flowtable, NULL, NULL);
if (err < 0)
goto err_fill_flowtable_info;
@@ -9498,7 +9644,9 @@ static int nf_tables_getflowtable(struct sk_buff *skb,
static void nf_tables_flowtable_notify(struct nft_ctx *ctx,
struct nft_flowtable *flowtable,
- struct list_head *hook_list, int event)
+ struct list_head *hook_list,
+ struct list_head *trans_hook_list,
+ int event)
{
struct nftables_pernet *nft_net = nft_pernet(ctx->net);
struct sk_buff *skb;
@@ -9518,7 +9666,8 @@ static void nf_tables_flowtable_notify(struct nft_ctx *ctx,
err = nf_tables_fill_flowtable_info(skb, ctx->net, ctx->portid,
ctx->seq, event, flags,
- ctx->family, flowtable, hook_list);
+ ctx->family, flowtable,
+ hook_list, trans_hook_list);
if (err < 0) {
kfree_skb(skb);
goto err;
@@ -10052,9 +10201,7 @@ static void nft_commit_release(struct nft_trans *trans)
break;
case NFT_MSG_DELCHAIN:
case NFT_MSG_DESTROYCHAIN:
- if (nft_trans_chain_update(trans))
- nft_hooks_destroy(&nft_trans_chain_hooks(trans));
- else
+ if (!nft_trans_chain_update(trans))
nf_tables_chain_destroy(nft_trans_chain(trans));
break;
case NFT_MSG_DELRULE:
@@ -10075,9 +10222,7 @@ static void nft_commit_release(struct nft_trans *trans)
break;
case NFT_MSG_DELFLOWTABLE:
case NFT_MSG_DESTROYFLOWTABLE:
- if (nft_trans_flowtable_update(trans))
- nft_hooks_destroy(&nft_trans_flowtable_hooks(trans));
- else
+ if (!nft_trans_flowtable_update(trans))
nf_tables_flowtable_destroy(nft_trans_flowtable(trans));
break;
}
@@ -10837,31 +10982,28 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
if (nft_trans_chain_update(trans)) {
nft_chain_commit_update(nft_trans_container_chain(trans));
nf_tables_chain_notify(&ctx, NFT_MSG_NEWCHAIN,
- &nft_trans_chain_hooks(trans));
+ &nft_trans_chain_hooks(trans), NULL);
list_splice_rcu(&nft_trans_chain_hooks(trans),
&nft_trans_basechain(trans)->hook_list);
/* trans destroyed after rcu grace period */
} else {
nft_chain_commit_drop_policy(nft_trans_container_chain(trans));
nft_clear(net, nft_trans_chain(trans));
- nf_tables_chain_notify(&ctx, NFT_MSG_NEWCHAIN, NULL);
+ nf_tables_chain_notify(&ctx, NFT_MSG_NEWCHAIN, NULL, NULL);
nft_trans_destroy(trans);
}
break;
case NFT_MSG_DELCHAIN:
case NFT_MSG_DESTROYCHAIN:
if (nft_trans_chain_update(trans)) {
- nf_tables_chain_notify(&ctx, NFT_MSG_DELCHAIN,
+ nf_tables_chain_notify(&ctx, NFT_MSG_DELCHAIN, NULL,
&nft_trans_chain_hooks(trans));
- if (!(table->flags & NFT_TABLE_F_DORMANT)) {
- nft_netdev_unregister_hooks(net,
- &nft_trans_chain_hooks(trans),
- true);
- }
+ nft_netdev_unregister_trans_hook(net, table,
+ &nft_trans_chain_hooks(trans));
} else {
nft_chain_del(nft_trans_chain(trans));
nf_tables_chain_notify(&ctx, NFT_MSG_DELCHAIN,
- NULL);
+ NULL, NULL);
nf_tables_unregister_hook(ctx.net, ctx.table,
nft_trans_chain(trans));
}
@@ -10967,6 +11109,7 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
nf_tables_flowtable_notify(&ctx,
nft_trans_flowtable(trans),
&nft_trans_flowtable_hooks(trans),
+ NULL,
NFT_MSG_NEWFLOWTABLE);
list_splice_rcu(&nft_trans_flowtable_hooks(trans),
&nft_trans_flowtable(trans)->hook_list);
@@ -10975,6 +11118,7 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
nf_tables_flowtable_notify(&ctx,
nft_trans_flowtable(trans),
NULL,
+ NULL,
NFT_MSG_NEWFLOWTABLE);
}
nft_trans_destroy(trans);
@@ -10984,16 +11128,18 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
if (nft_trans_flowtable_update(trans)) {
nf_tables_flowtable_notify(&ctx,
nft_trans_flowtable(trans),
+ NULL,
&nft_trans_flowtable_hooks(trans),
trans->msg_type);
- nft_unregister_flowtable_net_hooks(net,
- nft_trans_flowtable(trans),
- &nft_trans_flowtable_hooks(trans));
+ nft_flowtable_unregister_trans_hook(net,
+ nft_trans_flowtable(trans),
+ &nft_trans_flowtable_hooks(trans));
} else {
list_del_rcu(&nft_trans_flowtable(trans)->list);
nf_tables_flowtable_notify(&ctx,
nft_trans_flowtable(trans),
NULL,
+ NULL,
trans->msg_type);
nft_unregister_flowtable_net_hooks(net,
nft_trans_flowtable(trans),
@@ -11157,8 +11303,7 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
case NFT_MSG_DELCHAIN:
case NFT_MSG_DESTROYCHAIN:
if (nft_trans_chain_update(trans)) {
- list_splice(&nft_trans_chain_hooks(trans),
- &nft_trans_basechain(trans)->hook_list);
+ nft_trans_delhook_abort(&nft_trans_chain_hooks(trans));
} else {
nft_use_inc_restore(&table->use);
nft_clear(trans->net, nft_trans_chain(trans));
@@ -11272,8 +11417,7 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
case NFT_MSG_DELFLOWTABLE:
case NFT_MSG_DESTROYFLOWTABLE:
if (nft_trans_flowtable_update(trans)) {
- list_splice(&nft_trans_flowtable_hooks(trans),
- &nft_trans_flowtable(trans)->hook_list);
+ nft_trans_delhook_abort(&nft_trans_flowtable_hooks(trans));
} else {
nft_use_inc_restore(&table->use);
nft_clear(trans->net, nft_trans_flowtable(trans));
--
2.47.3
^ permalink raw reply related
* [PATCH net 6/8] netfilter: xt_policy: fix strict mode inbound policy matching
From: Pablo Neira Ayuso @ 2026-04-28 9:58 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev, kuba, pabeni, edumazet, fw, horms
In-Reply-To: <20260428095840.51961-1-pablo@netfilter.org>
From: Jiexun Wang <wangjiexun2025@gmail.com>
match_policy_in() walks sec_path entries from the last transform to the
first one, but strict policy matching needs to consume info->pol[] in
the same forward order as the rule layout.
Derive the strict-match policy position from the number of transforms
already consumed so that multi-element inbound rules are matched
consistently.
Fixes: c4b885139203 ("[NETFILTER]: x_tables: replace IPv4/IPv6 policy match by address family independant version")
Reported-by: Yuan Tan <yuantan098@gmail.com>
Reported-by: Yifan Wu <yifanwucs@gmail.com>
Reported-by: Juefei Pu <tomapufckgml@gmail.com>
Reported-by: Xin Liu <bird@lzu.edu.cn>
Signed-off-by: Jiexun Wang <wangjiexun2025@gmail.com>
Signed-off-by: Ren Wei <n05ec@lzu.edu.cn>
Acked-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
net/netfilter/xt_policy.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/netfilter/xt_policy.c b/net/netfilter/xt_policy.c
index cb6e8279010a..b5fa65558318 100644
--- a/net/netfilter/xt_policy.c
+++ b/net/netfilter/xt_policy.c
@@ -63,7 +63,7 @@ match_policy_in(const struct sk_buff *skb, const struct xt_policy_info *info,
return 0;
for (i = sp->len - 1; i >= 0; i--) {
- pos = strict ? i - sp->len + 1 : 0;
+ pos = strict ? sp->len - i - 1 : 0;
if (pos >= info->len)
return 0;
e = &info->pol[pos];
--
2.47.3
^ permalink raw reply related
* [PATCH net 4/8] netfilter: nf_tables: join hook list via splice_list_rcu() in commit phase
From: Pablo Neira Ayuso @ 2026-04-28 9:58 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev, kuba, pabeni, edumazet, fw, horms
In-Reply-To: <20260428095840.51961-1-pablo@netfilter.org>
Publish new hooks in the list into the basechain/flowtable using
splice_list_rcu() to ensure netlink dump list traversal via rcu is safe
while concurrent ruleset update is going on.
Fixes: 78d9f48f7f44 ("netfilter: nf_tables: add devices to existing flowtable")
Fixes: b9703ed44ffb ("netfilter: nf_tables: support for adding new devices to an existing netdev chain")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
net/netfilter/nf_tables_api.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index 07e151245765..ae10116af923 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -10838,8 +10838,8 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
nft_chain_commit_update(nft_trans_container_chain(trans));
nf_tables_chain_notify(&ctx, NFT_MSG_NEWCHAIN,
&nft_trans_chain_hooks(trans));
- list_splice(&nft_trans_chain_hooks(trans),
- &nft_trans_basechain(trans)->hook_list);
+ list_splice_rcu(&nft_trans_chain_hooks(trans),
+ &nft_trans_basechain(trans)->hook_list);
/* trans destroyed after rcu grace period */
} else {
nft_chain_commit_drop_policy(nft_trans_container_chain(trans));
@@ -10968,8 +10968,8 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
nft_trans_flowtable(trans),
&nft_trans_flowtable_hooks(trans),
NFT_MSG_NEWFLOWTABLE);
- list_splice(&nft_trans_flowtable_hooks(trans),
- &nft_trans_flowtable(trans)->hook_list);
+ list_splice_rcu(&nft_trans_flowtable_hooks(trans),
+ &nft_trans_flowtable(trans)->hook_list);
} else {
nft_clear(net, nft_trans_flowtable(trans));
nf_tables_flowtable_notify(&ctx,
--
2.47.3
^ permalink raw reply related
* [PATCH net 3/8] rculist: add list_splice_rcu() for private lists
From: Pablo Neira Ayuso @ 2026-04-28 9:58 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev, kuba, pabeni, edumazet, fw, horms
In-Reply-To: <20260428095840.51961-1-pablo@netfilter.org>
This patch adds a helper function, list_splice_rcu(), to safely splice
a private (non-RCU-protected) list into an RCU-protected list.
The function ensures that only the pointer visible to RCU readers
(prev->next) is updated using rcu_assign_pointer(), while the rest of
the list manipulations are performed with regular assignments, as the
source list is private and not visible to concurrent RCU readers.
This is useful for moving elements from a private list into a global
RCU-protected list, ensuring safe publication for RCU readers.
Subsystems with some sort of batching mechanism from userspace can
benefit from this new function.
The function __list_splice_rcu() has been added for clarity and to
follow the same pattern as in the existing list_splice*() interfaces,
where there is a check to ensure that the list to splice is not
empty. Note that __list_splice_rcu() has no documentation for this
reason.
Reviewed-by: Paul E. McKenney <paulmck@kernel.org>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
include/linux/rculist.h | 29 +++++++++++++++++++++++++++++
1 file changed, 29 insertions(+)
diff --git a/include/linux/rculist.h b/include/linux/rculist.h
index 2abba7552605..e3bc44225692 100644
--- a/include/linux/rculist.h
+++ b/include/linux/rculist.h
@@ -261,6 +261,35 @@ static inline void list_replace_rcu(struct list_head *old,
old->prev = LIST_POISON2;
}
+static inline void __list_splice_rcu(struct list_head *list,
+ struct list_head *prev,
+ struct list_head *next)
+{
+ struct list_head *first = list->next;
+ struct list_head *last = list->prev;
+
+ last->next = next;
+ first->prev = prev;
+ next->prev = last;
+ rcu_assign_pointer(list_next_rcu(prev), first);
+}
+
+/**
+ * list_splice_rcu - splice a non-RCU list into an RCU-protected list,
+ * designed for stacks.
+ * @list: the non RCU-protected list to splice
+ * @head: the place in the existing RCU-protected list to splice
+ *
+ * The list pointed to by @head can be RCU-read traversed concurrently with
+ * this function.
+ */
+static inline void list_splice_rcu(struct list_head *list,
+ struct list_head *head)
+{
+ if (!list_empty(list))
+ __list_splice_rcu(list, head, head->next);
+}
+
/**
* __list_splice_init_rcu - join an RCU-protected list into an existing list.
* @list: the RCU-protected list to splice
--
2.47.3
^ permalink raw reply related
* [PATCH net 2/8] netfilter: nf_tables: use list_del_rcu for netlink hooks
From: Pablo Neira Ayuso @ 2026-04-28 9:58 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev, kuba, pabeni, edumazet, fw, horms
In-Reply-To: <20260428095840.51961-1-pablo@netfilter.org>
From: Florian Westphal <fw@strlen.de>
nft_netdev_unregister_hooks and __nft_unregister_flowtable_net_hooks need
to use list_del_rcu(), this list can be walked by concurrent dumpers.
Add a new helper and use it consistently.
Fixes: f9a43007d3f7 ("netfilter: nf_tables: double hook unregistration in netns path")
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
net/netfilter/nf_tables_api.c | 44 ++++++++++++++---------------------
1 file changed, 18 insertions(+), 26 deletions(-)
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index 8537b94653d3..07e151245765 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -374,6 +374,12 @@ static void nft_netdev_hook_free_rcu(struct nft_hook *hook)
call_rcu(&hook->rcu, __nft_netdev_hook_free_rcu);
}
+static void nft_netdev_hook_unlink_free_rcu(struct nft_hook *hook)
+{
+ list_del_rcu(&hook->list);
+ nft_netdev_hook_free_rcu(hook);
+}
+
static void nft_netdev_unregister_hooks(struct net *net,
struct list_head *hook_list,
bool release_netdev)
@@ -384,10 +390,8 @@ static void nft_netdev_unregister_hooks(struct net *net,
list_for_each_entry_safe(hook, next, hook_list, list) {
list_for_each_entry(ops, &hook->ops_list, list)
nf_unregister_net_hook(net, ops);
- if (release_netdev) {
- list_del(&hook->list);
- nft_netdev_hook_free_rcu(hook);
- }
+ if (release_netdev)
+ nft_netdev_hook_unlink_free_rcu(hook);
}
}
@@ -2271,10 +2275,8 @@ void nf_tables_chain_destroy(struct nft_chain *chain)
if (nft_base_chain_netdev(table->family, basechain->ops.hooknum)) {
list_for_each_entry_safe(hook, next,
- &basechain->hook_list, list) {
- list_del_rcu(&hook->list);
- nft_netdev_hook_free_rcu(hook);
- }
+ &basechain->hook_list, list)
+ nft_netdev_hook_unlink_free_rcu(hook);
}
module_put(basechain->type->owner);
if (rcu_access_pointer(basechain->stats)) {
@@ -2974,6 +2976,7 @@ static int nf_tables_updchain(struct nft_ctx *ctx, u8 genmask, u8 policy,
list_for_each_entry(ops, &h->ops_list, list)
nf_unregister_net_hook(ctx->net, ops);
}
+ /* hook.list is on stack, no need for list_del_rcu() */
list_del(&h->list);
nft_netdev_hook_free_rcu(h);
}
@@ -8852,10 +8855,8 @@ static void __nft_unregister_flowtable_net_hooks(struct net *net,
list_for_each_entry_safe(hook, next, hook_list, list) {
list_for_each_entry(ops, &hook->ops_list, list)
nft_unregister_flowtable_ops(net, flowtable, ops);
- if (release_netdev) {
- list_del(&hook->list);
- nft_netdev_hook_free_rcu(hook);
- }
+ if (release_netdev)
+ nft_netdev_hook_unlink_free_rcu(hook);
}
}
@@ -8926,8 +8927,7 @@ static int nft_register_flowtable_net_hooks(struct net *net,
nft_unregister_flowtable_ops(net, flowtable, ops);
}
- list_del_rcu(&hook->list);
- nft_netdev_hook_free_rcu(hook);
+ nft_netdev_hook_unlink_free_rcu(hook);
}
return err;
@@ -8937,10 +8937,8 @@ static void nft_hooks_destroy(struct list_head *hook_list)
{
struct nft_hook *hook, *next;
- list_for_each_entry_safe(hook, next, hook_list, list) {
- list_del_rcu(&hook->list);
- nft_netdev_hook_free_rcu(hook);
- }
+ list_for_each_entry_safe(hook, next, hook_list, list)
+ nft_netdev_hook_unlink_free_rcu(hook);
}
static int nft_flowtable_update(struct nft_ctx *ctx, const struct nlmsghdr *nlh,
@@ -9028,8 +9026,7 @@ static int nft_flowtable_update(struct nft_ctx *ctx, const struct nlmsghdr *nlh,
nft_unregister_flowtable_ops(ctx->net,
flowtable, ops);
}
- list_del_rcu(&hook->list);
- nft_netdev_hook_free_rcu(hook);
+ nft_netdev_hook_unlink_free_rcu(hook);
}
return err;
@@ -9535,13 +9532,8 @@ static void nf_tables_flowtable_notify(struct nft_ctx *ctx,
static void nf_tables_flowtable_destroy(struct nft_flowtable *flowtable)
{
- struct nft_hook *hook, *next;
-
flowtable->data.type->free(&flowtable->data);
- list_for_each_entry_safe(hook, next, &flowtable->hook_list, list) {
- list_del_rcu(&hook->list);
- nft_netdev_hook_free_rcu(hook);
- }
+ nft_hooks_destroy(&flowtable->hook_list);
kfree(flowtable->name);
module_put(flowtable->data.type->owner);
kfree(flowtable);
--
2.47.3
^ permalink raw reply related
* [PATCH net 1/8] netfilter: arp_tables: fix IEEE1394 ARP payload parsing
From: Pablo Neira Ayuso @ 2026-04-28 9:58 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev, kuba, pabeni, edumazet, fw, horms
In-Reply-To: <20260428095840.51961-1-pablo@netfilter.org>
Weiming Shi says:
"arp_packet_match() unconditionally parses the ARP payload assuming two
hardware addresses are present (source and target). However,
IPv4-over-IEEE1394 ARP (RFC 2734) omits the target hardware address
field, and arp_hdr_len() already accounts for this by returning a
shorter length for ARPHRD_IEEE1394 devices.
As a result, on IEEE1394 interfaces arp_packet_match() advances past a
nonexistent target hardware address and reads the wrong bytes for both
the target device address comparison and the target IP address. This
causes arptables rules to match against garbage data, leading to
incorrect filtering decisions: packets that should be accepted may be
dropped and vice versa.
The ARP stack in net/ipv4/arp.c (arp_create and arp_process) already
handles this correctly by skipping the target hardware address for
ARPHRD_IEEE1394. Apply the same pattern to arp_packet_match()."
Mangle the original patch to always return 0 (no match) in case user
matches on the target hardware address which is never present in
IEEE1394.
Note that this returns 0 (no match) for either normal and inverse match
because matching in the target hardware address in ARPHRD_IEEE1394 has
never been supported by arptables. This is intentional, matching on the
target hardware address should never evaluate true for ARPHRD_IEEE1394.
Moreover, adjust arpt_mangle to drop the packet too as AI suggests:
In arpt_mangle, the logic assumes a standard ARP layout. Because
IEEE1394 (FireWire) omits the target hardware address, the linear
pointer arithmetic miscalculates the offset for the target IP address.
This causes mangling operations to write to the wrong location, leading
to packet corruption. To ensure safety, this patch drops packets
(NF_DROP) when mangling is requested for these fields on IEEE1394
devices, as the current implementation cannot correctly map the FireWire
ARP payload.
This omits both mangling target hardware and IP address. Even if IP
address mangling should be possible in IEEE1394, this would require
to adjust arpt_mangle offset calculation, which has never been
supported.
Based on patch from Weiming Shi <bestswngs@gmail.com>.
Fixes: 6752c8db8e0c ("firewire net, ipv4 arp: Extend hardware address and remove driver-level packet inspection.")
Reported-by: Xiang Mei <xmei5@asu.edu>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
net/ipv4/netfilter/arp_tables.c | 18 +++++++++++++++---
net/ipv4/netfilter/arpt_mangle.c | 8 ++++++++
2 files changed, 23 insertions(+), 3 deletions(-)
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
index 1cdd9c28ab2d..97ead883e4a1 100644
--- a/net/ipv4/netfilter/arp_tables.c
+++ b/net/ipv4/netfilter/arp_tables.c
@@ -110,13 +110,25 @@ static inline int arp_packet_match(const struct arphdr *arphdr,
arpptr += dev->addr_len;
memcpy(&src_ipaddr, arpptr, sizeof(u32));
arpptr += sizeof(u32);
- tgt_devaddr = arpptr;
- arpptr += dev->addr_len;
+
+ if (IS_ENABLED(CONFIG_FIREWIRE_NET) && dev->type == ARPHRD_IEEE1394) {
+ if (unlikely(memchr_inv(arpinfo->tgt_devaddr.mask, 0,
+ sizeof(arpinfo->tgt_devaddr.mask))))
+ return 0;
+
+ tgt_devaddr = NULL;
+ } else {
+ tgt_devaddr = arpptr;
+ arpptr += dev->addr_len;
+ }
memcpy(&tgt_ipaddr, arpptr, sizeof(u32));
if (NF_INVF(arpinfo, ARPT_INV_SRCDEVADDR,
arp_devaddr_compare(&arpinfo->src_devaddr, src_devaddr,
- dev->addr_len)) ||
+ dev->addr_len)))
+ return 0;
+
+ if (tgt_devaddr &&
NF_INVF(arpinfo, ARPT_INV_TGTDEVADDR,
arp_devaddr_compare(&arpinfo->tgt_devaddr, tgt_devaddr,
dev->addr_len)))
diff --git a/net/ipv4/netfilter/arpt_mangle.c b/net/ipv4/netfilter/arpt_mangle.c
index a4e07e5e9c11..f65dd339208e 100644
--- a/net/ipv4/netfilter/arpt_mangle.c
+++ b/net/ipv4/netfilter/arpt_mangle.c
@@ -40,6 +40,10 @@ target(struct sk_buff *skb, const struct xt_action_param *par)
}
arpptr += pln;
if (mangle->flags & ARPT_MANGLE_TDEV) {
+ if (unlikely(IS_ENABLED(CONFIG_FIREWIRE_NET) &&
+ skb->dev->type == ARPHRD_IEEE1394))
+ return NF_DROP;
+
if (ARPT_DEV_ADDR_LEN_MAX < hln ||
(arpptr + hln > skb_tail_pointer(skb)))
return NF_DROP;
@@ -47,6 +51,10 @@ target(struct sk_buff *skb, const struct xt_action_param *par)
}
arpptr += hln;
if (mangle->flags & ARPT_MANGLE_TIP) {
+ if (unlikely(IS_ENABLED(CONFIG_FIREWIRE_NET) &&
+ skb->dev->type == ARPHRD_IEEE1394))
+ return NF_DROP;
+
if (ARPT_MANGLE_ADDR_LEN_MAX < pln ||
(arpptr + pln > skb_tail_pointer(skb)))
return NF_DROP;
--
2.47.3
^ permalink raw reply related
* [PATCH net,v2 0/8] Netfilter fixes for net
From: Pablo Neira Ayuso @ 2026-04-28 9:58 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev, kuba, pabeni, edumazet, fw, horms
Reposting this PR without IPVS fixes:
https://patchwork.kernel.org/project/netdevbpf/patch/20260424190513.32823-1-pablo@netfilter.org/
until the remaining issues are addressed.
-o-
Hi,
The following patchset contains Netfilter fixes for net:
1) IEEE1394 ARP payload contains no target hardware address in the
ARP packet. Apparently, arp_tables was never updated to deal with
IEEE1394 ARP properly. To deal with this, return no match in case
the target hardware address selector is used, either for inverse or
normal match. Moreover, arpt_mangle disallows mangling of the target
hardware and IP address because, it is not worth to adjust the
offset calculation to fix this, we suspect no users of arp_tables
for this family.
2) Use list_del_rcu() to delete device hooks in nf_tables, this hook
list is RCU protected, concurrent netlink dump readers can be
walking on this list, fix it by adding a helper function and use it
for consistency. From Florian Westphal.
3) Add list_splice_rcu(), this is useful for joining the local list of
new device hooks to the RCU protected hook list in chain and
flowtable. Reviewed by Paul E. McKenney.
4) Use list_splice_rcu() to publish the new device hooks in chain and
flowtable to fix concurrent netlink dump traversal.
5) Add a new hook transaction object to track device hook deletions.
The current approach moves device hooks to be deleted around during
the preparation phase, this breaks concurrent RCU reader via netlink
dump. This new hook transaction is combined with NFT_HOOK_REMOVE
flag to annotate hooks for removal in the preparation phase.
6) xt_policy inbound policy check in strict mode can lead to
out-of-bound access of the secpath array due to incorrect.
The iteration over the secpath needs to be reversed in the inbound
to check for the human readable policy, expecting inner in first
position and outer in second position, the secpath from inbound
actually stores outer in first position then in second position.
From Jiexun Wang.
7) Fix possible zero shift in nft_bitwise triggering UBSAN splat,
reject zero shift from control plane, from Kai Ma.
8) Replace simple_strtoul() in the conntrack SIP helper since it relies
on nul-terminated strings. From Florian Westphal.
Please, pull these changes from:
git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf.git nf-26-04-28
Thanks.
----------------------------------------------------------------
The following changes since commit 711987ba281fd806322a7cd244e98e2a81903114:
netfilter: nfnetlink_osf: fix potential NULL dereference in ttl check (2026-04-20 23:45:44 +0200)
are available in the Git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf.git tags/nf-26-04-28
for you to fetch changes up to 8cf6809cddcbe301aedfc6b51bcd4944d45795f6:
netfilter: nf_conntrack_sip: don't use simple_strtoul (2026-04-24 20:09:57 +0200)
----------------------------------------------------------------
netfilter pull request 26-04-28
----------------------------------------------------------------
Florian Westphal (2):
netfilter: nf_tables: use list_del_rcu for netlink hooks
netfilter: nf_conntrack_sip: don't use simple_strtoul
Jiexun Wang (1):
netfilter: xt_policy: fix strict mode inbound policy matching
Kai Ma (1):
netfilter: reject zero shift in nft_bitwise
Pablo Neira Ayuso (4):
netfilter: arp_tables: fix IEEE1394 ARP payload parsing
rculist: add list_splice_rcu() for private lists
netfilter: nf_tables: join hook list via splice_list_rcu() in commit phase
netfilter: nf_tables: add hook transactions for device deletions
include/linux/rculist.h | 29 ++++
include/net/netfilter/nf_tables.h | 13 ++
net/ipv4/netfilter/arp_tables.c | 18 ++-
net/ipv4/netfilter/arpt_mangle.c | 8 +
net/netfilter/nf_conntrack_sip.c | 152 +++++++++++++-----
net/netfilter/nf_nat_sip.c | 1 +
net/netfilter/nf_tables_api.c | 314 +++++++++++++++++++++++++++-----------
net/netfilter/nft_bitwise.c | 3 +-
net/netfilter/xt_policy.c | 2 +-
9 files changed, 412 insertions(+), 128 deletions(-)
^ permalink raw reply
* Re: [Intel-wired-lan] [RFC PATCH] ice: allow creating VFs when !CONFIG_ICE_SWITCHDEV
From: Paul Menzel @ 2026-04-28 9:44 UTC (permalink / raw)
To: Vincent Chen
Cc: anthony.l.nguyen, przemyslaw.kitszel, andrew+netdev, davem,
edumazet, kuba, pabeni, intel-wired-lan, netdev
In-Reply-To: <20260427031158.2665916-1-vincent.chen@sifive.com>
Dear Vincent,
Thank you for your patch.
Am 27.04.26 um 05:11 schrieb Vincent Chen via Intel-wired-lan:
> Currently ice_eswitch_attach_vf() is called unconditionally in
> ice_start_vfs() and ice_reset_all_vfs(), which causes VF creation
> to fail when CONFIG_ICE_SWITCHDEV is not defined or switchdev mode
> is not enabled at runtime.
I’d add a blank line between paragraphs.
> Fix this by adding switchdev mode checks at the call sites before
> calling ice_eswitch_attach_vf(), consistent with how
> ice_eswitch_attach_sf() is already handled in ice_devlink_port_new().
> Also remove the redundant check inside ice_eswitch_attach_vf() itself.
*Also* is a good indicator to make it a separate patch. I’d favor this
in this case.
> This is similar to commit aacca7a83b97 ("ice: allow creating VFs for
> !CONFIG_NET_SWITCHDEV") which fixed the same issue for the previous
> ice_eswitch_configure() API.
>
> Signed-off-by: Vincent Chen <vincent.chen@sifive.com>
> ---
> drivers/net/ethernet/intel/ice/ice_eswitch.c | 3 ---
> drivers/net/ethernet/intel/ice/ice_sriov.c | 14 ++++++++------
> drivers/net/ethernet/intel/ice/ice_vf_lib.c | 3 ++-
> 3 files changed, 10 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/net/ethernet/intel/ice/ice_eswitch.c b/drivers/net/ethernet/intel/ice/ice_eswitch.c
> index 2e4f0969035f..c709decb26d5 100644
> --- a/drivers/net/ethernet/intel/ice/ice_eswitch.c
> +++ b/drivers/net/ethernet/intel/ice/ice_eswitch.c
> @@ -512,9 +512,6 @@ int ice_eswitch_attach_vf(struct ice_pf *pf, struct ice_vf *vf)
> struct ice_repr *repr;
> int err;
>
> - if (!ice_is_eswitch_mode_switchdev(pf))
> - return 0;
> -
> repr = ice_repr_create_vf(vf);
> if (IS_ERR(repr))
> return PTR_ERR(repr);
> diff --git a/drivers/net/ethernet/intel/ice/ice_sriov.c b/drivers/net/ethernet/intel/ice/ice_sriov.c
> index 843e82fd3bf9..6a0b724e46f9 100644
> --- a/drivers/net/ethernet/intel/ice/ice_sriov.c
> +++ b/drivers/net/ethernet/intel/ice/ice_sriov.c
> @@ -484,12 +484,14 @@ static int ice_start_vfs(struct ice_pf *pf)
> goto teardown;
> }
>
> - retval = ice_eswitch_attach_vf(pf, vf);
> - if (retval) {
> - dev_err(ice_pf_to_dev(pf), "Failed to attach VF %d to eswitch, error %d",
> - vf->vf_id, retval);
> - ice_vf_vsi_release(vf);
> - goto teardown;
> + if (ice_is_eswitch_mode_switchdev(pf)) {
> + retval = ice_eswitch_attach_vf(pf, vf);
> + if (retval) {
> + dev_err(ice_pf_to_dev(pf), "Failed to attach VF %d to eswitch, error %d",
> + vf->vf_id, retval);
> + ice_vf_vsi_release(vf);
> + goto teardown;
> + }
> }
>
> set_bit(ICE_VF_STATE_INIT, vf->vf_states);
> diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib.c b/drivers/net/ethernet/intel/ice/ice_vf_lib.c
> index de9e81ccee66..71595410174c 100644
> --- a/drivers/net/ethernet/intel/ice/ice_vf_lib.c
> +++ b/drivers/net/ethernet/intel/ice/ice_vf_lib.c
> @@ -807,7 +807,8 @@ void ice_reset_all_vfs(struct ice_pf *pf)
> ice_vf_rebuild_vsi(vf);
> ice_vf_post_vsi_rebuild(vf);
>
> - ice_eswitch_attach_vf(pf, vf);
> + if (ice_is_eswitch_mode_switchdev(pf))
> + ice_eswitch_attach_vf(pf, vf);
>
> mutex_unlock(&vf->cfg_lock);
> }
The diff looks good.
Kind regards,
Paul
^ permalink raw reply
* Re: [PATCH v2 2/9] x86/extable: switch to using FIELD_GET_SIGNED()
From: Peter Zijlstra @ 2026-04-28 9:39 UTC (permalink / raw)
To: Yury Norov
Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
H. Peter Anvin, Andy Lutomirski, 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
In-Reply-To: <20260427214127.406067-3-ynorov@nvidia.com>
On Mon, Apr 27, 2026 at 05:41:19PM -0400, Yury Norov wrote:
> The EX_DATA register is laid out such that EX_DATA_IMM occupied MSB.
> It's done to make sure that FIELD_GET() will sign-extend the IMM
> field during extraction.
>
> To enforce that, all EX_DATA masks are made signed integers. This
> works, but relies on the particular implementation of FIELD_GET(),
> i.e. masking then shifting, not vice versa; and the particular
> placement of the fields in the register.
>
> Switch to using the dedicated FIELD_GET_SIGNED(), and relax those
> limitations.
>
> Signed-off-by: Yury Norov <ynorov@nvidia.com>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
> ---
> arch/x86/include/asm/extable_fixup_types.h | 13 ++++---------
> arch/x86/mm/extable.c | 2 +-
> 2 files changed, 5 insertions(+), 10 deletions(-)
>
> diff --git a/arch/x86/include/asm/extable_fixup_types.h b/arch/x86/include/asm/extable_fixup_types.h
> index 906b0d5541e8..fd0cfb472103 100644
> --- a/arch/x86/include/asm/extable_fixup_types.h
> +++ b/arch/x86/include/asm/extable_fixup_types.h
> @@ -2,15 +2,10 @@
> #ifndef _ASM_X86_EXTABLE_FIXUP_TYPES_H
> #define _ASM_X86_EXTABLE_FIXUP_TYPES_H
>
> -/*
> - * Our IMM is signed, as such it must live at the top end of the word. Also,
> - * since C99 hex constants are of ambiguous type, force cast the mask to 'int'
> - * so that FIELD_GET() will DTRT and sign extend the value when it extracts it.
> - */
> -#define EX_DATA_TYPE_MASK ((int)0x000000FF)
> -#define EX_DATA_REG_MASK ((int)0x00000F00)
> -#define EX_DATA_FLAG_MASK ((int)0x0000F000)
> -#define EX_DATA_IMM_MASK ((int)0xFFFF0000)
> +#define EX_DATA_TYPE_MASK (0x000000FF)
> +#define EX_DATA_REG_MASK (0x00000F00)
> +#define EX_DATA_FLAG_MASK (0x0000F000)
> +#define EX_DATA_IMM_MASK (0xFFFF0000)
>
> #define EX_DATA_REG_SHIFT 8
> #define EX_DATA_FLAG_SHIFT 12
> diff --git a/arch/x86/mm/extable.c b/arch/x86/mm/extable.c
> index 6b9ff1c6cafa..ceb8d03191ab 100644
> --- a/arch/x86/mm/extable.c
> +++ b/arch/x86/mm/extable.c
> @@ -322,7 +322,7 @@ int fixup_exception(struct pt_regs *regs, int trapnr, unsigned long error_code,
>
> type = FIELD_GET(EX_DATA_TYPE_MASK, e->data);
> reg = FIELD_GET(EX_DATA_REG_MASK, e->data);
> - imm = FIELD_GET(EX_DATA_IMM_MASK, e->data);
> + imm = FIELD_GET_SIGNED(EX_DATA_IMM_MASK, e->data);
>
> switch (type) {
> case EX_TYPE_DEFAULT:
> --
> 2.51.0
>
^ permalink raw reply
* Re: [Openvpn-devel] [PATCH ovpn-net-next] ovpn: reset MAC header before passing skb up
From: Antonio Quartulli @ 2026-04-28 9:36 UTC (permalink / raw)
To: Qingfang Deng, openvpn-devel
Cc: Minqiang Chen, Sabrina Dubroca, netdev, antonio
In-Reply-To: <501fb5d6-3247-40aa-aaa5-ce9dacb17255@linux.dev>
Hi,
On 28/04/2026 04:08, Qingfang Deng wrote:
> Hi,
>
> On 2026/4/27 17:45, Antonio Quartulli wrote:
>> Hi Qingfang,
>>
>> thanks for the patch!
>>
>> On 27/04/2026 06:00, Qingfang Deng wrote:
>>> After decapsulating a packet, the skb->mac_header still points to the
>>> outer transport header. Call skb_reset_mac_header() in
>>> ovpn_netdev_write() to ensure the MAC header points to the beginning of
>>> the inner IP packet.
>>
>> May you elaborate on what this is exactly fixing?
>> Did you encounter a bug triggered by this missing line?
>>
>> I am asking because I wonder what is "expected" as MAC header for a
>> packet not having one at all (packets delivered to the ovpn interface
>> are L3 only, as per the interface type itself).
>
> For L3-only devices, the net core expects skb->mac_header == skb-
> >network_header.
>
> For example, in __netif_receive_skb_core(), skb_reset_mac_len() sets
> skb->mac_len to (skb->network_header - skb->mac_header).
> If skb->mac_header still has a stale value, this will incorrectly assign
> a non-zero value to skb->mac_len.
>
> Also, if generic XDP or SOCK_PACKET is used, either will do
> skb_push(skb, skb->data - skb_mac_header(skb));
Thanks a lot! This makes sense!
I'm applying the patch to my tree.
Regards,
--
Antonio Quartulli
^ permalink raw reply
* Re: [RFC PATCH v1 2/9] uaccess: Convert INLINE_COPY_{TO/FROM}_USER to kconfig and reduce ifdefery
From: Andrew Cooper @ 2026-04-28 9:36 UTC (permalink / raw)
To: Yury Norov
Cc: Andrew Cooper, Christophe Leroy (CS GROUP), Andrew Morton,
Linus Torvalds, 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_LeSk7XDEseaZb@yury>
On 27/04/2026 9:47 pm, Yury Norov wrote:
> On Mon, Apr 27, 2026 at 09:39:33PM +0100, Andrew Cooper wrote:
>> On 27/04/2026 7:39 pm, Yury Norov wrote:
>>> On Mon, Apr 27, 2026 at 07:13:43PM +0200, Christophe Leroy (CS GROUP) wrote:
>>>> Among the 21 architectures supported by the kernel, 16 define both
>>>> INLINE_COPY_TO_USER and INLINE_COPY_FROM_USER while the 5 other ones
>>>> don't define any of the two.
>>>>
>>>> To simplify and reduce risk of mistakes, convert them to a single
>>>> kconfig item named CONFIG_ARCH_WANTS_NOINLINE_COPY which will be
>>> We've got a special word for it: outline. Can you name it
>>> CONFIG_OUTLINE_USERCOPY, or similar?
>> You can't swap the "in" for "out" like this. "out of line" is the
>> opposite of "inline" in this context, while "outline" means something
>> different and unrelated.
> Check KASAN_OUTLINE vs KASAN_INLINE for example
Then I suggest it gets corrected before more examples try to copy this
non-english.
~Andrew
^ permalink raw reply
* [PATCH net-next v3] net: mdio: drop unneeded dependency on OF_GPIO
From: Bartosz Golaszewski @ 2026-04-28 9:33 UTC (permalink / raw)
To: Andrew Lunn, Heiner Kallweit, Russell King, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni
Cc: brgl, netdev, linux-kernel, Bartosz Golaszewski
OF_GPIO is selected automatically on all OF systems. Any symbols it
controls also provide stubs so there's really no reason to select it
explicitly.
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
---
Changes in v3:
- Send the next patch separately so that it can be picked up
- Link to v2: https://patch.msgid.link/20260316-gpio-of-kconfig-v2-0-de2f4b00a0e4@oss.qualcomm.com
Changes in v2:
- Make gpio-watchdog depend on OF && GPIOLIB
- Drop picked up patches
- Link to v1: https://patch.msgid.link/20260304-gpio-of-kconfig-v1-0-d597916e79e7@oss.qualcomm.com
drivers/net/mdio/Kconfig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/mdio/Kconfig b/drivers/net/mdio/Kconfig
index c71132f33f847..c591eec8e97a5 100644
--- a/drivers/net/mdio/Kconfig
+++ b/drivers/net/mdio/Kconfig
@@ -254,7 +254,7 @@ config MDIO_BUS_MUX_BCM_IPROC
config MDIO_BUS_MUX_GPIO
tristate "GPIO controlled MDIO bus multiplexers"
- depends on OF_GPIO && OF_MDIO
+ depends on OF_MDIO
select MDIO_BUS_MUX
help
This module provides a driver for MDIO bus multiplexers that
--
2.47.3
^ permalink raw reply related
* Re: [RFC PATCH v1 4/9] uaccess: Introduce copy_{to/from}_user_partial()
From: Geert Uytterhoeven @ 2026-04-28 9:25 UTC (permalink / raw)
To: Christophe Leroy (CS GROUP)
Cc: Yury Norov, Andrew Morton, Linus Torvalds, David Laight,
Thomas Gleixner, linux-alpha, 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: <c73b90236f2810edd47c84edd2a8d8e8e0c816da.1777306795.git.chleroy@kernel.org>
Hi Christophe,
Thanks for your patch!
On Mon, 27 Apr 2026 at 19:18, Christophe Leroy (CS GROUP)
<chleroy@kernel.org> wrote:
> Today there are approximately 3000 calls for copy_to_user() and
> 3000 calls to copy_from_user().
>
> The majority of callers of copy_{to/from}_user() don't care about the
> return value, they only check whether it is 0 or not, and when it is
> not 0 they handle it as a -EACCES.
I think the "a" can be dropped.
> In order to allow better optimisation of copy_{to/from}_user() when
> the size of the copy is known at build time, create new fonctions
functions
> named copy_{to/from}_user_partial() to be used by the few callers
> that are interested in partial copies and need to now how many
know
> bytes remain at the end of the copy.
>
> For the time being it is just the same as copy_{to/from}_user().
>
> Signed-off-by: Christophe Leroy (CS GROUP) <chleroy@kernel.org>
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply
* Re: [PATCH net] net: ipv6: fix NOREF dst use in seg6 and rpl lwtunnels
From: patchwork-bot+netdevbpf @ 2026-04-28 9:30 UTC (permalink / raw)
To: Andrea Mayer
Cc: davem, dsahern, edumazet, kuba, pabeni, horms, bigeasy, clrkwllms,
rostedt, david.lebrun, alex.aring, stefano.salsano, netdev,
linux-rt-devel, linux-kernel, stable
In-Reply-To: <20260421094735.20997-1-andrea.mayer@uniroma2.it>
Hello:
This patch was applied to netdev/net.git (main)
by Paolo Abeni <pabeni@redhat.com>:
On Tue, 21 Apr 2026 11:47:35 +0200 you wrote:
> seg6_input_core() and rpl_input() call ip6_route_input() which sets a
> NOREF dst on the skb, then pass it to dst_cache_set_ip6() invoking
> dst_hold() unconditionally.
> On PREEMPT_RT, ksoftirqd is preemptible and a higher-priority task can
> release the underlying pcpu_rt between the lookup and the caching
> through a concurrent FIB lookup on a shared nexthop.
> Simplified race sequence:
>
> [...]
Here is the summary with links:
- [net] net: ipv6: fix NOREF dst use in seg6 and rpl lwtunnels
https://git.kernel.org/netdev/net/c/f9c52a6ba978
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* [PATCH net-next 2/2] ice: use shared devlink to store ice_adapters instead of custom xarray
From: Przemek Kitszel @ 2026-04-28 9:09 UTC (permalink / raw)
To: netdev, Jakub Kicinski, Jiri Pirko
Cc: intel-wired-lan, Tony Nguyen, Jacob Keller, Lukasz Czapnik,
Jedrzej Jagielski, Andrew Lunn, David S. Miller, Eric Dumazet,
Paolo Abeni, Saeed Mahameed, Leon Romanovsky, Tariq Toukan,
Mark Bloch, Simon Horman, Przemek Kitszel, Aleksandr Loktionov,
Sergey Temerkhanov
In-Reply-To: <20260428090912.3461-1-przemyslaw.kitszel@intel.com>
Refactor our storage and deduplication logic of ice_adapters by moving
it to be handled by shared devlink instance, recently added by
Jiri Pirko [1].
We wanted the devlink instance for whole device anyway - later in the
series I will add devlink resources under it.
Make the shared devlink a parent (wrt. nesting) of the actual PF devices.
[1] commit 411ad0605875 ("Merge branch 'devlink-introduce-shared-devlink-instance-for-pfs-on-same-chip'")
[1] https://lore.kernel.org/all/20260312100407.551173-1-jiri@resnulli.us
Reviewed-by: Jedrzej Jagielski <jedrzej.jagielski@intel.com>
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Signed-off-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
---
CC: Sergey Temerkhanov <sergey.temerkhanov@intel.com>
---
drivers/net/ethernet/intel/ice/ice_adapter.h | 13 +--
.../net/ethernet/intel/ice/devlink/devlink.c | 3 +
drivers/net/ethernet/intel/ice/ice_adapter.c | 95 ++++++-------------
drivers/net/ethernet/intel/ice/ice_main.c | 4 +-
4 files changed, 42 insertions(+), 73 deletions(-)
diff --git a/drivers/net/ethernet/intel/ice/ice_adapter.h b/drivers/net/ethernet/intel/ice/ice_adapter.h
index e95266c7f20b..d4ec7e78abb4 100644
--- a/drivers/net/ethernet/intel/ice/ice_adapter.h
+++ b/drivers/net/ethernet/intel/ice/ice_adapter.h
@@ -6,7 +6,8 @@
#include <linux/types.h>
#include <linux/spinlock_types.h>
-#include <linux/refcount_types.h>
+
+#include <net/devlink.h>
struct pci_dev;
struct ice_pf;
@@ -27,27 +28,26 @@ struct ice_port_list {
/**
* struct ice_adapter - PCI adapter resources shared across PFs
- * @refcount: Reference count. struct ice_pf objects hold the references.
+ * @devlink: ice adapter's devlink (whole dev devlink)
* @ptp_gltsyn_time_lock: Spinlock protecting access to the GLTSYN_TIME
* register of the PTP clock.
* @txq_ctx_lock: Spinlock protecting access to the GLCOMM_QTX_CNTX_CTL register
* @ctrl_pf: Control PF of the adapter
* @ports: Ports list
- * @index: 64-bit index cached for collision detection on 32bit systems
*/
struct ice_adapter {
- refcount_t refcount;
+ struct devlink *devlink;
+
/* For access to the GLTSYN_TIME register */
spinlock_t ptp_gltsyn_time_lock;
/* For access to GLCOMM_QTX_CNTX_CTL register */
spinlock_t txq_ctx_lock;
struct ice_pf *ctrl_pf;
struct ice_port_list ports;
- u64 index;
};
struct ice_adapter *ice_adapter_get(struct pci_dev *pdev);
-void ice_adapter_put(struct pci_dev *pdev);
+void ice_adapter_put(struct ice_adapter *adapter);
#endif /* _ICE_ADAPTER_H */
diff --git a/drivers/net/ethernet/intel/ice/devlink/devlink.c b/drivers/net/ethernet/intel/ice/devlink/devlink.c
index 641d6e289d5c..f6382d038048 100644
--- a/drivers/net/ethernet/intel/ice/devlink/devlink.c
+++ b/drivers/net/ethernet/intel/ice/devlink/devlink.c
@@ -1750,7 +1750,10 @@ struct ice_sf_priv *ice_allocate_sf(struct device *dev, struct ice_pf *pf)
void ice_devlink_register(struct ice_pf *pf)
{
struct devlink *devlink = priv_to_devlink(pf);
+ struct ice_adapter *adapter = pf->adapter;
+ if (adapter)
+ devl_nested_devlink_set(adapter->devlink, devlink);
devl_register(devlink);
}
diff --git a/drivers/net/ethernet/intel/ice/ice_adapter.c b/drivers/net/ethernet/intel/ice/ice_adapter.c
index cbb57060bd56..8ec1b600905f 100644
--- a/drivers/net/ethernet/intel/ice/ice_adapter.c
+++ b/drivers/net/ethernet/intel/ice/ice_adapter.c
@@ -1,18 +1,13 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright Red Hat
-#include <linux/cleanup.h>
-#include <linux/mutex.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
-#include <linux/xarray.h>
+
#include "ice_adapter.h"
#include "ice.h"
-static DEFINE_XARRAY(ice_adapters);
-static DEFINE_MUTEX(ice_adapters_mutex);
-
#define ICE_ADAPTER_FIXED_INDEX BIT_ULL(63)
#define ICE_ADAPTER_INDEX_E825C \
@@ -40,44 +35,36 @@ static u64 ice_adapter_index(struct pci_dev *pdev)
}
}
-static unsigned long ice_adapter_xa_index(struct pci_dev *pdev)
-{
- u64 index = ice_adapter_index(pdev);
-
-#if BITS_PER_LONG == 64
- return index;
-#else
- return (u32)index ^ (u32)(index >> 32);
-#endif
-}
-
-static struct ice_adapter *ice_adapter_new(struct pci_dev *pdev)
+static int ice_adapter_init(void *priv, void *init_param)
{
- struct ice_adapter *adapter;
+ struct ice_adapter *adapter = priv;
+ struct devlink *devlink;
- adapter = kzalloc_obj(*adapter);
- if (!adapter)
- return NULL;
+ devlink = shd_priv_to_devlink(adapter);
+ adapter->devlink = devlink;
- adapter->index = ice_adapter_index(pdev);
spin_lock_init(&adapter->ptp_gltsyn_time_lock);
spin_lock_init(&adapter->txq_ctx_lock);
- refcount_set(&adapter->refcount, 1);
mutex_init(&adapter->ports.lock);
INIT_LIST_HEAD(&adapter->ports.ports);
- return adapter;
+ return 0;
}
-static void ice_adapter_free(struct ice_adapter *adapter)
+static void ice_adapter_fini(void *priv)
{
+ struct ice_adapter *adapter = priv;
+
WARN_ON(!list_empty(&adapter->ports.ports));
mutex_destroy(&adapter->ports.lock);
-
- kfree(adapter);
}
+static const struct devlink_ops ice_adapter_devlink_ops = {
+ .shd_init = ice_adapter_init,
+ .shd_fini = ice_adapter_fini,
+};
+
/**
* ice_adapter_get - Get a shared ice_adapter structure.
* @pdev: Pointer to the pci_dev whose driver is getting the ice_adapter.
@@ -94,28 +81,19 @@ static void ice_adapter_free(struct ice_adapter *adapter)
struct ice_adapter *ice_adapter_get(struct pci_dev *pdev)
{
struct ice_adapter *adapter;
- unsigned long index;
- int err;
-
- index = ice_adapter_xa_index(pdev);
- scoped_guard(mutex, &ice_adapters_mutex) {
- adapter = xa_load(&ice_adapters, index);
- if (adapter) {
- refcount_inc(&adapter->refcount);
- WARN_ON_ONCE(adapter->index != ice_adapter_index(pdev));
- return adapter;
- }
- err = xa_reserve(&ice_adapters, index, GFP_KERNEL);
- if (err)
- return ERR_PTR(err);
-
- adapter = ice_adapter_new(pdev);
- if (!adapter) {
- xa_release(&ice_adapters, index);
- return ERR_PTR(-ENOMEM);
- }
- xa_store(&ice_adapters, index, adapter, GFP_KERNEL);
- }
+ struct devlink *devlink;
+ char devlink_id[32];
+ u64 index;
+
+ index = ice_adapter_index(pdev);
+ snprintf(devlink_id, sizeof(devlink_id), "%llx", index);
+ devlink = devlink_shd_get(devlink_id, &ice_adapter_devlink_ops,
+ sizeof(*adapter), NULL, pdev->dev.driver);
+ if (!devlink)
+ return ERR_PTR(-ENOMEM);
+
+ adapter = devlink_shd_get_priv(devlink);
+
return adapter;
}
@@ -128,20 +106,7 @@ struct ice_adapter *ice_adapter_get(struct pci_dev *pdev)
*
* Context: Process, may sleep.
*/
-void ice_adapter_put(struct pci_dev *pdev)
+void ice_adapter_put(struct ice_adapter *adapter)
{
- struct ice_adapter *adapter;
- unsigned long index;
-
- index = ice_adapter_xa_index(pdev);
- scoped_guard(mutex, &ice_adapters_mutex) {
- adapter = xa_load(&ice_adapters, index);
- if (WARN_ON(!adapter))
- return;
- if (!refcount_dec_and_test(&adapter->refcount))
- return;
-
- WARN_ON(xa_erase(&ice_adapters, index) != adapter);
- }
- ice_adapter_free(adapter);
+ devlink_shd_put(adapter->devlink);
}
diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c
index 6ebaa41127a4..6e257ad13bd1 100644
--- a/drivers/net/ethernet/intel/ice/ice_main.c
+++ b/drivers/net/ethernet/intel/ice/ice_main.c
@@ -5349,7 +5349,7 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)
unroll_dev_init:
need_dev_deinit = true;
unroll_adapter:
- ice_adapter_put(pdev);
+ ice_adapter_put(adapter);
unroll_hw_init:
ice_deinit_hw(hw);
if (need_dev_deinit)
@@ -5462,7 +5462,7 @@ static void ice_remove(struct pci_dev *pdev)
ice_setup_mc_magic_wake(pf);
ice_set_wake(pf);
- ice_adapter_put(pdev);
+ ice_adapter_put(pf->adapter);
ice_deinit_hw(&pf->hw);
ice_deinit_dev(pf);
--
2.39.3
^ permalink raw reply related
* [PATCH net-next 1/2] devlink, mlx5: add init/fini ops for shared devlink
From: Przemek Kitszel @ 2026-04-28 9:09 UTC (permalink / raw)
To: netdev, Jakub Kicinski, Jiri Pirko
Cc: intel-wired-lan, Tony Nguyen, Jacob Keller, Lukasz Czapnik,
Jedrzej Jagielski, Andrew Lunn, David S. Miller, Eric Dumazet,
Paolo Abeni, Saeed Mahameed, Leon Romanovsky, Tariq Toukan,
Mark Bloch, Simon Horman, Przemek Kitszel, Aleksandr Loktionov
In-Reply-To: <20260428090912.3461-1-przemyslaw.kitszel@intel.com>
Add .shd_init() and .shd_fini() ops, that will be called for the first
devlink_shd_get() (to initialize driver' priv data) and on the last
devlink_shd_put() (to allow for the cleanup). Both ops are optional.
.shd_init() could return an error, which will stop creation of shd
instance. The initializer also gets an additional, optional param,
that driver could use for any needs.
If any of the callbacks will need to get devlink instance, it could
be accessed by shd_priv_to_devlink().
Both callbacks are called with devl_lock held and devlink registered.
Next commit will make use of the callbacks, another one will make use also
of the non-null additional param (outside of this series).
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Signed-off-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
---
first discussed at:
https://lore.kernel.org/netdev/20260325063143.261806-3-przemyslaw.kitszel@intel.com
Sashiko suggested to convert devlink_shd_create() to return ERR_PTR(),
and propagate that up to the driver. It think it will just make code more
verbose for not much benefit. And drivers could just store err if they
want in the passed @init_param.
---
include/net/devlink.h | 26 +++++++++++++
.../ethernet/mellanox/mlx5/core/sh_devlink.c | 2 +-
net/devlink/sh_dev.c | 39 ++++++++++++++++++-
3 files changed, 64 insertions(+), 3 deletions(-)
diff --git a/include/net/devlink.h b/include/net/devlink.h
index bcd31de1f890..5d3a1337bfa1 100644
--- a/include/net/devlink.h
+++ b/include/net/devlink.h
@@ -1586,6 +1586,30 @@ struct devlink_ops {
struct devlink_rate *parent,
void *priv_child, void *priv_parent,
struct netlink_ext_ack *extack);
+
+ /**
+ * shd_init: Shared devlink instance initializer
+ * @priv: shd_devlink' priv
+ * @init_param: additional param to pass to driver callback
+ *
+ * Called once when the shared instance is first created (by the first
+ * devlink_shd_get() call).
+ * Should initialize the driver's private data embedded in the shared
+ * devlink. May be NULL.
+ *
+ * Return: 0 on success, negative to prevent shared instance usage.
+ */
+ int (*shd_init)(void *priv, void *init_param);
+ /**
+ * shd_fini: Shared devlink instance finalizer
+ * @priv: shd_devlink' priv
+ *
+ * Called once when the last reference is dropped and the shared
+ * instance is destroyed. Should clean up the driver's private data.
+ * May be NULL.
+ */
+ void (*shd_fini)(void *priv);
+
/**
* selftests_check() - queries if selftest is supported
* @devlink: devlink instance
@@ -1651,9 +1675,11 @@ void devlink_free(struct devlink *devlink);
struct devlink *devlink_shd_get(const char *id,
const struct devlink_ops *ops,
size_t priv_size,
+ void *init_param,
const struct device_driver *driver);
void devlink_shd_put(struct devlink *devlink);
void *devlink_shd_get_priv(struct devlink *devlink);
+struct devlink *shd_priv_to_devlink(void *priv);
/**
* struct devlink_port_ops - Port operations
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/sh_devlink.c b/drivers/net/ethernet/mellanox/mlx5/core/sh_devlink.c
index b925364765ac..1b8b1ce7e72d 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/sh_devlink.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/sh_devlink.c
@@ -43,7 +43,7 @@ int mlx5_shd_init(struct mlx5_core_dev *dev)
*end = '\0';
/* Get or create shared devlink instance */
- devlink = devlink_shd_get(sn, &mlx5_shd_ops, 0, pdev->dev.driver);
+ devlink = devlink_shd_get(sn, &mlx5_shd_ops, 0, NULL, pdev->dev.driver);
kfree(sn);
if (!devlink)
return -ENOMEM;
diff --git a/net/devlink/sh_dev.c b/net/devlink/sh_dev.c
index 85acce97e788..048a2a6adc9e 100644
--- a/net/devlink/sh_dev.c
+++ b/net/devlink/sh_dev.c
@@ -34,6 +34,7 @@ static struct devlink_shd *devlink_shd_lookup(const char *id)
static struct devlink_shd *devlink_shd_create(const char *id,
const struct devlink_ops *ops,
size_t priv_size,
+ void *init_param,
const struct device_driver *driver)
{
struct devlink_shd *shd;
@@ -49,16 +50,30 @@ static struct devlink_shd *devlink_shd_create(const char *id,
if (!shd->id)
goto err_devlink_free;
shd->priv_size = priv_size;
- refcount_set(&shd->refcount, 1);
devl_lock(devlink);
devl_register(devlink);
+
+ if (ops->shd_init) {
+ int err;
+
+ err = ops->shd_init(shd->priv, init_param);
+ if (err)
+ goto err_unregister;
+ }
+
devl_unlock(devlink);
+ refcount_set(&shd->refcount, 1);
list_add_tail(&shd->list, &shd_list);
return shd;
+err_unregister:
+ devl_unregister(devlink);
+ devl_unlock(devlink);
+ kfree(shd->id);
+
err_devlink_free:
devlink_free(devlink);
return NULL;
@@ -69,7 +84,12 @@ static void devlink_shd_destroy(struct devlink_shd *shd)
struct devlink *devlink = priv_to_devlink(shd);
list_del(&shd->list);
+
devl_lock(devlink);
+
+ if (devlink->ops->shd_fini)
+ devlink->ops->shd_fini(shd->priv);
+
devl_unregister(devlink);
devl_unlock(devlink);
kfree(shd->id);
@@ -81,6 +101,7 @@ static void devlink_shd_destroy(struct devlink_shd *shd)
* @id: Identifier string (e.g., serial number) for the shared instance
* @ops: Devlink operations structure
* @priv_size: Size of private data structure
+ * @init_param: Passed to .shd_init() callback alongside driver's priv
* @driver: Driver associated with the shared devlink instance
*
* Get an existing shared devlink instance identified by @id, or create
@@ -96,16 +117,17 @@ static void devlink_shd_destroy(struct devlink_shd *shd)
struct devlink *devlink_shd_get(const char *id,
const struct devlink_ops *ops,
size_t priv_size,
+ void *init_param,
const struct device_driver *driver)
{
struct devlink *devlink;
struct devlink_shd *shd;
mutex_lock(&shd_mutex);
shd = devlink_shd_lookup(id);
if (!shd) {
- shd = devlink_shd_create(id, ops, priv_size, driver);
+ shd = devlink_shd_create(id, ops, priv_size, init_param, driver);
goto unlock;
}
@@ -159,3 +181,16 @@ void *devlink_shd_get_priv(struct devlink *devlink)
return shd->priv;
}
EXPORT_SYMBOL_GPL(devlink_shd_get_priv);
+
+/** shd_priv_to_devlink - Get devlink instance from shd_devlink's priv
+ * @priv: Driver's priv data
+ *
+ * Return: pointer to shared devlink instance the @priv belongs to.
+ */
+struct devlink *shd_priv_to_devlink(void *priv)
+{
+ struct devlink_shd *shd = container_of(priv, struct devlink_shd, priv);
+
+ return priv_to_devlink(shd);
+}
+EXPORT_SYMBOL_GPL(shd_priv_to_devlink);
--
2.39.3
^ permalink raw reply related
* [PATCH net-next 0/2] devlink, ice, mlx5: add init/fini ops for shared devlink for ice to use
From: Przemek Kitszel @ 2026-04-28 9:09 UTC (permalink / raw)
To: netdev, Jakub Kicinski, Jiri Pirko
Cc: intel-wired-lan, Tony Nguyen, Jacob Keller, Lukasz Czapnik,
Jedrzej Jagielski, Andrew Lunn, David S. Miller, Eric Dumazet,
Paolo Abeni, Saeed Mahameed, Leon Romanovsky, Tariq Toukan,
Mark Bloch, Simon Horman, Przemek Kitszel
Extend devlink by two callbacks used by shared devlink.
Callbacks provide option for the driver to have constructor/destructor
for the priv data attached to the shared devlink instance.
Use the callbacks from ice.
mlx5 is just touched to have additional param passed.
Non-null additional param for the constructor will be used by separate series.
Przemek Kitszel (2):
devlink, mlx5: add init/fini ops for shared devlink
ice: use shared devlink to store ice_adapters instead of custom xarray
drivers/net/ethernet/intel/ice/ice_adapter.h | 13 +--
include/net/devlink.h | 26 +++++
.../net/ethernet/intel/ice/devlink/devlink.c | 3 +
drivers/net/ethernet/intel/ice/ice_adapter.c | 95 ++++++-------------
drivers/net/ethernet/intel/ice/ice_main.c | 4 +-
.../ethernet/mellanox/mlx5/core/sh_devlink.c | 2 +-
net/devlink/sh_dev.c | 39 +++++++-
7 files changed, 106 insertions(+), 76 deletions(-)
--
2.39.3
^ permalink raw reply
* Re: [net-next PATCH 06/10] net: dsa: realtek: rtl8365mb: add VLAN support
From: Gabor Juhos @ 2026-04-28 9:26 UTC (permalink / raw)
To: Luiz Angelo Daros de Luca, Linus Walleij
Cc: Andrew Lunn, Vladimir Oltean, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Alvin Šipraga,
Yury Norov, Rasmus Villemoes, Russell King, netdev, linux-kernel
In-Reply-To: <CAJq09z6PjXeDYhfo3=UmLyUhXyx5rPHCK4kBaMaJWNZNssjo2Q@mail.gmail.com>
Hi Luiz, Linus,
Sorry for the late reply.
>
>>> I haven't yet wrapped my head around if the RTL8367 (no extra letters)
>>> is more RTL8366RB-ish or more RTL8365MB-ish... take a look at the
>>> old code if you can figure it out from register maps etc:
>>> https://github.com/openwrt/openwrt/tree/main/target/linux/generic/files/drivers/net/phy
>>> (maybe Gabor knows, put him on cc)
>
> Regarding the RTL8367 (no extra letters), the RTL8367R is indeed a
> member of that original family, rather than the "B" family as I
> previously suggested. It uses Port 9 for the CPU, which is absent in
> RTL8367B. Architecturally, it is definitely more RTL8365MB-ish.
I wrote the rtl8367 driver for the RTL8367R and RTL8367M switches. I have
no datasheet for those chips, but there are some basic information about
their features [1].
The driver was based on various code found in GPL sources of the TP-Link
TL-WR2543ND and ASUS RT-N56U devices. Those sources were using the RTL8370
specific API for these chips.
It was not clear that the two models really belongs to the RTL8370 family
or simply the vendors were using the RTL8370 specific code as a base, so
I have used RTL8367 prefix in the swconfig driver. Probably, it would have
been better to keep the RTL8370 prefix to avoid confusion.
>
> The main challenge with the base RTL8367 is the lack of a public API.
> Most vendors support it via binary managers (ASUS) or proprietary
> kernel modules (TP-Link). The only available references I’ve found are
> the OpenWrt swconfig driver you mentioned and some U-Boot
> initialization code. I do have the rtl8367{b,c,d} APIs. While the
> rtl8367b seems close to the original RTL8367, it has fewer ports. Does
> anyone happen to have access to the original RTL8367 API
> documentation?
I have no documentation, but the RTL8370 API source can be found at various
places [2], [3].
To be honest, I don't remember all the details, but I hope that this helps.
Regards,
Gabor
[1] http://semitron.co.kr/product/product.php?lcate=001&mcate=005&scate=004&uid=47&PHPSESSID=ec195486d91ed175f698567462571180
[2] https://github.com/cgoder/openwrt_rtk/tree/master/rtk_openwrt_sdk/target/linux/rtkmipsel/files/drivers/net/rtl819x/RTL8370_RTL8367_API
[3] https://github.com/andy-padavan/rt-n56u/tree/master/uboot/mips/uboot-5.x.x.x/drivers/rtl8367/api_8370
^ permalink raw reply
* Re: [PATCH net] tcp: do not shrink window clamp when SO_RCVBUF is locked
From: Ankit Jain @ 2026-04-28 9:21 UTC (permalink / raw)
To: kuba
Cc: netdev, edumazet, ncardwell, kuniyu, davem, dsahern, pabeni,
horms, quic_stranche, quic_subashab, linux-kernel, karen.badiryan,
ajay.kaher, alexey.makhalov, vamsi-krishna.brahmajosyula,
yin.ding, tapas.kundu
In-Reply-To: <20260427131111.168ed0dc@kernel.org>
Hi Jakub,
Thank you for pointing this out.
I checked the logic again, I placed the SOCK_RCVBUF_LOCK check on
the outer if-statement. This successfully prevented
tcp_set_window_clamp() from crushing the window (fixing the
Java SWS bug), but it accidentally bypassed the tp->rcvq_space.space
bounds check as well. Because of this, the receive queue tracking got
out of sync when the test hit a negative window.
For v2, I will move the lock check inside the block so it only bypasses
tcp_set_window_clamp(), ensuring the rcvq_space.space limits still
execute as expected.
I will test the refined logic against my reproducer and the
tcp_rcv_neg_window.pkt script locally, and I will post the v2 series
in a new thread after the 24-hour cooldown.
Thanks,
Ankit
^ permalink raw reply
* Re: [PATCH net 3/3] netconsole: propagate device name truncation in dev_name_store()
From: Simon Horman @ 2026-04-28 9:23 UTC (permalink / raw)
To: Breno Leitao
Cc: andrew+netdev, davem, edumazet, kuba, pabeni, k-keiichi, satyam,
akpm, thepacketgeek, asantostc, gustavold, netdev, linux-kernel,
kernel-team
In-Reply-To: <ae85UEWf7dgJtmeS@gmail.com>
On Mon, Apr 27, 2026 at 03:26:29AM -0700, Breno Leitao wrote:
> On Sun, Apr 26, 2026 at 09:39:05AM +0100, Simon Horman wrote:
> > From: 'Simon Horman' <horms@kernel.org>
> >
> > This is an AI-generated review of your patch. The human sending this
> > email has considered the AI review valid, or at least plausible.
> > Full review at: https://sashiko.dev
> > ---
> > netconsole: propagate device name truncation in dev_name_store()
> >
> > This commit rejects interface name writes that exceed the size of the
> > destination buffer to avoid silently truncating names and binding to
> > unintended devices.
> >
> > > diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
> > > index 4bef003d9df64..3914fb90f9afd 100644
> > > --- a/drivers/net/netconsole.c
> > > +++ b/drivers/net/netconsole.c
> > > @@ -816,6 +816,9 @@ static ssize_t dev_name_store(struct config_item *item, const char *buf,
> > > {
> > > struct netconsole_target *nt = to_target(item);
> > >
> > > + if (count >= IFNAMSIZ)
> > > + return -ENAMETOOLONG;
> > > +
> >
> > Does this check incorrectly reject valid maximum-length interface names when
> > written with a trailing newline?
> >
> > Standard userspace tools like echo append a trailing newline when writing to
> > configfs attributes. If userspace writes a 15-character name, the count will
> > be exactly 16 bytes.
> >
> > Since IFNAMSIZ is 16, the condition count >= IFNAMSIZ evaluates to true,
> > causing dev_name_store() to reject the valid input with -ENAMETOOLONG.
> >
> > Prior to this patch, strscpy() safely truncated the trailing newline by
> > copying the 15 characters and a NUL terminator.
>
> That is a valid issue, if someone is using a 16-byte ifname, it will fail, for
> instance:
>
> echo eth0123456789012 (15 chars) writes 16 bytes including the trailing \n
>
> With IFNAMSIZ=16, a valid 15-character interface name written via echo arrives
> as 16 bytes (15 chars + \n), and the count >= IFNAMSIZ check rejects it — a
> regression compared to the prior strscpy() + trim_newline() behavior, which
> silently dropped the newline.
>
> I think a better approach would be:
>
> size_t len = count;
>
> if (len && buf[len - 1] == '\n')
> len--;
> if (len >= IFNAMSIZ)
> return -ENAMETOOLONG;
>
> That keeps the length check consistent with what trim_newline() does to the
> stored string.
>
> I will send a v2.
Thanks. The approach above looks good to me.
^ permalink raw reply
* Re: [Intel-wired-lan] [PATCH v2] ice: wait for reset completion in ice_resume()
From: Paul Menzel @ 2026-04-28 9:17 UTC (permalink / raw)
To: Aaron Ma
Cc: Tony Nguyen, Przemek Kitszel, Andrew Lunn, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, netdev, linux-kernel,
Akeem G Abodunrin, Jesse Brandeburg, intel-wired-lan, Kohei Enju
In-Reply-To: <CAJ6xRxUEcbadApMg0i7ngcqYMUacrGNvCrUZ96sqkW22TsC7iA@mail.gmail.com>
Dear Aaron,
Thank you for your reply.
Am 28.04.26 um 09:53 schrieb Aaron Ma:
> On Mon, Apr 27, 2026 at 6:13 PM Paul Menzel wrote:
>> Am 24.04.26 um 05:03 schrieb Aaron Ma via Intel-wired-lan:
>>> ice_resume() schedules an asynchronous PF reset and returns
>>> immediately. The reset runs later in ice_service_task(). If
>>> userspace tries to bring up the net device before the reset
>>> finishes, ice_open() fails with -EBUSY:
>>>
>>> ice_resume()
>>> ice_schedule_reset() # sets ICE_PFR_REQ, returns
>>> ...
>>> ice_open()
>>> ice_is_reset_in_progress() # ICE_PFR_REQ still set, -EBUSY
>>> ...
>>> ice_service_task()
>>> ice_do_reset()
>>> ice_rebuild() # clears ICE_PFR_REQ, too late
>>>
>>> Reproduced on E800 series NICs during suspend/resume with irdma
>>> enabled, where the aux device probe widens the race window.
>>
>> Please document, how you reproduced it, and also paste possible messages
>> by Linux or NetworkManager, so that people can easily search for the commit.
>
> The error message is "can't open net device while reset is in progress"
> I can add it in v3 if you like.
Yes, that’d be great.
> > > Wait for the reset to complete before returning from ice_resume().
>>
>> Please mention the delay length in the commit message.
>
> The timeout is 10 * HZ (10 seconds), matching the existing usage in
> ice_devlink_info_get() for the same ice_wait_for_reset() call. In
> practice the wait completes in ~300ms.
I often wonder, where the delay values come from. Maybe mention, that
you copied it.
>>> Fixes: 769c500dcc1e ("ice: Add advanced power mgmt for WoL")
>>> Cc: stable@vger.kernel.org
>>> Signed-off-by: Aaron Ma <aaron.ma@canonical.com>
>>> ---
>>> v2: reword comment to clarify best-effort semantics (Kohei Enju)
>>>
>>> drivers/net/ethernet/intel/ice/ice_main.c | 9 +++++++++
>>> 1 file changed, 9 insertions(+)
>>>
>>> diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c
>>> index 5f92377d4dfc2..a81eb21ea87c1 100644
>>> --- a/drivers/net/ethernet/intel/ice/ice_main.c
>>> +++ b/drivers/net/ethernet/intel/ice/ice_main.c
>>> @@ -5635,6 +5635,15 @@ static int ice_resume(struct device *dev)
>>> /* Restart the service task */
>>> mod_timer(&pf->serv_tmr, round_jiffies(jiffies + pf->serv_tmr_period));
>>>
>>> + /* Best-effort wait for the scheduled reset to finish so that the
>>> + * device is operational before returning. Without this, userspace
>>> + * (e.g. NetworkManager) may try to open the net device while the
>>> + * asynchronous reset is still in progress, hitting -EBUSY.
>>> + */
>>> + ret = ice_wait_for_reset(pf, 10 * HZ);
>>
>> Why not pass a delay in micro/milliseconds?
>
> ice_wait_for_reset() takes jiffies — that's the existing API.
It’s recommended to use `msecs_to_jiffies()` to make it HZ invariant.
>>> + if (ret)
>>> + dev_err(dev, "Wait for reset failed during resume: %d\n", ret);
>>
>> Mention the delay?
>
> Good point. I'll include the timeout in the error message in v3.
Awesome.
[…]
Thanks,
Paul
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox