f2fde91294755ef7f79035f628062bfe861f690f
[dpdk.git] / drivers / net / mlx5 / mlx5_flow_dv.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright 2018 Mellanox Technologies, Ltd
3  */
4
5 #include <sys/queue.h>
6 #include <stdalign.h>
7 #include <stdint.h>
8 #include <string.h>
9 #include <unistd.h>
10
11 #include <rte_common.h>
12 #include <rte_ether.h>
13 #include <ethdev_driver.h>
14 #include <rte_flow.h>
15 #include <rte_flow_driver.h>
16 #include <rte_malloc.h>
17 #include <rte_cycles.h>
18 #include <rte_ip.h>
19 #include <rte_gre.h>
20 #include <rte_vxlan.h>
21 #include <rte_gtp.h>
22 #include <rte_eal_paging.h>
23 #include <rte_mpls.h>
24 #include <rte_mtr.h>
25 #include <rte_mtr_driver.h>
26 #include <rte_tailq.h>
27
28 #include <mlx5_glue.h>
29 #include <mlx5_devx_cmds.h>
30 #include <mlx5_prm.h>
31 #include <mlx5_malloc.h>
32
33 #include "mlx5_defs.h"
34 #include "mlx5.h"
35 #include "mlx5_common_os.h"
36 #include "mlx5_flow.h"
37 #include "mlx5_flow_os.h"
38 #include "mlx5_rx.h"
39 #include "mlx5_tx.h"
40 #include "rte_pmd_mlx5.h"
41
42 #if defined(HAVE_IBV_FLOW_DV_SUPPORT) || !defined(HAVE_INFINIBAND_VERBS_H)
43
44 #ifndef HAVE_IBV_FLOW_DEVX_COUNTERS
45 #define MLX5DV_FLOW_ACTION_COUNTERS_DEVX 0
46 #endif
47
48 #ifndef HAVE_MLX5DV_DR_ESWITCH
49 #ifndef MLX5DV_FLOW_TABLE_TYPE_FDB
50 #define MLX5DV_FLOW_TABLE_TYPE_FDB 0
51 #endif
52 #endif
53
54 #ifndef HAVE_MLX5DV_DR
55 #define MLX5DV_DR_ACTION_FLAGS_ROOT_LEVEL 1
56 #endif
57
58 /* VLAN header definitions */
59 #define MLX5DV_FLOW_VLAN_PCP_SHIFT 13
60 #define MLX5DV_FLOW_VLAN_PCP_MASK (0x7 << MLX5DV_FLOW_VLAN_PCP_SHIFT)
61 #define MLX5DV_FLOW_VLAN_VID_MASK 0x0fff
62 #define MLX5DV_FLOW_VLAN_PCP_MASK_BE RTE_BE16(MLX5DV_FLOW_VLAN_PCP_MASK)
63 #define MLX5DV_FLOW_VLAN_VID_MASK_BE RTE_BE16(MLX5DV_FLOW_VLAN_VID_MASK)
64
65 union flow_dv_attr {
66         struct {
67                 uint32_t valid:1;
68                 uint32_t ipv4:1;
69                 uint32_t ipv6:1;
70                 uint32_t tcp:1;
71                 uint32_t udp:1;
72                 uint32_t reserved:27;
73         };
74         uint32_t attr;
75 };
76
77 static int
78 flow_dv_tbl_resource_release(struct mlx5_dev_ctx_shared *sh,
79                              struct mlx5_flow_tbl_resource *tbl);
80
81 static int
82 flow_dv_encap_decap_resource_release(struct rte_eth_dev *dev,
83                                      uint32_t encap_decap_idx);
84
85 static int
86 flow_dv_port_id_action_resource_release(struct rte_eth_dev *dev,
87                                         uint32_t port_id);
88 static void
89 flow_dv_shared_rss_action_release(struct rte_eth_dev *dev, uint32_t srss);
90
91 static int
92 flow_dv_jump_tbl_resource_release(struct rte_eth_dev *dev,
93                                   uint32_t rix_jump);
94
95 /**
96  * Initialize flow attributes structure according to flow items' types.
97  *
98  * flow_dv_validate() avoids multiple L3/L4 layers cases other than tunnel
99  * mode. For tunnel mode, the items to be modified are the outermost ones.
100  *
101  * @param[in] item
102  *   Pointer to item specification.
103  * @param[out] attr
104  *   Pointer to flow attributes structure.
105  * @param[in] dev_flow
106  *   Pointer to the sub flow.
107  * @param[in] tunnel_decap
108  *   Whether action is after tunnel decapsulation.
109  */
110 static void
111 flow_dv_attr_init(const struct rte_flow_item *item, union flow_dv_attr *attr,
112                   struct mlx5_flow *dev_flow, bool tunnel_decap)
113 {
114         uint64_t layers = dev_flow->handle->layers;
115
116         /*
117          * If layers is already initialized, it means this dev_flow is the
118          * suffix flow, the layers flags is set by the prefix flow. Need to
119          * use the layer flags from prefix flow as the suffix flow may not
120          * have the user defined items as the flow is split.
121          */
122         if (layers) {
123                 if (layers & MLX5_FLOW_LAYER_OUTER_L3_IPV4)
124                         attr->ipv4 = 1;
125                 else if (layers & MLX5_FLOW_LAYER_OUTER_L3_IPV6)
126                         attr->ipv6 = 1;
127                 if (layers & MLX5_FLOW_LAYER_OUTER_L4_TCP)
128                         attr->tcp = 1;
129                 else if (layers & MLX5_FLOW_LAYER_OUTER_L4_UDP)
130                         attr->udp = 1;
131                 attr->valid = 1;
132                 return;
133         }
134         for (; item->type != RTE_FLOW_ITEM_TYPE_END; item++) {
135                 uint8_t next_protocol = 0xff;
136                 switch (item->type) {
137                 case RTE_FLOW_ITEM_TYPE_GRE:
138                 case RTE_FLOW_ITEM_TYPE_NVGRE:
139                 case RTE_FLOW_ITEM_TYPE_VXLAN:
140                 case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
141                 case RTE_FLOW_ITEM_TYPE_GENEVE:
142                 case RTE_FLOW_ITEM_TYPE_MPLS:
143                         if (tunnel_decap)
144                                 attr->attr = 0;
145                         break;
146                 case RTE_FLOW_ITEM_TYPE_IPV4:
147                         if (!attr->ipv6)
148                                 attr->ipv4 = 1;
149                         if (item->mask != NULL &&
150                             ((const struct rte_flow_item_ipv4 *)
151                             item->mask)->hdr.next_proto_id)
152                                 next_protocol =
153                                     ((const struct rte_flow_item_ipv4 *)
154                                       (item->spec))->hdr.next_proto_id &
155                                     ((const struct rte_flow_item_ipv4 *)
156                                       (item->mask))->hdr.next_proto_id;
157                         if ((next_protocol == IPPROTO_IPIP ||
158                             next_protocol == IPPROTO_IPV6) && tunnel_decap)
159                                 attr->attr = 0;
160                         break;
161                 case RTE_FLOW_ITEM_TYPE_IPV6:
162                         if (!attr->ipv4)
163                                 attr->ipv6 = 1;
164                         if (item->mask != NULL &&
165                             ((const struct rte_flow_item_ipv6 *)
166                             item->mask)->hdr.proto)
167                                 next_protocol =
168                                     ((const struct rte_flow_item_ipv6 *)
169                                       (item->spec))->hdr.proto &
170                                     ((const struct rte_flow_item_ipv6 *)
171                                       (item->mask))->hdr.proto;
172                         if ((next_protocol == IPPROTO_IPIP ||
173                             next_protocol == IPPROTO_IPV6) && tunnel_decap)
174                                 attr->attr = 0;
175                         break;
176                 case RTE_FLOW_ITEM_TYPE_UDP:
177                         if (!attr->tcp)
178                                 attr->udp = 1;
179                         break;
180                 case RTE_FLOW_ITEM_TYPE_TCP:
181                         if (!attr->udp)
182                                 attr->tcp = 1;
183                         break;
184                 default:
185                         break;
186                 }
187         }
188         attr->valid = 1;
189 }
190
191 /*
192  * Convert rte_mtr_color to mlx5 color.
193  *
194  * @param[in] rcol
195  *   rte_mtr_color.
196  *
197  * @return
198  *   mlx5 color.
199  */
200 static inline int
201 rte_col_2_mlx5_col(enum rte_color rcol)
202 {
203         switch (rcol) {
204         case RTE_COLOR_GREEN:
205                 return MLX5_FLOW_COLOR_GREEN;
206         case RTE_COLOR_YELLOW:
207                 return MLX5_FLOW_COLOR_YELLOW;
208         case RTE_COLOR_RED:
209                 return MLX5_FLOW_COLOR_RED;
210         default:
211                 break;
212         }
213         return MLX5_FLOW_COLOR_UNDEFINED;
214 }
215
216 struct field_modify_info {
217         uint32_t size; /* Size of field in protocol header, in bytes. */
218         uint32_t offset; /* Offset of field in protocol header, in bytes. */
219         enum mlx5_modification_field id;
220 };
221
222 struct field_modify_info modify_eth[] = {
223         {4,  0, MLX5_MODI_OUT_DMAC_47_16},
224         {2,  4, MLX5_MODI_OUT_DMAC_15_0},
225         {4,  6, MLX5_MODI_OUT_SMAC_47_16},
226         {2, 10, MLX5_MODI_OUT_SMAC_15_0},
227         {0, 0, 0},
228 };
229
230 struct field_modify_info modify_vlan_out_first_vid[] = {
231         /* Size in bits !!! */
232         {12, 0, MLX5_MODI_OUT_FIRST_VID},
233         {0, 0, 0},
234 };
235
236 struct field_modify_info modify_ipv4[] = {
237         {1,  1, MLX5_MODI_OUT_IP_DSCP},
238         {1,  8, MLX5_MODI_OUT_IPV4_TTL},
239         {4, 12, MLX5_MODI_OUT_SIPV4},
240         {4, 16, MLX5_MODI_OUT_DIPV4},
241         {0, 0, 0},
242 };
243
244 struct field_modify_info modify_ipv6[] = {
245         {1,  0, MLX5_MODI_OUT_IP_DSCP},
246         {1,  7, MLX5_MODI_OUT_IPV6_HOPLIMIT},
247         {4,  8, MLX5_MODI_OUT_SIPV6_127_96},
248         {4, 12, MLX5_MODI_OUT_SIPV6_95_64},
249         {4, 16, MLX5_MODI_OUT_SIPV6_63_32},
250         {4, 20, MLX5_MODI_OUT_SIPV6_31_0},
251         {4, 24, MLX5_MODI_OUT_DIPV6_127_96},
252         {4, 28, MLX5_MODI_OUT_DIPV6_95_64},
253         {4, 32, MLX5_MODI_OUT_DIPV6_63_32},
254         {4, 36, MLX5_MODI_OUT_DIPV6_31_0},
255         {0, 0, 0},
256 };
257
258 struct field_modify_info modify_udp[] = {
259         {2, 0, MLX5_MODI_OUT_UDP_SPORT},
260         {2, 2, MLX5_MODI_OUT_UDP_DPORT},
261         {0, 0, 0},
262 };
263
264 struct field_modify_info modify_tcp[] = {
265         {2, 0, MLX5_MODI_OUT_TCP_SPORT},
266         {2, 2, MLX5_MODI_OUT_TCP_DPORT},
267         {4, 4, MLX5_MODI_OUT_TCP_SEQ_NUM},
268         {4, 8, MLX5_MODI_OUT_TCP_ACK_NUM},
269         {0, 0, 0},
270 };
271
272 static const struct rte_flow_item *
273 mlx5_flow_find_tunnel_item(const struct rte_flow_item *item)
274 {
275         for (; item->type != RTE_FLOW_ITEM_TYPE_END; item++) {
276                 switch (item->type) {
277                 default:
278                         break;
279                 case RTE_FLOW_ITEM_TYPE_VXLAN:
280                 case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
281                 case RTE_FLOW_ITEM_TYPE_GRE:
282                 case RTE_FLOW_ITEM_TYPE_MPLS:
283                 case RTE_FLOW_ITEM_TYPE_NVGRE:
284                 case RTE_FLOW_ITEM_TYPE_GENEVE:
285                         return item;
286                 case RTE_FLOW_ITEM_TYPE_IPV4:
287                 case RTE_FLOW_ITEM_TYPE_IPV6:
288                         if (item[1].type == RTE_FLOW_ITEM_TYPE_IPV4 ||
289                             item[1].type == RTE_FLOW_ITEM_TYPE_IPV6)
290                                 return item;
291                         break;
292                 }
293         }
294         return NULL;
295 }
296
297 static void
298 mlx5_flow_tunnel_ip_check(const struct rte_flow_item *item __rte_unused,
299                           uint8_t next_protocol, uint64_t *item_flags,
300                           int *tunnel)
301 {
302         MLX5_ASSERT(item->type == RTE_FLOW_ITEM_TYPE_IPV4 ||
303                     item->type == RTE_FLOW_ITEM_TYPE_IPV6);
304         if (next_protocol == IPPROTO_IPIP) {
305                 *item_flags |= MLX5_FLOW_LAYER_IPIP;
306                 *tunnel = 1;
307         }
308         if (next_protocol == IPPROTO_IPV6) {
309                 *item_flags |= MLX5_FLOW_LAYER_IPV6_ENCAP;
310                 *tunnel = 1;
311         }
312 }
313
314 static inline struct mlx5_hlist *
315 flow_dv_hlist_prepare(struct mlx5_dev_ctx_shared *sh, struct mlx5_hlist **phl,
316                      const char *name, uint32_t size, bool direct_key,
317                      bool lcores_share, void *ctx,
318                      mlx5_list_create_cb cb_create,
319                      mlx5_list_match_cb cb_match,
320                      mlx5_list_remove_cb cb_remove,
321                      mlx5_list_clone_cb cb_clone,
322                      mlx5_list_clone_free_cb cb_clone_free)
323 {
324         struct mlx5_hlist *hl;
325         struct mlx5_hlist *expected = NULL;
326         char s[MLX5_NAME_SIZE];
327
328         hl = __atomic_load_n(phl, __ATOMIC_SEQ_CST);
329         if (likely(hl))
330                 return hl;
331         snprintf(s, sizeof(s), "%s_%s", sh->ibdev_name, name);
332         hl = mlx5_hlist_create(s, size, direct_key, lcores_share,
333                         ctx, cb_create, cb_match, cb_remove, cb_clone,
334                         cb_clone_free);
335         if (!hl) {
336                 DRV_LOG(ERR, "%s hash creation failed", name);
337                 rte_errno = ENOMEM;
338                 return NULL;
339         }
340         if (!__atomic_compare_exchange_n(phl, &expected, hl, false,
341                                          __ATOMIC_SEQ_CST,
342                                          __ATOMIC_SEQ_CST)) {
343                 mlx5_hlist_destroy(hl);
344                 hl = __atomic_load_n(phl, __ATOMIC_SEQ_CST);
345         }
346         return hl;
347 }
348
349 /* Update VLAN's VID/PCP based on input rte_flow_action.
350  *
351  * @param[in] action
352  *   Pointer to struct rte_flow_action.
353  * @param[out] vlan
354  *   Pointer to struct rte_vlan_hdr.
355  */
356 static void
357 mlx5_update_vlan_vid_pcp(const struct rte_flow_action *action,
358                          struct rte_vlan_hdr *vlan)
359 {
360         uint16_t vlan_tci;
361         if (action->type == RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP) {
362                 vlan_tci =
363                     ((const struct rte_flow_action_of_set_vlan_pcp *)
364                                                action->conf)->vlan_pcp;
365                 vlan_tci = vlan_tci << MLX5DV_FLOW_VLAN_PCP_SHIFT;
366                 vlan->vlan_tci &= ~MLX5DV_FLOW_VLAN_PCP_MASK;
367                 vlan->vlan_tci |= vlan_tci;
368         } else if (action->type == RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID) {
369                 vlan->vlan_tci &= ~MLX5DV_FLOW_VLAN_VID_MASK;
370                 vlan->vlan_tci |= rte_be_to_cpu_16
371                     (((const struct rte_flow_action_of_set_vlan_vid *)
372                                              action->conf)->vlan_vid);
373         }
374 }
375
376 /**
377  * Fetch 1, 2, 3 or 4 byte field from the byte array
378  * and return as unsigned integer in host-endian format.
379  *
380  * @param[in] data
381  *   Pointer to data array.
382  * @param[in] size
383  *   Size of field to extract.
384  *
385  * @return
386  *   converted field in host endian format.
387  */
388 static inline uint32_t
389 flow_dv_fetch_field(const uint8_t *data, uint32_t size)
390 {
391         uint32_t ret;
392
393         switch (size) {
394         case 1:
395                 ret = *data;
396                 break;
397         case 2:
398                 ret = rte_be_to_cpu_16(*(const unaligned_uint16_t *)data);
399                 break;
400         case 3:
401                 ret = rte_be_to_cpu_16(*(const unaligned_uint16_t *)data);
402                 ret = (ret << 8) | *(data + sizeof(uint16_t));
403                 break;
404         case 4:
405                 ret = rte_be_to_cpu_32(*(const unaligned_uint32_t *)data);
406                 break;
407         default:
408                 MLX5_ASSERT(false);
409                 ret = 0;
410                 break;
411         }
412         return ret;
413 }
414
415 /**
416  * Convert modify-header action to DV specification.
417  *
418  * Data length of each action is determined by provided field description
419  * and the item mask. Data bit offset and width of each action is determined
420  * by provided item mask.
421  *
422  * @param[in] item
423  *   Pointer to item specification.
424  * @param[in] field
425  *   Pointer to field modification information.
426  *     For MLX5_MODIFICATION_TYPE_SET specifies destination field.
427  *     For MLX5_MODIFICATION_TYPE_ADD specifies destination field.
428  *     For MLX5_MODIFICATION_TYPE_COPY specifies source field.
429  * @param[in] dcopy
430  *   Destination field info for MLX5_MODIFICATION_TYPE_COPY in @type.
431  *   Negative offset value sets the same offset as source offset.
432  *   size field is ignored, value is taken from source field.
433  * @param[in,out] resource
434  *   Pointer to the modify-header resource.
435  * @param[in] type
436  *   Type of modification.
437  * @param[out] error
438  *   Pointer to the error structure.
439  *
440  * @return
441  *   0 on success, a negative errno value otherwise and rte_errno is set.
442  */
443 static int
444 flow_dv_convert_modify_action(struct rte_flow_item *item,
445                               struct field_modify_info *field,
446                               struct field_modify_info *dcopy,
447                               struct mlx5_flow_dv_modify_hdr_resource *resource,
448                               uint32_t type, struct rte_flow_error *error)
449 {
450         uint32_t i = resource->actions_num;
451         struct mlx5_modification_cmd *actions = resource->actions;
452         uint32_t carry_b = 0;
453
454         /*
455          * The item and mask are provided in big-endian format.
456          * The fields should be presented as in big-endian format either.
457          * Mask must be always present, it defines the actual field width.
458          */
459         MLX5_ASSERT(item->mask);
460         MLX5_ASSERT(field->size);
461         do {
462                 uint32_t size_b;
463                 uint32_t off_b;
464                 uint32_t mask;
465                 uint32_t data;
466                 bool next_field = true;
467                 bool next_dcopy = true;
468
469                 if (i >= MLX5_MAX_MODIFY_NUM)
470                         return rte_flow_error_set(error, EINVAL,
471                                  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
472                                  "too many items to modify");
473                 /* Fetch variable byte size mask from the array. */
474                 mask = flow_dv_fetch_field((const uint8_t *)item->mask +
475                                            field->offset, field->size);
476                 if (!mask) {
477                         ++field;
478                         continue;
479                 }
480                 /* Deduce actual data width in bits from mask value. */
481                 off_b = rte_bsf32(mask) + carry_b;
482                 size_b = sizeof(uint32_t) * CHAR_BIT -
483                          off_b - __builtin_clz(mask);
484                 MLX5_ASSERT(size_b);
485                 actions[i] = (struct mlx5_modification_cmd) {
486                         .action_type = type,
487                         .field = field->id,
488                         .offset = off_b,
489                         .length = (size_b == sizeof(uint32_t) * CHAR_BIT) ?
490                                 0 : size_b,
491                 };
492                 if (type == MLX5_MODIFICATION_TYPE_COPY) {
493                         MLX5_ASSERT(dcopy);
494                         actions[i].dst_field = dcopy->id;
495                         actions[i].dst_offset =
496                                 (int)dcopy->offset < 0 ? off_b : dcopy->offset;
497                         /* Convert entire record to big-endian format. */
498                         actions[i].data1 = rte_cpu_to_be_32(actions[i].data1);
499                         /*
500                          * Destination field overflow. Copy leftovers of
501                          * a source field to the next destination field.
502                          */
503                         carry_b = 0;
504                         if ((size_b > dcopy->size * CHAR_BIT - dcopy->offset) &&
505                             dcopy->size != 0) {
506                                 actions[i].length =
507                                         dcopy->size * CHAR_BIT - dcopy->offset;
508                                 carry_b = actions[i].length;
509                                 next_field = false;
510                         }
511                         /*
512                          * Not enough bits in a source filed to fill a
513                          * destination field. Switch to the next source.
514                          */
515                         if ((size_b < dcopy->size * CHAR_BIT - dcopy->offset) &&
516                             (size_b == field->size * CHAR_BIT - off_b)) {
517                                 actions[i].length =
518                                         field->size * CHAR_BIT - off_b;
519                                 dcopy->offset += actions[i].length;
520                                 next_dcopy = false;
521                         }
522                         if (next_dcopy)
523                                 ++dcopy;
524                 } else {
525                         MLX5_ASSERT(item->spec);
526                         data = flow_dv_fetch_field((const uint8_t *)item->spec +
527                                                    field->offset, field->size);
528                         /* Shift out the trailing masked bits from data. */
529                         data = (data & mask) >> off_b;
530                         actions[i].data1 = rte_cpu_to_be_32(data);
531                 }
532                 /* Convert entire record to expected big-endian format. */
533                 actions[i].data0 = rte_cpu_to_be_32(actions[i].data0);
534                 if (next_field)
535                         ++field;
536                 ++i;
537         } while (field->size);
538         if (resource->actions_num == i)
539                 return rte_flow_error_set(error, EINVAL,
540                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
541                                           "invalid modification flow item");
542         resource->actions_num = i;
543         return 0;
544 }
545
546 /**
547  * Convert modify-header set IPv4 address action to DV specification.
548  *
549  * @param[in,out] resource
550  *   Pointer to the modify-header resource.
551  * @param[in] action
552  *   Pointer to action specification.
553  * @param[out] error
554  *   Pointer to the error structure.
555  *
556  * @return
557  *   0 on success, a negative errno value otherwise and rte_errno is set.
558  */
559 static int
560 flow_dv_convert_action_modify_ipv4
561                         (struct mlx5_flow_dv_modify_hdr_resource *resource,
562                          const struct rte_flow_action *action,
563                          struct rte_flow_error *error)
564 {
565         const struct rte_flow_action_set_ipv4 *conf =
566                 (const struct rte_flow_action_set_ipv4 *)(action->conf);
567         struct rte_flow_item item = { .type = RTE_FLOW_ITEM_TYPE_IPV4 };
568         struct rte_flow_item_ipv4 ipv4;
569         struct rte_flow_item_ipv4 ipv4_mask;
570
571         memset(&ipv4, 0, sizeof(ipv4));
572         memset(&ipv4_mask, 0, sizeof(ipv4_mask));
573         if (action->type == RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC) {
574                 ipv4.hdr.src_addr = conf->ipv4_addr;
575                 ipv4_mask.hdr.src_addr = rte_flow_item_ipv4_mask.hdr.src_addr;
576         } else {
577                 ipv4.hdr.dst_addr = conf->ipv4_addr;
578                 ipv4_mask.hdr.dst_addr = rte_flow_item_ipv4_mask.hdr.dst_addr;
579         }
580         item.spec = &ipv4;
581         item.mask = &ipv4_mask;
582         return flow_dv_convert_modify_action(&item, modify_ipv4, NULL, resource,
583                                              MLX5_MODIFICATION_TYPE_SET, error);
584 }
585
586 /**
587  * Convert modify-header set IPv6 address action to DV specification.
588  *
589  * @param[in,out] resource
590  *   Pointer to the modify-header resource.
591  * @param[in] action
592  *   Pointer to action specification.
593  * @param[out] error
594  *   Pointer to the error structure.
595  *
596  * @return
597  *   0 on success, a negative errno value otherwise and rte_errno is set.
598  */
599 static int
600 flow_dv_convert_action_modify_ipv6
601                         (struct mlx5_flow_dv_modify_hdr_resource *resource,
602                          const struct rte_flow_action *action,
603                          struct rte_flow_error *error)
604 {
605         const struct rte_flow_action_set_ipv6 *conf =
606                 (const struct rte_flow_action_set_ipv6 *)(action->conf);
607         struct rte_flow_item item = { .type = RTE_FLOW_ITEM_TYPE_IPV6 };
608         struct rte_flow_item_ipv6 ipv6;
609         struct rte_flow_item_ipv6 ipv6_mask;
610
611         memset(&ipv6, 0, sizeof(ipv6));
612         memset(&ipv6_mask, 0, sizeof(ipv6_mask));
613         if (action->type == RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC) {
614                 memcpy(&ipv6.hdr.src_addr, &conf->ipv6_addr,
615                        sizeof(ipv6.hdr.src_addr));
616                 memcpy(&ipv6_mask.hdr.src_addr,
617                        &rte_flow_item_ipv6_mask.hdr.src_addr,
618                        sizeof(ipv6.hdr.src_addr));
619         } else {
620                 memcpy(&ipv6.hdr.dst_addr, &conf->ipv6_addr,
621                        sizeof(ipv6.hdr.dst_addr));
622                 memcpy(&ipv6_mask.hdr.dst_addr,
623                        &rte_flow_item_ipv6_mask.hdr.dst_addr,
624                        sizeof(ipv6.hdr.dst_addr));
625         }
626         item.spec = &ipv6;
627         item.mask = &ipv6_mask;
628         return flow_dv_convert_modify_action(&item, modify_ipv6, NULL, resource,
629                                              MLX5_MODIFICATION_TYPE_SET, error);
630 }
631
632 /**
633  * Convert modify-header set MAC address action to DV specification.
634  *
635  * @param[in,out] resource
636  *   Pointer to the modify-header resource.
637  * @param[in] action
638  *   Pointer to action specification.
639  * @param[out] error
640  *   Pointer to the error structure.
641  *
642  * @return
643  *   0 on success, a negative errno value otherwise and rte_errno is set.
644  */
645 static int
646 flow_dv_convert_action_modify_mac
647                         (struct mlx5_flow_dv_modify_hdr_resource *resource,
648                          const struct rte_flow_action *action,
649                          struct rte_flow_error *error)
650 {
651         const struct rte_flow_action_set_mac *conf =
652                 (const struct rte_flow_action_set_mac *)(action->conf);
653         struct rte_flow_item item = { .type = RTE_FLOW_ITEM_TYPE_ETH };
654         struct rte_flow_item_eth eth;
655         struct rte_flow_item_eth eth_mask;
656
657         memset(&eth, 0, sizeof(eth));
658         memset(&eth_mask, 0, sizeof(eth_mask));
659         if (action->type == RTE_FLOW_ACTION_TYPE_SET_MAC_SRC) {
660                 memcpy(&eth.src.addr_bytes, &conf->mac_addr,
661                        sizeof(eth.src.addr_bytes));
662                 memcpy(&eth_mask.src.addr_bytes,
663                        &rte_flow_item_eth_mask.src.addr_bytes,
664                        sizeof(eth_mask.src.addr_bytes));
665         } else {
666                 memcpy(&eth.dst.addr_bytes, &conf->mac_addr,
667                        sizeof(eth.dst.addr_bytes));
668                 memcpy(&eth_mask.dst.addr_bytes,
669                        &rte_flow_item_eth_mask.dst.addr_bytes,
670                        sizeof(eth_mask.dst.addr_bytes));
671         }
672         item.spec = &eth;
673         item.mask = &eth_mask;
674         return flow_dv_convert_modify_action(&item, modify_eth, NULL, resource,
675                                              MLX5_MODIFICATION_TYPE_SET, error);
676 }
677
678 /**
679  * Convert modify-header set VLAN VID action to DV specification.
680  *
681  * @param[in,out] resource
682  *   Pointer to the modify-header resource.
683  * @param[in] action
684  *   Pointer to action specification.
685  * @param[out] error
686  *   Pointer to the error structure.
687  *
688  * @return
689  *   0 on success, a negative errno value otherwise and rte_errno is set.
690  */
691 static int
692 flow_dv_convert_action_modify_vlan_vid
693                         (struct mlx5_flow_dv_modify_hdr_resource *resource,
694                          const struct rte_flow_action *action,
695                          struct rte_flow_error *error)
696 {
697         const struct rte_flow_action_of_set_vlan_vid *conf =
698                 (const struct rte_flow_action_of_set_vlan_vid *)(action->conf);
699         int i = resource->actions_num;
700         struct mlx5_modification_cmd *actions = resource->actions;
701         struct field_modify_info *field = modify_vlan_out_first_vid;
702
703         if (i >= MLX5_MAX_MODIFY_NUM)
704                 return rte_flow_error_set(error, EINVAL,
705                          RTE_FLOW_ERROR_TYPE_ACTION, NULL,
706                          "too many items to modify");
707         actions[i] = (struct mlx5_modification_cmd) {
708                 .action_type = MLX5_MODIFICATION_TYPE_SET,
709                 .field = field->id,
710                 .length = field->size,
711                 .offset = field->offset,
712         };
713         actions[i].data0 = rte_cpu_to_be_32(actions[i].data0);
714         actions[i].data1 = conf->vlan_vid;
715         actions[i].data1 = actions[i].data1 << 16;
716         resource->actions_num = ++i;
717         return 0;
718 }
719
720 /**
721  * Convert modify-header set TP action to DV specification.
722  *
723  * @param[in,out] resource
724  *   Pointer to the modify-header resource.
725  * @param[in] action
726  *   Pointer to action specification.
727  * @param[in] items
728  *   Pointer to rte_flow_item objects list.
729  * @param[in] attr
730  *   Pointer to flow attributes structure.
731  * @param[in] dev_flow
732  *   Pointer to the sub flow.
733  * @param[in] tunnel_decap
734  *   Whether action is after tunnel decapsulation.
735  * @param[out] error
736  *   Pointer to the error structure.
737  *
738  * @return
739  *   0 on success, a negative errno value otherwise and rte_errno is set.
740  */
741 static int
742 flow_dv_convert_action_modify_tp
743                         (struct mlx5_flow_dv_modify_hdr_resource *resource,
744                          const struct rte_flow_action *action,
745                          const struct rte_flow_item *items,
746                          union flow_dv_attr *attr, struct mlx5_flow *dev_flow,
747                          bool tunnel_decap, struct rte_flow_error *error)
748 {
749         const struct rte_flow_action_set_tp *conf =
750                 (const struct rte_flow_action_set_tp *)(action->conf);
751         struct rte_flow_item item;
752         struct rte_flow_item_udp udp;
753         struct rte_flow_item_udp udp_mask;
754         struct rte_flow_item_tcp tcp;
755         struct rte_flow_item_tcp tcp_mask;
756         struct field_modify_info *field;
757
758         if (!attr->valid)
759                 flow_dv_attr_init(items, attr, dev_flow, tunnel_decap);
760         if (attr->udp) {
761                 memset(&udp, 0, sizeof(udp));
762                 memset(&udp_mask, 0, sizeof(udp_mask));
763                 if (action->type == RTE_FLOW_ACTION_TYPE_SET_TP_SRC) {
764                         udp.hdr.src_port = conf->port;
765                         udp_mask.hdr.src_port =
766                                         rte_flow_item_udp_mask.hdr.src_port;
767                 } else {
768                         udp.hdr.dst_port = conf->port;
769                         udp_mask.hdr.dst_port =
770                                         rte_flow_item_udp_mask.hdr.dst_port;
771                 }
772                 item.type = RTE_FLOW_ITEM_TYPE_UDP;
773                 item.spec = &udp;
774                 item.mask = &udp_mask;
775                 field = modify_udp;
776         } else {
777                 MLX5_ASSERT(attr->tcp);
778                 memset(&tcp, 0, sizeof(tcp));
779                 memset(&tcp_mask, 0, sizeof(tcp_mask));
780                 if (action->type == RTE_FLOW_ACTION_TYPE_SET_TP_SRC) {
781                         tcp.hdr.src_port = conf->port;
782                         tcp_mask.hdr.src_port =
783                                         rte_flow_item_tcp_mask.hdr.src_port;
784                 } else {
785                         tcp.hdr.dst_port = conf->port;
786                         tcp_mask.hdr.dst_port =
787                                         rte_flow_item_tcp_mask.hdr.dst_port;
788                 }
789                 item.type = RTE_FLOW_ITEM_TYPE_TCP;
790                 item.spec = &tcp;
791                 item.mask = &tcp_mask;
792                 field = modify_tcp;
793         }
794         return flow_dv_convert_modify_action(&item, field, NULL, resource,
795                                              MLX5_MODIFICATION_TYPE_SET, error);
796 }
797
798 /**
799  * Convert modify-header set TTL action to DV specification.
800  *
801  * @param[in,out] resource
802  *   Pointer to the modify-header resource.
803  * @param[in] action
804  *   Pointer to action specification.
805  * @param[in] items
806  *   Pointer to rte_flow_item objects list.
807  * @param[in] attr
808  *   Pointer to flow attributes structure.
809  * @param[in] dev_flow
810  *   Pointer to the sub flow.
811  * @param[in] tunnel_decap
812  *   Whether action is after tunnel decapsulation.
813  * @param[out] error
814  *   Pointer to the error structure.
815  *
816  * @return
817  *   0 on success, a negative errno value otherwise and rte_errno is set.
818  */
819 static int
820 flow_dv_convert_action_modify_ttl
821                         (struct mlx5_flow_dv_modify_hdr_resource *resource,
822                          const struct rte_flow_action *action,
823                          const struct rte_flow_item *items,
824                          union flow_dv_attr *attr, struct mlx5_flow *dev_flow,
825                          bool tunnel_decap, struct rte_flow_error *error)
826 {
827         const struct rte_flow_action_set_ttl *conf =
828                 (const struct rte_flow_action_set_ttl *)(action->conf);
829         struct rte_flow_item item;
830         struct rte_flow_item_ipv4 ipv4;
831         struct rte_flow_item_ipv4 ipv4_mask;
832         struct rte_flow_item_ipv6 ipv6;
833         struct rte_flow_item_ipv6 ipv6_mask;
834         struct field_modify_info *field;
835
836         if (!attr->valid)
837                 flow_dv_attr_init(items, attr, dev_flow, tunnel_decap);
838         if (attr->ipv4) {
839                 memset(&ipv4, 0, sizeof(ipv4));
840                 memset(&ipv4_mask, 0, sizeof(ipv4_mask));
841                 ipv4.hdr.time_to_live = conf->ttl_value;
842                 ipv4_mask.hdr.time_to_live = 0xFF;
843                 item.type = RTE_FLOW_ITEM_TYPE_IPV4;
844                 item.spec = &ipv4;
845                 item.mask = &ipv4_mask;
846                 field = modify_ipv4;
847         } else {
848                 MLX5_ASSERT(attr->ipv6);
849                 memset(&ipv6, 0, sizeof(ipv6));
850                 memset(&ipv6_mask, 0, sizeof(ipv6_mask));
851                 ipv6.hdr.hop_limits = conf->ttl_value;
852                 ipv6_mask.hdr.hop_limits = 0xFF;
853                 item.type = RTE_FLOW_ITEM_TYPE_IPV6;
854                 item.spec = &ipv6;
855                 item.mask = &ipv6_mask;
856                 field = modify_ipv6;
857         }
858         return flow_dv_convert_modify_action(&item, field, NULL, resource,
859                                              MLX5_MODIFICATION_TYPE_SET, error);
860 }
861
862 /**
863  * Convert modify-header decrement TTL action to DV specification.
864  *
865  * @param[in,out] resource
866  *   Pointer to the modify-header resource.
867  * @param[in] action
868  *   Pointer to action specification.
869  * @param[in] items
870  *   Pointer to rte_flow_item objects list.
871  * @param[in] attr
872  *   Pointer to flow attributes structure.
873  * @param[in] dev_flow
874  *   Pointer to the sub flow.
875  * @param[in] tunnel_decap
876  *   Whether action is after tunnel decapsulation.
877  * @param[out] error
878  *   Pointer to the error structure.
879  *
880  * @return
881  *   0 on success, a negative errno value otherwise and rte_errno is set.
882  */
883 static int
884 flow_dv_convert_action_modify_dec_ttl
885                         (struct mlx5_flow_dv_modify_hdr_resource *resource,
886                          const struct rte_flow_item *items,
887                          union flow_dv_attr *attr, struct mlx5_flow *dev_flow,
888                          bool tunnel_decap, struct rte_flow_error *error)
889 {
890         struct rte_flow_item item;
891         struct rte_flow_item_ipv4 ipv4;
892         struct rte_flow_item_ipv4 ipv4_mask;
893         struct rte_flow_item_ipv6 ipv6;
894         struct rte_flow_item_ipv6 ipv6_mask;
895         struct field_modify_info *field;
896
897         if (!attr->valid)
898                 flow_dv_attr_init(items, attr, dev_flow, tunnel_decap);
899         if (attr->ipv4) {
900                 memset(&ipv4, 0, sizeof(ipv4));
901                 memset(&ipv4_mask, 0, sizeof(ipv4_mask));
902                 ipv4.hdr.time_to_live = 0xFF;
903                 ipv4_mask.hdr.time_to_live = 0xFF;
904                 item.type = RTE_FLOW_ITEM_TYPE_IPV4;
905                 item.spec = &ipv4;
906                 item.mask = &ipv4_mask;
907                 field = modify_ipv4;
908         } else {
909                 MLX5_ASSERT(attr->ipv6);
910                 memset(&ipv6, 0, sizeof(ipv6));
911                 memset(&ipv6_mask, 0, sizeof(ipv6_mask));
912                 ipv6.hdr.hop_limits = 0xFF;
913                 ipv6_mask.hdr.hop_limits = 0xFF;
914                 item.type = RTE_FLOW_ITEM_TYPE_IPV6;
915                 item.spec = &ipv6;
916                 item.mask = &ipv6_mask;
917                 field = modify_ipv6;
918         }
919         return flow_dv_convert_modify_action(&item, field, NULL, resource,
920                                              MLX5_MODIFICATION_TYPE_ADD, error);
921 }
922
923 /**
924  * Convert modify-header increment/decrement TCP Sequence number
925  * to DV specification.
926  *
927  * @param[in,out] resource
928  *   Pointer to the modify-header resource.
929  * @param[in] action
930  *   Pointer to action specification.
931  * @param[out] error
932  *   Pointer to the error structure.
933  *
934  * @return
935  *   0 on success, a negative errno value otherwise and rte_errno is set.
936  */
937 static int
938 flow_dv_convert_action_modify_tcp_seq
939                         (struct mlx5_flow_dv_modify_hdr_resource *resource,
940                          const struct rte_flow_action *action,
941                          struct rte_flow_error *error)
942 {
943         const rte_be32_t *conf = (const rte_be32_t *)(action->conf);
944         uint64_t value = rte_be_to_cpu_32(*conf);
945         struct rte_flow_item item;
946         struct rte_flow_item_tcp tcp;
947         struct rte_flow_item_tcp tcp_mask;
948
949         memset(&tcp, 0, sizeof(tcp));
950         memset(&tcp_mask, 0, sizeof(tcp_mask));
951         if (action->type == RTE_FLOW_ACTION_TYPE_DEC_TCP_SEQ)
952                 /*
953                  * The HW has no decrement operation, only increment operation.
954                  * To simulate decrement X from Y using increment operation
955                  * we need to add UINT32_MAX X times to Y.
956                  * Each adding of UINT32_MAX decrements Y by 1.
957                  */
958                 value *= UINT32_MAX;
959         tcp.hdr.sent_seq = rte_cpu_to_be_32((uint32_t)value);
960         tcp_mask.hdr.sent_seq = RTE_BE32(UINT32_MAX);
961         item.type = RTE_FLOW_ITEM_TYPE_TCP;
962         item.spec = &tcp;
963         item.mask = &tcp_mask;
964         return flow_dv_convert_modify_action(&item, modify_tcp, NULL, resource,
965                                              MLX5_MODIFICATION_TYPE_ADD, error);
966 }
967
968 /**
969  * Convert modify-header increment/decrement TCP Acknowledgment number
970  * to DV specification.
971  *
972  * @param[in,out] resource
973  *   Pointer to the modify-header resource.
974  * @param[in] action
975  *   Pointer to action specification.
976  * @param[out] error
977  *   Pointer to the error structure.
978  *
979  * @return
980  *   0 on success, a negative errno value otherwise and rte_errno is set.
981  */
982 static int
983 flow_dv_convert_action_modify_tcp_ack
984                         (struct mlx5_flow_dv_modify_hdr_resource *resource,
985                          const struct rte_flow_action *action,
986                          struct rte_flow_error *error)
987 {
988         const rte_be32_t *conf = (const rte_be32_t *)(action->conf);
989         uint64_t value = rte_be_to_cpu_32(*conf);
990         struct rte_flow_item item;
991         struct rte_flow_item_tcp tcp;
992         struct rte_flow_item_tcp tcp_mask;
993
994         memset(&tcp, 0, sizeof(tcp));
995         memset(&tcp_mask, 0, sizeof(tcp_mask));
996         if (action->type == RTE_FLOW_ACTION_TYPE_DEC_TCP_ACK)
997                 /*
998                  * The HW has no decrement operation, only increment operation.
999                  * To simulate decrement X from Y using increment operation
1000                  * we need to add UINT32_MAX X times to Y.
1001                  * Each adding of UINT32_MAX decrements Y by 1.
1002                  */
1003                 value *= UINT32_MAX;
1004         tcp.hdr.recv_ack = rte_cpu_to_be_32((uint32_t)value);
1005         tcp_mask.hdr.recv_ack = RTE_BE32(UINT32_MAX);
1006         item.type = RTE_FLOW_ITEM_TYPE_TCP;
1007         item.spec = &tcp;
1008         item.mask = &tcp_mask;
1009         return flow_dv_convert_modify_action(&item, modify_tcp, NULL, resource,
1010                                              MLX5_MODIFICATION_TYPE_ADD, error);
1011 }
1012
1013 static enum mlx5_modification_field reg_to_field[] = {
1014         [REG_NON] = MLX5_MODI_OUT_NONE,
1015         [REG_A] = MLX5_MODI_META_DATA_REG_A,
1016         [REG_B] = MLX5_MODI_META_DATA_REG_B,
1017         [REG_C_0] = MLX5_MODI_META_REG_C_0,
1018         [REG_C_1] = MLX5_MODI_META_REG_C_1,
1019         [REG_C_2] = MLX5_MODI_META_REG_C_2,
1020         [REG_C_3] = MLX5_MODI_META_REG_C_3,
1021         [REG_C_4] = MLX5_MODI_META_REG_C_4,
1022         [REG_C_5] = MLX5_MODI_META_REG_C_5,
1023         [REG_C_6] = MLX5_MODI_META_REG_C_6,
1024         [REG_C_7] = MLX5_MODI_META_REG_C_7,
1025 };
1026
1027 /**
1028  * Convert register set to DV specification.
1029  *
1030  * @param[in,out] resource
1031  *   Pointer to the modify-header resource.
1032  * @param[in] action
1033  *   Pointer to action specification.
1034  * @param[out] error
1035  *   Pointer to the error structure.
1036  *
1037  * @return
1038  *   0 on success, a negative errno value otherwise and rte_errno is set.
1039  */
1040 static int
1041 flow_dv_convert_action_set_reg
1042                         (struct mlx5_flow_dv_modify_hdr_resource *resource,
1043                          const struct rte_flow_action *action,
1044                          struct rte_flow_error *error)
1045 {
1046         const struct mlx5_rte_flow_action_set_tag *conf = action->conf;
1047         struct mlx5_modification_cmd *actions = resource->actions;
1048         uint32_t i = resource->actions_num;
1049
1050         if (i >= MLX5_MAX_MODIFY_NUM)
1051                 return rte_flow_error_set(error, EINVAL,
1052                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
1053                                           "too many items to modify");
1054         MLX5_ASSERT(conf->id != REG_NON);
1055         MLX5_ASSERT(conf->id < (enum modify_reg)RTE_DIM(reg_to_field));
1056         actions[i] = (struct mlx5_modification_cmd) {
1057                 .action_type = MLX5_MODIFICATION_TYPE_SET,
1058                 .field = reg_to_field[conf->id],
1059                 .offset = conf->offset,
1060                 .length = conf->length,
1061         };
1062         actions[i].data0 = rte_cpu_to_be_32(actions[i].data0);
1063         actions[i].data1 = rte_cpu_to_be_32(conf->data);
1064         ++i;
1065         resource->actions_num = i;
1066         return 0;
1067 }
1068
1069 /**
1070  * Convert SET_TAG action to DV specification.
1071  *
1072  * @param[in] dev
1073  *   Pointer to the rte_eth_dev structure.
1074  * @param[in,out] resource
1075  *   Pointer to the modify-header resource.
1076  * @param[in] conf
1077  *   Pointer to action specification.
1078  * @param[out] error
1079  *   Pointer to the error structure.
1080  *
1081  * @return
1082  *   0 on success, a negative errno value otherwise and rte_errno is set.
1083  */
1084 static int
1085 flow_dv_convert_action_set_tag
1086                         (struct rte_eth_dev *dev,
1087                          struct mlx5_flow_dv_modify_hdr_resource *resource,
1088                          const struct rte_flow_action_set_tag *conf,
1089                          struct rte_flow_error *error)
1090 {
1091         rte_be32_t data = rte_cpu_to_be_32(conf->data);
1092         rte_be32_t mask = rte_cpu_to_be_32(conf->mask);
1093         struct rte_flow_item item = {
1094                 .spec = &data,
1095                 .mask = &mask,
1096         };
1097         struct field_modify_info reg_c_x[] = {
1098                 [1] = {0, 0, 0},
1099         };
1100         enum mlx5_modification_field reg_type;
1101         int ret;
1102
1103         ret = mlx5_flow_get_reg_id(dev, MLX5_APP_TAG, conf->index, error);
1104         if (ret < 0)
1105                 return ret;
1106         MLX5_ASSERT(ret != REG_NON);
1107         MLX5_ASSERT((unsigned int)ret < RTE_DIM(reg_to_field));
1108         reg_type = reg_to_field[ret];
1109         MLX5_ASSERT(reg_type > 0);
1110         reg_c_x[0] = (struct field_modify_info){4, 0, reg_type};
1111         return flow_dv_convert_modify_action(&item, reg_c_x, NULL, resource,
1112                                              MLX5_MODIFICATION_TYPE_SET, error);
1113 }
1114
1115 /**
1116  * Convert internal COPY_REG action to DV specification.
1117  *
1118  * @param[in] dev
1119  *   Pointer to the rte_eth_dev structure.
1120  * @param[in,out] res
1121  *   Pointer to the modify-header resource.
1122  * @param[in] action
1123  *   Pointer to action specification.
1124  * @param[out] error
1125  *   Pointer to the error structure.
1126  *
1127  * @return
1128  *   0 on success, a negative errno value otherwise and rte_errno is set.
1129  */
1130 static int
1131 flow_dv_convert_action_copy_mreg(struct rte_eth_dev *dev,
1132                                  struct mlx5_flow_dv_modify_hdr_resource *res,
1133                                  const struct rte_flow_action *action,
1134                                  struct rte_flow_error *error)
1135 {
1136         const struct mlx5_flow_action_copy_mreg *conf = action->conf;
1137         rte_be32_t mask = RTE_BE32(UINT32_MAX);
1138         struct rte_flow_item item = {
1139                 .spec = NULL,
1140                 .mask = &mask,
1141         };
1142         struct field_modify_info reg_src[] = {
1143                 {4, 0, reg_to_field[conf->src]},
1144                 {0, 0, 0},
1145         };
1146         struct field_modify_info reg_dst = {
1147                 .offset = 0,
1148                 .id = reg_to_field[conf->dst],
1149         };
1150         /* Adjust reg_c[0] usage according to reported mask. */
1151         if (conf->dst == REG_C_0 || conf->src == REG_C_0) {
1152                 struct mlx5_priv *priv = dev->data->dev_private;
1153                 uint32_t reg_c0 = priv->sh->dv_regc0_mask;
1154
1155                 MLX5_ASSERT(reg_c0);
1156                 MLX5_ASSERT(priv->config.dv_xmeta_en != MLX5_XMETA_MODE_LEGACY);
1157                 if (conf->dst == REG_C_0) {
1158                         /* Copy to reg_c[0], within mask only. */
1159                         reg_dst.offset = rte_bsf32(reg_c0);
1160                         mask = rte_cpu_to_be_32(reg_c0 >> reg_dst.offset);
1161                 } else {
1162                         reg_dst.offset = 0;
1163                         mask = rte_cpu_to_be_32(reg_c0);
1164                 }
1165         }
1166         return flow_dv_convert_modify_action(&item,
1167                                              reg_src, &reg_dst, res,
1168                                              MLX5_MODIFICATION_TYPE_COPY,
1169                                              error);
1170 }
1171
1172 /**
1173  * Convert MARK action to DV specification. This routine is used
1174  * in extensive metadata only and requires metadata register to be
1175  * handled. In legacy mode hardware tag resource is engaged.
1176  *
1177  * @param[in] dev
1178  *   Pointer to the rte_eth_dev structure.
1179  * @param[in] conf
1180  *   Pointer to MARK action specification.
1181  * @param[in,out] resource
1182  *   Pointer to the modify-header resource.
1183  * @param[out] error
1184  *   Pointer to the error structure.
1185  *
1186  * @return
1187  *   0 on success, a negative errno value otherwise and rte_errno is set.
1188  */
1189 static int
1190 flow_dv_convert_action_mark(struct rte_eth_dev *dev,
1191                             const struct rte_flow_action_mark *conf,
1192                             struct mlx5_flow_dv_modify_hdr_resource *resource,
1193                             struct rte_flow_error *error)
1194 {
1195         struct mlx5_priv *priv = dev->data->dev_private;
1196         rte_be32_t mask = rte_cpu_to_be_32(MLX5_FLOW_MARK_MASK &
1197                                            priv->sh->dv_mark_mask);
1198         rte_be32_t data = rte_cpu_to_be_32(conf->id) & mask;
1199         struct rte_flow_item item = {
1200                 .spec = &data,
1201                 .mask = &mask,
1202         };
1203         struct field_modify_info reg_c_x[] = {
1204                 [1] = {0, 0, 0},
1205         };
1206         int reg;
1207
1208         if (!mask)
1209                 return rte_flow_error_set(error, EINVAL,
1210                                           RTE_FLOW_ERROR_TYPE_ACTION_CONF,
1211                                           NULL, "zero mark action mask");
1212         reg = mlx5_flow_get_reg_id(dev, MLX5_FLOW_MARK, 0, error);
1213         if (reg < 0)
1214                 return reg;
1215         MLX5_ASSERT(reg > 0);
1216         if (reg == REG_C_0) {
1217                 uint32_t msk_c0 = priv->sh->dv_regc0_mask;
1218                 uint32_t shl_c0 = rte_bsf32(msk_c0);
1219
1220                 data = rte_cpu_to_be_32(rte_cpu_to_be_32(data) << shl_c0);
1221                 mask = rte_cpu_to_be_32(mask) & msk_c0;
1222                 mask = rte_cpu_to_be_32(mask << shl_c0);
1223         }
1224         reg_c_x[0] = (struct field_modify_info){4, 0, reg_to_field[reg]};
1225         return flow_dv_convert_modify_action(&item, reg_c_x, NULL, resource,
1226                                              MLX5_MODIFICATION_TYPE_SET, error);
1227 }
1228
1229 /**
1230  * Get metadata register index for specified steering domain.
1231  *
1232  * @param[in] dev
1233  *   Pointer to the rte_eth_dev structure.
1234  * @param[in] attr
1235  *   Attributes of flow to determine steering domain.
1236  * @param[out] error
1237  *   Pointer to the error structure.
1238  *
1239  * @return
1240  *   positive index on success, a negative errno value otherwise
1241  *   and rte_errno is set.
1242  */
1243 static enum modify_reg
1244 flow_dv_get_metadata_reg(struct rte_eth_dev *dev,
1245                          const struct rte_flow_attr *attr,
1246                          struct rte_flow_error *error)
1247 {
1248         int reg =
1249                 mlx5_flow_get_reg_id(dev, attr->transfer ?
1250                                           MLX5_METADATA_FDB :
1251                                             attr->egress ?
1252                                             MLX5_METADATA_TX :
1253                                             MLX5_METADATA_RX, 0, error);
1254         if (reg < 0)
1255                 return rte_flow_error_set(error,
1256                                           ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM,
1257                                           NULL, "unavailable "
1258                                           "metadata register");
1259         return reg;
1260 }
1261
1262 /**
1263  * Convert SET_META action to DV specification.
1264  *
1265  * @param[in] dev
1266  *   Pointer to the rte_eth_dev structure.
1267  * @param[in,out] resource
1268  *   Pointer to the modify-header resource.
1269  * @param[in] attr
1270  *   Attributes of flow that includes this item.
1271  * @param[in] conf
1272  *   Pointer to action specification.
1273  * @param[out] error
1274  *   Pointer to the error structure.
1275  *
1276  * @return
1277  *   0 on success, a negative errno value otherwise and rte_errno is set.
1278  */
1279 static int
1280 flow_dv_convert_action_set_meta
1281                         (struct rte_eth_dev *dev,
1282                          struct mlx5_flow_dv_modify_hdr_resource *resource,
1283                          const struct rte_flow_attr *attr,
1284                          const struct rte_flow_action_set_meta *conf,
1285                          struct rte_flow_error *error)
1286 {
1287         uint32_t mask = rte_cpu_to_be_32(conf->mask);
1288         uint32_t data = rte_cpu_to_be_32(conf->data) & mask;
1289         struct rte_flow_item item = {
1290                 .spec = &data,
1291                 .mask = &mask,
1292         };
1293         struct field_modify_info reg_c_x[] = {
1294                 [1] = {0, 0, 0},
1295         };
1296         int reg = flow_dv_get_metadata_reg(dev, attr, error);
1297
1298         if (reg < 0)
1299                 return reg;
1300         MLX5_ASSERT(reg != REG_NON);
1301         if (reg == REG_C_0) {
1302                 struct mlx5_priv *priv = dev->data->dev_private;
1303                 uint32_t msk_c0 = priv->sh->dv_regc0_mask;
1304                 uint32_t shl_c0 = rte_bsf32(msk_c0);
1305
1306                 data = rte_cpu_to_be_32(rte_cpu_to_be_32(data) << shl_c0);
1307                 mask = rte_cpu_to_be_32(mask) & msk_c0;
1308                 mask = rte_cpu_to_be_32(mask << shl_c0);
1309         }
1310         reg_c_x[0] = (struct field_modify_info){4, 0, reg_to_field[reg]};
1311         /* The routine expects parameters in memory as big-endian ones. */
1312         return flow_dv_convert_modify_action(&item, reg_c_x, NULL, resource,
1313                                              MLX5_MODIFICATION_TYPE_SET, error);
1314 }
1315
1316 /**
1317  * Convert modify-header set IPv4 DSCP action to DV specification.
1318  *
1319  * @param[in,out] resource
1320  *   Pointer to the modify-header resource.
1321  * @param[in] action
1322  *   Pointer to action specification.
1323  * @param[out] error
1324  *   Pointer to the error structure.
1325  *
1326  * @return
1327  *   0 on success, a negative errno value otherwise and rte_errno is set.
1328  */
1329 static int
1330 flow_dv_convert_action_modify_ipv4_dscp
1331                         (struct mlx5_flow_dv_modify_hdr_resource *resource,
1332                          const struct rte_flow_action *action,
1333                          struct rte_flow_error *error)
1334 {
1335         const struct rte_flow_action_set_dscp *conf =
1336                 (const struct rte_flow_action_set_dscp *)(action->conf);
1337         struct rte_flow_item item = { .type = RTE_FLOW_ITEM_TYPE_IPV4 };
1338         struct rte_flow_item_ipv4 ipv4;
1339         struct rte_flow_item_ipv4 ipv4_mask;
1340
1341         memset(&ipv4, 0, sizeof(ipv4));
1342         memset(&ipv4_mask, 0, sizeof(ipv4_mask));
1343         ipv4.hdr.type_of_service = conf->dscp;
1344         ipv4_mask.hdr.type_of_service = RTE_IPV4_HDR_DSCP_MASK >> 2;
1345         item.spec = &ipv4;
1346         item.mask = &ipv4_mask;
1347         return flow_dv_convert_modify_action(&item, modify_ipv4, NULL, resource,
1348                                              MLX5_MODIFICATION_TYPE_SET, error);
1349 }
1350
1351 /**
1352  * Convert modify-header set IPv6 DSCP action to DV specification.
1353  *
1354  * @param[in,out] resource
1355  *   Pointer to the modify-header resource.
1356  * @param[in] action
1357  *   Pointer to action specification.
1358  * @param[out] error
1359  *   Pointer to the error structure.
1360  *
1361  * @return
1362  *   0 on success, a negative errno value otherwise and rte_errno is set.
1363  */
1364 static int
1365 flow_dv_convert_action_modify_ipv6_dscp
1366                         (struct mlx5_flow_dv_modify_hdr_resource *resource,
1367                          const struct rte_flow_action *action,
1368                          struct rte_flow_error *error)
1369 {
1370         const struct rte_flow_action_set_dscp *conf =
1371                 (const struct rte_flow_action_set_dscp *)(action->conf);
1372         struct rte_flow_item item = { .type = RTE_FLOW_ITEM_TYPE_IPV6 };
1373         struct rte_flow_item_ipv6 ipv6;
1374         struct rte_flow_item_ipv6 ipv6_mask;
1375
1376         memset(&ipv6, 0, sizeof(ipv6));
1377         memset(&ipv6_mask, 0, sizeof(ipv6_mask));
1378         /*
1379          * Even though the DSCP bits offset of IPv6 is not byte aligned,
1380          * rdma-core only accept the DSCP bits byte aligned start from
1381          * bit 0 to 5 as to be compatible with IPv4. No need to shift the
1382          * bits in IPv6 case as rdma-core requires byte aligned value.
1383          */
1384         ipv6.hdr.vtc_flow = conf->dscp;
1385         ipv6_mask.hdr.vtc_flow = RTE_IPV6_HDR_DSCP_MASK >> 22;
1386         item.spec = &ipv6;
1387         item.mask = &ipv6_mask;
1388         return flow_dv_convert_modify_action(&item, modify_ipv6, NULL, resource,
1389                                              MLX5_MODIFICATION_TYPE_SET, error);
1390 }
1391
1392 static int
1393 mlx5_flow_item_field_width(struct mlx5_priv *priv,
1394                            enum rte_flow_field_id field, int inherit)
1395 {
1396         switch (field) {
1397         case RTE_FLOW_FIELD_START:
1398                 return 32;
1399         case RTE_FLOW_FIELD_MAC_DST:
1400         case RTE_FLOW_FIELD_MAC_SRC:
1401                 return 48;
1402         case RTE_FLOW_FIELD_VLAN_TYPE:
1403                 return 16;
1404         case RTE_FLOW_FIELD_VLAN_ID:
1405                 return 12;
1406         case RTE_FLOW_FIELD_MAC_TYPE:
1407                 return 16;
1408         case RTE_FLOW_FIELD_IPV4_DSCP:
1409                 return 6;
1410         case RTE_FLOW_FIELD_IPV4_TTL:
1411                 return 8;
1412         case RTE_FLOW_FIELD_IPV4_SRC:
1413         case RTE_FLOW_FIELD_IPV4_DST:
1414                 return 32;
1415         case RTE_FLOW_FIELD_IPV6_DSCP:
1416                 return 6;
1417         case RTE_FLOW_FIELD_IPV6_HOPLIMIT:
1418                 return 8;
1419         case RTE_FLOW_FIELD_IPV6_SRC:
1420         case RTE_FLOW_FIELD_IPV6_DST:
1421                 return 128;
1422         case RTE_FLOW_FIELD_TCP_PORT_SRC:
1423         case RTE_FLOW_FIELD_TCP_PORT_DST:
1424                 return 16;
1425         case RTE_FLOW_FIELD_TCP_SEQ_NUM:
1426         case RTE_FLOW_FIELD_TCP_ACK_NUM:
1427                 return 32;
1428         case RTE_FLOW_FIELD_TCP_FLAGS:
1429                 return 9;
1430         case RTE_FLOW_FIELD_UDP_PORT_SRC:
1431         case RTE_FLOW_FIELD_UDP_PORT_DST:
1432                 return 16;
1433         case RTE_FLOW_FIELD_VXLAN_VNI:
1434         case RTE_FLOW_FIELD_GENEVE_VNI:
1435                 return 24;
1436         case RTE_FLOW_FIELD_GTP_TEID:
1437         case RTE_FLOW_FIELD_TAG:
1438                 return 32;
1439         case RTE_FLOW_FIELD_MARK:
1440                 return __builtin_popcount(priv->sh->dv_mark_mask);
1441         case RTE_FLOW_FIELD_META:
1442                 return __builtin_popcount(priv->sh->dv_meta_mask);
1443         case RTE_FLOW_FIELD_POINTER:
1444         case RTE_FLOW_FIELD_VALUE:
1445                 return inherit < 0 ? 0 : inherit;
1446         default:
1447                 MLX5_ASSERT(false);
1448         }
1449         return 0;
1450 }
1451
1452 static void
1453 mlx5_flow_field_id_to_modify_info
1454                 (const struct rte_flow_action_modify_data *data,
1455                  struct field_modify_info *info, uint32_t *mask,
1456                  uint32_t width, uint32_t *shift, struct rte_eth_dev *dev,
1457                  const struct rte_flow_attr *attr, struct rte_flow_error *error)
1458 {
1459         struct mlx5_priv *priv = dev->data->dev_private;
1460         uint32_t idx = 0;
1461         uint32_t off = 0;
1462
1463         switch (data->field) {
1464         case RTE_FLOW_FIELD_START:
1465                 /* not supported yet */
1466                 MLX5_ASSERT(false);
1467                 break;
1468         case RTE_FLOW_FIELD_MAC_DST:
1469                 off = data->offset > 16 ? data->offset - 16 : 0;
1470                 if (mask) {
1471                         if (data->offset < 16) {
1472                                 info[idx] = (struct field_modify_info){2, 4,
1473                                                 MLX5_MODI_OUT_DMAC_15_0};
1474                                 if (width < 16) {
1475                                         mask[idx] = rte_cpu_to_be_16(0xffff >>
1476                                                                  (16 - width));
1477                                         width = 0;
1478                                 } else {
1479                                         mask[idx] = RTE_BE16(0xffff);
1480                                         width -= 16;
1481                                 }
1482                                 if (!width)
1483                                         break;
1484                                 ++idx;
1485                         }
1486                         info[idx] = (struct field_modify_info){4, 0,
1487                                                 MLX5_MODI_OUT_DMAC_47_16};
1488                         mask[idx] = rte_cpu_to_be_32((0xffffffff >>
1489                                                       (32 - width)) << off);
1490                 } else {
1491                         if (data->offset < 16)
1492                                 info[idx++] = (struct field_modify_info){2, 4,
1493                                                 MLX5_MODI_OUT_DMAC_15_0};
1494                         info[idx] = (struct field_modify_info){4, 0,
1495                                                 MLX5_MODI_OUT_DMAC_47_16};
1496                 }
1497                 break;
1498         case RTE_FLOW_FIELD_MAC_SRC:
1499                 off = data->offset > 16 ? data->offset - 16 : 0;
1500                 if (mask) {
1501                         if (data->offset < 16) {
1502                                 info[idx] = (struct field_modify_info){2, 4,
1503                                                 MLX5_MODI_OUT_SMAC_15_0};
1504                                 if (width < 16) {
1505                                         mask[idx] = rte_cpu_to_be_16(0xffff >>
1506                                                                  (16 - width));
1507                                         width = 0;
1508                                 } else {
1509                                         mask[idx] = RTE_BE16(0xffff);
1510                                         width -= 16;
1511                                 }
1512                                 if (!width)
1513                                         break;
1514                                 ++idx;
1515                         }
1516                         info[idx] = (struct field_modify_info){4, 0,
1517                                                 MLX5_MODI_OUT_SMAC_47_16};
1518                         mask[idx] = rte_cpu_to_be_32((0xffffffff >>
1519                                                       (32 - width)) << off);
1520                 } else {
1521                         if (data->offset < 16)
1522                                 info[idx++] = (struct field_modify_info){2, 4,
1523                                                 MLX5_MODI_OUT_SMAC_15_0};
1524                         info[idx] = (struct field_modify_info){4, 0,
1525                                                 MLX5_MODI_OUT_SMAC_47_16};
1526                 }
1527                 break;
1528         case RTE_FLOW_FIELD_VLAN_TYPE:
1529                 /* not supported yet */
1530                 break;
1531         case RTE_FLOW_FIELD_VLAN_ID:
1532                 info[idx] = (struct field_modify_info){2, 0,
1533                                         MLX5_MODI_OUT_FIRST_VID};
1534                 if (mask)
1535                         mask[idx] = rte_cpu_to_be_16(0x0fff >> (12 - width));
1536                 break;
1537         case RTE_FLOW_FIELD_MAC_TYPE:
1538                 info[idx] = (struct field_modify_info){2, 0,
1539                                         MLX5_MODI_OUT_ETHERTYPE};
1540                 if (mask)
1541                         mask[idx] = rte_cpu_to_be_16(0xffff >> (16 - width));
1542                 break;
1543         case RTE_FLOW_FIELD_IPV4_DSCP:
1544                 info[idx] = (struct field_modify_info){1, 0,
1545                                         MLX5_MODI_OUT_IP_DSCP};
1546                 if (mask)
1547                         mask[idx] = 0x3f >> (6 - width);
1548                 break;
1549         case RTE_FLOW_FIELD_IPV4_TTL:
1550                 info[idx] = (struct field_modify_info){1, 0,
1551                                         MLX5_MODI_OUT_IPV4_TTL};
1552                 if (mask)
1553                         mask[idx] = 0xff >> (8 - width);
1554                 break;
1555         case RTE_FLOW_FIELD_IPV4_SRC:
1556                 info[idx] = (struct field_modify_info){4, 0,
1557                                         MLX5_MODI_OUT_SIPV4};
1558                 if (mask)
1559                         mask[idx] = rte_cpu_to_be_32(0xffffffff >>
1560                                                      (32 - width));
1561                 break;
1562         case RTE_FLOW_FIELD_IPV4_DST:
1563                 info[idx] = (struct field_modify_info){4, 0,
1564                                         MLX5_MODI_OUT_DIPV4};
1565                 if (mask)
1566                         mask[idx] = rte_cpu_to_be_32(0xffffffff >>
1567                                                      (32 - width));
1568                 break;
1569         case RTE_FLOW_FIELD_IPV6_DSCP:
1570                 info[idx] = (struct field_modify_info){1, 0,
1571                                         MLX5_MODI_OUT_IP_DSCP};
1572                 if (mask)
1573                         mask[idx] = 0x3f >> (6 - width);
1574                 break;
1575         case RTE_FLOW_FIELD_IPV6_HOPLIMIT:
1576                 info[idx] = (struct field_modify_info){1, 0,
1577                                         MLX5_MODI_OUT_IPV6_HOPLIMIT};
1578                 if (mask)
1579                         mask[idx] = 0xff >> (8 - width);
1580                 break;
1581         case RTE_FLOW_FIELD_IPV6_SRC:
1582                 if (mask) {
1583                         if (data->offset < 32) {
1584                                 info[idx] = (struct field_modify_info){4, 12,
1585                                                 MLX5_MODI_OUT_SIPV6_31_0};
1586                                 if (width < 32) {
1587                                         mask[idx] =
1588                                                 rte_cpu_to_be_32(0xffffffff >>
1589                                                                  (32 - width));
1590                                         width = 0;
1591                                 } else {
1592                                         mask[idx] = RTE_BE32(0xffffffff);
1593                                         width -= 32;
1594                                 }
1595                                 if (!width)
1596                                         break;
1597                                 ++idx;
1598                         }
1599                         if (data->offset < 64) {
1600                                 info[idx] = (struct field_modify_info){4, 8,
1601                                                 MLX5_MODI_OUT_SIPV6_63_32};
1602                                 if (width < 32) {
1603                                         mask[idx] =
1604                                                 rte_cpu_to_be_32(0xffffffff >>
1605                                                                  (32 - width));
1606                                         width = 0;
1607                                 } else {
1608                                         mask[idx] = RTE_BE32(0xffffffff);
1609                                         width -= 32;
1610                                 }
1611                                 if (!width)
1612                                         break;
1613                                 ++idx;
1614                         }
1615                         if (data->offset < 96) {
1616                                 info[idx] = (struct field_modify_info){4, 4,
1617                                                 MLX5_MODI_OUT_SIPV6_95_64};
1618                                 if (width < 32) {
1619                                         mask[idx] =
1620                                                 rte_cpu_to_be_32(0xffffffff >>
1621                                                                  (32 - width));
1622                                         width = 0;
1623                                 } else {
1624                                         mask[idx] = RTE_BE32(0xffffffff);
1625                                         width -= 32;
1626                                 }
1627                                 if (!width)
1628                                         break;
1629                                 ++idx;
1630                         }
1631                         info[idx] = (struct field_modify_info){4, 0,
1632                                                 MLX5_MODI_OUT_SIPV6_127_96};
1633                         mask[idx] = rte_cpu_to_be_32(0xffffffff >>
1634                                                      (32 - width));
1635                 } else {
1636                         if (data->offset < 32)
1637                                 info[idx++] = (struct field_modify_info){4, 12,
1638                                                 MLX5_MODI_OUT_SIPV6_31_0};
1639                         if (data->offset < 64)
1640                                 info[idx++] = (struct field_modify_info){4, 8,
1641                                                 MLX5_MODI_OUT_SIPV6_63_32};
1642                         if (data->offset < 96)
1643                                 info[idx++] = (struct field_modify_info){4, 4,
1644                                                 MLX5_MODI_OUT_SIPV6_95_64};
1645                         if (data->offset < 128)
1646                                 info[idx++] = (struct field_modify_info){4, 0,
1647                                                 MLX5_MODI_OUT_SIPV6_127_96};
1648                 }
1649                 break;
1650         case RTE_FLOW_FIELD_IPV6_DST:
1651                 if (mask) {
1652                         if (data->offset < 32) {
1653                                 info[idx] = (struct field_modify_info){4, 12,
1654                                                 MLX5_MODI_OUT_DIPV6_31_0};
1655                                 if (width < 32) {
1656                                         mask[idx] =
1657                                                 rte_cpu_to_be_32(0xffffffff >>
1658                                                                  (32 - width));
1659                                         width = 0;
1660                                 } else {
1661                                         mask[idx] = RTE_BE32(0xffffffff);
1662                                         width -= 32;
1663                                 }
1664                                 if (!width)
1665                                         break;
1666                                 ++idx;
1667                         }
1668                         if (data->offset < 64) {
1669                                 info[idx] = (struct field_modify_info){4, 8,
1670                                                 MLX5_MODI_OUT_DIPV6_63_32};
1671                                 if (width < 32) {
1672                                         mask[idx] =
1673                                                 rte_cpu_to_be_32(0xffffffff >>
1674                                                                  (32 - width));
1675                                         width = 0;
1676                                 } else {
1677                                         mask[idx] = RTE_BE32(0xffffffff);
1678                                         width -= 32;
1679                                 }
1680                                 if (!width)
1681                                         break;
1682                                 ++idx;
1683                         }
1684                         if (data->offset < 96) {
1685                                 info[idx] = (struct field_modify_info){4, 4,
1686                                                 MLX5_MODI_OUT_DIPV6_95_64};
1687                                 if (width < 32) {
1688                                         mask[idx] =
1689                                                 rte_cpu_to_be_32(0xffffffff >>
1690                                                                  (32 - width));
1691                                         width = 0;
1692                                 } else {
1693                                         mask[idx] = RTE_BE32(0xffffffff);
1694                                         width -= 32;
1695                                 }
1696                                 if (!width)
1697                                         break;
1698                                 ++idx;
1699                         }
1700                         info[idx] = (struct field_modify_info){4, 0,
1701                                                 MLX5_MODI_OUT_DIPV6_127_96};
1702                         mask[idx] = rte_cpu_to_be_32(0xffffffff >>
1703                                                      (32 - width));
1704                 } else {
1705                         if (data->offset < 32)
1706                                 info[idx++] = (struct field_modify_info){4, 12,
1707                                                 MLX5_MODI_OUT_DIPV6_31_0};
1708                         if (data->offset < 64)
1709                                 info[idx++] = (struct field_modify_info){4, 8,
1710                                                 MLX5_MODI_OUT_DIPV6_63_32};
1711                         if (data->offset < 96)
1712                                 info[idx++] = (struct field_modify_info){4, 4,
1713                                                 MLX5_MODI_OUT_DIPV6_95_64};
1714                         if (data->offset < 128)
1715                                 info[idx++] = (struct field_modify_info){4, 0,
1716                                                 MLX5_MODI_OUT_DIPV6_127_96};
1717                 }
1718                 break;
1719         case RTE_FLOW_FIELD_TCP_PORT_SRC:
1720                 info[idx] = (struct field_modify_info){2, 0,
1721                                         MLX5_MODI_OUT_TCP_SPORT};
1722                 if (mask)
1723                         mask[idx] = rte_cpu_to_be_16(0xffff >> (16 - width));
1724                 break;
1725         case RTE_FLOW_FIELD_TCP_PORT_DST:
1726                 info[idx] = (struct field_modify_info){2, 0,
1727                                         MLX5_MODI_OUT_TCP_DPORT};
1728                 if (mask)
1729                         mask[idx] = rte_cpu_to_be_16(0xffff >> (16 - width));
1730                 break;
1731         case RTE_FLOW_FIELD_TCP_SEQ_NUM:
1732                 info[idx] = (struct field_modify_info){4, 0,
1733                                         MLX5_MODI_OUT_TCP_SEQ_NUM};
1734                 if (mask)
1735                         mask[idx] = rte_cpu_to_be_32(0xffffffff >>
1736                                                      (32 - width));
1737                 break;
1738         case RTE_FLOW_FIELD_TCP_ACK_NUM:
1739                 info[idx] = (struct field_modify_info){4, 0,
1740                                         MLX5_MODI_OUT_TCP_ACK_NUM};
1741                 if (mask)
1742                         mask[idx] = rte_cpu_to_be_32(0xffffffff >>
1743                                                      (32 - width));
1744                 break;
1745         case RTE_FLOW_FIELD_TCP_FLAGS:
1746                 info[idx] = (struct field_modify_info){2, 0,
1747                                         MLX5_MODI_OUT_TCP_FLAGS};
1748                 if (mask)
1749                         mask[idx] = rte_cpu_to_be_16(0x1ff >> (9 - width));
1750                 break;
1751         case RTE_FLOW_FIELD_UDP_PORT_SRC:
1752                 info[idx] = (struct field_modify_info){2, 0,
1753                                         MLX5_MODI_OUT_UDP_SPORT};
1754                 if (mask)
1755                         mask[idx] = rte_cpu_to_be_16(0xffff >> (16 - width));
1756                 break;
1757         case RTE_FLOW_FIELD_UDP_PORT_DST:
1758                 info[idx] = (struct field_modify_info){2, 0,
1759                                         MLX5_MODI_OUT_UDP_DPORT};
1760                 if (mask)
1761                         mask[idx] = rte_cpu_to_be_16(0xffff >> (16 - width));
1762                 break;
1763         case RTE_FLOW_FIELD_VXLAN_VNI:
1764                 /* not supported yet */
1765                 break;
1766         case RTE_FLOW_FIELD_GENEVE_VNI:
1767                 /* not supported yet*/
1768                 break;
1769         case RTE_FLOW_FIELD_GTP_TEID:
1770                 info[idx] = (struct field_modify_info){4, 0,
1771                                         MLX5_MODI_GTP_TEID};
1772                 if (mask)
1773                         mask[idx] = rte_cpu_to_be_32(0xffffffff >>
1774                                                      (32 - width));
1775                 break;
1776         case RTE_FLOW_FIELD_TAG:
1777                 {
1778                         int reg = mlx5_flow_get_reg_id(dev, MLX5_APP_TAG,
1779                                                    data->level, error);
1780                         if (reg < 0)
1781                                 return;
1782                         MLX5_ASSERT(reg != REG_NON);
1783                         MLX5_ASSERT((unsigned int)reg < RTE_DIM(reg_to_field));
1784                         info[idx] = (struct field_modify_info){4, 0,
1785                                                 reg_to_field[reg]};
1786                         if (mask)
1787                                 mask[idx] =
1788                                         rte_cpu_to_be_32(0xffffffff >>
1789                                                          (32 - width));
1790                 }
1791                 break;
1792         case RTE_FLOW_FIELD_MARK:
1793                 {
1794                         uint32_t mark_mask = priv->sh->dv_mark_mask;
1795                         uint32_t mark_count = __builtin_popcount(mark_mask);
1796                         int reg = mlx5_flow_get_reg_id(dev, MLX5_FLOW_MARK,
1797                                                        0, error);
1798                         if (reg < 0)
1799                                 return;
1800                         MLX5_ASSERT(reg != REG_NON);
1801                         MLX5_ASSERT((unsigned int)reg < RTE_DIM(reg_to_field));
1802                         info[idx] = (struct field_modify_info){4, 0,
1803                                                 reg_to_field[reg]};
1804                         if (mask)
1805                                 mask[idx] = rte_cpu_to_be_32((mark_mask >>
1806                                          (mark_count - width)) & mark_mask);
1807                 }
1808                 break;
1809         case RTE_FLOW_FIELD_META:
1810                 {
1811                         uint32_t meta_mask = priv->sh->dv_meta_mask;
1812                         uint32_t meta_count = __builtin_popcount(meta_mask);
1813                         uint32_t msk_c0 =
1814                                 rte_cpu_to_be_32(priv->sh->dv_regc0_mask);
1815                         uint32_t shl_c0 = rte_bsf32(msk_c0);
1816                         int reg = flow_dv_get_metadata_reg(dev, attr, error);
1817                         if (reg < 0)
1818                                 return;
1819                         MLX5_ASSERT(reg != REG_NON);
1820                         MLX5_ASSERT((unsigned int)reg < RTE_DIM(reg_to_field));
1821                         if (reg == REG_C_0)
1822                                 *shift = shl_c0;
1823                         info[idx] = (struct field_modify_info){4, 0,
1824                                                 reg_to_field[reg]};
1825                         if (mask)
1826                                 mask[idx] = rte_cpu_to_be_32((meta_mask >>
1827                                         (meta_count - width)) & meta_mask);
1828                 }
1829                 break;
1830         case RTE_FLOW_FIELD_POINTER:
1831         case RTE_FLOW_FIELD_VALUE:
1832         default:
1833                 MLX5_ASSERT(false);
1834                 break;
1835         }
1836 }
1837
1838 /**
1839  * Convert modify_field action to DV specification.
1840  *
1841  * @param[in] dev
1842  *   Pointer to the rte_eth_dev structure.
1843  * @param[in,out] resource
1844  *   Pointer to the modify-header resource.
1845  * @param[in] action
1846  *   Pointer to action specification.
1847  * @param[in] attr
1848  *   Attributes of flow that includes this item.
1849  * @param[out] error
1850  *   Pointer to the error structure.
1851  *
1852  * @return
1853  *   0 on success, a negative errno value otherwise and rte_errno is set.
1854  */
1855 static int
1856 flow_dv_convert_action_modify_field
1857                         (struct rte_eth_dev *dev,
1858                          struct mlx5_flow_dv_modify_hdr_resource *resource,
1859                          const struct rte_flow_action *action,
1860                          const struct rte_flow_attr *attr,
1861                          struct rte_flow_error *error)
1862 {
1863         const struct rte_flow_action_modify_field *conf =
1864                 (const struct rte_flow_action_modify_field *)(action->conf);
1865         struct rte_flow_item item = {
1866                 .spec = NULL,
1867                 .mask = NULL
1868         };
1869         struct field_modify_info field[MLX5_ACT_MAX_MOD_FIELDS] = {
1870                                                                 {0, 0, 0} };
1871         struct field_modify_info dcopy[MLX5_ACT_MAX_MOD_FIELDS] = {
1872                                                                 {0, 0, 0} };
1873         uint32_t mask[MLX5_ACT_MAX_MOD_FIELDS] = {0, 0, 0, 0, 0};
1874         uint32_t type;
1875         uint32_t shift = 0;
1876
1877         if (conf->src.field == RTE_FLOW_FIELD_POINTER ||
1878             conf->src.field == RTE_FLOW_FIELD_VALUE) {
1879                 type = MLX5_MODIFICATION_TYPE_SET;
1880                 /** For SET fill the destination field (field) first. */
1881                 mlx5_flow_field_id_to_modify_info(&conf->dst, field, mask,
1882                                                   conf->width, &shift, dev,
1883                                                   attr, error);
1884                 item.spec = conf->src.field == RTE_FLOW_FIELD_POINTER ?
1885                                         (void *)(uintptr_t)conf->src.pvalue :
1886                                         (void *)(uintptr_t)&conf->src.value;
1887         } else {
1888                 type = MLX5_MODIFICATION_TYPE_COPY;
1889                 /** For COPY fill the destination field (dcopy) without mask. */
1890                 mlx5_flow_field_id_to_modify_info(&conf->dst, dcopy, NULL,
1891                                                   conf->width, &shift, dev,
1892                                                   attr, error);
1893                 /** Then construct the source field (field) with mask. */
1894                 mlx5_flow_field_id_to_modify_info(&conf->src, field, mask,
1895                                                   conf->width, &shift,
1896                                                   dev, attr, error);
1897         }
1898         item.mask = &mask;
1899         return flow_dv_convert_modify_action(&item,
1900                         field, dcopy, resource, type, error);
1901 }
1902
1903 /**
1904  * Validate MARK item.
1905  *
1906  * @param[in] dev
1907  *   Pointer to the rte_eth_dev structure.
1908  * @param[in] item
1909  *   Item specification.
1910  * @param[in] attr
1911  *   Attributes of flow that includes this item.
1912  * @param[out] error
1913  *   Pointer to error structure.
1914  *
1915  * @return
1916  *   0 on success, a negative errno value otherwise and rte_errno is set.
1917  */
1918 static int
1919 flow_dv_validate_item_mark(struct rte_eth_dev *dev,
1920                            const struct rte_flow_item *item,
1921                            const struct rte_flow_attr *attr __rte_unused,
1922                            struct rte_flow_error *error)
1923 {
1924         struct mlx5_priv *priv = dev->data->dev_private;
1925         struct mlx5_dev_config *config = &priv->config;
1926         const struct rte_flow_item_mark *spec = item->spec;
1927         const struct rte_flow_item_mark *mask = item->mask;
1928         const struct rte_flow_item_mark nic_mask = {
1929                 .id = priv->sh->dv_mark_mask,
1930         };
1931         int ret;
1932
1933         if (config->dv_xmeta_en == MLX5_XMETA_MODE_LEGACY)
1934                 return rte_flow_error_set(error, ENOTSUP,
1935                                           RTE_FLOW_ERROR_TYPE_ITEM, item,
1936                                           "extended metadata feature"
1937                                           " isn't enabled");
1938         if (!mlx5_flow_ext_mreg_supported(dev))
1939                 return rte_flow_error_set(error, ENOTSUP,
1940                                           RTE_FLOW_ERROR_TYPE_ITEM, item,
1941                                           "extended metadata register"
1942                                           " isn't supported");
1943         if (!nic_mask.id)
1944                 return rte_flow_error_set(error, ENOTSUP,
1945                                           RTE_FLOW_ERROR_TYPE_ITEM, item,
1946                                           "extended metadata register"
1947                                           " isn't available");
1948         ret = mlx5_flow_get_reg_id(dev, MLX5_FLOW_MARK, 0, error);
1949         if (ret < 0)
1950                 return ret;
1951         if (!spec)
1952                 return rte_flow_error_set(error, EINVAL,
1953                                           RTE_FLOW_ERROR_TYPE_ITEM_SPEC,
1954                                           item->spec,
1955                                           "data cannot be empty");
1956         if (spec->id >= (MLX5_FLOW_MARK_MAX & nic_mask.id))
1957                 return rte_flow_error_set(error, EINVAL,
1958                                           RTE_FLOW_ERROR_TYPE_ACTION_CONF,
1959                                           &spec->id,
1960                                           "mark id exceeds the limit");
1961         if (!mask)
1962                 mask = &nic_mask;
1963         if (!mask->id)
1964                 return rte_flow_error_set(error, EINVAL,
1965                                         RTE_FLOW_ERROR_TYPE_ITEM_SPEC, NULL,
1966                                         "mask cannot be zero");
1967
1968         ret = mlx5_flow_item_acceptable(item, (const uint8_t *)mask,
1969                                         (const uint8_t *)&nic_mask,
1970                                         sizeof(struct rte_flow_item_mark),
1971                                         MLX5_ITEM_RANGE_NOT_ACCEPTED, error);
1972         if (ret < 0)
1973                 return ret;
1974         return 0;
1975 }
1976
1977 /**
1978  * Validate META item.
1979  *
1980  * @param[in] dev
1981  *   Pointer to the rte_eth_dev structure.
1982  * @param[in] item
1983  *   Item specification.
1984  * @param[in] attr
1985  *   Attributes of flow that includes this item.
1986  * @param[out] error
1987  *   Pointer to error structure.
1988  *
1989  * @return
1990  *   0 on success, a negative errno value otherwise and rte_errno is set.
1991  */
1992 static int
1993 flow_dv_validate_item_meta(struct rte_eth_dev *dev __rte_unused,
1994                            const struct rte_flow_item *item,
1995                            const struct rte_flow_attr *attr,
1996                            struct rte_flow_error *error)
1997 {
1998         struct mlx5_priv *priv = dev->data->dev_private;
1999         struct mlx5_dev_config *config = &priv->config;
2000         const struct rte_flow_item_meta *spec = item->spec;
2001         const struct rte_flow_item_meta *mask = item->mask;
2002         struct rte_flow_item_meta nic_mask = {
2003                 .data = UINT32_MAX
2004         };
2005         int reg;
2006         int ret;
2007
2008         if (!spec)
2009                 return rte_flow_error_set(error, EINVAL,
2010                                           RTE_FLOW_ERROR_TYPE_ITEM_SPEC,
2011                                           item->spec,
2012                                           "data cannot be empty");
2013         if (config->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY) {
2014                 if (!mlx5_flow_ext_mreg_supported(dev))
2015                         return rte_flow_error_set(error, ENOTSUP,
2016                                           RTE_FLOW_ERROR_TYPE_ITEM, item,
2017                                           "extended metadata register"
2018                                           " isn't supported");
2019                 reg = flow_dv_get_metadata_reg(dev, attr, error);
2020                 if (reg < 0)
2021                         return reg;
2022                 if (reg == REG_NON)
2023                         return rte_flow_error_set(error, ENOTSUP,
2024                                         RTE_FLOW_ERROR_TYPE_ITEM, item,
2025                                         "unavalable extended metadata register");
2026                 if (reg == REG_B)
2027                         return rte_flow_error_set(error, ENOTSUP,
2028                                           RTE_FLOW_ERROR_TYPE_ITEM, item,
2029                                           "match on reg_b "
2030                                           "isn't supported");
2031                 if (reg != REG_A)
2032                         nic_mask.data = priv->sh->dv_meta_mask;
2033         } else {
2034                 if (attr->transfer)
2035                         return rte_flow_error_set(error, ENOTSUP,
2036                                         RTE_FLOW_ERROR_TYPE_ITEM, item,
2037                                         "extended metadata feature "
2038                                         "should be enabled when "
2039                                         "meta item is requested "
2040                                         "with e-switch mode ");
2041                 if (attr->ingress)
2042                         return rte_flow_error_set(error, ENOTSUP,
2043                                         RTE_FLOW_ERROR_TYPE_ITEM, item,
2044                                         "match on metadata for ingress "
2045                                         "is not supported in legacy "
2046                                         "metadata mode");
2047         }
2048         if (!mask)
2049                 mask = &rte_flow_item_meta_mask;
2050         if (!mask->data)
2051                 return rte_flow_error_set(error, EINVAL,
2052                                         RTE_FLOW_ERROR_TYPE_ITEM_SPEC, NULL,
2053                                         "mask cannot be zero");
2054
2055         ret = mlx5_flow_item_acceptable(item, (const uint8_t *)mask,
2056                                         (const uint8_t *)&nic_mask,
2057                                         sizeof(struct rte_flow_item_meta),
2058                                         MLX5_ITEM_RANGE_NOT_ACCEPTED, error);
2059         return ret;
2060 }
2061
2062 /**
2063  * Validate TAG item.
2064  *
2065  * @param[in] dev
2066  *   Pointer to the rte_eth_dev structure.
2067  * @param[in] item
2068  *   Item specification.
2069  * @param[in] attr
2070  *   Attributes of flow that includes this item.
2071  * @param[out] error
2072  *   Pointer to error structure.
2073  *
2074  * @return
2075  *   0 on success, a negative errno value otherwise and rte_errno is set.
2076  */
2077 static int
2078 flow_dv_validate_item_tag(struct rte_eth_dev *dev,
2079                           const struct rte_flow_item *item,
2080                           const struct rte_flow_attr *attr __rte_unused,
2081                           struct rte_flow_error *error)
2082 {
2083         const struct rte_flow_item_tag *spec = item->spec;
2084         const struct rte_flow_item_tag *mask = item->mask;
2085         const struct rte_flow_item_tag nic_mask = {
2086                 .data = RTE_BE32(UINT32_MAX),
2087                 .index = 0xff,
2088         };
2089         int ret;
2090
2091         if (!mlx5_flow_ext_mreg_supported(dev))
2092                 return rte_flow_error_set(error, ENOTSUP,
2093                                           RTE_FLOW_ERROR_TYPE_ITEM, item,
2094                                           "extensive metadata register"
2095                                           " isn't supported");
2096         if (!spec)
2097                 return rte_flow_error_set(error, EINVAL,
2098                                           RTE_FLOW_ERROR_TYPE_ITEM_SPEC,
2099                                           item->spec,
2100                                           "data cannot be empty");
2101         if (!mask)
2102                 mask = &rte_flow_item_tag_mask;
2103         if (!mask->data)
2104                 return rte_flow_error_set(error, EINVAL,
2105                                         RTE_FLOW_ERROR_TYPE_ITEM_SPEC, NULL,
2106                                         "mask cannot be zero");
2107
2108         ret = mlx5_flow_item_acceptable(item, (const uint8_t *)mask,
2109                                         (const uint8_t *)&nic_mask,
2110                                         sizeof(struct rte_flow_item_tag),
2111                                         MLX5_ITEM_RANGE_NOT_ACCEPTED, error);
2112         if (ret < 0)
2113                 return ret;
2114         if (mask->index != 0xff)
2115                 return rte_flow_error_set(error, EINVAL,
2116                                           RTE_FLOW_ERROR_TYPE_ITEM_SPEC, NULL,
2117                                           "partial mask for tag index"
2118                                           " is not supported");
2119         ret = mlx5_flow_get_reg_id(dev, MLX5_APP_TAG, spec->index, error);
2120         if (ret < 0)
2121                 return ret;
2122         MLX5_ASSERT(ret != REG_NON);
2123         return 0;
2124 }
2125
2126 /**
2127  * Validate vport item.
2128  *
2129  * @param[in] dev
2130  *   Pointer to the rte_eth_dev structure.
2131  * @param[in] item
2132  *   Item specification.
2133  * @param[in] attr
2134  *   Attributes of flow that includes this item.
2135  * @param[in] item_flags
2136  *   Bit-fields that holds the items detected until now.
2137  * @param[out] error
2138  *   Pointer to error structure.
2139  *
2140  * @return
2141  *   0 on success, a negative errno value otherwise and rte_errno is set.
2142  */
2143 static int
2144 flow_dv_validate_item_port_id(struct rte_eth_dev *dev,
2145                               const struct rte_flow_item *item,
2146                               const struct rte_flow_attr *attr,
2147                               uint64_t item_flags,
2148                               struct rte_flow_error *error)
2149 {
2150         const struct rte_flow_item_port_id *spec = item->spec;
2151         const struct rte_flow_item_port_id *mask = item->mask;
2152         const struct rte_flow_item_port_id switch_mask = {
2153                         .id = 0xffffffff,
2154         };
2155         struct mlx5_priv *esw_priv;
2156         struct mlx5_priv *dev_priv;
2157         int ret;
2158
2159         if (!attr->transfer)
2160                 return rte_flow_error_set(error, EINVAL,
2161                                           RTE_FLOW_ERROR_TYPE_ITEM,
2162                                           NULL,
2163                                           "match on port id is valid only"
2164                                           " when transfer flag is enabled");
2165         if (item_flags & MLX5_FLOW_ITEM_PORT_ID)
2166                 return rte_flow_error_set(error, ENOTSUP,
2167                                           RTE_FLOW_ERROR_TYPE_ITEM, item,
2168                                           "multiple source ports are not"
2169                                           " supported");
2170         if (!mask)
2171                 mask = &switch_mask;
2172         if (mask->id != 0xffffffff)
2173                 return rte_flow_error_set(error, ENOTSUP,
2174                                            RTE_FLOW_ERROR_TYPE_ITEM_MASK,
2175                                            mask,
2176                                            "no support for partial mask on"
2177                                            " \"id\" field");
2178         ret = mlx5_flow_item_acceptable
2179                                 (item, (const uint8_t *)mask,
2180                                  (const uint8_t *)&rte_flow_item_port_id_mask,
2181                                  sizeof(struct rte_flow_item_port_id),
2182                                  MLX5_ITEM_RANGE_NOT_ACCEPTED, error);
2183         if (ret)
2184                 return ret;
2185         if (!spec)
2186                 return 0;
2187         esw_priv = mlx5_port_to_eswitch_info(spec->id, false);
2188         if (!esw_priv)
2189                 return rte_flow_error_set(error, rte_errno,
2190                                           RTE_FLOW_ERROR_TYPE_ITEM_SPEC, spec,
2191                                           "failed to obtain E-Switch info for"
2192                                           " port");
2193         dev_priv = mlx5_dev_to_eswitch_info(dev);
2194         if (!dev_priv)
2195                 return rte_flow_error_set(error, rte_errno,
2196                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2197                                           NULL,
2198                                           "failed to obtain E-Switch info");
2199         if (esw_priv->domain_id != dev_priv->domain_id)
2200                 return rte_flow_error_set(error, EINVAL,
2201                                           RTE_FLOW_ERROR_TYPE_ITEM_SPEC, spec,
2202                                           "cannot match on a port from a"
2203                                           " different E-Switch");
2204         return 0;
2205 }
2206
2207 /**
2208  * Validate VLAN item.
2209  *
2210  * @param[in] item
2211  *   Item specification.
2212  * @param[in] item_flags
2213  *   Bit-fields that holds the items detected until now.
2214  * @param[in] dev
2215  *   Ethernet device flow is being created on.
2216  * @param[out] error
2217  *   Pointer to error structure.
2218  *
2219  * @return
2220  *   0 on success, a negative errno value otherwise and rte_errno is set.
2221  */
2222 static int
2223 flow_dv_validate_item_vlan(const struct rte_flow_item *item,
2224                            uint64_t item_flags,
2225                            struct rte_eth_dev *dev,
2226                            struct rte_flow_error *error)
2227 {
2228         const struct rte_flow_item_vlan *mask = item->mask;
2229         const struct rte_flow_item_vlan nic_mask = {
2230                 .tci = RTE_BE16(UINT16_MAX),
2231                 .inner_type = RTE_BE16(UINT16_MAX),
2232                 .has_more_vlan = 1,
2233         };
2234         const int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL);
2235         int ret;
2236         const uint64_t l34m = tunnel ? (MLX5_FLOW_LAYER_INNER_L3 |
2237                                         MLX5_FLOW_LAYER_INNER_L4) :
2238                                        (MLX5_FLOW_LAYER_OUTER_L3 |
2239                                         MLX5_FLOW_LAYER_OUTER_L4);
2240         const uint64_t vlanm = tunnel ? MLX5_FLOW_LAYER_INNER_VLAN :
2241                                         MLX5_FLOW_LAYER_OUTER_VLAN;
2242
2243         if (item_flags & vlanm)
2244                 return rte_flow_error_set(error, EINVAL,
2245                                           RTE_FLOW_ERROR_TYPE_ITEM, item,
2246                                           "multiple VLAN layers not supported");
2247         else if ((item_flags & l34m) != 0)
2248                 return rte_flow_error_set(error, EINVAL,
2249                                           RTE_FLOW_ERROR_TYPE_ITEM, item,
2250                                           "VLAN cannot follow L3/L4 layer");
2251         if (!mask)
2252                 mask = &rte_flow_item_vlan_mask;
2253         ret = mlx5_flow_item_acceptable(item, (const uint8_t *)mask,
2254                                         (const uint8_t *)&nic_mask,
2255                                         sizeof(struct rte_flow_item_vlan),
2256                                         MLX5_ITEM_RANGE_NOT_ACCEPTED, error);
2257         if (ret)
2258                 return ret;
2259         if (!tunnel && mask->tci != RTE_BE16(0x0fff)) {
2260                 struct mlx5_priv *priv = dev->data->dev_private;
2261
2262                 if (priv->vmwa_context) {
2263                         /*
2264                          * Non-NULL context means we have a virtual machine
2265                          * and SR-IOV enabled, we have to create VLAN interface
2266                          * to make hypervisor to setup E-Switch vport
2267                          * context correctly. We avoid creating the multiple
2268                          * VLAN interfaces, so we cannot support VLAN tag mask.
2269                          */
2270                         return rte_flow_error_set(error, EINVAL,
2271                                                   RTE_FLOW_ERROR_TYPE_ITEM,
2272                                                   item,
2273                                                   "VLAN tag mask is not"
2274                                                   " supported in virtual"
2275                                                   " environment");
2276                 }
2277         }
2278         return 0;
2279 }
2280
2281 /*
2282  * GTP flags are contained in 1 byte of the format:
2283  * -------------------------------------------
2284  * | bit   | 0 - 2   | 3  | 4   | 5 | 6 | 7  |
2285  * |-----------------------------------------|
2286  * | value | Version | PT | Res | E | S | PN |
2287  * -------------------------------------------
2288  *
2289  * Matching is supported only for GTP flags E, S, PN.
2290  */
2291 #define MLX5_GTP_FLAGS_MASK     0x07
2292
2293 /**
2294  * Validate GTP item.
2295  *
2296  * @param[in] dev
2297  *   Pointer to the rte_eth_dev structure.
2298  * @param[in] item
2299  *   Item specification.
2300  * @param[in] item_flags
2301  *   Bit-fields that holds the items detected until now.
2302  * @param[out] error
2303  *   Pointer to error structure.
2304  *
2305  * @return
2306  *   0 on success, a negative errno value otherwise and rte_errno is set.
2307  */
2308 static int
2309 flow_dv_validate_item_gtp(struct rte_eth_dev *dev,
2310                           const struct rte_flow_item *item,
2311                           uint64_t item_flags,
2312                           struct rte_flow_error *error)
2313 {
2314         struct mlx5_priv *priv = dev->data->dev_private;
2315         const struct rte_flow_item_gtp *spec = item->spec;
2316         const struct rte_flow_item_gtp *mask = item->mask;
2317         const struct rte_flow_item_gtp nic_mask = {
2318                 .v_pt_rsv_flags = MLX5_GTP_FLAGS_MASK,
2319                 .msg_type = 0xff,
2320                 .teid = RTE_BE32(0xffffffff),
2321         };
2322
2323         if (!priv->config.hca_attr.tunnel_stateless_gtp)
2324                 return rte_flow_error_set(error, ENOTSUP,
2325                                           RTE_FLOW_ERROR_TYPE_ITEM, item,
2326                                           "GTP support is not enabled");
2327         if (item_flags & MLX5_FLOW_LAYER_TUNNEL)
2328                 return rte_flow_error_set(error, ENOTSUP,
2329                                           RTE_FLOW_ERROR_TYPE_ITEM, item,
2330                                           "multiple tunnel layers not"
2331                                           " supported");
2332         if (!(item_flags & MLX5_FLOW_LAYER_OUTER_L4_UDP))
2333                 return rte_flow_error_set(error, EINVAL,
2334                                           RTE_FLOW_ERROR_TYPE_ITEM, item,
2335                                           "no outer UDP layer found");
2336         if (!mask)
2337                 mask = &rte_flow_item_gtp_mask;
2338         if (spec && spec->v_pt_rsv_flags & ~MLX5_GTP_FLAGS_MASK)
2339                 return rte_flow_error_set(error, ENOTSUP,
2340                                           RTE_FLOW_ERROR_TYPE_ITEM, item,
2341                                           "Match is supported for GTP"
2342                                           " flags only");
2343         return mlx5_flow_item_acceptable(item, (const uint8_t *)mask,
2344                                          (const uint8_t *)&nic_mask,
2345                                          sizeof(struct rte_flow_item_gtp),
2346                                          MLX5_ITEM_RANGE_NOT_ACCEPTED, error);
2347 }
2348
2349 /**
2350  * Validate GTP PSC item.
2351  *
2352  * @param[in] item
2353  *   Item specification.
2354  * @param[in] last_item
2355  *   Previous validated item in the pattern items.
2356  * @param[in] gtp_item
2357  *   Previous GTP item specification.
2358  * @param[in] attr
2359  *   Pointer to flow attributes.
2360  * @param[out] error
2361  *   Pointer to error structure.
2362  *
2363  * @return
2364  *   0 on success, a negative errno value otherwise and rte_errno is set.
2365  */
2366 static int
2367 flow_dv_validate_item_gtp_psc(const struct rte_flow_item *item,
2368                               uint64_t last_item,
2369                               const struct rte_flow_item *gtp_item,
2370                               const struct rte_flow_attr *attr,
2371                               struct rte_flow_error *error)
2372 {
2373         const struct rte_flow_item_gtp *gtp_spec;
2374         const struct rte_flow_item_gtp *gtp_mask;
2375         const struct rte_flow_item_gtp_psc *mask;
2376         const struct rte_flow_item_gtp_psc nic_mask = {
2377                 .hdr.type = 0xF,
2378                 .hdr.qfi = 0x3F,
2379         };
2380
2381         if (!gtp_item || !(last_item & MLX5_FLOW_LAYER_GTP))
2382                 return rte_flow_error_set
2383                         (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM, item,
2384                          "GTP PSC item must be preceded with GTP item");
2385         gtp_spec = gtp_item->spec;
2386         gtp_mask = gtp_item->mask ? gtp_item->mask : &rte_flow_item_gtp_mask;
2387         /* GTP spec and E flag is requested to match zero. */
2388         if (gtp_spec &&
2389                 (gtp_mask->v_pt_rsv_flags &
2390                 ~gtp_spec->v_pt_rsv_flags & MLX5_GTP_EXT_HEADER_FLAG))
2391                 return rte_flow_error_set
2392                         (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM, item,
2393                          "GTP E flag must be 1 to match GTP PSC");
2394         /* Check the flow is not created in group zero. */
2395         if (!attr->transfer && !attr->group)
2396                 return rte_flow_error_set
2397                         (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
2398                          "GTP PSC is not supported for group 0");
2399         /* GTP spec is here and E flag is requested to match zero. */
2400         if (!item->spec)
2401                 return 0;
2402         mask = item->mask ? item->mask : &rte_flow_item_gtp_psc_mask;
2403         return mlx5_flow_item_acceptable(item, (const uint8_t *)mask,
2404                                          (const uint8_t *)&nic_mask,
2405                                          sizeof(struct rte_flow_item_gtp_psc),
2406                                          MLX5_ITEM_RANGE_NOT_ACCEPTED, error);
2407 }
2408
2409 /**
2410  * Validate IPV4 item.
2411  * Use existing validation function mlx5_flow_validate_item_ipv4(), and
2412  * add specific validation of fragment_offset field,
2413  *
2414  * @param[in] item
2415  *   Item specification.
2416  * @param[in] item_flags
2417  *   Bit-fields that holds the items detected until now.
2418  * @param[out] error
2419  *   Pointer to error structure.
2420  *
2421  * @return
2422  *   0 on success, a negative errno value otherwise and rte_errno is set.
2423  */
2424 static int
2425 flow_dv_validate_item_ipv4(struct rte_eth_dev *dev,
2426                            const struct rte_flow_item *item,
2427                            uint64_t item_flags, uint64_t last_item,
2428                            uint16_t ether_type, struct rte_flow_error *error)
2429 {
2430         int ret;
2431         struct mlx5_priv *priv = dev->data->dev_private;
2432         const struct rte_flow_item_ipv4 *spec = item->spec;
2433         const struct rte_flow_item_ipv4 *last = item->last;
2434         const struct rte_flow_item_ipv4 *mask = item->mask;
2435         rte_be16_t fragment_offset_spec = 0;
2436         rte_be16_t fragment_offset_last = 0;
2437         struct rte_flow_item_ipv4 nic_ipv4_mask = {
2438                 .hdr = {
2439                         .src_addr = RTE_BE32(0xffffffff),
2440                         .dst_addr = RTE_BE32(0xffffffff),
2441                         .type_of_service = 0xff,
2442                         .fragment_offset = RTE_BE16(0xffff),
2443                         .next_proto_id = 0xff,
2444                         .time_to_live = 0xff,
2445                 },
2446         };
2447
2448         if (mask && (mask->hdr.version_ihl & RTE_IPV4_HDR_IHL_MASK)) {
2449                 int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL);
2450                 bool ihl_cap = !tunnel ? priv->config.hca_attr.outer_ipv4_ihl :
2451                                priv->config.hca_attr.inner_ipv4_ihl;
2452                 if (!ihl_cap)
2453                         return rte_flow_error_set(error, ENOTSUP,
2454                                                   RTE_FLOW_ERROR_TYPE_ITEM,
2455                                                   item,
2456                                                   "IPV4 ihl offload not supported");
2457                 nic_ipv4_mask.hdr.version_ihl = mask->hdr.version_ihl;
2458         }
2459         ret = mlx5_flow_validate_item_ipv4(item, item_flags, last_item,
2460                                            ether_type, &nic_ipv4_mask,
2461                                            MLX5_ITEM_RANGE_ACCEPTED, error);
2462         if (ret < 0)
2463                 return ret;
2464         if (spec && mask)
2465                 fragment_offset_spec = spec->hdr.fragment_offset &
2466                                        mask->hdr.fragment_offset;
2467         if (!fragment_offset_spec)
2468                 return 0;
2469         /*
2470          * spec and mask are valid, enforce using full mask to make sure the
2471          * complete value is used correctly.
2472          */
2473         if ((mask->hdr.fragment_offset & RTE_BE16(MLX5_IPV4_FRAG_OFFSET_MASK))
2474                         != RTE_BE16(MLX5_IPV4_FRAG_OFFSET_MASK))
2475                 return rte_flow_error_set(error, EINVAL,
2476                                           RTE_FLOW_ERROR_TYPE_ITEM_MASK,
2477                                           item, "must use full mask for"
2478                                           " fragment_offset");
2479         /*
2480          * Match on fragment_offset 0x2000 means MF is 1 and frag-offset is 0,
2481          * indicating this is 1st fragment of fragmented packet.
2482          * This is not yet supported in MLX5, return appropriate error message.
2483          */
2484         if (fragment_offset_spec == RTE_BE16(RTE_IPV4_HDR_MF_FLAG))
2485                 return rte_flow_error_set(error, ENOTSUP,
2486                                           RTE_FLOW_ERROR_TYPE_ITEM, item,
2487                                           "match on first fragment not "
2488                                           "supported");
2489         if (fragment_offset_spec && !last)
2490                 return rte_flow_error_set(error, ENOTSUP,
2491                                           RTE_FLOW_ERROR_TYPE_ITEM, item,
2492                                           "specified value not supported");
2493         /* spec and last are valid, validate the specified range. */
2494         fragment_offset_last = last->hdr.fragment_offset &
2495                                mask->hdr.fragment_offset;
2496         /*
2497          * Match on fragment_offset spec 0x2001 and last 0x3fff
2498          * means MF is 1 and frag-offset is > 0.
2499          * This packet is fragment 2nd and onward, excluding last.
2500          * This is not yet supported in MLX5, return appropriate
2501          * error message.
2502          */
2503         if (fragment_offset_spec == RTE_BE16(RTE_IPV4_HDR_MF_FLAG + 1) &&
2504             fragment_offset_last == RTE_BE16(MLX5_IPV4_FRAG_OFFSET_MASK))
2505                 return rte_flow_error_set(error, ENOTSUP,
2506                                           RTE_FLOW_ERROR_TYPE_ITEM_LAST,
2507                                           last, "match on following "
2508                                           "fragments not supported");
2509         /*
2510          * Match on fragment_offset spec 0x0001 and last 0x1fff
2511          * means MF is 0 and frag-offset is > 0.
2512          * This packet is last fragment of fragmented packet.
2513          * This is not yet supported in MLX5, return appropriate
2514          * error message.
2515          */
2516         if (fragment_offset_spec == RTE_BE16(1) &&
2517             fragment_offset_last == RTE_BE16(RTE_IPV4_HDR_OFFSET_MASK))
2518                 return rte_flow_error_set(error, ENOTSUP,
2519                                           RTE_FLOW_ERROR_TYPE_ITEM_LAST,
2520                                           last, "match on last "
2521                                           "fragment not supported");
2522         /*
2523          * Match on fragment_offset spec 0x0001 and last 0x3fff
2524          * means MF and/or frag-offset is not 0.
2525          * This is a fragmented packet.
2526          * Other range values are invalid and rejected.
2527          */
2528         if (!(fragment_offset_spec == RTE_BE16(1) &&
2529               fragment_offset_last == RTE_BE16(MLX5_IPV4_FRAG_OFFSET_MASK)))
2530                 return rte_flow_error_set(error, ENOTSUP,
2531                                           RTE_FLOW_ERROR_TYPE_ITEM_LAST, last,
2532                                           "specified range not supported");
2533         return 0;
2534 }
2535
2536 /**
2537  * Validate IPV6 fragment extension item.
2538  *
2539  * @param[in] item
2540  *   Item specification.
2541  * @param[in] item_flags
2542  *   Bit-fields that holds the items detected until now.
2543  * @param[out] error
2544  *   Pointer to error structure.
2545  *
2546  * @return
2547  *   0 on success, a negative errno value otherwise and rte_errno is set.
2548  */
2549 static int
2550 flow_dv_validate_item_ipv6_frag_ext(const struct rte_flow_item *item,
2551                                     uint64_t item_flags,
2552                                     struct rte_flow_error *error)
2553 {
2554         const struct rte_flow_item_ipv6_frag_ext *spec = item->spec;
2555         const struct rte_flow_item_ipv6_frag_ext *last = item->last;
2556         const struct rte_flow_item_ipv6_frag_ext *mask = item->mask;
2557         rte_be16_t frag_data_spec = 0;
2558         rte_be16_t frag_data_last = 0;
2559         const int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL);
2560         const uint64_t l4m = tunnel ? MLX5_FLOW_LAYER_INNER_L4 :
2561                                       MLX5_FLOW_LAYER_OUTER_L4;
2562         int ret = 0;
2563         struct rte_flow_item_ipv6_frag_ext nic_mask = {
2564                 .hdr = {
2565                         .next_header = 0xff,
2566                         .frag_data = RTE_BE16(0xffff),
2567                 },
2568         };
2569
2570         if (item_flags & l4m)
2571                 return rte_flow_error_set(error, EINVAL,
2572                                           RTE_FLOW_ERROR_TYPE_ITEM, item,
2573                                           "ipv6 fragment extension item cannot "
2574                                           "follow L4 item.");
2575         if ((tunnel && !(item_flags & MLX5_FLOW_LAYER_INNER_L3_IPV6)) ||
2576             (!tunnel && !(item_flags & MLX5_FLOW_LAYER_OUTER_L3_IPV6)))
2577                 return rte_flow_error_set(error, EINVAL,
2578                                           RTE_FLOW_ERROR_TYPE_ITEM, item,
2579                                           "ipv6 fragment extension item must "
2580                                           "follow ipv6 item");
2581         if (spec && mask)
2582                 frag_data_spec = spec->hdr.frag_data & mask->hdr.frag_data;
2583         if (!frag_data_spec)
2584                 return 0;
2585         /*
2586          * spec and mask are valid, enforce using full mask to make sure the
2587          * complete value is used correctly.
2588          */
2589         if ((mask->hdr.frag_data & RTE_BE16(RTE_IPV6_FRAG_USED_MASK)) !=
2590                                 RTE_BE16(RTE_IPV6_FRAG_USED_MASK))
2591                 return rte_flow_error_set(error, EINVAL,
2592                                           RTE_FLOW_ERROR_TYPE_ITEM_MASK,
2593                                           item, "must use full mask for"
2594                                           " frag_data");
2595         /*
2596          * Match on frag_data 0x00001 means M is 1 and frag-offset is 0.
2597          * This is 1st fragment of fragmented packet.
2598          */
2599         if (frag_data_spec == RTE_BE16(RTE_IPV6_EHDR_MF_MASK))
2600                 return rte_flow_error_set(error, ENOTSUP,
2601                                           RTE_FLOW_ERROR_TYPE_ITEM, item,
2602                                           "match on first fragment not "
2603                                           "supported");
2604         if (frag_data_spec && !last)
2605                 return rte_flow_error_set(error, EINVAL,
2606                                           RTE_FLOW_ERROR_TYPE_ITEM, item,
2607                                           "specified value not supported");
2608         ret = mlx5_flow_item_acceptable
2609                                 (item, (const uint8_t *)mask,
2610                                  (const uint8_t *)&nic_mask,
2611                                  sizeof(struct rte_flow_item_ipv6_frag_ext),
2612                                  MLX5_ITEM_RANGE_ACCEPTED, error);
2613         if (ret)
2614                 return ret;
2615         /* spec and last are valid, validate the specified range. */
2616         frag_data_last = last->hdr.frag_data & mask->hdr.frag_data;
2617         /*
2618          * Match on frag_data spec 0x0009 and last 0xfff9
2619          * means M is 1 and frag-offset is > 0.
2620          * This packet is fragment 2nd and onward, excluding last.
2621          * This is not yet supported in MLX5, return appropriate
2622          * error message.
2623          */
2624         if (frag_data_spec == RTE_BE16(RTE_IPV6_EHDR_FO_ALIGN |
2625                                        RTE_IPV6_EHDR_MF_MASK) &&
2626             frag_data_last == RTE_BE16(RTE_IPV6_FRAG_USED_MASK))
2627                 return rte_flow_error_set(error, ENOTSUP,
2628                                           RTE_FLOW_ERROR_TYPE_ITEM_LAST,
2629                                           last, "match on following "
2630                                           "fragments not supported");
2631         /*
2632          * Match on frag_data spec 0x0008 and last 0xfff8
2633          * means M is 0 and frag-offset is > 0.
2634          * This packet is last fragment of fragmented packet.
2635          * This is not yet supported in MLX5, return appropriate
2636          * error message.
2637          */
2638         if (frag_data_spec == RTE_BE16(RTE_IPV6_EHDR_FO_ALIGN) &&
2639             frag_data_last == RTE_BE16(RTE_IPV6_EHDR_FO_MASK))
2640                 return rte_flow_error_set(error, ENOTSUP,
2641                                           RTE_FLOW_ERROR_TYPE_ITEM_LAST,
2642                                           last, "match on last "
2643                                           "fragment not supported");
2644         /* Other range values are invalid and rejected. */
2645         return rte_flow_error_set(error, EINVAL,
2646                                   RTE_FLOW_ERROR_TYPE_ITEM_LAST, last,
2647                                   "specified range not supported");
2648 }
2649
2650 /*
2651  * Validate ASO CT item.
2652  *
2653  * @param[in] dev
2654  *   Pointer to the rte_eth_dev structure.
2655  * @param[in] item
2656  *   Item specification.
2657  * @param[in] item_flags
2658  *   Pointer to bit-fields that holds the items detected until now.
2659  * @param[out] error
2660  *   Pointer to error structure.
2661  *
2662  * @return
2663  *   0 on success, a negative errno value otherwise and rte_errno is set.
2664  */
2665 static int
2666 flow_dv_validate_item_aso_ct(struct rte_eth_dev *dev,
2667                              const struct rte_flow_item *item,
2668                              uint64_t *item_flags,
2669                              struct rte_flow_error *error)
2670 {
2671         const struct rte_flow_item_conntrack *spec = item->spec;
2672         const struct rte_flow_item_conntrack *mask = item->mask;
2673         RTE_SET_USED(dev);
2674         uint32_t flags;
2675
2676         if (*item_flags & MLX5_FLOW_LAYER_ASO_CT)
2677                 return rte_flow_error_set(error, EINVAL,
2678                                           RTE_FLOW_ERROR_TYPE_ITEM, NULL,
2679                                           "Only one CT is supported");
2680         if (!mask)
2681                 mask = &rte_flow_item_conntrack_mask;
2682         flags = spec->flags & mask->flags;
2683         if ((flags & RTE_FLOW_CONNTRACK_PKT_STATE_VALID) &&
2684             ((flags & RTE_FLOW_CONNTRACK_PKT_STATE_INVALID) ||
2685              (flags & RTE_FLOW_CONNTRACK_PKT_STATE_BAD) ||
2686              (flags & RTE_FLOW_CONNTRACK_PKT_STATE_DISABLED)))
2687                 return rte_flow_error_set(error, EINVAL,
2688                                           RTE_FLOW_ERROR_TYPE_ITEM, NULL,
2689                                           "Conflict status bits");
2690         /* State change also needs to be considered. */
2691         *item_flags |= MLX5_FLOW_LAYER_ASO_CT;
2692         return 0;
2693 }
2694
2695 /**
2696  * Validate the pop VLAN action.
2697  *
2698  * @param[in] dev
2699  *   Pointer to the rte_eth_dev structure.
2700  * @param[in] action_flags
2701  *   Holds the actions detected until now.
2702  * @param[in] action
2703  *   Pointer to the pop vlan action.
2704  * @param[in] item_flags
2705  *   The items found in this flow rule.
2706  * @param[in] attr
2707  *   Pointer to flow attributes.
2708  * @param[out] error
2709  *   Pointer to error structure.
2710  *
2711  * @return
2712  *   0 on success, a negative errno value otherwise and rte_errno is set.
2713  */
2714 static int
2715 flow_dv_validate_action_pop_vlan(struct rte_eth_dev *dev,
2716                                  uint64_t action_flags,
2717                                  const struct rte_flow_action *action,
2718                                  uint64_t item_flags,
2719                                  const struct rte_flow_attr *attr,
2720                                  struct rte_flow_error *error)
2721 {
2722         const struct mlx5_priv *priv = dev->data->dev_private;
2723         struct mlx5_dev_ctx_shared *sh = priv->sh;
2724         bool direction_error = false;
2725
2726         if (!priv->sh->pop_vlan_action)
2727                 return rte_flow_error_set(error, ENOTSUP,
2728                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2729                                           NULL,
2730                                           "pop vlan action is not supported");
2731         /* Pop VLAN is not supported in egress except for CX6 FDB mode. */
2732         if (attr->transfer) {
2733                 bool fdb_tx = priv->representor_id != UINT16_MAX;
2734                 bool is_cx5 = sh->steering_format_version ==
2735                     MLX5_STEERING_LOGIC_FORMAT_CONNECTX_5;
2736
2737                 if (fdb_tx && is_cx5)
2738                         direction_error = true;
2739         } else if (attr->egress) {
2740                 direction_error = true;
2741         }
2742         if (direction_error)
2743                 return rte_flow_error_set(error, ENOTSUP,
2744                                           RTE_FLOW_ERROR_TYPE_ATTR_EGRESS,
2745                                           NULL,
2746                                           "pop vlan action not supported for egress");
2747         if (action_flags & MLX5_FLOW_VLAN_ACTIONS)
2748                 return rte_flow_error_set(error, ENOTSUP,
2749                                           RTE_FLOW_ERROR_TYPE_ACTION, action,
2750                                           "no support for multiple VLAN "
2751                                           "actions");
2752         /* Pop VLAN with preceding Decap requires inner header with VLAN. */
2753         if ((action_flags & MLX5_FLOW_ACTION_DECAP) &&
2754             !(item_flags & MLX5_FLOW_LAYER_INNER_VLAN))
2755                 return rte_flow_error_set(error, ENOTSUP,
2756                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2757                                           NULL,
2758                                           "cannot pop vlan after decap without "
2759                                           "match on inner vlan in the flow");
2760         /* Pop VLAN without preceding Decap requires outer header with VLAN. */
2761         if (!(action_flags & MLX5_FLOW_ACTION_DECAP) &&
2762             !(item_flags & MLX5_FLOW_LAYER_OUTER_VLAN))
2763                 return rte_flow_error_set(error, ENOTSUP,
2764                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2765                                           NULL,
2766                                           "cannot pop vlan without a "
2767                                           "match on (outer) vlan in the flow");
2768         if (action_flags & MLX5_FLOW_ACTION_PORT_ID)
2769                 return rte_flow_error_set(error, EINVAL,
2770                                           RTE_FLOW_ERROR_TYPE_ACTION, action,
2771                                           "wrong action order, port_id should "
2772                                           "be after pop VLAN action");
2773         if (!attr->transfer && priv->representor)
2774                 return rte_flow_error_set(error, ENOTSUP,
2775                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
2776                                           "pop vlan action for VF representor "
2777                                           "not supported on NIC table");
2778         return 0;
2779 }
2780
2781 /**
2782  * Get VLAN default info from vlan match info.
2783  *
2784  * @param[in] items
2785  *   the list of item specifications.
2786  * @param[out] vlan
2787  *   pointer VLAN info to fill to.
2788  *
2789  * @return
2790  *   0 on success, a negative errno value otherwise and rte_errno is set.
2791  */
2792 static void
2793 flow_dev_get_vlan_info_from_items(const struct rte_flow_item *items,
2794                                   struct rte_vlan_hdr *vlan)
2795 {
2796         const struct rte_flow_item_vlan nic_mask = {
2797                 .tci = RTE_BE16(MLX5DV_FLOW_VLAN_PCP_MASK |
2798                                 MLX5DV_FLOW_VLAN_VID_MASK),
2799                 .inner_type = RTE_BE16(0xffff),
2800         };
2801
2802         if (items == NULL)
2803                 return;
2804         for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
2805                 int type = items->type;
2806
2807                 if (type == RTE_FLOW_ITEM_TYPE_VLAN ||
2808                     type == MLX5_RTE_FLOW_ITEM_TYPE_VLAN)
2809                         break;
2810         }
2811         if (items->type != RTE_FLOW_ITEM_TYPE_END) {
2812                 const struct rte_flow_item_vlan *vlan_m = items->mask;
2813                 const struct rte_flow_item_vlan *vlan_v = items->spec;
2814
2815                 /* If VLAN item in pattern doesn't contain data, return here. */
2816                 if (!vlan_v)
2817                         return;
2818                 if (!vlan_m)
2819                         vlan_m = &nic_mask;
2820                 /* Only full match values are accepted */
2821                 if ((vlan_m->tci & MLX5DV_FLOW_VLAN_PCP_MASK_BE) ==
2822                      MLX5DV_FLOW_VLAN_PCP_MASK_BE) {
2823                         vlan->vlan_tci &= ~MLX5DV_FLOW_VLAN_PCP_MASK;
2824                         vlan->vlan_tci |=
2825                                 rte_be_to_cpu_16(vlan_v->tci &
2826                                                  MLX5DV_FLOW_VLAN_PCP_MASK_BE);
2827                 }
2828                 if ((vlan_m->tci & MLX5DV_FLOW_VLAN_VID_MASK_BE) ==
2829                      MLX5DV_FLOW_VLAN_VID_MASK_BE) {
2830                         vlan->vlan_tci &= ~MLX5DV_FLOW_VLAN_VID_MASK;
2831                         vlan->vlan_tci |=
2832                                 rte_be_to_cpu_16(vlan_v->tci &
2833                                                  MLX5DV_FLOW_VLAN_VID_MASK_BE);
2834                 }
2835                 if (vlan_m->inner_type == nic_mask.inner_type)
2836                         vlan->eth_proto = rte_be_to_cpu_16(vlan_v->inner_type &
2837                                                            vlan_m->inner_type);
2838         }
2839 }
2840
2841 /**
2842  * Validate the push VLAN action.
2843  *
2844  * @param[in] dev
2845  *   Pointer to the rte_eth_dev structure.
2846  * @param[in] action_flags
2847  *   Holds the actions detected until now.
2848  * @param[in] item_flags
2849  *   The items found in this flow rule.
2850  * @param[in] action
2851  *   Pointer to the action structure.
2852  * @param[in] attr
2853  *   Pointer to flow attributes
2854  * @param[out] error
2855  *   Pointer to error structure.
2856  *
2857  * @return
2858  *   0 on success, a negative errno value otherwise and rte_errno is set.
2859  */
2860 static int
2861 flow_dv_validate_action_push_vlan(struct rte_eth_dev *dev,
2862                                   uint64_t action_flags,
2863                                   const struct rte_flow_item_vlan *vlan_m,
2864                                   const struct rte_flow_action *action,
2865                                   const struct rte_flow_attr *attr,
2866                                   struct rte_flow_error *error)
2867 {
2868         const struct rte_flow_action_of_push_vlan *push_vlan = action->conf;
2869         const struct mlx5_priv *priv = dev->data->dev_private;
2870         struct mlx5_dev_ctx_shared *sh = priv->sh;
2871         bool direction_error = false;
2872
2873         if (push_vlan->ethertype != RTE_BE16(RTE_ETHER_TYPE_VLAN) &&
2874             push_vlan->ethertype != RTE_BE16(RTE_ETHER_TYPE_QINQ))
2875                 return rte_flow_error_set(error, EINVAL,
2876                                           RTE_FLOW_ERROR_TYPE_ACTION, action,
2877                                           "invalid vlan ethertype");
2878         if (action_flags & MLX5_FLOW_ACTION_PORT_ID)
2879                 return rte_flow_error_set(error, EINVAL,
2880                                           RTE_FLOW_ERROR_TYPE_ACTION, action,
2881                                           "wrong action order, port_id should "
2882                                           "be after push VLAN");
2883         /* Push VLAN is not supported in ingress except for CX6 FDB mode. */
2884         if (attr->transfer) {
2885                 bool fdb_tx = priv->representor_id != UINT16_MAX;
2886                 bool is_cx5 = sh->steering_format_version ==
2887                     MLX5_STEERING_LOGIC_FORMAT_CONNECTX_5;
2888
2889                 if (!fdb_tx && is_cx5)
2890                         direction_error = true;
2891         } else if (attr->ingress) {
2892                 direction_error = true;
2893         }
2894         if (direction_error)
2895                 return rte_flow_error_set(error, ENOTSUP,
2896                                           RTE_FLOW_ERROR_TYPE_ATTR_INGRESS,
2897                                           NULL,
2898                                           "push vlan action not supported for ingress");
2899         if (!attr->transfer && priv->representor)
2900                 return rte_flow_error_set(error, ENOTSUP,
2901                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
2902                                           "push vlan action for VF representor "
2903                                           "not supported on NIC table");
2904         if (vlan_m &&
2905             (vlan_m->tci & MLX5DV_FLOW_VLAN_PCP_MASK_BE) &&
2906             (vlan_m->tci & MLX5DV_FLOW_VLAN_PCP_MASK_BE) !=
2907                 MLX5DV_FLOW_VLAN_PCP_MASK_BE &&
2908             !(action_flags & MLX5_FLOW_ACTION_OF_SET_VLAN_PCP) &&
2909             !(mlx5_flow_find_action
2910                 (action + 1, RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP)))
2911                 return rte_flow_error_set(error, EINVAL,
2912                                           RTE_FLOW_ERROR_TYPE_ACTION, action,
2913                                           "not full match mask on VLAN PCP and "
2914                                           "there is no of_set_vlan_pcp action, "
2915                                           "push VLAN action cannot figure out "
2916                                           "PCP value");
2917         if (vlan_m &&
2918             (vlan_m->tci & MLX5DV_FLOW_VLAN_VID_MASK_BE) &&
2919             (vlan_m->tci & MLX5DV_FLOW_VLAN_VID_MASK_BE) !=
2920                 MLX5DV_FLOW_VLAN_VID_MASK_BE &&
2921             !(action_flags & MLX5_FLOW_ACTION_OF_SET_VLAN_VID) &&
2922             !(mlx5_flow_find_action
2923                 (action + 1, RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID)))
2924                 return rte_flow_error_set(error, EINVAL,
2925                                           RTE_FLOW_ERROR_TYPE_ACTION, action,
2926                                           "not full match mask on VLAN VID and "
2927                                           "there is no of_set_vlan_vid action, "
2928                                           "push VLAN action cannot figure out "
2929                                           "VID value");
2930         (void)attr;
2931         return 0;
2932 }
2933
2934 /**
2935  * Validate the set VLAN PCP.
2936  *
2937  * @param[in] action_flags
2938  *   Holds the actions detected until now.
2939  * @param[in] actions
2940  *   Pointer to the list of actions remaining in the flow rule.
2941  * @param[out] error
2942  *   Pointer to error structure.
2943  *
2944  * @return
2945  *   0 on success, a negative errno value otherwise and rte_errno is set.
2946  */
2947 static int
2948 flow_dv_validate_action_set_vlan_pcp(uint64_t action_flags,
2949                                      const struct rte_flow_action actions[],
2950                                      struct rte_flow_error *error)
2951 {
2952         const struct rte_flow_action *action = actions;
2953         const struct rte_flow_action_of_set_vlan_pcp *conf = action->conf;
2954
2955         if (conf->vlan_pcp > 7)
2956                 return rte_flow_error_set(error, EINVAL,
2957                                           RTE_FLOW_ERROR_TYPE_ACTION, action,
2958                                           "VLAN PCP value is too big");
2959         if (!(action_flags & MLX5_FLOW_ACTION_OF_PUSH_VLAN))
2960                 return rte_flow_error_set(error, ENOTSUP,
2961                                           RTE_FLOW_ERROR_TYPE_ACTION, action,
2962                                           "set VLAN PCP action must follow "
2963                                           "the push VLAN action");
2964         if (action_flags & MLX5_FLOW_ACTION_OF_SET_VLAN_PCP)
2965                 return rte_flow_error_set(error, ENOTSUP,
2966                                           RTE_FLOW_ERROR_TYPE_ACTION, action,
2967                                           "Multiple VLAN PCP modification are "
2968                                           "not supported");
2969         if (action_flags & MLX5_FLOW_ACTION_PORT_ID)
2970                 return rte_flow_error_set(error, EINVAL,
2971                                           RTE_FLOW_ERROR_TYPE_ACTION, action,
2972                                           "wrong action order, port_id should "
2973                                           "be after set VLAN PCP");
2974         return 0;
2975 }
2976
2977 /**
2978  * Validate the set VLAN VID.
2979  *
2980  * @param[in] item_flags
2981  *   Holds the items detected in this rule.
2982  * @param[in] action_flags
2983  *   Holds the actions detected until now.
2984  * @param[in] actions
2985  *   Pointer to the list of actions remaining in the flow rule.
2986  * @param[out] error
2987  *   Pointer to error structure.
2988  *
2989  * @return
2990  *   0 on success, a negative errno value otherwise and rte_errno is set.
2991  */
2992 static int
2993 flow_dv_validate_action_set_vlan_vid(uint64_t item_flags,
2994                                      uint64_t action_flags,
2995                                      const struct rte_flow_action actions[],
2996                                      struct rte_flow_error *error)
2997 {
2998         const struct rte_flow_action *action = actions;
2999         const struct rte_flow_action_of_set_vlan_vid *conf = action->conf;
3000
3001         if (rte_be_to_cpu_16(conf->vlan_vid) > 0xFFE)
3002                 return rte_flow_error_set(error, EINVAL,
3003                                           RTE_FLOW_ERROR_TYPE_ACTION, action,
3004                                           "VLAN VID value is too big");
3005         if (!(action_flags & MLX5_FLOW_ACTION_OF_PUSH_VLAN) &&
3006             !(item_flags & MLX5_FLOW_LAYER_OUTER_VLAN))
3007                 return rte_flow_error_set(error, ENOTSUP,
3008                                           RTE_FLOW_ERROR_TYPE_ACTION, action,
3009                                           "set VLAN VID action must follow push"
3010                                           " VLAN action or match on VLAN item");
3011         if (action_flags & MLX5_FLOW_ACTION_OF_SET_VLAN_VID)
3012                 return rte_flow_error_set(error, ENOTSUP,
3013                                           RTE_FLOW_ERROR_TYPE_ACTION, action,
3014                                           "Multiple VLAN VID modifications are "
3015                                           "not supported");
3016         if (action_flags & MLX5_FLOW_ACTION_PORT_ID)
3017                 return rte_flow_error_set(error, EINVAL,
3018                                           RTE_FLOW_ERROR_TYPE_ACTION, action,
3019                                           "wrong action order, port_id should "
3020                                           "be after set VLAN VID");
3021         return 0;
3022 }
3023
3024 /*
3025  * Validate the FLAG action.
3026  *
3027  * @param[in] dev
3028  *   Pointer to the rte_eth_dev structure.
3029  * @param[in] action_flags
3030  *   Holds the actions detected until now.
3031  * @param[in] attr
3032  *   Pointer to flow attributes
3033  * @param[out] error
3034  *   Pointer to error structure.
3035  *
3036  * @return
3037  *   0 on success, a negative errno value otherwise and rte_errno is set.
3038  */
3039 static int
3040 flow_dv_validate_action_flag(struct rte_eth_dev *dev,
3041                              uint64_t action_flags,
3042                              const struct rte_flow_attr *attr,
3043                              struct rte_flow_error *error)
3044 {
3045         struct mlx5_priv *priv = dev->data->dev_private;
3046         struct mlx5_dev_config *config = &priv->config;
3047         int ret;
3048
3049         /* Fall back if no extended metadata register support. */
3050         if (config->dv_xmeta_en == MLX5_XMETA_MODE_LEGACY)
3051                 return mlx5_flow_validate_action_flag(action_flags, attr,
3052                                                       error);
3053         /* Extensive metadata mode requires registers. */
3054         if (!mlx5_flow_ext_mreg_supported(dev))
3055                 return rte_flow_error_set(error, ENOTSUP,
3056                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3057                                           "no metadata registers "
3058                                           "to support flag action");
3059         if (!(priv->sh->dv_mark_mask & MLX5_FLOW_MARK_DEFAULT))
3060                 return rte_flow_error_set(error, ENOTSUP,
3061                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3062                                           "extended metadata register"
3063                                           " isn't available");
3064         ret = mlx5_flow_get_reg_id(dev, MLX5_FLOW_MARK, 0, error);
3065         if (ret < 0)
3066                 return ret;
3067         MLX5_ASSERT(ret > 0);
3068         if (action_flags & MLX5_FLOW_ACTION_MARK)
3069                 return rte_flow_error_set(error, EINVAL,
3070                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3071                                           "can't mark and flag in same flow");
3072         if (action_flags & MLX5_FLOW_ACTION_FLAG)
3073                 return rte_flow_error_set(error, EINVAL,
3074                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3075                                           "can't have 2 flag"
3076                                           " actions in same flow");
3077         return 0;
3078 }
3079
3080 /**
3081  * Validate MARK action.
3082  *
3083  * @param[in] dev
3084  *   Pointer to the rte_eth_dev structure.
3085  * @param[in] action
3086  *   Pointer to action.
3087  * @param[in] action_flags
3088  *   Holds the actions detected until now.
3089  * @param[in] attr
3090  *   Pointer to flow attributes
3091  * @param[out] error
3092  *   Pointer to error structure.
3093  *
3094  * @return
3095  *   0 on success, a negative errno value otherwise and rte_errno is set.
3096  */
3097 static int
3098 flow_dv_validate_action_mark(struct rte_eth_dev *dev,
3099                              const struct rte_flow_action *action,
3100                              uint64_t action_flags,
3101                              const struct rte_flow_attr *attr,
3102                              struct rte_flow_error *error)
3103 {
3104         struct mlx5_priv *priv = dev->data->dev_private;
3105         struct mlx5_dev_config *config = &priv->config;
3106         const struct rte_flow_action_mark *mark = action->conf;
3107         int ret;
3108
3109         if (is_tunnel_offload_active(dev))
3110                 return rte_flow_error_set(error, ENOTSUP,
3111                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3112                                           "no mark action "
3113                                           "if tunnel offload active");
3114         /* Fall back if no extended metadata register support. */
3115         if (config->dv_xmeta_en == MLX5_XMETA_MODE_LEGACY)
3116                 return mlx5_flow_validate_action_mark(action, action_flags,
3117                                                       attr, error);
3118         /* Extensive metadata mode requires registers. */
3119         if (!mlx5_flow_ext_mreg_supported(dev))
3120                 return rte_flow_error_set(error, ENOTSUP,
3121                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3122                                           "no metadata registers "
3123                                           "to support mark action");
3124         if (!priv->sh->dv_mark_mask)
3125                 return rte_flow_error_set(error, ENOTSUP,
3126                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3127                                           "extended metadata register"
3128                                           " isn't available");
3129         ret = mlx5_flow_get_reg_id(dev, MLX5_FLOW_MARK, 0, error);
3130         if (ret < 0)
3131                 return ret;
3132         MLX5_ASSERT(ret > 0);
3133         if (!mark)
3134                 return rte_flow_error_set(error, EINVAL,
3135                                           RTE_FLOW_ERROR_TYPE_ACTION, action,
3136                                           "configuration cannot be null");
3137         if (mark->id >= (MLX5_FLOW_MARK_MAX & priv->sh->dv_mark_mask))
3138                 return rte_flow_error_set(error, EINVAL,
3139                                           RTE_FLOW_ERROR_TYPE_ACTION_CONF,
3140                                           &mark->id,
3141                                           "mark id exceeds the limit");
3142         if (action_flags & MLX5_FLOW_ACTION_FLAG)
3143                 return rte_flow_error_set(error, EINVAL,
3144                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3145                                           "can't flag and mark in same flow");
3146         if (action_flags & MLX5_FLOW_ACTION_MARK)
3147                 return rte_flow_error_set(error, EINVAL,
3148                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3149                                           "can't have 2 mark actions in same"
3150                                           " flow");
3151         return 0;
3152 }
3153
3154 /**
3155  * Validate SET_META action.
3156  *
3157  * @param[in] dev
3158  *   Pointer to the rte_eth_dev structure.
3159  * @param[in] action
3160  *   Pointer to the action structure.
3161  * @param[in] action_flags
3162  *   Holds the actions detected until now.
3163  * @param[in] attr
3164  *   Pointer to flow attributes
3165  * @param[out] error
3166  *   Pointer to error structure.
3167  *
3168  * @return
3169  *   0 on success, a negative errno value otherwise and rte_errno is set.
3170  */
3171 static int
3172 flow_dv_validate_action_set_meta(struct rte_eth_dev *dev,
3173                                  const struct rte_flow_action *action,
3174                                  uint64_t action_flags __rte_unused,
3175                                  const struct rte_flow_attr *attr,
3176                                  struct rte_flow_error *error)
3177 {
3178         const struct rte_flow_action_set_meta *conf;
3179         uint32_t nic_mask = UINT32_MAX;
3180         int reg;
3181
3182         if (!mlx5_flow_ext_mreg_supported(dev))
3183                 return rte_flow_error_set(error, ENOTSUP,
3184                                           RTE_FLOW_ERROR_TYPE_ACTION, action,
3185                                           "extended metadata register"
3186                                           " isn't supported");
3187         reg = flow_dv_get_metadata_reg(dev, attr, error);
3188         if (reg < 0)
3189                 return reg;
3190         if (reg == REG_NON)
3191                 return rte_flow_error_set(error, ENOTSUP,
3192                                           RTE_FLOW_ERROR_TYPE_ACTION, action,
3193                                           "unavalable extended metadata register");
3194         if (reg != REG_A && reg != REG_B) {
3195                 struct mlx5_priv *priv = dev->data->dev_private;
3196
3197                 nic_mask = priv->sh->dv_meta_mask;
3198         }
3199         if (!(action->conf))
3200                 return rte_flow_error_set(error, EINVAL,
3201                                           RTE_FLOW_ERROR_TYPE_ACTION, action,
3202                                           "configuration cannot be null");
3203         conf = (const struct rte_flow_action_set_meta *)action->conf;
3204         if (!conf->mask)
3205                 return rte_flow_error_set(error, EINVAL,
3206                                           RTE_FLOW_ERROR_TYPE_ACTION, action,
3207                                           "zero mask doesn't have any effect");
3208         if (conf->mask & ~nic_mask)
3209                 return rte_flow_error_set(error, EINVAL,
3210                                           RTE_FLOW_ERROR_TYPE_ACTION, action,
3211                                           "meta data must be within reg C0");
3212         return 0;
3213 }
3214
3215 /**
3216  * Validate SET_TAG action.
3217  *
3218  * @param[in] dev
3219  *   Pointer to the rte_eth_dev structure.
3220  * @param[in] action
3221  *   Pointer to the action structure.
3222  * @param[in] action_flags
3223  *   Holds the actions detected until now.
3224  * @param[in] attr
3225  *   Pointer to flow attributes
3226  * @param[out] error
3227  *   Pointer to error structure.
3228  *
3229  * @return
3230  *   0 on success, a negative errno value otherwise and rte_errno is set.
3231  */
3232 static int
3233 flow_dv_validate_action_set_tag(struct rte_eth_dev *dev,
3234                                 const struct rte_flow_action *action,
3235                                 uint64_t action_flags,
3236                                 const struct rte_flow_attr *attr,
3237                                 struct rte_flow_error *error)
3238 {
3239         const struct rte_flow_action_set_tag *conf;
3240         const uint64_t terminal_action_flags =
3241                 MLX5_FLOW_ACTION_DROP | MLX5_FLOW_ACTION_QUEUE |
3242                 MLX5_FLOW_ACTION_RSS;
3243         int ret;
3244
3245         if (!mlx5_flow_ext_mreg_supported(dev))
3246                 return rte_flow_error_set(error, ENOTSUP,
3247                                           RTE_FLOW_ERROR_TYPE_ACTION, action,
3248                                           "extensive metadata register"
3249                                           " isn't supported");
3250         if (!(action->conf))
3251                 return rte_flow_error_set(error, EINVAL,
3252                                           RTE_FLOW_ERROR_TYPE_ACTION, action,
3253                                           "configuration cannot be null");
3254         conf = (const struct rte_flow_action_set_tag *)action->conf;
3255         if (!conf->mask)
3256                 return rte_flow_error_set(error, EINVAL,
3257                                           RTE_FLOW_ERROR_TYPE_ACTION, action,
3258                                           "zero mask doesn't have any effect");
3259         ret = mlx5_flow_get_reg_id(dev, MLX5_APP_TAG, conf->index, error);
3260         if (ret < 0)
3261                 return ret;
3262         if (!attr->transfer && attr->ingress &&
3263             (action_flags & terminal_action_flags))
3264                 return rte_flow_error_set(error, EINVAL,
3265                                           RTE_FLOW_ERROR_TYPE_ACTION, action,
3266                                           "set_tag has no effect"
3267                                           " with terminal actions");
3268         return 0;
3269 }
3270
3271 /**
3272  * Validate count action.
3273  *
3274  * @param[in] dev
3275  *   Pointer to rte_eth_dev structure.
3276  * @param[in] shared
3277  *   Indicator if action is shared.
3278  * @param[in] action_flags
3279  *   Holds the actions detected until now.
3280  * @param[out] error
3281  *   Pointer to error structure.
3282  *
3283  * @return
3284  *   0 on success, a negative errno value otherwise and rte_errno is set.
3285  */
3286 static int
3287 flow_dv_validate_action_count(struct rte_eth_dev *dev, bool shared,
3288                               uint64_t action_flags,
3289                               struct rte_flow_error *error)
3290 {
3291         struct mlx5_priv *priv = dev->data->dev_private;
3292
3293         if (!priv->sh->devx)
3294                 goto notsup_err;
3295         if (action_flags & MLX5_FLOW_ACTION_COUNT)
3296                 return rte_flow_error_set(error, EINVAL,
3297                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3298                                           "duplicate count actions set");
3299         if (shared && (action_flags & MLX5_FLOW_ACTION_AGE) &&
3300             !priv->sh->flow_hit_aso_en)
3301                 return rte_flow_error_set(error, EINVAL,
3302                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3303                                           "old age and shared count combination is not supported");
3304 #ifdef HAVE_IBV_FLOW_DEVX_COUNTERS
3305         return 0;
3306 #endif
3307 notsup_err:
3308         return rte_flow_error_set
3309                       (error, ENOTSUP,
3310                        RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
3311                        NULL,
3312                        "count action not supported");
3313 }
3314
3315 /**
3316  * Validate the L2 encap action.
3317  *
3318  * @param[in] dev
3319  *   Pointer to the rte_eth_dev structure.
3320  * @param[in] action_flags
3321  *   Holds the actions detected until now.
3322  * @param[in] action
3323  *   Pointer to the action structure.
3324  * @param[in] attr
3325  *   Pointer to flow attributes.
3326  * @param[out] error
3327  *   Pointer to error structure.
3328  *
3329  * @return
3330  *   0 on success, a negative errno value otherwise and rte_errno is set.
3331  */
3332 static int
3333 flow_dv_validate_action_l2_encap(struct rte_eth_dev *dev,
3334                                  uint64_t action_flags,
3335                                  const struct rte_flow_action *action,
3336                                  const struct rte_flow_attr *attr,
3337                                  struct rte_flow_error *error)
3338 {
3339         const struct mlx5_priv *priv = dev->data->dev_private;
3340
3341         if (!(action->conf))
3342                 return rte_flow_error_set(error, EINVAL,
3343                                           RTE_FLOW_ERROR_TYPE_ACTION, action,
3344                                           "configuration cannot be null");
3345         if (action_flags & MLX5_FLOW_ACTION_ENCAP)
3346                 return rte_flow_error_set(error, EINVAL,
3347                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3348                                           "can only have a single encap action "
3349                                           "in a flow");
3350         if (!attr->transfer && priv->representor)
3351                 return rte_flow_error_set(error, ENOTSUP,
3352                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3353                                           "encap action for VF representor "
3354                                           "not supported on NIC table");
3355         return 0;
3356 }
3357
3358 /**
3359  * Validate a decap action.
3360  *
3361  * @param[in] dev
3362  *   Pointer to the rte_eth_dev structure.
3363  * @param[in] action_flags
3364  *   Holds the actions detected until now.
3365  * @param[in] action
3366  *   Pointer to the action structure.
3367  * @param[in] item_flags
3368  *   Holds the items detected.
3369  * @param[in] attr
3370  *   Pointer to flow attributes
3371  * @param[out] error
3372  *   Pointer to error structure.
3373  *
3374  * @return
3375  *   0 on success, a negative errno value otherwise and rte_errno is set.
3376  */
3377 static int
3378 flow_dv_validate_action_decap(struct rte_eth_dev *dev,
3379                               uint64_t action_flags,
3380                               const struct rte_flow_action *action,
3381                               const uint64_t item_flags,
3382                               const struct rte_flow_attr *attr,
3383                               struct rte_flow_error *error)
3384 {
3385         const struct mlx5_priv *priv = dev->data->dev_private;
3386
3387         if (priv->config.hca_attr.scatter_fcs_w_decap_disable &&
3388             !priv->config.decap_en)
3389                 return rte_flow_error_set(error, ENOTSUP,
3390                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3391                                           "decap is not enabled");
3392         if (action_flags & MLX5_FLOW_XCAP_ACTIONS)
3393                 return rte_flow_error_set(error, ENOTSUP,
3394                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3395                                           action_flags &
3396                                           MLX5_FLOW_ACTION_DECAP ? "can only "
3397                                           "have a single decap action" : "decap "
3398                                           "after encap is not supported");
3399         if (action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)
3400                 return rte_flow_error_set(error, EINVAL,
3401                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3402                                           "can't have decap action after"
3403                                           " modify action");
3404         if (attr->egress)
3405                 return rte_flow_error_set(error, ENOTSUP,
3406                                           RTE_FLOW_ERROR_TYPE_ATTR_EGRESS,
3407                                           NULL,
3408                                           "decap action not supported for "
3409                                           "egress");
3410         if (!attr->transfer && priv->representor)
3411                 return rte_flow_error_set(error, ENOTSUP,
3412                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3413                                           "decap action for VF representor "
3414                                           "not supported on NIC table");
3415         if (action->type == RTE_FLOW_ACTION_TYPE_VXLAN_DECAP &&
3416             !(item_flags & MLX5_FLOW_LAYER_VXLAN))
3417                 return rte_flow_error_set(error, ENOTSUP,
3418                                 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3419                                 "VXLAN item should be present for VXLAN decap");
3420         return 0;
3421 }
3422
3423 const struct rte_flow_action_raw_decap empty_decap = {.data = NULL, .size = 0,};
3424
3425 /**
3426  * Validate the raw encap and decap actions.
3427  *
3428  * @param[in] dev
3429  *   Pointer to the rte_eth_dev structure.
3430  * @param[in] decap
3431  *   Pointer to the decap action.
3432  * @param[in] encap
3433  *   Pointer to the encap action.
3434  * @param[in] attr
3435  *   Pointer to flow attributes
3436  * @param[in/out] action_flags
3437  *   Holds the actions detected until now.
3438  * @param[out] actions_n
3439  *   pointer to the number of actions counter.
3440  * @param[in] action
3441  *   Pointer to the action structure.
3442  * @param[in] item_flags
3443  *   Holds the items detected.
3444  * @param[out] error
3445  *   Pointer to error structure.
3446  *
3447  * @return
3448  *   0 on success, a negative errno value otherwise and rte_errno is set.
3449  */
3450 static int
3451 flow_dv_validate_action_raw_encap_decap
3452         (struct rte_eth_dev *dev,
3453          const struct rte_flow_action_raw_decap *decap,
3454          const struct rte_flow_action_raw_encap *encap,
3455          const struct rte_flow_attr *attr, uint64_t *action_flags,
3456          int *actions_n, const struct rte_flow_action *action,
3457          uint64_t item_flags, struct rte_flow_error *error)
3458 {
3459         const struct mlx5_priv *priv = dev->data->dev_private;
3460         int ret;
3461
3462         if (encap && (!encap->size || !encap->data))
3463                 return rte_flow_error_set(error, EINVAL,
3464                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3465                                           "raw encap data cannot be empty");
3466         if (decap && encap) {
3467                 if (decap->size <= MLX5_ENCAPSULATION_DECISION_SIZE &&
3468                     encap->size > MLX5_ENCAPSULATION_DECISION_SIZE)
3469                         /* L3 encap. */
3470                         decap = NULL;
3471                 else if (encap->size <=
3472                            MLX5_ENCAPSULATION_DECISION_SIZE &&
3473                            decap->size >
3474                            MLX5_ENCAPSULATION_DECISION_SIZE)
3475                         /* L3 decap. */
3476                         encap = NULL;
3477                 else if (encap->size >
3478                            MLX5_ENCAPSULATION_DECISION_SIZE &&
3479                            decap->size >
3480                            MLX5_ENCAPSULATION_DECISION_SIZE)
3481                         /* 2 L2 actions: encap and decap. */
3482                         ;
3483                 else
3484                         return rte_flow_error_set(error,
3485                                 ENOTSUP,
3486                                 RTE_FLOW_ERROR_TYPE_ACTION,
3487                                 NULL, "unsupported too small "
3488                                 "raw decap and too small raw "
3489                                 "encap combination");
3490         }
3491         if (decap) {
3492                 ret = flow_dv_validate_action_decap(dev, *action_flags, action,
3493                                                     item_flags, attr, error);
3494                 if (ret < 0)
3495                         return ret;
3496                 *action_flags |= MLX5_FLOW_ACTION_DECAP;
3497                 ++(*actions_n);
3498         }
3499         if (encap) {
3500                 if (encap->size <= MLX5_ENCAPSULATION_DECISION_SIZE)
3501                         return rte_flow_error_set(error, ENOTSUP,
3502                                                   RTE_FLOW_ERROR_TYPE_ACTION,
3503                                                   NULL,
3504                                                   "small raw encap size");
3505                 if (*action_flags & MLX5_FLOW_ACTION_ENCAP)
3506                         return rte_flow_error_set(error, EINVAL,
3507                                                   RTE_FLOW_ERROR_TYPE_ACTION,
3508                                                   NULL,
3509                                                   "more than one encap action");
3510                 if (!attr->transfer && priv->representor)
3511                         return rte_flow_error_set
3512                                         (error, ENOTSUP,
3513                                          RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3514                                          "encap action for VF representor "
3515                                          "not supported on NIC table");
3516                 *action_flags |= MLX5_FLOW_ACTION_ENCAP;
3517                 ++(*actions_n);
3518         }
3519         return 0;
3520 }
3521
3522 /*
3523  * Validate the ASO CT action.
3524  *
3525  * @param[in] dev
3526  *   Pointer to the rte_eth_dev structure.
3527  * @param[in] action_flags
3528  *   Holds the actions detected until now.
3529  * @param[in] item_flags
3530  *   The items found in this flow rule.
3531  * @param[in] attr
3532  *   Pointer to flow attributes.
3533  * @param[out] error
3534  *   Pointer to error structure.
3535  *
3536  * @return
3537  *   0 on success, a negative errno value otherwise and rte_errno is set.
3538  */
3539 static int
3540 flow_dv_validate_action_aso_ct(struct rte_eth_dev *dev,
3541                                uint64_t action_flags,
3542                                uint64_t item_flags,
3543                                const struct rte_flow_attr *attr,
3544                                struct rte_flow_error *error)
3545 {
3546         RTE_SET_USED(dev);
3547
3548         if (attr->group == 0 && !attr->transfer)
3549                 return rte_flow_error_set(error, ENOTSUP,
3550                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
3551                                           NULL,
3552                                           "Only support non-root table");
3553         if (action_flags & MLX5_FLOW_FATE_ACTIONS)
3554                 return rte_flow_error_set(error, ENOTSUP,
3555                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3556                                           "CT cannot follow a fate action");
3557         if ((action_flags & MLX5_FLOW_ACTION_METER) ||
3558             (action_flags & MLX5_FLOW_ACTION_AGE))
3559                 return rte_flow_error_set(error, EINVAL,
3560                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3561                                           "Only one ASO action is supported");
3562         if (action_flags & MLX5_FLOW_ACTION_ENCAP)
3563                 return rte_flow_error_set(error, EINVAL,
3564                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3565                                           "Encap cannot exist before CT");
3566         if (!(item_flags & MLX5_FLOW_LAYER_OUTER_L4_TCP))
3567                 return rte_flow_error_set(error, EINVAL,
3568                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3569                                           "Not a outer TCP packet");
3570         return 0;
3571 }
3572
3573 int
3574 flow_dv_encap_decap_match_cb(void *tool_ctx __rte_unused,
3575                              struct mlx5_list_entry *entry, void *cb_ctx)
3576 {
3577         struct mlx5_flow_cb_ctx *ctx = cb_ctx;
3578         struct mlx5_flow_dv_encap_decap_resource *ctx_resource = ctx->data;
3579         struct mlx5_flow_dv_encap_decap_resource *resource;
3580
3581         resource = container_of(entry, struct mlx5_flow_dv_encap_decap_resource,
3582                                 entry);
3583         if (resource->reformat_type == ctx_resource->reformat_type &&
3584             resource->ft_type == ctx_resource->ft_type &&
3585             resource->flags == ctx_resource->flags &&
3586             resource->size == ctx_resource->size &&
3587             !memcmp((const void *)resource->buf,
3588                     (const void *)ctx_resource->buf,
3589                     resource->size))
3590                 return 0;
3591         return -1;
3592 }
3593
3594 struct mlx5_list_entry *
3595 flow_dv_encap_decap_create_cb(void *tool_ctx, void *cb_ctx)
3596 {
3597         struct mlx5_dev_ctx_shared *sh = tool_ctx;
3598         struct mlx5_flow_cb_ctx *ctx = cb_ctx;
3599         struct mlx5dv_dr_domain *domain;
3600         struct mlx5_flow_dv_encap_decap_resource *ctx_resource = ctx->data;
3601         struct mlx5_flow_dv_encap_decap_resource *resource;
3602         uint32_t idx;
3603         int ret;
3604
3605         if (ctx_resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB)
3606                 domain = sh->fdb_domain;
3607         else if (ctx_resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_NIC_RX)
3608                 domain = sh->rx_domain;
3609         else
3610                 domain = sh->tx_domain;
3611         /* Register new encap/decap resource. */
3612         resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_DECAP_ENCAP], &idx);
3613         if (!resource) {
3614                 rte_flow_error_set(ctx->error, ENOMEM,
3615                                    RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3616                                    "cannot allocate resource memory");
3617                 return NULL;
3618         }
3619         *resource = *ctx_resource;
3620         resource->idx = idx;
3621         ret = mlx5_flow_os_create_flow_action_packet_reformat(sh->cdev->ctx,
3622                                                               domain, resource,
3623                                                              &resource->action);
3624         if (ret) {
3625                 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_DECAP_ENCAP], idx);
3626                 rte_flow_error_set(ctx->error, ENOMEM,
3627                                    RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
3628                                    NULL, "cannot create action");
3629                 return NULL;
3630         }
3631
3632         return &resource->entry;
3633 }
3634
3635 struct mlx5_list_entry *
3636 flow_dv_encap_decap_clone_cb(void *tool_ctx, struct mlx5_list_entry *oentry,
3637                              void *cb_ctx)
3638 {
3639         struct mlx5_dev_ctx_shared *sh = tool_ctx;
3640         struct mlx5_flow_cb_ctx *ctx = cb_ctx;
3641         struct mlx5_flow_dv_encap_decap_resource *cache_resource;
3642         uint32_t idx;
3643
3644         cache_resource = mlx5_ipool_malloc(sh->ipool[MLX5_IPOOL_DECAP_ENCAP],
3645                                            &idx);
3646         if (!cache_resource) {
3647                 rte_flow_error_set(ctx->error, ENOMEM,
3648                                    RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3649                                    "cannot allocate resource memory");
3650                 return NULL;
3651         }
3652         memcpy(cache_resource, oentry, sizeof(*cache_resource));
3653         cache_resource->idx = idx;
3654         return &cache_resource->entry;
3655 }
3656
3657 void
3658 flow_dv_encap_decap_clone_free_cb(void *tool_ctx, struct mlx5_list_entry *entry)
3659 {
3660         struct mlx5_dev_ctx_shared *sh = tool_ctx;
3661         struct mlx5_flow_dv_encap_decap_resource *res =
3662                                        container_of(entry, typeof(*res), entry);
3663
3664         mlx5_ipool_free(sh->ipool[MLX5_IPOOL_DECAP_ENCAP], res->idx);
3665 }
3666
3667 /**
3668  * Find existing encap/decap resource or create and register a new one.
3669  *
3670  * @param[in, out] dev
3671  *   Pointer to rte_eth_dev structure.
3672  * @param[in, out] resource
3673  *   Pointer to encap/decap resource.
3674  * @parm[in, out] dev_flow
3675  *   Pointer to the dev_flow.
3676  * @param[out] error
3677  *   pointer to error structure.
3678  *
3679  * @return
3680  *   0 on success otherwise -errno and errno is set.
3681  */
3682 static int
3683 flow_dv_encap_decap_resource_register
3684                         (struct rte_eth_dev *dev,
3685                          struct mlx5_flow_dv_encap_decap_resource *resource,
3686                          struct mlx5_flow *dev_flow,
3687                          struct rte_flow_error *error)
3688 {
3689         struct mlx5_priv *priv = dev->data->dev_private;
3690         struct mlx5_dev_ctx_shared *sh = priv->sh;
3691         struct mlx5_list_entry *entry;
3692         union {
3693                 struct {
3694                         uint32_t ft_type:8;
3695                         uint32_t refmt_type:8;
3696                         /*
3697                          * Header reformat actions can be shared between
3698                          * non-root tables. One bit to indicate non-root
3699                          * table or not.
3700                          */
3701                         uint32_t is_root:1;
3702                         uint32_t reserve:15;
3703                 };
3704                 uint32_t v32;
3705         } encap_decap_key = {
3706                 {
3707                         .ft_type = resource->ft_type,
3708                         .refmt_type = resource->reformat_type,
3709                         .is_root = !!dev_flow->dv.group,
3710                         .reserve = 0,
3711                 }
3712         };
3713         struct mlx5_flow_cb_ctx ctx = {
3714                 .error = error,
3715                 .data = resource,
3716         };
3717         struct mlx5_hlist *encaps_decaps;
3718         uint64_t key64;
3719
3720         encaps_decaps = flow_dv_hlist_prepare(sh, &sh->encaps_decaps,
3721                                 "encaps_decaps",
3722                                 MLX5_FLOW_ENCAP_DECAP_HTABLE_SZ,
3723                                 true, true, sh,
3724                                 flow_dv_encap_decap_create_cb,
3725                                 flow_dv_encap_decap_match_cb,
3726                                 flow_dv_encap_decap_remove_cb,
3727                                 flow_dv_encap_decap_clone_cb,
3728                                 flow_dv_encap_decap_clone_free_cb);
3729         if (unlikely(!encaps_decaps))
3730                 return -rte_errno;
3731         resource->flags = dev_flow->dv.group ? 0 : 1;
3732         key64 =  __rte_raw_cksum(&encap_decap_key.v32,
3733                                  sizeof(encap_decap_key.v32), 0);
3734         if (resource->reformat_type !=
3735             MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TUNNEL_TO_L2 &&
3736             resource->size)
3737                 key64 = __rte_raw_cksum(resource->buf, resource->size, key64);
3738         entry = mlx5_hlist_register(encaps_decaps, key64, &ctx);
3739         if (!entry)
3740                 return -rte_errno;
3741         resource = container_of(entry, typeof(*resource), entry);
3742         dev_flow->dv.encap_decap = resource;
3743         dev_flow->handle->dvh.rix_encap_decap = resource->idx;
3744         return 0;
3745 }
3746
3747 /**
3748  * Find existing table jump resource or create and register a new one.
3749  *
3750  * @param[in, out] dev
3751  *   Pointer to rte_eth_dev structure.
3752  * @param[in, out] tbl
3753  *   Pointer to flow table resource.
3754  * @parm[in, out] dev_flow
3755  *   Pointer to the dev_flow.
3756  * @param[out] error
3757  *   pointer to error structure.
3758  *
3759  * @return
3760  *   0 on success otherwise -errno and errno is set.
3761  */
3762 static int
3763 flow_dv_jump_tbl_resource_register
3764                         (struct rte_eth_dev *dev __rte_unused,
3765                          struct mlx5_flow_tbl_resource *tbl,
3766                          struct mlx5_flow *dev_flow,
3767                          struct rte_flow_error *error __rte_unused)
3768 {
3769         struct mlx5_flow_tbl_data_entry *tbl_data =
3770                 container_of(tbl, struct mlx5_flow_tbl_data_entry, tbl);
3771
3772         MLX5_ASSERT(tbl);
3773         MLX5_ASSERT(tbl_data->jump.action);
3774         dev_flow->handle->rix_jump = tbl_data->idx;
3775         dev_flow->dv.jump = &tbl_data->jump;
3776         return 0;
3777 }
3778
3779 int
3780 flow_dv_port_id_match_cb(void *tool_ctx __rte_unused,
3781                          struct mlx5_list_entry *entry, void *cb_ctx)
3782 {
3783         struct mlx5_flow_cb_ctx *ctx = cb_ctx;
3784         struct mlx5_flow_dv_port_id_action_resource *ref = ctx->data;
3785         struct mlx5_flow_dv_port_id_action_resource *res =
3786                                        container_of(entry, typeof(*res), entry);
3787
3788         return ref->port_id != res->port_id;
3789 }
3790
3791 struct mlx5_list_entry *
3792 flow_dv_port_id_create_cb(void *tool_ctx, void *cb_ctx)
3793 {
3794         struct mlx5_dev_ctx_shared *sh = tool_ctx;
3795         struct mlx5_flow_cb_ctx *ctx = cb_ctx;
3796         struct mlx5_flow_dv_port_id_action_resource *ref = ctx->data;
3797         struct mlx5_flow_dv_port_id_action_resource *resource;
3798         uint32_t idx;
3799         int ret;
3800
3801         /* Register new port id action resource. */
3802         resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_PORT_ID], &idx);
3803         if (!resource) {
3804                 rte_flow_error_set(ctx->error, ENOMEM,
3805                                    RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3806                                    "cannot allocate port_id action memory");
3807                 return NULL;
3808         }
3809         *resource = *ref;
3810         ret = mlx5_flow_os_create_flow_action_dest_port(sh->fdb_domain,
3811                                                         ref->port_id,
3812                                                         &resource->action);
3813         if (ret) {
3814                 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_PORT_ID], idx);
3815                 rte_flow_error_set(ctx->error, ENOMEM,
3816                                    RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3817                                    "cannot create action");
3818                 return NULL;
3819         }
3820         resource->idx = idx;
3821         return &resource->entry;
3822 }
3823
3824 struct mlx5_list_entry *
3825 flow_dv_port_id_clone_cb(void *tool_ctx,
3826                          struct mlx5_list_entry *entry __rte_unused,
3827                          void *cb_ctx)
3828 {
3829         struct mlx5_dev_ctx_shared *sh = tool_ctx;
3830         struct mlx5_flow_cb_ctx *ctx = cb_ctx;
3831         struct mlx5_flow_dv_port_id_action_resource *resource;
3832         uint32_t idx;
3833
3834         resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_PORT_ID], &idx);
3835         if (!resource) {
3836                 rte_flow_error_set(ctx->error, ENOMEM,
3837                                    RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3838                                    "cannot allocate port_id action memory");
3839                 return NULL;
3840         }
3841         memcpy(resource, entry, sizeof(*resource));
3842         resource->idx = idx;
3843         return &resource->entry;
3844 }
3845
3846 void
3847 flow_dv_port_id_clone_free_cb(void *tool_ctx, struct mlx5_list_entry *entry)
3848 {
3849         struct mlx5_dev_ctx_shared *sh = tool_ctx;
3850         struct mlx5_flow_dv_port_id_action_resource *resource =
3851                                   container_of(entry, typeof(*resource), entry);
3852
3853         mlx5_ipool_free(sh->ipool[MLX5_IPOOL_PORT_ID], resource->idx);
3854 }
3855
3856 /**
3857  * Find existing table port ID resource or create and register a new one.
3858  *
3859  * @param[in, out] dev
3860  *   Pointer to rte_eth_dev structure.
3861  * @param[in, out] ref
3862  *   Pointer to port ID action resource reference.
3863  * @parm[in, out] dev_flow
3864  *   Pointer to the dev_flow.
3865  * @param[out] error
3866  *   pointer to error structure.
3867  *
3868  * @return
3869  *   0 on success otherwise -errno and errno is set.
3870  */
3871 static int
3872 flow_dv_port_id_action_resource_register
3873                         (struct rte_eth_dev *dev,
3874                          struct mlx5_flow_dv_port_id_action_resource *ref,
3875                          struct mlx5_flow *dev_flow,
3876                          struct rte_flow_error *error)
3877 {
3878         struct mlx5_priv *priv = dev->data->dev_private;
3879         struct mlx5_list_entry *entry;
3880         struct mlx5_flow_dv_port_id_action_resource *resource;
3881         struct mlx5_flow_cb_ctx ctx = {
3882                 .error = error,
3883                 .data = ref,
3884         };
3885
3886         entry = mlx5_list_register(priv->sh->port_id_action_list, &ctx);
3887         if (!entry)
3888                 return -rte_errno;
3889         resource = container_of(entry, typeof(*resource), entry);
3890         dev_flow->dv.port_id_action = resource;
3891         dev_flow->handle->rix_port_id_action = resource->idx;
3892         return 0;
3893 }
3894
3895 int
3896 flow_dv_push_vlan_match_cb(void *tool_ctx __rte_unused,
3897                            struct mlx5_list_entry *entry, void *cb_ctx)
3898 {
3899         struct mlx5_flow_cb_ctx *ctx = cb_ctx;
3900         struct mlx5_flow_dv_push_vlan_action_resource *ref = ctx->data;
3901         struct mlx5_flow_dv_push_vlan_action_resource *res =
3902                                        container_of(entry, typeof(*res), entry);
3903
3904         return ref->vlan_tag != res->vlan_tag || ref->ft_type != res->ft_type;
3905 }
3906
3907 struct mlx5_list_entry *
3908 flow_dv_push_vlan_create_cb(void *tool_ctx, void *cb_ctx)
3909 {
3910         struct mlx5_dev_ctx_shared *sh = tool_ctx;
3911         struct mlx5_flow_cb_ctx *ctx = cb_ctx;
3912         struct mlx5_flow_dv_push_vlan_action_resource *ref = ctx->data;
3913         struct mlx5_flow_dv_push_vlan_action_resource *resource;
3914         struct mlx5dv_dr_domain *domain;
3915         uint32_t idx;
3916         int ret;
3917
3918         /* Register new port id action resource. */
3919         resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_PUSH_VLAN], &idx);
3920         if (!resource) {
3921                 rte_flow_error_set(ctx->error, ENOMEM,
3922                                    RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3923                                    "cannot allocate push_vlan action memory");
3924                 return NULL;
3925         }
3926         *resource = *ref;
3927         if (ref->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB)
3928                 domain = sh->fdb_domain;
3929         else if (ref->ft_type == MLX5DV_FLOW_TABLE_TYPE_NIC_RX)
3930                 domain = sh->rx_domain;
3931         else
3932                 domain = sh->tx_domain;
3933         ret = mlx5_flow_os_create_flow_action_push_vlan(domain, ref->vlan_tag,
3934                                                         &resource->action);
3935         if (ret) {
3936                 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_PUSH_VLAN], idx);
3937                 rte_flow_error_set(ctx->error, ENOMEM,
3938                                    RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3939                                    "cannot create push vlan action");
3940                 return NULL;
3941         }
3942         resource->idx = idx;
3943         return &resource->entry;
3944 }
3945
3946 struct mlx5_list_entry *
3947 flow_dv_push_vlan_clone_cb(void *tool_ctx,
3948                            struct mlx5_list_entry *entry __rte_unused,
3949                            void *cb_ctx)
3950 {
3951         struct mlx5_dev_ctx_shared *sh = tool_ctx;
3952         struct mlx5_flow_cb_ctx *ctx = cb_ctx;
3953         struct mlx5_flow_dv_push_vlan_action_resource *resource;
3954         uint32_t idx;
3955
3956         resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_PUSH_VLAN], &idx);
3957         if (!resource) {
3958                 rte_flow_error_set(ctx->error, ENOMEM,
3959                                    RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3960                                    "cannot allocate push_vlan action memory");
3961                 return NULL;
3962         }
3963         memcpy(resource, entry, sizeof(*resource));
3964         resource->idx = idx;
3965         return &resource->entry;
3966 }
3967
3968 void
3969 flow_dv_push_vlan_clone_free_cb(void *tool_ctx, struct mlx5_list_entry *entry)
3970 {
3971         struct mlx5_dev_ctx_shared *sh = tool_ctx;
3972         struct mlx5_flow_dv_push_vlan_action_resource *resource =
3973                                   container_of(entry, typeof(*resource), entry);
3974
3975         mlx5_ipool_free(sh->ipool[MLX5_IPOOL_PUSH_VLAN], resource->idx);
3976 }
3977
3978 /**
3979  * Find existing push vlan resource or create and register a new one.
3980  *
3981  * @param [in, out] dev
3982  *   Pointer to rte_eth_dev structure.
3983  * @param[in, out] ref
3984  *   Pointer to port ID action resource reference.
3985  * @parm[in, out] dev_flow
3986  *   Pointer to the dev_flow.
3987  * @param[out] error
3988  *   pointer to error structure.
3989  *
3990  * @return
3991  *   0 on success otherwise -errno and errno is set.
3992  */
3993 static int
3994 flow_dv_push_vlan_action_resource_register
3995                        (struct rte_eth_dev *dev,
3996                         struct mlx5_flow_dv_push_vlan_action_resource *ref,
3997                         struct mlx5_flow *dev_flow,
3998                         struct rte_flow_error *error)
3999 {
4000         struct mlx5_priv *priv = dev->data->dev_private;
4001         struct mlx5_flow_dv_push_vlan_action_resource *resource;
4002         struct mlx5_list_entry *entry;
4003         struct mlx5_flow_cb_ctx ctx = {
4004                 .error = error,
4005                 .data = ref,
4006         };
4007
4008         entry = mlx5_list_register(priv->sh->push_vlan_action_list, &ctx);
4009         if (!entry)
4010                 return -rte_errno;
4011         resource = container_of(entry, typeof(*resource), entry);
4012
4013         dev_flow->handle->dvh.rix_push_vlan = resource->idx;
4014         dev_flow->dv.push_vlan_res = resource;
4015         return 0;
4016 }
4017
4018 /**
4019  * Get the size of specific rte_flow_item_type hdr size
4020  *
4021  * @param[in] item_type
4022  *   Tested rte_flow_item_type.
4023  *
4024  * @return
4025  *   sizeof struct item_type, 0 if void or irrelevant.
4026  */
4027 static size_t
4028 flow_dv_get_item_hdr_len(const enum rte_flow_item_type item_type)
4029 {
4030         size_t retval;
4031
4032         switch (item_type) {
4033         case RTE_FLOW_ITEM_TYPE_ETH:
4034                 retval = sizeof(struct rte_ether_hdr);
4035                 break;
4036         case RTE_FLOW_ITEM_TYPE_VLAN:
4037                 retval = sizeof(struct rte_vlan_hdr);
4038                 break;
4039         case RTE_FLOW_ITEM_TYPE_IPV4:
4040                 retval = sizeof(struct rte_ipv4_hdr);
4041                 break;
4042         case RTE_FLOW_ITEM_TYPE_IPV6:
4043                 retval = sizeof(struct rte_ipv6_hdr);
4044                 break;
4045         case RTE_FLOW_ITEM_TYPE_UDP:
4046                 retval = sizeof(struct rte_udp_hdr);
4047                 break;
4048         case RTE_FLOW_ITEM_TYPE_TCP:
4049                 retval = sizeof(struct rte_tcp_hdr);
4050                 break;
4051         case RTE_FLOW_ITEM_TYPE_VXLAN:
4052         case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
4053                 retval = sizeof(struct rte_vxlan_hdr);
4054                 break;
4055         case RTE_FLOW_ITEM_TYPE_GRE:
4056         case RTE_FLOW_ITEM_TYPE_NVGRE:
4057                 retval = sizeof(struct rte_gre_hdr);
4058                 break;
4059         case RTE_FLOW_ITEM_TYPE_MPLS:
4060                 retval = sizeof(struct rte_mpls_hdr);
4061                 break;
4062         case RTE_FLOW_ITEM_TYPE_VOID: /* Fall through. */
4063         default:
4064                 retval = 0;
4065                 break;
4066         }
4067         return retval;
4068 }
4069
4070 #define MLX5_ENCAP_IPV4_VERSION         0x40
4071 #define MLX5_ENCAP_IPV4_IHL_MIN         0x05
4072 #define MLX5_ENCAP_IPV4_TTL_DEF         0x40
4073 #define MLX5_ENCAP_IPV6_VTC_FLOW        0x60000000
4074 #define MLX5_ENCAP_IPV6_HOP_LIMIT       0xff
4075 #define MLX5_ENCAP_VXLAN_FLAGS          0x08000000
4076 #define MLX5_ENCAP_VXLAN_GPE_FLAGS      0x04
4077
4078 /**
4079  * Convert the encap action data from list of rte_flow_item to raw buffer
4080  *
4081  * @param[in] items
4082  *   Pointer to rte_flow_item objects list.
4083  * @param[out] buf
4084  *   Pointer to the output buffer.
4085  * @param[out] size
4086  *   Pointer to the output buffer size.
4087  * @param[out] error
4088  *   Pointer to the error structure.
4089  *
4090  * @return
4091  *   0 on success, a negative errno value otherwise and rte_errno is set.
4092  */
4093 static int
4094 flow_dv_convert_encap_data(const struct rte_flow_item *items, uint8_t *buf,
4095                            size_t *size, struct rte_flow_error *error)
4096 {
4097         struct rte_ether_hdr *eth = NULL;
4098         struct rte_vlan_hdr *vlan = NULL;
4099         struct rte_ipv4_hdr *ipv4 = NULL;
4100         struct rte_ipv6_hdr *ipv6 = NULL;
4101         struct rte_udp_hdr *udp = NULL;
4102         struct rte_vxlan_hdr *vxlan = NULL;
4103         struct rte_vxlan_gpe_hdr *vxlan_gpe = NULL;
4104         struct rte_gre_hdr *gre = NULL;
4105         size_t len;
4106         size_t temp_size = 0;
4107
4108         if (!items)
4109                 return rte_flow_error_set(error, EINVAL,
4110                                           RTE_FLOW_ERROR_TYPE_ACTION,
4111                                           NULL, "invalid empty data");
4112         for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
4113                 len = flow_dv_get_item_hdr_len(items->type);
4114                 if (len + temp_size > MLX5_ENCAP_MAX_LEN)
4115                         return rte_flow_error_set(error, EINVAL,
4116                                                   RTE_FLOW_ERROR_TYPE_ACTION,
4117                                                   (void *)items->type,
4118                                                   "items total size is too big"
4119                                                   " for encap action");
4120                 rte_memcpy((void *)&buf[temp_size], items->spec, len);
4121                 switch (items->type) {
4122                 case RTE_FLOW_ITEM_TYPE_ETH:
4123                         eth = (struct rte_ether_hdr *)&buf[temp_size];
4124                         break;
4125                 case RTE_FLOW_ITEM_TYPE_VLAN:
4126                         vlan = (struct rte_vlan_hdr *)&buf[temp_size];
4127                         if (!eth)
4128                                 return rte_flow_error_set(error, EINVAL,
4129                                                 RTE_FLOW_ERROR_TYPE_ACTION,
4130                                                 (void *)items->type,
4131                                                 "eth header not found");
4132                         if (!eth->ether_type)
4133                                 eth->ether_type = RTE_BE16(RTE_ETHER_TYPE_VLAN);
4134                         break;
4135                 case RTE_FLOW_ITEM_TYPE_IPV4:
4136                         ipv4 = (struct rte_ipv4_hdr *)&buf[temp_size];
4137                         if (!vlan && !eth)
4138                                 return rte_flow_error_set(error, EINVAL,
4139                                                 RTE_FLOW_ERROR_TYPE_ACTION,
4140                                                 (void *)items->type,
4141                                                 "neither eth nor vlan"
4142                                                 " header found");
4143                         if (vlan && !vlan->eth_proto)
4144                                 vlan->eth_proto = RTE_BE16(RTE_ETHER_TYPE_IPV4);
4145                         else if (eth && !eth->ether_type)
4146                                 eth->ether_type = RTE_BE16(RTE_ETHER_TYPE_IPV4);
4147                         if (!ipv4->version_ihl)
4148                                 ipv4->version_ihl = MLX5_ENCAP_IPV4_VERSION |
4149                                                     MLX5_ENCAP_IPV4_IHL_MIN;
4150                         if (!ipv4->time_to_live)
4151                                 ipv4->time_to_live = MLX5_ENCAP_IPV4_TTL_DEF;
4152                         break;
4153                 case RTE_FLOW_ITEM_TYPE_IPV6:
4154                         ipv6 = (struct rte_ipv6_hdr *)&buf[temp_size];
4155                         if (!vlan && !eth)
4156                                 return rte_flow_error_set(error, EINVAL,
4157                                                 RTE_FLOW_ERROR_TYPE_ACTION,
4158                                                 (void *)items->type,
4159                                                 "neither eth nor vlan"
4160                                                 " header found");
4161                         if (vlan && !vlan->eth_proto)
4162                                 vlan->eth_proto = RTE_BE16(RTE_ETHER_TYPE_IPV6);
4163                         else if (eth && !eth->ether_type)
4164                                 eth->ether_type = RTE_BE16(RTE_ETHER_TYPE_IPV6);
4165                         if (!ipv6->vtc_flow)
4166                                 ipv6->vtc_flow =
4167                                         RTE_BE32(MLX5_ENCAP_IPV6_VTC_FLOW);
4168                         if (!ipv6->hop_limits)
4169                                 ipv6->hop_limits = MLX5_ENCAP_IPV6_HOP_LIMIT;
4170                         break;
4171                 case RTE_FLOW_ITEM_TYPE_UDP:
4172                         udp = (struct rte_udp_hdr *)&buf[temp_size];
4173                         if (!ipv4 && !ipv6)
4174                                 return rte_flow_error_set(error, EINVAL,
4175                                                 RTE_FLOW_ERROR_TYPE_ACTION,
4176                                                 (void *)items->type,
4177                                                 "ip header not found");
4178                         if (ipv4 && !ipv4->next_proto_id)
4179                                 ipv4->next_proto_id = IPPROTO_UDP;
4180                         else if (ipv6 && !ipv6->proto)
4181                                 ipv6->proto = IPPROTO_UDP;
4182                         break;
4183                 case RTE_FLOW_ITEM_TYPE_VXLAN:
4184                         vxlan = (struct rte_vxlan_hdr *)&buf[temp_size];
4185                         if (!udp)
4186                                 return rte_flow_error_set(error, EINVAL,
4187                                                 RTE_FLOW_ERROR_TYPE_ACTION,
4188                                                 (void *)items->type,
4189                                                 "udp header not found");
4190                         if (!udp->dst_port)
4191                                 udp->dst_port = RTE_BE16(MLX5_UDP_PORT_VXLAN);
4192                         if (!vxlan->vx_flags)
4193                                 vxlan->vx_flags =
4194                                         RTE_BE32(MLX5_ENCAP_VXLAN_FLAGS);
4195                         break;
4196                 case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
4197                         vxlan_gpe = (struct rte_vxlan_gpe_hdr *)&buf[temp_size];
4198                         if (!udp)
4199                                 return rte_flow_error_set(error, EINVAL,
4200                                                 RTE_FLOW_ERROR_TYPE_ACTION,
4201                                                 (void *)items->type,
4202                                                 "udp header not found");
4203                         if (!vxlan_gpe->proto)
4204                                 return rte_flow_error_set(error, EINVAL,
4205                                                 RTE_FLOW_ERROR_TYPE_ACTION,
4206                                                 (void *)items->type,
4207                                                 "next protocol not found");
4208                         if (!udp->dst_port)
4209                                 udp->dst_port =
4210                                         RTE_BE16(MLX5_UDP_PORT_VXLAN_GPE);
4211                         if (!vxlan_gpe->vx_flags)
4212                                 vxlan_gpe->vx_flags =
4213                                                 MLX5_ENCAP_VXLAN_GPE_FLAGS;
4214                         break;
4215                 case RTE_FLOW_ITEM_TYPE_GRE:
4216                 case RTE_FLOW_ITEM_TYPE_NVGRE:
4217                         gre = (struct rte_gre_hdr *)&buf[temp_size];
4218                         if (!gre->proto)
4219                                 return rte_flow_error_set(error, EINVAL,
4220                                                 RTE_FLOW_ERROR_TYPE_ACTION,
4221                                                 (void *)items->type,
4222                                                 "next protocol not found");
4223                         if (!ipv4 && !ipv6)
4224                                 return rte_flow_error_set(error, EINVAL,
4225                                                 RTE_FLOW_ERROR_TYPE_ACTION,
4226                                                 (void *)items->type,
4227                                                 "ip header not found");
4228                         if (ipv4 && !ipv4->next_proto_id)
4229                                 ipv4->next_proto_id = IPPROTO_GRE;
4230                         else if (ipv6 && !ipv6->proto)
4231                                 ipv6->proto = IPPROTO_GRE;
4232                         break;
4233                 case RTE_FLOW_ITEM_TYPE_VOID:
4234                         break;
4235                 default:
4236                         return rte_flow_error_set(error, EINVAL,
4237                                                   RTE_FLOW_ERROR_TYPE_ACTION,
4238                                                   (void *)items->type,
4239                                                   "unsupported item type");
4240                         break;
4241                 }
4242                 temp_size += len;
4243         }
4244         *size = temp_size;
4245         return 0;
4246 }
4247
4248 static int
4249 flow_dv_zero_encap_udp_csum(void *data, struct rte_flow_error *error)
4250 {
4251         struct rte_ether_hdr *eth = NULL;
4252         struct rte_vlan_hdr *vlan = NULL;
4253         struct rte_ipv6_hdr *ipv6 = NULL;
4254         struct rte_udp_hdr *udp = NULL;
4255         char *next_hdr;
4256         uint16_t proto;
4257
4258         eth = (struct rte_ether_hdr *)data;
4259         next_hdr = (char *)(eth + 1);
4260         proto = RTE_BE16(eth->ether_type);
4261
4262         /* VLAN skipping */
4263         while (proto == RTE_ETHER_TYPE_VLAN || proto == RTE_ETHER_TYPE_QINQ) {
4264                 vlan = (struct rte_vlan_hdr *)next_hdr;
4265                 proto = RTE_BE16(vlan->eth_proto);
4266                 next_hdr += sizeof(struct rte_vlan_hdr);
4267         }
4268
4269         /* HW calculates IPv4 csum. no need to proceed */
4270         if (proto == RTE_ETHER_TYPE_IPV4)
4271                 return 0;
4272
4273         /* non IPv4/IPv6 header. not supported */
4274         if (proto != RTE_ETHER_TYPE_IPV6) {
4275                 return rte_flow_error_set(error, ENOTSUP,
4276                                           RTE_FLOW_ERROR_TYPE_ACTION,
4277                                           NULL, "Cannot offload non IPv4/IPv6");
4278         }
4279
4280         ipv6 = (struct rte_ipv6_hdr *)next_hdr;
4281
4282         /* ignore non UDP */
4283         if (ipv6->proto != IPPROTO_UDP)
4284                 return 0;
4285
4286         udp = (struct rte_udp_hdr *)(ipv6 + 1);
4287         udp->dgram_cksum = 0;
4288
4289         return 0;
4290 }
4291
4292 /**
4293  * Convert L2 encap action to DV specification.
4294  *
4295  * @param[in] dev
4296  *   Pointer to rte_eth_dev structure.
4297  * @param[in] action
4298  *   Pointer to action structure.
4299  * @param[in, out] dev_flow
4300  *   Pointer to the mlx5_flow.
4301  * @param[in] transfer
4302  *   Mark if the flow is E-Switch flow.
4303  * @param[out] error
4304  *   Pointer to the error structure.
4305  *
4306  * @return
4307  *   0 on success, a negative errno value otherwise and rte_errno is set.
4308  */
4309 static int
4310 flow_dv_create_action_l2_encap(struct rte_eth_dev *dev,
4311                                const struct rte_flow_action *action,
4312                                struct mlx5_flow *dev_flow,
4313                                uint8_t transfer,
4314                                struct rte_flow_error *error)
4315 {
4316         const struct rte_flow_item *encap_data;
4317         const struct rte_flow_action_raw_encap *raw_encap_data;
4318         struct mlx5_flow_dv_encap_decap_resource res = {
4319                 .reformat_type =
4320                         MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L2_TUNNEL,
4321                 .ft_type = transfer ? MLX5DV_FLOW_TABLE_TYPE_FDB :
4322                                       MLX5DV_FLOW_TABLE_TYPE_NIC_TX,
4323         };
4324
4325         if (action->type == RTE_FLOW_ACTION_TYPE_RAW_ENCAP) {
4326                 raw_encap_data =
4327                         (const struct rte_flow_action_raw_encap *)action->conf;
4328                 res.size = raw_encap_data->size;
4329                 memcpy(res.buf, raw_encap_data->data, res.size);
4330         } else {
4331                 if (action->type == RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP)
4332                         encap_data =
4333                                 ((const struct rte_flow_action_vxlan_encap *)
4334                                                 action->conf)->definition;
4335                 else
4336                         encap_data =
4337                                 ((const struct rte_flow_action_nvgre_encap *)
4338                                                 action->conf)->definition;
4339                 if (flow_dv_convert_encap_data(encap_data, res.buf,
4340                                                &res.size, error))
4341                         return -rte_errno;
4342         }
4343         if (flow_dv_zero_encap_udp_csum(res.buf, error))
4344                 return -rte_errno;
4345         if (flow_dv_encap_decap_resource_register(dev, &res, dev_flow, error))
4346                 return rte_flow_error_set(error, EINVAL,
4347                                           RTE_FLOW_ERROR_TYPE_ACTION,
4348                                           NULL, "can't create L2 encap action");
4349         return 0;
4350 }
4351
4352 /**
4353  * Convert L2 decap action to DV specification.
4354  *
4355  * @param[in] dev
4356  *   Pointer to rte_eth_dev structure.
4357  * @param[in, out] dev_flow
4358  *   Pointer to the mlx5_flow.
4359  * @param[in] transfer
4360  *   Mark if the flow is E-Switch flow.
4361  * @param[out] error
4362  *   Pointer to the error structure.
4363  *
4364  * @return
4365  *   0 on success, a negative errno value otherwise and rte_errno is set.
4366  */
4367 static int
4368 flow_dv_create_action_l2_decap(struct rte_eth_dev *dev,
4369                                struct mlx5_flow *dev_flow,
4370                                uint8_t transfer,
4371                                struct rte_flow_error *error)
4372 {
4373         struct mlx5_flow_dv_encap_decap_resource res = {
4374                 .size = 0,
4375                 .reformat_type =
4376                         MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TUNNEL_TO_L2,
4377                 .ft_type = transfer ? MLX5DV_FLOW_TABLE_TYPE_FDB :
4378                                       MLX5DV_FLOW_TABLE_TYPE_NIC_RX,
4379         };
4380
4381         if (flow_dv_encap_decap_resource_register(dev, &res, dev_flow, error))
4382                 return rte_flow_error_set(error, EINVAL,
4383                                           RTE_FLOW_ERROR_TYPE_ACTION,
4384                                           NULL, "can't create L2 decap action");
4385         return 0;
4386 }
4387
4388 /**
4389  * Convert raw decap/encap (L3 tunnel) action to DV specification.
4390  *
4391  * @param[in] dev
4392  *   Pointer to rte_eth_dev structure.
4393  * @param[in] action
4394  *   Pointer to action structure.
4395  * @param[in, out] dev_flow
4396  *   Pointer to the mlx5_flow.
4397  * @param[in] attr
4398  *   Pointer to the flow attributes.
4399  * @param[out] error
4400  *   Pointer to the error structure.
4401  *
4402  * @return
4403  *   0 on success, a negative errno value otherwise and rte_errno is set.
4404  */
4405 static int
4406 flow_dv_create_action_raw_encap(struct rte_eth_dev *dev,
4407                                 const struct rte_flow_action *action,
4408                                 struct mlx5_flow *dev_flow,
4409                                 const struct rte_flow_attr *attr,
4410                                 struct rte_flow_error *error)
4411 {
4412         const struct rte_flow_action_raw_encap *encap_data;
4413         struct mlx5_flow_dv_encap_decap_resource res;
4414
4415         memset(&res, 0, sizeof(res));
4416         encap_data = (const struct rte_flow_action_raw_encap *)action->conf;
4417         res.size = encap_data->size;
4418         memcpy(res.buf, encap_data->data, res.size);
4419         res.reformat_type = res.size < MLX5_ENCAPSULATION_DECISION_SIZE ?
4420                 MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L3_TUNNEL_TO_L2 :
4421                 MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L3_TUNNEL;
4422         if (attr->transfer)
4423                 res.ft_type = MLX5DV_FLOW_TABLE_TYPE_FDB;
4424         else
4425                 res.ft_type = attr->egress ? MLX5DV_FLOW_TABLE_TYPE_NIC_TX :
4426                                              MLX5DV_FLOW_TABLE_TYPE_NIC_RX;
4427         if (flow_dv_encap_decap_resource_register(dev, &res, dev_flow, error))
4428                 return rte_flow_error_set(error, EINVAL,
4429                                           RTE_FLOW_ERROR_TYPE_ACTION,
4430                                           NULL, "can't create encap action");
4431         return 0;
4432 }
4433
4434 /**
4435  * Create action push VLAN.
4436  *
4437  * @param[in] dev
4438  *   Pointer to rte_eth_dev structure.
4439  * @param[in] attr
4440  *   Pointer to the flow attributes.
4441  * @param[in] vlan
4442  *   Pointer to the vlan to push to the Ethernet header.
4443  * @param[in, out] dev_flow
4444  *   Pointer to the mlx5_flow.
4445  * @param[out] error
4446  *   Pointer to the error structure.
4447  *
4448  * @return
4449  *   0 on success, a negative errno value otherwise and rte_errno is set.
4450  */
4451 static int
4452 flow_dv_create_action_push_vlan(struct rte_eth_dev *dev,
4453                                 const struct rte_flow_attr *attr,
4454                                 const struct rte_vlan_hdr *vlan,
4455                                 struct mlx5_flow *dev_flow,
4456                                 struct rte_flow_error *error)
4457 {
4458         struct mlx5_flow_dv_push_vlan_action_resource res;
4459
4460         memset(&res, 0, sizeof(res));
4461         res.vlan_tag =
4462                 rte_cpu_to_be_32(((uint32_t)vlan->eth_proto) << 16 |
4463                                  vlan->vlan_tci);
4464         if (attr->transfer)
4465                 res.ft_type = MLX5DV_FLOW_TABLE_TYPE_FDB;
4466         else
4467                 res.ft_type = attr->egress ? MLX5DV_FLOW_TABLE_TYPE_NIC_TX :
4468                                              MLX5DV_FLOW_TABLE_TYPE_NIC_RX;
4469         return flow_dv_push_vlan_action_resource_register
4470                                             (dev, &res, dev_flow, error);
4471 }
4472
4473 /**
4474  * Validate the modify-header actions.
4475  *
4476  * @param[in] action_flags
4477  *   Holds the actions detected until now.
4478  * @param[in] action
4479  *   Pointer to the modify action.
4480  * @param[out] error
4481  *   Pointer to error structure.
4482  *
4483  * @return
4484  *   0 on success, a negative errno value otherwise and rte_errno is set.
4485  */
4486 static int
4487 flow_dv_validate_action_modify_hdr(const uint64_t action_flags,
4488                                    const struct rte_flow_action *action,
4489                                    struct rte_flow_error *error)
4490 {
4491         if (action->type != RTE_FLOW_ACTION_TYPE_DEC_TTL && !action->conf)
4492                 return rte_flow_error_set(error, EINVAL,
4493                                           RTE_FLOW_ERROR_TYPE_ACTION_CONF,
4494                                           NULL, "action configuration not set");
4495         if (action_flags & MLX5_FLOW_ACTION_ENCAP)
4496                 return rte_flow_error_set(error, EINVAL,
4497                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
4498                                           "can't have encap action before"
4499                                           " modify action");
4500         return 0;
4501 }
4502
4503 /**
4504  * Validate the modify-header MAC address actions.
4505  *
4506  * @param[in] action_flags
4507  *   Holds the actions detected until now.
4508  * @param[in] action
4509  *   Pointer to the modify action.
4510  * @param[in] item_flags
4511  *   Holds the items detected.
4512  * @param[out] error
4513  *   Pointer to error structure.
4514  *
4515  * @return
4516  *   0 on success, a negative errno value otherwise and rte_errno is set.
4517  */
4518 static int
4519 flow_dv_validate_action_modify_mac(const uint64_t action_flags,
4520                                    const struct rte_flow_action *action,
4521                                    const uint64_t item_flags,
4522                                    struct rte_flow_error *error)
4523 {
4524         int ret = 0;
4525
4526         ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
4527         if (!ret) {
4528                 if (!(item_flags & MLX5_FLOW_LAYER_L2))
4529                         return rte_flow_error_set(error, EINVAL,
4530                                                   RTE_FLOW_ERROR_TYPE_ACTION,
4531                                                   NULL,
4532                                                   "no L2 item in pattern");
4533         }
4534         return ret;
4535 }
4536
4537 /**
4538  * Validate the modify-header IPv4 address actions.
4539  *
4540  * @param[in] action_flags
4541  *   Holds the actions detected until now.
4542  * @param[in] action
4543  *   Pointer to the modify action.
4544  * @param[in] item_flags
4545  *   Holds the items detected.
4546  * @param[out] error
4547  *   Pointer to error structure.
4548  *
4549  * @return
4550  *   0 on success, a negative errno value otherwise and rte_errno is set.
4551  */
4552 static int
4553 flow_dv_validate_action_modify_ipv4(const uint64_t action_flags,
4554                                     const struct rte_flow_action *action,
4555                                     const uint64_t item_flags,
4556                                     struct rte_flow_error *error)
4557 {
4558         int ret = 0;
4559         uint64_t layer;
4560
4561         ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
4562         if (!ret) {
4563                 layer = (action_flags & MLX5_FLOW_ACTION_DECAP) ?
4564                                  MLX5_FLOW_LAYER_INNER_L3_IPV4 :
4565                                  MLX5_FLOW_LAYER_OUTER_L3_IPV4;
4566                 if (!(item_flags & layer))
4567                         return rte_flow_error_set(error, EINVAL,
4568                                                   RTE_FLOW_ERROR_TYPE_ACTION,
4569                                                   NULL,
4570                                                   "no ipv4 item in pattern");
4571         }
4572         return ret;
4573 }
4574
4575 /**
4576  * Validate the modify-header IPv6 address actions.
4577  *
4578  * @param[in] action_flags
4579  *   Holds the actions detected until now.
4580  * @param[in] action
4581  *   Pointer to the modify action.
4582  * @param[in] item_flags
4583  *   Holds the items detected.
4584  * @param[out] error
4585  *   Pointer to error structure.
4586  *
4587  * @return
4588  *   0 on success, a negative errno value otherwise and rte_errno is set.
4589  */
4590 static int
4591 flow_dv_validate_action_modify_ipv6(const uint64_t action_flags,
4592                                     const struct rte_flow_action *action,
4593                                     const uint64_t item_flags,
4594                                     struct rte_flow_error *error)
4595 {
4596         int ret = 0;
4597         uint64_t layer;
4598
4599         ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
4600         if (!ret) {
4601                 layer = (action_flags & MLX5_FLOW_ACTION_DECAP) ?
4602                                  MLX5_FLOW_LAYER_INNER_L3_IPV6 :
4603                                  MLX5_FLOW_LAYER_OUTER_L3_IPV6;
4604                 if (!(item_flags & layer))
4605                         return rte_flow_error_set(error, EINVAL,
4606                                                   RTE_FLOW_ERROR_TYPE_ACTION,
4607                                                   NULL,
4608                                                   "no ipv6 item in pattern");
4609         }
4610         return ret;
4611 }
4612
4613 /**
4614  * Validate the modify-header TP actions.
4615  *
4616  * @param[in] action_flags
4617  *   Holds the actions detected until now.
4618  * @param[in] action
4619  *   Pointer to the modify action.
4620  * @param[in] item_flags
4621  *   Holds the items detected.
4622  * @param[out] error
4623  *   Pointer to error structure.
4624  *
4625  * @return
4626  *   0 on success, a negative errno value otherwise and rte_errno is set.
4627  */
4628 static int
4629 flow_dv_validate_action_modify_tp(const uint64_t action_flags,
4630                                   const struct rte_flow_action *action,
4631                                   const uint64_t item_flags,
4632                                   struct rte_flow_error *error)
4633 {
4634         int ret = 0;
4635         uint64_t layer;
4636
4637         ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
4638         if (!ret) {
4639                 layer = (action_flags & MLX5_FLOW_ACTION_DECAP) ?
4640                                  MLX5_FLOW_LAYER_INNER_L4 :
4641                                  MLX5_FLOW_LAYER_OUTER_L4;
4642                 if (!(item_flags & layer))
4643                         return rte_flow_error_set(error, EINVAL,
4644                                                   RTE_FLOW_ERROR_TYPE_ACTION,
4645                                                   NULL, "no transport layer "
4646                                                   "in pattern");
4647         }
4648         return ret;
4649 }
4650
4651 /**
4652  * Validate the modify-header actions of increment/decrement
4653  * TCP Sequence-number.
4654  *
4655  * @param[in] action_flags
4656  *   Holds the actions detected until now.
4657  * @param[in] action
4658  *   Pointer to the modify action.
4659  * @param[in] item_flags
4660  *   Holds the items detected.
4661  * @param[out] error
4662  *   Pointer to error structure.
4663  *
4664  * @return
4665  *   0 on success, a negative errno value otherwise and rte_errno is set.
4666  */
4667 static int
4668 flow_dv_validate_action_modify_tcp_seq(const uint64_t action_flags,
4669                                        const struct rte_flow_action *action,
4670                                        const uint64_t item_flags,
4671                                        struct rte_flow_error *error)
4672 {
4673         int ret = 0;
4674         uint64_t layer;
4675
4676         ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
4677         if (!ret) {
4678                 layer = (action_flags & MLX5_FLOW_ACTION_DECAP) ?
4679                                  MLX5_FLOW_LAYER_INNER_L4_TCP :
4680                                  MLX5_FLOW_LAYER_OUTER_L4_TCP;
4681                 if (!(item_flags & layer))
4682                         return rte_flow_error_set(error, EINVAL,
4683                                                   RTE_FLOW_ERROR_TYPE_ACTION,
4684                                                   NULL, "no TCP item in"
4685                                                   " pattern");
4686                 if ((action->type == RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ &&
4687                         (action_flags & MLX5_FLOW_ACTION_DEC_TCP_SEQ)) ||
4688                     (action->type == RTE_FLOW_ACTION_TYPE_DEC_TCP_SEQ &&
4689                         (action_flags & MLX5_FLOW_ACTION_INC_TCP_SEQ)))
4690                         return rte_flow_error_set(error, EINVAL,
4691                                                   RTE_FLOW_ERROR_TYPE_ACTION,
4692                                                   NULL,
4693                                                   "cannot decrease and increase"
4694                                                   " TCP sequence number"
4695                                                   " at the same time");
4696         }
4697         return ret;
4698 }
4699
4700 /**
4701  * Validate the modify-header actions of increment/decrement
4702  * TCP Acknowledgment number.
4703  *
4704  * @param[in] action_flags
4705  *   Holds the actions detected until now.
4706  * @param[in] action
4707  *   Pointer to the modify action.
4708  * @param[in] item_flags
4709  *   Holds the items detected.
4710  * @param[out] error
4711  *   Pointer to error structure.
4712  *
4713  * @return
4714  *   0 on success, a negative errno value otherwise and rte_errno is set.
4715  */
4716 static int
4717 flow_dv_validate_action_modify_tcp_ack(const uint64_t action_flags,
4718                                        const struct rte_flow_action *action,
4719                                        const uint64_t item_flags,
4720                                        struct rte_flow_error *error)
4721 {
4722         int ret = 0;
4723         uint64_t layer;
4724
4725         ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
4726         if (!ret) {
4727                 layer = (action_flags & MLX5_FLOW_ACTION_DECAP) ?
4728                                  MLX5_FLOW_LAYER_INNER_L4_TCP :
4729                                  MLX5_FLOW_LAYER_OUTER_L4_TCP;
4730                 if (!(item_flags & layer))
4731                         return rte_flow_error_set(error, EINVAL,
4732                                                   RTE_FLOW_ERROR_TYPE_ACTION,
4733                                                   NULL, "no TCP item in"
4734                                                   " pattern");
4735                 if ((action->type == RTE_FLOW_ACTION_TYPE_INC_TCP_ACK &&
4736                         (action_flags & MLX5_FLOW_ACTION_DEC_TCP_ACK)) ||
4737                     (action->type == RTE_FLOW_ACTION_TYPE_DEC_TCP_ACK &&
4738                         (action_flags & MLX5_FLOW_ACTION_INC_TCP_ACK)))
4739                         return rte_flow_error_set(error, EINVAL,
4740                                                   RTE_FLOW_ERROR_TYPE_ACTION,
4741                                                   NULL,
4742                                                   "cannot decrease and increase"
4743                                                   " TCP acknowledgment number"
4744                                                   " at the same time");
4745         }
4746         return ret;
4747 }
4748
4749 /**
4750  * Validate the modify-header TTL actions.
4751  *
4752  * @param[in] action_flags
4753  *   Holds the actions detected until now.
4754  * @param[in] action
4755  *   Pointer to the modify action.
4756  * @param[in] item_flags
4757  *   Holds the items detected.
4758  * @param[out] error
4759  *   Pointer to error structure.
4760  *
4761  * @return
4762  *   0 on success, a negative errno value otherwise and rte_errno is set.
4763  */
4764 static int
4765 flow_dv_validate_action_modify_ttl(const uint64_t action_flags,
4766                                    const struct rte_flow_action *action,
4767                                    const uint64_t item_flags,
4768                                    struct rte_flow_error *error)
4769 {
4770         int ret = 0;
4771         uint64_t layer;
4772
4773         ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
4774         if (!ret) {
4775                 layer = (action_flags & MLX5_FLOW_ACTION_DECAP) ?
4776                                  MLX5_FLOW_LAYER_INNER_L3 :
4777                                  MLX5_FLOW_LAYER_OUTER_L3;
4778                 if (!(item_flags & layer))
4779                         return rte_flow_error_set(error, EINVAL,
4780                                                   RTE_FLOW_ERROR_TYPE_ACTION,
4781                                                   NULL,
4782                                                   "no IP protocol in pattern");
4783         }
4784         return ret;
4785 }
4786
4787 /**
4788  * Validate the generic modify field actions.
4789  * @param[in] dev
4790  *   Pointer to the rte_eth_dev structure.
4791  * @param[in] action_flags
4792  *   Holds the actions detected until now.
4793  * @param[in] action
4794  *   Pointer to the modify action.
4795  * @param[in] attr
4796  *   Pointer to the flow attributes.
4797  * @param[out] error
4798  *   Pointer to error structure.
4799  *
4800  * @return
4801  *   Number of header fields to modify (0 or more) on success,
4802  *   a negative errno value otherwise and rte_errno is set.
4803  */
4804 static int
4805 flow_dv_validate_action_modify_field(struct rte_eth_dev *dev,
4806                                    const uint64_t action_flags,
4807                                    const struct rte_flow_action *action,
4808                                    const struct rte_flow_attr *attr,
4809                                    struct rte_flow_error *error)
4810 {
4811         int ret = 0;
4812         struct mlx5_priv *priv = dev->data->dev_private;
4813         struct mlx5_dev_config *config = &priv->config;
4814         const struct rte_flow_action_modify_field *action_modify_field =
4815                 action->conf;
4816         uint32_t dst_width = mlx5_flow_item_field_width(priv,
4817                                 action_modify_field->dst.field, -1);
4818         uint32_t src_width = mlx5_flow_item_field_width(priv,
4819                                 action_modify_field->src.field, dst_width);
4820
4821         ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
4822         if (ret)
4823                 return ret;
4824
4825         if (action_modify_field->width == 0)
4826                 return rte_flow_error_set(error, EINVAL,
4827                                 RTE_FLOW_ERROR_TYPE_ACTION, action,
4828                                 "no bits are requested to be modified");
4829         else if (action_modify_field->width > dst_width ||
4830                  action_modify_field->width > src_width)
4831                 return rte_flow_error_set(error, EINVAL,
4832                                 RTE_FLOW_ERROR_TYPE_ACTION, action,
4833                                 "cannot modify more bits than"
4834                                 " the width of a field");
4835         if (action_modify_field->dst.field != RTE_FLOW_FIELD_VALUE &&
4836             action_modify_field->dst.field != RTE_FLOW_FIELD_POINTER) {
4837                 if ((action_modify_field->dst.offset +
4838                      action_modify_field->width > dst_width) ||
4839                     (action_modify_field->dst.offset % 32))
4840                         return rte_flow_error_set(error, EINVAL,
4841                                         RTE_FLOW_ERROR_TYPE_ACTION, action,
4842                                         "destination offset is too big"
4843                                         " or not aligned to 4 bytes");
4844                 if (action_modify_field->dst.level &&
4845                     action_modify_field->dst.field != RTE_FLOW_FIELD_TAG)
4846                         return rte_flow_error_set(error, ENOTSUP,
4847                                         RTE_FLOW_ERROR_TYPE_ACTION, action,
4848                                         "inner header fields modification"
4849                                         " is not supported");
4850         }
4851         if (action_modify_field->src.field != RTE_FLOW_FIELD_VALUE &&
4852             action_modify_field->src.field != RTE_FLOW_FIELD_POINTER) {
4853                 if (!attr->transfer && !attr->group)
4854                         return rte_flow_error_set(error, ENOTSUP,
4855                                         RTE_FLOW_ERROR_TYPE_ACTION, action,
4856                                         "modify field action is not"
4857                                         " supported for group 0");
4858                 if ((action_modify_field->src.offset +
4859                      action_modify_field->width > src_width) ||
4860                     (action_modify_field->src.offset % 32))
4861                         return rte_flow_error_set(error, EINVAL,
4862                                         RTE_FLOW_ERROR_TYPE_ACTION, action,
4863                                         "source offset is too big"
4864                                         " or not aligned to 4 bytes");
4865                 if (action_modify_field->src.level &&
4866                     action_modify_field->src.field != RTE_FLOW_FIELD_TAG)
4867                         return rte_flow_error_set(error, ENOTSUP,
4868                                         RTE_FLOW_ERROR_TYPE_ACTION, action,
4869                                         "inner header fields modification"
4870                                         " is not supported");
4871         }
4872         if ((action_modify_field->dst.field ==
4873              action_modify_field->src.field) &&
4874             (action_modify_field->dst.level ==
4875              action_modify_field->src.level))
4876                 return rte_flow_error_set(error, EINVAL,
4877                                 RTE_FLOW_ERROR_TYPE_ACTION, action,
4878                                 "source and destination fields"
4879                                 " cannot be the same");
4880         if (action_modify_field->dst.field == RTE_FLOW_FIELD_VALUE ||
4881             action_modify_field->dst.field == RTE_FLOW_FIELD_POINTER ||
4882             action_modify_field->dst.field == RTE_FLOW_FIELD_MARK)
4883                 return rte_flow_error_set(error, EINVAL,
4884                                 RTE_FLOW_ERROR_TYPE_ACTION, action,
4885                                 "mark, immediate value or a pointer to it"
4886                                 " cannot be used as a destination");
4887         if (action_modify_field->dst.field == RTE_FLOW_FIELD_START ||
4888             action_modify_field->src.field == RTE_FLOW_FIELD_START)
4889                 return rte_flow_error_set(error, ENOTSUP,
4890                                 RTE_FLOW_ERROR_TYPE_ACTION, action,
4891                                 "modifications of an arbitrary"
4892                                 " place in a packet is not supported");
4893         if (action_modify_field->dst.field == RTE_FLOW_FIELD_VLAN_TYPE ||
4894             action_modify_field->src.field == RTE_FLOW_FIELD_VLAN_TYPE)
4895                 return rte_flow_error_set(error, ENOTSUP,
4896                                 RTE_FLOW_ERROR_TYPE_ACTION, action,
4897                                 "modifications of the 802.1Q Tag"
4898                                 " Identifier is not supported");
4899         if (action_modify_field->dst.field == RTE_FLOW_FIELD_VXLAN_VNI ||
4900             action_modify_field->src.field == RTE_FLOW_FIELD_VXLAN_VNI)
4901                 return rte_flow_error_set(error, ENOTSUP,
4902                                 RTE_FLOW_ERROR_TYPE_ACTION, action,
4903                                 "modifications of the VXLAN Network"
4904                                 " Identifier is not supported");
4905         if (action_modify_field->dst.field == RTE_FLOW_FIELD_GENEVE_VNI ||
4906             action_modify_field->src.field == RTE_FLOW_FIELD_GENEVE_VNI)
4907                 return rte_flow_error_set(error, ENOTSUP,
4908                                 RTE_FLOW_ERROR_TYPE_ACTION, action,
4909                                 "modifications of the GENEVE Network"
4910                                 " Identifier is not supported");
4911         if (action_modify_field->dst.field == RTE_FLOW_FIELD_MARK ||
4912             action_modify_field->src.field == RTE_FLOW_FIELD_MARK ||
4913             action_modify_field->dst.field == RTE_FLOW_FIELD_META ||
4914             action_modify_field->src.field == RTE_FLOW_FIELD_META) {
4915                 if (config->dv_xmeta_en == MLX5_XMETA_MODE_LEGACY ||
4916                     !mlx5_flow_ext_mreg_supported(dev))
4917                         return rte_flow_error_set(error, ENOTSUP,
4918                                         RTE_FLOW_ERROR_TYPE_ACTION, action,
4919                                         "cannot modify mark or metadata without"
4920                                         " extended metadata register support");
4921         }
4922         if (action_modify_field->operation != RTE_FLOW_MODIFY_SET)
4923                 return rte_flow_error_set(error, ENOTSUP,
4924                                 RTE_FLOW_ERROR_TYPE_ACTION, action,
4925                                 "add and sub operations"
4926                                 " are not supported");
4927         return (action_modify_field->width / 32) +
4928                !!(action_modify_field->width % 32);
4929 }
4930
4931 /**
4932  * Validate jump action.
4933  *
4934  * @param[in] action
4935  *   Pointer to the jump action.
4936  * @param[in] action_flags
4937  *   Holds the actions detected until now.
4938  * @param[in] attributes
4939  *   Pointer to flow attributes
4940  * @param[in] external
4941  *   Action belongs to flow rule created by request external to PMD.
4942  * @param[out] error
4943  *   Pointer to error structure.
4944  *
4945  * @return
4946  *   0 on success, a negative errno value otherwise and rte_errno is set.
4947  */
4948 static int
4949 flow_dv_validate_action_jump(struct rte_eth_dev *dev,
4950                              const struct mlx5_flow_tunnel *tunnel,
4951                              const struct rte_flow_action *action,
4952                              uint64_t action_flags,
4953                              const struct rte_flow_attr *attributes,
4954                              bool external, struct rte_flow_error *error)
4955 {
4956         uint32_t target_group, table;
4957         int ret = 0;
4958         struct flow_grp_info grp_info = {
4959                 .external = !!external,
4960                 .transfer = !!attributes->transfer,
4961                 .fdb_def_rule = 1,
4962                 .std_tbl_fix = 0
4963         };
4964         if (action_flags & (MLX5_FLOW_FATE_ACTIONS |
4965                             MLX5_FLOW_FATE_ESWITCH_ACTIONS))
4966                 return rte_flow_error_set(error, EINVAL,
4967                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
4968                                           "can't have 2 fate actions in"
4969                                           " same flow");
4970         if (!action->conf)
4971                 return rte_flow_error_set(error, EINVAL,
4972                                           RTE_FLOW_ERROR_TYPE_ACTION_CONF,
4973                                           NULL, "action configuration not set");
4974         target_group =
4975                 ((const struct rte_flow_action_jump *)action->conf)->group;
4976         ret = mlx5_flow_group_to_table(dev, tunnel, target_group, &table,
4977                                        &grp_info, error);
4978         if (ret)
4979                 return ret;
4980         if (attributes->group == target_group &&
4981             !(action_flags & (MLX5_FLOW_ACTION_TUNNEL_SET |
4982                               MLX5_FLOW_ACTION_TUNNEL_MATCH)))
4983                 return rte_flow_error_set(error, EINVAL,
4984                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
4985                                           "target group must be other than"
4986                                           " the current flow group");
4987         return 0;
4988 }
4989
4990 /*
4991  * Validate action PORT_ID / REPRESENTED_PORT.
4992  *
4993  * @param[in] dev
4994  *   Pointer to rte_eth_dev structure.
4995  * @param[in] action_flags
4996  *   Bit-fields that holds the actions detected until now.
4997  * @param[in] action
4998  *   PORT_ID / REPRESENTED_PORT action structure.
4999  * @param[in] attr
5000  *   Attributes of flow that includes this action.
5001  * @param[out] error
5002  *   Pointer to error structure.
5003  *
5004  * @return
5005  *   0 on success, a negative errno value otherwise and rte_errno is set.
5006  */
5007 static int
5008 flow_dv_validate_action_port_id(struct rte_eth_dev *dev,
5009                                 uint64_t action_flags,
5010                                 const struct rte_flow_action *action,
5011                                 const struct rte_flow_attr *attr,
5012                                 struct rte_flow_error *error)
5013 {
5014         const struct rte_flow_action_port_id *port_id;
5015         const struct rte_flow_action_ethdev *ethdev;
5016         struct mlx5_priv *act_priv;
5017         struct mlx5_priv *dev_priv;
5018         uint16_t port;
5019
5020         if (!attr->transfer)
5021                 return rte_flow_error_set(error, ENOTSUP,
5022                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
5023                                           NULL,
5024                                           "port action is valid in transfer"
5025                                           " mode only");
5026         if (!action || !action->conf)
5027                 return rte_flow_error_set(error, ENOTSUP,
5028                                           RTE_FLOW_ERROR_TYPE_ACTION_CONF,
5029                                           NULL,
5030                                           "port action parameters must be"
5031                                           " specified");
5032         if (action_flags & (MLX5_FLOW_FATE_ACTIONS |
5033                             MLX5_FLOW_FATE_ESWITCH_ACTIONS))
5034                 return rte_flow_error_set(error, EINVAL,
5035                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5036                                           "can have only one fate actions in"
5037                                           " a flow");
5038         dev_priv = mlx5_dev_to_eswitch_info(dev);
5039         if (!dev_priv)
5040                 return rte_flow_error_set(error, rte_errno,
5041                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
5042                                           NULL,
5043                                           "failed to obtain E-Switch info");
5044         switch (action->type) {
5045         case RTE_FLOW_ACTION_TYPE_PORT_ID:
5046                 port_id = action->conf;
5047                 port = port_id->original ? dev->data->port_id : port_id->id;
5048                 break;
5049         case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT:
5050                 ethdev = action->conf;
5051                 port = ethdev->port_id;
5052                 break;
5053         default:
5054                 MLX5_ASSERT(false);
5055                 return rte_flow_error_set
5056                                 (error, EINVAL,
5057                                  RTE_FLOW_ERROR_TYPE_ACTION, action,
5058                                  "unknown E-Switch action");
5059         }
5060         act_priv = mlx5_port_to_eswitch_info(port, false);
5061         if (!act_priv)
5062                 return rte_flow_error_set
5063                                 (error, rte_errno,
5064                                  RTE_FLOW_ERROR_TYPE_ACTION_CONF, action->conf,
5065                                  "failed to obtain E-Switch port id for port");
5066         if (act_priv->domain_id != dev_priv->domain_id)
5067                 return rte_flow_error_set
5068                                 (error, EINVAL,
5069                                  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5070                                  "port does not belong to"
5071                                  " E-Switch being configured");
5072         return 0;
5073 }
5074
5075 /**
5076  * Get the maximum number of modify header actions.
5077  *
5078  * @param dev
5079  *   Pointer to rte_eth_dev structure.
5080  * @param root
5081  *   Whether action is on root table.
5082  *
5083  * @return
5084  *   Max number of modify header actions device can support.
5085  */
5086 static inline unsigned int
5087 flow_dv_modify_hdr_action_max(struct rte_eth_dev *dev __rte_unused,
5088                               bool root)
5089 {
5090         /*
5091          * There's no way to directly query the max capacity from FW.
5092          * The maximal value on root table should be assumed to be supported.
5093          */
5094         if (!root)
5095                 return MLX5_MAX_MODIFY_NUM;
5096         else
5097                 return MLX5_ROOT_TBL_MODIFY_NUM;
5098 }
5099
5100 /**
5101  * Validate the meter action.
5102  *
5103  * @param[in] dev
5104  *   Pointer to rte_eth_dev structure.
5105  * @param[in] action_flags
5106  *   Bit-fields that holds the actions detected until now.
5107  * @param[in] action
5108  *   Pointer to the meter action.
5109  * @param[in] attr
5110  *   Attributes of flow that includes this action.
5111  * @param[in] port_id_item
5112  *   Pointer to item indicating port id.
5113  * @param[out] error
5114  *   Pointer to error structure.
5115  *
5116  * @return
5117  *   0 on success, a negative errno value otherwise and rte_ernno is set.
5118  */
5119 static int
5120 mlx5_flow_validate_action_meter(struct rte_eth_dev *dev,
5121                                 uint64_t action_flags,
5122                                 const struct rte_flow_action *action,
5123                                 const struct rte_flow_attr *attr,
5124                                 const struct rte_flow_item *port_id_item,
5125                                 bool *def_policy,
5126                                 struct rte_flow_error *error)
5127 {
5128         struct mlx5_priv *priv = dev->data->dev_private;
5129         const struct rte_flow_action_meter *am = action->conf;
5130         struct mlx5_flow_meter_info *fm;
5131         struct mlx5_flow_meter_policy *mtr_policy;
5132         struct mlx5_flow_mtr_mng *mtrmng = priv->sh->mtrmng;
5133
5134         if (!am)
5135                 return rte_flow_error_set(error, EINVAL,
5136                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5137                                           "meter action conf is NULL");
5138
5139         if (action_flags & MLX5_FLOW_ACTION_METER)
5140                 return rte_flow_error_set(error, ENOTSUP,
5141                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5142                                           "meter chaining not support");
5143         if (action_flags & MLX5_FLOW_ACTION_JUMP)
5144                 return rte_flow_error_set(error, ENOTSUP,
5145                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5146                                           "meter with jump not support");
5147         if (!priv->mtr_en)
5148                 return rte_flow_error_set(error, ENOTSUP,
5149                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
5150                                           NULL,
5151                                           "meter action not supported");
5152         fm = mlx5_flow_meter_find(priv, am->mtr_id, NULL);
5153         if (!fm)
5154                 return rte_flow_error_set(error, EINVAL,
5155                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5156                                           "Meter not found");
5157         /* aso meter can always be shared by different domains */
5158         if (fm->ref_cnt && !priv->sh->meter_aso_en &&
5159             !(fm->transfer == attr->transfer ||
5160               (!fm->ingress && !attr->ingress && attr->egress) ||
5161               (!fm->egress && !attr->egress && attr->ingress)))
5162                 return rte_flow_error_set(error, EINVAL,
5163                         RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5164                         "Flow attributes domain are either invalid "
5165                         "or have a domain conflict with current "
5166                         "meter attributes");
5167         if (fm->def_policy) {
5168                 if (!((attr->transfer &&
5169                         mtrmng->def_policy[MLX5_MTR_DOMAIN_TRANSFER]) ||
5170                         (attr->egress &&
5171                         mtrmng->def_policy[MLX5_MTR_DOMAIN_EGRESS]) ||
5172                         (attr->ingress &&
5173                         mtrmng->def_policy[MLX5_MTR_DOMAIN_INGRESS])))
5174                         return rte_flow_error_set(error, EINVAL,
5175                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5176                                           "Flow attributes domain "
5177                                           "have a conflict with current "
5178                                           "meter domain attributes");
5179                 *def_policy = true;
5180         } else {
5181                 mtr_policy = mlx5_flow_meter_policy_find(dev,
5182                                                 fm->policy_id, NULL);
5183                 if (!mtr_policy)
5184                         return rte_flow_error_set(error, EINVAL,
5185                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5186                                           "Invalid policy id for meter ");
5187                 if (!((attr->transfer && mtr_policy->transfer) ||
5188                         (attr->egress && mtr_policy->egress) ||
5189                         (attr->ingress && mtr_policy->ingress)))
5190                         return rte_flow_error_set(error, EINVAL,
5191                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5192                                           "Flow attributes domain "
5193                                           "have a conflict with current "
5194                                           "meter domain attributes");
5195                 if (attr->transfer && mtr_policy->dev) {
5196                         /**
5197                          * When policy has fate action of port_id,
5198                          * the flow should have the same src port as policy.
5199                          */
5200                         struct mlx5_priv *policy_port_priv =
5201                                         mtr_policy->dev->data->dev_private;
5202                         int32_t flow_src_port = priv->representor_id;
5203
5204                         if (port_id_item) {
5205                                 const struct rte_flow_item_port_id *spec =
5206                                                         port_id_item->spec;
5207                                 struct mlx5_priv *port_priv =
5208                                         mlx5_port_to_eswitch_info(spec->id,
5209                                                                   false);
5210                                 if (!port_priv)
5211                                         return rte_flow_error_set(error,
5212                                                 rte_errno,
5213                                                 RTE_FLOW_ERROR_TYPE_ITEM_SPEC,
5214                                                 spec,
5215                                                 "Failed to get port info.");
5216                                 flow_src_port = port_priv->representor_id;
5217                         }
5218                         if (flow_src_port != policy_port_priv->representor_id)
5219                                 return rte_flow_error_set(error,
5220                                                 rte_errno,
5221                                                 RTE_FLOW_ERROR_TYPE_ITEM_SPEC,
5222                                                 NULL,
5223                                                 "Flow and meter policy "
5224                                                 "have different src port.");
5225                 }
5226                 *def_policy = false;
5227         }
5228         return 0;
5229 }
5230
5231 /**
5232  * Validate the age action.
5233  *
5234  * @param[in] action_flags
5235  *   Holds the actions detected until now.
5236  * @param[in] action
5237  *   Pointer to the age action.
5238  * @param[in] dev
5239  *   Pointer to the Ethernet device structure.
5240  * @param[out] error
5241  *   Pointer to error structure.
5242  *
5243  * @return
5244  *   0 on success, a negative errno value otherwise and rte_errno is set.
5245  */
5246 static int
5247 flow_dv_validate_action_age(uint64_t action_flags,
5248                             const struct rte_flow_action *action,
5249                             struct rte_eth_dev *dev,
5250                             struct rte_flow_error *error)
5251 {
5252         struct mlx5_priv *priv = dev->data->dev_private;
5253         const struct rte_flow_action_age *age = action->conf;
5254
5255         if (!priv->sh->devx || (priv->sh->cmng.counter_fallback &&
5256             !priv->sh->aso_age_mng))
5257                 return rte_flow_error_set(error, ENOTSUP,
5258                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
5259                                           NULL,
5260                                           "age action not supported");
5261         if (!(action->conf))
5262                 return rte_flow_error_set(error, EINVAL,
5263                                           RTE_FLOW_ERROR_TYPE_ACTION, action,
5264                                           "configuration cannot be null");
5265         if (!(age->timeout))
5266                 return rte_flow_error_set(error, EINVAL,
5267                                           RTE_FLOW_ERROR_TYPE_ACTION, action,
5268                                           "invalid timeout value 0");
5269         if (action_flags & MLX5_FLOW_ACTION_AGE)
5270                 return rte_flow_error_set(error, EINVAL,
5271                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5272                                           "duplicate age actions set");
5273         return 0;
5274 }
5275
5276 /**
5277  * Validate the modify-header IPv4 DSCP actions.
5278  *
5279  * @param[in] action_flags
5280  *   Holds the actions detected until now.
5281  * @param[in] action
5282  *   Pointer to the modify action.
5283  * @param[in] item_flags
5284  *   Holds the items detected.
5285  * @param[out] error
5286  *   Pointer to error structure.
5287  *
5288  * @return
5289  *   0 on success, a negative errno value otherwise and rte_errno is set.
5290  */
5291 static int
5292 flow_dv_validate_action_modify_ipv4_dscp(const uint64_t action_flags,
5293                                          const struct rte_flow_action *action,
5294                                          const uint64_t item_flags,
5295                                          struct rte_flow_error *error)
5296 {
5297         int ret = 0;
5298
5299         ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
5300         if (!ret) {
5301                 if (!(item_flags & MLX5_FLOW_LAYER_L3_IPV4))
5302                         return rte_flow_error_set(error, EINVAL,
5303                                                   RTE_FLOW_ERROR_TYPE_ACTION,
5304                                                   NULL,
5305                                                   "no ipv4 item in pattern");
5306         }
5307         return ret;
5308 }
5309
5310 /**
5311  * Validate the modify-header IPv6 DSCP actions.
5312  *
5313  * @param[in] action_flags
5314  *   Holds the actions detected until now.
5315  * @param[in] action
5316  *   Pointer to the modify action.
5317  * @param[in] item_flags
5318  *   Holds the items detected.
5319  * @param[out] error
5320  *   Pointer to error structure.
5321  *
5322  * @return
5323  *   0 on success, a negative errno value otherwise and rte_errno is set.
5324  */
5325 static int
5326 flow_dv_validate_action_modify_ipv6_dscp(const uint64_t action_flags,
5327                                          const struct rte_flow_action *action,
5328                                          const uint64_t item_flags,
5329                                          struct rte_flow_error *error)
5330 {
5331         int ret = 0;
5332
5333         ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
5334         if (!ret) {
5335                 if (!(item_flags & MLX5_FLOW_LAYER_L3_IPV6))
5336                         return rte_flow_error_set(error, EINVAL,
5337                                                   RTE_FLOW_ERROR_TYPE_ACTION,
5338                                                   NULL,
5339                                                   "no ipv6 item in pattern");
5340         }
5341         return ret;
5342 }
5343
5344 int
5345 flow_dv_modify_match_cb(void *tool_ctx __rte_unused,
5346                         struct mlx5_list_entry *entry, void *cb_ctx)
5347 {
5348         struct mlx5_flow_cb_ctx *ctx = cb_ctx;
5349         struct mlx5_flow_dv_modify_hdr_resource *ref = ctx->data;
5350         struct mlx5_flow_dv_modify_hdr_resource *resource =
5351                                   container_of(entry, typeof(*resource), entry);
5352         uint32_t key_len = sizeof(*ref) - offsetof(typeof(*ref), ft_type);
5353
5354         key_len += ref->actions_num * sizeof(ref->actions[0]);
5355         return ref->actions_num != resource->actions_num ||
5356                memcmp(&ref->ft_type, &resource->ft_type, key_len);
5357 }
5358
5359 static struct mlx5_indexed_pool *
5360 flow_dv_modify_ipool_get(struct mlx5_dev_ctx_shared *sh, uint8_t index)
5361 {
5362         struct mlx5_indexed_pool *ipool = __atomic_load_n
5363                                      (&sh->mdh_ipools[index], __ATOMIC_SEQ_CST);
5364
5365         if (!ipool) {
5366                 struct mlx5_indexed_pool *expected = NULL;
5367                 struct mlx5_indexed_pool_config cfg =
5368                     (struct mlx5_indexed_pool_config) {
5369                        .size = sizeof(struct mlx5_flow_dv_modify_hdr_resource) +
5370                                                                    (index + 1) *
5371                                            sizeof(struct mlx5_modification_cmd),
5372                        .trunk_size = 64,
5373                        .grow_trunk = 3,
5374                        .grow_shift = 2,
5375                        .need_lock = 1,
5376                        .release_mem_en = !!sh->reclaim_mode,
5377                        .per_core_cache = sh->reclaim_mode ? 0 : (1 << 16),
5378                        .malloc = mlx5_malloc,
5379                        .free = mlx5_free,
5380                        .type = "mlx5_modify_action_resource",
5381                 };
5382
5383                 cfg.size = RTE_ALIGN(cfg.size, sizeof(ipool));
5384                 ipool = mlx5_ipool_create(&cfg);
5385                 if (!ipool)
5386                         return NULL;
5387                 if (!__atomic_compare_exchange_n(&sh->mdh_ipools[index],
5388                                                  &expected, ipool, false,
5389                                                  __ATOMIC_SEQ_CST,
5390                                                  __ATOMIC_SEQ_CST)) {
5391                         mlx5_ipool_destroy(ipool);
5392                         ipool = __atomic_load_n(&sh->mdh_ipools[index],
5393                                                 __ATOMIC_SEQ_CST);
5394                 }
5395         }
5396         return ipool;
5397 }
5398
5399 struct mlx5_list_entry *
5400 flow_dv_modify_create_cb(void *tool_ctx, void *cb_ctx)
5401 {
5402         struct mlx5_dev_ctx_shared *sh = tool_ctx;
5403         struct mlx5_flow_cb_ctx *ctx = cb_ctx;
5404         struct mlx5dv_dr_domain *ns;
5405         struct mlx5_flow_dv_modify_hdr_resource *entry;
5406         struct mlx5_flow_dv_modify_hdr_resource *ref = ctx->data;
5407         struct mlx5_indexed_pool *ipool = flow_dv_modify_ipool_get(sh,
5408                                                           ref->actions_num - 1);
5409         int ret;
5410         uint32_t data_len = ref->actions_num * sizeof(ref->actions[0]);
5411         uint32_t key_len = sizeof(*ref) - offsetof(typeof(*ref), ft_type);
5412         uint32_t idx;
5413
5414         if (unlikely(!ipool)) {
5415                 rte_flow_error_set(ctx->error, ENOMEM,
5416                                    RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
5417                                    NULL, "cannot allocate modify ipool");
5418                 return NULL;
5419         }
5420         entry = mlx5_ipool_zmalloc(ipool, &idx);
5421         if (!entry) {
5422                 rte_flow_error_set(ctx->error, ENOMEM,
5423                                    RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
5424                                    "cannot allocate resource memory");
5425                 return NULL;
5426         }
5427         rte_memcpy(&entry->ft_type,
5428                    RTE_PTR_ADD(ref, offsetof(typeof(*ref), ft_type)),
5429                    key_len + data_len);
5430         if (entry->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB)
5431                 ns = sh->fdb_domain;
5432         else if (entry->ft_type == MLX5DV_FLOW_TABLE_TYPE_NIC_TX)
5433                 ns = sh->tx_domain;
5434         else
5435                 ns = sh->rx_domain;
5436         ret = mlx5_flow_os_create_flow_action_modify_header
5437                                         (sh->cdev->ctx, ns, entry,
5438                                          data_len, &entry->action);
5439         if (ret) {
5440                 mlx5_ipool_free(sh->mdh_ipools[ref->actions_num - 1], idx);
5441                 rte_flow_error_set(ctx->error, ENOMEM,
5442                                    RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
5443                                    NULL, "cannot create modification action");
5444                 return NULL;
5445         }
5446         entry->idx = idx;
5447         return &entry->entry;
5448 }
5449
5450 struct mlx5_list_entry *
5451 flow_dv_modify_clone_cb(void *tool_ctx, struct mlx5_list_entry *oentry,
5452                         void *cb_ctx)
5453 {
5454         struct mlx5_dev_ctx_shared *sh = tool_ctx;
5455         struct mlx5_flow_cb_ctx *ctx = cb_ctx;
5456         struct mlx5_flow_dv_modify_hdr_resource *entry;
5457         struct mlx5_flow_dv_modify_hdr_resource *ref = ctx->data;
5458         uint32_t data_len = ref->actions_num * sizeof(ref->actions[0]);
5459         uint32_t idx;
5460
5461         entry = mlx5_ipool_malloc(sh->mdh_ipools[ref->actions_num - 1],
5462                                   &idx);
5463         if (!entry) {
5464                 rte_flow_error_set(ctx->error, ENOMEM,
5465                                    RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
5466                                    "cannot allocate resource memory");
5467                 return NULL;
5468         }
5469         memcpy(entry, oentry, sizeof(*entry) + data_len);
5470         entry->idx = idx;
5471         return &entry->entry;
5472 }
5473
5474 void
5475 flow_dv_modify_clone_free_cb(void *tool_ctx, struct mlx5_list_entry *entry)
5476 {
5477         struct mlx5_dev_ctx_shared *sh = tool_ctx;
5478         struct mlx5_flow_dv_modify_hdr_resource *res =
5479                 container_of(entry, typeof(*res), entry);
5480
5481         mlx5_ipool_free(sh->mdh_ipools[res->actions_num - 1], res->idx);
5482 }
5483
5484 /**
5485  * Validate the sample action.
5486  *
5487  * @param[in, out] action_flags
5488  *   Holds the actions detected until now.
5489  * @param[in] action
5490  *   Pointer to the sample action.
5491  * @param[in] dev
5492  *   Pointer to the Ethernet device structure.
5493  * @param[in] attr
5494  *   Attributes of flow that includes this action.
5495  * @param[in] item_flags
5496  *   Holds the items detected.
5497  * @param[in] rss
5498  *   Pointer to the RSS action.
5499  * @param[out] sample_rss
5500  *   Pointer to the RSS action in sample action list.
5501  * @param[out] count
5502  *   Pointer to the COUNT action in sample action list.
5503  * @param[out] fdb_mirror_limit
5504  *   Pointer to the FDB mirror limitation flag.
5505  * @param[out] error
5506  *   Pointer to error structure.
5507  *
5508  * @return
5509  *   0 on success, a negative errno value otherwise and rte_errno is set.
5510  */
5511 static int
5512 flow_dv_validate_action_sample(uint64_t *action_flags,
5513                                const struct rte_flow_action *action,
5514                                struct rte_eth_dev *dev,
5515                                const struct rte_flow_attr *attr,
5516                                uint64_t item_flags,
5517                                const struct rte_flow_action_rss *rss,
5518                                const struct rte_flow_action_rss **sample_rss,
5519                                const struct rte_flow_action_count **count,
5520                                int *fdb_mirror_limit,
5521                                struct rte_flow_error *error)
5522 {
5523         struct mlx5_priv *priv = dev->data->dev_private;
5524         struct mlx5_dev_config *dev_conf = &priv->config;
5525         const struct rte_flow_action_sample *sample = action->conf;
5526         const struct rte_flow_action *act;
5527         uint64_t sub_action_flags = 0;
5528         uint16_t queue_index = 0xFFFF;
5529         int actions_n = 0;
5530         int ret;
5531
5532         if (!sample)
5533                 return rte_flow_error_set(error, EINVAL,
5534                                           RTE_FLOW_ERROR_TYPE_ACTION, action,
5535                                           "configuration cannot be NULL");
5536         if (sample->ratio == 0)
5537                 return rte_flow_error_set(error, EINVAL,
5538                                           RTE_FLOW_ERROR_TYPE_ACTION, action,
5539                                           "ratio value starts from 1");
5540         if (!priv->sh->devx || (sample->ratio > 0 && !priv->sampler_en))
5541                 return rte_flow_error_set(error, ENOTSUP,
5542                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
5543                                           NULL,
5544                                           "sample action not supported");
5545         if (*action_flags & MLX5_FLOW_ACTION_SAMPLE)
5546                 return rte_flow_error_set(error, EINVAL,
5547                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5548                                           "Multiple sample actions not "
5549                                           "supported");
5550         if (*action_flags & MLX5_FLOW_ACTION_METER)
5551                 return rte_flow_error_set(error, EINVAL,
5552                                           RTE_FLOW_ERROR_TYPE_ACTION, action,
5553                                           "wrong action order, meter should "
5554                                           "be after sample action");
5555         if (*action_flags & MLX5_FLOW_ACTION_JUMP)
5556                 return rte_flow_error_set(error, EINVAL,
5557                                           RTE_FLOW_ERROR_TYPE_ACTION, action,
5558                                           "wrong action order, jump should "
5559                                           "be after sample action");
5560         act = sample->actions;
5561         for (; act->type != RTE_FLOW_ACTION_TYPE_END; act++) {
5562                 if (actions_n == MLX5_DV_MAX_NUMBER_OF_ACTIONS)
5563                         return rte_flow_error_set(error, ENOTSUP,
5564                                                   RTE_FLOW_ERROR_TYPE_ACTION,
5565                                                   act, "too many actions");
5566                 switch (act->type) {
5567                 case RTE_FLOW_ACTION_TYPE_QUEUE:
5568                         ret = mlx5_flow_validate_action_queue(act,
5569                                                               sub_action_flags,
5570                                                               dev,
5571                                                               attr, error);
5572                         if (ret < 0)
5573                                 return ret;
5574                         queue_index = ((const struct rte_flow_action_queue *)
5575                                                         (act->conf))->index;
5576                         sub_action_flags |= MLX5_FLOW_ACTION_QUEUE;
5577                         ++actions_n;
5578                         break;
5579                 case RTE_FLOW_ACTION_TYPE_RSS:
5580                         *sample_rss = act->conf;
5581                         ret = mlx5_flow_validate_action_rss(act,
5582                                                             sub_action_flags,
5583                                                             dev, attr,
5584                                                             item_flags,
5585                                                             error);
5586                         if (ret < 0)
5587                                 return ret;
5588                         if (rss && *sample_rss &&
5589                             ((*sample_rss)->level != rss->level ||
5590                             (*sample_rss)->types != rss->types))
5591                                 return rte_flow_error_set(error, ENOTSUP,
5592                                         RTE_FLOW_ERROR_TYPE_ACTION,
5593                                         NULL,
5594                                         "Can't use the different RSS types "
5595                                         "or level in the same flow");
5596                         if (*sample_rss != NULL && (*sample_rss)->queue_num)
5597                                 queue_index = (*sample_rss)->queue[0];
5598                         sub_action_flags |= MLX5_FLOW_ACTION_RSS;
5599                         ++actions_n;
5600                         break;
5601                 case RTE_FLOW_ACTION_TYPE_MARK:
5602                         ret = flow_dv_validate_action_mark(dev, act,
5603                                                            sub_action_flags,
5604                                                            attr, error);
5605                         if (ret < 0)
5606                                 return ret;
5607                         if (dev_conf->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY)
5608                                 sub_action_flags |= MLX5_FLOW_ACTION_MARK |
5609                                                 MLX5_FLOW_ACTION_MARK_EXT;
5610                         else
5611                                 sub_action_flags |= MLX5_FLOW_ACTION_MARK;
5612                         ++actions_n;
5613                         break;
5614                 case RTE_FLOW_ACTION_TYPE_COUNT:
5615                         ret = flow_dv_validate_action_count
5616                                 (dev, false, *action_flags | sub_action_flags,
5617                                  error);
5618                         if (ret < 0)
5619                                 return ret;
5620                         *count = act->conf;
5621                         sub_action_flags |= MLX5_FLOW_ACTION_COUNT;
5622                         *action_flags |= MLX5_FLOW_ACTION_COUNT;
5623                         ++actions_n;
5624                         break;
5625                 case RTE_FLOW_ACTION_TYPE_PORT_ID:
5626                 case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT:
5627                         ret = flow_dv_validate_action_port_id(dev,
5628                                                               sub_action_flags,
5629                                                               act,
5630                                                               attr,
5631                                                               error);
5632                         if (ret)
5633                                 return ret;
5634                         sub_action_flags |= MLX5_FLOW_ACTION_PORT_ID;
5635                         ++actions_n;
5636                         break;
5637                 case RTE_FLOW_ACTION_TYPE_RAW_ENCAP:
5638                         ret = flow_dv_validate_action_raw_encap_decap
5639                                 (dev, NULL, act->conf, attr, &sub_action_flags,
5640                                  &actions_n, action, item_flags, error);
5641                         if (ret < 0)
5642                                 return ret;
5643                         ++actions_n;
5644                         break;
5645                 case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP:
5646                 case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP:
5647                         ret = flow_dv_validate_action_l2_encap(dev,
5648                                                                sub_action_flags,
5649                                                                act, attr,
5650                                                                error);
5651                         if (ret < 0)
5652                                 return ret;
5653                         sub_action_flags |= MLX5_FLOW_ACTION_ENCAP;
5654                         ++actions_n;
5655                         break;
5656                 default:
5657                         return rte_flow_error_set(error, ENOTSUP,
5658                                                   RTE_FLOW_ERROR_TYPE_ACTION,
5659                                                   NULL,
5660                                                   "Doesn't support optional "
5661                                                   "action");
5662                 }
5663         }
5664         if (attr->ingress && !attr->transfer) {
5665                 if (!(sub_action_flags & (MLX5_FLOW_ACTION_QUEUE |
5666                                           MLX5_FLOW_ACTION_RSS)))
5667                         return rte_flow_error_set(error, EINVAL,
5668                                                   RTE_FLOW_ERROR_TYPE_ACTION,
5669                                                   NULL,
5670                                                   "Ingress must has a dest "
5671                                                   "QUEUE for Sample");
5672         } else if (attr->egress && !attr->transfer) {
5673                 return rte_flow_error_set(error, ENOTSUP,
5674                                           RTE_FLOW_ERROR_TYPE_ACTION,
5675                                           NULL,
5676                                           "Sample Only support Ingress "
5677                                           "or E-Switch");
5678         } else if (sample->actions->type != RTE_FLOW_ACTION_TYPE_END) {
5679                 MLX5_ASSERT(attr->transfer);
5680                 if (sample->ratio > 1)
5681                         return rte_flow_error_set(error, ENOTSUP,
5682                                                   RTE_FLOW_ERROR_TYPE_ACTION,
5683                                                   NULL,
5684                                                   "E-Switch doesn't support "
5685                                                   "any optional action "
5686                                                   "for sampling");
5687                 if (sub_action_flags & MLX5_FLOW_ACTION_QUEUE)
5688                         return rte_flow_error_set(error, ENOTSUP,
5689                                                   RTE_FLOW_ERROR_TYPE_ACTION,
5690                                                   NULL,
5691                                                   "unsupported action QUEUE");
5692                 if (sub_action_flags & MLX5_FLOW_ACTION_RSS)
5693                         return rte_flow_error_set(error, ENOTSUP,
5694                                                   RTE_FLOW_ERROR_TYPE_ACTION,
5695                                                   NULL,
5696                                                   "unsupported action QUEUE");
5697                 if (!(sub_action_flags & MLX5_FLOW_ACTION_PORT_ID))
5698                         return rte_flow_error_set(error, EINVAL,
5699                                                   RTE_FLOW_ERROR_TYPE_ACTION,
5700                                                   NULL,
5701                                                   "E-Switch must has a dest "
5702                                                   "port for mirroring");
5703                 if (!priv->config.hca_attr.reg_c_preserve &&
5704                      priv->representor_id != UINT16_MAX)
5705                         *fdb_mirror_limit = 1;
5706         }
5707         /* Continue validation for Xcap actions.*/
5708         if ((sub_action_flags & MLX5_FLOW_XCAP_ACTIONS) &&
5709             (queue_index == 0xFFFF ||
5710              mlx5_rxq_get_type(dev, queue_index) != MLX5_RXQ_TYPE_HAIRPIN)) {
5711                 if ((sub_action_flags & MLX5_FLOW_XCAP_ACTIONS) ==
5712                      MLX5_FLOW_XCAP_ACTIONS)
5713                         return rte_flow_error_set(error, ENOTSUP,
5714                                                   RTE_FLOW_ERROR_TYPE_ACTION,
5715                                                   NULL, "encap and decap "
5716                                                   "combination aren't "
5717                                                   "supported");
5718                 if (!attr->transfer && attr->ingress && (sub_action_flags &
5719                                                         MLX5_FLOW_ACTION_ENCAP))
5720                         return rte_flow_error_set(error, ENOTSUP,
5721                                                   RTE_FLOW_ERROR_TYPE_ACTION,
5722                                                   NULL, "encap is not supported"
5723                                                   " for ingress traffic");
5724         }
5725         return 0;
5726 }
5727
5728 /**
5729  * Find existing modify-header resource or create and register a new one.
5730  *
5731  * @param dev[in, out]
5732  *   Pointer to rte_eth_dev structure.
5733  * @param[in, out] resource
5734  *   Pointer to modify-header resource.
5735  * @parm[in, out] dev_flow
5736  *   Pointer to the dev_flow.
5737  * @param[out] error
5738  *   pointer to error structure.
5739  *
5740  * @return
5741  *   0 on success otherwise -errno and errno is set.
5742  */
5743 static int
5744 flow_dv_modify_hdr_resource_register
5745                         (struct rte_eth_dev *dev,
5746                          struct mlx5_flow_dv_modify_hdr_resource *resource,
5747                          struct mlx5_flow *dev_flow,
5748                          struct rte_flow_error *error)
5749 {
5750         struct mlx5_priv *priv = dev->data->dev_private;
5751         struct mlx5_dev_ctx_shared *sh = priv->sh;
5752         uint32_t key_len = sizeof(*resource) -
5753                            offsetof(typeof(*resource), ft_type) +
5754                            resource->actions_num * sizeof(resource->actions[0]);
5755         struct mlx5_list_entry *entry;
5756         struct mlx5_flow_cb_ctx ctx = {
5757                 .error = error,
5758                 .data = resource,
5759         };
5760         struct mlx5_hlist *modify_cmds;
5761         uint64_t key64;
5762
5763         modify_cmds = flow_dv_hlist_prepare(sh, &sh->modify_cmds,
5764                                 "hdr_modify",
5765                                 MLX5_FLOW_HDR_MODIFY_HTABLE_SZ,
5766                                 true, false, sh,
5767                                 flow_dv_modify_create_cb,
5768                                 flow_dv_modify_match_cb,
5769                                 flow_dv_modify_remove_cb,
5770                                 flow_dv_modify_clone_cb,
5771                                 flow_dv_modify_clone_free_cb);
5772         if (unlikely(!modify_cmds))
5773                 return -rte_errno;
5774         resource->root = !dev_flow->dv.group;
5775         if (resource->actions_num > flow_dv_modify_hdr_action_max(dev,
5776                                                                 resource->root))
5777                 return rte_flow_error_set(error, EOVERFLOW,
5778                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5779                                           "too many modify header items");
5780         key64 = __rte_raw_cksum(&resource->ft_type, key_len, 0);
5781         entry = mlx5_hlist_register(modify_cmds, key64, &ctx);
5782         if (!entry)
5783                 return -rte_errno;
5784         resource = container_of(entry, typeof(*resource), entry);
5785         dev_flow->handle->dvh.modify_hdr = resource;
5786         return 0;
5787 }
5788
5789 /**
5790  * Get DV flow counter by index.
5791  *
5792  * @param[in] dev
5793  *   Pointer to the Ethernet device structure.
5794  * @param[in] idx
5795  *   mlx5 flow counter index in the container.
5796  * @param[out] ppool
5797  *   mlx5 flow counter pool in the container.
5798  *
5799  * @return
5800  *   Pointer to the counter, NULL otherwise.
5801  */
5802 static struct mlx5_flow_counter *
5803 flow_dv_counter_get_by_idx(struct rte_eth_dev *dev,
5804                            uint32_t idx,
5805                            struct mlx5_flow_counter_pool **ppool)
5806 {
5807         struct mlx5_priv *priv = dev->data->dev_private;
5808         struct mlx5_flow_counter_mng *cmng = &priv->sh->cmng;
5809         struct mlx5_flow_counter_pool *pool;
5810
5811         /* Decrease to original index and clear shared bit. */
5812         idx = (idx - 1) & (MLX5_CNT_SHARED_OFFSET - 1);
5813         MLX5_ASSERT(idx / MLX5_COUNTERS_PER_POOL < cmng->n);
5814         pool = cmng->pools[idx / MLX5_COUNTERS_PER_POOL];
5815         MLX5_ASSERT(pool);
5816         if (ppool)
5817                 *ppool = pool;
5818         return MLX5_POOL_GET_CNT(pool, idx % MLX5_COUNTERS_PER_POOL);
5819 }
5820
5821 /**
5822  * Check the devx counter belongs to the pool.
5823  *
5824  * @param[in] pool
5825  *   Pointer to the counter pool.
5826  * @param[in] id
5827  *   The counter devx ID.
5828  *
5829  * @return
5830  *   True if counter belongs to the pool, false otherwise.
5831  */
5832 static bool
5833 flow_dv_is_counter_in_pool(struct mlx5_flow_counter_pool *pool, int id)
5834 {
5835         int base = (pool->min_dcs->id / MLX5_COUNTERS_PER_POOL) *
5836                    MLX5_COUNTERS_PER_POOL;
5837
5838         if (id >= base && id < base + MLX5_COUNTERS_PER_POOL)
5839                 return true;
5840         return false;
5841 }
5842
5843 /**
5844  * Get a pool by devx counter ID.
5845  *
5846  * @param[in] cmng
5847  *   Pointer to the counter management.
5848  * @param[in] id
5849  *   The counter devx ID.
5850  *
5851  * @return
5852  *   The counter pool pointer if exists, NULL otherwise,
5853  */
5854 static struct mlx5_flow_counter_pool *
5855 flow_dv_find_pool_by_id(struct mlx5_flow_counter_mng *cmng, int id)
5856 {
5857         uint32_t i;
5858         struct mlx5_flow_counter_pool *pool = NULL;
5859
5860         rte_spinlock_lock(&cmng->pool_update_sl);
5861         /* Check last used pool. */
5862         if (cmng->last_pool_idx != POOL_IDX_INVALID &&
5863             flow_dv_is_counter_in_pool(cmng->pools[cmng->last_pool_idx], id)) {
5864                 pool = cmng->pools[cmng->last_pool_idx];
5865                 goto out;
5866         }
5867         /* ID out of range means no suitable pool in the container. */
5868         if (id > cmng->max_id || id < cmng->min_id)
5869                 goto out;
5870         /*
5871          * Find the pool from the end of the container, since mostly counter
5872          * ID is sequence increasing, and the last pool should be the needed
5873          * one.
5874          */
5875         i = cmng->n_valid;
5876         while (i--) {
5877                 struct mlx5_flow_counter_pool *pool_tmp = cmng->pools[i];
5878
5879                 if (flow_dv_is_counter_in_pool(pool_tmp, id)) {
5880                         pool = pool_tmp;
5881                         break;
5882                 }
5883         }
5884 out:
5885         rte_spinlock_unlock(&cmng->pool_update_sl);
5886         return pool;
5887 }
5888
5889 /**
5890  * Resize a counter container.
5891  *
5892  * @param[in] dev
5893  *   Pointer to the Ethernet device structure.
5894  *
5895  * @return
5896  *   0 on success, otherwise negative errno value and rte_errno is set.
5897  */
5898 static int
5899 flow_dv_container_resize(struct rte_eth_dev *dev)
5900 {
5901         struct mlx5_priv *priv = dev->data->dev_private;
5902         struct mlx5_flow_counter_mng *cmng = &priv->sh->cmng;
5903         void *old_pools = cmng->pools;
5904         uint32_t resize = cmng->n + MLX5_CNT_CONTAINER_RESIZE;
5905         uint32_t mem_size = sizeof(struct mlx5_flow_counter_pool *) * resize;
5906         void *pools = mlx5_malloc(MLX5_MEM_ZERO, mem_size, 0, SOCKET_ID_ANY);
5907
5908         if (!pools) {
5909                 rte_errno = ENOMEM;
5910                 return -ENOMEM;
5911         }
5912         if (old_pools)
5913                 memcpy(pools, old_pools, cmng->n *
5914                                        sizeof(struct mlx5_flow_counter_pool *));
5915         cmng->n = resize;
5916         cmng->pools = pools;
5917         if (old_pools)
5918                 mlx5_free(old_pools);
5919         return 0;
5920 }
5921
5922 /**
5923  * Query a devx flow counter.
5924  *
5925  * @param[in] dev
5926  *   Pointer to the Ethernet device structure.
5927  * @param[in] counter
5928  *   Index to the flow counter.
5929  * @param[out] pkts
5930  *   The statistics value of packets.
5931  * @param[out] bytes
5932  *   The statistics value of bytes.
5933  *
5934  * @return
5935  *   0 on success, otherwise a negative errno value and rte_errno is set.
5936  */
5937 static inline int
5938 _flow_dv_query_count(struct rte_eth_dev *dev, uint32_t counter, uint64_t *pkts,
5939                      uint64_t *bytes)
5940 {
5941         struct mlx5_priv *priv = dev->data->dev_private;
5942         struct mlx5_flow_counter_pool *pool = NULL;
5943         struct mlx5_flow_counter *cnt;
5944         int offset;
5945
5946         cnt = flow_dv_counter_get_by_idx(dev, counter, &pool);
5947         MLX5_ASSERT(pool);
5948         if (priv->sh->cmng.counter_fallback)
5949                 return mlx5_devx_cmd_flow_counter_query(cnt->dcs_when_active, 0,
5950                                         0, pkts, bytes, 0, NULL, NULL, 0);
5951         rte_spinlock_lock(&pool->sl);
5952         if (!pool->raw) {
5953                 *pkts = 0;
5954                 *bytes = 0;
5955         } else {
5956                 offset = MLX5_CNT_ARRAY_IDX(pool, cnt);
5957                 *pkts = rte_be_to_cpu_64(pool->raw->data[offset].hits);
5958                 *bytes = rte_be_to_cpu_64(pool->raw->data[offset].bytes);
5959         }
5960         rte_spinlock_unlock(&pool->sl);
5961         return 0;
5962 }
5963
5964 /**
5965  * Create and initialize a new counter pool.
5966  *
5967  * @param[in] dev
5968  *   Pointer to the Ethernet device structure.
5969  * @param[out] dcs
5970  *   The devX counter handle.
5971  * @param[in] age
5972  *   Whether the pool is for counter that was allocated for aging.
5973  * @param[in/out] cont_cur
5974  *   Pointer to the container pointer, it will be update in pool resize.
5975  *
5976  * @return
5977  *   The pool container pointer on success, NULL otherwise and rte_errno is set.
5978  */
5979 static struct mlx5_flow_counter_pool *
5980 flow_dv_pool_create(struct rte_eth_dev *dev, struct mlx5_devx_obj *dcs,
5981                     uint32_t age)
5982 {
5983         struct mlx5_priv *priv = dev->data->dev_private;
5984         struct mlx5_flow_counter_pool *pool;
5985         struct mlx5_flow_counter_mng *cmng = &priv->sh->cmng;
5986         bool fallback = priv->sh->cmng.counter_fallback;
5987         uint32_t size = sizeof(*pool);
5988
5989         size += MLX5_COUNTERS_PER_POOL * MLX5_CNT_SIZE;
5990         size += (!age ? 0 : MLX5_COUNTERS_PER_POOL * MLX5_AGE_SIZE);
5991         pool = mlx5_malloc(MLX5_MEM_ZERO, size, 0, SOCKET_ID_ANY);
5992         if (!pool) {
5993                 rte_errno = ENOMEM;
5994                 return NULL;
5995         }
5996         pool->raw = NULL;
5997         pool->is_aged = !!age;
5998         pool->query_gen = 0;
5999         pool->min_dcs = dcs;
6000         rte_spinlock_init(&pool->sl);
6001         rte_spinlock_init(&pool->csl);
6002         TAILQ_INIT(&pool->counters[0]);
6003         TAILQ_INIT(&pool->counters[1]);
6004         pool->time_of_last_age_check = MLX5_CURR_TIME_SEC;
6005         rte_spinlock_lock(&cmng->pool_update_sl);
6006         pool->index = cmng->n_valid;
6007         if (pool->index == cmng->n && flow_dv_container_resize(dev)) {
6008                 mlx5_free(pool);
6009                 rte_spinlock_unlock(&cmng->pool_update_sl);
6010                 return NULL;
6011         }
6012         cmng->pools[pool->index] = pool;
6013         cmng->n_valid++;
6014         if (unlikely(fallback)) {
6015                 int base = RTE_ALIGN_FLOOR(dcs->id, MLX5_COUNTERS_PER_POOL);
6016
6017                 if (base < cmng->min_id)
6018                         cmng->min_id = base;
6019                 if (base > cmng->max_id)
6020                         cmng->max_id = base + MLX5_COUNTERS_PER_POOL - 1;
6021                 cmng->last_pool_idx = pool->index;
6022         }
6023         rte_spinlock_unlock(&cmng->pool_update_sl);
6024         return pool;
6025 }
6026
6027 /**
6028  * Prepare a new counter and/or a new counter pool.
6029  *
6030  * @param[in] dev
6031  *   Pointer to the Ethernet device structure.
6032  * @param[out] cnt_free
6033  *   Where to put the pointer of a new counter.
6034  * @param[in] age
6035  *   Whether the pool is for counter that was allocated for aging.
6036  *
6037  * @return
6038  *   The counter pool pointer and @p cnt_free is set on success,
6039  *   NULL otherwise and rte_errno is set.
6040  */
6041 static struct mlx5_flow_counter_pool *
6042 flow_dv_counter_pool_prepare(struct rte_eth_dev *dev,
6043                              struct mlx5_flow_counter **cnt_free,
6044                              uint32_t age)
6045 {
6046         struct mlx5_priv *priv = dev->data->dev_private;
6047         struct mlx5_flow_counter_mng *cmng = &priv->sh->cmng;
6048         struct mlx5_flow_counter_pool *pool;
6049         struct mlx5_counters tmp_tq;
6050         struct mlx5_devx_obj *dcs = NULL;
6051         struct mlx5_flow_counter *cnt;
6052         enum mlx5_counter_type cnt_type =
6053                         age ? MLX5_COUNTER_TYPE_AGE : MLX5_COUNTER_TYPE_ORIGIN;
6054         bool fallback = priv->sh->cmng.counter_fallback;
6055         uint32_t i;
6056
6057         if (fallback) {
6058                 /* bulk_bitmap must be 0 for single counter allocation. */
6059                 dcs = mlx5_devx_cmd_flow_counter_alloc(priv->sh->cdev->ctx, 0);
6060                 if (!dcs)
6061                         return NULL;
6062                 pool = flow_dv_find_pool_by_id(cmng, dcs->id);
6063                 if (!pool) {
6064                         pool = flow_dv_pool_create(dev, dcs, age);
6065                         if (!pool) {
6066                                 mlx5_devx_cmd_destroy(dcs);
6067                                 return NULL;
6068                         }
6069                 }
6070                 i = dcs->id % MLX5_COUNTERS_PER_POOL;
6071                 cnt = MLX5_POOL_GET_CNT(pool, i);
6072                 cnt->pool = pool;
6073                 cnt->dcs_when_free = dcs;
6074                 *cnt_free = cnt;
6075                 return pool;
6076         }
6077         dcs = mlx5_devx_cmd_flow_counter_alloc(priv->sh->cdev->ctx, 0x4);
6078         if (!dcs) {
6079                 rte_errno = ENODATA;
6080                 return NULL;
6081         }
6082         pool = flow_dv_pool_create(dev, dcs, age);
6083         if (!pool) {
6084                 mlx5_devx_cmd_destroy(dcs);
6085                 return NULL;
6086         }
6087         TAILQ_INIT(&tmp_tq);
6088         for (i = 1; i < MLX5_COUNTERS_PER_POOL; ++i) {
6089                 cnt = MLX5_POOL_GET_CNT(pool, i);
6090                 cnt->pool = pool;
6091                 TAILQ_INSERT_HEAD(&tmp_tq, cnt, next);
6092         }
6093         rte_spinlock_lock(&cmng->csl[cnt_type]);
6094         TAILQ_CONCAT(&cmng->counters[cnt_type], &tmp_tq, next);
6095         rte_spinlock_unlock(&cmng->csl[cnt_type]);
6096         *cnt_free = MLX5_POOL_GET_CNT(pool, 0);
6097         (*cnt_free)->pool = pool;
6098         return pool;
6099 }
6100
6101 /**
6102  * Allocate a flow counter.
6103  *
6104  * @param[in] dev
6105  *   Pointer to the Ethernet device structure.
6106  * @param[in] age
6107  *   Whether the counter was allocated for aging.
6108  *
6109  * @return
6110  *   Index to flow counter on success, 0 otherwise and rte_errno is set.
6111  */
6112 static uint32_t
6113 flow_dv_counter_alloc(struct rte_eth_dev *dev, uint32_t age)
6114 {
6115         struct mlx5_priv *priv = dev->data->dev_private;
6116         struct mlx5_flow_counter_pool *pool = NULL;
6117         struct mlx5_flow_counter *cnt_free = NULL;
6118         bool fallback = priv->sh->cmng.counter_fallback;
6119         struct mlx5_flow_counter_mng *cmng = &priv->sh->cmng;
6120         enum mlx5_counter_type cnt_type =
6121                         age ? MLX5_COUNTER_TYPE_AGE : MLX5_COUNTER_TYPE_ORIGIN;
6122         uint32_t cnt_idx;
6123
6124         if (!priv->sh->devx) {
6125                 rte_errno = ENOTSUP;
6126                 return 0;
6127         }
6128         /* Get free counters from container. */
6129         rte_spinlock_lock(&cmng->csl[cnt_type]);
6130         cnt_free = TAILQ_FIRST(&cmng->counters[cnt_type]);
6131         if (cnt_free)
6132                 TAILQ_REMOVE(&cmng->counters[cnt_type], cnt_free, next);
6133         rte_spinlock_unlock(&cmng->csl[cnt_type]);
6134         if (!cnt_free && !flow_dv_counter_pool_prepare(dev, &cnt_free, age))
6135                 goto err;
6136         pool = cnt_free->pool;
6137         if (fallback)
6138                 cnt_free->dcs_when_active = cnt_free->dcs_when_free;
6139         /* Create a DV counter action only in the first time usage. */
6140         if (!cnt_free->action) {
6141                 uint16_t offset;
6142                 struct mlx5_devx_obj *dcs;
6143                 int ret;
6144
6145                 if (!fallback) {
6146                         offset = MLX5_CNT_ARRAY_IDX(pool, cnt_free);
6147                         dcs = pool->min_dcs;
6148                 } else {
6149                         offset = 0;
6150                         dcs = cnt_free->dcs_when_free;
6151                 }
6152                 ret = mlx5_flow_os_create_flow_action_count(dcs->obj, offset,
6153                                                             &cnt_free->action);
6154                 if (ret) {
6155                         rte_errno = errno;
6156                         goto err;
6157                 }
6158         }
6159         cnt_idx = MLX5_MAKE_CNT_IDX(pool->index,
6160                                 MLX5_CNT_ARRAY_IDX(pool, cnt_free));
6161         /* Update the counter reset values. */
6162         if (_flow_dv_query_count(dev, cnt_idx, &cnt_free->hits,
6163                                  &cnt_free->bytes))
6164                 goto err;
6165         if (!fallback && !priv->sh->cmng.query_thread_on)
6166                 /* Start the asynchronous batch query by the host thread. */
6167                 mlx5_set_query_alarm(priv->sh);
6168         /*
6169          * When the count action isn't shared (by ID), shared_info field is
6170          * used for indirect action API's refcnt.
6171          * When the counter action is not shared neither by ID nor by indirect
6172          * action API, shared info must be 1.
6173          */
6174         cnt_free->shared_info.refcnt = 1;
6175         return cnt_idx;
6176 err:
6177         if (cnt_free) {
6178                 cnt_free->pool = pool;
6179                 if (fallback)
6180                         cnt_free->dcs_when_free = cnt_free->dcs_when_active;
6181                 rte_spinlock_lock(&cmng->csl[cnt_type]);
6182                 TAILQ_INSERT_TAIL(&cmng->counters[cnt_type], cnt_free, next);
6183                 rte_spinlock_unlock(&cmng->csl[cnt_type]);
6184         }
6185         return 0;
6186 }
6187
6188 /**
6189  * Get age param from counter index.
6190  *
6191  * @param[in] dev
6192  *   Pointer to the Ethernet device structure.
6193  * @param[in] counter
6194  *   Index to the counter handler.
6195  *
6196  * @return
6197  *   The aging parameter specified for the counter index.
6198  */
6199 static struct mlx5_age_param*
6200 flow_dv_counter_idx_get_age(struct rte_eth_dev *dev,
6201                                 uint32_t counter)
6202 {
6203         struct mlx5_flow_counter *cnt;
6204         struct mlx5_flow_counter_pool *pool = NULL;
6205
6206         flow_dv_counter_get_by_idx(dev, counter, &pool);
6207         counter = (counter - 1) % MLX5_COUNTERS_PER_POOL;
6208         cnt = MLX5_POOL_GET_CNT(pool, counter);
6209         return MLX5_CNT_TO_AGE(cnt);
6210 }
6211
6212 /**
6213  * Remove a flow counter from aged counter list.
6214  *
6215  * @param[in] dev
6216  *   Pointer to the Ethernet device structure.
6217  * @param[in] counter
6218  *   Index to the counter handler.
6219  * @param[in] cnt
6220  *   Pointer to the counter handler.
6221  */
6222 static void
6223 flow_dv_counter_remove_from_age(struct rte_eth_dev *dev,
6224                                 uint32_t counter, struct mlx5_flow_counter *cnt)
6225 {
6226         struct mlx5_age_info *age_info;
6227         struct mlx5_age_param *age_param;
6228         struct mlx5_priv *priv = dev->data->dev_private;
6229         uint16_t expected = AGE_CANDIDATE;
6230
6231         age_info = GET_PORT_AGE_INFO(priv);
6232         age_param = flow_dv_counter_idx_get_age(dev, counter);
6233         if (!__atomic_compare_exchange_n(&age_param->state, &expected,
6234                                          AGE_FREE, false, __ATOMIC_RELAXED,
6235                                          __ATOMIC_RELAXED)) {
6236                 /**
6237                  * We need the lock even it is age timeout,
6238                  * since counter may still in process.
6239                  */
6240                 rte_spinlock_lock(&age_info->aged_sl);
6241                 TAILQ_REMOVE(&age_info->aged_counters, cnt, next);
6242                 rte_spinlock_unlock(&age_info->aged_sl);
6243                 __atomic_store_n(&age_param->state, AGE_FREE, __ATOMIC_RELAXED);
6244         }
6245 }
6246
6247 /**
6248  * Release a flow counter.
6249  *
6250  * @param[in] dev
6251  *   Pointer to the Ethernet device structure.
6252  * @param[in] counter
6253  *   Index to the counter handler.
6254  */
6255 static void
6256 flow_dv_counter_free(struct rte_eth_dev *dev, uint32_t counter)
6257 {
6258         struct mlx5_priv *priv = dev->data->dev_private;
6259         struct mlx5_flow_counter_pool *pool = NULL;
6260         struct mlx5_flow_counter *cnt;
6261         enum mlx5_counter_type cnt_type;
6262
6263         if (!counter)
6264                 return;
6265         cnt = flow_dv_counter_get_by_idx(dev, counter, &pool);
6266         MLX5_ASSERT(pool);
6267         if (pool->is_aged) {
6268                 flow_dv_counter_remove_from_age(dev, counter, cnt);
6269         } else {
6270                 /*
6271                  * If the counter action is shared by indirect action API,
6272                  * the atomic function reduces its references counter.
6273                  * If after the reduction the action is still referenced, the
6274                  * function returns here and does not release it.
6275                  * When the counter action is not shared by
6276                  * indirect action API, shared info is 1 before the reduction,
6277                  * so this condition is failed and function doesn't return here.
6278                  */
6279                 if (__atomic_sub_fetch(&cnt->shared_info.refcnt, 1,
6280                                        __ATOMIC_RELAXED))
6281                         return;
6282         }
6283         cnt->pool = pool;
6284         /*
6285          * Put the counter back to list to be updated in none fallback mode.
6286          * Currently, we are using two list alternately, while one is in query,
6287          * add the freed counter to the other list based on the pool query_gen
6288          * value. After query finishes, add counter the list to the global
6289          * container counter list. The list changes while query starts. In
6290          * this case, lock will not be needed as query callback and release
6291          * function both operate with the different list.
6292          */
6293         if (!priv->sh->cmng.counter_fallback) {
6294                 rte_spinlock_lock(&pool->csl);
6295                 TAILQ_INSERT_TAIL(&pool->counters[pool->query_gen], cnt, next);
6296                 rte_spinlock_unlock(&pool->csl);
6297         } else {
6298                 cnt->dcs_when_free = cnt->dcs_when_active;
6299                 cnt_type = pool->is_aged ? MLX5_COUNTER_TYPE_AGE :
6300                                            MLX5_COUNTER_TYPE_ORIGIN;
6301                 rte_spinlock_lock(&priv->sh->cmng.csl[cnt_type]);
6302                 TAILQ_INSERT_TAIL(&priv->sh->cmng.counters[cnt_type],
6303                                   cnt, next);
6304                 rte_spinlock_unlock(&priv->sh->cmng.csl[cnt_type]);
6305         }
6306 }
6307
6308 /**
6309  * Resize a meter id container.
6310  *
6311  * @param[in] dev
6312  *   Pointer to the Ethernet device structure.
6313  *
6314  * @return
6315  *   0 on success, otherwise negative errno value and rte_errno is set.
6316  */
6317 static int
6318 flow_dv_mtr_container_resize(struct rte_eth_dev *dev)
6319 {
6320         struct mlx5_priv *priv = dev->data->dev_private;
6321         struct mlx5_aso_mtr_pools_mng *pools_mng =
6322                                 &priv->sh->mtrmng->pools_mng;
6323         void *old_pools = pools_mng->pools;
6324         uint32_t resize = pools_mng->n + MLX5_MTRS_CONTAINER_RESIZE;
6325         uint32_t mem_size = sizeof(struct mlx5_aso_mtr_pool *) * resize;
6326         void *pools = mlx5_malloc(MLX5_MEM_ZERO, mem_size, 0, SOCKET_ID_ANY);
6327
6328         if (!pools) {
6329                 rte_errno = ENOMEM;
6330                 return -ENOMEM;
6331         }
6332         if (!pools_mng->n)
6333                 if (mlx5_aso_queue_init(priv->sh, ASO_OPC_MOD_POLICER)) {
6334                         mlx5_free(pools);
6335                         return -ENOMEM;
6336                 }
6337         if (old_pools)
6338                 memcpy(pools, old_pools, pools_mng->n *
6339                                        sizeof(struct mlx5_aso_mtr_pool *));
6340         pools_mng->n = resize;
6341         pools_mng->pools = pools;
6342         if (old_pools)
6343                 mlx5_free(old_pools);
6344         return 0;
6345 }
6346
6347 /**
6348  * Prepare a new meter and/or a new meter pool.
6349  *
6350  * @param[in] dev
6351  *   Pointer to the Ethernet device structure.
6352  * @param[out] mtr_free
6353  *   Where to put the pointer of a new meter.g.
6354  *
6355  * @return
6356  *   The meter pool pointer and @mtr_free is set on success,
6357  *   NULL otherwise and rte_errno is set.
6358  */
6359 static struct mlx5_aso_mtr_pool *
6360 flow_dv_mtr_pool_create(struct rte_eth_dev *dev, struct mlx5_aso_mtr **mtr_free)
6361 {
6362         struct mlx5_priv *priv = dev->data->dev_private;
6363         struct mlx5_aso_mtr_pools_mng *pools_mng = &priv->sh->mtrmng->pools_mng;
6364         struct mlx5_aso_mtr_pool *pool = NULL;
6365         struct mlx5_devx_obj *dcs = NULL;
6366         uint32_t i;
6367         uint32_t log_obj_size;
6368
6369         log_obj_size = rte_log2_u32(MLX5_ASO_MTRS_PER_POOL >> 1);
6370         dcs = mlx5_devx_cmd_create_flow_meter_aso_obj(priv->sh->cdev->ctx,
6371                                                       priv->sh->cdev->pdn,
6372                                                       log_obj_size);
6373         if (!dcs) {
6374                 rte_errno = ENODATA;
6375                 return NULL;
6376         }
6377         pool = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*pool), 0, SOCKET_ID_ANY);
6378         if (!pool) {
6379                 rte_errno = ENOMEM;
6380                 claim_zero(mlx5_devx_cmd_destroy(dcs));
6381                 return NULL;
6382         }
6383         pool->devx_obj = dcs;
6384         pool->index = pools_mng->n_valid;
6385         if (pool->index == pools_mng->n && flow_dv_mtr_container_resize(dev)) {
6386                 mlx5_free(pool);
6387                 claim_zero(mlx5_devx_cmd_destroy(dcs));
6388                 return NULL;
6389         }
6390         pools_mng->pools[pool->index] = pool;
6391         pools_mng->n_valid++;
6392         for (i = 1; i < MLX5_ASO_MTRS_PER_POOL; ++i) {
6393                 pool->mtrs[i].offset = i;
6394                 LIST_INSERT_HEAD(&pools_mng->meters, &pool->mtrs[i], next);
6395         }
6396         pool->mtrs[0].offset = 0;
6397         *mtr_free = &pool->mtrs[0];
6398         return pool;
6399 }
6400
6401 /**
6402  * Release a flow meter into pool.
6403  *
6404  * @param[in] dev
6405  *   Pointer to the Ethernet device structure.
6406  * @param[in] mtr_idx
6407  *   Index to aso flow meter.
6408  */
6409 static void
6410 flow_dv_aso_mtr_release_to_pool(struct rte_eth_dev *dev, uint32_t mtr_idx)
6411 {
6412         struct mlx5_priv *priv = dev->data->dev_private;
6413         struct mlx5_aso_mtr_pools_mng *pools_mng =
6414                                 &priv->sh->mtrmng->pools_mng;
6415         struct mlx5_aso_mtr *aso_mtr = mlx5_aso_meter_by_idx(priv, mtr_idx);
6416
6417         MLX5_ASSERT(aso_mtr);
6418         rte_spinlock_lock(&pools_mng->mtrsl);
6419         memset(&aso_mtr->fm, 0, sizeof(struct mlx5_flow_meter_info));
6420         aso_mtr->state = ASO_METER_FREE;
6421         LIST_INSERT_HEAD(&pools_mng->meters, aso_mtr, next);
6422         rte_spinlock_unlock(&pools_mng->mtrsl);
6423 }
6424
6425 /**
6426  * Allocate a aso flow meter.
6427  *
6428  * @param[in] dev
6429  *   Pointer to the Ethernet device structure.
6430  *
6431  * @return
6432  *   Index to aso flow meter on success, 0 otherwise and rte_errno is set.
6433  */
6434 static uint32_t
6435 flow_dv_mtr_alloc(struct rte_eth_dev *dev)
6436 {
6437         struct mlx5_priv *priv = dev->data->dev_private;
6438         struct mlx5_aso_mtr *mtr_free = NULL;
6439         struct mlx5_aso_mtr_pools_mng *pools_mng =
6440                                 &priv->sh->mtrmng->pools_mng;
6441         struct mlx5_aso_mtr_pool *pool;
6442         uint32_t mtr_idx = 0;
6443
6444         if (!priv->sh->devx) {
6445                 rte_errno = ENOTSUP;
6446                 return 0;
6447         }
6448         /* Allocate the flow meter memory. */
6449         /* Get free meters from management. */
6450         rte_spinlock_lock(&pools_mng->mtrsl);
6451         mtr_free = LIST_FIRST(&pools_mng->meters);
6452         if (mtr_free)
6453                 LIST_REMOVE(mtr_free, next);
6454         if (!mtr_free && !flow_dv_mtr_pool_create(dev, &mtr_free)) {
6455                 rte_spinlock_unlock(&pools_mng->mtrsl);
6456                 return 0;
6457         }
6458         mtr_free->state = ASO_METER_WAIT;
6459         rte_spinlock_unlock(&pools_mng->mtrsl);
6460         pool = container_of(mtr_free,
6461                         struct mlx5_aso_mtr_pool,
6462                         mtrs[mtr_free->offset]);
6463         mtr_idx = MLX5_MAKE_MTR_IDX(pool->index, mtr_free->offset);
6464         if (!mtr_free->fm.meter_action) {
6465 #ifdef HAVE_MLX5_DR_CREATE_ACTION_ASO
6466                 struct rte_flow_error error;
6467                 uint8_t reg_id;
6468
6469                 reg_id = mlx5_flow_get_reg_id(dev, MLX5_MTR_COLOR, 0, &error);
6470                 mtr_free->fm.meter_action =
6471                         mlx5_glue->dv_create_flow_action_aso
6472                                                 (priv->sh->rx_domain,
6473                                                  pool->devx_obj->obj,
6474                                                  mtr_free->offset,
6475                                                  (1 << MLX5_FLOW_COLOR_GREEN),
6476                                                  reg_id - REG_C_0);
6477 #endif /* HAVE_MLX5_DR_CREATE_ACTION_ASO */
6478                 if (!mtr_free->fm.meter_action) {
6479                         flow_dv_aso_mtr_release_to_pool(dev, mtr_idx);
6480                         return 0;
6481                 }
6482         }
6483         return mtr_idx;
6484 }
6485
6486 /**
6487  * Verify the @p attributes will be correctly understood by the NIC and store
6488  * them in the @p flow if everything is correct.
6489  *
6490  * @param[in] dev
6491  *   Pointer to dev struct.
6492  * @param[in] attributes
6493  *   Pointer to flow attributes
6494  * @param[in] external
6495  *   This flow rule is created by request external to PMD.
6496  * @param[out] error
6497  *   Pointer to error structure.
6498  *
6499  * @return
6500  *   - 0 on success and non root table.
6501  *   - 1 on success and root table.
6502  *   - a negative errno value otherwise and rte_errno is set.
6503  */
6504 static int
6505 flow_dv_validate_attributes(struct rte_eth_dev *dev,
6506                             const struct mlx5_flow_tunnel *tunnel,
6507                             const struct rte_flow_attr *attributes,
6508                             const struct flow_grp_info *grp_info,
6509                             struct rte_flow_error *error)
6510 {
6511         struct mlx5_priv *priv = dev->data->dev_private;
6512         uint32_t lowest_priority = mlx5_get_lowest_priority(dev, attributes);
6513         int ret = 0;
6514
6515 #ifndef HAVE_MLX5DV_DR
6516         RTE_SET_USED(tunnel);
6517         RTE_SET_USED(grp_info);
6518         if (attributes->group)
6519                 return rte_flow_error_set(error, ENOTSUP,
6520                                           RTE_FLOW_ERROR_TYPE_ATTR_GROUP,
6521                                           NULL,
6522                                           "groups are not supported");
6523 #else
6524         uint32_t table = 0;
6525
6526         ret = mlx5_flow_group_to_table(dev, tunnel, attributes->group, &table,
6527                                        grp_info, error);
6528         if (ret)
6529                 return ret;
6530         if (!table)
6531                 ret = MLX5DV_DR_ACTION_FLAGS_ROOT_LEVEL;
6532 #endif
6533         if (attributes->priority != MLX5_FLOW_LOWEST_PRIO_INDICATOR &&
6534             attributes->priority > lowest_priority)
6535                 return rte_flow_error_set(error, ENOTSUP,
6536                                           RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY,
6537                                           NULL,
6538                                           "priority out of range");
6539         if (attributes->transfer) {
6540                 if (!priv->config.dv_esw_en)
6541                         return rte_flow_error_set
6542                                 (error, ENOTSUP,
6543                                  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
6544                                  "E-Switch dr is not supported");
6545                 if (!(priv->representor || priv->master))
6546                         return rte_flow_error_set
6547                                 (error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
6548                                  NULL, "E-Switch configuration can only be"
6549                                  " done by a master or a representor device");
6550                 if (attributes->egress)
6551                         return rte_flow_error_set
6552                                 (error, ENOTSUP,
6553                                  RTE_FLOW_ERROR_TYPE_ATTR_EGRESS, attributes,
6554                                  "egress is not supported");
6555         }
6556         if (!(attributes->egress ^ attributes->ingress))
6557                 return rte_flow_error_set(error, ENOTSUP,
6558                                           RTE_FLOW_ERROR_TYPE_ATTR, NULL,
6559                                           "must specify exactly one of "
6560                                           "ingress or egress");
6561         return ret;
6562 }
6563
6564 static uint16_t
6565 mlx5_flow_locate_proto_l3(const struct rte_flow_item **head,
6566                           const struct rte_flow_item *end)
6567 {
6568         const struct rte_flow_item *item = *head;
6569         uint16_t l3_protocol;
6570
6571         for (; item != end; item++) {
6572                 switch (item->type) {
6573                 default:
6574                         break;
6575                 case RTE_FLOW_ITEM_TYPE_IPV4:
6576                         l3_protocol = RTE_ETHER_TYPE_IPV4;
6577                         goto l3_ok;
6578                 case RTE_FLOW_ITEM_TYPE_IPV6:
6579                         l3_protocol = RTE_ETHER_TYPE_IPV6;
6580                         goto l3_ok;
6581                 case RTE_FLOW_ITEM_TYPE_ETH:
6582                         if (item->mask && item->spec) {
6583                                 MLX5_ETHER_TYPE_FROM_HEADER(rte_flow_item_eth,
6584                                                             type, item,
6585                                                             l3_protocol);
6586                                 if (l3_protocol == RTE_ETHER_TYPE_IPV4 ||
6587                                     l3_protocol == RTE_ETHER_TYPE_IPV6)
6588                                         goto l3_ok;
6589                         }
6590                         break;
6591                 case RTE_FLOW_ITEM_TYPE_VLAN:
6592                         if (item->mask && item->spec) {
6593                                 MLX5_ETHER_TYPE_FROM_HEADER(rte_flow_item_vlan,
6594                                                             inner_type, item,
6595                                                             l3_protocol);
6596                                 if (l3_protocol == RTE_ETHER_TYPE_IPV4 ||
6597                                     l3_protocol == RTE_ETHER_TYPE_IPV6)
6598                                         goto l3_ok;
6599                         }
6600                         break;
6601                 }
6602         }
6603         return 0;
6604 l3_ok:
6605         *head = item;
6606         return l3_protocol;
6607 }
6608
6609 static uint8_t
6610 mlx5_flow_locate_proto_l4(const struct rte_flow_item **head,
6611                           const struct rte_flow_item *end)
6612 {
6613         const struct rte_flow_item *item = *head;
6614         uint8_t l4_protocol;
6615
6616         for (; item != end; item++) {
6617                 switch (item->type) {
6618                 default:
6619                         break;
6620                 case RTE_FLOW_ITEM_TYPE_TCP:
6621                         l4_protocol = IPPROTO_TCP;
6622                         goto l4_ok;
6623                 case RTE_FLOW_ITEM_TYPE_UDP:
6624                         l4_protocol = IPPROTO_UDP;
6625                         goto l4_ok;
6626                 case RTE_FLOW_ITEM_TYPE_IPV4:
6627                         if (item->mask && item->spec) {
6628                                 const struct rte_flow_item_ipv4 *mask, *spec;
6629
6630                                 mask = (typeof(mask))item->mask;
6631                                 spec = (typeof(spec))item->spec;
6632                                 l4_protocol = mask->hdr.next_proto_id &
6633                                               spec->hdr.next_proto_id;
6634                                 if (l4_protocol == IPPROTO_TCP ||
6635                                     l4_protocol == IPPROTO_UDP)
6636                                         goto l4_ok;
6637                         }
6638                         break;
6639                 case RTE_FLOW_ITEM_TYPE_IPV6:
6640                         if (item->mask && item->spec) {
6641                                 const struct rte_flow_item_ipv6 *mask, *spec;
6642                                 mask = (typeof(mask))item->mask;
6643                                 spec = (typeof(spec))item->spec;
6644                                 l4_protocol = mask->hdr.proto & spec->hdr.proto;
6645                                 if (l4_protocol == IPPROTO_TCP ||
6646                                     l4_protocol == IPPROTO_UDP)
6647                                         goto l4_ok;
6648                         }
6649                         break;
6650                 }
6651         }
6652         return 0;
6653 l4_ok:
6654         *head = item;
6655         return l4_protocol;
6656 }
6657
6658 static int
6659 flow_dv_validate_item_integrity(struct rte_eth_dev *dev,
6660                                 const struct rte_flow_item *rule_items,
6661                                 const struct rte_flow_item *integrity_item,
6662                                 struct rte_flow_error *error)
6663 {
6664         struct mlx5_priv *priv = dev->data->dev_private;
6665         const struct rte_flow_item *tunnel_item, *end_item, *item = rule_items;
6666         const struct rte_flow_item_integrity *mask = (typeof(mask))
6667                                                      integrity_item->mask;
6668         const struct rte_flow_item_integrity *spec = (typeof(spec))
6669                                                      integrity_item->spec;
6670         uint32_t protocol;
6671
6672         if (!priv->config.hca_attr.pkt_integrity_match)
6673                 return rte_flow_error_set(error, ENOTSUP,
6674                                           RTE_FLOW_ERROR_TYPE_ITEM,
6675                                           integrity_item,
6676                                           "packet integrity integrity_item not supported");
6677         if (!mask)
6678                 mask = &rte_flow_item_integrity_mask;
6679         if (!mlx5_validate_integrity_item(mask))
6680                 return rte_flow_error_set(error, ENOTSUP,
6681                                           RTE_FLOW_ERROR_TYPE_ITEM,
6682                                           integrity_item,
6683                                           "unsupported integrity filter");
6684         tunnel_item = mlx5_flow_find_tunnel_item(rule_items);
6685         if (spec->level > 1) {
6686                 if (!tunnel_item)
6687                         return rte_flow_error_set(error, ENOTSUP,
6688                                                   RTE_FLOW_ERROR_TYPE_ITEM,
6689                                                   integrity_item,
6690                                                   "missing tunnel item");
6691                 item = tunnel_item;
6692                 end_item = mlx5_find_end_item(tunnel_item);
6693         } else {
6694                 end_item = tunnel_item ? tunnel_item :
6695                            mlx5_find_end_item(integrity_item);
6696         }
6697         if (mask->l3_ok || mask->ipv4_csum_ok) {
6698                 protocol = mlx5_flow_locate_proto_l3(&item, end_item);
6699                 if (!protocol)
6700                         return rte_flow_error_set(error, EINVAL,
6701                                                   RTE_FLOW_ERROR_TYPE_ITEM,
6702                                                   integrity_item,
6703                                                   "missing L3 protocol");
6704         }
6705         if (mask->l4_ok || mask->l4_csum_ok) {
6706                 protocol = mlx5_flow_locate_proto_l4(&item, end_item);
6707                 if (!protocol)
6708                         return rte_flow_error_set(error, EINVAL,
6709                                                   RTE_FLOW_ERROR_TYPE_ITEM,
6710                                                   integrity_item,
6711                                                   "missing L4 protocol");
6712         }
6713         return 0;
6714 }
6715
6716 /**
6717  * Internal validation function. For validating both actions and items.
6718  *
6719  * @param[in] dev
6720  *   Pointer to the rte_eth_dev structure.
6721  * @param[in] attr
6722  *   Pointer to the flow attributes.
6723  * @param[in] items
6724  *   Pointer to the list of items.
6725  * @param[in] actions
6726  *   Pointer to the list of actions.
6727  * @param[in] external
6728  *   This flow rule is created by request external to PMD.
6729  * @param[in] hairpin
6730  *   Number of hairpin TX actions, 0 means classic flow.
6731  * @param[out] error
6732  *   Pointer to the error structure.
6733  *
6734  * @return
6735  *   0 on success, a negative errno value otherwise and rte_errno is set.
6736  */
6737 static int
6738 flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
6739                  const struct rte_flow_item items[],
6740                  const struct rte_flow_action actions[],
6741                  bool external, int hairpin, struct rte_flow_error *error)
6742 {
6743         int ret;
6744         uint64_t action_flags = 0;
6745         uint64_t item_flags = 0;
6746         uint64_t last_item = 0;
6747         uint8_t next_protocol = 0xff;
6748         uint16_t ether_type = 0;
6749         int actions_n = 0;
6750         uint8_t item_ipv6_proto = 0;
6751         int fdb_mirror_limit = 0;
6752         int modify_after_mirror = 0;
6753         const struct rte_flow_item *geneve_item = NULL;
6754         const struct rte_flow_item *gre_item = NULL;
6755         const struct rte_flow_item *gtp_item = NULL;
6756         const struct rte_flow_action_raw_decap *decap;
6757         const struct rte_flow_action_raw_encap *encap;
6758         const struct rte_flow_action_rss *rss = NULL;
6759         const struct rte_flow_action_rss *sample_rss = NULL;
6760         const struct rte_flow_action_count *sample_count = NULL;
6761         const struct rte_flow_item_tcp nic_tcp_mask = {
6762                 .hdr = {
6763                         .tcp_flags = 0xFF,
6764                         .src_port = RTE_BE16(UINT16_MAX),
6765                         .dst_port = RTE_BE16(UINT16_MAX),
6766                 }
6767         };
6768         const struct rte_flow_item_ipv6 nic_ipv6_mask = {
6769                 .hdr = {
6770                         .src_addr =
6771                         "\xff\xff\xff\xff\xff\xff\xff\xff"
6772                         "\xff\xff\xff\xff\xff\xff\xff\xff",
6773                         .dst_addr =
6774                         "\xff\xff\xff\xff\xff\xff\xff\xff"
6775                         "\xff\xff\xff\xff\xff\xff\xff\xff",
6776                         .vtc_flow = RTE_BE32(0xffffffff),
6777                         .proto = 0xff,
6778                         .hop_limits = 0xff,
6779                 },
6780                 .has_frag_ext = 1,
6781         };
6782         const struct rte_flow_item_ecpri nic_ecpri_mask = {
6783                 .hdr = {
6784                         .common = {
6785                                 .u32 =
6786                                 RTE_BE32(((const struct rte_ecpri_common_hdr) {
6787                                         .type = 0xFF,
6788                                         }).u32),
6789                         },
6790                         .dummy[0] = 0xffffffff,
6791                 },
6792         };
6793         struct mlx5_priv *priv = dev->data->dev_private;
6794         struct mlx5_dev_config *dev_conf = &priv->config;
6795         uint16_t queue_index = 0xFFFF;
6796         const struct rte_flow_item_vlan *vlan_m = NULL;
6797         uint32_t rw_act_num = 0;
6798         uint64_t is_root;
6799         const struct mlx5_flow_tunnel *tunnel;
6800         enum mlx5_tof_rule_type tof_rule_type;
6801         struct flow_grp_info grp_info = {
6802                 .external = !!external,
6803                 .transfer = !!attr->transfer,
6804                 .fdb_def_rule = !!priv->fdb_def_rule,
6805                 .std_tbl_fix = true,
6806         };
6807         const struct rte_eth_hairpin_conf *conf;
6808         const struct rte_flow_item *rule_items = items;
6809         const struct rte_flow_item *port_id_item = NULL;
6810         bool def_policy = false;
6811         uint16_t udp_dport = 0;
6812
6813         if (items == NULL)
6814                 return -1;
6815         tunnel = is_tunnel_offload_active(dev) ?
6816                  mlx5_get_tof(items, actions, &tof_rule_type) : NULL;
6817         if (tunnel) {
6818                 if (priv->representor)
6819                         return rte_flow_error_set
6820                                 (error, ENOTSUP,
6821                                  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
6822                                  NULL, "decap not supported for VF representor");
6823                 if (tof_rule_type == MLX5_TUNNEL_OFFLOAD_SET_RULE)
6824                         action_flags |= MLX5_FLOW_ACTION_TUNNEL_SET;
6825                 else if (tof_rule_type == MLX5_TUNNEL_OFFLOAD_MATCH_RULE)
6826                         action_flags |= MLX5_FLOW_ACTION_TUNNEL_MATCH |
6827                                         MLX5_FLOW_ACTION_DECAP;
6828                 grp_info.std_tbl_fix = tunnel_use_standard_attr_group_translate
6829                                         (dev, attr, tunnel, tof_rule_type);
6830         }
6831         ret = flow_dv_validate_attributes(dev, tunnel, attr, &grp_info, error);
6832         if (ret < 0)
6833                 return ret;
6834         is_root = (uint64_t)ret;
6835         for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
6836                 int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL);
6837                 int type = items->type;
6838
6839                 if (!mlx5_flow_os_item_supported(type))
6840                         return rte_flow_error_set(error, ENOTSUP,
6841                                                   RTE_FLOW_ERROR_TYPE_ITEM,
6842                                                   NULL, "item not supported");
6843                 switch (type) {
6844                 case RTE_FLOW_ITEM_TYPE_VOID:
6845                         break;
6846                 case RTE_FLOW_ITEM_TYPE_PORT_ID:
6847                         ret = flow_dv_validate_item_port_id
6848                                         (dev, items, attr, item_flags, error);
6849                         if (ret < 0)
6850                                 return ret;
6851                         last_item = MLX5_FLOW_ITEM_PORT_ID;
6852                         port_id_item = items;
6853                         break;
6854                 case RTE_FLOW_ITEM_TYPE_ETH:
6855                         ret = mlx5_flow_validate_item_eth(items, item_flags,
6856                                                           true, error);
6857                         if (ret < 0)
6858                                 return ret;
6859                         last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L2 :
6860                                              MLX5_FLOW_LAYER_OUTER_L2;
6861                         if (items->mask != NULL && items->spec != NULL) {
6862                                 ether_type =
6863                                         ((const struct rte_flow_item_eth *)
6864                                          items->spec)->type;
6865                                 ether_type &=
6866                                         ((const struct rte_flow_item_eth *)
6867                                          items->mask)->type;
6868                                 ether_type = rte_be_to_cpu_16(ether_type);
6869                         } else {
6870                                 ether_type = 0;
6871                         }
6872                         break;
6873                 case RTE_FLOW_ITEM_TYPE_VLAN:
6874                         ret = flow_dv_validate_item_vlan(items, item_flags,
6875                                                          dev, error);
6876                         if (ret < 0)
6877                                 return ret;
6878                         last_item = tunnel ? MLX5_FLOW_LAYER_INNER_VLAN :
6879                                              MLX5_FLOW_LAYER_OUTER_VLAN;
6880                         if (items->mask != NULL && items->spec != NULL) {
6881                                 ether_type =
6882                                         ((const struct rte_flow_item_vlan *)
6883                                          items->spec)->inner_type;
6884                                 ether_type &=
6885                                         ((const struct rte_flow_item_vlan *)
6886                                          items->mask)->inner_type;
6887                                 ether_type = rte_be_to_cpu_16(ether_type);
6888                         } else {
6889                                 ether_type = 0;
6890                         }
6891                         /* Store outer VLAN mask for of_push_vlan action. */
6892                         if (!tunnel)
6893                                 vlan_m = items->mask;
6894                         break;
6895                 case RTE_FLOW_ITEM_TYPE_IPV4:
6896                         mlx5_flow_tunnel_ip_check(items, next_protocol,
6897                                                   &item_flags, &tunnel);
6898                         ret = flow_dv_validate_item_ipv4(dev, items, item_flags,
6899                                                          last_item, ether_type,
6900                                                          error);
6901                         if (ret < 0)
6902                                 return ret;
6903                         last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV4 :
6904                                              MLX5_FLOW_LAYER_OUTER_L3_IPV4;
6905                         if (items->mask != NULL &&
6906                             ((const struct rte_flow_item_ipv4 *)
6907                              items->mask)->hdr.next_proto_id) {
6908                                 next_protocol =
6909                                         ((const struct rte_flow_item_ipv4 *)
6910                                          (items->spec))->hdr.next_proto_id;
6911                                 next_protocol &=
6912                                         ((const struct rte_flow_item_ipv4 *)
6913                                          (items->mask))->hdr.next_proto_id;
6914                         } else {
6915                                 /* Reset for inner layer. */
6916                                 next_protocol = 0xff;
6917                         }
6918                         break;
6919                 case RTE_FLOW_ITEM_TYPE_IPV6:
6920                         mlx5_flow_tunnel_ip_check(items, next_protocol,
6921                                                   &item_flags, &tunnel);
6922                         ret = mlx5_flow_validate_item_ipv6(items, item_flags,
6923                                                            last_item,
6924                                                            ether_type,
6925                                                            &nic_ipv6_mask,
6926                                                            error);
6927                         if (ret < 0)
6928                                 return ret;
6929                         last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV6 :
6930                                              MLX5_FLOW_LAYER_OUTER_L3_IPV6;
6931                         if (items->mask != NULL &&
6932                             ((const struct rte_flow_item_ipv6 *)
6933                              items->mask)->hdr.proto) {
6934                                 item_ipv6_proto =
6935                                         ((const struct rte_flow_item_ipv6 *)
6936                                          items->spec)->hdr.proto;
6937                                 next_protocol =
6938                                         ((const struct rte_flow_item_ipv6 *)
6939                                          items->spec)->hdr.proto;
6940                                 next_protocol &=
6941                                         ((const struct rte_flow_item_ipv6 *)
6942                                          items->mask)->hdr.proto;
6943                         } else {
6944                                 /* Reset for inner layer. */
6945                                 next_protocol = 0xff;
6946                         }
6947                         break;
6948                 case RTE_FLOW_ITEM_TYPE_IPV6_FRAG_EXT:
6949                         ret = flow_dv_validate_item_ipv6_frag_ext(items,
6950                                                                   item_flags,
6951                                                                   error);
6952                         if (ret < 0)
6953                                 return ret;
6954                         last_item = tunnel ?
6955                                         MLX5_FLOW_LAYER_INNER_L3_IPV6_FRAG_EXT :
6956                                         MLX5_FLOW_LAYER_OUTER_L3_IPV6_FRAG_EXT;
6957                         if (items->mask != NULL &&
6958                             ((const struct rte_flow_item_ipv6_frag_ext *)
6959                              items->mask)->hdr.next_header) {
6960                                 next_protocol =
6961                                 ((const struct rte_flow_item_ipv6_frag_ext *)
6962                                  items->spec)->hdr.next_header;
6963                                 next_protocol &=
6964                                 ((const struct rte_flow_item_ipv6_frag_ext *)
6965                                  items->mask)->hdr.next_header;
6966                         } else {
6967                                 /* Reset for inner layer. */
6968                                 next_protocol = 0xff;
6969                         }
6970                         break;
6971                 case RTE_FLOW_ITEM_TYPE_TCP:
6972                         ret = mlx5_flow_validate_item_tcp
6973                                                 (items, item_flags,
6974                                                  next_protocol,
6975                                                  &nic_tcp_mask,
6976                                                  error);
6977                         if (ret < 0)
6978                                 return ret;
6979                         last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_TCP :
6980                                              MLX5_FLOW_LAYER_OUTER_L4_TCP;
6981                         break;
6982                 case RTE_FLOW_ITEM_TYPE_UDP:
6983                         ret = mlx5_flow_validate_item_udp(items, item_flags,
6984                                                           next_protocol,
6985                                                           error);
6986                         const struct rte_flow_item_udp *spec = items->spec;
6987                         const struct rte_flow_item_udp *mask = items->mask;
6988                         if (!mask)
6989                                 mask = &rte_flow_item_udp_mask;
6990                         if (spec != NULL)
6991                                 udp_dport = rte_be_to_cpu_16
6992                                                 (spec->hdr.dst_port &
6993                                                  mask->hdr.dst_port);
6994                         if (ret < 0)
6995                                 return ret;
6996                         last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_UDP :
6997                                              MLX5_FLOW_LAYER_OUTER_L4_UDP;
6998                         break;
6999                 case RTE_FLOW_ITEM_TYPE_GRE:
7000                         ret = mlx5_flow_validate_item_gre(items, item_flags,
7001                                                           next_protocol, error);
7002                         if (ret < 0)
7003                                 return ret;
7004                         gre_item = items;
7005                         last_item = MLX5_FLOW_LAYER_GRE;
7006                         break;
7007                 case RTE_FLOW_ITEM_TYPE_NVGRE:
7008                         ret = mlx5_flow_validate_item_nvgre(items, item_flags,
7009                                                             next_protocol,
7010                                                             error);
7011                         if (ret < 0)
7012                                 return ret;
7013                         last_item = MLX5_FLOW_LAYER_NVGRE;
7014                         break;
7015                 case RTE_FLOW_ITEM_TYPE_GRE_KEY:
7016                         ret = mlx5_flow_validate_item_gre_key
7017                                 (items, item_flags, gre_item, error);
7018                         if (ret < 0)
7019                                 return ret;
7020                         last_item = MLX5_FLOW_LAYER_GRE_KEY;
7021                         break;
7022                 case RTE_FLOW_ITEM_TYPE_VXLAN:
7023                         ret = mlx5_flow_validate_item_vxlan(dev, udp_dport,
7024                                                             items, item_flags,
7025                                                             attr, error);
7026                         if (ret < 0)
7027                                 return ret;
7028                         last_item = MLX5_FLOW_LAYER_VXLAN;
7029                         break;
7030                 case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
7031                         ret = mlx5_flow_validate_item_vxlan_gpe(items,
7032                                                                 item_flags, dev,
7033                                                                 error);
7034                         if (ret < 0)
7035                                 return ret;
7036                         last_item = MLX5_FLOW_LAYER_VXLAN_GPE;
7037                         break;
7038                 case RTE_FLOW_ITEM_TYPE_GENEVE:
7039                         ret = mlx5_flow_validate_item_geneve(items,
7040                                                              item_flags, dev,
7041                                                              error);
7042                         if (ret < 0)
7043                                 return ret;
7044                         geneve_item = items;
7045                         last_item = MLX5_FLOW_LAYER_GENEVE;
7046                         break;
7047                 case RTE_FLOW_ITEM_TYPE_GENEVE_OPT:
7048                         ret = mlx5_flow_validate_item_geneve_opt(items,
7049                                                                  last_item,
7050                                                                  geneve_item,
7051                                                                  dev,
7052                                                                  error);
7053                         if (ret < 0)
7054                                 return ret;
7055                         last_item = MLX5_FLOW_LAYER_GENEVE_OPT;
7056                         break;
7057                 case RTE_FLOW_ITEM_TYPE_MPLS:
7058                         ret = mlx5_flow_validate_item_mpls(dev, items,
7059                                                            item_flags,
7060                                                            last_item, error);
7061                         if (ret < 0)
7062                                 return ret;
7063                         last_item = MLX5_FLOW_LAYER_MPLS;
7064                         break;
7065
7066                 case RTE_FLOW_ITEM_TYPE_MARK:
7067                         ret = flow_dv_validate_item_mark(dev, items, attr,
7068                                                          error);
7069                         if (ret < 0)
7070                                 return ret;
7071                         last_item = MLX5_FLOW_ITEM_MARK;
7072                         break;
7073                 case RTE_FLOW_ITEM_TYPE_META:
7074                         ret = flow_dv_validate_item_meta(dev, items, attr,
7075                                                          error);
7076                         if (ret < 0)
7077                                 return ret;
7078                         last_item = MLX5_FLOW_ITEM_METADATA;
7079                         break;
7080                 case RTE_FLOW_ITEM_TYPE_ICMP:
7081                         ret = mlx5_flow_validate_item_icmp(items, item_flags,
7082                                                            next_protocol,
7083                                                            error);
7084                         if (ret < 0)
7085                                 return ret;
7086                         last_item = MLX5_FLOW_LAYER_ICMP;
7087                         break;
7088                 case RTE_FLOW_ITEM_TYPE_ICMP6:
7089                         ret = mlx5_flow_validate_item_icmp6(items, item_flags,
7090                                                             next_protocol,
7091                                                             error);
7092                         if (ret < 0)
7093                                 return ret;
7094                         item_ipv6_proto = IPPROTO_ICMPV6;
7095                         last_item = MLX5_FLOW_LAYER_ICMP6;
7096                         break;
7097                 case RTE_FLOW_ITEM_TYPE_TAG:
7098                         ret = flow_dv_validate_item_tag(dev, items,
7099                                                         attr, error);
7100                         if (ret < 0)
7101                                 return ret;
7102                         last_item = MLX5_FLOW_ITEM_TAG;
7103                         break;
7104                 case MLX5_RTE_FLOW_ITEM_TYPE_TAG:
7105                 case MLX5_RTE_FLOW_ITEM_TYPE_TX_QUEUE:
7106                         break;
7107                 case RTE_FLOW_ITEM_TYPE_GTP:
7108                         ret = flow_dv_validate_item_gtp(dev, items, item_flags,
7109                                                         error);
7110                         if (ret < 0)
7111                                 return ret;
7112                         gtp_item = items;
7113                         last_item = MLX5_FLOW_LAYER_GTP;
7114                         break;
7115                 case RTE_FLOW_ITEM_TYPE_GTP_PSC:
7116                         ret = flow_dv_validate_item_gtp_psc(items, last_item,
7117                                                             gtp_item, attr,
7118                                                             error);
7119                         if (ret < 0)
7120                                 return ret;
7121                         last_item = MLX5_FLOW_LAYER_GTP_PSC;
7122                         break;
7123                 case RTE_FLOW_ITEM_TYPE_ECPRI:
7124                         /* Capacity will be checked in the translate stage. */
7125                         ret = mlx5_flow_validate_item_ecpri(items, item_flags,
7126                                                             last_item,
7127                                                             ether_type,
7128                                                             &nic_ecpri_mask,
7129                                                             error);
7130                         if (ret < 0)
7131                                 return ret;
7132                         last_item = MLX5_FLOW_LAYER_ECPRI;
7133                         break;
7134                 case RTE_FLOW_ITEM_TYPE_INTEGRITY:
7135                         if (item_flags & MLX5_FLOW_ITEM_INTEGRITY)
7136                                 return rte_flow_error_set
7137                                         (error, ENOTSUP,
7138                                          RTE_FLOW_ERROR_TYPE_ITEM,
7139                                          NULL, "multiple integrity items not supported");
7140                         ret = flow_dv_validate_item_integrity(dev, rule_items,
7141                                                               items, error);
7142                         if (ret < 0)
7143                                 return ret;
7144                         last_item = MLX5_FLOW_ITEM_INTEGRITY;
7145                         break;
7146                 case RTE_FLOW_ITEM_TYPE_CONNTRACK:
7147                         ret = flow_dv_validate_item_aso_ct(dev, items,
7148                                                            &item_flags, error);
7149                         if (ret < 0)
7150                                 return ret;
7151                         break;
7152                 case MLX5_RTE_FLOW_ITEM_TYPE_TUNNEL:
7153                         /* tunnel offload item was processed before
7154                          * list it here as a supported type
7155                          */
7156                         break;
7157                 default:
7158                         return rte_flow_error_set(error, ENOTSUP,
7159                                                   RTE_FLOW_ERROR_TYPE_ITEM,
7160                                                   NULL, "item not supported");
7161                 }
7162                 item_flags |= last_item;
7163         }
7164         for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
7165                 int type = actions->type;
7166                 bool shared_count = false;
7167
7168                 if (!mlx5_flow_os_action_supported(type))
7169                         return rte_flow_error_set(error, ENOTSUP,
7170                                                   RTE_FLOW_ERROR_TYPE_ACTION,
7171                                                   actions,
7172                                                   "action not supported");
7173                 if (actions_n == MLX5_DV_MAX_NUMBER_OF_ACTIONS)
7174                         return rte_flow_error_set(error, ENOTSUP,
7175                                                   RTE_FLOW_ERROR_TYPE_ACTION,
7176                                                   actions, "too many actions");
7177                 if (action_flags &
7178                         MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY)
7179                         return rte_flow_error_set(error, ENOTSUP,
7180                                 RTE_FLOW_ERROR_TYPE_ACTION,
7181                                 NULL, "meter action with policy "
7182                                 "must be the last action");
7183                 switch (type) {
7184                 case RTE_FLOW_ACTION_TYPE_VOID:
7185                         break;
7186                 case RTE_FLOW_ACTION_TYPE_PORT_ID:
7187                 case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT:
7188                         ret = flow_dv_validate_action_port_id(dev,
7189                                                               action_flags,
7190                                                               actions,
7191                                                               attr,
7192                                                               error);
7193                         if (ret)
7194                                 return ret;
7195                         action_flags |= MLX5_FLOW_ACTION_PORT_ID;
7196                         ++actions_n;
7197                         break;
7198                 case RTE_FLOW_ACTION_TYPE_FLAG:
7199                         ret = flow_dv_validate_action_flag(dev, action_flags,
7200                                                            attr, error);
7201                         if (ret < 0)
7202                                 return ret;
7203                         if (dev_conf->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY) {
7204                                 /* Count all modify-header actions as one. */
7205                                 if (!(action_flags &
7206                                       MLX5_FLOW_MODIFY_HDR_ACTIONS))
7207                                         ++actions_n;
7208                                 action_flags |= MLX5_FLOW_ACTION_FLAG |
7209                                                 MLX5_FLOW_ACTION_MARK_EXT;
7210                                 if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7211                                         modify_after_mirror = 1;
7212
7213                         } else {
7214                                 action_flags |= MLX5_FLOW_ACTION_FLAG;
7215                                 ++actions_n;
7216                         }
7217                         rw_act_num += MLX5_ACT_NUM_SET_MARK;
7218                         break;
7219                 case RTE_FLOW_ACTION_TYPE_MARK:
7220                         ret = flow_dv_validate_action_mark(dev, actions,
7221                                                            action_flags,
7222                                                            attr, error);
7223                         if (ret < 0)
7224                                 return ret;
7225                         if (dev_conf->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY) {
7226                                 /* Count all modify-header actions as one. */
7227                                 if (!(action_flags &
7228                                       MLX5_FLOW_MODIFY_HDR_ACTIONS))
7229                                         ++actions_n;
7230                                 action_flags |= MLX5_FLOW_ACTION_MARK |
7231                                                 MLX5_FLOW_ACTION_MARK_EXT;
7232                                 if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7233                                         modify_after_mirror = 1;
7234                         } else {
7235                                 action_flags |= MLX5_FLOW_ACTION_MARK;
7236                                 ++actions_n;
7237                         }
7238                         rw_act_num += MLX5_ACT_NUM_SET_MARK;
7239                         break;
7240                 case RTE_FLOW_ACTION_TYPE_SET_META:
7241                         ret = flow_dv_validate_action_set_meta(dev, actions,
7242                                                                action_flags,
7243                                                                attr, error);
7244                         if (ret < 0)
7245                                 return ret;
7246                         /* Count all modify-header actions as one action. */
7247                         if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
7248                                 ++actions_n;
7249                         if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7250                                 modify_after_mirror = 1;
7251                         action_flags |= MLX5_FLOW_ACTION_SET_META;
7252                         rw_act_num += MLX5_ACT_NUM_SET_META;
7253                         break;
7254                 case RTE_FLOW_ACTION_TYPE_SET_TAG:
7255                         ret = flow_dv_validate_action_set_tag(dev, actions,
7256                                                               action_flags,
7257                                                               attr, error);
7258                         if (ret < 0)
7259                                 return ret;
7260                         /* Count all modify-header actions as one action. */
7261                         if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
7262                                 ++actions_n;
7263                         if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7264                                 modify_after_mirror = 1;
7265                         action_flags |= MLX5_FLOW_ACTION_SET_TAG;
7266                         rw_act_num += MLX5_ACT_NUM_SET_TAG;
7267                         break;
7268                 case RTE_FLOW_ACTION_TYPE_DROP:
7269                         ret = mlx5_flow_validate_action_drop(action_flags,
7270                                                              attr, error);
7271                         if (ret < 0)
7272                                 return ret;
7273                         action_flags |= MLX5_FLOW_ACTION_DROP;
7274                         ++actions_n;
7275                         break;
7276                 case RTE_FLOW_ACTION_TYPE_QUEUE:
7277                         ret = mlx5_flow_validate_action_queue(actions,
7278                                                               action_flags, dev,
7279                                                               attr, error);
7280                         if (ret < 0)
7281                                 return ret;
7282                         queue_index = ((const struct rte_flow_action_queue *)
7283                                                         (actions->conf))->index;
7284                         action_flags |= MLX5_FLOW_ACTION_QUEUE;
7285                         ++actions_n;
7286                         break;
7287                 case RTE_FLOW_ACTION_TYPE_RSS:
7288                         rss = actions->conf;
7289                         ret = mlx5_flow_validate_action_rss(actions,
7290                                                             action_flags, dev,
7291                                                             attr, item_flags,
7292                                                             error);
7293                         if (ret < 0)
7294                                 return ret;
7295                         if (rss && sample_rss &&
7296                             (sample_rss->level != rss->level ||
7297                             sample_rss->types != rss->types))
7298                                 return rte_flow_error_set(error, ENOTSUP,
7299                                         RTE_FLOW_ERROR_TYPE_ACTION,
7300                                         NULL,
7301                                         "Can't use the different RSS types "
7302                                         "or level in the same flow");
7303                         if (rss != NULL && rss->queue_num)
7304                                 queue_index = rss->queue[0];
7305                         action_flags |= MLX5_FLOW_ACTION_RSS;
7306                         ++actions_n;
7307                         break;
7308                 case MLX5_RTE_FLOW_ACTION_TYPE_DEFAULT_MISS:
7309                         ret =
7310                         mlx5_flow_validate_action_default_miss(action_flags,
7311                                         attr, error);
7312                         if (ret < 0)
7313                                 return ret;
7314                         action_flags |= MLX5_FLOW_ACTION_DEFAULT_MISS;
7315                         ++actions_n;
7316                         break;
7317                 case MLX5_RTE_FLOW_ACTION_TYPE_COUNT:
7318                         shared_count = true;
7319                         /* fall-through. */
7320                 case RTE_FLOW_ACTION_TYPE_COUNT:
7321                         ret = flow_dv_validate_action_count(dev, shared_count,
7322                                                             action_flags,
7323                                                             error);
7324                         if (ret < 0)
7325                                 return ret;
7326                         action_flags |= MLX5_FLOW_ACTION_COUNT;
7327                         ++actions_n;
7328                         break;
7329                 case RTE_FLOW_ACTION_TYPE_OF_POP_VLAN:
7330                         if (flow_dv_validate_action_pop_vlan(dev,
7331                                                              action_flags,
7332                                                              actions,
7333                                                              item_flags, attr,
7334                                                              error))
7335                                 return -rte_errno;
7336                         if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7337                                 modify_after_mirror = 1;
7338                         action_flags |= MLX5_FLOW_ACTION_OF_POP_VLAN;
7339                         ++actions_n;
7340                         break;
7341                 case RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN:
7342                         ret = flow_dv_validate_action_push_vlan(dev,
7343                                                                 action_flags,
7344                                                                 vlan_m,
7345                                                                 actions, attr,
7346                                                                 error);
7347                         if (ret < 0)
7348                                 return ret;
7349                         if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7350                                 modify_after_mirror = 1;
7351                         action_flags |= MLX5_FLOW_ACTION_OF_PUSH_VLAN;
7352                         ++actions_n;
7353                         break;
7354                 case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP:
7355                         ret = flow_dv_validate_action_set_vlan_pcp
7356                                                 (action_flags, actions, error);
7357                         if (ret < 0)
7358                                 return ret;
7359                         if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7360                                 modify_after_mirror = 1;
7361                         /* Count PCP with push_vlan command. */
7362                         action_flags |= MLX5_FLOW_ACTION_OF_SET_VLAN_PCP;
7363                         break;
7364                 case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID:
7365                         ret = flow_dv_validate_action_set_vlan_vid
7366                                                 (item_flags, action_flags,
7367                                                  actions, error);
7368                         if (ret < 0)
7369                                 return ret;
7370                         if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7371                                 modify_after_mirror = 1;
7372                         /* Count VID with push_vlan command. */
7373                         action_flags |= MLX5_FLOW_ACTION_OF_SET_VLAN_VID;
7374                         rw_act_num += MLX5_ACT_NUM_MDF_VID;
7375                         break;
7376                 case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP:
7377                 case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP:
7378                         ret = flow_dv_validate_action_l2_encap(dev,
7379                                                                action_flags,
7380                                                                actions, attr,
7381                                                                error);
7382                         if (ret < 0)
7383                                 return ret;
7384                         action_flags |= MLX5_FLOW_ACTION_ENCAP;
7385                         ++actions_n;
7386                         break;
7387                 case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP:
7388                 case RTE_FLOW_ACTION_TYPE_NVGRE_DECAP:
7389                         ret = flow_dv_validate_action_decap(dev, action_flags,
7390                                                             actions, item_flags,
7391                                                             attr, error);
7392                         if (ret < 0)
7393                                 return ret;
7394                         if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7395                                 modify_after_mirror = 1;
7396                         action_flags |= MLX5_FLOW_ACTION_DECAP;
7397                         ++actions_n;
7398                         break;
7399                 case RTE_FLOW_ACTION_TYPE_RAW_ENCAP:
7400                         ret = flow_dv_validate_action_raw_encap_decap
7401                                 (dev, NULL, actions->conf, attr, &action_flags,
7402                                  &actions_n, actions, item_flags, error);
7403                         if (ret < 0)
7404                                 return ret;
7405                         break;
7406                 case RTE_FLOW_ACTION_TYPE_RAW_DECAP:
7407                         decap = actions->conf;
7408                         while ((++actions)->type == RTE_FLOW_ACTION_TYPE_VOID)
7409                                 ;
7410                         if (actions->type != RTE_FLOW_ACTION_TYPE_RAW_ENCAP) {
7411                                 encap = NULL;
7412                                 actions--;
7413                         } else {
7414                                 encap = actions->conf;
7415                         }
7416                         ret = flow_dv_validate_action_raw_encap_decap
7417                                            (dev,
7418                                             decap ? decap : &empty_decap, encap,
7419                                             attr, &action_flags, &actions_n,
7420                                             actions, item_flags, error);
7421                         if (ret < 0)
7422                                 return ret;
7423                         if ((action_flags & MLX5_FLOW_ACTION_SAMPLE) &&
7424                             (action_flags & MLX5_FLOW_ACTION_DECAP))
7425                                 modify_after_mirror = 1;
7426                         break;
7427                 case RTE_FLOW_ACTION_TYPE_SET_MAC_SRC:
7428                 case RTE_FLOW_ACTION_TYPE_SET_MAC_DST:
7429                         ret = flow_dv_validate_action_modify_mac(action_flags,
7430                                                                  actions,
7431                                                                  item_flags,
7432                                                                  error);
7433                         if (ret < 0)
7434                                 return ret;
7435                         /* Count all modify-header actions as one action. */
7436                         if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
7437                                 ++actions_n;
7438                         action_flags |= actions->type ==
7439                                         RTE_FLOW_ACTION_TYPE_SET_MAC_SRC ?
7440                                                 MLX5_FLOW_ACTION_SET_MAC_SRC :
7441                                                 MLX5_FLOW_ACTION_SET_MAC_DST;
7442                         if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7443                                 modify_after_mirror = 1;
7444                         /*
7445                          * Even if the source and destination MAC addresses have
7446                          * overlap in the header with 4B alignment, the convert
7447                          * function will handle them separately and 4 SW actions
7448                          * will be created. And 2 actions will be added each
7449                          * time no matter how many bytes of address will be set.
7450                          */
7451                         rw_act_num += MLX5_ACT_NUM_MDF_MAC;
7452                         break;
7453                 case RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC:
7454                 case RTE_FLOW_ACTION_TYPE_SET_IPV4_DST:
7455                         ret = flow_dv_validate_action_modify_ipv4(action_flags,
7456                                                                   actions,
7457                                                                   item_flags,
7458                                                                   error);
7459                         if (ret < 0)
7460                                 return ret;
7461                         /* Count all modify-header actions as one action. */
7462                         if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
7463                                 ++actions_n;
7464                         if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7465                                 modify_after_mirror = 1;
7466                         action_flags |= actions->type ==
7467                                         RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC ?
7468                                                 MLX5_FLOW_ACTION_SET_IPV4_SRC :
7469                                                 MLX5_FLOW_ACTION_SET_IPV4_DST;
7470                         rw_act_num += MLX5_ACT_NUM_MDF_IPV4;
7471                         break;
7472                 case RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC:
7473                 case RTE_FLOW_ACTION_TYPE_SET_IPV6_DST:
7474                         ret = flow_dv_validate_action_modify_ipv6(action_flags,
7475                                                                   actions,
7476                                                                   item_flags,
7477                                                                   error);
7478                         if (ret < 0)
7479                                 return ret;
7480                         if (item_ipv6_proto == IPPROTO_ICMPV6)
7481                                 return rte_flow_error_set(error, ENOTSUP,
7482                                         RTE_FLOW_ERROR_TYPE_ACTION,
7483                                         actions,
7484                                         "Can't change header "
7485                                         "with ICMPv6 proto");
7486                         /* Count all modify-header actions as one action. */
7487                         if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
7488                                 ++actions_n;
7489                         if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7490                                 modify_after_mirror = 1;
7491                         action_flags |= actions->type ==
7492                                         RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC ?
7493                                                 MLX5_FLOW_ACTION_SET_IPV6_SRC :
7494                                                 MLX5_FLOW_ACTION_SET_IPV6_DST;
7495                         rw_act_num += MLX5_ACT_NUM_MDF_IPV6;
7496                         break;
7497                 case RTE_FLOW_ACTION_TYPE_SET_TP_SRC:
7498                 case RTE_FLOW_ACTION_TYPE_SET_TP_DST:
7499                         ret = flow_dv_validate_action_modify_tp(action_flags,
7500                                                                 actions,
7501                                                                 item_flags,
7502                                                                 error);
7503                         if (ret < 0)
7504                                 return ret;
7505                         /* Count all modify-header actions as one action. */
7506                         if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
7507                                 ++actions_n;
7508                         if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7509                                 modify_after_mirror = 1;
7510                         action_flags |= actions->type ==
7511                                         RTE_FLOW_ACTION_TYPE_SET_TP_SRC ?
7512                                                 MLX5_FLOW_ACTION_SET_TP_SRC :
7513                                                 MLX5_FLOW_ACTION_SET_TP_DST;
7514                         rw_act_num += MLX5_ACT_NUM_MDF_PORT;
7515                         break;
7516                 case RTE_FLOW_ACTION_TYPE_DEC_TTL:
7517                 case RTE_FLOW_ACTION_TYPE_SET_TTL:
7518                         ret = flow_dv_validate_action_modify_ttl(action_flags,
7519                                                                  actions,
7520                                                                  item_flags,
7521                                                                  error);
7522                         if (ret < 0)
7523                                 return ret;
7524                         /* Count all modify-header actions as one action. */
7525                         if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
7526                                 ++actions_n;
7527                         if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7528                                 modify_after_mirror = 1;
7529                         action_flags |= actions->type ==
7530                                         RTE_FLOW_ACTION_TYPE_SET_TTL ?
7531                                                 MLX5_FLOW_ACTION_SET_TTL :
7532                                                 MLX5_FLOW_ACTION_DEC_TTL;
7533                         rw_act_num += MLX5_ACT_NUM_MDF_TTL;
7534                         break;
7535                 case RTE_FLOW_ACTION_TYPE_JUMP:
7536                         ret = flow_dv_validate_action_jump(dev, tunnel, actions,
7537                                                            action_flags,
7538                                                            attr, external,
7539                                                            error);
7540                         if (ret)
7541                                 return ret;
7542                         if ((action_flags & MLX5_FLOW_ACTION_SAMPLE) &&
7543                             fdb_mirror_limit)
7544                                 return rte_flow_error_set(error, EINVAL,
7545                                                   RTE_FLOW_ERROR_TYPE_ACTION,
7546                                                   NULL,
7547                                                   "sample and jump action combination is not supported");
7548                         ++actions_n;
7549                         action_flags |= MLX5_FLOW_ACTION_JUMP;
7550                         break;
7551                 case RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ:
7552                 case RTE_FLOW_ACTION_TYPE_DEC_TCP_SEQ:
7553                         ret = flow_dv_validate_action_modify_tcp_seq
7554                                                                 (action_flags,
7555                                                                  actions,
7556                                                                  item_flags,
7557                                                                  error);
7558                         if (ret < 0)
7559                                 return ret;
7560                         /* Count all modify-header actions as one action. */
7561                         if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
7562                                 ++actions_n;
7563                         if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7564                                 modify_after_mirror = 1;
7565                         action_flags |= actions->type ==
7566                                         RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ ?
7567                                                 MLX5_FLOW_ACTION_INC_TCP_SEQ :
7568                                                 MLX5_FLOW_ACTION_DEC_TCP_SEQ;
7569                         rw_act_num += MLX5_ACT_NUM_MDF_TCPSEQ;
7570                         break;
7571                 case RTE_FLOW_ACTION_TYPE_INC_TCP_ACK:
7572                 case RTE_FLOW_ACTION_TYPE_DEC_TCP_ACK:
7573                         ret = flow_dv_validate_action_modify_tcp_ack
7574                                                                 (action_flags,
7575                                                                  actions,
7576                                                                  item_flags,
7577                                                                  error);
7578                         if (ret < 0)
7579                                 return ret;
7580                         /* Count all modify-header actions as one action. */
7581                         if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
7582                                 ++actions_n;
7583                         if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7584                                 modify_after_mirror = 1;
7585                         action_flags |= actions->type ==
7586                                         RTE_FLOW_ACTION_TYPE_INC_TCP_ACK ?
7587                                                 MLX5_FLOW_ACTION_INC_TCP_ACK :
7588                                                 MLX5_FLOW_ACTION_DEC_TCP_ACK;
7589                         rw_act_num += MLX5_ACT_NUM_MDF_TCPACK;
7590                         break;
7591                 case MLX5_RTE_FLOW_ACTION_TYPE_MARK:
7592                         break;
7593                 case MLX5_RTE_FLOW_ACTION_TYPE_TAG:
7594                 case MLX5_RTE_FLOW_ACTION_TYPE_COPY_MREG:
7595                         rw_act_num += MLX5_ACT_NUM_SET_TAG;
7596                         break;
7597                 case RTE_FLOW_ACTION_TYPE_METER:
7598                         ret = mlx5_flow_validate_action_meter(dev,
7599                                                               action_flags,
7600                                                               actions, attr,
7601                                                               port_id_item,
7602                                                               &def_policy,
7603                                                               error);
7604                         if (ret < 0)
7605                                 return ret;
7606                         action_flags |= MLX5_FLOW_ACTION_METER;
7607                         if (!def_policy)
7608                                 action_flags |=
7609                                 MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY;
7610                         ++actions_n;
7611                         /* Meter action will add one more TAG action. */
7612                         rw_act_num += MLX5_ACT_NUM_SET_TAG;
7613                         break;
7614                 case MLX5_RTE_FLOW_ACTION_TYPE_AGE:
7615                         if (!attr->transfer && !attr->group)
7616                                 return rte_flow_error_set(error, ENOTSUP,
7617                                                 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
7618                                                                            NULL,
7619                           "Shared ASO age action is not supported for group 0");
7620                         if (action_flags & MLX5_FLOW_ACTION_AGE)
7621                                 return rte_flow_error_set
7622                                                   (error, EINVAL,
7623                                                    RTE_FLOW_ERROR_TYPE_ACTION,
7624                                                    NULL,
7625                                                    "duplicate age actions set");
7626                         action_flags |= MLX5_FLOW_ACTION_AGE;
7627                         ++actions_n;
7628                         break;
7629                 case RTE_FLOW_ACTION_TYPE_AGE:
7630                         ret = flow_dv_validate_action_age(action_flags,
7631                                                           actions, dev,
7632                                                           error);
7633                         if (ret < 0)
7634                                 return ret;
7635                         /*
7636                          * Validate the regular AGE action (using counter)
7637                          * mutual exclusion with share counter actions.
7638                          */
7639                         if (!priv->sh->flow_hit_aso_en) {
7640                                 if (shared_count)
7641                                         return rte_flow_error_set
7642                                                 (error, EINVAL,
7643                                                 RTE_FLOW_ERROR_TYPE_ACTION,
7644                                                 NULL,
7645                                                 "old age and shared count combination is not supported");
7646                                 if (sample_count)
7647                                         return rte_flow_error_set
7648                                                 (error, EINVAL,
7649                                                 RTE_FLOW_ERROR_TYPE_ACTION,
7650                                                 NULL,
7651                                                 "old age action and count must be in the same sub flow");
7652                         }
7653                         action_flags |= MLX5_FLOW_ACTION_AGE;
7654                         ++actions_n;
7655                         break;
7656                 case RTE_FLOW_ACTION_TYPE_SET_IPV4_DSCP:
7657                         ret = flow_dv_validate_action_modify_ipv4_dscp
7658                                                          (action_flags,
7659                                                           actions,
7660                                                           item_flags,
7661                                                           error);
7662                         if (ret < 0)
7663                                 return ret;
7664                         /* Count all modify-header actions as one action. */
7665                         if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
7666                                 ++actions_n;
7667                         if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7668                                 modify_after_mirror = 1;
7669                         action_flags |= MLX5_FLOW_ACTION_SET_IPV4_DSCP;
7670                         rw_act_num += MLX5_ACT_NUM_SET_DSCP;
7671                         break;
7672                 case RTE_FLOW_ACTION_TYPE_SET_IPV6_DSCP:
7673                         ret = flow_dv_validate_action_modify_ipv6_dscp
7674                                                                 (action_flags,
7675                                                                  actions,
7676                                                                  item_flags,
7677                                                                  error);
7678                         if (ret < 0)
7679                                 return ret;
7680                         /* Count all modify-header actions as one action. */
7681                         if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
7682                                 ++actions_n;
7683                         if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7684                                 modify_after_mirror = 1;
7685                         action_flags |= MLX5_FLOW_ACTION_SET_IPV6_DSCP;
7686                         rw_act_num += MLX5_ACT_NUM_SET_DSCP;
7687                         break;
7688                 case RTE_FLOW_ACTION_TYPE_SAMPLE:
7689                         ret = flow_dv_validate_action_sample(&action_flags,
7690                                                              actions, dev,
7691                                                              attr, item_flags,
7692                                                              rss, &sample_rss,
7693                                                              &sample_count,
7694                                                              &fdb_mirror_limit,
7695                                                              error);
7696                         if (ret < 0)
7697                                 return ret;
7698                         action_flags |= MLX5_FLOW_ACTION_SAMPLE;
7699                         ++actions_n;
7700                         break;
7701                 case RTE_FLOW_ACTION_TYPE_MODIFY_FIELD:
7702                         ret = flow_dv_validate_action_modify_field(dev,
7703                                                                    action_flags,
7704                                                                    actions,
7705                                                                    attr,
7706                                                                    error);
7707                         if (ret < 0)
7708                                 return ret;
7709                         if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7710                                 modify_after_mirror = 1;
7711                         /* Count all modify-header actions as one action. */
7712                         if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
7713                                 ++actions_n;
7714                         action_flags |= MLX5_FLOW_ACTION_MODIFY_FIELD;
7715                         rw_act_num += ret;
7716                         break;
7717                 case RTE_FLOW_ACTION_TYPE_CONNTRACK:
7718                         ret = flow_dv_validate_action_aso_ct(dev, action_flags,
7719                                                              item_flags, attr,
7720                                                              error);
7721                         if (ret < 0)
7722                                 return ret;
7723                         action_flags |= MLX5_FLOW_ACTION_CT;
7724                         break;
7725                 case MLX5_RTE_FLOW_ACTION_TYPE_TUNNEL_SET:
7726                         /* tunnel offload action was processed before
7727                          * list it here as a supported type
7728                          */
7729                         break;
7730                 default:
7731                         return rte_flow_error_set(error, ENOTSUP,
7732                                                   RTE_FLOW_ERROR_TYPE_ACTION,
7733                                                   actions,
7734                                                   "action not supported");
7735                 }
7736         }
7737         /*
7738          * Validate actions in flow rules
7739          * - Explicit decap action is prohibited by the tunnel offload API.
7740          * - Drop action in tunnel steer rule is prohibited by the API.
7741          * - Application cannot use MARK action because it's value can mask
7742          *   tunnel default miss nitification.
7743          * - JUMP in tunnel match rule has no support in current PMD
7744          *   implementation.
7745          * - TAG & META are reserved for future uses.
7746          */
7747         if (action_flags & MLX5_FLOW_ACTION_TUNNEL_SET) {
7748                 uint64_t bad_actions_mask = MLX5_FLOW_ACTION_DECAP    |
7749                                             MLX5_FLOW_ACTION_MARK     |
7750                                             MLX5_FLOW_ACTION_SET_TAG  |
7751                                             MLX5_FLOW_ACTION_SET_META |
7752                                             MLX5_FLOW_ACTION_DROP;
7753
7754                 if (action_flags & bad_actions_mask)
7755                         return rte_flow_error_set
7756                                         (error, EINVAL,
7757                                         RTE_FLOW_ERROR_TYPE_ACTION, NULL,
7758                                         "Invalid RTE action in tunnel "
7759                                         "set decap rule");
7760                 if (!(action_flags & MLX5_FLOW_ACTION_JUMP))
7761                         return rte_flow_error_set
7762                                         (error, EINVAL,
7763                                         RTE_FLOW_ERROR_TYPE_ACTION, NULL,
7764                                         "tunnel set decap rule must terminate "
7765                                         "with JUMP");
7766                 if (!attr->ingress)
7767                         return rte_flow_error_set
7768                                         (error, EINVAL,
7769                                         RTE_FLOW_ERROR_TYPE_ACTION, NULL,
7770                                         "tunnel flows for ingress traffic only");
7771         }
7772         if (action_flags & MLX5_FLOW_ACTION_TUNNEL_MATCH) {
7773                 uint64_t bad_actions_mask = MLX5_FLOW_ACTION_JUMP    |
7774                                             MLX5_FLOW_ACTION_MARK    |
7775                                             MLX5_FLOW_ACTION_SET_TAG |
7776                                             MLX5_FLOW_ACTION_SET_META;
7777
7778                 if (action_flags & bad_actions_mask)
7779                         return rte_flow_error_set
7780                                         (error, EINVAL,
7781                                         RTE_FLOW_ERROR_TYPE_ACTION, NULL,
7782                                         "Invalid RTE action in tunnel "
7783                                         "set match rule");
7784         }
7785         /*
7786          * Validate the drop action mutual exclusion with other actions.
7787          * Drop action is mutually-exclusive with any other action, except for
7788          * Count action.
7789          * Drop action compatibility with tunnel offload was already validated.
7790          */
7791         if (action_flags & (MLX5_FLOW_ACTION_TUNNEL_MATCH |
7792                             MLX5_FLOW_ACTION_TUNNEL_MATCH));
7793         else if ((action_flags & MLX5_FLOW_ACTION_DROP) &&
7794             (action_flags & ~(MLX5_FLOW_ACTION_DROP | MLX5_FLOW_ACTION_COUNT)))
7795                 return rte_flow_error_set(error, EINVAL,
7796                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
7797                                           "Drop action is mutually-exclusive "
7798                                           "with any other action, except for "
7799                                           "Count action");
7800         /* Eswitch has few restrictions on using items and actions */
7801         if (attr->transfer) {
7802                 if (!mlx5_flow_ext_mreg_supported(dev) &&
7803                     action_flags & MLX5_FLOW_ACTION_FLAG)
7804                         return rte_flow_error_set(error, ENOTSUP,
7805                                                   RTE_FLOW_ERROR_TYPE_ACTION,
7806                                                   NULL,
7807                                                   "unsupported action FLAG");
7808                 if (!mlx5_flow_ext_mreg_supported(dev) &&
7809                     action_flags & MLX5_FLOW_ACTION_MARK)
7810                         return rte_flow_error_set(error, ENOTSUP,
7811                                                   RTE_FLOW_ERROR_TYPE_ACTION,
7812                                                   NULL,
7813                                                   "unsupported action MARK");
7814                 if (action_flags & MLX5_FLOW_ACTION_QUEUE)
7815                         return rte_flow_error_set(error, ENOTSUP,
7816                                                   RTE_FLOW_ERROR_TYPE_ACTION,
7817                                                   NULL,
7818                                                   "unsupported action QUEUE");
7819                 if (action_flags & MLX5_FLOW_ACTION_RSS)
7820                         return rte_flow_error_set(error, ENOTSUP,
7821                                                   RTE_FLOW_ERROR_TYPE_ACTION,
7822                                                   NULL,
7823                                                   "unsupported action RSS");
7824                 if (!(action_flags & MLX5_FLOW_FATE_ESWITCH_ACTIONS))
7825                         return rte_flow_error_set(error, EINVAL,
7826                                                   RTE_FLOW_ERROR_TYPE_ACTION,
7827                                                   actions,
7828                                                   "no fate action is found");
7829         } else {
7830                 if (!(action_flags & MLX5_FLOW_FATE_ACTIONS) && attr->ingress)
7831                         return rte_flow_error_set(error, EINVAL,
7832                                                   RTE_FLOW_ERROR_TYPE_ACTION,
7833                                                   actions,
7834                                                   "no fate action is found");
7835         }
7836         /*
7837          * Continue validation for Xcap and VLAN actions.
7838          * If hairpin is working in explicit TX rule mode, there is no actions
7839          * splitting and the validation of hairpin ingress flow should be the
7840          * same as other standard flows.
7841          */
7842         if ((action_flags & (MLX5_FLOW_XCAP_ACTIONS |
7843                              MLX5_FLOW_VLAN_ACTIONS)) &&
7844             (queue_index == 0xFFFF ||
7845              mlx5_rxq_get_type(dev, queue_index) != MLX5_RXQ_TYPE_HAIRPIN ||
7846              ((conf = mlx5_rxq_get_hairpin_conf(dev, queue_index)) != NULL &&
7847              conf->tx_explicit != 0))) {
7848                 if ((action_flags & MLX5_FLOW_XCAP_ACTIONS) ==
7849                     MLX5_FLOW_XCAP_ACTIONS)
7850                         return rte_flow_error_set(error, ENOTSUP,
7851                                                   RTE_FLOW_ERROR_TYPE_ACTION,
7852                                                   NULL, "encap and decap "
7853                                                   "combination aren't supported");
7854                 if (!attr->transfer && attr->ingress) {
7855                         if (action_flags & MLX5_FLOW_ACTION_ENCAP)
7856                                 return rte_flow_error_set
7857                                                 (error, ENOTSUP,
7858                                                  RTE_FLOW_ERROR_TYPE_ACTION,
7859                                                  NULL, "encap is not supported"
7860                                                  " for ingress traffic");
7861                         else if (action_flags & MLX5_FLOW_ACTION_OF_PUSH_VLAN)
7862                                 return rte_flow_error_set
7863                                                 (error, ENOTSUP,
7864                                                  RTE_FLOW_ERROR_TYPE_ACTION,
7865                                                  NULL, "push VLAN action not "
7866                                                  "supported for ingress");
7867                         else if ((action_flags & MLX5_FLOW_VLAN_ACTIONS) ==
7868                                         MLX5_FLOW_VLAN_ACTIONS)
7869                                 return rte_flow_error_set
7870                                                 (error, ENOTSUP,
7871                                                  RTE_FLOW_ERROR_TYPE_ACTION,
7872                                                  NULL, "no support for "
7873                                                  "multiple VLAN actions");
7874                 }
7875         }
7876         if (action_flags & MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY) {
7877                 if ((action_flags & (MLX5_FLOW_FATE_ACTIONS &
7878                         ~MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY)) &&
7879                         attr->ingress)
7880                         return rte_flow_error_set
7881                                 (error, ENOTSUP,
7882                                 RTE_FLOW_ERROR_TYPE_ACTION,
7883                                 NULL, "fate action not supported for "
7884                                 "meter with policy");
7885                 if (attr->egress) {
7886                         if (action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)
7887                                 return rte_flow_error_set
7888                                         (error, ENOTSUP,
7889                                         RTE_FLOW_ERROR_TYPE_ACTION,
7890                                         NULL, "modify header action in egress "
7891                                         "cannot be done before meter action");
7892                         if (action_flags & MLX5_FLOW_ACTION_ENCAP)
7893                                 return rte_flow_error_set
7894                                         (error, ENOTSUP,
7895                                         RTE_FLOW_ERROR_TYPE_ACTION,
7896                                         NULL, "encap action in egress "
7897                                         "cannot be done before meter action");
7898                         if (action_flags & MLX5_FLOW_ACTION_OF_PUSH_VLAN)
7899                                 return rte_flow_error_set
7900                                         (error, ENOTSUP,
7901                                         RTE_FLOW_ERROR_TYPE_ACTION,
7902                                         NULL, "push vlan action in egress "
7903                                         "cannot be done before meter action");
7904                 }
7905         }
7906         /*
7907          * Hairpin flow will add one more TAG action in TX implicit mode.
7908          * In TX explicit mode, there will be no hairpin flow ID.
7909          */
7910         if (hairpin > 0)
7911                 rw_act_num += MLX5_ACT_NUM_SET_TAG;
7912         /* extra metadata enabled: one more TAG action will be add. */
7913         if (dev_conf->dv_flow_en &&
7914             dev_conf->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY &&
7915             mlx5_flow_ext_mreg_supported(dev))
7916                 rw_act_num += MLX5_ACT_NUM_SET_TAG;
7917         if (rw_act_num >
7918                         flow_dv_modify_hdr_action_max(dev, is_root)) {
7919                 return rte_flow_error_set(error, ENOTSUP,
7920                                           RTE_FLOW_ERROR_TYPE_ACTION,
7921                                           NULL, "too many header modify"
7922                                           " actions to support");
7923         }
7924         /* Eswitch egress mirror and modify flow has limitation on CX5 */
7925         if (fdb_mirror_limit && modify_after_mirror)
7926                 return rte_flow_error_set(error, EINVAL,
7927                                 RTE_FLOW_ERROR_TYPE_ACTION, NULL,
7928                                 "sample before modify action is not supported");
7929         return 0;
7930 }
7931
7932 /**
7933  * Internal preparation function. Allocates the DV flow size,
7934  * this size is constant.
7935  *
7936  * @param[in] dev
7937  *   Pointer to the rte_eth_dev structure.
7938  * @param[in] attr
7939  *   Pointer to the flow attributes.
7940  * @param[in] items
7941  *   Pointer to the list of items.
7942  * @param[in] actions
7943  *   Pointer to the list of actions.
7944  * @param[out] error
7945  *   Pointer to the error structure.
7946  *
7947  * @return
7948  *   Pointer to mlx5_flow object on success,
7949  *   otherwise NULL and rte_errno is set.
7950  */
7951 static struct mlx5_flow *
7952 flow_dv_prepare(struct rte_eth_dev *dev,
7953                 const struct rte_flow_attr *attr __rte_unused,
7954                 const struct rte_flow_item items[] __rte_unused,
7955                 const struct rte_flow_action actions[] __rte_unused,
7956                 struct rte_flow_error *error)
7957 {
7958         uint32_t handle_idx = 0;
7959         struct mlx5_flow *dev_flow;
7960         struct mlx5_flow_handle *dev_handle;
7961         struct mlx5_priv *priv = dev->data->dev_private;
7962         struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace();
7963
7964         MLX5_ASSERT(wks);
7965         wks->skip_matcher_reg = 0;
7966         wks->policy = NULL;
7967         wks->final_policy = NULL;
7968         /* In case of corrupting the memory. */
7969         if (wks->flow_idx >= MLX5_NUM_MAX_DEV_FLOWS) {
7970                 rte_flow_error_set(error, ENOSPC,
7971                                    RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
7972                                    "not free temporary device flow");
7973                 return NULL;
7974         }
7975         dev_handle = mlx5_ipool_zmalloc(priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW],
7976                                    &handle_idx);
7977         if (!dev_handle) {
7978                 rte_flow_error_set(error, ENOMEM,
7979                                    RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
7980                                    "not enough memory to create flow handle");
7981                 return NULL;
7982         }
7983         MLX5_ASSERT(wks->flow_idx < RTE_DIM(wks->flows));
7984         dev_flow = &wks->flows[wks->flow_idx++];
7985         memset(dev_flow, 0, sizeof(*dev_flow));
7986         dev_flow->handle = dev_handle;
7987         dev_flow->handle_idx = handle_idx;
7988         dev_flow->dv.value.size = MLX5_ST_SZ_BYTES(fte_match_param);
7989         dev_flow->ingress = attr->ingress;
7990         dev_flow->dv.transfer = attr->transfer;
7991         return dev_flow;
7992 }
7993
7994 #ifdef RTE_LIBRTE_MLX5_DEBUG
7995 /**
7996  * Sanity check for match mask and value. Similar to check_valid_spec() in
7997  * kernel driver. If unmasked bit is present in value, it returns failure.
7998  *
7999  * @param match_mask
8000  *   pointer to match mask buffer.
8001  * @param match_value
8002  *   pointer to match value buffer.
8003  *
8004  * @return
8005  *   0 if valid, -EINVAL otherwise.
8006  */
8007 static int
8008 flow_dv_check_valid_spec(void *match_mask, void *match_value)
8009 {
8010         uint8_t *m = match_mask;
8011         uint8_t *v = match_value;
8012         unsigned int i;
8013
8014         for (i = 0; i < MLX5_ST_SZ_BYTES(fte_match_param); ++i) {
8015                 if (v[i] & ~m[i]) {
8016                         DRV_LOG(ERR,
8017                                 "match_value differs from match_criteria"
8018                                 " %p[%u] != %p[%u]",
8019                                 match_value, i, match_mask, i);
8020                         return -EINVAL;
8021                 }
8022         }
8023         return 0;
8024 }
8025 #endif
8026
8027 /**
8028  * Add match of ip_version.
8029  *
8030  * @param[in] group
8031  *   Flow group.
8032  * @param[in] headers_v
8033  *   Values header pointer.
8034  * @param[in] headers_m
8035  *   Masks header pointer.
8036  * @param[in] ip_version
8037  *   The IP version to set.
8038  */
8039 static inline void
8040 flow_dv_set_match_ip_version(uint32_t group,
8041                              void *headers_v,
8042                              void *headers_m,
8043                              uint8_t ip_version)
8044 {
8045         if (group == 0)
8046                 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_version, 0xf);
8047         else
8048                 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_version,
8049                          ip_version);
8050         MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_version, ip_version);
8051         MLX5_SET(fte_match_set_lyr_2_4, headers_v, ethertype, 0);
8052         MLX5_SET(fte_match_set_lyr_2_4, headers_m, ethertype, 0);
8053 }
8054
8055 /**
8056  * Add Ethernet item to matcher and to the value.
8057  *
8058  * @param[in, out] matcher
8059  *   Flow matcher.
8060  * @param[in, out] key
8061  *   Flow matcher value.
8062  * @param[in] item
8063  *   Flow pattern to translate.
8064  * @param[in] inner
8065  *   Item is inner pattern.
8066  */
8067 static void
8068 flow_dv_translate_item_eth(void *matcher, void *key,
8069                            const struct rte_flow_item *item, int inner,
8070                            uint32_t group)
8071 {
8072         const struct rte_flow_item_eth *eth_m = item->mask;
8073         const struct rte_flow_item_eth *eth_v = item->spec;
8074         const struct rte_flow_item_eth nic_mask = {
8075                 .dst.addr_bytes = "\xff\xff\xff\xff\xff\xff",
8076                 .src.addr_bytes = "\xff\xff\xff\xff\xff\xff",
8077                 .type = RTE_BE16(0xffff),
8078                 .has_vlan = 0,
8079         };
8080         void *hdrs_m;
8081         void *hdrs_v;
8082         char *l24_v;
8083         unsigned int i;
8084
8085         if (!eth_v)
8086                 return;
8087         if (!eth_m)
8088                 eth_m = &nic_mask;
8089         if (inner) {
8090                 hdrs_m = MLX5_ADDR_OF(fte_match_param, matcher,
8091                                          inner_headers);
8092                 hdrs_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
8093         } else {
8094                 hdrs_m = MLX5_ADDR_OF(fte_match_param, matcher,
8095                                          outer_headers);
8096                 hdrs_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
8097         }
8098         memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_m, dmac_47_16),
8099                &eth_m->dst, sizeof(eth_m->dst));
8100         /* The value must be in the range of the mask. */
8101         l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_v, dmac_47_16);
8102         for (i = 0; i < sizeof(eth_m->dst); ++i)
8103                 l24_v[i] = eth_m->dst.addr_bytes[i] & eth_v->dst.addr_bytes[i];
8104         memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_m, smac_47_16),
8105                &eth_m->src, sizeof(eth_m->src));
8106         l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_v, smac_47_16);
8107         /* The value must be in the range of the mask. */
8108         for (i = 0; i < sizeof(eth_m->dst); ++i)
8109                 l24_v[i] = eth_m->src.addr_bytes[i] & eth_v->src.addr_bytes[i];
8110         /*
8111          * HW supports match on one Ethertype, the Ethertype following the last
8112          * VLAN tag of the packet (see PRM).
8113          * Set match on ethertype only if ETH header is not followed by VLAN.
8114          * HW is optimized for IPv4/IPv6. In such cases, avoid setting
8115          * ethertype, and use ip_version field instead.
8116          * eCPRI over Ether layer will use type value 0xAEFE.
8117          */
8118         if (eth_m->type == 0xFFFF) {
8119                 /* Set cvlan_tag mask for any single\multi\un-tagged case. */
8120                 MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, cvlan_tag, 1);
8121                 switch (eth_v->type) {
8122                 case RTE_BE16(RTE_ETHER_TYPE_VLAN):
8123                         MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, cvlan_tag, 1);
8124                         return;
8125                 case RTE_BE16(RTE_ETHER_TYPE_QINQ):
8126                         MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, svlan_tag, 1);
8127                         MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, svlan_tag, 1);
8128                         return;
8129                 case RTE_BE16(RTE_ETHER_TYPE_IPV4):
8130                         flow_dv_set_match_ip_version(group, hdrs_v, hdrs_m, 4);
8131                         return;
8132                 case RTE_BE16(RTE_ETHER_TYPE_IPV6):
8133                         flow_dv_set_match_ip_version(group, hdrs_v, hdrs_m, 6);
8134                         return;
8135                 default:
8136                         break;
8137                 }
8138         }
8139         if (eth_m->has_vlan) {
8140                 MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, cvlan_tag, 1);
8141                 if (eth_v->has_vlan) {
8142                         /*
8143                          * Here, when also has_more_vlan field in VLAN item is
8144                          * not set, only single-tagged packets will be matched.
8145                          */
8146                         MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, cvlan_tag, 1);
8147                         return;
8148                 }
8149         }
8150         MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, ethertype,
8151                  rte_be_to_cpu_16(eth_m->type));
8152         l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_v, ethertype);
8153         *(uint16_t *)(l24_v) = eth_m->type & eth_v->type;
8154 }
8155
8156 /**
8157  * Add VLAN item to matcher and to the value.
8158  *
8159  * @param[in, out] dev_flow
8160  *   Flow descriptor.
8161  * @param[in, out] matcher
8162  *   Flow matcher.
8163  * @param[in, out] key
8164  *   Flow matcher value.
8165  * @param[in] item
8166  *   Flow pattern to translate.
8167  * @param[in] inner
8168  *   Item is inner pattern.
8169  */
8170 static void
8171 flow_dv_translate_item_vlan(struct mlx5_flow *dev_flow,
8172                             void *matcher, void *key,
8173                             const struct rte_flow_item *item,
8174                             int inner, uint32_t group)
8175 {
8176         const struct rte_flow_item_vlan *vlan_m = item->mask;
8177         const struct rte_flow_item_vlan *vlan_v = item->spec;
8178         void *hdrs_m;
8179         void *hdrs_v;
8180         uint16_t tci_m;
8181         uint16_t tci_v;
8182
8183         if (inner) {
8184                 hdrs_m = MLX5_ADDR_OF(fte_match_param, matcher,
8185                                          inner_headers);
8186                 hdrs_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
8187         } else {
8188                 hdrs_m = MLX5_ADDR_OF(fte_match_param, matcher,
8189                                          outer_headers);
8190                 hdrs_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
8191                 /*
8192                  * This is workaround, masks are not supported,
8193                  * and pre-validated.
8194                  */
8195                 if (vlan_v)
8196                         dev_flow->handle->vf_vlan.tag =
8197                                         rte_be_to_cpu_16(vlan_v->tci) & 0x0fff;
8198         }
8199         /*
8200          * When VLAN item exists in flow, mark packet as tagged,
8201          * even if TCI is not specified.
8202          */
8203         if (!MLX5_GET(fte_match_set_lyr_2_4, hdrs_v, svlan_tag)) {
8204                 MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, cvlan_tag, 1);
8205                 MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, cvlan_tag, 1);
8206         }
8207         if (!vlan_v)
8208                 return;
8209         if (!vlan_m)
8210                 vlan_m = &rte_flow_item_vlan_mask;
8211         tci_m = rte_be_to_cpu_16(vlan_m->tci);
8212         tci_v = rte_be_to_cpu_16(vlan_m->tci & vlan_v->tci);
8213         MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, first_vid, tci_m);
8214         MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, first_vid, tci_v);
8215         MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, first_cfi, tci_m >> 12);
8216         MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, first_cfi, tci_v >> 12);
8217         MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, first_prio, tci_m >> 13);
8218         MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, first_prio, tci_v >> 13);
8219         /*
8220          * HW is optimized for IPv4/IPv6. In such cases, avoid setting
8221          * ethertype, and use ip_version field instead.
8222          */
8223         if (vlan_m->inner_type == 0xFFFF) {
8224                 switch (vlan_v->inner_type) {
8225                 case RTE_BE16(RTE_ETHER_TYPE_VLAN):
8226                         MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, svlan_tag, 1);
8227                         MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, svlan_tag, 1);
8228                         MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, cvlan_tag, 0);
8229                         return;
8230                 case RTE_BE16(RTE_ETHER_TYPE_IPV4):
8231                         flow_dv_set_match_ip_version(group, hdrs_v, hdrs_m, 4);
8232                         return;
8233                 case RTE_BE16(RTE_ETHER_TYPE_IPV6):
8234                         flow_dv_set_match_ip_version(group, hdrs_v, hdrs_m, 6);
8235                         return;
8236                 default:
8237                         break;
8238                 }
8239         }
8240         if (vlan_m->has_more_vlan && vlan_v->has_more_vlan) {
8241                 MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, svlan_tag, 1);
8242                 MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, svlan_tag, 1);
8243                 /* Only one vlan_tag bit can be set. */
8244                 MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, cvlan_tag, 0);
8245                 return;
8246         }
8247         MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, ethertype,
8248                  rte_be_to_cpu_16(vlan_m->inner_type));
8249         MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, ethertype,
8250                  rte_be_to_cpu_16(vlan_m->inner_type & vlan_v->inner_type));
8251 }
8252
8253 /**
8254  * Add IPV4 item to matcher and to the value.
8255  *
8256  * @param[in, out] matcher
8257  *   Flow matcher.
8258  * @param[in, out] key
8259  *   Flow matcher value.
8260  * @param[in] item
8261  *   Flow pattern to translate.
8262  * @param[in] inner
8263  *   Item is inner pattern.
8264  * @param[in] group
8265  *   The group to insert the rule.
8266  */
8267 static void
8268 flow_dv_translate_item_ipv4(void *matcher, void *key,
8269                             const struct rte_flow_item *item,
8270                             int inner, uint32_t group)
8271 {
8272         const struct rte_flow_item_ipv4 *ipv4_m = item->mask;
8273         const struct rte_flow_item_ipv4 *ipv4_v = item->spec;
8274         const struct rte_flow_item_ipv4 nic_mask = {
8275                 .hdr = {
8276                         .src_addr = RTE_BE32(0xffffffff),
8277                         .dst_addr = RTE_BE32(0xffffffff),
8278                         .type_of_service = 0xff,
8279                         .next_proto_id = 0xff,
8280                         .time_to_live = 0xff,
8281                 },
8282         };
8283         void *headers_m;
8284         void *headers_v;
8285         char *l24_m;
8286         char *l24_v;
8287         uint8_t tos, ihl_m, ihl_v;
8288
8289         if (inner) {
8290                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8291                                          inner_headers);
8292                 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
8293         } else {
8294                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8295                                          outer_headers);
8296                 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
8297         }
8298         flow_dv_set_match_ip_version(group, headers_v, headers_m, 4);
8299         if (!ipv4_v)
8300                 return;
8301         if (!ipv4_m)
8302                 ipv4_m = &nic_mask;
8303         l24_m = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_m,
8304                              dst_ipv4_dst_ipv6.ipv4_layout.ipv4);
8305         l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
8306                              dst_ipv4_dst_ipv6.ipv4_layout.ipv4);
8307         *(uint32_t *)l24_m = ipv4_m->hdr.dst_addr;
8308         *(uint32_t *)l24_v = ipv4_m->hdr.dst_addr & ipv4_v->hdr.dst_addr;
8309         l24_m = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_m,
8310                           src_ipv4_src_ipv6.ipv4_layout.ipv4);
8311         l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
8312                           src_ipv4_src_ipv6.ipv4_layout.ipv4);
8313         *(uint32_t *)l24_m = ipv4_m->hdr.src_addr;
8314         *(uint32_t *)l24_v = ipv4_m->hdr.src_addr & ipv4_v->hdr.src_addr;
8315         tos = ipv4_m->hdr.type_of_service & ipv4_v->hdr.type_of_service;
8316         ihl_m = ipv4_m->hdr.version_ihl & RTE_IPV4_HDR_IHL_MASK;
8317         ihl_v = ipv4_v->hdr.version_ihl & RTE_IPV4_HDR_IHL_MASK;
8318         MLX5_SET(fte_match_set_lyr_2_4, headers_m, ipv4_ihl, ihl_m);
8319         MLX5_SET(fte_match_set_lyr_2_4, headers_v, ipv4_ihl, ihl_m & ihl_v);
8320         MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_ecn,
8321                  ipv4_m->hdr.type_of_service);
8322         MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_ecn, tos);
8323         MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_dscp,
8324                  ipv4_m->hdr.type_of_service >> 2);
8325         MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_dscp, tos >> 2);
8326         MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol,
8327                  ipv4_m->hdr.next_proto_id);
8328         MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol,
8329                  ipv4_v->hdr.next_proto_id & ipv4_m->hdr.next_proto_id);
8330         MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_ttl_hoplimit,
8331                  ipv4_m->hdr.time_to_live);
8332         MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_ttl_hoplimit,
8333                  ipv4_v->hdr.time_to_live & ipv4_m->hdr.time_to_live);
8334         MLX5_SET(fte_match_set_lyr_2_4, headers_m, frag,
8335                  !!(ipv4_m->hdr.fragment_offset));
8336         MLX5_SET(fte_match_set_lyr_2_4, headers_v, frag,
8337                  !!(ipv4_v->hdr.fragment_offset & ipv4_m->hdr.fragment_offset));
8338 }
8339
8340 /**
8341  * Add IPV6 item to matcher and to the value.
8342  *
8343  * @param[in, out] matcher
8344  *   Flow matcher.
8345  * @param[in, out] key
8346  *   Flow matcher value.
8347  * @param[in] item
8348  *   Flow pattern to translate.
8349  * @param[in] inner
8350  *   Item is inner pattern.
8351  * @param[in] group
8352  *   The group to insert the rule.
8353  */
8354 static void
8355 flow_dv_translate_item_ipv6(void *matcher, void *key,
8356                             const struct rte_flow_item *item,
8357                             int inner, uint32_t group)
8358 {
8359         const struct rte_flow_item_ipv6 *ipv6_m = item->mask;
8360         const struct rte_flow_item_ipv6 *ipv6_v = item->spec;
8361         const struct rte_flow_item_ipv6 nic_mask = {
8362                 .hdr = {
8363                         .src_addr =
8364                                 "\xff\xff\xff\xff\xff\xff\xff\xff"
8365                                 "\xff\xff\xff\xff\xff\xff\xff\xff",
8366                         .dst_addr =
8367                                 "\xff\xff\xff\xff\xff\xff\xff\xff"
8368                                 "\xff\xff\xff\xff\xff\xff\xff\xff",
8369                         .vtc_flow = RTE_BE32(0xffffffff),
8370                         .proto = 0xff,
8371                         .hop_limits = 0xff,
8372                 },
8373         };
8374         void *headers_m;
8375         void *headers_v;
8376         void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
8377         void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
8378         char *l24_m;
8379         char *l24_v;
8380         uint32_t vtc_m;
8381         uint32_t vtc_v;
8382         int i;
8383         int size;
8384
8385         if (inner) {
8386                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8387                                          inner_headers);
8388                 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
8389         } else {
8390                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8391                                          outer_headers);
8392                 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
8393         }
8394         flow_dv_set_match_ip_version(group, headers_v, headers_m, 6);
8395         if (!ipv6_v)
8396                 return;
8397         if (!ipv6_m)
8398                 ipv6_m = &nic_mask;
8399         size = sizeof(ipv6_m->hdr.dst_addr);
8400         l24_m = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_m,
8401                              dst_ipv4_dst_ipv6.ipv6_layout.ipv6);
8402         l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
8403                              dst_ipv4_dst_ipv6.ipv6_layout.ipv6);
8404         memcpy(l24_m, ipv6_m->hdr.dst_addr, size);
8405         for (i = 0; i < size; ++i)
8406                 l24_v[i] = l24_m[i] & ipv6_v->hdr.dst_addr[i];
8407         l24_m = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_m,
8408                              src_ipv4_src_ipv6.ipv6_layout.ipv6);
8409         l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
8410                              src_ipv4_src_ipv6.ipv6_layout.ipv6);
8411         memcpy(l24_m, ipv6_m->hdr.src_addr, size);
8412         for (i = 0; i < size; ++i)
8413                 l24_v[i] = l24_m[i] & ipv6_v->hdr.src_addr[i];
8414         /* TOS. */
8415         vtc_m = rte_be_to_cpu_32(ipv6_m->hdr.vtc_flow);
8416         vtc_v = rte_be_to_cpu_32(ipv6_m->hdr.vtc_flow & ipv6_v->hdr.vtc_flow);
8417         MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_ecn, vtc_m >> 20);
8418         MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_ecn, vtc_v >> 20);
8419         MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_dscp, vtc_m >> 22);
8420         MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_dscp, vtc_v >> 22);
8421         /* Label. */
8422         if (inner) {
8423                 MLX5_SET(fte_match_set_misc, misc_m, inner_ipv6_flow_label,
8424                          vtc_m);
8425                 MLX5_SET(fte_match_set_misc, misc_v, inner_ipv6_flow_label,
8426                          vtc_v);
8427         } else {
8428                 MLX5_SET(fte_match_set_misc, misc_m, outer_ipv6_flow_label,
8429                          vtc_m);
8430                 MLX5_SET(fte_match_set_misc, misc_v, outer_ipv6_flow_label,
8431                          vtc_v);
8432         }
8433         /* Protocol. */
8434         MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol,
8435                  ipv6_m->hdr.proto);
8436         MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol,
8437                  ipv6_v->hdr.proto & ipv6_m->hdr.proto);
8438         /* Hop limit. */
8439         MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_ttl_hoplimit,
8440                  ipv6_m->hdr.hop_limits);
8441         MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_ttl_hoplimit,
8442                  ipv6_v->hdr.hop_limits & ipv6_m->hdr.hop_limits);
8443         MLX5_SET(fte_match_set_lyr_2_4, headers_m, frag,
8444                  !!(ipv6_m->has_frag_ext));
8445         MLX5_SET(fte_match_set_lyr_2_4, headers_v, frag,
8446                  !!(ipv6_v->has_frag_ext & ipv6_m->has_frag_ext));
8447 }
8448
8449 /**
8450  * Add IPV6 fragment extension item to matcher and to the value.
8451  *
8452  * @param[in, out] matcher
8453  *   Flow matcher.
8454  * @param[in, out] key
8455  *   Flow matcher value.
8456  * @param[in] item
8457  *   Flow pattern to translate.
8458  * @param[in] inner
8459  *   Item is inner pattern.
8460  */
8461 static void
8462 flow_dv_translate_item_ipv6_frag_ext(void *matcher, void *key,
8463                                      const struct rte_flow_item *item,
8464                                      int inner)
8465 {
8466         const struct rte_flow_item_ipv6_frag_ext *ipv6_frag_ext_m = item->mask;
8467         const struct rte_flow_item_ipv6_frag_ext *ipv6_frag_ext_v = item->spec;
8468         const struct rte_flow_item_ipv6_frag_ext nic_mask = {
8469                 .hdr = {
8470                         .next_header = 0xff,
8471                         .frag_data = RTE_BE16(0xffff),
8472                 },
8473         };
8474         void *headers_m;
8475         void *headers_v;
8476
8477         if (inner) {
8478                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8479                                          inner_headers);
8480                 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
8481         } else {
8482                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8483                                          outer_headers);
8484                 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
8485         }
8486         /* IPv6 fragment extension item exists, so packet is IP fragment. */
8487         MLX5_SET(fte_match_set_lyr_2_4, headers_m, frag, 1);
8488         MLX5_SET(fte_match_set_lyr_2_4, headers_v, frag, 1);
8489         if (!ipv6_frag_ext_v)
8490                 return;
8491         if (!ipv6_frag_ext_m)
8492                 ipv6_frag_ext_m = &nic_mask;
8493         MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol,
8494                  ipv6_frag_ext_m->hdr.next_header);
8495         MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol,
8496                  ipv6_frag_ext_v->hdr.next_header &
8497                  ipv6_frag_ext_m->hdr.next_header);
8498 }
8499
8500 /**
8501  * Add TCP item to matcher and to the value.
8502  *
8503  * @param[in, out] matcher
8504  *   Flow matcher.
8505  * @param[in, out] key
8506  *   Flow matcher value.
8507  * @param[in] item
8508  *   Flow pattern to translate.
8509  * @param[in] inner
8510  *   Item is inner pattern.
8511  */
8512 static void
8513 flow_dv_translate_item_tcp(void *matcher, void *key,
8514                            const struct rte_flow_item *item,
8515                            int inner)
8516 {
8517         const struct rte_flow_item_tcp *tcp_m = item->mask;
8518         const struct rte_flow_item_tcp *tcp_v = item->spec;
8519         void *headers_m;
8520         void *headers_v;
8521
8522         if (inner) {
8523                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8524                                          inner_headers);
8525                 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
8526         } else {
8527                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8528                                          outer_headers);
8529                 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
8530         }
8531         MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 0xff);
8532         MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_TCP);
8533         if (!tcp_v)
8534                 return;
8535         if (!tcp_m)
8536                 tcp_m = &rte_flow_item_tcp_mask;
8537         MLX5_SET(fte_match_set_lyr_2_4, headers_m, tcp_sport,
8538                  rte_be_to_cpu_16(tcp_m->hdr.src_port));
8539         MLX5_SET(fte_match_set_lyr_2_4, headers_v, tcp_sport,
8540                  rte_be_to_cpu_16(tcp_v->hdr.src_port & tcp_m->hdr.src_port));
8541         MLX5_SET(fte_match_set_lyr_2_4, headers_m, tcp_dport,
8542                  rte_be_to_cpu_16(tcp_m->hdr.dst_port));
8543         MLX5_SET(fte_match_set_lyr_2_4, headers_v, tcp_dport,
8544                  rte_be_to_cpu_16(tcp_v->hdr.dst_port & tcp_m->hdr.dst_port));
8545         MLX5_SET(fte_match_set_lyr_2_4, headers_m, tcp_flags,
8546                  tcp_m->hdr.tcp_flags);
8547         MLX5_SET(fte_match_set_lyr_2_4, headers_v, tcp_flags,
8548                  (tcp_v->hdr.tcp_flags & tcp_m->hdr.tcp_flags));
8549 }
8550
8551 /**
8552  * Add UDP item to matcher and to the value.
8553  *
8554  * @param[in, out] matcher
8555  *   Flow matcher.
8556  * @param[in, out] key
8557  *   Flow matcher value.
8558  * @param[in] item
8559  *   Flow pattern to translate.
8560  * @param[in] inner
8561  *   Item is inner pattern.
8562  */
8563 static void
8564 flow_dv_translate_item_udp(void *matcher, void *key,
8565                            const struct rte_flow_item *item,
8566                            int inner)
8567 {
8568         const struct rte_flow_item_udp *udp_m = item->mask;
8569         const struct rte_flow_item_udp *udp_v = item->spec;
8570         void *headers_m;
8571         void *headers_v;
8572
8573         if (inner) {
8574                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8575                                          inner_headers);
8576                 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
8577         } else {
8578                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8579                                          outer_headers);
8580                 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
8581         }
8582         MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 0xff);
8583         MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_UDP);
8584         if (!udp_v)
8585                 return;
8586         if (!udp_m)
8587                 udp_m = &rte_flow_item_udp_mask;
8588         MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_sport,
8589                  rte_be_to_cpu_16(udp_m->hdr.src_port));
8590         MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_sport,
8591                  rte_be_to_cpu_16(udp_v->hdr.src_port & udp_m->hdr.src_port));
8592         MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_dport,
8593                  rte_be_to_cpu_16(udp_m->hdr.dst_port));
8594         MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport,
8595                  rte_be_to_cpu_16(udp_v->hdr.dst_port & udp_m->hdr.dst_port));
8596 }
8597
8598 /**
8599  * Add GRE optional Key item to matcher and to the value.
8600  *
8601  * @param[in, out] matcher
8602  *   Flow matcher.
8603  * @param[in, out] key
8604  *   Flow matcher value.
8605  * @param[in] item
8606  *   Flow pattern to translate.
8607  * @param[in] inner
8608  *   Item is inner pattern.
8609  */
8610 static void
8611 flow_dv_translate_item_gre_key(void *matcher, void *key,
8612                                    const struct rte_flow_item *item)
8613 {
8614         const rte_be32_t *key_m = item->mask;
8615         const rte_be32_t *key_v = item->spec;
8616         void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
8617         void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
8618         rte_be32_t gre_key_default_mask = RTE_BE32(UINT32_MAX);
8619
8620         /* GRE K bit must be on and should already be validated */
8621         MLX5_SET(fte_match_set_misc, misc_m, gre_k_present, 1);
8622         MLX5_SET(fte_match_set_misc, misc_v, gre_k_present, 1);
8623         if (!key_v)
8624                 return;
8625         if (!key_m)
8626                 key_m = &gre_key_default_mask;
8627         MLX5_SET(fte_match_set_misc, misc_m, gre_key_h,
8628                  rte_be_to_cpu_32(*key_m) >> 8);
8629         MLX5_SET(fte_match_set_misc, misc_v, gre_key_h,
8630                  rte_be_to_cpu_32((*key_v) & (*key_m)) >> 8);
8631         MLX5_SET(fte_match_set_misc, misc_m, gre_key_l,
8632                  rte_be_to_cpu_32(*key_m) & 0xFF);
8633         MLX5_SET(fte_match_set_misc, misc_v, gre_key_l,
8634                  rte_be_to_cpu_32((*key_v) & (*key_m)) & 0xFF);
8635 }
8636
8637 /**
8638  * Add GRE item to matcher and to the value.
8639  *
8640  * @param[in, out] matcher
8641  *   Flow matcher.
8642  * @param[in, out] key
8643  *   Flow matcher value.
8644  * @param[in] item
8645  *   Flow pattern to translate.
8646  * @param[in] inner
8647  *   Item is inner pattern.
8648  */
8649 static void
8650 flow_dv_translate_item_gre(void *matcher, void *key,
8651                            const struct rte_flow_item *item,
8652                            int inner)
8653 {
8654         const struct rte_flow_item_gre *gre_m = item->mask;
8655         const struct rte_flow_item_gre *gre_v = item->spec;
8656         void *headers_m;
8657         void *headers_v;
8658         void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
8659         void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
8660         struct {
8661                 union {
8662                         __extension__
8663                         struct {
8664                                 uint16_t version:3;
8665                                 uint16_t rsvd0:9;
8666                                 uint16_t s_present:1;
8667                                 uint16_t k_present:1;
8668                                 uint16_t rsvd_bit1:1;
8669                                 uint16_t c_present:1;
8670                         };
8671                         uint16_t value;
8672                 };
8673         } gre_crks_rsvd0_ver_m, gre_crks_rsvd0_ver_v;
8674
8675         if (inner) {
8676                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8677                                          inner_headers);
8678                 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
8679         } else {
8680                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8681                                          outer_headers);
8682                 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
8683         }
8684         MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 0xff);
8685         MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_GRE);
8686         if (!gre_v)
8687                 return;
8688         if (!gre_m)
8689                 gre_m = &rte_flow_item_gre_mask;
8690         MLX5_SET(fte_match_set_misc, misc_m, gre_protocol,
8691                  rte_be_to_cpu_16(gre_m->protocol));
8692         MLX5_SET(fte_match_set_misc, misc_v, gre_protocol,
8693                  rte_be_to_cpu_16(gre_v->protocol & gre_m->protocol));
8694         gre_crks_rsvd0_ver_m.value = rte_be_to_cpu_16(gre_m->c_rsvd0_ver);
8695         gre_crks_rsvd0_ver_v.value = rte_be_to_cpu_16(gre_v->c_rsvd0_ver);
8696         MLX5_SET(fte_match_set_misc, misc_m, gre_c_present,
8697                  gre_crks_rsvd0_ver_m.c_present);
8698         MLX5_SET(fte_match_set_misc, misc_v, gre_c_present,
8699                  gre_crks_rsvd0_ver_v.c_present &
8700                  gre_crks_rsvd0_ver_m.c_present);
8701         MLX5_SET(fte_match_set_misc, misc_m, gre_k_present,
8702                  gre_crks_rsvd0_ver_m.k_present);
8703         MLX5_SET(fte_match_set_misc, misc_v, gre_k_present,
8704                  gre_crks_rsvd0_ver_v.k_present &
8705                  gre_crks_rsvd0_ver_m.k_present);
8706         MLX5_SET(fte_match_set_misc, misc_m, gre_s_present,
8707                  gre_crks_rsvd0_ver_m.s_present);
8708         MLX5_SET(fte_match_set_misc, misc_v, gre_s_present,
8709                  gre_crks_rsvd0_ver_v.s_present &
8710                  gre_crks_rsvd0_ver_m.s_present);
8711 }
8712
8713 /**
8714  * Add NVGRE item to matcher and to the value.
8715  *
8716  * @param[in, out] matcher
8717  *   Flow matcher.
8718  * @param[in, out] key
8719  *   Flow matcher value.
8720  * @param[in] item
8721  *   Flow pattern to translate.
8722  * @param[in] inner
8723  *   Item is inner pattern.
8724  */
8725 static void
8726 flow_dv_translate_item_nvgre(void *matcher, void *key,
8727                              const struct rte_flow_item *item,
8728                              int inner)
8729 {
8730         const struct rte_flow_item_nvgre *nvgre_m = item->mask;
8731         const struct rte_flow_item_nvgre *nvgre_v = item->spec;
8732         void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
8733         void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
8734         const char *tni_flow_id_m;
8735         const char *tni_flow_id_v;
8736         char *gre_key_m;
8737         char *gre_key_v;
8738         int size;
8739         int i;
8740
8741         /* For NVGRE, GRE header fields must be set with defined values. */
8742         const struct rte_flow_item_gre gre_spec = {
8743                 .c_rsvd0_ver = RTE_BE16(0x2000),
8744                 .protocol = RTE_BE16(RTE_ETHER_TYPE_TEB)
8745         };
8746         const struct rte_flow_item_gre gre_mask = {
8747                 .c_rsvd0_ver = RTE_BE16(0xB000),
8748                 .protocol = RTE_BE16(UINT16_MAX),
8749         };
8750         const struct rte_flow_item gre_item = {
8751                 .spec = &gre_spec,
8752                 .mask = &gre_mask,
8753                 .last = NULL,
8754         };
8755         flow_dv_translate_item_gre(matcher, key, &gre_item, inner);
8756         if (!nvgre_v)
8757                 return;
8758         if (!nvgre_m)
8759                 nvgre_m = &rte_flow_item_nvgre_mask;
8760         tni_flow_id_m = (const char *)nvgre_m->tni;
8761         tni_flow_id_v = (const char *)nvgre_v->tni;
8762         size = sizeof(nvgre_m->tni) + sizeof(nvgre_m->flow_id);
8763         gre_key_m = MLX5_ADDR_OF(fte_match_set_misc, misc_m, gre_key_h);
8764         gre_key_v = MLX5_ADDR_OF(fte_match_set_misc, misc_v, gre_key_h);
8765         memcpy(gre_key_m, tni_flow_id_m, size);
8766         for (i = 0; i < size; ++i)
8767                 gre_key_v[i] = gre_key_m[i] & tni_flow_id_v[i];
8768 }
8769
8770 /**
8771  * Add VXLAN item to matcher and to the value.
8772  *
8773  * @param[in] dev
8774  *   Pointer to the Ethernet device structure.
8775  * @param[in] attr
8776  *   Flow rule attributes.
8777  * @param[in, out] matcher
8778  *   Flow matcher.
8779  * @param[in, out] key
8780  *   Flow matcher value.
8781  * @param[in] item
8782  *   Flow pattern to translate.
8783  * @param[in] inner
8784  *   Item is inner pattern.
8785  */
8786 static void
8787 flow_dv_translate_item_vxlan(struct rte_eth_dev *dev,
8788                              const struct rte_flow_attr *attr,
8789                              void *matcher, void *key,
8790                              const struct rte_flow_item *item,
8791                              int inner)
8792 {
8793         const struct rte_flow_item_vxlan *vxlan_m = item->mask;
8794         const struct rte_flow_item_vxlan *vxlan_v = item->spec;
8795         void *headers_m;
8796         void *headers_v;
8797         void *misc5_m;
8798         void *misc5_v;
8799         uint32_t *tunnel_header_v;
8800         uint32_t *tunnel_header_m;
8801         uint16_t dport;
8802         struct mlx5_priv *priv = dev->data->dev_private;
8803         const struct rte_flow_item_vxlan nic_mask = {
8804                 .vni = "\xff\xff\xff",
8805                 .rsvd1 = 0xff,
8806         };
8807
8808         if (inner) {
8809                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8810                                          inner_headers);
8811                 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
8812         } else {
8813                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8814                                          outer_headers);
8815                 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
8816         }
8817         dport = item->type == RTE_FLOW_ITEM_TYPE_VXLAN ?
8818                 MLX5_UDP_PORT_VXLAN : MLX5_UDP_PORT_VXLAN_GPE;
8819         if (!MLX5_GET16(fte_match_set_lyr_2_4, headers_v, udp_dport)) {
8820                 MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_dport, 0xFFFF);
8821                 MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport, dport);
8822         }
8823         dport = MLX5_GET16(fte_match_set_lyr_2_4, headers_v, udp_dport);
8824         if (!vxlan_v)
8825                 return;
8826         if (!vxlan_m) {
8827                 if ((!attr->group && !priv->sh->tunnel_header_0_1) ||
8828                     (attr->group && !priv->sh->misc5_cap))
8829                         vxlan_m = &rte_flow_item_vxlan_mask;
8830                 else
8831                         vxlan_m = &nic_mask;
8832         }
8833         if ((priv->sh->steering_format_version ==
8834             MLX5_STEERING_LOGIC_FORMAT_CONNECTX_5 &&
8835             dport != MLX5_UDP_PORT_VXLAN) ||
8836             (!attr->group && !attr->transfer && !priv->sh->tunnel_header_0_1) ||
8837             ((attr->group || attr->transfer) && !priv->sh->misc5_cap)) {
8838                 void *misc_m;
8839                 void *misc_v;
8840                 char *vni_m;
8841                 char *vni_v;
8842                 int size;
8843                 int i;
8844                 misc_m = MLX5_ADDR_OF(fte_match_param,
8845                                       matcher, misc_parameters);
8846                 misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
8847                 size = sizeof(vxlan_m->vni);
8848                 vni_m = MLX5_ADDR_OF(fte_match_set_misc, misc_m, vxlan_vni);
8849                 vni_v = MLX5_ADDR_OF(fte_match_set_misc, misc_v, vxlan_vni);
8850                 memcpy(vni_m, vxlan_m->vni, size);
8851                 for (i = 0; i < size; ++i)
8852                         vni_v[i] = vni_m[i] & vxlan_v->vni[i];
8853                 return;
8854         }
8855         misc5_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters_5);
8856         misc5_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_5);
8857         tunnel_header_v = (uint32_t *)MLX5_ADDR_OF(fte_match_set_misc5,
8858                                                    misc5_v,
8859                                                    tunnel_header_1);
8860         tunnel_header_m = (uint32_t *)MLX5_ADDR_OF(fte_match_set_misc5,
8861                                                    misc5_m,
8862                                                    tunnel_header_1);
8863         *tunnel_header_v = (vxlan_v->vni[0] & vxlan_m->vni[0]) |
8864                            (vxlan_v->vni[1] & vxlan_m->vni[1]) << 8 |
8865                            (vxlan_v->vni[2] & vxlan_m->vni[2]) << 16;
8866         if (*tunnel_header_v)
8867                 *tunnel_header_m = vxlan_m->vni[0] |
8868                         vxlan_m->vni[1] << 8 |
8869                         vxlan_m->vni[2] << 16;
8870         else
8871                 *tunnel_header_m = 0x0;
8872         *tunnel_header_v |= (vxlan_v->rsvd1 & vxlan_m->rsvd1) << 24;
8873         if (vxlan_v->rsvd1 & vxlan_m->rsvd1)
8874                 *tunnel_header_m |= vxlan_m->rsvd1 << 24;
8875 }
8876
8877 /**
8878  * Add VXLAN-GPE item to matcher and to the value.
8879  *
8880  * @param[in, out] matcher
8881  *   Flow matcher.
8882  * @param[in, out] key
8883  *   Flow matcher value.
8884  * @param[in] item
8885  *   Flow pattern to translate.
8886  * @param[in] inner
8887  *   Item is inner pattern.
8888  */
8889
8890 static void
8891 flow_dv_translate_item_vxlan_gpe(void *matcher, void *key,
8892                                  const struct rte_flow_item *item, int inner)
8893 {
8894         const struct rte_flow_item_vxlan_gpe *vxlan_m = item->mask;
8895         const struct rte_flow_item_vxlan_gpe *vxlan_v = item->spec;
8896         void *headers_m;
8897         void *headers_v;
8898         void *misc_m =
8899                 MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters_3);
8900         void *misc_v =
8901                 MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3);
8902         char *vni_m;
8903         char *vni_v;
8904         uint16_t dport;
8905         int size;
8906         int i;
8907         uint8_t flags_m = 0xff;
8908         uint8_t flags_v = 0xc;
8909
8910         if (inner) {
8911                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8912                                          inner_headers);
8913                 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
8914         } else {
8915                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8916                                          outer_headers);
8917                 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
8918         }
8919         dport = item->type == RTE_FLOW_ITEM_TYPE_VXLAN ?
8920                 MLX5_UDP_PORT_VXLAN : MLX5_UDP_PORT_VXLAN_GPE;
8921         if (!MLX5_GET16(fte_match_set_lyr_2_4, headers_v, udp_dport)) {
8922                 MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_dport, 0xFFFF);
8923                 MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport, dport);
8924         }
8925         if (!vxlan_v)
8926                 return;
8927         if (!vxlan_m)
8928                 vxlan_m = &rte_flow_item_vxlan_gpe_mask;
8929         size = sizeof(vxlan_m->vni);
8930         vni_m = MLX5_ADDR_OF(fte_match_set_misc3, misc_m, outer_vxlan_gpe_vni);
8931         vni_v = MLX5_ADDR_OF(fte_match_set_misc3, misc_v, outer_vxlan_gpe_vni);
8932         memcpy(vni_m, vxlan_m->vni, size);
8933         for (i = 0; i < size; ++i)
8934                 vni_v[i] = vni_m[i] & vxlan_v->vni[i];
8935         if (vxlan_m->flags) {
8936                 flags_m = vxlan_m->flags;
8937                 flags_v = vxlan_v->flags;
8938         }
8939         MLX5_SET(fte_match_set_misc3, misc_m, outer_vxlan_gpe_flags, flags_m);
8940         MLX5_SET(fte_match_set_misc3, misc_v, outer_vxlan_gpe_flags, flags_v);
8941         MLX5_SET(fte_match_set_misc3, misc_m, outer_vxlan_gpe_next_protocol,
8942                  vxlan_m->protocol);
8943         MLX5_SET(fte_match_set_misc3, misc_v, outer_vxlan_gpe_next_protocol,
8944                  vxlan_v->protocol);
8945 }
8946
8947 /**
8948  * Add Geneve item to matcher and to the value.
8949  *
8950  * @param[in, out] matcher
8951  *   Flow matcher.
8952  * @param[in, out] key
8953  *   Flow matcher value.
8954  * @param[in] item
8955  *   Flow pattern to translate.
8956  * @param[in] inner
8957  *   Item is inner pattern.
8958  */
8959
8960 static void
8961 flow_dv_translate_item_geneve(void *matcher, void *key,
8962                               const struct rte_flow_item *item, int inner)
8963 {
8964         const struct rte_flow_item_geneve *geneve_m = item->mask;
8965         const struct rte_flow_item_geneve *geneve_v = item->spec;
8966         void *headers_m;
8967         void *headers_v;
8968         void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
8969         void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
8970         uint16_t dport;
8971         uint16_t gbhdr_m;
8972         uint16_t gbhdr_v;
8973         char *vni_m;
8974         char *vni_v;
8975         size_t size, i;
8976
8977         if (inner) {
8978                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8979                                          inner_headers);
8980                 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
8981         } else {
8982                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8983                                          outer_headers);
8984                 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
8985         }
8986         dport = MLX5_UDP_PORT_GENEVE;
8987         if (!MLX5_GET16(fte_match_set_lyr_2_4, headers_v, udp_dport)) {
8988                 MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_dport, 0xFFFF);
8989                 MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport, dport);
8990         }
8991         if (!geneve_v)
8992                 return;
8993         if (!geneve_m)
8994                 geneve_m = &rte_flow_item_geneve_mask;
8995         size = sizeof(geneve_m->vni);
8996         vni_m = MLX5_ADDR_OF(fte_match_set_misc, misc_m, geneve_vni);
8997         vni_v = MLX5_ADDR_OF(fte_match_set_misc, misc_v, geneve_vni);
8998         memcpy(vni_m, geneve_m->vni, size);
8999         for (i = 0; i < size; ++i)
9000                 vni_v[i] = vni_m[i] & geneve_v->vni[i];
9001         MLX5_SET(fte_match_set_misc, misc_m, geneve_protocol_type,
9002                  rte_be_to_cpu_16(geneve_m->protocol));
9003         MLX5_SET(fte_match_set_misc, misc_v, geneve_protocol_type,
9004                  rte_be_to_cpu_16(geneve_v->protocol & geneve_m->protocol));
9005         gbhdr_m = rte_be_to_cpu_16(geneve_m->ver_opt_len_o_c_rsvd0);
9006         gbhdr_v = rte_be_to_cpu_16(geneve_v->ver_opt_len_o_c_rsvd0);
9007         MLX5_SET(fte_match_set_misc, misc_m, geneve_oam,
9008                  MLX5_GENEVE_OAMF_VAL(gbhdr_m));
9009         MLX5_SET(fte_match_set_misc, misc_v, geneve_oam,
9010                  MLX5_GENEVE_OAMF_VAL(gbhdr_v) & MLX5_GENEVE_OAMF_VAL(gbhdr_m));
9011         MLX5_SET(fte_match_set_misc, misc_m, geneve_opt_len,
9012                  MLX5_GENEVE_OPTLEN_VAL(gbhdr_m));
9013         MLX5_SET(fte_match_set_misc, misc_v, geneve_opt_len,
9014                  MLX5_GENEVE_OPTLEN_VAL(gbhdr_v) &
9015                  MLX5_GENEVE_OPTLEN_VAL(gbhdr_m));
9016 }
9017
9018 /**
9019  * Create Geneve TLV option resource.
9020  *
9021  * @param dev[in, out]
9022  *   Pointer to rte_eth_dev structure.
9023  * @param[in, out] tag_be24
9024  *   Tag value in big endian then R-shift 8.
9025  * @parm[in, out] dev_flow
9026  *   Pointer to the dev_flow.
9027  * @param[out] error
9028  *   pointer to error structure.
9029  *
9030  * @return
9031  *   0 on success otherwise -errno and errno is set.
9032  */
9033
9034 int
9035 flow_dev_geneve_tlv_option_resource_register(struct rte_eth_dev *dev,
9036                                              const struct rte_flow_item *item,
9037                                              struct rte_flow_error *error)
9038 {
9039         struct mlx5_priv *priv = dev->data->dev_private;
9040         struct mlx5_dev_ctx_shared *sh = priv->sh;
9041         struct mlx5_geneve_tlv_option_resource *geneve_opt_resource =
9042                         sh->geneve_tlv_option_resource;
9043         struct mlx5_devx_obj *obj;
9044         const struct rte_flow_item_geneve_opt *geneve_opt_v = item->spec;
9045         int ret = 0;
9046
9047         if (!geneve_opt_v)
9048                 return -1;
9049         rte_spinlock_lock(&sh->geneve_tlv_opt_sl);
9050         if (geneve_opt_resource != NULL) {
9051                 if (geneve_opt_resource->option_class ==
9052                         geneve_opt_v->option_class &&
9053                         geneve_opt_resource->option_type ==
9054                         geneve_opt_v->option_type &&
9055                         geneve_opt_resource->length ==
9056                         geneve_opt_v->option_len) {
9057                         /* We already have GENVE TLV option obj allocated. */
9058                         __atomic_fetch_add(&geneve_opt_resource->refcnt, 1,
9059                                            __ATOMIC_RELAXED);
9060                 } else {
9061                         ret = rte_flow_error_set(error, ENOMEM,
9062                                 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
9063                                 "Only one GENEVE TLV option supported");
9064                         goto exit;
9065                 }
9066         } else {
9067                 /* Create a GENEVE TLV object and resource. */
9068                 obj = mlx5_devx_cmd_create_geneve_tlv_option(sh->cdev->ctx,
9069                                 geneve_opt_v->option_class,
9070                                 geneve_opt_v->option_type,
9071                                 geneve_opt_v->option_len);
9072                 if (!obj) {
9073                         ret = rte_flow_error_set(error, ENODATA,
9074                                 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
9075                                 "Failed to create GENEVE TLV Devx object");
9076                         goto exit;
9077                 }
9078                 sh->geneve_tlv_option_resource =
9079                                 mlx5_malloc(MLX5_MEM_ZERO,
9080                                                 sizeof(*geneve_opt_resource),
9081                                                 0, SOCKET_ID_ANY);
9082                 if (!sh->geneve_tlv_option_resource) {
9083                         claim_zero(mlx5_devx_cmd_destroy(obj));
9084                         ret = rte_flow_error_set(error, ENOMEM,
9085                                 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
9086                                 "GENEVE TLV object memory allocation failed");
9087                         goto exit;
9088                 }
9089                 geneve_opt_resource = sh->geneve_tlv_option_resource;
9090                 geneve_opt_resource->obj = obj;
9091                 geneve_opt_resource->option_class = geneve_opt_v->option_class;
9092                 geneve_opt_resource->option_type = geneve_opt_v->option_type;
9093                 geneve_opt_resource->length = geneve_opt_v->option_len;
9094                 __atomic_store_n(&geneve_opt_resource->refcnt, 1,
9095                                 __ATOMIC_RELAXED);
9096         }
9097 exit:
9098         rte_spinlock_unlock(&sh->geneve_tlv_opt_sl);
9099         return ret;
9100 }
9101
9102 /**
9103  * Add Geneve TLV option item to matcher.
9104  *
9105  * @param[in, out] dev
9106  *   Pointer to rte_eth_dev structure.
9107  * @param[in, out] matcher
9108  *   Flow matcher.
9109  * @param[in, out] key
9110  *   Flow matcher value.
9111  * @param[in] item
9112  *   Flow pattern to translate.
9113  * @param[out] error
9114  *   Pointer to error structure.
9115  */
9116 static int
9117 flow_dv_translate_item_geneve_opt(struct rte_eth_dev *dev, void *matcher,
9118                                   void *key, const struct rte_flow_item *item,
9119                                   struct rte_flow_error *error)
9120 {
9121         const struct rte_flow_item_geneve_opt *geneve_opt_m = item->mask;
9122         const struct rte_flow_item_geneve_opt *geneve_opt_v = item->spec;
9123         void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
9124         void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
9125         void *misc3_m = MLX5_ADDR_OF(fte_match_param, matcher,
9126                         misc_parameters_3);
9127         void *misc3_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3);
9128         rte_be32_t opt_data_key = 0, opt_data_mask = 0;
9129         int ret = 0;
9130
9131         if (!geneve_opt_v)
9132                 return -1;
9133         if (!geneve_opt_m)
9134                 geneve_opt_m = &rte_flow_item_geneve_opt_mask;
9135         ret = flow_dev_geneve_tlv_option_resource_register(dev, item,
9136                                                            error);
9137         if (ret) {
9138                 DRV_LOG(ERR, "Failed to create geneve_tlv_obj");
9139                 return ret;
9140         }
9141         /*
9142          * Set the option length in GENEVE header if not requested.
9143          * The GENEVE TLV option length is expressed by the option length field
9144          * in the GENEVE header.
9145          * If the option length was not requested but the GENEVE TLV option item
9146          * is present we set the option length field implicitly.
9147          */
9148         if (!MLX5_GET16(fte_match_set_misc, misc_m, geneve_opt_len)) {
9149                 MLX5_SET(fte_match_set_misc, misc_m, geneve_opt_len,
9150                          MLX5_GENEVE_OPTLEN_MASK);
9151                 MLX5_SET(fte_match_set_misc, misc_v, geneve_opt_len,
9152                          geneve_opt_v->option_len + 1);
9153         }
9154         MLX5_SET(fte_match_set_misc, misc_m, geneve_tlv_option_0_exist, 1);
9155         MLX5_SET(fte_match_set_misc, misc_v, geneve_tlv_option_0_exist, 1);
9156         /* Set the data. */
9157         if (geneve_opt_v->data) {
9158                 memcpy(&opt_data_key, geneve_opt_v->data,
9159                         RTE_MIN((uint32_t)(geneve_opt_v->option_len * 4),
9160                                 sizeof(opt_data_key)));
9161                 MLX5_ASSERT((uint32_t)(geneve_opt_v->option_len * 4) <=
9162                                 sizeof(opt_data_key));
9163                 memcpy(&opt_data_mask, geneve_opt_m->data,
9164                         RTE_MIN((uint32_t)(geneve_opt_v->option_len * 4),
9165                                 sizeof(opt_data_mask)));
9166                 MLX5_ASSERT((uint32_t)(geneve_opt_v->option_len * 4) <=
9167                                 sizeof(opt_data_mask));
9168                 MLX5_SET(fte_match_set_misc3, misc3_m,
9169                                 geneve_tlv_option_0_data,
9170                                 rte_be_to_cpu_32(opt_data_mask));
9171                 MLX5_SET(fte_match_set_misc3, misc3_v,
9172                                 geneve_tlv_option_0_data,
9173                         rte_be_to_cpu_32(opt_data_key & opt_data_mask));
9174         }
9175         return ret;
9176 }
9177
9178 /**
9179  * Add MPLS item to matcher and to the value.
9180  *
9181  * @param[in, out] matcher
9182  *   Flow matcher.
9183  * @param[in, out] key
9184  *   Flow matcher value.
9185  * @param[in] item
9186  *   Flow pattern to translate.
9187  * @param[in] prev_layer
9188  *   The protocol layer indicated in previous item.
9189  * @param[in] inner
9190  *   Item is inner pattern.
9191  */
9192 static void
9193 flow_dv_translate_item_mpls(void *matcher, void *key,
9194                             const struct rte_flow_item *item,
9195                             uint64_t prev_layer,
9196                             int inner)
9197 {
9198         const uint32_t *in_mpls_m = item->mask;
9199         const uint32_t *in_mpls_v = item->spec;
9200         uint32_t *out_mpls_m = 0;
9201         uint32_t *out_mpls_v = 0;
9202         void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
9203         void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
9204         void *misc2_m = MLX5_ADDR_OF(fte_match_param, matcher,
9205                                      misc_parameters_2);
9206         void *misc2_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_2);
9207         void *headers_m = MLX5_ADDR_OF(fte_match_param, matcher, outer_headers);
9208         void *headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
9209
9210         switch (prev_layer) {
9211         case MLX5_FLOW_LAYER_OUTER_L4_UDP:
9212                 MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_dport, 0xffff);
9213                 MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport,
9214                          MLX5_UDP_PORT_MPLS);
9215                 break;
9216         case MLX5_FLOW_LAYER_GRE:
9217                 /* Fall-through. */
9218         case MLX5_FLOW_LAYER_GRE_KEY:
9219                 MLX5_SET(fte_match_set_misc, misc_m, gre_protocol, 0xffff);
9220                 MLX5_SET(fte_match_set_misc, misc_v, gre_protocol,
9221                          RTE_ETHER_TYPE_MPLS);
9222                 break;
9223         default:
9224                 break;
9225         }
9226         if (!in_mpls_v)
9227                 return;
9228         if (!in_mpls_m)
9229                 in_mpls_m = (const uint32_t *)&rte_flow_item_mpls_mask;
9230         switch (prev_layer) {
9231         case MLX5_FLOW_LAYER_OUTER_L4_UDP:
9232                 out_mpls_m =
9233                         (uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2, misc2_m,
9234                                                  outer_first_mpls_over_udp);
9235                 out_mpls_v =
9236                         (uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2, misc2_v,
9237                                                  outer_first_mpls_over_udp);
9238                 break;
9239         case MLX5_FLOW_LAYER_GRE:
9240                 out_mpls_m =
9241                         (uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2, misc2_m,
9242                                                  outer_first_mpls_over_gre);
9243                 out_mpls_v =
9244                         (uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2, misc2_v,
9245                                                  outer_first_mpls_over_gre);
9246                 break;
9247         default:
9248                 /* Inner MPLS not over GRE is not supported. */
9249                 if (!inner) {
9250                         out_mpls_m =
9251                                 (uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2,
9252                                                          misc2_m,
9253                                                          outer_first_mpls);
9254                         out_mpls_v =
9255                                 (uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2,
9256                                                          misc2_v,
9257                                                          outer_first_mpls);
9258                 }
9259                 break;
9260         }
9261         if (out_mpls_m && out_mpls_v) {
9262                 *out_mpls_m = *in_mpls_m;
9263                 *out_mpls_v = *in_mpls_v & *in_mpls_m;
9264         }
9265 }
9266
9267 /**
9268  * Add metadata register item to matcher
9269  *
9270  * @param[in, out] matcher
9271  *   Flow matcher.
9272  * @param[in, out] key
9273  *   Flow matcher value.
9274  * @param[in] reg_type
9275  *   Type of device metadata register
9276  * @param[in] value
9277  *   Register value
9278  * @param[in] mask
9279  *   Register mask
9280  */
9281 static void
9282 flow_dv_match_meta_reg(void *matcher, void *key,
9283                        enum modify_reg reg_type,
9284                        uint32_t data, uint32_t mask)
9285 {
9286         void *misc2_m =
9287                 MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters_2);
9288         void *misc2_v =
9289                 MLX5_ADDR_OF(fte_match_param, key, misc_parameters_2);
9290         uint32_t temp;
9291
9292         data &= mask;
9293         switch (reg_type) {
9294         case REG_A:
9295                 MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_a, mask);
9296                 MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_a, data);
9297                 break;
9298         case REG_B:
9299                 MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_b, mask);
9300                 MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_b, data);
9301                 break;
9302         case REG_C_0:
9303                 /*
9304                  * The metadata register C0 field might be divided into
9305                  * source vport index and META item value, we should set
9306                  * this field according to specified mask, not as whole one.
9307                  */
9308                 temp = MLX5_GET(fte_match_set_misc2, misc2_m, metadata_reg_c_0);
9309                 temp |= mask;
9310                 MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_0, temp);
9311                 temp = MLX5_GET(fte_match_set_misc2, misc2_v, metadata_reg_c_0);
9312                 temp &= ~mask;
9313                 temp |= data;
9314                 MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_0, temp);
9315                 break;
9316         case REG_C_1:
9317                 MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_1, mask);
9318                 MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_1, data);
9319                 break;
9320         case REG_C_2:
9321                 MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_2, mask);
9322                 MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_2, data);
9323                 break;
9324         case REG_C_3:
9325                 MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_3, mask);
9326                 MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_3, data);
9327                 break;
9328         case REG_C_4:
9329                 MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_4, mask);
9330                 MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_4, data);
9331                 break;
9332         case REG_C_5:
9333                 MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_5, mask);
9334                 MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_5, data);
9335                 break;
9336         case REG_C_6:
9337                 MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_6, mask);
9338                 MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_6, data);
9339                 break;
9340         case REG_C_7:
9341                 MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_7, mask);
9342                 MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_7, data);
9343                 break;
9344         default:
9345                 MLX5_ASSERT(false);
9346                 break;
9347         }
9348 }
9349
9350 /**
9351  * Add MARK item to matcher
9352  *
9353  * @param[in] dev
9354  *   The device to configure through.
9355  * @param[in, out] matcher
9356  *   Flow matcher.
9357  * @param[in, out] key
9358  *   Flow matcher value.
9359  * @param[in] item
9360  *   Flow pattern to translate.
9361  */
9362 static void
9363 flow_dv_translate_item_mark(struct rte_eth_dev *dev,
9364                             void *matcher, void *key,
9365                             const struct rte_flow_item *item)
9366 {
9367         struct mlx5_priv *priv = dev->data->dev_private;
9368         const struct rte_flow_item_mark *mark;
9369         uint32_t value;
9370         uint32_t mask;
9371
9372         mark = item->mask ? (const void *)item->mask :
9373                             &rte_flow_item_mark_mask;
9374         mask = mark->id & priv->sh->dv_mark_mask;
9375         mark = (const void *)item->spec;
9376         MLX5_ASSERT(mark);
9377         value = mark->id & priv->sh->dv_mark_mask & mask;
9378         if (mask) {
9379                 enum modify_reg reg;
9380
9381                 /* Get the metadata register index for the mark. */
9382                 reg = mlx5_flow_get_reg_id(dev, MLX5_FLOW_MARK, 0, NULL);
9383                 MLX5_ASSERT(reg > 0);
9384                 if (reg == REG_C_0) {
9385                         struct mlx5_priv *priv = dev->data->dev_private;
9386                         uint32_t msk_c0 = priv->sh->dv_regc0_mask;
9387                         uint32_t shl_c0 = rte_bsf32(msk_c0);
9388
9389                         mask &= msk_c0;
9390                         mask <<= shl_c0;
9391                         value <<= shl_c0;
9392                 }
9393                 flow_dv_match_meta_reg(matcher, key, reg, value, mask);
9394         }
9395 }
9396
9397 /**
9398  * Add META item to matcher
9399  *
9400  * @param[in] dev
9401  *   The devich to configure through.
9402  * @param[in, out] matcher
9403  *   Flow matcher.
9404  * @param[in, out] key
9405  *   Flow matcher value.
9406  * @param[in] attr
9407  *   Attributes of flow that includes this item.
9408  * @param[in] item
9409  *   Flow pattern to translate.
9410  */
9411 static void
9412 flow_dv_translate_item_meta(struct rte_eth_dev *dev,
9413                             void *matcher, void *key,
9414                             const struct rte_flow_attr *attr,
9415                             const struct rte_flow_item *item)
9416 {
9417         const struct rte_flow_item_meta *meta_m;
9418         const struct rte_flow_item_meta *meta_v;
9419
9420         meta_m = (const void *)item->mask;
9421         if (!meta_m)
9422                 meta_m = &rte_flow_item_meta_mask;
9423         meta_v = (const void *)item->spec;
9424         if (meta_v) {
9425                 int reg;
9426                 uint32_t value = meta_v->data;
9427                 uint32_t mask = meta_m->data;
9428
9429                 reg = flow_dv_get_metadata_reg(dev, attr, NULL);
9430                 if (reg < 0)
9431                         return;
9432                 MLX5_ASSERT(reg != REG_NON);
9433                 if (reg == REG_C_0) {
9434                         struct mlx5_priv *priv = dev->data->dev_private;
9435                         uint32_t msk_c0 = priv->sh->dv_regc0_mask;
9436                         uint32_t shl_c0 = rte_bsf32(msk_c0);
9437
9438                         mask &= msk_c0;
9439                         mask <<= shl_c0;
9440                         value <<= shl_c0;
9441                 }
9442                 flow_dv_match_meta_reg(matcher, key, reg, value, mask);
9443         }
9444 }
9445
9446 /**
9447  * Add vport metadata Reg C0 item to matcher
9448  *
9449  * @param[in, out] matcher
9450  *   Flow matcher.
9451  * @param[in, out] key
9452  *   Flow matcher value.
9453  * @param[in] reg
9454  *   Flow pattern to translate.
9455  */
9456 static void
9457 flow_dv_translate_item_meta_vport(void *matcher, void *key,
9458                                   uint32_t value, uint32_t mask)
9459 {
9460         flow_dv_match_meta_reg(matcher, key, REG_C_0, value, mask);
9461 }
9462
9463 /**
9464  * Add tag item to matcher
9465  *
9466  * @param[in] dev
9467  *   The devich to configure through.
9468  * @param[in, out] matcher
9469  *   Flow matcher.
9470  * @param[in, out] key
9471  *   Flow matcher value.
9472  * @param[in] item
9473  *   Flow pattern to translate.
9474  */
9475 static void
9476 flow_dv_translate_mlx5_item_tag(struct rte_eth_dev *dev,
9477                                 void *matcher, void *key,
9478                                 const struct rte_flow_item *item)
9479 {
9480         const struct mlx5_rte_flow_item_tag *tag_v = item->spec;
9481         const struct mlx5_rte_flow_item_tag *tag_m = item->mask;
9482         uint32_t mask, value;
9483
9484         MLX5_ASSERT(tag_v);
9485         value = tag_v->data;
9486         mask = tag_m ? tag_m->data : UINT32_MAX;
9487         if (tag_v->id == REG_C_0) {
9488                 struct mlx5_priv *priv = dev->data->dev_private;
9489                 uint32_t msk_c0 = priv->sh->dv_regc0_mask;
9490                 uint32_t shl_c0 = rte_bsf32(msk_c0);
9491
9492                 mask &= msk_c0;
9493                 mask <<= shl_c0;
9494                 value <<= shl_c0;
9495         }
9496         flow_dv_match_meta_reg(matcher, key, tag_v->id, value, mask);
9497 }
9498
9499 /**
9500  * Add TAG item to matcher
9501  *
9502  * @param[in] dev
9503  *   The devich to configure through.
9504  * @param[in, out] matcher
9505  *   Flow matcher.
9506  * @param[in, out] key
9507  *   Flow matcher value.
9508  * @param[in] item
9509  *   Flow pattern to translate.
9510  */
9511 static void
9512 flow_dv_translate_item_tag(struct rte_eth_dev *dev,
9513                            void *matcher, void *key,
9514                            const struct rte_flow_item *item)
9515 {
9516         const struct rte_flow_item_tag *tag_v = item->spec;
9517         const struct rte_flow_item_tag *tag_m = item->mask;
9518         enum modify_reg reg;
9519
9520         MLX5_ASSERT(tag_v);
9521         tag_m = tag_m ? tag_m : &rte_flow_item_tag_mask;
9522         /* Get the metadata register index for the tag. */
9523         reg = mlx5_flow_get_reg_id(dev, MLX5_APP_TAG, tag_v->index, NULL);
9524         MLX5_ASSERT(reg > 0);
9525         flow_dv_match_meta_reg(matcher, key, reg, tag_v->data, tag_m->data);
9526 }
9527
9528 /**
9529  * Add source vport match to the specified matcher.
9530  *
9531  * @param[in, out] matcher
9532  *   Flow matcher.
9533  * @param[in, out] key
9534  *   Flow matcher value.
9535  * @param[in] port
9536  *   Source vport value to match
9537  * @param[in] mask
9538  *   Mask
9539  */
9540 static void
9541 flow_dv_translate_item_source_vport(void *matcher, void *key,
9542                                     int16_t port, uint16_t mask)
9543 {
9544         void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
9545         void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
9546
9547         MLX5_SET(fte_match_set_misc, misc_m, source_port, mask);
9548         MLX5_SET(fte_match_set_misc, misc_v, source_port, port);
9549 }
9550
9551 /**
9552  * Translate port-id item to eswitch match on  port-id.
9553  *
9554  * @param[in] dev
9555  *   The devich to configure through.
9556  * @param[in, out] matcher
9557  *   Flow matcher.
9558  * @param[in, out] key
9559  *   Flow matcher value.
9560  * @param[in] item
9561  *   Flow pattern to translate.
9562  * @param[in]
9563  *   Flow attributes.
9564  *
9565  * @return
9566  *   0 on success, a negative errno value otherwise.
9567  */
9568 static int
9569 flow_dv_translate_item_port_id(struct rte_eth_dev *dev, void *matcher,
9570                                void *key, const struct rte_flow_item *item,
9571                                const struct rte_flow_attr *attr)
9572 {
9573         const struct rte_flow_item_port_id *pid_m = item ? item->mask : NULL;
9574         const struct rte_flow_item_port_id *pid_v = item ? item->spec : NULL;
9575         struct mlx5_priv *priv;
9576         uint16_t mask, id;
9577
9578         mask = pid_m ? pid_m->id : 0xffff;
9579         id = pid_v ? pid_v->id : dev->data->port_id;
9580         priv = mlx5_port_to_eswitch_info(id, item == NULL);
9581         if (!priv)
9582                 return -rte_errno;
9583         /*
9584          * Translate to vport field or to metadata, depending on mode.
9585          * Kernel can use either misc.source_port or half of C0 metadata
9586          * register.
9587          */
9588         if (priv->vport_meta_mask) {
9589                 /*
9590                  * Provide the hint for SW steering library
9591                  * to insert the flow into ingress domain and
9592                  * save the extra vport match.
9593                  */
9594                 if (mask == 0xffff && priv->vport_id == 0xffff &&
9595                     priv->pf_bond < 0 && attr->transfer)
9596                         flow_dv_translate_item_source_vport
9597                                 (matcher, key, priv->vport_id, mask);
9598                 /*
9599                  * We should always set the vport metadata register,
9600                  * otherwise the SW steering library can drop
9601                  * the rule if wire vport metadata value is not zero,
9602                  * it depends on kernel configuration.
9603                  */
9604                 flow_dv_translate_item_meta_vport(matcher, key,
9605                                                   priv->vport_meta_tag,
9606                                                   priv->vport_meta_mask);
9607         } else {
9608                 flow_dv_translate_item_source_vport(matcher, key,
9609                                                     priv->vport_id, mask);
9610         }
9611         return 0;
9612 }
9613
9614 /**
9615  * Add ICMP6 item to matcher and to the value.
9616  *
9617  * @param[in, out] matcher
9618  *   Flow matcher.
9619  * @param[in, out] key
9620  *   Flow matcher value.
9621  * @param[in] item
9622  *   Flow pattern to translate.
9623  * @param[in] inner
9624  *   Item is inner pattern.
9625  */
9626 static void
9627 flow_dv_translate_item_icmp6(void *matcher, void *key,
9628                               const struct rte_flow_item *item,
9629                               int inner)
9630 {
9631         const struct rte_flow_item_icmp6 *icmp6_m = item->mask;
9632         const struct rte_flow_item_icmp6 *icmp6_v = item->spec;
9633         void *headers_m;
9634         void *headers_v;
9635         void *misc3_m = MLX5_ADDR_OF(fte_match_param, matcher,
9636                                      misc_parameters_3);
9637         void *misc3_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3);
9638         if (inner) {
9639                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
9640                                          inner_headers);
9641                 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
9642         } else {
9643                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
9644                                          outer_headers);
9645                 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
9646         }
9647         MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 0xFF);
9648         MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_ICMPV6);
9649         if (!icmp6_v)
9650                 return;
9651         if (!icmp6_m)
9652                 icmp6_m = &rte_flow_item_icmp6_mask;
9653         MLX5_SET(fte_match_set_misc3, misc3_m, icmpv6_type, icmp6_m->type);
9654         MLX5_SET(fte_match_set_misc3, misc3_v, icmpv6_type,
9655                  icmp6_v->type & icmp6_m->type);
9656         MLX5_SET(fte_match_set_misc3, misc3_m, icmpv6_code, icmp6_m->code);
9657         MLX5_SET(fte_match_set_misc3, misc3_v, icmpv6_code,
9658                  icmp6_v->code & icmp6_m->code);
9659 }
9660
9661 /**
9662  * Add ICMP item to matcher and to the value.
9663  *
9664  * @param[in, out] matcher
9665  *   Flow matcher.
9666  * @param[in, out] key
9667  *   Flow matcher value.
9668  * @param[in] item
9669  *   Flow pattern to translate.
9670  * @param[in] inner
9671  *   Item is inner pattern.
9672  */
9673 static void
9674 flow_dv_translate_item_icmp(void *matcher, void *key,
9675                             const struct rte_flow_item *item,
9676                             int inner)
9677 {
9678         const struct rte_flow_item_icmp *icmp_m = item->mask;
9679         const struct rte_flow_item_icmp *icmp_v = item->spec;
9680         uint32_t icmp_header_data_m = 0;
9681         uint32_t icmp_header_data_v = 0;
9682         void *headers_m;
9683         void *headers_v;
9684         void *misc3_m = MLX5_ADDR_OF(fte_match_param, matcher,
9685                                      misc_parameters_3);
9686         void *misc3_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3);
9687         if (inner) {
9688                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
9689                                          inner_headers);
9690                 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
9691         } else {
9692                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
9693                                          outer_headers);
9694                 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
9695         }
9696         MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 0xFF);
9697         MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_ICMP);
9698         if (!icmp_v)
9699                 return;
9700         if (!icmp_m)
9701                 icmp_m = &rte_flow_item_icmp_mask;
9702         MLX5_SET(fte_match_set_misc3, misc3_m, icmp_type,
9703                  icmp_m->hdr.icmp_type);
9704         MLX5_SET(fte_match_set_misc3, misc3_v, icmp_type,
9705                  icmp_v->hdr.icmp_type & icmp_m->hdr.icmp_type);
9706         MLX5_SET(fte_match_set_misc3, misc3_m, icmp_code,
9707                  icmp_m->hdr.icmp_code);
9708         MLX5_SET(fte_match_set_misc3, misc3_v, icmp_code,
9709                  icmp_v->hdr.icmp_code & icmp_m->hdr.icmp_code);
9710         icmp_header_data_m = rte_be_to_cpu_16(icmp_m->hdr.icmp_seq_nb);
9711         icmp_header_data_m |= rte_be_to_cpu_16(icmp_m->hdr.icmp_ident) << 16;
9712         if (icmp_header_data_m) {
9713                 icmp_header_data_v = rte_be_to_cpu_16(icmp_v->hdr.icmp_seq_nb);
9714                 icmp_header_data_v |=
9715                          rte_be_to_cpu_16(icmp_v->hdr.icmp_ident) << 16;
9716                 MLX5_SET(fte_match_set_misc3, misc3_m, icmp_header_data,
9717                          icmp_header_data_m);
9718                 MLX5_SET(fte_match_set_misc3, misc3_v, icmp_header_data,
9719                          icmp_header_data_v & icmp_header_data_m);
9720         }
9721 }
9722
9723 /**
9724  * Add GTP item to matcher and to the value.
9725  *
9726  * @param[in, out] matcher
9727  *   Flow matcher.
9728  * @param[in, out] key
9729  *   Flow matcher value.
9730  * @param[in] item
9731  *   Flow pattern to translate.
9732  * @param[in] inner
9733  *   Item is inner pattern.
9734  */
9735 static void
9736 flow_dv_translate_item_gtp(void *matcher, void *key,
9737                            const struct rte_flow_item *item, int inner)
9738 {
9739         const struct rte_flow_item_gtp *gtp_m = item->mask;
9740         const struct rte_flow_item_gtp *gtp_v = item->spec;
9741         void *headers_m;
9742         void *headers_v;
9743         void *misc3_m = MLX5_ADDR_OF(fte_match_param, matcher,
9744                                      misc_parameters_3);
9745         void *misc3_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3);
9746         uint16_t dport = RTE_GTPU_UDP_PORT;
9747
9748         if (inner) {
9749                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
9750                                          inner_headers);
9751                 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
9752         } else {
9753                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
9754                                          outer_headers);
9755                 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
9756         }
9757         if (!MLX5_GET16(fte_match_set_lyr_2_4, headers_v, udp_dport)) {
9758                 MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_dport, 0xFFFF);
9759                 MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport, dport);
9760         }
9761         if (!gtp_v)
9762                 return;
9763         if (!gtp_m)
9764                 gtp_m = &rte_flow_item_gtp_mask;
9765         MLX5_SET(fte_match_set_misc3, misc3_m, gtpu_msg_flags,
9766                  gtp_m->v_pt_rsv_flags);
9767         MLX5_SET(fte_match_set_misc3, misc3_v, gtpu_msg_flags,
9768                  gtp_v->v_pt_rsv_flags & gtp_m->v_pt_rsv_flags);
9769         MLX5_SET(fte_match_set_misc3, misc3_m, gtpu_msg_type, gtp_m->msg_type);
9770         MLX5_SET(fte_match_set_misc3, misc3_v, gtpu_msg_type,
9771                  gtp_v->msg_type & gtp_m->msg_type);
9772         MLX5_SET(fte_match_set_misc3, misc3_m, gtpu_teid,
9773                  rte_be_to_cpu_32(gtp_m->teid));
9774         MLX5_SET(fte_match_set_misc3, misc3_v, gtpu_teid,
9775                  rte_be_to_cpu_32(gtp_v->teid & gtp_m->teid));
9776 }
9777
9778 /**
9779  * Add GTP PSC item to matcher.
9780  *
9781  * @param[in, out] matcher
9782  *   Flow matcher.
9783  * @param[in, out] key
9784  *   Flow matcher value.
9785  * @param[in] item
9786  *   Flow pattern to translate.
9787  */
9788 static int
9789 flow_dv_translate_item_gtp_psc(void *matcher, void *key,
9790                                const struct rte_flow_item *item)
9791 {
9792         const struct rte_flow_item_gtp_psc *gtp_psc_m = item->mask;
9793         const struct rte_flow_item_gtp_psc *gtp_psc_v = item->spec;
9794         void *misc3_m = MLX5_ADDR_OF(fte_match_param, matcher,
9795                         misc_parameters_3);
9796         void *misc3_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3);
9797         union {
9798                 uint32_t w32;
9799                 struct {
9800                         uint16_t seq_num;
9801                         uint8_t npdu_num;
9802                         uint8_t next_ext_header_type;
9803                 };
9804         } dw_2;
9805         uint8_t gtp_flags;
9806
9807         /* Always set E-flag match on one, regardless of GTP item settings. */
9808         gtp_flags = MLX5_GET(fte_match_set_misc3, misc3_m, gtpu_msg_flags);
9809         gtp_flags |= MLX5_GTP_EXT_HEADER_FLAG;
9810         MLX5_SET(fte_match_set_misc3, misc3_m, gtpu_msg_flags, gtp_flags);
9811         gtp_flags = MLX5_GET(fte_match_set_misc3, misc3_v, gtpu_msg_flags);
9812         gtp_flags |= MLX5_GTP_EXT_HEADER_FLAG;
9813         MLX5_SET(fte_match_set_misc3, misc3_v, gtpu_msg_flags, gtp_flags);
9814         /*Set next extension header type. */
9815         dw_2.seq_num = 0;
9816         dw_2.npdu_num = 0;
9817         dw_2.next_ext_header_type = 0xff;
9818         MLX5_SET(fte_match_set_misc3, misc3_m, gtpu_dw_2,
9819                  rte_cpu_to_be_32(dw_2.w32));
9820         dw_2.seq_num = 0;
9821         dw_2.npdu_num = 0;
9822         dw_2.next_ext_header_type = 0x85;
9823         MLX5_SET(fte_match_set_misc3, misc3_v, gtpu_dw_2,
9824                  rte_cpu_to_be_32(dw_2.w32));
9825         if (gtp_psc_v) {
9826                 union {
9827                         uint32_t w32;
9828                         struct {
9829                                 uint8_t len;
9830                                 uint8_t type_flags;
9831                                 uint8_t qfi;
9832                                 uint8_t reserved;
9833                         };
9834                 } dw_0;
9835
9836                 /*Set extension header PDU type and Qos. */
9837                 if (!gtp_psc_m)
9838                         gtp_psc_m = &rte_flow_item_gtp_psc_mask;
9839                 dw_0.w32 = 0;
9840                 dw_0.type_flags = MLX5_GTP_PDU_TYPE_SHIFT(gtp_psc_m->hdr.type);
9841                 dw_0.qfi = gtp_psc_m->hdr.qfi;
9842                 MLX5_SET(fte_match_set_misc3, misc3_m, gtpu_first_ext_dw_0,
9843                          rte_cpu_to_be_32(dw_0.w32));
9844                 dw_0.w32 = 0;
9845                 dw_0.type_flags = MLX5_GTP_PDU_TYPE_SHIFT(gtp_psc_v->hdr.type &
9846                                                         gtp_psc_m->hdr.type);
9847                 dw_0.qfi = gtp_psc_v->hdr.qfi & gtp_psc_m->hdr.qfi;
9848                 MLX5_SET(fte_match_set_misc3, misc3_v, gtpu_first_ext_dw_0,
9849                          rte_cpu_to_be_32(dw_0.w32));
9850         }
9851         return 0;
9852 }
9853
9854 /**
9855  * Add eCPRI item to matcher and to the value.
9856  *
9857  * @param[in] dev
9858  *   The devich to configure through.
9859  * @param[in, out] matcher
9860  *   Flow matcher.
9861  * @param[in, out] key
9862  *   Flow matcher value.
9863  * @param[in] item
9864  *   Flow pattern to translate.
9865  * @param[in] last_item
9866  *   Last item flags.
9867  */
9868 static void
9869 flow_dv_translate_item_ecpri(struct rte_eth_dev *dev, void *matcher,
9870                              void *key, const struct rte_flow_item *item,
9871                              uint64_t last_item)
9872 {
9873         struct mlx5_priv *priv = dev->data->dev_private;
9874         const struct rte_flow_item_ecpri *ecpri_m = item->mask;
9875         const struct rte_flow_item_ecpri *ecpri_v = item->spec;
9876         struct rte_ecpri_common_hdr common;
9877         void *misc4_m = MLX5_ADDR_OF(fte_match_param, matcher,
9878                                      misc_parameters_4);
9879         void *misc4_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_4);
9880         uint32_t *samples;
9881         void *dw_m;
9882         void *dw_v;
9883
9884         /*
9885          * In case of eCPRI over Ethernet, if EtherType is not specified,
9886          * match on eCPRI EtherType implicitly.
9887          */
9888         if (last_item & MLX5_FLOW_LAYER_OUTER_L2) {
9889                 void *hdrs_m, *hdrs_v, *l2m, *l2v;
9890
9891                 hdrs_m = MLX5_ADDR_OF(fte_match_param, matcher, outer_headers);
9892                 hdrs_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
9893                 l2m = MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_m, ethertype);
9894                 l2v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_v, ethertype);
9895                 if (*(uint16_t *)l2m == 0 && *(uint16_t *)l2v == 0) {
9896                         *(uint16_t *)l2m = UINT16_MAX;
9897                         *(uint16_t *)l2v = RTE_BE16(RTE_ETHER_TYPE_ECPRI);
9898                 }
9899         }
9900         if (!ecpri_v)
9901                 return;
9902         if (!ecpri_m)
9903                 ecpri_m = &rte_flow_item_ecpri_mask;
9904         /*
9905          * Maximal four DW samples are supported in a single matching now.
9906          * Two are used now for a eCPRI matching:
9907          * 1. Type: one byte, mask should be 0x00ff0000 in network order
9908          * 2. ID of a message: one or two bytes, mask 0xffff0000 or 0xff000000
9909          *    if any.
9910          */
9911         if (!ecpri_m->hdr.common.u32)
9912                 return;
9913         samples = priv->sh->fp[MLX5_FLEX_PARSER_ECPRI_0].ids;
9914         /* Need to take the whole DW as the mask to fill the entry. */
9915         dw_m = MLX5_ADDR_OF(fte_match_set_misc4, misc4_m,
9916                             prog_sample_field_value_0);
9917         dw_v = MLX5_ADDR_OF(fte_match_set_misc4, misc4_v,
9918                             prog_sample_field_value_0);
9919         /* Already big endian (network order) in the header. */
9920         *(uint32_t *)dw_m = ecpri_m->hdr.common.u32;
9921         *(uint32_t *)dw_v = ecpri_v->hdr.common.u32 & ecpri_m->hdr.common.u32;
9922         /* Sample#0, used for matching type, offset 0. */
9923         MLX5_SET(fte_match_set_misc4, misc4_m,
9924                  prog_sample_field_id_0, samples[0]);
9925         /* It makes no sense to set the sample ID in the mask field. */
9926         MLX5_SET(fte_match_set_misc4, misc4_v,
9927                  prog_sample_field_id_0, samples[0]);
9928         /*
9929          * Checking if message body part needs to be matched.
9930          * Some wildcard rules only matching type field should be supported.
9931          */
9932         if (ecpri_m->hdr.dummy[0]) {
9933                 common.u32 = rte_be_to_cpu_32(ecpri_v->hdr.common.u32);
9934                 switch (common.type) {
9935                 case RTE_ECPRI_MSG_TYPE_IQ_DATA:
9936                 case RTE_ECPRI_MSG_TYPE_RTC_CTRL:
9937                 case RTE_ECPRI_MSG_TYPE_DLY_MSR:
9938                         dw_m = MLX5_ADDR_OF(fte_match_set_misc4, misc4_m,
9939                                             prog_sample_field_value_1);
9940                         dw_v = MLX5_ADDR_OF(fte_match_set_misc4, misc4_v,
9941                                             prog_sample_field_value_1);
9942                         *(uint32_t *)dw_m = ecpri_m->hdr.dummy[0];
9943                         *(uint32_t *)dw_v = ecpri_v->hdr.dummy[0] &
9944                                             ecpri_m->hdr.dummy[0];
9945                         /* Sample#1, to match message body, offset 4. */
9946                         MLX5_SET(fte_match_set_misc4, misc4_m,
9947                                  prog_sample_field_id_1, samples[1]);
9948                         MLX5_SET(fte_match_set_misc4, misc4_v,
9949                                  prog_sample_field_id_1, samples[1]);
9950                         break;
9951                 default:
9952                         /* Others, do not match any sample ID. */
9953                         break;
9954                 }
9955         }
9956 }
9957
9958 /*
9959  * Add connection tracking status item to matcher
9960  *
9961  * @param[in] dev
9962  *   The devich to configure through.
9963  * @param[in, out] matcher
9964  *   Flow matcher.
9965  * @param[in, out] key
9966  *   Flow matcher value.
9967  * @param[in] item
9968  *   Flow pattern to translate.
9969  */
9970 static void
9971 flow_dv_translate_item_aso_ct(struct rte_eth_dev *dev,
9972                               void *matcher, void *key,
9973                               const struct rte_flow_item *item)
9974 {
9975         uint32_t reg_value = 0;
9976         int reg_id;
9977         /* 8LSB 0b 11/0000/11, middle 4 bits are reserved. */
9978         uint32_t reg_mask = 0;
9979         const struct rte_flow_item_conntrack *spec = item->spec;
9980         const struct rte_flow_item_conntrack *mask = item->mask;
9981         uint32_t flags;
9982         struct rte_flow_error error;
9983
9984         if (!mask)
9985                 mask = &rte_flow_item_conntrack_mask;
9986         if (!spec || !mask->flags)
9987                 return;
9988         flags = spec->flags & mask->flags;
9989         /* The conflict should be checked in the validation. */
9990         if (flags & RTE_FLOW_CONNTRACK_PKT_STATE_VALID)
9991                 reg_value |= MLX5_CT_SYNDROME_VALID;
9992         if (flags & RTE_FLOW_CONNTRACK_PKT_STATE_CHANGED)
9993                 reg_value |= MLX5_CT_SYNDROME_STATE_CHANGE;
9994         if (flags & RTE_FLOW_CONNTRACK_PKT_STATE_INVALID)
9995                 reg_value |= MLX5_CT_SYNDROME_INVALID;
9996         if (flags & RTE_FLOW_CONNTRACK_PKT_STATE_DISABLED)
9997                 reg_value |= MLX5_CT_SYNDROME_TRAP;
9998         if (flags & RTE_FLOW_CONNTRACK_PKT_STATE_BAD)
9999                 reg_value |= MLX5_CT_SYNDROME_BAD_PACKET;
10000         if (mask->flags & (RTE_FLOW_CONNTRACK_PKT_STATE_VALID |
10001                            RTE_FLOW_CONNTRACK_PKT_STATE_INVALID |
10002                            RTE_FLOW_CONNTRACK_PKT_STATE_DISABLED))
10003                 reg_mask |= 0xc0;
10004         if (mask->flags & RTE_FLOW_CONNTRACK_PKT_STATE_CHANGED)
10005                 reg_mask |= MLX5_CT_SYNDROME_STATE_CHANGE;
10006         if (mask->flags & RTE_FLOW_CONNTRACK_PKT_STATE_BAD)
10007                 reg_mask |= MLX5_CT_SYNDROME_BAD_PACKET;
10008         /* The REG_C_x value could be saved during startup. */
10009         reg_id = mlx5_flow_get_reg_id(dev, MLX5_ASO_CONNTRACK, 0, &error);
10010         if (reg_id == REG_NON)
10011                 return;
10012         flow_dv_match_meta_reg(matcher, key, (enum modify_reg)reg_id,
10013                                reg_value, reg_mask);
10014 }
10015
10016 static uint32_t matcher_zero[MLX5_ST_SZ_DW(fte_match_param)] = { 0 };
10017
10018 #define HEADER_IS_ZERO(match_criteria, headers)                              \
10019         !(memcmp(MLX5_ADDR_OF(fte_match_param, match_criteria, headers),     \
10020                  matcher_zero, MLX5_FLD_SZ_BYTES(fte_match_param, headers))) \
10021
10022 /**
10023  * Calculate flow matcher enable bitmap.
10024  *
10025  * @param match_criteria
10026  *   Pointer to flow matcher criteria.
10027  *
10028  * @return
10029  *   Bitmap of enabled fields.
10030  */
10031 static uint8_t
10032 flow_dv_matcher_enable(uint32_t *match_criteria)
10033 {
10034         uint8_t match_criteria_enable;
10035
10036         match_criteria_enable =
10037                 (!HEADER_IS_ZERO(match_criteria, outer_headers)) <<
10038                 MLX5_MATCH_CRITERIA_ENABLE_OUTER_BIT;
10039         match_criteria_enable |=
10040                 (!HEADER_IS_ZERO(match_criteria, misc_parameters)) <<
10041                 MLX5_MATCH_CRITERIA_ENABLE_MISC_BIT;
10042         match_criteria_enable |=
10043                 (!HEADER_IS_ZERO(match_criteria, inner_headers)) <<
10044                 MLX5_MATCH_CRITERIA_ENABLE_INNER_BIT;
10045         match_criteria_enable |=
10046                 (!HEADER_IS_ZERO(match_criteria, misc_parameters_2)) <<
10047                 MLX5_MATCH_CRITERIA_ENABLE_MISC2_BIT;
10048         match_criteria_enable |=
10049                 (!HEADER_IS_ZERO(match_criteria, misc_parameters_3)) <<
10050                 MLX5_MATCH_CRITERIA_ENABLE_MISC3_BIT;
10051         match_criteria_enable |=
10052                 (!HEADER_IS_ZERO(match_criteria, misc_parameters_4)) <<
10053                 MLX5_MATCH_CRITERIA_ENABLE_MISC4_BIT;
10054         match_criteria_enable |=
10055                 (!HEADER_IS_ZERO(match_criteria, misc_parameters_5)) <<
10056                 MLX5_MATCH_CRITERIA_ENABLE_MISC5_BIT;
10057         return match_criteria_enable;
10058 }
10059
10060 static void
10061 __flow_dv_adjust_buf_size(size_t *size, uint8_t match_criteria)
10062 {
10063         /*
10064          * Check flow matching criteria first, subtract misc5/4 length if flow
10065          * doesn't own misc5/4 parameters. In some old rdma-core releases,
10066          * misc5/4 are not supported, and matcher creation failure is expected
10067          * w/o subtration. If misc5 is provided, misc4 must be counted in since
10068          * misc5 is right after misc4.
10069          */
10070         if (!(match_criteria & (1 << MLX5_MATCH_CRITERIA_ENABLE_MISC5_BIT))) {
10071                 *size = MLX5_ST_SZ_BYTES(fte_match_param) -
10072                         MLX5_ST_SZ_BYTES(fte_match_set_misc5);
10073                 if (!(match_criteria & (1 <<
10074                         MLX5_MATCH_CRITERIA_ENABLE_MISC4_BIT))) {
10075                         *size -= MLX5_ST_SZ_BYTES(fte_match_set_misc4);
10076                 }
10077         }
10078 }
10079
10080 static struct mlx5_list_entry *
10081 flow_dv_matcher_clone_cb(void *tool_ctx __rte_unused,
10082                          struct mlx5_list_entry *entry, void *cb_ctx)
10083 {
10084         struct mlx5_flow_cb_ctx *ctx = cb_ctx;
10085         struct mlx5_flow_dv_matcher *ref = ctx->data;
10086         struct mlx5_flow_tbl_data_entry *tbl = container_of(ref->tbl,
10087                                                             typeof(*tbl), tbl);
10088         struct mlx5_flow_dv_matcher *resource = mlx5_malloc(MLX5_MEM_ANY,
10089                                                             sizeof(*resource),
10090                                                             0, SOCKET_ID_ANY);
10091
10092         if (!resource) {
10093                 rte_flow_error_set(ctx->error, ENOMEM,
10094                                    RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
10095                                    "cannot create matcher");
10096                 return NULL;
10097         }
10098         memcpy(resource, entry, sizeof(*resource));
10099         resource->tbl = &tbl->tbl;
10100         return &resource->entry;
10101 }
10102
10103 static void
10104 flow_dv_matcher_clone_free_cb(void *tool_ctx __rte_unused,
10105                              struct mlx5_list_entry *entry)
10106 {
10107         mlx5_free(entry);
10108 }
10109
10110 struct mlx5_list_entry *
10111 flow_dv_tbl_create_cb(void *tool_ctx, void *cb_ctx)
10112 {
10113         struct mlx5_dev_ctx_shared *sh = tool_ctx;
10114         struct mlx5_flow_cb_ctx *ctx = cb_ctx;
10115         struct rte_eth_dev *dev = ctx->dev;
10116         struct mlx5_flow_tbl_data_entry *tbl_data;
10117         struct mlx5_flow_tbl_tunnel_prm *tt_prm = ctx->data2;
10118         struct rte_flow_error *error = ctx->error;
10119         union mlx5_flow_tbl_key key = { .v64 = *(uint64_t *)(ctx->data) };
10120         struct mlx5_flow_tbl_resource *tbl;
10121         void *domain;
10122         uint32_t idx = 0;
10123         int ret;
10124
10125         tbl_data = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_JUMP], &idx);
10126         if (!tbl_data) {
10127                 rte_flow_error_set(error, ENOMEM,
10128                                    RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
10129                                    NULL,
10130                                    "cannot allocate flow table data entry");
10131                 return NULL;
10132         }
10133         tbl_data->idx = idx;
10134         tbl_data->tunnel = tt_prm->tunnel;
10135         tbl_data->group_id = tt_prm->group_id;
10136         tbl_data->external = !!tt_prm->external;
10137         tbl_data->tunnel_offload = is_tunnel_offload_active(dev);
10138         tbl_data->is_egress = !!key.is_egress;
10139         tbl_data->is_transfer = !!key.is_fdb;
10140         tbl_data->dummy = !!key.dummy;
10141         tbl_data->level = key.level;
10142         tbl_data->id = key.id;
10143         tbl = &tbl_data->tbl;
10144         if (key.dummy)
10145                 return &tbl_data->entry;
10146         if (key.is_fdb)
10147                 domain = sh->fdb_domain;
10148         else if (key.is_egress)
10149                 domain = sh->tx_domain;
10150         else
10151                 domain = sh->rx_domain;
10152         ret = mlx5_flow_os_create_flow_tbl(domain, key.level, &tbl->obj);
10153         if (ret) {
10154                 rte_flow_error_set(error, ENOMEM,
10155                                    RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
10156                                    NULL, "cannot create flow table object");
10157                 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_JUMP], idx);
10158                 return NULL;
10159         }
10160         if (key.level != 0) {
10161                 ret = mlx5_flow_os_create_flow_action_dest_flow_tbl
10162                                         (tbl->obj, &tbl_data->jump.action);
10163                 if (ret) {
10164                         rte_flow_error_set(error, ENOMEM,
10165                                            RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
10166                                            NULL,
10167                                            "cannot create flow jump action");
10168                         mlx5_flow_os_destroy_flow_tbl(tbl->obj);
10169                         mlx5_ipool_free(sh->ipool[MLX5_IPOOL_JUMP], idx);
10170                         return NULL;
10171                 }
10172         }
10173         MKSTR(matcher_name, "%s_%s_%u_%u_matcher_list",
10174               key.is_fdb ? "FDB" : "NIC", key.is_egress ? "egress" : "ingress",
10175               key.level, key.id);
10176         tbl_data->matchers = mlx5_list_create(matcher_name, sh, true,
10177                                               flow_dv_matcher_create_cb,
10178                                               flow_dv_matcher_match_cb,
10179                                               flow_dv_matcher_remove_cb,
10180                                               flow_dv_matcher_clone_cb,
10181                                               flow_dv_matcher_clone_free_cb);
10182         if (!tbl_data->matchers) {
10183                 rte_flow_error_set(error, ENOMEM,
10184                                    RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
10185                                    NULL,
10186                                    "cannot create tbl matcher list");
10187                 mlx5_flow_os_destroy_flow_action(tbl_data->jump.action);
10188                 mlx5_flow_os_destroy_flow_tbl(tbl->obj);
10189                 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_JUMP], idx);
10190                 return NULL;
10191         }
10192         return &tbl_data->entry;
10193 }
10194
10195 int
10196 flow_dv_tbl_match_cb(void *tool_ctx __rte_unused, struct mlx5_list_entry *entry,
10197                      void *cb_ctx)
10198 {
10199         struct mlx5_flow_cb_ctx *ctx = cb_ctx;
10200         struct mlx5_flow_tbl_data_entry *tbl_data =
10201                 container_of(entry, struct mlx5_flow_tbl_data_entry, entry);
10202         union mlx5_flow_tbl_key key = { .v64 =  *(uint64_t *)(ctx->data) };
10203
10204         return tbl_data->level != key.level ||
10205                tbl_data->id != key.id ||
10206                tbl_data->dummy != key.dummy ||
10207                tbl_data->is_transfer != !!key.is_fdb ||
10208                tbl_data->is_egress != !!key.is_egress;
10209 }
10210
10211 struct mlx5_list_entry *
10212 flow_dv_tbl_clone_cb(void *tool_ctx, struct mlx5_list_entry *oentry,
10213                       void *cb_ctx)
10214 {
10215         struct mlx5_dev_ctx_shared *sh = tool_ctx;
10216         struct mlx5_flow_cb_ctx *ctx = cb_ctx;
10217         struct mlx5_flow_tbl_data_entry *tbl_data;
10218         struct rte_flow_error *error = ctx->error;
10219         uint32_t idx = 0;
10220
10221         tbl_data = mlx5_ipool_malloc(sh->ipool[MLX5_IPOOL_JUMP], &idx);
10222         if (!tbl_data) {
10223                 rte_flow_error_set(error, ENOMEM,
10224                                    RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
10225                                    NULL,
10226                                    "cannot allocate flow table data entry");
10227                 return NULL;
10228         }
10229         memcpy(tbl_data, oentry, sizeof(*tbl_data));
10230         tbl_data->idx = idx;
10231         return &tbl_data->entry;
10232 }
10233
10234 void
10235 flow_dv_tbl_clone_free_cb(void *tool_ctx, struct mlx5_list_entry *entry)
10236 {
10237         struct mlx5_dev_ctx_shared *sh = tool_ctx;
10238         struct mlx5_flow_tbl_data_entry *tbl_data =
10239                     container_of(entry, struct mlx5_flow_tbl_data_entry, entry);
10240
10241         mlx5_ipool_free(sh->ipool[MLX5_IPOOL_JUMP], tbl_data->idx);
10242 }
10243
10244 /**
10245  * Get a flow table.
10246  *
10247  * @param[in, out] dev
10248  *   Pointer to rte_eth_dev structure.
10249  * @param[in] table_level
10250  *   Table level to use.
10251  * @param[in] egress
10252  *   Direction of the table.
10253  * @param[in] transfer
10254  *   E-Switch or NIC flow.
10255  * @param[in] dummy
10256  *   Dummy entry for dv API.
10257  * @param[in] table_id
10258  *   Table id to use.
10259  * @param[out] error
10260  *   pointer to error structure.
10261  *
10262  * @return
10263  *   Returns tables resource based on the index, NULL in case of failed.
10264  */
10265 struct mlx5_flow_tbl_resource *
10266 flow_dv_tbl_resource_get(struct rte_eth_dev *dev,
10267                          uint32_t table_level, uint8_t egress,
10268                          uint8_t transfer,
10269                          bool external,
10270                          const struct mlx5_flow_tunnel *tunnel,
10271                          uint32_t group_id, uint8_t dummy,
10272                          uint32_t table_id,
10273                          struct rte_flow_error *error)
10274 {
10275         struct mlx5_priv *priv = dev->data->dev_private;
10276         union mlx5_flow_tbl_key table_key = {
10277                 {
10278                         .level = table_level,
10279                         .id = table_id,
10280                         .reserved = 0,
10281                         .dummy = !!dummy,
10282                         .is_fdb = !!transfer,
10283                         .is_egress = !!egress,
10284                 }
10285         };
10286         struct mlx5_flow_tbl_tunnel_prm tt_prm = {
10287                 .tunnel = tunnel,
10288                 .group_id = group_id,
10289                 .external = external,
10290         };
10291         struct mlx5_flow_cb_ctx ctx = {
10292                 .dev = dev,
10293                 .error = error,
10294                 .data = &table_key.v64,
10295                 .data2 = &tt_prm,
10296         };
10297         struct mlx5_list_entry *entry;
10298         struct mlx5_flow_tbl_data_entry *tbl_data;
10299
10300         entry = mlx5_hlist_register(priv->sh->flow_tbls, table_key.v64, &ctx);
10301         if (!entry) {
10302                 rte_flow_error_set(error, ENOMEM,
10303                                    RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
10304                                    "cannot get table");
10305                 return NULL;
10306         }
10307         DRV_LOG(DEBUG, "table_level %u table_id %u "
10308                 "tunnel %u group %u registered.",
10309                 table_level, table_id,
10310                 tunnel ? tunnel->tunnel_id : 0, group_id);
10311         tbl_data = container_of(entry, struct mlx5_flow_tbl_data_entry, entry);
10312         return &tbl_data->tbl;
10313 }
10314
10315 void
10316 flow_dv_tbl_remove_cb(void *tool_ctx, struct mlx5_list_entry *entry)
10317 {
10318         struct mlx5_dev_ctx_shared *sh = tool_ctx;
10319         struct mlx5_flow_tbl_data_entry *tbl_data =
10320                     container_of(entry, struct mlx5_flow_tbl_data_entry, entry);
10321
10322         MLX5_ASSERT(entry && sh);
10323         if (tbl_data->jump.action)
10324                 mlx5_flow_os_destroy_flow_action(tbl_data->jump.action);
10325         if (tbl_data->tbl.obj)
10326                 mlx5_flow_os_destroy_flow_tbl(tbl_data->tbl.obj);
10327         if (tbl_data->tunnel_offload && tbl_data->external) {
10328                 struct mlx5_list_entry *he;
10329                 struct mlx5_hlist *tunnel_grp_hash;
10330                 struct mlx5_flow_tunnel_hub *thub = sh->tunnel_hub;
10331                 union tunnel_tbl_key tunnel_key = {
10332                         .tunnel_id = tbl_data->tunnel ?
10333                                         tbl_data->tunnel->tunnel_id : 0,
10334                         .group = tbl_data->group_id
10335                 };
10336                 uint32_t table_level = tbl_data->level;
10337                 struct mlx5_flow_cb_ctx ctx = {
10338                         .data = (void *)&tunnel_key.val,
10339                 };
10340
10341                 tunnel_grp_hash = tbl_data->tunnel ?
10342                                         tbl_data->tunnel->groups :
10343                                         thub->groups;
10344                 he = mlx5_hlist_lookup(tunnel_grp_hash, tunnel_key.val, &ctx);
10345                 if (he)
10346                         mlx5_hlist_unregister(tunnel_grp_hash, he);
10347                 DRV_LOG(DEBUG,
10348                         "table_level %u id %u tunnel %u group %u released.",
10349                         table_level,
10350                         tbl_data->id,
10351                         tbl_data->tunnel ?
10352                         tbl_data->tunnel->tunnel_id : 0,
10353                         tbl_data->group_id);
10354         }
10355         mlx5_list_destroy(tbl_data->matchers);
10356         mlx5_ipool_free(sh->ipool[MLX5_IPOOL_JUMP], tbl_data->idx);
10357 }
10358
10359 /**
10360  * Release a flow table.
10361  *
10362  * @param[in] sh
10363  *   Pointer to device shared structure.
10364  * @param[in] tbl
10365  *   Table resource to be released.
10366  *
10367  * @return
10368  *   Returns 0 if table was released, else return 1;
10369  */
10370 static int
10371 flow_dv_tbl_resource_release(struct mlx5_dev_ctx_shared *sh,
10372                              struct mlx5_flow_tbl_resource *tbl)
10373 {
10374         struct mlx5_flow_tbl_data_entry *tbl_data =
10375                 container_of(tbl, struct mlx5_flow_tbl_data_entry, tbl);
10376
10377         if (!tbl)
10378                 return 0;
10379         return mlx5_hlist_unregister(sh->flow_tbls, &tbl_data->entry);
10380 }
10381
10382 int
10383 flow_dv_matcher_match_cb(void *tool_ctx __rte_unused,
10384                          struct mlx5_list_entry *entry, void *cb_ctx)
10385 {
10386         struct mlx5_flow_cb_ctx *ctx = cb_ctx;
10387         struct mlx5_flow_dv_matcher *ref = ctx->data;
10388         struct mlx5_flow_dv_matcher *cur = container_of(entry, typeof(*cur),
10389                                                         entry);
10390
10391         return cur->crc != ref->crc ||
10392                cur->priority != ref->priority ||
10393                memcmp((const void *)cur->mask.buf,
10394                       (const void *)ref->mask.buf, ref->mask.size);
10395 }
10396
10397 struct mlx5_list_entry *
10398 flow_dv_matcher_create_cb(void *tool_ctx, void *cb_ctx)
10399 {
10400         struct mlx5_dev_ctx_shared *sh = tool_ctx;
10401         struct mlx5_flow_cb_ctx *ctx = cb_ctx;
10402         struct mlx5_flow_dv_matcher *ref = ctx->data;
10403         struct mlx5_flow_dv_matcher *resource;
10404         struct mlx5dv_flow_matcher_attr dv_attr = {
10405                 .type = IBV_FLOW_ATTR_NORMAL,
10406                 .match_mask = (void *)&ref->mask,
10407         };
10408         struct mlx5_flow_tbl_data_entry *tbl = container_of(ref->tbl,
10409                                                             typeof(*tbl), tbl);
10410         int ret;
10411
10412         resource = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*resource), 0,
10413                                SOCKET_ID_ANY);
10414         if (!resource) {
10415                 rte_flow_error_set(ctx->error, ENOMEM,
10416                                    RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
10417                                    "cannot create matcher");
10418                 return NULL;
10419         }
10420         *resource = *ref;
10421         dv_attr.match_criteria_enable =
10422                 flow_dv_matcher_enable(resource->mask.buf);
10423         __flow_dv_adjust_buf_size(&ref->mask.size,
10424                                   dv_attr.match_criteria_enable);
10425         dv_attr.priority = ref->priority;
10426         if (tbl->is_egress)
10427                 dv_attr.flags |= IBV_FLOW_ATTR_FLAGS_EGRESS;
10428         ret = mlx5_flow_os_create_flow_matcher(sh->cdev->ctx, &dv_attr,
10429                                                tbl->tbl.obj,
10430                                                &resource->matcher_object);
10431         if (ret) {
10432                 mlx5_free(resource);
10433                 rte_flow_error_set(ctx->error, ENOMEM,
10434                                    RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
10435                                    "cannot create matcher");
10436                 return NULL;
10437         }
10438         return &resource->entry;
10439 }
10440
10441 /**
10442  * Register the flow matcher.
10443  *
10444  * @param[in, out] dev
10445  *   Pointer to rte_eth_dev structure.
10446  * @param[in, out] matcher
10447  *   Pointer to flow matcher.
10448  * @param[in, out] key
10449  *   Pointer to flow table key.
10450  * @parm[in, out] dev_flow
10451  *   Pointer to the dev_flow.
10452  * @param[out] error
10453  *   pointer to error structure.
10454  *
10455  * @return
10456  *   0 on success otherwise -errno and errno is set.
10457  */
10458 static int
10459 flow_dv_matcher_register(struct rte_eth_dev *dev,
10460                          struct mlx5_flow_dv_matcher *ref,
10461                          union mlx5_flow_tbl_key *key,
10462                          struct mlx5_flow *dev_flow,
10463                          const struct mlx5_flow_tunnel *tunnel,
10464                          uint32_t group_id,
10465                          struct rte_flow_error *error)
10466 {
10467         struct mlx5_list_entry *entry;
10468         struct mlx5_flow_dv_matcher *resource;
10469         struct mlx5_flow_tbl_resource *tbl;
10470         struct mlx5_flow_tbl_data_entry *tbl_data;
10471         struct mlx5_flow_cb_ctx ctx = {
10472                 .error = error,
10473                 .data = ref,
10474         };
10475         /**
10476          * tunnel offload API requires this registration for cases when
10477          * tunnel match rule was inserted before tunnel set rule.
10478          */
10479         tbl = flow_dv_tbl_resource_get(dev, key->level,
10480                                        key->is_egress, key->is_fdb,
10481                                        dev_flow->external, tunnel,
10482                                        group_id, 0, key->id, error);
10483         if (!tbl)
10484                 return -rte_errno;      /* No need to refill the error info */
10485         tbl_data = container_of(tbl, struct mlx5_flow_tbl_data_entry, tbl);
10486         ref->tbl = tbl;
10487         entry = mlx5_list_register(tbl_data->matchers, &ctx);
10488         if (!entry) {
10489                 flow_dv_tbl_resource_release(MLX5_SH(dev), tbl);
10490                 return rte_flow_error_set(error, ENOMEM,
10491                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
10492                                           "cannot allocate ref memory");
10493         }
10494         resource = container_of(entry, typeof(*resource), entry);
10495         dev_flow->handle->dvh.matcher = resource;
10496         return 0;
10497 }
10498
10499 struct mlx5_list_entry *
10500 flow_dv_tag_create_cb(void *tool_ctx, void *cb_ctx)
10501 {
10502         struct mlx5_dev_ctx_shared *sh = tool_ctx;
10503         struct mlx5_flow_cb_ctx *ctx = cb_ctx;
10504         struct mlx5_flow_dv_tag_resource *entry;
10505         uint32_t idx = 0;
10506         int ret;
10507
10508         entry = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_TAG], &idx);
10509         if (!entry) {
10510                 rte_flow_error_set(ctx->error, ENOMEM,
10511                                    RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
10512                                    "cannot allocate resource memory");
10513                 return NULL;
10514         }
10515         entry->idx = idx;
10516         entry->tag_id = *(uint32_t *)(ctx->data);
10517         ret = mlx5_flow_os_create_flow_action_tag(entry->tag_id,
10518                                                   &entry->action);
10519         if (ret) {
10520                 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_TAG], idx);
10521                 rte_flow_error_set(ctx->error, ENOMEM,
10522                                    RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
10523                                    NULL, "cannot create action");
10524                 return NULL;
10525         }
10526         return &entry->entry;
10527 }
10528
10529 int
10530 flow_dv_tag_match_cb(void *tool_ctx __rte_unused, struct mlx5_list_entry *entry,
10531                      void *cb_ctx)
10532 {
10533         struct mlx5_flow_cb_ctx *ctx = cb_ctx;
10534         struct mlx5_flow_dv_tag_resource *tag =
10535                    container_of(entry, struct mlx5_flow_dv_tag_resource, entry);
10536
10537         return *(uint32_t *)(ctx->data) != tag->tag_id;
10538 }
10539
10540 struct mlx5_list_entry *
10541 flow_dv_tag_clone_cb(void *tool_ctx, struct mlx5_list_entry *oentry,
10542                      void *cb_ctx)
10543 {
10544         struct mlx5_dev_ctx_shared *sh = tool_ctx;
10545         struct mlx5_flow_cb_ctx *ctx = cb_ctx;
10546         struct mlx5_flow_dv_tag_resource *entry;
10547         uint32_t idx = 0;
10548
10549         entry = mlx5_ipool_malloc(sh->ipool[MLX5_IPOOL_TAG], &idx);
10550         if (!entry) {
10551                 rte_flow_error_set(ctx->error, ENOMEM,
10552                                    RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
10553                                    "cannot allocate tag resource memory");
10554                 return NULL;
10555         }
10556         memcpy(entry, oentry, sizeof(*entry));
10557         entry->idx = idx;
10558         return &entry->entry;
10559 }
10560
10561 void
10562 flow_dv_tag_clone_free_cb(void *tool_ctx, struct mlx5_list_entry *entry)
10563 {
10564         struct mlx5_dev_ctx_shared *sh = tool_ctx;
10565         struct mlx5_flow_dv_tag_resource *tag =
10566                    container_of(entry, struct mlx5_flow_dv_tag_resource, entry);
10567
10568         mlx5_ipool_free(sh->ipool[MLX5_IPOOL_TAG], tag->idx);
10569 }
10570
10571 /**
10572  * Find existing tag resource or create and register a new one.
10573  *
10574  * @param dev[in, out]
10575  *   Pointer to rte_eth_dev structure.
10576  * @param[in, out] tag_be24
10577  *   Tag value in big endian then R-shift 8.
10578  * @parm[in, out] dev_flow
10579  *   Pointer to the dev_flow.
10580  * @param[out] error
10581  *   pointer to error structure.
10582  *
10583  * @return
10584  *   0 on success otherwise -errno and errno is set.
10585  */
10586 static int
10587 flow_dv_tag_resource_register
10588                         (struct rte_eth_dev *dev,
10589                          uint32_t tag_be24,
10590                          struct mlx5_flow *dev_flow,
10591                          struct rte_flow_error *error)
10592 {
10593         struct mlx5_priv *priv = dev->data->dev_private;
10594         struct mlx5_flow_dv_tag_resource *resource;
10595         struct mlx5_list_entry *entry;
10596         struct mlx5_flow_cb_ctx ctx = {
10597                                         .error = error,
10598                                         .data = &tag_be24,
10599                                         };
10600         struct mlx5_hlist *tag_table;
10601
10602         tag_table = flow_dv_hlist_prepare(priv->sh, &priv->sh->tag_table,
10603                                       "tags",
10604                                       MLX5_TAGS_HLIST_ARRAY_SIZE,
10605                                       false, false, priv->sh,
10606                                       flow_dv_tag_create_cb,
10607                                       flow_dv_tag_match_cb,
10608                                       flow_dv_tag_remove_cb,
10609                                       flow_dv_tag_clone_cb,
10610                                       flow_dv_tag_clone_free_cb);
10611         if (unlikely(!tag_table))
10612                 return -rte_errno;
10613         entry = mlx5_hlist_register(tag_table, tag_be24, &ctx);
10614         if (entry) {
10615                 resource = container_of(entry, struct mlx5_flow_dv_tag_resource,
10616                                         entry);
10617                 dev_flow->handle->dvh.rix_tag = resource->idx;
10618                 dev_flow->dv.tag_resource = resource;
10619                 return 0;
10620         }
10621         return -rte_errno;
10622 }
10623
10624 void
10625 flow_dv_tag_remove_cb(void *tool_ctx, struct mlx5_list_entry *entry)
10626 {
10627         struct mlx5_dev_ctx_shared *sh = tool_ctx;
10628         struct mlx5_flow_dv_tag_resource *tag =
10629                    container_of(entry, struct mlx5_flow_dv_tag_resource, entry);
10630
10631         MLX5_ASSERT(tag && sh && tag->action);
10632         claim_zero(mlx5_flow_os_destroy_flow_action(tag->action));
10633         DRV_LOG(DEBUG, "Tag %p: removed.", (void *)tag);
10634         mlx5_ipool_free(sh->ipool[MLX5_IPOOL_TAG], tag->idx);
10635 }
10636
10637 /**
10638  * Release the tag.
10639  *
10640  * @param dev
10641  *   Pointer to Ethernet device.
10642  * @param tag_idx
10643  *   Tag index.
10644  *
10645  * @return
10646  *   1 while a reference on it exists, 0 when freed.
10647  */
10648 static int
10649 flow_dv_tag_release(struct rte_eth_dev *dev,
10650                     uint32_t tag_idx)
10651 {
10652         struct mlx5_priv *priv = dev->data->dev_private;
10653         struct mlx5_flow_dv_tag_resource *tag;
10654
10655         tag = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_TAG], tag_idx);
10656         if (!tag)
10657                 return 0;
10658         DRV_LOG(DEBUG, "port %u tag %p: refcnt %d--",
10659                 dev->data->port_id, (void *)tag, tag->entry.ref_cnt);
10660         return mlx5_hlist_unregister(priv->sh->tag_table, &tag->entry);
10661 }
10662
10663 /**
10664  * Translate action PORT_ID / REPRESENTED_PORT to vport.
10665  *
10666  * @param[in] dev
10667  *   Pointer to rte_eth_dev structure.
10668  * @param[in] action
10669  *   Pointer to action PORT_ID / REPRESENTED_PORT.
10670  * @param[out] dst_port_id
10671  *   The target port ID.
10672  * @param[out] error
10673  *   Pointer to the error structure.
10674  *
10675  * @return
10676  *   0 on success, a negative errno value otherwise and rte_errno is set.
10677  */
10678 static int
10679 flow_dv_translate_action_port_id(struct rte_eth_dev *dev,
10680                                  const struct rte_flow_action *action,
10681                                  uint32_t *dst_port_id,
10682                                  struct rte_flow_error *error)
10683 {
10684         uint32_t port;
10685         struct mlx5_priv *priv;
10686
10687         switch (action->type) {
10688         case RTE_FLOW_ACTION_TYPE_PORT_ID: {
10689                 const struct rte_flow_action_port_id *conf;
10690
10691                 conf = (const struct rte_flow_action_port_id *)action->conf;
10692                 port = conf->original ? dev->data->port_id : conf->id;
10693                 break;
10694         }
10695         case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT: {
10696                 const struct rte_flow_action_ethdev *ethdev;
10697
10698                 ethdev = (const struct rte_flow_action_ethdev *)action->conf;
10699                 port = ethdev->port_id;
10700                 break;
10701         }
10702         default:
10703                 MLX5_ASSERT(false);
10704                 return rte_flow_error_set(error, EINVAL,
10705                                           RTE_FLOW_ERROR_TYPE_ACTION, action,
10706                                           "unknown E-Switch action");
10707         }
10708
10709         priv = mlx5_port_to_eswitch_info(port, false);
10710         if (!priv)
10711                 return rte_flow_error_set(error, -rte_errno,
10712                                           RTE_FLOW_ERROR_TYPE_ACTION,
10713                                           NULL,
10714                                           "No eswitch info was found for port");
10715 #ifdef HAVE_MLX5DV_DR_CREATE_DEST_IB_PORT
10716         /*
10717          * This parameter is transferred to
10718          * mlx5dv_dr_action_create_dest_ib_port().
10719          */
10720         *dst_port_id = priv->dev_port;
10721 #else
10722         /*
10723          * Legacy mode, no LAG configurations is supported.
10724          * This parameter is transferred to
10725          * mlx5dv_dr_action_create_dest_vport().
10726          */
10727         *dst_port_id = priv->vport_id;
10728 #endif
10729         return 0;
10730 }
10731
10732 /**
10733  * Create a counter with aging configuration.
10734  *
10735  * @param[in] dev
10736  *   Pointer to rte_eth_dev structure.
10737  * @param[in] dev_flow
10738  *   Pointer to the mlx5_flow.
10739  * @param[out] count
10740  *   Pointer to the counter action configuration.
10741  * @param[in] age
10742  *   Pointer to the aging action configuration.
10743  *
10744  * @return
10745  *   Index to flow counter on success, 0 otherwise.
10746  */
10747 static uint32_t
10748 flow_dv_translate_create_counter(struct rte_eth_dev *dev,
10749                                 struct mlx5_flow *dev_flow,
10750                                 const struct rte_flow_action_count *count
10751                                         __rte_unused,
10752                                 const struct rte_flow_action_age *age)
10753 {
10754         uint32_t counter;
10755         struct mlx5_age_param *age_param;
10756
10757         counter = flow_dv_counter_alloc(dev, !!age);
10758         if (!counter || age == NULL)
10759                 return counter;
10760         age_param = flow_dv_counter_idx_get_age(dev, counter);
10761         age_param->context = age->context ? age->context :
10762                 (void *)(uintptr_t)(dev_flow->flow_idx);
10763         age_param->timeout = age->timeout;
10764         age_param->port_id = dev->data->port_id;
10765         __atomic_store_n(&age_param->sec_since_last_hit, 0, __ATOMIC_RELAXED);
10766         __atomic_store_n(&age_param->state, AGE_CANDIDATE, __ATOMIC_RELAXED);
10767         return counter;
10768 }
10769
10770 /**
10771  * Add Tx queue matcher
10772  *
10773  * @param[in] dev
10774  *   Pointer to the dev struct.
10775  * @param[in, out] matcher
10776  *   Flow matcher.
10777  * @param[in, out] key
10778  *   Flow matcher value.
10779  * @param[in] item
10780  *   Flow pattern to translate.
10781  * @param[in] inner
10782  *   Item is inner pattern.
10783  */
10784 static void
10785 flow_dv_translate_item_tx_queue(struct rte_eth_dev *dev,
10786                                 void *matcher, void *key,
10787                                 const struct rte_flow_item *item)
10788 {
10789         const struct mlx5_rte_flow_item_tx_queue *queue_m;
10790         const struct mlx5_rte_flow_item_tx_queue *queue_v;
10791         void *misc_m =
10792                 MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
10793         void *misc_v =
10794                 MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
10795         struct mlx5_txq_ctrl *txq;
10796         uint32_t queue;
10797
10798
10799         queue_m = (const void *)item->mask;
10800         if (!queue_m)
10801                 return;
10802         queue_v = (const void *)item->spec;
10803         if (!queue_v)
10804                 return;
10805         txq = mlx5_txq_get(dev, queue_v->queue);
10806         if (!txq)
10807                 return;
10808         queue = txq->obj->sq->id;
10809         MLX5_SET(fte_match_set_misc, misc_m, source_sqn, queue_m->queue);
10810         MLX5_SET(fte_match_set_misc, misc_v, source_sqn,
10811                  queue & queue_m->queue);
10812         mlx5_txq_release(dev, queue_v->queue);
10813 }
10814
10815 /**
10816  * Set the hash fields according to the @p flow information.
10817  *
10818  * @param[in] dev_flow
10819  *   Pointer to the mlx5_flow.
10820  * @param[in] rss_desc
10821  *   Pointer to the mlx5_flow_rss_desc.
10822  */
10823 static void
10824 flow_dv_hashfields_set(struct mlx5_flow *dev_flow,
10825                        struct mlx5_flow_rss_desc *rss_desc)
10826 {
10827         uint64_t items = dev_flow->handle->layers;
10828         int rss_inner = 0;
10829         uint64_t rss_types = rte_eth_rss_hf_refine(rss_desc->types);
10830
10831         dev_flow->hash_fields = 0;
10832 #ifdef HAVE_IBV_DEVICE_TUNNEL_SUPPORT
10833         if (rss_desc->level >= 2)
10834                 rss_inner = 1;
10835 #endif
10836         if ((rss_inner && (items & MLX5_FLOW_LAYER_INNER_L3_IPV4)) ||
10837             (!rss_inner && (items & MLX5_FLOW_LAYER_OUTER_L3_IPV4))) {
10838                 if (rss_types & MLX5_IPV4_LAYER_TYPES) {
10839                         if (rss_types & ETH_RSS_L3_SRC_ONLY)
10840                                 dev_flow->hash_fields |= IBV_RX_HASH_SRC_IPV4;
10841                         else if (rss_types & ETH_RSS_L3_DST_ONLY)
10842                                 dev_flow->hash_fields |= IBV_RX_HASH_DST_IPV4;
10843                         else
10844                                 dev_flow->hash_fields |= MLX5_IPV4_IBV_RX_HASH;
10845                 }
10846         } else if ((rss_inner && (items & MLX5_FLOW_LAYER_INNER_L3_IPV6)) ||
10847                    (!rss_inner && (items & MLX5_FLOW_LAYER_OUTER_L3_IPV6))) {
10848                 if (rss_types & MLX5_IPV6_LAYER_TYPES) {
10849                         if (rss_types & ETH_RSS_L3_SRC_ONLY)
10850                                 dev_flow->hash_fields |= IBV_RX_HASH_SRC_IPV6;
10851                         else if (rss_types & ETH_RSS_L3_DST_ONLY)
10852                                 dev_flow->hash_fields |= IBV_RX_HASH_DST_IPV6;
10853                         else
10854                                 dev_flow->hash_fields |= MLX5_IPV6_IBV_RX_HASH;
10855                 }
10856         }
10857         if (dev_flow->hash_fields == 0)
10858                 /*
10859                  * There is no match between the RSS types and the
10860                  * L3 protocol (IPv4/IPv6) defined in the flow rule.
10861                  */
10862                 return;
10863         if ((rss_inner && (items & MLX5_FLOW_LAYER_INNER_L4_UDP)) ||
10864             (!rss_inner && (items & MLX5_FLOW_LAYER_OUTER_L4_UDP))) {
10865                 if (rss_types & ETH_RSS_UDP) {
10866                         if (rss_types & ETH_RSS_L4_SRC_ONLY)
10867                                 dev_flow->hash_fields |=
10868                                                 IBV_RX_HASH_SRC_PORT_UDP;
10869                         else if (rss_types & ETH_RSS_L4_DST_ONLY)
10870                                 dev_flow->hash_fields |=
10871                                                 IBV_RX_HASH_DST_PORT_UDP;
10872                         else
10873                                 dev_flow->hash_fields |= MLX5_UDP_IBV_RX_HASH;
10874                 }
10875         } else if ((rss_inner && (items & MLX5_FLOW_LAYER_INNER_L4_TCP)) ||
10876                    (!rss_inner && (items & MLX5_FLOW_LAYER_OUTER_L4_TCP))) {
10877                 if (rss_types & ETH_RSS_TCP) {
10878                         if (rss_types & ETH_RSS_L4_SRC_ONLY)
10879                                 dev_flow->hash_fields |=
10880                                                 IBV_RX_HASH_SRC_PORT_TCP;
10881                         else if (rss_types & ETH_RSS_L4_DST_ONLY)
10882                                 dev_flow->hash_fields |=
10883                                                 IBV_RX_HASH_DST_PORT_TCP;
10884                         else
10885                                 dev_flow->hash_fields |= MLX5_TCP_IBV_RX_HASH;
10886                 }
10887         }
10888         if (rss_inner)
10889                 dev_flow->hash_fields |= IBV_RX_HASH_INNER;
10890 }
10891
10892 /**
10893  * Prepare an Rx Hash queue.
10894  *
10895  * @param dev
10896  *   Pointer to Ethernet device.
10897  * @param[in] dev_flow
10898  *   Pointer to the mlx5_flow.
10899  * @param[in] rss_desc
10900  *   Pointer to the mlx5_flow_rss_desc.
10901  * @param[out] hrxq_idx
10902  *   Hash Rx queue index.
10903  *
10904  * @return
10905  *   The Verbs/DevX object initialised, NULL otherwise and rte_errno is set.
10906  */
10907 static struct mlx5_hrxq *
10908 flow_dv_hrxq_prepare(struct rte_eth_dev *dev,
10909                      struct mlx5_flow *dev_flow,
10910                      struct mlx5_flow_rss_desc *rss_desc,
10911                      uint32_t *hrxq_idx)
10912 {
10913         struct mlx5_priv *priv = dev->data->dev_private;
10914         struct mlx5_flow_handle *dh = dev_flow->handle;
10915         struct mlx5_hrxq *hrxq;
10916
10917         MLX5_ASSERT(rss_desc->queue_num);
10918         rss_desc->key_len = MLX5_RSS_HASH_KEY_LEN;
10919         rss_desc->hash_fields = dev_flow->hash_fields;
10920         rss_desc->tunnel = !!(dh->layers & MLX5_FLOW_LAYER_TUNNEL);
10921         rss_desc->shared_rss = 0;
10922         if (rss_desc->hash_fields == 0)
10923                 rss_desc->queue_num = 1;
10924         *hrxq_idx = mlx5_hrxq_get(dev, rss_desc);
10925         if (!*hrxq_idx)
10926                 return NULL;
10927         hrxq = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_HRXQ],
10928                               *hrxq_idx);
10929         return hrxq;
10930 }
10931
10932 /**
10933  * Release sample sub action resource.
10934  *
10935  * @param[in, out] dev
10936  *   Pointer to rte_eth_dev structure.
10937  * @param[in] act_res
10938  *   Pointer to sample sub action resource.
10939  */
10940 static void
10941 flow_dv_sample_sub_actions_release(struct rte_eth_dev *dev,
10942                                    struct mlx5_flow_sub_actions_idx *act_res)
10943 {
10944         if (act_res->rix_hrxq) {
10945                 mlx5_hrxq_release(dev, act_res->rix_hrxq);
10946                 act_res->rix_hrxq = 0;
10947         }
10948         if (act_res->rix_encap_decap) {
10949                 flow_dv_encap_decap_resource_release(dev,
10950                                                      act_res->rix_encap_decap);
10951                 act_res->rix_encap_decap = 0;
10952         }
10953         if (act_res->rix_port_id_action) {
10954                 flow_dv_port_id_action_resource_release(dev,
10955                                                 act_res->rix_port_id_action);
10956                 act_res->rix_port_id_action = 0;
10957         }
10958         if (act_res->rix_tag) {
10959                 flow_dv_tag_release(dev, act_res->rix_tag);
10960                 act_res->rix_tag = 0;
10961         }
10962         if (act_res->rix_jump) {
10963                 flow_dv_jump_tbl_resource_release(dev, act_res->rix_jump);
10964                 act_res->rix_jump = 0;
10965         }
10966 }
10967
10968 int
10969 flow_dv_sample_match_cb(void *tool_ctx __rte_unused,
10970                         struct mlx5_list_entry *entry, void *cb_ctx)
10971 {
10972         struct mlx5_flow_cb_ctx *ctx = cb_ctx;
10973         struct rte_eth_dev *dev = ctx->dev;
10974         struct mlx5_flow_dv_sample_resource *ctx_resource = ctx->data;
10975         struct mlx5_flow_dv_sample_resource *resource = container_of(entry,
10976                                                               typeof(*resource),
10977                                                               entry);
10978
10979         if (ctx_resource->ratio == resource->ratio &&
10980             ctx_resource->ft_type == resource->ft_type &&
10981             ctx_resource->ft_id == resource->ft_id &&
10982             ctx_resource->set_action == resource->set_action &&
10983             !memcmp((void *)&ctx_resource->sample_act,
10984                     (void *)&resource->sample_act,
10985                     sizeof(struct mlx5_flow_sub_actions_list))) {
10986                 /*
10987                  * Existing sample action should release the prepared
10988                  * sub-actions reference counter.
10989                  */
10990                 flow_dv_sample_sub_actions_release(dev,
10991                                                    &ctx_resource->sample_idx);
10992                 return 0;
10993         }
10994         return 1;
10995 }
10996
10997 struct mlx5_list_entry *
10998 flow_dv_sample_create_cb(void *tool_ctx __rte_unused, void *cb_ctx)
10999 {
11000         struct mlx5_flow_cb_ctx *ctx = cb_ctx;
11001         struct rte_eth_dev *dev = ctx->dev;
11002         struct mlx5_flow_dv_sample_resource *ctx_resource = ctx->data;
11003         void **sample_dv_actions = ctx_resource->sub_actions;
11004         struct mlx5_flow_dv_sample_resource *resource;
11005         struct mlx5dv_dr_flow_sampler_attr sampler_attr;
11006         struct mlx5_priv *priv = dev->data->dev_private;
11007         struct mlx5_dev_ctx_shared *sh = priv->sh;
11008         struct mlx5_flow_tbl_resource *tbl;
11009         uint32_t idx = 0;
11010         const uint32_t next_ft_step = 1;
11011         uint32_t next_ft_id = ctx_resource->ft_id + next_ft_step;
11012         uint8_t is_egress = 0;
11013         uint8_t is_transfer = 0;
11014         struct rte_flow_error *error = ctx->error;
11015
11016         /* Register new sample resource. */
11017         resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_SAMPLE], &idx);
11018         if (!resource) {
11019                 rte_flow_error_set(error, ENOMEM,
11020                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
11021                                           NULL,
11022                                           "cannot allocate resource memory");
11023                 return NULL;
11024         }
11025         *resource = *ctx_resource;
11026         /* Create normal path table level */
11027         if (ctx_resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB)
11028                 is_transfer = 1;
11029         else if (ctx_resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_NIC_TX)
11030                 is_egress = 1;
11031         tbl = flow_dv_tbl_resource_get(dev, next_ft_id,
11032                                         is_egress, is_transfer,
11033                                         true, NULL, 0, 0, 0, error);
11034         if (!tbl) {
11035                 rte_flow_error_set(error, ENOMEM,
11036                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
11037                                           NULL,
11038                                           "fail to create normal path table "
11039                                           "for sample");
11040                 goto error;
11041         }
11042         resource->normal_path_tbl = tbl;
11043         if (ctx_resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB) {
11044                 if (!sh->default_miss_action) {
11045                         rte_flow_error_set(error, ENOMEM,
11046                                                 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
11047                                                 NULL,
11048                                                 "default miss action was not "
11049                                                 "created");
11050                         goto error;
11051                 }
11052                 sample_dv_actions[ctx_resource->sample_act.actions_num++] =
11053                                                 sh->default_miss_action;
11054         }
11055         /* Create a DR sample action */
11056         sampler_attr.sample_ratio = resource->ratio;
11057         sampler_attr.default_next_table = tbl->obj;
11058         sampler_attr.num_sample_actions = ctx_resource->sample_act.actions_num;
11059         sampler_attr.sample_actions = (struct mlx5dv_dr_action **)
11060                                                         &sample_dv_actions[0];
11061         sampler_attr.action = resource->set_action;
11062         if (mlx5_os_flow_dr_create_flow_action_sampler
11063                         (&sampler_attr, &resource->verbs_action)) {
11064                 rte_flow_error_set(error, ENOMEM,
11065                                         RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
11066                                         NULL, "cannot create sample action");
11067                 goto error;
11068         }
11069         resource->idx = idx;
11070         resource->dev = dev;
11071         return &resource->entry;
11072 error:
11073         if (resource->ft_type != MLX5DV_FLOW_TABLE_TYPE_FDB)
11074                 flow_dv_sample_sub_actions_release(dev,
11075                                                    &resource->sample_idx);
11076         if (resource->normal_path_tbl)
11077                 flow_dv_tbl_resource_release(MLX5_SH(dev),
11078                                 resource->normal_path_tbl);
11079         mlx5_ipool_free(sh->ipool[MLX5_IPOOL_SAMPLE], idx);
11080         return NULL;
11081
11082 }
11083
11084 struct mlx5_list_entry *
11085 flow_dv_sample_clone_cb(void *tool_ctx __rte_unused,
11086                          struct mlx5_list_entry *entry __rte_unused,
11087                          void *cb_ctx)
11088 {
11089         struct mlx5_flow_cb_ctx *ctx = cb_ctx;
11090         struct rte_eth_dev *dev = ctx->dev;
11091         struct mlx5_flow_dv_sample_resource *resource;
11092         struct mlx5_priv *priv = dev->data->dev_private;
11093         struct mlx5_dev_ctx_shared *sh = priv->sh;
11094         uint32_t idx = 0;
11095
11096         resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_SAMPLE], &idx);
11097         if (!resource) {
11098                 rte_flow_error_set(ctx->error, ENOMEM,
11099                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
11100                                           NULL,
11101                                           "cannot allocate resource memory");
11102                 return NULL;
11103         }
11104         memcpy(resource, entry, sizeof(*resource));
11105         resource->idx = idx;
11106         resource->dev = dev;
11107         return &resource->entry;
11108 }
11109
11110 void
11111 flow_dv_sample_clone_free_cb(void *tool_ctx __rte_unused,
11112                              struct mlx5_list_entry *entry)
11113 {
11114         struct mlx5_flow_dv_sample_resource *resource =
11115                                   container_of(entry, typeof(*resource), entry);
11116         struct rte_eth_dev *dev = resource->dev;
11117         struct mlx5_priv *priv = dev->data->dev_private;
11118
11119         mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_SAMPLE], resource->idx);
11120 }
11121
11122 /**
11123  * Find existing sample resource or create and register a new one.
11124  *
11125  * @param[in, out] dev
11126  *   Pointer to rte_eth_dev structure.
11127  * @param[in] ref
11128  *   Pointer to sample resource reference.
11129  * @parm[in, out] dev_flow
11130  *   Pointer to the dev_flow.
11131  * @param[out] error
11132  *   pointer to error structure.
11133  *
11134  * @return
11135  *   0 on success otherwise -errno and errno is set.
11136  */
11137 static int
11138 flow_dv_sample_resource_register(struct rte_eth_dev *dev,
11139                          struct mlx5_flow_dv_sample_resource *ref,
11140                          struct mlx5_flow *dev_flow,
11141                          struct rte_flow_error *error)
11142 {
11143         struct mlx5_flow_dv_sample_resource *resource;
11144         struct mlx5_list_entry *entry;
11145         struct mlx5_priv *priv = dev->data->dev_private;
11146         struct mlx5_flow_cb_ctx ctx = {
11147                 .dev = dev,
11148                 .error = error,
11149                 .data = ref,
11150         };
11151
11152         entry = mlx5_list_register(priv->sh->sample_action_list, &ctx);
11153         if (!entry)
11154                 return -rte_errno;
11155         resource = container_of(entry, typeof(*resource), entry);
11156         dev_flow->handle->dvh.rix_sample = resource->idx;
11157         dev_flow->dv.sample_res = resource;
11158         return 0;
11159 }
11160
11161 int
11162 flow_dv_dest_array_match_cb(void *tool_ctx __rte_unused,
11163                             struct mlx5_list_entry *entry, void *cb_ctx)
11164 {
11165         struct mlx5_flow_cb_ctx *ctx = cb_ctx;
11166         struct mlx5_flow_dv_dest_array_resource *ctx_resource = ctx->data;
11167         struct rte_eth_dev *dev = ctx->dev;
11168         struct mlx5_flow_dv_dest_array_resource *resource =
11169                                   container_of(entry, typeof(*resource), entry);
11170         uint32_t idx = 0;
11171
11172         if (ctx_resource->num_of_dest == resource->num_of_dest &&
11173             ctx_resource->ft_type == resource->ft_type &&
11174             !memcmp((void *)resource->sample_act,
11175                     (void *)ctx_resource->sample_act,
11176                    (ctx_resource->num_of_dest *
11177                    sizeof(struct mlx5_flow_sub_actions_list)))) {
11178                 /*
11179                  * Existing sample action should release the prepared
11180                  * sub-actions reference counter.
11181                  */
11182                 for (idx = 0; idx < ctx_resource->num_of_dest; idx++)
11183                         flow_dv_sample_sub_actions_release(dev,
11184                                         &ctx_resource->sample_idx[idx]);
11185                 return 0;
11186         }
11187         return 1;
11188 }
11189
11190 struct mlx5_list_entry *
11191 flow_dv_dest_array_create_cb(void *tool_ctx __rte_unused, void *cb_ctx)
11192 {
11193         struct mlx5_flow_cb_ctx *ctx = cb_ctx;
11194         struct rte_eth_dev *dev = ctx->dev;
11195         struct mlx5_flow_dv_dest_array_resource *resource;
11196         struct mlx5_flow_dv_dest_array_resource *ctx_resource = ctx->data;
11197         struct mlx5dv_dr_action_dest_attr *dest_attr[MLX5_MAX_DEST_NUM] = { 0 };
11198         struct mlx5dv_dr_action_dest_reformat dest_reformat[MLX5_MAX_DEST_NUM];
11199         struct mlx5_priv *priv = dev->data->dev_private;
11200         struct mlx5_dev_ctx_shared *sh = priv->sh;
11201         struct mlx5_flow_sub_actions_list *sample_act;
11202         struct mlx5dv_dr_domain *domain;
11203         uint32_t idx = 0, res_idx = 0;
11204         struct rte_flow_error *error = ctx->error;
11205         uint64_t action_flags;
11206         int ret;
11207
11208         /* Register new destination array resource. */
11209         resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_DEST_ARRAY],
11210                                             &res_idx);
11211         if (!resource) {
11212                 rte_flow_error_set(error, ENOMEM,
11213                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
11214                                           NULL,
11215                                           "cannot allocate resource memory");
11216                 return NULL;
11217         }
11218         *resource = *ctx_resource;
11219         if (resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB)
11220                 domain = sh->fdb_domain;
11221         else if (resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_NIC_RX)
11222                 domain = sh->rx_domain;
11223         else
11224                 domain = sh->tx_domain;
11225         for (idx = 0; idx < ctx_resource->num_of_dest; idx++) {
11226                 dest_attr[idx] = (struct mlx5dv_dr_action_dest_attr *)
11227                                  mlx5_malloc(MLX5_MEM_ZERO,
11228                                  sizeof(struct mlx5dv_dr_action_dest_attr),
11229                                  0, SOCKET_ID_ANY);
11230                 if (!dest_attr[idx]) {
11231                         rte_flow_error_set(error, ENOMEM,
11232                                            RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
11233                                            NULL,
11234                                            "cannot allocate resource memory");
11235                         goto error;
11236                 }
11237                 dest_attr[idx]->type = MLX5DV_DR_ACTION_DEST;
11238                 sample_act = &ctx_resource->sample_act[idx];
11239                 action_flags = sample_act->action_flags;
11240                 switch (action_flags) {
11241                 case MLX5_FLOW_ACTION_QUEUE:
11242                         dest_attr[idx]->dest = sample_act->dr_queue_action;
11243                         break;
11244                 case (MLX5_FLOW_ACTION_PORT_ID | MLX5_FLOW_ACTION_ENCAP):
11245                         dest_attr[idx]->type = MLX5DV_DR_ACTION_DEST_REFORMAT;
11246                         dest_attr[idx]->dest_reformat = &dest_reformat[idx];
11247                         dest_attr[idx]->dest_reformat->reformat =
11248                                         sample_act->dr_encap_action;
11249                         dest_attr[idx]->dest_reformat->dest =
11250                                         sample_act->dr_port_id_action;
11251                         break;
11252                 case MLX5_FLOW_ACTION_PORT_ID:
11253                         dest_attr[idx]->dest = sample_act->dr_port_id_action;
11254                         break;
11255                 case MLX5_FLOW_ACTION_JUMP:
11256                         dest_attr[idx]->dest = sample_act->dr_jump_action;
11257                         break;
11258                 default:
11259                         rte_flow_error_set(error, EINVAL,
11260                                            RTE_FLOW_ERROR_TYPE_ACTION,
11261                                            NULL,
11262                                            "unsupported actions type");
11263                         goto error;
11264                 }
11265         }
11266         /* create a dest array actioin */
11267         ret = mlx5_os_flow_dr_create_flow_action_dest_array
11268                                                 (domain,
11269                                                  resource->num_of_dest,
11270                                                  dest_attr,
11271                                                  &resource->action);
11272         if (ret) {
11273                 rte_flow_error_set(error, ENOMEM,
11274                                    RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
11275                                    NULL,
11276                                    "cannot create destination array action");
11277                 goto error;
11278         }
11279         resource->idx = res_idx;
11280         resource->dev = dev;
11281         for (idx = 0; idx < ctx_resource->num_of_dest; idx++)
11282                 mlx5_free(dest_attr[idx]);
11283         return &resource->entry;
11284 error:
11285         for (idx = 0; idx < ctx_resource->num_of_dest; idx++) {
11286                 flow_dv_sample_sub_actions_release(dev,
11287                                                    &resource->sample_idx[idx]);
11288                 if (dest_attr[idx])
11289                         mlx5_free(dest_attr[idx]);
11290         }
11291         mlx5_ipool_free(sh->ipool[MLX5_IPOOL_DEST_ARRAY], res_idx);
11292         return NULL;
11293 }
11294
11295 struct mlx5_list_entry *
11296 flow_dv_dest_array_clone_cb(void *tool_ctx __rte_unused,
11297                             struct mlx5_list_entry *entry __rte_unused,
11298                             void *cb_ctx)
11299 {
11300         struct mlx5_flow_cb_ctx *ctx = cb_ctx;
11301         struct rte_eth_dev *dev = ctx->dev;
11302         struct mlx5_flow_dv_dest_array_resource *resource;
11303         struct mlx5_priv *priv = dev->data->dev_private;
11304         struct mlx5_dev_ctx_shared *sh = priv->sh;
11305         uint32_t res_idx = 0;
11306         struct rte_flow_error *error = ctx->error;
11307
11308         resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_DEST_ARRAY],
11309                                       &res_idx);
11310         if (!resource) {
11311                 rte_flow_error_set(error, ENOMEM,
11312                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
11313                                           NULL,
11314                                           "cannot allocate dest-array memory");
11315                 return NULL;
11316         }
11317         memcpy(resource, entry, sizeof(*resource));
11318         resource->idx = res_idx;
11319         resource->dev = dev;
11320         return &resource->entry;
11321 }
11322
11323 void
11324 flow_dv_dest_array_clone_free_cb(void *tool_ctx __rte_unused,
11325                                  struct mlx5_list_entry *entry)
11326 {
11327         struct mlx5_flow_dv_dest_array_resource *resource =
11328                         container_of(entry, typeof(*resource), entry);
11329         struct rte_eth_dev *dev = resource->dev;
11330         struct mlx5_priv *priv = dev->data->dev_private;
11331
11332         mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_DEST_ARRAY], resource->idx);
11333 }
11334
11335 /**
11336  * Find existing destination array resource or create and register a new one.
11337  *
11338  * @param[in, out] dev
11339  *   Pointer to rte_eth_dev structure.
11340  * @param[in] ref
11341  *   Pointer to destination array resource reference.
11342  * @parm[in, out] dev_flow
11343  *   Pointer to the dev_flow.
11344  * @param[out] error
11345  *   pointer to error structure.
11346  *
11347  * @return
11348  *   0 on success otherwise -errno and errno is set.
11349  */
11350 static int
11351 flow_dv_dest_array_resource_register(struct rte_eth_dev *dev,
11352                          struct mlx5_flow_dv_dest_array_resource *ref,
11353                          struct mlx5_flow *dev_flow,
11354                          struct rte_flow_error *error)
11355 {
11356         struct mlx5_flow_dv_dest_array_resource *resource;
11357         struct mlx5_priv *priv = dev->data->dev_private;
11358         struct mlx5_list_entry *entry;
11359         struct mlx5_flow_cb_ctx ctx = {
11360                 .dev = dev,
11361                 .error = error,
11362                 .data = ref,
11363         };
11364
11365         entry = mlx5_list_register(priv->sh->dest_array_list, &ctx);
11366         if (!entry)
11367                 return -rte_errno;
11368         resource = container_of(entry, typeof(*resource), entry);
11369         dev_flow->handle->dvh.rix_dest_array = resource->idx;
11370         dev_flow->dv.dest_array_res = resource;
11371         return 0;
11372 }
11373
11374 /**
11375  * Convert Sample action to DV specification.
11376  *
11377  * @param[in] dev
11378  *   Pointer to rte_eth_dev structure.
11379  * @param[in] action
11380  *   Pointer to sample action structure.
11381  * @param[in, out] dev_flow
11382  *   Pointer to the mlx5_flow.
11383  * @param[in] attr
11384  *   Pointer to the flow attributes.
11385  * @param[in, out] num_of_dest
11386  *   Pointer to the num of destination.
11387  * @param[in, out] sample_actions
11388  *   Pointer to sample actions list.
11389  * @param[in, out] res
11390  *   Pointer to sample resource.
11391  * @param[out] error
11392  *   Pointer to the error structure.
11393  *
11394  * @return
11395  *   0 on success, a negative errno value otherwise and rte_errno is set.
11396  */
11397 static int
11398 flow_dv_translate_action_sample(struct rte_eth_dev *dev,
11399                                 const struct rte_flow_action_sample *action,
11400                                 struct mlx5_flow *dev_flow,
11401                                 const struct rte_flow_attr *attr,
11402                                 uint32_t *num_of_dest,
11403                                 void **sample_actions,
11404                                 struct mlx5_flow_dv_sample_resource *res,
11405                                 struct rte_flow_error *error)
11406 {
11407         struct mlx5_priv *priv = dev->data->dev_private;
11408         const struct rte_flow_action *sub_actions;
11409         struct mlx5_flow_sub_actions_list *sample_act;
11410         struct mlx5_flow_sub_actions_idx *sample_idx;
11411         struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace();
11412         struct rte_flow *flow = dev_flow->flow;
11413         struct mlx5_flow_rss_desc *rss_desc;
11414         uint64_t action_flags = 0;
11415
11416         MLX5_ASSERT(wks);
11417         rss_desc = &wks->rss_desc;
11418         sample_act = &res->sample_act;
11419         sample_idx = &res->sample_idx;
11420         res->ratio = action->ratio;
11421         sub_actions = action->actions;
11422         for (; sub_actions->type != RTE_FLOW_ACTION_TYPE_END; sub_actions++) {
11423                 int type = sub_actions->type;
11424                 uint32_t pre_rix = 0;
11425                 void *pre_r;
11426                 switch (type) {
11427                 case RTE_FLOW_ACTION_TYPE_QUEUE:
11428                 {
11429                         const struct rte_flow_action_queue *queue;
11430                         struct mlx5_hrxq *hrxq;
11431                         uint32_t hrxq_idx;
11432
11433                         queue = sub_actions->conf;
11434                         rss_desc->queue_num = 1;
11435                         rss_desc->queue[0] = queue->index;
11436                         hrxq = flow_dv_hrxq_prepare(dev, dev_flow,
11437                                                     rss_desc, &hrxq_idx);
11438                         if (!hrxq)
11439                                 return rte_flow_error_set
11440                                         (error, rte_errno,
11441                                          RTE_FLOW_ERROR_TYPE_ACTION,
11442                                          NULL,
11443                                          "cannot create fate queue");
11444                         sample_act->dr_queue_action = hrxq->action;
11445                         sample_idx->rix_hrxq = hrxq_idx;
11446                         sample_actions[sample_act->actions_num++] =
11447                                                 hrxq->action;
11448                         (*num_of_dest)++;
11449                         action_flags |= MLX5_FLOW_ACTION_QUEUE;
11450                         if (action_flags & MLX5_FLOW_ACTION_MARK)
11451                                 dev_flow->handle->rix_hrxq = hrxq_idx;
11452                         dev_flow->handle->fate_action =
11453                                         MLX5_FLOW_FATE_QUEUE;
11454                         break;
11455                 }
11456                 case RTE_FLOW_ACTION_TYPE_RSS:
11457                 {
11458                         struct mlx5_hrxq *hrxq;
11459                         uint32_t hrxq_idx;
11460                         const struct rte_flow_action_rss *rss;
11461                         const uint8_t *rss_key;
11462
11463                         rss = sub_actions->conf;
11464                         memcpy(rss_desc->queue, rss->queue,
11465                                rss->queue_num * sizeof(uint16_t));
11466                         rss_desc->queue_num = rss->queue_num;
11467                         /* NULL RSS key indicates default RSS key. */
11468                         rss_key = !rss->key ? rss_hash_default_key : rss->key;
11469                         memcpy(rss_desc->key, rss_key, MLX5_RSS_HASH_KEY_LEN);
11470                         /*
11471                          * rss->level and rss.types should be set in advance
11472                          * when expanding items for RSS.
11473                          */
11474                         flow_dv_hashfields_set(dev_flow, rss_desc);
11475                         hrxq = flow_dv_hrxq_prepare(dev, dev_flow,
11476                                                     rss_desc, &hrxq_idx);
11477                         if (!hrxq)
11478                                 return rte_flow_error_set
11479                                         (error, rte_errno,
11480                                          RTE_FLOW_ERROR_TYPE_ACTION,
11481                                          NULL,
11482                                          "cannot create fate queue");
11483                         sample_act->dr_queue_action = hrxq->action;
11484                         sample_idx->rix_hrxq = hrxq_idx;
11485                         sample_actions[sample_act->actions_num++] =
11486                                                 hrxq->action;
11487                         (*num_of_dest)++;
11488                         action_flags |= MLX5_FLOW_ACTION_RSS;
11489                         if (action_flags & MLX5_FLOW_ACTION_MARK)
11490                                 dev_flow->handle->rix_hrxq = hrxq_idx;
11491                         dev_flow->handle->fate_action =
11492                                         MLX5_FLOW_FATE_QUEUE;
11493                         break;
11494                 }
11495                 case RTE_FLOW_ACTION_TYPE_MARK:
11496                 {
11497                         uint32_t tag_be = mlx5_flow_mark_set
11498                                 (((const struct rte_flow_action_mark *)
11499                                 (sub_actions->conf))->id);
11500
11501                         dev_flow->handle->mark = 1;
11502                         pre_rix = dev_flow->handle->dvh.rix_tag;
11503                         /* Save the mark resource before sample */
11504                         pre_r = dev_flow->dv.tag_resource;
11505                         if (flow_dv_tag_resource_register(dev, tag_be,
11506                                                   dev_flow, error))
11507                                 return -rte_errno;
11508                         MLX5_ASSERT(dev_flow->dv.tag_resource);
11509                         sample_act->dr_tag_action =
11510                                 dev_flow->dv.tag_resource->action;
11511                         sample_idx->rix_tag =
11512                                 dev_flow->handle->dvh.rix_tag;
11513                         sample_actions[sample_act->actions_num++] =
11514                                                 sample_act->dr_tag_action;
11515                         /* Recover the mark resource after sample */
11516                         dev_flow->dv.tag_resource = pre_r;
11517                         dev_flow->handle->dvh.rix_tag = pre_rix;
11518                         action_flags |= MLX5_FLOW_ACTION_MARK;
11519                         break;
11520                 }
11521                 case RTE_FLOW_ACTION_TYPE_COUNT:
11522                 {
11523                         if (!flow->counter) {
11524                                 flow->counter =
11525                                         flow_dv_translate_create_counter(dev,
11526                                                 dev_flow, sub_actions->conf,
11527                                                 0);
11528                                 if (!flow->counter)
11529                                         return rte_flow_error_set
11530                                                 (error, rte_errno,
11531                                                 RTE_FLOW_ERROR_TYPE_ACTION,
11532                                                 NULL,
11533                                                 "cannot create counter"
11534                                                 " object.");
11535                         }
11536                         sample_act->dr_cnt_action =
11537                                   (flow_dv_counter_get_by_idx(dev,
11538                                   flow->counter, NULL))->action;
11539                         sample_actions[sample_act->actions_num++] =
11540                                                 sample_act->dr_cnt_action;
11541                         action_flags |= MLX5_FLOW_ACTION_COUNT;
11542                         break;
11543                 }
11544                 case RTE_FLOW_ACTION_TYPE_PORT_ID:
11545                 case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT:
11546                 {
11547                         struct mlx5_flow_dv_port_id_action_resource
11548                                         port_id_resource;
11549                         uint32_t port_id = 0;
11550
11551                         memset(&port_id_resource, 0, sizeof(port_id_resource));
11552                         /* Save the port id resource before sample */
11553                         pre_rix = dev_flow->handle->rix_port_id_action;
11554                         pre_r = dev_flow->dv.port_id_action;
11555                         if (flow_dv_translate_action_port_id(dev, sub_actions,
11556                                                              &port_id, error))
11557                                 return -rte_errno;
11558                         port_id_resource.port_id = port_id;
11559                         if (flow_dv_port_id_action_resource_register
11560                             (dev, &port_id_resource, dev_flow, error))
11561                                 return -rte_errno;
11562                         sample_act->dr_port_id_action =
11563                                 dev_flow->dv.port_id_action->action;
11564                         sample_idx->rix_port_id_action =
11565                                 dev_flow->handle->rix_port_id_action;
11566                         sample_actions[sample_act->actions_num++] =
11567                                                 sample_act->dr_port_id_action;
11568                         /* Recover the port id resource after sample */
11569                         dev_flow->dv.port_id_action = pre_r;
11570                         dev_flow->handle->rix_port_id_action = pre_rix;
11571                         (*num_of_dest)++;
11572                         action_flags |= MLX5_FLOW_ACTION_PORT_ID;
11573                         break;
11574                 }
11575                 case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP:
11576                 case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP:
11577                 case RTE_FLOW_ACTION_TYPE_RAW_ENCAP:
11578                         /* Save the encap resource before sample */
11579                         pre_rix = dev_flow->handle->dvh.rix_encap_decap;
11580                         pre_r = dev_flow->dv.encap_decap;
11581                         if (flow_dv_create_action_l2_encap(dev, sub_actions,
11582                                                            dev_flow,
11583                                                            attr->transfer,
11584                                                            error))
11585                                 return -rte_errno;
11586                         sample_act->dr_encap_action =
11587                                 dev_flow->dv.encap_decap->action;
11588                         sample_idx->rix_encap_decap =
11589                                 dev_flow->handle->dvh.rix_encap_decap;
11590                         sample_actions[sample_act->actions_num++] =
11591                                                 sample_act->dr_encap_action;
11592                         /* Recover the encap resource after sample */
11593                         dev_flow->dv.encap_decap = pre_r;
11594                         dev_flow->handle->dvh.rix_encap_decap = pre_rix;
11595                         action_flags |= MLX5_FLOW_ACTION_ENCAP;
11596                         break;
11597                 default:
11598                         return rte_flow_error_set(error, EINVAL,
11599                                 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
11600                                 NULL,
11601                                 "Not support for sampler action");
11602                 }
11603         }
11604         sample_act->action_flags = action_flags;
11605         res->ft_id = dev_flow->dv.group;
11606         if (attr->transfer) {
11607                 union {
11608                         uint32_t action_in[MLX5_ST_SZ_DW(set_action_in)];
11609                         uint64_t set_action;
11610                 } action_ctx = { .set_action = 0 };
11611
11612                 res->ft_type = MLX5DV_FLOW_TABLE_TYPE_FDB;
11613                 MLX5_SET(set_action_in, action_ctx.action_in, action_type,
11614                          MLX5_MODIFICATION_TYPE_SET);
11615                 MLX5_SET(set_action_in, action_ctx.action_in, field,
11616                          MLX5_MODI_META_REG_C_0);
11617                 MLX5_SET(set_action_in, action_ctx.action_in, data,
11618                          priv->vport_meta_tag);
11619                 res->set_action = action_ctx.set_action;
11620         } else if (attr->ingress) {
11621                 res->ft_type = MLX5DV_FLOW_TABLE_TYPE_NIC_RX;
11622         } else {
11623                 res->ft_type = MLX5DV_FLOW_TABLE_TYPE_NIC_TX;
11624         }
11625         return 0;
11626 }
11627
11628 /**
11629  * Convert Sample action to DV specification.
11630  *
11631  * @param[in] dev
11632  *   Pointer to rte_eth_dev structure.
11633  * @param[in, out] dev_flow
11634  *   Pointer to the mlx5_flow.
11635  * @param[in] num_of_dest
11636  *   The num of destination.
11637  * @param[in, out] res
11638  *   Pointer to sample resource.
11639  * @param[in, out] mdest_res
11640  *   Pointer to destination array resource.
11641  * @param[in] sample_actions
11642  *   Pointer to sample path actions list.
11643  * @param[in] action_flags
11644  *   Holds the actions detected until now.
11645  * @param[out] error
11646  *   Pointer to the error structure.
11647  *
11648  * @return
11649  *   0 on success, a negative errno value otherwise and rte_errno is set.
11650  */
11651 static int
11652 flow_dv_create_action_sample(struct rte_eth_dev *dev,
11653                              struct mlx5_flow *dev_flow,
11654                              uint32_t num_of_dest,
11655                              struct mlx5_flow_dv_sample_resource *res,
11656                              struct mlx5_flow_dv_dest_array_resource *mdest_res,
11657                              void **sample_actions,
11658                              uint64_t action_flags,
11659                              struct rte_flow_error *error)
11660 {
11661         /* update normal path action resource into last index of array */
11662         uint32_t dest_index = MLX5_MAX_DEST_NUM - 1;
11663         struct mlx5_flow_sub_actions_list *sample_act =
11664                                         &mdest_res->sample_act[dest_index];
11665         struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace();
11666         struct mlx5_flow_rss_desc *rss_desc;
11667         uint32_t normal_idx = 0;
11668         struct mlx5_hrxq *hrxq;
11669         uint32_t hrxq_idx;
11670
11671         MLX5_ASSERT(wks);
11672         rss_desc = &wks->rss_desc;
11673         if (num_of_dest > 1) {
11674                 if (sample_act->action_flags & MLX5_FLOW_ACTION_QUEUE) {
11675                         /* Handle QP action for mirroring */
11676                         hrxq = flow_dv_hrxq_prepare(dev, dev_flow,
11677                                                     rss_desc, &hrxq_idx);
11678                         if (!hrxq)
11679                                 return rte_flow_error_set
11680                                      (error, rte_errno,
11681                                       RTE_FLOW_ERROR_TYPE_ACTION,
11682                                       NULL,
11683                                       "cannot create rx queue");
11684                         normal_idx++;
11685                         mdest_res->sample_idx[dest_index].rix_hrxq = hrxq_idx;
11686                         sample_act->dr_queue_action = hrxq->action;
11687                         if (action_flags & MLX5_FLOW_ACTION_MARK)
11688                                 dev_flow->handle->rix_hrxq = hrxq_idx;
11689                         dev_flow->handle->fate_action = MLX5_FLOW_FATE_QUEUE;
11690                 }
11691                 if (sample_act->action_flags & MLX5_FLOW_ACTION_ENCAP) {
11692                         normal_idx++;
11693                         mdest_res->sample_idx[dest_index].rix_encap_decap =
11694                                 dev_flow->handle->dvh.rix_encap_decap;
11695                         sample_act->dr_encap_action =
11696                                 dev_flow->dv.encap_decap->action;
11697                         dev_flow->handle->dvh.rix_encap_decap = 0;
11698                 }
11699                 if (sample_act->action_flags & MLX5_FLOW_ACTION_PORT_ID) {
11700                         normal_idx++;
11701                         mdest_res->sample_idx[dest_index].rix_port_id_action =
11702                                 dev_flow->handle->rix_port_id_action;
11703                         sample_act->dr_port_id_action =
11704                                 dev_flow->dv.port_id_action->action;
11705                         dev_flow->handle->rix_port_id_action = 0;
11706                 }
11707                 if (sample_act->action_flags & MLX5_FLOW_ACTION_JUMP) {
11708                         normal_idx++;
11709                         mdest_res->sample_idx[dest_index].rix_jump =
11710                                 dev_flow->handle->rix_jump;
11711                         sample_act->dr_jump_action =
11712                                 dev_flow->dv.jump->action;
11713                         dev_flow->handle->rix_jump = 0;
11714                 }
11715                 sample_act->actions_num = normal_idx;
11716                 /* update sample action resource into first index of array */
11717                 mdest_res->ft_type = res->ft_type;
11718                 memcpy(&mdest_res->sample_idx[0], &res->sample_idx,
11719                                 sizeof(struct mlx5_flow_sub_actions_idx));
11720                 memcpy(&mdest_res->sample_act[0], &res->sample_act,
11721                                 sizeof(struct mlx5_flow_sub_actions_list));
11722                 mdest_res->num_of_dest = num_of_dest;
11723                 if (flow_dv_dest_array_resource_register(dev, mdest_res,
11724                                                          dev_flow, error))
11725                         return rte_flow_error_set(error, EINVAL,
11726                                                   RTE_FLOW_ERROR_TYPE_ACTION,
11727                                                   NULL, "can't create sample "
11728                                                   "action");
11729         } else {
11730                 res->sub_actions = sample_actions;
11731                 if (flow_dv_sample_resource_register(dev, res, dev_flow, error))
11732                         return rte_flow_error_set(error, EINVAL,
11733                                                   RTE_FLOW_ERROR_TYPE_ACTION,
11734                                                   NULL,
11735                                                   "can't create sample action");
11736         }
11737         return 0;
11738 }
11739
11740 /**
11741  * Remove an ASO age action from age actions list.
11742  *
11743  * @param[in] dev
11744  *   Pointer to the Ethernet device structure.
11745  * @param[in] age
11746  *   Pointer to the aso age action handler.
11747  */
11748 static void
11749 flow_dv_aso_age_remove_from_age(struct rte_eth_dev *dev,
11750                                 struct mlx5_aso_age_action *age)
11751 {
11752         struct mlx5_age_info *age_info;
11753         struct mlx5_age_param *age_param = &age->age_params;
11754         struct mlx5_priv *priv = dev->data->dev_private;
11755         uint16_t expected = AGE_CANDIDATE;
11756
11757         age_info = GET_PORT_AGE_INFO(priv);
11758         if (!__atomic_compare_exchange_n(&age_param->state, &expected,
11759                                          AGE_FREE, false, __ATOMIC_RELAXED,
11760                                          __ATOMIC_RELAXED)) {
11761                 /**
11762                  * We need the lock even it is age timeout,
11763                  * since age action may still in process.
11764                  */
11765                 rte_spinlock_lock(&age_info->aged_sl);
11766                 LIST_REMOVE(age, next);
11767                 rte_spinlock_unlock(&age_info->aged_sl);
11768                 __atomic_store_n(&age_param->state, AGE_FREE, __ATOMIC_RELAXED);
11769         }
11770 }
11771
11772 /**
11773  * Release an ASO age action.
11774  *
11775  * @param[in] dev
11776  *   Pointer to the Ethernet device structure.
11777  * @param[in] age_idx
11778  *   Index of ASO age action to release.
11779  * @param[in] flow
11780  *   True if the release operation is during flow destroy operation.
11781  *   False if the release operation is during action destroy operation.
11782  *
11783  * @return
11784  *   0 when age action was removed, otherwise the number of references.
11785  */
11786 static int
11787 flow_dv_aso_age_release(struct rte_eth_dev *dev, uint32_t age_idx)
11788 {
11789         struct mlx5_priv *priv = dev->data->dev_private;
11790         struct mlx5_aso_age_mng *mng = priv->sh->aso_age_mng;
11791         struct mlx5_aso_age_action *age = flow_aso_age_get_by_idx(dev, age_idx);
11792         uint32_t ret = __atomic_sub_fetch(&age->refcnt, 1, __ATOMIC_RELAXED);
11793
11794         if (!ret) {
11795                 flow_dv_aso_age_remove_from_age(dev, age);
11796                 rte_spinlock_lock(&mng->free_sl);
11797                 LIST_INSERT_HEAD(&mng->free, age, next);
11798                 rte_spinlock_unlock(&mng->free_sl);
11799         }
11800         return ret;
11801 }
11802
11803 /**
11804  * Resize the ASO age pools array by MLX5_CNT_CONTAINER_RESIZE pools.
11805  *
11806  * @param[in] dev
11807  *   Pointer to the Ethernet device structure.
11808  *
11809  * @return
11810  *   0 on success, otherwise negative errno value and rte_errno is set.
11811  */
11812 static int
11813 flow_dv_aso_age_pools_resize(struct rte_eth_dev *dev)
11814 {
11815         struct mlx5_priv *priv = dev->data->dev_private;
11816         struct mlx5_aso_age_mng *mng = priv->sh->aso_age_mng;
11817         void *old_pools = mng->pools;
11818         uint32_t resize = mng->n + MLX5_CNT_CONTAINER_RESIZE;
11819         uint32_t mem_size = sizeof(struct mlx5_aso_age_pool *) * resize;
11820         void *pools = mlx5_malloc(MLX5_MEM_ZERO, mem_size, 0, SOCKET_ID_ANY);
11821
11822         if (!pools) {
11823                 rte_errno = ENOMEM;
11824                 return -ENOMEM;
11825         }
11826         if (old_pools) {
11827                 memcpy(pools, old_pools,
11828                        mng->n * sizeof(struct mlx5_flow_counter_pool *));
11829                 mlx5_free(old_pools);
11830         } else {
11831                 /* First ASO flow hit allocation - starting ASO data-path. */
11832                 int ret = mlx5_aso_flow_hit_queue_poll_start(priv->sh);
11833
11834                 if (ret) {
11835                         mlx5_free(pools);
11836                         return ret;
11837                 }
11838         }
11839         mng->n = resize;
11840         mng->pools = pools;
11841         return 0;
11842 }
11843
11844 /**
11845  * Create and initialize a new ASO aging pool.
11846  *
11847  * @param[in] dev
11848  *   Pointer to the Ethernet device structure.
11849  * @param[out] age_free
11850  *   Where to put the pointer of a new age action.
11851  *
11852  * @return
11853  *   The age actions pool pointer and @p age_free is set on success,
11854  *   NULL otherwise and rte_errno is set.
11855  */
11856 static struct mlx5_aso_age_pool *
11857 flow_dv_age_pool_create(struct rte_eth_dev *dev,
11858                         struct mlx5_aso_age_action **age_free)
11859 {
11860         struct mlx5_priv *priv = dev->data->dev_private;
11861         struct mlx5_aso_age_mng *mng = priv->sh->aso_age_mng;
11862         struct mlx5_aso_age_pool *pool = NULL;
11863         struct mlx5_devx_obj *obj = NULL;
11864         uint32_t i;
11865
11866         obj = mlx5_devx_cmd_create_flow_hit_aso_obj(priv->sh->cdev->ctx,
11867                                                     priv->sh->cdev->pdn);
11868         if (!obj) {
11869                 rte_errno = ENODATA;
11870                 DRV_LOG(ERR, "Failed to create flow_hit_aso_obj using DevX.");
11871                 return NULL;
11872         }
11873         pool = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*pool), 0, SOCKET_ID_ANY);
11874         if (!pool) {
11875                 claim_zero(mlx5_devx_cmd_destroy(obj));
11876                 rte_errno = ENOMEM;
11877                 return NULL;
11878         }
11879         pool->flow_hit_aso_obj = obj;
11880         pool->time_of_last_age_check = MLX5_CURR_TIME_SEC;
11881         rte_spinlock_lock(&mng->resize_sl);
11882         pool->index = mng->next;
11883         /* Resize pools array if there is no room for the new pool in it. */
11884         if (pool->index == mng->n && flow_dv_aso_age_pools_resize(dev)) {
11885                 claim_zero(mlx5_devx_cmd_destroy(obj));
11886                 mlx5_free(pool);
11887                 rte_spinlock_unlock(&mng->resize_sl);
11888                 return NULL;
11889         }
11890         mng->pools[pool->index] = pool;
11891         mng->next++;
11892         rte_spinlock_unlock(&mng->resize_sl);
11893         /* Assign the first action in the new pool, the rest go to free list. */
11894         *age_free = &pool->actions[0];
11895         for (i = 1; i < MLX5_ASO_AGE_ACTIONS_PER_POOL; i++) {
11896                 pool->actions[i].offset = i;
11897                 LIST_INSERT_HEAD(&mng->free, &pool->actions[i], next);
11898         }
11899         return pool;
11900 }
11901
11902 /**
11903  * Allocate a ASO aging bit.
11904  *
11905  * @param[in] dev
11906  *   Pointer to the Ethernet device structure.
11907  * @param[out] error
11908  *   Pointer to the error structure.
11909  *
11910  * @return
11911  *   Index to ASO age action on success, 0 otherwise and rte_errno is set.
11912  */
11913 static uint32_t
11914 flow_dv_aso_age_alloc(struct rte_eth_dev *dev, struct rte_flow_error *error)
11915 {
11916         struct mlx5_priv *priv = dev->data->dev_private;
11917         const struct mlx5_aso_age_pool *pool;
11918         struct mlx5_aso_age_action *age_free = NULL;
11919         struct mlx5_aso_age_mng *mng = priv->sh->aso_age_mng;
11920
11921         MLX5_ASSERT(mng);
11922         /* Try to get the next free age action bit. */
11923         rte_spinlock_lock(&mng->free_sl);
11924         age_free = LIST_FIRST(&mng->free);
11925         if (age_free) {
11926                 LIST_REMOVE(age_free, next);
11927         } else if (!flow_dv_age_pool_create(dev, &age_free)) {
11928                 rte_spinlock_unlock(&mng->free_sl);
11929                 rte_flow_error_set(error, rte_errno, RTE_FLOW_ERROR_TYPE_ACTION,
11930                                    NULL, "failed to create ASO age pool");
11931                 return 0; /* 0 is an error. */
11932         }
11933         rte_spinlock_unlock(&mng->free_sl);
11934         pool = container_of
11935           ((const struct mlx5_aso_age_action (*)[MLX5_ASO_AGE_ACTIONS_PER_POOL])
11936                   (age_free - age_free->offset), const struct mlx5_aso_age_pool,
11937                                                                        actions);
11938         if (!age_free->dr_action) {
11939                 int reg_c = mlx5_flow_get_reg_id(dev, MLX5_ASO_FLOW_HIT, 0,
11940                                                  error);
11941
11942                 if (reg_c < 0) {
11943                         rte_flow_error_set(error, rte_errno,
11944                                            RTE_FLOW_ERROR_TYPE_ACTION,
11945                                            NULL, "failed to get reg_c "
11946                                            "for ASO flow hit");
11947                         return 0; /* 0 is an error. */
11948                 }
11949 #ifdef HAVE_MLX5_DR_CREATE_ACTION_ASO
11950                 age_free->dr_action = mlx5_glue->dv_create_flow_action_aso
11951                                 (priv->sh->rx_domain,
11952                                  pool->flow_hit_aso_obj->obj, age_free->offset,
11953                                  MLX5DV_DR_ACTION_FLAGS_ASO_FIRST_HIT_SET,
11954                                  (reg_c - REG_C_0));
11955 #endif /* HAVE_MLX5_DR_CREATE_ACTION_ASO */
11956                 if (!age_free->dr_action) {
11957                         rte_errno = errno;
11958                         rte_spinlock_lock(&mng->free_sl);
11959                         LIST_INSERT_HEAD(&mng->free, age_free, next);
11960                         rte_spinlock_unlock(&mng->free_sl);
11961                         rte_flow_error_set(error, rte_errno,
11962                                            RTE_FLOW_ERROR_TYPE_ACTION,
11963                                            NULL, "failed to create ASO "
11964                                            "flow hit action");
11965                         return 0; /* 0 is an error. */
11966                 }
11967         }
11968         __atomic_store_n(&age_free->refcnt, 1, __ATOMIC_RELAXED);
11969         return pool->index | ((age_free->offset + 1) << 16);
11970 }
11971
11972 /**
11973  * Initialize flow ASO age parameters.
11974  *
11975  * @param[in] dev
11976  *   Pointer to rte_eth_dev structure.
11977  * @param[in] age_idx
11978  *   Index of ASO age action.
11979  * @param[in] context
11980  *   Pointer to flow counter age context.
11981  * @param[in] timeout
11982  *   Aging timeout in seconds.
11983  *
11984  */
11985 static void
11986 flow_dv_aso_age_params_init(struct rte_eth_dev *dev,
11987                             uint32_t age_idx,
11988                             void *context,
11989                             uint32_t timeout)
11990 {
11991         struct mlx5_aso_age_action *aso_age;
11992
11993         aso_age = flow_aso_age_get_by_idx(dev, age_idx);
11994         MLX5_ASSERT(aso_age);
11995         aso_age->age_params.context = context;
11996         aso_age->age_params.timeout = timeout;
11997         aso_age->age_params.port_id = dev->data->port_id;
11998         __atomic_store_n(&aso_age->age_params.sec_since_last_hit, 0,
11999                          __ATOMIC_RELAXED);
12000         __atomic_store_n(&aso_age->age_params.state, AGE_CANDIDATE,
12001                          __ATOMIC_RELAXED);
12002 }
12003
12004 static void
12005 flow_dv_translate_integrity_l4(const struct rte_flow_item_integrity *mask,
12006                                const struct rte_flow_item_integrity *value,
12007                                void *headers_m, void *headers_v)
12008 {
12009         if (mask->l4_ok) {
12010                 /* application l4_ok filter aggregates all hardware l4 filters
12011                  * therefore hw l4_checksum_ok must be implicitly added here.
12012                  */
12013                 struct rte_flow_item_integrity local_item;
12014
12015                 local_item.l4_csum_ok = 1;
12016                 MLX5_SET(fte_match_set_lyr_2_4, headers_m, l4_checksum_ok,
12017                          local_item.l4_csum_ok);
12018                 if (value->l4_ok) {
12019                         /* application l4_ok = 1 matches sets both hw flags
12020                          * l4_ok and l4_checksum_ok flags to 1.
12021                          */
12022                         MLX5_SET(fte_match_set_lyr_2_4, headers_v,
12023                                  l4_checksum_ok, local_item.l4_csum_ok);
12024                         MLX5_SET(fte_match_set_lyr_2_4, headers_m, l4_ok,
12025                                  mask->l4_ok);
12026                         MLX5_SET(fte_match_set_lyr_2_4, headers_v, l4_ok,
12027                                  value->l4_ok);
12028                 } else {
12029                         /* application l4_ok = 0 matches on hw flag
12030                          * l4_checksum_ok = 0 only.
12031                          */
12032                         MLX5_SET(fte_match_set_lyr_2_4, headers_v,
12033                                  l4_checksum_ok, 0);
12034                 }
12035         } else if (mask->l4_csum_ok) {
12036                 MLX5_SET(fte_match_set_lyr_2_4, headers_m, l4_checksum_ok,
12037                          mask->l4_csum_ok);
12038                 MLX5_SET(fte_match_set_lyr_2_4, headers_v, l4_checksum_ok,
12039                          value->l4_csum_ok);
12040         }
12041 }
12042
12043 static void
12044 flow_dv_translate_integrity_l3(const struct rte_flow_item_integrity *mask,
12045                                const struct rte_flow_item_integrity *value,
12046                                void *headers_m, void *headers_v,
12047                                bool is_ipv4)
12048 {
12049         if (mask->l3_ok) {
12050                 /* application l3_ok filter aggregates all hardware l3 filters
12051                  * therefore hw ipv4_checksum_ok must be implicitly added here.
12052                  */
12053                 struct rte_flow_item_integrity local_item;
12054
12055                 local_item.ipv4_csum_ok = !!is_ipv4;
12056                 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ipv4_checksum_ok,
12057                          local_item.ipv4_csum_ok);
12058                 if (value->l3_ok) {
12059                         MLX5_SET(fte_match_set_lyr_2_4, headers_v,
12060                                  ipv4_checksum_ok, local_item.ipv4_csum_ok);
12061                         MLX5_SET(fte_match_set_lyr_2_4, headers_m, l3_ok,
12062                                  mask->l3_ok);
12063                         MLX5_SET(fte_match_set_lyr_2_4, headers_v, l3_ok,
12064                                  value->l3_ok);
12065                 } else {
12066                         MLX5_SET(fte_match_set_lyr_2_4, headers_v,
12067                                  ipv4_checksum_ok, 0);
12068                 }
12069         } else if (mask->ipv4_csum_ok) {
12070                 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ipv4_checksum_ok,
12071                          mask->ipv4_csum_ok);
12072                 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ipv4_checksum_ok,
12073                          value->ipv4_csum_ok);
12074         }
12075 }
12076
12077 static void
12078 flow_dv_translate_item_integrity(void *matcher, void *key,
12079                                  const struct rte_flow_item *head_item,
12080                                  const struct rte_flow_item *integrity_item)
12081 {
12082         const struct rte_flow_item_integrity *mask = integrity_item->mask;
12083         const struct rte_flow_item_integrity *value = integrity_item->spec;
12084         const struct rte_flow_item *tunnel_item, *end_item, *item;
12085         void *headers_m;
12086         void *headers_v;
12087         uint32_t l3_protocol;
12088
12089         if (!value)
12090                 return;
12091         if (!mask)
12092                 mask = &rte_flow_item_integrity_mask;
12093         if (value->level > 1) {
12094                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
12095                                          inner_headers);
12096                 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
12097         } else {
12098                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
12099                                          outer_headers);
12100                 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
12101         }
12102         tunnel_item = mlx5_flow_find_tunnel_item(head_item);
12103         if (value->level > 1) {
12104                 /* tunnel item was verified during the item validation */
12105                 item = tunnel_item;
12106                 end_item = mlx5_find_end_item(tunnel_item);
12107         } else {
12108                 item = head_item;
12109                 end_item = tunnel_item ? tunnel_item :
12110                            mlx5_find_end_item(integrity_item);
12111         }
12112         l3_protocol = mask->l3_ok ?
12113                       mlx5_flow_locate_proto_l3(&item, end_item) : 0;
12114         flow_dv_translate_integrity_l3(mask, value, headers_m, headers_v,
12115                                        l3_protocol == RTE_ETHER_TYPE_IPV4);
12116         flow_dv_translate_integrity_l4(mask, value, headers_m, headers_v);
12117 }
12118
12119 /**
12120  * Prepares DV flow counter with aging configuration.
12121  * Gets it by index when exists, creates a new one when doesn't.
12122  *
12123  * @param[in] dev
12124  *   Pointer to rte_eth_dev structure.
12125  * @param[in] dev_flow
12126  *   Pointer to the mlx5_flow.
12127  * @param[in, out] flow
12128  *   Pointer to the sub flow.
12129  * @param[in] count
12130  *   Pointer to the counter action configuration.
12131  * @param[in] age
12132  *   Pointer to the aging action configuration.
12133  * @param[out] error
12134  *   Pointer to the error structure.
12135  *
12136  * @return
12137  *   Pointer to the counter, NULL otherwise.
12138  */
12139 static struct mlx5_flow_counter *
12140 flow_dv_prepare_counter(struct rte_eth_dev *dev,
12141                         struct mlx5_flow *dev_flow,
12142                         struct rte_flow *flow,
12143                         const struct rte_flow_action_count *count,
12144                         const struct rte_flow_action_age *age,
12145                         struct rte_flow_error *error)
12146 {
12147         if (!flow->counter) {
12148                 flow->counter = flow_dv_translate_create_counter(dev, dev_flow,
12149                                                                  count, age);
12150                 if (!flow->counter) {
12151                         rte_flow_error_set(error, rte_errno,
12152                                            RTE_FLOW_ERROR_TYPE_ACTION, NULL,
12153                                            "cannot create counter object.");
12154                         return NULL;
12155                 }
12156         }
12157         return flow_dv_counter_get_by_idx(dev, flow->counter, NULL);
12158 }
12159
12160 /*
12161  * Release an ASO CT action by its own device.
12162  *
12163  * @param[in] dev
12164  *   Pointer to the Ethernet device structure.
12165  * @param[in] idx
12166  *   Index of ASO CT action to release.
12167  *
12168  * @return
12169  *   0 when CT action was removed, otherwise the number of references.
12170  */
12171 static inline int
12172 flow_dv_aso_ct_dev_release(struct rte_eth_dev *dev, uint32_t idx)
12173 {
12174         struct mlx5_priv *priv = dev->data->dev_private;
12175         struct mlx5_aso_ct_pools_mng *mng = priv->sh->ct_mng;
12176         uint32_t ret;
12177         struct mlx5_aso_ct_action *ct = flow_aso_ct_get_by_dev_idx(dev, idx);
12178         enum mlx5_aso_ct_state state =
12179                         __atomic_load_n(&ct->state, __ATOMIC_RELAXED);
12180
12181         /* Cannot release when CT is in the ASO SQ. */
12182         if (state == ASO_CONNTRACK_WAIT || state == ASO_CONNTRACK_QUERY)
12183                 return -1;
12184         ret = __atomic_sub_fetch(&ct->refcnt, 1, __ATOMIC_RELAXED);
12185         if (!ret) {
12186                 if (ct->dr_action_orig) {
12187 #ifdef HAVE_MLX5_DR_ACTION_ASO_CT
12188                         claim_zero(mlx5_glue->destroy_flow_action
12189                                         (ct->dr_action_orig));
12190 #endif
12191                         ct->dr_action_orig = NULL;
12192                 }
12193                 if (ct->dr_action_rply) {
12194 #ifdef HAVE_MLX5_DR_ACTION_ASO_CT
12195                         claim_zero(mlx5_glue->destroy_flow_action
12196                                         (ct->dr_action_rply));
12197 #endif
12198                         ct->dr_action_rply = NULL;
12199                 }
12200                 /* Clear the state to free, no need in 1st allocation. */
12201                 MLX5_ASO_CT_UPDATE_STATE(ct, ASO_CONNTRACK_FREE);
12202                 rte_spinlock_lock(&mng->ct_sl);
12203                 LIST_INSERT_HEAD(&mng->free_cts, ct, next);
12204                 rte_spinlock_unlock(&mng->ct_sl);
12205         }
12206         return (int)ret;
12207 }
12208
12209 static inline int
12210 flow_dv_aso_ct_release(struct rte_eth_dev *dev, uint32_t own_idx,
12211                        struct rte_flow_error *error)
12212 {
12213         uint16_t owner = (uint16_t)MLX5_INDIRECT_ACT_CT_GET_OWNER(own_idx);
12214         uint32_t idx = MLX5_INDIRECT_ACT_CT_GET_IDX(own_idx);
12215         struct rte_eth_dev *owndev = &rte_eth_devices[owner];
12216         int ret;
12217
12218         MLX5_ASSERT(owner < RTE_MAX_ETHPORTS);
12219         if (dev->data->dev_started != 1)
12220                 return rte_flow_error_set(error, EAGAIN,
12221                                           RTE_FLOW_ERROR_TYPE_ACTION,
12222                                           NULL,
12223                                           "Indirect CT action cannot be destroyed when the port is stopped");
12224         ret = flow_dv_aso_ct_dev_release(owndev, idx);
12225         if (ret < 0)
12226                 return rte_flow_error_set(error, EAGAIN,
12227                                           RTE_FLOW_ERROR_TYPE_ACTION,
12228                                           NULL,
12229                                           "Current state prevents indirect CT action from being destroyed");
12230         return ret;
12231 }
12232
12233 /*
12234  * Resize the ASO CT pools array by 64 pools.
12235  *
12236  * @param[in] dev
12237  *   Pointer to the Ethernet device structure.
12238  *
12239  * @return
12240  *   0 on success, otherwise negative errno value and rte_errno is set.
12241  */
12242 static int
12243 flow_dv_aso_ct_pools_resize(struct rte_eth_dev *dev)
12244 {
12245         struct mlx5_priv *priv = dev->data->dev_private;
12246         struct mlx5_aso_ct_pools_mng *mng = priv->sh->ct_mng;
12247         void *old_pools = mng->pools;
12248         /* Magic number now, need a macro. */
12249         uint32_t resize = mng->n + 64;
12250         uint32_t mem_size = sizeof(struct mlx5_aso_ct_pool *) * resize;
12251         void *pools = mlx5_malloc(MLX5_MEM_ZERO, mem_size, 0, SOCKET_ID_ANY);
12252
12253         if (!pools) {
12254                 rte_errno = ENOMEM;
12255                 return -rte_errno;
12256         }
12257         rte_rwlock_write_lock(&mng->resize_rwl);
12258         /* ASO SQ/QP was already initialized in the startup. */
12259         if (old_pools) {
12260                 /* Realloc could be an alternative choice. */
12261                 rte_memcpy(pools, old_pools,
12262                            mng->n * sizeof(struct mlx5_aso_ct_pool *));
12263                 mlx5_free(old_pools);
12264         }
12265         mng->n = resize;
12266         mng->pools = pools;
12267         rte_rwlock_write_unlock(&mng->resize_rwl);
12268         return 0;
12269 }
12270
12271 /*
12272  * Create and initialize a new ASO CT pool.
12273  *
12274  * @param[in] dev
12275  *   Pointer to the Ethernet device structure.
12276  * @param[out] ct_free
12277  *   Where to put the pointer of a new CT action.
12278  *
12279  * @return
12280  *   The CT actions pool pointer and @p ct_free is set on success,
12281  *   NULL otherwise and rte_errno is set.
12282  */
12283 static struct mlx5_aso_ct_pool *
12284 flow_dv_ct_pool_create(struct rte_eth_dev *dev,
12285                        struct mlx5_aso_ct_action **ct_free)
12286 {
12287         struct mlx5_priv *priv = dev->data->dev_private;
12288         struct mlx5_aso_ct_pools_mng *mng = priv->sh->ct_mng;
12289         struct mlx5_aso_ct_pool *pool = NULL;
12290         struct mlx5_devx_obj *obj = NULL;
12291         uint32_t i;
12292         uint32_t log_obj_size = rte_log2_u32(MLX5_ASO_CT_ACTIONS_PER_POOL);
12293
12294         obj = mlx5_devx_cmd_create_conn_track_offload_obj(priv->sh->cdev->ctx,
12295                                                           priv->sh->cdev->pdn,
12296                                                           log_obj_size);
12297         if (!obj) {
12298                 rte_errno = ENODATA;
12299                 DRV_LOG(ERR, "Failed to create conn_track_offload_obj using DevX.");
12300                 return NULL;
12301         }
12302         pool = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*pool), 0, SOCKET_ID_ANY);
12303         if (!pool) {
12304                 rte_errno = ENOMEM;
12305                 claim_zero(mlx5_devx_cmd_destroy(obj));
12306                 return NULL;
12307         }
12308         pool->devx_obj = obj;
12309         pool->index = mng->next;
12310         /* Resize pools array if there is no room for the new pool in it. */
12311         if (pool->index == mng->n && flow_dv_aso_ct_pools_resize(dev)) {
12312                 claim_zero(mlx5_devx_cmd_destroy(obj));
12313                 mlx5_free(pool);
12314                 return NULL;
12315         }
12316         mng->pools[pool->index] = pool;
12317         mng->next++;
12318         /* Assign the first action in the new pool, the rest go to free list. */
12319         *ct_free = &pool->actions[0];
12320         /* Lock outside, the list operation is safe here. */
12321         for (i = 1; i < MLX5_ASO_CT_ACTIONS_PER_POOL; i++) {
12322                 /* refcnt is 0 when allocating the memory. */
12323                 pool->actions[i].offset = i;
12324                 LIST_INSERT_HEAD(&mng->free_cts, &pool->actions[i], next);
12325         }
12326         return pool;
12327 }
12328
12329 /*
12330  * Allocate a ASO CT action from free list.
12331  *
12332  * @param[in] dev
12333  *   Pointer to the Ethernet device structure.
12334  * @param[out] error
12335  *   Pointer to the error structure.
12336  *
12337  * @return
12338  *   Index to ASO CT action on success, 0 otherwise and rte_errno is set.
12339  */
12340 static uint32_t
12341 flow_dv_aso_ct_alloc(struct rte_eth_dev *dev, struct rte_flow_error *error)
12342 {
12343         struct mlx5_priv *priv = dev->data->dev_private;
12344         struct mlx5_aso_ct_pools_mng *mng = priv->sh->ct_mng;
12345         struct mlx5_aso_ct_action *ct = NULL;
12346         struct mlx5_aso_ct_pool *pool;
12347         uint8_t reg_c;
12348         uint32_t ct_idx;
12349
12350         MLX5_ASSERT(mng);
12351         if (!priv->sh->devx) {
12352                 rte_errno = ENOTSUP;
12353                 return 0;
12354         }
12355         /* Get a free CT action, if no, a new pool will be created. */
12356         rte_spinlock_lock(&mng->ct_sl);
12357         ct = LIST_FIRST(&mng->free_cts);
12358         if (ct) {
12359                 LIST_REMOVE(ct, next);
12360         } else if (!flow_dv_ct_pool_create(dev, &ct)) {
12361                 rte_spinlock_unlock(&mng->ct_sl);
12362                 rte_flow_error_set(error, rte_errno, RTE_FLOW_ERROR_TYPE_ACTION,
12363                                    NULL, "failed to create ASO CT pool");
12364                 return 0;
12365         }
12366         rte_spinlock_unlock(&mng->ct_sl);
12367         pool = container_of(ct, struct mlx5_aso_ct_pool, actions[ct->offset]);
12368         ct_idx = MLX5_MAKE_CT_IDX(pool->index, ct->offset);
12369         /* 0: inactive, 1: created, 2+: used by flows. */
12370         __atomic_store_n(&ct->refcnt, 1, __ATOMIC_RELAXED);
12371         reg_c = mlx5_flow_get_reg_id(dev, MLX5_ASO_CONNTRACK, 0, error);
12372         if (!ct->dr_action_orig) {
12373 #ifdef HAVE_MLX5_DR_ACTION_ASO_CT
12374                 ct->dr_action_orig = mlx5_glue->dv_create_flow_action_aso
12375                         (priv->sh->rx_domain, pool->devx_obj->obj,
12376                          ct->offset,
12377                          MLX5DV_DR_ACTION_FLAGS_ASO_CT_DIRECTION_INITIATOR,
12378                          reg_c - REG_C_0);
12379 #else
12380                 RTE_SET_USED(reg_c);
12381 #endif
12382                 if (!ct->dr_action_orig) {
12383                         flow_dv_aso_ct_dev_release(dev, ct_idx);
12384                         rte_flow_error_set(error, rte_errno,
12385                                            RTE_FLOW_ERROR_TYPE_ACTION, NULL,
12386                                            "failed to create ASO CT action");
12387                         return 0;
12388                 }
12389         }
12390         if (!ct->dr_action_rply) {
12391 #ifdef HAVE_MLX5_DR_ACTION_ASO_CT
12392                 ct->dr_action_rply = mlx5_glue->dv_create_flow_action_aso
12393                         (priv->sh->rx_domain, pool->devx_obj->obj,
12394                          ct->offset,
12395                          MLX5DV_DR_ACTION_FLAGS_ASO_CT_DIRECTION_RESPONDER,
12396                          reg_c - REG_C_0);
12397 #endif
12398                 if (!ct->dr_action_rply) {
12399                         flow_dv_aso_ct_dev_release(dev, ct_idx);
12400                         rte_flow_error_set(error, rte_errno,
12401                                            RTE_FLOW_ERROR_TYPE_ACTION, NULL,
12402                                            "failed to create ASO CT action");
12403                         return 0;
12404                 }
12405         }
12406         return ct_idx;
12407 }
12408
12409 /*
12410  * Create a conntrack object with context and actions by using ASO mechanism.
12411  *
12412  * @param[in] dev
12413  *   Pointer to rte_eth_dev structure.
12414  * @param[in] pro
12415  *   Pointer to conntrack information profile.
12416  * @param[out] error
12417  *   Pointer to the error structure.
12418  *
12419  * @return
12420  *   Index to conntrack object on success, 0 otherwise.
12421  */
12422 static uint32_t
12423 flow_dv_translate_create_conntrack(struct rte_eth_dev *dev,
12424                                    const struct rte_flow_action_conntrack *pro,
12425                                    struct rte_flow_error *error)
12426 {
12427         struct mlx5_priv *priv = dev->data->dev_private;
12428         struct mlx5_dev_ctx_shared *sh = priv->sh;
12429         struct mlx5_aso_ct_action *ct;
12430         uint32_t idx;
12431
12432         if (!sh->ct_aso_en)
12433                 return rte_flow_error_set(error, ENOTSUP,
12434                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
12435                                           "Connection is not supported");
12436         idx = flow_dv_aso_ct_alloc(dev, error);
12437         if (!idx)
12438                 return rte_flow_error_set(error, rte_errno,
12439                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
12440                                           "Failed to allocate CT object");
12441         ct = flow_aso_ct_get_by_dev_idx(dev, idx);
12442         if (mlx5_aso_ct_update_by_wqe(sh, ct, pro))
12443                 return rte_flow_error_set(error, EBUSY,
12444                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
12445                                           "Failed to update CT");
12446         ct->is_original = !!pro->is_original_dir;
12447         ct->peer = pro->peer_port;
12448         return idx;
12449 }
12450
12451 /**
12452  * Fill the flow with DV spec, lock free
12453  * (mutex should be acquired by caller).
12454  *
12455  * @param[in] dev
12456  *   Pointer to rte_eth_dev structure.
12457  * @param[in, out] dev_flow
12458  *   Pointer to the sub flow.
12459  * @param[in] attr
12460  *   Pointer to the flow attributes.
12461  * @param[in] items
12462  *   Pointer to the list of items.
12463  * @param[in] actions
12464  *   Pointer to the list of actions.
12465  * @param[out] error
12466  *   Pointer to the error structure.
12467  *
12468  * @return
12469  *   0 on success, a negative errno value otherwise and rte_errno is set.
12470  */
12471 static int
12472 flow_dv_translate(struct rte_eth_dev *dev,
12473                   struct mlx5_flow *dev_flow,
12474                   const struct rte_flow_attr *attr,
12475                   const struct rte_flow_item items[],
12476                   const struct rte_flow_action actions[],
12477                   struct rte_flow_error *error)
12478 {
12479         struct mlx5_priv *priv = dev->data->dev_private;
12480         struct mlx5_dev_config *dev_conf = &priv->config;
12481         struct rte_flow *flow = dev_flow->flow;
12482         struct mlx5_flow_handle *handle = dev_flow->handle;
12483         struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace();
12484         struct mlx5_flow_rss_desc *rss_desc;
12485         uint64_t item_flags = 0;
12486         uint64_t last_item = 0;
12487         uint64_t action_flags = 0;
12488         struct mlx5_flow_dv_matcher matcher = {
12489                 .mask = {
12490                         .size = sizeof(matcher.mask.buf),
12491                 },
12492         };
12493         int actions_n = 0;
12494         bool actions_end = false;
12495         union {
12496                 struct mlx5_flow_dv_modify_hdr_resource res;
12497                 uint8_t len[sizeof(struct mlx5_flow_dv_modify_hdr_resource) +
12498                             sizeof(struct mlx5_modification_cmd) *
12499                             (MLX5_MAX_MODIFY_NUM + 1)];
12500         } mhdr_dummy;
12501         struct mlx5_flow_dv_modify_hdr_resource *mhdr_res = &mhdr_dummy.res;
12502         const struct rte_flow_action_count *count = NULL;
12503         const struct rte_flow_action_age *non_shared_age = NULL;
12504         union flow_dv_attr flow_attr = { .attr = 0 };
12505         uint32_t tag_be;
12506         union mlx5_flow_tbl_key tbl_key;
12507         uint32_t modify_action_position = UINT32_MAX;
12508         void *match_mask = matcher.mask.buf;
12509         void *match_value = dev_flow->dv.value.buf;
12510         uint8_t next_protocol = 0xff;
12511         struct rte_vlan_hdr vlan = { 0 };
12512         struct mlx5_flow_dv_dest_array_resource mdest_res;
12513         struct mlx5_flow_dv_sample_resource sample_res;
12514         void *sample_actions[MLX5_DV_MAX_NUMBER_OF_ACTIONS] = {0};
12515         const struct rte_flow_action_sample *sample = NULL;
12516         struct mlx5_flow_sub_actions_list *sample_act;
12517         uint32_t sample_act_pos = UINT32_MAX;
12518         uint32_t age_act_pos = UINT32_MAX;
12519         uint32_t num_of_dest = 0;
12520         int tmp_actions_n = 0;
12521         uint32_t table;
12522         int ret = 0;
12523         const struct mlx5_flow_tunnel *tunnel = NULL;
12524         struct flow_grp_info grp_info = {
12525                 .external = !!dev_flow->external,
12526                 .transfer = !!attr->transfer,
12527                 .fdb_def_rule = !!priv->fdb_def_rule,
12528                 .skip_scale = dev_flow->skip_scale &
12529                         (1 << MLX5_SCALE_FLOW_GROUP_BIT),
12530                 .std_tbl_fix = true,
12531         };
12532         const struct rte_flow_item *head_item = items;
12533
12534         if (!wks)
12535                 return rte_flow_error_set(error, ENOMEM,
12536                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
12537                                           NULL,
12538                                           "failed to push flow workspace");
12539         rss_desc = &wks->rss_desc;
12540         memset(&mdest_res, 0, sizeof(struct mlx5_flow_dv_dest_array_resource));
12541         memset(&sample_res, 0, sizeof(struct mlx5_flow_dv_sample_resource));
12542         mhdr_res->ft_type = attr->egress ? MLX5DV_FLOW_TABLE_TYPE_NIC_TX :
12543                                            MLX5DV_FLOW_TABLE_TYPE_NIC_RX;
12544         /* update normal path action resource into last index of array */
12545         sample_act = &mdest_res.sample_act[MLX5_MAX_DEST_NUM - 1];
12546         if (is_tunnel_offload_active(dev)) {
12547                 if (dev_flow->tunnel) {
12548                         RTE_VERIFY(dev_flow->tof_type ==
12549                                    MLX5_TUNNEL_OFFLOAD_MISS_RULE);
12550                         tunnel = dev_flow->tunnel;
12551                 } else {
12552                         tunnel = mlx5_get_tof(items, actions,
12553                                               &dev_flow->tof_type);
12554                         dev_flow->tunnel = tunnel;
12555                 }
12556                 grp_info.std_tbl_fix = tunnel_use_standard_attr_group_translate
12557                                         (dev, attr, tunnel, dev_flow->tof_type);
12558         }
12559         mhdr_res->ft_type = attr->egress ? MLX5DV_FLOW_TABLE_TYPE_NIC_TX :
12560                                            MLX5DV_FLOW_TABLE_TYPE_NIC_RX;
12561         ret = mlx5_flow_group_to_table(dev, tunnel, attr->group, &table,
12562                                        &grp_info, error);
12563         if (ret)
12564                 return ret;
12565         dev_flow->dv.group = table;
12566         if (attr->transfer)
12567                 mhdr_res->ft_type = MLX5DV_FLOW_TABLE_TYPE_FDB;
12568         /* number of actions must be set to 0 in case of dirty stack. */
12569         mhdr_res->actions_num = 0;
12570         if (is_flow_tunnel_match_rule(dev_flow->tof_type)) {
12571                 /*
12572                  * do not add decap action if match rule drops packet
12573                  * HW rejects rules with decap & drop
12574                  *
12575                  * if tunnel match rule was inserted before matching tunnel set
12576                  * rule flow table used in the match rule must be registered.
12577                  * current implementation handles that in the
12578                  * flow_dv_match_register() at the function end.
12579                  */
12580                 bool add_decap = true;
12581                 const struct rte_flow_action *ptr = actions;
12582
12583                 for (; ptr->type != RTE_FLOW_ACTION_TYPE_END; ptr++) {
12584                         if (ptr->type == RTE_FLOW_ACTION_TYPE_DROP) {
12585                                 add_decap = false;
12586                                 break;
12587                         }
12588                 }
12589                 if (add_decap) {
12590                         if (flow_dv_create_action_l2_decap(dev, dev_flow,
12591                                                            attr->transfer,
12592                                                            error))
12593                                 return -rte_errno;
12594                         dev_flow->dv.actions[actions_n++] =
12595                                         dev_flow->dv.encap_decap->action;
12596                         action_flags |= MLX5_FLOW_ACTION_DECAP;
12597                 }
12598         }
12599         for (; !actions_end ; actions++) {
12600                 const struct rte_flow_action_queue *queue;
12601                 const struct rte_flow_action_rss *rss;
12602                 const struct rte_flow_action *action = actions;
12603                 const uint8_t *rss_key;
12604                 struct mlx5_flow_tbl_resource *tbl;
12605                 struct mlx5_aso_age_action *age_act;
12606                 struct mlx5_flow_counter *cnt_act;
12607                 uint32_t port_id = 0;
12608                 struct mlx5_flow_dv_port_id_action_resource port_id_resource;
12609                 int action_type = actions->type;
12610                 const struct rte_flow_action *found_action = NULL;
12611                 uint32_t jump_group = 0;
12612                 uint32_t owner_idx;
12613                 struct mlx5_aso_ct_action *ct;
12614
12615                 if (!mlx5_flow_os_action_supported(action_type))
12616                         return rte_flow_error_set(error, ENOTSUP,
12617                                                   RTE_FLOW_ERROR_TYPE_ACTION,
12618                                                   actions,
12619                                                   "action not supported");
12620                 switch (action_type) {
12621                 case MLX5_RTE_FLOW_ACTION_TYPE_TUNNEL_SET:
12622                         action_flags |= MLX5_FLOW_ACTION_TUNNEL_SET;
12623                         break;
12624                 case RTE_FLOW_ACTION_TYPE_VOID:
12625                         break;
12626                 case RTE_FLOW_ACTION_TYPE_PORT_ID:
12627                 case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT:
12628                         if (flow_dv_translate_action_port_id(dev, action,
12629                                                              &port_id, error))
12630                                 return -rte_errno;
12631                         port_id_resource.port_id = port_id;
12632                         MLX5_ASSERT(!handle->rix_port_id_action);
12633                         if (flow_dv_port_id_action_resource_register
12634                             (dev, &port_id_resource, dev_flow, error))
12635                                 return -rte_errno;
12636                         dev_flow->dv.actions[actions_n++] =
12637                                         dev_flow->dv.port_id_action->action;
12638                         action_flags |= MLX5_FLOW_ACTION_PORT_ID;
12639                         dev_flow->handle->fate_action = MLX5_FLOW_FATE_PORT_ID;
12640                         sample_act->action_flags |= MLX5_FLOW_ACTION_PORT_ID;
12641                         num_of_dest++;
12642                         break;
12643                 case RTE_FLOW_ACTION_TYPE_FLAG:
12644                         action_flags |= MLX5_FLOW_ACTION_FLAG;
12645                         dev_flow->handle->mark = 1;
12646                         if (dev_conf->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY) {
12647                                 struct rte_flow_action_mark mark = {
12648                                         .id = MLX5_FLOW_MARK_DEFAULT,
12649                                 };
12650
12651                                 if (flow_dv_convert_action_mark(dev, &mark,
12652                                                                 mhdr_res,
12653                                                                 error))
12654                                         return -rte_errno;
12655                                 action_flags |= MLX5_FLOW_ACTION_MARK_EXT;
12656                                 break;
12657                         }
12658                         tag_be = mlx5_flow_mark_set(MLX5_FLOW_MARK_DEFAULT);
12659                         /*
12660                          * Only one FLAG or MARK is supported per device flow
12661                          * right now. So the pointer to the tag resource must be
12662                          * zero before the register process.
12663                          */
12664                         MLX5_ASSERT(!handle->dvh.rix_tag);
12665                         if (flow_dv_tag_resource_register(dev, tag_be,
12666                                                           dev_flow, error))
12667                                 return -rte_errno;
12668                         MLX5_ASSERT(dev_flow->dv.tag_resource);
12669                         dev_flow->dv.actions[actions_n++] =
12670                                         dev_flow->dv.tag_resource->action;
12671                         break;
12672                 case RTE_FLOW_ACTION_TYPE_MARK:
12673                         action_flags |= MLX5_FLOW_ACTION_MARK;
12674                         dev_flow->handle->mark = 1;
12675                         if (dev_conf->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY) {
12676                                 const struct rte_flow_action_mark *mark =
12677                                         (const struct rte_flow_action_mark *)
12678                                                 actions->conf;
12679
12680                                 if (flow_dv_convert_action_mark(dev, mark,
12681                                                                 mhdr_res,
12682                                                                 error))
12683                                         return -rte_errno;
12684                                 action_flags |= MLX5_FLOW_ACTION_MARK_EXT;
12685                                 break;
12686                         }
12687                         /* Fall-through */
12688                 case MLX5_RTE_FLOW_ACTION_TYPE_MARK:
12689                         /* Legacy (non-extensive) MARK action. */
12690                         tag_be = mlx5_flow_mark_set
12691                               (((const struct rte_flow_action_mark *)
12692                                (actions->conf))->id);
12693                         MLX5_ASSERT(!handle->dvh.rix_tag);
12694                         if (flow_dv_tag_resource_register(dev, tag_be,
12695                                                           dev_flow, error))
12696                                 return -rte_errno;
12697                         MLX5_ASSERT(dev_flow->dv.tag_resource);
12698                         dev_flow->dv.actions[actions_n++] =
12699                                         dev_flow->dv.tag_resource->action;
12700                         break;
12701                 case RTE_FLOW_ACTION_TYPE_SET_META:
12702                         if (flow_dv_convert_action_set_meta
12703                                 (dev, mhdr_res, attr,
12704                                  (const struct rte_flow_action_set_meta *)
12705                                   actions->conf, error))
12706                                 return -rte_errno;
12707                         action_flags |= MLX5_FLOW_ACTION_SET_META;
12708                         break;
12709                 case RTE_FLOW_ACTION_TYPE_SET_TAG:
12710                         if (flow_dv_convert_action_set_tag
12711                                 (dev, mhdr_res,
12712                                  (const struct rte_flow_action_set_tag *)
12713                                   actions->conf, error))
12714                                 return -rte_errno;
12715                         action_flags |= MLX5_FLOW_ACTION_SET_TAG;
12716                         break;
12717                 case RTE_FLOW_ACTION_TYPE_DROP:
12718                         action_flags |= MLX5_FLOW_ACTION_DROP;
12719                         dev_flow->handle->fate_action = MLX5_FLOW_FATE_DROP;
12720                         break;
12721                 case RTE_FLOW_ACTION_TYPE_QUEUE:
12722                         queue = actions->conf;
12723                         rss_desc->queue_num = 1;
12724                         rss_desc->queue[0] = queue->index;
12725                         action_flags |= MLX5_FLOW_ACTION_QUEUE;
12726                         dev_flow->handle->fate_action = MLX5_FLOW_FATE_QUEUE;
12727                         sample_act->action_flags |= MLX5_FLOW_ACTION_QUEUE;
12728                         num_of_dest++;
12729                         break;
12730                 case RTE_FLOW_ACTION_TYPE_RSS:
12731                         rss = actions->conf;
12732                         memcpy(rss_desc->queue, rss->queue,
12733                                rss->queue_num * sizeof(uint16_t));
12734                         rss_desc->queue_num = rss->queue_num;
12735                         /* NULL RSS key indicates default RSS key. */
12736                         rss_key = !rss->key ? rss_hash_default_key : rss->key;
12737                         memcpy(rss_desc->key, rss_key, MLX5_RSS_HASH_KEY_LEN);
12738                         /*
12739                          * rss->level and rss.types should be set in advance
12740                          * when expanding items for RSS.
12741                          */
12742                         action_flags |= MLX5_FLOW_ACTION_RSS;
12743                         dev_flow->handle->fate_action = rss_desc->shared_rss ?
12744                                 MLX5_FLOW_FATE_SHARED_RSS :
12745                                 MLX5_FLOW_FATE_QUEUE;
12746                         break;
12747                 case MLX5_RTE_FLOW_ACTION_TYPE_AGE:
12748                         owner_idx = (uint32_t)(uintptr_t)action->conf;
12749                         age_act = flow_aso_age_get_by_idx(dev, owner_idx);
12750                         if (flow->age == 0) {
12751                                 flow->age = owner_idx;
12752                                 __atomic_fetch_add(&age_act->refcnt, 1,
12753                                                    __ATOMIC_RELAXED);
12754                         }
12755                         age_act_pos = actions_n++;
12756                         action_flags |= MLX5_FLOW_ACTION_AGE;
12757                         break;
12758                 case RTE_FLOW_ACTION_TYPE_AGE:
12759                         non_shared_age = action->conf;
12760                         age_act_pos = actions_n++;
12761                         action_flags |= MLX5_FLOW_ACTION_AGE;
12762                         break;
12763                 case MLX5_RTE_FLOW_ACTION_TYPE_COUNT:
12764                         owner_idx = (uint32_t)(uintptr_t)action->conf;
12765                         cnt_act = flow_dv_counter_get_by_idx(dev, owner_idx,
12766                                                              NULL);
12767                         MLX5_ASSERT(cnt_act != NULL);
12768                         /**
12769                          * When creating meter drop flow in drop table, the
12770                          * counter should not overwrite the rte flow counter.
12771                          */
12772                         if (attr->group == MLX5_FLOW_TABLE_LEVEL_METER &&
12773                             dev_flow->dv.table_id == MLX5_MTR_TABLE_ID_DROP) {
12774                                 dev_flow->dv.actions[actions_n++] =
12775                                                         cnt_act->action;
12776                         } else {
12777                                 if (flow->counter == 0) {
12778                                         flow->counter = owner_idx;
12779                                         __atomic_fetch_add
12780                                                 (&cnt_act->shared_info.refcnt,
12781                                                  1, __ATOMIC_RELAXED);
12782                                 }
12783                                 /* Save information first, will apply later. */
12784                                 action_flags |= MLX5_FLOW_ACTION_COUNT;
12785                         }
12786                         break;
12787                 case RTE_FLOW_ACTION_TYPE_COUNT:
12788                         if (!priv->sh->devx) {
12789                                 return rte_flow_error_set
12790                                               (error, ENOTSUP,
12791                                                RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
12792                                                NULL,
12793                                                "count action not supported");
12794                         }
12795                         /* Save information first, will apply later. */
12796                         count = action->conf;
12797                         action_flags |= MLX5_FLOW_ACTION_COUNT;
12798                         break;
12799                 case RTE_FLOW_ACTION_TYPE_OF_POP_VLAN:
12800                         dev_flow->dv.actions[actions_n++] =
12801                                                 priv->sh->pop_vlan_action;
12802                         action_flags |= MLX5_FLOW_ACTION_OF_POP_VLAN;
12803                         break;
12804                 case RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN:
12805                         if (!(action_flags &
12806                               MLX5_FLOW_ACTION_OF_SET_VLAN_VID))
12807                                 flow_dev_get_vlan_info_from_items(items, &vlan);
12808                         vlan.eth_proto = rte_be_to_cpu_16
12809                              ((((const struct rte_flow_action_of_push_vlan *)
12810                                                    actions->conf)->ethertype));
12811                         found_action = mlx5_flow_find_action
12812                                         (actions + 1,
12813                                          RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID);
12814                         if (found_action)
12815                                 mlx5_update_vlan_vid_pcp(found_action, &vlan);
12816                         found_action = mlx5_flow_find_action
12817                                         (actions + 1,
12818                                          RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP);
12819                         if (found_action)
12820                                 mlx5_update_vlan_vid_pcp(found_action, &vlan);
12821                         if (flow_dv_create_action_push_vlan
12822                                             (dev, attr, &vlan, dev_flow, error))
12823                                 return -rte_errno;
12824                         dev_flow->dv.actions[actions_n++] =
12825                                         dev_flow->dv.push_vlan_res->action;
12826                         action_flags |= MLX5_FLOW_ACTION_OF_PUSH_VLAN;
12827                         break;
12828                 case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP:
12829                         /* of_vlan_push action handled this action */
12830                         MLX5_ASSERT(action_flags &
12831                                     MLX5_FLOW_ACTION_OF_PUSH_VLAN);
12832                         break;
12833                 case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID:
12834                         if (action_flags & MLX5_FLOW_ACTION_OF_PUSH_VLAN)
12835                                 break;
12836                         flow_dev_get_vlan_info_from_items(items, &vlan);
12837                         mlx5_update_vlan_vid_pcp(actions, &vlan);
12838                         /* If no VLAN push - this is a modify header action */
12839                         if (flow_dv_convert_action_modify_vlan_vid
12840                                                 (mhdr_res, actions, error))
12841                                 return -rte_errno;
12842                         action_flags |= MLX5_FLOW_ACTION_OF_SET_VLAN_VID;
12843                         break;
12844                 case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP:
12845                 case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP:
12846                         if (flow_dv_create_action_l2_encap(dev, actions,
12847                                                            dev_flow,
12848                                                            attr->transfer,
12849                                                            error))
12850                                 return -rte_errno;
12851                         dev_flow->dv.actions[actions_n++] =
12852                                         dev_flow->dv.encap_decap->action;
12853                         action_flags |= MLX5_FLOW_ACTION_ENCAP;
12854                         if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
12855                                 sample_act->action_flags |=
12856                                                         MLX5_FLOW_ACTION_ENCAP;
12857                         break;
12858                 case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP:
12859                 case RTE_FLOW_ACTION_TYPE_NVGRE_DECAP:
12860                         if (flow_dv_create_action_l2_decap(dev, dev_flow,
12861                                                            attr->transfer,
12862                                                            error))
12863                                 return -rte_errno;
12864                         dev_flow->dv.actions[actions_n++] =
12865                                         dev_flow->dv.encap_decap->action;
12866                         action_flags |= MLX5_FLOW_ACTION_DECAP;
12867                         break;
12868                 case RTE_FLOW_ACTION_TYPE_RAW_ENCAP:
12869                         /* Handle encap with preceding decap. */
12870                         if (action_flags & MLX5_FLOW_ACTION_DECAP) {
12871                                 if (flow_dv_create_action_raw_encap
12872                                         (dev, actions, dev_flow, attr, error))
12873                                         return -rte_errno;
12874                                 dev_flow->dv.actions[actions_n++] =
12875                                         dev_flow->dv.encap_decap->action;
12876                         } else {
12877                                 /* Handle encap without preceding decap. */
12878                                 if (flow_dv_create_action_l2_encap
12879                                     (dev, actions, dev_flow, attr->transfer,
12880                                      error))
12881                                         return -rte_errno;
12882                                 dev_flow->dv.actions[actions_n++] =
12883                                         dev_flow->dv.encap_decap->action;
12884                         }
12885                         action_flags |= MLX5_FLOW_ACTION_ENCAP;
12886                         if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
12887                                 sample_act->action_flags |=
12888                                                         MLX5_FLOW_ACTION_ENCAP;
12889                         break;
12890                 case RTE_FLOW_ACTION_TYPE_RAW_DECAP:
12891                         while ((++action)->type == RTE_FLOW_ACTION_TYPE_VOID)
12892                                 ;
12893                         if (action->type != RTE_FLOW_ACTION_TYPE_RAW_ENCAP) {
12894                                 if (flow_dv_create_action_l2_decap
12895                                     (dev, dev_flow, attr->transfer, error))
12896                                         return -rte_errno;
12897                                 dev_flow->dv.actions[actions_n++] =
12898                                         dev_flow->dv.encap_decap->action;
12899                         }
12900                         /* If decap is followed by encap, handle it at encap. */
12901                         action_flags |= MLX5_FLOW_ACTION_DECAP;
12902                         break;
12903                 case MLX5_RTE_FLOW_ACTION_TYPE_JUMP:
12904                         dev_flow->dv.actions[actions_n++] =
12905                                 (void *)(uintptr_t)action->conf;
12906                         action_flags |= MLX5_FLOW_ACTION_JUMP;
12907                         break;
12908                 case RTE_FLOW_ACTION_TYPE_JUMP:
12909                         jump_group = ((const struct rte_flow_action_jump *)
12910                                                         action->conf)->group;
12911                         grp_info.std_tbl_fix = 0;
12912                         if (dev_flow->skip_scale &
12913                                 (1 << MLX5_SCALE_JUMP_FLOW_GROUP_BIT))
12914                                 grp_info.skip_scale = 1;
12915                         else
12916                                 grp_info.skip_scale = 0;
12917                         ret = mlx5_flow_group_to_table(dev, tunnel,
12918                                                        jump_group,
12919                                                        &table,
12920                                                        &grp_info, error);
12921                         if (ret)
12922                                 return ret;
12923                         tbl = flow_dv_tbl_resource_get(dev, table, attr->egress,
12924                                                        attr->transfer,
12925                                                        !!dev_flow->external,
12926                                                        tunnel, jump_group, 0,
12927                                                        0, error);
12928                         if (!tbl)
12929                                 return rte_flow_error_set
12930                                                 (error, errno,
12931                                                  RTE_FLOW_ERROR_TYPE_ACTION,
12932                                                  NULL,
12933                                                  "cannot create jump action.");
12934                         if (flow_dv_jump_tbl_resource_register
12935                             (dev, tbl, dev_flow, error)) {
12936                                 flow_dv_tbl_resource_release(MLX5_SH(dev), tbl);
12937                                 return rte_flow_error_set
12938                                                 (error, errno,
12939                                                  RTE_FLOW_ERROR_TYPE_ACTION,
12940                                                  NULL,
12941                                                  "cannot create jump action.");
12942                         }
12943                         dev_flow->dv.actions[actions_n++] =
12944                                         dev_flow->dv.jump->action;
12945                         action_flags |= MLX5_FLOW_ACTION_JUMP;
12946                         dev_flow->handle->fate_action = MLX5_FLOW_FATE_JUMP;
12947                         sample_act->action_flags |= MLX5_FLOW_ACTION_JUMP;
12948                         num_of_dest++;
12949                         break;
12950                 case RTE_FLOW_ACTION_TYPE_SET_MAC_SRC:
12951                 case RTE_FLOW_ACTION_TYPE_SET_MAC_DST:
12952                         if (flow_dv_convert_action_modify_mac
12953                                         (mhdr_res, actions, error))
12954                                 return -rte_errno;
12955                         action_flags |= actions->type ==
12956                                         RTE_FLOW_ACTION_TYPE_SET_MAC_SRC ?
12957                                         MLX5_FLOW_ACTION_SET_MAC_SRC :
12958                                         MLX5_FLOW_ACTION_SET_MAC_DST;
12959                         break;
12960                 case RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC:
12961                 case RTE_FLOW_ACTION_TYPE_SET_IPV4_DST:
12962                         if (flow_dv_convert_action_modify_ipv4
12963                                         (mhdr_res, actions, error))
12964                                 return -rte_errno;
12965                         action_flags |= actions->type ==
12966                                         RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC ?
12967                                         MLX5_FLOW_ACTION_SET_IPV4_SRC :
12968                                         MLX5_FLOW_ACTION_SET_IPV4_DST;
12969                         break;
12970                 case RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC:
12971                 case RTE_FLOW_ACTION_TYPE_SET_IPV6_DST:
12972                         if (flow_dv_convert_action_modify_ipv6
12973                                         (mhdr_res, actions, error))
12974                                 return -rte_errno;
12975                         action_flags |= actions->type ==
12976                                         RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC ?
12977                                         MLX5_FLOW_ACTION_SET_IPV6_SRC :
12978                                         MLX5_FLOW_ACTION_SET_IPV6_DST;
12979                         break;
12980                 case RTE_FLOW_ACTION_TYPE_SET_TP_SRC:
12981                 case RTE_FLOW_ACTION_TYPE_SET_TP_DST:
12982                         if (flow_dv_convert_action_modify_tp
12983                                         (mhdr_res, actions, items,
12984                                          &flow_attr, dev_flow, !!(action_flags &
12985                                          MLX5_FLOW_ACTION_DECAP), error))
12986                                 return -rte_errno;
12987                         action_flags |= actions->type ==
12988                                         RTE_FLOW_ACTION_TYPE_SET_TP_SRC ?
12989                                         MLX5_FLOW_ACTION_SET_TP_SRC :
12990                                         MLX5_FLOW_ACTION_SET_TP_DST;
12991                         break;
12992                 case RTE_FLOW_ACTION_TYPE_DEC_TTL:
12993                         if (flow_dv_convert_action_modify_dec_ttl
12994                                         (mhdr_res, items, &flow_attr, dev_flow,
12995                                          !!(action_flags &
12996                                          MLX5_FLOW_ACTION_DECAP), error))
12997                                 return -rte_errno;
12998                         action_flags |= MLX5_FLOW_ACTION_DEC_TTL;
12999                         break;
13000                 case RTE_FLOW_ACTION_TYPE_SET_TTL:
13001                         if (flow_dv_convert_action_modify_ttl
13002                                         (mhdr_res, actions, items, &flow_attr,
13003                                          dev_flow, !!(action_flags &
13004                                          MLX5_FLOW_ACTION_DECAP), error))
13005                                 return -rte_errno;
13006                         action_flags |= MLX5_FLOW_ACTION_SET_TTL;
13007                         break;
13008                 case RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ:
13009                 case RTE_FLOW_ACTION_TYPE_DEC_TCP_SEQ:
13010                         if (flow_dv_convert_action_modify_tcp_seq
13011                                         (mhdr_res, actions, error))
13012                                 return -rte_errno;
13013                         action_flags |= actions->type ==
13014                                         RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ ?
13015                                         MLX5_FLOW_ACTION_INC_TCP_SEQ :
13016                                         MLX5_FLOW_ACTION_DEC_TCP_SEQ;
13017                         break;
13018
13019                 case RTE_FLOW_ACTION_TYPE_INC_TCP_ACK:
13020                 case RTE_FLOW_ACTION_TYPE_DEC_TCP_ACK:
13021                         if (flow_dv_convert_action_modify_tcp_ack
13022                                         (mhdr_res, actions, error))
13023                                 return -rte_errno;
13024                         action_flags |= actions->type ==
13025                                         RTE_FLOW_ACTION_TYPE_INC_TCP_ACK ?
13026                                         MLX5_FLOW_ACTION_INC_TCP_ACK :
13027                                         MLX5_FLOW_ACTION_DEC_TCP_ACK;
13028                         break;
13029                 case MLX5_RTE_FLOW_ACTION_TYPE_TAG:
13030                         if (flow_dv_convert_action_set_reg
13031                                         (mhdr_res, actions, error))
13032                                 return -rte_errno;
13033                         action_flags |= MLX5_FLOW_ACTION_SET_TAG;
13034                         break;
13035                 case MLX5_RTE_FLOW_ACTION_TYPE_COPY_MREG:
13036                         if (flow_dv_convert_action_copy_mreg
13037                                         (dev, mhdr_res, actions, error))
13038                                 return -rte_errno;
13039                         action_flags |= MLX5_FLOW_ACTION_SET_TAG;
13040                         break;
13041                 case MLX5_RTE_FLOW_ACTION_TYPE_DEFAULT_MISS:
13042                         action_flags |= MLX5_FLOW_ACTION_DEFAULT_MISS;
13043                         dev_flow->handle->fate_action =
13044                                         MLX5_FLOW_FATE_DEFAULT_MISS;
13045                         break;
13046                 case RTE_FLOW_ACTION_TYPE_METER:
13047                         if (!wks->fm)
13048                                 return rte_flow_error_set(error, rte_errno,
13049                                         RTE_FLOW_ERROR_TYPE_ACTION,
13050                                         NULL, "Failed to get meter in flow.");
13051                         /* Set the meter action. */
13052                         dev_flow->dv.actions[actions_n++] =
13053                                 wks->fm->meter_action;
13054                         action_flags |= MLX5_FLOW_ACTION_METER;
13055                         break;
13056                 case RTE_FLOW_ACTION_TYPE_SET_IPV4_DSCP:
13057                         if (flow_dv_convert_action_modify_ipv4_dscp(mhdr_res,
13058                                                               actions, error))
13059                                 return -rte_errno;
13060                         action_flags |= MLX5_FLOW_ACTION_SET_IPV4_DSCP;
13061                         break;
13062                 case RTE_FLOW_ACTION_TYPE_SET_IPV6_DSCP:
13063                         if (flow_dv_convert_action_modify_ipv6_dscp(mhdr_res,
13064                                                               actions, error))
13065                                 return -rte_errno;
13066                         action_flags |= MLX5_FLOW_ACTION_SET_IPV6_DSCP;
13067                         break;
13068                 case RTE_FLOW_ACTION_TYPE_SAMPLE:
13069                         sample_act_pos = actions_n;
13070                         sample = (const struct rte_flow_action_sample *)
13071                                  action->conf;
13072                         actions_n++;
13073                         action_flags |= MLX5_FLOW_ACTION_SAMPLE;
13074                         /* put encap action into group if work with port id */
13075                         if ((action_flags & MLX5_FLOW_ACTION_ENCAP) &&
13076                             (action_flags & MLX5_FLOW_ACTION_PORT_ID))
13077                                 sample_act->action_flags |=
13078                                                         MLX5_FLOW_ACTION_ENCAP;
13079                         break;
13080                 case RTE_FLOW_ACTION_TYPE_MODIFY_FIELD:
13081                         if (flow_dv_convert_action_modify_field
13082                                         (dev, mhdr_res, actions, attr, error))
13083                                 return -rte_errno;
13084                         action_flags |= MLX5_FLOW_ACTION_MODIFY_FIELD;
13085                         break;
13086                 case RTE_FLOW_ACTION_TYPE_CONNTRACK:
13087                         owner_idx = (uint32_t)(uintptr_t)action->conf;
13088                         ct = flow_aso_ct_get_by_idx(dev, owner_idx);
13089                         if (!ct)
13090                                 return rte_flow_error_set(error, EINVAL,
13091                                                 RTE_FLOW_ERROR_TYPE_ACTION,
13092                                                 NULL,
13093                                                 "Failed to get CT object.");
13094                         if (mlx5_aso_ct_available(priv->sh, ct))
13095                                 return rte_flow_error_set(error, rte_errno,
13096                                                 RTE_FLOW_ERROR_TYPE_ACTION,
13097                                                 NULL,
13098                                                 "CT is unavailable.");
13099                         if (ct->is_original)
13100                                 dev_flow->dv.actions[actions_n] =
13101                                                         ct->dr_action_orig;
13102                         else
13103                                 dev_flow->dv.actions[actions_n] =
13104                                                         ct->dr_action_rply;
13105                         if (flow->ct == 0) {
13106                                 flow->indirect_type =
13107                                                 MLX5_INDIRECT_ACTION_TYPE_CT;
13108                                 flow->ct = owner_idx;
13109                                 __atomic_fetch_add(&ct->refcnt, 1,
13110                                                    __ATOMIC_RELAXED);
13111                         }
13112                         actions_n++;
13113                         action_flags |= MLX5_FLOW_ACTION_CT;
13114                         break;
13115                 case RTE_FLOW_ACTION_TYPE_END:
13116                         actions_end = true;
13117                         if (mhdr_res->actions_num) {
13118                                 /* create modify action if needed. */
13119                                 if (flow_dv_modify_hdr_resource_register
13120                                         (dev, mhdr_res, dev_flow, error))
13121                                         return -rte_errno;
13122                                 dev_flow->dv.actions[modify_action_position] =
13123                                         handle->dvh.modify_hdr->action;
13124                         }
13125                         /*
13126                          * Handle AGE and COUNT action by single HW counter
13127                          * when they are not shared.
13128                          */
13129                         if (action_flags & MLX5_FLOW_ACTION_AGE) {
13130                                 if ((non_shared_age && count) ||
13131                                     !(priv->sh->flow_hit_aso_en &&
13132                                       (attr->group || attr->transfer))) {
13133                                         /* Creates age by counters. */
13134                                         cnt_act = flow_dv_prepare_counter
13135                                                                 (dev, dev_flow,
13136                                                                  flow, count,
13137                                                                  non_shared_age,
13138                                                                  error);
13139                                         if (!cnt_act)
13140                                                 return -rte_errno;
13141                                         dev_flow->dv.actions[age_act_pos] =
13142                                                                 cnt_act->action;
13143                                         break;
13144                                 }
13145                                 if (!flow->age && non_shared_age) {
13146                                         flow->age = flow_dv_aso_age_alloc
13147                                                                 (dev, error);
13148                                         if (!flow->age)
13149                                                 return -rte_errno;
13150                                         flow_dv_aso_age_params_init
13151                                                     (dev, flow->age,
13152                                                      non_shared_age->context ?
13153                                                      non_shared_age->context :
13154                                                      (void *)(uintptr_t)
13155                                                      (dev_flow->flow_idx),
13156                                                      non_shared_age->timeout);
13157                                 }
13158                                 age_act = flow_aso_age_get_by_idx(dev,
13159                                                                   flow->age);
13160                                 dev_flow->dv.actions[age_act_pos] =
13161                                                              age_act->dr_action;
13162                         }
13163                         if (action_flags & MLX5_FLOW_ACTION_COUNT) {
13164                                 /*
13165                                  * Create one count action, to be used
13166                                  * by all sub-flows.
13167                                  */
13168                                 cnt_act = flow_dv_prepare_counter(dev, dev_flow,
13169                                                                   flow, count,
13170                                                                   NULL, error);
13171                                 if (!cnt_act)
13172                                         return -rte_errno;
13173                                 dev_flow->dv.actions[actions_n++] =
13174                                                                 cnt_act->action;
13175                         }
13176                 default:
13177                         break;
13178                 }
13179                 if (mhdr_res->actions_num &&
13180                     modify_action_position == UINT32_MAX)
13181                         modify_action_position = actions_n++;
13182         }
13183         for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
13184                 int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL);
13185                 int item_type = items->type;
13186
13187                 if (!mlx5_flow_os_item_supported(item_type))
13188                         return rte_flow_error_set(error, ENOTSUP,
13189                                                   RTE_FLOW_ERROR_TYPE_ITEM,
13190                                                   NULL, "item not supported");
13191                 switch (item_type) {
13192                 case RTE_FLOW_ITEM_TYPE_PORT_ID:
13193                         flow_dv_translate_item_port_id
13194                                 (dev, match_mask, match_value, items, attr);
13195                         last_item = MLX5_FLOW_ITEM_PORT_ID;
13196                         break;
13197                 case RTE_FLOW_ITEM_TYPE_ETH:
13198                         flow_dv_translate_item_eth(match_mask, match_value,
13199                                                    items, tunnel,
13200                                                    dev_flow->dv.group);
13201                         matcher.priority = action_flags &
13202                                         MLX5_FLOW_ACTION_DEFAULT_MISS &&
13203                                         !dev_flow->external ?
13204                                         MLX5_PRIORITY_MAP_L3 :
13205                                         MLX5_PRIORITY_MAP_L2;
13206                         last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L2 :
13207                                              MLX5_FLOW_LAYER_OUTER_L2;
13208                         break;
13209                 case RTE_FLOW_ITEM_TYPE_VLAN:
13210                         flow_dv_translate_item_vlan(dev_flow,
13211                                                     match_mask, match_value,
13212                                                     items, tunnel,
13213                                                     dev_flow->dv.group);
13214                         matcher.priority = MLX5_PRIORITY_MAP_L2;
13215                         last_item = tunnel ? (MLX5_FLOW_LAYER_INNER_L2 |
13216                                               MLX5_FLOW_LAYER_INNER_VLAN) :
13217                                              (MLX5_FLOW_LAYER_OUTER_L2 |
13218                                               MLX5_FLOW_LAYER_OUTER_VLAN);
13219                         break;
13220                 case RTE_FLOW_ITEM_TYPE_IPV4:
13221                         mlx5_flow_tunnel_ip_check(items, next_protocol,
13222                                                   &item_flags, &tunnel);
13223                         flow_dv_translate_item_ipv4(match_mask, match_value,
13224                                                     items, tunnel,
13225                                                     dev_flow->dv.group);
13226                         matcher.priority = MLX5_PRIORITY_MAP_L3;
13227                         last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV4 :
13228                                              MLX5_FLOW_LAYER_OUTER_L3_IPV4;
13229                         if (items->mask != NULL &&
13230                             ((const struct rte_flow_item_ipv4 *)
13231                              items->mask)->hdr.next_proto_id) {
13232                                 next_protocol =
13233                                         ((const struct rte_flow_item_ipv4 *)
13234                                          (items->spec))->hdr.next_proto_id;
13235                                 next_protocol &=
13236                                         ((const struct rte_flow_item_ipv4 *)
13237                                          (items->mask))->hdr.next_proto_id;
13238                         } else {
13239                                 /* Reset for inner layer. */
13240                                 next_protocol = 0xff;
13241                         }
13242                         break;
13243                 case RTE_FLOW_ITEM_TYPE_IPV6:
13244                         mlx5_flow_tunnel_ip_check(items, next_protocol,
13245                                                   &item_flags, &tunnel);
13246                         flow_dv_translate_item_ipv6(match_mask, match_value,
13247                                                     items, tunnel,
13248                                                     dev_flow->dv.group);
13249                         matcher.priority = MLX5_PRIORITY_MAP_L3;
13250                         last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV6 :
13251                                              MLX5_FLOW_LAYER_OUTER_L3_IPV6;
13252                         if (items->mask != NULL &&
13253                             ((const struct rte_flow_item_ipv6 *)
13254                              items->mask)->hdr.proto) {
13255                                 next_protocol =
13256                                         ((const struct rte_flow_item_ipv6 *)
13257                                          items->spec)->hdr.proto;
13258                                 next_protocol &=
13259                                         ((const struct rte_flow_item_ipv6 *)
13260                                          items->mask)->hdr.proto;
13261                         } else {
13262                                 /* Reset for inner layer. */
13263                                 next_protocol = 0xff;
13264                         }
13265                         break;
13266                 case RTE_FLOW_ITEM_TYPE_IPV6_FRAG_EXT:
13267                         flow_dv_translate_item_ipv6_frag_ext(match_mask,
13268                                                              match_value,
13269                                                              items, tunnel);
13270                         last_item = tunnel ?
13271                                         MLX5_FLOW_LAYER_INNER_L3_IPV6_FRAG_EXT :
13272                                         MLX5_FLOW_LAYER_OUTER_L3_IPV6_FRAG_EXT;
13273                         if (items->mask != NULL &&
13274                             ((const struct rte_flow_item_ipv6_frag_ext *)
13275                              items->mask)->hdr.next_header) {
13276                                 next_protocol =
13277                                 ((const struct rte_flow_item_ipv6_frag_ext *)
13278                                  items->spec)->hdr.next_header;
13279                                 next_protocol &=
13280                                 ((const struct rte_flow_item_ipv6_frag_ext *)
13281                                  items->mask)->hdr.next_header;
13282                         } else {
13283                                 /* Reset for inner layer. */
13284                                 next_protocol = 0xff;
13285                         }
13286                         break;
13287                 case RTE_FLOW_ITEM_TYPE_TCP:
13288                         flow_dv_translate_item_tcp(match_mask, match_value,
13289                                                    items, tunnel);
13290                         matcher.priority = MLX5_PRIORITY_MAP_L4;
13291                         last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_TCP :
13292                                              MLX5_FLOW_LAYER_OUTER_L4_TCP;
13293                         break;
13294                 case RTE_FLOW_ITEM_TYPE_UDP:
13295                         flow_dv_translate_item_udp(match_mask, match_value,
13296                                                    items, tunnel);
13297                         matcher.priority = MLX5_PRIORITY_MAP_L4;
13298                         last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_UDP :
13299                                              MLX5_FLOW_LAYER_OUTER_L4_UDP;
13300                         break;
13301                 case RTE_FLOW_ITEM_TYPE_GRE:
13302                         flow_dv_translate_item_gre(match_mask, match_value,
13303                                                    items, tunnel);
13304                         matcher.priority = MLX5_TUNNEL_PRIO_GET(rss_desc);
13305                         last_item = MLX5_FLOW_LAYER_GRE;
13306                         break;
13307                 case RTE_FLOW_ITEM_TYPE_GRE_KEY:
13308                         flow_dv_translate_item_gre_key(match_mask,
13309                                                        match_value, items);
13310                         last_item = MLX5_FLOW_LAYER_GRE_KEY;
13311                         break;
13312                 case RTE_FLOW_ITEM_TYPE_NVGRE:
13313                         flow_dv_translate_item_nvgre(match_mask, match_value,
13314                                                      items, tunnel);
13315                         matcher.priority = MLX5_TUNNEL_PRIO_GET(rss_desc);
13316                         last_item = MLX5_FLOW_LAYER_GRE;
13317                         break;
13318                 case RTE_FLOW_ITEM_TYPE_VXLAN:
13319                         flow_dv_translate_item_vxlan(dev, attr,
13320                                                      match_mask, match_value,
13321                                                      items, tunnel);
13322                         matcher.priority = MLX5_TUNNEL_PRIO_GET(rss_desc);
13323                         last_item = MLX5_FLOW_LAYER_VXLAN;
13324                         break;
13325                 case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
13326                         flow_dv_translate_item_vxlan_gpe(match_mask,
13327                                                          match_value, items,
13328                                                          tunnel);
13329                         matcher.priority = MLX5_TUNNEL_PRIO_GET(rss_desc);
13330                         last_item = MLX5_FLOW_LAYER_VXLAN_GPE;
13331                         break;
13332                 case RTE_FLOW_ITEM_TYPE_GENEVE:
13333                         flow_dv_translate_item_geneve(match_mask, match_value,
13334                                                       items, tunnel);
13335                         matcher.priority = MLX5_TUNNEL_PRIO_GET(rss_desc);
13336                         last_item = MLX5_FLOW_LAYER_GENEVE;
13337                         break;
13338                 case RTE_FLOW_ITEM_TYPE_GENEVE_OPT:
13339                         ret = flow_dv_translate_item_geneve_opt(dev, match_mask,
13340                                                           match_value,
13341                                                           items, error);
13342                         if (ret)
13343                                 return rte_flow_error_set(error, -ret,
13344                                         RTE_FLOW_ERROR_TYPE_ITEM, NULL,
13345                                         "cannot create GENEVE TLV option");
13346                         flow->geneve_tlv_option = 1;
13347                         last_item = MLX5_FLOW_LAYER_GENEVE_OPT;
13348                         break;
13349                 case RTE_FLOW_ITEM_TYPE_MPLS:
13350                         flow_dv_translate_item_mpls(match_mask, match_value,
13351                                                     items, last_item, tunnel);
13352                         matcher.priority = MLX5_TUNNEL_PRIO_GET(rss_desc);
13353                         last_item = MLX5_FLOW_LAYER_MPLS;
13354                         break;
13355                 case RTE_FLOW_ITEM_TYPE_MARK:
13356                         flow_dv_translate_item_mark(dev, match_mask,
13357                                                     match_value, items);
13358                         last_item = MLX5_FLOW_ITEM_MARK;
13359                         break;
13360                 case RTE_FLOW_ITEM_TYPE_META:
13361                         flow_dv_translate_item_meta(dev, match_mask,
13362                                                     match_value, attr, items);
13363                         last_item = MLX5_FLOW_ITEM_METADATA;
13364                         break;
13365                 case RTE_FLOW_ITEM_TYPE_ICMP:
13366                         flow_dv_translate_item_icmp(match_mask, match_value,
13367                                                     items, tunnel);
13368                         last_item = MLX5_FLOW_LAYER_ICMP;
13369                         break;
13370                 case RTE_FLOW_ITEM_TYPE_ICMP6:
13371                         flow_dv_translate_item_icmp6(match_mask, match_value,
13372                                                       items, tunnel);
13373                         last_item = MLX5_FLOW_LAYER_ICMP6;
13374                         break;
13375                 case RTE_FLOW_ITEM_TYPE_TAG:
13376                         flow_dv_translate_item_tag(dev, match_mask,
13377                                                    match_value, items);
13378                         last_item = MLX5_FLOW_ITEM_TAG;
13379                         break;
13380                 case MLX5_RTE_FLOW_ITEM_TYPE_TAG:
13381                         flow_dv_translate_mlx5_item_tag(dev, match_mask,
13382                                                         match_value, items);
13383                         last_item = MLX5_FLOW_ITEM_TAG;
13384                         break;
13385                 case MLX5_RTE_FLOW_ITEM_TYPE_TX_QUEUE:
13386                         flow_dv_translate_item_tx_queue(dev, match_mask,
13387                                                         match_value,
13388                                                         items);
13389                         last_item = MLX5_FLOW_ITEM_TX_QUEUE;
13390                         break;
13391                 case RTE_FLOW_ITEM_TYPE_GTP:
13392                         flow_dv_translate_item_gtp(match_mask, match_value,
13393                                                    items, tunnel);
13394                         matcher.priority = MLX5_TUNNEL_PRIO_GET(rss_desc);
13395                         last_item = MLX5_FLOW_LAYER_GTP;
13396                         break;
13397                 case RTE_FLOW_ITEM_TYPE_GTP_PSC:
13398                         ret = flow_dv_translate_item_gtp_psc(match_mask,
13399                                                           match_value,
13400                                                           items);
13401                         if (ret)
13402                                 return rte_flow_error_set(error, -ret,
13403                                         RTE_FLOW_ERROR_TYPE_ITEM, NULL,
13404                                         "cannot create GTP PSC item");
13405                         last_item = MLX5_FLOW_LAYER_GTP_PSC;
13406                         break;
13407                 case RTE_FLOW_ITEM_TYPE_ECPRI:
13408                         if (!mlx5_flex_parser_ecpri_exist(dev)) {
13409                                 /* Create it only the first time to be used. */
13410                                 ret = mlx5_flex_parser_ecpri_alloc(dev);
13411                                 if (ret)
13412                                         return rte_flow_error_set
13413                                                 (error, -ret,
13414                                                 RTE_FLOW_ERROR_TYPE_ITEM,
13415                                                 NULL,
13416                                                 "cannot create eCPRI parser");
13417                         }
13418                         flow_dv_translate_item_ecpri(dev, match_mask,
13419                                                      match_value, items,
13420                                                      last_item);
13421                         /* No other protocol should follow eCPRI layer. */
13422                         last_item = MLX5_FLOW_LAYER_ECPRI;
13423                         break;
13424                 case RTE_FLOW_ITEM_TYPE_INTEGRITY:
13425                         flow_dv_translate_item_integrity(match_mask,
13426                                                          match_value,
13427                                                          head_item, items);
13428                         break;
13429                 case RTE_FLOW_ITEM_TYPE_CONNTRACK:
13430                         flow_dv_translate_item_aso_ct(dev, match_mask,
13431                                                       match_value, items);
13432                         break;
13433                 default:
13434                         break;
13435                 }
13436                 item_flags |= last_item;
13437         }
13438         /*
13439          * When E-Switch mode is enabled, we have two cases where we need to
13440          * set the source port manually.
13441          * The first one, is in case of Nic steering rule, and the second is
13442          * E-Switch rule where no port_id item was found. In both cases
13443          * the source port is set according the current port in use.
13444          */
13445         if (!(item_flags & MLX5_FLOW_ITEM_PORT_ID) &&
13446             (priv->representor || priv->master)) {
13447                 if (flow_dv_translate_item_port_id(dev, match_mask,
13448                                                    match_value, NULL, attr))
13449                         return -rte_errno;
13450         }
13451 #ifdef RTE_LIBRTE_MLX5_DEBUG
13452         MLX5_ASSERT(!flow_dv_check_valid_spec(matcher.mask.buf,
13453                                               dev_flow->dv.value.buf));
13454 #endif
13455         /*
13456          * Layers may be already initialized from prefix flow if this dev_flow
13457          * is the suffix flow.
13458          */
13459         handle->layers |= item_flags;
13460         if (action_flags & MLX5_FLOW_ACTION_RSS)
13461                 flow_dv_hashfields_set(dev_flow, rss_desc);
13462         /* If has RSS action in the sample action, the Sample/Mirror resource
13463          * should be registered after the hash filed be update.
13464          */
13465         if (action_flags & MLX5_FLOW_ACTION_SAMPLE) {
13466                 ret = flow_dv_translate_action_sample(dev,
13467                                                       sample,
13468                                                       dev_flow, attr,
13469                                                       &num_of_dest,
13470                                                       sample_actions,
13471                                                       &sample_res,
13472                                                       error);
13473                 if (ret < 0)
13474                         return ret;
13475                 ret = flow_dv_create_action_sample(dev,
13476                                                    dev_flow,
13477                                                    num_of_dest,
13478                                                    &sample_res,
13479                                                    &mdest_res,
13480                                                    sample_actions,
13481                                                    action_flags,
13482                                                    error);
13483                 if (ret < 0)
13484                         return rte_flow_error_set
13485                                                 (error, rte_errno,
13486                                                 RTE_FLOW_ERROR_TYPE_ACTION,
13487                                                 NULL,
13488                                                 "cannot create sample action");
13489                 if (num_of_dest > 1) {
13490                         dev_flow->dv.actions[sample_act_pos] =
13491                         dev_flow->dv.dest_array_res->action;
13492                 } else {
13493                         dev_flow->dv.actions[sample_act_pos] =
13494                         dev_flow->dv.sample_res->verbs_action;
13495                 }
13496         }
13497         /*
13498          * For multiple destination (sample action with ratio=1), the encap
13499          * action and port id action will be combined into group action.
13500          * So need remove the original these actions in the flow and only
13501          * use the sample action instead of.
13502          */
13503         if (num_of_dest > 1 &&
13504             (sample_act->dr_port_id_action || sample_act->dr_jump_action)) {
13505                 int i;
13506                 void *temp_actions[MLX5_DV_MAX_NUMBER_OF_ACTIONS] = {0};
13507
13508                 for (i = 0; i < actions_n; i++) {
13509                         if ((sample_act->dr_encap_action &&
13510                                 sample_act->dr_encap_action ==
13511                                 dev_flow->dv.actions[i]) ||
13512                                 (sample_act->dr_port_id_action &&
13513                                 sample_act->dr_port_id_action ==
13514                                 dev_flow->dv.actions[i]) ||
13515                                 (sample_act->dr_jump_action &&
13516                                 sample_act->dr_jump_action ==
13517                                 dev_flow->dv.actions[i]))
13518                                 continue;
13519                         temp_actions[tmp_actions_n++] = dev_flow->dv.actions[i];
13520                 }
13521                 memcpy((void *)dev_flow->dv.actions,
13522                                 (void *)temp_actions,
13523                                 tmp_actions_n * sizeof(void *));
13524                 actions_n = tmp_actions_n;
13525         }
13526         dev_flow->dv.actions_n = actions_n;
13527         dev_flow->act_flags = action_flags;
13528         if (wks->skip_matcher_reg)
13529                 return 0;
13530         /* Register matcher. */
13531         matcher.crc = rte_raw_cksum((const void *)matcher.mask.buf,
13532                                     matcher.mask.size);
13533         matcher.priority = mlx5_get_matcher_priority(dev, attr,
13534                                         matcher.priority);
13535         /**
13536          * When creating meter drop flow in drop table, using original
13537          * 5-tuple match, the matcher priority should be lower than
13538          * mtr_id matcher.
13539          */
13540         if (attr->group == MLX5_FLOW_TABLE_LEVEL_METER &&
13541             dev_flow->dv.table_id == MLX5_MTR_TABLE_ID_DROP &&
13542             matcher.priority <= MLX5_REG_BITS)
13543                 matcher.priority += MLX5_REG_BITS;
13544         /* reserved field no needs to be set to 0 here. */
13545         tbl_key.is_fdb = attr->transfer;
13546         tbl_key.is_egress = attr->egress;
13547         tbl_key.level = dev_flow->dv.group;
13548         tbl_key.id = dev_flow->dv.table_id;
13549         if (flow_dv_matcher_register(dev, &matcher, &tbl_key, dev_flow,
13550                                      tunnel, attr->group, error))
13551                 return -rte_errno;
13552         return 0;
13553 }
13554
13555 /**
13556  * Set hash RX queue by hash fields (see enum ibv_rx_hash_fields)
13557  * and tunnel.
13558  *
13559  * @param[in, out] action
13560  *   Shred RSS action holding hash RX queue objects.
13561  * @param[in] hash_fields
13562  *   Defines combination of packet fields to participate in RX hash.
13563  * @param[in] tunnel
13564  *   Tunnel type
13565  * @param[in] hrxq_idx
13566  *   Hash RX queue index to set.
13567  *
13568  * @return
13569  *   0 on success, otherwise negative errno value.
13570  */
13571 static int
13572 __flow_dv_action_rss_hrxq_set(struct mlx5_shared_action_rss *action,
13573                               const uint64_t hash_fields,
13574                               uint32_t hrxq_idx)
13575 {
13576         uint32_t *hrxqs = action->hrxq;
13577
13578         switch (hash_fields & ~IBV_RX_HASH_INNER) {
13579         case MLX5_RSS_HASH_IPV4:
13580                 /* fall-through. */
13581         case MLX5_RSS_HASH_IPV4_DST_ONLY:
13582                 /* fall-through. */
13583         case MLX5_RSS_HASH_IPV4_SRC_ONLY:
13584                 hrxqs[0] = hrxq_idx;
13585                 return 0;
13586         case MLX5_RSS_HASH_IPV4_TCP:
13587                 /* fall-through. */
13588         case MLX5_RSS_HASH_IPV4_TCP_DST_ONLY:
13589                 /* fall-through. */
13590         case MLX5_RSS_HASH_IPV4_TCP_SRC_ONLY:
13591                 hrxqs[1] = hrxq_idx;
13592                 return 0;
13593         case MLX5_RSS_HASH_IPV4_UDP:
13594                 /* fall-through. */
13595         case MLX5_RSS_HASH_IPV4_UDP_DST_ONLY:
13596                 /* fall-through. */
13597         case MLX5_RSS_HASH_IPV4_UDP_SRC_ONLY:
13598                 hrxqs[2] = hrxq_idx;
13599                 return 0;
13600         case MLX5_RSS_HASH_IPV6:
13601                 /* fall-through. */
13602         case MLX5_RSS_HASH_IPV6_DST_ONLY:
13603                 /* fall-through. */
13604         case MLX5_RSS_HASH_IPV6_SRC_ONLY:
13605                 hrxqs[3] = hrxq_idx;
13606                 return 0;
13607         case MLX5_RSS_HASH_IPV6_TCP:
13608                 /* fall-through. */
13609         case MLX5_RSS_HASH_IPV6_TCP_DST_ONLY:
13610                 /* fall-through. */
13611         case MLX5_RSS_HASH_IPV6_TCP_SRC_ONLY:
13612                 hrxqs[4] = hrxq_idx;
13613                 return 0;
13614         case MLX5_RSS_HASH_IPV6_UDP:
13615                 /* fall-through. */
13616         case MLX5_RSS_HASH_IPV6_UDP_DST_ONLY:
13617                 /* fall-through. */
13618         case MLX5_RSS_HASH_IPV6_UDP_SRC_ONLY:
13619                 hrxqs[5] = hrxq_idx;
13620                 return 0;
13621         case MLX5_RSS_HASH_NONE:
13622                 hrxqs[6] = hrxq_idx;
13623                 return 0;
13624         default:
13625                 return -1;
13626         }
13627 }
13628
13629 /**
13630  * Look up for hash RX queue by hash fields (see enum ibv_rx_hash_fields)
13631  * and tunnel.
13632  *
13633  * @param[in] dev
13634  *   Pointer to the Ethernet device structure.
13635  * @param[in] idx
13636  *   Shared RSS action ID holding hash RX queue objects.
13637  * @param[in] hash_fields
13638  *   Defines combination of packet fields to participate in RX hash.
13639  * @param[in] tunnel
13640  *   Tunnel type
13641  *
13642  * @return
13643  *   Valid hash RX queue index, otherwise 0.
13644  */
13645 static uint32_t
13646 __flow_dv_action_rss_hrxq_lookup(struct rte_eth_dev *dev, uint32_t idx,
13647                                  const uint64_t hash_fields)
13648 {
13649         struct mlx5_priv *priv = dev->data->dev_private;
13650         struct mlx5_shared_action_rss *shared_rss =
13651             mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], idx);
13652         const uint32_t *hrxqs = shared_rss->hrxq;
13653
13654         switch (hash_fields & ~IBV_RX_HASH_INNER) {
13655         case MLX5_RSS_HASH_IPV4:
13656                 /* fall-through. */
13657         case MLX5_RSS_HASH_IPV4_DST_ONLY:
13658                 /* fall-through. */
13659         case MLX5_RSS_HASH_IPV4_SRC_ONLY:
13660                 return hrxqs[0];
13661         case MLX5_RSS_HASH_IPV4_TCP:
13662                 /* fall-through. */
13663         case MLX5_RSS_HASH_IPV4_TCP_DST_ONLY:
13664                 /* fall-through. */
13665         case MLX5_RSS_HASH_IPV4_TCP_SRC_ONLY:
13666                 return hrxqs[1];
13667         case MLX5_RSS_HASH_IPV4_UDP:
13668                 /* fall-through. */
13669         case MLX5_RSS_HASH_IPV4_UDP_DST_ONLY:
13670                 /* fall-through. */
13671         case MLX5_RSS_HASH_IPV4_UDP_SRC_ONLY:
13672                 return hrxqs[2];
13673         case MLX5_RSS_HASH_IPV6:
13674                 /* fall-through. */
13675         case MLX5_RSS_HASH_IPV6_DST_ONLY:
13676                 /* fall-through. */
13677         case MLX5_RSS_HASH_IPV6_SRC_ONLY:
13678                 return hrxqs[3];
13679         case MLX5_RSS_HASH_IPV6_TCP:
13680                 /* fall-through. */
13681         case MLX5_RSS_HASH_IPV6_TCP_DST_ONLY:
13682                 /* fall-through. */
13683         case MLX5_RSS_HASH_IPV6_TCP_SRC_ONLY:
13684                 return hrxqs[4];
13685         case MLX5_RSS_HASH_IPV6_UDP:
13686                 /* fall-through. */
13687         case MLX5_RSS_HASH_IPV6_UDP_DST_ONLY:
13688                 /* fall-through. */
13689         case MLX5_RSS_HASH_IPV6_UDP_SRC_ONLY:
13690                 return hrxqs[5];
13691         case MLX5_RSS_HASH_NONE:
13692                 return hrxqs[6];
13693         default:
13694                 return 0;
13695         }
13696
13697 }
13698
13699 /**
13700  * Apply the flow to the NIC, lock free,
13701  * (mutex should be acquired by caller).
13702  *
13703  * @param[in] dev
13704  *   Pointer to the Ethernet device structure.
13705  * @param[in, out] flow
13706  *   Pointer to flow structure.
13707  * @param[out] error
13708  *   Pointer to error structure.
13709  *
13710  * @return
13711  *   0 on success, a negative errno value otherwise and rte_errno is set.
13712  */
13713 static int
13714 flow_dv_apply(struct rte_eth_dev *dev, struct rte_flow *flow,
13715               struct rte_flow_error *error)
13716 {
13717         struct mlx5_flow_dv_workspace *dv;
13718         struct mlx5_flow_handle *dh;
13719         struct mlx5_flow_handle_dv *dv_h;
13720         struct mlx5_flow *dev_flow;
13721         struct mlx5_priv *priv = dev->data->dev_private;
13722         uint32_t handle_idx;
13723         int n;
13724         int err;
13725         int idx;
13726         struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace();
13727         struct mlx5_flow_rss_desc *rss_desc = &wks->rss_desc;
13728         uint8_t misc_mask;
13729
13730         MLX5_ASSERT(wks);
13731         for (idx = wks->flow_idx - 1; idx >= 0; idx--) {
13732                 dev_flow = &wks->flows[idx];
13733                 dv = &dev_flow->dv;
13734                 dh = dev_flow->handle;
13735                 dv_h = &dh->dvh;
13736                 n = dv->actions_n;
13737                 if (dh->fate_action == MLX5_FLOW_FATE_DROP) {
13738                         if (dv->transfer) {
13739                                 MLX5_ASSERT(priv->sh->dr_drop_action);
13740                                 dv->actions[n++] = priv->sh->dr_drop_action;
13741                         } else {
13742 #ifdef HAVE_MLX5DV_DR
13743                                 /* DR supports drop action placeholder. */
13744                                 MLX5_ASSERT(priv->sh->dr_drop_action);
13745                                 dv->actions[n++] = dv->group ?
13746                                         priv->sh->dr_drop_action :
13747                                         priv->root_drop_action;
13748 #else
13749                                 /* For DV we use the explicit drop queue. */
13750                                 MLX5_ASSERT(priv->drop_queue.hrxq);
13751                                 dv->actions[n++] =
13752                                                 priv->drop_queue.hrxq->action;
13753 #endif
13754                         }
13755                 } else if ((dh->fate_action == MLX5_FLOW_FATE_QUEUE &&
13756                            !dv_h->rix_sample && !dv_h->rix_dest_array)) {
13757                         struct mlx5_hrxq *hrxq;
13758                         uint32_t hrxq_idx;
13759
13760                         hrxq = flow_dv_hrxq_prepare(dev, dev_flow, rss_desc,
13761                                                     &hrxq_idx);
13762                         if (!hrxq) {
13763                                 rte_flow_error_set
13764                                         (error, rte_errno,
13765                                          RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
13766                                          "cannot get hash queue");
13767                                 goto error;
13768                         }
13769                         dh->rix_hrxq = hrxq_idx;
13770                         dv->actions[n++] = hrxq->action;
13771                 } else if (dh->fate_action == MLX5_FLOW_FATE_SHARED_RSS) {
13772                         struct mlx5_hrxq *hrxq = NULL;
13773                         uint32_t hrxq_idx;
13774
13775                         hrxq_idx = __flow_dv_action_rss_hrxq_lookup(dev,
13776                                                 rss_desc->shared_rss,
13777                                                 dev_flow->hash_fields);
13778                         if (hrxq_idx)
13779                                 hrxq = mlx5_ipool_get
13780                                         (priv->sh->ipool[MLX5_IPOOL_HRXQ],
13781                                          hrxq_idx);
13782                         if (!hrxq) {
13783                                 rte_flow_error_set
13784                                         (error, rte_errno,
13785                                          RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
13786                                          "cannot get hash queue");
13787                                 goto error;
13788                         }
13789                         dh->rix_srss = rss_desc->shared_rss;
13790                         dv->actions[n++] = hrxq->action;
13791                 } else if (dh->fate_action == MLX5_FLOW_FATE_DEFAULT_MISS) {
13792                         if (!priv->sh->default_miss_action) {
13793                                 rte_flow_error_set
13794                                         (error, rte_errno,
13795                                          RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
13796                                          "default miss action not be created.");
13797                                 goto error;
13798                         }
13799                         dv->actions[n++] = priv->sh->default_miss_action;
13800                 }
13801                 misc_mask = flow_dv_matcher_enable(dv->value.buf);
13802                 __flow_dv_adjust_buf_size(&dv->value.size, misc_mask);
13803                 err = mlx5_flow_os_create_flow(dv_h->matcher->matcher_object,
13804                                                (void *)&dv->value, n,
13805                                                dv->actions, &dh->drv_flow);
13806                 if (err) {
13807                         rte_flow_error_set
13808                                 (error, errno,
13809                                 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
13810                                 NULL,
13811                                 (!priv->config.allow_duplicate_pattern &&
13812                                 errno == EEXIST) ?
13813                                 "duplicating pattern is not allowed" :
13814                                 "hardware refuses to create flow");
13815                         goto error;
13816                 }
13817                 if (priv->vmwa_context &&
13818                     dh->vf_vlan.tag && !dh->vf_vlan.created) {
13819                         /*
13820                          * The rule contains the VLAN pattern.
13821                          * For VF we are going to create VLAN
13822                          * interface to make hypervisor set correct
13823                          * e-Switch vport context.
13824                          */
13825                         mlx5_vlan_vmwa_acquire(dev, &dh->vf_vlan);
13826                 }
13827         }
13828         return 0;
13829 error:
13830         err = rte_errno; /* Save rte_errno before cleanup. */
13831         SILIST_FOREACH(priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW], flow->dev_handles,
13832                        handle_idx, dh, next) {
13833                 /* hrxq is union, don't clear it if the flag is not set. */
13834                 if (dh->fate_action == MLX5_FLOW_FATE_QUEUE && dh->rix_hrxq) {
13835                         mlx5_hrxq_release(dev, dh->rix_hrxq);
13836                         dh->rix_hrxq = 0;
13837                 } else if (dh->fate_action == MLX5_FLOW_FATE_SHARED_RSS) {
13838                         dh->rix_srss = 0;
13839                 }
13840                 if (dh->vf_vlan.tag && dh->vf_vlan.created)
13841                         mlx5_vlan_vmwa_release(dev, &dh->vf_vlan);
13842         }
13843         rte_errno = err; /* Restore rte_errno. */
13844         return -rte_errno;
13845 }
13846
13847 void
13848 flow_dv_matcher_remove_cb(void *tool_ctx __rte_unused,
13849                           struct mlx5_list_entry *entry)
13850 {
13851         struct mlx5_flow_dv_matcher *resource = container_of(entry,
13852                                                              typeof(*resource),
13853                                                              entry);
13854
13855         claim_zero(mlx5_flow_os_destroy_flow_matcher(resource->matcher_object));
13856         mlx5_free(resource);
13857 }
13858
13859 /**
13860  * Release the flow matcher.
13861  *
13862  * @param dev
13863  *   Pointer to Ethernet device.
13864  * @param port_id
13865  *   Index to port ID action resource.
13866  *
13867  * @return
13868  *   1 while a reference on it exists, 0 when freed.
13869  */
13870 static int
13871 flow_dv_matcher_release(struct rte_eth_dev *dev,
13872                         struct mlx5_flow_handle *handle)
13873 {
13874         struct mlx5_flow_dv_matcher *matcher = handle->dvh.matcher;
13875         struct mlx5_flow_tbl_data_entry *tbl = container_of(matcher->tbl,
13876                                                             typeof(*tbl), tbl);
13877         int ret;
13878
13879         MLX5_ASSERT(matcher->matcher_object);
13880         ret = mlx5_list_unregister(tbl->matchers, &matcher->entry);
13881         flow_dv_tbl_resource_release(MLX5_SH(dev), &tbl->tbl);
13882         return ret;
13883 }
13884
13885 void
13886 flow_dv_encap_decap_remove_cb(void *tool_ctx, struct mlx5_list_entry *entry)
13887 {
13888         struct mlx5_dev_ctx_shared *sh = tool_ctx;
13889         struct mlx5_flow_dv_encap_decap_resource *res =
13890                                        container_of(entry, typeof(*res), entry);
13891
13892         claim_zero(mlx5_flow_os_destroy_flow_action(res->action));
13893         mlx5_ipool_free(sh->ipool[MLX5_IPOOL_DECAP_ENCAP], res->idx);
13894 }
13895
13896 /**
13897  * Release an encap/decap resource.
13898  *
13899  * @param dev
13900  *   Pointer to Ethernet device.
13901  * @param encap_decap_idx
13902  *   Index of encap decap resource.
13903  *
13904  * @return
13905  *   1 while a reference on it exists, 0 when freed.
13906  */
13907 static int
13908 flow_dv_encap_decap_resource_release(struct rte_eth_dev *dev,
13909                                      uint32_t encap_decap_idx)
13910 {
13911         struct mlx5_priv *priv = dev->data->dev_private;
13912         struct mlx5_flow_dv_encap_decap_resource *resource;
13913
13914         resource = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_DECAP_ENCAP],
13915                                   encap_decap_idx);
13916         if (!resource)
13917                 return 0;
13918         MLX5_ASSERT(resource->action);
13919         return mlx5_hlist_unregister(priv->sh->encaps_decaps, &resource->entry);
13920 }
13921
13922 /**
13923  * Release an jump to table action resource.
13924  *
13925  * @param dev
13926  *   Pointer to Ethernet device.
13927  * @param rix_jump
13928  *   Index to the jump action resource.
13929  *
13930  * @return
13931  *   1 while a reference on it exists, 0 when freed.
13932  */
13933 static int
13934 flow_dv_jump_tbl_resource_release(struct rte_eth_dev *dev,
13935                                   uint32_t rix_jump)
13936 {
13937         struct mlx5_priv *priv = dev->data->dev_private;
13938         struct mlx5_flow_tbl_data_entry *tbl_data;
13939
13940         tbl_data = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_JUMP],
13941                                   rix_jump);
13942         if (!tbl_data)
13943                 return 0;
13944         return flow_dv_tbl_resource_release(MLX5_SH(dev), &tbl_data->tbl);
13945 }
13946
13947 void
13948 flow_dv_modify_remove_cb(void *tool_ctx, struct mlx5_list_entry *entry)
13949 {
13950         struct mlx5_flow_dv_modify_hdr_resource *res =
13951                 container_of(entry, typeof(*res), entry);
13952         struct mlx5_dev_ctx_shared *sh = tool_ctx;
13953
13954         claim_zero(mlx5_flow_os_destroy_flow_action(res->action));
13955         mlx5_ipool_free(sh->mdh_ipools[res->actions_num - 1], res->idx);
13956 }
13957
13958 /**
13959  * Release a modify-header resource.
13960  *
13961  * @param dev
13962  *   Pointer to Ethernet device.
13963  * @param handle
13964  *   Pointer to mlx5_flow_handle.
13965  *
13966  * @return
13967  *   1 while a reference on it exists, 0 when freed.
13968  */
13969 static int
13970 flow_dv_modify_hdr_resource_release(struct rte_eth_dev *dev,
13971                                     struct mlx5_flow_handle *handle)
13972 {
13973         struct mlx5_priv *priv = dev->data->dev_private;
13974         struct mlx5_flow_dv_modify_hdr_resource *entry = handle->dvh.modify_hdr;
13975
13976         MLX5_ASSERT(entry->action);
13977         return mlx5_hlist_unregister(priv->sh->modify_cmds, &entry->entry);
13978 }
13979
13980 void
13981 flow_dv_port_id_remove_cb(void *tool_ctx, struct mlx5_list_entry *entry)
13982 {
13983         struct mlx5_dev_ctx_shared *sh = tool_ctx;
13984         struct mlx5_flow_dv_port_id_action_resource *resource =
13985                                   container_of(entry, typeof(*resource), entry);
13986
13987         claim_zero(mlx5_flow_os_destroy_flow_action(resource->action));
13988         mlx5_ipool_free(sh->ipool[MLX5_IPOOL_PORT_ID], resource->idx);
13989 }
13990
13991 /**
13992  * Release port ID action resource.
13993  *
13994  * @param dev
13995  *   Pointer to Ethernet device.
13996  * @param handle
13997  *   Pointer to mlx5_flow_handle.
13998  *
13999  * @return
14000  *   1 while a reference on it exists, 0 when freed.
14001  */
14002 static int
14003 flow_dv_port_id_action_resource_release(struct rte_eth_dev *dev,
14004                                         uint32_t port_id)
14005 {
14006         struct mlx5_priv *priv = dev->data->dev_private;
14007         struct mlx5_flow_dv_port_id_action_resource *resource;
14008
14009         resource = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_PORT_ID], port_id);
14010         if (!resource)
14011                 return 0;
14012         MLX5_ASSERT(resource->action);
14013         return mlx5_list_unregister(priv->sh->port_id_action_list,
14014                                     &resource->entry);
14015 }
14016
14017 /**
14018  * Release shared RSS action resource.
14019  *
14020  * @param dev
14021  *   Pointer to Ethernet device.
14022  * @param srss
14023  *   Shared RSS action index.
14024  */
14025 static void
14026 flow_dv_shared_rss_action_release(struct rte_eth_dev *dev, uint32_t srss)
14027 {
14028         struct mlx5_priv *priv = dev->data->dev_private;
14029         struct mlx5_shared_action_rss *shared_rss;
14030
14031         shared_rss = mlx5_ipool_get
14032                         (priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], srss);
14033         __atomic_sub_fetch(&shared_rss->refcnt, 1, __ATOMIC_RELAXED);
14034 }
14035
14036 void
14037 flow_dv_push_vlan_remove_cb(void *tool_ctx, struct mlx5_list_entry *entry)
14038 {
14039         struct mlx5_dev_ctx_shared *sh = tool_ctx;
14040         struct mlx5_flow_dv_push_vlan_action_resource *resource =
14041                         container_of(entry, typeof(*resource), entry);
14042
14043         claim_zero(mlx5_flow_os_destroy_flow_action(resource->action));
14044         mlx5_ipool_free(sh->ipool[MLX5_IPOOL_PUSH_VLAN], resource->idx);
14045 }
14046
14047 /**
14048  * Release push vlan action resource.
14049  *
14050  * @param dev
14051  *   Pointer to Ethernet device.
14052  * @param handle
14053  *   Pointer to mlx5_flow_handle.
14054  *
14055  * @return
14056  *   1 while a reference on it exists, 0 when freed.
14057  */
14058 static int
14059 flow_dv_push_vlan_action_resource_release(struct rte_eth_dev *dev,
14060                                           struct mlx5_flow_handle *handle)
14061 {
14062         struct mlx5_priv *priv = dev->data->dev_private;
14063         struct mlx5_flow_dv_push_vlan_action_resource *resource;
14064         uint32_t idx = handle->dvh.rix_push_vlan;
14065
14066         resource = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_PUSH_VLAN], idx);
14067         if (!resource)
14068                 return 0;
14069         MLX5_ASSERT(resource->action);
14070         return mlx5_list_unregister(priv->sh->push_vlan_action_list,
14071                                     &resource->entry);
14072 }
14073
14074 /**
14075  * Release the fate resource.
14076  *
14077  * @param dev
14078  *   Pointer to Ethernet device.
14079  * @param handle
14080  *   Pointer to mlx5_flow_handle.
14081  */
14082 static void
14083 flow_dv_fate_resource_release(struct rte_eth_dev *dev,
14084                                struct mlx5_flow_handle *handle)
14085 {
14086         if (!handle->rix_fate)
14087                 return;
14088         switch (handle->fate_action) {
14089         case MLX5_FLOW_FATE_QUEUE:
14090                 if (!handle->dvh.rix_sample && !handle->dvh.rix_dest_array)
14091                         mlx5_hrxq_release(dev, handle->rix_hrxq);
14092                 break;
14093         case MLX5_FLOW_FATE_JUMP:
14094                 flow_dv_jump_tbl_resource_release(dev, handle->rix_jump);
14095                 break;
14096         case MLX5_FLOW_FATE_PORT_ID:
14097                 flow_dv_port_id_action_resource_release(dev,
14098                                 handle->rix_port_id_action);
14099                 break;
14100         default:
14101                 DRV_LOG(DEBUG, "Incorrect fate action:%d", handle->fate_action);
14102                 break;
14103         }
14104         handle->rix_fate = 0;
14105 }
14106
14107 void
14108 flow_dv_sample_remove_cb(void *tool_ctx __rte_unused,
14109                          struct mlx5_list_entry *entry)
14110 {
14111         struct mlx5_flow_dv_sample_resource *resource = container_of(entry,
14112                                                               typeof(*resource),
14113                                                               entry);
14114         struct rte_eth_dev *dev = resource->dev;
14115         struct mlx5_priv *priv = dev->data->dev_private;
14116
14117         if (resource->verbs_action)
14118                 claim_zero(mlx5_flow_os_destroy_flow_action
14119                                                       (resource->verbs_action));
14120         if (resource->normal_path_tbl)
14121                 flow_dv_tbl_resource_release(MLX5_SH(dev),
14122                                              resource->normal_path_tbl);
14123         flow_dv_sample_sub_actions_release(dev, &resource->sample_idx);
14124         mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_SAMPLE], resource->idx);
14125         DRV_LOG(DEBUG, "sample resource %p: removed", (void *)resource);
14126 }
14127
14128 /**
14129  * Release an sample resource.
14130  *
14131  * @param dev
14132  *   Pointer to Ethernet device.
14133  * @param handle
14134  *   Pointer to mlx5_flow_handle.
14135  *
14136  * @return
14137  *   1 while a reference on it exists, 0 when freed.
14138  */
14139 static int
14140 flow_dv_sample_resource_release(struct rte_eth_dev *dev,
14141                                      struct mlx5_flow_handle *handle)
14142 {
14143         struct mlx5_priv *priv = dev->data->dev_private;
14144         struct mlx5_flow_dv_sample_resource *resource;
14145
14146         resource = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_SAMPLE],
14147                                   handle->dvh.rix_sample);
14148         if (!resource)
14149                 return 0;
14150         MLX5_ASSERT(resource->verbs_action);
14151         return mlx5_list_unregister(priv->sh->sample_action_list,
14152                                     &resource->entry);
14153 }
14154
14155 void
14156 flow_dv_dest_array_remove_cb(void *tool_ctx __rte_unused,
14157                              struct mlx5_list_entry *entry)
14158 {
14159         struct mlx5_flow_dv_dest_array_resource *resource =
14160                         container_of(entry, typeof(*resource), entry);
14161         struct rte_eth_dev *dev = resource->dev;
14162         struct mlx5_priv *priv = dev->data->dev_private;
14163         uint32_t i = 0;
14164
14165         MLX5_ASSERT(resource->action);
14166         if (resource->action)
14167                 claim_zero(mlx5_flow_os_destroy_flow_action(resource->action));
14168         for (; i < resource->num_of_dest; i++)
14169                 flow_dv_sample_sub_actions_release(dev,
14170                                                    &resource->sample_idx[i]);
14171         mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_DEST_ARRAY], resource->idx);
14172         DRV_LOG(DEBUG, "destination array resource %p: removed",
14173                 (void *)resource);
14174 }
14175
14176 /**
14177  * Release an destination array resource.
14178  *
14179  * @param dev
14180  *   Pointer to Ethernet device.
14181  * @param handle
14182  *   Pointer to mlx5_flow_handle.
14183  *
14184  * @return
14185  *   1 while a reference on it exists, 0 when freed.
14186  */
14187 static int
14188 flow_dv_dest_array_resource_release(struct rte_eth_dev *dev,
14189                                     struct mlx5_flow_handle *handle)
14190 {
14191         struct mlx5_priv *priv = dev->data->dev_private;
14192         struct mlx5_flow_dv_dest_array_resource *resource;
14193
14194         resource = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_DEST_ARRAY],
14195                                   handle->dvh.rix_dest_array);
14196         if (!resource)
14197                 return 0;
14198         MLX5_ASSERT(resource->action);
14199         return mlx5_list_unregister(priv->sh->dest_array_list,
14200                                     &resource->entry);
14201 }
14202
14203 static void
14204 flow_dv_geneve_tlv_option_resource_release(struct rte_eth_dev *dev)
14205 {
14206         struct mlx5_priv *priv = dev->data->dev_private;
14207         struct mlx5_dev_ctx_shared *sh = priv->sh;
14208         struct mlx5_geneve_tlv_option_resource *geneve_opt_resource =
14209                                 sh->geneve_tlv_option_resource;
14210         rte_spinlock_lock(&sh->geneve_tlv_opt_sl);
14211         if (geneve_opt_resource) {
14212                 if (!(__atomic_sub_fetch(&geneve_opt_resource->refcnt, 1,
14213                                          __ATOMIC_RELAXED))) {
14214                         claim_zero(mlx5_devx_cmd_destroy
14215                                         (geneve_opt_resource->obj));
14216                         mlx5_free(sh->geneve_tlv_option_resource);
14217                         sh->geneve_tlv_option_resource = NULL;
14218                 }
14219         }
14220         rte_spinlock_unlock(&sh->geneve_tlv_opt_sl);
14221 }
14222
14223 /**
14224  * Remove the flow from the NIC but keeps it in memory.
14225  * Lock free, (mutex should be acquired by caller).
14226  *
14227  * @param[in] dev
14228  *   Pointer to Ethernet device.
14229  * @param[in, out] flow
14230  *   Pointer to flow structure.
14231  */
14232 static void
14233 flow_dv_remove(struct rte_eth_dev *dev, struct rte_flow *flow)
14234 {
14235         struct mlx5_flow_handle *dh;
14236         uint32_t handle_idx;
14237         struct mlx5_priv *priv = dev->data->dev_private;
14238
14239         if (!flow)
14240                 return;
14241         handle_idx = flow->dev_handles;
14242         while (handle_idx) {
14243                 dh = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW],
14244                                     handle_idx);
14245                 if (!dh)
14246                         return;
14247                 if (dh->drv_flow) {
14248                         claim_zero(mlx5_flow_os_destroy_flow(dh->drv_flow));
14249                         dh->drv_flow = NULL;
14250                 }
14251                 if (dh->fate_action == MLX5_FLOW_FATE_QUEUE)
14252                         flow_dv_fate_resource_release(dev, dh);
14253                 if (dh->vf_vlan.tag && dh->vf_vlan.created)
14254                         mlx5_vlan_vmwa_release(dev, &dh->vf_vlan);
14255                 handle_idx = dh->next.next;
14256         }
14257 }
14258
14259 /**
14260  * Remove the flow from the NIC and the memory.
14261  * Lock free, (mutex should be acquired by caller).
14262  *
14263  * @param[in] dev
14264  *   Pointer to the Ethernet device structure.
14265  * @param[in, out] flow
14266  *   Pointer to flow structure.
14267  */
14268 static void
14269 flow_dv_destroy(struct rte_eth_dev *dev, struct rte_flow *flow)
14270 {
14271         struct mlx5_flow_handle *dev_handle;
14272         struct mlx5_priv *priv = dev->data->dev_private;
14273         struct mlx5_flow_meter_info *fm = NULL;
14274         uint32_t srss = 0;
14275
14276         if (!flow)
14277                 return;
14278         flow_dv_remove(dev, flow);
14279         if (flow->counter) {
14280                 flow_dv_counter_free(dev, flow->counter);
14281                 flow->counter = 0;
14282         }
14283         if (flow->meter) {
14284                 fm = flow_dv_meter_find_by_idx(priv, flow->meter);
14285                 if (fm)
14286                         mlx5_flow_meter_detach(priv, fm);
14287                 flow->meter = 0;
14288         }
14289         /* Keep the current age handling by default. */
14290         if (flow->indirect_type == MLX5_INDIRECT_ACTION_TYPE_CT && flow->ct)
14291                 flow_dv_aso_ct_release(dev, flow->ct, NULL);
14292         else if (flow->age)
14293                 flow_dv_aso_age_release(dev, flow->age);
14294         if (flow->geneve_tlv_option) {
14295                 flow_dv_geneve_tlv_option_resource_release(dev);
14296                 flow->geneve_tlv_option = 0;
14297         }
14298         while (flow->dev_handles) {
14299                 uint32_t tmp_idx = flow->dev_handles;
14300
14301                 dev_handle = mlx5_ipool_get(priv->sh->ipool
14302                                             [MLX5_IPOOL_MLX5_FLOW], tmp_idx);
14303                 if (!dev_handle)
14304                         return;
14305                 flow->dev_handles = dev_handle->next.next;
14306                 if (dev_handle->dvh.matcher)
14307                         flow_dv_matcher_release(dev, dev_handle);
14308                 if (dev_handle->dvh.rix_sample)
14309                         flow_dv_sample_resource_release(dev, dev_handle);
14310                 if (dev_handle->dvh.rix_dest_array)
14311                         flow_dv_dest_array_resource_release(dev, dev_handle);
14312                 if (dev_handle->dvh.rix_encap_decap)
14313                         flow_dv_encap_decap_resource_release(dev,
14314                                 dev_handle->dvh.rix_encap_decap);
14315                 if (dev_handle->dvh.modify_hdr)
14316                         flow_dv_modify_hdr_resource_release(dev, dev_handle);
14317                 if (dev_handle->dvh.rix_push_vlan)
14318                         flow_dv_push_vlan_action_resource_release(dev,
14319                                                                   dev_handle);
14320                 if (dev_handle->dvh.rix_tag)
14321                         flow_dv_tag_release(dev,
14322                                             dev_handle->dvh.rix_tag);
14323                 if (dev_handle->fate_action != MLX5_FLOW_FATE_SHARED_RSS)
14324                         flow_dv_fate_resource_release(dev, dev_handle);
14325                 else if (!srss)
14326                         srss = dev_handle->rix_srss;
14327                 if (fm && dev_handle->is_meter_flow_id &&
14328                     dev_handle->split_flow_id)
14329                         mlx5_ipool_free(fm->flow_ipool,
14330                                         dev_handle->split_flow_id);
14331                 else if (dev_handle->split_flow_id &&
14332                     !dev_handle->is_meter_flow_id)
14333                         mlx5_ipool_free(priv->sh->ipool
14334                                         [MLX5_IPOOL_RSS_EXPANTION_FLOW_ID],
14335                                         dev_handle->split_flow_id);
14336                 mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW],
14337                            tmp_idx);
14338         }
14339         if (srss)
14340                 flow_dv_shared_rss_action_release(dev, srss);
14341 }
14342
14343 /**
14344  * Release array of hash RX queue objects.
14345  * Helper function.
14346  *
14347  * @param[in] dev
14348  *   Pointer to the Ethernet device structure.
14349  * @param[in, out] hrxqs
14350  *   Array of hash RX queue objects.
14351  *
14352  * @return
14353  *   Total number of references to hash RX queue objects in *hrxqs* array
14354  *   after this operation.
14355  */
14356 static int
14357 __flow_dv_hrxqs_release(struct rte_eth_dev *dev,
14358                         uint32_t (*hrxqs)[MLX5_RSS_HASH_FIELDS_LEN])
14359 {
14360         size_t i;
14361         int remaining = 0;
14362
14363         for (i = 0; i < RTE_DIM(*hrxqs); i++) {
14364                 int ret = mlx5_hrxq_release(dev, (*hrxqs)[i]);
14365
14366                 if (!ret)
14367                         (*hrxqs)[i] = 0;
14368                 remaining += ret;
14369         }
14370         return remaining;
14371 }
14372
14373 /**
14374  * Release all hash RX queue objects representing shared RSS action.
14375  *
14376  * @param[in] dev
14377  *   Pointer to the Ethernet device structure.
14378  * @param[in, out] action
14379  *   Shared RSS action to remove hash RX queue objects from.
14380  *
14381  * @return
14382  *   Total number of references to hash RX queue objects stored in *action*
14383  *   after this operation.
14384  *   Expected to be 0 if no external references held.
14385  */
14386 static int
14387 __flow_dv_action_rss_hrxqs_release(struct rte_eth_dev *dev,
14388                                  struct mlx5_shared_action_rss *shared_rss)
14389 {
14390         return __flow_dv_hrxqs_release(dev, &shared_rss->hrxq);
14391 }
14392
14393 /**
14394  * Adjust L3/L4 hash value of pre-created shared RSS hrxq according to
14395  * user input.
14396  *
14397  * Only one hash value is available for one L3+L4 combination:
14398  * for example:
14399  * MLX5_RSS_HASH_IPV4, MLX5_RSS_HASH_IPV4_SRC_ONLY, and
14400  * MLX5_RSS_HASH_IPV4_DST_ONLY are mutually exclusive so they can share
14401  * same slot in mlx5_rss_hash_fields.
14402  *
14403  * @param[in] rss
14404  *   Pointer to the shared action RSS conf.
14405  * @param[in, out] hash_field
14406  *   hash_field variable needed to be adjusted.
14407  *
14408  * @return
14409  *   void
14410  */
14411 static void
14412 __flow_dv_action_rss_l34_hash_adjust(struct mlx5_shared_action_rss *rss,
14413                                      uint64_t *hash_field)
14414 {
14415         uint64_t rss_types = rss->origin.types;
14416
14417         switch (*hash_field & ~IBV_RX_HASH_INNER) {
14418         case MLX5_RSS_HASH_IPV4:
14419                 if (rss_types & MLX5_IPV4_LAYER_TYPES) {
14420                         *hash_field &= ~MLX5_RSS_HASH_IPV4;
14421                         if (rss_types & ETH_RSS_L3_DST_ONLY)
14422                                 *hash_field |= IBV_RX_HASH_DST_IPV4;
14423                         else if (rss_types & ETH_RSS_L3_SRC_ONLY)
14424                                 *hash_field |= IBV_RX_HASH_SRC_IPV4;
14425                         else
14426                                 *hash_field |= MLX5_RSS_HASH_IPV4;
14427                 }
14428                 return;
14429         case MLX5_RSS_HASH_IPV6:
14430                 if (rss_types & MLX5_IPV6_LAYER_TYPES) {
14431                         *hash_field &= ~MLX5_RSS_HASH_IPV6;
14432                         if (rss_types & ETH_RSS_L3_DST_ONLY)
14433                                 *hash_field |= IBV_RX_HASH_DST_IPV6;
14434                         else if (rss_types & ETH_RSS_L3_SRC_ONLY)
14435                                 *hash_field |= IBV_RX_HASH_SRC_IPV6;
14436                         else
14437                                 *hash_field |= MLX5_RSS_HASH_IPV6;
14438                 }
14439                 return;
14440         case MLX5_RSS_HASH_IPV4_UDP:
14441                 /* fall-through. */
14442         case MLX5_RSS_HASH_IPV6_UDP:
14443                 if (rss_types & ETH_RSS_UDP) {
14444                         *hash_field &= ~MLX5_UDP_IBV_RX_HASH;
14445                         if (rss_types & ETH_RSS_L4_DST_ONLY)
14446                                 *hash_field |= IBV_RX_HASH_DST_PORT_UDP;
14447                         else if (rss_types & ETH_RSS_L4_SRC_ONLY)
14448                                 *hash_field |= IBV_RX_HASH_SRC_PORT_UDP;
14449                         else
14450                                 *hash_field |= MLX5_UDP_IBV_RX_HASH;
14451                 }
14452                 return;
14453         case MLX5_RSS_HASH_IPV4_TCP:
14454                 /* fall-through. */
14455         case MLX5_RSS_HASH_IPV6_TCP:
14456                 if (rss_types & ETH_RSS_TCP) {
14457                         *hash_field &= ~MLX5_TCP_IBV_RX_HASH;
14458                         if (rss_types & ETH_RSS_L4_DST_ONLY)
14459                                 *hash_field |= IBV_RX_HASH_DST_PORT_TCP;
14460                         else if (rss_types & ETH_RSS_L4_SRC_ONLY)
14461                                 *hash_field |= IBV_RX_HASH_SRC_PORT_TCP;
14462                         else
14463                                 *hash_field |= MLX5_TCP_IBV_RX_HASH;
14464                 }
14465                 return;
14466         default:
14467                 return;
14468         }
14469 }
14470
14471 /**
14472  * Setup shared RSS action.
14473  * Prepare set of hash RX queue objects sufficient to handle all valid
14474  * hash_fields combinations (see enum ibv_rx_hash_fields).
14475  *
14476  * @param[in] dev
14477  *   Pointer to the Ethernet device structure.
14478  * @param[in] action_idx
14479  *   Shared RSS action ipool index.
14480  * @param[in, out] action
14481  *   Partially initialized shared RSS action.
14482  * @param[out] error
14483  *   Perform verbose error reporting if not NULL. Initialized in case of
14484  *   error only.
14485  *
14486  * @return
14487  *   0 on success, otherwise negative errno value.
14488  */
14489 static int
14490 __flow_dv_action_rss_setup(struct rte_eth_dev *dev,
14491                            uint32_t action_idx,
14492                            struct mlx5_shared_action_rss *shared_rss,
14493                            struct rte_flow_error *error)
14494 {
14495         struct mlx5_flow_rss_desc rss_desc = { 0 };
14496         size_t i;
14497         int err;
14498
14499         if (mlx5_ind_table_obj_setup(dev, shared_rss->ind_tbl)) {
14500                 return rte_flow_error_set(error, rte_errno,
14501                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
14502                                           "cannot setup indirection table");
14503         }
14504         memcpy(rss_desc.key, shared_rss->origin.key, MLX5_RSS_HASH_KEY_LEN);
14505         rss_desc.key_len = MLX5_RSS_HASH_KEY_LEN;
14506         rss_desc.const_q = shared_rss->origin.queue;
14507         rss_desc.queue_num = shared_rss->origin.queue_num;
14508         /* Set non-zero value to indicate a shared RSS. */
14509         rss_desc.shared_rss = action_idx;
14510         rss_desc.ind_tbl = shared_rss->ind_tbl;
14511         for (i = 0; i < MLX5_RSS_HASH_FIELDS_LEN; i++) {
14512                 uint32_t hrxq_idx;
14513                 uint64_t hash_fields = mlx5_rss_hash_fields[i];
14514                 int tunnel = 0;
14515
14516                 __flow_dv_action_rss_l34_hash_adjust(shared_rss, &hash_fields);
14517                 if (shared_rss->origin.level > 1) {
14518                         hash_fields |= IBV_RX_HASH_INNER;
14519                         tunnel = 1;
14520                 }
14521                 rss_desc.tunnel = tunnel;
14522                 rss_desc.hash_fields = hash_fields;
14523                 hrxq_idx = mlx5_hrxq_get(dev, &rss_desc);
14524                 if (!hrxq_idx) {
14525                         rte_flow_error_set
14526                                 (error, rte_errno,
14527                                  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
14528                                  "cannot get hash queue");
14529                         goto error_hrxq_new;
14530                 }
14531                 err = __flow_dv_action_rss_hrxq_set
14532                         (shared_rss, hash_fields, hrxq_idx);
14533                 MLX5_ASSERT(!err);
14534         }
14535         return 0;
14536 error_hrxq_new:
14537         err = rte_errno;
14538         __flow_dv_action_rss_hrxqs_release(dev, shared_rss);
14539         if (!mlx5_ind_table_obj_release(dev, shared_rss->ind_tbl, true))
14540                 shared_rss->ind_tbl = NULL;
14541         rte_errno = err;
14542         return -rte_errno;
14543 }
14544
14545 /**
14546  * Create shared RSS action.
14547  *
14548  * @param[in] dev
14549  *   Pointer to the Ethernet device structure.
14550  * @param[in] conf
14551  *   Shared action configuration.
14552  * @param[in] rss
14553  *   RSS action specification used to create shared action.
14554  * @param[out] error
14555  *   Perform verbose error reporting if not NULL. Initialized in case of
14556  *   error only.
14557  *
14558  * @return
14559  *   A valid shared action ID in case of success, 0 otherwise and
14560  *   rte_errno is set.
14561  */
14562 static uint32_t
14563 __flow_dv_action_rss_create(struct rte_eth_dev *dev,
14564                             const struct rte_flow_indir_action_conf *conf,
14565                             const struct rte_flow_action_rss *rss,
14566                             struct rte_flow_error *error)
14567 {
14568         struct mlx5_priv *priv = dev->data->dev_private;
14569         struct mlx5_shared_action_rss *shared_rss = NULL;
14570         void *queue = NULL;
14571         struct rte_flow_action_rss *origin;
14572         const uint8_t *rss_key;
14573         uint32_t queue_size = rss->queue_num * sizeof(uint16_t);
14574         uint32_t idx;
14575
14576         RTE_SET_USED(conf);
14577         queue = mlx5_malloc(0, RTE_ALIGN_CEIL(queue_size, sizeof(void *)),
14578                             0, SOCKET_ID_ANY);
14579         shared_rss = mlx5_ipool_zmalloc
14580                          (priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], &idx);
14581         if (!shared_rss || !queue) {
14582                 rte_flow_error_set(error, ENOMEM,
14583                                    RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
14584                                    "cannot allocate resource memory");
14585                 goto error_rss_init;
14586         }
14587         if (idx > (1u << MLX5_INDIRECT_ACTION_TYPE_OFFSET)) {
14588                 rte_flow_error_set(error, E2BIG,
14589                                    RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
14590                                    "rss action number out of range");
14591                 goto error_rss_init;
14592         }
14593         shared_rss->ind_tbl = mlx5_malloc(MLX5_MEM_ZERO,
14594                                           sizeof(*shared_rss->ind_tbl),
14595                                           0, SOCKET_ID_ANY);
14596         if (!shared_rss->ind_tbl) {
14597                 rte_flow_error_set(error, ENOMEM,
14598                                    RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
14599                                    "cannot allocate resource memory");
14600                 goto error_rss_init;
14601         }
14602         memcpy(queue, rss->queue, queue_size);
14603         shared_rss->ind_tbl->queues = queue;
14604         shared_rss->ind_tbl->queues_n = rss->queue_num;
14605         origin = &shared_rss->origin;
14606         origin->func = rss->func;
14607         origin->level = rss->level;
14608         /* RSS type 0 indicates default RSS type (ETH_RSS_IP). */
14609         origin->types = !rss->types ? ETH_RSS_IP : rss->types;
14610         /* NULL RSS key indicates default RSS key. */
14611         rss_key = !rss->key ? rss_hash_default_key : rss->key;
14612         memcpy(shared_rss->key, rss_key, MLX5_RSS_HASH_KEY_LEN);
14613         origin->key = &shared_rss->key[0];
14614         origin->key_len = MLX5_RSS_HASH_KEY_LEN;
14615         origin->queue = queue;
14616         origin->queue_num = rss->queue_num;
14617         if (__flow_dv_action_rss_setup(dev, idx, shared_rss, error))
14618                 goto error_rss_init;
14619         rte_spinlock_init(&shared_rss->action_rss_sl);
14620         __atomic_add_fetch(&shared_rss->refcnt, 1, __ATOMIC_RELAXED);
14621         rte_spinlock_lock(&priv->shared_act_sl);
14622         ILIST_INSERT(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS],
14623                      &priv->rss_shared_actions, idx, shared_rss, next);
14624         rte_spinlock_unlock(&priv->shared_act_sl);
14625         return idx;
14626 error_rss_init:
14627         if (shared_rss) {
14628                 if (shared_rss->ind_tbl)
14629                         mlx5_free(shared_rss->ind_tbl);
14630                 mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS],
14631                                 idx);
14632         }
14633         if (queue)
14634                 mlx5_free(queue);
14635         return 0;
14636 }
14637
14638 /**
14639  * Destroy the shared RSS action.
14640  * Release related hash RX queue objects.
14641  *
14642  * @param[in] dev
14643  *   Pointer to the Ethernet device structure.
14644  * @param[in] idx
14645  *   The shared RSS action object ID to be removed.
14646  * @param[out] error
14647  *   Perform verbose error reporting if not NULL. Initialized in case of
14648  *   error only.
14649  *
14650  * @return
14651  *   0 on success, otherwise negative errno value.
14652  */
14653 static int
14654 __flow_dv_action_rss_release(struct rte_eth_dev *dev, uint32_t idx,
14655                              struct rte_flow_error *error)
14656 {
14657         struct mlx5_priv *priv = dev->data->dev_private;
14658         struct mlx5_shared_action_rss *shared_rss =
14659             mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], idx);
14660         uint32_t old_refcnt = 1;
14661         int remaining;
14662         uint16_t *queue = NULL;
14663
14664         if (!shared_rss)
14665                 return rte_flow_error_set(error, EINVAL,
14666                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
14667                                           "invalid shared action");
14668         if (!__atomic_compare_exchange_n(&shared_rss->refcnt, &old_refcnt,
14669                                          0, 0, __ATOMIC_ACQUIRE,
14670                                          __ATOMIC_RELAXED))
14671                 return rte_flow_error_set(error, EBUSY,
14672                                           RTE_FLOW_ERROR_TYPE_ACTION,
14673                                           NULL,
14674                                           "shared rss has references");
14675         remaining = __flow_dv_action_rss_hrxqs_release(dev, shared_rss);
14676         if (remaining)
14677                 return rte_flow_error_set(error, EBUSY,
14678                                           RTE_FLOW_ERROR_TYPE_ACTION,
14679                                           NULL,
14680                                           "shared rss hrxq has references");
14681         queue = shared_rss->ind_tbl->queues;
14682         remaining = mlx5_ind_table_obj_release(dev, shared_rss->ind_tbl, true);
14683         if (remaining)
14684                 return rte_flow_error_set(error, EBUSY,
14685                                           RTE_FLOW_ERROR_TYPE_ACTION,
14686                                           NULL,
14687                                           "shared rss indirection table has"
14688                                           " references");
14689         mlx5_free(queue);
14690         rte_spinlock_lock(&priv->shared_act_sl);
14691         ILIST_REMOVE(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS],
14692                      &priv->rss_shared_actions, idx, shared_rss, next);
14693         rte_spinlock_unlock(&priv->shared_act_sl);
14694         mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS],
14695                         idx);
14696         return 0;
14697 }
14698
14699 /**
14700  * Create indirect action, lock free,
14701  * (mutex should be acquired by caller).
14702  * Dispatcher for action type specific call.
14703  *
14704  * @param[in] dev
14705  *   Pointer to the Ethernet device structure.
14706  * @param[in] conf
14707  *   Shared action configuration.
14708  * @param[in] action
14709  *   Action specification used to create indirect action.
14710  * @param[out] error
14711  *   Perform verbose error reporting if not NULL. Initialized in case of
14712  *   error only.
14713  *
14714  * @return
14715  *   A valid shared action handle in case of success, NULL otherwise and
14716  *   rte_errno is set.
14717  */
14718 static struct rte_flow_action_handle *
14719 flow_dv_action_create(struct rte_eth_dev *dev,
14720                       const struct rte_flow_indir_action_conf *conf,
14721                       const struct rte_flow_action *action,
14722                       struct rte_flow_error *err)
14723 {
14724         struct mlx5_priv *priv = dev->data->dev_private;
14725         uint32_t age_idx = 0;
14726         uint32_t idx = 0;
14727         uint32_t ret = 0;
14728
14729         switch (action->type) {
14730         case RTE_FLOW_ACTION_TYPE_RSS:
14731                 ret = __flow_dv_action_rss_create(dev, conf, action->conf, err);
14732                 idx = (MLX5_INDIRECT_ACTION_TYPE_RSS <<
14733                        MLX5_INDIRECT_ACTION_TYPE_OFFSET) | ret;
14734                 break;
14735         case RTE_FLOW_ACTION_TYPE_AGE:
14736                 age_idx = flow_dv_aso_age_alloc(dev, err);
14737                 if (!age_idx) {
14738                         ret = -rte_errno;
14739                         break;
14740                 }
14741                 idx = (MLX5_INDIRECT_ACTION_TYPE_AGE <<
14742                        MLX5_INDIRECT_ACTION_TYPE_OFFSET) | age_idx;
14743                 flow_dv_aso_age_params_init(dev, age_idx,
14744                                         ((const struct rte_flow_action_age *)
14745                                                 action->conf)->context ?
14746                                         ((const struct rte_flow_action_age *)
14747                                                 action->conf)->context :
14748                                         (void *)(uintptr_t)idx,
14749                                         ((const struct rte_flow_action_age *)
14750                                                 action->conf)->timeout);
14751                 ret = age_idx;
14752                 break;
14753         case RTE_FLOW_ACTION_TYPE_COUNT:
14754                 ret = flow_dv_translate_create_counter(dev, NULL, NULL, NULL);
14755                 idx = (MLX5_INDIRECT_ACTION_TYPE_COUNT <<
14756                        MLX5_INDIRECT_ACTION_TYPE_OFFSET) | ret;
14757                 break;
14758         case RTE_FLOW_ACTION_TYPE_CONNTRACK:
14759                 ret = flow_dv_translate_create_conntrack(dev, action->conf,
14760                                                          err);
14761                 idx = MLX5_INDIRECT_ACT_CT_GEN_IDX(PORT_ID(priv), ret);
14762                 break;
14763         default:
14764                 rte_flow_error_set(err, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION,
14765                                    NULL, "action type not supported");
14766                 break;
14767         }
14768         return ret ? (struct rte_flow_action_handle *)(uintptr_t)idx : NULL;
14769 }
14770
14771 /**
14772  * Destroy the indirect action.
14773  * Release action related resources on the NIC and the memory.
14774  * Lock free, (mutex should be acquired by caller).
14775  * Dispatcher for action type specific call.
14776  *
14777  * @param[in] dev
14778  *   Pointer to the Ethernet device structure.
14779  * @param[in] handle
14780  *   The indirect action object handle to be removed.
14781  * @param[out] error
14782  *   Perform verbose error reporting if not NULL. Initialized in case of
14783  *   error only.
14784  *
14785  * @return
14786  *   0 on success, otherwise negative errno value.
14787  */
14788 static int
14789 flow_dv_action_destroy(struct rte_eth_dev *dev,
14790                        struct rte_flow_action_handle *handle,
14791                        struct rte_flow_error *error)
14792 {
14793         uint32_t act_idx = (uint32_t)(uintptr_t)handle;
14794         uint32_t type = act_idx >> MLX5_INDIRECT_ACTION_TYPE_OFFSET;
14795         uint32_t idx = act_idx & ((1u << MLX5_INDIRECT_ACTION_TYPE_OFFSET) - 1);
14796         struct mlx5_flow_counter *cnt;
14797         uint32_t no_flow_refcnt = 1;
14798         int ret;
14799
14800         switch (type) {
14801         case MLX5_INDIRECT_ACTION_TYPE_RSS:
14802                 return __flow_dv_action_rss_release(dev, idx, error);
14803         case MLX5_INDIRECT_ACTION_TYPE_COUNT:
14804                 cnt = flow_dv_counter_get_by_idx(dev, idx, NULL);
14805                 if (!__atomic_compare_exchange_n(&cnt->shared_info.refcnt,
14806                                                  &no_flow_refcnt, 1, false,
14807                                                  __ATOMIC_ACQUIRE,
14808                                                  __ATOMIC_RELAXED))
14809                         return rte_flow_error_set(error, EBUSY,
14810                                                   RTE_FLOW_ERROR_TYPE_ACTION,
14811                                                   NULL,
14812                                                   "Indirect count action has references");
14813                 flow_dv_counter_free(dev, idx);
14814                 return 0;
14815         case MLX5_INDIRECT_ACTION_TYPE_AGE:
14816                 ret = flow_dv_aso_age_release(dev, idx);
14817                 if (ret)
14818                         /*
14819                          * In this case, the last flow has a reference will
14820                          * actually release the age action.
14821                          */
14822                         DRV_LOG(DEBUG, "Indirect age action %" PRIu32 " was"
14823                                 " released with references %d.", idx, ret);
14824                 return 0;
14825         case MLX5_INDIRECT_ACTION_TYPE_CT:
14826                 ret = flow_dv_aso_ct_release(dev, idx, error);
14827                 if (ret < 0)
14828                         return ret;
14829                 if (ret > 0)
14830                         DRV_LOG(DEBUG, "Connection tracking object %u still "
14831                                 "has references %d.", idx, ret);
14832                 return 0;
14833         default:
14834                 return rte_flow_error_set(error, ENOTSUP,
14835                                           RTE_FLOW_ERROR_TYPE_ACTION,
14836                                           NULL,
14837                                           "action type not supported");
14838         }
14839 }
14840
14841 /**
14842  * Updates in place shared RSS action configuration.
14843  *
14844  * @param[in] dev
14845  *   Pointer to the Ethernet device structure.
14846  * @param[in] idx
14847  *   The shared RSS action object ID to be updated.
14848  * @param[in] action_conf
14849  *   RSS action specification used to modify *shared_rss*.
14850  * @param[out] error
14851  *   Perform verbose error reporting if not NULL. Initialized in case of
14852  *   error only.
14853  *
14854  * @return
14855  *   0 on success, otherwise negative errno value.
14856  * @note: currently only support update of RSS queues.
14857  */
14858 static int
14859 __flow_dv_action_rss_update(struct rte_eth_dev *dev, uint32_t idx,
14860                             const struct rte_flow_action_rss *action_conf,
14861                             struct rte_flow_error *error)
14862 {
14863         struct mlx5_priv *priv = dev->data->dev_private;
14864         struct mlx5_shared_action_rss *shared_rss =
14865             mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], idx);
14866         int ret = 0;
14867         void *queue = NULL;
14868         uint16_t *queue_old = NULL;
14869         uint32_t queue_size = action_conf->queue_num * sizeof(uint16_t);
14870
14871         if (!shared_rss)
14872                 return rte_flow_error_set(error, EINVAL,
14873                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
14874                                           "invalid shared action to update");
14875         if (priv->obj_ops.ind_table_modify == NULL)
14876                 return rte_flow_error_set(error, ENOTSUP,
14877                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
14878                                           "cannot modify indirection table");
14879         queue = mlx5_malloc(MLX5_MEM_ZERO,
14880                             RTE_ALIGN_CEIL(queue_size, sizeof(void *)),
14881                             0, SOCKET_ID_ANY);
14882         if (!queue)
14883                 return rte_flow_error_set(error, ENOMEM,
14884                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
14885                                           NULL,
14886                                           "cannot allocate resource memory");
14887         memcpy(queue, action_conf->queue, queue_size);
14888         MLX5_ASSERT(shared_rss->ind_tbl);
14889         rte_spinlock_lock(&shared_rss->action_rss_sl);
14890         queue_old = shared_rss->ind_tbl->queues;
14891         ret = mlx5_ind_table_obj_modify(dev, shared_rss->ind_tbl,
14892                                         queue, action_conf->queue_num, true);
14893         if (ret) {
14894                 mlx5_free(queue);
14895                 ret = rte_flow_error_set(error, rte_errno,
14896                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
14897                                           "cannot update indirection table");
14898         } else {
14899                 mlx5_free(queue_old);
14900                 shared_rss->origin.queue = queue;
14901                 shared_rss->origin.queue_num = action_conf->queue_num;
14902         }
14903         rte_spinlock_unlock(&shared_rss->action_rss_sl);
14904         return ret;
14905 }
14906
14907 /*
14908  * Updates in place conntrack context or direction.
14909  * Context update should be synchronized.
14910  *
14911  * @param[in] dev
14912  *   Pointer to the Ethernet device structure.
14913  * @param[in] idx
14914  *   The conntrack object ID to be updated.
14915  * @param[in] update
14916  *   Pointer to the structure of information to update.
14917  * @param[out] error
14918  *   Perform verbose error reporting if not NULL. Initialized in case of
14919  *   error only.
14920  *
14921  * @return
14922  *   0 on success, otherwise negative errno value.
14923  */
14924 static int
14925 __flow_dv_action_ct_update(struct rte_eth_dev *dev, uint32_t idx,
14926                            const struct rte_flow_modify_conntrack *update,
14927                            struct rte_flow_error *error)
14928 {
14929         struct mlx5_priv *priv = dev->data->dev_private;
14930         struct mlx5_aso_ct_action *ct;
14931         const struct rte_flow_action_conntrack *new_prf;
14932         int ret = 0;
14933         uint16_t owner = (uint16_t)MLX5_INDIRECT_ACT_CT_GET_OWNER(idx);
14934         uint32_t dev_idx;
14935
14936         if (PORT_ID(priv) != owner)
14937                 return rte_flow_error_set(error, EACCES,
14938                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
14939                                           NULL,
14940                                           "CT object owned by another port");
14941         dev_idx = MLX5_INDIRECT_ACT_CT_GET_IDX(idx);
14942         ct = flow_aso_ct_get_by_dev_idx(dev, dev_idx);
14943         if (!ct->refcnt)
14944                 return rte_flow_error_set(error, ENOMEM,
14945                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
14946                                           NULL,
14947                                           "CT object is inactive");
14948         new_prf = &update->new_ct;
14949         if (update->direction)
14950                 ct->is_original = !!new_prf->is_original_dir;
14951         if (update->state) {
14952                 /* Only validate the profile when it needs to be updated. */
14953                 ret = mlx5_validate_action_ct(dev, new_prf, error);
14954                 if (ret)
14955                         return ret;
14956                 ret = mlx5_aso_ct_update_by_wqe(priv->sh, ct, new_prf);
14957                 if (ret)
14958                         return rte_flow_error_set(error, EIO,
14959                                         RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
14960                                         NULL,
14961                                         "Failed to send CT context update WQE");
14962                 /* Block until ready or a failure. */
14963                 ret = mlx5_aso_ct_available(priv->sh, ct);
14964                 if (ret)
14965                         rte_flow_error_set(error, rte_errno,
14966                                            RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
14967                                            NULL,
14968                                            "Timeout to get the CT update");
14969         }
14970         return ret;
14971 }
14972
14973 /**
14974  * Updates in place shared action configuration, lock free,
14975  * (mutex should be acquired by caller).
14976  *
14977  * @param[in] dev
14978  *   Pointer to the Ethernet device structure.
14979  * @param[in] handle
14980  *   The indirect action object handle to be updated.
14981  * @param[in] update
14982  *   Action specification used to modify the action pointed by *handle*.
14983  *   *update* could be of same type with the action pointed by the *handle*
14984  *   handle argument, or some other structures like a wrapper, depending on
14985  *   the indirect action type.
14986  * @param[out] error
14987  *   Perform verbose error reporting if not NULL. Initialized in case of
14988  *   error only.
14989  *
14990  * @return
14991  *   0 on success, otherwise negative errno value.
14992  */
14993 static int
14994 flow_dv_action_update(struct rte_eth_dev *dev,
14995                         struct rte_flow_action_handle *handle,
14996                         const void *update,
14997                         struct rte_flow_error *err)
14998 {
14999         uint32_t act_idx = (uint32_t)(uintptr_t)handle;
15000         uint32_t type = act_idx >> MLX5_INDIRECT_ACTION_TYPE_OFFSET;
15001         uint32_t idx = act_idx & ((1u << MLX5_INDIRECT_ACTION_TYPE_OFFSET) - 1);
15002         const void *action_conf;
15003
15004         switch (type) {
15005         case MLX5_INDIRECT_ACTION_TYPE_RSS:
15006                 action_conf = ((const struct rte_flow_action *)update)->conf;
15007                 return __flow_dv_action_rss_update(dev, idx, action_conf, err);
15008         case MLX5_INDIRECT_ACTION_TYPE_CT:
15009                 return __flow_dv_action_ct_update(dev, idx, update, err);
15010         default:
15011                 return rte_flow_error_set(err, ENOTSUP,
15012                                           RTE_FLOW_ERROR_TYPE_ACTION,
15013                                           NULL,
15014                                           "action type update not supported");
15015         }
15016 }
15017
15018 /**
15019  * Destroy the meter sub policy table rules.
15020  * Lock free, (mutex should be acquired by caller).
15021  *
15022  * @param[in] dev
15023  *   Pointer to Ethernet device.
15024  * @param[in] sub_policy
15025  *   Pointer to meter sub policy table.
15026  */
15027 static void
15028 __flow_dv_destroy_sub_policy_rules(struct rte_eth_dev *dev,
15029                              struct mlx5_flow_meter_sub_policy *sub_policy)
15030 {
15031         struct mlx5_priv *priv = dev->data->dev_private;
15032         struct mlx5_flow_tbl_data_entry *tbl;
15033         struct mlx5_flow_meter_policy *policy = sub_policy->main_policy;
15034         struct mlx5_flow_meter_info *next_fm;
15035         struct mlx5_sub_policy_color_rule *color_rule;
15036         void *tmp;
15037         uint32_t i;
15038
15039         for (i = 0; i < RTE_COLORS; i++) {
15040                 next_fm = NULL;
15041                 if (i == RTE_COLOR_GREEN && policy &&
15042                     policy->act_cnt[i].fate_action == MLX5_FLOW_FATE_MTR)
15043                         next_fm = mlx5_flow_meter_find(priv,
15044                                         policy->act_cnt[i].next_mtr_id, NULL);
15045                 RTE_TAILQ_FOREACH_SAFE(color_rule, &sub_policy->color_rules[i],
15046                                    next_port, tmp) {
15047                         claim_zero(mlx5_flow_os_destroy_flow(color_rule->rule));
15048                         tbl = container_of(color_rule->matcher->tbl,
15049                                            typeof(*tbl), tbl);
15050                         mlx5_list_unregister(tbl->matchers,
15051                                              &color_rule->matcher->entry);
15052                         TAILQ_REMOVE(&sub_policy->color_rules[i],
15053                                      color_rule, next_port);
15054                         mlx5_free(color_rule);
15055                         if (next_fm)
15056                                 mlx5_flow_meter_detach(priv, next_fm);
15057                 }
15058         }
15059         for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
15060                 if (sub_policy->rix_hrxq[i]) {
15061                         if (policy && !policy->is_hierarchy)
15062                                 mlx5_hrxq_release(dev, sub_policy->rix_hrxq[i]);
15063                         sub_policy->rix_hrxq[i] = 0;
15064                 }
15065                 if (sub_policy->jump_tbl[i]) {
15066                         flow_dv_tbl_resource_release(MLX5_SH(dev),
15067                                                      sub_policy->jump_tbl[i]);
15068                         sub_policy->jump_tbl[i] = NULL;
15069                 }
15070         }
15071         if (sub_policy->tbl_rsc) {
15072                 flow_dv_tbl_resource_release(MLX5_SH(dev),
15073                                              sub_policy->tbl_rsc);
15074                 sub_policy->tbl_rsc = NULL;
15075         }
15076 }
15077
15078 /**
15079  * Destroy policy rules, lock free,
15080  * (mutex should be acquired by caller).
15081  * Dispatcher for action type specific call.
15082  *
15083  * @param[in] dev
15084  *   Pointer to the Ethernet device structure.
15085  * @param[in] mtr_policy
15086  *   Meter policy struct.
15087  */
15088 static void
15089 flow_dv_destroy_policy_rules(struct rte_eth_dev *dev,
15090                              struct mlx5_flow_meter_policy *mtr_policy)
15091 {
15092         uint32_t i, j;
15093         struct mlx5_flow_meter_sub_policy *sub_policy;
15094         uint16_t sub_policy_num;
15095
15096         for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
15097                 sub_policy_num = (mtr_policy->sub_policy_num >>
15098                         (MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) &
15099                         MLX5_MTR_SUB_POLICY_NUM_MASK;
15100                 for (j = 0; j < sub_policy_num; j++) {
15101                         sub_policy = mtr_policy->sub_policys[i][j];
15102                         if (sub_policy)
15103                                 __flow_dv_destroy_sub_policy_rules(dev,
15104                                                                    sub_policy);
15105                 }
15106         }
15107 }
15108
15109 /**
15110  * Destroy policy action, lock free,
15111  * (mutex should be acquired by caller).
15112  * Dispatcher for action type specific call.
15113  *
15114  * @param[in] dev
15115  *   Pointer to the Ethernet device structure.
15116  * @param[in] mtr_policy
15117  *   Meter policy struct.
15118  */
15119 static void
15120 flow_dv_destroy_mtr_policy_acts(struct rte_eth_dev *dev,
15121                       struct mlx5_flow_meter_policy *mtr_policy)
15122 {
15123         struct rte_flow_action *rss_action;
15124         struct mlx5_flow_handle dev_handle;
15125         uint32_t i, j;
15126
15127         for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
15128                 if (mtr_policy->act_cnt[i].rix_mark) {
15129                         flow_dv_tag_release(dev,
15130                                 mtr_policy->act_cnt[i].rix_mark);
15131                         mtr_policy->act_cnt[i].rix_mark = 0;
15132                 }
15133                 if (mtr_policy->act_cnt[i].modify_hdr) {
15134                         dev_handle.dvh.modify_hdr =
15135                                 mtr_policy->act_cnt[i].modify_hdr;
15136                         flow_dv_modify_hdr_resource_release(dev, &dev_handle);
15137                 }
15138                 switch (mtr_policy->act_cnt[i].fate_action) {
15139                 case MLX5_FLOW_FATE_SHARED_RSS:
15140                         rss_action = mtr_policy->act_cnt[i].rss;
15141                         mlx5_free(rss_action);
15142                         break;
15143                 case MLX5_FLOW_FATE_PORT_ID:
15144                         if (mtr_policy->act_cnt[i].rix_port_id_action) {
15145                                 flow_dv_port_id_action_resource_release(dev,
15146                                 mtr_policy->act_cnt[i].rix_port_id_action);
15147                                 mtr_policy->act_cnt[i].rix_port_id_action = 0;
15148                         }
15149                         break;
15150                 case MLX5_FLOW_FATE_DROP:
15151                 case MLX5_FLOW_FATE_JUMP:
15152                         for (j = 0; j < MLX5_MTR_DOMAIN_MAX; j++)
15153                                 mtr_policy->act_cnt[i].dr_jump_action[j] =
15154                                                 NULL;
15155                         break;
15156                 default:
15157                         /*Queue action do nothing*/
15158                         break;
15159                 }
15160         }
15161         for (j = 0; j < MLX5_MTR_DOMAIN_MAX; j++)
15162                 mtr_policy->dr_drop_action[j] = NULL;
15163 }
15164
15165 /**
15166  * Create policy action per domain, lock free,
15167  * (mutex should be acquired by caller).
15168  * Dispatcher for action type specific call.
15169  *
15170  * @param[in] dev
15171  *   Pointer to the Ethernet device structure.
15172  * @param[in] mtr_policy
15173  *   Meter policy struct.
15174  * @param[in] action
15175  *   Action specification used to create meter actions.
15176  * @param[out] error
15177  *   Perform verbose error reporting if not NULL. Initialized in case of
15178  *   error only.
15179  *
15180  * @return
15181  *   0 on success, otherwise negative errno value.
15182  */
15183 static int
15184 __flow_dv_create_domain_policy_acts(struct rte_eth_dev *dev,
15185                         struct mlx5_flow_meter_policy *mtr_policy,
15186                         const struct rte_flow_action *actions[RTE_COLORS],
15187                         enum mlx5_meter_domain domain,
15188                         struct rte_mtr_error *error)
15189 {
15190         struct mlx5_priv *priv = dev->data->dev_private;
15191         struct rte_flow_error flow_err;
15192         const struct rte_flow_action *act;
15193         uint64_t action_flags;
15194         struct mlx5_flow_handle dh;
15195         struct mlx5_flow dev_flow;
15196         struct mlx5_flow_dv_port_id_action_resource port_id_action;
15197         int i, ret;
15198         uint8_t egress, transfer;
15199         struct mlx5_meter_policy_action_container *act_cnt = NULL;
15200         union {
15201                 struct mlx5_flow_dv_modify_hdr_resource res;
15202                 uint8_t len[sizeof(struct mlx5_flow_dv_modify_hdr_resource) +
15203                             sizeof(struct mlx5_modification_cmd) *
15204                             (MLX5_MAX_MODIFY_NUM + 1)];
15205         } mhdr_dummy;
15206         struct mlx5_flow_dv_modify_hdr_resource *mhdr_res = &mhdr_dummy.res;
15207
15208         egress = (domain == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0;
15209         transfer = (domain == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0;
15210         memset(&dh, 0, sizeof(struct mlx5_flow_handle));
15211         memset(&dev_flow, 0, sizeof(struct mlx5_flow));
15212         memset(&port_id_action, 0,
15213                sizeof(struct mlx5_flow_dv_port_id_action_resource));
15214         memset(mhdr_res, 0, sizeof(*mhdr_res));
15215         mhdr_res->ft_type = transfer ? MLX5DV_FLOW_TABLE_TYPE_FDB :
15216                                        (egress ? MLX5DV_FLOW_TABLE_TYPE_NIC_TX :
15217                                         MLX5DV_FLOW_TABLE_TYPE_NIC_RX);
15218         dev_flow.handle = &dh;
15219         dev_flow.dv.port_id_action = &port_id_action;
15220         dev_flow.external = true;
15221         for (i = 0; i < RTE_COLORS; i++) {
15222                 if (i < MLX5_MTR_RTE_COLORS)
15223                         act_cnt = &mtr_policy->act_cnt[i];
15224                 /* Skip the color policy actions creation. */
15225                 if ((i == RTE_COLOR_YELLOW && mtr_policy->skip_y) ||
15226                     (i == RTE_COLOR_GREEN && mtr_policy->skip_g))
15227                         continue;
15228                 action_flags = 0;
15229                 for (act = actions[i];
15230                      act && act->type != RTE_FLOW_ACTION_TYPE_END; act++) {
15231                         switch (act->type) {
15232                         case RTE_FLOW_ACTION_TYPE_MARK:
15233                         {
15234                                 uint32_t tag_be = mlx5_flow_mark_set
15235                                         (((const struct rte_flow_action_mark *)
15236                                         (act->conf))->id);
15237
15238                                 if (i >= MLX5_MTR_RTE_COLORS)
15239                                         return -rte_mtr_error_set(error,
15240                                           ENOTSUP,
15241                                           RTE_MTR_ERROR_TYPE_METER_POLICY,
15242                                           NULL,
15243                                           "cannot create policy "
15244                                           "mark action for this color");
15245                                 dev_flow.handle->mark = 1;
15246                                 if (flow_dv_tag_resource_register(dev, tag_be,
15247                                                   &dev_flow, &flow_err))
15248                                         return -rte_mtr_error_set(error,
15249                                         ENOTSUP,
15250                                         RTE_MTR_ERROR_TYPE_METER_POLICY,
15251                                         NULL,
15252                                         "cannot setup policy mark action");
15253                                 MLX5_ASSERT(dev_flow.dv.tag_resource);
15254                                 act_cnt->rix_mark =
15255                                         dev_flow.handle->dvh.rix_tag;
15256                                 action_flags |= MLX5_FLOW_ACTION_MARK;
15257                                 break;
15258                         }
15259                         case RTE_FLOW_ACTION_TYPE_SET_TAG:
15260                                 if (i >= MLX5_MTR_RTE_COLORS)
15261                                         return -rte_mtr_error_set(error,
15262                                           ENOTSUP,
15263                                           RTE_MTR_ERROR_TYPE_METER_POLICY,
15264                                           NULL,
15265                                           "cannot create policy "
15266                                           "set tag action for this color");
15267                                 if (flow_dv_convert_action_set_tag
15268                                 (dev, mhdr_res,
15269                                 (const struct rte_flow_action_set_tag *)
15270                                 act->conf,  &flow_err))
15271                                         return -rte_mtr_error_set(error,
15272                                         ENOTSUP,
15273                                         RTE_MTR_ERROR_TYPE_METER_POLICY,
15274                                         NULL, "cannot convert policy "
15275                                         "set tag action");
15276                                 if (!mhdr_res->actions_num)
15277                                         return -rte_mtr_error_set(error,
15278                                         ENOTSUP,
15279                                         RTE_MTR_ERROR_TYPE_METER_POLICY,
15280                                         NULL, "cannot find policy "
15281                                         "set tag action");
15282                                 action_flags |= MLX5_FLOW_ACTION_SET_TAG;
15283                                 break;
15284                         case RTE_FLOW_ACTION_TYPE_DROP:
15285                         {
15286                                 struct mlx5_flow_mtr_mng *mtrmng =
15287                                                 priv->sh->mtrmng;
15288                                 struct mlx5_flow_tbl_data_entry *tbl_data;
15289
15290                                 /*
15291                                  * Create the drop table with
15292                                  * METER DROP level.
15293                                  */
15294                                 if (!mtrmng->drop_tbl[domain]) {
15295                                         mtrmng->drop_tbl[domain] =
15296                                         flow_dv_tbl_resource_get(dev,
15297                                         MLX5_FLOW_TABLE_LEVEL_METER,
15298                                         egress, transfer, false, NULL, 0,
15299                                         0, MLX5_MTR_TABLE_ID_DROP, &flow_err);
15300                                         if (!mtrmng->drop_tbl[domain])
15301                                                 return -rte_mtr_error_set
15302                                         (error, ENOTSUP,
15303                                         RTE_MTR_ERROR_TYPE_METER_POLICY,
15304                                         NULL,
15305                                         "Failed to create meter drop table");
15306                                 }
15307                                 tbl_data = container_of
15308                                 (mtrmng->drop_tbl[domain],
15309                                 struct mlx5_flow_tbl_data_entry, tbl);
15310                                 if (i < MLX5_MTR_RTE_COLORS) {
15311                                         act_cnt->dr_jump_action[domain] =
15312                                                 tbl_data->jump.action;
15313                                         act_cnt->fate_action =
15314                                                 MLX5_FLOW_FATE_DROP;
15315                                 }
15316                                 if (i == RTE_COLOR_RED)
15317                                         mtr_policy->dr_drop_action[domain] =
15318                                                 tbl_data->jump.action;
15319                                 action_flags |= MLX5_FLOW_ACTION_DROP;
15320                                 break;
15321                         }
15322                         case RTE_FLOW_ACTION_TYPE_QUEUE:
15323                         {
15324                                 if (i >= MLX5_MTR_RTE_COLORS)
15325                                         return -rte_mtr_error_set(error,
15326                                         ENOTSUP,
15327                                         RTE_MTR_ERROR_TYPE_METER_POLICY,
15328                                         NULL, "cannot create policy "
15329                                         "fate queue for this color");
15330                                 act_cnt->queue =
15331                                 ((const struct rte_flow_action_queue *)
15332                                         (act->conf))->index;
15333                                 act_cnt->fate_action =
15334                                         MLX5_FLOW_FATE_QUEUE;
15335                                 dev_flow.handle->fate_action =
15336                                         MLX5_FLOW_FATE_QUEUE;
15337                                 mtr_policy->is_queue = 1;
15338                                 action_flags |= MLX5_FLOW_ACTION_QUEUE;
15339                                 break;
15340                         }
15341                         case RTE_FLOW_ACTION_TYPE_RSS:
15342                         {
15343                                 int rss_size;
15344
15345                                 if (i >= MLX5_MTR_RTE_COLORS)
15346                                         return -rte_mtr_error_set(error,
15347                                           ENOTSUP,
15348                                           RTE_MTR_ERROR_TYPE_METER_POLICY,
15349                                           NULL,
15350                                           "cannot create policy "
15351                                           "rss action for this color");
15352                                 /*
15353                                  * Save RSS conf into policy struct
15354                                  * for translate stage.
15355                                  */
15356                                 rss_size = (int)rte_flow_conv
15357                                         (RTE_FLOW_CONV_OP_ACTION,
15358                                         NULL, 0, act, &flow_err);
15359                                 if (rss_size <= 0)
15360                                         return -rte_mtr_error_set(error,
15361                                           ENOTSUP,
15362                                           RTE_MTR_ERROR_TYPE_METER_POLICY,
15363                                           NULL, "Get the wrong "
15364                                           "rss action struct size");
15365                                 act_cnt->rss = mlx5_malloc(MLX5_MEM_ZERO,
15366                                                 rss_size, 0, SOCKET_ID_ANY);
15367                                 if (!act_cnt->rss)
15368                                         return -rte_mtr_error_set(error,
15369                                           ENOTSUP,
15370                                           RTE_MTR_ERROR_TYPE_METER_POLICY,
15371                                           NULL,
15372                                           "Fail to malloc rss action memory");
15373                                 ret = rte_flow_conv(RTE_FLOW_CONV_OP_ACTION,
15374                                         act_cnt->rss, rss_size,
15375                                         act, &flow_err);
15376                                 if (ret < 0)
15377                                         return -rte_mtr_error_set(error,
15378                                           ENOTSUP,
15379                                           RTE_MTR_ERROR_TYPE_METER_POLICY,
15380                                           NULL, "Fail to save "
15381                                           "rss action into policy struct");
15382                                 act_cnt->fate_action =
15383                                         MLX5_FLOW_FATE_SHARED_RSS;
15384                                 action_flags |= MLX5_FLOW_ACTION_RSS;
15385                                 break;
15386                         }
15387                         case RTE_FLOW_ACTION_TYPE_PORT_ID:
15388                         case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT:
15389                         {
15390                                 struct mlx5_flow_dv_port_id_action_resource
15391                                         port_id_resource;
15392                                 uint32_t port_id = 0;
15393
15394                                 if (i >= MLX5_MTR_RTE_COLORS)
15395                                         return -rte_mtr_error_set(error,
15396                                         ENOTSUP,
15397                                         RTE_MTR_ERROR_TYPE_METER_POLICY,
15398                                         NULL, "cannot create policy "
15399                                         "port action for this color");
15400                                 memset(&port_id_resource, 0,
15401                                         sizeof(port_id_resource));
15402                                 if (flow_dv_translate_action_port_id(dev, act,
15403                                                 &port_id, &flow_err))
15404                                         return -rte_mtr_error_set(error,
15405                                         ENOTSUP,
15406                                         RTE_MTR_ERROR_TYPE_METER_POLICY,
15407                                         NULL, "cannot translate "
15408                                         "policy port action");
15409                                 port_id_resource.port_id = port_id;
15410                                 if (flow_dv_port_id_action_resource_register
15411                                         (dev, &port_id_resource,
15412                                         &dev_flow, &flow_err))
15413                                         return -rte_mtr_error_set(error,
15414                                         ENOTSUP,
15415                                         RTE_MTR_ERROR_TYPE_METER_POLICY,
15416                                         NULL, "cannot setup "
15417                                         "policy port action");
15418                                 act_cnt->rix_port_id_action =
15419                                         dev_flow.handle->rix_port_id_action;
15420                                 act_cnt->fate_action =
15421                                         MLX5_FLOW_FATE_PORT_ID;
15422                                 action_flags |= MLX5_FLOW_ACTION_PORT_ID;
15423                                 break;
15424                         }
15425                         case RTE_FLOW_ACTION_TYPE_JUMP:
15426                         {
15427                                 uint32_t jump_group = 0;
15428                                 uint32_t table = 0;
15429                                 struct mlx5_flow_tbl_data_entry *tbl_data;
15430                                 struct flow_grp_info grp_info = {
15431                                         .external = !!dev_flow.external,
15432                                         .transfer = !!transfer,
15433                                         .fdb_def_rule = !!priv->fdb_def_rule,
15434                                         .std_tbl_fix = 0,
15435                                         .skip_scale = dev_flow.skip_scale &
15436                                         (1 << MLX5_SCALE_FLOW_GROUP_BIT),
15437                                 };
15438                                 struct mlx5_flow_meter_sub_policy *sub_policy =
15439                                         mtr_policy->sub_policys[domain][0];
15440
15441                                 if (i >= MLX5_MTR_RTE_COLORS)
15442                                         return -rte_mtr_error_set(error,
15443                                           ENOTSUP,
15444                                           RTE_MTR_ERROR_TYPE_METER_POLICY,
15445                                           NULL,
15446                                           "cannot create policy "
15447                                           "jump action for this color");
15448                                 jump_group =
15449                                 ((const struct rte_flow_action_jump *)
15450                                                         act->conf)->group;
15451                                 if (mlx5_flow_group_to_table(dev, NULL,
15452                                                        jump_group,
15453                                                        &table,
15454                                                        &grp_info, &flow_err))
15455                                         return -rte_mtr_error_set(error,
15456                                         ENOTSUP,
15457                                         RTE_MTR_ERROR_TYPE_METER_POLICY,
15458                                         NULL, "cannot setup "
15459                                         "policy jump action");
15460                                 sub_policy->jump_tbl[i] =
15461                                 flow_dv_tbl_resource_get(dev,
15462                                         table, egress,
15463                                         transfer,
15464                                         !!dev_flow.external,
15465                                         NULL, jump_group, 0,
15466                                         0, &flow_err);
15467                                 if
15468                                 (!sub_policy->jump_tbl[i])
15469                                         return  -rte_mtr_error_set(error,
15470                                         ENOTSUP,
15471                                         RTE_MTR_ERROR_TYPE_METER_POLICY,
15472                                         NULL, "cannot create jump action.");
15473                                 tbl_data = container_of
15474                                 (sub_policy->jump_tbl[i],
15475                                 struct mlx5_flow_tbl_data_entry, tbl);
15476                                 act_cnt->dr_jump_action[domain] =
15477                                         tbl_data->jump.action;
15478                                 act_cnt->fate_action =
15479                                         MLX5_FLOW_FATE_JUMP;
15480                                 action_flags |= MLX5_FLOW_ACTION_JUMP;
15481                                 break;
15482                         }
15483                         /*
15484                          * No need to check meter hierarchy for Y or R colors
15485                          * here since it is done in the validation stage.
15486                          */
15487                         case RTE_FLOW_ACTION_TYPE_METER:
15488                         {
15489                                 const struct rte_flow_action_meter *mtr;
15490                                 struct mlx5_flow_meter_info *next_fm;
15491                                 struct mlx5_flow_meter_policy *next_policy;
15492                                 struct rte_flow_action tag_action;
15493                                 struct mlx5_rte_flow_action_set_tag set_tag;
15494                                 uint32_t next_mtr_idx = 0;
15495
15496                                 mtr = act->conf;
15497                                 next_fm = mlx5_flow_meter_find(priv,
15498                                                         mtr->mtr_id,
15499                                                         &next_mtr_idx);
15500                                 if (!next_fm)
15501                                         return -rte_mtr_error_set(error, EINVAL,
15502                                                 RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
15503                                                 "Fail to find next meter.");
15504                                 if (next_fm->def_policy)
15505                                         return -rte_mtr_error_set(error, EINVAL,
15506                                                 RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
15507                                 "Hierarchy only supports termination meter.");
15508                                 next_policy = mlx5_flow_meter_policy_find(dev,
15509                                                 next_fm->policy_id, NULL);
15510                                 MLX5_ASSERT(next_policy);
15511                                 if (next_fm->drop_cnt) {
15512                                         set_tag.id =
15513                                                 (enum modify_reg)
15514                                                 mlx5_flow_get_reg_id(dev,
15515                                                 MLX5_MTR_ID,
15516                                                 0,
15517                                                 (struct rte_flow_error *)error);
15518                                         set_tag.offset = (priv->mtr_reg_share ?
15519                                                 MLX5_MTR_COLOR_BITS : 0);
15520                                         set_tag.length = (priv->mtr_reg_share ?
15521                                                MLX5_MTR_IDLE_BITS_IN_COLOR_REG :
15522                                                MLX5_REG_BITS);
15523                                         set_tag.data = next_mtr_idx;
15524                                         tag_action.type =
15525                                                 (enum rte_flow_action_type)
15526                                                 MLX5_RTE_FLOW_ACTION_TYPE_TAG;
15527                                         tag_action.conf = &set_tag;
15528                                         if (flow_dv_convert_action_set_reg
15529                                                 (mhdr_res, &tag_action,
15530                                                 (struct rte_flow_error *)error))
15531                                                 return -rte_errno;
15532                                         action_flags |=
15533                                                 MLX5_FLOW_ACTION_SET_TAG;
15534                                 }
15535                                 act_cnt->fate_action = MLX5_FLOW_FATE_MTR;
15536                                 act_cnt->next_mtr_id = next_fm->meter_id;
15537                                 act_cnt->next_sub_policy = NULL;
15538                                 mtr_policy->is_hierarchy = 1;
15539                                 mtr_policy->dev = next_policy->dev;
15540                                 action_flags |=
15541                                 MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY;
15542                                 break;
15543                         }
15544                         default:
15545                                 return -rte_mtr_error_set(error, ENOTSUP,
15546                                           RTE_MTR_ERROR_TYPE_METER_POLICY,
15547                                           NULL, "action type not supported");
15548                         }
15549                         if (action_flags & MLX5_FLOW_ACTION_SET_TAG) {
15550                                 /* create modify action if needed. */
15551                                 dev_flow.dv.group = 1;
15552                                 if (flow_dv_modify_hdr_resource_register
15553                                         (dev, mhdr_res, &dev_flow, &flow_err))
15554                                         return -rte_mtr_error_set(error,
15555                                                 ENOTSUP,
15556                                                 RTE_MTR_ERROR_TYPE_METER_POLICY,
15557                                                 NULL, "cannot register policy "
15558                                                 "set tag action");
15559                                 act_cnt->modify_hdr =
15560                                         dev_flow.handle->dvh.modify_hdr;
15561                         }
15562                 }
15563         }
15564         return 0;
15565 }
15566
15567 /**
15568  * Create policy action per domain, lock free,
15569  * (mutex should be acquired by caller).
15570  * Dispatcher for action type specific call.
15571  *
15572  * @param[in] dev
15573  *   Pointer to the Ethernet device structure.
15574  * @param[in] mtr_policy
15575  *   Meter policy struct.
15576  * @param[in] action
15577  *   Action specification used to create meter actions.
15578  * @param[out] error
15579  *   Perform verbose error reporting if not NULL. Initialized in case of
15580  *   error only.
15581  *
15582  * @return
15583  *   0 on success, otherwise negative errno value.
15584  */
15585 static int
15586 flow_dv_create_mtr_policy_acts(struct rte_eth_dev *dev,
15587                       struct mlx5_flow_meter_policy *mtr_policy,
15588                       const struct rte_flow_action *actions[RTE_COLORS],
15589                       struct rte_mtr_error *error)
15590 {
15591         int ret, i;
15592         uint16_t sub_policy_num;
15593
15594         for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
15595                 sub_policy_num = (mtr_policy->sub_policy_num >>
15596                         (MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) &
15597                         MLX5_MTR_SUB_POLICY_NUM_MASK;
15598                 if (sub_policy_num) {
15599                         ret = __flow_dv_create_domain_policy_acts(dev,
15600                                 mtr_policy, actions,
15601                                 (enum mlx5_meter_domain)i, error);
15602                         /* Cleaning resource is done in the caller level. */
15603                         if (ret)
15604                                 return ret;
15605                 }
15606         }
15607         return 0;
15608 }
15609
15610 /**
15611  * Query a DV flow rule for its statistics via DevX.
15612  *
15613  * @param[in] dev
15614  *   Pointer to Ethernet device.
15615  * @param[in] cnt_idx
15616  *   Index to the flow counter.
15617  * @param[out] data
15618  *   Data retrieved by the query.
15619  * @param[out] error
15620  *   Perform verbose error reporting if not NULL.
15621  *
15622  * @return
15623  *   0 on success, a negative errno value otherwise and rte_errno is set.
15624  */
15625 static int
15626 flow_dv_query_count(struct rte_eth_dev *dev, uint32_t cnt_idx, void *data,
15627                     struct rte_flow_error *error)
15628 {
15629         struct mlx5_priv *priv = dev->data->dev_private;
15630         struct rte_flow_query_count *qc = data;
15631
15632         if (!priv->sh->devx)
15633                 return rte_flow_error_set(error, ENOTSUP,
15634                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
15635                                           NULL,
15636                                           "counters are not supported");
15637         if (cnt_idx) {
15638                 uint64_t pkts, bytes;
15639                 struct mlx5_flow_counter *cnt;
15640                 int err = _flow_dv_query_count(dev, cnt_idx, &pkts, &bytes);
15641
15642                 if (err)
15643                         return rte_flow_error_set(error, -err,
15644                                         RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
15645                                         NULL, "cannot read counters");
15646                 cnt = flow_dv_counter_get_by_idx(dev, cnt_idx, NULL);
15647                 qc->hits_set = 1;
15648                 qc->bytes_set = 1;
15649                 qc->hits = pkts - cnt->hits;
15650                 qc->bytes = bytes - cnt->bytes;
15651                 if (qc->reset) {
15652                         cnt->hits = pkts;
15653                         cnt->bytes = bytes;
15654                 }
15655                 return 0;
15656         }
15657         return rte_flow_error_set(error, EINVAL,
15658                                   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
15659                                   NULL,
15660                                   "counters are not available");
15661 }
15662
15663 static int
15664 flow_dv_action_query(struct rte_eth_dev *dev,
15665                      const struct rte_flow_action_handle *handle, void *data,
15666                      struct rte_flow_error *error)
15667 {
15668         struct mlx5_age_param *age_param;
15669         struct rte_flow_query_age *resp;
15670         uint32_t act_idx = (uint32_t)(uintptr_t)handle;
15671         uint32_t type = act_idx >> MLX5_INDIRECT_ACTION_TYPE_OFFSET;
15672         uint32_t idx = act_idx & ((1u << MLX5_INDIRECT_ACTION_TYPE_OFFSET) - 1);
15673         struct mlx5_priv *priv = dev->data->dev_private;
15674         struct mlx5_aso_ct_action *ct;
15675         uint16_t owner;
15676         uint32_t dev_idx;
15677
15678         switch (type) {
15679         case MLX5_INDIRECT_ACTION_TYPE_AGE:
15680                 age_param = &flow_aso_age_get_by_idx(dev, idx)->age_params;
15681                 resp = data;
15682                 resp->aged = __atomic_load_n(&age_param->state,
15683                                               __ATOMIC_RELAXED) == AGE_TMOUT ?
15684                                                                           1 : 0;
15685                 resp->sec_since_last_hit_valid = !resp->aged;
15686                 if (resp->sec_since_last_hit_valid)
15687                         resp->sec_since_last_hit = __atomic_load_n
15688                              (&age_param->sec_since_last_hit, __ATOMIC_RELAXED);
15689                 return 0;
15690         case MLX5_INDIRECT_ACTION_TYPE_COUNT:
15691                 return flow_dv_query_count(dev, idx, data, error);
15692         case MLX5_INDIRECT_ACTION_TYPE_CT:
15693                 owner = (uint16_t)MLX5_INDIRECT_ACT_CT_GET_OWNER(idx);
15694                 if (owner != PORT_ID(priv))
15695                         return rte_flow_error_set(error, EACCES,
15696                                         RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
15697                                         NULL,
15698                                         "CT object owned by another port");
15699                 dev_idx = MLX5_INDIRECT_ACT_CT_GET_IDX(idx);
15700                 ct = flow_aso_ct_get_by_dev_idx(dev, dev_idx);
15701                 MLX5_ASSERT(ct);
15702                 if (!ct->refcnt)
15703                         return rte_flow_error_set(error, EFAULT,
15704                                         RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
15705                                         NULL,
15706                                         "CT object is inactive");
15707                 ((struct rte_flow_action_conntrack *)data)->peer_port =
15708                                                         ct->peer;
15709                 ((struct rte_flow_action_conntrack *)data)->is_original_dir =
15710                                                         ct->is_original;
15711                 if (mlx5_aso_ct_query_by_wqe(priv->sh, ct, data))
15712                         return rte_flow_error_set(error, EIO,
15713                                         RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
15714                                         NULL,
15715                                         "Failed to query CT context");
15716                 return 0;
15717         default:
15718                 return rte_flow_error_set(error, ENOTSUP,
15719                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
15720                                           "action type query not supported");
15721         }
15722 }
15723
15724 /**
15725  * Query a flow rule AGE action for aging information.
15726  *
15727  * @param[in] dev
15728  *   Pointer to Ethernet device.
15729  * @param[in] flow
15730  *   Pointer to the sub flow.
15731  * @param[out] data
15732  *   data retrieved by the query.
15733  * @param[out] error
15734  *   Perform verbose error reporting if not NULL.
15735  *
15736  * @return
15737  *   0 on success, a negative errno value otherwise and rte_errno is set.
15738  */
15739 static int
15740 flow_dv_query_age(struct rte_eth_dev *dev, struct rte_flow *flow,
15741                   void *data, struct rte_flow_error *error)
15742 {
15743         struct rte_flow_query_age *resp = data;
15744         struct mlx5_age_param *age_param;
15745
15746         if (flow->age) {
15747                 struct mlx5_aso_age_action *act =
15748                                      flow_aso_age_get_by_idx(dev, flow->age);
15749
15750                 age_param = &act->age_params;
15751         } else if (flow->counter) {
15752                 age_param = flow_dv_counter_idx_get_age(dev, flow->counter);
15753
15754                 if (!age_param || !age_param->timeout)
15755                         return rte_flow_error_set
15756                                         (error, EINVAL,
15757                                          RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
15758                                          NULL, "cannot read age data");
15759         } else {
15760                 return rte_flow_error_set(error, EINVAL,
15761                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
15762                                           NULL, "age data not available");
15763         }
15764         resp->aged = __atomic_load_n(&age_param->state, __ATOMIC_RELAXED) ==
15765                                      AGE_TMOUT ? 1 : 0;
15766         resp->sec_since_last_hit_valid = !resp->aged;
15767         if (resp->sec_since_last_hit_valid)
15768                 resp->sec_since_last_hit = __atomic_load_n
15769                              (&age_param->sec_since_last_hit, __ATOMIC_RELAXED);
15770         return 0;
15771 }
15772
15773 /**
15774  * Query a flow.
15775  *
15776  * @see rte_flow_query()
15777  * @see rte_flow_ops
15778  */
15779 static int
15780 flow_dv_query(struct rte_eth_dev *dev,
15781               struct rte_flow *flow __rte_unused,
15782               const struct rte_flow_action *actions __rte_unused,
15783               void *data __rte_unused,
15784               struct rte_flow_error *error __rte_unused)
15785 {
15786         int ret = -EINVAL;
15787
15788         for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
15789                 switch (actions->type) {
15790                 case RTE_FLOW_ACTION_TYPE_VOID:
15791                         break;
15792                 case RTE_FLOW_ACTION_TYPE_COUNT:
15793                         ret = flow_dv_query_count(dev, flow->counter, data,
15794                                                   error);
15795                         break;
15796                 case RTE_FLOW_ACTION_TYPE_AGE:
15797                         ret = flow_dv_query_age(dev, flow, data, error);
15798                         break;
15799                 default:
15800                         return rte_flow_error_set(error, ENOTSUP,
15801                                                   RTE_FLOW_ERROR_TYPE_ACTION,
15802                                                   actions,
15803                                                   "action not supported");
15804                 }
15805         }
15806         return ret;
15807 }
15808
15809 /**
15810  * Destroy the meter table set.
15811  * Lock free, (mutex should be acquired by caller).
15812  *
15813  * @param[in] dev
15814  *   Pointer to Ethernet device.
15815  * @param[in] fm
15816  *   Meter information table.
15817  */
15818 static void
15819 flow_dv_destroy_mtr_tbls(struct rte_eth_dev *dev,
15820                         struct mlx5_flow_meter_info *fm)
15821 {
15822         struct mlx5_priv *priv = dev->data->dev_private;
15823         int i;
15824
15825         if (!fm || !priv->config.dv_flow_en)
15826                 return;
15827         for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
15828                 if (fm->drop_rule[i]) {
15829                         claim_zero(mlx5_flow_os_destroy_flow(fm->drop_rule[i]));
15830                         fm->drop_rule[i] = NULL;
15831                 }
15832         }
15833 }
15834
15835 static void
15836 flow_dv_destroy_mtr_drop_tbls(struct rte_eth_dev *dev)
15837 {
15838         struct mlx5_priv *priv = dev->data->dev_private;
15839         struct mlx5_flow_mtr_mng *mtrmng = priv->sh->mtrmng;
15840         struct mlx5_flow_tbl_data_entry *tbl;
15841         int i, j;
15842
15843         for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
15844                 if (mtrmng->def_rule[i]) {
15845                         claim_zero(mlx5_flow_os_destroy_flow
15846                                         (mtrmng->def_rule[i]));
15847                         mtrmng->def_rule[i] = NULL;
15848                 }
15849                 if (mtrmng->def_matcher[i]) {
15850                         tbl = container_of(mtrmng->def_matcher[i]->tbl,
15851                                 struct mlx5_flow_tbl_data_entry, tbl);
15852                         mlx5_list_unregister(tbl->matchers,
15853                                              &mtrmng->def_matcher[i]->entry);
15854                         mtrmng->def_matcher[i] = NULL;
15855                 }
15856                 for (j = 0; j < MLX5_REG_BITS; j++) {
15857                         if (mtrmng->drop_matcher[i][j]) {
15858                                 tbl =
15859                                 container_of(mtrmng->drop_matcher[i][j]->tbl,
15860                                              struct mlx5_flow_tbl_data_entry,
15861                                              tbl);
15862                                 mlx5_list_unregister(tbl->matchers,
15863                                             &mtrmng->drop_matcher[i][j]->entry);
15864                                 mtrmng->drop_matcher[i][j] = NULL;
15865                         }
15866                 }
15867                 if (mtrmng->drop_tbl[i]) {
15868                         flow_dv_tbl_resource_release(MLX5_SH(dev),
15869                                 mtrmng->drop_tbl[i]);
15870                         mtrmng->drop_tbl[i] = NULL;
15871                 }
15872         }
15873 }
15874
15875 /* Number of meter flow actions, count and jump or count and drop. */
15876 #define METER_ACTIONS 2
15877
15878 static void
15879 __flow_dv_destroy_domain_def_policy(struct rte_eth_dev *dev,
15880                                     enum mlx5_meter_domain domain)
15881 {
15882         struct mlx5_priv *priv = dev->data->dev_private;
15883         struct mlx5_flow_meter_def_policy *def_policy =
15884                         priv->sh->mtrmng->def_policy[domain];
15885
15886         __flow_dv_destroy_sub_policy_rules(dev, &def_policy->sub_policy);
15887         mlx5_free(def_policy);
15888         priv->sh->mtrmng->def_policy[domain] = NULL;
15889 }
15890
15891 /**
15892  * Destroy the default policy table set.
15893  *
15894  * @param[in] dev
15895  *   Pointer to Ethernet device.
15896  */
15897 static void
15898 flow_dv_destroy_def_policy(struct rte_eth_dev *dev)
15899 {
15900         struct mlx5_priv *priv = dev->data->dev_private;
15901         int i;
15902
15903         for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++)
15904                 if (priv->sh->mtrmng->def_policy[i])
15905                         __flow_dv_destroy_domain_def_policy(dev,
15906                                         (enum mlx5_meter_domain)i);
15907         priv->sh->mtrmng->def_policy_id = MLX5_INVALID_POLICY_ID;
15908 }
15909
15910 static int
15911 __flow_dv_create_policy_flow(struct rte_eth_dev *dev,
15912                         uint32_t color_reg_c_idx,
15913                         enum rte_color color, void *matcher_object,
15914                         int actions_n, void *actions,
15915                         bool match_src_port, const struct rte_flow_item *item,
15916                         void **rule, const struct rte_flow_attr *attr)
15917 {
15918         int ret;
15919         struct mlx5_flow_dv_match_params value = {
15920                 .size = sizeof(value.buf),
15921         };
15922         struct mlx5_flow_dv_match_params matcher = {
15923                 .size = sizeof(matcher.buf),
15924         };
15925         struct mlx5_priv *priv = dev->data->dev_private;
15926         uint8_t misc_mask;
15927
15928         if (match_src_port && (priv->representor || priv->master)) {
15929                 if (flow_dv_translate_item_port_id(dev, matcher.buf,
15930                                                    value.buf, item, attr)) {
15931                         DRV_LOG(ERR, "Failed to create meter policy%d flow's"
15932                                 " value with port.", color);
15933                         return -1;
15934                 }
15935         }
15936         flow_dv_match_meta_reg(matcher.buf, value.buf,
15937                                (enum modify_reg)color_reg_c_idx,
15938                                rte_col_2_mlx5_col(color), UINT32_MAX);
15939         misc_mask = flow_dv_matcher_enable(value.buf);
15940         __flow_dv_adjust_buf_size(&value.size, misc_mask);
15941         ret = mlx5_flow_os_create_flow(matcher_object, (void *)&value,
15942                                        actions_n, actions, rule);
15943         if (ret) {
15944                 DRV_LOG(ERR, "Failed to create meter policy%d flow.", color);
15945                 return -1;
15946         }
15947         return 0;
15948 }
15949
15950 static int
15951 __flow_dv_create_policy_matcher(struct rte_eth_dev *dev,
15952                         uint32_t color_reg_c_idx,
15953                         uint16_t priority,
15954                         struct mlx5_flow_meter_sub_policy *sub_policy,
15955                         const struct rte_flow_attr *attr,
15956                         bool match_src_port,
15957                         const struct rte_flow_item *item,
15958                         struct mlx5_flow_dv_matcher **policy_matcher,
15959                         struct rte_flow_error *error)
15960 {
15961         struct mlx5_list_entry *entry;
15962         struct mlx5_flow_tbl_resource *tbl_rsc = sub_policy->tbl_rsc;
15963         struct mlx5_flow_dv_matcher matcher = {
15964                 .mask = {
15965                         .size = sizeof(matcher.mask.buf),
15966                 },
15967                 .tbl = tbl_rsc,
15968         };
15969         struct mlx5_flow_dv_match_params value = {
15970                 .size = sizeof(value.buf),
15971         };
15972         struct mlx5_flow_cb_ctx ctx = {
15973                 .error = error,
15974                 .data = &matcher,
15975         };
15976         struct mlx5_flow_tbl_data_entry *tbl_data;
15977         struct mlx5_priv *priv = dev->data->dev_private;
15978         const uint32_t color_mask = (UINT32_C(1) << MLX5_MTR_COLOR_BITS) - 1;
15979
15980         if (match_src_port && (priv->representor || priv->master)) {
15981                 if (flow_dv_translate_item_port_id(dev, matcher.mask.buf,
15982                                                    value.buf, item, attr)) {
15983                         DRV_LOG(ERR, "Failed to register meter policy%d matcher"
15984                                 " with port.", priority);
15985                         return -1;
15986                 }
15987         }
15988         tbl_data = container_of(tbl_rsc, struct mlx5_flow_tbl_data_entry, tbl);
15989         if (priority < RTE_COLOR_RED)
15990                 flow_dv_match_meta_reg(matcher.mask.buf, value.buf,
15991                         (enum modify_reg)color_reg_c_idx, 0, color_mask);
15992         matcher.priority = priority;
15993         matcher.crc = rte_raw_cksum((const void *)matcher.mask.buf,
15994                                     matcher.mask.size);
15995         entry = mlx5_list_register(tbl_data->matchers, &ctx);
15996         if (!entry) {
15997                 DRV_LOG(ERR, "Failed to register meter drop matcher.");
15998                 return -1;
15999         }
16000         *policy_matcher =
16001                 container_of(entry, struct mlx5_flow_dv_matcher, entry);
16002         return 0;
16003 }
16004
16005 /**
16006  * Create the policy rules per domain.
16007  *
16008  * @param[in] dev
16009  *   Pointer to Ethernet device.
16010  * @param[in] sub_policy
16011  *    Pointer to sub policy table..
16012  * @param[in] egress
16013  *   Direction of the table.
16014  * @param[in] transfer
16015  *   E-Switch or NIC flow.
16016  * @param[in] acts
16017  *   Pointer to policy action list per color.
16018  *
16019  * @return
16020  *   0 on success, -1 otherwise.
16021  */
16022 static int
16023 __flow_dv_create_domain_policy_rules(struct rte_eth_dev *dev,
16024                 struct mlx5_flow_meter_sub_policy *sub_policy,
16025                 uint8_t egress, uint8_t transfer, bool match_src_port,
16026                 struct mlx5_meter_policy_acts acts[RTE_COLORS])
16027 {
16028         struct mlx5_priv *priv = dev->data->dev_private;
16029         struct rte_flow_error flow_err;
16030         uint32_t color_reg_c_idx;
16031         struct rte_flow_attr attr = {
16032                 .group = MLX5_FLOW_TABLE_LEVEL_POLICY,
16033                 .priority = 0,
16034                 .ingress = 0,
16035                 .egress = !!egress,
16036                 .transfer = !!transfer,
16037                 .reserved = 0,
16038         };
16039         int i;
16040         int ret = mlx5_flow_get_reg_id(dev, MLX5_MTR_COLOR, 0, &flow_err);
16041         struct mlx5_sub_policy_color_rule *color_rule;
16042         bool svport_match;
16043         struct mlx5_sub_policy_color_rule *tmp_rules[RTE_COLORS] = {NULL};
16044
16045         if (ret < 0)
16046                 return -1;
16047         /* Create policy table with POLICY level. */
16048         if (!sub_policy->tbl_rsc)
16049                 sub_policy->tbl_rsc = flow_dv_tbl_resource_get(dev,
16050                                 MLX5_FLOW_TABLE_LEVEL_POLICY,
16051                                 egress, transfer, false, NULL, 0, 0,
16052                                 sub_policy->idx, &flow_err);
16053         if (!sub_policy->tbl_rsc) {
16054                 DRV_LOG(ERR,
16055                         "Failed to create meter sub policy table.");
16056                 return -1;
16057         }
16058         /* Prepare matchers. */
16059         color_reg_c_idx = ret;
16060         for (i = 0; i < RTE_COLORS; i++) {
16061                 TAILQ_INIT(&sub_policy->color_rules[i]);
16062                 if (!acts[i].actions_n)
16063                         continue;
16064                 color_rule = mlx5_malloc(MLX5_MEM_ZERO,
16065                                 sizeof(struct mlx5_sub_policy_color_rule),
16066                                 0, SOCKET_ID_ANY);
16067                 if (!color_rule) {
16068                         DRV_LOG(ERR, "No memory to create color rule.");
16069                         goto err_exit;
16070                 }
16071                 tmp_rules[i] = color_rule;
16072                 TAILQ_INSERT_TAIL(&sub_policy->color_rules[i],
16073                                   color_rule, next_port);
16074                 color_rule->src_port = priv->representor_id;
16075                 /* No use. */
16076                 attr.priority = i;
16077                 /* Create matchers for colors. */
16078                 svport_match = (i != RTE_COLOR_RED) ? match_src_port : false;
16079                 if (__flow_dv_create_policy_matcher(dev, color_reg_c_idx,
16080                                 MLX5_MTR_POLICY_MATCHER_PRIO, sub_policy,
16081                                 &attr, svport_match, NULL,
16082                                 &color_rule->matcher, &flow_err)) {
16083                         DRV_LOG(ERR, "Failed to create color%u matcher.", i);
16084                         goto err_exit;
16085                 }
16086                 /* Create flow, matching color. */
16087                 if (__flow_dv_create_policy_flow(dev,
16088                                 color_reg_c_idx, (enum rte_color)i,
16089                                 color_rule->matcher->matcher_object,
16090                                 acts[i].actions_n, acts[i].dv_actions,
16091                                 svport_match, NULL, &color_rule->rule,
16092                                 &attr)) {
16093                         DRV_LOG(ERR, "Failed to create color%u rule.", i);
16094                         goto err_exit;
16095                 }
16096         }
16097         return 0;
16098 err_exit:
16099         /* All the policy rules will be cleared. */
16100         do {
16101                 color_rule = tmp_rules[i];
16102                 if (color_rule) {
16103                         if (color_rule->rule)
16104                                 mlx5_flow_os_destroy_flow(color_rule->rule);
16105                         if (color_rule->matcher) {
16106                                 struct mlx5_flow_tbl_data_entry *tbl =
16107                                         container_of(color_rule->matcher->tbl,
16108                                                      typeof(*tbl), tbl);
16109                                 mlx5_list_unregister(tbl->matchers,
16110                                                 &color_rule->matcher->entry);
16111                         }
16112                         TAILQ_REMOVE(&sub_policy->color_rules[i],
16113                                      color_rule, next_port);
16114                         mlx5_free(color_rule);
16115                 }
16116         } while (i--);
16117         return -1;
16118 }
16119
16120 static int
16121 __flow_dv_create_policy_acts_rules(struct rte_eth_dev *dev,
16122                         struct mlx5_flow_meter_policy *mtr_policy,
16123                         struct mlx5_flow_meter_sub_policy *sub_policy,
16124                         uint32_t domain)
16125 {
16126         struct mlx5_priv *priv = dev->data->dev_private;
16127         struct mlx5_meter_policy_acts acts[RTE_COLORS];
16128         struct mlx5_flow_dv_tag_resource *tag;
16129         struct mlx5_flow_dv_port_id_action_resource *port_action;
16130         struct mlx5_hrxq *hrxq;
16131         struct mlx5_flow_meter_info *next_fm = NULL;
16132         struct mlx5_flow_meter_policy *next_policy;
16133         struct mlx5_flow_meter_sub_policy *next_sub_policy;
16134         struct mlx5_flow_tbl_data_entry *tbl_data;
16135         struct rte_flow_error error;
16136         uint8_t egress = (domain == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0;
16137         uint8_t transfer = (domain == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0;
16138         bool mtr_first = egress || (transfer && priv->representor_id != UINT16_MAX);
16139         bool match_src_port = false;
16140         int i;
16141
16142         /* If RSS or Queue, no previous actions / rules is created. */
16143         for (i = 0; i < RTE_COLORS; i++) {
16144                 acts[i].actions_n = 0;
16145                 if (i == RTE_COLOR_RED) {
16146                         /* Only support drop on red. */
16147                         acts[i].dv_actions[0] =
16148                                 mtr_policy->dr_drop_action[domain];
16149                         acts[i].actions_n = 1;
16150                         continue;
16151                 }
16152                 if (i == RTE_COLOR_GREEN &&
16153                     mtr_policy->act_cnt[i].fate_action == MLX5_FLOW_FATE_MTR) {
16154                         struct rte_flow_attr attr = {
16155                                 .transfer = transfer
16156                         };
16157
16158                         next_fm = mlx5_flow_meter_find(priv,
16159                                         mtr_policy->act_cnt[i].next_mtr_id,
16160                                         NULL);
16161                         if (!next_fm) {
16162                                 DRV_LOG(ERR,
16163                                         "Failed to get next hierarchy meter.");
16164                                 goto err_exit;
16165                         }
16166                         if (mlx5_flow_meter_attach(priv, next_fm,
16167                                                    &attr, &error)) {
16168                                 DRV_LOG(ERR, "%s", error.message);
16169                                 next_fm = NULL;
16170                                 goto err_exit;
16171                         }
16172                         /* Meter action must be the first for TX. */
16173                         if (mtr_first) {
16174                                 acts[i].dv_actions[acts[i].actions_n] =
16175                                         next_fm->meter_action;
16176                                 acts[i].actions_n++;
16177                         }
16178                 }
16179                 if (mtr_policy->act_cnt[i].rix_mark) {
16180                         tag = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_TAG],
16181                                         mtr_policy->act_cnt[i].rix_mark);
16182                         if (!tag) {
16183                                 DRV_LOG(ERR, "Failed to find "
16184                                 "mark action for policy.");
16185                                 goto err_exit;
16186                         }
16187                         acts[i].dv_actions[acts[i].actions_n] = tag->action;
16188                         acts[i].actions_n++;
16189                 }
16190                 if (mtr_policy->act_cnt[i].modify_hdr) {
16191                         acts[i].dv_actions[acts[i].actions_n] =
16192                                 mtr_policy->act_cnt[i].modify_hdr->action;
16193                         acts[i].actions_n++;
16194                 }
16195                 if (mtr_policy->act_cnt[i].fate_action) {
16196                         switch (mtr_policy->act_cnt[i].fate_action) {
16197                         case MLX5_FLOW_FATE_PORT_ID:
16198                                 port_action = mlx5_ipool_get
16199                                         (priv->sh->ipool[MLX5_IPOOL_PORT_ID],
16200                                 mtr_policy->act_cnt[i].rix_port_id_action);
16201                                 if (!port_action) {
16202                                         DRV_LOG(ERR, "Failed to find "
16203                                                 "port action for policy.");
16204                                         goto err_exit;
16205                                 }
16206                                 acts[i].dv_actions[acts[i].actions_n] =
16207                                         port_action->action;
16208                                 acts[i].actions_n++;
16209                                 mtr_policy->dev = dev;
16210                                 match_src_port = true;
16211                                 break;
16212                         case MLX5_FLOW_FATE_DROP:
16213                         case MLX5_FLOW_FATE_JUMP:
16214                                 acts[i].dv_actions[acts[i].actions_n] =
16215                                 mtr_policy->act_cnt[i].dr_jump_action[domain];
16216                                 acts[i].actions_n++;
16217                                 break;
16218                         case MLX5_FLOW_FATE_SHARED_RSS:
16219                         case MLX5_FLOW_FATE_QUEUE:
16220                                 hrxq = mlx5_ipool_get
16221                                         (priv->sh->ipool[MLX5_IPOOL_HRXQ],
16222                                          sub_policy->rix_hrxq[i]);
16223                                 if (!hrxq) {
16224                                         DRV_LOG(ERR, "Failed to find "
16225                                                 "queue action for policy.");
16226                                         goto err_exit;
16227                                 }
16228                                 acts[i].dv_actions[acts[i].actions_n] =
16229                                         hrxq->action;
16230                                 acts[i].actions_n++;
16231                                 break;
16232                         case MLX5_FLOW_FATE_MTR:
16233                                 if (!next_fm) {
16234                                         DRV_LOG(ERR,
16235                                                 "No next hierarchy meter.");
16236                                         goto err_exit;
16237                                 }
16238                                 if (!mtr_first) {
16239                                         acts[i].dv_actions[acts[i].actions_n] =
16240                                                         next_fm->meter_action;
16241                                         acts[i].actions_n++;
16242                                 }
16243                                 if (mtr_policy->act_cnt[i].next_sub_policy) {
16244                                         next_sub_policy =
16245                                         mtr_policy->act_cnt[i].next_sub_policy;
16246                                 } else {
16247                                         next_policy =
16248                                                 mlx5_flow_meter_policy_find(dev,
16249                                                 next_fm->policy_id, NULL);
16250                                         MLX5_ASSERT(next_policy);
16251                                         next_sub_policy =
16252                                         next_policy->sub_policys[domain][0];
16253                                 }
16254                                 tbl_data =
16255                                         container_of(next_sub_policy->tbl_rsc,
16256                                         struct mlx5_flow_tbl_data_entry, tbl);
16257                                 acts[i].dv_actions[acts[i].actions_n++] =
16258                                                         tbl_data->jump.action;
16259                                 if (mtr_policy->act_cnt[i].modify_hdr)
16260                                         match_src_port = !!transfer;
16261                                 break;
16262                         default:
16263                                 /*Queue action do nothing*/
16264                                 break;
16265                         }
16266                 }
16267         }
16268         if (__flow_dv_create_domain_policy_rules(dev, sub_policy,
16269                                 egress, transfer, match_src_port, acts)) {
16270                 DRV_LOG(ERR,
16271                         "Failed to create policy rules per domain.");
16272                 goto err_exit;
16273         }
16274         return 0;
16275 err_exit:
16276         if (next_fm)
16277                 mlx5_flow_meter_detach(priv, next_fm);
16278         return -1;
16279 }
16280
16281 /**
16282  * Create the policy rules.
16283  *
16284  * @param[in] dev
16285  *   Pointer to Ethernet device.
16286  * @param[in,out] mtr_policy
16287  *   Pointer to meter policy table.
16288  *
16289  * @return
16290  *   0 on success, -1 otherwise.
16291  */
16292 static int
16293 flow_dv_create_policy_rules(struct rte_eth_dev *dev,
16294                              struct mlx5_flow_meter_policy *mtr_policy)
16295 {
16296         int i;
16297         uint16_t sub_policy_num;
16298
16299         for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
16300                 sub_policy_num = (mtr_policy->sub_policy_num >>
16301                         (MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) &
16302                         MLX5_MTR_SUB_POLICY_NUM_MASK;
16303                 if (!sub_policy_num)
16304                         continue;
16305                 /* Prepare actions list and create policy rules. */
16306                 if (__flow_dv_create_policy_acts_rules(dev, mtr_policy,
16307                         mtr_policy->sub_policys[i][0], i)) {
16308                         DRV_LOG(ERR, "Failed to create policy action "
16309                                 "list per domain.");
16310                         return -1;
16311                 }
16312         }
16313         return 0;
16314 }
16315
16316 static int
16317 __flow_dv_create_domain_def_policy(struct rte_eth_dev *dev, uint32_t domain)
16318 {
16319         struct mlx5_priv *priv = dev->data->dev_private;
16320         struct mlx5_flow_mtr_mng *mtrmng = priv->sh->mtrmng;
16321         struct mlx5_flow_meter_def_policy *def_policy;
16322         struct mlx5_flow_tbl_resource *jump_tbl;
16323         struct mlx5_flow_tbl_data_entry *tbl_data;
16324         uint8_t egress, transfer;
16325         struct rte_flow_error error;
16326         struct mlx5_meter_policy_acts acts[RTE_COLORS];
16327         int ret;
16328
16329         egress = (domain == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0;
16330         transfer = (domain == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0;
16331         def_policy = mtrmng->def_policy[domain];
16332         if (!def_policy) {
16333                 def_policy = mlx5_malloc(MLX5_MEM_ZERO,
16334                         sizeof(struct mlx5_flow_meter_def_policy),
16335                         RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
16336                 if (!def_policy) {
16337                         DRV_LOG(ERR, "Failed to alloc default policy table.");
16338                         goto def_policy_error;
16339                 }
16340                 mtrmng->def_policy[domain] = def_policy;
16341                 /* Create the meter suffix table with SUFFIX level. */
16342                 jump_tbl = flow_dv_tbl_resource_get(dev,
16343                                 MLX5_FLOW_TABLE_LEVEL_METER,
16344                                 egress, transfer, false, NULL, 0,
16345                                 0, MLX5_MTR_TABLE_ID_SUFFIX, &error);
16346                 if (!jump_tbl) {
16347                         DRV_LOG(ERR,
16348                                 "Failed to create meter suffix table.");
16349                         goto def_policy_error;
16350                 }
16351                 def_policy->sub_policy.jump_tbl[RTE_COLOR_GREEN] = jump_tbl;
16352                 tbl_data = container_of(jump_tbl,
16353                                         struct mlx5_flow_tbl_data_entry, tbl);
16354                 def_policy->dr_jump_action[RTE_COLOR_GREEN] =
16355                                                 tbl_data->jump.action;
16356                 acts[RTE_COLOR_GREEN].dv_actions[0] = tbl_data->jump.action;
16357                 acts[RTE_COLOR_GREEN].actions_n = 1;
16358                 /*
16359                  * YELLOW has the same default policy as GREEN does.
16360                  * G & Y share the same table and action. The 2nd time of table
16361                  * resource getting is just to update the reference count for
16362                  * the releasing stage.
16363                  */
16364                 jump_tbl = flow_dv_tbl_resource_get(dev,
16365                                 MLX5_FLOW_TABLE_LEVEL_METER,
16366                                 egress, transfer, false, NULL, 0,
16367                                 0, MLX5_MTR_TABLE_ID_SUFFIX, &error);
16368                 if (!jump_tbl) {
16369                         DRV_LOG(ERR,
16370                                 "Failed to get meter suffix table.");
16371                         goto def_policy_error;
16372                 }
16373                 def_policy->sub_policy.jump_tbl[RTE_COLOR_YELLOW] = jump_tbl;
16374                 tbl_data = container_of(jump_tbl,
16375                                         struct mlx5_flow_tbl_data_entry, tbl);
16376                 def_policy->dr_jump_action[RTE_COLOR_YELLOW] =
16377                                                 tbl_data->jump.action;
16378                 acts[RTE_COLOR_YELLOW].dv_actions[0] = tbl_data->jump.action;
16379                 acts[RTE_COLOR_YELLOW].actions_n = 1;
16380                 /* Create jump action to the drop table. */
16381                 if (!mtrmng->drop_tbl[domain]) {
16382                         mtrmng->drop_tbl[domain] = flow_dv_tbl_resource_get
16383                                 (dev, MLX5_FLOW_TABLE_LEVEL_METER,
16384                                  egress, transfer, false, NULL, 0,
16385                                  0, MLX5_MTR_TABLE_ID_DROP, &error);
16386                         if (!mtrmng->drop_tbl[domain]) {
16387                                 DRV_LOG(ERR, "Failed to create meter "
16388                                         "drop table for default policy.");
16389                                 goto def_policy_error;
16390                         }
16391                 }
16392                 /* all RED: unique Drop table for jump action. */
16393                 tbl_data = container_of(mtrmng->drop_tbl[domain],
16394                                         struct mlx5_flow_tbl_data_entry, tbl);
16395                 def_policy->dr_jump_action[RTE_COLOR_RED] =
16396                                                 tbl_data->jump.action;
16397                 acts[RTE_COLOR_RED].dv_actions[0] = tbl_data->jump.action;
16398                 acts[RTE_COLOR_RED].actions_n = 1;
16399                 /* Create default policy rules. */
16400                 ret = __flow_dv_create_domain_policy_rules(dev,
16401                                         &def_policy->sub_policy,
16402                                         egress, transfer, false, acts);
16403                 if (ret) {
16404                         DRV_LOG(ERR, "Failed to create default policy rules.");
16405                         goto def_policy_error;
16406                 }
16407         }
16408         return 0;
16409 def_policy_error:
16410         __flow_dv_destroy_domain_def_policy(dev,
16411                                             (enum mlx5_meter_domain)domain);
16412         return -1;
16413 }
16414
16415 /**
16416  * Create the default policy table set.
16417  *
16418  * @param[in] dev
16419  *   Pointer to Ethernet device.
16420  * @return
16421  *   0 on success, -1 otherwise.
16422  */
16423 static int
16424 flow_dv_create_def_policy(struct rte_eth_dev *dev)
16425 {
16426         struct mlx5_priv *priv = dev->data->dev_private;
16427         int i;
16428
16429         /* Non-termination policy table. */
16430         for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
16431                 if (!priv->config.dv_esw_en && i == MLX5_MTR_DOMAIN_TRANSFER)
16432                         continue;
16433                 if (__flow_dv_create_domain_def_policy(dev, i)) {
16434                         DRV_LOG(ERR, "Failed to create default policy");
16435                         /* Rollback the created default policies for others. */
16436                         flow_dv_destroy_def_policy(dev);
16437                         return -1;
16438                 }
16439         }
16440         return 0;
16441 }
16442
16443 /**
16444  * Create the needed meter tables.
16445  * Lock free, (mutex should be acquired by caller).
16446  *
16447  * @param[in] dev
16448  *   Pointer to Ethernet device.
16449  * @param[in] fm
16450  *   Meter information table.
16451  * @param[in] mtr_idx
16452  *   Meter index.
16453  * @param[in] domain_bitmap
16454  *   Domain bitmap.
16455  * @return
16456  *   0 on success, -1 otherwise.
16457  */
16458 static int
16459 flow_dv_create_mtr_tbls(struct rte_eth_dev *dev,
16460                         struct mlx5_flow_meter_info *fm,
16461                         uint32_t mtr_idx,
16462                         uint8_t domain_bitmap)
16463 {
16464         struct mlx5_priv *priv = dev->data->dev_private;
16465         struct mlx5_flow_mtr_mng *mtrmng = priv->sh->mtrmng;
16466         struct rte_flow_error error;
16467         struct mlx5_flow_tbl_data_entry *tbl_data;
16468         uint8_t egress, transfer;
16469         void *actions[METER_ACTIONS];
16470         int domain, ret, i;
16471         struct mlx5_flow_counter *cnt;
16472         struct mlx5_flow_dv_match_params value = {
16473                 .size = sizeof(value.buf),
16474         };
16475         struct mlx5_flow_dv_match_params matcher_para = {
16476                 .size = sizeof(matcher_para.buf),
16477         };
16478         int mtr_id_reg_c = mlx5_flow_get_reg_id(dev, MLX5_MTR_ID,
16479                                                      0, &error);
16480         uint32_t mtr_id_mask = (UINT32_C(1) << mtrmng->max_mtr_bits) - 1;
16481         uint8_t mtr_id_offset = priv->mtr_reg_share ? MLX5_MTR_COLOR_BITS : 0;
16482         struct mlx5_list_entry *entry;
16483         struct mlx5_flow_dv_matcher matcher = {
16484                 .mask = {
16485                         .size = sizeof(matcher.mask.buf),
16486                 },
16487         };
16488         struct mlx5_flow_dv_matcher *drop_matcher;
16489         struct mlx5_flow_cb_ctx ctx = {
16490                 .error = &error,
16491                 .data = &matcher,
16492         };
16493         uint8_t misc_mask;
16494
16495         if (!priv->mtr_en || mtr_id_reg_c < 0) {
16496                 rte_errno = ENOTSUP;
16497                 return -1;
16498         }
16499         for (domain = 0; domain < MLX5_MTR_DOMAIN_MAX; domain++) {
16500                 if (!(domain_bitmap & (1 << domain)) ||
16501                         (mtrmng->def_rule[domain] && !fm->drop_cnt))
16502                         continue;
16503                 egress = (domain == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0;
16504                 transfer = (domain == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0;
16505                 /* Create the drop table with METER DROP level. */
16506                 if (!mtrmng->drop_tbl[domain]) {
16507                         mtrmng->drop_tbl[domain] = flow_dv_tbl_resource_get(dev,
16508                                         MLX5_FLOW_TABLE_LEVEL_METER,
16509                                         egress, transfer, false, NULL, 0,
16510                                         0, MLX5_MTR_TABLE_ID_DROP, &error);
16511                         if (!mtrmng->drop_tbl[domain]) {
16512                                 DRV_LOG(ERR, "Failed to create meter drop table.");
16513                                 goto policy_error;
16514                         }
16515                 }
16516                 /* Create default matcher in drop table. */
16517                 matcher.tbl = mtrmng->drop_tbl[domain],
16518                 tbl_data = container_of(mtrmng->drop_tbl[domain],
16519                                 struct mlx5_flow_tbl_data_entry, tbl);
16520                 if (!mtrmng->def_matcher[domain]) {
16521                         flow_dv_match_meta_reg(matcher.mask.buf, value.buf,
16522                                        (enum modify_reg)mtr_id_reg_c,
16523                                        0, 0);
16524                         matcher.priority = MLX5_MTRS_DEFAULT_RULE_PRIORITY;
16525                         matcher.crc = rte_raw_cksum
16526                                         ((const void *)matcher.mask.buf,
16527                                         matcher.mask.size);
16528                         entry = mlx5_list_register(tbl_data->matchers, &ctx);
16529                         if (!entry) {
16530                                 DRV_LOG(ERR, "Failed to register meter "
16531                                 "drop default matcher.");
16532                                 goto policy_error;
16533                         }
16534                         mtrmng->def_matcher[domain] = container_of(entry,
16535                         struct mlx5_flow_dv_matcher, entry);
16536                 }
16537                 /* Create default rule in drop table. */
16538                 if (!mtrmng->def_rule[domain]) {
16539                         i = 0;
16540                         actions[i++] = priv->sh->dr_drop_action;
16541                         flow_dv_match_meta_reg(matcher_para.buf, value.buf,
16542                                 (enum modify_reg)mtr_id_reg_c, 0, 0);
16543                         misc_mask = flow_dv_matcher_enable(value.buf);
16544                         __flow_dv_adjust_buf_size(&value.size, misc_mask);
16545                         ret = mlx5_flow_os_create_flow
16546                                 (mtrmng->def_matcher[domain]->matcher_object,
16547                                 (void *)&value, i, actions,
16548                                 &mtrmng->def_rule[domain]);
16549                         if (ret) {
16550                                 DRV_LOG(ERR, "Failed to create meter "
16551                                 "default drop rule for drop table.");
16552                                 goto policy_error;
16553                         }
16554                 }
16555                 if (!fm->drop_cnt)
16556                         continue;
16557                 MLX5_ASSERT(mtrmng->max_mtr_bits);
16558                 if (!mtrmng->drop_matcher[domain][mtrmng->max_mtr_bits - 1]) {
16559                         /* Create matchers for Drop. */
16560                         flow_dv_match_meta_reg(matcher.mask.buf, value.buf,
16561                                         (enum modify_reg)mtr_id_reg_c, 0,
16562                                         (mtr_id_mask << mtr_id_offset));
16563                         matcher.priority = MLX5_REG_BITS - mtrmng->max_mtr_bits;
16564                         matcher.crc = rte_raw_cksum
16565                                         ((const void *)matcher.mask.buf,
16566                                         matcher.mask.size);
16567                         entry = mlx5_list_register(tbl_data->matchers, &ctx);
16568                         if (!entry) {
16569                                 DRV_LOG(ERR,
16570                                 "Failed to register meter drop matcher.");
16571                                 goto policy_error;
16572                         }
16573                         mtrmng->drop_matcher[domain][mtrmng->max_mtr_bits - 1] =
16574                                 container_of(entry, struct mlx5_flow_dv_matcher,
16575                                              entry);
16576                 }
16577                 drop_matcher =
16578                         mtrmng->drop_matcher[domain][mtrmng->max_mtr_bits - 1];
16579                 /* Create drop rule, matching meter_id only. */
16580                 flow_dv_match_meta_reg(matcher_para.buf, value.buf,
16581                                 (enum modify_reg)mtr_id_reg_c,
16582                                 (mtr_idx << mtr_id_offset), UINT32_MAX);
16583                 i = 0;
16584                 cnt = flow_dv_counter_get_by_idx(dev,
16585                                         fm->drop_cnt, NULL);
16586                 actions[i++] = cnt->action;
16587                 actions[i++] = priv->sh->dr_drop_action;
16588                 misc_mask = flow_dv_matcher_enable(value.buf);
16589                 __flow_dv_adjust_buf_size(&value.size, misc_mask);
16590                 ret = mlx5_flow_os_create_flow(drop_matcher->matcher_object,
16591                                                (void *)&value, i, actions,
16592                                                &fm->drop_rule[domain]);
16593                 if (ret) {
16594                         DRV_LOG(ERR, "Failed to create meter "
16595                                 "drop rule for drop table.");
16596                                 goto policy_error;
16597                 }
16598         }
16599         return 0;
16600 policy_error:
16601         for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
16602                 if (fm->drop_rule[i]) {
16603                         claim_zero(mlx5_flow_os_destroy_flow
16604                                 (fm->drop_rule[i]));
16605                         fm->drop_rule[i] = NULL;
16606                 }
16607         }
16608         return -1;
16609 }
16610
16611 static struct mlx5_flow_meter_sub_policy *
16612 __flow_dv_meter_get_rss_sub_policy(struct rte_eth_dev *dev,
16613                 struct mlx5_flow_meter_policy *mtr_policy,
16614                 struct mlx5_flow_rss_desc *rss_desc[MLX5_MTR_RTE_COLORS],
16615                 struct mlx5_flow_meter_sub_policy *next_sub_policy,
16616                 bool *is_reuse)
16617 {
16618         struct mlx5_priv *priv = dev->data->dev_private;
16619         struct mlx5_flow_meter_sub_policy *sub_policy = NULL;
16620         uint32_t sub_policy_idx = 0;
16621         uint32_t hrxq_idx[MLX5_MTR_RTE_COLORS] = {0};
16622         uint32_t i, j;
16623         struct mlx5_hrxq *hrxq;
16624         struct mlx5_flow_handle dh;
16625         struct mlx5_meter_policy_action_container *act_cnt;
16626         uint32_t domain = MLX5_MTR_DOMAIN_INGRESS;
16627         uint16_t sub_policy_num;
16628
16629         rte_spinlock_lock(&mtr_policy->sl);
16630         for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
16631                 if (!rss_desc[i])
16632                         continue;
16633                 hrxq_idx[i] = mlx5_hrxq_get(dev, rss_desc[i]);
16634                 if (!hrxq_idx[i]) {
16635                         rte_spinlock_unlock(&mtr_policy->sl);
16636                         return NULL;
16637                 }
16638         }
16639         sub_policy_num = (mtr_policy->sub_policy_num >>
16640                         (MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)) &
16641                         MLX5_MTR_SUB_POLICY_NUM_MASK;
16642         for (j = 0; j < sub_policy_num; j++) {
16643                 for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
16644                         if (rss_desc[i] &&
16645                             hrxq_idx[i] !=
16646                             mtr_policy->sub_policys[domain][j]->rix_hrxq[i])
16647                                 break;
16648                 }
16649                 if (i >= MLX5_MTR_RTE_COLORS) {
16650                         /*
16651                          * Found the sub policy table with
16652                          * the same queue per color.
16653                          */
16654                         rte_spinlock_unlock(&mtr_policy->sl);
16655                         for (i = 0; i < MLX5_MTR_RTE_COLORS; i++)
16656                                 mlx5_hrxq_release(dev, hrxq_idx[i]);
16657                         *is_reuse = true;
16658                         return mtr_policy->sub_policys[domain][j];
16659                 }
16660         }
16661         /* Create sub policy. */
16662         if (!mtr_policy->sub_policys[domain][0]->rix_hrxq[0]) {
16663                 /* Reuse the first pre-allocated sub_policy. */
16664                 sub_policy = mtr_policy->sub_policys[domain][0];
16665                 sub_policy_idx = sub_policy->idx;
16666         } else {
16667                 sub_policy = mlx5_ipool_zmalloc
16668                                 (priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
16669                                  &sub_policy_idx);
16670                 if (!sub_policy ||
16671                     sub_policy_idx > MLX5_MAX_SUB_POLICY_TBL_NUM) {
16672                         for (i = 0; i < MLX5_MTR_RTE_COLORS; i++)
16673                                 mlx5_hrxq_release(dev, hrxq_idx[i]);
16674                         goto rss_sub_policy_error;
16675                 }
16676                 sub_policy->idx = sub_policy_idx;
16677                 sub_policy->main_policy = mtr_policy;
16678         }
16679         for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
16680                 if (!rss_desc[i])
16681                         continue;
16682                 sub_policy->rix_hrxq[i] = hrxq_idx[i];
16683                 if (mtr_policy->is_hierarchy) {
16684                         act_cnt = &mtr_policy->act_cnt[i];
16685                         act_cnt->next_sub_policy = next_sub_policy;
16686                         mlx5_hrxq_release(dev, hrxq_idx[i]);
16687                 } else {
16688                         /*
16689                          * Overwrite the last action from
16690                          * RSS action to Queue action.
16691                          */
16692                         hrxq = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_HRXQ],
16693                                               hrxq_idx[i]);
16694                         if (!hrxq) {
16695                                 DRV_LOG(ERR, "Failed to get policy hrxq");
16696                                 goto rss_sub_policy_error;
16697                         }
16698                         act_cnt = &mtr_policy->act_cnt[i];
16699                         if (act_cnt->rix_mark || act_cnt->modify_hdr) {
16700                                 memset(&dh, 0, sizeof(struct mlx5_flow_handle));
16701                                 if (act_cnt->rix_mark)
16702                                         dh.mark = 1;
16703                                 dh.fate_action = MLX5_FLOW_FATE_QUEUE;
16704                                 dh.rix_hrxq = hrxq_idx[i];
16705                                 flow_drv_rxq_flags_set(dev, &dh);
16706                         }
16707                 }
16708         }
16709         if (__flow_dv_create_policy_acts_rules(dev, mtr_policy,
16710                                                sub_policy, domain)) {
16711                 DRV_LOG(ERR, "Failed to create policy "
16712                         "rules for ingress domain.");
16713                 goto rss_sub_policy_error;
16714         }
16715         if (sub_policy != mtr_policy->sub_policys[domain][0]) {
16716                 i = (mtr_policy->sub_policy_num >>
16717                         (MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)) &
16718                         MLX5_MTR_SUB_POLICY_NUM_MASK;
16719                 if (i >= MLX5_MTR_RSS_MAX_SUB_POLICY) {
16720                         DRV_LOG(ERR, "No free sub-policy slot.");
16721                         goto rss_sub_policy_error;
16722                 }
16723                 mtr_policy->sub_policys[domain][i] = sub_policy;
16724                 i++;
16725                 mtr_policy->sub_policy_num &= ~(MLX5_MTR_SUB_POLICY_NUM_MASK <<
16726                         (MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain));
16727                 mtr_policy->sub_policy_num |=
16728                         (i & MLX5_MTR_SUB_POLICY_NUM_MASK) <<
16729                         (MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain);
16730         }
16731         rte_spinlock_unlock(&mtr_policy->sl);
16732         *is_reuse = false;
16733         return sub_policy;
16734 rss_sub_policy_error:
16735         if (sub_policy) {
16736                 __flow_dv_destroy_sub_policy_rules(dev, sub_policy);
16737                 if (sub_policy != mtr_policy->sub_policys[domain][0]) {
16738                         i = (mtr_policy->sub_policy_num >>
16739                         (MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)) &
16740                         MLX5_MTR_SUB_POLICY_NUM_MASK;
16741                         mtr_policy->sub_policys[domain][i] = NULL;
16742                         mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
16743                                         sub_policy->idx);
16744                 }
16745         }
16746         rte_spinlock_unlock(&mtr_policy->sl);
16747         return NULL;
16748 }
16749
16750 /**
16751  * Find the policy table for prefix table with RSS.
16752  *
16753  * @param[in] dev
16754  *   Pointer to Ethernet device.
16755  * @param[in] mtr_policy
16756  *   Pointer to meter policy table.
16757  * @param[in] rss_desc
16758  *   Pointer to rss_desc
16759  * @return
16760  *   Pointer to table set on success, NULL otherwise and rte_errno is set.
16761  */
16762 static struct mlx5_flow_meter_sub_policy *
16763 flow_dv_meter_sub_policy_rss_prepare(struct rte_eth_dev *dev,
16764                 struct mlx5_flow_meter_policy *mtr_policy,
16765                 struct mlx5_flow_rss_desc *rss_desc[MLX5_MTR_RTE_COLORS])
16766 {
16767         struct mlx5_priv *priv = dev->data->dev_private;
16768         struct mlx5_flow_meter_sub_policy *sub_policy = NULL;
16769         struct mlx5_flow_meter_info *next_fm;
16770         struct mlx5_flow_meter_policy *next_policy;
16771         struct mlx5_flow_meter_sub_policy *next_sub_policy = NULL;
16772         struct mlx5_flow_meter_policy *policies[MLX5_MTR_CHAIN_MAX_NUM];
16773         struct mlx5_flow_meter_sub_policy *sub_policies[MLX5_MTR_CHAIN_MAX_NUM];
16774         uint32_t domain = MLX5_MTR_DOMAIN_INGRESS;
16775         bool reuse_sub_policy;
16776         uint32_t i = 0;
16777         uint32_t j = 0;
16778
16779         while (true) {
16780                 /* Iterate hierarchy to get all policies in this hierarchy. */
16781                 policies[i++] = mtr_policy;
16782                 if (!mtr_policy->is_hierarchy)
16783                         break;
16784                 if (i >= MLX5_MTR_CHAIN_MAX_NUM) {
16785                         DRV_LOG(ERR, "Exceed max meter number in hierarchy.");
16786                         return NULL;
16787                 }
16788                 next_fm = mlx5_flow_meter_find(priv,
16789                         mtr_policy->act_cnt[RTE_COLOR_GREEN].next_mtr_id, NULL);
16790                 if (!next_fm) {
16791                         DRV_LOG(ERR, "Failed to get next meter in hierarchy.");
16792                         return NULL;
16793                 }
16794                 next_policy =
16795                         mlx5_flow_meter_policy_find(dev, next_fm->policy_id,
16796                                                     NULL);
16797                 MLX5_ASSERT(next_policy);
16798                 mtr_policy = next_policy;
16799         }
16800         while (i) {
16801                 /**
16802                  * From last policy to the first one in hierarchy,
16803                  * create / get the sub policy for each of them.
16804                  */
16805                 sub_policy = __flow_dv_meter_get_rss_sub_policy(dev,
16806                                                         policies[--i],
16807                                                         rss_desc,
16808                                                         next_sub_policy,
16809                                                         &reuse_sub_policy);
16810                 if (!sub_policy) {
16811                         DRV_LOG(ERR, "Failed to get the sub policy.");
16812                         goto err_exit;
16813                 }
16814                 if (!reuse_sub_policy)
16815                         sub_policies[j++] = sub_policy;
16816                 next_sub_policy = sub_policy;
16817         }
16818         return sub_policy;
16819 err_exit:
16820         while (j) {
16821                 uint16_t sub_policy_num;
16822
16823                 sub_policy = sub_policies[--j];
16824                 mtr_policy = sub_policy->main_policy;
16825                 __flow_dv_destroy_sub_policy_rules(dev, sub_policy);
16826                 if (sub_policy != mtr_policy->sub_policys[domain][0]) {
16827                         sub_policy_num = (mtr_policy->sub_policy_num >>
16828                                 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)) &
16829                                 MLX5_MTR_SUB_POLICY_NUM_MASK;
16830                         mtr_policy->sub_policys[domain][sub_policy_num - 1] =
16831                                                                         NULL;
16832                         sub_policy_num--;
16833                         mtr_policy->sub_policy_num &=
16834                                 ~(MLX5_MTR_SUB_POLICY_NUM_MASK <<
16835                                   (MLX5_MTR_SUB_POLICY_NUM_SHIFT * i));
16836                         mtr_policy->sub_policy_num |=
16837                         (sub_policy_num & MLX5_MTR_SUB_POLICY_NUM_MASK) <<
16838                         (MLX5_MTR_SUB_POLICY_NUM_SHIFT * i);
16839                         mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
16840                                         sub_policy->idx);
16841                 }
16842         }
16843         return NULL;
16844 }
16845
16846 /**
16847  * Create the sub policy tag rule for all meters in hierarchy.
16848  *
16849  * @param[in] dev
16850  *   Pointer to Ethernet device.
16851  * @param[in] fm
16852  *   Meter information table.
16853  * @param[in] src_port
16854  *   The src port this extra rule should use.
16855  * @param[in] item
16856  *   The src port match item.
16857  * @param[out] error
16858  *   Perform verbose error reporting if not NULL.
16859  * @return
16860  *   0 on success, a negative errno value otherwise and rte_errno is set.
16861  */
16862 static int
16863 flow_dv_meter_hierarchy_rule_create(struct rte_eth_dev *dev,
16864                                 struct mlx5_flow_meter_info *fm,
16865                                 int32_t src_port,
16866                                 const struct rte_flow_item *item,
16867                                 struct rte_flow_error *error)
16868 {
16869         struct mlx5_priv *priv = dev->data->dev_private;
16870         struct mlx5_flow_meter_policy *mtr_policy;
16871         struct mlx5_flow_meter_sub_policy *sub_policy;
16872         struct mlx5_flow_meter_info *next_fm = NULL;
16873         struct mlx5_flow_meter_policy *next_policy;
16874         struct mlx5_flow_meter_sub_policy *next_sub_policy;
16875         struct mlx5_flow_tbl_data_entry *tbl_data;
16876         struct mlx5_sub_policy_color_rule *color_rule;
16877         struct mlx5_meter_policy_acts acts;
16878         uint32_t color_reg_c_idx;
16879         bool mtr_first = (src_port != UINT16_MAX) ? true : false;
16880         struct rte_flow_attr attr = {
16881                 .group = MLX5_FLOW_TABLE_LEVEL_POLICY,
16882                 .priority = 0,
16883                 .ingress = 0,
16884                 .egress = 0,
16885                 .transfer = 1,
16886                 .reserved = 0,
16887         };
16888         uint32_t domain = MLX5_MTR_DOMAIN_TRANSFER;
16889         int i;
16890
16891         mtr_policy = mlx5_flow_meter_policy_find(dev, fm->policy_id, NULL);
16892         MLX5_ASSERT(mtr_policy);
16893         if (!mtr_policy->is_hierarchy)
16894                 return 0;
16895         next_fm = mlx5_flow_meter_find(priv,
16896                         mtr_policy->act_cnt[RTE_COLOR_GREEN].next_mtr_id, NULL);
16897         if (!next_fm) {
16898                 return rte_flow_error_set(error, EINVAL,
16899                                 RTE_FLOW_ERROR_TYPE_ACTION, NULL,
16900                                 "Failed to find next meter in hierarchy.");
16901         }
16902         if (!next_fm->drop_cnt)
16903                 goto exit;
16904         color_reg_c_idx = mlx5_flow_get_reg_id(dev, MLX5_MTR_COLOR, 0, error);
16905         sub_policy = mtr_policy->sub_policys[domain][0];
16906         for (i = 0; i < RTE_COLORS; i++) {
16907                 bool rule_exist = false;
16908                 struct mlx5_meter_policy_action_container *act_cnt;
16909
16910                 if (i >= RTE_COLOR_YELLOW)
16911                         break;
16912                 TAILQ_FOREACH(color_rule,
16913                               &sub_policy->color_rules[i], next_port)
16914                         if (color_rule->src_port == src_port) {
16915                                 rule_exist = true;
16916                                 break;
16917                         }
16918                 if (rule_exist)
16919                         continue;
16920                 color_rule = mlx5_malloc(MLX5_MEM_ZERO,
16921                                 sizeof(struct mlx5_sub_policy_color_rule),
16922                                 0, SOCKET_ID_ANY);
16923                 if (!color_rule)
16924                         return rte_flow_error_set(error, ENOMEM,
16925                                 RTE_FLOW_ERROR_TYPE_ACTION,
16926                                 NULL, "No memory to create tag color rule.");
16927                 color_rule->src_port = src_port;
16928                 attr.priority = i;
16929                 next_policy = mlx5_flow_meter_policy_find(dev,
16930                                                 next_fm->policy_id, NULL);
16931                 MLX5_ASSERT(next_policy);
16932                 next_sub_policy = next_policy->sub_policys[domain][0];
16933                 tbl_data = container_of(next_sub_policy->tbl_rsc,
16934                                         struct mlx5_flow_tbl_data_entry, tbl);
16935                 act_cnt = &mtr_policy->act_cnt[i];
16936                 if (mtr_first) {
16937                         acts.dv_actions[0] = next_fm->meter_action;
16938                         acts.dv_actions[1] = act_cnt->modify_hdr->action;
16939                 } else {
16940                         acts.dv_actions[0] = act_cnt->modify_hdr->action;
16941                         acts.dv_actions[1] = next_fm->meter_action;
16942                 }
16943                 acts.dv_actions[2] = tbl_data->jump.action;
16944                 acts.actions_n = 3;
16945                 if (mlx5_flow_meter_attach(priv, next_fm, &attr, error)) {
16946                         next_fm = NULL;
16947                         goto err_exit;
16948                 }
16949                 if (__flow_dv_create_policy_matcher(dev, color_reg_c_idx,
16950                                 MLX5_MTR_POLICY_MATCHER_PRIO, sub_policy,
16951                                 &attr, true, item,
16952                                 &color_rule->matcher, error)) {
16953                         rte_flow_error_set(error, errno,
16954                                 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
16955                                 "Failed to create hierarchy meter matcher.");
16956                         goto err_exit;
16957                 }
16958                 if (__flow_dv_create_policy_flow(dev, color_reg_c_idx,
16959                                         (enum rte_color)i,
16960                                         color_rule->matcher->matcher_object,
16961                                         acts.actions_n, acts.dv_actions,
16962                                         true, item,
16963                                         &color_rule->rule, &attr)) {
16964                         rte_flow_error_set(error, errno,
16965                                 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
16966                                 "Failed to create hierarchy meter rule.");
16967                         goto err_exit;
16968                 }
16969                 TAILQ_INSERT_TAIL(&sub_policy->color_rules[i],
16970                                   color_rule, next_port);
16971         }
16972 exit:
16973         /**
16974          * Recursive call to iterate all meters in hierarchy and
16975          * create needed rules.
16976          */
16977         return flow_dv_meter_hierarchy_rule_create(dev, next_fm,
16978                                                 src_port, item, error);
16979 err_exit:
16980         if (color_rule) {
16981                 if (color_rule->rule)
16982                         mlx5_flow_os_destroy_flow(color_rule->rule);
16983                 if (color_rule->matcher) {
16984                         struct mlx5_flow_tbl_data_entry *tbl =
16985                                 container_of(color_rule->matcher->tbl,
16986                                                 typeof(*tbl), tbl);
16987                         mlx5_list_unregister(tbl->matchers,
16988                                                 &color_rule->matcher->entry);
16989                 }
16990                 mlx5_free(color_rule);
16991         }
16992         if (next_fm)
16993                 mlx5_flow_meter_detach(priv, next_fm);
16994         return -rte_errno;
16995 }
16996
16997 /**
16998  * Destroy the sub policy table with RX queue.
16999  *
17000  * @param[in] dev
17001  *   Pointer to Ethernet device.
17002  * @param[in] mtr_policy
17003  *   Pointer to meter policy table.
17004  */
17005 static void
17006 flow_dv_destroy_sub_policy_with_rxq(struct rte_eth_dev *dev,
17007                                     struct mlx5_flow_meter_policy *mtr_policy)
17008 {
17009         struct mlx5_priv *priv = dev->data->dev_private;
17010         struct mlx5_flow_meter_sub_policy *sub_policy = NULL;
17011         uint32_t domain = MLX5_MTR_DOMAIN_INGRESS;
17012         uint32_t i, j;
17013         uint16_t sub_policy_num, new_policy_num;
17014
17015         rte_spinlock_lock(&mtr_policy->sl);
17016         for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
17017                 switch (mtr_policy->act_cnt[i].fate_action) {
17018                 case MLX5_FLOW_FATE_SHARED_RSS:
17019                         sub_policy_num = (mtr_policy->sub_policy_num >>
17020                         (MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)) &
17021                         MLX5_MTR_SUB_POLICY_NUM_MASK;
17022                         new_policy_num = sub_policy_num;
17023                         for (j = 0; j < sub_policy_num; j++) {
17024                                 sub_policy =
17025                                         mtr_policy->sub_policys[domain][j];
17026                                 if (sub_policy) {
17027                                         __flow_dv_destroy_sub_policy_rules(dev,
17028                                                 sub_policy);
17029                                 if (sub_policy !=
17030                                         mtr_policy->sub_policys[domain][0]) {
17031                                         mtr_policy->sub_policys[domain][j] =
17032                                                                 NULL;
17033                                         mlx5_ipool_free
17034                                 (priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
17035                                                 sub_policy->idx);
17036                                                 new_policy_num--;
17037                                         }
17038                                 }
17039                         }
17040                         if (new_policy_num != sub_policy_num) {
17041                                 mtr_policy->sub_policy_num &=
17042                                 ~(MLX5_MTR_SUB_POLICY_NUM_MASK <<
17043                                 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain));
17044                                 mtr_policy->sub_policy_num |=
17045                                 (new_policy_num &
17046                                         MLX5_MTR_SUB_POLICY_NUM_MASK) <<
17047                                 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain);
17048                         }
17049                         break;
17050                 case MLX5_FLOW_FATE_QUEUE:
17051                         sub_policy = mtr_policy->sub_policys[domain][0];
17052                         __flow_dv_destroy_sub_policy_rules(dev,
17053                                                            sub_policy);
17054                         break;
17055                 default:
17056                         /*Other actions without queue and do nothing*/
17057                         break;
17058                 }
17059         }
17060         rte_spinlock_unlock(&mtr_policy->sl);
17061 }
17062 /**
17063  * Check whether the DR drop action is supported on the root table or not.
17064  *
17065  * Create a simple flow with DR drop action on root table to validate
17066  * if DR drop action on root table is supported or not.
17067  *
17068  * @param[in] dev
17069  *   Pointer to rte_eth_dev structure.
17070  *
17071  * @return
17072  *   0 on success, a negative errno value otherwise and rte_errno is set.
17073  */
17074 int
17075 mlx5_flow_discover_dr_action_support(struct rte_eth_dev *dev)
17076 {
17077         struct mlx5_priv *priv = dev->data->dev_private;
17078         struct mlx5_dev_ctx_shared *sh = priv->sh;
17079         struct mlx5_flow_dv_match_params mask = {
17080                 .size = sizeof(mask.buf),
17081         };
17082         struct mlx5_flow_dv_match_params value = {
17083                 .size = sizeof(value.buf),
17084         };
17085         struct mlx5dv_flow_matcher_attr dv_attr = {
17086                 .type = IBV_FLOW_ATTR_NORMAL,
17087                 .priority = 0,
17088                 .match_criteria_enable = 0,
17089                 .match_mask = (void *)&mask,
17090         };
17091         struct mlx5_flow_tbl_resource *tbl = NULL;
17092         void *matcher = NULL;
17093         void *flow = NULL;
17094         int ret = -1;
17095
17096         tbl = flow_dv_tbl_resource_get(dev, 0, 0, 0, false, NULL,
17097                                         0, 0, 0, NULL);
17098         if (!tbl)
17099                 goto err;
17100         dv_attr.match_criteria_enable = flow_dv_matcher_enable(mask.buf);
17101         __flow_dv_adjust_buf_size(&mask.size, dv_attr.match_criteria_enable);
17102         ret = mlx5_flow_os_create_flow_matcher(sh->cdev->ctx, &dv_attr,
17103                                                tbl->obj, &matcher);
17104         if (ret)
17105                 goto err;
17106         __flow_dv_adjust_buf_size(&value.size, dv_attr.match_criteria_enable);
17107         ret = mlx5_flow_os_create_flow(matcher, (void *)&value, 1,
17108                                        &sh->dr_drop_action, &flow);
17109 err:
17110         /*
17111          * If DR drop action is not supported on root table, flow create will
17112          * be failed with EOPNOTSUPP or EPROTONOSUPPORT.
17113          */
17114         if (!flow) {
17115                 if (matcher &&
17116                     (errno == EPROTONOSUPPORT || errno == EOPNOTSUPP))
17117                         DRV_LOG(INFO, "DR drop action is not supported in root table.");
17118                 else
17119                         DRV_LOG(ERR, "Unexpected error in DR drop action support detection");
17120                 ret = -1;
17121         } else {
17122                 claim_zero(mlx5_flow_os_destroy_flow(flow));
17123         }
17124         if (matcher)
17125                 claim_zero(mlx5_flow_os_destroy_flow_matcher(matcher));
17126         if (tbl)
17127                 flow_dv_tbl_resource_release(MLX5_SH(dev), tbl);
17128         return ret;
17129 }
17130
17131 /**
17132  * Validate the batch counter support in root table.
17133  *
17134  * Create a simple flow with invalid counter and drop action on root table to
17135  * validate if batch counter with offset on root table is supported or not.
17136  *
17137  * @param[in] dev
17138  *   Pointer to rte_eth_dev structure.
17139  *
17140  * @return
17141  *   0 on success, a negative errno value otherwise and rte_errno is set.
17142  */
17143 int
17144 mlx5_flow_dv_discover_counter_offset_support(struct rte_eth_dev *dev)
17145 {
17146         struct mlx5_priv *priv = dev->data->dev_private;
17147         struct mlx5_dev_ctx_shared *sh = priv->sh;
17148         struct mlx5_flow_dv_match_params mask = {
17149                 .size = sizeof(mask.buf),
17150         };
17151         struct mlx5_flow_dv_match_params value = {
17152                 .size = sizeof(value.buf),
17153         };
17154         struct mlx5dv_flow_matcher_attr dv_attr = {
17155                 .type = IBV_FLOW_ATTR_NORMAL | IBV_FLOW_ATTR_FLAGS_EGRESS,
17156                 .priority = 0,
17157                 .match_criteria_enable = 0,
17158                 .match_mask = (void *)&mask,
17159         };
17160         void *actions[2] = { 0 };
17161         struct mlx5_flow_tbl_resource *tbl = NULL;
17162         struct mlx5_devx_obj *dcs = NULL;
17163         void *matcher = NULL;
17164         void *flow = NULL;
17165         int ret = -1;
17166
17167         tbl = flow_dv_tbl_resource_get(dev, 0, 1, 0, false, NULL,
17168                                         0, 0, 0, NULL);
17169         if (!tbl)
17170                 goto err;
17171         dcs = mlx5_devx_cmd_flow_counter_alloc(priv->sh->cdev->ctx, 0x4);
17172         if (!dcs)
17173                 goto err;
17174         ret = mlx5_flow_os_create_flow_action_count(dcs->obj, UINT16_MAX,
17175                                                     &actions[0]);
17176         if (ret)
17177                 goto err;
17178         dv_attr.match_criteria_enable = flow_dv_matcher_enable(mask.buf);
17179         __flow_dv_adjust_buf_size(&mask.size, dv_attr.match_criteria_enable);
17180         ret = mlx5_flow_os_create_flow_matcher(sh->cdev->ctx, &dv_attr,
17181                                                tbl->obj, &matcher);
17182         if (ret)
17183                 goto err;
17184         __flow_dv_adjust_buf_size(&value.size, dv_attr.match_criteria_enable);
17185         ret = mlx5_flow_os_create_flow(matcher, (void *)&value, 1,
17186                                        actions, &flow);
17187 err:
17188         /*
17189          * If batch counter with offset is not supported, the driver will not
17190          * validate the invalid offset value, flow create should success.
17191          * In this case, it means batch counter is not supported in root table.
17192          *
17193          * Otherwise, if flow create is failed, counter offset is supported.
17194          */
17195         if (flow) {
17196                 DRV_LOG(INFO, "Batch counter is not supported in root "
17197                               "table. Switch to fallback mode.");
17198                 rte_errno = ENOTSUP;
17199                 ret = -rte_errno;
17200                 claim_zero(mlx5_flow_os_destroy_flow(flow));
17201         } else {
17202                 /* Check matcher to make sure validate fail at flow create. */
17203                 if (!matcher || (matcher && errno != EINVAL))
17204                         DRV_LOG(ERR, "Unexpected error in counter offset "
17205                                      "support detection");
17206                 ret = 0;
17207         }
17208         if (actions[0])
17209                 claim_zero(mlx5_flow_os_destroy_flow_action(actions[0]));
17210         if (matcher)
17211                 claim_zero(mlx5_flow_os_destroy_flow_matcher(matcher));
17212         if (tbl)
17213                 flow_dv_tbl_resource_release(MLX5_SH(dev), tbl);
17214         if (dcs)
17215                 claim_zero(mlx5_devx_cmd_destroy(dcs));
17216         return ret;
17217 }
17218
17219 /**
17220  * Query a devx counter.
17221  *
17222  * @param[in] dev
17223  *   Pointer to the Ethernet device structure.
17224  * @param[in] cnt
17225  *   Index to the flow counter.
17226  * @param[in] clear
17227  *   Set to clear the counter statistics.
17228  * @param[out] pkts
17229  *   The statistics value of packets.
17230  * @param[out] bytes
17231  *   The statistics value of bytes.
17232  *
17233  * @return
17234  *   0 on success, otherwise return -1.
17235  */
17236 static int
17237 flow_dv_counter_query(struct rte_eth_dev *dev, uint32_t counter, bool clear,
17238                       uint64_t *pkts, uint64_t *bytes)
17239 {
17240         struct mlx5_priv *priv = dev->data->dev_private;
17241         struct mlx5_flow_counter *cnt;
17242         uint64_t inn_pkts, inn_bytes;
17243         int ret;
17244
17245         if (!priv->sh->devx)
17246                 return -1;
17247
17248         ret = _flow_dv_query_count(dev, counter, &inn_pkts, &inn_bytes);
17249         if (ret)
17250                 return -1;
17251         cnt = flow_dv_counter_get_by_idx(dev, counter, NULL);
17252         *pkts = inn_pkts - cnt->hits;
17253         *bytes = inn_bytes - cnt->bytes;
17254         if (clear) {
17255                 cnt->hits = inn_pkts;
17256                 cnt->bytes = inn_bytes;
17257         }
17258         return 0;
17259 }
17260
17261 /**
17262  * Get aged-out flows.
17263  *
17264  * @param[in] dev
17265  *   Pointer to the Ethernet device structure.
17266  * @param[in] context
17267  *   The address of an array of pointers to the aged-out flows contexts.
17268  * @param[in] nb_contexts
17269  *   The length of context array pointers.
17270  * @param[out] error
17271  *   Perform verbose error reporting if not NULL. Initialized in case of
17272  *   error only.
17273  *
17274  * @return
17275  *   how many contexts get in success, otherwise negative errno value.
17276  *   if nb_contexts is 0, return the amount of all aged contexts.
17277  *   if nb_contexts is not 0 , return the amount of aged flows reported
17278  *   in the context array.
17279  * @note: only stub for now
17280  */
17281 static int
17282 flow_dv_get_aged_flows(struct rte_eth_dev *dev,
17283                     void **context,
17284                     uint32_t nb_contexts,
17285                     struct rte_flow_error *error)
17286 {
17287         struct mlx5_priv *priv = dev->data->dev_private;
17288         struct mlx5_age_info *age_info;
17289         struct mlx5_age_param *age_param;
17290         struct mlx5_flow_counter *counter;
17291         struct mlx5_aso_age_action *act;
17292         int nb_flows = 0;
17293
17294         if (nb_contexts && !context)
17295                 return rte_flow_error_set(error, EINVAL,
17296                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
17297                                           NULL, "empty context");
17298         age_info = GET_PORT_AGE_INFO(priv);
17299         rte_spinlock_lock(&age_info->aged_sl);
17300         LIST_FOREACH(act, &age_info->aged_aso, next) {
17301                 nb_flows++;
17302                 if (nb_contexts) {
17303                         context[nb_flows - 1] =
17304                                                 act->age_params.context;
17305                         if (!(--nb_contexts))
17306                                 break;
17307                 }
17308         }
17309         TAILQ_FOREACH(counter, &age_info->aged_counters, next) {
17310                 nb_flows++;
17311                 if (nb_contexts) {
17312                         age_param = MLX5_CNT_TO_AGE(counter);
17313                         context[nb_flows - 1] = age_param->context;
17314                         if (!(--nb_contexts))
17315                                 break;
17316                 }
17317         }
17318         rte_spinlock_unlock(&age_info->aged_sl);
17319         MLX5_AGE_SET(age_info, MLX5_AGE_TRIGGER);
17320         return nb_flows;
17321 }
17322
17323 /*
17324  * Mutex-protected thunk to lock-free flow_dv_counter_alloc().
17325  */
17326 static uint32_t
17327 flow_dv_counter_allocate(struct rte_eth_dev *dev)
17328 {
17329         return flow_dv_counter_alloc(dev, 0);
17330 }
17331
17332 /**
17333  * Validate indirect action.
17334  * Dispatcher for action type specific validation.
17335  *
17336  * @param[in] dev
17337  *   Pointer to the Ethernet device structure.
17338  * @param[in] conf
17339  *   Indirect action configuration.
17340  * @param[in] action
17341  *   The indirect action object to validate.
17342  * @param[out] error
17343  *   Perform verbose error reporting if not NULL. Initialized in case of
17344  *   error only.
17345  *
17346  * @return
17347  *   0 on success, otherwise negative errno value.
17348  */
17349 static int
17350 flow_dv_action_validate(struct rte_eth_dev *dev,
17351                         const struct rte_flow_indir_action_conf *conf,
17352                         const struct rte_flow_action *action,
17353                         struct rte_flow_error *err)
17354 {
17355         struct mlx5_priv *priv = dev->data->dev_private;
17356
17357         RTE_SET_USED(conf);
17358         switch (action->type) {
17359         case RTE_FLOW_ACTION_TYPE_RSS:
17360                 /*
17361                  * priv->obj_ops is set according to driver capabilities.
17362                  * When DevX capabilities are
17363                  * sufficient, it is set to devx_obj_ops.
17364                  * Otherwise, it is set to ibv_obj_ops.
17365                  * ibv_obj_ops doesn't support ind_table_modify operation.
17366                  * In this case the indirect RSS action can't be used.
17367                  */
17368                 if (priv->obj_ops.ind_table_modify == NULL)
17369                         return rte_flow_error_set
17370                                         (err, ENOTSUP,
17371                                          RTE_FLOW_ERROR_TYPE_ACTION,
17372                                          NULL,
17373                                          "Indirect RSS action not supported");
17374                 return mlx5_validate_action_rss(dev, action, err);
17375         case RTE_FLOW_ACTION_TYPE_AGE:
17376                 if (!priv->sh->aso_age_mng)
17377                         return rte_flow_error_set(err, ENOTSUP,
17378                                                 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
17379                                                 NULL,
17380                                                 "Indirect age action not supported");
17381                 return flow_dv_validate_action_age(0, action, dev, err);
17382         case RTE_FLOW_ACTION_TYPE_COUNT:
17383                 return flow_dv_validate_action_count(dev, true, 0, err);
17384         case RTE_FLOW_ACTION_TYPE_CONNTRACK:
17385                 if (!priv->sh->ct_aso_en)
17386                         return rte_flow_error_set(err, ENOTSUP,
17387                                         RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
17388                                         "ASO CT is not supported");
17389                 return mlx5_validate_action_ct(dev, action->conf, err);
17390         default:
17391                 return rte_flow_error_set(err, ENOTSUP,
17392                                           RTE_FLOW_ERROR_TYPE_ACTION,
17393                                           NULL,
17394                                           "action type not supported");
17395         }
17396 }
17397
17398 /*
17399  * Check if the RSS configurations for colors of a meter policy match
17400  * each other, except the queues.
17401  *
17402  * @param[in] r1
17403  *   Pointer to the first RSS flow action.
17404  * @param[in] r2
17405  *   Pointer to the second RSS flow action.
17406  *
17407  * @return
17408  *   0 on match, 1 on conflict.
17409  */
17410 static inline int
17411 flow_dv_mtr_policy_rss_compare(const struct rte_flow_action_rss *r1,
17412                                const struct rte_flow_action_rss *r2)
17413 {
17414         if (!r1 || !r2)
17415                 return 0;
17416         if (r1->func != r2->func || r1->level != r2->level ||
17417             r1->types != r2->types || r1->key_len != r2->key_len ||
17418             memcmp(r1->key, r2->key, r1->key_len))
17419                 return 1;
17420         return 0;
17421 }
17422
17423 /**
17424  * Validate the meter hierarchy chain for meter policy.
17425  *
17426  * @param[in] dev
17427  *   Pointer to the Ethernet device structure.
17428  * @param[in] meter_id
17429  *   Meter id.
17430  * @param[in] action_flags
17431  *   Holds the actions detected until now.
17432  * @param[out] is_rss
17433  *   Is RSS or not.
17434  * @param[out] hierarchy_domain
17435  *   The domain bitmap for hierarchy policy.
17436  * @param[out] error
17437  *   Perform verbose error reporting if not NULL. Initialized in case of
17438  *   error only.
17439  *
17440  * @return
17441  *   0 on success, otherwise negative errno value with error set.
17442  */
17443 static int
17444 flow_dv_validate_policy_mtr_hierarchy(struct rte_eth_dev *dev,
17445                                   uint32_t meter_id,
17446                                   uint64_t action_flags,
17447                                   bool *is_rss,
17448                                   uint8_t *hierarchy_domain,
17449                                   struct rte_mtr_error *error)
17450 {
17451         struct mlx5_priv *priv = dev->data->dev_private;
17452         struct mlx5_flow_meter_info *fm;
17453         struct mlx5_flow_meter_policy *policy;
17454         uint8_t cnt = 1;
17455
17456         if (action_flags & (MLX5_FLOW_FATE_ACTIONS |
17457                             MLX5_FLOW_FATE_ESWITCH_ACTIONS))
17458                 return -rte_mtr_error_set(error, EINVAL,
17459                                         RTE_MTR_ERROR_TYPE_POLICER_ACTION_GREEN,
17460                                         NULL,
17461                                         "Multiple fate actions not supported.");
17462         *hierarchy_domain = 0;
17463         while (true) {
17464                 fm = mlx5_flow_meter_find(priv, meter_id, NULL);
17465                 if (!fm)
17466                         return -rte_mtr_error_set(error, EINVAL,
17467                                                 RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
17468                                         "Meter not found in meter hierarchy.");
17469                 if (fm->def_policy)
17470                         return -rte_mtr_error_set(error, EINVAL,
17471                                         RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
17472                         "Non termination meter not supported in hierarchy.");
17473                 policy = mlx5_flow_meter_policy_find(dev, fm->policy_id, NULL);
17474                 MLX5_ASSERT(policy);
17475                 /**
17476                  * Only inherit the supported domains of the first meter in
17477                  * hierarchy.
17478                  * One meter supports at least one domain.
17479                  */
17480                 if (!*hierarchy_domain) {
17481                         if (policy->transfer)
17482                                 *hierarchy_domain |=
17483                                                 MLX5_MTR_DOMAIN_TRANSFER_BIT;
17484                         if (policy->ingress)
17485                                 *hierarchy_domain |=
17486                                                 MLX5_MTR_DOMAIN_INGRESS_BIT;
17487                         if (policy->egress)
17488                                 *hierarchy_domain |= MLX5_MTR_DOMAIN_EGRESS_BIT;
17489                 }
17490                 if (!policy->is_hierarchy) {
17491                         *is_rss = policy->is_rss;
17492                         break;
17493                 }
17494                 meter_id = policy->act_cnt[RTE_COLOR_GREEN].next_mtr_id;
17495                 if (++cnt >= MLX5_MTR_CHAIN_MAX_NUM)
17496                         return -rte_mtr_error_set(error, EINVAL,
17497                                         RTE_MTR_ERROR_TYPE_METER_POLICY, NULL,
17498                                         "Exceed max hierarchy meter number.");
17499         }
17500         return 0;
17501 }
17502
17503 /**
17504  * Validate meter policy actions.
17505  * Dispatcher for action type specific validation.
17506  *
17507  * @param[in] dev
17508  *   Pointer to the Ethernet device structure.
17509  * @param[in] action
17510  *   The meter policy action object to validate.
17511  * @param[in] attr
17512  *   Attributes of flow to determine steering domain.
17513  * @param[out] error
17514  *   Perform verbose error reporting if not NULL. Initialized in case of
17515  *   error only.
17516  *
17517  * @return
17518  *   0 on success, otherwise negative errno value.
17519  */
17520 static int
17521 flow_dv_validate_mtr_policy_acts(struct rte_eth_dev *dev,
17522                         const struct rte_flow_action *actions[RTE_COLORS],
17523                         struct rte_flow_attr *attr,
17524                         bool *is_rss,
17525                         uint8_t *domain_bitmap,
17526                         uint8_t *policy_mode,
17527                         struct rte_mtr_error *error)
17528 {
17529         struct mlx5_priv *priv = dev->data->dev_private;
17530         struct mlx5_dev_config *dev_conf = &priv->config;
17531         const struct rte_flow_action *act;
17532         uint64_t action_flags[RTE_COLORS] = {0};
17533         int actions_n;
17534         int i, ret;
17535         struct rte_flow_error flow_err;
17536         uint8_t domain_color[RTE_COLORS] = {0};
17537         uint8_t def_domain = MLX5_MTR_ALL_DOMAIN_BIT;
17538         uint8_t hierarchy_domain = 0;
17539         const struct rte_flow_action_meter *mtr;
17540         bool def_green = false;
17541         bool def_yellow = false;
17542         const struct rte_flow_action_rss *rss_color[RTE_COLORS] = {NULL};
17543
17544         if (!priv->config.dv_esw_en)
17545                 def_domain &= ~MLX5_MTR_DOMAIN_TRANSFER_BIT;
17546         *domain_bitmap = def_domain;
17547         /* Red color could only support DROP action. */
17548         if (!actions[RTE_COLOR_RED] ||
17549             actions[RTE_COLOR_RED]->type != RTE_FLOW_ACTION_TYPE_DROP)
17550                 return -rte_mtr_error_set(error, ENOTSUP,
17551                                 RTE_MTR_ERROR_TYPE_METER_POLICY,
17552                                 NULL, "Red color only supports drop action.");
17553         /*
17554          * Check default policy actions:
17555          * Green / Yellow: no action, Red: drop action
17556          * Either G or Y will trigger default policy actions to be created.
17557          */
17558         if (!actions[RTE_COLOR_GREEN] ||
17559             actions[RTE_COLOR_GREEN]->type == RTE_FLOW_ACTION_TYPE_END)
17560                 def_green = true;
17561         if (!actions[RTE_COLOR_YELLOW] ||
17562             actions[RTE_COLOR_YELLOW]->type == RTE_FLOW_ACTION_TYPE_END)
17563                 def_yellow = true;
17564         if (def_green && def_yellow) {
17565                 *policy_mode = MLX5_MTR_POLICY_MODE_DEF;
17566                 return 0;
17567         } else if (!def_green && def_yellow) {
17568                 *policy_mode = MLX5_MTR_POLICY_MODE_OG;
17569         } else if (def_green && !def_yellow) {
17570                 *policy_mode = MLX5_MTR_POLICY_MODE_OY;
17571         }
17572         /* Set to empty string in case of NULL pointer access by user. */
17573         flow_err.message = "";
17574         for (i = 0; i < RTE_COLORS; i++) {
17575                 act = actions[i];
17576                 for (action_flags[i] = 0, actions_n = 0;
17577                      act && act->type != RTE_FLOW_ACTION_TYPE_END;
17578                      act++) {
17579                         if (actions_n == MLX5_DV_MAX_NUMBER_OF_ACTIONS)
17580                                 return -rte_mtr_error_set(error, ENOTSUP,
17581                                           RTE_MTR_ERROR_TYPE_METER_POLICY,
17582                                           NULL, "too many actions");
17583                         switch (act->type) {
17584                         case RTE_FLOW_ACTION_TYPE_PORT_ID:
17585                         case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT:
17586                                 if (!priv->config.dv_esw_en)
17587                                         return -rte_mtr_error_set(error,
17588                                         ENOTSUP,
17589                                         RTE_MTR_ERROR_TYPE_METER_POLICY,
17590                                         NULL, "PORT action validate check"
17591                                         " fail for ESW disable");
17592                                 ret = flow_dv_validate_action_port_id(dev,
17593                                                 action_flags[i],
17594                                                 act, attr, &flow_err);
17595                                 if (ret)
17596                                         return -rte_mtr_error_set(error,
17597                                         ENOTSUP,
17598                                         RTE_MTR_ERROR_TYPE_METER_POLICY,
17599                                         NULL, flow_err.message ?
17600                                         flow_err.message :
17601                                         "PORT action validate check fail");
17602                                 ++actions_n;
17603                                 action_flags[i] |= MLX5_FLOW_ACTION_PORT_ID;
17604                                 break;
17605                         case RTE_FLOW_ACTION_TYPE_MARK:
17606                                 ret = flow_dv_validate_action_mark(dev, act,
17607                                                            action_flags[i],
17608                                                            attr, &flow_err);
17609                                 if (ret < 0)
17610                                         return -rte_mtr_error_set(error,
17611                                         ENOTSUP,
17612                                         RTE_MTR_ERROR_TYPE_METER_POLICY,
17613                                         NULL, flow_err.message ?
17614                                         flow_err.message :
17615                                         "Mark action validate check fail");
17616                                 if (dev_conf->dv_xmeta_en !=
17617                                         MLX5_XMETA_MODE_LEGACY)
17618                                         return -rte_mtr_error_set(error,
17619                                         ENOTSUP,
17620                                         RTE_MTR_ERROR_TYPE_METER_POLICY,
17621                                         NULL, "Extend MARK action is "
17622                                         "not supported. Please try use "
17623                                         "default policy for meter.");
17624                                 action_flags[i] |= MLX5_FLOW_ACTION_MARK;
17625                                 ++actions_n;
17626                                 break;
17627                         case RTE_FLOW_ACTION_TYPE_SET_TAG:
17628                                 ret = flow_dv_validate_action_set_tag(dev,
17629                                                         act, action_flags[i],
17630                                                         attr, &flow_err);
17631                                 if (ret)
17632                                         return -rte_mtr_error_set(error,
17633                                         ENOTSUP,
17634                                         RTE_MTR_ERROR_TYPE_METER_POLICY,
17635                                         NULL, flow_err.message ?
17636                                         flow_err.message :
17637                                         "Set tag action validate check fail");
17638                                 action_flags[i] |= MLX5_FLOW_ACTION_SET_TAG;
17639                                 ++actions_n;
17640                                 break;
17641                         case RTE_FLOW_ACTION_TYPE_DROP:
17642                                 ret = mlx5_flow_validate_action_drop
17643                                         (action_flags[i], attr, &flow_err);
17644                                 if (ret < 0)
17645                                         return -rte_mtr_error_set(error,
17646                                         ENOTSUP,
17647                                         RTE_MTR_ERROR_TYPE_METER_POLICY,
17648                                         NULL, flow_err.message ?
17649                                         flow_err.message :
17650                                         "Drop action validate check fail");
17651                                 action_flags[i] |= MLX5_FLOW_ACTION_DROP;
17652                                 ++actions_n;
17653                                 break;
17654                         case RTE_FLOW_ACTION_TYPE_QUEUE:
17655                                 /*
17656                                  * Check whether extensive
17657                                  * metadata feature is engaged.
17658                                  */
17659                                 if (dev_conf->dv_flow_en &&
17660                                     (dev_conf->dv_xmeta_en !=
17661                                      MLX5_XMETA_MODE_LEGACY) &&
17662                                     mlx5_flow_ext_mreg_supported(dev))
17663                                         return -rte_mtr_error_set(error,
17664                                           ENOTSUP,
17665                                           RTE_MTR_ERROR_TYPE_METER_POLICY,
17666                                           NULL, "Queue action with meta "
17667                                           "is not supported. Please try use "
17668                                           "default policy for meter.");
17669                                 ret = mlx5_flow_validate_action_queue(act,
17670                                                         action_flags[i], dev,
17671                                                         attr, &flow_err);
17672                                 if (ret < 0)
17673                                         return -rte_mtr_error_set(error,
17674                                           ENOTSUP,
17675                                           RTE_MTR_ERROR_TYPE_METER_POLICY,
17676                                           NULL, flow_err.message ?
17677                                           flow_err.message :
17678                                           "Queue action validate check fail");
17679                                 action_flags[i] |= MLX5_FLOW_ACTION_QUEUE;
17680                                 ++actions_n;
17681                                 break;
17682                         case RTE_FLOW_ACTION_TYPE_RSS:
17683                                 if (dev_conf->dv_flow_en &&
17684                                     (dev_conf->dv_xmeta_en !=
17685                                      MLX5_XMETA_MODE_LEGACY) &&
17686                                     mlx5_flow_ext_mreg_supported(dev))
17687                                         return -rte_mtr_error_set(error,
17688                                           ENOTSUP,
17689                                           RTE_MTR_ERROR_TYPE_METER_POLICY,
17690                                           NULL, "RSS action with meta "
17691                                           "is not supported. Please try use "
17692                                           "default policy for meter.");
17693                                 ret = mlx5_validate_action_rss(dev, act,
17694                                                                &flow_err);
17695                                 if (ret < 0)
17696                                         return -rte_mtr_error_set(error,
17697                                           ENOTSUP,
17698                                           RTE_MTR_ERROR_TYPE_METER_POLICY,
17699                                           NULL, flow_err.message ?
17700                                           flow_err.message :
17701                                           "RSS action validate check fail");
17702                                 action_flags[i] |= MLX5_FLOW_ACTION_RSS;
17703                                 ++actions_n;
17704                                 /* Either G or Y will set the RSS. */
17705                                 rss_color[i] = act->conf;
17706                                 break;
17707                         case RTE_FLOW_ACTION_TYPE_JUMP:
17708                                 ret = flow_dv_validate_action_jump(dev,
17709                                         NULL, act, action_flags[i],
17710                                         attr, true, &flow_err);
17711                                 if (ret)
17712                                         return -rte_mtr_error_set(error,
17713                                           ENOTSUP,
17714                                           RTE_MTR_ERROR_TYPE_METER_POLICY,
17715                                           NULL, flow_err.message ?
17716                                           flow_err.message :
17717                                           "Jump action validate check fail");
17718                                 ++actions_n;
17719                                 action_flags[i] |= MLX5_FLOW_ACTION_JUMP;
17720                                 break;
17721                         /*
17722                          * Only the last meter in the hierarchy will support
17723                          * the YELLOW color steering. Then in the meter policy
17724                          * actions list, there should be no other meter inside.
17725                          */
17726                         case RTE_FLOW_ACTION_TYPE_METER:
17727                                 if (i != RTE_COLOR_GREEN)
17728                                         return -rte_mtr_error_set(error,
17729                                                 ENOTSUP,
17730                                                 RTE_MTR_ERROR_TYPE_METER_POLICY,
17731                                                 NULL,
17732                                                 "Meter hierarchy only supports GREEN color.");
17733                                 if (*policy_mode != MLX5_MTR_POLICY_MODE_OG)
17734                                         return -rte_mtr_error_set(error,
17735                                                 ENOTSUP,
17736                                                 RTE_MTR_ERROR_TYPE_METER_POLICY,
17737                                                 NULL,
17738                                                 "No yellow policy should be provided in meter hierarchy.");
17739                                 mtr = act->conf;
17740                                 ret = flow_dv_validate_policy_mtr_hierarchy(dev,
17741                                                         mtr->mtr_id,
17742                                                         action_flags[i],
17743                                                         is_rss,
17744                                                         &hierarchy_domain,
17745                                                         error);
17746                                 if (ret)
17747                                         return ret;
17748                                 ++actions_n;
17749                                 action_flags[i] |=
17750                                 MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY;
17751                                 break;
17752                         default:
17753                                 return -rte_mtr_error_set(error, ENOTSUP,
17754                                         RTE_MTR_ERROR_TYPE_METER_POLICY,
17755                                         NULL,
17756                                         "Doesn't support optional action");
17757                         }
17758                 }
17759                 if (action_flags[i] & MLX5_FLOW_ACTION_PORT_ID) {
17760                         domain_color[i] = MLX5_MTR_DOMAIN_TRANSFER_BIT;
17761                 } else if ((action_flags[i] &
17762                           (MLX5_FLOW_ACTION_RSS | MLX5_FLOW_ACTION_QUEUE)) ||
17763                           (action_flags[i] & MLX5_FLOW_ACTION_MARK)) {
17764                         /*
17765                          * Only support MLX5_XMETA_MODE_LEGACY
17766                          * so MARK action is only in ingress domain.
17767                          */
17768                         domain_color[i] = MLX5_MTR_DOMAIN_INGRESS_BIT;
17769                 } else {
17770                         domain_color[i] = def_domain;
17771                         if (action_flags[i] &&
17772                             !(action_flags[i] & MLX5_FLOW_FATE_ESWITCH_ACTIONS))
17773                                 domain_color[i] &=
17774                                 ~MLX5_MTR_DOMAIN_TRANSFER_BIT;
17775                 }
17776                 if (action_flags[i] &
17777                     MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY)
17778                         domain_color[i] &= hierarchy_domain;
17779                 /*
17780                  * Non-termination actions only support NIC Tx domain.
17781                  * The adjustion should be skipped when there is no
17782                  * action or only END is provided. The default domains
17783                  * bit-mask is set to find the MIN intersection.
17784                  * The action flags checking should also be skipped.
17785                  */
17786                 if ((def_green && i == RTE_COLOR_GREEN) ||
17787                     (def_yellow && i == RTE_COLOR_YELLOW))
17788                         continue;
17789                 /*
17790                  * Validate the drop action mutual exclusion
17791                  * with other actions. Drop action is mutually-exclusive
17792                  * with any other action, except for Count action.
17793                  */
17794                 if ((action_flags[i] & MLX5_FLOW_ACTION_DROP) &&
17795                     (action_flags[i] & ~MLX5_FLOW_ACTION_DROP)) {
17796                         return -rte_mtr_error_set(error, ENOTSUP,
17797                                 RTE_MTR_ERROR_TYPE_METER_POLICY,
17798                                 NULL, "Drop action is mutually-exclusive "
17799                                 "with any other action");
17800                 }
17801                 /* Eswitch has few restrictions on using items and actions */
17802                 if (domain_color[i] & MLX5_MTR_DOMAIN_TRANSFER_BIT) {
17803                         if (!mlx5_flow_ext_mreg_supported(dev) &&
17804                             action_flags[i] & MLX5_FLOW_ACTION_MARK)
17805                                 return -rte_mtr_error_set(error, ENOTSUP,
17806                                         RTE_MTR_ERROR_TYPE_METER_POLICY,
17807                                         NULL, "unsupported action MARK");
17808                         if (action_flags[i] & MLX5_FLOW_ACTION_QUEUE)
17809                                 return -rte_mtr_error_set(error, ENOTSUP,
17810                                         RTE_MTR_ERROR_TYPE_METER_POLICY,
17811                                         NULL, "unsupported action QUEUE");
17812                         if (action_flags[i] & MLX5_FLOW_ACTION_RSS)
17813                                 return -rte_mtr_error_set(error, ENOTSUP,
17814                                         RTE_MTR_ERROR_TYPE_METER_POLICY,
17815                                         NULL, "unsupported action RSS");
17816                         if (!(action_flags[i] & MLX5_FLOW_FATE_ESWITCH_ACTIONS))
17817                                 return -rte_mtr_error_set(error, ENOTSUP,
17818                                         RTE_MTR_ERROR_TYPE_METER_POLICY,
17819                                         NULL, "no fate action is found");
17820                 } else {
17821                         if (!(action_flags[i] & MLX5_FLOW_FATE_ACTIONS) &&
17822                             (domain_color[i] & MLX5_MTR_DOMAIN_INGRESS_BIT)) {
17823                                 if ((domain_color[i] &
17824                                      MLX5_MTR_DOMAIN_EGRESS_BIT))
17825                                         domain_color[i] =
17826                                                 MLX5_MTR_DOMAIN_EGRESS_BIT;
17827                                 else
17828                                         return -rte_mtr_error_set(error,
17829                                                 ENOTSUP,
17830                                                 RTE_MTR_ERROR_TYPE_METER_POLICY,
17831                                                 NULL,
17832                                                 "no fate action is found");
17833                         }
17834                 }
17835         }
17836         /* If both colors have RSS, the attributes should be the same. */
17837         if (flow_dv_mtr_policy_rss_compare(rss_color[RTE_COLOR_GREEN],
17838                                            rss_color[RTE_COLOR_YELLOW]))
17839                 return -rte_mtr_error_set(error, EINVAL,
17840                                           RTE_MTR_ERROR_TYPE_METER_POLICY,
17841                                           NULL, "policy RSS attr conflict");
17842         if (rss_color[RTE_COLOR_GREEN] || rss_color[RTE_COLOR_YELLOW])
17843                 *is_rss = true;
17844         /* "domain_color[C]" is non-zero for each color, default is ALL. */
17845         if (!def_green && !def_yellow &&
17846             domain_color[RTE_COLOR_GREEN] != domain_color[RTE_COLOR_YELLOW] &&
17847             !(action_flags[RTE_COLOR_GREEN] & MLX5_FLOW_ACTION_DROP) &&
17848             !(action_flags[RTE_COLOR_YELLOW] & MLX5_FLOW_ACTION_DROP))
17849                 return -rte_mtr_error_set(error, EINVAL,
17850                                           RTE_MTR_ERROR_TYPE_METER_POLICY,
17851                                           NULL, "policy domains conflict");
17852         /*
17853          * At least one color policy is listed in the actions, the domains
17854          * to be supported should be the intersection.
17855          */
17856         *domain_bitmap = domain_color[RTE_COLOR_GREEN] &
17857                          domain_color[RTE_COLOR_YELLOW];
17858         return 0;
17859 }
17860
17861 static int
17862 flow_dv_sync_domain(struct rte_eth_dev *dev, uint32_t domains, uint32_t flags)
17863 {
17864         struct mlx5_priv *priv = dev->data->dev_private;
17865         int ret = 0;
17866
17867         if ((domains & MLX5_DOMAIN_BIT_NIC_RX) && priv->sh->rx_domain != NULL) {
17868                 ret = mlx5_os_flow_dr_sync_domain(priv->sh->rx_domain,
17869                                                 flags);
17870                 if (ret != 0)
17871                         return ret;
17872         }
17873         if ((domains & MLX5_DOMAIN_BIT_NIC_TX) && priv->sh->tx_domain != NULL) {
17874                 ret = mlx5_os_flow_dr_sync_domain(priv->sh->tx_domain, flags);
17875                 if (ret != 0)
17876                         return ret;
17877         }
17878         if ((domains & MLX5_DOMAIN_BIT_FDB) && priv->sh->fdb_domain != NULL) {
17879                 ret = mlx5_os_flow_dr_sync_domain(priv->sh->fdb_domain, flags);
17880                 if (ret != 0)
17881                         return ret;
17882         }
17883         return 0;
17884 }
17885
17886 const struct mlx5_flow_driver_ops mlx5_flow_dv_drv_ops = {
17887         .validate = flow_dv_validate,
17888         .prepare = flow_dv_prepare,
17889         .translate = flow_dv_translate,
17890         .apply = flow_dv_apply,
17891         .remove = flow_dv_remove,
17892         .destroy = flow_dv_destroy,
17893         .query = flow_dv_query,
17894         .create_mtr_tbls = flow_dv_create_mtr_tbls,
17895         .destroy_mtr_tbls = flow_dv_destroy_mtr_tbls,
17896         .destroy_mtr_drop_tbls = flow_dv_destroy_mtr_drop_tbls,
17897         .create_meter = flow_dv_mtr_alloc,
17898         .free_meter = flow_dv_aso_mtr_release_to_pool,
17899         .validate_mtr_acts = flow_dv_validate_mtr_policy_acts,
17900         .create_mtr_acts = flow_dv_create_mtr_policy_acts,
17901         .destroy_mtr_acts = flow_dv_destroy_mtr_policy_acts,
17902         .create_policy_rules = flow_dv_create_policy_rules,
17903         .destroy_policy_rules = flow_dv_destroy_policy_rules,
17904         .create_def_policy = flow_dv_create_def_policy,
17905         .destroy_def_policy = flow_dv_destroy_def_policy,
17906         .meter_sub_policy_rss_prepare = flow_dv_meter_sub_policy_rss_prepare,
17907         .meter_hierarchy_rule_create = flow_dv_meter_hierarchy_rule_create,
17908         .destroy_sub_policy_with_rxq = flow_dv_destroy_sub_policy_with_rxq,
17909         .counter_alloc = flow_dv_counter_allocate,
17910         .counter_free = flow_dv_counter_free,
17911         .counter_query = flow_dv_counter_query,
17912         .get_aged_flows = flow_dv_get_aged_flows,
17913         .action_validate = flow_dv_action_validate,
17914         .action_create = flow_dv_action_create,
17915         .action_destroy = flow_dv_action_destroy,
17916         .action_update = flow_dv_action_update,
17917         .action_query = flow_dv_action_query,
17918         .sync_domain = flow_dv_sync_domain,
17919 };
17920
17921 #endif /* HAVE_IBV_FLOW_DV_SUPPORT */
17922