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_rss_flows_destroy(struct mlx5_vdpa_priv *priv)
20 for (i = 0; i < RTE_DIM(priv->steer.rss); ++i) {
21 if (priv->steer.rss[i].flow) {
22 claim_zero(mlx5_glue->dv_destroy_flow
23 (priv->steer.rss[i].flow));
24 priv->steer.rss[i].flow = NULL;
26 if (priv->steer.rss[i].tir_action) {
27 claim_zero(mlx5_glue->destroy_flow_action
28 (priv->steer.rss[i].tir_action));
29 priv->steer.rss[i].tir_action = NULL;
31 if (priv->steer.rss[i].tir) {
32 claim_zero(mlx5_devx_cmd_destroy
33 (priv->steer.rss[i].tir));
34 priv->steer.rss[i].tir = NULL;
36 if (priv->steer.rss[i].matcher) {
37 claim_zero(mlx5_glue->dv_destroy_flow_matcher
38 (priv->steer.rss[i].matcher));
39 priv->steer.rss[i].matcher = NULL;
45 mlx5_vdpa_steer_unset(struct mlx5_vdpa_priv *priv)
47 mlx5_vdpa_rss_flows_destroy(priv);
48 if (priv->steer.tbl) {
49 claim_zero(mlx5_glue->dr_destroy_flow_tbl(priv->steer.tbl));
50 priv->steer.tbl = NULL;
52 if (priv->steer.domain) {
53 claim_zero(mlx5_glue->dr_destroy_domain(priv->steer.domain));
54 priv->steer.domain = NULL;
56 if (priv->steer.rqt) {
57 claim_zero(mlx5_devx_cmd_destroy(priv->steer.rqt));
58 priv->steer.rqt = NULL;
62 #define MLX5_VDPA_DEFAULT_RQT_SIZE 512
64 * Return the number of queues configured to the table on success, otherwise
68 mlx5_vdpa_rqt_prepare(struct mlx5_vdpa_priv *priv)
71 uint32_t rqt_n = RTE_MIN(MLX5_VDPA_DEFAULT_RQT_SIZE,
72 1 << priv->log_max_rqt_size);
73 struct mlx5_devx_rqt_attr *attr = rte_zmalloc(__func__, sizeof(*attr)
80 DRV_LOG(ERR, "Failed to allocate RQT attributes memory.");
84 for (i = 0; i < priv->nr_virtqs; i++) {
85 if (is_virtq_recvq(i, priv->nr_virtqs) &&
86 priv->virtqs[i].enable && priv->virtqs[i].virtq) {
87 attr->rq_list[k] = priv->virtqs[i].virtq->id;
92 /* No enabled RQ to configure for RSS. */
95 for (j = 0; k != rqt_n; ++k, ++j)
96 attr->rq_list[k] = attr->rq_list[j];
97 attr->rq_type = MLX5_INLINE_Q_TYPE_VIRTQ;
98 attr->rqt_max_size = rqt_n;
99 attr->rqt_actual_size = rqt_n;
100 if (!priv->steer.rqt) {
101 priv->steer.rqt = mlx5_devx_cmd_create_rqt(priv->ctx, attr);
102 if (!priv->steer.rqt) {
103 DRV_LOG(ERR, "Failed to create RQT.");
107 ret = mlx5_devx_cmd_modify_rqt(priv->steer.rqt, attr);
109 DRV_LOG(ERR, "Failed to modify RQT.");
112 return ret ? -1 : num;
115 static int __rte_unused
116 mlx5_vdpa_rss_flows_create(struct mlx5_vdpa_priv *priv)
118 #ifdef HAVE_MLX5DV_DR
119 struct mlx5_devx_tir_attr tir_att = {
120 .disp_type = MLX5_TIRC_DISP_TYPE_INDIRECT,
121 .rx_hash_fn = MLX5_RX_HASH_FN_TOEPLITZ,
122 .transport_domain = priv->td->id,
123 .indirect_table = priv->steer.rqt->id,
124 .rx_hash_symmetric = 1,
125 .rx_hash_toeplitz_key = { 0x2c, 0xc6, 0x81, 0xd1,
126 0x5b, 0xdb, 0xf4, 0xf7,
127 0xfc, 0xa2, 0x83, 0x19,
128 0xdb, 0x1a, 0x3e, 0x94,
129 0x6b, 0x9e, 0x38, 0xd9,
130 0x2c, 0x9c, 0x03, 0xd1,
131 0xad, 0x99, 0x44, 0xa7,
132 0xd9, 0x56, 0x3d, 0x59,
133 0x06, 0x3c, 0x25, 0xf3,
134 0xfc, 0x1f, 0xdc, 0x2a },
138 /**< Size of match value. Do NOT split size and key! */
139 uint32_t buf[MLX5_ST_SZ_DW(fte_match_param)];
140 /**< Matcher value. This value is used as the mask or a key. */
142 .size = sizeof(matcher_mask.buf) -
143 MLX5_ST_SZ_BYTES(fte_match_set_misc4) -
144 MLX5_ST_SZ_BYTES(fte_match_set_misc5),
147 .size = sizeof(matcher_value.buf) -
148 MLX5_ST_SZ_BYTES(fte_match_set_misc4) -
149 MLX5_ST_SZ_BYTES(fte_match_set_misc5),
151 struct mlx5dv_flow_matcher_attr dv_attr = {
152 .type = IBV_FLOW_ATTR_NORMAL,
153 .match_mask = (void *)&matcher_mask,
155 void *match_m = matcher_mask.buf;
156 void *match_v = matcher_value.buf;
157 void *headers_m = MLX5_ADDR_OF(fte_match_param, match_m, outer_headers);
158 void *headers_v = MLX5_ADDR_OF(fte_match_param, match_v, outer_headers);
160 const uint8_t l3_hash =
161 (1 << MLX5_RX_HASH_FIELD_SELECT_SELECTED_FIELDS_SRC_IP) |
162 (1 << MLX5_RX_HASH_FIELD_SELECT_SELECTED_FIELDS_DST_IP);
163 const uint8_t l4_hash =
164 (1 << MLX5_RX_HASH_FIELD_SELECT_SELECTED_FIELDS_L4_SPORT) |
165 (1 << MLX5_RX_HASH_FIELD_SELECT_SELECTED_FIELDS_L4_DPORT);
166 enum { PRIO, CRITERIA, IP_VER_M, IP_VER_V, IP_PROT_M, IP_PROT_V, L3_BIT,
168 const uint8_t vars[RTE_DIM(priv->steer.rss)][END] = {
169 { 7, 0, 0, 0, 0, 0, 0, 0, 0 },
170 { 6, 1 << MLX5_MATCH_CRITERIA_ENABLE_OUTER_BIT, 0xf, 4, 0, 0,
171 MLX5_L3_PROT_TYPE_IPV4, 0, l3_hash },
172 { 6, 1 << MLX5_MATCH_CRITERIA_ENABLE_OUTER_BIT, 0xf, 6, 0, 0,
173 MLX5_L3_PROT_TYPE_IPV6, 0, l3_hash },
174 { 5, 1 << MLX5_MATCH_CRITERIA_ENABLE_OUTER_BIT, 0xf, 4, 0xff,
175 IPPROTO_UDP, MLX5_L3_PROT_TYPE_IPV4, MLX5_L4_PROT_TYPE_UDP,
177 { 5, 1 << MLX5_MATCH_CRITERIA_ENABLE_OUTER_BIT, 0xf, 4, 0xff,
178 IPPROTO_TCP, MLX5_L3_PROT_TYPE_IPV4, MLX5_L4_PROT_TYPE_TCP,
180 { 5, 1 << MLX5_MATCH_CRITERIA_ENABLE_OUTER_BIT, 0xf, 6, 0xff,
181 IPPROTO_UDP, MLX5_L3_PROT_TYPE_IPV6, MLX5_L4_PROT_TYPE_UDP,
183 { 5, 1 << MLX5_MATCH_CRITERIA_ENABLE_OUTER_BIT, 0xf, 6, 0xff,
184 IPPROTO_TCP, MLX5_L3_PROT_TYPE_IPV6, MLX5_L4_PROT_TYPE_TCP,
189 for (i = 0; i < RTE_DIM(priv->steer.rss); ++i) {
190 dv_attr.priority = vars[i][PRIO];
191 dv_attr.match_criteria_enable = vars[i][CRITERIA];
192 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_version,
194 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_version,
196 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol,
198 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol,
200 tir_att.rx_hash_field_selector_outer.l3_prot_type =
202 tir_att.rx_hash_field_selector_outer.l4_prot_type =
204 tir_att.rx_hash_field_selector_outer.selected_fields =
206 priv->steer.rss[i].matcher = mlx5_glue->dv_create_flow_matcher
207 (priv->ctx, &dv_attr, priv->steer.tbl);
208 if (!priv->steer.rss[i].matcher) {
209 DRV_LOG(ERR, "Failed to create matcher %d.", i);
212 priv->steer.rss[i].tir = mlx5_devx_cmd_create_tir(priv->ctx,
214 if (!priv->steer.rss[i].tir) {
215 DRV_LOG(ERR, "Failed to create TIR %d.", i);
218 priv->steer.rss[i].tir_action =
219 mlx5_glue->dv_create_flow_action_dest_devx_tir
220 (priv->steer.rss[i].tir->obj);
221 if (!priv->steer.rss[i].tir_action) {
222 DRV_LOG(ERR, "Failed to create TIR action %d.", i);
225 actions[0] = priv->steer.rss[i].tir_action;
226 priv->steer.rss[i].flow = mlx5_glue->dv_create_flow
227 (priv->steer.rss[i].matcher,
228 (void *)&matcher_value, 1, actions);
229 if (!priv->steer.rss[i].flow) {
230 DRV_LOG(ERR, "Failed to create flow %d.", i);
236 /* Resources will be freed by the caller. */
241 #endif /* HAVE_MLX5DV_DR */
245 mlx5_vdpa_steer_update(struct mlx5_vdpa_priv *priv)
247 int ret = mlx5_vdpa_rqt_prepare(priv);
250 mlx5_vdpa_rss_flows_destroy(priv);
251 if (priv->steer.rqt) {
252 claim_zero(mlx5_devx_cmd_destroy(priv->steer.rqt));
253 priv->steer.rqt = NULL;
255 } else if (ret < 0) {
257 } else if (!priv->steer.rss[0].flow) {
258 ret = mlx5_vdpa_rss_flows_create(priv);
260 DRV_LOG(ERR, "Cannot create RSS flows.");
268 mlx5_vdpa_steer_setup(struct mlx5_vdpa_priv *priv)
270 #ifdef HAVE_MLX5DV_DR
271 priv->steer.domain = mlx5_glue->dr_create_domain(priv->ctx,
272 MLX5DV_DR_DOMAIN_TYPE_NIC_RX);
273 if (!priv->steer.domain) {
274 DRV_LOG(ERR, "Failed to create Rx domain.");
277 priv->steer.tbl = mlx5_glue->dr_create_flow_tbl(priv->steer.domain, 0);
278 if (!priv->steer.tbl) {
279 DRV_LOG(ERR, "Failed to create table 0 with Rx domain.");
282 if (mlx5_vdpa_steer_update(priv))
286 mlx5_vdpa_steer_unset(priv);
291 #endif /* HAVE_MLX5DV_DR */