Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (c) 2022 NVIDIA Corporation & Affiliates
3 : : */
4 : :
5 : : #include "mlx5dr_internal.h"
6 : :
7 : : static int
8 : : table_type_to_root_action_flags(enum mlx5dr_table_type table_type,
9 : : enum mlx5dr_action_flags *out)
10 : : {
11 [ # # # # ]: 0 : switch (table_type) {
12 : 0 : case MLX5DR_TABLE_TYPE_NIC_RX:
13 : 0 : *out = MLX5DR_ACTION_FLAG_ROOT_RX;
14 : : break;
15 : 0 : case MLX5DR_TABLE_TYPE_NIC_TX:
16 : 0 : *out = MLX5DR_ACTION_FLAG_ROOT_TX;
17 : : break;
18 : 0 : case MLX5DR_TABLE_TYPE_FDB:
19 : 0 : *out = MLX5DR_ACTION_FLAG_ROOT_FDB;
20 : : break;
21 : 0 : default:
22 : 0 : rte_errno = EINVAL;
23 : : return -rte_errno;
24 : : }
25 : :
26 : : return 0;
27 : : }
28 : :
29 : : static int
30 : : table_type_to_nonroot_action_flags(enum mlx5dr_table_type table_type,
31 : : enum mlx5dr_action_flags *out)
32 : : {
33 [ # # # # : 0 : switch (table_type) {
# # # ]
34 : 0 : case MLX5DR_TABLE_TYPE_NIC_RX:
35 : 0 : *out = MLX5DR_ACTION_FLAG_HWS_RX;
36 : : break;
37 : 0 : case MLX5DR_TABLE_TYPE_NIC_TX:
38 : 0 : *out = MLX5DR_ACTION_FLAG_HWS_TX;
39 : : break;
40 : 0 : case MLX5DR_TABLE_TYPE_FDB:
41 : 0 : *out = MLX5DR_ACTION_FLAG_HWS_FDB;
42 : : break;
43 : 0 : case MLX5DR_TABLE_TYPE_FDB_RX:
44 : 0 : *out = MLX5DR_ACTION_FLAG_HWS_FDB_RX;
45 : : break;
46 : 0 : case MLX5DR_TABLE_TYPE_FDB_TX:
47 : 0 : *out = MLX5DR_ACTION_FLAG_HWS_FDB_TX;
48 : : break;
49 : 0 : case MLX5DR_TABLE_TYPE_FDB_UNIFIED:
50 : 0 : *out = MLX5DR_ACTION_FLAG_HWS_FDB_UNIFIED;
51 : : break;
52 : 0 : default:
53 : 0 : rte_errno = EINVAL;
54 : : return -rte_errno;
55 : : }
56 : :
57 : : return 0;
58 : : }
59 : :
60 : : int
61 : 0 : mlx5dr_table_type_to_action_flags(const enum mlx5dr_table_type table_type,
62 : : const bool is_root,
63 : : enum mlx5dr_action_flags *action_flags)
64 : : {
65 : : int ret = 0;
66 : :
67 [ # # ]: 0 : if (is_root) {
68 : : ret = table_type_to_root_action_flags(table_type, action_flags);
69 : : if (ret < 0)
70 : 0 : DR_LOG(ERR, "Cannot convert table type %d to action flags for root table",
71 : : table_type);
72 : : } else {
73 : : ret = table_type_to_nonroot_action_flags(table_type, action_flags);
74 : : if (ret < 0)
75 : 0 : DR_LOG(ERR, "Cannot convert table type %d to action flags for HWS table",
76 : : table_type);
77 : : }
78 : :
79 : 0 : return ret;
80 : : }
81 : :
82 : 0 : static void mlx5dr_table_init_next_ft_attr(struct mlx5dr_table *tbl,
83 : : struct mlx5dr_cmd_ft_create_attr *ft_attr)
84 : : {
85 : 0 : ft_attr->type = tbl->fw_ft_type;
86 [ # # ]: 0 : if (mlx5dr_table_is_fdb_any(tbl->type))
87 : 0 : ft_attr->level = tbl->ctx->caps->fdb_ft.max_level - 1;
88 : : else
89 : 0 : ft_attr->level = tbl->ctx->caps->nic_ft.max_level - 1;
90 : 0 : ft_attr->rtc_valid = true;
91 : 0 : }
92 : :
93 : : /* Call this under ctx->ctrl_lock */
94 : : static int
95 : 0 : mlx5dr_table_up_default_fdb_miss_tbl(struct mlx5dr_table *tbl)
96 : : {
97 : 0 : struct mlx5dr_cmd_ft_create_attr ft_attr = {0};
98 : 0 : struct mlx5dr_cmd_set_fte_attr fte_attr = {0};
99 : : struct mlx5dr_cmd_forward_tbl *default_miss;
100 : 0 : struct mlx5dr_cmd_set_fte_dest dest = {0};
101 : 0 : struct mlx5dr_context *ctx = tbl->ctx;
102 [ # # ]: 0 : uint8_t tbl_type = tbl->type;
103 : :
104 : : if (!mlx5dr_table_is_fdb_any(tbl_type))
105 : : return 0;
106 : :
107 [ # # ]: 0 : if (ctx->common_res[tbl_type].default_miss) {
108 : 0 : ctx->common_res[tbl_type].default_miss->refcount++;
109 : 0 : return 0;
110 : : }
111 : :
112 : 0 : ft_attr.type = tbl->fw_ft_type;
113 : 0 : ft_attr.level = tbl->ctx->caps->fdb_ft.max_level; /* The last level */
114 : : ft_attr.rtc_valid = false;
115 : :
116 : : dest.destination_type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
117 : 0 : dest.destination_id = ctx->caps->eswitch_manager_vport_number;
118 : 0 : fte_attr.action_flags = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
119 : 0 : fte_attr.dests_num = 1;
120 [ # # ]: 0 : fte_attr.dests = &dest;
121 : :
122 : 0 : default_miss = mlx5dr_cmd_forward_tbl_create(mlx5dr_context_get_local_ibv(ctx),
123 : : &ft_attr, &fte_attr);
124 [ # # ]: 0 : if (!default_miss) {
125 : 0 : DR_LOG(ERR, "Failed to default miss table type: 0x%x", tbl_type);
126 : 0 : return rte_errno;
127 : : }
128 : :
129 : 0 : ctx->common_res[tbl_type].default_miss = default_miss;
130 : 0 : ctx->common_res[tbl_type].default_miss->refcount++;
131 : 0 : return 0;
132 : : }
133 : :
134 : : /* Called under pthread_spin_lock(&ctx->ctrl_lock) */
135 : 0 : static void mlx5dr_table_down_default_fdb_miss_tbl(struct mlx5dr_table *tbl)
136 : : {
137 : : struct mlx5dr_cmd_forward_tbl *default_miss;
138 : 0 : struct mlx5dr_context *ctx = tbl->ctx;
139 [ # # ]: 0 : uint8_t tbl_type = tbl->type;
140 : :
141 : : if (!mlx5dr_table_is_fdb_any(tbl->type))
142 : : return;
143 : :
144 : 0 : default_miss = ctx->common_res[tbl_type].default_miss;
145 [ # # ]: 0 : if (--default_miss->refcount)
146 : : return;
147 : :
148 : 0 : mlx5dr_cmd_forward_tbl_destroy(default_miss);
149 : 0 : ctx->common_res[tbl_type].default_miss = NULL;
150 : : }
151 : :
152 : : static int
153 : 0 : mlx5dr_table_connect_to_default_miss_tbl(struct mlx5dr_table *tbl,
154 : : struct mlx5dr_devx_obj *ft)
155 : : {
156 : 0 : struct mlx5dr_cmd_ft_modify_attr ft_attr = {0};
157 : : int ret;
158 : :
159 [ # # ]: 0 : assert(mlx5dr_table_is_fdb_any(tbl->type));
160 : :
161 : 0 : mlx5dr_cmd_set_attr_connect_miss_tbl(tbl->ctx,
162 : : tbl->fw_ft_type,
163 : : tbl->type,
164 : : &ft_attr);
165 : :
166 : : /* Connect to next */
167 : 0 : ret = mlx5dr_cmd_flow_table_modify(ft, &ft_attr);
168 [ # # ]: 0 : if (ret) {
169 : 0 : DR_LOG(ERR, "Failed to connect FT to default FDB FT");
170 : 0 : return ret;
171 : : }
172 : :
173 : : return 0;
174 : : }
175 : :
176 : : struct mlx5dr_devx_obj *
177 : 0 : mlx5dr_table_create_default_ft(struct ibv_context *ibv,
178 : : struct mlx5dr_table *tbl)
179 : : {
180 : 0 : struct mlx5dr_cmd_ft_create_attr ft_attr = {0};
181 : : struct mlx5dr_devx_obj *ft_obj;
182 : : int ret;
183 : :
184 : 0 : mlx5dr_table_init_next_ft_attr(tbl, &ft_attr);
185 : :
186 : 0 : ft_obj = mlx5dr_cmd_flow_table_create(ibv, &ft_attr);
187 [ # # # # ]: 0 : if (ft_obj && mlx5dr_table_is_fdb_any(tbl->type)) {
188 : : /* Take/create ref over the default miss */
189 : 0 : ret = mlx5dr_table_up_default_fdb_miss_tbl(tbl);
190 [ # # ]: 0 : if (ret) {
191 : 0 : DR_LOG(ERR, "Failed to get default fdb miss for type: %d\n",
192 : : tbl->type);
193 : 0 : goto free_ft_obj;
194 : : }
195 : 0 : ret = mlx5dr_table_connect_to_default_miss_tbl(tbl, ft_obj);
196 [ # # ]: 0 : if (ret) {
197 : 0 : DR_LOG(ERR, "Failed connecting to default miss tbl (type: %d)",
198 : : tbl->type);
199 : 0 : goto down_miss_tbl;
200 : : }
201 : : }
202 : :
203 : : return ft_obj;
204 : :
205 : : down_miss_tbl:
206 : 0 : mlx5dr_table_down_default_fdb_miss_tbl(tbl);
207 : 0 : free_ft_obj:
208 : 0 : mlx5dr_cmd_destroy_obj(ft_obj);
209 : 0 : return NULL;
210 : : }
211 : :
212 : : static int
213 : 0 : mlx5dr_table_init_check_hws_support(struct mlx5dr_context *ctx,
214 : : struct mlx5dr_table *tbl)
215 : : {
216 [ # # ]: 0 : if (!(ctx->flags & MLX5DR_CONTEXT_FLAG_HWS_SUPPORT)) {
217 : 0 : DR_LOG(ERR, "HWS not supported, cannot create mlx5dr_table");
218 : 0 : rte_errno = EOPNOTSUPP;
219 : 0 : return rte_errno;
220 : : }
221 : :
222 [ # # # # ]: 0 : if (mlx5dr_context_shared_gvmi_used(ctx) && mlx5dr_table_is_fdb_any(tbl->type)) {
223 : 0 : DR_LOG(ERR, "FDB with shared port resources is not supported");
224 : 0 : rte_errno = EOPNOTSUPP;
225 : 0 : return rte_errno;
226 : : }
227 : :
228 : : return 0;
229 : : }
230 : :
231 : : static int
232 : 0 : mlx5dr_table_shared_gvmi_resource_create(struct mlx5dr_context *ctx,
233 : : enum mlx5dr_table_type type,
234 : : struct mlx5dr_context_shared_gvmi_res *gvmi_res)
235 : : {
236 [ # # ]: 0 : struct mlx5dr_cmd_ft_create_attr ft_attr = {0};
237 : : uint32_t calculated_ft_id;
238 : : int ret;
239 : :
240 [ # # ]: 0 : if (!mlx5dr_context_shared_gvmi_used(ctx))
241 : : return 0;
242 : :
243 : 0 : ft_attr.type = mlx5dr_table_get_res_fw_ft_type(type, false);
244 : 0 : ft_attr.level = ctx->caps->nic_ft.max_level - 1;
245 : 0 : ft_attr.rtc_valid = true;
246 : :
247 : 0 : gvmi_res->end_ft =
248 : 0 : mlx5dr_cmd_flow_table_create(mlx5dr_context_get_local_ibv(ctx),
249 : : &ft_attr);
250 [ # # ]: 0 : if (!gvmi_res->end_ft) {
251 : 0 : DR_LOG(ERR, "Failed to create end-ft");
252 : 0 : return rte_errno;
253 : : }
254 : :
255 : 0 : calculated_ft_id =
256 : 0 : mlx5dr_table_get_res_fw_ft_type(type, false) << FT_ID_FT_TYPE_OFFSET;
257 : 0 : calculated_ft_id |= gvmi_res->end_ft->id;
258 : :
259 : : /* create alias to that FT */
260 : 0 : ret = mlx5dr_matcher_create_aliased_obj(ctx,
261 : : ctx->local_ibv_ctx,
262 : : ctx->ibv_ctx,
263 : 0 : ctx->caps->vhca_id,
264 : : calculated_ft_id,
265 : : MLX5_GENERAL_OBJ_TYPE_FT_ALIAS,
266 : : &gvmi_res->aliased_end_ft);
267 [ # # ]: 0 : if (ret) {
268 : 0 : DR_LOG(ERR, "Failed to create alias end-ft");
269 : 0 : goto free_end_ft;
270 : : }
271 : :
272 : : return 0;
273 : :
274 : : free_end_ft:
275 : 0 : mlx5dr_cmd_destroy_obj(gvmi_res->end_ft);
276 : :
277 : 0 : return rte_errno;
278 : : }
279 : :
280 : : static void
281 [ # # ]: 0 : mlx5dr_table_shared_gvmi_resourse_destroy(struct mlx5dr_context *ctx,
282 : : struct mlx5dr_context_shared_gvmi_res *gvmi_res)
283 : : {
284 [ # # ]: 0 : if (!mlx5dr_context_shared_gvmi_used(ctx))
285 : : return;
286 : :
287 [ # # ]: 0 : if (gvmi_res->aliased_end_ft) {
288 : 0 : mlx5dr_cmd_destroy_obj(gvmi_res->aliased_end_ft);
289 : 0 : gvmi_res->aliased_end_ft = NULL;
290 : : }
291 [ # # ]: 0 : if (gvmi_res->end_ft) {
292 : 0 : mlx5dr_cmd_destroy_obj(gvmi_res->end_ft);
293 : 0 : gvmi_res->end_ft = NULL;
294 : : }
295 : : }
296 : :
297 : : /* called under spinlock ctx->ctrl_lock */
298 : : static struct mlx5dr_context_shared_gvmi_res *
299 [ # # ]: 0 : mlx5dr_table_get_shared_gvmi_res(struct mlx5dr_context *ctx, enum mlx5dr_table_type type)
300 : : {
301 : : int ret;
302 : :
303 [ # # ]: 0 : if (!mlx5dr_context_shared_gvmi_used(ctx))
304 : : return NULL;
305 : :
306 [ # # ]: 0 : if (ctx->gvmi_res[type].aliased_end_ft) {
307 : 0 : ctx->gvmi_res[type].refcount++;
308 : 0 : return &ctx->gvmi_res[type];
309 : : }
310 : :
311 : 0 : ret = mlx5dr_table_shared_gvmi_resource_create(ctx, type, &ctx->gvmi_res[type]);
312 [ # # ]: 0 : if (ret) {
313 : 0 : DR_LOG(ERR, "Failed to create shared gvmi res for type: %d", type);
314 : 0 : goto out;
315 : : }
316 : :
317 : 0 : ctx->gvmi_res[type].refcount = 1;
318 : :
319 : 0 : return &ctx->gvmi_res[type];
320 : :
321 : : out:
322 : 0 : return NULL;
323 : : }
324 : :
325 : : /* called under spinlock ctx->ctrl_lock */
326 : 0 : static void mlx5dr_table_put_shared_gvmi_res(struct mlx5dr_table *tbl)
327 : : {
328 [ # # ]: 0 : struct mlx5dr_context *ctx = tbl->ctx;
329 : :
330 [ # # ]: 0 : if (!mlx5dr_context_shared_gvmi_used(ctx))
331 : : return;
332 : :
333 [ # # ]: 0 : if (--ctx->gvmi_res[tbl->type].refcount)
334 : : return;
335 : :
336 : 0 : mlx5dr_table_shared_gvmi_resourse_destroy(ctx, &ctx->gvmi_res[tbl->type]);
337 : : }
338 : :
339 : 0 : static void mlx5dr_table_uninit_shared_ctx_res(struct mlx5dr_table *tbl)
340 : : {
341 [ # # ]: 0 : struct mlx5dr_context *ctx = tbl->ctx;
342 : :
343 [ # # ]: 0 : if (!mlx5dr_context_shared_gvmi_used(ctx))
344 : : return;
345 : :
346 : 0 : mlx5dr_cmd_destroy_obj(tbl->local_ft);
347 : :
348 : 0 : mlx5dr_table_put_shared_gvmi_res(tbl);
349 : : }
350 : :
351 : : /* called under spin_lock ctx->ctrl_lock */
352 : 0 : static int mlx5dr_table_init_shared_ctx_res(struct mlx5dr_context *ctx, struct mlx5dr_table *tbl)
353 : : {
354 [ # # ]: 0 : struct mlx5dr_cmd_ft_modify_attr ft_attr = {0};
355 : : int ret;
356 : :
357 [ # # ]: 0 : if (!mlx5dr_context_shared_gvmi_used(ctx))
358 : : return 0;
359 : :
360 : : /* create local-ft for root access */
361 : 0 : tbl->local_ft =
362 : 0 : mlx5dr_table_create_default_ft(mlx5dr_context_get_local_ibv(ctx), tbl);
363 [ # # ]: 0 : if (!tbl->local_ft) {
364 : 0 : DR_LOG(ERR, "Failed to create local-ft");
365 : 0 : return rte_errno;
366 : : }
367 : :
368 [ # # ]: 0 : if (!mlx5dr_table_get_shared_gvmi_res(tbl->ctx, tbl->type)) {
369 : 0 : DR_LOG(ERR, "Failed to shared gvmi resources");
370 : 0 : goto clean_local_ft;
371 : : }
372 : :
373 : : /* On shared gvmi the default behavior is jump to alias end ft */
374 : 0 : mlx5dr_cmd_set_attr_connect_miss_tbl(tbl->ctx,
375 : : tbl->fw_ft_type,
376 : : tbl->type,
377 : : &ft_attr);
378 : :
379 : 0 : ret = mlx5dr_cmd_flow_table_modify(tbl->ft, &ft_attr);
380 [ # # ]: 0 : if (ret) {
381 : 0 : DR_LOG(ERR, "Failed to point table to its default miss");
382 : 0 : goto clean_shared_res;
383 : : }
384 : :
385 : : return 0;
386 : :
387 : : clean_shared_res:
388 : 0 : mlx5dr_table_put_shared_gvmi_res(tbl);
389 : 0 : clean_local_ft:
390 : 0 : mlx5dr_table_destroy_default_ft(tbl, tbl->local_ft);
391 : 0 : return rte_errno;
392 : : }
393 : :
394 : 0 : void mlx5dr_table_destroy_default_ft(struct mlx5dr_table *tbl,
395 : : struct mlx5dr_devx_obj *ft_obj)
396 : : {
397 : 0 : mlx5dr_cmd_destroy_obj(ft_obj);
398 : 0 : mlx5dr_table_down_default_fdb_miss_tbl(tbl);
399 : 0 : }
400 : :
401 : 0 : static int mlx5dr_table_init(struct mlx5dr_table *tbl)
402 : : {
403 [ # # ]: 0 : struct mlx5dr_context *ctx = tbl->ctx;
404 : : int ret;
405 : :
406 [ # # ]: 0 : if (mlx5dr_table_is_root(tbl))
407 : : return 0;
408 : :
409 : 0 : ret = mlx5dr_table_init_check_hws_support(ctx, tbl);
410 [ # # ]: 0 : if (ret)
411 : : return ret;
412 : :
413 : 0 : mlx5dr_table_get_fw_ft_type(tbl->type, (uint8_t *)&tbl->fw_ft_type);
414 : :
415 : 0 : pthread_spin_lock(&ctx->ctrl_lock);
416 : 0 : tbl->ft = mlx5dr_table_create_default_ft(tbl->ctx->ibv_ctx, tbl);
417 [ # # ]: 0 : if (!tbl->ft) {
418 : 0 : DR_LOG(ERR, "Failed to create flow table devx object");
419 : 0 : pthread_spin_unlock(&ctx->ctrl_lock);
420 : 0 : return rte_errno;
421 : : }
422 : :
423 : 0 : ret = mlx5dr_table_init_shared_ctx_res(ctx, tbl);
424 [ # # ]: 0 : if (ret)
425 : 0 : goto tbl_destroy;
426 : :
427 : 0 : ret = mlx5dr_action_get_default_stc(ctx, tbl->type);
428 [ # # ]: 0 : if (ret)
429 : 0 : goto free_shared_ctx;
430 : :
431 : 0 : pthread_spin_unlock(&ctx->ctrl_lock);
432 : :
433 : 0 : return 0;
434 : :
435 : : free_shared_ctx:
436 : 0 : mlx5dr_table_uninit_shared_ctx_res(tbl);
437 : 0 : tbl_destroy:
438 : 0 : mlx5dr_table_destroy_default_ft(tbl, tbl->ft);
439 : 0 : pthread_spin_unlock(&ctx->ctrl_lock);
440 : 0 : return rte_errno;
441 : : }
442 : :
443 [ # # ]: 0 : static void mlx5dr_table_uninit(struct mlx5dr_table *tbl)
444 : : {
445 [ # # ]: 0 : if (mlx5dr_table_is_root(tbl))
446 : : return;
447 : 0 : pthread_spin_lock(&tbl->ctx->ctrl_lock);
448 : 0 : mlx5dr_action_put_default_stc(tbl->ctx, tbl->type);
449 : 0 : mlx5dr_table_uninit_shared_ctx_res(tbl);
450 : 0 : mlx5dr_table_destroy_default_ft(tbl, tbl->ft);
451 : 0 : pthread_spin_unlock(&tbl->ctx->ctrl_lock);
452 : : }
453 : :
454 : 0 : struct mlx5dr_table *mlx5dr_table_create(struct mlx5dr_context *ctx,
455 : : struct mlx5dr_table_attr *attr)
456 : : {
457 : : struct mlx5dr_table *tbl;
458 : : int ret;
459 : :
460 [ # # ]: 0 : if (attr->type >= MLX5DR_TABLE_TYPE_MAX) {
461 : 0 : DR_LOG(ERR, "Invalid table type %d", attr->type);
462 : 0 : return NULL;
463 : : }
464 : :
465 [ # # # # ]: 0 : if (attr->type == MLX5DR_TABLE_TYPE_FDB_UNIFIED && !ctx->caps->fdb_unified_en) {
466 : 0 : DR_LOG(ERR, "Table type %d not supported by current FW", attr->type);
467 : 0 : rte_errno = ENOTSUP;
468 : 0 : return NULL;
469 : : }
470 : :
471 [ # # # # ]: 0 : if (attr->type == MLX5DR_TABLE_TYPE_FDB_UNIFIED && !ctx->caps->vport_metadata_match) {
472 : 0 : DR_LOG(ERR, "Table type %d requires vport metadata to be enabled", attr->type);
473 : 0 : rte_errno = ENOTSUP;
474 : 0 : return NULL;
475 : : }
476 : :
477 [ # # ]: 0 : if ((mlx5dr_table_is_fdb_any(attr->type) && attr->type != MLX5DR_TABLE_TYPE_FDB) &&
478 [ # # ]: 0 : !attr->level) {
479 : 0 : DR_LOG(ERR, "Table type %d not supported by root table", attr->type);
480 : 0 : rte_errno = ENOTSUP;
481 : 0 : return NULL;
482 : : }
483 : :
484 : : tbl = simple_calloc(1, sizeof(*tbl));
485 [ # # ]: 0 : if (!tbl) {
486 : 0 : rte_errno = ENOMEM;
487 : 0 : return NULL;
488 : : }
489 : :
490 : 0 : tbl->ctx = ctx;
491 : 0 : tbl->type = attr->type;
492 : 0 : tbl->level = attr->level;
493 : :
494 : 0 : ret = mlx5dr_table_init(tbl);
495 [ # # ]: 0 : if (ret) {
496 : 0 : DR_LOG(ERR, "Failed to initialise table");
497 : 0 : goto free_tbl;
498 : : }
499 : :
500 : 0 : pthread_spin_lock(&ctx->ctrl_lock);
501 [ # # ]: 0 : LIST_INSERT_HEAD(&ctx->head, tbl, next);
502 : 0 : pthread_spin_unlock(&ctx->ctrl_lock);
503 : :
504 : 0 : return tbl;
505 : :
506 : : free_tbl:
507 : : simple_free(tbl);
508 : 0 : return NULL;
509 : : }
510 : :
511 : 0 : int mlx5dr_table_destroy(struct mlx5dr_table *tbl)
512 : : {
513 : 0 : struct mlx5dr_context *ctx = tbl->ctx;
514 : 0 : pthread_spin_lock(&ctx->ctrl_lock);
515 [ # # # # ]: 0 : if (!LIST_EMPTY(&tbl->head) || !LIST_EMPTY(&tbl->isolated_matchers)) {
516 : 0 : DR_LOG(ERR, "Cannot destroy table containing matchers");
517 : 0 : rte_errno = EBUSY;
518 : 0 : goto unlock_err;
519 : : }
520 : :
521 [ # # ]: 0 : if (!LIST_EMPTY(&tbl->default_miss.head)) {
522 : 0 : DR_LOG(ERR, "Cannot destroy table pointed by default miss");
523 : 0 : rte_errno = EBUSY;
524 : 0 : goto unlock_err;
525 : : }
526 : :
527 [ # # ]: 0 : LIST_REMOVE(tbl, next);
528 : 0 : pthread_spin_unlock(&ctx->ctrl_lock);
529 : 0 : mlx5dr_table_uninit(tbl);
530 : : simple_free(tbl);
531 : :
532 : 0 : return 0;
533 : :
534 : 0 : unlock_err:
535 : 0 : pthread_spin_unlock(&ctx->ctrl_lock);
536 : 0 : return -rte_errno;
537 : : }
538 : :
539 : : static struct mlx5dr_devx_obj *
540 : : mlx5dr_table_get_last_ft(struct mlx5dr_table *tbl)
541 : : {
542 : 0 : struct mlx5dr_devx_obj *last_ft = tbl->ft;
543 : : struct mlx5dr_matcher *matcher;
544 : :
545 [ # # ]: 0 : LIST_FOREACH(matcher, &tbl->head, next)
546 : 0 : last_ft = matcher->end_ft;
547 : :
548 : : return last_ft;
549 : : }
550 : :
551 : 0 : int mlx5dr_table_ft_set_default_next_ft(struct mlx5dr_table *tbl,
552 : : struct mlx5dr_devx_obj *ft_obj)
553 : : {
554 : 0 : struct mlx5dr_cmd_ft_modify_attr ft_attr = {0};
555 : : int ret;
556 : :
557 : : /* Due to FW limitation, resetting the flow table to default action will
558 : : * disconnect RTC when ignore_flow_level_rtc_valid is not supported.
559 : : */
560 [ # # ]: 0 : if (!tbl->ctx->caps->nic_ft.ignore_flow_level_rtc_valid)
561 : : return 0;
562 : :
563 [ # # ]: 0 : if (mlx5dr_table_is_fdb_any(tbl->type))
564 : 0 : return mlx5dr_table_connect_to_default_miss_tbl(tbl, ft_obj);
565 : :
566 : 0 : ft_attr.type = tbl->fw_ft_type;
567 : 0 : ft_attr.modify_fs = MLX5_IFC_MODIFY_FLOW_TABLE_MISS_ACTION;
568 : : ft_attr.table_miss_action = MLX5_IFC_MODIFY_FLOW_TABLE_MISS_ACTION_DEFAULT;
569 : :
570 : 0 : ret = mlx5dr_cmd_flow_table_modify(ft_obj, &ft_attr);
571 [ # # ]: 0 : if (ret) {
572 : 0 : DR_LOG(ERR, "Failed to set FT default miss action");
573 : 0 : return ret;
574 : : }
575 : :
576 : : return 0;
577 : : }
578 : :
579 : 0 : int mlx5dr_table_ft_set_next_rtc(struct mlx5dr_devx_obj *ft,
580 : : uint32_t fw_ft_type,
581 : : struct mlx5dr_devx_obj *rtc_0,
582 : : struct mlx5dr_devx_obj *rtc_1)
583 : : {
584 : 0 : struct mlx5dr_cmd_ft_modify_attr ft_attr = {0};
585 : :
586 : 0 : ft_attr.modify_fs = MLX5_IFC_MODIFY_FLOW_TABLE_RTC_ID;
587 : 0 : ft_attr.type = fw_ft_type;
588 [ # # ]: 0 : ft_attr.rtc_id_0 = rtc_0 ? rtc_0->id : 0;
589 [ # # ]: 0 : ft_attr.rtc_id_1 = rtc_1 ? rtc_1->id : 0;
590 : :
591 : 0 : return mlx5dr_cmd_flow_table_modify(ft, &ft_attr);
592 : : }
593 : :
594 : : static int mlx5dr_table_ft_set_next_ft(struct mlx5dr_devx_obj *ft,
595 : : uint32_t fw_ft_type,
596 : : uint32_t next_ft_id)
597 : : {
598 : 0 : struct mlx5dr_cmd_ft_modify_attr ft_attr = {0};
599 : :
600 : 0 : ft_attr.modify_fs = MLX5_IFC_MODIFY_FLOW_TABLE_MISS_ACTION;
601 : 0 : ft_attr.table_miss_action = MLX5_IFC_MODIFY_FLOW_TABLE_MISS_ACTION_GOTO_TBL;
602 : 0 : ft_attr.type = fw_ft_type;
603 : 0 : ft_attr.table_miss_id = next_ft_id;
604 : :
605 : 0 : return mlx5dr_cmd_flow_table_modify(ft, &ft_attr);
606 : : }
607 : :
608 : 0 : int mlx5dr_table_update_connected_miss_tables(struct mlx5dr_table *dst_tbl)
609 : : {
610 : : struct mlx5dr_table *src_tbl;
611 : : int ret;
612 : :
613 [ # # ]: 0 : if (LIST_EMPTY(&dst_tbl->default_miss.head))
614 : : return 0;
615 : :
616 [ # # ]: 0 : LIST_FOREACH(src_tbl, &dst_tbl->default_miss.head, default_miss.next) {
617 : 0 : ret = mlx5dr_table_connect_to_miss_table(src_tbl, dst_tbl, false);
618 [ # # ]: 0 : if (ret) {
619 : 0 : DR_LOG(ERR, "Failed to update source miss table, unexpected behavior");
620 : 0 : return ret;
621 : : }
622 : : }
623 : :
624 : : return 0;
625 : : }
626 : :
627 : 0 : int mlx5dr_table_connect_src_ft_to_miss_table(struct mlx5dr_table *src_tbl,
628 : : struct mlx5dr_devx_obj *ft,
629 : : struct mlx5dr_table *dst_tbl)
630 : : {
631 : : struct mlx5dr_matcher *matcher;
632 : : int ret;
633 : :
634 [ # # ]: 0 : if (dst_tbl) {
635 [ # # ]: 0 : if (LIST_EMPTY(&dst_tbl->head)) {
636 : : /* Connect src_tbl ft to dst_tbl start anchor */
637 : 0 : ret = mlx5dr_table_ft_set_next_ft(ft,
638 : : src_tbl->fw_ft_type,
639 : 0 : dst_tbl->ft->id);
640 [ # # ]: 0 : if (ret)
641 : : return ret;
642 : :
643 : : /* Reset ft RTC to default RTC */
644 : 0 : ret = mlx5dr_table_ft_set_next_rtc(ft,
645 : : src_tbl->fw_ft_type,
646 : : NULL, NULL);
647 [ # # ]: 0 : if (ret)
648 : 0 : return ret;
649 : : } else {
650 : : /* Connect src_tbl ft to first matcher RTC */
651 : : matcher = LIST_FIRST(&dst_tbl->head);
652 : 0 : ret = mlx5dr_table_ft_set_next_rtc(ft,
653 : : src_tbl->fw_ft_type,
654 : : matcher->match_ste.rtc_0,
655 : : matcher->match_ste.rtc_1);
656 [ # # ]: 0 : if (ret)
657 : : return ret;
658 : :
659 : : /* Reset next miss FT to default */
660 : 0 : ret = mlx5dr_table_ft_set_default_next_ft(src_tbl, ft);
661 [ # # ]: 0 : if (ret)
662 : 0 : return ret;
663 : : }
664 : : } else {
665 : : /* Reset next miss FT to default */
666 : 0 : ret = mlx5dr_table_ft_set_default_next_ft(src_tbl, ft);
667 [ # # ]: 0 : if (ret)
668 : : return ret;
669 : :
670 : : /* Reset ft RTC to default RTC */
671 : 0 : ret = mlx5dr_table_ft_set_next_rtc(ft,
672 : : src_tbl->fw_ft_type,
673 : : NULL, NULL);
674 [ # # ]: 0 : if (ret)
675 : 0 : return ret;
676 : : }
677 : :
678 : : return 0;
679 : : }
680 : :
681 : 0 : int mlx5dr_table_connect_to_miss_table(struct mlx5dr_table *src_tbl,
682 : : struct mlx5dr_table *dst_tbl,
683 : : bool only_update_last_ft)
684 : : {
685 : : struct mlx5dr_matcher *matcher;
686 : : struct mlx5dr_devx_obj *ft;
687 : : int ret;
688 : :
689 : : /* Connect last FT in the src_tbl matchers chain */
690 : : ft = mlx5dr_table_get_last_ft(src_tbl);
691 : 0 : ret = mlx5dr_table_connect_src_ft_to_miss_table(src_tbl, ft, dst_tbl);
692 [ # # ]: 0 : if (ret)
693 : : return ret;
694 : :
695 [ # # ]: 0 : if (!only_update_last_ft) {
696 : : /* Connect isolated matchers FT */
697 [ # # ]: 0 : LIST_FOREACH(matcher, &src_tbl->isolated_matchers, next) {
698 : 0 : ft = matcher->end_ft;
699 : 0 : ret = mlx5dr_table_connect_src_ft_to_miss_table(src_tbl, ft, dst_tbl);
700 [ # # ]: 0 : if (ret)
701 : 0 : return ret;
702 : : }
703 : : }
704 : :
705 : 0 : src_tbl->default_miss.miss_tbl = dst_tbl;
706 : :
707 : 0 : return 0;
708 : : }
709 : :
710 : : static bool mlx5dr_table_set_default_miss_valid_types(enum mlx5dr_table_type from,
711 : : enum mlx5dr_table_type to)
712 : : {
713 [ # # ]: 0 : if (from == to ||
714 : 0 : ((from == MLX5DR_TABLE_TYPE_FDB_UNIFIED &&
715 [ # # # # ]: 0 : (to == MLX5DR_TABLE_TYPE_FDB_RX || to == MLX5DR_TABLE_TYPE_FDB_TX)) ||
716 : 0 : (to == MLX5DR_TABLE_TYPE_FDB_UNIFIED &&
717 [ # # ]: 0 : (from == MLX5DR_TABLE_TYPE_FDB_RX || from == MLX5DR_TABLE_TYPE_FDB_TX))))
718 : : return true;
719 : :
720 : : return false;
721 : : }
722 : :
723 : 0 : static int mlx5dr_table_set_default_miss_not_valid(struct mlx5dr_table *tbl,
724 : : struct mlx5dr_table *miss_tbl)
725 : : {
726 [ # # # # ]: 0 : if (!tbl->ctx->caps->nic_ft.ignore_flow_level_rtc_valid ||
727 : : mlx5dr_context_shared_gvmi_used(tbl->ctx)) {
728 : 0 : DR_LOG(ERR, "Default miss table is not supported");
729 : 0 : rte_errno = EOPNOTSUPP;
730 : 0 : return -rte_errno;
731 : : }
732 : :
733 [ # # # # ]: 0 : if (mlx5dr_table_is_root(tbl) ||
734 [ # # ]: 0 : (miss_tbl &&
735 : : ((mlx5dr_table_is_root(miss_tbl)) ||
736 [ # # ]: 0 : !mlx5dr_table_set_default_miss_valid_types(tbl->type, miss_tbl->type)))) {
737 : 0 : DR_LOG(ERR, "Invalid arguments");
738 : 0 : rte_errno = EINVAL;
739 : 0 : return -rte_errno;
740 : : }
741 : :
742 : : return 0;
743 : : }
744 : :
745 : 0 : int mlx5dr_table_set_default_miss(struct mlx5dr_table *tbl,
746 : : struct mlx5dr_table *miss_tbl)
747 : : {
748 : 0 : struct mlx5dr_context *ctx = tbl->ctx;
749 : : struct mlx5dr_table *old_miss_tbl;
750 : : int ret;
751 : :
752 : 0 : ret = mlx5dr_table_set_default_miss_not_valid(tbl, miss_tbl);
753 [ # # ]: 0 : if (ret)
754 : : return ret;
755 : :
756 : 0 : pthread_spin_lock(&ctx->ctrl_lock);
757 : 0 : old_miss_tbl = tbl->default_miss.miss_tbl;
758 : 0 : ret = mlx5dr_table_connect_to_miss_table(tbl, miss_tbl, false);
759 [ # # ]: 0 : if (ret)
760 : 0 : goto out;
761 : :
762 [ # # ]: 0 : if (old_miss_tbl)
763 [ # # ]: 0 : LIST_REMOVE(tbl, default_miss.next);
764 : :
765 [ # # ]: 0 : if (miss_tbl)
766 [ # # ]: 0 : LIST_INSERT_HEAD(&miss_tbl->default_miss.head, tbl, default_miss.next);
767 : :
768 : 0 : pthread_spin_unlock(&ctx->ctrl_lock);
769 : 0 : return 0;
770 : : out:
771 : 0 : pthread_spin_unlock(&ctx->ctrl_lock);
772 : 0 : return -ret;
773 : : }
|