#include <rte_vxlan.h>
#include <rte_gtp.h>
#include <rte_eal_paging.h>
+#include <rte_mpls.h>
#include <mlx5_glue.h>
#include <mlx5_devx_cmds.h>
.mask = &mask,
};
struct field_modify_info reg_c_x[] = {
- {4, 0, 0}, /* dynamic instead of MLX5_MODI_META_REG_C_1. */
- {0, 0, 0},
+ [1] = {0, 0, 0},
};
int reg;
mask = rte_cpu_to_be_32(mask) & msk_c0;
mask = rte_cpu_to_be_32(mask << shl_c0);
}
- reg_c_x[0].id = reg_to_field[reg];
+ reg_c_x[0] = (struct field_modify_info){4, 0, reg_to_field[reg]};
return flow_dv_convert_modify_action(&item, reg_c_x, NULL, resource,
MLX5_MODIFICATION_TYPE_SET, error);
}
return 0;
}
/**
- * Get the size of specific rte_flow_item_type
+ * Get the size of specific rte_flow_item_type hdr size
*
* @param[in] item_type
* Tested rte_flow_item_type.
* sizeof struct item_type, 0 if void or irrelevant.
*/
static size_t
-flow_dv_get_item_len(const enum rte_flow_item_type item_type)
+flow_dv_get_item_hdr_len(const enum rte_flow_item_type item_type)
{
size_t retval;
switch (item_type) {
case RTE_FLOW_ITEM_TYPE_ETH:
- retval = sizeof(struct rte_flow_item_eth);
+ retval = sizeof(struct rte_ether_hdr);
break;
case RTE_FLOW_ITEM_TYPE_VLAN:
- retval = sizeof(struct rte_flow_item_vlan);
+ retval = sizeof(struct rte_vlan_hdr);
break;
case RTE_FLOW_ITEM_TYPE_IPV4:
- retval = sizeof(struct rte_flow_item_ipv4);
+ retval = sizeof(struct rte_ipv4_hdr);
break;
case RTE_FLOW_ITEM_TYPE_IPV6:
- retval = sizeof(struct rte_flow_item_ipv6);
+ retval = sizeof(struct rte_ipv6_hdr);
break;
case RTE_FLOW_ITEM_TYPE_UDP:
- retval = sizeof(struct rte_flow_item_udp);
+ retval = sizeof(struct rte_udp_hdr);
break;
case RTE_FLOW_ITEM_TYPE_TCP:
- retval = sizeof(struct rte_flow_item_tcp);
+ retval = sizeof(struct rte_tcp_hdr);
break;
case RTE_FLOW_ITEM_TYPE_VXLAN:
- retval = sizeof(struct rte_flow_item_vxlan);
+ case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
+ retval = sizeof(struct rte_vxlan_hdr);
break;
case RTE_FLOW_ITEM_TYPE_GRE:
- retval = sizeof(struct rte_flow_item_gre);
- break;
case RTE_FLOW_ITEM_TYPE_NVGRE:
- retval = sizeof(struct rte_flow_item_nvgre);
- break;
- case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
- retval = sizeof(struct rte_flow_item_vxlan_gpe);
+ retval = sizeof(struct rte_gre_hdr);
break;
case RTE_FLOW_ITEM_TYPE_MPLS:
- retval = sizeof(struct rte_flow_item_mpls);
+ retval = sizeof(struct rte_mpls_hdr);
break;
case RTE_FLOW_ITEM_TYPE_VOID: /* Fall through. */
default:
RTE_FLOW_ERROR_TYPE_ACTION,
NULL, "invalid empty data");
for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
- len = flow_dv_get_item_len(items->type);
+ len = flow_dv_get_item_hdr_len(items->type);
if (len + temp_size > MLX5_ENCAP_MAX_LEN)
return rte_flow_error_set(error, EINVAL,
RTE_FLOW_ERROR_TYPE_ACTION,
}
/**
- * Update the minimum dcs-id for aged or no-aged counter pool.
+ * Restore skipped counters in the pool.
+ *
+ * As counter pool query requires the first counter dcs
+ * ID start with 4 alinged, if the pool counters with
+ * min_dcs ID are not aligned with 4, the counters will
+ * be skipped.
+ * Once other min_dcs ID less than these skipped counter
+ * dcs ID appears, the skipped counters will be safe to
+ * use.
+ * Should be called when min_dcs is updated.
*
- * @param[in] dev
- * Pointer to the Ethernet device structure.
* @param[in] pool
* Current counter pool.
- * @param[in] batch
- * Whether the pool is for counter that was allocated by batch command.
- * @param[in] age
- * Whether the counter is for aging.
+ * @param[in] last_min_dcs
+ * Last min_dcs.
*/
static void
-flow_dv_counter_update_min_dcs(struct rte_eth_dev *dev,
- struct mlx5_flow_counter_pool *pool,
- uint32_t batch, uint32_t age)
+flow_dv_counter_restore(struct mlx5_flow_counter_pool *pool,
+ struct mlx5_devx_obj *last_min_dcs)
{
- struct mlx5_priv *priv = dev->data->dev_private;
- struct mlx5_flow_counter_pool *other;
- struct mlx5_pools_container *cont;
+ struct mlx5_flow_counter_ext *cnt_ext;
+ uint32_t offset, new_offset;
+ uint32_t skip_cnt = 0;
+ uint32_t i;
- cont = MLX5_CNT_CONTAINER(priv->sh, batch, (age ^ 0x1));
- other = flow_dv_find_pool_by_id(cont, pool->min_dcs->id);
- if (!other)
+ if (!pool->skip_cnt)
return;
- if (pool->min_dcs->id < other->min_dcs->id) {
- rte_atomic64_set(&other->a64_dcs,
- rte_atomic64_read(&pool->a64_dcs));
- } else {
- rte_atomic64_set(&pool->a64_dcs,
- rte_atomic64_read(&other->a64_dcs));
+ /*
+ * If last min_dcs is not valid. The skipped counter may even after
+ * last min_dcs, set the offset to the whole pool.
+ */
+ if (last_min_dcs->id & (MLX5_CNT_BATCH_QUERY_ID_ALIGNMENT - 1))
+ offset = MLX5_COUNTERS_PER_POOL;
+ else
+ offset = last_min_dcs->id % MLX5_COUNTERS_PER_POOL;
+ new_offset = pool->min_dcs->id % MLX5_COUNTERS_PER_POOL;
+ /*
+ * Check the counters from 1 to the last_min_dcs range. Counters
+ * before new min_dcs indicates pool still has skipped counters.
+ * Counters be skipped after new min_dcs will be ready to use.
+ * Offset 0 counter must be empty or min_dcs, start from 1.
+ */
+ for (i = 1; i < offset; i++) {
+ cnt_ext = MLX5_GET_POOL_CNT_EXT(pool, i);
+ if (cnt_ext->skipped) {
+ if (i > new_offset) {
+ cnt_ext->skipped = 0;
+ TAILQ_INSERT_TAIL
+ (&pool->counters[pool->query_gen],
+ MLX5_POOL_GET_CNT(pool, i), next);
+ } else {
+ skip_cnt++;
+ }
+ }
}
+ if (!skip_cnt)
+ pool->skip_cnt = 0;
}
+
/**
* Prepare a new counter and/or a new counter pool.
*
struct mlx5_pools_container *cont;
struct mlx5_flow_counter_pool *pool;
struct mlx5_counters tmp_tq;
+ struct mlx5_devx_obj *last_min_dcs;
struct mlx5_devx_obj *dcs = NULL;
struct mlx5_flow_counter *cnt;
+ uint32_t add2other;
uint32_t i;
cont = MLX5_CNT_CONTAINER(priv->sh, batch, age);
if (!batch) {
+retry:
+ add2other = 0;
/* bulk_bitmap must be 0 for single counter allocation. */
dcs = mlx5_devx_cmd_flow_counter_alloc(priv->sh->ctx, 0);
if (!dcs)
return NULL;
pool = flow_dv_find_pool_by_id(cont, dcs->id);
+ /* Check if counter belongs to exist pool ID range. */
if (!pool) {
- pool = flow_dv_pool_create(dev, dcs, batch, age);
- if (!pool) {
- mlx5_devx_cmd_destroy(dcs);
- return NULL;
+ pool = flow_dv_find_pool_by_id
+ (MLX5_CNT_CONTAINER
+ (priv->sh, batch, (age ^ 0x1)), dcs->id);
+ /*
+ * Pool eixsts, counter will be added to the other
+ * container, need to reallocate it later.
+ */
+ if (pool) {
+ add2other = 1;
+ } else {
+ pool = flow_dv_pool_create(dev, dcs, batch,
+ age);
+ if (!pool) {
+ mlx5_devx_cmd_destroy(dcs);
+ return NULL;
+ }
}
- } else if (dcs->id < pool->min_dcs->id) {
+ }
+ if ((dcs->id < pool->min_dcs->id ||
+ pool->min_dcs->id &
+ (MLX5_CNT_BATCH_QUERY_ID_ALIGNMENT - 1)) &&
+ !(dcs->id & (MLX5_CNT_BATCH_QUERY_ID_ALIGNMENT - 1))) {
+ /*
+ * Update the pool min_dcs only if current dcs is
+ * valid and exist min_dcs is not valid or greater
+ * than new dcs.
+ */
+ last_min_dcs = pool->min_dcs;
rte_atomic64_set(&pool->a64_dcs,
(int64_t)(uintptr_t)dcs);
+ /*
+ * Restore any skipped counters if the new min_dcs
+ * ID is smaller or min_dcs is not valid.
+ */
+ if (dcs->id < last_min_dcs->id ||
+ last_min_dcs->id &
+ (MLX5_CNT_BATCH_QUERY_ID_ALIGNMENT - 1))
+ flow_dv_counter_restore(pool, last_min_dcs);
}
- flow_dv_counter_update_min_dcs(dev,
- pool, batch, age);
i = dcs->id % MLX5_COUNTERS_PER_POOL;
cnt = MLX5_POOL_GET_CNT(pool, i);
cnt->pool = pool;
MLX5_GET_POOL_CNT_EXT(pool, i)->dcs = dcs;
+ /*
+ * If min_dcs is not valid, it means the new allocated dcs
+ * also fail to become the valid min_dcs, just skip it.
+ * Or if min_dcs is valid, and new dcs ID is smaller than
+ * min_dcs, but not become the min_dcs, also skip it.
+ */
+ if (pool->min_dcs->id &
+ (MLX5_CNT_BATCH_QUERY_ID_ALIGNMENT - 1) ||
+ dcs->id < pool->min_dcs->id) {
+ MLX5_GET_POOL_CNT_EXT(pool, i)->skipped = 1;
+ pool->skip_cnt = 1;
+ goto retry;
+ }
+ if (add2other) {
+ TAILQ_INSERT_TAIL(&pool->counters[pool->query_gen],
+ cnt, next);
+ goto retry;
+ }
*cnt_free = cnt;
return pool;
}
const struct rte_flow_item_nvgre *nvgre_v = item->spec;
void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
- const char *tni_flow_id_m = (const char *)nvgre_m->tni;
- const char *tni_flow_id_v = (const char *)nvgre_v->tni;
+ const char *tni_flow_id_m;
+ const char *tni_flow_id_v;
char *gre_key_m;
char *gre_key_v;
int size;
return;
if (!nvgre_m)
nvgre_m = &rte_flow_item_nvgre_mask;
+ tni_flow_id_m = (const char *)nvgre_m->tni;
+ tni_flow_id_v = (const char *)nvgre_v->tni;
size = sizeof(nvgre_m->tni) + sizeof(nvgre_m->flow_id);
gre_key_m = MLX5_ADDR_OF(fte_match_set_misc, misc_m, gre_key_h);
gre_key_v = MLX5_ADDR_OF(fte_match_set_misc, misc_v, gre_key_h);
};
#endif /* HAVE_IBV_FLOW_DV_SUPPORT */
+