xref: /dpdk/drivers/net/mlx5/hws/mlx5dr_action.c (revision 21a66096bb44a4468353782c36fc85913520dc6c)
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 /* Header removal size limited to 128B (64 words) */
11 #define MLX5DR_ACTION_REMOVE_HEADER_MAX_SIZE 128
12 
13 /* This is the maximum allowed action order for each table type:
14  *	 TX: POP_VLAN, CTR, ASO_METER, AS_CT, PUSH_VLAN, MODIFY, ENCAP, Term
15  *	 RX: TAG, DECAP, POP_VLAN, CTR, ASO_METER, ASO_CT, PUSH_VLAN, MODIFY,
16  *	     ENCAP, Term
17  *	FDB: DECAP, POP_VLAN, CTR, ASO_METER, ASO_CT, PUSH_VLAN, MODIFY,
18  *	     ENCAP, Term
19  */
20 static const uint32_t action_order_arr[MLX5DR_TABLE_TYPE_MAX][MLX5DR_ACTION_TYP_MAX] = {
21 	[MLX5DR_TABLE_TYPE_NIC_RX] = {
22 		BIT(MLX5DR_ACTION_TYP_TAG),
23 		BIT(MLX5DR_ACTION_TYP_REMOVE_HEADER) |
24 		BIT(MLX5DR_ACTION_TYP_REFORMAT_TNL_L2_TO_L2) |
25 		BIT(MLX5DR_ACTION_TYP_REFORMAT_TNL_L3_TO_L2) |
26 		BIT(MLX5DR_ACTION_TYP_POP_IPV6_ROUTE_EXT),
27 		BIT(MLX5DR_ACTION_TYP_POP_VLAN),
28 		BIT(MLX5DR_ACTION_TYP_POP_VLAN),
29 		BIT(MLX5DR_ACTION_TYP_CTR),
30 		BIT(MLX5DR_ACTION_TYP_ASO_METER),
31 		BIT(MLX5DR_ACTION_TYP_ASO_CT),
32 		BIT(MLX5DR_ACTION_TYP_PUSH_VLAN),
33 		BIT(MLX5DR_ACTION_TYP_PUSH_VLAN),
34 		BIT(MLX5DR_ACTION_TYP_NAT64),
35 		BIT(MLX5DR_ACTION_TYP_MODIFY_HDR),
36 		BIT(MLX5DR_ACTION_TYP_INSERT_HEADER) |
37 		BIT(MLX5DR_ACTION_TYP_PUSH_IPV6_ROUTE_EXT) |
38 		BIT(MLX5DR_ACTION_TYP_REFORMAT_L2_TO_TNL_L2) |
39 		BIT(MLX5DR_ACTION_TYP_REFORMAT_L2_TO_TNL_L3),
40 		BIT(MLX5DR_ACTION_TYP_TBL) |
41 		BIT(MLX5DR_ACTION_TYP_MISS) |
42 		BIT(MLX5DR_ACTION_TYP_TIR) |
43 		BIT(MLX5DR_ACTION_TYP_DROP) |
44 		BIT(MLX5DR_ACTION_TYP_DEST_ROOT) |
45 		BIT(MLX5DR_ACTION_TYP_DEST_ARRAY) |
46 		BIT(MLX5DR_ACTION_TYP_JUMP_TO_MATCHER),
47 		BIT(MLX5DR_ACTION_TYP_LAST),
48 	},
49 	[MLX5DR_TABLE_TYPE_NIC_TX] = {
50 		BIT(MLX5DR_ACTION_TYP_POP_VLAN),
51 		BIT(MLX5DR_ACTION_TYP_POP_VLAN),
52 		BIT(MLX5DR_ACTION_TYP_CTR),
53 		BIT(MLX5DR_ACTION_TYP_ASO_METER),
54 		BIT(MLX5DR_ACTION_TYP_ASO_CT),
55 		BIT(MLX5DR_ACTION_TYP_PUSH_VLAN),
56 		BIT(MLX5DR_ACTION_TYP_PUSH_VLAN),
57 		BIT(MLX5DR_ACTION_TYP_NAT64),
58 		BIT(MLX5DR_ACTION_TYP_MODIFY_HDR),
59 		BIT(MLX5DR_ACTION_TYP_INSERT_HEADER) |
60 		BIT(MLX5DR_ACTION_TYP_PUSH_IPV6_ROUTE_EXT) |
61 		BIT(MLX5DR_ACTION_TYP_REFORMAT_L2_TO_TNL_L2) |
62 		BIT(MLX5DR_ACTION_TYP_REFORMAT_L2_TO_TNL_L3),
63 		BIT(MLX5DR_ACTION_TYP_TBL) |
64 		BIT(MLX5DR_ACTION_TYP_MISS) |
65 		BIT(MLX5DR_ACTION_TYP_DROP) |
66 		BIT(MLX5DR_ACTION_TYP_DEST_ROOT) |
67 		BIT(MLX5DR_ACTION_TYP_JUMP_TO_MATCHER),
68 		BIT(MLX5DR_ACTION_TYP_LAST),
69 	},
70 	[MLX5DR_TABLE_TYPE_FDB] = {
71 		BIT(MLX5DR_ACTION_TYP_REMOVE_HEADER) |
72 		BIT(MLX5DR_ACTION_TYP_REFORMAT_TNL_L2_TO_L2) |
73 		BIT(MLX5DR_ACTION_TYP_REFORMAT_TNL_L3_TO_L2) |
74 		BIT(MLX5DR_ACTION_TYP_POP_IPV6_ROUTE_EXT),
75 		BIT(MLX5DR_ACTION_TYP_POP_VLAN),
76 		BIT(MLX5DR_ACTION_TYP_POP_VLAN),
77 		BIT(MLX5DR_ACTION_TYP_CTR),
78 		BIT(MLX5DR_ACTION_TYP_ASO_METER),
79 		BIT(MLX5DR_ACTION_TYP_ASO_CT),
80 		BIT(MLX5DR_ACTION_TYP_PUSH_VLAN),
81 		BIT(MLX5DR_ACTION_TYP_PUSH_VLAN),
82 		BIT(MLX5DR_ACTION_TYP_NAT64),
83 		BIT(MLX5DR_ACTION_TYP_MODIFY_HDR),
84 		BIT(MLX5DR_ACTION_TYP_INSERT_HEADER) |
85 		BIT(MLX5DR_ACTION_TYP_PUSH_IPV6_ROUTE_EXT) |
86 		BIT(MLX5DR_ACTION_TYP_REFORMAT_L2_TO_TNL_L2) |
87 		BIT(MLX5DR_ACTION_TYP_REFORMAT_L2_TO_TNL_L3),
88 		BIT(MLX5DR_ACTION_TYP_TBL) |
89 		BIT(MLX5DR_ACTION_TYP_MISS) |
90 		BIT(MLX5DR_ACTION_TYP_VPORT) |
91 		BIT(MLX5DR_ACTION_TYP_DROP) |
92 		BIT(MLX5DR_ACTION_TYP_DEST_ROOT) |
93 		BIT(MLX5DR_ACTION_TYP_DEST_ARRAY) |
94 		BIT(MLX5DR_ACTION_TYP_JUMP_TO_MATCHER),
95 		BIT(MLX5DR_ACTION_TYP_LAST),
96 	},
97 };
98 
99 static int mlx5dr_action_get_shared_stc_nic(struct mlx5dr_context *ctx,
100 					    enum mlx5dr_context_shared_stc_type stc_type,
101 					    uint8_t tbl_type)
102 {
103 	struct mlx5dr_cmd_stc_modify_attr stc_attr = {0};
104 	struct mlx5dr_action_shared_stc *shared_stc;
105 	int ret;
106 
107 	pthread_spin_lock(&ctx->ctrl_lock);
108 	if (ctx->common_res[tbl_type].shared_stc[stc_type]) {
109 		ctx->common_res[tbl_type].shared_stc[stc_type]->refcount++;
110 		pthread_spin_unlock(&ctx->ctrl_lock);
111 		return 0;
112 	}
113 
114 	shared_stc = simple_calloc(1, sizeof(*shared_stc));
115 	if (!shared_stc) {
116 		DR_LOG(ERR, "Failed to allocate memory for shared STCs");
117 		rte_errno = ENOMEM;
118 		goto unlock_and_out;
119 	}
120 	switch (stc_type) {
121 	case MLX5DR_CONTEXT_SHARED_STC_DECAP_L3:
122 		stc_attr.action_type = MLX5_IFC_STC_ACTION_TYPE_HEADER_REMOVE;
123 		stc_attr.action_offset = MLX5DR_ACTION_OFFSET_DW5;
124 		stc_attr.reparse_mode = MLX5_IFC_STC_REPARSE_IGNORE;
125 		stc_attr.remove_header.decap = 0;
126 		stc_attr.remove_header.start_anchor = MLX5_HEADER_ANCHOR_PACKET_START;
127 		stc_attr.remove_header.end_anchor = MLX5_HEADER_ANCHOR_IPV6_IPV4;
128 		break;
129 	case MLX5DR_CONTEXT_SHARED_STC_DOUBLE_POP:
130 		stc_attr.action_type = MLX5_IFC_STC_ACTION_TYPE_REMOVE_WORDS;
131 		stc_attr.action_offset = MLX5DR_ACTION_OFFSET_DW5;
132 		stc_attr.reparse_mode = MLX5_IFC_STC_REPARSE_ALWAYS;
133 		stc_attr.remove_words.start_anchor = MLX5_HEADER_ANCHOR_FIRST_VLAN_START;
134 		stc_attr.remove_words.num_of_words = MLX5DR_ACTION_HDR_LEN_L2_VLAN;
135 		break;
136 	default:
137 		DR_LOG(ERR, "No such type : stc_type");
138 		assert(false);
139 		rte_errno = EINVAL;
140 		goto unlock_and_out;
141 	}
142 
143 	ret = mlx5dr_action_alloc_single_stc(ctx, &stc_attr, tbl_type,
144 					     &shared_stc->remove_header);
145 	if (ret) {
146 		DR_LOG(ERR, "Failed to allocate shared decap l2 STC");
147 		goto free_shared_stc;
148 	}
149 
150 	ctx->common_res[tbl_type].shared_stc[stc_type] = shared_stc;
151 	ctx->common_res[tbl_type].shared_stc[stc_type]->refcount = 1;
152 
153 	pthread_spin_unlock(&ctx->ctrl_lock);
154 
155 	return 0;
156 
157 free_shared_stc:
158 	simple_free(shared_stc);
159 unlock_and_out:
160 	pthread_spin_unlock(&ctx->ctrl_lock);
161 	return rte_errno;
162 }
163 
164 static void mlx5dr_action_put_shared_stc_nic(struct mlx5dr_context *ctx,
165 					     enum mlx5dr_context_shared_stc_type stc_type,
166 					     uint8_t tbl_type)
167 {
168 	struct mlx5dr_action_shared_stc *shared_stc;
169 
170 	pthread_spin_lock(&ctx->ctrl_lock);
171 	if (--ctx->common_res[tbl_type].shared_stc[stc_type]->refcount) {
172 		pthread_spin_unlock(&ctx->ctrl_lock);
173 		return;
174 	}
175 
176 	shared_stc = ctx->common_res[tbl_type].shared_stc[stc_type];
177 
178 	mlx5dr_action_free_single_stc(ctx, tbl_type, &shared_stc->remove_header);
179 	simple_free(shared_stc);
180 	ctx->common_res[tbl_type].shared_stc[stc_type] = NULL;
181 	pthread_spin_unlock(&ctx->ctrl_lock);
182 }
183 
184 static int mlx5dr_action_get_shared_stc(struct mlx5dr_action *action,
185 					enum mlx5dr_context_shared_stc_type stc_type)
186 {
187 	struct mlx5dr_context *ctx = action->ctx;
188 	int ret;
189 
190 	if (stc_type >= MLX5DR_CONTEXT_SHARED_STC_MAX) {
191 		assert(false);
192 		rte_errno = EINVAL;
193 		return rte_errno;
194 	}
195 
196 	if (action->flags & MLX5DR_ACTION_FLAG_HWS_RX) {
197 		ret = mlx5dr_action_get_shared_stc_nic(ctx, stc_type, MLX5DR_TABLE_TYPE_NIC_RX);
198 		if (ret) {
199 			DR_LOG(ERR, "Failed to allocate memory for RX shared STCs (type: %d)",
200 			       stc_type);
201 			return ret;
202 		}
203 	}
204 
205 	if (action->flags & MLX5DR_ACTION_FLAG_HWS_TX) {
206 		ret = mlx5dr_action_get_shared_stc_nic(ctx, stc_type, MLX5DR_TABLE_TYPE_NIC_TX);
207 		if (ret) {
208 			DR_LOG(ERR, "Failed to allocate memory for TX shared STCs(type: %d)",
209 			       stc_type);
210 			goto clean_nic_rx_stc;
211 		}
212 	}
213 
214 	if (action->flags & MLX5DR_ACTION_FLAG_HWS_FDB) {
215 		ret = mlx5dr_action_get_shared_stc_nic(ctx, stc_type, MLX5DR_TABLE_TYPE_FDB);
216 		if (ret) {
217 			DR_LOG(ERR, "Failed to allocate memory for FDB shared STCs (type: %d)",
218 			       stc_type);
219 			goto clean_nic_tx_stc;
220 		}
221 	}
222 
223 	return 0;
224 
225 clean_nic_tx_stc:
226 	if (action->flags & MLX5DR_ACTION_FLAG_HWS_TX)
227 		mlx5dr_action_put_shared_stc_nic(ctx, stc_type, MLX5DR_TABLE_TYPE_NIC_TX);
228 clean_nic_rx_stc:
229 	if (action->flags & MLX5DR_ACTION_FLAG_HWS_RX)
230 		mlx5dr_action_put_shared_stc_nic(ctx, stc_type, MLX5DR_TABLE_TYPE_NIC_RX);
231 
232 	return ret;
233 }
234 
235 static void mlx5dr_action_put_shared_stc(struct mlx5dr_action *action,
236 					 enum mlx5dr_context_shared_stc_type stc_type)
237 {
238 	struct mlx5dr_context *ctx = action->ctx;
239 
240 	if (stc_type >= MLX5DR_CONTEXT_SHARED_STC_MAX) {
241 		assert(false);
242 		return;
243 	}
244 
245 	if (action->flags & MLX5DR_ACTION_FLAG_HWS_RX)
246 		mlx5dr_action_put_shared_stc_nic(ctx, stc_type, MLX5DR_TABLE_TYPE_NIC_RX);
247 
248 	if (action->flags & MLX5DR_ACTION_FLAG_HWS_TX)
249 		mlx5dr_action_put_shared_stc_nic(ctx, stc_type, MLX5DR_TABLE_TYPE_NIC_TX);
250 
251 	if (action->flags & MLX5DR_ACTION_FLAG_HWS_FDB)
252 		mlx5dr_action_put_shared_stc_nic(ctx, stc_type, MLX5DR_TABLE_TYPE_FDB);
253 }
254 
255 static void
256 mlx5dr_action_create_nat64_zero_all_addr(uint8_t **action_ptr, bool is_v4_to_v6)
257 {
258 	if (is_v4_to_v6) {
259 		MLX5_SET(set_action_in, *action_ptr, action_type, MLX5_MODIFICATION_TYPE_SET);
260 		MLX5_SET(set_action_in, *action_ptr, field, MLX5_MODI_OUT_SIPV4);
261 		MLX5_SET(set_action_in, *action_ptr, data, 0);
262 		*action_ptr += MLX5DR_ACTION_DOUBLE_SIZE;
263 
264 		MLX5_SET(set_action_in, *action_ptr, action_type, MLX5_MODIFICATION_TYPE_SET);
265 		MLX5_SET(set_action_in, *action_ptr, field, MLX5_MODI_OUT_DIPV4);
266 		MLX5_SET(set_action_in, *action_ptr, data, 0);
267 		*action_ptr += MLX5DR_ACTION_DOUBLE_SIZE;
268 	} else {
269 		MLX5_SET(set_action_in, *action_ptr, action_type, MLX5_MODIFICATION_TYPE_SET);
270 		MLX5_SET(set_action_in, *action_ptr, field, MLX5_MODI_OUT_SIPV6_127_96);
271 		MLX5_SET(set_action_in, *action_ptr, data, 0);
272 		*action_ptr += MLX5DR_ACTION_DOUBLE_SIZE;
273 
274 		MLX5_SET(set_action_in, *action_ptr, action_type, MLX5_MODIFICATION_TYPE_SET);
275 		MLX5_SET(set_action_in, *action_ptr, field, MLX5_MODI_OUT_SIPV6_95_64);
276 		MLX5_SET(set_action_in, *action_ptr, data, 0);
277 		*action_ptr += MLX5DR_ACTION_DOUBLE_SIZE;
278 
279 		MLX5_SET(set_action_in, *action_ptr, action_type, MLX5_MODIFICATION_TYPE_SET);
280 		MLX5_SET(set_action_in, *action_ptr, field, MLX5_MODI_OUT_SIPV6_63_32);
281 		MLX5_SET(set_action_in, *action_ptr, data, 0);
282 		*action_ptr += MLX5DR_ACTION_DOUBLE_SIZE;
283 
284 		MLX5_SET(set_action_in, *action_ptr, action_type, MLX5_MODIFICATION_TYPE_SET);
285 		MLX5_SET(set_action_in, *action_ptr, field, MLX5_MODI_OUT_SIPV6_31_0);
286 		MLX5_SET(set_action_in, *action_ptr, data, 0);
287 		*action_ptr += MLX5DR_ACTION_DOUBLE_SIZE;
288 
289 		MLX5_SET(set_action_in, *action_ptr, action_type, MLX5_MODIFICATION_TYPE_SET);
290 		MLX5_SET(set_action_in, *action_ptr, field, MLX5_MODI_OUT_DIPV6_127_96);
291 		MLX5_SET(set_action_in, *action_ptr, data, 0);
292 		*action_ptr += MLX5DR_ACTION_DOUBLE_SIZE;
293 
294 		MLX5_SET(set_action_in, *action_ptr, action_type, MLX5_MODIFICATION_TYPE_SET);
295 		MLX5_SET(set_action_in, *action_ptr, field, MLX5_MODI_OUT_DIPV6_95_64);
296 		MLX5_SET(set_action_in, *action_ptr, data, 0);
297 		*action_ptr += MLX5DR_ACTION_DOUBLE_SIZE;
298 
299 		MLX5_SET(set_action_in, *action_ptr, action_type, MLX5_MODIFICATION_TYPE_SET);
300 		MLX5_SET(set_action_in, *action_ptr, field, MLX5_MODI_OUT_DIPV6_63_32);
301 		MLX5_SET(set_action_in, *action_ptr, data, 0);
302 		*action_ptr += MLX5DR_ACTION_DOUBLE_SIZE;
303 
304 		MLX5_SET(set_action_in, *action_ptr, action_type, MLX5_MODIFICATION_TYPE_SET);
305 		MLX5_SET(set_action_in, *action_ptr, field, MLX5_MODI_OUT_DIPV6_31_0);
306 		MLX5_SET(set_action_in, *action_ptr, data, 0);
307 		*action_ptr += MLX5DR_ACTION_DOUBLE_SIZE;
308 	}
309 }
310 
311 static struct mlx5dr_action *
312 mlx5dr_action_create_nat64_copy_state(struct mlx5dr_context *ctx,
313 				      struct mlx5dr_action_nat64_attr *attr,
314 				      uint32_t flags)
315 {
316 	__be64 modify_action_data[MLX5DR_ACTION_NAT64_MAX_MODIFY_ACTIONS];
317 	struct mlx5dr_action_mh_pattern pat[2];
318 	struct mlx5dr_action *action;
319 	uint32_t packet_len_field;
320 	uint8_t *action_ptr;
321 	uint32_t tos_field;
322 	uint32_t tos_size;
323 	uint32_t src_addr;
324 	uint32_t dst_addr;
325 	bool is_v4_to_v6;
326 	uint32_t ecn;
327 
328 	is_v4_to_v6 = attr->flags & MLX5DR_ACTION_NAT64_V4_TO_V6;
329 
330 	if (is_v4_to_v6) {
331 		packet_len_field = MLX5_MODI_OUT_IPV4_TOTAL_LEN;
332 		tos_field = MLX5_MODI_OUT_IP_DSCP;
333 		tos_size = 6;
334 		ecn = MLX5_MODI_OUT_IP_ECN;
335 		src_addr = MLX5_MODI_OUT_SIPV4;
336 		dst_addr = MLX5_MODI_OUT_DIPV4;
337 	} else {
338 		packet_len_field = MLX5_MODI_OUT_IPV6_PAYLOAD_LEN;
339 		tos_field = MLX5_MODI_OUT_IPV6_TRAFFIC_CLASS;
340 		tos_size = 8;
341 		ecn = 0;
342 		src_addr = MLX5_MODI_OUT_SIPV6_31_0;
343 		dst_addr = MLX5_MODI_OUT_DIPV6_31_0;
344 	}
345 
346 	memset(modify_action_data, 0, sizeof(modify_action_data));
347 	action_ptr = (uint8_t *)modify_action_data;
348 
349 	if (attr->flags & MLX5DR_ACTION_NAT64_BACKUP_ADDR) {
350 		MLX5_SET(copy_action_in, action_ptr, action_type, MLX5_MODIFICATION_TYPE_COPY);
351 		MLX5_SET(copy_action_in, action_ptr, src_field, src_addr);
352 		MLX5_SET(copy_action_in, action_ptr, dst_field,
353 			 attr->registers[MLX5DR_ACTION_NAT64_REG_SRC_IP]);
354 		action_ptr += MLX5DR_ACTION_DOUBLE_SIZE;
355 
356 		MLX5_SET(copy_action_in, action_ptr, action_type, MLX5_MODIFICATION_TYPE_COPY);
357 		MLX5_SET(copy_action_in, action_ptr, src_field, dst_addr);
358 		MLX5_SET(copy_action_in, action_ptr, dst_field,
359 			 attr->registers[MLX5DR_ACTION_NAT64_REG_DST_IP]);
360 		action_ptr += MLX5DR_ACTION_DOUBLE_SIZE;
361 	}
362 
363 	/* | 8 bit - 8 bit     - 16 bit     |
364 	 * | TOS   - protocol  - packet-len |
365 	 */
366 	MLX5_SET(copy_action_in, action_ptr, action_type, MLX5_MODIFICATION_TYPE_COPY);
367 	MLX5_SET(copy_action_in, action_ptr, src_field, packet_len_field);
368 	MLX5_SET(copy_action_in, action_ptr, dst_field,
369 		 attr->registers[MLX5DR_ACTION_NAT64_REG_CONTROL]);
370 	MLX5_SET(copy_action_in, action_ptr, dst_offset, 0);/* 16 bits in the lsb */
371 	MLX5_SET(copy_action_in, action_ptr, length, 16);
372 	action_ptr += MLX5DR_ACTION_DOUBLE_SIZE;
373 
374 	MLX5_SET(copy_action_in, action_ptr, action_type, MLX5_MODIFICATION_TYPE_NOP);
375 	action_ptr += MLX5DR_ACTION_DOUBLE_SIZE;
376 
377 	MLX5_SET(copy_action_in, action_ptr, action_type, MLX5_MODIFICATION_TYPE_COPY);
378 	MLX5_SET(copy_action_in, action_ptr, src_field, MLX5_MODI_OUT_IP_PROTOCOL);
379 	MLX5_SET(copy_action_in, action_ptr, dst_field,
380 		 attr->registers[MLX5DR_ACTION_NAT64_REG_CONTROL]);
381 	MLX5_SET(copy_action_in, action_ptr, dst_offset, 16);
382 	MLX5_SET(copy_action_in, action_ptr, length, 8);
383 	action_ptr += MLX5DR_ACTION_DOUBLE_SIZE;
384 
385 	MLX5_SET(copy_action_in, action_ptr, action_type, MLX5_MODIFICATION_TYPE_NOP);
386 	action_ptr += MLX5DR_ACTION_DOUBLE_SIZE;
387 
388 	MLX5_SET(copy_action_in, action_ptr, action_type, MLX5_MODIFICATION_TYPE_COPY);
389 	MLX5_SET(copy_action_in, action_ptr, src_field, tos_field);
390 	MLX5_SET(copy_action_in, action_ptr, dst_field,
391 		 attr->registers[MLX5DR_ACTION_NAT64_REG_CONTROL]);
392 	MLX5_SET(copy_action_in, action_ptr, dst_offset, 24);
393 	MLX5_SET(copy_action_in, action_ptr, length, tos_size);
394 	action_ptr += MLX5DR_ACTION_DOUBLE_SIZE;
395 	/* in ipv4 TOS = {dscp (6bits) - ecn (2bits) }*/
396 	if (ecn) {
397 		MLX5_SET(copy_action_in, action_ptr, action_type, MLX5_MODIFICATION_TYPE_NOP);
398 		action_ptr += MLX5DR_ACTION_DOUBLE_SIZE;
399 
400 		MLX5_SET(copy_action_in, action_ptr, action_type, MLX5_MODIFICATION_TYPE_COPY);
401 		MLX5_SET(copy_action_in, action_ptr, src_field, ecn);
402 		MLX5_SET(copy_action_in, action_ptr, dst_field,
403 			attr->registers[MLX5DR_ACTION_NAT64_REG_CONTROL]);
404 		MLX5_SET(copy_action_in, action_ptr, dst_offset, 24 + tos_size);
405 		MLX5_SET(copy_action_in, action_ptr, length, MLX5DR_ACTION_NAT64_ECN_SIZE);
406 		action_ptr += MLX5DR_ACTION_DOUBLE_SIZE;
407 	}
408 
409 	/* set sip and dip to 0, in order to have new csum */
410 	mlx5dr_action_create_nat64_zero_all_addr(&action_ptr, is_v4_to_v6);
411 
412 	pat[0].data = modify_action_data;
413 	pat[0].sz = (action_ptr - (uint8_t *)modify_action_data);
414 
415 	action = mlx5dr_action_create_modify_header(ctx, 1, pat, 0, flags);
416 	if (!action) {
417 		DR_LOG(ERR, "Failed to create copy for NAT64: action_sz: %zu, flags: 0x%x\n",
418 		       pat[0].sz, flags);
419 		return NULL;
420 	}
421 
422 	return action;
423 }
424 
425 static struct mlx5dr_action *
426 mlx5dr_action_create_nat64_repalce_state(struct mlx5dr_context *ctx,
427 					 struct mlx5dr_action_nat64_attr *attr,
428 					 uint32_t flags)
429 {
430 	uint32_t address_prefix[MLX5DR_ACTION_NAT64_HEADER_MINUS_ONE] = {0};
431 	__be64 modify_action_data[MLX5DR_ACTION_NAT64_MAX_MODIFY_ACTIONS];
432 	struct mlx5dr_action_mh_pattern pat[2];
433 	static struct mlx5dr_action *action;
434 	uint8_t header_size_in_dw;
435 	uint8_t *action_ptr;
436 	uint32_t eth_type;
437 	bool is_v4_to_v6;
438 	uint32_t ip_ver;
439 	int i;
440 
441 	is_v4_to_v6 = attr->flags & MLX5DR_ACTION_NAT64_V4_TO_V6;
442 
443 	if (is_v4_to_v6) {
444 		uint32_t nat64_well_known_pref[] = {0x00010000,
445 						    0x9bff6400, 0x0, 0x0, 0x0,
446 						    0x9bff6400, 0x0, 0x0, 0x0};
447 
448 		header_size_in_dw = MLX5DR_ACTION_NAT64_IPV6_HEADER;
449 		ip_ver = MLX5DR_ACTION_NAT64_IPV6_VER;
450 		eth_type = RTE_ETHER_TYPE_IPV6;
451 		memcpy(address_prefix, nat64_well_known_pref,
452 		       MLX5DR_ACTION_NAT64_HEADER_MINUS_ONE * sizeof(uint32_t));
453 	} else {
454 		/* In order to fix HW csum issue, make the prefix ready */
455 		uint32_t ipv4_pref[] = {0x0, 0xffba0000, 0x0, 0x0, 0x0};
456 
457 		header_size_in_dw = MLX5DR_ACTION_NAT64_IPV4_HEADER;
458 		ip_ver = MLX5DR_ACTION_NAT64_IPV4_VER;
459 		eth_type = RTE_ETHER_TYPE_IPV4;
460 		memcpy(address_prefix, ipv4_pref,
461 		       MLX5DR_ACTION_NAT64_IPV4_HEADER * sizeof(uint32_t));
462 	}
463 
464 	memset(modify_action_data, 0, sizeof(modify_action_data));
465 	action_ptr = (uint8_t *)modify_action_data;
466 
467 	MLX5_SET(set_action_in, action_ptr, action_type, MLX5_MODIFICATION_TYPE_SET);
468 	MLX5_SET(set_action_in, action_ptr, field, MLX5_MODI_OUT_ETHERTYPE);
469 	MLX5_SET(set_action_in, action_ptr, length, 16);
470 	MLX5_SET(set_action_in, action_ptr, data, eth_type);
471 	action_ptr += MLX5DR_ACTION_DOUBLE_SIZE;
472 
473 	/* push empty header with ipv6 as version */
474 	MLX5_SET(stc_ste_param_insert, action_ptr, action_type,
475 		 MLX5_MODIFICATION_TYPE_INSERT);
476 	MLX5_SET(stc_ste_param_insert, action_ptr, inline_data, 0x1);
477 	MLX5_SET(stc_ste_param_insert, action_ptr, insert_anchor,
478 		 MLX5_HEADER_ANCHOR_IPV6_IPV4);
479 	MLX5_SET(stc_ste_param_insert, action_ptr, insert_size, 2);
480 	MLX5_SET(stc_ste_param_insert, action_ptr, insert_argument, ip_ver);
481 	action_ptr += MLX5DR_ACTION_DOUBLE_SIZE;
482 
483 	for (i = 0; i < header_size_in_dw - 1; i++) {
484 		MLX5_SET(stc_ste_param_insert, action_ptr, action_type,
485 				MLX5_MODIFICATION_TYPE_INSERT);
486 		MLX5_SET(stc_ste_param_insert, action_ptr, inline_data, 0x1);
487 		MLX5_SET(stc_ste_param_insert, action_ptr, insert_anchor,
488 				MLX5_HEADER_ANCHOR_IPV6_IPV4);
489 		MLX5_SET(stc_ste_param_insert, action_ptr, insert_size, 2);
490 		MLX5_SET(stc_ste_param_insert, action_ptr, insert_argument,
491 			 htobe32(address_prefix[i]));
492 		action_ptr += MLX5DR_ACTION_DOUBLE_SIZE;
493 	}
494 
495 	/* Remove orig src/dst addr (8 bytes, 4 words) */
496 	MLX5_SET(stc_ste_param_remove, action_ptr, action_type,
497 		 MLX5_MODIFICATION_TYPE_REMOVE);
498 	MLX5_SET(stc_ste_param_remove, action_ptr, remove_start_anchor,
499 		 MLX5_HEADER_ANCHOR_IPV6_IPV4);
500 	MLX5_SET(stc_ste_param_remove, action_ptr, remove_end_anchor,
501 		 MLX5_HEADER_ANCHOR_TCP_UDP);
502 	action_ptr += MLX5DR_ACTION_DOUBLE_SIZE;
503 
504 	pat[0].data = modify_action_data;
505 	pat[0].sz = action_ptr - (uint8_t *)modify_action_data;
506 
507 	action = mlx5dr_action_create_modify_header(ctx, 1, pat, 0, flags);
508 	if (!action) {
509 		DR_LOG(ERR, "Failed to create action: action_sz: %zu flags: 0x%x\n",
510 		       pat[0].sz, flags);
511 		return NULL;
512 	}
513 
514 	return action;
515 }
516 
517 static struct mlx5dr_action *
518 mlx5dr_action_create_nat64_copy_proto_state(struct mlx5dr_context *ctx,
519 					    struct mlx5dr_action_nat64_attr *attr,
520 					    uint32_t flags)
521 {
522 	__be64 modify_action_data[MLX5DR_ACTION_NAT64_MAX_MODIFY_ACTIONS];
523 	struct mlx5dr_action_mh_pattern pat[2];
524 	struct mlx5dr_action *action;
525 	uint8_t *action_ptr;
526 
527 	memset(modify_action_data, 0, sizeof(modify_action_data));
528 	action_ptr = (uint8_t *)modify_action_data;
529 
530 	MLX5_SET(copy_action_in, action_ptr, action_type, MLX5_MODIFICATION_TYPE_COPY);
531 	MLX5_SET(copy_action_in, action_ptr, src_field,
532 		 attr->registers[MLX5DR_ACTION_NAT64_REG_CONTROL]);
533 	MLX5_SET(copy_action_in, action_ptr, dst_field,
534 		 MLX5_MODI_OUT_IP_PROTOCOL);
535 	MLX5_SET(copy_action_in, action_ptr, src_offset, 16);
536 	MLX5_SET(copy_action_in, action_ptr, dst_offset, 0);
537 	MLX5_SET(copy_action_in, action_ptr, length, 8);
538 	action_ptr += MLX5DR_ACTION_DOUBLE_SIZE;
539 
540 	MLX5_SET(copy_action_in, action_ptr, action_type, MLX5_MODIFICATION_TYPE_NOP);
541 	action_ptr += MLX5DR_ACTION_DOUBLE_SIZE;
542 
543 	pat[0].data = modify_action_data;
544 	pat[0].sz = action_ptr - (uint8_t *)modify_action_data;
545 
546 	action = mlx5dr_action_create_modify_header_reparse(ctx, 1, pat, 0, flags,
547 							    MLX5DR_ACTION_STC_REPARSE_ON);
548 	if (!action) {
549 		DR_LOG(ERR, "Failed to create action: action_sz: %zu, flags: 0x%x\n",
550 		       pat[0].sz, flags);
551 		return NULL;
552 	}
553 
554 	return action;
555 }
556 
557 static struct mlx5dr_action *
558 mlx5dr_action_create_nat64_copy_back_state(struct mlx5dr_context *ctx,
559 					   struct mlx5dr_action_nat64_attr *attr,
560 					   uint32_t flags)
561 {
562 	__be64 modify_action_data[MLX5DR_ACTION_NAT64_MAX_MODIFY_ACTIONS];
563 	struct mlx5dr_action_mh_pattern pat[2];
564 	struct mlx5dr_action *action;
565 	uint32_t packet_len_field;
566 	uint32_t packet_len_add;
567 	uint8_t *action_ptr;
568 	uint32_t tos_field;
569 	uint32_t ttl_field;
570 	uint32_t tos_size;
571 	uint32_t src_addr;
572 	uint32_t dst_addr;
573 	bool is_v4_to_v6;
574 	uint32_t ecn;
575 
576 	is_v4_to_v6 = attr->flags & MLX5DR_ACTION_NAT64_V4_TO_V6;
577 
578 	if (is_v4_to_v6) {
579 		packet_len_field = MLX5_MODI_OUT_IPV6_PAYLOAD_LEN;
580 		 /* 2' comp to 20, to get -20 in add operation */
581 		packet_len_add = MLX5DR_ACTION_NAT64_DEC_20;
582 		ttl_field = MLX5_MODI_OUT_IPV6_HOPLIMIT;
583 		src_addr = MLX5_MODI_OUT_SIPV6_31_0;
584 		dst_addr = MLX5_MODI_OUT_DIPV6_31_0;
585 		tos_field = MLX5_MODI_OUT_IPV6_TRAFFIC_CLASS;
586 		tos_size = 8;
587 		ecn = 0;
588 	} else {
589 		packet_len_field = MLX5_MODI_OUT_IPV4_TOTAL_LEN;
590 		/* ipv4 len is including 20 bytes of the header, so add 20 over ipv6 len */
591 		packet_len_add = MLX5DR_ACTION_NAT64_ADD_20;
592 		ttl_field = MLX5_MODI_OUT_IPV4_TTL;
593 		src_addr = MLX5_MODI_OUT_SIPV4;
594 		dst_addr = MLX5_MODI_OUT_DIPV4;
595 		tos_field = MLX5_MODI_OUT_IP_DSCP;
596 		tos_size = 6;
597 		ecn = MLX5_MODI_OUT_IP_ECN;
598 	}
599 
600 	memset(modify_action_data, 0, sizeof(modify_action_data));
601 	action_ptr = (uint8_t *)modify_action_data;
602 
603 	MLX5_SET(copy_action_in, action_ptr, action_type, MLX5_MODIFICATION_TYPE_COPY);
604 	MLX5_SET(copy_action_in, action_ptr, src_field,
605 		 attr->registers[MLX5DR_ACTION_NAT64_REG_CONTROL]);
606 	MLX5_SET(copy_action_in, action_ptr, dst_field,
607 		 packet_len_field);
608 	MLX5_SET(copy_action_in, action_ptr, src_offset, 32);
609 	MLX5_SET(copy_action_in, action_ptr, length, 16);
610 	action_ptr += MLX5DR_ACTION_DOUBLE_SIZE;
611 
612 	MLX5_SET(set_action_in, action_ptr, action_type, MLX5_MODIFICATION_TYPE_SET);
613 	MLX5_SET(set_action_in, action_ptr, field, ttl_field);
614 	MLX5_SET(set_action_in, action_ptr, length, 8);
615 	MLX5_SET(set_action_in, action_ptr, data, MLX5DR_ACTION_NAT64_TTL_DEFAULT_VAL);
616 	action_ptr += MLX5DR_ACTION_DOUBLE_SIZE;
617 
618 	/* copy TOS */
619 	MLX5_SET(copy_action_in, action_ptr, action_type, MLX5_MODIFICATION_TYPE_COPY);
620 	MLX5_SET(copy_action_in, action_ptr, src_field,
621 		 attr->registers[MLX5DR_ACTION_NAT64_REG_CONTROL]);
622 	MLX5_SET(copy_action_in, action_ptr, dst_field, tos_field);
623 	MLX5_SET(copy_action_in, action_ptr, src_offset, 24 + (ecn ?
624 							       MLX5DR_ACTION_NAT64_ECN_SIZE : 0));
625 	MLX5_SET(copy_action_in, action_ptr, length, tos_size);
626 	action_ptr += MLX5DR_ACTION_DOUBLE_SIZE;
627 
628 	if (ecn) {
629 		MLX5_SET(copy_action_in, action_ptr, action_type, MLX5_MODIFICATION_TYPE_NOP);
630 		action_ptr += MLX5DR_ACTION_DOUBLE_SIZE;
631 
632 		MLX5_SET(copy_action_in, action_ptr, action_type, MLX5_MODIFICATION_TYPE_COPY);
633 		MLX5_SET(copy_action_in, action_ptr, src_field,
634 			attr->registers[MLX5DR_ACTION_NAT64_REG_CONTROL]);
635 		MLX5_SET(copy_action_in, action_ptr, dst_field, ecn);
636 		MLX5_SET(copy_action_in, action_ptr, src_offset, 24);
637 		MLX5_SET(copy_action_in, action_ptr, length, MLX5DR_ACTION_NAT64_ECN_SIZE);
638 		action_ptr += MLX5DR_ACTION_DOUBLE_SIZE;
639 	}
640 
641 	MLX5_SET(copy_action_in, action_ptr, action_type, MLX5_MODIFICATION_TYPE_NOP);
642 	action_ptr += MLX5DR_ACTION_DOUBLE_SIZE;
643 
644 	/* if required Copy original addresses */
645 	if (attr->flags & MLX5DR_ACTION_NAT64_BACKUP_ADDR) {
646 		MLX5_SET(copy_action_in, action_ptr, action_type, MLX5_MODIFICATION_TYPE_COPY);
647 		MLX5_SET(copy_action_in, action_ptr, src_field,
648 			 attr->registers[MLX5DR_ACTION_NAT64_REG_SRC_IP]);
649 		MLX5_SET(copy_action_in, action_ptr, dst_field, src_addr);
650 		MLX5_SET(copy_action_in, action_ptr, src_offset, 0);
651 		MLX5_SET(copy_action_in, action_ptr, length, 32);
652 		action_ptr += MLX5DR_ACTION_DOUBLE_SIZE;
653 
654 		MLX5_SET(copy_action_in, action_ptr, action_type, MLX5_MODIFICATION_TYPE_COPY);
655 		MLX5_SET(copy_action_in, action_ptr, src_field,
656 			 attr->registers[MLX5DR_ACTION_NAT64_REG_DST_IP]);
657 		MLX5_SET(copy_action_in, action_ptr, dst_field, dst_addr);
658 		MLX5_SET(copy_action_in, action_ptr, src_offset, 0);
659 		MLX5_SET(copy_action_in, action_ptr, length, 32);
660 		action_ptr += MLX5DR_ACTION_DOUBLE_SIZE;
661 	}
662 
663 	/* take/add off 20 bytes ipv4/6 from/to the total size */
664 	MLX5_SET(set_action_in, action_ptr, action_type, MLX5_MODIFICATION_TYPE_ADD);
665 	MLX5_SET(set_action_in, action_ptr, field, packet_len_field);
666 	MLX5_SET(set_action_in, action_ptr, data, packet_len_add);
667 	MLX5_SET(set_action_in, action_ptr, length, 16);
668 	action_ptr += MLX5DR_ACTION_DOUBLE_SIZE;
669 
670 	pat[0].data = modify_action_data;
671 	pat[0].sz = action_ptr - (uint8_t *)modify_action_data;
672 
673 	action = mlx5dr_action_create_modify_header(ctx, 1, pat, 0, flags);
674 	if (!action) {
675 		DR_LOG(ERR, "Failed to create action: action_sz: %zu, flags: 0x%x\n",
676 		       pat[0].sz, flags);
677 		return NULL;
678 	}
679 
680 	return action;
681 }
682 
683 static void mlx5dr_action_print_combo(enum mlx5dr_action_type *user_actions)
684 {
685 	DR_LOG(ERR, "Invalid action_type sequence");
686 	while (*user_actions != MLX5DR_ACTION_TYP_LAST) {
687 		DR_LOG(ERR, "%s", mlx5dr_debug_action_type_to_str(*user_actions));
688 		user_actions++;
689 	}
690 }
691 
692 bool mlx5dr_action_check_combo(enum mlx5dr_action_type *user_actions,
693 			       enum mlx5dr_table_type table_type)
694 {
695 	const uint32_t *order_arr = action_order_arr[table_type];
696 	uint8_t order_idx = 0;
697 	uint8_t user_idx = 0;
698 	bool valid_combo;
699 
700 	while (order_arr[order_idx] != BIT(MLX5DR_ACTION_TYP_LAST)) {
701 		/* User action order validated move to next user action */
702 		if (BIT(user_actions[user_idx]) & order_arr[order_idx])
703 			user_idx++;
704 
705 		/* Iterate to the next supported action in the order */
706 		order_idx++;
707 	}
708 
709 	/* Combination is valid if all user action were processed */
710 	valid_combo = user_actions[user_idx] == MLX5DR_ACTION_TYP_LAST;
711 	if (!valid_combo)
712 		mlx5dr_action_print_combo(user_actions);
713 
714 	return valid_combo;
715 }
716 
717 int mlx5dr_action_root_build_attr(struct mlx5dr_rule_action rule_actions[],
718 				  uint32_t num_actions,
719 				  struct mlx5dv_flow_action_attr *attr)
720 {
721 	struct mlx5dr_action *action;
722 	uint32_t i;
723 
724 	for (i = 0; i < num_actions; i++) {
725 		action = rule_actions[i].action;
726 
727 		switch (action->type) {
728 		case MLX5DR_ACTION_TYP_TBL:
729 		case MLX5DR_ACTION_TYP_TIR:
730 			attr[i].type = MLX5DV_FLOW_ACTION_DEST_DEVX;
731 			attr[i].obj = action->devx_obj;
732 			break;
733 		case MLX5DR_ACTION_TYP_TAG:
734 			attr[i].type = MLX5DV_FLOW_ACTION_TAG;
735 			attr[i].tag_value = rule_actions[i].tag.value;
736 			break;
737 #ifdef HAVE_MLX5_DR_CREATE_ACTION_DEFAULT_MISS
738 		case MLX5DR_ACTION_TYP_MISS:
739 			attr[i].type = MLX5DV_FLOW_ACTION_DEFAULT_MISS;
740 			break;
741 #endif
742 		case MLX5DR_ACTION_TYP_DROP:
743 			attr[i].type = MLX5DV_FLOW_ACTION_DROP;
744 			break;
745 		case MLX5DR_ACTION_TYP_REFORMAT_TNL_L2_TO_L2:
746 		case MLX5DR_ACTION_TYP_REFORMAT_L2_TO_TNL_L2:
747 		case MLX5DR_ACTION_TYP_REFORMAT_TNL_L3_TO_L2:
748 		case MLX5DR_ACTION_TYP_REFORMAT_L2_TO_TNL_L3:
749 		case MLX5DR_ACTION_TYP_MODIFY_HDR:
750 			attr[i].type = MLX5DV_FLOW_ACTION_IBV_FLOW_ACTION;
751 			attr[i].action = action->flow_action;
752 			break;
753 #ifdef HAVE_IBV_FLOW_DEVX_COUNTERS
754 		case MLX5DR_ACTION_TYP_CTR:
755 			attr[i].type = MLX5DV_FLOW_ACTION_COUNTERS_DEVX;
756 			attr[i].obj = action->devx_obj;
757 
758 			if (rule_actions[i].counter.offset) {
759 				DR_LOG(ERR, "Counter offset not supported over root");
760 				rte_errno = ENOTSUP;
761 				return rte_errno;
762 			}
763 			break;
764 #endif
765 		default:
766 			DR_LOG(ERR, "Found unsupported action type: %d", action->type);
767 			rte_errno = ENOTSUP;
768 			return rte_errno;
769 		}
770 	}
771 
772 	return 0;
773 }
774 
775 static bool
776 mlx5dr_action_fixup_stc_attr(struct mlx5dr_context *ctx,
777 			     struct mlx5dr_cmd_stc_modify_attr *stc_attr,
778 			     struct mlx5dr_cmd_stc_modify_attr *fixup_stc_attr,
779 			     enum mlx5dr_table_type table_type,
780 			     bool is_mirror)
781 {
782 	struct mlx5dr_devx_obj *devx_obj;
783 	bool use_fixup = false;
784 	uint32_t fw_tbl_type;
785 
786 	fw_tbl_type = mlx5dr_table_get_res_fw_ft_type(table_type, is_mirror);
787 
788 	switch (stc_attr->action_type) {
789 	case MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_STE_TABLE:
790 		if (!is_mirror)
791 			devx_obj = mlx5dr_pool_chunk_get_base_devx_obj(stc_attr->ste_table.ste_pool,
792 								       &stc_attr->ste_table.ste);
793 		else
794 			devx_obj =
795 			mlx5dr_pool_chunk_get_base_devx_obj_mirror(stc_attr->ste_table.ste_pool,
796 								   &stc_attr->ste_table.ste);
797 
798 		*fixup_stc_attr = *stc_attr;
799 		fixup_stc_attr->ste_table.ste_obj_id = devx_obj->id;
800 		use_fixup = true;
801 		break;
802 
803 	case MLX5_IFC_STC_ACTION_TYPE_ALLOW:
804 		if (fw_tbl_type == FS_FT_FDB_TX || fw_tbl_type == FS_FT_FDB_RX) {
805 			fixup_stc_attr->action_type = MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_VPORT;
806 			fixup_stc_attr->action_offset = stc_attr->action_offset;
807 			fixup_stc_attr->stc_offset = stc_attr->stc_offset;
808 			fixup_stc_attr->vport.esw_owner_vhca_id = ctx->caps->vhca_id;
809 			fixup_stc_attr->vport.vport_num = ctx->caps->eswitch_manager_vport_number;
810 			fixup_stc_attr->vport.eswitch_owner_vhca_id_valid =
811 				ctx->caps->merged_eswitch;
812 			use_fixup = true;
813 		}
814 		break;
815 
816 	case MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_VPORT:
817 		if (stc_attr->vport.vport_num != WIRE_PORT)
818 			break;
819 
820 		if (fw_tbl_type == FS_FT_FDB_RX) {
821 			/* The FW doesn't allow to go back to wire in RX, so change it to DROP */
822 			fixup_stc_attr->action_type = MLX5_IFC_STC_ACTION_TYPE_DROP;
823 			fixup_stc_attr->action_offset = MLX5DR_ACTION_OFFSET_HIT;
824 			fixup_stc_attr->stc_offset = stc_attr->stc_offset;
825 		} else if (fw_tbl_type == FS_FT_FDB_TX) {
826 			/*The FW doesn't allow to go to wire in the TX by JUMP_TO_VPORT*/
827 			fixup_stc_attr->action_type = MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_UPLINK;
828 			fixup_stc_attr->action_offset = stc_attr->action_offset;
829 			fixup_stc_attr->stc_offset = stc_attr->stc_offset;
830 			fixup_stc_attr->vport.vport_num = 0;
831 			fixup_stc_attr->vport.esw_owner_vhca_id = stc_attr->vport.esw_owner_vhca_id;
832 			fixup_stc_attr->vport.eswitch_owner_vhca_id_valid =
833 				stc_attr->vport.eswitch_owner_vhca_id_valid;
834 		}
835 		use_fixup = true;
836 		break;
837 	case MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_TIR:
838 		/* TIR is allowed on RX side, requires mask in case of FDB */
839 		if (fw_tbl_type == FS_FT_FDB_TX) {
840 			fixup_stc_attr->action_type = MLX5_IFC_STC_ACTION_TYPE_DROP;
841 			fixup_stc_attr->action_offset = MLX5DR_ACTION_OFFSET_HIT;
842 			fixup_stc_attr->stc_offset = stc_attr->stc_offset;
843 			use_fixup = true;
844 		}
845 		break;
846 	default:
847 		break;
848 	}
849 
850 	return use_fixup;
851 }
852 
853 int mlx5dr_action_alloc_single_stc(struct mlx5dr_context *ctx,
854 				   struct mlx5dr_cmd_stc_modify_attr *stc_attr,
855 				   uint32_t table_type,
856 				   struct mlx5dr_pool_chunk *stc)
857 {
858 	struct mlx5dr_cmd_stc_modify_attr cleanup_stc_attr = {0};
859 	struct mlx5dr_pool *stc_pool = ctx->stc_pool[table_type];
860 	struct mlx5dr_cmd_stc_modify_attr fixup_stc_attr = {0};
861 	struct mlx5dr_devx_obj *devx_obj_0;
862 	bool use_fixup;
863 	int ret;
864 
865 	ret = mlx5dr_pool_chunk_alloc(stc_pool, stc);
866 	if (ret) {
867 		DR_LOG(ERR, "Failed to allocate single action STC");
868 		return ret;
869 	}
870 
871 	stc_attr->stc_offset = stc->offset;
872 
873 	/* Dynamic reparse not supported, overwrite and use default */
874 	if (!mlx5dr_context_cap_dynamic_reparse(ctx))
875 		stc_attr->reparse_mode = MLX5_IFC_STC_REPARSE_IGNORE;
876 
877 	devx_obj_0 = mlx5dr_pool_chunk_get_base_devx_obj(stc_pool, stc);
878 
879 	/* According to table/action limitation change the stc_attr */
880 	use_fixup = mlx5dr_action_fixup_stc_attr(ctx, stc_attr, &fixup_stc_attr, table_type, false);
881 	ret = mlx5dr_cmd_stc_modify(devx_obj_0, use_fixup ? &fixup_stc_attr : stc_attr);
882 	if (ret) {
883 		DR_LOG(ERR, "Failed to modify STC action_type %d tbl_type %d",
884 		       stc_attr->action_type, table_type);
885 		goto free_chunk;
886 	}
887 
888 	/* Modify the FDB peer */
889 	if (table_type == MLX5DR_TABLE_TYPE_FDB) {
890 		struct mlx5dr_devx_obj *devx_obj_1;
891 
892 		devx_obj_1 = mlx5dr_pool_chunk_get_base_devx_obj_mirror(stc_pool, stc);
893 
894 		use_fixup = mlx5dr_action_fixup_stc_attr(ctx, stc_attr,
895 							 &fixup_stc_attr,
896 							 table_type, true);
897 		ret = mlx5dr_cmd_stc_modify(devx_obj_1, use_fixup ? &fixup_stc_attr : stc_attr);
898 		if (ret) {
899 			DR_LOG(ERR, "Failed to modify peer STC action_type %d tbl_type %d",
900 			       stc_attr->action_type, table_type);
901 			goto clean_devx_obj_0;
902 		}
903 	}
904 
905 	return 0;
906 
907 clean_devx_obj_0:
908 	cleanup_stc_attr.action_type = MLX5_IFC_STC_ACTION_TYPE_DROP;
909 	cleanup_stc_attr.action_offset = MLX5DR_ACTION_OFFSET_HIT;
910 	cleanup_stc_attr.stc_offset = stc->offset;
911 	mlx5dr_cmd_stc_modify(devx_obj_0, &cleanup_stc_attr);
912 free_chunk:
913 	mlx5dr_pool_chunk_free(stc_pool, stc);
914 	return rte_errno;
915 }
916 
917 void mlx5dr_action_free_single_stc(struct mlx5dr_context *ctx,
918 				   uint32_t table_type,
919 				   struct mlx5dr_pool_chunk *stc)
920 {
921 	struct mlx5dr_pool *stc_pool = ctx->stc_pool[table_type];
922 	struct mlx5dr_cmd_stc_modify_attr stc_attr = {0};
923 	struct mlx5dr_devx_obj *devx_obj;
924 
925 	/* Modify the STC not to point to an object */
926 	stc_attr.action_type = MLX5_IFC_STC_ACTION_TYPE_DROP;
927 	stc_attr.action_offset = MLX5DR_ACTION_OFFSET_HIT;
928 	stc_attr.stc_offset = stc->offset;
929 	devx_obj = mlx5dr_pool_chunk_get_base_devx_obj(stc_pool, stc);
930 	mlx5dr_cmd_stc_modify(devx_obj, &stc_attr);
931 
932 	if (table_type == MLX5DR_TABLE_TYPE_FDB) {
933 		devx_obj = mlx5dr_pool_chunk_get_base_devx_obj_mirror(stc_pool, stc);
934 		mlx5dr_cmd_stc_modify(devx_obj, &stc_attr);
935 	}
936 
937 	mlx5dr_pool_chunk_free(stc_pool, stc);
938 }
939 
940 static uint32_t mlx5dr_action_get_mh_stc_type(__be64 pattern)
941 {
942 	uint8_t action_type = MLX5_GET(set_action_in, &pattern, action_type);
943 
944 	switch (action_type) {
945 	case MLX5_MODIFICATION_TYPE_SET:
946 		return MLX5_IFC_STC_ACTION_TYPE_SET;
947 	case MLX5_MODIFICATION_TYPE_ADD:
948 		return MLX5_IFC_STC_ACTION_TYPE_ADD;
949 	case MLX5_MODIFICATION_TYPE_COPY:
950 		return MLX5_IFC_STC_ACTION_TYPE_COPY;
951 	case MLX5_MODIFICATION_TYPE_ADD_FIELD:
952 		return MLX5_IFC_STC_ACTION_TYPE_ADD_FIELD;
953 	default:
954 		assert(false);
955 		DR_LOG(ERR, "Unsupported action type: 0x%x", action_type);
956 		rte_errno = ENOTSUP;
957 		return MLX5_IFC_STC_ACTION_TYPE_NOP;
958 	}
959 }
960 
961 static void mlx5dr_action_fill_stc_attr(struct mlx5dr_action *action,
962 					struct mlx5dr_devx_obj *obj,
963 					struct mlx5dr_cmd_stc_modify_attr *attr)
964 {
965 	attr->reparse_mode = MLX5_IFC_STC_REPARSE_IGNORE;
966 
967 	switch (action->type) {
968 	case MLX5DR_ACTION_TYP_TAG:
969 		attr->action_type = MLX5_IFC_STC_ACTION_TYPE_TAG;
970 		attr->action_offset = MLX5DR_ACTION_OFFSET_DW5;
971 		break;
972 	case MLX5DR_ACTION_TYP_DROP:
973 		attr->action_type = MLX5_IFC_STC_ACTION_TYPE_DROP;
974 		attr->action_offset = MLX5DR_ACTION_OFFSET_HIT;
975 		break;
976 	case MLX5DR_ACTION_TYP_MISS:
977 		attr->action_type = MLX5_IFC_STC_ACTION_TYPE_ALLOW;
978 		attr->action_offset = MLX5DR_ACTION_OFFSET_HIT;
979 		break;
980 	case MLX5DR_ACTION_TYP_CTR:
981 		attr->id = obj->id;
982 		attr->action_type = MLX5_IFC_STC_ACTION_TYPE_COUNTER;
983 		attr->action_offset = MLX5DR_ACTION_OFFSET_DW0;
984 		break;
985 	case MLX5DR_ACTION_TYP_TIR:
986 		attr->action_type = MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_TIR;
987 		attr->action_offset = MLX5DR_ACTION_OFFSET_HIT;
988 		attr->dest_tir_num = obj->id;
989 		break;
990 	case MLX5DR_ACTION_TYP_REFORMAT_TNL_L3_TO_L2:
991 	case MLX5DR_ACTION_TYP_MODIFY_HDR:
992 		attr->action_offset = MLX5DR_ACTION_OFFSET_DW6;
993 		attr->reparse_mode = MLX5_IFC_STC_REPARSE_IGNORE;
994 		if (action->modify_header.require_reparse)
995 			attr->reparse_mode = MLX5_IFC_STC_REPARSE_ALWAYS;
996 
997 		if (action->modify_header.num_of_actions == 1) {
998 			attr->modify_action.data = action->modify_header.single_action;
999 			attr->action_type = mlx5dr_action_get_mh_stc_type(attr->modify_action.data);
1000 
1001 			if (attr->action_type == MLX5_IFC_STC_ACTION_TYPE_ADD ||
1002 			    attr->action_type == MLX5_IFC_STC_ACTION_TYPE_SET)
1003 				MLX5_SET(set_action_in, &attr->modify_action.data, data, 0);
1004 		} else {
1005 			attr->action_type = MLX5_IFC_STC_ACTION_TYPE_ACC_MODIFY_LIST;
1006 			attr->modify_header.arg_id = action->modify_header.arg_obj->id;
1007 			attr->modify_header.pattern_id = action->modify_header.pat_obj->id;
1008 		}
1009 		break;
1010 	case MLX5DR_ACTION_TYP_TBL:
1011 	case MLX5DR_ACTION_TYP_DEST_ARRAY:
1012 		attr->action_type = MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_FT;
1013 		attr->action_offset = MLX5DR_ACTION_OFFSET_HIT;
1014 		attr->dest_table_id = obj->id;
1015 		break;
1016 	case MLX5DR_ACTION_TYP_DEST_ROOT:
1017 		attr->action_type = MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_FT;
1018 		attr->action_offset = MLX5DR_ACTION_OFFSET_HIT;
1019 		attr->dest_table_id = action->root_tbl.sa->id;
1020 		break;
1021 	case MLX5DR_ACTION_TYP_REFORMAT_TNL_L2_TO_L2:
1022 		attr->action_type = MLX5_IFC_STC_ACTION_TYPE_HEADER_REMOVE;
1023 		attr->action_offset = MLX5DR_ACTION_OFFSET_DW5;
1024 		attr->reparse_mode = MLX5_IFC_STC_REPARSE_ALWAYS;
1025 		attr->remove_header.decap = 1;
1026 		attr->remove_header.start_anchor = MLX5_HEADER_ANCHOR_PACKET_START;
1027 		attr->remove_header.end_anchor = MLX5_HEADER_ANCHOR_INNER_MAC;
1028 		break;
1029 	case MLX5DR_ACTION_TYP_REFORMAT_L2_TO_TNL_L2:
1030 	case MLX5DR_ACTION_TYP_REFORMAT_L2_TO_TNL_L3:
1031 	case MLX5DR_ACTION_TYP_INSERT_HEADER:
1032 		attr->reparse_mode = MLX5_IFC_STC_REPARSE_ALWAYS;
1033 		if (!action->reformat.require_reparse)
1034 			attr->reparse_mode = MLX5_IFC_STC_REPARSE_IGNORE;
1035 
1036 		attr->action_type = MLX5_IFC_STC_ACTION_TYPE_HEADER_INSERT;
1037 		attr->action_offset = MLX5DR_ACTION_OFFSET_DW6;
1038 		attr->insert_header.encap = action->reformat.encap;
1039 		attr->insert_header.push_esp = action->reformat.push_esp;
1040 		attr->insert_header.insert_anchor = action->reformat.anchor;
1041 		attr->insert_header.arg_id = action->reformat.arg_obj->id;
1042 		attr->insert_header.header_size = action->reformat.header_size;
1043 		attr->insert_header.insert_offset = action->reformat.offset;
1044 		break;
1045 	case MLX5DR_ACTION_TYP_ASO_METER:
1046 		attr->action_offset = MLX5DR_ACTION_OFFSET_DW6;
1047 		attr->action_type = MLX5_IFC_STC_ACTION_TYPE_ASO;
1048 		attr->aso.aso_type = ASO_OPC_MOD_POLICER;
1049 		attr->aso.devx_obj_id = obj->id;
1050 		attr->aso.return_reg_id = action->aso.return_reg_id;
1051 		break;
1052 	case MLX5DR_ACTION_TYP_ASO_CT:
1053 		attr->action_offset = MLX5DR_ACTION_OFFSET_DW6;
1054 		attr->action_type = MLX5_IFC_STC_ACTION_TYPE_ASO;
1055 		attr->aso.aso_type = ASO_OPC_MOD_CONNECTION_TRACKING;
1056 		attr->aso.devx_obj_id = obj->id;
1057 		attr->aso.return_reg_id = action->aso.return_reg_id;
1058 		break;
1059 	case MLX5DR_ACTION_TYP_VPORT:
1060 		attr->action_offset = MLX5DR_ACTION_OFFSET_HIT;
1061 		attr->action_type = MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_VPORT;
1062 		attr->vport.vport_num = action->vport.vport_num;
1063 		attr->vport.esw_owner_vhca_id =	action->vport.esw_owner_vhca_id;
1064 		attr->vport.eswitch_owner_vhca_id_valid = action->ctx->caps->merged_eswitch;
1065 		break;
1066 	case MLX5DR_ACTION_TYP_POP_VLAN:
1067 		attr->action_type = MLX5_IFC_STC_ACTION_TYPE_REMOVE_WORDS;
1068 		attr->action_offset = MLX5DR_ACTION_OFFSET_DW5;
1069 		attr->reparse_mode = MLX5_IFC_STC_REPARSE_ALWAYS;
1070 		attr->remove_words.start_anchor = MLX5_HEADER_ANCHOR_FIRST_VLAN_START;
1071 		attr->remove_words.num_of_words = MLX5DR_ACTION_HDR_LEN_L2_VLAN / 2;
1072 		break;
1073 	case MLX5DR_ACTION_TYP_PUSH_VLAN:
1074 		attr->action_type = MLX5_IFC_STC_ACTION_TYPE_HEADER_INSERT;
1075 		attr->action_offset = MLX5DR_ACTION_OFFSET_DW6;
1076 		attr->reparse_mode = MLX5_IFC_STC_REPARSE_ALWAYS;
1077 		attr->insert_header.encap = 0;
1078 		attr->insert_header.push_esp = 0;
1079 		attr->insert_header.is_inline = 1;
1080 		attr->insert_header.insert_anchor = MLX5_HEADER_ANCHOR_PACKET_START;
1081 		attr->insert_header.insert_offset = MLX5DR_ACTION_HDR_LEN_L2_MACS;
1082 		attr->insert_header.header_size = MLX5DR_ACTION_HDR_LEN_L2_VLAN;
1083 		break;
1084 	case MLX5DR_ACTION_TYP_REMOVE_HEADER:
1085 		if (action->remove_header.type == MLX5DR_ACTION_REMOVE_HEADER_TYPE_BY_HEADER) {
1086 			attr->action_type = MLX5_IFC_STC_ACTION_TYPE_HEADER_REMOVE;
1087 			attr->remove_header.decap = action->remove_header.decap;
1088 			attr->remove_header.start_anchor = action->remove_header.start_anchor;
1089 			attr->remove_header.end_anchor = action->remove_header.end_anchor;
1090 		} else {
1091 			attr->action_type = MLX5_IFC_STC_ACTION_TYPE_REMOVE_WORDS;
1092 			attr->remove_words.start_anchor = action->remove_header.start_anchor;
1093 			attr->remove_words.num_of_words = action->remove_header.num_of_words;
1094 		}
1095 		attr->action_offset = MLX5DR_ACTION_OFFSET_DW5;
1096 		attr->reparse_mode = MLX5_IFC_STC_REPARSE_ALWAYS;
1097 		break;
1098 	case MLX5DR_ACTION_TYP_JUMP_TO_MATCHER:
1099 		attr->action_type = MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_STE_TABLE;
1100 		attr->action_offset = MLX5DR_ACTION_OFFSET_HIT;
1101 		attr->ste_table.ste = action->jump_to_matcher.matcher->match_ste.ste;
1102 		attr->ste_table.ste_pool = action->jump_to_matcher.matcher->match_ste.pool;
1103 		attr->ste_table.match_definer_id = action->ctx->caps->trivial_match_definer;
1104 		break;
1105 	default:
1106 		DR_LOG(ERR, "Invalid action type %d", action->type);
1107 		assert(false);
1108 	}
1109 }
1110 
1111 static int
1112 mlx5dr_action_create_stcs(struct mlx5dr_action *action,
1113 			  struct mlx5dr_devx_obj *obj)
1114 {
1115 	struct mlx5dr_cmd_stc_modify_attr stc_attr = {0};
1116 	struct mlx5dr_context *ctx = action->ctx;
1117 	int ret;
1118 
1119 	mlx5dr_action_fill_stc_attr(action, obj, &stc_attr);
1120 
1121 	/* Block unsupported parallel devx obj modify over the same base */
1122 	pthread_spin_lock(&ctx->ctrl_lock);
1123 
1124 	/* Allocate STC for RX */
1125 	if (action->flags & MLX5DR_ACTION_FLAG_HWS_RX) {
1126 		ret = mlx5dr_action_alloc_single_stc(ctx, &stc_attr,
1127 						     MLX5DR_TABLE_TYPE_NIC_RX,
1128 						     &action->stc[MLX5DR_TABLE_TYPE_NIC_RX]);
1129 		if (ret)
1130 			goto out_err;
1131 	}
1132 
1133 	/* Allocate STC for TX */
1134 	if (action->flags & MLX5DR_ACTION_FLAG_HWS_TX) {
1135 		ret = mlx5dr_action_alloc_single_stc(ctx, &stc_attr,
1136 						     MLX5DR_TABLE_TYPE_NIC_TX,
1137 						     &action->stc[MLX5DR_TABLE_TYPE_NIC_TX]);
1138 		if (ret)
1139 			goto free_nic_rx_stc;
1140 	}
1141 
1142 	/* Allocate STC for FDB */
1143 	if (action->flags & MLX5DR_ACTION_FLAG_HWS_FDB) {
1144 		ret = mlx5dr_action_alloc_single_stc(ctx, &stc_attr,
1145 						     MLX5DR_TABLE_TYPE_FDB,
1146 						     &action->stc[MLX5DR_TABLE_TYPE_FDB]);
1147 		if (ret)
1148 			goto free_nic_tx_stc;
1149 	}
1150 
1151 	pthread_spin_unlock(&ctx->ctrl_lock);
1152 
1153 	return 0;
1154 
1155 free_nic_tx_stc:
1156 	if (action->flags & MLX5DR_ACTION_FLAG_HWS_TX)
1157 		mlx5dr_action_free_single_stc(ctx,
1158 					      MLX5DR_TABLE_TYPE_NIC_TX,
1159 					      &action->stc[MLX5DR_TABLE_TYPE_NIC_TX]);
1160 free_nic_rx_stc:
1161 	if (action->flags & MLX5DR_ACTION_FLAG_HWS_RX)
1162 		mlx5dr_action_free_single_stc(ctx,
1163 					      MLX5DR_TABLE_TYPE_NIC_RX,
1164 					      &action->stc[MLX5DR_TABLE_TYPE_NIC_RX]);
1165 out_err:
1166 	pthread_spin_unlock(&ctx->ctrl_lock);
1167 	return rte_errno;
1168 }
1169 
1170 static void
1171 mlx5dr_action_destroy_stcs(struct mlx5dr_action *action)
1172 {
1173 	struct mlx5dr_context *ctx = action->ctx;
1174 
1175 	/* Block unsupported parallel devx obj modify over the same base */
1176 	pthread_spin_lock(&ctx->ctrl_lock);
1177 
1178 	if (action->flags & MLX5DR_ACTION_FLAG_HWS_RX)
1179 		mlx5dr_action_free_single_stc(ctx, MLX5DR_TABLE_TYPE_NIC_RX,
1180 					      &action->stc[MLX5DR_TABLE_TYPE_NIC_RX]);
1181 
1182 	if (action->flags & MLX5DR_ACTION_FLAG_HWS_TX)
1183 		mlx5dr_action_free_single_stc(ctx, MLX5DR_TABLE_TYPE_NIC_TX,
1184 					      &action->stc[MLX5DR_TABLE_TYPE_NIC_TX]);
1185 
1186 	if (action->flags & MLX5DR_ACTION_FLAG_HWS_FDB)
1187 		mlx5dr_action_free_single_stc(ctx, MLX5DR_TABLE_TYPE_FDB,
1188 					      &action->stc[MLX5DR_TABLE_TYPE_FDB]);
1189 
1190 	pthread_spin_unlock(&ctx->ctrl_lock);
1191 }
1192 
1193 static bool
1194 mlx5dr_action_is_root_flags(uint32_t flags)
1195 {
1196 	return flags & (MLX5DR_ACTION_FLAG_ROOT_RX |
1197 			MLX5DR_ACTION_FLAG_ROOT_TX |
1198 			MLX5DR_ACTION_FLAG_ROOT_FDB);
1199 }
1200 
1201 static bool
1202 mlx5dr_action_is_hws_flags(uint32_t flags)
1203 {
1204 	return flags & (MLX5DR_ACTION_FLAG_HWS_RX |
1205 			MLX5DR_ACTION_FLAG_HWS_TX |
1206 			MLX5DR_ACTION_FLAG_HWS_FDB);
1207 }
1208 
1209 static struct mlx5dr_action *
1210 mlx5dr_action_create_generic_bulk(struct mlx5dr_context *ctx,
1211 				  uint32_t flags,
1212 				  enum mlx5dr_action_type action_type,
1213 				  uint8_t bulk_sz)
1214 {
1215 	struct mlx5dr_action *action;
1216 	int i;
1217 
1218 	if (!mlx5dr_action_is_root_flags(flags) &&
1219 	    !mlx5dr_action_is_hws_flags(flags)) {
1220 		DR_LOG(ERR, "Action flags must specify root or non root (HWS)");
1221 		rte_errno = ENOTSUP;
1222 		return NULL;
1223 	}
1224 
1225 	if (mlx5dr_action_is_hws_flags(flags) &&
1226 	    !(ctx->flags & MLX5DR_CONTEXT_FLAG_HWS_SUPPORT)) {
1227 		DR_LOG(ERR, "Cannot create HWS action since HWS is not supported");
1228 		rte_errno = ENOTSUP;
1229 		return NULL;
1230 	}
1231 
1232 	action = simple_calloc(bulk_sz, sizeof(*action));
1233 	if (!action) {
1234 		DR_LOG(ERR, "Failed to allocate memory for action [%d]", action_type);
1235 		rte_errno = ENOMEM;
1236 		return NULL;
1237 	}
1238 
1239 	for (i = 0; i < bulk_sz; i++) {
1240 		action[i].ctx = ctx;
1241 		action[i].flags = flags;
1242 		action[i].type = action_type;
1243 	}
1244 
1245 	return action;
1246 }
1247 
1248 static struct mlx5dr_action *
1249 mlx5dr_action_create_generic(struct mlx5dr_context *ctx,
1250 			     uint32_t flags,
1251 			     enum mlx5dr_action_type action_type)
1252 {
1253 	return mlx5dr_action_create_generic_bulk(ctx, flags, action_type, 1);
1254 }
1255 
1256 struct mlx5dr_action *
1257 mlx5dr_action_create_dest_table(struct mlx5dr_context *ctx,
1258 				struct mlx5dr_table *tbl,
1259 				uint32_t flags)
1260 {
1261 	struct mlx5dr_action *action;
1262 	int ret;
1263 
1264 	if (mlx5dr_table_is_root(tbl)) {
1265 		DR_LOG(ERR, "Root table cannot be set as destination");
1266 		rte_errno = ENOTSUP;
1267 		return NULL;
1268 	}
1269 
1270 	if (mlx5dr_action_is_hws_flags(flags) &&
1271 	    mlx5dr_action_is_root_flags(flags)) {
1272 		DR_LOG(ERR, "Same action cannot be used for root and non root");
1273 		rte_errno = ENOTSUP;
1274 		return NULL;
1275 	}
1276 
1277 	action = mlx5dr_action_create_generic(ctx, flags, MLX5DR_ACTION_TYP_TBL);
1278 	if (!action)
1279 		return NULL;
1280 
1281 	if (mlx5dr_action_is_root_flags(flags)) {
1282 		if (mlx5dr_context_shared_gvmi_used(ctx))
1283 			action->devx_obj = tbl->local_ft->obj;
1284 		else
1285 			action->devx_obj = tbl->ft->obj;
1286 	} else {
1287 		ret = mlx5dr_action_create_stcs(action, tbl->ft);
1288 		if (ret)
1289 			goto free_action;
1290 
1291 		action->devx_dest.devx_obj = tbl->ft;
1292 	}
1293 
1294 	return action;
1295 
1296 free_action:
1297 	simple_free(action);
1298 	return NULL;
1299 }
1300 
1301 static int mlx5dr_action_get_dest_tir_obj(struct mlx5dr_context *ctx,
1302 					  struct mlx5dr_action *action,
1303 					  struct mlx5dr_devx_obj *obj,
1304 					  struct mlx5dr_devx_obj **ret_obj)
1305 {
1306 	int ret;
1307 
1308 	if (mlx5dr_context_shared_gvmi_used(ctx)) {
1309 		ret = mlx5dr_matcher_create_aliased_obj(ctx,
1310 							ctx->local_ibv_ctx,
1311 							ctx->ibv_ctx,
1312 							ctx->caps->vhca_id,
1313 							obj->id,
1314 							MLX5_GENERAL_OBJ_TYPE_TIR_ALIAS,
1315 							&action->alias.devx_obj);
1316 		if (ret) {
1317 			DR_LOG(ERR, "Failed to create tir alias");
1318 			return rte_errno;
1319 		}
1320 		*ret_obj = action->alias.devx_obj;
1321 	} else {
1322 		*ret_obj = obj;
1323 	}
1324 
1325 	return 0;
1326 }
1327 
1328 struct mlx5dr_action *
1329 mlx5dr_action_create_dest_tir(struct mlx5dr_context *ctx,
1330 			      struct mlx5dr_devx_obj *obj,
1331 			      uint32_t flags,
1332 			      bool is_local)
1333 {
1334 	struct mlx5dr_action *action;
1335 	int ret;
1336 
1337 	if (mlx5dr_action_is_hws_flags(flags) &&
1338 	    mlx5dr_action_is_root_flags(flags)) {
1339 		DR_LOG(ERR, "Same action cannot be used for root and non root");
1340 		rte_errno = ENOTSUP;
1341 		return NULL;
1342 	}
1343 
1344 	if ((flags & MLX5DR_ACTION_FLAG_ROOT_FDB) ||
1345 	    (flags & MLX5DR_ACTION_FLAG_HWS_FDB && !ctx->caps->fdb_tir_stc)) {
1346 		DR_LOG(ERR, "TIR action not support on FDB");
1347 		rte_errno = ENOTSUP;
1348 		return NULL;
1349 	}
1350 
1351 	if (!is_local) {
1352 		DR_LOG(ERR, "TIR should be created on local ibv_device, flags: 0x%x",
1353 		       flags);
1354 		rte_errno = ENOTSUP;
1355 		return NULL;
1356 	}
1357 
1358 	action = mlx5dr_action_create_generic(ctx, flags, MLX5DR_ACTION_TYP_TIR);
1359 	if (!action)
1360 		return NULL;
1361 
1362 	if (mlx5dr_action_is_root_flags(flags)) {
1363 		action->devx_obj = obj->obj;
1364 	} else {
1365 		struct mlx5dr_devx_obj *cur_obj = NULL; /*compilation warn*/
1366 
1367 		ret = mlx5dr_action_get_dest_tir_obj(ctx, action, obj, &cur_obj);
1368 		if (ret) {
1369 			DR_LOG(ERR, "Failed to create tir alias (flags: %d)", flags);
1370 			goto free_action;
1371 		}
1372 
1373 		ret = mlx5dr_action_create_stcs(action, cur_obj);
1374 		if (ret)
1375 			goto clean_obj;
1376 
1377 		action->devx_dest.devx_obj = cur_obj;
1378 	}
1379 
1380 	return action;
1381 
1382 clean_obj:
1383 	mlx5dr_cmd_destroy_obj(action->alias.devx_obj);
1384 free_action:
1385 	simple_free(action);
1386 	return NULL;
1387 }
1388 
1389 struct mlx5dr_action *
1390 mlx5dr_action_create_dest_drop(struct mlx5dr_context *ctx,
1391 			       uint32_t flags)
1392 {
1393 	struct mlx5dr_action *action;
1394 	int ret;
1395 
1396 	action = mlx5dr_action_create_generic(ctx, flags, MLX5DR_ACTION_TYP_DROP);
1397 	if (!action)
1398 		return NULL;
1399 
1400 	if (mlx5dr_action_is_hws_flags(flags)) {
1401 		ret = mlx5dr_action_create_stcs(action, NULL);
1402 		if (ret)
1403 			goto free_action;
1404 	}
1405 
1406 	return action;
1407 
1408 free_action:
1409 	simple_free(action);
1410 	return NULL;
1411 }
1412 
1413 struct mlx5dr_action *
1414 mlx5dr_action_create_default_miss(struct mlx5dr_context *ctx,
1415 				  uint32_t flags)
1416 {
1417 	struct mlx5dr_action *action;
1418 	int ret;
1419 
1420 	action = mlx5dr_action_create_generic(ctx, flags, MLX5DR_ACTION_TYP_MISS);
1421 	if (!action)
1422 		return NULL;
1423 
1424 	if (mlx5dr_action_is_hws_flags(flags)) {
1425 		ret = mlx5dr_action_create_stcs(action, NULL);
1426 		if (ret)
1427 			goto free_action;
1428 	}
1429 
1430 	return action;
1431 
1432 free_action:
1433 	simple_free(action);
1434 	return NULL;
1435 }
1436 
1437 struct mlx5dr_action *
1438 mlx5dr_action_create_tag(struct mlx5dr_context *ctx,
1439 			 uint32_t flags)
1440 {
1441 	struct mlx5dr_action *action;
1442 	int ret;
1443 
1444 	action = mlx5dr_action_create_generic(ctx, flags, MLX5DR_ACTION_TYP_TAG);
1445 	if (!action)
1446 		return NULL;
1447 
1448 	if (mlx5dr_action_is_hws_flags(flags)) {
1449 		ret = mlx5dr_action_create_stcs(action, NULL);
1450 		if (ret)
1451 			goto free_action;
1452 	}
1453 
1454 	return action;
1455 
1456 free_action:
1457 	simple_free(action);
1458 	return NULL;
1459 }
1460 
1461 struct mlx5dr_action *
1462 mlx5dr_action_create_last(struct mlx5dr_context *ctx,
1463 			  uint32_t flags)
1464 {
1465 	return mlx5dr_action_create_generic(ctx, flags, MLX5DR_ACTION_TYP_LAST);
1466 }
1467 
1468 static struct mlx5dr_action *
1469 mlx5dr_action_create_aso(struct mlx5dr_context *ctx,
1470 			 enum mlx5dr_action_type action_type,
1471 			 struct mlx5dr_devx_obj *devx_obj,
1472 			 uint8_t return_reg_id,
1473 			 uint32_t flags)
1474 {
1475 	struct mlx5dr_action *action;
1476 	int ret;
1477 
1478 	if (mlx5dr_action_is_root_flags(flags)) {
1479 		DR_LOG(ERR, "ASO action cannot be used over root table");
1480 		rte_errno = ENOTSUP;
1481 		return NULL;
1482 	}
1483 
1484 	action = mlx5dr_action_create_generic(ctx, flags, action_type);
1485 	if (!action)
1486 		return NULL;
1487 
1488 	action->aso.devx_obj = devx_obj;
1489 	action->aso.return_reg_id = return_reg_id;
1490 
1491 	ret = mlx5dr_action_create_stcs(action, devx_obj);
1492 	if (ret)
1493 		goto free_action;
1494 
1495 	return action;
1496 
1497 free_action:
1498 	simple_free(action);
1499 	return NULL;
1500 }
1501 
1502 struct mlx5dr_action *
1503 mlx5dr_action_create_aso_meter(struct mlx5dr_context *ctx,
1504 			       struct mlx5dr_devx_obj *devx_obj,
1505 			       uint8_t return_reg_id,
1506 			       uint32_t flags)
1507 {
1508 	return mlx5dr_action_create_aso(ctx, MLX5DR_ACTION_TYP_ASO_METER,
1509 					devx_obj, return_reg_id, flags);
1510 }
1511 
1512 struct mlx5dr_action *
1513 mlx5dr_action_create_aso_ct(struct mlx5dr_context *ctx,
1514 			    struct mlx5dr_devx_obj *devx_obj,
1515 			    uint8_t return_reg_id,
1516 			    uint32_t flags)
1517 {
1518 	return mlx5dr_action_create_aso(ctx, MLX5DR_ACTION_TYP_ASO_CT,
1519 					devx_obj, return_reg_id, flags);
1520 }
1521 
1522 struct mlx5dr_action *
1523 mlx5dr_action_create_counter(struct mlx5dr_context *ctx,
1524 			     struct mlx5dr_devx_obj *obj,
1525 			     uint32_t flags)
1526 {
1527 	struct mlx5dr_action *action;
1528 	int ret;
1529 
1530 	if (mlx5dr_action_is_hws_flags(flags) &&
1531 	    mlx5dr_action_is_root_flags(flags)) {
1532 		DR_LOG(ERR, "Same action cannot be used for root and non root");
1533 		rte_errno = ENOTSUP;
1534 		return NULL;
1535 	}
1536 
1537 	action = mlx5dr_action_create_generic(ctx, flags, MLX5DR_ACTION_TYP_CTR);
1538 	if (!action)
1539 		return NULL;
1540 
1541 	if (mlx5dr_action_is_root_flags(flags)) {
1542 		action->devx_obj = obj->obj;
1543 	} else {
1544 		ret = mlx5dr_action_create_stcs(action, obj);
1545 		if (ret)
1546 			goto free_action;
1547 	}
1548 
1549 	return action;
1550 
1551 free_action:
1552 	simple_free(action);
1553 	return NULL;
1554 }
1555 
1556 static int mlx5dr_action_create_dest_vport_hws(struct mlx5dr_context *ctx,
1557 					       struct mlx5dr_action *action,
1558 					       uint32_t ib_port_num)
1559 {
1560 	struct mlx5dr_cmd_query_vport_caps vport_caps = {0};
1561 	int ret;
1562 
1563 	ret = mlx5dr_cmd_query_ib_port(ctx->ibv_ctx, &vport_caps, ib_port_num);
1564 	if (ret) {
1565 		DR_LOG(ERR, "Failed querying port %d", ib_port_num);
1566 		return ret;
1567 	}
1568 	action->vport.vport_num = vport_caps.vport_num;
1569 	action->vport.esw_owner_vhca_id = vport_caps.esw_owner_vhca_id;
1570 
1571 	if (!ctx->caps->merged_eswitch &&
1572 	    action->vport.esw_owner_vhca_id != ctx->caps->vhca_id) {
1573 		DR_LOG(ERR, "Not merged-eswitch (%d), not allowed to send to other vhca_id (%d)",
1574 		       ctx->caps->vhca_id, action->vport.esw_owner_vhca_id);
1575 		rte_errno = ENOTSUP;
1576 		return rte_errno;
1577 	}
1578 
1579 	ret = mlx5dr_action_create_stcs(action, NULL);
1580 	if (ret) {
1581 		DR_LOG(ERR, "Failed creating stc for port %d", ib_port_num);
1582 		return ret;
1583 	}
1584 
1585 	return 0;
1586 }
1587 
1588 struct mlx5dr_action *
1589 mlx5dr_action_create_dest_vport(struct mlx5dr_context *ctx,
1590 				uint32_t ib_port_num,
1591 				uint32_t flags)
1592 {
1593 	struct mlx5dr_action *action;
1594 	int ret;
1595 
1596 	if (!(flags & MLX5DR_ACTION_FLAG_HWS_FDB)) {
1597 		DR_LOG(ERR, "Vport action is supported for FDB only");
1598 		rte_errno = EINVAL;
1599 		return NULL;
1600 	}
1601 
1602 	action = mlx5dr_action_create_generic(ctx, flags, MLX5DR_ACTION_TYP_VPORT);
1603 	if (!action)
1604 		return NULL;
1605 
1606 	ret = mlx5dr_action_create_dest_vport_hws(ctx, action, ib_port_num);
1607 	if (ret) {
1608 		DR_LOG(ERR, "Failed to create vport action HWS");
1609 		goto free_action;
1610 	}
1611 
1612 	return action;
1613 
1614 free_action:
1615 	simple_free(action);
1616 	return NULL;
1617 }
1618 
1619 struct mlx5dr_action *
1620 mlx5dr_action_create_push_vlan(struct mlx5dr_context *ctx, uint32_t flags)
1621 {
1622 	struct mlx5dr_action *action;
1623 	int ret;
1624 
1625 	if (mlx5dr_action_is_root_flags(flags)) {
1626 		DR_LOG(ERR, "Push vlan action not supported for root");
1627 		rte_errno = ENOTSUP;
1628 		return NULL;
1629 	}
1630 
1631 	action = mlx5dr_action_create_generic(ctx, flags, MLX5DR_ACTION_TYP_PUSH_VLAN);
1632 	if (!action)
1633 		return NULL;
1634 
1635 	ret = mlx5dr_action_create_stcs(action, NULL);
1636 	if (ret) {
1637 		DR_LOG(ERR, "Failed creating stc for push vlan");
1638 		goto free_action;
1639 	}
1640 
1641 	return action;
1642 
1643 free_action:
1644 	simple_free(action);
1645 	return NULL;
1646 }
1647 
1648 struct mlx5dr_action *
1649 mlx5dr_action_create_pop_vlan(struct mlx5dr_context *ctx, uint32_t flags)
1650 {
1651 	struct mlx5dr_action *action;
1652 	int ret;
1653 
1654 	if (mlx5dr_action_is_root_flags(flags)) {
1655 		DR_LOG(ERR, "Pop vlan action not supported for root");
1656 		rte_errno = ENOTSUP;
1657 		return NULL;
1658 	}
1659 	action = mlx5dr_action_create_generic(ctx, flags, MLX5DR_ACTION_TYP_POP_VLAN);
1660 	if (!action)
1661 		return NULL;
1662 
1663 	ret = mlx5dr_action_get_shared_stc(action, MLX5DR_CONTEXT_SHARED_STC_DOUBLE_POP);
1664 	if (ret) {
1665 		DR_LOG(ERR, "Failed to create remove stc for reformat");
1666 		goto free_action;
1667 	}
1668 
1669 	ret = mlx5dr_action_create_stcs(action, NULL);
1670 	if (ret) {
1671 		DR_LOG(ERR, "Failed creating stc for pop vlan");
1672 		goto free_shared;
1673 	}
1674 
1675 	return action;
1676 
1677 free_shared:
1678 	mlx5dr_action_put_shared_stc(action, MLX5DR_CONTEXT_SHARED_STC_DOUBLE_POP);
1679 free_action:
1680 	simple_free(action);
1681 	return NULL;
1682 }
1683 
1684 static int
1685 mlx5dr_action_conv_reformat_to_verbs(uint32_t action_type,
1686 				     uint32_t *verb_reformat_type)
1687 {
1688 	switch (action_type) {
1689 	case MLX5DR_ACTION_TYP_REFORMAT_TNL_L2_TO_L2:
1690 		*verb_reformat_type =
1691 			MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TUNNEL_TO_L2;
1692 		return 0;
1693 	case MLX5DR_ACTION_TYP_REFORMAT_L2_TO_TNL_L2:
1694 		*verb_reformat_type =
1695 			MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L2_TUNNEL;
1696 		return 0;
1697 	case MLX5DR_ACTION_TYP_REFORMAT_TNL_L3_TO_L2:
1698 		*verb_reformat_type =
1699 			MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L3_TUNNEL_TO_L2;
1700 		return 0;
1701 	case MLX5DR_ACTION_TYP_REFORMAT_L2_TO_TNL_L3:
1702 		*verb_reformat_type =
1703 			MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L3_TUNNEL;
1704 		return 0;
1705 	default:
1706 		DR_LOG(ERR, "Invalid root reformat action type");
1707 		rte_errno = EINVAL;
1708 		return rte_errno;
1709 	}
1710 }
1711 
1712 static int
1713 mlx5dr_action_conv_flags_to_ft_type(uint32_t flags, enum mlx5dv_flow_table_type *ft_type)
1714 {
1715 	if (flags & (MLX5DR_ACTION_FLAG_ROOT_RX | MLX5DR_ACTION_FLAG_HWS_RX)) {
1716 		*ft_type = MLX5DV_FLOW_TABLE_TYPE_NIC_RX;
1717 	} else if (flags & (MLX5DR_ACTION_FLAG_ROOT_TX | MLX5DR_ACTION_FLAG_HWS_TX)) {
1718 		*ft_type = MLX5DV_FLOW_TABLE_TYPE_NIC_TX;
1719 #ifdef HAVE_MLX5DV_FLOW_MATCHER_FT_TYPE
1720 	} else if (flags & (MLX5DR_ACTION_FLAG_ROOT_FDB | MLX5DR_ACTION_FLAG_HWS_FDB)) {
1721 		*ft_type = MLX5DV_FLOW_TABLE_TYPE_FDB;
1722 #endif
1723 	} else {
1724 		rte_errno = ENOTSUP;
1725 		return 1;
1726 	}
1727 
1728 	return 0;
1729 }
1730 
1731 static int
1732 mlx5dr_action_create_reformat_root(struct mlx5dr_action *action,
1733 				   size_t data_sz,
1734 				   void *data)
1735 {
1736 	enum mlx5dv_flow_table_type ft_type = 0; /*fix compilation warn*/
1737 	uint32_t verb_reformat_type = 0;
1738 	struct ibv_context *ibv_ctx;
1739 	int ret;
1740 
1741 	/* Convert action to FT type and verbs reformat type */
1742 	ret = mlx5dr_action_conv_flags_to_ft_type(action->flags, &ft_type);
1743 	if (ret)
1744 		return rte_errno;
1745 
1746 	ret = mlx5dr_action_conv_reformat_to_verbs(action->type, &verb_reformat_type);
1747 	if (ret)
1748 		return rte_errno;
1749 
1750 	/* Create the reformat type for root table */
1751 	ibv_ctx = mlx5dr_context_get_local_ibv(action->ctx);
1752 	action->flow_action =
1753 		mlx5_glue->dv_create_flow_action_packet_reformat_root(ibv_ctx,
1754 								      data_sz,
1755 								      data,
1756 								      verb_reformat_type,
1757 								      ft_type);
1758 	if (!action->flow_action) {
1759 		DR_LOG(ERR, "Failed to create dv_create_flow reformat");
1760 		rte_errno = errno;
1761 		return rte_errno;
1762 	}
1763 
1764 	return 0;
1765 }
1766 
1767 static int
1768 mlx5dr_action_handle_insert_with_ptr(struct mlx5dr_action *action,
1769 				     uint8_t num_of_hdrs,
1770 				     struct mlx5dr_action_reformat_header *hdrs,
1771 				     uint32_t log_bulk_sz, uint32_t reparse)
1772 {
1773 	struct mlx5dr_devx_obj *arg_obj;
1774 	size_t max_sz = 0;
1775 	int ret, i;
1776 
1777 	for (i = 0; i < num_of_hdrs; i++) {
1778 		if (hdrs[i].sz % W_SIZE != 0) {
1779 			DR_LOG(ERR, "Header data size should be in WORD granularity");
1780 			rte_errno = EINVAL;
1781 			return rte_errno;
1782 		}
1783 		max_sz = RTE_MAX(hdrs[i].sz, max_sz);
1784 	}
1785 
1786 	/* Allocate single shared arg object for all headers */
1787 	arg_obj = mlx5dr_arg_create(action->ctx,
1788 				    hdrs->data,
1789 				    max_sz,
1790 				    log_bulk_sz,
1791 				    action->flags & MLX5DR_ACTION_FLAG_SHARED);
1792 	if (!arg_obj)
1793 		return rte_errno;
1794 
1795 	for (i = 0; i < num_of_hdrs; i++) {
1796 		action[i].reformat.arg_obj = arg_obj;
1797 		action[i].reformat.header_size = hdrs[i].sz;
1798 		action[i].reformat.num_of_hdrs = num_of_hdrs;
1799 		action[i].reformat.max_hdr_sz = max_sz;
1800 
1801 		if (action[i].type == MLX5DR_ACTION_TYP_REFORMAT_L2_TO_TNL_L2 ||
1802 		    action[i].type == MLX5DR_ACTION_TYP_REFORMAT_L2_TO_TNL_L3) {
1803 			action[i].reformat.anchor = MLX5_HEADER_ANCHOR_PACKET_START;
1804 			action[i].reformat.offset = 0;
1805 			action[i].reformat.encap = 1;
1806 			action[i].reformat.push_esp = 0;
1807 		}
1808 
1809 		if (likely(reparse == MLX5DR_ACTION_STC_REPARSE_DEFAULT))
1810 			action[i].reformat.require_reparse = true;
1811 		else if (reparse == MLX5DR_ACTION_STC_REPARSE_ON)
1812 			action[i].reformat.require_reparse = true;
1813 
1814 		ret = mlx5dr_action_create_stcs(&action[i], NULL);
1815 		if (ret) {
1816 			DR_LOG(ERR, "Failed to create stc for reformat");
1817 			goto free_stc;
1818 		}
1819 	}
1820 
1821 	return 0;
1822 
1823 free_stc:
1824 	while (i--)
1825 		mlx5dr_action_destroy_stcs(&action[i]);
1826 
1827 	mlx5dr_cmd_destroy_obj(arg_obj);
1828 	return ret;
1829 }
1830 
1831 static int
1832 mlx5dr_action_handle_l2_to_tunnel_l3(struct mlx5dr_action *action,
1833 				     uint8_t num_of_hdrs,
1834 				     struct mlx5dr_action_reformat_header *hdrs,
1835 				     uint32_t log_bulk_sz)
1836 {
1837 	int ret;
1838 
1839 	/* The action is remove-l2-header + insert-l3-header */
1840 	ret = mlx5dr_action_get_shared_stc(action, MLX5DR_CONTEXT_SHARED_STC_DECAP_L3);
1841 	if (ret) {
1842 		DR_LOG(ERR, "Failed to create remove stc for reformat");
1843 		return ret;
1844 	}
1845 
1846 	/* Reuse the insert with pointer for the L2L3 header */
1847 	ret = mlx5dr_action_handle_insert_with_ptr(action,
1848 						   num_of_hdrs,
1849 						   hdrs,
1850 						   log_bulk_sz,
1851 						   MLX5DR_ACTION_STC_REPARSE_DEFAULT);
1852 	if (ret)
1853 		goto put_shared_stc;
1854 
1855 	return 0;
1856 
1857 put_shared_stc:
1858 	mlx5dr_action_put_shared_stc(action, MLX5DR_CONTEXT_SHARED_STC_DECAP_L3);
1859 	return ret;
1860 }
1861 
1862 static void mlx5dr_action_prepare_decap_l3_actions(size_t data_sz,
1863 						   uint8_t *mh_data,
1864 						   int *num_of_actions)
1865 {
1866 	int actions;
1867 	uint32_t i;
1868 
1869 	/* Remove L2L3 outer headers */
1870 	MLX5_SET(stc_ste_param_remove, mh_data, action_type,
1871 		 MLX5_MODIFICATION_TYPE_REMOVE);
1872 	MLX5_SET(stc_ste_param_remove, mh_data, decap, 0x1);
1873 	MLX5_SET(stc_ste_param_remove, mh_data, remove_start_anchor,
1874 		 MLX5_HEADER_ANCHOR_PACKET_START);
1875 	MLX5_SET(stc_ste_param_remove, mh_data, remove_end_anchor,
1876 		 MLX5_HEADER_ANCHOR_INNER_IPV6_IPV4);
1877 	mh_data += MLX5DR_ACTION_DOUBLE_SIZE; /* Assume every action is 2 dw */
1878 	actions = 1;
1879 
1880 	/* Add the new header using inline action 4Byte at a time, the header
1881 	 * is added in reversed order to the beginning of the packet to avoid
1882 	 * incorrect parsing by the HW. Since header is 14B or 18B an extra
1883 	 * two bytes are padded and later removed.
1884 	 */
1885 	for (i = 0; i < data_sz / MLX5DR_ACTION_INLINE_DATA_SIZE + 1; i++) {
1886 		MLX5_SET(stc_ste_param_insert, mh_data, action_type,
1887 			 MLX5_MODIFICATION_TYPE_INSERT);
1888 		MLX5_SET(stc_ste_param_insert, mh_data, inline_data, 0x1);
1889 		MLX5_SET(stc_ste_param_insert, mh_data, insert_anchor,
1890 			 MLX5_HEADER_ANCHOR_PACKET_START);
1891 		MLX5_SET(stc_ste_param_insert, mh_data, insert_size, 2);
1892 		mh_data += MLX5DR_ACTION_DOUBLE_SIZE;
1893 		actions++;
1894 	}
1895 
1896 	/* Remove first 2 extra bytes */
1897 	MLX5_SET(stc_ste_param_remove_words, mh_data, action_type,
1898 		 MLX5_MODIFICATION_TYPE_REMOVE_WORDS);
1899 	MLX5_SET(stc_ste_param_remove_words, mh_data, remove_start_anchor,
1900 		 MLX5_HEADER_ANCHOR_PACKET_START);
1901 	/* The hardware expects here size in words (2 bytes) */
1902 	MLX5_SET(stc_ste_param_remove_words, mh_data, remove_size, 1);
1903 	actions++;
1904 
1905 	*num_of_actions = actions;
1906 }
1907 
1908 static int
1909 mlx5dr_action_handle_tunnel_l3_to_l2(struct mlx5dr_action *action,
1910 				     uint8_t num_of_hdrs,
1911 				     struct mlx5dr_action_reformat_header *hdrs,
1912 				     uint32_t log_bulk_sz)
1913 {
1914 	uint8_t mh_data[MLX5DR_ACTION_REFORMAT_DATA_SIZE] = {0};
1915 	struct mlx5dr_devx_obj *arg_obj, *pat_obj;
1916 	struct mlx5dr_context *ctx = action->ctx;
1917 	int num_of_actions;
1918 	int mh_data_size;
1919 	int ret, i;
1920 
1921 	for (i = 0; i < num_of_hdrs; i++) {
1922 		if (hdrs[i].sz != MLX5DR_ACTION_HDR_LEN_L2 &&
1923 		    hdrs[i].sz != MLX5DR_ACTION_HDR_LEN_L2_W_VLAN) {
1924 			DR_LOG(ERR, "Data size is not supported for decap-l3");
1925 			rte_errno = EINVAL;
1926 			return rte_errno;
1927 		}
1928 	}
1929 
1930 	/* Create a full modify header action list in case shared */
1931 	mlx5dr_action_prepare_decap_l3_actions(hdrs->sz, mh_data, &num_of_actions);
1932 
1933 	if (action->flags & MLX5DR_ACTION_FLAG_SHARED)
1934 		mlx5dr_action_prepare_decap_l3_data(hdrs->data, mh_data, num_of_actions);
1935 
1936 	/* All DecapL3 cases require the same max arg size */
1937 	arg_obj = mlx5dr_arg_create_modify_header_arg(ctx,
1938 						      (__be64 *)mh_data,
1939 						      num_of_actions,
1940 						      log_bulk_sz,
1941 						      action->flags & MLX5DR_ACTION_FLAG_SHARED);
1942 	if (!arg_obj)
1943 		return rte_errno;
1944 
1945 	for (i = 0; i < num_of_hdrs; i++) {
1946 		memset(mh_data, 0, MLX5DR_ACTION_REFORMAT_DATA_SIZE);
1947 		mlx5dr_action_prepare_decap_l3_actions(hdrs[i].sz, mh_data, &num_of_actions);
1948 		mh_data_size = num_of_actions * MLX5DR_MODIFY_ACTION_SIZE;
1949 
1950 		pat_obj = mlx5dr_pat_get_pattern(ctx, (__be64 *)mh_data, mh_data_size);
1951 		if (!pat_obj) {
1952 			DR_LOG(ERR, "Failed to allocate pattern for DecapL3");
1953 			goto free_stc_and_pat;
1954 		}
1955 
1956 		action[i].modify_header.max_num_of_actions = num_of_actions;
1957 		action[i].modify_header.num_of_actions = num_of_actions;
1958 		action[i].modify_header.num_of_patterns = num_of_hdrs;
1959 		action[i].modify_header.arg_obj = arg_obj;
1960 		action[i].modify_header.pat_obj = pat_obj;
1961 		action[i].modify_header.require_reparse =
1962 			mlx5dr_pat_require_reparse((__be64 *)mh_data, num_of_actions);
1963 
1964 		ret = mlx5dr_action_create_stcs(&action[i], NULL);
1965 		if (ret) {
1966 			mlx5dr_pat_put_pattern(ctx, pat_obj);
1967 			goto free_stc_and_pat;
1968 		}
1969 	}
1970 
1971 	return 0;
1972 
1973 
1974 free_stc_and_pat:
1975 	while (i--) {
1976 		mlx5dr_action_destroy_stcs(&action[i]);
1977 		mlx5dr_pat_put_pattern(ctx, action[i].modify_header.pat_obj);
1978 	}
1979 
1980 	mlx5dr_cmd_destroy_obj(arg_obj);
1981 	return 0;
1982 }
1983 
1984 static int
1985 mlx5dr_action_create_reformat_hws(struct mlx5dr_action *action,
1986 				  uint8_t num_of_hdrs,
1987 				  struct mlx5dr_action_reformat_header *hdrs,
1988 				  uint32_t bulk_size)
1989 {
1990 	int ret;
1991 
1992 	switch (action->type) {
1993 	case MLX5DR_ACTION_TYP_REFORMAT_TNL_L2_TO_L2:
1994 		ret = mlx5dr_action_create_stcs(action, NULL);
1995 		break;
1996 	case MLX5DR_ACTION_TYP_REFORMAT_L2_TO_TNL_L2:
1997 		ret = mlx5dr_action_handle_insert_with_ptr(action, num_of_hdrs, hdrs, bulk_size,
1998 							   MLX5DR_ACTION_STC_REPARSE_DEFAULT);
1999 		break;
2000 	case MLX5DR_ACTION_TYP_REFORMAT_L2_TO_TNL_L3:
2001 		ret = mlx5dr_action_handle_l2_to_tunnel_l3(action, num_of_hdrs, hdrs, bulk_size);
2002 		break;
2003 	case MLX5DR_ACTION_TYP_REFORMAT_TNL_L3_TO_L2:
2004 		ret = mlx5dr_action_handle_tunnel_l3_to_l2(action, num_of_hdrs, hdrs, bulk_size);
2005 		break;
2006 	default:
2007 		DR_LOG(ERR, "Invalid HWS reformat action type");
2008 		rte_errno = EINVAL;
2009 		return rte_errno;
2010 	}
2011 
2012 	return ret;
2013 }
2014 
2015 struct mlx5dr_action *
2016 mlx5dr_action_create_reformat(struct mlx5dr_context *ctx,
2017 			      enum mlx5dr_action_type reformat_type,
2018 			      uint8_t num_of_hdrs,
2019 			      struct mlx5dr_action_reformat_header *hdrs,
2020 			      uint32_t log_bulk_size,
2021 			      uint32_t flags)
2022 {
2023 	struct mlx5dr_action *action;
2024 	int ret;
2025 
2026 	if (!num_of_hdrs) {
2027 		DR_LOG(ERR, "Reformat num_of_hdrs cannot be zero");
2028 		rte_errno = EINVAL;
2029 		return NULL;
2030 	}
2031 
2032 	action = mlx5dr_action_create_generic_bulk(ctx, flags, reformat_type, num_of_hdrs);
2033 	if (!action)
2034 		return NULL;
2035 
2036 	if (mlx5dr_action_is_root_flags(flags)) {
2037 		if (log_bulk_size) {
2038 			DR_LOG(ERR, "Bulk reformat not supported over root");
2039 			rte_errno = ENOTSUP;
2040 			goto free_action;
2041 		}
2042 
2043 		ret = mlx5dr_action_create_reformat_root(action,
2044 							 hdrs ? hdrs->sz : 0,
2045 							 hdrs ? hdrs->data : NULL);
2046 		if (ret) {
2047 			DR_LOG(ERR, "Failed to create root reformat action");
2048 			goto free_action;
2049 		}
2050 
2051 		return action;
2052 	}
2053 
2054 	if (!mlx5dr_action_is_hws_flags(flags) ||
2055 	    ((flags & MLX5DR_ACTION_FLAG_SHARED) && (log_bulk_size || num_of_hdrs > 1))) {
2056 		DR_LOG(ERR, "Reformat flags don't fit HWS (flags: 0x%x)", flags);
2057 		rte_errno = EINVAL;
2058 		goto free_action;
2059 	}
2060 
2061 	ret = mlx5dr_action_create_reformat_hws(action, num_of_hdrs, hdrs, log_bulk_size);
2062 	if (ret) {
2063 		DR_LOG(ERR, "Failed to create HWS reformat action");
2064 		goto free_action;
2065 	}
2066 
2067 	return action;
2068 
2069 free_action:
2070 	simple_free(action);
2071 	return NULL;
2072 }
2073 
2074 static int
2075 mlx5dr_action_create_modify_header_root(struct mlx5dr_action *action,
2076 					size_t actions_sz,
2077 					__be64 *actions)
2078 {
2079 	enum mlx5dv_flow_table_type ft_type = 0;
2080 	struct ibv_context *local_ibv_ctx;
2081 	int ret;
2082 
2083 	ret = mlx5dr_action_conv_flags_to_ft_type(action->flags, &ft_type);
2084 	if (ret)
2085 		return rte_errno;
2086 
2087 	local_ibv_ctx = mlx5dr_context_get_local_ibv(action->ctx);
2088 
2089 	action->flow_action =
2090 		mlx5_glue->dv_create_flow_action_modify_header_root(local_ibv_ctx,
2091 								    actions_sz,
2092 								    (uint64_t *)actions,
2093 								    ft_type);
2094 	if (!action->flow_action) {
2095 		rte_errno = errno;
2096 		return rte_errno;
2097 	}
2098 
2099 	return 0;
2100 }
2101 
2102 static int
2103 mlx5dr_action_create_modify_header_hws(struct mlx5dr_action *action,
2104 				       uint8_t num_of_patterns,
2105 				       struct mlx5dr_action_mh_pattern *pattern,
2106 				       uint32_t log_bulk_size,
2107 				       uint32_t reparse)
2108 {
2109 	struct mlx5dr_devx_obj *pat_obj, *arg_obj = NULL;
2110 	struct mlx5dr_context *ctx = action->ctx;
2111 	uint16_t num_actions, max_mh_actions = 0;
2112 	int i, ret;
2113 
2114 	/* Calculate maximum number of mh actions for shared arg allocation */
2115 	for (i = 0; i < num_of_patterns; i++)
2116 		max_mh_actions = RTE_MAX(max_mh_actions, pattern[i].sz / MLX5DR_MODIFY_ACTION_SIZE);
2117 
2118 	/* Allocate single shared arg for all patterns based on the max size */
2119 	if (max_mh_actions > 1) {
2120 		arg_obj = mlx5dr_arg_create_modify_header_arg(ctx,
2121 							      pattern->data,
2122 							      max_mh_actions,
2123 							      log_bulk_size,
2124 							      action->flags &
2125 							      MLX5DR_ACTION_FLAG_SHARED);
2126 		if (!arg_obj)
2127 			return rte_errno;
2128 	}
2129 
2130 	for (i = 0; i < num_of_patterns; i++) {
2131 		if (!mlx5dr_pat_verify_actions(pattern[i].data, pattern[i].sz)) {
2132 			DR_LOG(ERR, "Fail to verify pattern modify actions");
2133 			rte_errno = EINVAL;
2134 			goto free_stc_and_pat;
2135 		}
2136 
2137 		num_actions = pattern[i].sz / MLX5DR_MODIFY_ACTION_SIZE;
2138 		action[i].modify_header.num_of_patterns = num_of_patterns;
2139 		action[i].modify_header.max_num_of_actions = max_mh_actions;
2140 		action[i].modify_header.num_of_actions = num_actions;
2141 
2142 		if (likely(reparse == MLX5DR_ACTION_STC_REPARSE_DEFAULT))
2143 			action[i].modify_header.require_reparse =
2144 				mlx5dr_pat_require_reparse(pattern[i].data, num_actions);
2145 		else if (reparse == MLX5DR_ACTION_STC_REPARSE_ON)
2146 			action[i].modify_header.require_reparse = true;
2147 
2148 		if (num_actions == 1) {
2149 			pat_obj = NULL;
2150 			/* Optimize single modify action to be used inline */
2151 			action[i].modify_header.single_action = pattern[i].data[0];
2152 			action[i].modify_header.single_action_type =
2153 				MLX5_GET(set_action_in, pattern[i].data, action_type);
2154 		} else {
2155 			/* Multiple modify actions require a pattern */
2156 			pat_obj = mlx5dr_pat_get_pattern(ctx, pattern[i].data, pattern[i].sz);
2157 			if (!pat_obj) {
2158 				DR_LOG(ERR, "Failed to allocate pattern for modify header");
2159 				goto free_stc_and_pat;
2160 			}
2161 
2162 			action[i].modify_header.arg_obj = arg_obj;
2163 			action[i].modify_header.pat_obj = pat_obj;
2164 		}
2165 		/* Allocate STC for each action representing a header */
2166 		ret = mlx5dr_action_create_stcs(&action[i], NULL);
2167 		if (ret) {
2168 			if (pat_obj)
2169 				mlx5dr_pat_put_pattern(ctx, pat_obj);
2170 			goto free_stc_and_pat;
2171 		}
2172 	}
2173 
2174 	return 0;
2175 
2176 free_stc_and_pat:
2177 	while (i--) {
2178 		mlx5dr_action_destroy_stcs(&action[i]);
2179 		if (action[i].modify_header.pat_obj)
2180 			mlx5dr_pat_put_pattern(ctx, action[i].modify_header.pat_obj);
2181 	}
2182 
2183 	if (arg_obj)
2184 		mlx5dr_cmd_destroy_obj(arg_obj);
2185 
2186 	return rte_errno;
2187 }
2188 
2189 struct mlx5dr_action *
2190 mlx5dr_action_create_modify_header_reparse(struct mlx5dr_context *ctx,
2191 					   uint8_t num_of_patterns,
2192 					   struct mlx5dr_action_mh_pattern *patterns,
2193 					   uint32_t log_bulk_size,
2194 					   uint32_t flags, uint32_t reparse)
2195 {
2196 	struct mlx5dr_action *action;
2197 	int ret;
2198 
2199 	if (!num_of_patterns) {
2200 		DR_LOG(ERR, "Invalid number of patterns");
2201 		rte_errno = ENOTSUP;
2202 		return NULL;
2203 	}
2204 
2205 	action = mlx5dr_action_create_generic_bulk(ctx, flags,
2206 						   MLX5DR_ACTION_TYP_MODIFY_HDR,
2207 						   num_of_patterns);
2208 	if (!action)
2209 		return NULL;
2210 
2211 	if (mlx5dr_action_is_root_flags(flags)) {
2212 		if (log_bulk_size) {
2213 			DR_LOG(ERR, "Bulk modify-header not supported over root");
2214 			rte_errno = ENOTSUP;
2215 			goto free_action;
2216 		}
2217 
2218 		if (num_of_patterns != 1) {
2219 			DR_LOG(ERR, "Only a single pattern supported over root");
2220 			rte_errno = ENOTSUP;
2221 			goto free_action;
2222 		}
2223 
2224 		ret = mlx5dr_action_create_modify_header_root(action,
2225 							      patterns->sz,
2226 							      patterns->data);
2227 		if (ret)
2228 			goto free_action;
2229 
2230 		return action;
2231 	}
2232 
2233 	if ((flags & MLX5DR_ACTION_FLAG_SHARED) && (log_bulk_size || num_of_patterns > 1)) {
2234 		DR_LOG(ERR, "Action cannot be shared with requested pattern or size");
2235 		rte_errno = EINVAL;
2236 		goto free_action;
2237 	}
2238 
2239 	ret = mlx5dr_action_create_modify_header_hws(action,
2240 						     num_of_patterns,
2241 						     patterns,
2242 						     log_bulk_size,
2243 						     reparse);
2244 	if (ret)
2245 		goto free_action;
2246 
2247 	return action;
2248 
2249 free_action:
2250 	simple_free(action);
2251 	return NULL;
2252 }
2253 
2254 struct mlx5dr_action *
2255 mlx5dr_action_create_modify_header(struct mlx5dr_context *ctx,
2256 				   uint8_t num_of_patterns,
2257 				   struct mlx5dr_action_mh_pattern *patterns,
2258 				   uint32_t log_bulk_size,
2259 				   uint32_t flags)
2260 {
2261 	return mlx5dr_action_create_modify_header_reparse(ctx, num_of_patterns, patterns,
2262 							  log_bulk_size, flags,
2263 							  MLX5DR_ACTION_STC_REPARSE_DEFAULT);
2264 }
2265 static struct mlx5dr_devx_obj *
2266 mlx5dr_action_dest_array_process_reformat(struct mlx5dr_context *ctx,
2267 					  enum mlx5dr_action_type type,
2268 					  void *reformat_data,
2269 					  size_t reformat_data_sz)
2270 {
2271 	struct mlx5dr_cmd_packet_reformat_create_attr pr_attr = {0};
2272 	struct mlx5dr_devx_obj *reformat_devx_obj;
2273 
2274 	if (!reformat_data || !reformat_data_sz) {
2275 		DR_LOG(ERR, "Empty reformat action or data");
2276 		rte_errno = EINVAL;
2277 		return NULL;
2278 	}
2279 
2280 	switch (type) {
2281 	case MLX5DR_ACTION_TYP_REFORMAT_L2_TO_TNL_L2:
2282 		pr_attr.type = MLX5_PACKET_REFORMAT_CONTEXT_REFORMAT_TYPE_L2_TO_L2_TUNNEL;
2283 		break;
2284 	case MLX5DR_ACTION_TYP_REFORMAT_L2_TO_TNL_L3:
2285 		pr_attr.type = MLX5_PACKET_REFORMAT_CONTEXT_REFORMAT_TYPE_L2_TO_L3_TUNNEL;
2286 		break;
2287 	default:
2288 		DR_LOG(ERR, "Invalid value for reformat type");
2289 		rte_errno = EINVAL;
2290 		return NULL;
2291 	}
2292 	pr_attr.reformat_param_0 = 0;
2293 	pr_attr.data_sz = reformat_data_sz;
2294 	pr_attr.data = reformat_data;
2295 
2296 	reformat_devx_obj = mlx5dr_cmd_packet_reformat_create(ctx->ibv_ctx, &pr_attr);
2297 	if (!reformat_devx_obj)
2298 		return NULL;
2299 
2300 	return reformat_devx_obj;
2301 }
2302 
2303 struct mlx5dr_action *
2304 mlx5dr_action_create_dest_array(struct mlx5dr_context *ctx,
2305 				size_t num_dest,
2306 				struct mlx5dr_action_dest_attr *dests,
2307 				uint32_t flags)
2308 {
2309 	struct mlx5dr_cmd_set_fte_dest *dest_list = NULL;
2310 	struct mlx5dr_devx_obj *packet_reformat = NULL;
2311 	struct mlx5dr_cmd_ft_create_attr ft_attr = {0};
2312 	struct mlx5dr_cmd_set_fte_attr fte_attr = {0};
2313 	struct mlx5dr_cmd_forward_tbl *fw_island;
2314 	enum mlx5dr_table_type table_type;
2315 	struct mlx5dr_action *action;
2316 	uint32_t i;
2317 	int ret;
2318 
2319 	if (num_dest <= 1) {
2320 		rte_errno = EINVAL;
2321 		DR_LOG(ERR, "Action must have multiple dests");
2322 		return NULL;
2323 	}
2324 
2325 	if (flags == (MLX5DR_ACTION_FLAG_HWS_RX | MLX5DR_ACTION_FLAG_SHARED)) {
2326 		ft_attr.type = FS_FT_NIC_RX;
2327 		ft_attr.level = MLX5_IFC_MULTI_PATH_FT_MAX_LEVEL - 1;
2328 		table_type = MLX5DR_TABLE_TYPE_NIC_RX;
2329 	} else if (flags == (MLX5DR_ACTION_FLAG_HWS_FDB | MLX5DR_ACTION_FLAG_SHARED)) {
2330 		ft_attr.type = FS_FT_FDB;
2331 		ft_attr.level = ctx->caps->fdb_ft.max_level - 1;
2332 		table_type = MLX5DR_TABLE_TYPE_FDB;
2333 	} else {
2334 		DR_LOG(ERR, "Action flags not supported");
2335 		rte_errno = ENOTSUP;
2336 		return NULL;
2337 	}
2338 
2339 	if (mlx5dr_context_shared_gvmi_used(ctx)) {
2340 		DR_LOG(ERR, "Cannot use this action in shared GVMI context");
2341 		rte_errno = ENOTSUP;
2342 		return NULL;
2343 	}
2344 
2345 	dest_list = simple_calloc(num_dest, sizeof(*dest_list));
2346 	if (!dest_list) {
2347 		DR_LOG(ERR, "Failed to allocate memory for destinations");
2348 		rte_errno = ENOMEM;
2349 		return NULL;
2350 	}
2351 
2352 	for (i = 0; i < num_dest; i++) {
2353 		enum mlx5dr_action_type *action_type = dests[i].action_type;
2354 
2355 		if (!mlx5dr_action_check_combo(dests[i].action_type, table_type)) {
2356 			DR_LOG(ERR, "Invalid combination of actions");
2357 			rte_errno = EINVAL;
2358 			goto free_dest_list;
2359 		}
2360 
2361 		for (; *action_type != MLX5DR_ACTION_TYP_LAST; action_type++) {
2362 			switch (*action_type) {
2363 			case MLX5DR_ACTION_TYP_TBL:
2364 				dest_list[i].destination_type =
2365 					MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
2366 				dest_list[i].destination_id = dests[i].dest->devx_dest.devx_obj->id;
2367 				fte_attr.action_flags |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
2368 				fte_attr.ignore_flow_level = 1;
2369 				break;
2370 			case MLX5DR_ACTION_TYP_MISS:
2371 				if (table_type != MLX5DR_TABLE_TYPE_FDB) {
2372 					DR_LOG(ERR, "Miss action supported for FDB only");
2373 					rte_errno = ENOTSUP;
2374 					goto free_dest_list;
2375 				}
2376 				dest_list[i].destination_type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
2377 				dest_list[i].destination_id =
2378 					ctx->caps->eswitch_manager_vport_number;
2379 				fte_attr.action_flags |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
2380 				break;
2381 			case MLX5DR_ACTION_TYP_VPORT:
2382 				dest_list[i].destination_type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
2383 				dest_list[i].destination_id = dests[i].dest->vport.vport_num;
2384 				fte_attr.action_flags |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
2385 				if (ctx->caps->merged_eswitch) {
2386 					dest_list[i].ext_flags |=
2387 						MLX5DR_CMD_EXT_DEST_ESW_OWNER_VHCA_ID;
2388 					dest_list[i].esw_owner_vhca_id =
2389 						dests[i].dest->vport.esw_owner_vhca_id;
2390 				}
2391 				break;
2392 			case MLX5DR_ACTION_TYP_TIR:
2393 				dest_list[i].destination_type = MLX5_FLOW_DESTINATION_TYPE_TIR;
2394 				dest_list[i].destination_id = dests[i].dest->devx_dest.devx_obj->id;
2395 				fte_attr.action_flags |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
2396 				break;
2397 			case MLX5DR_ACTION_TYP_REFORMAT_L2_TO_TNL_L2:
2398 			case MLX5DR_ACTION_TYP_REFORMAT_L2_TO_TNL_L3:
2399 				packet_reformat = mlx5dr_action_dest_array_process_reformat
2400 							(ctx,
2401 							 *action_type,
2402 							 dests[i].reformat.reformat_data,
2403 							 dests[i].reformat.reformat_data_sz);
2404 				if (!packet_reformat)
2405 					goto free_dest_list;
2406 
2407 				dest_list[i].ext_flags |= MLX5DR_CMD_EXT_DEST_REFORMAT;
2408 				dest_list[i].ext_reformat = packet_reformat;
2409 				ft_attr.reformat_en = true;
2410 				fte_attr.extended_dest = 1;
2411 				break;
2412 			default:
2413 				DR_LOG(ERR, "Unsupported action in dest_array");
2414 				rte_errno = ENOTSUP;
2415 				goto free_dest_list;
2416 			}
2417 		}
2418 	}
2419 	fte_attr.dests_num = num_dest;
2420 	fte_attr.dests = dest_list;
2421 
2422 	fw_island = mlx5dr_cmd_forward_tbl_create(ctx->ibv_ctx, &ft_attr, &fte_attr);
2423 	if (!fw_island)
2424 		goto free_dest_list;
2425 
2426 	action = mlx5dr_action_create_generic(ctx, flags, MLX5DR_ACTION_TYP_DEST_ARRAY);
2427 	if (!action)
2428 		goto destroy_fw_island;
2429 
2430 	ret = mlx5dr_action_create_stcs(action, fw_island->ft);
2431 	if (ret)
2432 		goto free_action;
2433 
2434 	action->dest_array.fw_island = fw_island;
2435 	action->dest_array.num_dest = num_dest;
2436 	action->dest_array.dest_list = dest_list;
2437 
2438 	return action;
2439 
2440 free_action:
2441 	simple_free(action);
2442 destroy_fw_island:
2443 	mlx5dr_cmd_forward_tbl_destroy(fw_island);
2444 free_dest_list:
2445 	for (i = 0; i < num_dest; i++) {
2446 		if (dest_list[i].ext_reformat)
2447 			mlx5dr_cmd_destroy_obj(dest_list[i].ext_reformat);
2448 	}
2449 	simple_free(dest_list);
2450 	return NULL;
2451 }
2452 
2453 struct mlx5dr_action *
2454 mlx5dr_action_create_dest_root(struct mlx5dr_context *ctx,
2455 			       uint16_t priority,
2456 			       uint32_t flags)
2457 {
2458 	struct mlx5dv_steering_anchor_attr attr = {0};
2459 	struct mlx5dv_steering_anchor *sa;
2460 	struct mlx5dr_action *action;
2461 	int ret;
2462 
2463 	if (mlx5dr_action_is_root_flags(flags)) {
2464 		DR_LOG(ERR, "Action flags must be only non root (HWS)");
2465 		rte_errno = ENOTSUP;
2466 		return NULL;
2467 	}
2468 
2469 	if (mlx5dr_context_shared_gvmi_used(ctx)) {
2470 		DR_LOG(ERR, "Cannot use this action in shared GVMI context");
2471 		rte_errno = ENOTSUP;
2472 		return NULL;
2473 	}
2474 
2475 	if (mlx5dr_action_conv_flags_to_ft_type(flags, &attr.ft_type))
2476 		return NULL;
2477 
2478 	attr.priority = priority;
2479 
2480 	sa = mlx5_glue->create_steering_anchor(ctx->ibv_ctx, &attr);
2481 	if (!sa) {
2482 		DR_LOG(ERR, "Creation of steering anchor failed");
2483 		return NULL;
2484 	}
2485 
2486 	action = mlx5dr_action_create_generic(ctx, flags, MLX5DR_ACTION_TYP_DEST_ROOT);
2487 	if (!action)
2488 		goto free_steering_anchor;
2489 
2490 	action->root_tbl.sa = sa;
2491 
2492 	ret = mlx5dr_action_create_stcs(action, NULL);
2493 	if (ret)
2494 		goto free_action;
2495 
2496 	return action;
2497 
2498 free_action:
2499 	simple_free(action);
2500 free_steering_anchor:
2501 	mlx5_glue->destroy_steering_anchor(sa);
2502 	return NULL;
2503 }
2504 
2505 static struct mlx5dr_action *
2506 mlx5dr_action_create_insert_header_reparse(struct mlx5dr_context *ctx,
2507 					   uint8_t num_of_hdrs,
2508 					   struct mlx5dr_action_insert_header *hdrs,
2509 					   uint32_t log_bulk_size,
2510 					   uint32_t flags, uint32_t reparse)
2511 {
2512 	struct mlx5dr_action_reformat_header *reformat_hdrs;
2513 	struct mlx5dr_action *action;
2514 	int i, ret;
2515 
2516 	if (!num_of_hdrs) {
2517 		DR_LOG(ERR, "Reformat num_of_hdrs cannot be zero");
2518 		rte_errno = EINVAL;
2519 		return NULL;
2520 	}
2521 
2522 	if (mlx5dr_action_is_root_flags(flags)) {
2523 		DR_LOG(ERR, "Dynamic reformat action not supported over root");
2524 		rte_errno = ENOTSUP;
2525 		return NULL;
2526 	}
2527 
2528 	if (!mlx5dr_action_is_hws_flags(flags) ||
2529 	    ((flags & MLX5DR_ACTION_FLAG_SHARED) && (log_bulk_size || num_of_hdrs > 1))) {
2530 		DR_LOG(ERR, "Reformat flags don't fit HWS (flags: 0x%x)", flags);
2531 		rte_errno = EINVAL;
2532 		return NULL;
2533 	}
2534 
2535 	action = mlx5dr_action_create_generic_bulk(ctx, flags,
2536 						   MLX5DR_ACTION_TYP_INSERT_HEADER,
2537 						   num_of_hdrs);
2538 	if (!action)
2539 		return NULL;
2540 
2541 	reformat_hdrs = simple_calloc(num_of_hdrs, sizeof(*reformat_hdrs));
2542 	if (!reformat_hdrs) {
2543 		DR_LOG(ERR, "Failed to allocate memory for reformat_hdrs");
2544 		rte_errno = ENOMEM;
2545 		goto free_action;
2546 	}
2547 
2548 	for (i = 0; i < num_of_hdrs; i++) {
2549 		if (hdrs[i].offset % W_SIZE != 0) {
2550 			DR_LOG(ERR, "Header offset should be in WORD granularity");
2551 			rte_errno = EINVAL;
2552 			goto free_reformat_hdrs;
2553 		}
2554 
2555 		action[i].reformat.anchor = hdrs[i].anchor;
2556 		action[i].reformat.encap = hdrs[i].encap;
2557 		action[i].reformat.push_esp = hdrs[i].push_esp;
2558 		action[i].reformat.offset = hdrs[i].offset;
2559 		reformat_hdrs[i].sz = hdrs[i].hdr.sz;
2560 		reformat_hdrs[i].data = hdrs[i].hdr.data;
2561 	}
2562 
2563 	ret = mlx5dr_action_handle_insert_with_ptr(action, num_of_hdrs,
2564 						   reformat_hdrs, log_bulk_size,
2565 						   reparse);
2566 	if (ret) {
2567 		DR_LOG(ERR, "Failed to create HWS reformat action");
2568 		goto free_reformat_hdrs;
2569 	}
2570 
2571 	simple_free(reformat_hdrs);
2572 
2573 	return action;
2574 
2575 free_reformat_hdrs:
2576 	simple_free(reformat_hdrs);
2577 free_action:
2578 	simple_free(action);
2579 	return NULL;
2580 }
2581 
2582 struct mlx5dr_action *
2583 mlx5dr_action_create_insert_header(struct mlx5dr_context *ctx,
2584 				   uint8_t num_of_hdrs,
2585 				   struct mlx5dr_action_insert_header *hdrs,
2586 				   uint32_t log_bulk_size,
2587 				   uint32_t flags)
2588 {
2589 	return mlx5dr_action_create_insert_header_reparse(ctx, num_of_hdrs, hdrs,
2590 							  log_bulk_size, flags,
2591 							  MLX5DR_ACTION_STC_REPARSE_DEFAULT);
2592 }
2593 
2594 struct mlx5dr_action *
2595 mlx5dr_action_create_remove_header(struct mlx5dr_context *ctx,
2596 				   struct mlx5dr_action_remove_header_attr *attr,
2597 				   uint32_t flags)
2598 {
2599 	struct mlx5dr_action *action;
2600 
2601 	if (mlx5dr_action_is_root_flags(flags)) {
2602 		DR_LOG(ERR, "Remove header action not supported over root");
2603 		rte_errno = ENOTSUP;
2604 		return NULL;
2605 	}
2606 
2607 	action = mlx5dr_action_create_generic(ctx, flags, MLX5DR_ACTION_TYP_REMOVE_HEADER);
2608 	if (!action)
2609 		return NULL;
2610 
2611 	switch (attr->type) {
2612 	case MLX5DR_ACTION_REMOVE_HEADER_TYPE_BY_HEADER:
2613 		action->remove_header.type = MLX5DR_ACTION_REMOVE_HEADER_TYPE_BY_HEADER;
2614 		action->remove_header.start_anchor = attr->by_anchor.start_anchor;
2615 		action->remove_header.end_anchor = attr->by_anchor.end_anchor;
2616 		action->remove_header.decap = attr->by_anchor.decap;
2617 		break;
2618 	case MLX5DR_ACTION_REMOVE_HEADER_TYPE_BY_OFFSET:
2619 		if (attr->by_offset.size % W_SIZE != 0) {
2620 			DR_LOG(ERR, "Invalid size, HW supports header remove in WORD granularity");
2621 			rte_errno = EINVAL;
2622 			goto free_action;
2623 		}
2624 
2625 		if (attr->by_offset.size > MLX5DR_ACTION_REMOVE_HEADER_MAX_SIZE) {
2626 			DR_LOG(ERR, "Header removal size limited to %u bytes",
2627 			       MLX5DR_ACTION_REMOVE_HEADER_MAX_SIZE);
2628 			rte_errno = EINVAL;
2629 			goto free_action;
2630 		}
2631 
2632 		action->remove_header.type = MLX5DR_ACTION_REMOVE_HEADER_TYPE_BY_OFFSET;
2633 		action->remove_header.start_anchor = attr->by_offset.start_anchor;
2634 		action->remove_header.num_of_words = attr->by_offset.size / W_SIZE;
2635 		break;
2636 	default:
2637 		DR_LOG(ERR, "Unsupported remove header type %u", attr->type);
2638 		rte_errno = ENOTSUP;
2639 		goto free_action;
2640 	}
2641 
2642 	if (mlx5dr_action_create_stcs(action, NULL))
2643 		goto free_action;
2644 
2645 	return action;
2646 
2647 free_action:
2648 	simple_free(action);
2649 	return NULL;
2650 }
2651 
2652 static void *
2653 mlx5dr_action_create_pop_ipv6_route_ext_mhdr1(struct mlx5dr_action *action)
2654 {
2655 	struct mlx5dr_action_mh_pattern pattern;
2656 	__be64 cmd[3] = {0};
2657 	uint16_t mod_id;
2658 
2659 	mod_id = flow_hw_get_ipv6_route_ext_mod_id_from_ctx(action->ctx, 0);
2660 	if (!mod_id) {
2661 		rte_errno = EINVAL;
2662 		return NULL;
2663 	}
2664 
2665 	/*
2666 	 * Backup ipv6_route_ext.next_hdr to ipv6_route_ext.seg_left.
2667 	 * Next_hdr will be copied to ipv6.protocol after pop done.
2668 	 */
2669 	MLX5_SET(copy_action_in, &cmd[0], action_type, MLX5_MODIFICATION_TYPE_COPY);
2670 	MLX5_SET(copy_action_in, &cmd[0], length, 8);
2671 	MLX5_SET(copy_action_in, &cmd[0], src_offset, 24);
2672 	MLX5_SET(copy_action_in, &cmd[0], src_field, mod_id);
2673 	MLX5_SET(copy_action_in, &cmd[0], dst_field, mod_id);
2674 
2675 	/* Add nop between the continuous same modify field id */
2676 	MLX5_SET(copy_action_in, &cmd[1], action_type, MLX5_MODIFICATION_TYPE_NOP);
2677 
2678 	/* Clear next_hdr for right checksum */
2679 	MLX5_SET(set_action_in, &cmd[2], action_type, MLX5_MODIFICATION_TYPE_SET);
2680 	MLX5_SET(set_action_in, &cmd[2], length, 8);
2681 	MLX5_SET(set_action_in, &cmd[2], offset, 24);
2682 	MLX5_SET(set_action_in, &cmd[2], field, mod_id);
2683 
2684 	pattern.data = cmd;
2685 	pattern.sz = sizeof(cmd);
2686 
2687 	return mlx5dr_action_create_modify_header_reparse(action->ctx, 1, &pattern, 0,
2688 							  action->flags,
2689 							  MLX5DR_ACTION_STC_REPARSE_ON);
2690 }
2691 
2692 static void *
2693 mlx5dr_action_create_pop_ipv6_route_ext_mhdr2(struct mlx5dr_action *action)
2694 {
2695 	enum mlx5_modification_field field[MLX5_ST_SZ_DW(definer_hl_ipv6_addr)] = {
2696 		MLX5_MODI_OUT_DIPV6_127_96,
2697 		MLX5_MODI_OUT_DIPV6_95_64,
2698 		MLX5_MODI_OUT_DIPV6_63_32,
2699 		MLX5_MODI_OUT_DIPV6_31_0
2700 	};
2701 	struct mlx5dr_action_mh_pattern pattern;
2702 	__be64 cmd[5] = {0};
2703 	uint16_t mod_id;
2704 	uint32_t i;
2705 
2706 	/* Copy ipv6_route_ext[first_segment].dst_addr by flex parser to ipv6.dst_addr */
2707 	for (i = 0; i < MLX5_ST_SZ_DW(definer_hl_ipv6_addr); i++) {
2708 		mod_id = flow_hw_get_ipv6_route_ext_mod_id_from_ctx(action->ctx, i + 1);
2709 		if (!mod_id) {
2710 			rte_errno = EINVAL;
2711 			return NULL;
2712 		}
2713 
2714 		MLX5_SET(copy_action_in, &cmd[i], action_type, MLX5_MODIFICATION_TYPE_COPY);
2715 		MLX5_SET(copy_action_in, &cmd[i], dst_field, field[i]);
2716 		MLX5_SET(copy_action_in, &cmd[i], src_field, mod_id);
2717 	}
2718 
2719 	mod_id = flow_hw_get_ipv6_route_ext_mod_id_from_ctx(action->ctx, 0);
2720 	if (!mod_id) {
2721 		rte_errno = EINVAL;
2722 		return NULL;
2723 	}
2724 
2725 	/* Restore next_hdr from seg_left for flex parser identifying */
2726 	MLX5_SET(copy_action_in, &cmd[4], action_type, MLX5_MODIFICATION_TYPE_COPY);
2727 	MLX5_SET(copy_action_in, &cmd[4], length, 8);
2728 	MLX5_SET(copy_action_in, &cmd[4], dst_offset, 24);
2729 	MLX5_SET(copy_action_in, &cmd[4], src_field, mod_id);
2730 	MLX5_SET(copy_action_in, &cmd[4], dst_field, mod_id);
2731 
2732 	pattern.data = cmd;
2733 	pattern.sz = sizeof(cmd);
2734 
2735 	return mlx5dr_action_create_modify_header_reparse(action->ctx, 1, &pattern, 0,
2736 							  action->flags,
2737 							  MLX5DR_ACTION_STC_REPARSE_ON);
2738 }
2739 
2740 static void *
2741 mlx5dr_action_create_pop_ipv6_route_ext_mhdr3(struct mlx5dr_action *action)
2742 {
2743 	uint8_t cmd[MLX5DR_MODIFY_ACTION_SIZE] = {0};
2744 	struct mlx5dr_action_mh_pattern pattern;
2745 	uint16_t mod_id;
2746 
2747 	mod_id = flow_hw_get_ipv6_route_ext_mod_id_from_ctx(action->ctx, 0);
2748 	if (!mod_id) {
2749 		rte_errno = EINVAL;
2750 		return NULL;
2751 	}
2752 
2753 	/* Copy ipv6_route_ext.next_hdr to ipv6.protocol */
2754 	MLX5_SET(copy_action_in, cmd, action_type, MLX5_MODIFICATION_TYPE_COPY);
2755 	MLX5_SET(copy_action_in, cmd, length, 8);
2756 	MLX5_SET(copy_action_in, cmd, src_offset, 24);
2757 	MLX5_SET(copy_action_in, cmd, src_field, mod_id);
2758 	MLX5_SET(copy_action_in, cmd, dst_field, MLX5_MODI_OUT_IP_PROTOCOL);
2759 
2760 	pattern.data = (__be64 *)cmd;
2761 	pattern.sz = sizeof(cmd);
2762 
2763 	return mlx5dr_action_create_modify_header_reparse(action->ctx, 1, &pattern, 0,
2764 							  action->flags,
2765 							  MLX5DR_ACTION_STC_REPARSE_OFF);
2766 }
2767 
2768 static int
2769 mlx5dr_action_create_pop_ipv6_route_ext(struct mlx5dr_action *action)
2770 {
2771 	uint8_t anchor_id = flow_hw_get_ipv6_route_ext_anchor_from_ctx(action->ctx);
2772 	struct mlx5dr_action_remove_header_attr hdr_attr;
2773 	uint32_t i;
2774 
2775 	if (!anchor_id) {
2776 		rte_errno = EINVAL;
2777 		return rte_errno;
2778 	}
2779 
2780 	action->ipv6_route_ext.action[0] =
2781 		mlx5dr_action_create_pop_ipv6_route_ext_mhdr1(action);
2782 	action->ipv6_route_ext.action[1] =
2783 		mlx5dr_action_create_pop_ipv6_route_ext_mhdr2(action);
2784 	action->ipv6_route_ext.action[2] =
2785 		mlx5dr_action_create_pop_ipv6_route_ext_mhdr3(action);
2786 
2787 	hdr_attr.by_anchor.decap = 1;
2788 	hdr_attr.by_anchor.start_anchor = anchor_id;
2789 	hdr_attr.by_anchor.end_anchor = MLX5_HEADER_ANCHOR_TCP_UDP;
2790 	hdr_attr.type = MLX5DR_ACTION_REMOVE_HEADER_TYPE_BY_HEADER;
2791 	action->ipv6_route_ext.action[3] =
2792 		mlx5dr_action_create_remove_header(action->ctx, &hdr_attr, action->flags);
2793 
2794 	if (!action->ipv6_route_ext.action[0] || !action->ipv6_route_ext.action[1] ||
2795 	    !action->ipv6_route_ext.action[2] || !action->ipv6_route_ext.action[3]) {
2796 		DR_LOG(ERR, "Failed to create ipv6_route_ext pop subaction");
2797 		goto err;
2798 	}
2799 
2800 	return 0;
2801 
2802 err:
2803 	for (i = 0; i < MLX5DR_ACTION_IPV6_EXT_MAX_SA; i++)
2804 		if (action->ipv6_route_ext.action[i])
2805 			mlx5dr_action_destroy(action->ipv6_route_ext.action[i]);
2806 
2807 	return rte_errno;
2808 }
2809 
2810 static void *
2811 mlx5dr_action_create_push_ipv6_route_ext_mhdr1(struct mlx5dr_action *action)
2812 {
2813 	uint8_t cmd[MLX5DR_MODIFY_ACTION_SIZE] = {0};
2814 	struct mlx5dr_action_mh_pattern pattern;
2815 
2816 	/* Set ipv6.protocol to IPPROTO_ROUTING */
2817 	MLX5_SET(set_action_in, cmd, action_type, MLX5_MODIFICATION_TYPE_SET);
2818 	MLX5_SET(set_action_in, cmd, length, 8);
2819 	MLX5_SET(set_action_in, cmd, field, MLX5_MODI_OUT_IP_PROTOCOL);
2820 	MLX5_SET(set_action_in, cmd, data, IPPROTO_ROUTING);
2821 
2822 	pattern.data = (__be64 *)cmd;
2823 	pattern.sz = sizeof(cmd);
2824 
2825 	return mlx5dr_action_create_modify_header(action->ctx, 1, &pattern, 0,
2826 						  action->flags | MLX5DR_ACTION_FLAG_SHARED);
2827 }
2828 
2829 static void *
2830 mlx5dr_action_create_push_ipv6_route_ext_mhdr2(struct mlx5dr_action *action,
2831 					       uint32_t bulk_size,
2832 					       uint8_t *data)
2833 {
2834 	enum mlx5_modification_field field[MLX5_ST_SZ_DW(definer_hl_ipv6_addr)] = {
2835 		MLX5_MODI_OUT_DIPV6_127_96,
2836 		MLX5_MODI_OUT_DIPV6_95_64,
2837 		MLX5_MODI_OUT_DIPV6_63_32,
2838 		MLX5_MODI_OUT_DIPV6_31_0
2839 	};
2840 	struct mlx5dr_action_mh_pattern pattern;
2841 	uint32_t *ipv6_dst_addr = NULL;
2842 	uint8_t seg_left, next_hdr;
2843 	__be64 cmd[5] = {0};
2844 	uint16_t mod_id;
2845 	uint32_t i;
2846 
2847 	/* Fetch the last IPv6 address in the segment list */
2848 	if (action->flags & MLX5DR_ACTION_FLAG_SHARED) {
2849 		seg_left = MLX5_GET(header_ipv6_routing_ext, data, segments_left) - 1;
2850 		ipv6_dst_addr = (uint32_t *)data + MLX5_ST_SZ_DW(header_ipv6_routing_ext) +
2851 				seg_left * MLX5_ST_SZ_DW(definer_hl_ipv6_addr);
2852 	}
2853 
2854 	/* Copy IPv6 destination address from ipv6_route_ext.last_segment */
2855 	for (i = 0; i < MLX5_ST_SZ_DW(definer_hl_ipv6_addr); i++) {
2856 		MLX5_SET(set_action_in, &cmd[i], action_type, MLX5_MODIFICATION_TYPE_SET);
2857 		MLX5_SET(set_action_in, &cmd[i], field, field[i]);
2858 		if (action->flags & MLX5DR_ACTION_FLAG_SHARED)
2859 			MLX5_SET(set_action_in, &cmd[i], data, be32toh(*ipv6_dst_addr++));
2860 	}
2861 
2862 	mod_id = flow_hw_get_ipv6_route_ext_mod_id_from_ctx(action->ctx, 0);
2863 	if (!mod_id) {
2864 		rte_errno = EINVAL;
2865 		return NULL;
2866 	}
2867 
2868 	/* Set ipv6_route_ext.next_hdr since initially pushed as 0 for right checksum */
2869 	MLX5_SET(set_action_in, &cmd[4], action_type, MLX5_MODIFICATION_TYPE_SET);
2870 	MLX5_SET(set_action_in, &cmd[4], length, 8);
2871 	MLX5_SET(set_action_in, &cmd[4], offset, 24);
2872 	MLX5_SET(set_action_in, &cmd[4], field, mod_id);
2873 	if (action->flags & MLX5DR_ACTION_FLAG_SHARED) {
2874 		next_hdr = MLX5_GET(header_ipv6_routing_ext, data, next_hdr);
2875 		MLX5_SET(set_action_in, &cmd[4], data, next_hdr);
2876 	}
2877 
2878 	pattern.data = cmd;
2879 	pattern.sz = sizeof(cmd);
2880 
2881 	return mlx5dr_action_create_modify_header(action->ctx, 1, &pattern,
2882 						  bulk_size, action->flags);
2883 }
2884 
2885 static int
2886 mlx5dr_action_create_push_ipv6_route_ext(struct mlx5dr_action *action,
2887 					 struct mlx5dr_action_reformat_header *hdr,
2888 					 uint32_t bulk_size)
2889 {
2890 	struct mlx5dr_action_insert_header insert_hdr = { {0} };
2891 	uint8_t header[MLX5_PUSH_MAX_LEN];
2892 	uint32_t i;
2893 
2894 	if (!hdr || !hdr->sz || hdr->sz > MLX5_PUSH_MAX_LEN ||
2895 	    ((action->flags & MLX5DR_ACTION_FLAG_SHARED) && !hdr->data)) {
2896 		DR_LOG(ERR, "Invalid ipv6_route_ext header");
2897 		rte_errno = EINVAL;
2898 		return rte_errno;
2899 	}
2900 
2901 	if (action->flags & MLX5DR_ACTION_FLAG_SHARED) {
2902 		memcpy(header, hdr->data, hdr->sz);
2903 		/* Clear ipv6_route_ext.next_hdr for right checksum */
2904 		MLX5_SET(header_ipv6_routing_ext, header, next_hdr, 0);
2905 	}
2906 
2907 	insert_hdr.anchor = MLX5_HEADER_ANCHOR_TCP_UDP;
2908 	insert_hdr.encap = 1;
2909 	insert_hdr.hdr.sz = hdr->sz;
2910 	insert_hdr.hdr.data = header;
2911 	action->ipv6_route_ext.action[0] =
2912 		mlx5dr_action_create_insert_header_reparse(action->ctx, 1, &insert_hdr,
2913 							    bulk_size, action->flags,
2914 							    MLX5DR_ACTION_STC_REPARSE_OFF);
2915 	action->ipv6_route_ext.action[1] =
2916 		mlx5dr_action_create_push_ipv6_route_ext_mhdr1(action);
2917 	action->ipv6_route_ext.action[2] =
2918 		mlx5dr_action_create_push_ipv6_route_ext_mhdr2(action, bulk_size, hdr->data);
2919 
2920 	if (!action->ipv6_route_ext.action[0] ||
2921 	    !action->ipv6_route_ext.action[1] ||
2922 	    !action->ipv6_route_ext.action[2]) {
2923 		DR_LOG(ERR, "Failed to create ipv6_route_ext push subaction");
2924 		goto err;
2925 	}
2926 
2927 	return 0;
2928 
2929 err:
2930 	for (i = 0; i < MLX5DR_ACTION_IPV6_EXT_MAX_SA; i++)
2931 		if (action->ipv6_route_ext.action[i])
2932 			mlx5dr_action_destroy(action->ipv6_route_ext.action[i]);
2933 
2934 	return rte_errno;
2935 }
2936 
2937 struct mlx5dr_action *
2938 mlx5dr_action_create_reformat_ipv6_ext(struct mlx5dr_context *ctx,
2939 				       enum mlx5dr_action_type action_type,
2940 				       struct mlx5dr_action_reformat_header *hdr,
2941 				       uint32_t log_bulk_size,
2942 				       uint32_t flags)
2943 {
2944 	struct mlx5dr_action *action;
2945 	int ret;
2946 
2947 	if (!mlx5dr_action_is_hws_flags(flags) ||
2948 	    ((flags & MLX5DR_ACTION_FLAG_SHARED) && log_bulk_size)) {
2949 		DR_LOG(ERR, "IPv6 extension flags don't fit HWS (flags: 0x%x)", flags);
2950 		rte_errno = EINVAL;
2951 		return NULL;
2952 	}
2953 
2954 	action = mlx5dr_action_create_generic(ctx, flags, action_type);
2955 	if (!action) {
2956 		rte_errno = ENOMEM;
2957 		return NULL;
2958 	}
2959 
2960 	switch (action_type) {
2961 	case MLX5DR_ACTION_TYP_POP_IPV6_ROUTE_EXT:
2962 		if (!(flags & MLX5DR_ACTION_FLAG_SHARED)) {
2963 			DR_LOG(ERR, "Pop ipv6_route_ext must be shared");
2964 			rte_errno = EINVAL;
2965 			goto free_action;
2966 		}
2967 
2968 		ret = mlx5dr_action_create_pop_ipv6_route_ext(action);
2969 		break;
2970 	case MLX5DR_ACTION_TYP_PUSH_IPV6_ROUTE_EXT:
2971 		if (!mlx5dr_context_cap_dynamic_reparse(ctx)) {
2972 			DR_LOG(ERR, "IPv6 routing extension push actions is not supported");
2973 			rte_errno = ENOTSUP;
2974 			goto free_action;
2975 		}
2976 
2977 		ret = mlx5dr_action_create_push_ipv6_route_ext(action, hdr, log_bulk_size);
2978 		break;
2979 	default:
2980 		DR_LOG(ERR, "Unsupported action type %d\n", action_type);
2981 		rte_errno = ENOTSUP;
2982 		goto free_action;
2983 	}
2984 
2985 	if (ret) {
2986 		DR_LOG(ERR, "Failed to create IPv6 extension reformat action");
2987 		goto free_action;
2988 	}
2989 
2990 	return action;
2991 
2992 free_action:
2993 	simple_free(action);
2994 	return NULL;
2995 }
2996 
2997 static bool
2998 mlx5dr_action_nat64_validate_param(struct mlx5dr_action_nat64_attr *attr,
2999 				   uint32_t flags)
3000 {
3001 	if (mlx5dr_action_is_root_flags(flags)) {
3002 		DR_LOG(ERR, "Nat64 action not supported for root");
3003 		rte_errno = ENOTSUP;
3004 		return false;
3005 	}
3006 
3007 	if (!(flags & MLX5DR_ACTION_FLAG_SHARED)) {
3008 		DR_LOG(ERR, "Nat64 action must be with SHARED flag");
3009 		rte_errno = EINVAL;
3010 		return false;
3011 	}
3012 
3013 	if (attr->num_of_registers > MLX5DR_ACTION_NAT64_REG_MAX) {
3014 		DR_LOG(ERR, "Nat64 action doesn't support more than %d registers",
3015 		       MLX5DR_ACTION_NAT64_REG_MAX);
3016 		rte_errno = EINVAL;
3017 		return false;
3018 	}
3019 
3020 	if (attr->flags & MLX5DR_ACTION_NAT64_BACKUP_ADDR &&
3021 	    attr->num_of_registers != MLX5DR_ACTION_NAT64_REG_MAX) {
3022 		DR_LOG(ERR, "Nat64 backup addr requires %d registers",
3023 		       MLX5DR_ACTION_NAT64_REG_MAX);
3024 		rte_errno = EINVAL;
3025 		return false;
3026 	}
3027 
3028 	if (!(attr->flags & MLX5DR_ACTION_NAT64_V4_TO_V6 ||
3029 	      attr->flags & MLX5DR_ACTION_NAT64_V6_TO_V4)) {
3030 		DR_LOG(ERR, "Nat64 backup addr requires one mode at least");
3031 		rte_errno = EINVAL;
3032 		return false;
3033 	}
3034 
3035 	return true;
3036 }
3037 
3038 struct mlx5dr_action *
3039 mlx5dr_action_create_nat64(struct mlx5dr_context *ctx,
3040 			   struct mlx5dr_action_nat64_attr *attr,
3041 			   uint32_t flags)
3042 {
3043 	struct mlx5dr_action *action;
3044 
3045 	if (!mlx5dr_action_nat64_validate_param(attr, flags))
3046 		return NULL;
3047 
3048 	action = mlx5dr_action_create_generic(ctx, flags, MLX5DR_ACTION_TYP_NAT64);
3049 	if (!action)
3050 		return NULL;
3051 
3052 	action->nat64.stages[MLX5DR_ACTION_NAT64_STAGE_COPY] =
3053 		mlx5dr_action_create_nat64_copy_state(ctx, attr, flags);
3054 	if (!action->nat64.stages[MLX5DR_ACTION_NAT64_STAGE_COPY]) {
3055 		DR_LOG(ERR, "Nat64 failed creating copy state");
3056 		goto free_action;
3057 	}
3058 
3059 	action->nat64.stages[MLX5DR_ACTION_NAT64_STAGE_REPLACE] =
3060 		mlx5dr_action_create_nat64_repalce_state(ctx, attr, flags);
3061 	if (!action->nat64.stages[MLX5DR_ACTION_NAT64_STAGE_REPLACE]) {
3062 		DR_LOG(ERR, "Nat64 failed creating replace state");
3063 		goto free_copy;
3064 	}
3065 	action->nat64.stages[MLX5DR_ACTION_NAT64_STAGE_COPY_PROTOCOL] =
3066 		mlx5dr_action_create_nat64_copy_proto_state(ctx, attr, flags);
3067 	if (!action->nat64.stages[MLX5DR_ACTION_NAT64_STAGE_COPY_PROTOCOL]) {
3068 		DR_LOG(ERR, "Nat64 failed creating copy protocol state");
3069 		goto free_replace;
3070 	}
3071 
3072 	action->nat64.stages[MLX5DR_ACTION_NAT64_STAGE_COPYBACK] =
3073 		mlx5dr_action_create_nat64_copy_back_state(ctx, attr, flags);
3074 	if (!action->nat64.stages[MLX5DR_ACTION_NAT64_STAGE_COPYBACK]) {
3075 		DR_LOG(ERR, "Nat64 failed creating copyback state");
3076 		goto free_copy_proto;
3077 	}
3078 
3079 	return action;
3080 
3081 free_copy_proto:
3082 	mlx5dr_action_destroy(action->nat64.stages[MLX5DR_ACTION_NAT64_STAGE_COPY_PROTOCOL]);
3083 free_replace:
3084 	mlx5dr_action_destroy(action->nat64.stages[MLX5DR_ACTION_NAT64_STAGE_REPLACE]);
3085 free_copy:
3086 	mlx5dr_action_destroy(action->nat64.stages[MLX5DR_ACTION_NAT64_STAGE_COPY]);
3087 free_action:
3088 	simple_free(action);
3089 	return NULL;
3090 }
3091 
3092 struct mlx5dr_action *
3093 mlx5dr_action_create_jump_to_matcher(struct mlx5dr_context *ctx,
3094 				     struct mlx5dr_action_jump_to_matcher_attr *attr,
3095 				     uint32_t flags)
3096 {
3097 	struct mlx5dr_matcher *matcher = attr->matcher;
3098 	struct mlx5dr_matcher_attr *m_attr;
3099 	struct mlx5dr_action *action;
3100 
3101 	if (attr->type != MLX5DR_ACTION_JUMP_TO_MATCHER_BY_INDEX) {
3102 		DR_LOG(ERR, "Only jump to matcher by index is supported");
3103 		goto enotsup;
3104 	}
3105 
3106 	if (mlx5dr_action_is_root_flags(flags)) {
3107 		DR_LOG(ERR, "Action flags must be only non root (HWS)");
3108 		goto enotsup;
3109 	}
3110 
3111 	if (mlx5dr_table_is_root(matcher->tbl)) {
3112 		DR_LOG(ERR, "Root matcher cannot be set as destination");
3113 		goto enotsup;
3114 	}
3115 
3116 	m_attr = &matcher->attr;
3117 
3118 	if (!(matcher->flags & MLX5DR_MATCHER_FLAGS_STE_ARRAY) &&
3119 	    (m_attr->resizable || m_attr->table.sz_col_log || m_attr->table.sz_row_log)) {
3120 		DR_LOG(ERR, "Only STE array or matcher of size 1 can be set as destination");
3121 		goto enotsup;
3122 	}
3123 
3124 	action = mlx5dr_action_create_generic(ctx, flags, MLX5DR_ACTION_TYP_JUMP_TO_MATCHER);
3125 	if (!action)
3126 		return NULL;
3127 
3128 	action->jump_to_matcher.matcher = matcher;
3129 
3130 	if (mlx5dr_action_create_stcs(action, NULL)) {
3131 		DR_LOG(ERR, "Failed to create action jump to matcher STC");
3132 		simple_free(action);
3133 		return NULL;
3134 	}
3135 
3136 	return action;
3137 
3138 enotsup:
3139 	rte_errno = ENOTSUP;
3140 	return NULL;
3141 }
3142 
3143 static void mlx5dr_action_destroy_hws(struct mlx5dr_action *action)
3144 {
3145 	struct mlx5dr_devx_obj *obj = NULL;
3146 	uint32_t i;
3147 
3148 	switch (action->type) {
3149 	case MLX5DR_ACTION_TYP_TIR:
3150 		mlx5dr_action_destroy_stcs(action);
3151 		if (mlx5dr_context_shared_gvmi_used(action->ctx))
3152 			mlx5dr_cmd_destroy_obj(action->alias.devx_obj);
3153 		break;
3154 	case MLX5DR_ACTION_TYP_MISS:
3155 	case MLX5DR_ACTION_TYP_TAG:
3156 	case MLX5DR_ACTION_TYP_DROP:
3157 	case MLX5DR_ACTION_TYP_CTR:
3158 	case MLX5DR_ACTION_TYP_TBL:
3159 	case MLX5DR_ACTION_TYP_REFORMAT_TNL_L2_TO_L2:
3160 	case MLX5DR_ACTION_TYP_ASO_METER:
3161 	case MLX5DR_ACTION_TYP_ASO_CT:
3162 	case MLX5DR_ACTION_TYP_PUSH_VLAN:
3163 	case MLX5DR_ACTION_TYP_REMOVE_HEADER:
3164 	case MLX5DR_ACTION_TYP_VPORT:
3165 	case MLX5DR_ACTION_TYP_JUMP_TO_MATCHER:
3166 		mlx5dr_action_destroy_stcs(action);
3167 		break;
3168 	case MLX5DR_ACTION_TYP_DEST_ROOT:
3169 		mlx5dr_action_destroy_stcs(action);
3170 		mlx5_glue->destroy_steering_anchor(action->root_tbl.sa);
3171 		break;
3172 	case MLX5DR_ACTION_TYP_POP_VLAN:
3173 		mlx5dr_action_destroy_stcs(action);
3174 		mlx5dr_action_put_shared_stc(action, MLX5DR_CONTEXT_SHARED_STC_DOUBLE_POP);
3175 		break;
3176 	case MLX5DR_ACTION_TYP_DEST_ARRAY:
3177 		mlx5dr_action_destroy_stcs(action);
3178 		mlx5dr_cmd_forward_tbl_destroy(action->dest_array.fw_island);
3179 		for (i = 0; i < action->dest_array.num_dest; i++) {
3180 			if (action->dest_array.dest_list[i].ext_reformat)
3181 				mlx5dr_cmd_destroy_obj
3182 					(action->dest_array.dest_list[i].ext_reformat);
3183 		}
3184 		simple_free(action->dest_array.dest_list);
3185 		break;
3186 	case MLX5DR_ACTION_TYP_REFORMAT_TNL_L3_TO_L2:
3187 	case MLX5DR_ACTION_TYP_MODIFY_HDR:
3188 		for (i = 0; i < action->modify_header.num_of_patterns; i++) {
3189 			mlx5dr_action_destroy_stcs(&action[i]);
3190 			if (action[i].modify_header.num_of_actions > 1) {
3191 				mlx5dr_pat_put_pattern(action[i].ctx,
3192 						       action[i].modify_header.pat_obj);
3193 				/* Save shared arg object if was used to free */
3194 				if (action[i].modify_header.arg_obj)
3195 					obj = action[i].modify_header.arg_obj;
3196 			}
3197 		}
3198 		if (obj)
3199 			mlx5dr_cmd_destroy_obj(obj);
3200 		break;
3201 	case MLX5DR_ACTION_TYP_REFORMAT_L2_TO_TNL_L3:
3202 		mlx5dr_action_put_shared_stc(action, MLX5DR_CONTEXT_SHARED_STC_DECAP_L3);
3203 		for (i = 0; i < action->reformat.num_of_hdrs; i++)
3204 			mlx5dr_action_destroy_stcs(&action[i]);
3205 		mlx5dr_cmd_destroy_obj(action->reformat.arg_obj);
3206 		break;
3207 	case MLX5DR_ACTION_TYP_INSERT_HEADER:
3208 	case MLX5DR_ACTION_TYP_REFORMAT_L2_TO_TNL_L2:
3209 		for (i = 0; i < action->reformat.num_of_hdrs; i++)
3210 			mlx5dr_action_destroy_stcs(&action[i]);
3211 		mlx5dr_cmd_destroy_obj(action->reformat.arg_obj);
3212 		break;
3213 	case MLX5DR_ACTION_TYP_PUSH_IPV6_ROUTE_EXT:
3214 	case MLX5DR_ACTION_TYP_POP_IPV6_ROUTE_EXT:
3215 		for (i = 0; i < MLX5DR_ACTION_IPV6_EXT_MAX_SA; i++)
3216 			if (action->ipv6_route_ext.action[i])
3217 				mlx5dr_action_destroy(action->ipv6_route_ext.action[i]);
3218 		break;
3219 	case MLX5DR_ACTION_TYP_NAT64:
3220 		for (i = 0; i < MLX5DR_ACTION_NAT64_STAGES; i++)
3221 			mlx5dr_action_destroy(action->nat64.stages[i]);
3222 		break;
3223 	case MLX5DR_ACTION_TYP_LAST:
3224 		break;
3225 	default:
3226 		DR_LOG(ERR, "Not supported action type: %d", action->type);
3227 		assert(false);
3228 	}
3229 }
3230 
3231 static void mlx5dr_action_destroy_root(struct mlx5dr_action *action)
3232 {
3233 	switch (action->type) {
3234 	case MLX5DR_ACTION_TYP_REFORMAT_TNL_L2_TO_L2:
3235 	case MLX5DR_ACTION_TYP_REFORMAT_L2_TO_TNL_L2:
3236 	case MLX5DR_ACTION_TYP_REFORMAT_TNL_L3_TO_L2:
3237 	case MLX5DR_ACTION_TYP_REFORMAT_L2_TO_TNL_L3:
3238 	case MLX5DR_ACTION_TYP_MODIFY_HDR:
3239 		ibv_destroy_flow_action(action->flow_action);
3240 		break;
3241 	}
3242 }
3243 
3244 int mlx5dr_action_destroy(struct mlx5dr_action *action)
3245 {
3246 	if (mlx5dr_action_is_root_flags(action->flags))
3247 		mlx5dr_action_destroy_root(action);
3248 	else
3249 		mlx5dr_action_destroy_hws(action);
3250 
3251 	simple_free(action);
3252 	return 0;
3253 }
3254 
3255 /* Called under pthread_spin_lock(&ctx->ctrl_lock) */
3256 int mlx5dr_action_get_default_stc(struct mlx5dr_context *ctx,
3257 				  uint8_t tbl_type)
3258 {
3259 	struct mlx5dr_cmd_stc_modify_attr stc_attr = {0};
3260 	struct mlx5dr_action_default_stc *default_stc;
3261 	int ret;
3262 
3263 	if (ctx->common_res[tbl_type].default_stc) {
3264 		ctx->common_res[tbl_type].default_stc->refcount++;
3265 		return 0;
3266 	}
3267 
3268 	default_stc = simple_calloc(1, sizeof(*default_stc));
3269 	if (!default_stc) {
3270 		DR_LOG(ERR, "Failed to allocate memory for default STCs");
3271 		rte_errno = ENOMEM;
3272 		return rte_errno;
3273 	}
3274 
3275 	stc_attr.action_type = MLX5_IFC_STC_ACTION_TYPE_NOP;
3276 	stc_attr.action_offset = MLX5DR_ACTION_OFFSET_DW0;
3277 	stc_attr.reparse_mode = MLX5_IFC_STC_REPARSE_IGNORE;
3278 	ret = mlx5dr_action_alloc_single_stc(ctx, &stc_attr, tbl_type,
3279 					     &default_stc->nop_ctr);
3280 	if (ret) {
3281 		DR_LOG(ERR, "Failed to allocate default counter STC");
3282 		goto free_default_stc;
3283 	}
3284 
3285 	stc_attr.action_offset = MLX5DR_ACTION_OFFSET_DW5;
3286 	ret = mlx5dr_action_alloc_single_stc(ctx, &stc_attr, tbl_type,
3287 					     &default_stc->nop_dw5);
3288 	if (ret) {
3289 		DR_LOG(ERR, "Failed to allocate default NOP DW5 STC");
3290 		goto free_nop_ctr;
3291 	}
3292 
3293 	stc_attr.action_offset = MLX5DR_ACTION_OFFSET_DW6;
3294 	ret = mlx5dr_action_alloc_single_stc(ctx, &stc_attr, tbl_type,
3295 					     &default_stc->nop_dw6);
3296 	if (ret) {
3297 		DR_LOG(ERR, "Failed to allocate default NOP DW6 STC");
3298 		goto free_nop_dw5;
3299 	}
3300 
3301 	stc_attr.action_offset = MLX5DR_ACTION_OFFSET_DW7;
3302 	ret = mlx5dr_action_alloc_single_stc(ctx, &stc_attr, tbl_type,
3303 					     &default_stc->nop_dw7);
3304 	if (ret) {
3305 		DR_LOG(ERR, "Failed to allocate default NOP DW7 STC");
3306 		goto free_nop_dw6;
3307 	}
3308 
3309 	stc_attr.action_offset = MLX5DR_ACTION_OFFSET_HIT;
3310 	if (!mlx5dr_context_shared_gvmi_used(ctx)) {
3311 		stc_attr.action_type = MLX5_IFC_STC_ACTION_TYPE_ALLOW;
3312 	} else {
3313 		/* On shared gvmi the default hit behavior is jump to alias end ft */
3314 		stc_attr.action_type = MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_FT;
3315 		stc_attr.dest_table_id = ctx->gvmi_res[tbl_type].aliased_end_ft->id;
3316 	}
3317 
3318 	ret = mlx5dr_action_alloc_single_stc(ctx, &stc_attr, tbl_type,
3319 					     &default_stc->default_hit);
3320 	if (ret) {
3321 		DR_LOG(ERR, "Failed to allocate default allow STC");
3322 		goto free_nop_dw7;
3323 	}
3324 
3325 	ctx->common_res[tbl_type].default_stc = default_stc;
3326 	ctx->common_res[tbl_type].default_stc->refcount++;
3327 
3328 	return 0;
3329 
3330 free_nop_dw7:
3331 	mlx5dr_action_free_single_stc(ctx, tbl_type, &default_stc->nop_dw7);
3332 free_nop_dw6:
3333 	mlx5dr_action_free_single_stc(ctx, tbl_type, &default_stc->nop_dw6);
3334 free_nop_dw5:
3335 	mlx5dr_action_free_single_stc(ctx, tbl_type, &default_stc->nop_dw5);
3336 free_nop_ctr:
3337 	mlx5dr_action_free_single_stc(ctx, tbl_type, &default_stc->nop_ctr);
3338 free_default_stc:
3339 	simple_free(default_stc);
3340 	return rte_errno;
3341 }
3342 
3343 void mlx5dr_action_put_default_stc(struct mlx5dr_context *ctx,
3344 				   uint8_t tbl_type)
3345 {
3346 	struct mlx5dr_action_default_stc *default_stc;
3347 
3348 	default_stc = ctx->common_res[tbl_type].default_stc;
3349 
3350 	default_stc = ctx->common_res[tbl_type].default_stc;
3351 	if (--default_stc->refcount)
3352 		return;
3353 
3354 	mlx5dr_action_free_single_stc(ctx, tbl_type, &default_stc->default_hit);
3355 	mlx5dr_action_free_single_stc(ctx, tbl_type, &default_stc->nop_dw7);
3356 	mlx5dr_action_free_single_stc(ctx, tbl_type, &default_stc->nop_dw6);
3357 	mlx5dr_action_free_single_stc(ctx, tbl_type, &default_stc->nop_dw5);
3358 	mlx5dr_action_free_single_stc(ctx, tbl_type, &default_stc->nop_ctr);
3359 	simple_free(default_stc);
3360 	ctx->common_res[tbl_type].default_stc = NULL;
3361 }
3362 
3363 static void mlx5dr_action_modify_write(struct mlx5dr_send_engine *queue,
3364 				       uint32_t arg_idx,
3365 				       uint8_t *arg_data,
3366 				       uint16_t num_of_actions)
3367 {
3368 	mlx5dr_arg_write(queue, NULL, arg_idx, arg_data,
3369 			 num_of_actions * MLX5DR_MODIFY_ACTION_SIZE);
3370 }
3371 
3372 void
3373 mlx5dr_action_prepare_decap_l3_data(uint8_t *src, uint8_t *dst,
3374 				    uint16_t num_of_actions)
3375 {
3376 	uint8_t *e_src;
3377 	int i;
3378 
3379 	/* num_of_actions = remove l3l2 + 4/5 inserts + remove extra 2 bytes
3380 	 * copy from end of src to the start of dst.
3381 	 * move to the end, 2 is the leftover from 14B or 18B
3382 	 */
3383 	if (num_of_actions == DECAP_L3_NUM_ACTIONS_W_NO_VLAN)
3384 		e_src = src + MLX5DR_ACTION_HDR_LEN_L2;
3385 	else
3386 		e_src = src + MLX5DR_ACTION_HDR_LEN_L2_W_VLAN;
3387 
3388 	/* Move dst over the first remove action + zero data */
3389 	dst += MLX5DR_ACTION_DOUBLE_SIZE;
3390 	/* Move dst over the first insert ctrl action */
3391 	dst += MLX5DR_ACTION_DOUBLE_SIZE / 2;
3392 	/* Actions:
3393 	 * no vlan: r_h-insert_4b-insert_4b-insert_4b-insert_4b-remove_2b.
3394 	 * with vlan: r_h-insert_4b-insert_4b-insert_4b-insert_4b-insert_4b-remove_2b.
3395 	 * the loop is without the last insertion.
3396 	 */
3397 	for (i = 0; i < num_of_actions - 3; i++) {
3398 		e_src -= MLX5DR_ACTION_INLINE_DATA_SIZE;
3399 		memcpy(dst, e_src, MLX5DR_ACTION_INLINE_DATA_SIZE); /* data */
3400 		dst += MLX5DR_ACTION_DOUBLE_SIZE;
3401 	}
3402 	/* Copy the last 2 bytes after a gap of 2 bytes which will be removed */
3403 	e_src -= MLX5DR_ACTION_INLINE_DATA_SIZE / 2;
3404 	dst += MLX5DR_ACTION_INLINE_DATA_SIZE / 2;
3405 	memcpy(dst, e_src, 2);
3406 }
3407 
3408 static int mlx5dr_action_get_shared_stc_offset(struct mlx5dr_context_common_res *common_res,
3409 					       enum mlx5dr_context_shared_stc_type stc_type)
3410 {
3411 	return common_res->shared_stc[stc_type]->remove_header.offset;
3412 }
3413 
3414 static struct mlx5dr_actions_wqe_setter *
3415 mlx5dr_action_setter_find_first(struct mlx5dr_actions_wqe_setter *setter,
3416 				uint8_t req_flags)
3417 {
3418 	/* Use a new setter if requested flags are taken */
3419 	while (setter->flags & req_flags)
3420 		setter++;
3421 
3422 	/* Use current setter in required flags are not used */
3423 	return setter;
3424 }
3425 
3426 static void
3427 mlx5dr_action_apply_stc(struct mlx5dr_actions_apply_data *apply,
3428 			enum mlx5dr_action_stc_idx stc_idx,
3429 			uint8_t action_idx)
3430 {
3431 	struct mlx5dr_action *action = apply->rule_action[action_idx].action;
3432 
3433 	apply->wqe_ctrl->stc_ix[stc_idx] =
3434 		htobe32(action->stc[apply->tbl_type].offset);
3435 }
3436 
3437 static void
3438 mlx5dr_action_setter_push_vlan(struct mlx5dr_actions_apply_data *apply,
3439 			       struct mlx5dr_actions_wqe_setter *setter)
3440 {
3441 	struct mlx5dr_rule_action *rule_action;
3442 
3443 	rule_action = &apply->rule_action[setter->idx_double];
3444 	apply->wqe_data[MLX5DR_ACTION_OFFSET_DW6] = 0;
3445 	apply->wqe_data[MLX5DR_ACTION_OFFSET_DW7] = rule_action->push_vlan.vlan_hdr;
3446 
3447 	mlx5dr_action_apply_stc(apply, MLX5DR_ACTION_STC_IDX_DW6, setter->idx_double);
3448 	apply->wqe_ctrl->stc_ix[MLX5DR_ACTION_STC_IDX_DW7] = 0;
3449 }
3450 
3451 static void
3452 mlx5dr_action_setter_modify_header(struct mlx5dr_actions_apply_data *apply,
3453 				   struct mlx5dr_actions_wqe_setter *setter)
3454 {
3455 	struct mlx5dr_rule_action *rule_action;
3456 	uint32_t stc_idx, arg_sz, arg_idx;
3457 	struct mlx5dr_action *action;
3458 	uint8_t *single_action;
3459 
3460 	rule_action = &apply->rule_action[setter->idx_double];
3461 	action = rule_action->action + rule_action->modify_header.pattern_idx;
3462 
3463 	stc_idx = htobe32(action->stc[apply->tbl_type].offset);
3464 	apply->wqe_ctrl->stc_ix[MLX5DR_ACTION_STC_IDX_DW6] = stc_idx;
3465 	apply->wqe_ctrl->stc_ix[MLX5DR_ACTION_STC_IDX_DW7] = 0;
3466 
3467 	apply->wqe_data[MLX5DR_ACTION_OFFSET_DW6] = 0;
3468 
3469 	if (action->modify_header.num_of_actions == 1) {
3470 		if (action->modify_header.single_action_type ==
3471 		    MLX5_MODIFICATION_TYPE_COPY ||
3472 		    action->modify_header.single_action_type ==
3473 		    MLX5_MODIFICATION_TYPE_ADD_FIELD) {
3474 			apply->wqe_data[MLX5DR_ACTION_OFFSET_DW7] = 0;
3475 			return;
3476 		}
3477 
3478 		if (action->flags & MLX5DR_ACTION_FLAG_SHARED)
3479 			single_action = (uint8_t *)&action->modify_header.single_action;
3480 		else
3481 			single_action = rule_action->modify_header.data;
3482 
3483 		apply->wqe_data[MLX5DR_ACTION_OFFSET_DW7] =
3484 			*(__be32 *)MLX5_ADDR_OF(set_action_in, single_action, data);
3485 	} else {
3486 		/* Argument offset multiple with number of args per these actions */
3487 		arg_sz = mlx5dr_arg_get_arg_size(action->modify_header.max_num_of_actions);
3488 		arg_idx = rule_action->modify_header.offset * arg_sz;
3489 
3490 		apply->wqe_data[MLX5DR_ACTION_OFFSET_DW7] = htobe32(arg_idx);
3491 
3492 		if (!(action->flags & MLX5DR_ACTION_FLAG_SHARED)) {
3493 			apply->require_dep = 1;
3494 			mlx5dr_action_modify_write(apply->queue,
3495 						   action->modify_header.arg_obj->id + arg_idx,
3496 						   rule_action->modify_header.data,
3497 						   action->modify_header.num_of_actions);
3498 		}
3499 	}
3500 }
3501 
3502 static void
3503 mlx5dr_action_setter_nat64(struct mlx5dr_actions_apply_data *apply,
3504 			   struct mlx5dr_actions_wqe_setter *setter)
3505 {
3506 	struct mlx5dr_rule_action *rule_action;
3507 	struct mlx5dr_action *cur_stage_action;
3508 	struct mlx5dr_action *action;
3509 	uint32_t stc_idx;
3510 
3511 	rule_action = &apply->rule_action[setter->idx_double];
3512 	action = rule_action->action;
3513 	cur_stage_action = action->nat64.stages[setter->stage_idx];
3514 
3515 	stc_idx = htobe32(cur_stage_action->stc[apply->tbl_type].offset);
3516 
3517 	apply->wqe_ctrl->stc_ix[MLX5DR_ACTION_STC_IDX_DW6] = stc_idx;
3518 	apply->wqe_ctrl->stc_ix[MLX5DR_ACTION_STC_IDX_DW7] = 0;
3519 
3520 	apply->wqe_data[MLX5DR_ACTION_OFFSET_DW6] = 0;
3521 	apply->wqe_data[MLX5DR_ACTION_OFFSET_DW7] = 0;
3522 }
3523 
3524 static void
3525 mlx5dr_action_setter_insert_ptr(struct mlx5dr_actions_apply_data *apply,
3526 				struct mlx5dr_actions_wqe_setter *setter)
3527 {
3528 	struct mlx5dr_rule_action *rule_action;
3529 	uint32_t stc_idx, arg_idx, arg_sz;
3530 	struct mlx5dr_action *action;
3531 
3532 	rule_action = &apply->rule_action[setter->idx_double];
3533 	action = rule_action->action + rule_action->reformat.hdr_idx;
3534 
3535 	/* Argument offset multiple on args required for header size */
3536 	arg_sz = mlx5dr_arg_data_size_to_arg_size(action->reformat.max_hdr_sz);
3537 	arg_idx = rule_action->reformat.offset * arg_sz;
3538 
3539 	apply->wqe_data[MLX5DR_ACTION_OFFSET_DW6] = 0;
3540 	apply->wqe_data[MLX5DR_ACTION_OFFSET_DW7] = htobe32(arg_idx);
3541 
3542 	stc_idx = htobe32(action->stc[apply->tbl_type].offset);
3543 	apply->wqe_ctrl->stc_ix[MLX5DR_ACTION_STC_IDX_DW6] = stc_idx;
3544 	apply->wqe_ctrl->stc_ix[MLX5DR_ACTION_STC_IDX_DW7] = 0;
3545 
3546 	if (!(action->flags & MLX5DR_ACTION_FLAG_SHARED)) {
3547 		apply->require_dep = 1;
3548 		mlx5dr_arg_write(apply->queue, NULL,
3549 				 action->reformat.arg_obj->id + arg_idx,
3550 				 rule_action->reformat.data,
3551 				 action->reformat.header_size);
3552 	}
3553 }
3554 
3555 static void
3556 mlx5dr_action_setter_tnl_l3_to_l2(struct mlx5dr_actions_apply_data *apply,
3557 				  struct mlx5dr_actions_wqe_setter *setter)
3558 {
3559 	struct mlx5dr_rule_action *rule_action;
3560 	uint32_t stc_idx, arg_sz, arg_idx;
3561 	struct mlx5dr_action *action;
3562 
3563 	rule_action = &apply->rule_action[setter->idx_double];
3564 	action = rule_action->action + rule_action->reformat.hdr_idx;
3565 
3566 	/* Argument offset multiple on args required for num of actions */
3567 	arg_sz = mlx5dr_arg_get_arg_size(action->modify_header.max_num_of_actions);
3568 	arg_idx = rule_action->reformat.offset * arg_sz;
3569 
3570 	apply->wqe_data[MLX5DR_ACTION_OFFSET_DW6] = 0;
3571 	apply->wqe_data[MLX5DR_ACTION_OFFSET_DW7] = htobe32(arg_idx);
3572 
3573 	stc_idx = htobe32(action->stc[apply->tbl_type].offset);
3574 	apply->wqe_ctrl->stc_ix[MLX5DR_ACTION_STC_IDX_DW6] = stc_idx;
3575 	apply->wqe_ctrl->stc_ix[MLX5DR_ACTION_STC_IDX_DW7] = 0;
3576 
3577 	if (!(action->flags & MLX5DR_ACTION_FLAG_SHARED)) {
3578 		apply->require_dep = 1;
3579 		mlx5dr_arg_decapl3_write(apply->queue,
3580 					 action->modify_header.arg_obj->id + arg_idx,
3581 					 rule_action->reformat.data,
3582 					 action->modify_header.num_of_actions);
3583 	}
3584 }
3585 
3586 static void
3587 mlx5dr_action_setter_aso(struct mlx5dr_actions_apply_data *apply,
3588 			 struct mlx5dr_actions_wqe_setter *setter)
3589 {
3590 	struct mlx5dr_rule_action *rule_action;
3591 	uint32_t exe_aso_ctrl;
3592 	uint32_t offset;
3593 
3594 	rule_action = &apply->rule_action[setter->idx_double];
3595 
3596 	switch (rule_action->action->type) {
3597 	case MLX5DR_ACTION_TYP_ASO_METER:
3598 		/* exe_aso_ctrl format:
3599 		 * [STC only and reserved bits 29b][init_color 2b][meter_id 1b]
3600 		 */
3601 		offset = rule_action->aso_meter.offset / MLX5_ASO_METER_NUM_PER_OBJ;
3602 		exe_aso_ctrl = rule_action->aso_meter.offset % MLX5_ASO_METER_NUM_PER_OBJ;
3603 		exe_aso_ctrl |= rule_action->aso_meter.init_color <<
3604 				MLX5DR_ACTION_METER_INIT_COLOR_OFFSET;
3605 		break;
3606 	case MLX5DR_ACTION_TYP_ASO_CT:
3607 		/* exe_aso_ctrl CT format:
3608 		 * [STC only and reserved bits 31b][direction 1b]
3609 		 */
3610 		offset = rule_action->aso_ct.offset / MLX5_ASO_CT_NUM_PER_OBJ;
3611 		exe_aso_ctrl = rule_action->aso_ct.direction;
3612 		break;
3613 	default:
3614 		DR_LOG(ERR, "Unsupported ASO action type: %d", rule_action->action->type);
3615 		rte_errno = ENOTSUP;
3616 		return;
3617 	}
3618 
3619 	/* aso_object_offset format: [24B] */
3620 	apply->wqe_data[MLX5DR_ACTION_OFFSET_DW6] = htobe32(offset);
3621 	apply->wqe_data[MLX5DR_ACTION_OFFSET_DW7] = htobe32(exe_aso_ctrl);
3622 
3623 	mlx5dr_action_apply_stc(apply, MLX5DR_ACTION_STC_IDX_DW6, setter->idx_double);
3624 	apply->wqe_ctrl->stc_ix[MLX5DR_ACTION_STC_IDX_DW7] = 0;
3625 }
3626 
3627 static void
3628 mlx5dr_action_setter_tag(struct mlx5dr_actions_apply_data *apply,
3629 			 struct mlx5dr_actions_wqe_setter *setter)
3630 {
3631 	struct mlx5dr_rule_action *rule_action;
3632 
3633 	rule_action = &apply->rule_action[setter->idx_single];
3634 	apply->wqe_data[MLX5DR_ACTION_OFFSET_DW5] = htobe32(rule_action->tag.value);
3635 	mlx5dr_action_apply_stc(apply, MLX5DR_ACTION_STC_IDX_DW5, setter->idx_single);
3636 }
3637 
3638 static void
3639 mlx5dr_action_setter_ctrl_ctr(struct mlx5dr_actions_apply_data *apply,
3640 			      struct mlx5dr_actions_wqe_setter *setter)
3641 {
3642 	struct mlx5dr_rule_action *rule_action;
3643 
3644 	rule_action = &apply->rule_action[setter->idx_ctr];
3645 	apply->wqe_data[MLX5DR_ACTION_OFFSET_DW0] = htobe32(rule_action->counter.offset);
3646 	mlx5dr_action_apply_stc(apply, MLX5DR_ACTION_STC_IDX_CTRL, setter->idx_ctr);
3647 }
3648 
3649 static void
3650 mlx5dr_action_setter_single(struct mlx5dr_actions_apply_data *apply,
3651 			    struct mlx5dr_actions_wqe_setter *setter)
3652 {
3653 	apply->wqe_data[MLX5DR_ACTION_OFFSET_DW5] = 0;
3654 	mlx5dr_action_apply_stc(apply, MLX5DR_ACTION_STC_IDX_DW5, setter->idx_single);
3655 }
3656 
3657 static void
3658 mlx5dr_action_setter_single_double_pop(struct mlx5dr_actions_apply_data *apply,
3659 				       __rte_unused struct mlx5dr_actions_wqe_setter *setter)
3660 {
3661 	apply->wqe_data[MLX5DR_ACTION_OFFSET_DW5] = 0;
3662 	apply->wqe_ctrl->stc_ix[MLX5DR_ACTION_STC_IDX_DW5] =
3663 		htobe32(mlx5dr_action_get_shared_stc_offset(apply->common_res,
3664 							    MLX5DR_CONTEXT_SHARED_STC_DOUBLE_POP));
3665 }
3666 
3667 static void
3668 mlx5dr_action_setter_hit(struct mlx5dr_actions_apply_data *apply,
3669 			 struct mlx5dr_actions_wqe_setter *setter)
3670 {
3671 	apply->wqe_data[MLX5DR_ACTION_OFFSET_HIT_LSB] = 0;
3672 	mlx5dr_action_apply_stc(apply, MLX5DR_ACTION_STC_IDX_HIT, setter->idx_hit);
3673 }
3674 
3675 static void
3676 mlx5dr_action_setter_default_hit(struct mlx5dr_actions_apply_data *apply,
3677 				 __rte_unused struct mlx5dr_actions_wqe_setter *setter)
3678 {
3679 	apply->wqe_data[MLX5DR_ACTION_OFFSET_HIT_LSB] = 0;
3680 	apply->wqe_ctrl->stc_ix[MLX5DR_ACTION_STC_IDX_HIT] =
3681 		htobe32(apply->common_res->default_stc->default_hit.offset);
3682 }
3683 
3684 static void
3685 mlx5dr_action_setter_hit_matcher(struct mlx5dr_actions_apply_data *apply,
3686 				 struct mlx5dr_actions_wqe_setter *setter)
3687 {
3688 	struct mlx5dr_rule_action *rule_action;
3689 
3690 	rule_action = &apply->rule_action[setter->idx_hit];
3691 
3692 	apply->wqe_data[MLX5DR_ACTION_OFFSET_HIT_LSB] =
3693 		htobe32(rule_action->jump_to_matcher.offset << 6);
3694 	mlx5dr_action_apply_stc(apply, MLX5DR_ACTION_STC_IDX_HIT, setter->idx_hit);
3695 }
3696 
3697 static void
3698 mlx5dr_action_setter_hit_next_action(struct mlx5dr_actions_apply_data *apply,
3699 				     __rte_unused struct mlx5dr_actions_wqe_setter *setter)
3700 {
3701 	apply->wqe_data[MLX5DR_ACTION_OFFSET_HIT_LSB] = htobe32(apply->next_direct_idx << 6);
3702 	apply->wqe_ctrl->stc_ix[MLX5DR_ACTION_STC_IDX_HIT] = htobe32(apply->jump_to_action_stc);
3703 }
3704 
3705 static void
3706 mlx5dr_action_setter_common_decap(struct mlx5dr_actions_apply_data *apply,
3707 				  __rte_unused struct mlx5dr_actions_wqe_setter *setter)
3708 {
3709 	apply->wqe_data[MLX5DR_ACTION_OFFSET_DW5] = 0;
3710 	apply->wqe_ctrl->stc_ix[MLX5DR_ACTION_STC_IDX_DW5] =
3711 		htobe32(mlx5dr_action_get_shared_stc_offset(apply->common_res,
3712 							    MLX5DR_CONTEXT_SHARED_STC_DECAP_L3));
3713 }
3714 
3715 static void
3716 mlx5dr_action_setter_ipv6_route_ext_gen_push_mhdr(uint8_t *data, void *mh_data)
3717 {
3718 	uint8_t *action_ptr = mh_data;
3719 	uint32_t *ipv6_dst_addr;
3720 	uint8_t seg_left;
3721 	uint32_t i;
3722 
3723 	/* Fetch the last IPv6 address in the segment list which is the next hop */
3724 	seg_left = MLX5_GET(header_ipv6_routing_ext, data, segments_left) - 1;
3725 	ipv6_dst_addr = (uint32_t *)data + MLX5_ST_SZ_DW(header_ipv6_routing_ext)
3726 			+ seg_left * MLX5_ST_SZ_DW(definer_hl_ipv6_addr);
3727 
3728 	/* Load next hop IPv6 address in reverse order to ipv6.dst_address */
3729 	for (i = 0; i < MLX5_ST_SZ_DW(definer_hl_ipv6_addr); i++) {
3730 		MLX5_SET(set_action_in, action_ptr, data, be32toh(*ipv6_dst_addr++));
3731 		action_ptr += MLX5DR_MODIFY_ACTION_SIZE;
3732 	}
3733 
3734 	/* Set ipv6_route_ext.next_hdr per user input */
3735 	MLX5_SET(set_action_in, action_ptr, data, *data);
3736 }
3737 
3738 static void
3739 mlx5dr_action_setter_ipv6_route_ext_mhdr(struct mlx5dr_actions_apply_data *apply,
3740 					 struct mlx5dr_actions_wqe_setter *setter)
3741 {
3742 	struct mlx5dr_rule_action *rule_action = apply->rule_action;
3743 	struct mlx5dr_actions_wqe_setter tmp_setter = {0};
3744 	struct mlx5dr_rule_action tmp_rule_action;
3745 	__be64 cmd[MLX5_SRV6_SAMPLE_NUM] = {0};
3746 	struct mlx5dr_action *ipv6_ext_action;
3747 	uint8_t *header;
3748 
3749 	header = rule_action[setter->idx_double].ipv6_ext.header;
3750 	ipv6_ext_action = rule_action[setter->idx_double].action;
3751 	tmp_rule_action.action = ipv6_ext_action->ipv6_route_ext.action[setter->extra_data];
3752 
3753 	if (tmp_rule_action.action->flags & MLX5DR_ACTION_FLAG_SHARED) {
3754 		tmp_rule_action.modify_header.offset = 0;
3755 		tmp_rule_action.modify_header.pattern_idx = 0;
3756 		tmp_rule_action.modify_header.data = NULL;
3757 	} else {
3758 		/*
3759 		 * Copy ipv6_dst from ipv6_route_ext.last_seg.
3760 		 * Set ipv6_route_ext.next_hdr.
3761 		 */
3762 		mlx5dr_action_setter_ipv6_route_ext_gen_push_mhdr(header, cmd);
3763 		tmp_rule_action.modify_header.data = (uint8_t *)cmd;
3764 		tmp_rule_action.modify_header.pattern_idx = 0;
3765 		tmp_rule_action.modify_header.offset =
3766 			rule_action[setter->idx_double].ipv6_ext.offset;
3767 	}
3768 
3769 	apply->rule_action = &tmp_rule_action;
3770 
3771 	/* Reuse regular */
3772 	mlx5dr_action_setter_modify_header(apply, &tmp_setter);
3773 
3774 	/* Swap rule actions from backup */
3775 	apply->rule_action = rule_action;
3776 }
3777 
3778 static void
3779 mlx5dr_action_setter_ipv6_route_ext_insert_ptr(struct mlx5dr_actions_apply_data *apply,
3780 					       struct mlx5dr_actions_wqe_setter *setter)
3781 {
3782 	struct mlx5dr_rule_action *rule_action = apply->rule_action;
3783 	struct mlx5dr_actions_wqe_setter tmp_setter = {0};
3784 	struct mlx5dr_rule_action tmp_rule_action;
3785 	struct mlx5dr_action *ipv6_ext_action;
3786 	uint8_t header[MLX5_PUSH_MAX_LEN];
3787 
3788 	ipv6_ext_action = rule_action[setter->idx_double].action;
3789 	tmp_rule_action.action = ipv6_ext_action->ipv6_route_ext.action[setter->extra_data];
3790 
3791 	if (tmp_rule_action.action->flags & MLX5DR_ACTION_FLAG_SHARED) {
3792 		tmp_rule_action.reformat.offset = 0;
3793 		tmp_rule_action.reformat.hdr_idx = 0;
3794 		tmp_rule_action.reformat.data = NULL;
3795 	} else {
3796 		memcpy(header, rule_action[setter->idx_double].ipv6_ext.header,
3797 		       tmp_rule_action.action->reformat.header_size);
3798 		/* Clear ipv6_route_ext.next_hdr for right checksum */
3799 		MLX5_SET(header_ipv6_routing_ext, header, next_hdr, 0);
3800 		tmp_rule_action.reformat.data = header;
3801 		tmp_rule_action.reformat.hdr_idx = 0;
3802 		tmp_rule_action.reformat.offset =
3803 			rule_action[setter->idx_double].ipv6_ext.offset;
3804 	}
3805 
3806 	apply->rule_action = &tmp_rule_action;
3807 
3808 	/* Reuse regular */
3809 	mlx5dr_action_setter_insert_ptr(apply, &tmp_setter);
3810 
3811 	/* Swap rule actions from backup */
3812 	apply->rule_action = rule_action;
3813 }
3814 
3815 static void
3816 mlx5dr_action_setter_ipv6_route_ext_pop(struct mlx5dr_actions_apply_data *apply,
3817 					struct mlx5dr_actions_wqe_setter *setter)
3818 {
3819 	struct mlx5dr_rule_action *rule_action = &apply->rule_action[setter->idx_single];
3820 	uint8_t idx = MLX5DR_ACTION_IPV6_EXT_MAX_SA - 1;
3821 	struct mlx5dr_action *action;
3822 
3823 	/* Pop the ipv6_route_ext as set_single logic */
3824 	action = rule_action->action->ipv6_route_ext.action[idx];
3825 	apply->wqe_data[MLX5DR_ACTION_OFFSET_DW5] = 0;
3826 	apply->wqe_ctrl->stc_ix[MLX5DR_ACTION_STC_IDX_DW5] =
3827 		htobe32(action->stc[apply->tbl_type].offset);
3828 }
3829 
3830 int mlx5dr_action_template_process(struct mlx5dr_action_template *at)
3831 {
3832 	struct mlx5dr_actions_wqe_setter *start_setter = at->setters + 1;
3833 	enum mlx5dr_action_type *action_type = at->action_type_arr;
3834 	struct mlx5dr_actions_wqe_setter *setter = at->setters;
3835 	struct mlx5dr_actions_wqe_setter *pop_setter = NULL;
3836 	struct mlx5dr_actions_wqe_setter *last_setter;
3837 	int i, j;
3838 
3839 	/* Note: Given action combination must be valid */
3840 
3841 	/* Check if action were already processed */
3842 	if (at->num_of_action_stes)
3843 		return 0;
3844 
3845 	for (i = 0; i < MLX5DR_ACTION_MAX_STE; i++)
3846 		setter[i].set_hit = &mlx5dr_action_setter_hit_next_action;
3847 
3848 	/* The same action template setters can be used with jumbo or match
3849 	 * STE, to support both cases we reseve the first setter for cases
3850 	 * with jumbo STE to allow jump to the first action STE.
3851 	 * This extra setter can be reduced in some cases on rule creation.
3852 	 */
3853 	setter = start_setter;
3854 	last_setter = start_setter;
3855 
3856 	for (i = 0; i < at->num_actions; i++) {
3857 		switch (action_type[i]) {
3858 		case MLX5DR_ACTION_TYP_DROP:
3859 		case MLX5DR_ACTION_TYP_TIR:
3860 		case MLX5DR_ACTION_TYP_TBL:
3861 		case MLX5DR_ACTION_TYP_DEST_ROOT:
3862 		case MLX5DR_ACTION_TYP_DEST_ARRAY:
3863 		case MLX5DR_ACTION_TYP_VPORT:
3864 		case MLX5DR_ACTION_TYP_MISS:
3865 			/* Hit action */
3866 			last_setter->flags |= ASF_HIT;
3867 			last_setter->set_hit = &mlx5dr_action_setter_hit;
3868 			last_setter->idx_hit = i;
3869 			break;
3870 
3871 		case MLX5DR_ACTION_TYP_POP_VLAN:
3872 			/* Single remove header to header */
3873 			if (pop_setter) {
3874 				/* We have 2 pops, use the shared */
3875 				pop_setter->set_single = &mlx5dr_action_setter_single_double_pop;
3876 				break;
3877 			}
3878 			setter = mlx5dr_action_setter_find_first(last_setter, ASF_SINGLE1 | ASF_MODIFY | ASF_INSERT);
3879 			setter->flags |= ASF_SINGLE1 | ASF_REMOVE;
3880 			setter->set_single = &mlx5dr_action_setter_single;
3881 			setter->idx_single = i;
3882 			pop_setter = setter;
3883 			break;
3884 
3885 		case MLX5DR_ACTION_TYP_PUSH_VLAN:
3886 			/* Double insert inline */
3887 			setter = mlx5dr_action_setter_find_first(last_setter, ASF_DOUBLE | ASF_REMOVE);
3888 			setter->flags |= ASF_DOUBLE | ASF_INSERT;
3889 			setter->set_double = &mlx5dr_action_setter_push_vlan;
3890 			setter->idx_double = i;
3891 			break;
3892 
3893 		case MLX5DR_ACTION_TYP_POP_IPV6_ROUTE_EXT:
3894 			/*
3895 			 * Backup ipv6_route_ext.next_hdr to ipv6_route_ext.seg_left.
3896 			 * Set ipv6_route_ext.next_hdr to 0 for checksum bug.
3897 			 */
3898 			setter = mlx5dr_action_setter_find_first(last_setter, ASF_DOUBLE | ASF_REMOVE);
3899 			setter->flags |= ASF_DOUBLE | ASF_MODIFY;
3900 			setter->set_double = &mlx5dr_action_setter_ipv6_route_ext_mhdr;
3901 			setter->idx_double = i;
3902 			setter->extra_data = 0;
3903 			setter++;
3904 
3905 			/*
3906 			 * Restore ipv6_route_ext.next_hdr from ipv6_route_ext.seg_left.
3907 			 * Load the final destination address from flex parser sample 1->4.
3908 			 */
3909 			setter->flags |= ASF_DOUBLE | ASF_MODIFY;
3910 			setter->set_double = &mlx5dr_action_setter_ipv6_route_ext_mhdr;
3911 			setter->idx_double = i;
3912 			setter->extra_data = 1;
3913 			setter++;
3914 
3915 			/* Set the ipv6.protocol per ipv6_route_ext.next_hdr */
3916 			setter->flags |= ASF_DOUBLE | ASF_MODIFY;
3917 			setter->set_double = &mlx5dr_action_setter_ipv6_route_ext_mhdr;
3918 			setter->idx_double = i;
3919 			setter->extra_data = 2;
3920 			/* Pop ipv6_route_ext */
3921 			setter->flags |= ASF_SINGLE1 | ASF_REMOVE;
3922 			setter->set_single = &mlx5dr_action_setter_ipv6_route_ext_pop;
3923 			setter->idx_single = i;
3924 			at->need_dep_write = true;
3925 			break;
3926 
3927 		case MLX5DR_ACTION_TYP_PUSH_IPV6_ROUTE_EXT:
3928 			/* Insert ipv6_route_ext with next_hdr as 0 due to checksum bug */
3929 			setter = mlx5dr_action_setter_find_first(last_setter, ASF_DOUBLE | ASF_REMOVE);
3930 			setter->flags |= ASF_DOUBLE | ASF_INSERT;
3931 			setter->set_double = &mlx5dr_action_setter_ipv6_route_ext_insert_ptr;
3932 			setter->idx_double = i;
3933 			setter->extra_data = 0;
3934 			setter++;
3935 
3936 			/* Set ipv6.protocol as IPPROTO_ROUTING: 0x2b */
3937 			setter->flags |= ASF_DOUBLE | ASF_MODIFY;
3938 			setter->set_double = &mlx5dr_action_setter_ipv6_route_ext_mhdr;
3939 			setter->idx_double = i;
3940 			setter->extra_data = 1;
3941 			setter++;
3942 
3943 			/*
3944 			 * Load the right ipv6_route_ext.next_hdr per user input buffer.
3945 			 * Load the next dest_addr from the ipv6_route_ext.seg_list[last].
3946 			 */
3947 			setter->flags |= ASF_DOUBLE | ASF_MODIFY;
3948 			setter->set_double = &mlx5dr_action_setter_ipv6_route_ext_mhdr;
3949 			setter->idx_double = i;
3950 			setter->extra_data = 2;
3951 			at->need_dep_write = true;
3952 			break;
3953 
3954 		case MLX5DR_ACTION_TYP_MODIFY_HDR:
3955 			/* Double modify header list */
3956 			setter = mlx5dr_action_setter_find_first(last_setter, ASF_DOUBLE | ASF_REMOVE);
3957 			setter->flags |= ASF_DOUBLE | ASF_MODIFY;
3958 			setter->set_double = &mlx5dr_action_setter_modify_header;
3959 			setter->idx_double = i;
3960 			at->need_dep_write = true;
3961 			break;
3962 
3963 		case MLX5DR_ACTION_TYP_ASO_METER:
3964 		case MLX5DR_ACTION_TYP_ASO_CT:
3965 			setter = mlx5dr_action_setter_find_first(last_setter, ASF_DOUBLE);
3966 			setter->flags |= ASF_DOUBLE;
3967 			setter->set_double = &mlx5dr_action_setter_aso;
3968 			setter->idx_double = i;
3969 			break;
3970 
3971 		case MLX5DR_ACTION_TYP_REMOVE_HEADER:
3972 		case MLX5DR_ACTION_TYP_REFORMAT_TNL_L2_TO_L2:
3973 			/* Single remove header to header */
3974 			setter = mlx5dr_action_setter_find_first(last_setter,
3975 					ASF_SINGLE1 | ASF_MODIFY | ASF_INSERT);
3976 			setter->flags |= ASF_SINGLE1 | ASF_REMOVE;
3977 			setter->set_single = &mlx5dr_action_setter_single;
3978 			setter->idx_single = i;
3979 			break;
3980 
3981 		case MLX5DR_ACTION_TYP_INSERT_HEADER:
3982 		case MLX5DR_ACTION_TYP_REFORMAT_L2_TO_TNL_L2:
3983 			/* Double insert header with pointer */
3984 			setter = mlx5dr_action_setter_find_first(last_setter, ASF_DOUBLE | ASF_REMOVE);
3985 			setter->flags |= ASF_DOUBLE | ASF_INSERT;
3986 			setter->set_double = &mlx5dr_action_setter_insert_ptr;
3987 			setter->idx_double = i;
3988 			at->need_dep_write = true;
3989 			break;
3990 
3991 		case MLX5DR_ACTION_TYP_REFORMAT_L2_TO_TNL_L3:
3992 			/* Single remove + Double insert header with pointer */
3993 			setter = mlx5dr_action_setter_find_first(last_setter, ASF_SINGLE1 | ASF_DOUBLE);
3994 			setter->flags |= ASF_SINGLE1 | ASF_DOUBLE;
3995 			setter->set_double = &mlx5dr_action_setter_insert_ptr;
3996 			setter->idx_double = i;
3997 			setter->set_single = &mlx5dr_action_setter_common_decap;
3998 			setter->idx_single = i;
3999 			at->need_dep_write = true;
4000 			break;
4001 
4002 		case MLX5DR_ACTION_TYP_REFORMAT_TNL_L3_TO_L2:
4003 			/* Double modify header list with remove and push inline */
4004 			setter = mlx5dr_action_setter_find_first(last_setter, ASF_DOUBLE | ASF_REMOVE);
4005 			setter->flags |= ASF_DOUBLE | ASF_MODIFY | ASF_INSERT;
4006 			setter->set_double = &mlx5dr_action_setter_tnl_l3_to_l2;
4007 			setter->idx_double = i;
4008 			at->need_dep_write = true;
4009 			break;
4010 
4011 		case MLX5DR_ACTION_TYP_TAG:
4012 			/* Single TAG action, search for any room from the start */
4013 			setter = mlx5dr_action_setter_find_first(start_setter, ASF_SINGLE1);
4014 			setter->flags |= ASF_SINGLE1;
4015 			setter->set_single = &mlx5dr_action_setter_tag;
4016 			setter->idx_single = i;
4017 			break;
4018 
4019 		case MLX5DR_ACTION_TYP_CTR:
4020 			/* Control counter action
4021 			 * TODO: Current counter executed first. Support is needed
4022 			 *	 for single ation counter action which is done last.
4023 			 *	 Example: Decap + CTR
4024 			 */
4025 			setter = mlx5dr_action_setter_find_first(start_setter, ASF_CTR);
4026 			setter->flags |= ASF_CTR;
4027 			setter->set_ctr = &mlx5dr_action_setter_ctrl_ctr;
4028 			setter->idx_ctr = i;
4029 			break;
4030 
4031 		case MLX5DR_ACTION_TYP_NAT64:
4032 			/* NAT64 requires 3 setters, each of them does specific modify header */
4033 			for (j = 0; j < MLX5DR_ACTION_NAT64_STAGES; j++) {
4034 				setter = mlx5dr_action_setter_find_first(last_setter,
4035 									 ASF_DOUBLE | ASF_REMOVE);
4036 				setter->flags |= ASF_DOUBLE | ASF_MODIFY;
4037 				setter->set_double = &mlx5dr_action_setter_nat64;
4038 				setter->idx_double = i;
4039 				/* The stage indicates which modify-header to push */
4040 				setter->stage_idx = j;
4041 			}
4042 			break;
4043 
4044 		case MLX5DR_ACTION_TYP_JUMP_TO_MATCHER:
4045 			last_setter->flags |= ASF_HIT;
4046 			last_setter->set_hit = &mlx5dr_action_setter_hit_matcher;
4047 			last_setter->idx_hit = i;
4048 			break;
4049 
4050 		default:
4051 			DR_LOG(ERR, "Unsupported action type: %d", action_type[i]);
4052 			rte_errno = ENOTSUP;
4053 			assert(false);
4054 			return rte_errno;
4055 		}
4056 
4057 		last_setter = RTE_MAX(setter, last_setter);
4058 	}
4059 
4060 	/* Set default hit on the last STE if no hit action provided */
4061 	if (!(last_setter->flags & ASF_HIT))
4062 		last_setter->set_hit = &mlx5dr_action_setter_default_hit;
4063 
4064 	at->num_of_action_stes = last_setter - start_setter + 1;
4065 
4066 	/* Check if action template doesn't require any action DWs */
4067 	at->only_term = (at->num_of_action_stes == 1) &&
4068 		!(last_setter->flags & ~(ASF_CTR | ASF_HIT));
4069 
4070 	return 0;
4071 }
4072 
4073 struct mlx5dr_action_template *
4074 mlx5dr_action_template_create(const enum mlx5dr_action_type action_type[],
4075 			      uint32_t flags)
4076 {
4077 	struct mlx5dr_action_template *at;
4078 	uint8_t num_actions = 0;
4079 	int i;
4080 
4081 	if (flags > MLX5DR_ACTION_TEMPLATE_FLAG_RELAXED_ORDER) {
4082 		DR_LOG(ERR, "Unsupported action template flag provided");
4083 		rte_errno = EINVAL;
4084 		return NULL;
4085 	}
4086 
4087 	at = simple_calloc(1, sizeof(*at));
4088 	if (!at) {
4089 		DR_LOG(ERR, "Failed to allocate action template");
4090 		rte_errno = ENOMEM;
4091 		return NULL;
4092 	}
4093 
4094 	at->flags = flags;
4095 
4096 	while (action_type[num_actions++] != MLX5DR_ACTION_TYP_LAST)
4097 		;
4098 
4099 	at->num_actions = num_actions - 1;
4100 	at->action_type_arr = simple_calloc(num_actions, sizeof(*action_type));
4101 	if (!at->action_type_arr) {
4102 		DR_LOG(ERR, "Failed to allocate action type array");
4103 		rte_errno = ENOMEM;
4104 		goto free_at;
4105 	}
4106 
4107 	for (i = 0; i < num_actions; i++)
4108 		at->action_type_arr[i] = action_type[i];
4109 
4110 	return at;
4111 
4112 free_at:
4113 	simple_free(at);
4114 	return NULL;
4115 }
4116 
4117 int mlx5dr_action_template_destroy(struct mlx5dr_action_template *at)
4118 {
4119 	simple_free(at->action_type_arr);
4120 	simple_free(at);
4121 	return 0;
4122 }
4123