[PATCH net-next 5/5] net: sparx5: Offload tc port policers via matchall
flat view
WARM1d
From: Daniel Machon <daniel.machon@microchip.com>
Date: 2026-10-09 11:54:21
Also in:
linux-arm-kernel, lkml
Subsystem:
networking drivers, the rest · Maintainers:
Andrew Lunn, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds
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@microchip.com>
---
.../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