From 0a33bdce34c68f1d158d2ee3c9dfd011bef5c290 Mon Sep 17 00:00:00 2001 From: Ismael Luceno Date: Thu, 2 Jul 2026 12:10:50 +0200 Subject: [PATCH 1/7] ipvs: Move defense_work and est_reload_work to system_dfl_long_wq Under synflood conditions binding these handlers to system_long_wq may pin them to a saturated CPU. We've observed improved throughtput on a DPDK/VPP application with this change, which we attribute to the reduced context switching. Neither handler has per-CPU data dependencies nor cache locality requirements that would prevent this change. Signed-off-by: Ismael Luceno Acked-by: Julian Anastasov Signed-off-by: Pablo Neira Ayuso --- net/netfilter/ipvs/ip_vs_ctl.c | 6 +++--- net/netfilter/ipvs/ip_vs_est.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c index bcf40b8c41cf..d7e669efab4d 100644 --- a/net/netfilter/ipvs/ip_vs_ctl.c +++ b/net/netfilter/ipvs/ip_vs_ctl.c @@ -235,7 +235,7 @@ static void defense_work_handler(struct work_struct *work) update_defense_level(ipvs); if (atomic_read(&ipvs->dropentry)) ip_vs_random_dropentry(ipvs); - queue_delayed_work(system_long_wq, &ipvs->defense_work, + queue_delayed_work(system_dfl_long_wq, &ipvs->defense_work, DEFENSE_TIMER_PERIOD); } #endif @@ -290,7 +290,7 @@ static void est_reload_work_handler(struct work_struct *work) atomic_set(&ipvs->est_genid_done, genid); if (repeat) - queue_delayed_work(system_long_wq, &ipvs->est_reload_work, + queue_delayed_work(system_dfl_long_wq, &ipvs->est_reload_work, delay); unlock: @@ -5126,7 +5126,7 @@ static int __net_init ip_vs_control_net_init_sysctl(struct netns_ipvs *ipvs) goto err; /* Schedule defense work */ - queue_delayed_work(system_long_wq, &ipvs->defense_work, + queue_delayed_work(system_dfl_long_wq, &ipvs->defense_work, DEFENSE_TIMER_PERIOD); return 0; diff --git a/net/netfilter/ipvs/ip_vs_est.c b/net/netfilter/ipvs/ip_vs_est.c index ab09f5182951..78964aa861e9 100644 --- a/net/netfilter/ipvs/ip_vs_est.c +++ b/net/netfilter/ipvs/ip_vs_est.c @@ -243,7 +243,7 @@ void ip_vs_est_reload_start(struct netns_ipvs *ipvs, bool restart) /* Bump the kthread configuration genid if stopping is requested */ if (restart) atomic_inc(&ipvs->est_genid); - queue_delayed_work(system_long_wq, &ipvs->est_reload_work, 0); + queue_delayed_work(system_dfl_long_wq, &ipvs->est_reload_work, 0); } /* Start kthread task with current configuration */ From 4172fd3697b0405e4f9654a950b4adf33f3a796c Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Sat, 4 Jul 2026 09:31:33 +0200 Subject: [PATCH 2/7] netfilter: xt_tcpmss: extend checkentry to ipv6 sashiko reports: Is it intentional that the new parameter validation callback is applied only to the NFPROTO_IPV4 match? Fixes: 68fc6c6470d6 ("netfilter: xt_tcpmss: add checkentry for parameter validation") Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- net/netfilter/xt_tcpmss.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/netfilter/xt_tcpmss.c b/net/netfilter/xt_tcpmss.c index b08b077d7f0a..5f7f97dbace5 100644 --- a/net/netfilter/xt_tcpmss.c +++ b/net/netfilter/xt_tcpmss.c @@ -103,6 +103,7 @@ static struct xt_match tcpmss_mt_reg[] __read_mostly = { { .name = "tcpmss", .family = NFPROTO_IPV6, + .checkentry = tcpmss_mt_check, .match = tcpmss_mt, .matchsize = sizeof(struct xt_tcpmss_match_info), .proto = IPPROTO_TCP, From 16aecbe3036f6097c26b51b12e4c1cf207769690 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Mon, 6 Jul 2026 14:30:55 +0200 Subject: [PATCH 3/7] netfilter: nf_nat_sip: rewind offset when NAT shrinks the packet sashiko says: If map_addr() changes the packet length, such as when the public NAT IP string is shorter or longer than the internal IP, coff will still point to the offset relative to the pre-mangled packet. If the packet shrinks, coff could overshoot the correct position, potentially causing the next ct_sip_parse_header_uri() call to silently skip bytes and miss subsequent Contact headers. Could this lead to a failure to NAT those subsequent headers and leak internal network details? Fixes: c978cd3a9371 ("[NETFILTER]: nf_nat_sip: translate all Contact headers") Assisted-by: Claude:claude-sonnet-4-6 Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nf_nat_sip.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/net/netfilter/nf_nat_sip.c b/net/netfilter/nf_nat_sip.c index aea02f6aff09..762d7e7bb7c7 100644 --- a/net/netfilter/nf_nat_sip.c +++ b/net/netfilter/nf_nat_sip.c @@ -273,12 +273,17 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff, SIP_HDR_CONTACT, &in_header, &matchoff, &matchlen, &addr, &port) > 0) { + int old_len = skb->len, delta; + if (!map_addr(skb, protoff, dataoff, dptr, datalen, matchoff, matchlen, &addr, port)) { nf_ct_helper_log(skb, ct, "cannot mangle contact"); return NF_DROP; } + + delta = (int)skb->len - old_len; + coff += delta; } if (!map_sip_addr(skb, protoff, dataoff, dptr, datalen, SIP_HDR_FROM) || From edd51a23343870dbd7cedf6e2765c13cf7a5ccbc Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 10 Jul 2026 09:54:09 +0200 Subject: [PATCH 4/7] netfilter: flowtable: tear down flow entries with stale dst from GC In case of route updates, tear down flow entries with stale dst to give them a chance to obtain a fresh route. This is specifically useful for hardware offloaded entries, where the flowtable software dataplane sees no packet, where the existing check for stale dst entries does not help. Signed-off-by: Pablo Neira Ayuso --- include/net/netfilter/nf_flow_table.h | 8 ++++++++ net/netfilter/nf_flow_table_core.c | 2 ++ net/netfilter/nf_flow_table_ip.c | 8 -------- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/include/net/netfilter/nf_flow_table.h b/include/net/netfilter/nf_flow_table.h index ce414118962f..a090ec3ffef2 100644 --- a/include/net/netfilter/nf_flow_table.h +++ b/include/net/netfilter/nf_flow_table.h @@ -310,6 +310,14 @@ int flow_offload_add(struct nf_flowtable *flow_table, struct flow_offload *flow) void flow_offload_refresh(struct nf_flowtable *flow_table, struct flow_offload *flow, bool force); +static inline bool nf_flow_dst_check(struct flow_offload_tuple *tuple) +{ + if (!tuple->dst_cache) + return true; + + return dst_check(tuple->dst_cache, tuple->dst_cookie); +} + struct flow_offload_tuple_rhash *flow_offload_lookup(struct nf_flowtable *flow_table, struct flow_offload_tuple *tuple); void nf_flow_table_gc_run(struct nf_flowtable *flow_table); diff --git a/net/netfilter/nf_flow_table_core.c b/net/netfilter/nf_flow_table_core.c index b66e65439341..58e6a675332d 100644 --- a/net/netfilter/nf_flow_table_core.c +++ b/net/netfilter/nf_flow_table_core.c @@ -571,6 +571,8 @@ static void nf_flow_offload_gc_step(struct nf_flowtable *flow_table, if (nf_flow_has_expired(flow) || nf_ct_is_dying(flow->ct) || + !nf_flow_dst_check(&flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple) || + !nf_flow_dst_check(&flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple) || nf_flow_custom_gc(flow_table, flow)) { flow_offload_teardown(flow); teardown = true; diff --git a/net/netfilter/nf_flow_table_ip.c b/net/netfilter/nf_flow_table_ip.c index 0b78decce8a9..0b314b10e705 100644 --- a/net/netfilter/nf_flow_table_ip.c +++ b/net/netfilter/nf_flow_table_ip.c @@ -297,14 +297,6 @@ static bool nf_flow_exceeds_mtu(const struct sk_buff *skb, unsigned int mtu) return true; } -static inline bool nf_flow_dst_check(struct flow_offload_tuple *tuple) -{ - if (!tuple->dst_cache) - return true; - - return dst_check(tuple->dst_cache, tuple->dst_cookie); -} - static unsigned int nf_flow_xmit_xfrm(struct sk_buff *skb, const struct nf_hook_state *state, struct dst_entry *dst) From 1c66ad76ddd4c9f141cae84e6a56c34e090cb3d9 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 13 Jul 2026 18:06:57 +0200 Subject: [PATCH 5/7] netfilter: conntrack_helper: pass master conntrack to helper functions Pass master conntrack as argument to helper functions that parse the packet payload, instead of using exp->master. Although accessing exp->master is safe in this case because it refers to the master conntrack in used by this skb, remove it to step towards turning the exp->master field into a cookie value. Signed-off-by: Pablo Neira Ayuso --- include/linux/netfilter/nf_conntrack_amanda.h | 1 + include/linux/netfilter/nf_conntrack_ftp.h | 1 + include/linux/netfilter/nf_conntrack_irc.h | 1 + include/linux/netfilter/nf_conntrack_tftp.h | 1 + net/netfilter/nf_conntrack_amanda.c | 2 +- net/netfilter/nf_conntrack_ftp.c | 2 +- net/netfilter/nf_conntrack_irc.c | 2 +- net/netfilter/nf_conntrack_tftp.c | 2 +- net/netfilter/nf_nat_amanda.c | 7 ++++--- net/netfilter/nf_nat_ftp.c | 4 ++-- net/netfilter/nf_nat_irc.c | 2 +- net/netfilter/nf_nat_tftp.c | 5 ++--- 12 files changed, 17 insertions(+), 13 deletions(-) diff --git a/include/linux/netfilter/nf_conntrack_amanda.h b/include/linux/netfilter/nf_conntrack_amanda.h index 1719987e8fd8..deb560bb79c4 100644 --- a/include/linux/netfilter/nf_conntrack_amanda.h +++ b/include/linux/netfilter/nf_conntrack_amanda.h @@ -9,6 +9,7 @@ typedef unsigned int nf_nat_amanda_hook_fn(struct sk_buff *skb, + struct nf_conn *ct, enum ip_conntrack_info ctinfo, unsigned int protoff, unsigned int matchoff, diff --git a/include/linux/netfilter/nf_conntrack_ftp.h b/include/linux/netfilter/nf_conntrack_ftp.h index 7b62446ccec4..712702183b94 100644 --- a/include/linux/netfilter/nf_conntrack_ftp.h +++ b/include/linux/netfilter/nf_conntrack_ftp.h @@ -28,6 +28,7 @@ struct nf_ct_ftp_master { * connection we should expect. */ typedef unsigned int nf_nat_ftp_hook_fn(struct sk_buff *skb, + struct nf_conn *ct, enum ip_conntrack_info ctinfo, enum nf_ct_ftp_type type, unsigned int protoff, diff --git a/include/linux/netfilter/nf_conntrack_irc.h b/include/linux/netfilter/nf_conntrack_irc.h index ce07250afb4e..c73b3b44a0b7 100644 --- a/include/linux/netfilter/nf_conntrack_irc.h +++ b/include/linux/netfilter/nf_conntrack_irc.h @@ -10,6 +10,7 @@ typedef unsigned int nf_nat_irc_hook_fn(struct sk_buff *skb, + struct nf_conn *ct, enum ip_conntrack_info ctinfo, unsigned int protoff, unsigned int matchoff, diff --git a/include/linux/netfilter/nf_conntrack_tftp.h b/include/linux/netfilter/nf_conntrack_tftp.h index e3d1739c557d..802cb7fc19cd 100644 --- a/include/linux/netfilter/nf_conntrack_tftp.h +++ b/include/linux/netfilter/nf_conntrack_tftp.h @@ -19,6 +19,7 @@ struct tftphdr { typedef unsigned int nf_nat_tftp_hook_fn(struct sk_buff *skb, + struct nf_conn *ct, enum ip_conntrack_info ctinfo, struct nf_conntrack_expect *exp); diff --git a/net/netfilter/nf_conntrack_amanda.c b/net/netfilter/nf_conntrack_amanda.c index 06d6ec12c86d..14ae660491f3 100644 --- a/net/netfilter/nf_conntrack_amanda.c +++ b/net/netfilter/nf_conntrack_amanda.c @@ -151,7 +151,7 @@ static int amanda_help(struct sk_buff *skb, nf_nat_amanda = rcu_dereference(nf_nat_amanda_hook); if (nf_nat_amanda && ct->status & IPS_NAT_MASK) - ret = nf_nat_amanda(skb, ctinfo, protoff, + ret = nf_nat_amanda(skb, ct, ctinfo, protoff, off - dataoff, len, exp); else if (nf_ct_expect_related(exp, 0) != 0) { nf_ct_helper_log(skb, ct, "cannot add expectation"); diff --git a/net/netfilter/nf_conntrack_ftp.c b/net/netfilter/nf_conntrack_ftp.c index f3944598c172..f4fe13fd0e70 100644 --- a/net/netfilter/nf_conntrack_ftp.c +++ b/net/netfilter/nf_conntrack_ftp.c @@ -515,7 +515,7 @@ static int help(struct sk_buff *skb, * (possibly changed) expectation itself. */ nf_nat_ftp = rcu_dereference(nf_nat_ftp_hook); if (nf_nat_ftp && ct->status & IPS_NAT_MASK) - ret = nf_nat_ftp(skb, ctinfo, search[dir][i].ftptype, + ret = nf_nat_ftp(skb, ct, ctinfo, search[dir][i].ftptype, protoff, matchoff, matchlen, exp); else { /* Can't expect this? Best to drop packet now. */ diff --git a/net/netfilter/nf_conntrack_irc.c b/net/netfilter/nf_conntrack_irc.c index 4e6bafe41437..92360963757a 100644 --- a/net/netfilter/nf_conntrack_irc.c +++ b/net/netfilter/nf_conntrack_irc.c @@ -231,7 +231,7 @@ static int help(struct sk_buff *skb, unsigned int protoff, nf_nat_irc = rcu_dereference(nf_nat_irc_hook); if (nf_nat_irc && ct->status & IPS_NAT_MASK) - ret = nf_nat_irc(skb, ctinfo, protoff, + ret = nf_nat_irc(skb, ct, ctinfo, protoff, addr_beg_p - ib_ptr, addr_end_p - addr_beg_p, exp); diff --git a/net/netfilter/nf_conntrack_tftp.c b/net/netfilter/nf_conntrack_tftp.c index a69559edf9b3..e672d74a6817 100644 --- a/net/netfilter/nf_conntrack_tftp.c +++ b/net/netfilter/nf_conntrack_tftp.c @@ -69,7 +69,7 @@ static int tftp_help(struct sk_buff *skb, nf_nat_tftp = rcu_dereference(nf_nat_tftp_hook); if (nf_nat_tftp && ct->status & IPS_NAT_MASK) - ret = nf_nat_tftp(skb, ctinfo, exp); + ret = nf_nat_tftp(skb, ct, ctinfo, exp); else if (nf_ct_expect_related(exp, 0) != 0) { nf_ct_helper_log(skb, ct, "cannot add expectation"); ret = NF_DROP; diff --git a/net/netfilter/nf_nat_amanda.c b/net/netfilter/nf_nat_amanda.c index 8f1054920a85..330415809425 100644 --- a/net/netfilter/nf_nat_amanda.c +++ b/net/netfilter/nf_nat_amanda.c @@ -26,6 +26,7 @@ static struct nf_conntrack_nat_helper nat_helper_amanda = NF_CT_NAT_HELPER_INIT(NAT_HELPER_NAME); static unsigned int help(struct sk_buff *skb, + struct nf_conn *ct, enum ip_conntrack_info ctinfo, unsigned int protoff, unsigned int matchoff, @@ -46,15 +47,15 @@ static unsigned int help(struct sk_buff *skb, /* Try to get same port: if not, try to change it. */ port = nf_nat_exp_find_port(exp, ntohs(exp->saved_proto.tcp.port)); if (port == 0) { - nf_ct_helper_log(skb, exp->master, "all ports in use"); + nf_ct_helper_log(skb, ct, "all ports in use"); return NF_DROP; } snprintf(buffer, sizeof(buffer), "%u", port); - if (!nf_nat_mangle_udp_packet(skb, exp->master, ctinfo, + if (!nf_nat_mangle_udp_packet(skb, ct, ctinfo, protoff, matchoff, matchlen, buffer, strlen(buffer))) { - nf_ct_helper_log(skb, exp->master, "cannot mangle packet"); + nf_ct_helper_log(skb, ct, "cannot mangle packet"); nf_ct_unexpect_related(exp); return NF_DROP; } diff --git a/net/netfilter/nf_nat_ftp.c b/net/netfilter/nf_nat_ftp.c index c92a436d9c48..25d20e2970ae 100644 --- a/net/netfilter/nf_nat_ftp.c +++ b/net/netfilter/nf_nat_ftp.c @@ -61,6 +61,7 @@ static int nf_nat_ftp_fmt_cmd(struct nf_conn *ct, enum nf_ct_ftp_type type, /* So, this packet has hit the connection tracking matching code. Mangle it, and change the expectation to match the new version. */ static unsigned int nf_nat_ftp(struct sk_buff *skb, + struct nf_conn *ct, enum ip_conntrack_info ctinfo, enum nf_ct_ftp_type type, unsigned int protoff, @@ -71,7 +72,6 @@ static unsigned int nf_nat_ftp(struct sk_buff *skb, union nf_inet_addr newaddr; u_int16_t port; int dir = CTINFO2DIR(ctinfo); - struct nf_conn *ct = exp->master; char buffer[sizeof("|1||65535|") + INET6_ADDRSTRLEN]; unsigned int buflen; @@ -88,7 +88,7 @@ static unsigned int nf_nat_ftp(struct sk_buff *skb, port = nf_nat_exp_find_port(exp, ntohs(exp->saved_proto.tcp.port)); if (port == 0) { - nf_ct_helper_log(skb, exp->master, "all ports in use"); + nf_ct_helper_log(skb, ct, "all ports in use"); return NF_DROP; } diff --git a/net/netfilter/nf_nat_irc.c b/net/netfilter/nf_nat_irc.c index 19c4fcc60c50..89b31fe932ba 100644 --- a/net/netfilter/nf_nat_irc.c +++ b/net/netfilter/nf_nat_irc.c @@ -30,6 +30,7 @@ static struct nf_conntrack_nat_helper nat_helper_irc = NF_CT_NAT_HELPER_INIT(NAT_HELPER_NAME); static unsigned int help(struct sk_buff *skb, + struct nf_conn *ct, enum ip_conntrack_info ctinfo, unsigned int protoff, unsigned int matchoff, @@ -37,7 +38,6 @@ static unsigned int help(struct sk_buff *skb, struct nf_conntrack_expect *exp) { char buffer[sizeof("4294967296 65635")]; - struct nf_conn *ct = exp->master; union nf_inet_addr newaddr; u_int16_t port; diff --git a/net/netfilter/nf_nat_tftp.c b/net/netfilter/nf_nat_tftp.c index 1a591132d6eb..7121e6704f34 100644 --- a/net/netfilter/nf_nat_tftp.c +++ b/net/netfilter/nf_nat_tftp.c @@ -21,17 +21,16 @@ static struct nf_conntrack_nat_helper nat_helper_tftp = NF_CT_NAT_HELPER_INIT(NAT_HELPER_NAME); static unsigned int help(struct sk_buff *skb, + struct nf_conn *ct, enum ip_conntrack_info ctinfo, struct nf_conntrack_expect *exp) { - const struct nf_conn *ct = exp->master; - exp->saved_proto.udp.port = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.udp.port; exp->dir = IP_CT_DIR_REPLY; exp->expectfn = nf_nat_follow_master; if (nf_ct_expect_related(exp, 0) != 0) { - nf_ct_helper_log(skb, exp->master, "cannot add expectation"); + nf_ct_helper_log(skb, ct, "cannot add expectation"); return NF_DROP; } return NF_ACCEPT; From 874f455c3a2954b5b56fbedf97da39c34df9dc0e Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 13 Jul 2026 18:06:58 +0200 Subject: [PATCH 6/7] netfilter: nf_conntrack_expect: store event cache in expectation Store the event cache in the expectation instead of accessing the exp->master cache, as a step forward towards turning the exp->master into a cookie. Signed-off-by: Pablo Neira Ayuso --- include/net/netfilter/nf_conntrack_expect.h | 3 +++ net/netfilter/nf_conntrack_broadcast.c | 6 ++++++ net/netfilter/nf_conntrack_ecache.c | 7 +------ net/netfilter/nf_conntrack_expect.c | 5 +++++ net/netfilter/nf_conntrack_netlink.c | 5 +++++ 5 files changed, 20 insertions(+), 6 deletions(-) diff --git a/include/net/netfilter/nf_conntrack_expect.h b/include/net/netfilter/nf_conntrack_expect.h index c024345c9bd8..5d0f5b2f12a7 100644 --- a/include/net/netfilter/nf_conntrack_expect.h +++ b/include/net/netfilter/nf_conntrack_expect.h @@ -42,6 +42,9 @@ struct nf_conntrack_expect { /* Expectation class */ unsigned int class; + /* Event filter mask */ + u16 event_mask; + /* Function to call after setup and insertion */ void (*expectfn)(struct nf_conn *new, struct nf_conntrack_expect *this); diff --git a/net/netfilter/nf_conntrack_broadcast.c b/net/netfilter/nf_conntrack_broadcast.c index 6ff954f1bfb8..0922e30b6ab0 100644 --- a/net/netfilter/nf_conntrack_broadcast.c +++ b/net/netfilter/nf_conntrack_broadcast.c @@ -14,6 +14,7 @@ #include #include #include +#include int nf_conntrack_broadcast_help(struct sk_buff *skb, struct nf_conn *ct, @@ -27,6 +28,7 @@ int nf_conntrack_broadcast_help(struct sk_buff *skb, struct rtable *rt = skb_rtable(skb); struct in_device *in_dev; struct nf_conn_help *help = nfct_help(ct); + struct nf_conntrack_ecache *ecache; __be32 mask = 0; if (!help) @@ -79,6 +81,10 @@ int nf_conntrack_broadcast_help(struct sk_buff *skb, #ifdef CONFIG_NF_CONNTRACK_ZONES exp->zone = ct->zone; #endif + ecache = nf_ct_ecache_find(ct); + if (ecache) + exp->event_mask = ecache->expmask; + nf_ct_expect_related(exp, 0); nf_ct_expect_put(exp); diff --git a/net/netfilter/nf_conntrack_ecache.c b/net/netfilter/nf_conntrack_ecache.c index cc8d8e85169f..fb731ee235d8 100644 --- a/net/netfilter/nf_conntrack_ecache.c +++ b/net/netfilter/nf_conntrack_ecache.c @@ -245,7 +245,6 @@ void nf_ct_expect_event_report(enum ip_conntrack_expect_events event, { struct net *net = nf_ct_exp_net(exp); struct nf_ct_event_notifier *notify; - struct nf_conntrack_ecache *e; lockdep_nfct_expect_lock_held(); @@ -254,11 +253,7 @@ void nf_ct_expect_event_report(enum ip_conntrack_expect_events event, if (!notify) goto out_unlock; - e = nf_ct_ecache_find(exp->master); - if (!e) - goto out_unlock; - - if (e->expmask & (1 << event)) { + if (exp->event_mask & (1 << event)) { struct nf_exp_event item = { .exp = exp, .portid = portid, diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c index 7ae68d60586a..cd9af3620af5 100644 --- a/net/netfilter/nf_conntrack_expect.c +++ b/net/netfilter/nf_conntrack_expect.c @@ -330,6 +330,7 @@ void nf_ct_expect_init(struct nf_conntrack_expect *exp, unsigned int class, struct nf_conntrack_helper *helper = NULL; struct nf_conn *ct = exp->master; struct net *net = read_pnet(&ct->ct_net); + struct nf_conntrack_ecache *ecache; struct nf_conn_help *help; int len; @@ -342,6 +343,10 @@ void nf_ct_expect_init(struct nf_conntrack_expect *exp, unsigned int class, exp->class = class; exp->expectfn = NULL; + ecache = nf_ct_ecache_find(ct); + if (ecache) + exp->event_mask = ecache->expmask; + help = nfct_help(ct); if (help) helper = rcu_dereference(help->helper); diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 31cbb1b55b9e..fc3f60099af3 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -3524,6 +3524,7 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct, { struct net *net = read_pnet(&ct->ct_net); struct nf_conntrack_helper *helper; + struct nf_conntrack_ecache *ecache; struct nf_conntrack_expect *exp; struct nf_conn_help *help; u32 class = 0; @@ -3575,6 +3576,10 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct, exp->mask.src.u3 = mask->src.u3; exp->mask.src.u.all = mask->src.u.all; + ecache = nf_ct_ecache_find(ct); + if (ecache) + exp->event_mask = ecache->expmask; + if (cda[CTA_EXPECT_NAT]) { err = ctnetlink_parse_expect_nat(cda[CTA_EXPECT_NAT], exp, nf_ct_l3num(ct)); From cca2780b61947fd27ec621541edd0902e193a609 Mon Sep 17 00:00:00 2001 From: Subasri S Date: Thu, 16 Jul 2026 19:37:10 +0530 Subject: [PATCH 7/7] ipvs: use type-safe allocation helpers in ip_vs_rht_alloc As per Documentation/process/deprecated.rst, open-coded kmalloc assignments for struct objects are deprecated. Replace kzalloc(sizeof(*ptr), GFP_KERNEL) with kzalloc_obj() and kvmalloc_array(n, sizeof(*ptr), GFP_KERNEL) with kvmalloc_objs() in ip_vs_rht_alloc(). Compile tested with CONFIG_IP_VS=y and runtime tested using tools/testing/selftests/net/netfilter/ipvs.sh on x86_64/QEMU. Signed-off-by: Subasri S Reviewed-by: Phil Sutter Acked-by: Julian Anastasov Signed-off-by: Pablo Neira Ayuso --- net/netfilter/ipvs/ip_vs_core.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c index bafab93451d0..a896bfb53f07 100644 --- a/net/netfilter/ipvs/ip_vs_core.c +++ b/net/netfilter/ipvs/ip_vs_core.c @@ -176,7 +176,7 @@ void ip_vs_rht_rcu_free(struct rcu_head *head) struct ip_vs_rht *ip_vs_rht_alloc(int buckets, int scounts, int locks) { - struct ip_vs_rht *t = kzalloc(sizeof(*t), GFP_KERNEL); + struct ip_vs_rht *t = kzalloc_obj(*t); int i; if (!t) @@ -186,7 +186,7 @@ struct ip_vs_rht *ip_vs_rht_alloc(int buckets, int scounts, int locks) scounts = min(scounts, buckets); scounts = min(scounts, ml); - t->seqc = kvmalloc_array(scounts, sizeof(*t->seqc), GFP_KERNEL); + t->seqc = kvmalloc_objs(*t->seqc, scounts); if (!t->seqc) goto err; for (i = 0; i < scounts; i++) @@ -194,8 +194,7 @@ struct ip_vs_rht *ip_vs_rht_alloc(int buckets, int scounts, int locks) if (locks) { locks = min(locks, scounts); - t->lock = kvmalloc_array(locks, sizeof(*t->lock), - GFP_KERNEL); + t->lock = kvmalloc_objs(*t->lock, locks); if (!t->lock) goto err; for (i = 0; i < locks; i++) @@ -203,7 +202,7 @@ struct ip_vs_rht *ip_vs_rht_alloc(int buckets, int scounts, int locks) } } - t->buckets = kvmalloc_array(buckets, sizeof(*t->buckets), GFP_KERNEL); + t->buckets = kvmalloc_objs(*t->buckets, buckets); if (!t->buckets) goto err; for (i = 0; i < buckets; i++)