net/mlx5e: TC, support per action stats
authorOz Shlomo <ozsh@nvidia.com>
Sun, 12 Feb 2023 13:25:20 +0000 (15:25 +0200)
committerPaolo Abeni <pabeni@redhat.com>
Tue, 14 Feb 2023 10:00:01 +0000 (11:00 +0100)
Extend the action stats callback implementation to update stats for actions
that are associated with hw counters.
Note that the callback may be called from tc action utility or from tc
flower. Both apis expect the driver to return the stats difference from
the last update. As such, query the raw counter value and maintain
the diff from the last api call in the tc layer, instead of the fs_core
layer.

Signed-off-by: Oz Shlomo <ozsh@nvidia.com>
Reviewed-by: Roi Dayan <roid@nvidia.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c
drivers/net/ethernet/mellanox/mlx5/core/en/tc/act_stats.c
drivers/net/ethernet/mellanox/mlx5/core/en/tc/act_stats.h
drivers/net/ethernet/mellanox/mlx5/core/en/tc_priv.h
drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
drivers/net/ethernet/mellanox/mlx5/core/en_tc.h
drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c
include/linux/mlx5/fs.h

index b08339d986d5f72e5a9c45a70c6e8c1ce3dfefe9..3b590cfe33b84d5d79ff1e66d502166004af3781 100644 (file)
@@ -589,7 +589,7 @@ mlx5e_rep_indr_stats_act(struct mlx5e_rep_priv *rpriv,
 
        act = mlx5e_tc_act_get(fl_act->id, ns_type);
        if (!act || !act->stats_action)
-               return -EOPNOTSUPP;
+               return mlx5e_tc_fill_action_stats(priv, fl_act);
 
        return act->stats_action(priv, fl_act);
 }
index d1272c0f883cf2b2a5bf47bb1144db980a2e7533..f71766dca66021f7973e15712beb129cb5cbe682 100644 (file)
@@ -102,6 +102,9 @@ mlx5e_tc_act_stats_del_flow(struct mlx5e_tc_act_stats_handle *handle,
        struct mlx5e_tc_act_stats *act_stats;
        int i;
 
+       if (!flow_flag_test(flow, USE_ACT_STATS))
+               return;
+
        list_for_each_entry(attr, &flow->attrs, list) {
                for (i = 0; i < attr->tc_act_cookies_count; i++) {
                        struct rhashtable *ht = &handle->ht;
@@ -130,6 +133,9 @@ mlx5e_tc_act_stats_add_flow(struct mlx5e_tc_act_stats_handle *handle,
        int err;
        int i;
 
+       if (!flow_flag_test(flow, USE_ACT_STATS))
+               return 0;
+
        list_for_each_entry(attr, &flow->attrs, list) {
                if (attr->counter)
                        curr_counter = attr->counter;
@@ -151,3 +157,41 @@ out_err:
        mlx5e_tc_act_stats_del_flow(handle, flow);
        return err;
 }
+
+int
+mlx5e_tc_act_stats_fill_stats(struct mlx5e_tc_act_stats_handle *handle,
+                             struct flow_offload_action *fl_act)
+{
+       struct rhashtable *ht = &handle->ht;
+       struct mlx5e_tc_act_stats *item;
+       struct mlx5e_tc_act_stats key;
+       u64 pkts, bytes, lastused;
+       int err = 0;
+
+       key.tc_act_cookie = fl_act->cookie;
+
+       rcu_read_lock();
+       item = rhashtable_lookup(ht, &key, act_counters_ht_params);
+       if (!item) {
+               rcu_read_unlock();
+               err = -ENOENT;
+               goto err_out;
+       }
+
+       mlx5_fc_query_cached_raw(item->counter,
+                                &bytes, &pkts, &lastused);
+
+       flow_stats_update(&fl_act->stats,
+                         bytes - item->lastbytes,
+                         pkts - item->lastpackets,
+                         0, lastused, FLOW_ACTION_HW_STATS_DELAYED);
+
+       item->lastpackets = pkts;
+       item->lastbytes = bytes;
+       rcu_read_unlock();
+
+       return 0;
+
+err_out:
+       return err;
+}
index 4929301a52607984c6d67a62a5527a9fb52ceb41..002292c2567ced51c6967dc4988003c947124eeb 100644 (file)
@@ -20,4 +20,8 @@ void
 mlx5e_tc_act_stats_del_flow(struct mlx5e_tc_act_stats_handle *handle,
                            struct mlx5e_tc_flow *flow);
 
+int
+mlx5e_tc_act_stats_fill_stats(struct mlx5e_tc_act_stats_handle *handle,
+                             struct flow_offload_action *fl_act);
+
 #endif /* __MLX5_EN_ACT_STATS_H__ */
index f575646d2f50fc2f75a22dfd8343d3c3434cd8f8..451fd4342a5ac2925800858ad45feafd9b52ece3 100644 (file)
@@ -30,6 +30,7 @@ enum {
        MLX5E_TC_FLOW_FLAG_TUN_RX                = MLX5E_TC_FLOW_BASE + 9,
        MLX5E_TC_FLOW_FLAG_FAILED                = MLX5E_TC_FLOW_BASE + 10,
        MLX5E_TC_FLOW_FLAG_SAMPLE                = MLX5E_TC_FLOW_BASE + 11,
+       MLX5E_TC_FLOW_FLAG_USE_ACT_STATS         = MLX5E_TC_FLOW_BASE + 12,
 };
 
 struct mlx5e_tc_flow_parse_attr {
index f1dd257014067c7eef188e96e167548d6002ceec..2d06b44127621fbe006e8c2e19729e170408db38 100644 (file)
@@ -4117,6 +4117,7 @@ parse_branch_ctrl(struct flow_action_entry *act, struct mlx5e_tc_act *tc_act,
 
        /* branching action requires its own counter */
        attr->action |= MLX5_FLOW_CONTEXT_ACTION_COUNT;
+       flow_flag_set(flow, USE_ACT_STATS);
 
        return 0;
 
@@ -4967,6 +4968,12 @@ errout:
        return err;
 }
 
+int mlx5e_tc_fill_action_stats(struct mlx5e_priv *priv,
+                              struct flow_offload_action *fl_act)
+{
+       return mlx5e_tc_act_stats_fill_stats(get_act_stats_handle(priv), fl_act);
+}
+
 int mlx5e_stats_flower(struct net_device *dev, struct mlx5e_priv *priv,
                       struct flow_cls_offload *f, unsigned long flags)
 {
@@ -4993,11 +5000,15 @@ int mlx5e_stats_flower(struct net_device *dev, struct mlx5e_priv *priv,
        }
 
        if (mlx5e_is_offloaded_flow(flow) || flow_flag_test(flow, CT)) {
-               counter = mlx5e_tc_get_counter(flow);
-               if (!counter)
-                       goto errout;
+               if (flow_flag_test(flow, USE_ACT_STATS)) {
+                       f->use_act_stats = true;
+               } else {
+                       counter = mlx5e_tc_get_counter(flow);
+                       if (!counter)
+                               goto errout;
 
-               mlx5_fc_query_cached(counter, &bytes, &packets, &lastuse);
+                       mlx5_fc_query_cached(counter, &bytes, &packets, &lastuse);
+               }
        }
 
        /* Under multipath it's possible for one rule to be currently
@@ -5013,14 +5024,18 @@ int mlx5e_stats_flower(struct net_device *dev, struct mlx5e_priv *priv,
                u64 packets2;
                u64 lastuse2;
 
-               counter = mlx5e_tc_get_counter(flow->peer_flow);
-               if (!counter)
-                       goto no_peer_counter;
-               mlx5_fc_query_cached(counter, &bytes2, &packets2, &lastuse2);
-
-               bytes += bytes2;
-               packets += packets2;
-               lastuse = max_t(u64, lastuse, lastuse2);
+               if (flow_flag_test(flow, USE_ACT_STATS)) {
+                       f->use_act_stats = true;
+               } else {
+                       counter = mlx5e_tc_get_counter(flow->peer_flow);
+                       if (!counter)
+                               goto no_peer_counter;
+                       mlx5_fc_query_cached(counter, &bytes2, &packets2, &lastuse2);
+
+                       bytes += bytes2;
+                       packets += packets2;
+                       lastuse = max_t(u64, lastuse, lastuse2);
+               }
        }
 
 no_peer_counter:
index 75b34e63291685ee2714341abdeac87c2cd7f16f..e8e39fdcda73779a0cd76017fb55b32a8ac864a5 100644 (file)
@@ -199,6 +199,8 @@ int mlx5e_delete_flower(struct net_device *dev, struct mlx5e_priv *priv,
 
 int mlx5e_stats_flower(struct net_device *dev, struct mlx5e_priv *priv,
                       struct flow_cls_offload *f, unsigned long flags);
+int mlx5e_tc_fill_action_stats(struct mlx5e_priv *priv,
+                              struct flow_offload_action *fl_act);
 
 int mlx5e_tc_configure_matchall(struct mlx5e_priv *priv,
                                struct tc_cls_matchall_offload *f);
index b406e0367af617c7df8dbdd9f8626eed7afddc88..17fe30a4c06ca73d6d724d6e68c3bdb25e1c0639 100644 (file)
@@ -504,6 +504,16 @@ void mlx5_fc_query_cached(struct mlx5_fc *counter,
        counter->lastpackets = c.packets;
 }
 
+void mlx5_fc_query_cached_raw(struct mlx5_fc *counter,
+                             u64 *bytes, u64 *packets, u64 *lastuse)
+{
+       struct mlx5_fc_cache c = counter->cache;
+
+       *bytes = c.bytes;
+       *packets = c.packets;
+       *lastuse = c.lastuse;
+}
+
 void mlx5_fc_queue_stats_work(struct mlx5_core_dev *dev,
                              struct delayed_work *dwork,
                              unsigned long delay)
index ba6958b49a8ed48fc15d86de06893c8ad6c15935..90a2fe5839fabdbe331fef96b37fc520ba7aa8f2 100644 (file)
@@ -296,6 +296,8 @@ void mlx5_fc_destroy(struct mlx5_core_dev *dev, struct mlx5_fc *counter);
 u64 mlx5_fc_query_lastuse(struct mlx5_fc *counter);
 void mlx5_fc_query_cached(struct mlx5_fc *counter,
                          u64 *bytes, u64 *packets, u64 *lastuse);
+void mlx5_fc_query_cached_raw(struct mlx5_fc *counter,
+                             u64 *bytes, u64 *packets, u64 *lastuse);
 int mlx5_fc_query(struct mlx5_core_dev *dev, struct mlx5_fc *counter,
                  u64 *packets, u64 *bytes);
 u32 mlx5_fc_id(struct mlx5_fc *counter);