From patchwork Sun Oct 18 07:02:41 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dekel Peled X-Patchwork-Id: 81244 X-Patchwork-Delegate: rasland@nvidia.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id 3DCDAA04B0; Sun, 18 Oct 2020 09:03:46 +0200 (CEST) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id C65F5C9EE; Sun, 18 Oct 2020 09:03:44 +0200 (CEST) Received: from mellanox.co.il (mail-il-dmz.mellanox.com [193.47.165.129]) by dpdk.org (Postfix) with ESMTP id 84C82C9EC for ; Sun, 18 Oct 2020 09:03:42 +0200 (CEST) Received: from Internal Mail-Server by MTLPINE1 (envelope-from dekelp@nvidia.com) with SMTP; 18 Oct 2020 10:03:38 +0300 Received: from mtl-vdi-280.wap.labs.mlnx. (mtl-vdi-280.wap.labs.mlnx [10.228.134.250]) by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id 09I73baL001046; Sun, 18 Oct 2020 10:03:37 +0300 From: Dekel Peled To: viacheslavo@nvidia.com, shahafs@nvidia.com, matan@nvidia.com Cc: dev@dpdk.org Date: Sun, 18 Oct 2020 10:02:41 +0300 Message-Id: <7fca00a763b1f9578b5c4da3a0b749ae6cb985e9.1603004314.git.dekelp@nvidia.com> X-Mailer: git-send-email 1.7.1 In-Reply-To: References: Subject: [dpdk-dev] [PATCH v5] net/mlx5: support query of AGE action X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" 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/184864.html --- v2: Update age resolution to seconds, v3: Replace rte_atomic ops with c11 atomics. v4: Remove redundant blank line in RN. v5: Fix pointer type compilation issue. --- Signed-off-by: Dekel Peled Acked-by: Matan Azrad --- doc/guides/rel_notes/release_20_11.rst | 8 ++++ drivers/net/mlx5/mlx5.h | 20 ++++---- drivers/net/mlx5/mlx5_flow.c | 21 ++++++--- drivers/net/mlx5/mlx5_flow_dv.c | 84 +++++++++++++++++++++++++--------- 4 files changed, 94 insertions(+), 39 deletions(-) diff --git a/doc/guides/rel_notes/release_20_11.rst b/doc/guides/rel_notes/release_20_11.rst index f8686a5..fd82d0b 100644 --- a/doc/guides/rel_notes/release_20_11.rst +++ b/doc/guides/rel_notes/release_20_11.rst @@ -206,6 +206,14 @@ New Features * Extern objects and functions can be plugged into the pipeline. * Transaction-oriented table updates. +* **Updated Mellanox mlx5 driver.** + + Updated Mellanox mlx5 driver with new features and improvements, including: + + * Updated the supported timeout for Age action to the maximal value supported + by rte_flow API. + * Added support of Age action query. + * **Add new AVX512 specific classify algorithms for ACL library.** * Added new ``RTE_ACL_CLASSIFY_AVX512X16`` vector implementation, diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h index e528833..b08de80 100644 --- a/drivers/net/mlx5/mlx5.h +++ b/drivers/net/mlx5/mlx5.h @@ -276,7 +276,6 @@ struct mlx5_drop { #define CNT_SIZE (sizeof(struct mlx5_flow_counter)) #define CNTEXT_SIZE (sizeof(struct mlx5_flow_counter_ext)) #define AGE_SIZE (sizeof(struct mlx5_age_param)) -#define MLX5_AGING_TIME_DELAY 7 #define CNT_POOL_TYPE_EXT (1 << 0) #define CNT_POOL_TYPE_AGE (1 << 1) #define IS_EXT_POOL(pool) (((pool)->type) & CNT_POOL_TYPE_EXT) @@ -315,9 +314,7 @@ struct mlx5_drop { */ #define POOL_IDX_INVALID UINT16_MAX -struct mlx5_flow_counter_pool; - -/*age status*/ +/* Age status. */ enum { AGE_FREE, /* Initialized state. */ AGE_CANDIDATE, /* Counter assigned to flows. */ @@ -337,10 +334,10 @@ enum { /* Counter age parameter. */ struct mlx5_age_param { - rte_atomic16_t state; /**< Age state. */ + uint16_t state; /**< Age state (atomically accessed). */ 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 timeout:24; /**< Aging timeout in seconds. */ + uint32_t sec_since_last_hit:25; /**< Time in seconds since last hit. */ void *context; /**< Flow counter age context. */ }; @@ -349,7 +346,6 @@ struct flow_counter_stats { uint64_t bytes; }; -struct mlx5_flow_counter_pool; /* Generic counters information. */ struct mlx5_flow_counter { TAILQ_ENTRY(mlx5_flow_counter) next; @@ -391,6 +387,8 @@ struct mlx5_flow_counter_pool { rte_atomic64_t a64_dcs; }; /* The devx object of the minimum counter ID. */ + uint64_t time_of_last_age_check; + /* System time (from rte_rdtsc()) read in the last aging check. */ uint32_t index:28; /* Pool index in container. */ uint32_t type:2; /* Memory type behind the counter array. */ uint32_t skip_cnt:1; /* Pool contains skipped counter. */ @@ -400,8 +398,6 @@ struct mlx5_flow_counter_pool { struct mlx5_counter_stats_raw *raw_hw; /* The raw on HW working. */ }; -struct mlx5_counter_stats_raw; - /* Memory management structure for group of counter statistics raws. */ struct mlx5_counter_stats_mem_mng { LIST_ENTRY(mlx5_counter_stats_mem_mng) next; @@ -463,10 +459,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()) /* Aging information for per port. */ struct mlx5_age_info { - uint8_t flags; /*Indicate if is new event or need be trigered*/ + uint8_t flags; /* Indicate if is new event or need to be triggered. */ struct mlx5_counters aged_counters; /* Aged flow counter list. */ rte_spinlock_t aged_sl; /* Aged flow counter list lock. */ }; diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c index 2729629..31a494d 100644 --- a/drivers/net/mlx5/mlx5_flow.c +++ b/drivers/net/mlx5/mlx5_flow.c @@ -6670,7 +6670,7 @@ struct mlx5_meter_domains_infos * offset = batch ? 0 : dcs->id % MLX5_COUNTERS_PER_POOL; /* * Identify the counters released between query trigger and query - * handle more effiecntly. The counter released in this gap period + * handle more efficiently. The counter released in this gap period * should wait for a new round of query as the new arrived packets * will not be taken into account. */ @@ -6724,19 +6724,24 @@ 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); + const uint64_t curr_time = MLX5_CURR_TIME_SEC; + const uint32_t time_delta = curr_time - pool->time_of_last_age_check; + uint16_t expected = AGE_CANDIDATE; uint32_t i; + pool->time_of_last_age_check = curr_time; for (i = 0; i < MLX5_COUNTERS_PER_POOL; ++i) { cnt = MLX5_POOL_GET_CNT(pool, i); age_param = MLX5_CNT_TO_AGE(cnt); - if (rte_atomic16_read(&age_param->state) != AGE_CANDIDATE) + if (__atomic_load_n(&age_param->state, + __ATOMIC_RELAXED) != AGE_CANDIDATE) continue; if (cur->data[i].hits != prev->data[i].hits) { - age_param->expire = curr + age_param->timeout; + age_param->sec_since_last_hit = 0; continue; } - if ((uint16_t)(curr - age_param->expire) >= (UINT16_MAX / 2)) + age_param->sec_since_last_hit += time_delta; + if (age_param->sec_since_last_hit <= age_param->timeout) continue; /** * Hold the lock first, or if between the @@ -6747,8 +6752,10 @@ struct mlx5_meter_domains_infos * priv = rte_eth_devices[age_param->port_id].data->dev_private; age_info = GET_PORT_AGE_INFO(priv); rte_spinlock_lock(&age_info->aged_sl); - if (rte_atomic16_cmpset((volatile uint16_t *)&age_param->state, - AGE_CANDIDATE, AGE_TMOUT)) { + if (__atomic_compare_exchange_n(&age_param->state, &expected, + AGE_TMOUT, false, + __ATOMIC_RELAXED, + __ATOMIC_RELAXED)) { TAILQ_INSERT_TAIL(&age_info->aged_counters, cnt, next); MLX5_AGE_SET(age_info, MLX5_AGE_EVENT_NEW); } diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c index dc020c8..c1e9095 100644 --- a/drivers/net/mlx5/mlx5_flow_dv.c +++ b/drivers/net/mlx5/mlx5_flow_dv.c @@ -3950,14 +3950,14 @@ struct field_modify_info modify_tcp[] = { return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION, action, "configuration cannot be null"); - if (age->timeout >= UINT16_MAX / 2 / 10) - return rte_flow_error_set(error, ENOTSUP, + if (!(age->timeout)) + return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION, action, - "Max age time: 3275 seconds"); + "invalid timeout value 0"); if (action_flags & MLX5_FLOW_ACTION_AGE) return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION, NULL, - "Duplicate age ctions set"); + "duplicate age actions set"); return 0; } @@ -4697,6 +4697,7 @@ struct field_modify_info modify_tcp[] = { TAILQ_INIT(&pool->counters[1]); TAILQ_INSERT_HEAD(&cont->pool_list, pool, next); pool->index = n_valid; + pool->time_of_last_age_check = MLX5_CURR_TIME_SEC; cont->pools[n_valid] = pool; if (!batch) { int base = RTE_ALIGN_FLOOR(dcs->id, MLX5_COUNTERS_PER_POOL); @@ -4819,7 +4820,7 @@ struct field_modify_info modify_tcp[] = { (MLX5_CNT_CONTAINER (priv->sh, batch, (age ^ 0x1)), dcs->id); /* - * Pool eixsts, counter will be added to the other + * Pool exists, counter will be added to the other * container, need to reallocate it later. */ if (pool) { @@ -5100,11 +5101,13 @@ struct field_modify_info modify_tcp[] = { struct mlx5_age_info *age_info; struct mlx5_age_param *age_param; struct mlx5_priv *priv = dev->data->dev_private; + uint16_t expected = AGE_CANDIDATE; age_info = GET_PORT_AGE_INFO(priv); age_param = flow_dv_counter_idx_get_age(dev, counter); - if (!rte_atomic16_cmpset((volatile uint16_t *)&age_param->state, - AGE_CANDIDATE, AGE_FREE)) { + if (!__atomic_compare_exchange_n(&age_param->state, &expected, + AGE_FREE, false, __ATOMIC_RELAXED, + __ATOMIC_RELAXED)) { /** * We need the lock even it is age timeout, * since counter may still in process. @@ -5112,9 +5115,10 @@ struct field_modify_info modify_tcp[] = { rte_spinlock_lock(&age_info->aged_sl); TAILQ_REMOVE(&age_info->aged_counters, cnt, next); rte_spinlock_unlock(&age_info->aged_sl); - rte_atomic16_set(&age_param->state, AGE_FREE); + __atomic_store_n(&age_param->state, AGE_FREE, __ATOMIC_RELAXED); } } + /** * Release a flow counter. * @@ -8241,22 +8245,12 @@ 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. - */ - age_param->timeout = age->timeout * 10 - MLX5_AGING_TIME_DELAY; - /* Set expire time in unit of 0.1 sec. */ + age_param->timeout = age->timeout; age_param->port_id = dev->data->port_id; - age_param->expire = age_param->timeout + - rte_rdtsc() / (rte_get_tsc_hz() / 10); - rte_atomic16_set(&age_param->state, AGE_CANDIDATE); + age_param->sec_since_last_hit = 0; + __atomic_store_n(&age_param->state, AGE_CANDIDATE, __ATOMIC_RELAXED); return counter; } /** @@ -10644,6 +10638,51 @@ 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 = __atomic_load_n(&age_param->state, + __ATOMIC_RELAXED) == + AGE_TMOUT ? 1 : 0; + resp->sec_since_last_hit_valid = !resp->aged; + if (resp->sec_since_last_hit_valid) + resp->sec_since_last_hit = + age_param->sec_since_last_hit; + 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() @@ -10665,6 +10704,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,