[PATCH net-next 5/5] net: sparx5: Offload tc port policers via matchall
From: Daniel Machon
Date: Fri Oct 09 2026 - 08:35:55 EST
Offload a tc matchall filter with a police action to the port policer:
tc qdisc add dev <eth> clsact
tc filter add dev <eth> ingress matchall skip_sw \
action police rate <bps> burst <bytes> conform-exceed drop
The port policer meters all ingress frames on the port, so offload the
filter only on ingress, on chain 0, with protocol all, and on a block
that is not shared. Only drop is supported as the exceed action, and
only one policer per port. Report the pass and drop counts through the
matchall stats.
Signed-off-by: Daniel Machon <daniel.machon@xxxxxxxxxxxxx>
---
.../ethernet/microchip/sparx5/sparx5_tc_matchall.c | 38 ++++++++++++++++++++++
1 file changed, 38 insertions(+)
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_tc_matchall.c b/drivers/net/ethernet/microchip/sparx5/sparx5_tc_matchall.c
index 146d7f28e8f3..5bf17c52e564 100644
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_tc_matchall.c
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_tc_matchall.c
@@ -43,6 +43,13 @@ sparx5_tc_matchall_parse_mirror_action(struct sparx5_mall_entry *entry,
entry->mirror.port = netdev_priv(action->dev);
}
+static void
+sparx5_tc_matchall_parse_port_policer_action(struct sparx5_mall_entry *entry,
+ struct flow_action_entry *action)
+{
+ entry->port_policer.police = action->police;
+}
+
static int sparx5_tc_matchall_replace(struct net_device *ndev,
struct tc_cls_matchall_offload *tmo,
bool ingress)
@@ -98,6 +105,30 @@ static int sparx5_tc_matchall_replace(struct net_device *ndev,
}
/* Get baseline stats for this port */
sparx5_mirror_stats(mall_entry, &tmo->stats);
+ break;
+ case FLOW_ACTION_POLICE:
+ if (tmo->common.protocol != htons(ETH_P_ALL)) {
+ NL_SET_ERR_MSG_MOD(tmo->common.extack,
+ "Policer is only supported with protocol all");
+ kfree(mall_entry);
+ return -EOPNOTSUPP;
+ }
+
+ if (tmo->common.chain_index) {
+ NL_SET_ERR_MSG_MOD(tmo->common.extack,
+ "Policer is only supported on chain 0");
+ kfree(mall_entry);
+ return -EOPNOTSUPP;
+ }
+
+ sparx5_tc_matchall_parse_port_policer_action(mall_entry,
+ action);
+ err = sparx5_add_port_policer(mall_entry, tmo->common.extack);
+ if (err) {
+ kfree(mall_entry);
+ return err;
+ }
+
break;
case FLOW_ACTION_GOTO:
err = vcap_enable_lookups(sparx5->vcap_ctrl, ndev,
@@ -151,6 +182,11 @@ static int sparx5_tc_matchall_destroy(struct net_device *ndev,
if (entry->type == FLOW_ACTION_MIRRED) {
sparx5_mirror_del(entry);
+ } else if (entry->type == FLOW_ACTION_POLICE) {
+ err = sparx5_delete_port_policer(entry);
+ if (err)
+ NL_SET_ERR_MSG_MOD(tmo->common.extack,
+ "Could not delete port policer");
} else if (entry->type == FLOW_ACTION_GOTO) {
err = vcap_enable_lookups(sparx5->vcap_ctrl, ndev,
0, 0, tmo->cookie, false);
@@ -180,6 +216,8 @@ static int sparx5_tc_matchall_stats(struct net_device *ndev,
if (entry->type == FLOW_ACTION_MIRRED) {
sparx5_mirror_stats(entry, &tmo->stats);
+ } else if (entry->type == FLOW_ACTION_POLICE) {
+ sparx5_update_port_policer_stats(ndev, tmo);
} else {
NL_SET_ERR_MSG_MOD(tmo->common.extack, "Unsupported action");
return -EOPNOTSUPP;
--
2.34.1