[PATCH net-next 1/2] net/sched: honor TCA_ACT_FLAGS_NO_PERCPU_STATS in more actions
flat view
HOTtoday
From: Alexandre Cassen <hidden>
Date: 2026-10-09 05:19:39
Subsystem:
networking [general], tc subsystem, the rest · Maintainers:
"David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Jamal Hadi Salim, Jiri Pirko, Linus Torvalds
skbedit, police, mpls and sample store and dump
TCA_ACT_FLAGS_NO_PERCPU_STATS since commit 40bd094d65fc ("flow_offload:
fill flags to action structure"), but still allocate per CPU stats.
With the flag set, these actions update their counters the same way gact
and mirred already do via tcf_action_update_bstats() and the qstats
helpers, which take the action lock and use atomics when the per CPU
counters are absent. Those helpers are correct in the software path. The
problem is the hardware stats path used when an action is offloaded but
skip_sw is not set: tcf_action_update_stats() writes the same counters
without holding tcfa_lock, so the two paths can race on tcfa_bstats.
gact and mirred carry this same race today, these actions only come in
line with them. I will send a separate patch to fix it.
For example, a per subscriber policer offloaded to hardware:
tc filter add dev $DEV ingress protocol ip flower skip_sw \
dst_ip 10.0.0.1/32 \
action police index 1 rate 1mbit burst 10k \
conform-exceed drop/pipe no_percpu
Signed-off-by: Alexandre Cassen <redacted>
---
net/sched/act_mpls.c | 8 ++++----
net/sched/act_police.c | 10 +++++-----
net/sched/act_sample.c | 6 +++---
net/sched/act_skbedit.c | 9 +++++----
4 files changed, 17 insertions(+), 16 deletions(-)
diff --git a/net/sched/act_mpls.c b/net/sched/act_mpls.c
index aa56521b7179..a870386386d9 100644
--- a/net/sched/act_mpls.c
+++ b/net/sched/act_mpls.c@@ -60,7 +60,7 @@ TC_INDIRECT_SCOPE int tcf_mpls_act(struct sk_buff *skb, int mac_len; tcf_lastuse_update(&m->tcf_tm); - bstats_update(this_cpu_ptr(m->common.cpu_bstats), skb); + tcf_action_update_bstats(&m->common, skb); /* Ensure 'data' points at mac_header prior calling mpls manipulating * functions.
@@ -123,7 +123,7 @@ TC_INDIRECT_SCOPE int tcf_mpls_act(struct sk_buff *skb, return p->action; drop: - qstats_cpu_drop_inc(m->common.cpu_qstats); + tcf_action_inc_drop_qstats(&m->common); return TC_ACT_SHOT; }
@@ -196,8 +196,8 @@ static int tcf_mpls_init(struct net *net, struct nlattr *nla, return ACT_P_BOUND; if (!exists) { - ret = tcf_idr_create(tn, index, est, a, &act_mpls_ops, bind, - true, flags); + ret = tcf_idr_create_from_flags(tn, index, est, a, + &act_mpls_ops, bind, flags); if (ret) { tcf_idr_cleanup(tn, index); return ret;
diff --git a/net/sched/act_police.c b/net/sched/act_police.c
index 3f8147f37549..0b0c09e3dfd9 100644
--- a/net/sched/act_police.c
+++ b/net/sched/act_police.c@@ -80,8 +80,8 @@ static int tcf_police_init(struct net *net, struct nlattr *nla, return ACT_P_BOUND; if (!exists) { - ret = tcf_idr_create(tn, index, NULL, a, - &act_police_ops, bind, true, flags); + ret = tcf_idr_create_from_flags(tn, index, NULL, a, + &act_police_ops, bind, flags); if (ret) { tcf_idr_cleanup(tn, index); return ret;
@@ -259,7 +259,7 @@ TC_INDIRECT_SCOPE int tcf_police_act(struct sk_buff *skb, int ret; tcf_lastuse_update(&police->tcf_tm); - bstats_update(this_cpu_ptr(police->common.cpu_bstats), skb); + tcf_action_update_bstats(&police->common, skb); p = rcu_dereference_bh(police->params); ret = p->action;
@@ -313,10 +313,10 @@ TC_INDIRECT_SCOPE int tcf_police_act(struct sk_buff *skb, } inc_overlimits: - qstats_cpu_overlimit_inc(police->common.cpu_qstats); + tcf_action_inc_overlimit_qstats(&police->common); inc_drops: if (ret == TC_ACT_SHOT) - qstats_cpu_drop_inc(police->common.cpu_qstats); + tcf_action_inc_drop_qstats(&police->common); end: return ret; }
diff --git a/net/sched/act_sample.c b/net/sched/act_sample.c
index 44319a159b55..3029e93c4dea 100644
--- a/net/sched/act_sample.c
+++ b/net/sched/act_sample.c@@ -69,8 +69,8 @@ static int tcf_sample_init(struct net *net, struct nlattr *nla, return ACT_P_BOUND; if (!exists) { - ret = tcf_idr_create(tn, index, est, a, - &act_sample_ops, bind, true, flags); + ret = tcf_idr_create_from_flags(tn, index, est, a, + &act_sample_ops, bind, flags); if (ret) { tcf_idr_cleanup(tn, index); return ret;
@@ -173,7 +173,7 @@ TC_INDIRECT_SCOPE int tcf_sample_act(struct sk_buff *skb, int retval; tcf_lastuse_update(&s->tcf_tm); - bstats_update(this_cpu_ptr(s->common.cpu_bstats), skb); + tcf_action_update_bstats(&s->common, skb); retval = READ_ONCE(s->tcf_action); psample_group = rcu_dereference_bh(s->psample_group);
diff --git a/net/sched/act_skbedit.c b/net/sched/act_skbedit.c
index 26258b353cde..1f958b7d2a60 100644
--- a/net/sched/act_skbedit.c
+++ b/net/sched/act_skbedit.c@@ -45,7 +45,7 @@ TC_INDIRECT_SCOPE int tcf_skbedit_act(struct sk_buff *skb, struct tcf_skbedit_params *params; tcf_lastuse_update(&d->tcf_tm); - bstats_update(this_cpu_ptr(d->common.cpu_bstats), skb); + tcf_action_update_bstats(&d->common, skb); params = rcu_dereference_bh(d->params);
@@ -85,7 +85,7 @@ TC_INDIRECT_SCOPE int tcf_skbedit_act(struct sk_buff *skb, return params->action; err: - qstats_cpu_drop_inc(d->common.cpu_qstats); + tcf_action_inc_drop_qstats(&d->common); return TC_ACT_SHOT; }
@@ -221,8 +221,9 @@ static int tcf_skbedit_init(struct net *net, struct nlattr *nla, } if (!exists) { - ret = tcf_idr_create(tn, index, est, a, - &act_skbedit_ops, bind, true, act_flags); + ret = tcf_idr_create_from_flags(tn, index, est, a, + &act_skbedit_ops, bind, + act_flags); if (ret) { tcf_idr_cleanup(tn, index); return ret;
--
2.43.0