Recent patch [1] adds to ethdev the API for query of age action.
This patch implements in MLX5 PMD the query of age action using
this API.

[1] https://mails.dpdk.org/archives/dev/2020-October/184319.html

Signed-off-by: Dekel Peled <dek...@nvidia.com>
---
 drivers/net/mlx5/mlx5.h         |  7 +++++
 drivers/net/mlx5/mlx5_flow.c    |  3 ++-
 drivers/net/mlx5/mlx5_flow_dv.c | 59 +++++++++++++++++++++++++++++++++++------
 3 files changed, 60 insertions(+), 9 deletions(-)

diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h
index bd91e16..98f2e5d 100644
--- a/drivers/net/mlx5/mlx5.h
+++ b/drivers/net/mlx5/mlx5.h
@@ -339,6 +339,7 @@ struct mlx5_age_param {
        uint16_t port_id; /**< Port id of the counter. */
        uint32_t timeout:15; /**< Age timeout in unit of 0.1sec. */
        uint32_t expire:16; /**< Expire time(0.1sec) in the future. */
+       uint32_t last_hit_time; /**< Last hit time in seconds. */
        void *context; /**< Flow counter age context. */
 };
 
@@ -461,6 +462,12 @@ struct mlx5_flow_default_miss_resource {
        ((age_info)->flags & (1 << (BIT)))
 #define GET_PORT_AGE_INFO(priv) \
        (&((priv)->sh->port[(priv)->dev_port - 1].age_info))
+/* Current time in seconds. */
+#define MLX5_CURR_TIME_SEC     (rte_rdtsc() / rte_get_tsc_hz())
+#define MLX5_AGE_UNITS_PER_SEC 10 /* Aging is calculated in 0.1 sec units. */
+/* Current time in defined units. */
+#define MLX5_AGE_CURR_TIME \
+       (rte_rdtsc() / (rte_get_tsc_hz() / MLX5_AGE_UNITS_PER_SEC))
 
 /* Aging information for per port. */
 struct mlx5_age_info {
diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c
index ffa7646..0043fe4 100644
--- a/drivers/net/mlx5/mlx5_flow.c
+++ b/drivers/net/mlx5/mlx5_flow.c
@@ -6039,7 +6039,7 @@ struct mlx5_meter_domains_infos *
        struct mlx5_age_param *age_param;
        struct mlx5_counter_stats_raw *cur = pool->raw_hw;
        struct mlx5_counter_stats_raw *prev = pool->raw;
-       uint16_t curr = rte_rdtsc() / (rte_get_tsc_hz() / 10);
+       uint16_t curr = MLX5_AGE_CURR_TIME;
        uint32_t i;
 
        for (i = 0; i < MLX5_COUNTERS_PER_POOL; ++i) {
@@ -6049,6 +6049,7 @@ struct mlx5_meter_domains_infos *
                        continue;
                if (cur->data[i].hits != prev->data[i].hits) {
                        age_param->expire = curr + age_param->timeout;
+                       age_param->last_hit_time = MLX5_CURR_TIME_SEC;
                        continue;
                }
                if ((uint16_t)(curr - age_param->expire) >= (UINT16_MAX / 2))
diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c
index 79fdf34..28389c6 100644
--- a/drivers/net/mlx5/mlx5_flow_dv.c
+++ b/drivers/net/mlx5/mlx5_flow_dv.c
@@ -8015,21 +8015,17 @@ struct field_modify_info modify_tcp[] = {
        if (!counter || age == NULL)
                return counter;
        age_param  = flow_dv_counter_idx_get_age(dev, counter);
-       /*
-        * The counter age accuracy may have a bit delay. Have 3/4
-        * second bias on the timeount in order to let it age in time.
-        */
        age_param->context = age->context ? age->context :
                (void *)(uintptr_t)(dev_flow->flow_idx);
        /*
         * The counter age accuracy may have a bit delay. Have 3/4
-        * second bias on the timeount in order to let it age in time.
+        * second bias on the timeout in order to let it age in time.
         */
        age_param->timeout = age->timeout * 10 - MLX5_AGING_TIME_DELAY;
-       /* Set expire time in unit of 0.1 sec. */
        age_param->port_id = dev->data->port_id;
-       age_param->expire = age_param->timeout +
-                       rte_rdtsc() / (rte_get_tsc_hz() / 10);
+       /* Set expire time in unit of 0.1 sec. */
+       age_param->expire = age_param->timeout + MLX5_AGE_CURR_TIME;
+       age_param->last_hit_time = MLX5_CURR_TIME_SEC;
        rte_atomic16_set(&age_param->state, AGE_CANDIDATE);
        return counter;
 }
@@ -9529,6 +9525,50 @@ struct field_modify_info modify_tcp[] = {
 }
 
 /**
+ * Query a flow rule AGE action for aging information.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] flow
+ *   Pointer to the sub flow.
+ * @param[out] data
+ *   data retrieved by the query.
+ * @param[out] error
+ *   Perform verbose error reporting if not NULL.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+static int
+flow_dv_query_age(struct rte_eth_dev *dev, struct rte_flow *flow,
+                 void *data, struct rte_flow_error *error)
+{
+       struct rte_flow_query_age *resp = data;
+
+       if (flow->counter) {
+               struct mlx5_age_param *age_param =
+                               flow_dv_counter_idx_get_age(dev, flow->counter);
+
+               if (!age_param || !age_param->timeout)
+                       return rte_flow_error_set
+                                       (error, EINVAL,
+                                        RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+                                        NULL, "cannot read age data");
+               resp->aged = rte_atomic16_read(&age_param->state) ==
+                               AGE_TMOUT ? 1 : 0;
+               resp->last_hit_time_valid = !resp->aged;
+               if (resp->last_hit_time_valid)
+                       resp->sec_since_last_hit =
+                               MLX5_CURR_TIME_SEC - age_param->last_hit_time;
+               return 0;
+       }
+       return rte_flow_error_set(error, EINVAL,
+                                 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+                                 NULL,
+                                 "age data not available");
+}
+
+/**
  * Query a flow.
  *
  * @see rte_flow_query()
@@ -9550,6 +9590,9 @@ struct field_modify_info modify_tcp[] = {
                case RTE_FLOW_ACTION_TYPE_COUNT:
                        ret = flow_dv_query_count(dev, flow, data, error);
                        break;
+               case RTE_FLOW_ACTION_TYPE_AGE:
+                       ret = flow_dv_query_age(dev, flow, data, error);
+                       break;
                default:
                        return rte_flow_error_set(error, ENOTSUP,
                                                  RTE_FLOW_ERROR_TYPE_ACTION,
-- 
1.8.3.1

Reply via email to