* [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; 4+ 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] 4+ 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-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; 4+ 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] 4+ 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; 4+ 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] 4+ messages in thread