Commit 40e7fe18 authored by Steen Hegelund's avatar Steen Hegelund Committed by David S. Miller

net: microchip: sparx5: Add support for TC flower filter statistics

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: default avatarSteen Hegelund <steen.hegelund@microchip.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent f13230a4
...@@ -21,6 +21,11 @@ struct sparx5_tc_flower_parse_usage { ...@@ -21,6 +21,11 @@ struct sparx5_tc_flower_parse_usage {
unsigned int used_keys; 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 /* These protocols have dedicated keysets in IS2 and a TC dissector
* ETH_P_ARP does not have 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, ...@@ -605,6 +610,20 @@ static int sparx5_tc_flower_action_check(struct vcap_control *vctrl,
return 0; 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, static int sparx5_tc_flower_replace(struct net_device *ndev,
struct flow_cls_offload *fco, struct flow_cls_offload *fco,
struct vcap_admin *admin) struct vcap_admin *admin)
...@@ -630,6 +649,11 @@ static int sparx5_tc_flower_replace(struct net_device *ndev, ...@@ -630,6 +649,11 @@ static int sparx5_tc_flower_replace(struct net_device *ndev,
vrule->cookie = fco->cookie; vrule->cookie = fco->cookie;
sparx5_tc_use_dissectors(fco, admin, vrule, &l3_proto); 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); frule = flow_cls_offload_flow_rule(fco);
flow_action_for_each(idx, act, &frule->action) { flow_action_for_each(idx, act, &frule->action) {
switch (act->id) { switch (act->id) {
...@@ -708,6 +732,48 @@ static int sparx5_tc_flower_destroy(struct net_device *ndev, ...@@ -708,6 +732,48 @@ static int sparx5_tc_flower_destroy(struct net_device *ndev,
return err; 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, int sparx5_tc_flower(struct net_device *ndev, struct flow_cls_offload *fco,
bool ingress) bool ingress)
{ {
...@@ -729,6 +795,8 @@ int sparx5_tc_flower(struct net_device *ndev, struct flow_cls_offload *fco, ...@@ -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); return sparx5_tc_flower_replace(ndev, fco, admin);
case FLOW_CLS_DESTROY: case FLOW_CLS_DESTROY:
return sparx5_tc_flower_destroy(ndev, fco, admin); return sparx5_tc_flower_destroy(ndev, fco, admin);
case FLOW_CLS_STATS:
return sparx5_tc_flower_stats(ndev, fco, admin);
default: default:
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
......
...@@ -1729,6 +1729,31 @@ void vcap_rule_set_counter_id(struct vcap_rule *rule, u32 counter_id) ...@@ -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); 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) int vcap_rule_set_counter(struct vcap_rule *rule, struct vcap_counter *ctr)
{ {
struct vcap_rule_internal *ri = to_intrule(rule); struct vcap_rule_internal *ri = to_intrule(rule);
......
...@@ -210,6 +210,9 @@ const struct vcap_field *vcap_lookup_keyfield(struct vcap_rule *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); 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 */ /* 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); 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 */ /* Copy to host byte order */
void vcap_netbytes_copy(u8 *dst, u8 *src, int count); void vcap_netbytes_copy(u8 *dst, u8 *src, int count);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment