eal: remove sys/queue.h from public headers
[dpdk.git] / drivers / net / softnic / rte_eth_softnic_flow.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2018 Intel Corporation
3  */
4 #include <stdint.h>
5 #include <stdlib.h>
6 #include <string.h>
7
8 #include <rte_common.h>
9 #include <rte_byteorder.h>
10 #include <rte_malloc.h>
11 #include <rte_string_fns.h>
12 #include <rte_flow.h>
13 #include <rte_flow_driver.h>
14 #include <rte_tailq.h>
15
16 #include "rte_eth_softnic_internals.h"
17 #include "rte_eth_softnic.h"
18
19 #define rte_htons rte_cpu_to_be_16
20 #define rte_htonl rte_cpu_to_be_32
21
22 #define rte_ntohs rte_be_to_cpu_16
23 #define rte_ntohl rte_be_to_cpu_32
24
25 static struct rte_flow *
26 softnic_flow_find(struct softnic_table *table,
27         struct softnic_table_rule_match *rule_match)
28 {
29         struct rte_flow *flow;
30
31         TAILQ_FOREACH(flow, &table->flows, node)
32                 if (memcmp(&flow->match, rule_match, sizeof(*rule_match)) == 0)
33                         return flow;
34
35         return NULL;
36 }
37
38 int
39 flow_attr_map_set(struct pmd_internals *softnic,
40                 uint32_t group_id,
41                 int ingress,
42                 const char *pipeline_name,
43                 uint32_t table_id)
44 {
45         struct pipeline *pipeline;
46         struct flow_attr_map *map;
47
48         if (group_id >= SOFTNIC_FLOW_MAX_GROUPS ||
49                         pipeline_name == NULL)
50                 return -1;
51
52         pipeline = softnic_pipeline_find(softnic, pipeline_name);
53         if (pipeline == NULL ||
54                         table_id >= pipeline->n_tables)
55                 return -1;
56
57         map = (ingress) ? &softnic->flow.ingress_map[group_id] :
58                 &softnic->flow.egress_map[group_id];
59         strlcpy(map->pipeline_name, pipeline_name, sizeof(map->pipeline_name));
60         map->table_id = table_id;
61         map->valid = 1;
62
63         return 0;
64 }
65
66 struct flow_attr_map *
67 flow_attr_map_get(struct pmd_internals *softnic,
68                 uint32_t group_id,
69                 int ingress)
70 {
71         if (group_id >= SOFTNIC_FLOW_MAX_GROUPS)
72                 return NULL;
73
74         return (ingress) ? &softnic->flow.ingress_map[group_id] :
75                 &softnic->flow.egress_map[group_id];
76 }
77
78 static int
79 flow_pipeline_table_get(struct pmd_internals *softnic,
80                 const struct rte_flow_attr *attr,
81                 const char **pipeline_name,
82                 uint32_t *table_id,
83                 struct rte_flow_error *error)
84 {
85         struct flow_attr_map *map;
86
87         if (attr == NULL)
88                 return rte_flow_error_set(error,
89                                 EINVAL,
90                                 RTE_FLOW_ERROR_TYPE_ATTR,
91                                 NULL,
92                                 "Null attr");
93
94         if (!attr->ingress && !attr->egress)
95                 return rte_flow_error_set(error,
96                                 EINVAL,
97                                 RTE_FLOW_ERROR_TYPE_ATTR_INGRESS,
98                                 attr,
99                                 "Ingress/egress not specified");
100
101         if (attr->ingress && attr->egress)
102                 return rte_flow_error_set(error,
103                                 EINVAL,
104                                 RTE_FLOW_ERROR_TYPE_ATTR_INGRESS,
105                                 attr,
106                                 "Setting both ingress and egress is not allowed");
107
108         map = flow_attr_map_get(softnic,
109                         attr->group,
110                         attr->ingress);
111         if (map == NULL ||
112                         map->valid == 0)
113                 return rte_flow_error_set(error,
114                                 EINVAL,
115                                 RTE_FLOW_ERROR_TYPE_ATTR_GROUP,
116                                 attr,
117                                 "Invalid group ID");
118
119         if (pipeline_name)
120                 *pipeline_name = map->pipeline_name;
121
122         if (table_id)
123                 *table_id = map->table_id;
124
125         return 0;
126 }
127
128 union flow_item {
129         uint8_t raw[TABLE_RULE_MATCH_SIZE_MAX];
130         struct rte_flow_item_eth eth;
131         struct rte_flow_item_vlan vlan;
132         struct rte_flow_item_ipv4 ipv4;
133         struct rte_flow_item_ipv6 ipv6;
134         struct rte_flow_item_icmp icmp;
135         struct rte_flow_item_udp udp;
136         struct rte_flow_item_tcp tcp;
137         struct rte_flow_item_sctp sctp;
138         struct rte_flow_item_vxlan vxlan;
139         struct rte_flow_item_e_tag e_tag;
140         struct rte_flow_item_nvgre nvgre;
141         struct rte_flow_item_mpls mpls;
142         struct rte_flow_item_gre gre;
143         struct rte_flow_item_gtp gtp;
144         struct rte_flow_item_esp esp;
145         struct rte_flow_item_geneve geneve;
146         struct rte_flow_item_vxlan_gpe vxlan_gpe;
147         struct rte_flow_item_arp_eth_ipv4 arp_eth_ipv4;
148         struct rte_flow_item_ipv6_ext ipv6_ext;
149         struct rte_flow_item_icmp6 icmp6;
150         struct rte_flow_item_icmp6_nd_ns icmp6_nd_ns;
151         struct rte_flow_item_icmp6_nd_na icmp6_nd_na;
152         struct rte_flow_item_icmp6_nd_opt icmp6_nd_opt;
153         struct rte_flow_item_icmp6_nd_opt_sla_eth icmp6_nd_opt_sla_eth;
154         struct rte_flow_item_icmp6_nd_opt_tla_eth icmp6_nd_opt_tla_eth;
155 };
156
157 static const union flow_item flow_item_raw_mask;
158
159 static int
160 flow_item_is_proto(enum rte_flow_item_type type,
161         const void **mask,
162         size_t *size)
163 {
164         switch (type) {
165         case RTE_FLOW_ITEM_TYPE_RAW:
166                 *mask = &flow_item_raw_mask;
167                 *size = sizeof(flow_item_raw_mask);
168                 return 1; /* TRUE */
169
170         case RTE_FLOW_ITEM_TYPE_ETH:
171                 *mask = &rte_flow_item_eth_mask;
172                 *size = sizeof(struct rte_ether_hdr);
173                 return 1; /* TRUE */
174
175         case RTE_FLOW_ITEM_TYPE_VLAN:
176                 *mask = &rte_flow_item_vlan_mask;
177                 *size = sizeof(struct rte_vlan_hdr);
178                 return 1;
179
180         case RTE_FLOW_ITEM_TYPE_IPV4:
181                 *mask = &rte_flow_item_ipv4_mask;
182                 *size = sizeof(struct rte_ipv4_hdr);
183                 return 1;
184
185         case RTE_FLOW_ITEM_TYPE_IPV6:
186                 *mask = &rte_flow_item_ipv6_mask;
187                 *size = sizeof(struct rte_ipv6_hdr);
188                 return 1;
189
190         case RTE_FLOW_ITEM_TYPE_ICMP:
191                 *mask = &rte_flow_item_icmp_mask;
192                 *size = sizeof(struct rte_flow_item_icmp);
193                 return 1;
194
195         case RTE_FLOW_ITEM_TYPE_UDP:
196                 *mask = &rte_flow_item_udp_mask;
197                 *size = sizeof(struct rte_flow_item_udp);
198                 return 1;
199
200         case RTE_FLOW_ITEM_TYPE_TCP:
201                 *mask = &rte_flow_item_tcp_mask;
202                 *size = sizeof(struct rte_flow_item_tcp);
203                 return 1;
204
205         case RTE_FLOW_ITEM_TYPE_SCTP:
206                 *mask = &rte_flow_item_sctp_mask;
207                 *size = sizeof(struct rte_flow_item_sctp);
208                 return 1;
209
210         case RTE_FLOW_ITEM_TYPE_VXLAN:
211                 *mask = &rte_flow_item_vxlan_mask;
212                 *size = sizeof(struct rte_flow_item_vxlan);
213                 return 1;
214
215         case RTE_FLOW_ITEM_TYPE_E_TAG:
216                 *mask = &rte_flow_item_e_tag_mask;
217                 *size = sizeof(struct rte_flow_item_e_tag);
218                 return 1;
219
220         case RTE_FLOW_ITEM_TYPE_NVGRE:
221                 *mask = &rte_flow_item_nvgre_mask;
222                 *size = sizeof(struct rte_flow_item_nvgre);
223                 return 1;
224
225         case RTE_FLOW_ITEM_TYPE_MPLS:
226                 *mask = &rte_flow_item_mpls_mask;
227                 *size = sizeof(struct rte_flow_item_mpls);
228                 return 1;
229
230         case RTE_FLOW_ITEM_TYPE_GRE:
231                 *mask = &rte_flow_item_gre_mask;
232                 *size = sizeof(struct rte_flow_item_gre);
233                 return 1;
234
235         case RTE_FLOW_ITEM_TYPE_GTP:
236         case RTE_FLOW_ITEM_TYPE_GTPC:
237         case RTE_FLOW_ITEM_TYPE_GTPU:
238                 *mask = &rte_flow_item_gtp_mask;
239                 *size = sizeof(struct rte_flow_item_gtp);
240                 return 1;
241
242         case RTE_FLOW_ITEM_TYPE_ESP:
243                 *mask = &rte_flow_item_esp_mask;
244                 *size = sizeof(struct rte_flow_item_esp);
245                 return 1;
246
247         case RTE_FLOW_ITEM_TYPE_GENEVE:
248                 *mask = &rte_flow_item_geneve_mask;
249                 *size = sizeof(struct rte_flow_item_geneve);
250                 return 1;
251
252         case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
253                 *mask = &rte_flow_item_vxlan_gpe_mask;
254                 *size = sizeof(struct rte_flow_item_vxlan_gpe);
255                 return 1;
256
257         case RTE_FLOW_ITEM_TYPE_ARP_ETH_IPV4:
258                 *mask = &rte_flow_item_arp_eth_ipv4_mask;
259                 *size = sizeof(struct rte_flow_item_arp_eth_ipv4);
260                 return 1;
261
262         case RTE_FLOW_ITEM_TYPE_IPV6_EXT:
263                 *mask = &rte_flow_item_ipv6_ext_mask;
264                 *size = sizeof(struct rte_flow_item_ipv6_ext);
265                 return 1;
266
267         case RTE_FLOW_ITEM_TYPE_ICMP6:
268                 *mask = &rte_flow_item_icmp6_mask;
269                 *size = sizeof(struct rte_flow_item_icmp6);
270                 return 1;
271
272         case RTE_FLOW_ITEM_TYPE_ICMP6_ND_NS:
273                 *mask = &rte_flow_item_icmp6_nd_ns_mask;
274                 *size = sizeof(struct rte_flow_item_icmp6_nd_ns);
275                 return 1;
276
277         case RTE_FLOW_ITEM_TYPE_ICMP6_ND_NA:
278                 *mask = &rte_flow_item_icmp6_nd_na_mask;
279                 *size = sizeof(struct rte_flow_item_icmp6_nd_na);
280                 return 1;
281
282         case RTE_FLOW_ITEM_TYPE_ICMP6_ND_OPT:
283                 *mask = &rte_flow_item_icmp6_nd_opt_mask;
284                 *size = sizeof(struct rte_flow_item_icmp6_nd_opt);
285                 return 1;
286
287         case RTE_FLOW_ITEM_TYPE_ICMP6_ND_OPT_SLA_ETH:
288                 *mask = &rte_flow_item_icmp6_nd_opt_sla_eth_mask;
289                 *size = sizeof(struct rte_flow_item_icmp6_nd_opt_sla_eth);
290                 return 1;
291
292         case RTE_FLOW_ITEM_TYPE_ICMP6_ND_OPT_TLA_ETH:
293                 *mask = &rte_flow_item_icmp6_nd_opt_tla_eth_mask;
294                 *size = sizeof(struct rte_flow_item_icmp6_nd_opt_tla_eth);
295                 return 1;
296
297         default: return 0; /* FALSE */
298         }
299 }
300
301 static int
302 flow_item_raw_preprocess(const struct rte_flow_item *item,
303         union flow_item *item_spec,
304         union flow_item *item_mask,
305         size_t *item_size,
306         int *item_disabled,
307         struct rte_flow_error *error)
308 {
309         const struct rte_flow_item_raw *item_raw_spec = item->spec;
310         const struct rte_flow_item_raw *item_raw_mask = item->mask;
311         const uint8_t *pattern;
312         const uint8_t *pattern_mask;
313         uint8_t *spec = (uint8_t *)item_spec;
314         uint8_t *mask = (uint8_t *)item_mask;
315         size_t pattern_length, pattern_offset, i;
316         int disabled;
317
318         if (!item->spec)
319                 return rte_flow_error_set(error,
320                         ENOTSUP,
321                         RTE_FLOW_ERROR_TYPE_ITEM,
322                         item,
323                         "RAW: Null specification");
324
325         if (item->last)
326                 return rte_flow_error_set(error,
327                         ENOTSUP,
328                         RTE_FLOW_ERROR_TYPE_ITEM,
329                         item,
330                         "RAW: Range not allowed (last must be NULL)");
331
332         if (item_raw_spec->relative == 0)
333                 return rte_flow_error_set(error,
334                         ENOTSUP,
335                         RTE_FLOW_ERROR_TYPE_ITEM,
336                         item,
337                         "RAW: Absolute offset not supported");
338
339         if (item_raw_spec->search)
340                 return rte_flow_error_set(error,
341                         ENOTSUP,
342                         RTE_FLOW_ERROR_TYPE_ITEM,
343                         item,
344                         "RAW: Search not supported");
345
346         if (item_raw_spec->offset < 0)
347                 return rte_flow_error_set(error,
348                         ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM,
349                         item,
350                         "RAW: Negative offset not supported");
351
352         if (item_raw_spec->length == 0)
353                 return rte_flow_error_set(error,
354                         ENOTSUP,
355                         RTE_FLOW_ERROR_TYPE_ITEM,
356                         item,
357                         "RAW: Zero pattern length");
358
359         if (item_raw_spec->offset + item_raw_spec->length >
360                 TABLE_RULE_MATCH_SIZE_MAX)
361                 return rte_flow_error_set(error,
362                         ENOTSUP,
363                         RTE_FLOW_ERROR_TYPE_ITEM,
364                         item,
365                         "RAW: Item too big");
366
367         if (!item_raw_spec->pattern && item_raw_mask && item_raw_mask->pattern)
368                 return rte_flow_error_set(error,
369                         ENOTSUP,
370                         RTE_FLOW_ERROR_TYPE_ITEM,
371                         item,
372                         "RAW: Non-NULL pattern mask not allowed with NULL pattern");
373
374         pattern = item_raw_spec->pattern;
375         pattern_mask = (item_raw_mask) ? item_raw_mask->pattern : NULL;
376         pattern_length = (size_t)item_raw_spec->length;
377         pattern_offset = (size_t)item_raw_spec->offset;
378
379         disabled = 0;
380         if (pattern_mask == NULL)
381                 disabled = 1;
382         else
383                 for (i = 0; i < pattern_length; i++)
384                         if ((pattern)[i])
385                                 disabled = 1;
386
387         memset(spec, 0, TABLE_RULE_MATCH_SIZE_MAX);
388         if (pattern)
389                 memcpy(&spec[pattern_offset], pattern, pattern_length);
390
391         memset(mask, 0, TABLE_RULE_MATCH_SIZE_MAX);
392         if (pattern_mask)
393                 memcpy(&mask[pattern_offset], pattern_mask, pattern_length);
394
395         *item_size = pattern_offset + pattern_length;
396         *item_disabled = disabled;
397
398         return 0;
399 }
400
401 static int
402 flow_item_proto_preprocess(const struct rte_flow_item *item,
403         union flow_item *item_spec,
404         union flow_item *item_mask,
405         size_t *item_size,
406         int *item_disabled,
407         struct rte_flow_error *error)
408 {
409         const void *mask_default;
410         uint8_t *spec = (uint8_t *)item_spec;
411         uint8_t *mask = (uint8_t *)item_mask;
412         size_t size, i;
413
414         if (!flow_item_is_proto(item->type, &mask_default, &size))
415                 return rte_flow_error_set(error,
416                         ENOTSUP,
417                         RTE_FLOW_ERROR_TYPE_ITEM,
418                         item,
419                         "Item type not supported");
420
421         if (item->type == RTE_FLOW_ITEM_TYPE_RAW)
422                 return flow_item_raw_preprocess(item,
423                         item_spec,
424                         item_mask,
425                         item_size,
426                         item_disabled,
427                         error);
428
429         /* spec */
430         if (!item->spec) {
431                 /* If spec is NULL, then last and mask also have to be NULL. */
432                 if (item->last || item->mask)
433                         return rte_flow_error_set(error,
434                                 EINVAL,
435                                 RTE_FLOW_ERROR_TYPE_ITEM,
436                                 item,
437                                 "Invalid item (NULL spec with non-NULL last or mask)");
438
439                 memset(item_spec, 0, size);
440                 memset(item_mask, 0, size);
441                 *item_size = size;
442                 *item_disabled = 1; /* TRUE */
443                 return 0;
444         }
445
446         memcpy(spec, item->spec, size);
447         *item_size = size;
448
449         /* mask */
450         if (item->mask)
451                 memcpy(mask, item->mask, size);
452         else
453                 memcpy(mask, mask_default, size);
454
455         /* disabled */
456         for (i = 0; i < size; i++)
457                 if (mask[i])
458                         break;
459         *item_disabled = (i == size) ? 1 : 0;
460
461         /* Apply mask over spec. */
462         for (i = 0; i < size; i++)
463                 spec[i] &= mask[i];
464
465         /* last */
466         if (item->last) {
467                 uint8_t last[size];
468
469                 /* init last */
470                 memcpy(last, item->last, size);
471                 for (i = 0; i < size; i++)
472                         last[i] &= mask[i];
473
474                 /* check for range */
475                 for (i = 0; i < size; i++)
476                         if (last[i] != spec[i])
477                                 return rte_flow_error_set(error,
478                                         ENOTSUP,
479                                         RTE_FLOW_ERROR_TYPE_ITEM,
480                                         item,
481                                         "Range not supported");
482         }
483
484         return 0;
485 }
486
487 /***
488  * Skip disabled protocol items and VOID items
489  * until any of the mutually exclusive conditions
490  * from the list below takes place:
491  *    (A) A protocol present in the proto_mask
492  *        is met (either ENABLED or DISABLED);
493  *    (B) A protocol NOT present in the proto_mask is met in ENABLED state;
494  *    (C) The END item is met.
495  */
496 static int
497 flow_item_skip_disabled_protos(const struct rte_flow_item **item,
498         uint64_t proto_mask,
499         size_t *length,
500         struct rte_flow_error *error)
501 {
502         size_t len = 0;
503
504         for ( ; (*item)->type != RTE_FLOW_ITEM_TYPE_END; (*item)++) {
505                 union flow_item spec, mask;
506                 size_t size;
507                 int disabled = 0, status;
508
509                 if ((*item)->type == RTE_FLOW_ITEM_TYPE_VOID)
510                         continue;
511
512                 status = flow_item_proto_preprocess(*item,
513                                 &spec,
514                                 &mask,
515                                 &size,
516                                 &disabled,
517                                 error);
518                 if (status)
519                         return status;
520
521                 if ((proto_mask & (1LLU << (*item)->type)) ||
522                                 !disabled)
523                         break;
524
525                 len += size;
526         }
527
528         if (length)
529                 *length = len;
530
531         return 0;
532 }
533
534 #define FLOW_ITEM_PROTO_IP \
535         ((1LLU << RTE_FLOW_ITEM_TYPE_IPV4) | \
536          (1LLU << RTE_FLOW_ITEM_TYPE_IPV6))
537
538 static void
539 flow_item_skip_void(const struct rte_flow_item **item)
540 {
541         for ( ; ; (*item)++)
542                 if ((*item)->type != RTE_FLOW_ITEM_TYPE_VOID)
543                         return;
544 }
545
546 #define IP_PROTOCOL_TCP 0x06
547 #define IP_PROTOCOL_UDP 0x11
548 #define IP_PROTOCOL_SCTP 0x84
549
550 static int
551 mask_to_depth(uint64_t mask,
552                 uint32_t *depth)
553 {
554         uint64_t n;
555
556         if (mask == UINT64_MAX) {
557                 if (depth)
558                         *depth = 64;
559
560                 return 0;
561         }
562
563         mask = ~mask;
564
565         if (mask & (mask + 1))
566                 return -1;
567
568         n = __builtin_popcountll(mask);
569         if (depth)
570                 *depth = (uint32_t)(64 - n);
571
572         return 0;
573 }
574
575 static int
576 ipv4_mask_to_depth(uint32_t mask,
577                 uint32_t *depth)
578 {
579         uint32_t d;
580         int status;
581
582         status = mask_to_depth(mask | (UINT64_MAX << 32), &d);
583         if (status)
584                 return status;
585
586         d -= 32;
587         if (depth)
588                 *depth = d;
589
590         return 0;
591 }
592
593 static int
594 ipv6_mask_to_depth(uint8_t *mask,
595         uint32_t *depth)
596 {
597         uint64_t *m = (uint64_t *)mask;
598         uint64_t m0 = rte_be_to_cpu_64(m[0]);
599         uint64_t m1 = rte_be_to_cpu_64(m[1]);
600         uint32_t d0, d1;
601         int status;
602
603         status = mask_to_depth(m0, &d0);
604         if (status)
605                 return status;
606
607         status = mask_to_depth(m1, &d1);
608         if (status)
609                 return status;
610
611         if (d0 < 64 && d1)
612                 return -1;
613
614         if (depth)
615                 *depth = d0 + d1;
616
617         return 0;
618 }
619
620 static int
621 port_mask_to_range(uint16_t port,
622         uint16_t port_mask,
623         uint16_t *port0,
624         uint16_t *port1)
625 {
626         int status;
627         uint16_t p0, p1;
628
629         status = mask_to_depth(port_mask | (UINT64_MAX << 16), NULL);
630         if (status)
631                 return -1;
632
633         p0 = port & port_mask;
634         p1 = p0 | ~port_mask;
635
636         if (port0)
637                 *port0 = p0;
638
639         if (port1)
640                 *port1 = p1;
641
642         return 0;
643 }
644
645 static int
646 flow_rule_match_acl_get(struct pmd_internals *softnic __rte_unused,
647                 struct pipeline *pipeline __rte_unused,
648                 struct softnic_table *table __rte_unused,
649                 const struct rte_flow_attr *attr,
650                 const struct rte_flow_item *item,
651                 struct softnic_table_rule_match *rule_match,
652                 struct rte_flow_error *error)
653 {
654         union flow_item spec, mask;
655         size_t size, length = 0;
656         int disabled = 0, status;
657         uint8_t ip_proto, ip_proto_mask;
658
659         memset(rule_match, 0, sizeof(*rule_match));
660         rule_match->match_type = TABLE_ACL;
661         rule_match->match.acl.priority = attr->priority;
662
663         /* VOID or disabled protos only, if any. */
664         status = flow_item_skip_disabled_protos(&item,
665                         FLOW_ITEM_PROTO_IP, &length, error);
666         if (status)
667                 return status;
668
669         /* IP only. */
670         status = flow_item_proto_preprocess(item, &spec, &mask,
671                         &size, &disabled, error);
672         if (status)
673                 return status;
674
675         switch (item->type) {
676         case RTE_FLOW_ITEM_TYPE_IPV4:
677         {
678                 uint32_t sa_depth, da_depth;
679
680                 status = ipv4_mask_to_depth(rte_ntohl(mask.ipv4.hdr.src_addr),
681                                 &sa_depth);
682                 if (status)
683                         return rte_flow_error_set(error,
684                                 EINVAL,
685                                 RTE_FLOW_ERROR_TYPE_ITEM,
686                                 item,
687                                 "ACL: Illegal IPv4 header source address mask");
688
689                 status = ipv4_mask_to_depth(rte_ntohl(mask.ipv4.hdr.dst_addr),
690                                 &da_depth);
691                 if (status)
692                         return rte_flow_error_set(error,
693                                 EINVAL,
694                                 RTE_FLOW_ERROR_TYPE_ITEM,
695                                 item,
696                                 "ACL: Illegal IPv4 header destination address mask");
697
698                 ip_proto = spec.ipv4.hdr.next_proto_id;
699                 ip_proto_mask = mask.ipv4.hdr.next_proto_id;
700
701                 rule_match->match.acl.ip_version = 1;
702                 rule_match->match.acl.ipv4.sa =
703                         rte_ntohl(spec.ipv4.hdr.src_addr);
704                 rule_match->match.acl.ipv4.da =
705                         rte_ntohl(spec.ipv4.hdr.dst_addr);
706                 rule_match->match.acl.sa_depth = sa_depth;
707                 rule_match->match.acl.da_depth = da_depth;
708                 rule_match->match.acl.proto = ip_proto;
709                 rule_match->match.acl.proto_mask = ip_proto_mask;
710                 break;
711         } /* RTE_FLOW_ITEM_TYPE_IPV4 */
712
713         case RTE_FLOW_ITEM_TYPE_IPV6:
714         {
715                 uint32_t sa_depth, da_depth;
716
717                 status = ipv6_mask_to_depth(mask.ipv6.hdr.src_addr, &sa_depth);
718                 if (status)
719                         return rte_flow_error_set(error,
720                                 EINVAL,
721                                 RTE_FLOW_ERROR_TYPE_ITEM,
722                                 item,
723                                 "ACL: Illegal IPv6 header source address mask");
724
725                 status = ipv6_mask_to_depth(mask.ipv6.hdr.dst_addr, &da_depth);
726                 if (status)
727                         return rte_flow_error_set(error,
728                                 EINVAL,
729                                 RTE_FLOW_ERROR_TYPE_ITEM,
730                                 item,
731                                 "ACL: Illegal IPv6 header destination address mask");
732
733                 ip_proto = spec.ipv6.hdr.proto;
734                 ip_proto_mask = mask.ipv6.hdr.proto;
735
736                 rule_match->match.acl.ip_version = 0;
737                 memcpy(rule_match->match.acl.ipv6.sa,
738                         spec.ipv6.hdr.src_addr,
739                         sizeof(spec.ipv6.hdr.src_addr));
740                 memcpy(rule_match->match.acl.ipv6.da,
741                         spec.ipv6.hdr.dst_addr,
742                         sizeof(spec.ipv6.hdr.dst_addr));
743                 rule_match->match.acl.sa_depth = sa_depth;
744                 rule_match->match.acl.da_depth = da_depth;
745                 rule_match->match.acl.proto = ip_proto;
746                 rule_match->match.acl.proto_mask = ip_proto_mask;
747                 break;
748         } /* RTE_FLOW_ITEM_TYPE_IPV6 */
749
750         default:
751                 return rte_flow_error_set(error,
752                         ENOTSUP,
753                         RTE_FLOW_ERROR_TYPE_ITEM,
754                         item,
755                         "ACL: IP protocol required");
756         } /* switch */
757
758         if (ip_proto_mask != UINT8_MAX)
759                 return rte_flow_error_set(error,
760                         EINVAL,
761                         RTE_FLOW_ERROR_TYPE_ITEM,
762                         item,
763                         "ACL: Illegal IP protocol mask");
764
765         item++;
766
767         /* VOID only, if any. */
768         flow_item_skip_void(&item);
769
770         /* TCP/UDP/SCTP only. */
771         status = flow_item_proto_preprocess(item, &spec, &mask,
772                         &size, &disabled, error);
773         if (status)
774                 return status;
775
776         switch (item->type) {
777         case RTE_FLOW_ITEM_TYPE_TCP:
778         {
779                 uint16_t sp0, sp1, dp0, dp1;
780
781                 if (ip_proto != IP_PROTOCOL_TCP)
782                         return rte_flow_error_set(error,
783                                 EINVAL,
784                                 RTE_FLOW_ERROR_TYPE_ITEM,
785                                 item,
786                                 "ACL: Item type is TCP, but IP protocol is not");
787
788                 status = port_mask_to_range(rte_ntohs(spec.tcp.hdr.src_port),
789                                 rte_ntohs(mask.tcp.hdr.src_port),
790                                 &sp0,
791                                 &sp1);
792
793                 if (status)
794                         return rte_flow_error_set(error,
795                                 EINVAL,
796                                 RTE_FLOW_ERROR_TYPE_ITEM,
797                                 item,
798                                 "ACL: Illegal TCP source port mask");
799
800                 status = port_mask_to_range(rte_ntohs(spec.tcp.hdr.dst_port),
801                                 rte_ntohs(mask.tcp.hdr.dst_port),
802                                 &dp0,
803                                 &dp1);
804
805                 if (status)
806                         return rte_flow_error_set(error,
807                                 EINVAL,
808                                 RTE_FLOW_ERROR_TYPE_ITEM,
809                                 item,
810                                 "ACL: Illegal TCP destination port mask");
811
812                 rule_match->match.acl.sp0 = sp0;
813                 rule_match->match.acl.sp1 = sp1;
814                 rule_match->match.acl.dp0 = dp0;
815                 rule_match->match.acl.dp1 = dp1;
816
817                 break;
818         } /* RTE_FLOW_ITEM_TYPE_TCP */
819
820         case RTE_FLOW_ITEM_TYPE_UDP:
821         {
822                 uint16_t sp0, sp1, dp0, dp1;
823
824                 if (ip_proto != IP_PROTOCOL_UDP)
825                         return rte_flow_error_set(error,
826                                 EINVAL,
827                                 RTE_FLOW_ERROR_TYPE_ITEM,
828                                 item,
829                                 "ACL: Item type is UDP, but IP protocol is not");
830
831                 status = port_mask_to_range(rte_ntohs(spec.udp.hdr.src_port),
832                         rte_ntohs(mask.udp.hdr.src_port),
833                         &sp0,
834                         &sp1);
835                 if (status)
836                         return rte_flow_error_set(error,
837                                 EINVAL,
838                                 RTE_FLOW_ERROR_TYPE_ITEM,
839                                 item,
840                                 "ACL: Illegal UDP source port mask");
841
842                 status = port_mask_to_range(rte_ntohs(spec.udp.hdr.dst_port),
843                         rte_ntohs(mask.udp.hdr.dst_port),
844                         &dp0,
845                         &dp1);
846                 if (status)
847                         return rte_flow_error_set(error,
848                                 EINVAL,
849                                 RTE_FLOW_ERROR_TYPE_ITEM,
850                                 item,
851                                 "ACL: Illegal UDP destination port mask");
852
853                 rule_match->match.acl.sp0 = sp0;
854                 rule_match->match.acl.sp1 = sp1;
855                 rule_match->match.acl.dp0 = dp0;
856                 rule_match->match.acl.dp1 = dp1;
857
858                 break;
859         } /* RTE_FLOW_ITEM_TYPE_UDP */
860
861         case RTE_FLOW_ITEM_TYPE_SCTP:
862         {
863                 uint16_t sp0, sp1, dp0, dp1;
864
865                 if (ip_proto != IP_PROTOCOL_SCTP)
866                         return rte_flow_error_set(error,
867                                 EINVAL,
868                                 RTE_FLOW_ERROR_TYPE_ITEM,
869                                 item,
870                                 "ACL: Item type is SCTP, but IP protocol is not");
871
872                 status = port_mask_to_range(rte_ntohs(spec.sctp.hdr.src_port),
873                         rte_ntohs(mask.sctp.hdr.src_port),
874                         &sp0,
875                         &sp1);
876
877                 if (status)
878                         return rte_flow_error_set(error,
879                                 EINVAL,
880                                 RTE_FLOW_ERROR_TYPE_ITEM,
881                                 item,
882                                 "ACL: Illegal SCTP source port mask");
883
884                 status = port_mask_to_range(rte_ntohs(spec.sctp.hdr.dst_port),
885                         rte_ntohs(mask.sctp.hdr.dst_port),
886                         &dp0,
887                         &dp1);
888                 if (status)
889                         return rte_flow_error_set(error,
890                                 EINVAL,
891                                 RTE_FLOW_ERROR_TYPE_ITEM,
892                                 item,
893                                 "ACL: Illegal SCTP destination port mask");
894
895                 rule_match->match.acl.sp0 = sp0;
896                 rule_match->match.acl.sp1 = sp1;
897                 rule_match->match.acl.dp0 = dp0;
898                 rule_match->match.acl.dp1 = dp1;
899
900                 break;
901         } /* RTE_FLOW_ITEM_TYPE_SCTP */
902
903         default:
904                 return rte_flow_error_set(error,
905                         ENOTSUP,
906                         RTE_FLOW_ERROR_TYPE_ITEM,
907                         item,
908                         "ACL: TCP/UDP/SCTP required");
909         } /* switch */
910
911         item++;
912
913         /* VOID or disabled protos only, if any. */
914         status = flow_item_skip_disabled_protos(&item, 0, NULL, error);
915         if (status)
916                 return status;
917
918         /* END only. */
919         if (item->type != RTE_FLOW_ITEM_TYPE_END)
920                 return rte_flow_error_set(error,
921                         EINVAL,
922                         RTE_FLOW_ERROR_TYPE_ITEM,
923                         item,
924                         "ACL: Expecting END item");
925
926         return 0;
927 }
928
929 /***
930  * Both *tmask* and *fmask* are byte arrays of size *tsize* and *fsize*
931  * respectively.
932  * They are located within a larger buffer at offsets *toffset* and *foffset*
933  * respectivelly. Both *tmask* and *fmask* represent bitmasks for the larger
934  * buffer.
935  * Question: are the two masks equivalent?
936  *
937  * Notes:
938  * 1. Offset basically indicates that the first offset bytes in the buffer
939  *    are "don't care", so offset is equivalent to pre-pending an "all-zeros"
940  *    array of *offset* bytes to the *mask*.
941  * 2. Each *mask* might contain a number of zero bytes at the beginning or
942  *    at the end.
943  * 3. Bytes in the larger buffer after the end of the *mask* are also considered
944  *    "don't care", so they are equivalent to appending an "all-zeros" array of
945  *    bytes to the *mask*.
946  *
947  * Example:
948  * Buffer = [xx xx xx xx xx xx xx xx], buffer size = 8 bytes
949  * tmask = [00 22 00 33 00], toffset = 2, tsize = 5
950  *    => buffer mask = [00 00 00 22 00 33 00 00]
951  * fmask = [22 00 33], foffset = 3, fsize = 3 =>
952  *    => buffer mask = [00 00 00 22 00 33 00 00]
953  * Therefore, the tmask and fmask from this example are equivalent.
954  */
955 static int
956 hash_key_mask_is_same(uint8_t *tmask,
957         size_t toffset,
958         size_t tsize,
959         uint8_t *fmask,
960         size_t foffset,
961         size_t fsize,
962         size_t *toffset_plus,
963         size_t *foffset_plus)
964 {
965         size_t tpos; /* Position of first non-zero byte in the tmask buffer. */
966         size_t fpos; /* Position of first non-zero byte in the fmask buffer. */
967
968         /* Compute tpos and fpos. */
969         for (tpos = 0; tmask[tpos] == 0; tpos++)
970                 ;
971         for (fpos = 0; fmask[fpos] == 0; fpos++)
972                 ;
973
974         if (toffset + tpos != foffset + fpos)
975                 return 0; /* FALSE */
976
977         tsize -= tpos;
978         fsize -= fpos;
979
980         if (tsize < fsize) {
981                 size_t i;
982
983                 for (i = 0; i < tsize; i++)
984                         if (tmask[tpos + i] != fmask[fpos + i])
985                                 return 0; /* FALSE */
986
987                 for ( ; i < fsize; i++)
988                         if (fmask[fpos + i])
989                                 return 0; /* FALSE */
990         } else {
991                 size_t i;
992
993                 for (i = 0; i < fsize; i++)
994                         if (tmask[tpos + i] != fmask[fpos + i])
995                                 return 0; /* FALSE */
996
997                 for ( ; i < tsize; i++)
998                         if (tmask[tpos + i])
999                                 return 0; /* FALSE */
1000         }
1001
1002         if (toffset_plus)
1003                 *toffset_plus = tpos;
1004
1005         if (foffset_plus)
1006                 *foffset_plus = fpos;
1007
1008         return 1; /* TRUE */
1009 }
1010
1011 static int
1012 flow_rule_match_hash_get(struct pmd_internals *softnic __rte_unused,
1013         struct pipeline *pipeline __rte_unused,
1014         struct softnic_table *table,
1015         const struct rte_flow_attr *attr __rte_unused,
1016         const struct rte_flow_item *item,
1017         struct softnic_table_rule_match *rule_match,
1018         struct rte_flow_error *error)
1019 {
1020         struct softnic_table_rule_match_hash key, key_mask;
1021         struct softnic_table_hash_params *params = &table->params.match.hash;
1022         size_t offset = 0, length = 0, tpos, fpos;
1023         int status;
1024
1025         memset(&key, 0, sizeof(key));
1026         memset(&key_mask, 0, sizeof(key_mask));
1027
1028         /* VOID or disabled protos only, if any. */
1029         status = flow_item_skip_disabled_protos(&item, 0, &offset, error);
1030         if (status)
1031                 return status;
1032
1033         if (item->type == RTE_FLOW_ITEM_TYPE_END)
1034                 return rte_flow_error_set(error,
1035                         EINVAL,
1036                         RTE_FLOW_ERROR_TYPE_ITEM,
1037                         item,
1038                         "HASH: END detected too early");
1039
1040         /* VOID or any protocols (enabled or disabled). */
1041         for ( ; item->type != RTE_FLOW_ITEM_TYPE_END; item++) {
1042                 union flow_item spec, mask;
1043                 size_t size;
1044                 int disabled, status;
1045
1046                 if (item->type == RTE_FLOW_ITEM_TYPE_VOID)
1047                         continue;
1048
1049                 status = flow_item_proto_preprocess(item,
1050                         &spec,
1051                         &mask,
1052                         &size,
1053                         &disabled,
1054                         error);
1055                 if (status)
1056                         return status;
1057
1058                 if (length + size > sizeof(key)) {
1059                         if (disabled)
1060                                 break;
1061
1062                         return rte_flow_error_set(error,
1063                                 ENOTSUP,
1064                                 RTE_FLOW_ERROR_TYPE_ITEM,
1065                                 item,
1066                                 "HASH: Item too big");
1067                 }
1068
1069                 memcpy(&key.key[length], &spec, size);
1070                 memcpy(&key_mask.key[length], &mask, size);
1071                 length += size;
1072         }
1073
1074         if (item->type != RTE_FLOW_ITEM_TYPE_END) {
1075                 /* VOID or disabled protos only, if any. */
1076                 status = flow_item_skip_disabled_protos(&item, 0, NULL, error);
1077                 if (status)
1078                         return status;
1079
1080                 /* END only. */
1081                 if (item->type != RTE_FLOW_ITEM_TYPE_END)
1082                         return rte_flow_error_set(error,
1083                                 EINVAL,
1084                                 RTE_FLOW_ERROR_TYPE_ITEM,
1085                                 item,
1086                                 "HASH: Expecting END item");
1087         }
1088
1089         /* Compare flow key mask against table key mask. */
1090         offset += sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM;
1091
1092         if (!hash_key_mask_is_same(params->key_mask,
1093                 params->key_offset,
1094                 params->key_size,
1095                 key_mask.key,
1096                 offset,
1097                 length,
1098                 &tpos,
1099                 &fpos))
1100                 return rte_flow_error_set(error,
1101                         EINVAL,
1102                         RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1103                         NULL,
1104                         "HASH: Item list is not observing the match format");
1105
1106         /* Rule match. */
1107         memset(rule_match, 0, sizeof(*rule_match));
1108         rule_match->match_type = TABLE_HASH;
1109         memcpy(&rule_match->match.hash.key[tpos],
1110                 &key.key[fpos],
1111                 RTE_MIN(sizeof(rule_match->match.hash.key) - tpos,
1112                         length - fpos));
1113
1114         return 0;
1115 }
1116
1117 static int
1118 flow_rule_match_get(struct pmd_internals *softnic,
1119                 struct pipeline *pipeline,
1120                 struct softnic_table *table,
1121                 const struct rte_flow_attr *attr,
1122                 const struct rte_flow_item *item,
1123                 struct softnic_table_rule_match *rule_match,
1124                 struct rte_flow_error *error)
1125 {
1126         switch (table->params.match_type) {
1127         case TABLE_ACL:
1128                 return flow_rule_match_acl_get(softnic,
1129                         pipeline,
1130                         table,
1131                         attr,
1132                         item,
1133                         rule_match,
1134                         error);
1135
1136                 /* FALLTHROUGH */
1137
1138         case TABLE_HASH:
1139                 return flow_rule_match_hash_get(softnic,
1140                         pipeline,
1141                         table,
1142                         attr,
1143                         item,
1144                         rule_match,
1145                         error);
1146
1147                 /* FALLTHROUGH */
1148
1149         default:
1150                 return rte_flow_error_set(error,
1151                         ENOTSUP,
1152                         RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1153                         NULL,
1154                         "Unsupported pipeline table match type");
1155         }
1156 }
1157
1158 static int
1159 flow_rule_action_get(struct pmd_internals *softnic,
1160         struct pipeline *pipeline,
1161         struct softnic_table *table,
1162         const struct rte_flow_attr *attr,
1163         const struct rte_flow_action *action,
1164         struct softnic_table_rule_action *rule_action,
1165         struct rte_flow_error *error)
1166 {
1167         struct softnic_table_action_profile *profile;
1168         struct softnic_table_action_profile_params *params;
1169         struct softnic_mtr_meter_policy *policy;
1170         int n_jump_queue_rss_drop = 0;
1171         int n_count = 0;
1172         int n_mark = 0;
1173         int n_vxlan_decap = 0;
1174
1175         profile = softnic_table_action_profile_find(softnic,
1176                 table->params.action_profile_name);
1177         if (profile == NULL)
1178                 return rte_flow_error_set(error,
1179                         EINVAL,
1180                         RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1181                         action,
1182                         "JUMP: Table action profile");
1183
1184         params = &profile->params;
1185
1186         for ( ; action->type != RTE_FLOW_ACTION_TYPE_END; action++) {
1187                 if (action->type == RTE_FLOW_ACTION_TYPE_VOID)
1188                         continue;
1189
1190                 switch (action->type) {
1191                 case RTE_FLOW_ACTION_TYPE_JUMP:
1192                 {
1193                         const struct rte_flow_action_jump *conf = action->conf;
1194                         struct flow_attr_map *map;
1195
1196                         if (conf == NULL)
1197                                 return rte_flow_error_set(error,
1198                                         EINVAL,
1199                                         RTE_FLOW_ERROR_TYPE_ACTION,
1200                                         action,
1201                                         "JUMP: Null configuration");
1202
1203                         if (n_jump_queue_rss_drop)
1204                                 return rte_flow_error_set(error,
1205                                         EINVAL,
1206                                         RTE_FLOW_ERROR_TYPE_ACTION,
1207                                         action,
1208                                         "Only one termination action is"
1209                                         " allowed per flow");
1210
1211                         if ((params->action_mask &
1212                                 (1LLU << RTE_TABLE_ACTION_FWD)) == 0)
1213                                 return rte_flow_error_set(error,
1214                                         EINVAL,
1215                                         RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1216                                         NULL,
1217                                         "JUMP action not enabled for this table");
1218
1219                         n_jump_queue_rss_drop = 1;
1220
1221                         map = flow_attr_map_get(softnic,
1222                                 conf->group,
1223                                 attr->ingress);
1224                         if (map == NULL || map->valid == 0)
1225                                 return rte_flow_error_set(error,
1226                                         EINVAL,
1227                                         RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1228                                         NULL,
1229                                         "JUMP: Invalid group mapping");
1230
1231                         if (strcmp(pipeline->name, map->pipeline_name) != 0)
1232                                 return rte_flow_error_set(error,
1233                                         ENOTSUP,
1234                                         RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1235                                         NULL,
1236                                         "JUMP: Jump to table in different pipeline");
1237
1238                         /* RTE_TABLE_ACTION_FWD */
1239                         rule_action->fwd.action = RTE_PIPELINE_ACTION_TABLE;
1240                         rule_action->fwd.id = map->table_id;
1241                         rule_action->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
1242                         break;
1243                 } /* RTE_FLOW_ACTION_TYPE_JUMP */
1244
1245                 case RTE_FLOW_ACTION_TYPE_QUEUE:
1246                 {
1247                         char name[NAME_SIZE];
1248                         struct rte_eth_dev *dev;
1249                         const struct rte_flow_action_queue *conf = action->conf;
1250                         uint32_t port_id;
1251                         int status;
1252
1253                         if (conf == NULL)
1254                                 return rte_flow_error_set(error,
1255                                         EINVAL,
1256                                         RTE_FLOW_ERROR_TYPE_ACTION,
1257                                         action,
1258                                         "QUEUE: Null configuration");
1259
1260                         if (n_jump_queue_rss_drop)
1261                                 return rte_flow_error_set(error,
1262                                         EINVAL,
1263                                         RTE_FLOW_ERROR_TYPE_ACTION,
1264                                         action,
1265                                         "Only one termination action is allowed"
1266                                         " per flow");
1267
1268                         if ((params->action_mask &
1269                                 (1LLU << RTE_TABLE_ACTION_FWD)) == 0)
1270                                 return rte_flow_error_set(error,
1271                                         EINVAL,
1272                                         RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1273                                         NULL,
1274                                         "QUEUE action not enabled for this table");
1275
1276                         n_jump_queue_rss_drop = 1;
1277
1278                         dev = ETHDEV(softnic);
1279                         if (dev == NULL ||
1280                                 conf->index >= dev->data->nb_rx_queues)
1281                                 return rte_flow_error_set(error,
1282                                         EINVAL,
1283                                         RTE_FLOW_ERROR_TYPE_ACTION,
1284                                         action,
1285                                         "QUEUE: Invalid RX queue ID");
1286
1287                         snprintf(name, sizeof(name), "RXQ%u",
1288                                         (uint32_t)conf->index);
1289
1290                         status = softnic_pipeline_port_out_find(softnic,
1291                                 pipeline->name,
1292                                 name,
1293                                 &port_id);
1294                         if (status)
1295                                 return rte_flow_error_set(error,
1296                                         ENOTSUP,
1297                                         RTE_FLOW_ERROR_TYPE_ACTION,
1298                                         action,
1299                                         "QUEUE: RX queue not accessible from this pipeline");
1300
1301                         /* RTE_TABLE_ACTION_FWD */
1302                         rule_action->fwd.action = RTE_PIPELINE_ACTION_PORT;
1303                         rule_action->fwd.id = port_id;
1304                         rule_action->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
1305                         break;
1306                 } /*RTE_FLOW_ACTION_TYPE_QUEUE */
1307
1308                 case RTE_FLOW_ACTION_TYPE_RSS:
1309                 {
1310                         const struct rte_flow_action_rss *conf = action->conf;
1311                         uint32_t i;
1312
1313                         if (conf == NULL)
1314                                 return rte_flow_error_set(error,
1315                                         EINVAL,
1316                                         RTE_FLOW_ERROR_TYPE_ACTION,
1317                                         action,
1318                                         "RSS: Null configuration");
1319
1320                         if (!rte_is_power_of_2(conf->queue_num))
1321                                 return rte_flow_error_set(error,
1322                                         EINVAL,
1323                                         RTE_FLOW_ERROR_TYPE_ACTION_CONF,
1324                                         conf,
1325                                         "RSS: Number of queues must be a power of 2");
1326
1327                         if (conf->queue_num > RTE_DIM(rule_action->lb.out))
1328                                 return rte_flow_error_set(error,
1329                                         EINVAL,
1330                                         RTE_FLOW_ERROR_TYPE_ACTION_CONF,
1331                                         conf,
1332                                         "RSS: Number of queues too big");
1333
1334                         if (n_jump_queue_rss_drop)
1335                                 return rte_flow_error_set(error,
1336                                         EINVAL,
1337                                         RTE_FLOW_ERROR_TYPE_ACTION,
1338                                         action,
1339                                         "Only one termination action is allowed per flow");
1340
1341                         if (((params->action_mask &
1342                                 (1LLU << RTE_TABLE_ACTION_FWD)) == 0) ||
1343                                 ((params->action_mask &
1344                                 (1LLU << RTE_TABLE_ACTION_LB)) == 0))
1345                                 return rte_flow_error_set(error,
1346                                         ENOTSUP,
1347                                         RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1348                                         NULL,
1349                                         "RSS action not supported by this table");
1350
1351                         if (params->lb.out_offset !=
1352                                 pipeline->params.offset_port_id)
1353                                 return rte_flow_error_set(error,
1354                                         EINVAL,
1355                                         RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1356                                         NULL,
1357                                         "RSS action not supported by this pipeline");
1358
1359                         n_jump_queue_rss_drop = 1;
1360
1361                         /* RTE_TABLE_ACTION_LB */
1362                         for (i = 0; i < conf->queue_num; i++) {
1363                                 char name[NAME_SIZE];
1364                                 struct rte_eth_dev *dev;
1365                                 uint32_t port_id;
1366                                 int status;
1367
1368                                 dev = ETHDEV(softnic);
1369                                 if (dev == NULL ||
1370                                         conf->queue[i] >=
1371                                                 dev->data->nb_rx_queues)
1372                                         return rte_flow_error_set(error,
1373                                                 EINVAL,
1374                                                 RTE_FLOW_ERROR_TYPE_ACTION,
1375                                                 action,
1376                                                 "RSS: Invalid RX queue ID");
1377
1378                                 snprintf(name, sizeof(name), "RXQ%u",
1379                                         (uint32_t)conf->queue[i]);
1380
1381                                 status = softnic_pipeline_port_out_find(softnic,
1382                                         pipeline->name,
1383                                         name,
1384                                         &port_id);
1385                                 if (status)
1386                                         return rte_flow_error_set(error,
1387                                                 ENOTSUP,
1388                                                 RTE_FLOW_ERROR_TYPE_ACTION,
1389                                                 action,
1390                                                 "RSS: RX queue not accessible from this pipeline");
1391
1392                                 rule_action->lb.out[i] = port_id;
1393                         }
1394
1395                         for ( ; i < RTE_DIM(rule_action->lb.out); i++)
1396                                 rule_action->lb.out[i] =
1397                                 rule_action->lb.out[i % conf->queue_num];
1398
1399                         rule_action->action_mask |= 1 << RTE_TABLE_ACTION_LB;
1400
1401                         /* RTE_TABLE_ACTION_FWD */
1402                         rule_action->fwd.action = RTE_PIPELINE_ACTION_PORT_META;
1403                         rule_action->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
1404                         break;
1405                 } /* RTE_FLOW_ACTION_TYPE_RSS */
1406
1407                 case RTE_FLOW_ACTION_TYPE_DROP:
1408                 {
1409                         const void *conf = action->conf;
1410
1411                         if (conf != NULL)
1412                                 return rte_flow_error_set(error,
1413                                         EINVAL,
1414                                         RTE_FLOW_ERROR_TYPE_ACTION,
1415                                         action,
1416                                         "DROP: No configuration required");
1417
1418                         if (n_jump_queue_rss_drop)
1419                                 return rte_flow_error_set(error,
1420                                         EINVAL,
1421                                         RTE_FLOW_ERROR_TYPE_ACTION,
1422                                         action,
1423                                         "Only one termination action is allowed per flow");
1424                         if ((params->action_mask &
1425                                 (1LLU << RTE_TABLE_ACTION_FWD)) == 0)
1426                                 return rte_flow_error_set(error,
1427                                         ENOTSUP,
1428                                         RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1429                                         NULL,
1430                                         "DROP action not supported by this table");
1431
1432                         n_jump_queue_rss_drop = 1;
1433
1434                         /* RTE_TABLE_ACTION_FWD */
1435                         rule_action->fwd.action = RTE_PIPELINE_ACTION_DROP;
1436                         rule_action->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
1437                         break;
1438                 } /* RTE_FLOW_ACTION_TYPE_DROP */
1439
1440                 case RTE_FLOW_ACTION_TYPE_COUNT:
1441                 {
1442                         const struct rte_flow_action_count *conf = action->conf;
1443
1444                         if (conf == NULL)
1445                                 return rte_flow_error_set(error,
1446                                         EINVAL,
1447                                         RTE_FLOW_ERROR_TYPE_ACTION,
1448                                         action,
1449                                         "COUNT: Null configuration");
1450
1451                         if (conf->shared)
1452                                 return rte_flow_error_set(error,
1453                                         ENOTSUP,
1454                                         RTE_FLOW_ERROR_TYPE_ACTION_CONF,
1455                                         conf,
1456                                         "COUNT: Shared counters not supported");
1457
1458                         if (n_count)
1459                                 return rte_flow_error_set(error,
1460                                         ENOTSUP,
1461                                         RTE_FLOW_ERROR_TYPE_ACTION,
1462                                         action,
1463                                         "Only one COUNT action per flow");
1464
1465                         if ((params->action_mask &
1466                                 (1LLU << RTE_TABLE_ACTION_STATS)) == 0)
1467                                 return rte_flow_error_set(error,
1468                                         ENOTSUP,
1469                                         RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1470                                         NULL,
1471                                         "COUNT action not supported by this table");
1472
1473                         n_count = 1;
1474
1475                         /* RTE_TABLE_ACTION_STATS */
1476                         rule_action->stats.n_packets = 0;
1477                         rule_action->stats.n_bytes = 0;
1478                         rule_action->action_mask |= 1 << RTE_TABLE_ACTION_STATS;
1479                         break;
1480                 } /* RTE_FLOW_ACTION_TYPE_COUNT */
1481
1482                 case RTE_FLOW_ACTION_TYPE_MARK:
1483                 {
1484                         const struct rte_flow_action_mark *conf = action->conf;
1485
1486                         if (conf == NULL)
1487                                 return rte_flow_error_set(error,
1488                                         EINVAL,
1489                                         RTE_FLOW_ERROR_TYPE_ACTION,
1490                                         action,
1491                                         "MARK: Null configuration");
1492
1493                         if (n_mark)
1494                                 return rte_flow_error_set(error,
1495                                         ENOTSUP,
1496                                         RTE_FLOW_ERROR_TYPE_ACTION,
1497                                         action,
1498                                         "Only one MARK action per flow");
1499
1500                         if ((params->action_mask &
1501                                 (1LLU << RTE_TABLE_ACTION_TAG)) == 0)
1502                                 return rte_flow_error_set(error,
1503                                         ENOTSUP,
1504                                         RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1505                                         NULL,
1506                                         "MARK action not supported by this table");
1507
1508                         n_mark = 1;
1509
1510                         /* RTE_TABLE_ACTION_TAG */
1511                         rule_action->tag.tag = conf->id;
1512                         rule_action->action_mask |= 1 << RTE_TABLE_ACTION_TAG;
1513                         break;
1514                 } /* RTE_FLOW_ACTION_TYPE_MARK */
1515
1516                 case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP:
1517                 {
1518                         const struct rte_flow_action_mark *conf = action->conf;
1519
1520                         if (conf)
1521                                 return rte_flow_error_set(error,
1522                                         EINVAL,
1523                                         RTE_FLOW_ERROR_TYPE_ACTION,
1524                                         action,
1525                                         "VXLAN DECAP: Non-null configuration");
1526
1527                         if (n_vxlan_decap)
1528                                 return rte_flow_error_set(error,
1529                                         ENOTSUP,
1530                                         RTE_FLOW_ERROR_TYPE_ACTION,
1531                                         action,
1532                                         "Only one VXLAN DECAP action per flow");
1533
1534                         if ((params->action_mask &
1535                                 (1LLU << RTE_TABLE_ACTION_DECAP)) == 0)
1536                                 return rte_flow_error_set(error,
1537                                         ENOTSUP,
1538                                         RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1539                                         NULL,
1540                                         "VXLAN DECAP action not supported by this table");
1541
1542                         n_vxlan_decap = 1;
1543
1544                         /* RTE_TABLE_ACTION_DECAP */
1545                         rule_action->decap.n = 50; /* Ether/IPv4/UDP/VXLAN */
1546                         rule_action->action_mask |= 1 << RTE_TABLE_ACTION_DECAP;
1547                         break;
1548                 } /* RTE_FLOW_ACTION_TYPE_VXLAN_DECAP */
1549
1550                 case RTE_FLOW_ACTION_TYPE_METER:
1551                 {
1552                         const struct rte_flow_action_meter *conf = action->conf;
1553                         struct softnic_mtr_meter_profile *mp;
1554                         struct softnic_mtr *m;
1555                         uint32_t table_id = table - pipeline->table;
1556                         uint32_t meter_profile_id;
1557                         int status;
1558
1559                         if ((params->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) == 0)
1560                                 return rte_flow_error_set(error,
1561                                         EINVAL,
1562                                         RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1563                                         NULL,
1564                                         "METER: Table action not supported");
1565
1566                         if (params->mtr.n_tc != 1)
1567                                 return rte_flow_error_set(error,
1568                                         EINVAL,
1569                                         RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1570                                         NULL,
1571                                         "METER: Multiple TCs not supported");
1572
1573                         if (conf == NULL)
1574                                 return rte_flow_error_set(error,
1575                                         EINVAL,
1576                                         RTE_FLOW_ERROR_TYPE_ACTION,
1577                                         action,
1578                                         "METER: Null configuration");
1579
1580                         m = softnic_mtr_find(softnic, conf->mtr_id);
1581
1582                         if (m == NULL)
1583                                 return rte_flow_error_set(error,
1584                                         EINVAL,
1585                                         RTE_FLOW_ERROR_TYPE_ACTION_CONF,
1586                                         NULL,
1587                                         "METER: Invalid meter ID");
1588
1589                         if (m->flow)
1590                                 return rte_flow_error_set(error,
1591                                         EINVAL,
1592                                         RTE_FLOW_ERROR_TYPE_ACTION_CONF,
1593                                         NULL,
1594                                         "METER: Meter already attached to a flow");
1595
1596                         meter_profile_id = m->params.meter_profile_id;
1597                         mp = softnic_mtr_meter_profile_find(softnic, meter_profile_id);
1598
1599                         /* Add meter profile to pipeline table */
1600                         if (!softnic_pipeline_table_meter_profile_find(table,
1601                                         meter_profile_id)) {
1602                                 struct rte_table_action_meter_profile profile;
1603
1604                                 memset(&profile, 0, sizeof(profile));
1605                                 profile.alg = RTE_TABLE_ACTION_METER_TRTCM;
1606                                 profile.trtcm.cir = mp->params.trtcm_rfc2698.cir;
1607                                 profile.trtcm.pir = mp->params.trtcm_rfc2698.pir;
1608                                 profile.trtcm.cbs = mp->params.trtcm_rfc2698.cbs;
1609                                 profile.trtcm.pbs = mp->params.trtcm_rfc2698.pbs;
1610
1611                                 status = softnic_pipeline_table_mtr_profile_add(softnic,
1612                                                 pipeline->name,
1613                                                 table_id,
1614                                                 meter_profile_id,
1615                                                 &profile);
1616                                 if (status) {
1617                                         rte_flow_error_set(error,
1618                                                 EINVAL,
1619                                                 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1620                                                 NULL,
1621                                                 "METER: Table meter profile add failed");
1622                                         return -1;
1623                                 }
1624                         }
1625                         /* Meter policy must exist */
1626                         policy = softnic_mtr_meter_policy_find(softnic,
1627                                         m->params.meter_policy_id);
1628                         if (policy == NULL) {
1629                                 rte_flow_error_set(error,
1630                                                 EINVAL,
1631                                                 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1632                                                 NULL,
1633                                                 "METER: fail to find meter policy");
1634                                 return -1;
1635                         }
1636                         /* RTE_TABLE_ACTION_METER */
1637                         rule_action->mtr.mtr[0].meter_profile_id = meter_profile_id;
1638                         rule_action->mtr.mtr[0].policer[RTE_COLOR_GREEN] =
1639                                 policy->policer[RTE_COLOR_GREEN];
1640                         rule_action->mtr.mtr[0].policer[RTE_COLOR_YELLOW] =
1641                                 policy->policer[RTE_COLOR_YELLOW];
1642                         rule_action->mtr.mtr[0].policer[RTE_COLOR_RED] =
1643                                 policy->policer[RTE_COLOR_RED];
1644                         rule_action->mtr.tc_mask = 1;
1645                         rule_action->action_mask |= 1 << RTE_TABLE_ACTION_MTR;
1646                         break;
1647                 } /* RTE_FLOW_ACTION_TYPE_METER */
1648
1649                 case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP:
1650                 {
1651                         const struct rte_flow_action_vxlan_encap *conf =
1652                                 action->conf;
1653                         const struct rte_flow_item *item;
1654                         union flow_item spec, mask;
1655                         int disabled = 0, status;
1656                         size_t size;
1657
1658                         if (conf == NULL)
1659                                 return rte_flow_error_set(error,
1660                                         EINVAL,
1661                                         RTE_FLOW_ERROR_TYPE_ACTION,
1662                                         action,
1663                                         "VXLAN ENCAP: Null configuration");
1664
1665                         item = conf->definition;
1666                         if (item == NULL)
1667                                 return rte_flow_error_set(error,
1668                                         EINVAL,
1669                                         RTE_FLOW_ERROR_TYPE_ACTION,
1670                                         action,
1671                                         "VXLAN ENCAP: Null configuration definition");
1672
1673                         if (!(params->action_mask &
1674                                         (1LLU << RTE_TABLE_ACTION_ENCAP)))
1675                                 return rte_flow_error_set(error,
1676                                         EINVAL,
1677                                         RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1678                                         NULL,
1679                                         "VXLAN ENCAP: Encap action not enabled for this table");
1680
1681                         /* Check for Ether. */
1682                         flow_item_skip_void(&item);
1683                         status = flow_item_proto_preprocess(item, &spec, &mask,
1684                                 &size, &disabled, error);
1685                         if (status)
1686                                 return status;
1687
1688                         if (item->type != RTE_FLOW_ITEM_TYPE_ETH) {
1689                                 return rte_flow_error_set(error,
1690                                         EINVAL,
1691                                         RTE_FLOW_ERROR_TYPE_ITEM,
1692                                         item,
1693                                         "VXLAN ENCAP: first encap item should be ether");
1694                         }
1695                         rte_ether_addr_copy(&spec.eth.dst,
1696                                         &rule_action->encap.vxlan.ether.da);
1697                         rte_ether_addr_copy(&spec.eth.src,
1698                                         &rule_action->encap.vxlan.ether.sa);
1699
1700                         item++;
1701
1702                         /* Check for VLAN. */
1703                         flow_item_skip_void(&item);
1704                         status = flow_item_proto_preprocess(item, &spec, &mask,
1705                                         &size, &disabled, error);
1706                         if (status)
1707                                 return status;
1708
1709                         if (item->type == RTE_FLOW_ITEM_TYPE_VLAN) {
1710                                 if (!params->encap.vxlan.vlan)
1711                                         return rte_flow_error_set(error,
1712                                                 ENOTSUP,
1713                                                 RTE_FLOW_ERROR_TYPE_ITEM,
1714                                                 item,
1715                                                 "VXLAN ENCAP: vlan encap not supported by table");
1716
1717                                 uint16_t tci = rte_ntohs(spec.vlan.tci);
1718                                 rule_action->encap.vxlan.vlan.pcp =
1719                                         tci >> 13;
1720                                 rule_action->encap.vxlan.vlan.dei =
1721                                         (tci >> 12) & 0x1;
1722                                 rule_action->encap.vxlan.vlan.vid =
1723                                         tci & 0xfff;
1724
1725                                 item++;
1726
1727                                 flow_item_skip_void(&item);
1728                                 status = flow_item_proto_preprocess(item, &spec,
1729                                                 &mask, &size, &disabled, error);
1730                                 if (status)
1731                                         return status;
1732                         } else {
1733                                 if (params->encap.vxlan.vlan)
1734                                         return rte_flow_error_set(error,
1735                                                 ENOTSUP,
1736                                                 RTE_FLOW_ERROR_TYPE_ITEM,
1737                                                 item,
1738                                                 "VXLAN ENCAP: expecting vlan encap item");
1739                         }
1740
1741                         /* Check for IPV4/IPV6. */
1742                         switch (item->type) {
1743                         case RTE_FLOW_ITEM_TYPE_IPV4:
1744                         {
1745                                 rule_action->encap.vxlan.ipv4.sa =
1746                                         rte_ntohl(spec.ipv4.hdr.src_addr);
1747                                 rule_action->encap.vxlan.ipv4.da =
1748                                         rte_ntohl(spec.ipv4.hdr.dst_addr);
1749                                 rule_action->encap.vxlan.ipv4.dscp =
1750                                         spec.ipv4.hdr.type_of_service >> 2;
1751                                 rule_action->encap.vxlan.ipv4.ttl =
1752                                         spec.ipv4.hdr.time_to_live;
1753                                 break;
1754                         }
1755                         case RTE_FLOW_ITEM_TYPE_IPV6:
1756                         {
1757                                 uint32_t vtc_flow;
1758
1759                                 memcpy(&rule_action->encap.vxlan.ipv6.sa,
1760                                                 &spec.ipv6.hdr.src_addr,
1761                                                 sizeof(spec.ipv6.hdr.src_addr));
1762                                 memcpy(&rule_action->encap.vxlan.ipv6.da,
1763                                                 &spec.ipv6.hdr.dst_addr,
1764                                                 sizeof(spec.ipv6.hdr.dst_addr));
1765                                 vtc_flow = rte_ntohl(spec.ipv6.hdr.vtc_flow);
1766                                 rule_action->encap.vxlan.ipv6.flow_label =
1767                                                 vtc_flow & 0xfffff;
1768                                 rule_action->encap.vxlan.ipv6.dscp =
1769                                                 (vtc_flow >> 22) & 0x3f;
1770                                 rule_action->encap.vxlan.ipv6.hop_limit =
1771                                         spec.ipv6.hdr.hop_limits;
1772                                 break;
1773                         }
1774                         default:
1775                                 return rte_flow_error_set(error,
1776                                         EINVAL,
1777                                         RTE_FLOW_ERROR_TYPE_ITEM,
1778                                         item,
1779                                         "VXLAN ENCAP: encap item after ether should be ipv4/ipv6");
1780                         }
1781
1782                         item++;
1783
1784                         /* Check for UDP. */
1785                         flow_item_skip_void(&item);
1786                         status = flow_item_proto_preprocess(item, &spec, &mask,
1787                                         &size, &disabled, error);
1788                         if (status)
1789                                 return status;
1790
1791                         if (item->type != RTE_FLOW_ITEM_TYPE_UDP) {
1792                                 return rte_flow_error_set(error,
1793                                         EINVAL,
1794                                         RTE_FLOW_ERROR_TYPE_ITEM,
1795                                         item,
1796                                         "VXLAN ENCAP: encap item after ipv4/ipv6 should be udp");
1797                         }
1798                         rule_action->encap.vxlan.udp.sp =
1799                                 rte_ntohs(spec.udp.hdr.src_port);
1800                         rule_action->encap.vxlan.udp.dp =
1801                                 rte_ntohs(spec.udp.hdr.dst_port);
1802
1803                         item++;
1804
1805                         /* Check for VXLAN. */
1806                         flow_item_skip_void(&item);
1807                         status = flow_item_proto_preprocess(item, &spec, &mask,
1808                                         &size, &disabled, error);
1809                         if (status)
1810                                 return status;
1811
1812                         if (item->type != RTE_FLOW_ITEM_TYPE_VXLAN) {
1813                                 return rte_flow_error_set(error,
1814                                         EINVAL,
1815                                         RTE_FLOW_ERROR_TYPE_ITEM,
1816                                         item,
1817                                         "VXLAN ENCAP: encap item after udp should be vxlan");
1818                         }
1819                         rule_action->encap.vxlan.vxlan.vni =
1820                                 (spec.vxlan.vni[0] << 16U |
1821                                         spec.vxlan.vni[1] << 8U
1822                                         | spec.vxlan.vni[2]);
1823
1824                         item++;
1825
1826                         /* Check for END. */
1827                         flow_item_skip_void(&item);
1828
1829                         if (item->type != RTE_FLOW_ITEM_TYPE_END)
1830                                 return rte_flow_error_set(error,
1831                                         EINVAL,
1832                                         RTE_FLOW_ERROR_TYPE_ITEM,
1833                                         item,
1834                                         "VXLAN ENCAP: expecting END item");
1835
1836                         rule_action->encap.type = RTE_TABLE_ACTION_ENCAP_VXLAN;
1837                         rule_action->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
1838                         break;
1839                 } /* RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP */
1840
1841                 default:
1842                         return -ENOTSUP;
1843                 }
1844         }
1845
1846         if (n_jump_queue_rss_drop == 0)
1847                 return rte_flow_error_set(error,
1848                         EINVAL,
1849                         RTE_FLOW_ERROR_TYPE_ACTION,
1850                         action,
1851                         "Flow does not have any terminating action");
1852
1853         return 0;
1854 }
1855
1856 static int
1857 pmd_flow_validate(struct rte_eth_dev *dev,
1858                 const struct rte_flow_attr *attr,
1859                 const struct rte_flow_item item[],
1860                 const struct rte_flow_action action[],
1861                 struct rte_flow_error *error)
1862 {
1863         struct softnic_table_rule_match rule_match;
1864         struct softnic_table_rule_action rule_action;
1865
1866         struct pmd_internals *softnic = dev->data->dev_private;
1867         struct pipeline *pipeline;
1868         struct softnic_table *table;
1869         const char *pipeline_name = NULL;
1870         uint32_t table_id = 0;
1871         int status;
1872
1873         /* Check input parameters. */
1874         if (attr == NULL)
1875                 return rte_flow_error_set(error,
1876                                 EINVAL,
1877                                 RTE_FLOW_ERROR_TYPE_ATTR,
1878                                 NULL, "Null attr");
1879
1880         if (item == NULL)
1881                 return rte_flow_error_set(error,
1882                                 EINVAL,
1883                                 RTE_FLOW_ERROR_TYPE_ITEM,
1884                                 NULL,
1885                                 "Null item");
1886
1887         if (action == NULL)
1888                 return rte_flow_error_set(error,
1889                                 EINVAL,
1890                                 RTE_FLOW_ERROR_TYPE_ACTION,
1891                                 NULL,
1892                                 "Null action");
1893
1894         /* Identify the pipeline table to add this flow to. */
1895         status = flow_pipeline_table_get(softnic, attr, &pipeline_name,
1896                                         &table_id, error);
1897         if (status)
1898                 return status;
1899
1900         pipeline = softnic_pipeline_find(softnic, pipeline_name);
1901         if (pipeline == NULL)
1902                 return rte_flow_error_set(error,
1903                                 EINVAL,
1904                                 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1905                                 NULL,
1906                                 "Invalid pipeline name");
1907
1908         if (table_id >= pipeline->n_tables)
1909                 return rte_flow_error_set(error,
1910                                 EINVAL,
1911                                 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1912                                 NULL,
1913                                 "Invalid pipeline table ID");
1914
1915         table = &pipeline->table[table_id];
1916
1917         /* Rule match. */
1918         memset(&rule_match, 0, sizeof(rule_match));
1919         status = flow_rule_match_get(softnic,
1920                         pipeline,
1921                         table,
1922                         attr,
1923                         item,
1924                         &rule_match,
1925                         error);
1926         if (status)
1927                 return status;
1928
1929         /* Rule action. */
1930         memset(&rule_action, 0, sizeof(rule_action));
1931         status = flow_rule_action_get(softnic,
1932                 pipeline,
1933                 table,
1934                 attr,
1935                 action,
1936                 &rule_action,
1937                 error);
1938         if (status)
1939                 return status;
1940
1941         return 0;
1942 }
1943
1944 static struct softnic_mtr *
1945 flow_action_meter_get(struct pmd_internals *softnic,
1946         const struct rte_flow_action *action)
1947 {
1948         for ( ; action->type != RTE_FLOW_ACTION_TYPE_END; action++)
1949                 if (action->type == RTE_FLOW_ACTION_TYPE_METER) {
1950                         const struct rte_flow_action_meter *conf = action->conf;
1951
1952                         if (conf == NULL)
1953                                 return NULL;
1954
1955                         return softnic_mtr_find(softnic, conf->mtr_id);
1956                 }
1957
1958         return NULL;
1959 }
1960
1961 static void
1962 flow_meter_owner_reset(struct pmd_internals *softnic,
1963         struct rte_flow *flow)
1964 {
1965         struct softnic_mtr_list *ml = &softnic->mtr.mtrs;
1966         struct softnic_mtr *m;
1967
1968         TAILQ_FOREACH(m, ml, node)
1969                 if (m->flow == flow) {
1970                         m->flow = NULL;
1971                         break;
1972                 }
1973 }
1974
1975 static void
1976 flow_meter_owner_set(struct pmd_internals *softnic,
1977         struct rte_flow *flow,
1978         struct softnic_mtr *mtr)
1979 {
1980         /* Reset current flow meter  */
1981         flow_meter_owner_reset(softnic, flow);
1982
1983         /* Set new flow meter */
1984         mtr->flow = flow;
1985 }
1986
1987 static int
1988 is_meter_action_enable(struct pmd_internals *softnic,
1989         struct softnic_table *table)
1990 {
1991         struct softnic_table_action_profile *profile =
1992                 softnic_table_action_profile_find(softnic,
1993                         table->params.action_profile_name);
1994         struct softnic_table_action_profile_params *params = &profile->params;
1995
1996         return (params->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) ? 1 : 0;
1997 }
1998
1999 static struct rte_flow *
2000 pmd_flow_create(struct rte_eth_dev *dev,
2001         const struct rte_flow_attr *attr,
2002         const struct rte_flow_item item[],
2003         const struct rte_flow_action action[],
2004         struct rte_flow_error *error)
2005 {
2006         struct softnic_table_rule_match rule_match;
2007         struct softnic_table_rule_action rule_action;
2008         void *rule_data;
2009
2010         struct pmd_internals *softnic = dev->data->dev_private;
2011         struct pipeline *pipeline;
2012         struct softnic_table *table;
2013         struct rte_flow *flow;
2014         struct softnic_mtr *mtr;
2015         const char *pipeline_name = NULL;
2016         uint32_t table_id = 0;
2017         int new_flow, status;
2018
2019         /* Check input parameters. */
2020         if (attr == NULL) {
2021                 rte_flow_error_set(error,
2022                         EINVAL,
2023                         RTE_FLOW_ERROR_TYPE_ATTR,
2024                         NULL,
2025                         "Null attr");
2026                 return NULL;
2027         }
2028
2029         if (item == NULL) {
2030                 rte_flow_error_set(error,
2031                         EINVAL,
2032                         RTE_FLOW_ERROR_TYPE_ITEM,
2033                         NULL,
2034                         "Null item");
2035                 return NULL;
2036         }
2037
2038         if (action == NULL) {
2039                 rte_flow_error_set(error,
2040                         EINVAL,
2041                         RTE_FLOW_ERROR_TYPE_ACTION,
2042                         NULL,
2043                         "Null action");
2044                 return NULL;
2045         }
2046
2047         /* Identify the pipeline table to add this flow to. */
2048         status = flow_pipeline_table_get(softnic, attr, &pipeline_name,
2049                                         &table_id, error);
2050         if (status)
2051                 return NULL;
2052
2053         pipeline = softnic_pipeline_find(softnic, pipeline_name);
2054         if (pipeline == NULL) {
2055                 rte_flow_error_set(error,
2056                         EINVAL,
2057                         RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2058                         NULL,
2059                         "Invalid pipeline name");
2060                 return NULL;
2061         }
2062
2063         if (table_id >= pipeline->n_tables) {
2064                 rte_flow_error_set(error,
2065                         EINVAL,
2066                         RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2067                         NULL,
2068                         "Invalid pipeline table ID");
2069                 return NULL;
2070         }
2071
2072         table = &pipeline->table[table_id];
2073
2074         /* Rule match. */
2075         memset(&rule_match, 0, sizeof(rule_match));
2076         status = flow_rule_match_get(softnic,
2077                 pipeline,
2078                 table,
2079                 attr,
2080                 item,
2081                 &rule_match,
2082                 error);
2083         if (status)
2084                 return NULL;
2085
2086         /* Rule action. */
2087         memset(&rule_action, 0, sizeof(rule_action));
2088         status = flow_rule_action_get(softnic,
2089                 pipeline,
2090                 table,
2091                 attr,
2092                 action,
2093                 &rule_action,
2094                 error);
2095         if (status)
2096                 return NULL;
2097
2098         /* Flow find/allocate. */
2099         new_flow = 0;
2100         flow = softnic_flow_find(table, &rule_match);
2101         if (flow == NULL) {
2102                 new_flow = 1;
2103                 flow = calloc(1, sizeof(struct rte_flow));
2104                 if (flow == NULL) {
2105                         rte_flow_error_set(error,
2106                                 ENOMEM,
2107                                 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2108                                 NULL,
2109                                 "Not enough memory for new flow");
2110                         return NULL;
2111                 }
2112         }
2113
2114         /* Rule add. */
2115         status = softnic_pipeline_table_rule_add(softnic,
2116                 pipeline_name,
2117                 table_id,
2118                 &rule_match,
2119                 &rule_action,
2120                 &rule_data);
2121         if (status) {
2122                 if (new_flow)
2123                         free(flow);
2124
2125                 rte_flow_error_set(error,
2126                         EINVAL,
2127                         RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2128                         NULL,
2129                         "Pipeline table rule add failed");
2130                 return NULL;
2131         }
2132
2133         /* Flow fill in. */
2134         memcpy(&flow->match, &rule_match, sizeof(rule_match));
2135         memcpy(&flow->action, &rule_action, sizeof(rule_action));
2136         flow->data = rule_data;
2137         flow->pipeline = pipeline;
2138         flow->table_id = table_id;
2139
2140         mtr = flow_action_meter_get(softnic, action);
2141         if (mtr)
2142                 flow_meter_owner_set(softnic, flow, mtr);
2143
2144         /* Flow add to list. */
2145         if (new_flow)
2146                 TAILQ_INSERT_TAIL(&table->flows, flow, node);
2147
2148         return flow;
2149 }
2150
2151 static int
2152 pmd_flow_destroy(struct rte_eth_dev *dev,
2153         struct rte_flow *flow,
2154         struct rte_flow_error *error)
2155 {
2156         struct pmd_internals *softnic = dev->data->dev_private;
2157         struct softnic_table *table;
2158         int status;
2159
2160         /* Check input parameters. */
2161         if (flow == NULL)
2162                 return rte_flow_error_set(error,
2163                         EINVAL,
2164                         RTE_FLOW_ERROR_TYPE_HANDLE,
2165                         NULL,
2166                         "Null flow");
2167
2168         table = &flow->pipeline->table[flow->table_id];
2169
2170         /* Rule delete. */
2171         status = softnic_pipeline_table_rule_delete(softnic,
2172                 flow->pipeline->name,
2173                 flow->table_id,
2174                 &flow->match);
2175         if (status)
2176                 return rte_flow_error_set(error,
2177                         EINVAL,
2178                         RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2179                         NULL,
2180                         "Pipeline table rule delete failed");
2181
2182         /* Update dependencies */
2183         if (is_meter_action_enable(softnic, table))
2184                 flow_meter_owner_reset(softnic, flow);
2185
2186         /* Flow delete. */
2187         TAILQ_REMOVE(&table->flows, flow, node);
2188         free(flow);
2189
2190         return 0;
2191 }
2192
2193 static int
2194 pmd_flow_flush(struct rte_eth_dev *dev,
2195         struct rte_flow_error *error)
2196 {
2197         struct pmd_internals *softnic = dev->data->dev_private;
2198         struct pipeline *pipeline;
2199         int fail_to_del_rule = 0;
2200         uint32_t i;
2201
2202         TAILQ_FOREACH(pipeline, &softnic->pipeline_list, node) {
2203                 /* Remove all the flows added to the tables. */
2204                 for (i = 0; i < pipeline->n_tables; i++) {
2205                         struct softnic_table *table = &pipeline->table[i];
2206                         struct rte_flow *flow;
2207                         void *temp;
2208                         int status;
2209
2210                         RTE_TAILQ_FOREACH_SAFE(flow, &table->flows, node,
2211                                 temp) {
2212                                 /* Rule delete. */
2213                                 status = softnic_pipeline_table_rule_delete
2214                                                 (softnic,
2215                                                 pipeline->name,
2216                                                 i,
2217                                                 &flow->match);
2218                                 if (status)
2219                                         fail_to_del_rule = 1;
2220                                 /* Update dependencies */
2221                                 if (is_meter_action_enable(softnic, table))
2222                                         flow_meter_owner_reset(softnic, flow);
2223
2224                                 /* Flow delete. */
2225                                 TAILQ_REMOVE(&table->flows, flow, node);
2226                                 free(flow);
2227                         }
2228                 }
2229         }
2230
2231         if (fail_to_del_rule)
2232                 return rte_flow_error_set(error,
2233                         EINVAL,
2234                         RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2235                         NULL,
2236                         "Some of the rules could not be deleted");
2237
2238         return 0;
2239 }
2240
2241 static int
2242 pmd_flow_query(struct rte_eth_dev *dev __rte_unused,
2243         struct rte_flow *flow,
2244         const struct rte_flow_action *action __rte_unused,
2245         void *data,
2246         struct rte_flow_error *error)
2247 {
2248         struct rte_table_action_stats_counters stats;
2249         struct softnic_table *table;
2250         struct rte_flow_query_count *flow_stats = data;
2251         int status;
2252
2253         /* Check input parameters. */
2254         if (flow == NULL)
2255                 return rte_flow_error_set(error,
2256                         EINVAL,
2257                         RTE_FLOW_ERROR_TYPE_HANDLE,
2258                         NULL,
2259                         "Null flow");
2260
2261         if (data == NULL)
2262                 return rte_flow_error_set(error,
2263                         EINVAL,
2264                         RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2265                         NULL,
2266                         "Null data");
2267
2268         table = &flow->pipeline->table[flow->table_id];
2269
2270         /* Rule stats read. */
2271         status = rte_table_action_stats_read(table->a,
2272                 flow->data,
2273                 &stats,
2274                 flow_stats->reset);
2275         if (status)
2276                 return rte_flow_error_set(error,
2277                         EINVAL,
2278                         RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2279                         NULL,
2280                         "Pipeline table rule stats read failed");
2281
2282         /* Fill in flow stats. */
2283         flow_stats->hits_set =
2284                 (table->ap->params.stats.n_packets_enabled) ? 1 : 0;
2285         flow_stats->bytes_set =
2286                 (table->ap->params.stats.n_bytes_enabled) ? 1 : 0;
2287         flow_stats->hits = stats.n_packets;
2288         flow_stats->bytes = stats.n_bytes;
2289
2290         return 0;
2291 }
2292
2293 const struct rte_flow_ops pmd_flow_ops = {
2294         .validate = pmd_flow_validate,
2295         .create = pmd_flow_create,
2296         .destroy = pmd_flow_destroy,
2297         .flush = pmd_flow_flush,
2298         .query = pmd_flow_query,
2299         .isolate = NULL,
2300 };