xref: /dpdk/drivers/net/mlx5/hws/mlx5dr_action.c (revision 02d36ef6a9528e0f4a3403956e66bcea5fadbf8c)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright (c) 2022 NVIDIA Corporation & Affiliates
3  */
4 
5 #include "mlx5dr_internal.h"
6 
7 #define WIRE_PORT 0xFFFF
8 
9 #define MLX5DR_ACTION_METER_INIT_COLOR_OFFSET 1
10 
11 /* This is the maximum allowed action order for each table type:
12  *	 TX: POP_VLAN, CTR, ASO_METER, AS_CT, PUSH_VLAN, MODIFY, ENCAP, Term
13  *	 RX: TAG, DECAP, POP_VLAN, CTR, ASO_METER, ASO_CT, PUSH_VLAN, MODIFY,
14  *	     ENCAP, Term
15  *	FDB: DECAP, POP_VLAN, CTR, ASO_METER, ASO_CT, PUSH_VLAN, MODIFY,
16  *	     ENCAP, Term
17  */
18 static const uint32_t action_order_arr[MLX5DR_TABLE_TYPE_MAX][MLX5DR_ACTION_TYP_MAX] = {
19 	[MLX5DR_TABLE_TYPE_NIC_RX] = {
20 		BIT(MLX5DR_ACTION_TYP_TAG),
21 		BIT(MLX5DR_ACTION_TYP_TNL_L2_TO_L2) |
22 		BIT(MLX5DR_ACTION_TYP_TNL_L3_TO_L2),
23 		BIT(MLX5DR_ACTION_TYP_POP_VLAN),
24 		BIT(MLX5DR_ACTION_TYP_POP_VLAN),
25 		BIT(MLX5DR_ACTION_TYP_CTR),
26 		BIT(MLX5DR_ACTION_TYP_ASO_METER),
27 		BIT(MLX5DR_ACTION_TYP_ASO_CT),
28 		BIT(MLX5DR_ACTION_TYP_PUSH_VLAN),
29 		BIT(MLX5DR_ACTION_TYP_PUSH_VLAN),
30 		BIT(MLX5DR_ACTION_TYP_MODIFY_HDR),
31 		BIT(MLX5DR_ACTION_TYP_L2_TO_TNL_L2) |
32 		BIT(MLX5DR_ACTION_TYP_L2_TO_TNL_L3),
33 		BIT(MLX5DR_ACTION_TYP_FT) |
34 		BIT(MLX5DR_ACTION_TYP_MISS) |
35 		BIT(MLX5DR_ACTION_TYP_TIR) |
36 		BIT(MLX5DR_ACTION_TYP_DROP),
37 		BIT(MLX5DR_ACTION_TYP_LAST),
38 	},
39 	[MLX5DR_TABLE_TYPE_NIC_TX] = {
40 		BIT(MLX5DR_ACTION_TYP_POP_VLAN),
41 		BIT(MLX5DR_ACTION_TYP_POP_VLAN),
42 		BIT(MLX5DR_ACTION_TYP_CTR),
43 		BIT(MLX5DR_ACTION_TYP_ASO_METER),
44 		BIT(MLX5DR_ACTION_TYP_ASO_CT),
45 		BIT(MLX5DR_ACTION_TYP_PUSH_VLAN),
46 		BIT(MLX5DR_ACTION_TYP_PUSH_VLAN),
47 		BIT(MLX5DR_ACTION_TYP_MODIFY_HDR),
48 		BIT(MLX5DR_ACTION_TYP_L2_TO_TNL_L2) |
49 		BIT(MLX5DR_ACTION_TYP_L2_TO_TNL_L3),
50 		BIT(MLX5DR_ACTION_TYP_FT) |
51 		BIT(MLX5DR_ACTION_TYP_MISS) |
52 		BIT(MLX5DR_ACTION_TYP_DROP),
53 		BIT(MLX5DR_ACTION_TYP_LAST),
54 	},
55 	[MLX5DR_TABLE_TYPE_FDB] = {
56 		BIT(MLX5DR_ACTION_TYP_TNL_L2_TO_L2) |
57 		BIT(MLX5DR_ACTION_TYP_TNL_L3_TO_L2),
58 		BIT(MLX5DR_ACTION_TYP_POP_VLAN),
59 		BIT(MLX5DR_ACTION_TYP_POP_VLAN),
60 		BIT(MLX5DR_ACTION_TYP_CTR),
61 		BIT(MLX5DR_ACTION_TYP_ASO_METER),
62 		BIT(MLX5DR_ACTION_TYP_ASO_CT),
63 		BIT(MLX5DR_ACTION_TYP_PUSH_VLAN),
64 		BIT(MLX5DR_ACTION_TYP_PUSH_VLAN),
65 		BIT(MLX5DR_ACTION_TYP_MODIFY_HDR),
66 		BIT(MLX5DR_ACTION_TYP_L2_TO_TNL_L2) |
67 		BIT(MLX5DR_ACTION_TYP_L2_TO_TNL_L3),
68 		BIT(MLX5DR_ACTION_TYP_FT) |
69 		BIT(MLX5DR_ACTION_TYP_MISS) |
70 		BIT(MLX5DR_ACTION_TYP_VPORT) |
71 		BIT(MLX5DR_ACTION_TYP_DROP),
72 		BIT(MLX5DR_ACTION_TYP_LAST),
73 	},
74 };
75 
76 static int mlx5dr_action_get_shared_stc_nic(struct mlx5dr_context *ctx,
77 					    enum mlx5dr_context_shared_stc_type stc_type,
78 					    uint8_t tbl_type)
79 {
80 	struct mlx5dr_cmd_stc_modify_attr stc_attr = {0};
81 	struct mlx5dr_action_shared_stc *shared_stc;
82 	int ret;
83 
84 	pthread_spin_lock(&ctx->ctrl_lock);
85 	if (ctx->common_res[tbl_type].shared_stc[stc_type]) {
86 		ctx->common_res[tbl_type].shared_stc[stc_type]->refcount++;
87 		pthread_spin_unlock(&ctx->ctrl_lock);
88 		return 0;
89 	}
90 
91 	shared_stc = simple_calloc(1, sizeof(*shared_stc));
92 	if (!shared_stc) {
93 		DR_LOG(ERR, "Failed to allocate memory for shared STCs");
94 		rte_errno = ENOMEM;
95 		goto unlock_and_out;
96 	}
97 	switch (stc_type) {
98 	case MLX5DR_CONTEXT_SHARED_STC_DECAP:
99 		stc_attr.action_type = MLX5_IFC_STC_ACTION_TYPE_HEADER_REMOVE;
100 		stc_attr.action_offset = MLX5DR_ACTION_OFFSET_DW5;
101 		stc_attr.remove_header.decap = 0;
102 		stc_attr.remove_header.start_anchor = MLX5_HEADER_ANCHOR_PACKET_START;
103 		stc_attr.remove_header.end_anchor = MLX5_HEADER_ANCHOR_IPV6_IPV4;
104 		break;
105 	case MLX5DR_CONTEXT_SHARED_STC_POP:
106 		stc_attr.action_type = MLX5_IFC_STC_ACTION_TYPE_REMOVE_WORDS;
107 		stc_attr.action_offset = MLX5DR_ACTION_OFFSET_DW5;
108 		stc_attr.remove_words.start_anchor = MLX5_HEADER_ANCHOR_FIRST_VLAN_START;
109 		stc_attr.remove_words.num_of_words = MLX5DR_ACTION_HDR_LEN_L2_VLAN;
110 		break;
111 	default:
112 		DR_LOG(ERR, "No such type : stc_type\n");
113 		assert(false);
114 		rte_errno = EINVAL;
115 		goto unlock_and_out;
116 	}
117 
118 	ret = mlx5dr_action_alloc_single_stc(ctx, &stc_attr, tbl_type,
119 					     &shared_stc->remove_header);
120 	if (ret) {
121 		DR_LOG(ERR, "Failed to allocate shared decap l2 STC");
122 		goto free_shared_stc;
123 	}
124 
125 	ctx->common_res[tbl_type].shared_stc[stc_type] = shared_stc;
126 	ctx->common_res[tbl_type].shared_stc[stc_type]->refcount = 1;
127 
128 	pthread_spin_unlock(&ctx->ctrl_lock);
129 
130 	return 0;
131 
132 free_shared_stc:
133 	simple_free(shared_stc);
134 unlock_and_out:
135 	pthread_spin_unlock(&ctx->ctrl_lock);
136 	return rte_errno;
137 }
138 
139 static void mlx5dr_action_put_shared_stc_nic(struct mlx5dr_context *ctx,
140 					     enum mlx5dr_context_shared_stc_type stc_type,
141 					     uint8_t tbl_type)
142 {
143 	struct mlx5dr_action_shared_stc *shared_stc;
144 
145 	pthread_spin_lock(&ctx->ctrl_lock);
146 	if (--ctx->common_res[tbl_type].shared_stc[stc_type]->refcount) {
147 		pthread_spin_unlock(&ctx->ctrl_lock);
148 		return;
149 	}
150 
151 	shared_stc = ctx->common_res[tbl_type].shared_stc[stc_type];
152 
153 	mlx5dr_action_free_single_stc(ctx, tbl_type, &shared_stc->remove_header);
154 	simple_free(shared_stc);
155 	ctx->common_res[tbl_type].shared_stc[stc_type] = NULL;
156 	pthread_spin_unlock(&ctx->ctrl_lock);
157 }
158 
159 static int mlx5dr_action_get_shared_stc(struct mlx5dr_action *action,
160 					enum mlx5dr_context_shared_stc_type stc_type)
161 {
162 	struct mlx5dr_context *ctx = action->ctx;
163 	int ret;
164 
165 	if (stc_type >= MLX5DR_CONTEXT_SHARED_STC_MAX) {
166 		assert(false);
167 		rte_errno = EINVAL;
168 		return rte_errno;
169 	}
170 
171 	if (action->flags & MLX5DR_ACTION_FLAG_HWS_RX) {
172 		ret = mlx5dr_action_get_shared_stc_nic(ctx, stc_type, MLX5DR_TABLE_TYPE_NIC_RX);
173 		if (ret) {
174 			DR_LOG(ERR, "Failed to allocate memory for RX shared STCs (type: %d)",
175 			       stc_type);
176 			return ret;
177 		}
178 	}
179 
180 	if (action->flags & MLX5DR_ACTION_FLAG_HWS_TX) {
181 		ret = mlx5dr_action_get_shared_stc_nic(ctx, stc_type, MLX5DR_TABLE_TYPE_NIC_TX);
182 		if (ret) {
183 			DR_LOG(ERR, "Failed to allocate memory for TX shared STCs(type: %d)",
184 			       stc_type);
185 			goto clean_nic_rx_stc;
186 		}
187 	}
188 
189 	if (action->flags & MLX5DR_ACTION_FLAG_HWS_FDB) {
190 		ret = mlx5dr_action_get_shared_stc_nic(ctx, stc_type, MLX5DR_TABLE_TYPE_FDB);
191 		if (ret) {
192 			DR_LOG(ERR, "Failed to allocate memory for FDB shared STCs (type: %d)",
193 			       stc_type);
194 			goto clean_nic_tx_stc;
195 		}
196 	}
197 
198 	return 0;
199 
200 clean_nic_tx_stc:
201 	if (action->flags & MLX5DR_ACTION_FLAG_HWS_TX)
202 		mlx5dr_action_put_shared_stc_nic(ctx, stc_type, MLX5DR_TABLE_TYPE_NIC_TX);
203 clean_nic_rx_stc:
204 	if (action->flags & MLX5DR_ACTION_FLAG_HWS_RX)
205 		mlx5dr_action_put_shared_stc_nic(ctx, stc_type, MLX5DR_TABLE_TYPE_NIC_RX);
206 
207 	return ret;
208 }
209 
210 static void mlx5dr_action_put_shared_stc(struct mlx5dr_action *action,
211 					 enum mlx5dr_context_shared_stc_type stc_type)
212 {
213 	struct mlx5dr_context *ctx = action->ctx;
214 
215 	if (stc_type >= MLX5DR_CONTEXT_SHARED_STC_MAX) {
216 		assert(false);
217 		return;
218 	}
219 
220 	if (action->flags & MLX5DR_ACTION_FLAG_HWS_RX)
221 		mlx5dr_action_put_shared_stc_nic(ctx, stc_type, MLX5DR_TABLE_TYPE_NIC_RX);
222 
223 	if (action->flags & MLX5DR_ACTION_FLAG_HWS_TX)
224 		mlx5dr_action_put_shared_stc_nic(ctx, stc_type, MLX5DR_TABLE_TYPE_NIC_TX);
225 
226 	if (action->flags & MLX5DR_ACTION_FLAG_HWS_FDB)
227 		mlx5dr_action_put_shared_stc_nic(ctx, stc_type, MLX5DR_TABLE_TYPE_FDB);
228 }
229 
230 static void mlx5dr_action_print_combo(enum mlx5dr_action_type *user_actions)
231 {
232 	DR_LOG(ERR, "Invalid action_type sequence");
233 	while (*user_actions != MLX5DR_ACTION_TYP_LAST) {
234 		DR_LOG(ERR, "%s", mlx5dr_debug_action_type_to_str(*user_actions));
235 		user_actions++;
236 	}
237 }
238 
239 bool mlx5dr_action_check_combo(enum mlx5dr_action_type *user_actions,
240 			       enum mlx5dr_table_type table_type)
241 {
242 	const uint32_t *order_arr = action_order_arr[table_type];
243 	uint8_t order_idx = 0;
244 	uint8_t user_idx = 0;
245 	bool valid_combo;
246 
247 	while (order_arr[order_idx] != BIT(MLX5DR_ACTION_TYP_LAST)) {
248 		/* User action order validated move to next user action */
249 		if (BIT(user_actions[user_idx]) & order_arr[order_idx])
250 			user_idx++;
251 
252 		/* Iterate to the next supported action in the order */
253 		order_idx++;
254 	}
255 
256 	/* Combination is valid if all user action were processed */
257 	valid_combo = user_actions[user_idx] == MLX5DR_ACTION_TYP_LAST;
258 	if (!valid_combo)
259 		mlx5dr_action_print_combo(user_actions);
260 
261 	return valid_combo;
262 }
263 
264 int mlx5dr_action_root_build_attr(struct mlx5dr_rule_action rule_actions[],
265 				  uint32_t num_actions,
266 				  struct mlx5dv_flow_action_attr *attr)
267 {
268 	struct mlx5dr_action *action;
269 	uint32_t i;
270 
271 	for (i = 0; i < num_actions; i++) {
272 		action = rule_actions[i].action;
273 
274 		switch (action->type) {
275 		case MLX5DR_ACTION_TYP_FT:
276 		case MLX5DR_ACTION_TYP_TIR:
277 			attr[i].type = MLX5DV_FLOW_ACTION_DEST_DEVX;
278 			attr[i].obj = action->devx_obj;
279 			break;
280 		case MLX5DR_ACTION_TYP_TAG:
281 			attr[i].type = MLX5DV_FLOW_ACTION_TAG;
282 			attr[i].tag_value = rule_actions[i].tag.value;
283 			break;
284 #ifdef HAVE_MLX5_DR_CREATE_ACTION_DEFAULT_MISS
285 		case MLX5DR_ACTION_TYP_MISS:
286 			attr[i].type = MLX5DV_FLOW_ACTION_DEFAULT_MISS;
287 			break;
288 #endif
289 		case MLX5DR_ACTION_TYP_DROP:
290 			attr[i].type = MLX5DV_FLOW_ACTION_DROP;
291 			break;
292 		case MLX5DR_ACTION_TYP_TNL_L2_TO_L2:
293 		case MLX5DR_ACTION_TYP_L2_TO_TNL_L2:
294 		case MLX5DR_ACTION_TYP_TNL_L3_TO_L2:
295 		case MLX5DR_ACTION_TYP_L2_TO_TNL_L3:
296 		case MLX5DR_ACTION_TYP_MODIFY_HDR:
297 			attr[i].type = MLX5DV_FLOW_ACTION_IBV_FLOW_ACTION;
298 			attr[i].action = action->flow_action;
299 			break;
300 #ifdef HAVE_IBV_FLOW_DEVX_COUNTERS
301 		case MLX5DR_ACTION_TYP_CTR:
302 			attr[i].type = MLX5DV_FLOW_ACTION_COUNTERS_DEVX;
303 			attr[i].obj = action->devx_obj;
304 
305 			if (rule_actions[i].counter.offset) {
306 				DR_LOG(ERR, "Counter offset not supported over root");
307 				rte_errno = ENOTSUP;
308 				return rte_errno;
309 			}
310 			break;
311 #endif
312 		default:
313 			DR_LOG(ERR, "Found unsupported action type: %d", action->type);
314 			rte_errno = ENOTSUP;
315 			return rte_errno;
316 		}
317 	}
318 
319 	return 0;
320 }
321 
322 static bool mlx5dr_action_fixup_stc_attr(struct mlx5dr_cmd_stc_modify_attr *stc_attr,
323 					 struct mlx5dr_cmd_stc_modify_attr *fixup_stc_attr,
324 					 enum mlx5dr_table_type table_type,
325 					 bool is_mirror)
326 {
327 	struct mlx5dr_devx_obj *devx_obj;
328 	bool use_fixup = false;
329 	uint32_t fw_tbl_type;
330 
331 	fw_tbl_type = mlx5dr_table_get_res_fw_ft_type(table_type, is_mirror);
332 
333 	switch (stc_attr->action_type) {
334 	case MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_STE_TABLE:
335 		if (!is_mirror)
336 			devx_obj = mlx5dr_pool_chunk_get_base_devx_obj(stc_attr->ste_table.ste_pool,
337 								       &stc_attr->ste_table.ste);
338 		else
339 			devx_obj =
340 			mlx5dr_pool_chunk_get_base_devx_obj_mirror(stc_attr->ste_table.ste_pool,
341 								   &stc_attr->ste_table.ste);
342 
343 		*fixup_stc_attr = *stc_attr;
344 		fixup_stc_attr->ste_table.ste_obj_id = devx_obj->id;
345 		use_fixup = true;
346 		break;
347 
348 	case MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_VPORT:
349 		if (stc_attr->vport.vport_num != WIRE_PORT)
350 			break;
351 
352 		if (fw_tbl_type == FS_FT_FDB_RX) {
353 			/* The FW doesn't allow to go back to wire in RX, so change it to DROP */
354 			fixup_stc_attr->action_type = MLX5_IFC_STC_ACTION_TYPE_DROP;
355 			fixup_stc_attr->action_offset = MLX5DR_ACTION_OFFSET_HIT;
356 			fixup_stc_attr->stc_offset = stc_attr->stc_offset;
357 		} else if (fw_tbl_type == FS_FT_FDB_TX) {
358 			/*The FW doesn't allow to go to wire in the TX by JUMP_TO_VPORT*/
359 			fixup_stc_attr->action_type = MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_UPLINK;
360 			fixup_stc_attr->action_offset = stc_attr->action_offset;
361 			fixup_stc_attr->stc_offset = stc_attr->stc_offset;
362 			fixup_stc_attr->vport.vport_num = 0;
363 			fixup_stc_attr->vport.esw_owner_vhca_id = stc_attr->vport.esw_owner_vhca_id;
364 		}
365 		use_fixup = true;
366 		break;
367 
368 	default:
369 		break;
370 	}
371 
372 	return use_fixup;
373 }
374 
375 int mlx5dr_action_alloc_single_stc(struct mlx5dr_context *ctx,
376 				   struct mlx5dr_cmd_stc_modify_attr *stc_attr,
377 				   uint32_t table_type,
378 				   struct mlx5dr_pool_chunk *stc)
379 {
380 	struct mlx5dr_cmd_stc_modify_attr cleanup_stc_attr = {0};
381 	struct mlx5dr_pool *stc_pool = ctx->stc_pool[table_type];
382 	struct mlx5dr_cmd_stc_modify_attr fixup_stc_attr = {0};
383 	struct mlx5dr_devx_obj *devx_obj_0;
384 	bool use_fixup;
385 	int ret;
386 
387 	ret = mlx5dr_pool_chunk_alloc(stc_pool, stc);
388 	if (ret) {
389 		DR_LOG(ERR, "Failed to allocate single action STC");
390 		return ret;
391 	}
392 
393 	stc_attr->stc_offset = stc->offset;
394 	devx_obj_0 = mlx5dr_pool_chunk_get_base_devx_obj(stc_pool, stc);
395 
396 	/* According to table/action limitation change the stc_attr */
397 	use_fixup = mlx5dr_action_fixup_stc_attr(stc_attr, &fixup_stc_attr, table_type, false);
398 	ret = mlx5dr_cmd_stc_modify(devx_obj_0, use_fixup ? &fixup_stc_attr : stc_attr);
399 	if (ret) {
400 		DR_LOG(ERR, "Failed to modify STC action_type %d tbl_type %d",
401 		       stc_attr->action_type, table_type);
402 		goto free_chunk;
403 	}
404 
405 	/* Modify the FDB peer */
406 	if (table_type == MLX5DR_TABLE_TYPE_FDB) {
407 		struct mlx5dr_devx_obj *devx_obj_1;
408 
409 		devx_obj_1 = mlx5dr_pool_chunk_get_base_devx_obj_mirror(stc_pool, stc);
410 
411 		use_fixup = mlx5dr_action_fixup_stc_attr(stc_attr, &fixup_stc_attr,
412 							 table_type, true);
413 		ret = mlx5dr_cmd_stc_modify(devx_obj_1, use_fixup ? &fixup_stc_attr : stc_attr);
414 		if (ret) {
415 			DR_LOG(ERR, "Failed to modify peer STC action_type %d tbl_type %d",
416 			       stc_attr->action_type, table_type);
417 			goto clean_devx_obj_0;
418 		}
419 	}
420 
421 	return 0;
422 
423 clean_devx_obj_0:
424 	cleanup_stc_attr.action_type = MLX5_IFC_STC_ACTION_TYPE_DROP;
425 	cleanup_stc_attr.action_offset = MLX5DR_ACTION_OFFSET_HIT;
426 	cleanup_stc_attr.stc_offset = stc->offset;
427 	mlx5dr_cmd_stc_modify(devx_obj_0, &cleanup_stc_attr);
428 free_chunk:
429 	mlx5dr_pool_chunk_free(stc_pool, stc);
430 	return rte_errno;
431 }
432 
433 void mlx5dr_action_free_single_stc(struct mlx5dr_context *ctx,
434 				   uint32_t table_type,
435 				   struct mlx5dr_pool_chunk *stc)
436 {
437 	struct mlx5dr_pool *stc_pool = ctx->stc_pool[table_type];
438 	struct mlx5dr_cmd_stc_modify_attr stc_attr = {0};
439 	struct mlx5dr_devx_obj *devx_obj;
440 
441 	/* Modify the STC not to point to an object */
442 	stc_attr.action_type = MLX5_IFC_STC_ACTION_TYPE_DROP;
443 	stc_attr.action_offset = MLX5DR_ACTION_OFFSET_HIT;
444 	stc_attr.stc_offset = stc->offset;
445 	devx_obj = mlx5dr_pool_chunk_get_base_devx_obj(stc_pool, stc);
446 	mlx5dr_cmd_stc_modify(devx_obj, &stc_attr);
447 
448 	if (table_type == MLX5DR_TABLE_TYPE_FDB) {
449 		devx_obj = mlx5dr_pool_chunk_get_base_devx_obj_mirror(stc_pool, stc);
450 		mlx5dr_cmd_stc_modify(devx_obj, &stc_attr);
451 	}
452 
453 	mlx5dr_pool_chunk_free(stc_pool, stc);
454 }
455 
456 static uint32_t mlx5dr_action_get_mh_stc_type(__be64 pattern)
457 {
458 	uint8_t action_type = MLX5_GET(set_action_in, &pattern, action_type);
459 
460 	switch (action_type) {
461 	case MLX5_MODIFICATION_TYPE_SET:
462 		return MLX5_IFC_STC_ACTION_TYPE_SET;
463 	case MLX5_MODIFICATION_TYPE_ADD:
464 		return MLX5_IFC_STC_ACTION_TYPE_ADD;
465 	case MLX5_MODIFICATION_TYPE_COPY:
466 		return MLX5_IFC_STC_ACTION_TYPE_COPY;
467 	default:
468 		assert(false);
469 		DR_LOG(ERR, "Unsupported action type: 0x%x\n", action_type);
470 		rte_errno = ENOTSUP;
471 		return MLX5_IFC_STC_ACTION_TYPE_NOP;
472 	}
473 }
474 
475 static void mlx5dr_action_fill_stc_attr(struct mlx5dr_action *action,
476 					struct mlx5dr_devx_obj *obj,
477 					struct mlx5dr_cmd_stc_modify_attr *attr)
478 {
479 	switch (action->type) {
480 	case MLX5DR_ACTION_TYP_TAG:
481 		attr->action_type = MLX5_IFC_STC_ACTION_TYPE_TAG;
482 		attr->action_offset = MLX5DR_ACTION_OFFSET_DW5;
483 		break;
484 	case MLX5DR_ACTION_TYP_DROP:
485 		attr->action_type = MLX5_IFC_STC_ACTION_TYPE_DROP;
486 		attr->action_offset = MLX5DR_ACTION_OFFSET_HIT;
487 		break;
488 	case MLX5DR_ACTION_TYP_MISS:
489 		attr->action_type = MLX5_IFC_STC_ACTION_TYPE_ALLOW;
490 		attr->action_offset = MLX5DR_ACTION_OFFSET_HIT;
491 		/* TODO Need to support default miss for FDB */
492 		break;
493 	case MLX5DR_ACTION_TYP_CTR:
494 		attr->id = obj->id;
495 		attr->action_type = MLX5_IFC_STC_ACTION_TYPE_COUNTER;
496 		attr->action_offset = MLX5DR_ACTION_OFFSET_DW0;
497 		break;
498 	case MLX5DR_ACTION_TYP_TIR:
499 		attr->action_type = MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_TIR;
500 		attr->action_offset = MLX5DR_ACTION_OFFSET_HIT;
501 		attr->dest_tir_num = obj->id;
502 		break;
503 	case MLX5DR_ACTION_TYP_TNL_L3_TO_L2:
504 	case MLX5DR_ACTION_TYP_MODIFY_HDR:
505 		attr->action_offset = MLX5DR_ACTION_OFFSET_DW6;
506 		if (action->modify_header.num_of_actions == 1) {
507 			attr->modify_action.data = action->modify_header.single_action;
508 			attr->action_type = mlx5dr_action_get_mh_stc_type(attr->modify_action.data);
509 
510 			if (attr->action_type == MLX5_IFC_STC_ACTION_TYPE_ADD ||
511 			    attr->action_type == MLX5_IFC_STC_ACTION_TYPE_SET)
512 				MLX5_SET(set_action_in, &attr->modify_action.data, data, 0);
513 		} else {
514 			attr->action_type = MLX5_IFC_STC_ACTION_TYPE_ACC_MODIFY_LIST;
515 			attr->modify_header.arg_id = action->modify_header.arg_obj->id;
516 			attr->modify_header.pattern_id = action->modify_header.pattern_obj->id;
517 		}
518 		break;
519 	case MLX5DR_ACTION_TYP_FT:
520 		attr->action_type = MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_FT;
521 		attr->action_offset = MLX5DR_ACTION_OFFSET_HIT;
522 		attr->dest_table_id = obj->id;
523 		break;
524 	case MLX5DR_ACTION_TYP_TNL_L2_TO_L2:
525 		attr->action_type = MLX5_IFC_STC_ACTION_TYPE_HEADER_REMOVE;
526 		attr->action_offset = MLX5DR_ACTION_OFFSET_DW5;
527 		attr->remove_header.decap = 1;
528 		attr->remove_header.start_anchor = MLX5_HEADER_ANCHOR_PACKET_START;
529 		attr->remove_header.end_anchor = MLX5_HEADER_ANCHOR_INNER_MAC;
530 		break;
531 	case MLX5DR_ACTION_TYP_L2_TO_TNL_L2:
532 		attr->action_type = MLX5_IFC_STC_ACTION_TYPE_HEADER_INSERT;
533 		attr->action_offset = MLX5DR_ACTION_OFFSET_DW6;
534 		attr->insert_header.encap = 1;
535 		attr->insert_header.insert_anchor = MLX5_HEADER_ANCHOR_PACKET_START;
536 		attr->insert_header.arg_id = action->reformat.arg_obj->id;
537 		attr->insert_header.header_size = action->reformat.header_size;
538 		break;
539 	case MLX5DR_ACTION_TYP_L2_TO_TNL_L3:
540 		attr->action_type = MLX5_IFC_STC_ACTION_TYPE_HEADER_INSERT;
541 		attr->action_offset = MLX5DR_ACTION_OFFSET_DW6;
542 		attr->insert_header.encap = 1;
543 		attr->insert_header.insert_anchor = MLX5_HEADER_ANCHOR_PACKET_START;
544 		attr->insert_header.arg_id = action->reformat.arg_obj->id;
545 		attr->insert_header.header_size = action->reformat.header_size;
546 		break;
547 	case MLX5DR_ACTION_TYP_ASO_METER:
548 		attr->action_offset = MLX5DR_ACTION_OFFSET_DW6;
549 		attr->action_type = MLX5_IFC_STC_ACTION_TYPE_ASO;
550 		attr->aso.aso_type = ASO_OPC_MOD_POLICER;
551 		attr->aso.devx_obj_id = obj->id;
552 		attr->aso.return_reg_id = action->aso.return_reg_id;
553 		break;
554 	case MLX5DR_ACTION_TYP_ASO_CT:
555 		attr->action_offset = MLX5DR_ACTION_OFFSET_DW6;
556 		attr->action_type = MLX5_IFC_STC_ACTION_TYPE_ASO;
557 		attr->aso.aso_type = ASO_OPC_MOD_CONNECTION_TRACKING;
558 		attr->aso.devx_obj_id = obj->id;
559 		attr->aso.return_reg_id = action->aso.return_reg_id;
560 		break;
561 	case MLX5DR_ACTION_TYP_VPORT:
562 		attr->action_offset = MLX5DR_ACTION_OFFSET_HIT;
563 		attr->action_type = MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_VPORT;
564 		attr->vport.vport_num = action->vport.vport_num;
565 		attr->vport.esw_owner_vhca_id =	action->vport.esw_owner_vhca_id;
566 		break;
567 	case MLX5DR_ACTION_TYP_POP_VLAN:
568 		attr->action_type = MLX5_IFC_STC_ACTION_TYPE_REMOVE_WORDS;
569 		attr->action_offset = MLX5DR_ACTION_OFFSET_DW5;
570 		attr->remove_words.start_anchor = MLX5_HEADER_ANCHOR_FIRST_VLAN_START;
571 		attr->remove_words.num_of_words = MLX5DR_ACTION_HDR_LEN_L2_VLAN / 2;
572 		break;
573 	case MLX5DR_ACTION_TYP_PUSH_VLAN:
574 		attr->action_type = MLX5_IFC_STC_ACTION_TYPE_HEADER_INSERT;
575 		attr->action_offset = MLX5DR_ACTION_OFFSET_DW6;
576 		attr->insert_header.encap = 0;
577 		attr->insert_header.is_inline = 1;
578 		attr->insert_header.insert_anchor = MLX5_HEADER_ANCHOR_PACKET_START;
579 		attr->insert_header.insert_offset = MLX5DR_ACTION_HDR_LEN_L2_MACS;
580 		attr->insert_header.header_size = MLX5DR_ACTION_HDR_LEN_L2_VLAN;
581 		break;
582 	default:
583 		DR_LOG(ERR, "Invalid action type %d", action->type);
584 		assert(false);
585 	}
586 }
587 
588 static int
589 mlx5dr_action_create_stcs(struct mlx5dr_action *action,
590 			  struct mlx5dr_devx_obj *obj)
591 {
592 	struct mlx5dr_cmd_stc_modify_attr stc_attr = {0};
593 	struct mlx5dr_context *ctx = action->ctx;
594 	int ret;
595 
596 	mlx5dr_action_fill_stc_attr(action, obj, &stc_attr);
597 
598 	/* Block unsupported parallel devx obj modify over the same base */
599 	pthread_spin_lock(&ctx->ctrl_lock);
600 
601 	/* Allocate STC for RX */
602 	if (action->flags & MLX5DR_ACTION_FLAG_HWS_RX) {
603 		ret = mlx5dr_action_alloc_single_stc(ctx, &stc_attr,
604 						     MLX5DR_TABLE_TYPE_NIC_RX,
605 						     &action->stc[MLX5DR_TABLE_TYPE_NIC_RX]);
606 		if (ret)
607 			goto out_err;
608 	}
609 
610 	/* Allocate STC for TX */
611 	if (action->flags & MLX5DR_ACTION_FLAG_HWS_TX) {
612 		ret = mlx5dr_action_alloc_single_stc(ctx, &stc_attr,
613 						     MLX5DR_TABLE_TYPE_NIC_TX,
614 						     &action->stc[MLX5DR_TABLE_TYPE_NIC_TX]);
615 		if (ret)
616 			goto free_nic_rx_stc;
617 	}
618 
619 	/* Allocate STC for FDB */
620 	if (action->flags & MLX5DR_ACTION_FLAG_HWS_FDB) {
621 		ret = mlx5dr_action_alloc_single_stc(ctx, &stc_attr,
622 						     MLX5DR_TABLE_TYPE_FDB,
623 						     &action->stc[MLX5DR_TABLE_TYPE_FDB]);
624 		if (ret)
625 			goto free_nic_tx_stc;
626 	}
627 
628 	pthread_spin_unlock(&ctx->ctrl_lock);
629 
630 	return 0;
631 
632 free_nic_tx_stc:
633 	if (action->flags & MLX5DR_ACTION_FLAG_HWS_TX)
634 		mlx5dr_action_free_single_stc(ctx,
635 					      MLX5DR_TABLE_TYPE_NIC_TX,
636 					      &action->stc[MLX5DR_TABLE_TYPE_NIC_TX]);
637 free_nic_rx_stc:
638 	if (action->flags & MLX5DR_ACTION_FLAG_HWS_RX)
639 		mlx5dr_action_free_single_stc(ctx,
640 					      MLX5DR_TABLE_TYPE_NIC_RX,
641 					      &action->stc[MLX5DR_TABLE_TYPE_NIC_RX]);
642 out_err:
643 	pthread_spin_unlock(&ctx->ctrl_lock);
644 	return rte_errno;
645 }
646 
647 static void
648 mlx5dr_action_destroy_stcs(struct mlx5dr_action *action)
649 {
650 	struct mlx5dr_context *ctx = action->ctx;
651 
652 	/* Block unsupported parallel devx obj modify over the same base */
653 	pthread_spin_lock(&ctx->ctrl_lock);
654 
655 	if (action->flags & MLX5DR_ACTION_FLAG_HWS_RX)
656 		mlx5dr_action_free_single_stc(ctx, MLX5DR_TABLE_TYPE_NIC_RX,
657 					      &action->stc[MLX5DR_TABLE_TYPE_NIC_RX]);
658 
659 	if (action->flags & MLX5DR_ACTION_FLAG_HWS_TX)
660 		mlx5dr_action_free_single_stc(ctx, MLX5DR_TABLE_TYPE_NIC_TX,
661 					      &action->stc[MLX5DR_TABLE_TYPE_NIC_TX]);
662 
663 	if (action->flags & MLX5DR_ACTION_FLAG_HWS_FDB)
664 		mlx5dr_action_free_single_stc(ctx, MLX5DR_TABLE_TYPE_FDB,
665 					      &action->stc[MLX5DR_TABLE_TYPE_FDB]);
666 
667 	pthread_spin_unlock(&ctx->ctrl_lock);
668 }
669 
670 static bool
671 mlx5dr_action_is_root_flags(uint32_t flags)
672 {
673 	return flags & (MLX5DR_ACTION_FLAG_ROOT_RX |
674 			MLX5DR_ACTION_FLAG_ROOT_TX |
675 			MLX5DR_ACTION_FLAG_ROOT_FDB);
676 }
677 
678 static bool
679 mlx5dr_action_is_hws_flags(uint32_t flags)
680 {
681 	return flags & (MLX5DR_ACTION_FLAG_HWS_RX |
682 			MLX5DR_ACTION_FLAG_HWS_TX |
683 			MLX5DR_ACTION_FLAG_HWS_FDB);
684 }
685 
686 static struct mlx5dr_action *
687 mlx5dr_action_create_generic(struct mlx5dr_context *ctx,
688 			     uint32_t flags,
689 			     enum mlx5dr_action_type action_type)
690 {
691 	struct mlx5dr_action *action;
692 
693 	if (!mlx5dr_action_is_root_flags(flags) &&
694 	    !mlx5dr_action_is_hws_flags(flags)) {
695 		DR_LOG(ERR, "Action flags must specify root or non root (HWS)");
696 		rte_errno = ENOTSUP;
697 		return NULL;
698 	}
699 
700 	if (mlx5dr_action_is_hws_flags(flags) &&
701 	    !(ctx->flags & MLX5DR_CONTEXT_FLAG_HWS_SUPPORT)) {
702 		DR_LOG(ERR, "Cannot create HWS action since HWS is not supported");
703 		rte_errno = ENOTSUP;
704 		return NULL;
705 	}
706 
707 	action = simple_calloc(1, sizeof(*action));
708 	if (!action) {
709 		DR_LOG(ERR, "Failed to allocate memory for action [%d]", action_type);
710 		rte_errno = ENOMEM;
711 		return NULL;
712 	}
713 
714 	action->ctx = ctx;
715 	action->flags = flags;
716 	action->type = action_type;
717 
718 	return action;
719 }
720 
721 struct mlx5dr_action *
722 mlx5dr_action_create_dest_table(struct mlx5dr_context *ctx,
723 				struct mlx5dr_table *tbl,
724 				uint32_t flags)
725 {
726 	struct mlx5dr_action *action;
727 	int ret;
728 
729 	if (mlx5dr_table_is_root(tbl)) {
730 		DR_LOG(ERR, "Root table cannot be set as destination");
731 		rte_errno = ENOTSUP;
732 		return NULL;
733 	}
734 
735 	if (mlx5dr_action_is_hws_flags(flags) &&
736 	    mlx5dr_action_is_root_flags(flags)) {
737 		DR_LOG(ERR, "Same action cannot be used for root and non root");
738 		rte_errno = ENOTSUP;
739 		return NULL;
740 	}
741 
742 	action = mlx5dr_action_create_generic(ctx, flags, MLX5DR_ACTION_TYP_FT);
743 	if (!action)
744 		return NULL;
745 
746 	if (mlx5dr_action_is_root_flags(flags)) {
747 		action->devx_obj = tbl->ft->obj;
748 	} else {
749 		ret = mlx5dr_action_create_stcs(action, tbl->ft);
750 		if (ret)
751 			goto free_action;
752 	}
753 
754 	return action;
755 
756 free_action:
757 	simple_free(action);
758 	return NULL;
759 }
760 
761 struct mlx5dr_action *
762 mlx5dr_action_create_dest_tir(struct mlx5dr_context *ctx,
763 			      struct mlx5dr_devx_obj *obj,
764 			      uint32_t flags)
765 {
766 	struct mlx5dr_action *action;
767 	int ret;
768 
769 	if (mlx5dr_action_is_hws_flags(flags) &&
770 	    mlx5dr_action_is_root_flags(flags)) {
771 		DR_LOG(ERR, "Same action cannot be used for root and non root");
772 		rte_errno = ENOTSUP;
773 		return NULL;
774 	}
775 
776 	action = mlx5dr_action_create_generic(ctx, flags, MLX5DR_ACTION_TYP_TIR);
777 	if (!action)
778 		return NULL;
779 
780 	if (mlx5dr_action_is_root_flags(flags)) {
781 		action->devx_obj = obj->obj;
782 	} else {
783 		ret = mlx5dr_action_create_stcs(action, obj);
784 		if (ret)
785 			goto free_action;
786 	}
787 
788 	return action;
789 
790 free_action:
791 	simple_free(action);
792 	return NULL;
793 }
794 
795 struct mlx5dr_action *
796 mlx5dr_action_create_dest_drop(struct mlx5dr_context *ctx,
797 			       uint32_t flags)
798 {
799 	struct mlx5dr_action *action;
800 	int ret;
801 
802 	action = mlx5dr_action_create_generic(ctx, flags, MLX5DR_ACTION_TYP_DROP);
803 	if (!action)
804 		return NULL;
805 
806 	if (mlx5dr_action_is_hws_flags(flags)) {
807 		ret = mlx5dr_action_create_stcs(action, NULL);
808 		if (ret)
809 			goto free_action;
810 	}
811 
812 	return action;
813 
814 free_action:
815 	simple_free(action);
816 	return NULL;
817 }
818 
819 struct mlx5dr_action *
820 mlx5dr_action_create_default_miss(struct mlx5dr_context *ctx,
821 				  uint32_t flags)
822 {
823 	struct mlx5dr_action *action;
824 	int ret;
825 
826 	action = mlx5dr_action_create_generic(ctx, flags, MLX5DR_ACTION_TYP_MISS);
827 	if (!action)
828 		return NULL;
829 
830 	if (mlx5dr_action_is_hws_flags(flags)) {
831 		ret = mlx5dr_action_create_stcs(action, NULL);
832 		if (ret)
833 			goto free_action;
834 	}
835 
836 	return action;
837 
838 free_action:
839 	simple_free(action);
840 	return NULL;
841 }
842 
843 struct mlx5dr_action *
844 mlx5dr_action_create_tag(struct mlx5dr_context *ctx,
845 			 uint32_t flags)
846 {
847 	struct mlx5dr_action *action;
848 	int ret;
849 
850 	action = mlx5dr_action_create_generic(ctx, flags, MLX5DR_ACTION_TYP_TAG);
851 	if (!action)
852 		return NULL;
853 
854 	if (mlx5dr_action_is_hws_flags(flags)) {
855 		ret = mlx5dr_action_create_stcs(action, NULL);
856 		if (ret)
857 			goto free_action;
858 	}
859 
860 	return action;
861 
862 free_action:
863 	simple_free(action);
864 	return NULL;
865 }
866 
867 static struct mlx5dr_action *
868 mlx5dr_action_create_aso(struct mlx5dr_context *ctx,
869 			 enum mlx5dr_action_type action_type,
870 			 struct mlx5dr_devx_obj *devx_obj,
871 			 uint8_t return_reg_id,
872 			 uint32_t flags)
873 {
874 	struct mlx5dr_action *action;
875 	int ret;
876 
877 	if (mlx5dr_action_is_root_flags(flags)) {
878 		DR_LOG(ERR, "ASO action cannot be used over root table");
879 		rte_errno = ENOTSUP;
880 		return NULL;
881 	}
882 
883 	action = mlx5dr_action_create_generic(ctx, flags, action_type);
884 	if (!action)
885 		return NULL;
886 
887 	action->aso.devx_obj = devx_obj;
888 	action->aso.return_reg_id = return_reg_id;
889 
890 	ret = mlx5dr_action_create_stcs(action, devx_obj);
891 	if (ret)
892 		goto free_action;
893 
894 	return action;
895 
896 free_action:
897 	simple_free(action);
898 	return NULL;
899 }
900 
901 struct mlx5dr_action *
902 mlx5dr_action_create_aso_meter(struct mlx5dr_context *ctx,
903 			       struct mlx5dr_devx_obj *devx_obj,
904 			       uint8_t return_reg_id,
905 			       uint32_t flags)
906 {
907 	return mlx5dr_action_create_aso(ctx, MLX5DR_ACTION_TYP_ASO_METER,
908 					devx_obj, return_reg_id, flags);
909 }
910 
911 struct mlx5dr_action *
912 mlx5dr_action_create_aso_ct(struct mlx5dr_context *ctx,
913 			    struct mlx5dr_devx_obj *devx_obj,
914 			    uint8_t return_reg_id,
915 			    uint32_t flags)
916 {
917 	return mlx5dr_action_create_aso(ctx, MLX5DR_ACTION_TYP_ASO_CT,
918 					devx_obj, return_reg_id, flags);
919 }
920 
921 struct mlx5dr_action *
922 mlx5dr_action_create_counter(struct mlx5dr_context *ctx,
923 			     struct mlx5dr_devx_obj *obj,
924 			     uint32_t flags)
925 {
926 	struct mlx5dr_action *action;
927 	int ret;
928 
929 	if (mlx5dr_action_is_hws_flags(flags) &&
930 	    mlx5dr_action_is_root_flags(flags)) {
931 		DR_LOG(ERR, "Same action cannot be used for root and non root");
932 		rte_errno = ENOTSUP;
933 		return NULL;
934 	}
935 
936 	action = mlx5dr_action_create_generic(ctx, flags, MLX5DR_ACTION_TYP_CTR);
937 	if (!action)
938 		return NULL;
939 
940 	if (mlx5dr_action_is_root_flags(flags)) {
941 		action->devx_obj = obj->obj;
942 	} else {
943 		ret = mlx5dr_action_create_stcs(action, obj);
944 		if (ret)
945 			goto free_action;
946 	}
947 
948 	return action;
949 
950 free_action:
951 	simple_free(action);
952 	return NULL;
953 }
954 
955 static int mlx5dr_action_create_dest_vport_hws(struct mlx5dr_context *ctx,
956 					       struct mlx5dr_action *action,
957 					       uint32_t ib_port_num)
958 {
959 	struct mlx5dr_cmd_query_vport_caps vport_caps = {0};
960 	int ret;
961 
962 	ret = mlx5dr_cmd_query_ib_port(ctx->ibv_ctx, &vport_caps, ib_port_num);
963 	if (ret) {
964 		DR_LOG(ERR, "Failed querying port %d\n", ib_port_num);
965 		return ret;
966 	}
967 	action->vport.vport_num = vport_caps.vport_num;
968 	action->vport.esw_owner_vhca_id = vport_caps.esw_owner_vhca_id;
969 
970 	ret = mlx5dr_action_create_stcs(action, NULL);
971 	if (ret) {
972 		DR_LOG(ERR, "Failed creating stc for port %d\n", ib_port_num);
973 		return ret;
974 	}
975 
976 	return 0;
977 }
978 
979 struct mlx5dr_action *
980 mlx5dr_action_create_dest_vport(struct mlx5dr_context *ctx,
981 				uint32_t ib_port_num,
982 				uint32_t flags)
983 {
984 	struct mlx5dr_action *action;
985 	int ret;
986 
987 	if (!(flags & MLX5DR_ACTION_FLAG_HWS_FDB)) {
988 		DR_LOG(ERR, "Vport action is supported for FDB only\n");
989 		rte_errno = EINVAL;
990 		return NULL;
991 	}
992 
993 	action = mlx5dr_action_create_generic(ctx, flags, MLX5DR_ACTION_TYP_VPORT);
994 	if (!action)
995 		return NULL;
996 
997 	ret = mlx5dr_action_create_dest_vport_hws(ctx, action, ib_port_num);
998 	if (ret) {
999 		DR_LOG(ERR, "Failed to create vport action HWS\n");
1000 		goto free_action;
1001 	}
1002 
1003 	return action;
1004 
1005 free_action:
1006 	simple_free(action);
1007 	return NULL;
1008 }
1009 
1010 struct mlx5dr_action *
1011 mlx5dr_action_create_push_vlan(struct mlx5dr_context *ctx, uint32_t flags)
1012 {
1013 	struct mlx5dr_action *action;
1014 	int ret;
1015 
1016 	if (mlx5dr_action_is_root_flags(flags)) {
1017 		DR_LOG(ERR, "Push vlan action not supported for root");
1018 		rte_errno = ENOTSUP;
1019 		return NULL;
1020 	}
1021 
1022 	action = mlx5dr_action_create_generic(ctx, flags, MLX5DR_ACTION_TYP_PUSH_VLAN);
1023 	if (!action)
1024 		return NULL;
1025 
1026 	ret = mlx5dr_action_create_stcs(action, NULL);
1027 	if (ret) {
1028 		DR_LOG(ERR, "Failed creating stc for push vlan\n");
1029 		goto free_action;
1030 	}
1031 
1032 	return action;
1033 
1034 free_action:
1035 	simple_free(action);
1036 	return NULL;
1037 }
1038 
1039 struct mlx5dr_action *
1040 mlx5dr_action_create_pop_vlan(struct mlx5dr_context *ctx, uint32_t flags)
1041 {
1042 	struct mlx5dr_action *action;
1043 	int ret;
1044 
1045 	if (mlx5dr_action_is_root_flags(flags)) {
1046 		DR_LOG(ERR, "Pop vlan action not supported for root");
1047 		rte_errno = ENOTSUP;
1048 		return NULL;
1049 	}
1050 	action = mlx5dr_action_create_generic(ctx, flags, MLX5DR_ACTION_TYP_POP_VLAN);
1051 	if (!action)
1052 		return NULL;
1053 
1054 	ret = mlx5dr_action_get_shared_stc(action, MLX5DR_CONTEXT_SHARED_STC_POP);
1055 	if (ret) {
1056 		DR_LOG(ERR, "Failed to create remove stc for reformat");
1057 		goto free_action;
1058 	}
1059 
1060 	ret = mlx5dr_action_create_stcs(action, NULL);
1061 	if (ret) {
1062 		DR_LOG(ERR, "Failed creating stc for pop vlan\n");
1063 		goto free_shared;
1064 	}
1065 
1066 	return action;
1067 
1068 free_shared:
1069 	mlx5dr_action_put_shared_stc(action, MLX5DR_CONTEXT_SHARED_STC_POP);
1070 free_action:
1071 	simple_free(action);
1072 	return NULL;
1073 }
1074 
1075 static int
1076 mlx5dr_action_conv_reformat_type_to_action(uint32_t reformat_type,
1077 					   enum mlx5dr_action_type *action_type)
1078 {
1079 	switch (reformat_type) {
1080 	case MLX5DR_ACTION_REFORMAT_TYPE_TNL_L2_TO_L2:
1081 		*action_type = MLX5DR_ACTION_TYP_TNL_L2_TO_L2;
1082 		break;
1083 	case MLX5DR_ACTION_REFORMAT_TYPE_L2_TO_TNL_L2:
1084 		*action_type = MLX5DR_ACTION_TYP_L2_TO_TNL_L2;
1085 		break;
1086 	case MLX5DR_ACTION_REFORMAT_TYPE_TNL_L3_TO_L2:
1087 		*action_type = MLX5DR_ACTION_TYP_TNL_L3_TO_L2;
1088 		break;
1089 	case MLX5DR_ACTION_REFORMAT_TYPE_L2_TO_TNL_L3:
1090 		*action_type = MLX5DR_ACTION_TYP_L2_TO_TNL_L3;
1091 		break;
1092 	default:
1093 		DR_LOG(ERR, "Invalid reformat type requested");
1094 		rte_errno = ENOTSUP;
1095 		return rte_errno;
1096 	}
1097 	return 0;
1098 }
1099 
1100 static void
1101 mlx5dr_action_conv_reformat_to_verbs(uint32_t action_type,
1102 				     uint32_t *verb_reformat_type)
1103 {
1104 	switch (action_type) {
1105 	case MLX5DR_ACTION_TYP_TNL_L2_TO_L2:
1106 		*verb_reformat_type =
1107 			MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TUNNEL_TO_L2;
1108 		break;
1109 	case MLX5DR_ACTION_TYP_L2_TO_TNL_L2:
1110 		*verb_reformat_type =
1111 			MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L2_TUNNEL;
1112 		break;
1113 	case MLX5DR_ACTION_TYP_TNL_L3_TO_L2:
1114 		*verb_reformat_type =
1115 			MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L3_TUNNEL_TO_L2;
1116 		break;
1117 	case MLX5DR_ACTION_TYP_L2_TO_TNL_L3:
1118 		*verb_reformat_type =
1119 			MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L3_TUNNEL;
1120 		break;
1121 	}
1122 }
1123 
1124 static int
1125 mlx5dr_action_conv_flags_to_ft_type(uint32_t flags, enum mlx5dv_flow_table_type *ft_type)
1126 {
1127 	if (flags & MLX5DR_ACTION_FLAG_ROOT_RX) {
1128 		*ft_type = MLX5DV_FLOW_TABLE_TYPE_NIC_RX;
1129 	} else if (flags & MLX5DR_ACTION_FLAG_ROOT_TX) {
1130 		*ft_type = MLX5DV_FLOW_TABLE_TYPE_NIC_TX;
1131 #ifdef HAVE_MLX5DV_FLOW_MATCHER_FT_TYPE
1132 	} else if (flags & MLX5DR_ACTION_FLAG_ROOT_FDB) {
1133 		*ft_type = MLX5DV_FLOW_TABLE_TYPE_FDB;
1134 #endif
1135 	} else {
1136 		rte_errno = ENOTSUP;
1137 		return 1;
1138 	}
1139 
1140 	return 0;
1141 }
1142 
1143 static int
1144 mlx5dr_action_create_reformat_root(struct mlx5dr_action *action,
1145 				   size_t data_sz,
1146 				   void *data)
1147 {
1148 	enum mlx5dv_flow_table_type ft_type = 0; /*fix compilation warn*/
1149 	uint32_t verb_reformat_type = 0;
1150 	int ret;
1151 
1152 	/* Convert action to FT type and verbs reformat type */
1153 	ret = mlx5dr_action_conv_flags_to_ft_type(action->flags, &ft_type);
1154 	if (ret)
1155 		return rte_errno;
1156 
1157 	mlx5dr_action_conv_reformat_to_verbs(action->type, &verb_reformat_type);
1158 
1159 	/* Create the reformat type for root table */
1160 	action->flow_action =
1161 		mlx5_glue->dv_create_flow_action_packet_reformat_root(action->ctx->ibv_ctx,
1162 								      data_sz,
1163 								      data,
1164 								      verb_reformat_type,
1165 								      ft_type);
1166 	if (!action->flow_action) {
1167 		rte_errno = errno;
1168 		return rte_errno;
1169 	}
1170 
1171 	return 0;
1172 }
1173 
1174 static int mlx5dr_action_handle_reformat_args(struct mlx5dr_context *ctx,
1175 					      size_t data_sz,
1176 					      void *data,
1177 					      uint32_t bulk_size,
1178 					      struct mlx5dr_action *action)
1179 {
1180 	uint32_t args_log_size;
1181 	int ret;
1182 
1183 	if (data_sz % 2 != 0) {
1184 		DR_LOG(ERR, "Data size should be multiply of 2");
1185 		rte_errno = EINVAL;
1186 		return rte_errno;
1187 	}
1188 	action->reformat.header_size = data_sz;
1189 
1190 	args_log_size = mlx5dr_arg_data_size_to_arg_log_size(data_sz);
1191 	if (args_log_size >= MLX5DR_ARG_CHUNK_SIZE_MAX) {
1192 		DR_LOG(ERR, "Data size is bigger than supported");
1193 		rte_errno = EINVAL;
1194 		return rte_errno;
1195 	}
1196 	args_log_size += bulk_size;
1197 
1198 	if (!mlx5dr_arg_is_valid_arg_request_size(ctx, args_log_size)) {
1199 		DR_LOG(ERR, "Arg size %d does not fit FW requests",
1200 		       args_log_size);
1201 		rte_errno = EINVAL;
1202 		return rte_errno;
1203 	}
1204 
1205 	action->reformat.arg_obj = mlx5dr_cmd_arg_create(ctx->ibv_ctx,
1206 							 args_log_size,
1207 							 ctx->pd_num);
1208 	if (!action->reformat.arg_obj) {
1209 		DR_LOG(ERR, "Failed to create arg for reformat");
1210 		return rte_errno;
1211 	}
1212 
1213 	/* When INLINE need to write the arg data */
1214 	if (action->flags & MLX5DR_ACTION_FLAG_SHARED) {
1215 		ret = mlx5dr_arg_write_inline_arg_data(ctx,
1216 						       action->reformat.arg_obj->id,
1217 						       data,
1218 						       data_sz);
1219 		if (ret) {
1220 			DR_LOG(ERR, "Failed to write inline arg for reformat");
1221 			goto free_arg;
1222 		}
1223 	}
1224 
1225 	return 0;
1226 
1227 free_arg:
1228 	mlx5dr_cmd_destroy_obj(action->reformat.arg_obj);
1229 	return ret;
1230 }
1231 
1232 static int mlx5dr_action_handle_l2_to_tunnel_l2(struct mlx5dr_context *ctx,
1233 						size_t data_sz,
1234 						void *data,
1235 						uint32_t bulk_size,
1236 						struct mlx5dr_action *action)
1237 {
1238 	int ret;
1239 
1240 	ret = mlx5dr_action_handle_reformat_args(ctx, data_sz, data, bulk_size,
1241 						 action);
1242 	if (ret) {
1243 		DR_LOG(ERR, "Failed to create args for reformat");
1244 		return ret;
1245 	}
1246 
1247 	ret = mlx5dr_action_create_stcs(action, NULL);
1248 	if (ret) {
1249 		DR_LOG(ERR, "Failed to create stc for reformat");
1250 		goto free_arg;
1251 	}
1252 
1253 	return 0;
1254 
1255 free_arg:
1256 	mlx5dr_cmd_destroy_obj(action->reformat.arg_obj);
1257 	return ret;
1258 }
1259 
1260 static int mlx5dr_action_get_shared_stc_offset(struct mlx5dr_context_common_res *common_res,
1261 					       enum mlx5dr_context_shared_stc_type stc_type)
1262 {
1263 	return common_res->shared_stc[stc_type]->remove_header.offset;
1264 }
1265 
1266 static int mlx5dr_action_handle_l2_to_tunnel_l3(struct mlx5dr_context *ctx,
1267 						size_t data_sz,
1268 						void *data,
1269 						uint32_t bulk_size,
1270 						struct mlx5dr_action *action)
1271 {
1272 	int ret;
1273 
1274 	ret = mlx5dr_action_handle_reformat_args(ctx, data_sz, data, bulk_size,
1275 						 action);
1276 	if (ret) {
1277 		DR_LOG(ERR, "Failed to create args for reformat");
1278 		return ret;
1279 	}
1280 
1281 	/* The action is remove-l2-header + insert-l3-header */
1282 	ret = mlx5dr_action_get_shared_stc(action, MLX5DR_CONTEXT_SHARED_STC_DECAP);
1283 	if (ret) {
1284 		DR_LOG(ERR, "Failed to create remove stc for reformat");
1285 		goto free_arg;
1286 	}
1287 
1288 	ret = mlx5dr_action_create_stcs(action, NULL);
1289 	if (ret) {
1290 		DR_LOG(ERR, "Failed to create insert stc for reformat");
1291 		goto down_shared;
1292 	}
1293 
1294 	return 0;
1295 
1296 down_shared:
1297 	mlx5dr_action_put_shared_stc(action, MLX5DR_CONTEXT_SHARED_STC_DECAP);
1298 free_arg:
1299 	mlx5dr_cmd_destroy_obj(action->reformat.arg_obj);
1300 	return ret;
1301 }
1302 
1303 static void mlx5dr_action_prepare_decap_l3_actions(size_t data_sz,
1304 						   uint8_t *mh_data,
1305 						   int *num_of_actions)
1306 {
1307 	int actions;
1308 	uint32_t i;
1309 
1310 	/* Remove L2L3 outer headers */
1311 	MLX5_SET(stc_ste_param_remove, mh_data, action_type,
1312 		 MLX5_MODIFICATION_TYPE_REMOVE);
1313 	MLX5_SET(stc_ste_param_remove, mh_data, decap, 0x1);
1314 	MLX5_SET(stc_ste_param_remove, mh_data, remove_start_anchor,
1315 		 MLX5_HEADER_ANCHOR_PACKET_START);
1316 	MLX5_SET(stc_ste_param_remove, mh_data, remove_end_anchor,
1317 		 MLX5_HEADER_ANCHOR_INNER_IPV6_IPV4);
1318 	mh_data += MLX5DR_ACTION_DOUBLE_SIZE; /* Assume every action is 2 dw */
1319 	actions = 1;
1320 
1321 	/* Add the new header using inline action 4Byte at a time, the header
1322 	 * is added in reversed order to the beginning of the packet to avoid
1323 	 * incorrect parsing by the HW. Since header is 14B or 18B an extra
1324 	 * two bytes are padded and later removed.
1325 	 */
1326 	for (i = 0; i < data_sz / MLX5DR_ACTION_INLINE_DATA_SIZE + 1; i++) {
1327 		MLX5_SET(stc_ste_param_insert, mh_data, action_type,
1328 			 MLX5_MODIFICATION_TYPE_INSERT);
1329 		MLX5_SET(stc_ste_param_insert, mh_data, inline_data, 0x1);
1330 		MLX5_SET(stc_ste_param_insert, mh_data, insert_anchor,
1331 			 MLX5_HEADER_ANCHOR_PACKET_START);
1332 		MLX5_SET(stc_ste_param_insert, mh_data, insert_size, 2);
1333 		mh_data += MLX5DR_ACTION_DOUBLE_SIZE;
1334 		actions++;
1335 	}
1336 
1337 	/* Remove first 2 extra bytes */
1338 	MLX5_SET(stc_ste_param_remove_words, mh_data, action_type,
1339 		 MLX5_MODIFICATION_TYPE_REMOVE_WORDS);
1340 	MLX5_SET(stc_ste_param_remove_words, mh_data, remove_start_anchor,
1341 		 MLX5_HEADER_ANCHOR_PACKET_START);
1342 	/* The hardware expects here size in words (2 bytes) */
1343 	MLX5_SET(stc_ste_param_remove_words, mh_data, remove_size, 1);
1344 	actions++;
1345 
1346 	*num_of_actions = actions;
1347 }
1348 
1349 static int
1350 mlx5dr_action_handle_tunnel_l3_to_l2(struct mlx5dr_context *ctx,
1351 				     size_t data_sz,
1352 				     void *data,
1353 				     uint32_t bulk_size,
1354 				     struct mlx5dr_action *action)
1355 {
1356 	uint8_t mh_data[MLX5DR_ACTION_REFORMAT_DATA_SIZE] = {0};
1357 	int num_of_actions;
1358 	int mh_data_size;
1359 	int ret;
1360 
1361 	if (data_sz != MLX5DR_ACTION_HDR_LEN_L2 &&
1362 	    data_sz != MLX5DR_ACTION_HDR_LEN_L2_W_VLAN) {
1363 		DR_LOG(ERR, "Data size is not supported for decap-l3\n");
1364 		rte_errno = EINVAL;
1365 		return rte_errno;
1366 	}
1367 
1368 	mlx5dr_action_prepare_decap_l3_actions(data_sz, mh_data, &num_of_actions);
1369 
1370 	mh_data_size = num_of_actions * MLX5DR_MODIFY_ACTION_SIZE;
1371 
1372 	ret = mlx5dr_pat_arg_create_modify_header(ctx, action, mh_data_size,
1373 						  (__be64 *)mh_data, bulk_size);
1374 	if (ret) {
1375 		DR_LOG(ERR, "Failed allocating modify-header for decap-l3\n");
1376 		return ret;
1377 	}
1378 
1379 	ret = mlx5dr_action_create_stcs(action, NULL);
1380 	if (ret)
1381 		goto free_mh_obj;
1382 
1383 	if (action->flags & MLX5DR_ACTION_FLAG_SHARED) {
1384 		mlx5dr_action_prepare_decap_l3_data(data, mh_data, num_of_actions);
1385 		ret = mlx5dr_arg_write_inline_arg_data(ctx,
1386 						       action->modify_header.arg_obj->id,
1387 						       (uint8_t *)mh_data,
1388 						       num_of_actions *
1389 						       MLX5DR_MODIFY_ACTION_SIZE);
1390 		if (ret) {
1391 			DR_LOG(ERR, "Failed writing INLINE arg decap_l3");
1392 			goto clean_stc;
1393 		}
1394 	}
1395 
1396 	return 0;
1397 
1398 clean_stc:
1399 	mlx5dr_action_destroy_stcs(action);
1400 free_mh_obj:
1401 	mlx5dr_pat_arg_destroy_modify_header(ctx, action);
1402 	return ret;
1403 }
1404 
1405 static int
1406 mlx5dr_action_create_reformat_hws(struct mlx5dr_context *ctx,
1407 				  size_t data_sz,
1408 				  void *data,
1409 				  uint32_t bulk_size,
1410 				  struct mlx5dr_action *action)
1411 {
1412 	int ret;
1413 
1414 	switch (action->type) {
1415 	case MLX5DR_ACTION_TYP_TNL_L2_TO_L2:
1416 		ret = mlx5dr_action_create_stcs(action, NULL);
1417 		break;
1418 	case MLX5DR_ACTION_TYP_L2_TO_TNL_L2:
1419 		ret = mlx5dr_action_handle_l2_to_tunnel_l2(ctx, data_sz, data, bulk_size, action);
1420 		break;
1421 	case MLX5DR_ACTION_TYP_L2_TO_TNL_L3:
1422 		ret = mlx5dr_action_handle_l2_to_tunnel_l3(ctx, data_sz, data, bulk_size, action);
1423 		break;
1424 	case MLX5DR_ACTION_TYP_TNL_L3_TO_L2:
1425 		ret = mlx5dr_action_handle_tunnel_l3_to_l2(ctx, data_sz, data, bulk_size, action);
1426 		break;
1427 
1428 	default:
1429 		assert(false);
1430 		rte_errno = ENOTSUP;
1431 		return rte_errno;
1432 	}
1433 
1434 	return ret;
1435 }
1436 
1437 struct mlx5dr_action *
1438 mlx5dr_action_create_reformat(struct mlx5dr_context *ctx,
1439 			      enum mlx5dr_action_reformat_type reformat_type,
1440 			      size_t data_sz,
1441 			      void *inline_data,
1442 			      uint32_t log_bulk_size,
1443 			      uint32_t flags)
1444 {
1445 	enum mlx5dr_action_type action_type;
1446 	struct mlx5dr_action *action;
1447 	int ret;
1448 
1449 	ret = mlx5dr_action_conv_reformat_type_to_action(reformat_type, &action_type);
1450 	if (ret)
1451 		return NULL;
1452 
1453 	action = mlx5dr_action_create_generic(ctx, flags, action_type);
1454 	if (!action)
1455 		return NULL;
1456 
1457 	if (mlx5dr_action_is_root_flags(flags)) {
1458 		if (log_bulk_size) {
1459 			DR_LOG(ERR, "Bulk reformat not supported over root");
1460 			rte_errno = ENOTSUP;
1461 			goto free_action;
1462 		}
1463 
1464 		ret = mlx5dr_action_create_reformat_root(action, data_sz, inline_data);
1465 		if (ret)
1466 			goto free_action;
1467 
1468 		return action;
1469 	}
1470 
1471 	if (!mlx5dr_action_is_hws_flags(flags) ||
1472 	    ((flags & MLX5DR_ACTION_FLAG_SHARED) && log_bulk_size)) {
1473 		DR_LOG(ERR, "Reformat flags don't fit HWS (flags: %x0x)\n",
1474 			flags);
1475 		rte_errno = EINVAL;
1476 		goto free_action;
1477 	}
1478 
1479 	ret = mlx5dr_action_create_reformat_hws(ctx, data_sz, inline_data, log_bulk_size, action);
1480 	if (ret) {
1481 		DR_LOG(ERR, "Failed to create reformat.\n");
1482 		rte_errno = EINVAL;
1483 		goto free_action;
1484 	}
1485 
1486 	return action;
1487 
1488 free_action:
1489 	simple_free(action);
1490 	return NULL;
1491 }
1492 
1493 static int
1494 mlx5dr_action_create_modify_header_root(struct mlx5dr_action *action,
1495 					size_t actions_sz,
1496 					__be64 *actions)
1497 {
1498 	enum mlx5dv_flow_table_type ft_type = 0;
1499 	int ret;
1500 
1501 	ret = mlx5dr_action_conv_flags_to_ft_type(action->flags, &ft_type);
1502 	if (ret)
1503 		return rte_errno;
1504 
1505 	action->flow_action =
1506 		mlx5_glue->dv_create_flow_action_modify_header_root(action->ctx->ibv_ctx,
1507 								    actions_sz,
1508 								    (uint64_t *)actions,
1509 								    ft_type);
1510 	if (!action->flow_action) {
1511 		rte_errno = errno;
1512 		return rte_errno;
1513 	}
1514 
1515 	return 0;
1516 }
1517 
1518 struct mlx5dr_action *
1519 mlx5dr_action_create_modify_header(struct mlx5dr_context *ctx,
1520 				   size_t pattern_sz,
1521 				   __be64 pattern[],
1522 				   uint32_t log_bulk_size,
1523 				   uint32_t flags)
1524 {
1525 	struct mlx5dr_action *action;
1526 	int ret;
1527 
1528 	action = mlx5dr_action_create_generic(ctx, flags, MLX5DR_ACTION_TYP_MODIFY_HDR);
1529 	if (!action)
1530 		return NULL;
1531 
1532 	if (mlx5dr_action_is_root_flags(flags)) {
1533 		if (log_bulk_size) {
1534 			DR_LOG(ERR, "Bulk modify-header not supported over root");
1535 			rte_errno = ENOTSUP;
1536 			goto free_action;
1537 		}
1538 		ret = mlx5dr_action_create_modify_header_root(action, pattern_sz, pattern);
1539 		if (ret)
1540 			goto free_action;
1541 
1542 		return action;
1543 	}
1544 
1545 	if (!mlx5dr_action_is_hws_flags(flags) ||
1546 	    ((flags & MLX5DR_ACTION_FLAG_SHARED) && log_bulk_size)) {
1547 		DR_LOG(ERR, "Flags don't fit hws (flags: %x0x, log_bulk_size: %d)\n",
1548 			flags, log_bulk_size);
1549 		rte_errno = EINVAL;
1550 		goto free_action;
1551 	}
1552 
1553 	if (pattern_sz / MLX5DR_MODIFY_ACTION_SIZE == 1) {
1554 		/* Optimize single modiy action to be used inline */
1555 		action->modify_header.single_action = pattern[0];
1556 		action->modify_header.num_of_actions = 1;
1557 		action->modify_header.single_action_type =
1558 			MLX5_GET(set_action_in, pattern, action_type);
1559 	} else {
1560 		/* Use multi action pattern and argument */
1561 		ret = mlx5dr_pat_arg_create_modify_header(ctx, action, pattern_sz,
1562 							  pattern, log_bulk_size);
1563 		if (ret) {
1564 			DR_LOG(ERR, "Failed allocating modify-header\n");
1565 			goto free_action;
1566 		}
1567 	}
1568 
1569 	ret = mlx5dr_action_create_stcs(action, NULL);
1570 	if (ret)
1571 		goto free_mh_obj;
1572 
1573 	return action;
1574 
1575 free_mh_obj:
1576 	if (action->modify_header.num_of_actions > 1)
1577 		mlx5dr_pat_arg_destroy_modify_header(ctx, action);
1578 free_action:
1579 	simple_free(action);
1580 	return NULL;
1581 }
1582 
1583 static void mlx5dr_action_destroy_hws(struct mlx5dr_action *action)
1584 {
1585 	switch (action->type) {
1586 	case MLX5DR_ACTION_TYP_TIR:
1587 	case MLX5DR_ACTION_TYP_MISS:
1588 	case MLX5DR_ACTION_TYP_TAG:
1589 	case MLX5DR_ACTION_TYP_DROP:
1590 	case MLX5DR_ACTION_TYP_CTR:
1591 	case MLX5DR_ACTION_TYP_FT:
1592 	case MLX5DR_ACTION_TYP_TNL_L2_TO_L2:
1593 	case MLX5DR_ACTION_TYP_ASO_METER:
1594 	case MLX5DR_ACTION_TYP_ASO_CT:
1595 	case MLX5DR_ACTION_TYP_PUSH_VLAN:
1596 		mlx5dr_action_destroy_stcs(action);
1597 		break;
1598 	case MLX5DR_ACTION_TYP_POP_VLAN:
1599 		mlx5dr_action_destroy_stcs(action);
1600 		mlx5dr_action_put_shared_stc(action, MLX5DR_CONTEXT_SHARED_STC_POP);
1601 		break;
1602 	case MLX5DR_ACTION_TYP_TNL_L3_TO_L2:
1603 	case MLX5DR_ACTION_TYP_MODIFY_HDR:
1604 		mlx5dr_action_destroy_stcs(action);
1605 		if (action->modify_header.num_of_actions > 1)
1606 			mlx5dr_pat_arg_destroy_modify_header(action->ctx, action);
1607 		break;
1608 	case MLX5DR_ACTION_TYP_L2_TO_TNL_L3:
1609 		mlx5dr_action_destroy_stcs(action);
1610 		mlx5dr_action_put_shared_stc(action, MLX5DR_CONTEXT_SHARED_STC_DECAP);
1611 		mlx5dr_cmd_destroy_obj(action->reformat.arg_obj);
1612 		break;
1613 	case MLX5DR_ACTION_TYP_L2_TO_TNL_L2:
1614 		mlx5dr_action_destroy_stcs(action);
1615 		mlx5dr_cmd_destroy_obj(action->reformat.arg_obj);
1616 		break;
1617 	}
1618 }
1619 
1620 static void mlx5dr_action_destroy_root(struct mlx5dr_action *action)
1621 {
1622 	switch (action->type) {
1623 	case MLX5DR_ACTION_TYP_TNL_L2_TO_L2:
1624 	case MLX5DR_ACTION_TYP_L2_TO_TNL_L2:
1625 	case MLX5DR_ACTION_TYP_TNL_L3_TO_L2:
1626 	case MLX5DR_ACTION_TYP_L2_TO_TNL_L3:
1627 	case MLX5DR_ACTION_TYP_MODIFY_HDR:
1628 		ibv_destroy_flow_action(action->flow_action);
1629 		break;
1630 	}
1631 }
1632 
1633 int mlx5dr_action_destroy(struct mlx5dr_action *action)
1634 {
1635 	if (mlx5dr_action_is_root_flags(action->flags))
1636 		mlx5dr_action_destroy_root(action);
1637 	else
1638 		mlx5dr_action_destroy_hws(action);
1639 
1640 	simple_free(action);
1641 	return 0;
1642 }
1643 
1644 /* Called under pthread_spin_lock(&ctx->ctrl_lock) */
1645 int mlx5dr_action_get_default_stc(struct mlx5dr_context *ctx,
1646 				  uint8_t tbl_type)
1647 {
1648 	struct mlx5dr_cmd_stc_modify_attr stc_attr = {0};
1649 	struct mlx5dr_action_default_stc *default_stc;
1650 	int ret;
1651 
1652 	if (ctx->common_res[tbl_type].default_stc) {
1653 		ctx->common_res[tbl_type].default_stc->refcount++;
1654 		return 0;
1655 	}
1656 
1657 	default_stc = simple_calloc(1, sizeof(*default_stc));
1658 	if (!default_stc) {
1659 		DR_LOG(ERR, "Failed to allocate memory for default STCs");
1660 		rte_errno = ENOMEM;
1661 		return rte_errno;
1662 	}
1663 
1664 	stc_attr.action_type = MLX5_IFC_STC_ACTION_TYPE_NOP;
1665 	stc_attr.action_offset = MLX5DR_ACTION_OFFSET_DW0;
1666 	ret = mlx5dr_action_alloc_single_stc(ctx, &stc_attr, tbl_type,
1667 					     &default_stc->nop_ctr);
1668 	if (ret) {
1669 		DR_LOG(ERR, "Failed to allocate default counter STC");
1670 		goto free_default_stc;
1671 	}
1672 
1673 	stc_attr.action_offset = MLX5DR_ACTION_OFFSET_DW5;
1674 	ret = mlx5dr_action_alloc_single_stc(ctx, &stc_attr, tbl_type,
1675 					     &default_stc->nop_dw5);
1676 	if (ret) {
1677 		DR_LOG(ERR, "Failed to allocate default NOP DW5 STC");
1678 		goto free_nop_ctr;
1679 	}
1680 
1681 	stc_attr.action_offset = MLX5DR_ACTION_OFFSET_DW6;
1682 	ret = mlx5dr_action_alloc_single_stc(ctx, &stc_attr, tbl_type,
1683 					     &default_stc->nop_dw6);
1684 	if (ret) {
1685 		DR_LOG(ERR, "Failed to allocate default NOP DW6 STC");
1686 		goto free_nop_dw5;
1687 	}
1688 
1689 	stc_attr.action_offset = MLX5DR_ACTION_OFFSET_DW7;
1690 	ret = mlx5dr_action_alloc_single_stc(ctx, &stc_attr, tbl_type,
1691 					     &default_stc->nop_dw7);
1692 	if (ret) {
1693 		DR_LOG(ERR, "Failed to allocate default NOP DW7 STC");
1694 		goto free_nop_dw6;
1695 	}
1696 
1697 	stc_attr.action_type = MLX5_IFC_STC_ACTION_TYPE_ALLOW;
1698 	stc_attr.action_offset = MLX5DR_ACTION_OFFSET_HIT;
1699 	ret = mlx5dr_action_alloc_single_stc(ctx, &stc_attr, tbl_type,
1700 					     &default_stc->default_hit);
1701 	if (ret) {
1702 		DR_LOG(ERR, "Failed to allocate default allow STC");
1703 		goto free_nop_dw7;
1704 	}
1705 
1706 	ctx->common_res[tbl_type].default_stc = default_stc;
1707 	ctx->common_res[tbl_type].default_stc->refcount++;
1708 
1709 	return 0;
1710 
1711 free_nop_dw7:
1712 	mlx5dr_action_free_single_stc(ctx, tbl_type, &default_stc->nop_dw7);
1713 free_nop_dw6:
1714 	mlx5dr_action_free_single_stc(ctx, tbl_type, &default_stc->nop_dw6);
1715 free_nop_dw5:
1716 	mlx5dr_action_free_single_stc(ctx, tbl_type, &default_stc->nop_dw5);
1717 free_nop_ctr:
1718 	mlx5dr_action_free_single_stc(ctx, tbl_type, &default_stc->nop_ctr);
1719 free_default_stc:
1720 	simple_free(default_stc);
1721 	return rte_errno;
1722 }
1723 
1724 void mlx5dr_action_put_default_stc(struct mlx5dr_context *ctx,
1725 				   uint8_t tbl_type)
1726 {
1727 	struct mlx5dr_action_default_stc *default_stc;
1728 
1729 	default_stc = ctx->common_res[tbl_type].default_stc;
1730 
1731 	default_stc = ctx->common_res[tbl_type].default_stc;
1732 	if (--default_stc->refcount)
1733 		return;
1734 
1735 	mlx5dr_action_free_single_stc(ctx, tbl_type, &default_stc->default_hit);
1736 	mlx5dr_action_free_single_stc(ctx, tbl_type, &default_stc->nop_dw7);
1737 	mlx5dr_action_free_single_stc(ctx, tbl_type, &default_stc->nop_dw6);
1738 	mlx5dr_action_free_single_stc(ctx, tbl_type, &default_stc->nop_dw5);
1739 	mlx5dr_action_free_single_stc(ctx, tbl_type, &default_stc->nop_ctr);
1740 	simple_free(default_stc);
1741 	ctx->common_res[tbl_type].default_stc = NULL;
1742 }
1743 
1744 static void mlx5dr_action_modify_write(struct mlx5dr_send_engine *queue,
1745 				       uint32_t arg_idx,
1746 				       uint8_t *arg_data,
1747 				       uint16_t num_of_actions)
1748 {
1749 	mlx5dr_arg_write(queue, NULL, arg_idx, arg_data,
1750 			 num_of_actions * MLX5DR_MODIFY_ACTION_SIZE);
1751 }
1752 
1753 void
1754 mlx5dr_action_prepare_decap_l3_data(uint8_t *src, uint8_t *dst,
1755 				    uint16_t num_of_actions)
1756 {
1757 	uint8_t *e_src;
1758 	int i;
1759 
1760 	/* num_of_actions = remove l3l2 + 4/5 inserts + remove extra 2 bytes
1761 	 * copy from end of src to the start of dst.
1762 	 * move to the end, 2 is the leftover from 14B or 18B
1763 	 */
1764 	if (num_of_actions == DECAP_L3_NUM_ACTIONS_W_NO_VLAN)
1765 		e_src = src + MLX5DR_ACTION_HDR_LEN_L2;
1766 	else
1767 		e_src = src + MLX5DR_ACTION_HDR_LEN_L2_W_VLAN;
1768 
1769 	/* Move dst over the first remove action + zero data */
1770 	dst += MLX5DR_ACTION_DOUBLE_SIZE;
1771 	/* Move dst over the first insert ctrl action */
1772 	dst += MLX5DR_ACTION_DOUBLE_SIZE / 2;
1773 	/* Actions:
1774 	 * no vlan: r_h-insert_4b-insert_4b-insert_4b-insert_4b-remove_2b.
1775 	 * with vlan: r_h-insert_4b-insert_4b-insert_4b-insert_4b-insert_4b-remove_2b.
1776 	 * the loop is without the last insertion.
1777 	 */
1778 	for (i = 0; i < num_of_actions - 3; i++) {
1779 		e_src -= MLX5DR_ACTION_INLINE_DATA_SIZE;
1780 		memcpy(dst, e_src, MLX5DR_ACTION_INLINE_DATA_SIZE); /* data */
1781 		dst += MLX5DR_ACTION_DOUBLE_SIZE;
1782 	}
1783 	/* Copy the last 2 bytes after a gap of 2 bytes which will be removed */
1784 	e_src -= MLX5DR_ACTION_INLINE_DATA_SIZE / 2;
1785 	dst += MLX5DR_ACTION_INLINE_DATA_SIZE / 2;
1786 	memcpy(dst, e_src, 2);
1787 }
1788 
1789 static struct mlx5dr_actions_wqe_setter *
1790 mlx5dr_action_setter_find_first(struct mlx5dr_actions_wqe_setter *setter,
1791 				uint8_t req_flags)
1792 {
1793 	/* Use a new setter if requested flags are taken */
1794 	while (setter->flags & req_flags)
1795 		setter++;
1796 
1797 	/* Use current setter in required flags are not used */
1798 	return setter;
1799 }
1800 
1801 static void
1802 mlx5dr_action_apply_stc(struct mlx5dr_actions_apply_data *apply,
1803 			enum mlx5dr_action_stc_idx stc_idx,
1804 			uint8_t action_idx)
1805 {
1806 	struct mlx5dr_action *action = apply->rule_action[action_idx].action;
1807 
1808 	apply->wqe_ctrl->stc_ix[stc_idx] =
1809 		htobe32(action->stc[apply->tbl_type].offset);
1810 }
1811 
1812 static void
1813 mlx5dr_action_setter_push_vlan(struct mlx5dr_actions_apply_data *apply,
1814 			       struct mlx5dr_actions_wqe_setter *setter)
1815 {
1816 	struct mlx5dr_rule_action *rule_action;
1817 
1818 	rule_action = &apply->rule_action[setter->idx_double];
1819 	apply->wqe_data[MLX5DR_ACTION_OFFSET_DW6] = 0;
1820 	apply->wqe_data[MLX5DR_ACTION_OFFSET_DW7] = rule_action->push_vlan.vlan_hdr;
1821 
1822 	mlx5dr_action_apply_stc(apply, MLX5DR_ACTION_STC_IDX_DW6, setter->idx_double);
1823 	apply->wqe_ctrl->stc_ix[MLX5DR_ACTION_STC_IDX_DW7] = 0;
1824 }
1825 
1826 static void
1827 mlx5dr_action_setter_modify_header(struct mlx5dr_actions_apply_data *apply,
1828 				   struct mlx5dr_actions_wqe_setter *setter)
1829 {
1830 	struct mlx5dr_rule_action *rule_action;
1831 	struct mlx5dr_action *action;
1832 	uint32_t arg_sz, arg_idx;
1833 	uint8_t *single_action;
1834 
1835 	rule_action = &apply->rule_action[setter->idx_double];
1836 	action = rule_action->action;
1837 	mlx5dr_action_apply_stc(apply, MLX5DR_ACTION_STC_IDX_DW6, setter->idx_double);
1838 	apply->wqe_ctrl->stc_ix[MLX5DR_ACTION_STC_IDX_DW7] = 0;
1839 
1840 	apply->wqe_data[MLX5DR_ACTION_OFFSET_DW6] = 0;
1841 
1842 	if (action->modify_header.num_of_actions == 1) {
1843 		if (action->modify_header.single_action_type ==
1844 		    MLX5_MODIFICATION_TYPE_COPY) {
1845 			apply->wqe_data[MLX5DR_ACTION_OFFSET_DW7] = 0;
1846 			return;
1847 		}
1848 
1849 		if (action->flags & MLX5DR_ACTION_FLAG_SHARED)
1850 			single_action = (uint8_t *)&action->modify_header.single_action;
1851 		else
1852 			single_action = rule_action->modify_header.data;
1853 
1854 		apply->wqe_data[MLX5DR_ACTION_OFFSET_DW7] =
1855 			*(__be32 *)MLX5_ADDR_OF(set_action_in, single_action, data);
1856 	} else {
1857 		/* Argument offset multiple with number of args per these actions */
1858 		arg_sz = mlx5dr_arg_get_arg_size(action->modify_header.num_of_actions);
1859 		arg_idx = rule_action->modify_header.offset * arg_sz;
1860 
1861 		apply->wqe_data[MLX5DR_ACTION_OFFSET_DW7] = htobe32(arg_idx);
1862 
1863 		if (!(action->flags & MLX5DR_ACTION_FLAG_SHARED)) {
1864 			apply->require_dep = 1;
1865 			mlx5dr_action_modify_write(apply->queue,
1866 						   action->modify_header.arg_obj->id + arg_idx,
1867 						   rule_action->modify_header.data,
1868 						   action->modify_header.num_of_actions);
1869 		}
1870 	}
1871 }
1872 
1873 static void
1874 mlx5dr_action_setter_insert_ptr(struct mlx5dr_actions_apply_data *apply,
1875 				struct mlx5dr_actions_wqe_setter *setter)
1876 {
1877 	struct mlx5dr_rule_action *rule_action;
1878 	uint32_t arg_idx, arg_sz;
1879 
1880 	rule_action = &apply->rule_action[setter->idx_double];
1881 
1882 	/* Argument offset multiple on args required for header size */
1883 	arg_sz = mlx5dr_arg_data_size_to_arg_size(rule_action->action->reformat.header_size);
1884 	arg_idx = rule_action->reformat.offset * arg_sz;
1885 
1886 	apply->wqe_data[MLX5DR_ACTION_OFFSET_DW6] = 0;
1887 	apply->wqe_data[MLX5DR_ACTION_OFFSET_DW7] = htobe32(arg_idx);
1888 
1889 	mlx5dr_action_apply_stc(apply, MLX5DR_ACTION_STC_IDX_DW6, setter->idx_double);
1890 	apply->wqe_ctrl->stc_ix[MLX5DR_ACTION_STC_IDX_DW7] = 0;
1891 
1892 	if (!(rule_action->action->flags & MLX5DR_ACTION_FLAG_SHARED)) {
1893 		apply->require_dep = 1;
1894 		mlx5dr_arg_write(apply->queue, NULL,
1895 				 rule_action->action->reformat.arg_obj->id + arg_idx,
1896 				 rule_action->reformat.data,
1897 				 rule_action->action->reformat.header_size);
1898 	}
1899 }
1900 
1901 static void
1902 mlx5dr_action_setter_tnl_l3_to_l2(struct mlx5dr_actions_apply_data *apply,
1903 				  struct mlx5dr_actions_wqe_setter *setter)
1904 {
1905 	struct mlx5dr_rule_action *rule_action;
1906 	struct mlx5dr_action *action;
1907 	uint32_t arg_sz, arg_idx;
1908 
1909 	rule_action = &apply->rule_action[setter->idx_double];
1910 	action = rule_action->action;
1911 
1912 	/* Argument offset multiple on args required for num of actions */
1913 	arg_sz = mlx5dr_arg_get_arg_size(action->modify_header.num_of_actions);
1914 	arg_idx = rule_action->reformat.offset * arg_sz;
1915 
1916 	apply->wqe_data[MLX5DR_ACTION_OFFSET_DW6] = 0;
1917 	apply->wqe_data[MLX5DR_ACTION_OFFSET_DW7] = htobe32(arg_idx);
1918 
1919 	mlx5dr_action_apply_stc(apply, MLX5DR_ACTION_STC_IDX_DW6, setter->idx_double);
1920 	apply->wqe_ctrl->stc_ix[MLX5DR_ACTION_STC_IDX_DW7] = 0;
1921 
1922 	if (!(action->flags & MLX5DR_ACTION_FLAG_SHARED)) {
1923 		apply->require_dep = 1;
1924 		mlx5dr_arg_decapl3_write(apply->queue,
1925 					 action->modify_header.arg_obj->id + arg_idx,
1926 					 rule_action->reformat.data,
1927 					 action->modify_header.num_of_actions);
1928 	}
1929 }
1930 
1931 static void
1932 mlx5dr_action_setter_aso(struct mlx5dr_actions_apply_data *apply,
1933 			 struct mlx5dr_actions_wqe_setter *setter)
1934 {
1935 	struct mlx5dr_rule_action *rule_action;
1936 	uint32_t exe_aso_ctrl;
1937 	uint32_t offset;
1938 
1939 	rule_action = &apply->rule_action[setter->idx_double];
1940 
1941 	switch (rule_action->action->type) {
1942 	case MLX5DR_ACTION_TYP_ASO_METER:
1943 		/* exe_aso_ctrl format:
1944 		 * [STC only and reserved bits 29b][init_color 2b][meter_id 1b]
1945 		 */
1946 		offset = rule_action->aso_meter.offset / MLX5_ASO_METER_NUM_PER_OBJ;
1947 		exe_aso_ctrl = rule_action->aso_meter.offset % MLX5_ASO_METER_NUM_PER_OBJ;
1948 		exe_aso_ctrl |= rule_action->aso_meter.init_color <<
1949 				MLX5DR_ACTION_METER_INIT_COLOR_OFFSET;
1950 		break;
1951 	case MLX5DR_ACTION_TYP_ASO_CT:
1952 		/* exe_aso_ctrl CT format:
1953 		 * [STC only and reserved bits 31b][direction 1b]
1954 		 */
1955 		offset = rule_action->aso_ct.offset / MLX5_ASO_CT_NUM_PER_OBJ;
1956 		exe_aso_ctrl = rule_action->aso_ct.direction;
1957 		break;
1958 	default:
1959 		DR_LOG(ERR, "Unsupported ASO action type: %d", rule_action->action->type);
1960 		rte_errno = ENOTSUP;
1961 		return;
1962 	}
1963 
1964 	/* aso_object_offset format: [24B] */
1965 	apply->wqe_data[MLX5DR_ACTION_OFFSET_DW6] = htobe32(offset);
1966 	apply->wqe_data[MLX5DR_ACTION_OFFSET_DW7] = htobe32(exe_aso_ctrl);
1967 
1968 	mlx5dr_action_apply_stc(apply, MLX5DR_ACTION_STC_IDX_DW6, setter->idx_double);
1969 	apply->wqe_ctrl->stc_ix[MLX5DR_ACTION_STC_IDX_DW7] = 0;
1970 }
1971 
1972 static void
1973 mlx5dr_action_setter_tag(struct mlx5dr_actions_apply_data *apply,
1974 			 struct mlx5dr_actions_wqe_setter *setter)
1975 {
1976 	struct mlx5dr_rule_action *rule_action;
1977 
1978 	rule_action = &apply->rule_action[setter->idx_single];
1979 	apply->wqe_data[MLX5DR_ACTION_OFFSET_DW5] = htobe32(rule_action->tag.value);
1980 	mlx5dr_action_apply_stc(apply, MLX5DR_ACTION_STC_IDX_DW5, setter->idx_single);
1981 }
1982 
1983 static void
1984 mlx5dr_action_setter_ctrl_ctr(struct mlx5dr_actions_apply_data *apply,
1985 			      struct mlx5dr_actions_wqe_setter *setter)
1986 {
1987 	struct mlx5dr_rule_action *rule_action;
1988 
1989 	rule_action = &apply->rule_action[setter->idx_ctr];
1990 	apply->wqe_data[MLX5DR_ACTION_OFFSET_DW0] = htobe32(rule_action->counter.offset);
1991 	mlx5dr_action_apply_stc(apply, MLX5DR_ACTION_STC_IDX_CTRL, setter->idx_ctr);
1992 }
1993 
1994 static void
1995 mlx5dr_action_setter_single(struct mlx5dr_actions_apply_data *apply,
1996 			    struct mlx5dr_actions_wqe_setter *setter)
1997 {
1998 	apply->wqe_data[MLX5DR_ACTION_OFFSET_DW5] = 0;
1999 	mlx5dr_action_apply_stc(apply, MLX5DR_ACTION_STC_IDX_DW5, setter->idx_single);
2000 }
2001 
2002 static void
2003 mlx5dr_action_setter_single_double_pop(struct mlx5dr_actions_apply_data *apply,
2004 				       __rte_unused struct mlx5dr_actions_wqe_setter *setter)
2005 {
2006 	apply->wqe_data[MLX5DR_ACTION_OFFSET_DW5] = 0;
2007 	apply->wqe_ctrl->stc_ix[MLX5DR_ACTION_STC_IDX_DW5] =
2008 		htobe32(mlx5dr_action_get_shared_stc_offset(apply->common_res,
2009 						    MLX5DR_CONTEXT_SHARED_STC_POP));
2010 }
2011 
2012 static void
2013 mlx5dr_action_setter_hit(struct mlx5dr_actions_apply_data *apply,
2014 			 struct mlx5dr_actions_wqe_setter *setter)
2015 {
2016 	apply->wqe_data[MLX5DR_ACTION_OFFSET_HIT_LSB] = 0;
2017 	mlx5dr_action_apply_stc(apply, MLX5DR_ACTION_STC_IDX_HIT, setter->idx_hit);
2018 }
2019 
2020 static void
2021 mlx5dr_action_setter_default_hit(struct mlx5dr_actions_apply_data *apply,
2022 				 __rte_unused struct mlx5dr_actions_wqe_setter *setter)
2023 {
2024 	apply->wqe_data[MLX5DR_ACTION_OFFSET_HIT_LSB] = 0;
2025 	apply->wqe_ctrl->stc_ix[MLX5DR_ACTION_STC_IDX_HIT] =
2026 		htobe32(apply->common_res->default_stc->default_hit.offset);
2027 }
2028 
2029 static void
2030 mlx5dr_action_setter_hit_next_action(struct mlx5dr_actions_apply_data *apply,
2031 				     __rte_unused struct mlx5dr_actions_wqe_setter *setter)
2032 {
2033 	apply->wqe_data[MLX5DR_ACTION_OFFSET_HIT_LSB] = htobe32(apply->next_direct_idx << 6);
2034 	apply->wqe_ctrl->stc_ix[MLX5DR_ACTION_STC_IDX_HIT] = htobe32(apply->jump_to_action_stc);
2035 }
2036 
2037 static void
2038 mlx5dr_action_setter_common_decap(struct mlx5dr_actions_apply_data *apply,
2039 				  __rte_unused struct mlx5dr_actions_wqe_setter *setter)
2040 {
2041 	apply->wqe_data[MLX5DR_ACTION_OFFSET_DW5] = 0;
2042 	apply->wqe_ctrl->stc_ix[MLX5DR_ACTION_STC_IDX_DW5] =
2043 		htobe32(mlx5dr_action_get_shared_stc_offset(apply->common_res,
2044 							    MLX5DR_CONTEXT_SHARED_STC_DECAP));
2045 }
2046 
2047 int mlx5dr_action_template_process(struct mlx5dr_action_template *at)
2048 {
2049 	struct mlx5dr_actions_wqe_setter *start_setter = at->setters + 1;
2050 	enum mlx5dr_action_type *action_type = at->action_type_arr;
2051 	struct mlx5dr_actions_wqe_setter *setter = at->setters;
2052 	struct mlx5dr_actions_wqe_setter *pop_setter = NULL;
2053 	struct mlx5dr_actions_wqe_setter *last_setter;
2054 	int i;
2055 
2056 	/* Note: Given action combination must be valid */
2057 
2058 	/* Check if action were already processed */
2059 	if (at->num_of_action_stes)
2060 		return 0;
2061 
2062 	for (i = 0; i < MLX5DR_ACTION_MAX_STE; i++)
2063 		setter[i].set_hit = &mlx5dr_action_setter_hit_next_action;
2064 
2065 	/* The same action template setters can be used with jumbo or match
2066 	 * STE, to support both cases we reseve the first setter for cases
2067 	 * with jumbo STE to allow jump to the first action STE.
2068 	 * This extra setter can be reduced in some cases on rule creation.
2069 	 */
2070 	setter = start_setter;
2071 	last_setter = start_setter;
2072 
2073 	for (i = 0; i < at->num_actions; i++) {
2074 		switch (action_type[i]) {
2075 		case MLX5DR_ACTION_TYP_DROP:
2076 		case MLX5DR_ACTION_TYP_TIR:
2077 		case MLX5DR_ACTION_TYP_FT:
2078 		case MLX5DR_ACTION_TYP_VPORT:
2079 		case MLX5DR_ACTION_TYP_MISS:
2080 			/* Hit action */
2081 			last_setter->flags |= ASF_HIT;
2082 			last_setter->set_hit = &mlx5dr_action_setter_hit;
2083 			last_setter->idx_hit = i;
2084 			break;
2085 
2086 		case MLX5DR_ACTION_TYP_POP_VLAN:
2087 			/* Single remove header to header */
2088 			if (pop_setter) {
2089 				/* We have 2 pops, use the shared */
2090 				pop_setter->set_single = &mlx5dr_action_setter_single_double_pop;
2091 				break;
2092 			}
2093 			setter = mlx5dr_action_setter_find_first(last_setter, ASF_SINGLE1 | ASF_MODIFY);
2094 			setter->flags |= ASF_SINGLE1 | ASF_REPARSE | ASF_REMOVE;
2095 			setter->set_single = &mlx5dr_action_setter_single;
2096 			setter->idx_single = i;
2097 			pop_setter = setter;
2098 			break;
2099 
2100 		case MLX5DR_ACTION_TYP_PUSH_VLAN:
2101 			/* Double insert inline */
2102 			setter = mlx5dr_action_setter_find_first(last_setter, ASF_DOUBLE | ASF_REMOVE);
2103 			setter->flags |= ASF_DOUBLE | ASF_REPARSE | ASF_MODIFY;
2104 			setter->set_double = &mlx5dr_action_setter_push_vlan;
2105 			setter->idx_double = i;
2106 			break;
2107 
2108 		case MLX5DR_ACTION_TYP_MODIFY_HDR:
2109 			/* Double modify header list */
2110 			setter = mlx5dr_action_setter_find_first(last_setter, ASF_DOUBLE | ASF_REMOVE);
2111 			setter->flags |= ASF_DOUBLE | ASF_MODIFY | ASF_REPARSE;
2112 			setter->set_double = &mlx5dr_action_setter_modify_header;
2113 			setter->idx_double = i;
2114 			break;
2115 
2116 		case MLX5DR_ACTION_TYP_ASO_METER:
2117 		case MLX5DR_ACTION_TYP_ASO_CT:
2118 			setter = mlx5dr_action_setter_find_first(last_setter, ASF_DOUBLE);
2119 			setter->flags |= ASF_DOUBLE;
2120 			setter->set_double = &mlx5dr_action_setter_aso;
2121 			setter->idx_double = i;
2122 			break;
2123 
2124 		case MLX5DR_ACTION_TYP_TNL_L2_TO_L2:
2125 			/* Single remove header to header */
2126 			setter = mlx5dr_action_setter_find_first(last_setter, ASF_SINGLE1 | ASF_MODIFY);
2127 			setter->flags |= ASF_SINGLE1 | ASF_REMOVE | ASF_REPARSE;
2128 			setter->set_single = &mlx5dr_action_setter_single;
2129 			setter->idx_single = i;
2130 			break;
2131 
2132 		case MLX5DR_ACTION_TYP_L2_TO_TNL_L2:
2133 			/* Double insert header with pointer */
2134 			setter = mlx5dr_action_setter_find_first(last_setter, ASF_DOUBLE);
2135 			setter->flags |= ASF_DOUBLE | ASF_REPARSE;
2136 			setter->set_double = &mlx5dr_action_setter_insert_ptr;
2137 			setter->idx_double = i;
2138 			break;
2139 
2140 		case MLX5DR_ACTION_TYP_L2_TO_TNL_L3:
2141 			/* Single remove + Double insert header with pointer */
2142 			setter = mlx5dr_action_setter_find_first(last_setter, ASF_SINGLE1 | ASF_DOUBLE);
2143 			setter->flags |= ASF_SINGLE1 | ASF_DOUBLE | ASF_REPARSE | ASF_REMOVE;
2144 			setter->set_double = &mlx5dr_action_setter_insert_ptr;
2145 			setter->idx_double = i;
2146 			setter->set_single = &mlx5dr_action_setter_common_decap;
2147 			setter->idx_single = i;
2148 			break;
2149 
2150 		case MLX5DR_ACTION_TYP_TNL_L3_TO_L2:
2151 			/* Double modify header list with remove and push inline */
2152 			setter = mlx5dr_action_setter_find_first(last_setter,
2153 								 ASF_DOUBLE | ASF_REMOVE);
2154 			setter->flags |= ASF_DOUBLE | ASF_MODIFY | ASF_REPARSE;
2155 			setter->set_double = &mlx5dr_action_setter_tnl_l3_to_l2;
2156 			setter->idx_double = i;
2157 			break;
2158 
2159 		case MLX5DR_ACTION_TYP_TAG:
2160 			/* Single TAG action, search for any room from the start */
2161 			setter = mlx5dr_action_setter_find_first(start_setter, ASF_SINGLE1);
2162 			setter->flags |= ASF_SINGLE1;
2163 			setter->set_single = &mlx5dr_action_setter_tag;
2164 			setter->idx_single = i;
2165 			break;
2166 
2167 		case MLX5DR_ACTION_TYP_CTR:
2168 			/* Control counter action
2169 			 * TODO: Current counter executed first. Support is needed
2170 			 *	 for single ation counter action which is done last.
2171 			 *	 Example: Decap + CTR
2172 			 */
2173 			setter = mlx5dr_action_setter_find_first(start_setter, ASF_CTR);
2174 			setter->flags |= ASF_CTR;
2175 			setter->set_ctr = &mlx5dr_action_setter_ctrl_ctr;
2176 			setter->idx_ctr = i;
2177 			break;
2178 
2179 		default:
2180 			DR_LOG(ERR, "Unsupported action type: %d", action_type[i]);
2181 			rte_errno = ENOTSUP;
2182 			assert(false);
2183 			return rte_errno;
2184 		}
2185 
2186 		last_setter = RTE_MAX(setter, last_setter);
2187 	}
2188 
2189 	/* Set default hit on the last STE if no hit action provided */
2190 	if (!(last_setter->flags & ASF_HIT))
2191 		last_setter->set_hit = &mlx5dr_action_setter_default_hit;
2192 
2193 	at->num_of_action_stes = last_setter - start_setter + 1;
2194 
2195 	/* Check if action template doesn't require any action DWs */
2196 	at->only_term = (at->num_of_action_stes == 1) &&
2197 		!(last_setter->flags & ~(ASF_CTR | ASF_HIT));
2198 
2199 	return 0;
2200 }
2201 
2202 struct mlx5dr_action_template *
2203 mlx5dr_action_template_create(const enum mlx5dr_action_type action_type[])
2204 {
2205 	struct mlx5dr_action_template *at;
2206 	uint8_t num_actions = 0;
2207 	int i;
2208 
2209 	at = simple_calloc(1, sizeof(*at));
2210 	if (!at) {
2211 		DR_LOG(ERR, "Failed to allocate action template");
2212 		rte_errno = ENOMEM;
2213 		return NULL;
2214 	}
2215 
2216 	while (action_type[num_actions++] != MLX5DR_ACTION_TYP_LAST)
2217 		;
2218 
2219 	at->num_actions = num_actions - 1;
2220 	at->action_type_arr = simple_calloc(num_actions, sizeof(*action_type));
2221 	if (!at->action_type_arr) {
2222 		DR_LOG(ERR, "Failed to allocate action type array");
2223 		rte_errno = ENOMEM;
2224 		goto free_at;
2225 	}
2226 
2227 	for (i = 0; i < num_actions; i++)
2228 		at->action_type_arr[i] = action_type[i];
2229 
2230 	return at;
2231 
2232 free_at:
2233 	simple_free(at);
2234 	return NULL;
2235 }
2236 
2237 int mlx5dr_action_template_destroy(struct mlx5dr_action_template *at)
2238 {
2239 	simple_free(at->action_type_arr);
2240 	simple_free(at);
2241 	return 0;
2242 }
2243