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
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) &&
96 attr->rq_list[i] = virtq->virtq->id;
100 for (j = 0; i != rqt_n; ++i, ++j)
101 attr->rq_list[i] = attr->rq_list[j];
102 attr->rq_type = MLX5_INLINE_Q_TYPE_VIRTQ;
103 attr->rqt_max_size = rqt_n;
104 attr->rqt_actual_size = rqt_n;
105 if (!priv->steer.rqt) {
106 priv->steer.rqt = mlx5_devx_cmd_create_rqt(priv->ctx, attr);
107 if (!priv->steer.rqt) {
108 DRV_LOG(ERR, "Failed to create RQT.");
112 ret = mlx5_devx_cmd_modify_rqt(priv->steer.rqt, attr);
114 DRV_LOG(ERR, "Failed to modify RQT.");
121 mlx5_vdpa_virtq_enable(struct mlx5_vdpa_virtq *virtq, int enable)
123 struct mlx5_vdpa_priv *priv = virtq->priv;
126 if (virtq->enable == !!enable)
128 virtq->enable = !!enable;
129 if (is_virtq_recvq(virtq->index, priv->nr_virtqs)) {
130 ret = mlx5_vdpa_rqt_prepare(priv);
132 virtq->enable = !enable;
137 static int __rte_unused
138 mlx5_vdpa_rss_flows_create(struct mlx5_vdpa_priv *priv)
140 #ifdef HAVE_MLX5DV_DR
141 struct mlx5_devx_tir_attr tir_att = {
142 .disp_type = MLX5_TIRC_DISP_TYPE_INDIRECT,
143 .rx_hash_fn = MLX5_RX_HASH_FN_TOEPLITZ,
144 .transport_domain = priv->td->id,
145 .indirect_table = priv->steer.rqt->id,
146 .rx_hash_symmetric = 1,
147 .rx_hash_toeplitz_key = { 0x2c, 0xc6, 0x81, 0xd1,
148 0x5b, 0xdb, 0xf4, 0xf7,
149 0xfc, 0xa2, 0x83, 0x19,
150 0xdb, 0x1a, 0x3e, 0x94,
151 0x6b, 0x9e, 0x38, 0xd9,
152 0x2c, 0x9c, 0x03, 0xd1,
153 0xad, 0x99, 0x44, 0xa7,
154 0xd9, 0x56, 0x3d, 0x59,
155 0x06, 0x3c, 0x25, 0xf3,
156 0xfc, 0x1f, 0xdc, 0x2a },
160 /**< Size of match value. Do NOT split size and key! */
161 uint32_t buf[MLX5_ST_SZ_DW(fte_match_param)];
162 /**< Matcher value. This value is used as the mask or a key. */
164 .size = sizeof(matcher_mask.buf),
167 .size = sizeof(matcher_value.buf),
169 struct mlx5dv_flow_matcher_attr dv_attr = {
170 .type = IBV_FLOW_ATTR_NORMAL,
171 .match_mask = (void *)&matcher_mask,
173 void *match_m = matcher_mask.buf;
174 void *match_v = matcher_value.buf;
175 void *headers_m = MLX5_ADDR_OF(fte_match_param, match_m, outer_headers);
176 void *headers_v = MLX5_ADDR_OF(fte_match_param, match_v, outer_headers);
178 const uint8_t l3_hash =
179 (1 << MLX5_RX_HASH_FIELD_SELECT_SELECTED_FIELDS_SRC_IP) |
180 (1 << MLX5_RX_HASH_FIELD_SELECT_SELECTED_FIELDS_DST_IP);
181 const uint8_t l4_hash =
182 (1 << MLX5_RX_HASH_FIELD_SELECT_SELECTED_FIELDS_L4_SPORT) |
183 (1 << MLX5_RX_HASH_FIELD_SELECT_SELECTED_FIELDS_L4_DPORT);
184 enum { PRIO, CRITERIA, IP_VER_M, IP_VER_V, IP_PROT_M, IP_PROT_V, L3_BIT,
186 const uint8_t vars[RTE_DIM(priv->steer.rss)][END] = {
187 { 7, 0, 0, 0, 0, 0, 0, 0, 0 },
188 { 6, 1 << MLX5_MATCH_CRITERIA_ENABLE_OUTER_BIT, 0xf, 4, 0, 0,
189 MLX5_L3_PROT_TYPE_IPV4, 0, l3_hash },
190 { 6, 1 << MLX5_MATCH_CRITERIA_ENABLE_OUTER_BIT, 0xf, 6, 0, 0,
191 MLX5_L3_PROT_TYPE_IPV6, 0, l3_hash },
192 { 5, 1 << MLX5_MATCH_CRITERIA_ENABLE_OUTER_BIT, 0xf, 4, 0xff,
193 IPPROTO_UDP, MLX5_L3_PROT_TYPE_IPV4, MLX5_L4_PROT_TYPE_UDP,
195 { 5, 1 << MLX5_MATCH_CRITERIA_ENABLE_OUTER_BIT, 0xf, 4, 0xff,
196 IPPROTO_TCP, MLX5_L3_PROT_TYPE_IPV4, MLX5_L4_PROT_TYPE_TCP,
198 { 5, 1 << MLX5_MATCH_CRITERIA_ENABLE_OUTER_BIT, 0xf, 6, 0xff,
199 IPPROTO_UDP, MLX5_L3_PROT_TYPE_IPV6, MLX5_L4_PROT_TYPE_UDP,
201 { 5, 1 << MLX5_MATCH_CRITERIA_ENABLE_OUTER_BIT, 0xf, 6, 0xff,
202 IPPROTO_TCP, MLX5_L3_PROT_TYPE_IPV6, MLX5_L4_PROT_TYPE_TCP,
207 for (i = 0; i < RTE_DIM(priv->steer.rss); ++i) {
208 dv_attr.priority = vars[i][PRIO];
209 dv_attr.match_criteria_enable = vars[i][CRITERIA];
210 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_version,
212 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_version,
214 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol,
216 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol,
218 tir_att.rx_hash_field_selector_outer.l3_prot_type =
220 tir_att.rx_hash_field_selector_outer.l4_prot_type =
222 tir_att.rx_hash_field_selector_outer.selected_fields =
224 priv->steer.rss[i].matcher = mlx5_glue->dv_create_flow_matcher
225 (priv->ctx, &dv_attr, priv->steer.tbl);
226 if (!priv->steer.rss[i].matcher) {
227 DRV_LOG(ERR, "Failed to create matcher %d.", i);
230 priv->steer.rss[i].tir = mlx5_devx_cmd_create_tir(priv->ctx,
232 if (!priv->steer.rss[i].tir) {
233 DRV_LOG(ERR, "Failed to create TIR %d.", i);
236 priv->steer.rss[i].tir_action =
237 mlx5_glue->dv_create_flow_action_dest_devx_tir
238 (priv->steer.rss[i].tir->obj);
239 if (!priv->steer.rss[i].tir_action) {
240 DRV_LOG(ERR, "Failed to create TIR action %d.", i);
243 actions[0] = priv->steer.rss[i].tir_action;
244 priv->steer.rss[i].flow = mlx5_glue->dv_create_flow
245 (priv->steer.rss[i].matcher,
246 (void *)&matcher_value, 1, actions);
247 if (!priv->steer.rss[i].flow) {
248 DRV_LOG(ERR, "Failed to create flow %d.", i);
254 /* Resources will be freed by the caller. */
259 #endif /* HAVE_MLX5DV_DR */
263 mlx5_vdpa_steer_setup(struct mlx5_vdpa_priv *priv)
265 #ifdef HAVE_MLX5DV_DR
266 if (mlx5_vdpa_rqt_prepare(priv))
268 priv->steer.domain = mlx5_glue->dr_create_domain(priv->ctx,
269 MLX5DV_DR_DOMAIN_TYPE_NIC_RX);
270 if (!priv->steer.domain) {
271 DRV_LOG(ERR, "Failed to create Rx domain.");
274 priv->steer.tbl = mlx5_glue->dr_create_flow_tbl(priv->steer.domain, 0);
275 if (!priv->steer.tbl) {
276 DRV_LOG(ERR, "Failed to create table 0 with Rx domain.");
279 if (mlx5_vdpa_rss_flows_create(priv))
283 mlx5_vdpa_steer_unset(priv);
288 #endif /* HAVE_MLX5DV_DR */