@@ -21,6 +21,11 @@ struct sparx5_tc_flower_parse_usage {
unsigned int used_keys;
};
+struct sparx5_tc_rule_pkt_cnt {
+ u64 cookie;
+ u32 pkts;
+};
+
/* These protocols have dedicated keysets in IS2 and a TC dissector
* ETH_P_ARP does not have a TC dissector
*/
@@ -605,6 +610,20 @@ static int sparx5_tc_flower_action_check(struct vcap_control *vctrl,
return 0;
}
+/* Add a rule counter action - only IS2 is considered for now */
+static int sparx5_tc_add_rule_counter(struct vcap_admin *admin,
+ struct vcap_rule *vrule)
+{
+ int err;
+
+ err = vcap_rule_add_action_u32(vrule, VCAP_AF_CNT_ID, vrule->id);
+ if (err)
+ return err;
+
+ vcap_rule_set_counter_id(vrule, vrule->id);
+ return err;
+}
+
static int sparx5_tc_flower_replace(struct net_device *ndev,
struct flow_cls_offload *fco,
struct vcap_admin *admin)
@@ -630,6 +649,11 @@ static int sparx5_tc_flower_replace(struct net_device *ndev,
vrule->cookie = fco->cookie;
sparx5_tc_use_dissectors(fco, admin, vrule, &l3_proto);
+
+ err = sparx5_tc_add_rule_counter(admin, vrule);
+ if (err)
+ goto out;
+
frule = flow_cls_offload_flow_rule(fco);
flow_action_for_each(idx, act, &frule->action) {
switch (act->id) {
@@ -708,6 +732,48 @@ static int sparx5_tc_flower_destroy(struct net_device *ndev,
return err;
}
+/* Collect packet counts from all rules with the same cookie */
+static int sparx5_tc_rule_counter_cb(void *arg, struct vcap_rule *rule)
+{
+ struct sparx5_tc_rule_pkt_cnt *rinfo = arg;
+ struct vcap_counter counter;
+ int err = 0;
+
+ if (rule->cookie == rinfo->cookie) {
+ err = vcap_rule_get_counter(rule, &counter);
+ if (err)
+ return err;
+ rinfo->pkts += counter.value;
+ /* Reset the rule counter */
+ counter.value = 0;
+ vcap_rule_set_counter(rule, &counter);
+ }
+ return err;
+}
+
+static int sparx5_tc_flower_stats(struct net_device *ndev,
+ struct flow_cls_offload *fco,
+ struct vcap_admin *admin)
+{
+ struct sparx5_port *port = netdev_priv(ndev);
+ struct sparx5_tc_rule_pkt_cnt rinfo = {};
+ struct vcap_control *vctrl;
+ ulong lastused = 0;
+ u64 drops = 0;
+ u32 pkts = 0;
+ int err;
+
+ rinfo.cookie = fco->cookie;
+ vctrl = port->sparx5->vcap_ctrl;
+ err = vcap_rule_iter(vctrl, sparx5_tc_rule_counter_cb, &rinfo);
+ if (err)
+ return err;
+ pkts = rinfo.pkts;
+ flow_stats_update(&fco->stats, 0x0, pkts, drops, lastused,
+ FLOW_ACTION_HW_STATS_IMMEDIATE);
+ return err;
+}
+
int sparx5_tc_flower(struct net_device *ndev, struct flow_cls_offload *fco,
bool ingress)
{
@@ -729,6 +795,8 @@ int sparx5_tc_flower(struct net_device *ndev, struct flow_cls_offload *fco,
return sparx5_tc_flower_replace(ndev, fco, admin);
case FLOW_CLS_DESTROY:
return sparx5_tc_flower_destroy(ndev, fco, admin);
+ case FLOW_CLS_STATS:
+ return sparx5_tc_flower_stats(ndev, fco, admin);
default:
return -EOPNOTSUPP;
}
@@ -1729,6 +1729,31 @@ void vcap_rule_set_counter_id(struct vcap_rule *rule, u32 counter_id)
}
EXPORT_SYMBOL_GPL(vcap_rule_set_counter_id);
+/* Provide all rules via a callback interface */
+int vcap_rule_iter(struct vcap_control *vctrl,
+ int (*callback)(void *, struct vcap_rule *), void *arg)
+{
+ struct vcap_rule_internal *ri;
+ struct vcap_admin *admin;
+ int ret;
+
+ ret = vcap_api_check(vctrl);
+ if (ret)
+ return ret;
+
+ /* Iterate all rules in each VCAP instance */
+ list_for_each_entry(admin, &vctrl->list, list) {
+ list_for_each_entry(ri, &admin->rules, list) {
+ ret = callback(arg, &ri->data);
+ if (ret)
+ return ret;
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(vcap_rule_iter);
+
int vcap_rule_set_counter(struct vcap_rule *rule, struct vcap_counter *ctr)
{
struct vcap_rule_internal *ri = to_intrule(rule);
@@ -210,6 +210,9 @@ const struct vcap_field *vcap_lookup_keyfield(struct vcap_rule *rule,
int vcap_lookup_rule_by_cookie(struct vcap_control *vctrl, u64 cookie);
/* Is the next chain id in the following lookup, possible in another VCAP */
bool vcap_is_next_lookup(struct vcap_control *vctrl, int cur_cid, int next_cid);
+/* Provide all rules via a callback interface */
+int vcap_rule_iter(struct vcap_control *vctrl,
+ int (*callback)(void *, struct vcap_rule *), void *arg);
/* Copy to host byte order */
void vcap_netbytes_copy(u8 *dst, u8 *src, int count);
This provides flower filter packet statistics (bytes are not supported) via the dedicated IS2 counter feature. All rules having the same TC cookie will contribute to the packet statistics for the filter as they are considered to be part of the same TC flower filter. Signed-off-by: Steen Hegelund <steen.hegelund@microchip.com> --- .../microchip/sparx5/sparx5_tc_flower.c | 68 +++++++++++++++++++ .../net/ethernet/microchip/vcap/vcap_api.c | 25 +++++++ .../ethernet/microchip/vcap/vcap_api_client.h | 3 + 3 files changed, 96 insertions(+)