mlxsw: spectrum: Add support for TC flower offload statistics
authorArkadi Sharshevsky <arkadis@mellanox.com>
Sat, 11 Mar 2017 08:42:59 +0000 (09:42 +0100)
committerDavid S. Miller <davem@davemloft.net>
Mon, 13 Mar 2017 06:50:15 +0000 (23:50 -0700)
Add support for TC flower offload statistics including number of packets,
bytes and last use timestamp. Currently the statistics are gathered on a
per-rule basis.

Signed-off-by: Arkadi Sharshvesky <arkadis@mellanox.com>
Reviewed-by: Ido Schimmel <idosch@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/mellanox/mlxsw/spectrum.c
drivers/net/ethernet/mellanox/mlxsw/spectrum.h
drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c
drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c

index af430484ed2f6287509a6f179814d60a00f7d530..475499b6c989c8a2d56c70b08317e38e61127602 100644 (file)
@@ -1434,6 +1434,9 @@ static int mlxsw_sp_setup_tc(struct net_device *dev, u32 handle,
                        mlxsw_sp_flower_destroy(mlxsw_sp_port, ingress,
                                                tc->cls_flower);
                        return 0;
+               case TC_CLSFLOWER_STATS:
+                       return mlxsw_sp_flower_stats(mlxsw_sp_port, ingress,
+                                                    tc->cls_flower);
                default:
                        return -EOPNOTSUPP;
                }
index b4f32a6d0352d44cdbc43f654a957298c7bde0e2..5502232b06cff1ff18423cf2ab5117c326cc530e 100644 (file)
@@ -688,6 +688,8 @@ int mlxsw_sp_flower_replace(struct mlxsw_sp_port *mlxsw_sp_port, bool ingress,
                            __be16 protocol, struct tc_cls_flower_offload *f);
 void mlxsw_sp_flower_destroy(struct mlxsw_sp_port *mlxsw_sp_port, bool ingress,
                             struct tc_cls_flower_offload *f);
+int mlxsw_sp_flower_stats(struct mlxsw_sp_port *mlxsw_sp_port, bool ingress,
+                         struct tc_cls_flower_offload *f);
 int mlxsw_sp_flow_counter_get(struct mlxsw_sp *mlxsw_sp,
                              unsigned int counter_index, u64 *packets,
                              u64 *bytes);
index 87d011171da9abd4c522ca63b52fe44e13d91b4d..4d6920d4502609cbc9683ee14051879cd2beb43b 100644 (file)
@@ -92,6 +92,8 @@ struct mlxsw_sp_acl_rule {
        struct mlxsw_sp_acl_ruleset *ruleset;
        struct mlxsw_sp_acl_rule_info *rulei;
        u64 last_used;
+       u64 last_packets;
+       u64 last_bytes;
        unsigned long priv[0];
        /* priv has to be always the last item */
 };
@@ -559,6 +561,32 @@ static void mlxsw_sp_acl_rul_activity_update_work(struct work_struct *work)
        mlxsw_sp_acl_rule_activity_work_schedule(acl);
 }
 
+int mlxsw_sp_acl_rule_get_stats(struct mlxsw_sp *mlxsw_sp,
+                               struct mlxsw_sp_acl_rule *rule,
+                               u64 *packets, u64 *bytes, u64 *last_use)
+
+{
+       struct mlxsw_sp_acl_rule_info *rulei;
+       u64 current_packets;
+       u64 current_bytes;
+       int err;
+
+       rulei = mlxsw_sp_acl_rule_rulei(rule);
+       err = mlxsw_sp_flow_counter_get(mlxsw_sp, rulei->counter_index,
+                                       &current_packets, &current_bytes);
+       if (err)
+               return err;
+
+       *packets = current_packets - rule->last_packets;
+       *bytes = current_bytes - rule->last_bytes;
+       *last_use = rule->last_used;
+
+       rule->last_bytes = current_bytes;
+       rule->last_packets = current_packets;
+
+       return 0;
+}
+
 #define MLXSW_SP_KDVL_ACT_EXT_SIZE 1
 
 static int mlxsw_sp_act_kvdl_set_add(void *priv, u32 *p_kvdl_index,
index f2ed0b3d571855a60208508534bebc84dc1126f4..28bc989371c62e426b3ca514020f60585470200e 100644 (file)
@@ -56,6 +56,11 @@ static int mlxsw_sp_flower_parse_actions(struct mlxsw_sp *mlxsw_sp,
        if (tc_no_actions(exts))
                return 0;
 
+       /* Count action is inserted first */
+       err = mlxsw_sp_acl_rulei_act_count(mlxsw_sp, rulei);
+       if (err)
+               return err;
+
        tcf_exts_to_list(exts, &actions);
        list_for_each_entry(a, &actions, list) {
                if (is_tcf_gact_shot(a)) {
@@ -346,3 +351,47 @@ void mlxsw_sp_flower_destroy(struct mlxsw_sp_port *mlxsw_sp_port, bool ingress,
 
        mlxsw_sp_acl_ruleset_put(mlxsw_sp, ruleset);
 }
+
+int mlxsw_sp_flower_stats(struct mlxsw_sp_port *mlxsw_sp_port, bool ingress,
+                         struct tc_cls_flower_offload *f)
+{
+       struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
+       struct mlxsw_sp_acl_ruleset *ruleset;
+       struct mlxsw_sp_acl_rule *rule;
+       struct tc_action *a;
+       LIST_HEAD(actions);
+       u64 packets;
+       u64 lastuse;
+       u64 bytes;
+       int err;
+
+       ruleset = mlxsw_sp_acl_ruleset_get(mlxsw_sp, mlxsw_sp_port->dev,
+                                          ingress,
+                                          MLXSW_SP_ACL_PROFILE_FLOWER);
+       if (WARN_ON(IS_ERR(ruleset)))
+               return -EINVAL;
+
+       rule = mlxsw_sp_acl_rule_lookup(mlxsw_sp, ruleset, f->cookie);
+       if (!rule)
+               return -EINVAL;
+
+       err = mlxsw_sp_acl_rule_get_stats(mlxsw_sp, rule, &bytes, &packets,
+                                         &lastuse);
+       if (err)
+               goto err_rule_get_stats;
+
+       preempt_disable();
+
+       tcf_exts_to_list(f->exts, &actions);
+       list_for_each_entry(a, &actions, list)
+               tcf_action_stats_update(a, bytes, packets, lastuse);
+
+       preempt_enable();
+
+       mlxsw_sp_acl_ruleset_put(mlxsw_sp, ruleset);
+       return 0;
+
+err_rule_get_stats:
+       mlxsw_sp_acl_ruleset_put(mlxsw_sp, ruleset);
+       return err;
+}