A skip_sw filter gives its skip_sw flag to its actions only after their ->init() returns. ->init() then cannot know that the action never runs in software unless the user also sets skip_sw on the action. Since commit 34d35b4edbbe ("net/sched: act_api: deny mismatched skip_sw/skip_hw flags for actions created by classifiers"), this action flag also needs the filter one. The Sashiko AI review [1] of the tunnel_key dst cache patch reports this limit. Pass the filter offload flags to ->init() so that an action can skip the state only the software path needs, like the tunnel_key dst cache. tcf_idr_create() stores them in the new action, which replaces the inheritance after ->init(). Since commit 9463e8d8c692 ("net/sched: act_api: inherit filter offload flags only on new actions"), this inheritance only applies to new actions, so the final action flags do not change. No action reads skip_hw at init and only act_skbedit reads skip_sw. Since commit 4a6a676f8c16 ("act_skbedit: skbedit queue mapping for receive queue"), it requires skip_sw for a receive queue_mapping. The filter flag is now enough for this check. Link: https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261009051930.3619697-1-acassen%40corp.free.fr [1] Signed-off-by: Alexandre Cassen --- net/sched/act_api.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/net/sched/act_api.c b/net/sched/act_api.c index e142d33dc5ef..13317d1abde1 100644 --- a/net/sched/act_api.c +++ b/net/sched/act_api.c @@ -1531,6 +1531,12 @@ int tcf_action_init(struct net *net, struct tcf_proto *tp, struct nlattr *nla, ops[i - 1] = a_o; } + /* New actions inherit these flags and init can skip software state */ + if (tc_skip_sw(fl_flags)) + flags |= TCA_ACT_FLAGS_SKIP_SW; + if (tc_skip_hw(fl_flags)) + flags |= TCA_ACT_FLAGS_SKIP_HW; + for (i = 1; i <= TCA_ACT_MAX_PRIO && tb[i]; i++) { act = tcf_action_init_1(net, tp, tb[i], est, ops[i - 1], &init_res[i - 1], flags, extack); @@ -1549,9 +1555,7 @@ int tcf_action_init(struct net *net, struct tcf_proto *tp, struct nlattr *nla, /* Action is created by classifier and is not * standalone. Check that the user did not set * any action flags different than the - * classifier flags, and inherit the flags from - * the classifier for the compatibility case - * where no flags were specified at all. + * classifier flags. */ if ((tc_act_skip_sw(act->tcfa_flags) && !skip_sw) || (tc_act_skip_hw(act->tcfa_flags) && !skip_hw)) { @@ -1560,13 +1564,6 @@ int tcf_action_init(struct net *net, struct tcf_proto *tp, struct nlattr *nla, err = -EINVAL; goto err; } - /* Other filters share an existing action */ - if (init_res[i - 1] != ACT_P_CREATED) - continue; - if (skip_sw) - act->tcfa_flags |= TCA_ACT_FLAGS_SKIP_SW; - if (skip_hw) - act->tcfa_flags |= TCA_ACT_FLAGS_SKIP_HW; continue; } -- 2.43.0