Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net_sched: act_nat: use RCU in tcf_nat_dump()

Also storing tcf_action into struct tcf_nat_params
makes sure there is no discrepancy in tcf_nat_act().

Signed-off-by: Eric Dumazet <edumazet@google.com>
Link: https://patch.msgid.link/20250709090204.797558-9-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Eric Dumazet and committed by
Jakub Kicinski
5d289286 8151684e

+13 -13
+1
include/net/tc_act/tc_nat.h
··· 6 6 #include <net/act_api.h> 7 7 8 8 struct tcf_nat_parms { 9 + int action; 9 10 __be32 old_addr; 10 11 __be32 new_addr; 11 12 __be32 mask;
+12 -13
net/sched/act_nat.c
··· 91 91 nparm->new_addr = parm->new_addr; 92 92 nparm->mask = parm->mask; 93 93 nparm->flags = parm->flags; 94 + nparm->action = parm->action; 94 95 95 96 p = to_tcf_nat(*a); 96 97 ··· 131 130 tcf_lastuse_update(&p->tcf_tm); 132 131 tcf_action_update_bstats(&p->common, skb); 133 132 134 - action = READ_ONCE(p->tcf_action); 135 - 136 133 parms = rcu_dereference_bh(p->parms); 134 + action = parms->action; 135 + if (unlikely(action == TC_ACT_SHOT)) 136 + goto drop; 137 + 137 138 old_addr = parms->old_addr; 138 139 new_addr = parms->new_addr; 139 140 mask = parms->mask; 140 141 egress = parms->flags & TCA_NAT_FLAG_EGRESS; 141 - 142 - if (unlikely(action == TC_ACT_SHOT)) 143 - goto drop; 144 142 145 143 noff = skb_network_offset(skb); 146 144 if (!pskb_may_pull(skb, sizeof(*iph) + noff)) ··· 268 268 int bind, int ref) 269 269 { 270 270 unsigned char *b = skb_tail_pointer(skb); 271 - struct tcf_nat *p = to_tcf_nat(a); 271 + const struct tcf_nat *p = to_tcf_nat(a); 272 + const struct tcf_nat_parms *parms; 272 273 struct tc_nat opt = { 273 274 .index = p->tcf_index, 274 275 .refcnt = refcount_read(&p->tcf_refcnt) - ref, 275 276 .bindcnt = atomic_read(&p->tcf_bindcnt) - bind, 276 277 }; 277 - struct tcf_nat_parms *parms; 278 278 struct tcf_t t; 279 279 280 - spin_lock_bh(&p->tcf_lock); 280 + rcu_read_lock(); 281 281 282 - opt.action = p->tcf_action; 282 + parms = rcu_dereference(p->parms); 283 283 284 - parms = rcu_dereference_protected(p->parms, lockdep_is_held(&p->tcf_lock)); 285 - 284 + opt.action = parms->action; 286 285 opt.old_addr = parms->old_addr; 287 286 opt.new_addr = parms->new_addr; 288 287 opt.mask = parms->mask; ··· 293 294 tcf_tm_dump(&t, &p->tcf_tm); 294 295 if (nla_put_64bit(skb, TCA_NAT_TM, sizeof(t), &t, TCA_NAT_PAD)) 295 296 goto nla_put_failure; 296 - spin_unlock_bh(&p->tcf_lock); 297 + rcu_read_unlock(); 297 298 298 299 return skb->len; 299 300 300 301 nla_put_failure: 301 - spin_unlock_bh(&p->tcf_lock); 302 + rcu_read_unlock(); 302 303 nlmsg_trim(skb, b); 303 304 return -1; 304 305 }