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