1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright 2019 Mellanox Technologies, Ltd
4 #include <netinet/in.h>
6 #include <rte_malloc.h>
8 #include <rte_common.h>
10 #include <mlx5_common.h>
12 #include "mlx5_vdpa_utils.h"
13 #include "mlx5_vdpa.h"
16 mlx5_vdpa_steer_unset(struct mlx5_vdpa_priv *priv)
21 for (i = 0; i < RTE_DIM(priv->steer.rss); ++i) {
22 if (priv->steer.rss[i].flow) {
23 claim_zero(mlx5_glue->dv_destroy_flow
24 (priv->steer.rss[i].flow));
25 priv->steer.rss[i].flow = NULL;
27 if (priv->steer.rss[i].tir_action) {
28 claim_zero(mlx5_glue->destroy_flow_action
29 (priv->steer.rss[i].tir_action));
30 priv->steer.rss[i].tir_action = NULL;
32 if (priv->steer.rss[i].tir) {
33 claim_zero(mlx5_devx_cmd_destroy
34 (priv->steer.rss[i].tir));
35 priv->steer.rss[i].tir = NULL;
37 if (priv->steer.rss[i].matcher) {
38 claim_zero(mlx5_glue->dv_destroy_flow_matcher
39 (priv->steer.rss[i].matcher));
40 priv->steer.rss[i].matcher = NULL;
43 if (priv->steer.tbl) {
44 claim_zero(mlx5_glue->dr_destroy_flow_tbl(priv->steer.tbl));
45 priv->steer.tbl = NULL;
47 if (priv->steer.domain) {
48 claim_zero(mlx5_glue->dr_destroy_domain(priv->steer.domain));
49 priv->steer.domain = NULL;
51 if (priv->steer.rqt) {
52 claim_zero(mlx5_devx_cmd_destroy(priv->steer.rqt));
53 priv->steer.rqt = NULL;
59 * According to VIRTIO_NET Spec the virtqueues index identity its type by:
68 is_virtq_recvq(int virtq_index, int nr_vring)
70 if (virtq_index % 2 == 0 && virtq_index != nr_vring - 1)
75 #define MLX5_VDPA_DEFAULT_RQT_SIZE 512
76 static int __rte_unused
77 mlx5_vdpa_rqt_prepare(struct mlx5_vdpa_priv *priv)
79 struct mlx5_vdpa_virtq *virtq;
80 uint32_t rqt_n = RTE_MIN(MLX5_VDPA_DEFAULT_RQT_SIZE,
81 1 << priv->log_max_rqt_size);
82 struct mlx5_devx_rqt_attr *attr = rte_zmalloc(__func__, sizeof(*attr)
89 DRV_LOG(ERR, "Failed to allocate RQT attributes memory.");
93 SLIST_FOREACH(virtq, &priv->virtq_list, next) {
94 if (is_virtq_recvq(virtq->index, priv->nr_virtqs)) {
95 attr->rq_list[i] = virtq->virtq->id;
99 for (j = 0; i != rqt_n; ++i, ++j)
100 attr->rq_list[i] = attr->rq_list[j];
101 attr->rq_type = MLX5_INLINE_Q_TYPE_VIRTQ;
102 attr->rqt_max_size = rqt_n;
103 attr->rqt_actual_size = rqt_n;
104 if (!priv->steer.rqt) {
105 priv->steer.rqt = mlx5_devx_cmd_create_rqt(priv->ctx, attr);
106 if (!priv->steer.rqt) {
107 DRV_LOG(ERR, "Failed to create RQT.");
111 ret = mlx5_devx_cmd_modify_rqt(priv->steer.rqt, attr);
113 DRV_LOG(ERR, "Failed to modify RQT.");
119 static int __rte_unused
120 mlx5_vdpa_rss_flows_create(struct mlx5_vdpa_priv *priv)
122 #ifdef HAVE_MLX5DV_DR
123 struct mlx5_devx_tir_attr tir_att = {
124 .disp_type = MLX5_TIRC_DISP_TYPE_INDIRECT,
125 .rx_hash_fn = MLX5_RX_HASH_FN_TOEPLITZ,
126 .transport_domain = priv->td->id,
127 .indirect_table = priv->steer.rqt->id,
128 .rx_hash_symmetric = 1,
129 .rx_hash_toeplitz_key = { 0x2cc681d1, 0x5bdbf4f7, 0xfca28319,
130 0xdb1a3e94, 0x6b9e38d9, 0x2c9c03d1,
131 0xad9944a7, 0xd9563d59, 0x063c25f3,
136 /**< Size of match value. Do NOT split size and key! */
137 uint32_t buf[MLX5_ST_SZ_DW(fte_match_param)];
138 /**< Matcher value. This value is used as the mask or a key. */
140 .size = sizeof(matcher_mask.buf),
143 .size = sizeof(matcher_value.buf),
145 struct mlx5dv_flow_matcher_attr dv_attr = {
146 .type = IBV_FLOW_ATTR_NORMAL,
147 .match_mask = (void *)&matcher_mask,
149 void *match_m = matcher_mask.buf;
150 void *match_v = matcher_value.buf;
151 void *headers_m = MLX5_ADDR_OF(fte_match_param, match_m, outer_headers);
152 void *headers_v = MLX5_ADDR_OF(fte_match_param, match_v, outer_headers);
154 const uint8_t l3_hash =
155 (1 << MLX5_RX_HASH_FIELD_SELECT_SELECTED_FIELDS_SRC_IP) |
156 (1 << MLX5_RX_HASH_FIELD_SELECT_SELECTED_FIELDS_DST_IP);
157 const uint8_t l4_hash =
158 (1 << MLX5_RX_HASH_FIELD_SELECT_SELECTED_FIELDS_L4_SPORT) |
159 (1 << MLX5_RX_HASH_FIELD_SELECT_SELECTED_FIELDS_L4_DPORT);
160 enum { PRIO, CRITERIA, IP_VER_M, IP_VER_V, IP_PROT_M, IP_PROT_V, L3_BIT,
162 const uint8_t vars[RTE_DIM(priv->steer.rss)][END] = {
163 { 7, 0, 0, 0, 0, 0, 0, 0, 0 },
164 { 6, 1 << MLX5_MATCH_CRITERIA_ENABLE_OUTER_BIT, 0xf, 4, 0, 0,
165 MLX5_L3_PROT_TYPE_IPV4, 0, l3_hash },
166 { 6, 1 << MLX5_MATCH_CRITERIA_ENABLE_OUTER_BIT, 0xf, 6, 0, 0,
167 MLX5_L3_PROT_TYPE_IPV6, 0, l3_hash },
168 { 5, 1 << MLX5_MATCH_CRITERIA_ENABLE_OUTER_BIT, 0xf, 4, 0xff,
169 IPPROTO_UDP, MLX5_L3_PROT_TYPE_IPV4, MLX5_L4_PROT_TYPE_UDP,
171 { 5, 1 << MLX5_MATCH_CRITERIA_ENABLE_OUTER_BIT, 0xf, 4, 0xff,
172 IPPROTO_TCP, MLX5_L3_PROT_TYPE_IPV4, MLX5_L4_PROT_TYPE_TCP,
174 { 5, 1 << MLX5_MATCH_CRITERIA_ENABLE_OUTER_BIT, 0xf, 6, 0xff,
175 IPPROTO_UDP, MLX5_L3_PROT_TYPE_IPV6, MLX5_L4_PROT_TYPE_UDP,
177 { 5, 1 << MLX5_MATCH_CRITERIA_ENABLE_OUTER_BIT, 0xf, 6, 0xff,
178 IPPROTO_TCP, MLX5_L3_PROT_TYPE_IPV6, MLX5_L4_PROT_TYPE_TCP,
183 for (i = 0; i < RTE_DIM(priv->steer.rss); ++i) {
184 dv_attr.priority = vars[i][PRIO];
185 dv_attr.match_criteria_enable = vars[i][CRITERIA];
186 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_version,
188 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_version,
190 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol,
192 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol,
194 tir_att.rx_hash_field_selector_outer.l3_prot_type =
196 tir_att.rx_hash_field_selector_outer.l4_prot_type =
198 tir_att.rx_hash_field_selector_outer.selected_fields =
200 priv->steer.rss[i].matcher = mlx5_glue->dv_create_flow_matcher
201 (priv->ctx, &dv_attr, priv->steer.tbl);
202 if (!priv->steer.rss[i].matcher) {
203 DRV_LOG(ERR, "Failed to create matcher %d.", i);
206 priv->steer.rss[i].tir = mlx5_devx_cmd_create_tir(priv->ctx,
208 if (!priv->steer.rss[i].tir) {
209 DRV_LOG(ERR, "Failed to create TIR %d.", i);
212 priv->steer.rss[i].tir_action =
213 mlx5_glue->dv_create_flow_action_dest_devx_tir
214 (priv->steer.rss[i].tir->obj);
215 if (!priv->steer.rss[i].tir_action) {
216 DRV_LOG(ERR, "Failed to create TIR action %d.", i);
219 actions[0] = priv->steer.rss[i].tir_action;
220 priv->steer.rss[i].flow = mlx5_glue->dv_create_flow
221 (priv->steer.rss[i].matcher,
222 (void *)&matcher_value, 1, actions);
223 if (!priv->steer.rss[i].flow) {
224 DRV_LOG(ERR, "Failed to create flow %d.", i);
230 /* Resources will be freed by the caller. */
235 #endif /* HAVE_MLX5DV_DR */
239 mlx5_vdpa_steer_setup(struct mlx5_vdpa_priv *priv)
241 #ifdef HAVE_MLX5DV_DR
242 if (mlx5_vdpa_rqt_prepare(priv))
244 priv->steer.domain = mlx5_glue->dr_create_domain(priv->ctx,
245 MLX5DV_DR_DOMAIN_TYPE_NIC_RX);
246 if (!priv->steer.domain) {
247 DRV_LOG(ERR, "Failed to create Rx domain.");
250 priv->steer.tbl = mlx5_glue->dr_create_flow_tbl(priv->steer.domain, 0);
251 if (!priv->steer.tbl) {
252 DRV_LOG(ERR, "Failed to create table 0 with Rx domain.");
255 if (mlx5_vdpa_rss_flows_create(priv))
259 mlx5_vdpa_steer_unset(priv);
264 #endif /* HAVE_MLX5DV_DR */