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.rqt) {
49 claim_zero(mlx5_devx_cmd_destroy(priv->steer.rqt));
50 priv->steer.rqt = NULL;
54 #define MLX5_VDPA_DEFAULT_RQT_SIZE 512
56 * Return the number of queues configured to the table on success, otherwise
60 mlx5_vdpa_rqt_prepare(struct mlx5_vdpa_priv *priv)
63 uint32_t rqt_n = RTE_MIN(MLX5_VDPA_DEFAULT_RQT_SIZE,
64 1 << priv->log_max_rqt_size);
65 struct mlx5_devx_rqt_attr *attr = rte_zmalloc(__func__, sizeof(*attr)
72 DRV_LOG(ERR, "Failed to allocate RQT attributes memory.");
76 for (i = 0; i < priv->nr_virtqs; i++) {
77 if (is_virtq_recvq(i, priv->nr_virtqs) &&
78 priv->virtqs[i].enable && priv->virtqs[i].virtq) {
79 attr->rq_list[k] = priv->virtqs[i].virtq->id;
84 /* No enabled RQ to configure for RSS. */
87 for (j = 0; k != rqt_n; ++k, ++j)
88 attr->rq_list[k] = attr->rq_list[j];
89 attr->rq_type = MLX5_INLINE_Q_TYPE_VIRTQ;
90 attr->rqt_max_size = rqt_n;
91 attr->rqt_actual_size = rqt_n;
92 if (!priv->steer.rqt) {
93 priv->steer.rqt = mlx5_devx_cmd_create_rqt(priv->cdev->ctx,
95 if (!priv->steer.rqt) {
96 DRV_LOG(ERR, "Failed to create RQT.");
100 ret = mlx5_devx_cmd_modify_rqt(priv->steer.rqt, attr);
102 DRV_LOG(ERR, "Failed to modify RQT.");
105 return ret ? -1 : num;
108 static int __rte_unused
109 mlx5_vdpa_rss_flows_create(struct mlx5_vdpa_priv *priv)
111 #ifdef HAVE_MLX5DV_DR
112 struct mlx5_devx_tir_attr tir_att = {
113 .disp_type = MLX5_TIRC_DISP_TYPE_INDIRECT,
114 .rx_hash_fn = MLX5_RX_HASH_FN_TOEPLITZ,
115 .transport_domain = priv->td->id,
116 .indirect_table = priv->steer.rqt->id,
117 .rx_hash_symmetric = 1,
118 .rx_hash_toeplitz_key = { 0x2c, 0xc6, 0x81, 0xd1,
119 0x5b, 0xdb, 0xf4, 0xf7,
120 0xfc, 0xa2, 0x83, 0x19,
121 0xdb, 0x1a, 0x3e, 0x94,
122 0x6b, 0x9e, 0x38, 0xd9,
123 0x2c, 0x9c, 0x03, 0xd1,
124 0xad, 0x99, 0x44, 0xa7,
125 0xd9, 0x56, 0x3d, 0x59,
126 0x06, 0x3c, 0x25, 0xf3,
127 0xfc, 0x1f, 0xdc, 0x2a },
131 /**< Size of match value. Do NOT split size and key! */
132 uint32_t buf[MLX5_ST_SZ_DW(fte_match_param)];
133 /**< Matcher value. This value is used as the mask or a key. */
135 .size = sizeof(matcher_mask.buf) -
136 MLX5_ST_SZ_BYTES(fte_match_set_misc4) -
137 MLX5_ST_SZ_BYTES(fte_match_set_misc5),
140 .size = sizeof(matcher_value.buf) -
141 MLX5_ST_SZ_BYTES(fte_match_set_misc4) -
142 MLX5_ST_SZ_BYTES(fte_match_set_misc5),
144 struct mlx5dv_flow_matcher_attr dv_attr = {
145 .type = IBV_FLOW_ATTR_NORMAL,
146 .match_mask = (void *)&matcher_mask,
148 void *match_m = matcher_mask.buf;
149 void *match_v = matcher_value.buf;
150 void *headers_m = MLX5_ADDR_OF(fte_match_param, match_m, outer_headers);
151 void *headers_v = MLX5_ADDR_OF(fte_match_param, match_v, outer_headers);
153 const uint8_t l3_hash =
154 (1 << MLX5_RX_HASH_FIELD_SELECT_SELECTED_FIELDS_SRC_IP) |
155 (1 << MLX5_RX_HASH_FIELD_SELECT_SELECTED_FIELDS_DST_IP);
156 const uint8_t l4_hash =
157 (1 << MLX5_RX_HASH_FIELD_SELECT_SELECTED_FIELDS_L4_SPORT) |
158 (1 << MLX5_RX_HASH_FIELD_SELECT_SELECTED_FIELDS_L4_DPORT);
159 enum { PRIO, CRITERIA, IP_VER_M, IP_VER_V, IP_PROT_M, IP_PROT_V, L3_BIT,
161 const uint8_t vars[RTE_DIM(priv->steer.rss)][END] = {
162 { 7, 0, 0, 0, 0, 0, 0, 0, 0 },
163 { 6, 1 << MLX5_MATCH_CRITERIA_ENABLE_OUTER_BIT, 0xf, 4, 0, 0,
164 MLX5_L3_PROT_TYPE_IPV4, 0, l3_hash },
165 { 6, 1 << MLX5_MATCH_CRITERIA_ENABLE_OUTER_BIT, 0xf, 6, 0, 0,
166 MLX5_L3_PROT_TYPE_IPV6, 0, l3_hash },
167 { 5, 1 << MLX5_MATCH_CRITERIA_ENABLE_OUTER_BIT, 0xf, 4, 0xff,
168 IPPROTO_UDP, MLX5_L3_PROT_TYPE_IPV4, MLX5_L4_PROT_TYPE_UDP,
170 { 5, 1 << MLX5_MATCH_CRITERIA_ENABLE_OUTER_BIT, 0xf, 4, 0xff,
171 IPPROTO_TCP, MLX5_L3_PROT_TYPE_IPV4, MLX5_L4_PROT_TYPE_TCP,
173 { 5, 1 << MLX5_MATCH_CRITERIA_ENABLE_OUTER_BIT, 0xf, 6, 0xff,
174 IPPROTO_UDP, MLX5_L3_PROT_TYPE_IPV6, MLX5_L4_PROT_TYPE_UDP,
176 { 5, 1 << MLX5_MATCH_CRITERIA_ENABLE_OUTER_BIT, 0xf, 6, 0xff,
177 IPPROTO_TCP, MLX5_L3_PROT_TYPE_IPV6, MLX5_L4_PROT_TYPE_TCP,
182 for (i = 0; i < RTE_DIM(priv->steer.rss); ++i) {
183 dv_attr.priority = vars[i][PRIO];
184 dv_attr.match_criteria_enable = vars[i][CRITERIA];
185 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_version,
187 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_version,
189 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol,
191 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol,
193 tir_att.rx_hash_field_selector_outer.l3_prot_type =
195 tir_att.rx_hash_field_selector_outer.l4_prot_type =
197 tir_att.rx_hash_field_selector_outer.selected_fields =
199 priv->steer.rss[i].matcher = mlx5_glue->dv_create_flow_matcher
200 (priv->cdev->ctx, &dv_attr, priv->steer.tbl);
201 if (!priv->steer.rss[i].matcher) {
202 DRV_LOG(ERR, "Failed to create matcher %d.", i);
205 priv->steer.rss[i].tir = mlx5_devx_cmd_create_tir
206 (priv->cdev->ctx, &tir_att);
207 if (!priv->steer.rss[i].tir) {
208 DRV_LOG(ERR, "Failed to create TIR %d.", i);
211 priv->steer.rss[i].tir_action =
212 mlx5_glue->dv_create_flow_action_dest_devx_tir
213 (priv->steer.rss[i].tir->obj);
214 if (!priv->steer.rss[i].tir_action) {
215 DRV_LOG(ERR, "Failed to create TIR action %d.", i);
218 actions[0] = priv->steer.rss[i].tir_action;
219 priv->steer.rss[i].flow = mlx5_glue->dv_create_flow
220 (priv->steer.rss[i].matcher,
221 (void *)&matcher_value, 1, actions);
222 if (!priv->steer.rss[i].flow) {
223 DRV_LOG(ERR, "Failed to create flow %d.", i);
229 /* Resources will be freed by the caller. */
234 #endif /* HAVE_MLX5DV_DR */
238 mlx5_vdpa_steer_update(struct mlx5_vdpa_priv *priv)
242 pthread_mutex_lock(&priv->steer_update_lock);
243 ret = mlx5_vdpa_rqt_prepare(priv);
245 mlx5_vdpa_steer_unset(priv);
246 } else if (ret < 0) {
247 pthread_mutex_unlock(&priv->steer_update_lock);
249 } else if (!priv->steer.rss[0].flow) {
250 ret = mlx5_vdpa_rss_flows_create(priv);
252 DRV_LOG(ERR, "Cannot create RSS flows.");
253 pthread_mutex_unlock(&priv->steer_update_lock);
257 pthread_mutex_unlock(&priv->steer_update_lock);
262 mlx5_vdpa_steer_setup(struct mlx5_vdpa_priv *priv)
264 if (mlx5_vdpa_steer_update(priv))
268 mlx5_vdpa_steer_unset(priv);