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