* [PATCH net v2 0/3] net: dsa: motorcomm: ACL fixup
@ 2026-11-03 9:55 David Yang
2026-11-03 9:55 ` [PATCH net v2 1/3] net: dsa: motorcomm: Fix extack message on unsupported TC actions David Yang
` (2 more replies)
0 siblings, 3 replies; 5+ messages in thread
From: David Yang @ 2026-11-03 9:55 UTC (permalink / raw)
To: netdev
Cc: David Yang, Andrew Lunn, Vladimir Oltean, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, linux-kernel
Various ACL defects. Found by LLM and manually verified (on YT9215).
v2:
- withdraw patch 2 as it needs another test run on the device
- fix patch 3 to align with software behavior
v1: https://lore.kernel.org/r/20261102071119.3435180-1-mmyangfl@gmail.com
David Yang (3):
net: dsa: motorcomm: Fix extack message on unsupported TC actions
net: dsa: motorcomm: Resolve the flower action list to one ACL verdict
net: dsa: motorcomm: Delete the ACL rule of the port being unbound
drivers/net/dsa/motorcomm/tc.c | 86 ++++++++++++++++++----------------
1 file changed, 46 insertions(+), 40 deletions(-)
--
2.53.0
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH net v2 1/3] net: dsa: motorcomm: Fix extack message on unsupported TC actions
2026-11-03 9:55 [PATCH net v2 0/3] net: dsa: motorcomm: ACL fixup David Yang
@ 2026-11-03 9:55 ` David Yang
2026-11-03 9:55 ` [PATCH net v2 2/3] net: dsa: motorcomm: Resolve the flower action list to one ACL verdict David Yang
2026-11-03 9:55 ` [PATCH net v2 3/3] net: dsa: motorcomm: Delete the ACL rule of the port being unbound David Yang
2 siblings, 0 replies; 5+ messages in thread
From: David Yang @ 2026-11-03 9:55 UTC (permalink / raw)
To: netdev
Cc: David Yang, Andrew Lunn, Vladimir Oltean, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, linux-kernel
No extack reasons were given to unsupported TC actions. Fix it.
Fixes: 8eb9e7520b17 ("net: dsa: yt921x: Add ACL support")
Signed-off-by: David Yang <mmyangfl@gmail.com>
---
drivers/net/dsa/motorcomm/tc.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/net/dsa/motorcomm/tc.c b/drivers/net/dsa/motorcomm/tc.c
index 9dbd61e48fee..8835907366bf 100644
--- a/drivers/net/dsa/motorcomm/tc.c
+++ b/drivers/net/dsa/motorcomm/tc.c
@@ -1122,6 +1122,7 @@ yt921x_acl_rule_ext_parse_flow_action(struct yt921x_acl_rule_ext *ruleext,
break;
}
default:
+ reason = "Unsupported by HW";
fallback:
if (cls->common.skip_sw) {
NL_SET_ERR_MSG_FMT_MOD(extack,
--
2.53.0
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH net v2 2/3] net: dsa: motorcomm: Resolve the flower action list to one ACL verdict
2026-11-03 9:55 [PATCH net v2 0/3] net: dsa: motorcomm: ACL fixup David Yang
2026-11-03 9:55 ` [PATCH net v2 1/3] net: dsa: motorcomm: Fix extack message on unsupported TC actions David Yang
@ 2026-11-03 9:55 ` David Yang
2026-11-05 12:55 ` netdev-bot+sashiko
2026-11-03 9:55 ` [PATCH net v2 3/3] net: dsa: motorcomm: Delete the ACL rule of the port being unbound David Yang
2 siblings, 1 reply; 5+ messages in thread
From: David Yang @ 2026-11-03 9:55 UTC (permalink / raw)
To: netdev
Cc: David Yang, Andrew Lunn, Vladimir Oltean, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, linux-kernel
The hardware resolves one forward decision per ACL rule, but the
translation accumulated every action, so a later action silently changed
the verdict of the ones before it: an `action drop action trap` filter
with skip_sw trapped packets to the CPU instead of dropping them.
Resolve the list against its first terminal action. Consecutive
redirects merge into the destination port mask, since a flow action
entry carries no mirred control verdict to tell whether software would
have continued; an action asking for a second decision is rejected when
skip_sw is set and left to the software path otherwise.
Fixes: 8eb9e7520b17 ("net: dsa: yt921x: Add ACL support")
Signed-off-by: David Yang <mmyangfl@gmail.com>
---
drivers/net/dsa/motorcomm/tc.c | 72 +++++++++++++++++-----------------
1 file changed, 37 insertions(+), 35 deletions(-)
diff --git a/drivers/net/dsa/motorcomm/tc.c b/drivers/net/dsa/motorcomm/tc.c
index 8835907366bf..5d2db04f3385 100644
--- a/drivers/net/dsa/motorcomm/tc.c
+++ b/drivers/net/dsa/motorcomm/tc.c
@@ -1030,55 +1030,54 @@ yt921x_acl_rule_ext_parse_flow_action(struct yt921x_acl_rule_ext *ruleext,
const struct flow_rule *rule = flow_cls_offload_flow_rule(cls);
const struct flow_action *flow_action = &rule->action;
struct netlink_ext_ack *extack = cls->common.extack;
- enum flow_action_id redir_act = NUM_FLOW_ACTIONS;
const struct flow_action_entry *act;
u32 *action = ruleext->r.action;
bool seen_priority = false;
const char *reason = NULL;
bool seen_police = false;
+ bool terminal = false;
+ bool redir = false;
unsigned int i;
int res;
memset(action, 0, 3 * sizeof(*action));
- flow_action_for_each(i, act, flow_action)
+ flow_action_for_each(i, act, flow_action) {
+ /* Only another redirect, or a drop, can follow a redirect: a
+ * drop is an empty destination set, so the software verdict is
+ * the same whichever control the redirect carries.
+ */
+ if (redir && act->id != FLOW_ACTION_REDIRECT &&
+ act->id != FLOW_ACTION_DROP) {
+ reason = "Action after redirect";
+ goto fallback;
+ }
+
switch (act->id) {
case FLOW_ACTION_ACCEPT:
+ action[2] |= YT921X_ACL_ACTc_FWD_EN |
+ YT921X_ACL_ACTc_FWD_FWD;
+ terminal = true;
+ break;
case FLOW_ACTION_DROP:
- case FLOW_ACTION_REDIRECT:
- if (redir_act != NUM_FLOW_ACTIONS &&
- redir_act != act->id) {
- reason = "Different redirect actions";
+ action[2] |= YT921X_ACL_ACTc_FWD_EN |
+ YT921X_ACL_ACTc_FWD_REDIR;
+ terminal = true;
+ break;
+ case FLOW_ACTION_REDIRECT: {
+ struct dsa_port *to_dp;
+
+ to_dp = dsa_port_from_netdev(act->dev);
+ if (IS_ERR(to_dp) || to_dp->ds != &priv->ds) {
+ reason = "Redirect to non-local port";
goto fallback;
}
- redir_act = act->id;
-
- switch (act->id) {
- case FLOW_ACTION_ACCEPT:
- action[2] |= YT921X_ACL_ACTc_FWD_EN |
- YT921X_ACL_ACTc_FWD_FWD;
- break;
- case FLOW_ACTION_DROP:
- action[2] |= YT921X_ACL_ACTc_FWD_EN |
- YT921X_ACL_ACTc_FWD_REDIR;
- break;
- case FLOW_ACTION_REDIRECT: {
- struct dsa_port *to_dp;
- to_dp = dsa_port_from_netdev(act->dev);
- if (IS_ERR(to_dp) || to_dp->ds != &priv->ds) {
- reason = "Redirect to non-local port";
- goto fallback;
- }
-
- action[2] |= YT921X_ACL_ACTc_FWD_EN |
- YT921X_ACL_ACTc_FWD_REDIR |
- YT921X_ACL_ACTc_FWD_REDIR_DPORTn(to_dp->index);
- break;
- }
- default:
- break;
- }
+ action[2] |= YT921X_ACL_ACTc_FWD_EN |
+ YT921X_ACL_ACTc_FWD_REDIR |
+ YT921X_ACL_ACTc_FWD_REDIR_DPORTn(to_dp->index);
+ redir = true;
break;
+ }
case FLOW_ACTION_PRIORITY:
if (seen_priority) {
action[0] &= ~YT921X_ACL_ACTa_PRIO_EN;
@@ -1132,15 +1131,18 @@ yt921x_acl_rule_ext_parse_flow_action(struct yt921x_acl_rule_ext *ruleext,
}
fallthrough;
case FLOW_ACTION_TRAP:
- redir_act = FLOW_ACTION_TRAP;
-
action[2] &= ~YT921X_ACL_ACTc_FWD_REDIR_DPORTS_M &
~YT921X_ACL_ACTc_FWD_M;
action[2] |= YT921X_ACL_ACTc_FWD_EN |
YT921X_ACL_ACTc_FWD_TRAP;
+ terminal = true;
break;
}
+ if (terminal)
+ break;
+ }
+
ruleext->r.sw_assisted = !cls->common.skip_sw;
return 0;
}
--
2.53.0
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH net v2 3/3] net: dsa: motorcomm: Delete the ACL rule of the port being unbound
2026-11-03 9:55 [PATCH net v2 0/3] net: dsa: motorcomm: ACL fixup David Yang
2026-11-03 9:55 ` [PATCH net v2 1/3] net: dsa: motorcomm: Fix extack message on unsupported TC actions David Yang
2026-11-03 9:55 ` [PATCH net v2 2/3] net: dsa: motorcomm: Resolve the flower action list to one ACL verdict David Yang
@ 2026-11-03 9:55 ` David Yang
2 siblings, 0 replies; 5+ messages in thread
From: David Yang @ 2026-11-03 9:55 UTC (permalink / raw)
To: netdev
Cc: David Yang, Andrew Lunn, Vladimir Oltean, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, linux-kernel
A flower filter on a block shared across ports is offloaded as one
hardware rule per port, all carrying the same classifier cookie.
Deletion looked a rule up by cookie alone and could take another
port's copy: with skip_sw, a filter silently stopped being enforced
on a still-bound port, while the detached port kept enforcing it.
Delete the rule matching the port being unbound instead.
Fixes: 8eb9e7520b17 ("net: dsa: yt921x: Add ACL support")
Signed-off-by: David Yang <mmyangfl@gmail.com>
---
drivers/net/dsa/motorcomm/tc.c | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/drivers/net/dsa/motorcomm/tc.c b/drivers/net/dsa/motorcomm/tc.c
index 5d2db04f3385..159504694158 100644
--- a/drivers/net/dsa/motorcomm/tc.c
+++ b/drivers/net/dsa/motorcomm/tc.c
@@ -1226,7 +1226,7 @@ static u16 yt921x_acl_activated_ports(const struct yt921x_priv *priv)
static unsigned int
yt921x_acl_find(const struct yt921x_priv *priv, enum tc_setup_type type,
- unsigned long tag)
+ unsigned long tag, u16 ports_mask)
{
for (unsigned int blkid = 0; blkid < YT921X_ACL_BLK_NUM; blkid++) {
const struct yt921x_acl_blk *aclblk = priv->acl_blks[blkid];
@@ -1236,7 +1236,10 @@ yt921x_acl_find(const struct yt921x_priv *priv, enum tc_setup_type type,
for (unsigned int i = 0; i < YT921X_ACL_ENT_PER_BLK; i++)
if (aclblk->rules[i] && aclblk->rules[i]->tag == tag &&
- aclblk->rules[i]->type == type)
+ aclblk->rules[i]->type == type &&
+ FIELD_GET(YT921X_ACL_KEYb_SPORTS_M,
+ aclblk->rules[i]->entries[0].key[1]) ==
+ ports_mask)
return YT921X_ACL_ENT_PER_BLK * blkid + i;
}
@@ -1364,7 +1367,7 @@ yt921x_acl_commit(struct yt921x_priv *priv, unsigned int entid, u8 entsmask)
static int
yt921x_acl_del(struct yt921x_priv *priv, enum tc_setup_type type,
- unsigned long tag)
+ unsigned long tag, u16 ports_mask)
{
struct yt921x_acl_rule *aclrule;
struct yt921x_acl_blk *aclblk;
@@ -1378,7 +1381,7 @@ yt921x_acl_del(struct yt921x_priv *priv, enum tc_setup_type type,
int res;
int ret;
- entid = yt921x_acl_find(priv, type, tag);
+ entid = yt921x_acl_find(priv, type, tag, ports_mask);
if (entid == UINT_MAX)
return -ENOENT;
@@ -1553,7 +1556,7 @@ yt921x_dsa_cls_flower_del(struct dsa_switch *ds, int port,
int res;
mutex_lock(&priv->reg_lock);
- res = yt921x_acl_del(priv, TC_SETUP_CLSFLOWER, cls->cookie);
+ res = yt921x_acl_del(priv, TC_SETUP_CLSFLOWER, cls->cookie, BIT(port));
mutex_unlock(&priv->reg_lock);
return res;
--
2.53.0
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH net v2 2/3] net: dsa: motorcomm: Resolve the flower action list to one ACL verdict
2026-11-03 9:55 ` [PATCH net v2 2/3] net: dsa: motorcomm: Resolve the flower action list to one ACL verdict David Yang
@ 2026-11-05 12:55 ` netdev-bot+sashiko
0 siblings, 0 replies; 5+ messages in thread
From: netdev-bot+sashiko @ 2026-11-05 12:55 UTC (permalink / raw)
To: mmyangfl
Cc: netdev, andrew, olteanv, davem, edumazet, kuba, pabeni, linux-kernel
Thank you for your contribution! Sashiko AI review found 1 potential
issue(s) to consider.
Critical: 0 · High: 1 · Medium: 0 · Low: 0
If you believe none of the issues are legitimate, please reply to each
issue of Medium severity or higher and explain why the AI is wrong.
If any of them are legitimate and you plan to respin, please let patchwork
know by including "pw-bot: cr" as a separate line at the end of your reply
(one such reply per series is enough).
- [High] The patch says it makes the ACL use one verdict, the first
terminal action.
--
net: dsa: motorcomm: Resolve the flower action list to one ACL verdict
This commit changes yt921x_acl_rule_ext_parse_flow_action() to resolve
the flower action list against its first terminal action, so a later
action no longer overrides an earlier verdict. Consecutive redirects are
still merged into the destination port mask. Other actions that follow a
redirect are rejected under skip_sw, or trapped to the CPU otherwise.
> diff --git a/drivers/net/dsa/motorcomm/tc.c b/drivers/net/dsa/motorcomm/tc.c
> index 8835907366bf7..5d2db04f3385d 100644
> --- a/drivers/net/dsa/motorcomm/tc.c
> +++ b/drivers/net/dsa/motorcomm/tc.c
[ ... ]
> memset(action, 0, 3 * sizeof(*action));
> - flow_action_for_each(i, act, flow_action)
> + flow_action_for_each(i, act, flow_action) {
> + /* Only another redirect, or a drop, can follow a redirect: a
> + * drop is an empty destination set, so the software verdict is
> + * the same whichever control the redirect carries.
> + */
> + if (redir && act->id != FLOW_ACTION_REDIRECT &&
> + act->id != FLOW_ACTION_DROP) {
> + reason = "Action after redirect";
> + goto fallback;
> + }
> +
[ ... ]
> + case FLOW_ACTION_REDIRECT: {
> + struct dsa_port *to_dp;
> +
> + to_dp = dsa_port_from_netdev(act->dev);
> + if (IS_ERR(to_dp) || to_dp->ds != &priv->ds) {
> + reason = "Redirect to non-local port";
> goto fallback;
> }
[ ... ]
> + action[2] |= YT921X_ACL_ACTc_FWD_EN |
> + YT921X_ACL_ACTc_FWD_REDIR |
> + YT921X_ACL_ACTc_FWD_REDIR_DPORTn(to_dp->index);
> + redir = true;
> break;
> + }
[Severity: High]
Can a later redirect still widen the verdict of an earlier one here?
The guard at the top of the loop lets a second FLOW_ACTION_REDIRECT
through after a redirect. This case then ORs another DPORTn bit into
action[2] and does not set terminal.
The comment on the guard only explains why a drop gives the same result
whatever the redirect's control is. That does not hold for a second
redirect: with STOLEN only the first port gets the packet, and with PIPE
both ports do.
Take a filter like:
tc filter add dev swp0 ingress flower skip_sw ... \
action mirred egress redirect dev swp1 \
action mirred egress redirect dev swp2
iproute2 sets the redirect control to TC_ACT_STOLEN by default. In
software at ingress, tcf_mirred_can_reinsert(TC_ACT_STOLEN) is true. So
tcf_mirred_to_dev() sends the skb itself to swp1 without cloning it and
returns TC_ACT_CONSUMED. tcf_action_exec() then stops:
net/sched/act_api.c:tcf_action_exec() {
...
if (ret != TC_ACT_PIPE)
break;
...
}
The second redirect never runs.
The driver still accepts this rule, even with skip_sw. It programs the
hardware with FWD_REDIR and DPORTS = {swp1, swp2}, so matched frames are
also sent to swp2.
Dropping skip_sw gives the same result. A hardware redirect never reaches
the CPU, so software has no chance to correct it.
The commit message says:
Consecutive redirects merge into the destination port mask, since a flow
action entry carries no mirred control verdict to tell whether software
would have continued; an action asking for a second decision is rejected
when skip_sw is set and left to the software path otherwise.
tcf_mirred_offload_act_setup() only fills in entry->id and entry->dev, so
the driver cannot tell which case it has. Merging the ports picks the
PIPE behaviour.
Would it be better to send a second FLOW_ACTION_REDIRECT through the same
fallback path as other actions after a redirect? It would then be
rejected under skip_sw and trapped to the CPU otherwise.
The later patch in this series, "net: dsa: motorcomm: Delete the ACL rule
of the port being unbound", only changes yt921x_acl_find() and
yt921x_acl_del(). The merge is still in place at the end of the series.
[ ... ]
--
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261103095514.338700-1-mmyangfl%40gmail.com
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-11-05 12:55 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-11-03 9:55 [PATCH net v2 0/3] net: dsa: motorcomm: ACL fixup David Yang
2026-11-03 9:55 ` [PATCH net v2 1/3] net: dsa: motorcomm: Fix extack message on unsupported TC actions David Yang
2026-11-03 9:55 ` [PATCH net v2 2/3] net: dsa: motorcomm: Resolve the flower action list to one ACL verdict David Yang
2026-11-05 12:55 ` netdev-bot+sashiko
2026-11-03 9:55 ` [PATCH net v2 3/3] net: dsa: motorcomm: Delete the ACL rule of the port being unbound David Yang
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®