Skip to content

Commit

Permalink
net/mlx5: support flow counter action for HWS
Browse files Browse the repository at this point in the history
This commit adds HW steering counter action support.
The pool mechanism is the basic data structure for the HW steering
counter.

The HW steering's counter pool is based on the rte_ring of zero-copy
variation.

There are two global rte_rings:
1. free_list:
     Store the counters indexes, which are ready for use.
2. wait_reset_list:
     Store the counters indexes, which are just freed from the user and
     need to query the hardware counter to get the reset value before
     this counter can be reused again.

The counter pool also supports cache per HW steering's queues, which are
also based on the rte_ring of zero-copy variation.

The cache can be configured in size, preload, threshold, and fetch size,
they are all exposed via device args.

The main operations of the counter pool are as follows:

 - Get one counter from the pool:
   1. The user call _get_* API.
   2. If the cache is enabled, dequeue one counter index from the local
      cache:
      2. A: if the dequeued one from the local cache is still in reset
        status (counter's query_gen_when_free is equal to pool's query
        gen):
        I. Flush all counters in the local cache back to global
           wait_reset_list.
        II. Fetch _fetch_sz_ counters into the cache from the global
            free list.
        III. Fetch one counter from the cache.
   3. If the cache is empty, fetch _fetch_sz_ counters from the global
      free list into the cache and fetch one counter from the cache.
 - Free one counter into the pool:
   1. The user calls _put_* API.
   2. Put the counter into the local cache.
   3. If the local cache is full:
      A: Write back all counters above _threshold_ into the global
         wait_reset_list.
      B: Also, write back this counter into the global wait_reset_list.

When the local cache is disabled, _get_/_put_ cache directly from/into
global list.

Signed-off-by: Xiaoyu Min <[email protected]>
Acked-by: Viacheslav Ovsiienko <[email protected]>
  • Loading branch information
jackmin authored and raslandarawsheh committed Oct 26, 2022
1 parent 2486536 commit 4d368e1
Show file tree
Hide file tree
Showing 15 changed files with 1,831 additions and 31 deletions.
1 change: 1 addition & 0 deletions doc/guides/rel_notes/release_22_11.rst
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ New Features

* Added full support for queue-based async HW steering.
- Support of FDB.
- Support of counter.
- Support of meter.
- Support of modify fields.

Expand Down
50 changes: 50 additions & 0 deletions drivers/common/mlx5/mlx5_devx_cmds.c
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,41 @@ mlx5_devx_cmd_register_write(void *ctx, uint16_t reg_id, uint32_t arg,
return 0;
}

struct mlx5_devx_obj *
mlx5_devx_cmd_flow_counter_alloc_general(void *ctx,
struct mlx5_devx_counter_attr *attr)
{
struct mlx5_devx_obj *dcs = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*dcs),
0, SOCKET_ID_ANY);
uint32_t in[MLX5_ST_SZ_DW(alloc_flow_counter_in)] = {0};
uint32_t out[MLX5_ST_SZ_DW(alloc_flow_counter_out)] = {0};

if (!dcs) {
rte_errno = ENOMEM;
return NULL;
}
MLX5_SET(alloc_flow_counter_in, in, opcode,
MLX5_CMD_OP_ALLOC_FLOW_COUNTER);
if (attr->bulk_log_max_alloc)
MLX5_SET(alloc_flow_counter_in, in, flow_counter_bulk_log_size,
attr->flow_counter_bulk_log_size);
else
MLX5_SET(alloc_flow_counter_in, in, flow_counter_bulk,
attr->bulk_n_128);
if (attr->pd_valid)
MLX5_SET(alloc_flow_counter_in, in, pd, attr->pd);
dcs->obj = mlx5_glue->devx_obj_create(ctx, in,
sizeof(in), out, sizeof(out));
if (!dcs->obj) {
DRV_LOG(ERR, "Can't allocate counters - error %d", errno);
rte_errno = errno;
mlx5_free(dcs);
return NULL;
}
dcs->id = MLX5_GET(alloc_flow_counter_out, out, flow_counter_id);
return dcs;
}

/**
* Allocate flow counters via devx interface.
*
Expand Down Expand Up @@ -967,6 +1002,16 @@ mlx5_devx_cmd_query_hca_attr(void *ctx,
general_obj_types) &
MLX5_GENERAL_OBJ_TYPES_CAP_CONN_TRACK_OFFLOAD);
attr->rq_delay_drop = MLX5_GET(cmd_hca_cap, hcattr, rq_delay_drop);
attr->max_flow_counter_15_0 = MLX5_GET(cmd_hca_cap, hcattr,
max_flow_counter_15_0);
attr->max_flow_counter_31_16 = MLX5_GET(cmd_hca_cap, hcattr,
max_flow_counter_31_16);
attr->alloc_flow_counter_pd = MLX5_GET(cmd_hca_cap, hcattr,
alloc_flow_counter_pd);
attr->flow_counter_access_aso = MLX5_GET(cmd_hca_cap, hcattr,
flow_counter_access_aso);
attr->flow_access_aso_opc_mod = MLX5_GET(cmd_hca_cap, hcattr,
flow_access_aso_opc_mod);
if (attr->crypto) {
attr->aes_xts = MLX5_GET(cmd_hca_cap, hcattr, aes_xts);
hcattr = mlx5_devx_get_hca_cap(ctx, in, out, &rc,
Expand Down Expand Up @@ -995,6 +1040,11 @@ mlx5_devx_cmd_query_hca_attr(void *ctx,
hairpin_sq_wq_in_host_mem);
attr->hairpin_data_buffer_locked = MLX5_GET(cmd_hca_cap_2, hcattr,
hairpin_data_buffer_locked);
attr->flow_counter_bulk_log_max_alloc = MLX5_GET(cmd_hca_cap_2,
hcattr, flow_counter_bulk_log_max_alloc);
attr->flow_counter_bulk_log_granularity =
MLX5_GET(cmd_hca_cap_2, hcattr,
flow_counter_bulk_log_granularity);
}
if (attr->log_min_stride_wqe_sz == 0)
attr->log_min_stride_wqe_sz = MLX5_MPRQ_LOG_MIN_STRIDE_WQE_SIZE;
Expand Down
27 changes: 27 additions & 0 deletions drivers/common/mlx5/mlx5_devx_cmds.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,16 @@
#define MLX5_DEVX_MAX_KLM_ENTRIES ((UINT16_MAX - \
MLX5_ST_SZ_DW(create_mkey_in) * 4) / (MLX5_ST_SZ_DW(klm) * 4))

struct mlx5_devx_counter_attr {
uint32_t pd_valid:1;
uint32_t pd:24;
uint32_t bulk_log_max_alloc:1;
union {
uint8_t flow_counter_bulk_log_size;
uint8_t bulk_n_128;
};
};

struct mlx5_devx_mkey_attr {
uint64_t addr;
uint64_t size;
Expand Down Expand Up @@ -266,6 +276,18 @@ struct mlx5_hca_attr {
uint32_t set_reg_c:8;
uint32_t nic_flow_table:1;
uint32_t modify_outer_ip_ecn:1;
union {
uint32_t max_flow_counter;
struct {
uint16_t max_flow_counter_15_0;
uint16_t max_flow_counter_31_16;
};
};
uint32_t flow_counter_bulk_log_max_alloc:5;
uint32_t flow_counter_bulk_log_granularity:5;
uint32_t alloc_flow_counter_pd:1;
uint32_t flow_counter_access_aso:1;
uint32_t flow_access_aso_opc_mod:8;
};

/* LAG Context. */
Expand Down Expand Up @@ -598,6 +620,11 @@ struct mlx5_devx_crypto_login_attr {

/* mlx5_devx_cmds.c */

__rte_internal
struct mlx5_devx_obj *
mlx5_devx_cmd_flow_counter_alloc_general(void *ctx,
struct mlx5_devx_counter_attr *attr);

__rte_internal
struct mlx5_devx_obj *mlx5_devx_cmd_flow_counter_alloc(void *ctx,
uint32_t bulk_sz);
Expand Down
20 changes: 16 additions & 4 deletions drivers/common/mlx5/mlx5_prm.h
Original file line number Diff line number Diff line change
Expand Up @@ -1170,8 +1170,10 @@ struct mlx5_ifc_alloc_flow_counter_in_bits {
u8 reserved_at_10[0x10];
u8 reserved_at_20[0x10];
u8 op_mod[0x10];
u8 flow_counter_id[0x20];
u8 reserved_at_40[0x18];
u8 reserved_at_40[0x8];
u8 pd[0x18];
u8 reserved_at_60[0x13];
u8 flow_counter_bulk_log_size[0x5];
u8 flow_counter_bulk[0x8];
};

Expand Down Expand Up @@ -1405,7 +1407,13 @@ enum {
#define MLX5_STEERING_LOGIC_FORMAT_CONNECTX_6DX 0x1

struct mlx5_ifc_cmd_hca_cap_bits {
u8 reserved_at_0[0x20];
u8 access_other_hca_roce[0x1];
u8 alloc_flow_counter_pd[0x1];
u8 flow_counter_access_aso[0x1];
u8 reserved_at_3[0x5];
u8 flow_access_aso_opc_mod[0x8];
u8 reserved_at_10[0xf];
u8 vhca_resource_manager[0x1];
u8 hca_cap_2[0x1];
u8 reserved_at_21[0xf];
u8 vhca_id[0x10];
Expand Down Expand Up @@ -2118,7 +2126,11 @@ struct mlx5_ifc_cmd_hca_cap_2_bits {
u8 format_select_dw_8_6_ext[0x1];
u8 reserved_at_1ac[0x14];
u8 general_obj_types_127_64[0x40];
u8 reserved_at_200[0x80];
u8 reserved_at_200[0x53];
u8 flow_counter_bulk_log_max_alloc[0x5];
u8 reserved_at_258[0x3];
u8 flow_counter_bulk_log_granularity[0x5];
u8 reserved_at_260[0x20];
u8 format_select_dw_gtpu_dw_0[0x8];
u8 format_select_dw_gtpu_dw_1[0x8];
u8 format_select_dw_gtpu_dw_2[0x8];
Expand Down
1 change: 1 addition & 0 deletions drivers/common/mlx5/version.map
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ INTERNAL {
mlx5_devx_cmd_create_virtq;
mlx5_devx_cmd_destroy;
mlx5_devx_cmd_flow_counter_alloc;
mlx5_devx_cmd_flow_counter_alloc_general;
mlx5_devx_cmd_flow_counter_query;
mlx5_devx_cmd_flow_dump;
mlx5_devx_cmd_flow_single_dump;
Expand Down
1 change: 1 addition & 0 deletions drivers/net/mlx5/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ sources = files(
if is_linux
sources += files(
'mlx5_flow_hw.c',
'mlx5_hws_cnt.c',
'mlx5_flow_verbs.c',
)
if (dpdk_conf.has('RTE_ARCH_X86_64')
Expand Down
14 changes: 14 additions & 0 deletions drivers/net/mlx5/mlx5.c
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,12 @@
/* Device parameter to create the fdb default rule in PMD */
#define MLX5_FDB_DEFAULT_RULE_EN "fdb_def_rule_en"

/* HW steering counter configuration. */
#define MLX5_HWS_CNT_SERVICE_CORE "service_core"

/* HW steering counter's query interval. */
#define MLX5_HWS_CNT_CYCLE_TIME "svc_cycle_time"

/* Shared memory between primary and secondary processes. */
struct mlx5_shared_data *mlx5_shared_data;

Expand Down Expand Up @@ -1245,6 +1251,10 @@ mlx5_dev_args_check_handler(const char *key, const char *val, void *opaque)
config->allow_duplicate_pattern = !!tmp;
} else if (strcmp(MLX5_FDB_DEFAULT_RULE_EN, key) == 0) {
config->fdb_def_rule = !!tmp;
} else if (strcmp(MLX5_HWS_CNT_SERVICE_CORE, key) == 0) {
config->cnt_svc.service_core = tmp;
} else if (strcmp(MLX5_HWS_CNT_CYCLE_TIME, key) == 0) {
config->cnt_svc.cycle_time = tmp;
}
return 0;
}
Expand Down Expand Up @@ -1281,6 +1291,8 @@ mlx5_shared_dev_ctx_args_config(struct mlx5_dev_ctx_shared *sh,
MLX5_DECAP_EN,
MLX5_ALLOW_DUPLICATE_PATTERN,
MLX5_FDB_DEFAULT_RULE_EN,
MLX5_HWS_CNT_SERVICE_CORE,
MLX5_HWS_CNT_CYCLE_TIME,
NULL,
};
int ret = 0;
Expand All @@ -1293,6 +1305,8 @@ mlx5_shared_dev_ctx_args_config(struct mlx5_dev_ctx_shared *sh,
config->decap_en = 1;
config->allow_duplicate_pattern = 1;
config->fdb_def_rule = 1;
config->cnt_svc.cycle_time = MLX5_CNT_SVC_CYCLE_TIME_DEFAULT;
config->cnt_svc.service_core = rte_get_main_lcore();
if (mkvlist != NULL) {
/* Process parameters. */
ret = mlx5_kvargs_process(mkvlist, params,
Expand Down
27 changes: 27 additions & 0 deletions drivers/net/mlx5/mlx5.h
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,10 @@ struct mlx5_sh_config {
uint32_t hw_fcs_strip:1; /* FCS stripping is supported. */
uint32_t allow_duplicate_pattern:1;
uint32_t lro_allowed:1; /* Whether LRO is allowed. */
struct {
uint16_t service_core;
uint32_t cycle_time; /* query cycle time in milli-second. */
} cnt_svc; /* configure for HW steering's counter's service. */
/* Allow/Prevent the duplicate rules pattern. */
uint32_t fdb_def_rule:1; /* Create FDB default jump rule */
};
Expand Down Expand Up @@ -1234,6 +1238,22 @@ struct mlx5_send_to_kernel_action {
void *tbl;
};

#define HWS_CNT_ASO_SQ_NUM 4

struct mlx5_hws_aso_mng {
uint16_t sq_num;
struct mlx5_aso_sq sqs[HWS_CNT_ASO_SQ_NUM];
};

struct mlx5_hws_cnt_svc_mng {
uint32_t refcnt;
uint32_t service_core;
uint32_t query_interval;
pthread_t service_thread;
uint8_t svc_running;
struct mlx5_hws_aso_mng aso_mng __rte_cache_aligned;
};

/*
* Shared Infiniband device context for Master/Representors
* which belong to same IB device with multiple IB ports.
Expand Down Expand Up @@ -1334,6 +1354,7 @@ struct mlx5_dev_ctx_shared {
pthread_mutex_t lwm_config_lock;
uint32_t host_shaper_rate:8;
uint32_t lwm_triggered:1;
struct mlx5_hws_cnt_svc_mng *cnt_svc;
struct mlx5_dev_shared_port port[]; /* per device port data array. */
};

Expand Down Expand Up @@ -1620,6 +1641,7 @@ struct mlx5_priv {
/* Flex items have been created on the port. */
uint32_t flex_item_map; /* Map of allocated flex item elements. */
uint32_t nb_queue; /* HW steering queue number. */
struct mlx5_hws_cnt_pool *hws_cpool; /* HW steering's counter pool. */
#if defined(HAVE_IBV_FLOW_DV_SUPPORT) || !defined(HAVE_INFINIBAND_VERBS_H)
/* Item template list. */
LIST_HEAD(flow_hw_itt, rte_flow_pattern_template) flow_hw_itt;
Expand Down Expand Up @@ -2050,6 +2072,11 @@ mlx5_get_supported_sw_parsing_offloads(const struct mlx5_hca_attr *attr);
uint32_t
mlx5_get_supported_tunneling_offloads(const struct mlx5_hca_attr *attr);

int mlx5_aso_cnt_queue_init(struct mlx5_dev_ctx_shared *sh);
void mlx5_aso_cnt_queue_uninit(struct mlx5_dev_ctx_shared *sh);
int mlx5_aso_cnt_query(struct mlx5_dev_ctx_shared *sh,
struct mlx5_hws_cnt_pool *cpool);

/* mlx5_flow_flex.c */

struct rte_flow_item_flex_handle *
Expand Down
2 changes: 2 additions & 0 deletions drivers/net/mlx5/mlx5_defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -188,4 +188,6 @@
#define static_assert _Static_assert
#endif

#define MLX5_CNT_SVC_CYCLE_TIME_DEFAULT 500

#endif /* RTE_PMD_MLX5_DEFS_H_ */
27 changes: 15 additions & 12 deletions drivers/net/mlx5/mlx5_flow.c
Original file line number Diff line number Diff line change
Expand Up @@ -7830,24 +7830,33 @@ mlx5_flow_isolate(struct rte_eth_dev *dev,
*/
static int
flow_drv_query(struct rte_eth_dev *dev,
uint32_t flow_idx,
struct rte_flow *eflow,
const struct rte_flow_action *actions,
void *data,
struct rte_flow_error *error)
{
struct mlx5_priv *priv = dev->data->dev_private;
const struct mlx5_flow_driver_ops *fops;
struct rte_flow *flow = mlx5_ipool_get(priv->flows[MLX5_FLOW_TYPE_GEN],
flow_idx);
enum mlx5_flow_drv_type ftype;
struct rte_flow *flow = NULL;
enum mlx5_flow_drv_type ftype = MLX5_FLOW_TYPE_MIN;

if (priv->sh->config.dv_flow_en == 2) {
#ifdef HAVE_MLX5_HWS_SUPPORT
flow = eflow;
ftype = MLX5_FLOW_TYPE_HW;
#endif
} else {
flow = (struct rte_flow *)mlx5_ipool_get(priv->flows[MLX5_FLOW_TYPE_GEN],
(uintptr_t)(void *)eflow);
}
if (!flow) {
return rte_flow_error_set(error, ENOENT,
RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
NULL,
"invalid flow handle");
}
ftype = flow->drv_type;
if (ftype == MLX5_FLOW_TYPE_MIN)
ftype = flow->drv_type;
MLX5_ASSERT(ftype > MLX5_FLOW_TYPE_MIN && ftype < MLX5_FLOW_TYPE_MAX);
fops = flow_get_drv_ops(ftype);

Expand All @@ -7868,14 +7877,8 @@ mlx5_flow_query(struct rte_eth_dev *dev,
struct rte_flow_error *error)
{
int ret;
struct mlx5_priv *priv = dev->data->dev_private;

if (priv->sh->config.dv_flow_en == 2)
return rte_flow_error_set(error, ENOTSUP,
RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
NULL,
"Flow non-Q query not supported");
ret = flow_drv_query(dev, (uintptr_t)(void *)flow, actions, data,
ret = flow_drv_query(dev, flow, actions, data,
error);
if (ret < 0)
return ret;
Expand Down
5 changes: 5 additions & 0 deletions drivers/net/mlx5/mlx5_flow.h
Original file line number Diff line number Diff line change
Expand Up @@ -1112,6 +1112,7 @@ struct rte_flow_hw {
struct mlx5_hrxq *hrxq; /* TIR action. */
};
struct rte_flow_template_table *table; /* The table flow allcated from. */
uint32_t cnt_id;
uint8_t rule[0]; /* HWS layer data struct. */
} __rte_packed;

Expand Down Expand Up @@ -1160,6 +1161,9 @@ struct mlx5_action_construct_data {
uint32_t level; /* RSS level. */
uint32_t idx; /* Shared action index. */
} shared_rss;
struct {
uint32_t id;
} shared_counter;
};
};

Expand Down Expand Up @@ -1238,6 +1242,7 @@ struct mlx5_hw_actions {
uint16_t encap_decap_pos; /* Encap/Decap action position. */
uint32_t acts_num:4; /* Total action number. */
uint32_t mark:1; /* Indicate the mark action. */
uint32_t cnt_id; /* Counter id. */
/* Translated DR action array from action template. */
struct mlx5dr_rule_action rule_acts[MLX5_HW_MAX_ACTS];
};
Expand Down
Loading

0 comments on commit 4d368e1

Please sign in to comment.