net/mlx5: support query of age action
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 Signed-off-by: Dekel Peled <dekelp@nvidia.com> Acked-by: Matan Azrad <matan@nvidia.com>
This commit is contained in:
parent
613d64e412
commit
d5a7d04c79
@ -174,6 +174,9 @@ New Features
|
||||
Updated Mellanox mlx5 driver with new features and improvements, including:
|
||||
|
||||
* Added support for matching on fragmented/non-fragmented IPv4/IPv6 packets.
|
||||
* Updated the supported timeout for Age action to the maximal value supported
|
||||
by rte_flow API.
|
||||
* Added support of Age action query.
|
||||
|
||||
* **Updated Solarflare network PMD.**
|
||||
|
||||
|
@ -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,11 @@ 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;
|
||||
/**< Time in seconds since last hit (atomically accessed). */
|
||||
void *context; /**< Flow counter age context. */
|
||||
};
|
||||
|
||||
@ -349,7 +347,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 +388,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 +399,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 +460,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. */
|
||||
};
|
||||
|
@ -6694,7 +6694,7 @@ next_container:
|
||||
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.
|
||||
*/
|
||||
@ -6748,19 +6748,26 @@ mlx5_flow_aging_check(struct mlx5_dev_ctx_shared *sh,
|
||||
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;
|
||||
__atomic_store_n(&age_param->sec_since_last_hit, 0,
|
||||
__ATOMIC_RELAXED);
|
||||
continue;
|
||||
}
|
||||
if ((uint16_t)(curr - age_param->expire) >= (UINT16_MAX / 2))
|
||||
if (__atomic_add_fetch(&age_param->sec_since_last_hit,
|
||||
time_delta,
|
||||
__ATOMIC_RELAXED) <= age_param->timeout)
|
||||
continue;
|
||||
/**
|
||||
* Hold the lock first, or if between the
|
||||
@ -6771,8 +6778,10 @@ mlx5_flow_aging_check(struct mlx5_dev_ctx_shared *sh,
|
||||
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);
|
||||
}
|
||||
|
@ -4179,14 +4179,14 @@ flow_dv_validate_action_age(uint64_t action_flags,
|
||||
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;
|
||||
}
|
||||
|
||||
@ -4926,6 +4926,7 @@ flow_dv_pool_create(struct rte_eth_dev *dev, struct mlx5_devx_obj *dcs,
|
||||
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);
|
||||
@ -5048,7 +5049,7 @@ retry:
|
||||
(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) {
|
||||
@ -5329,11 +5330,13 @@ flow_dv_counter_remove_from_age(struct rte_eth_dev *dev,
|
||||
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.
|
||||
@ -5341,7 +5344,7 @@ flow_dv_counter_remove_from_age(struct rte_eth_dev *dev,
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -8531,22 +8534,12 @@ flow_dv_translate_create_counter(struct rte_eth_dev *dev,
|
||||
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);
|
||||
__atomic_store_n(&age_param->sec_since_last_hit, 0, __ATOMIC_RELAXED);
|
||||
__atomic_store_n(&age_param->state, AGE_CANDIDATE, __ATOMIC_RELAXED);
|
||||
return counter;
|
||||
}
|
||||
/**
|
||||
@ -10954,6 +10947,52 @@ flow_dv_query_count(struct rte_eth_dev *dev, struct rte_flow *flow,
|
||||
"counters are not available");
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 =
|
||||
__atomic_load_n(&age_param->sec_since_last_hit,
|
||||
__ATOMIC_RELAXED);
|
||||
return 0;
|
||||
}
|
||||
return rte_flow_error_set(error, EINVAL,
|
||||
RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
|
||||
NULL,
|
||||
"age data not available");
|
||||
}
|
||||
|
||||
/**
|
||||
* Query a flow.
|
||||
*
|
||||
@ -10976,6 +11015,9 @@ flow_dv_query(struct rte_eth_dev *dev,
|
||||
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,
|
||||
|
Loading…
x
Reference in New Issue
Block a user