net/softnic: support flow create
[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
15 #include "rte_eth_softnic_internals.h"
16 #include "rte_eth_softnic.h"
17
18 #define rte_htons rte_cpu_to_be_16
19 #define rte_htonl rte_cpu_to_be_32
20
21 #define rte_ntohs rte_be_to_cpu_16
22 #define rte_ntohl rte_be_to_cpu_32
23
24 static struct rte_flow *
25 softnic_flow_find(struct softnic_table *table,
26         struct softnic_table_rule_match *rule_match)
27 {
28         struct rte_flow *flow;
29
30         TAILQ_FOREACH(flow, &table->flows, node)
31                 if (memcmp(&flow->match, rule_match, sizeof(*rule_match)) == 0)
32                         return flow;
33
34         return NULL;
35 }
36
37 int
38 flow_attr_map_set(struct pmd_internals *softnic,
39                 uint32_t group_id,
40                 int ingress,
41                 const char *pipeline_name,
42                 uint32_t table_id)
43 {
44         struct pipeline *pipeline;
45         struct flow_attr_map *map;
46
47         if (group_id >= SOFTNIC_FLOW_MAX_GROUPS ||
48                         pipeline_name == NULL)
49                 return -1;
50
51         pipeline = softnic_pipeline_find(softnic, pipeline_name);
52         if (pipeline == NULL ||
53                         table_id >= pipeline->n_tables)
54                 return -1;
55
56         map = (ingress) ? &softnic->flow.ingress_map[group_id] :
57                 &softnic->flow.egress_map[group_id];
58         strcpy(map->pipeline_name, pipeline_name);
59         map->table_id = table_id;
60         map->valid = 1;
61
62         return 0;
63 }
64
65 struct flow_attr_map *
66 flow_attr_map_get(struct pmd_internals *softnic,
67                 uint32_t group_id,
68                 int ingress)
69 {
70         if (group_id >= SOFTNIC_FLOW_MAX_GROUPS)
71                 return NULL;
72
73         return (ingress) ? &softnic->flow.ingress_map[group_id] :
74                 &softnic->flow.egress_map[group_id];
75 }
76
77 static int
78 flow_pipeline_table_get(struct pmd_internals *softnic,
79                 const struct rte_flow_attr *attr,
80                 const char **pipeline_name,
81                 uint32_t *table_id,
82                 struct rte_flow_error *error)
83 {
84         struct flow_attr_map *map;
85
86         if (attr == NULL)
87                 return rte_flow_error_set(error,
88                                 EINVAL,
89                                 RTE_FLOW_ERROR_TYPE_ATTR,
90                                 NULL,
91                                 "Null attr");
92
93         if (!attr->ingress && !attr->egress)
94                 return rte_flow_error_set(error,
95                                 EINVAL,
96                                 RTE_FLOW_ERROR_TYPE_ATTR_INGRESS,
97                                 attr,
98                                 "Ingress/egress not specified");
99
100         if (attr->ingress && attr->egress)
101                 return rte_flow_error_set(error,
102                                 EINVAL,
103                                 RTE_FLOW_ERROR_TYPE_ATTR_INGRESS,
104                                 attr,
105                                 "Setting both ingress and egress is not allowed");
106
107         map = flow_attr_map_get(softnic,
108                         attr->group,
109                         attr->ingress);
110         if (map == NULL ||
111                         map->valid == 0)
112                 return rte_flow_error_set(error,
113                                 EINVAL,
114                                 RTE_FLOW_ERROR_TYPE_ATTR_GROUP,
115                                 attr,
116                                 "Invalid group ID");
117
118         if (pipeline_name)
119                 *pipeline_name = map->pipeline_name;
120
121         if (table_id)
122                 *table_id = map->table_id;
123
124         return 0;
125 }
126
127 union flow_item {
128         uint8_t raw[TABLE_RULE_MATCH_SIZE_MAX];
129         struct rte_flow_item_eth eth;
130         struct rte_flow_item_vlan vlan;
131         struct rte_flow_item_ipv4 ipv4;
132         struct rte_flow_item_ipv6 ipv6;
133         struct rte_flow_item_icmp icmp;
134         struct rte_flow_item_udp udp;
135         struct rte_flow_item_tcp tcp;
136         struct rte_flow_item_sctp sctp;
137         struct rte_flow_item_vxlan vxlan;
138         struct rte_flow_item_e_tag e_tag;
139         struct rte_flow_item_nvgre nvgre;
140         struct rte_flow_item_mpls mpls;
141         struct rte_flow_item_gre gre;
142         struct rte_flow_item_gtp gtp;
143         struct rte_flow_item_esp esp;
144         struct rte_flow_item_geneve geneve;
145         struct rte_flow_item_vxlan_gpe vxlan_gpe;
146         struct rte_flow_item_arp_eth_ipv4 arp_eth_ipv4;
147         struct rte_flow_item_ipv6_ext ipv6_ext;
148         struct rte_flow_item_icmp6 icmp6;
149         struct rte_flow_item_icmp6_nd_ns icmp6_nd_ns;
150         struct rte_flow_item_icmp6_nd_na icmp6_nd_na;
151         struct rte_flow_item_icmp6_nd_opt icmp6_nd_opt;
152         struct rte_flow_item_icmp6_nd_opt_sla_eth icmp6_nd_opt_sla_eth;
153         struct rte_flow_item_icmp6_nd_opt_tla_eth icmp6_nd_opt_tla_eth;
154 };
155
156 static const union flow_item flow_item_raw_mask;
157
158 static int
159 flow_item_is_proto(enum rte_flow_item_type type,
160         const void **mask,
161         size_t *size)
162 {
163         switch (type) {
164         case RTE_FLOW_ITEM_TYPE_RAW:
165                 *mask = &flow_item_raw_mask;
166                 *size = sizeof(flow_item_raw_mask);
167                 return 1; /* TRUE */
168
169         case RTE_FLOW_ITEM_TYPE_ETH:
170                 *mask = &rte_flow_item_eth_mask;
171                 *size = sizeof(struct rte_flow_item_eth);
172                 return 1; /* TRUE */
173
174         case RTE_FLOW_ITEM_TYPE_VLAN:
175                 *mask = &rte_flow_item_vlan_mask;
176                 *size = sizeof(struct rte_flow_item_vlan);
177                 return 1;
178
179         case RTE_FLOW_ITEM_TYPE_IPV4:
180                 *mask = &rte_flow_item_ipv4_mask;
181                 *size = sizeof(struct rte_flow_item_ipv4);
182                 return 1;
183
184         case RTE_FLOW_ITEM_TYPE_IPV6:
185                 *mask = &rte_flow_item_ipv6_mask;
186                 *size = sizeof(struct rte_flow_item_ipv6);
187                 return 1;
188
189         case RTE_FLOW_ITEM_TYPE_ICMP:
190                 *mask = &rte_flow_item_icmp_mask;
191                 *size = sizeof(struct rte_flow_item_icmp);
192                 return 1;
193
194         case RTE_FLOW_ITEM_TYPE_UDP:
195                 *mask = &rte_flow_item_udp_mask;
196                 *size = sizeof(struct rte_flow_item_udp);
197                 return 1;
198
199         case RTE_FLOW_ITEM_TYPE_TCP:
200                 *mask = &rte_flow_item_tcp_mask;
201                 *size = sizeof(struct rte_flow_item_tcp);
202                 return 1;
203
204         case RTE_FLOW_ITEM_TYPE_SCTP:
205                 *mask = &rte_flow_item_sctp_mask;
206                 *size = sizeof(struct rte_flow_item_sctp);
207                 return 1;
208
209         case RTE_FLOW_ITEM_TYPE_VXLAN:
210                 *mask = &rte_flow_item_vxlan_mask;
211                 *size = sizeof(struct rte_flow_item_vxlan);
212                 return 1;
213
214         case RTE_FLOW_ITEM_TYPE_E_TAG:
215                 *mask = &rte_flow_item_e_tag_mask;
216                 *size = sizeof(struct rte_flow_item_e_tag);
217                 return 1;
218
219         case RTE_FLOW_ITEM_TYPE_NVGRE:
220                 *mask = &rte_flow_item_nvgre_mask;
221                 *size = sizeof(struct rte_flow_item_nvgre);
222                 return 1;
223
224         case RTE_FLOW_ITEM_TYPE_MPLS:
225                 *mask = &rte_flow_item_mpls_mask;
226                 *size = sizeof(struct rte_flow_item_mpls);
227                 return 1;
228
229         case RTE_FLOW_ITEM_TYPE_GRE:
230                 *mask = &rte_flow_item_gre_mask;
231                 *size = sizeof(struct rte_flow_item_gre);
232                 return 1;
233
234         case RTE_FLOW_ITEM_TYPE_GTP:
235         case RTE_FLOW_ITEM_TYPE_GTPC:
236         case RTE_FLOW_ITEM_TYPE_GTPU:
237                 *mask = &rte_flow_item_gtp_mask;
238                 *size = sizeof(struct rte_flow_item_gtp);
239                 return 1;
240
241         case RTE_FLOW_ITEM_TYPE_ESP:
242                 *mask = &rte_flow_item_esp_mask;
243                 *size = sizeof(struct rte_flow_item_esp);
244                 return 1;
245
246         case RTE_FLOW_ITEM_TYPE_GENEVE:
247                 *mask = &rte_flow_item_geneve_mask;
248                 *size = sizeof(struct rte_flow_item_geneve);
249                 return 1;
250
251         case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
252                 *mask = &rte_flow_item_vxlan_gpe_mask;
253                 *size = sizeof(struct rte_flow_item_vxlan_gpe);
254                 return 1;
255
256         case RTE_FLOW_ITEM_TYPE_ARP_ETH_IPV4:
257                 *mask = &rte_flow_item_arp_eth_ipv4_mask;
258                 *size = sizeof(struct rte_flow_item_arp_eth_ipv4);
259                 return 1;
260
261         case RTE_FLOW_ITEM_TYPE_IPV6_EXT:
262                 *mask = &rte_flow_item_ipv6_ext_mask;
263                 *size = sizeof(struct rte_flow_item_ipv6_ext);
264                 return 1;
265
266         case RTE_FLOW_ITEM_TYPE_ICMP6:
267                 *mask = &rte_flow_item_icmp6_mask;
268                 *size = sizeof(struct rte_flow_item_icmp6);
269                 return 1;
270
271         case RTE_FLOW_ITEM_TYPE_ICMP6_ND_NS:
272                 *mask = &rte_flow_item_icmp6_nd_ns_mask;
273                 *size = sizeof(struct rte_flow_item_icmp6_nd_ns);
274                 return 1;
275
276         case RTE_FLOW_ITEM_TYPE_ICMP6_ND_NA:
277                 *mask = &rte_flow_item_icmp6_nd_na_mask;
278                 *size = sizeof(struct rte_flow_item_icmp6_nd_na);
279                 return 1;
280
281         case RTE_FLOW_ITEM_TYPE_ICMP6_ND_OPT:
282                 *mask = &rte_flow_item_icmp6_nd_opt_mask;
283                 *size = sizeof(struct rte_flow_item_icmp6_nd_opt);
284                 return 1;
285
286         case RTE_FLOW_ITEM_TYPE_ICMP6_ND_OPT_SLA_ETH:
287                 *mask = &rte_flow_item_icmp6_nd_opt_sla_eth_mask;
288                 *size = sizeof(struct rte_flow_item_icmp6_nd_opt_sla_eth);
289                 return 1;
290
291         case RTE_FLOW_ITEM_TYPE_ICMP6_ND_OPT_TLA_ETH:
292                 *mask = &rte_flow_item_icmp6_nd_opt_tla_eth_mask;
293                 *size = sizeof(struct rte_flow_item_icmp6_nd_opt_tla_eth);
294                 return 1;
295
296         default: return 0; /* FALSE */
297         }
298 }
299
300 static int
301 flow_item_proto_preprocess(const struct rte_flow_item *item,
302         union flow_item *item_spec,
303         union flow_item *item_mask,
304         size_t *item_size,
305         int *item_disabled,
306         struct rte_flow_error *error)
307 {
308         const void *mask_default;
309         uint8_t *spec = (uint8_t *)item_spec;
310         uint8_t *mask = (uint8_t *)item_mask;
311         size_t size, i;
312
313         if (!flow_item_is_proto(item->type, &mask_default, &size))
314                 return rte_flow_error_set(error,
315                         ENOTSUP,
316                         RTE_FLOW_ERROR_TYPE_ITEM,
317                         item,
318                         "Item type not supported");
319
320         /* spec */
321         if (!item->spec) {
322                 /* If spec is NULL, then last and mask also have to be NULL. */
323                 if (item->last || item->mask)
324                         return rte_flow_error_set(error,
325                                 EINVAL,
326                                 RTE_FLOW_ERROR_TYPE_ITEM,
327                                 item,
328                                 "Invalid item (NULL spec with non-NULL last or mask)");
329
330                 memset(item_spec, 0, size);
331                 memset(item_mask, 0, size);
332                 *item_size = size;
333                 *item_disabled = 1; /* TRUE */
334                 return 0;
335         }
336
337         memcpy(spec, item->spec, size);
338         *item_size = size;
339
340         /* mask */
341         if (item->mask)
342                 memcpy(mask, item->mask, size);
343         else
344                 memcpy(mask, mask_default, size);
345
346         /* disabled */
347         for (i = 0; i < size; i++)
348                 if (mask[i])
349                         break;
350         *item_disabled = (i == size) ? 1 : 0;
351
352         /* Apply mask over spec. */
353         for (i = 0; i < size; i++)
354                 spec[i] &= mask[i];
355
356         /* last */
357         if (item->last) {
358                 uint8_t last[size];
359
360                 /* init last */
361                 memcpy(last, item->last, size);
362                 for (i = 0; i < size; i++)
363                         last[i] &= mask[i];
364
365                 /* check for range */
366                 for (i = 0; i < size; i++)
367                         if (last[i] != spec[i])
368                                 return rte_flow_error_set(error,
369                                         ENOTSUP,
370                                         RTE_FLOW_ERROR_TYPE_ITEM,
371                                         item,
372                                         "Range not supported");
373         }
374
375         return 0;
376 }
377
378 /***
379  * Skip disabled protocol items and VOID items
380  * until any of the mutually exclusive conditions
381  * from the list below takes place:
382  *    (A) A protocol present in the proto_mask
383  *        is met (either ENABLED or DISABLED);
384  *    (B) A protocol NOT present in the proto_mask is met in ENABLED state;
385  *    (C) The END item is met.
386  */
387 static int
388 flow_item_skip_disabled_protos(const struct rte_flow_item **item,
389         uint64_t proto_mask,
390         size_t *length,
391         struct rte_flow_error *error)
392 {
393         size_t len = 0;
394
395         for ( ; (*item)->type != RTE_FLOW_ITEM_TYPE_END; (*item)++) {
396                 union flow_item spec, mask;
397                 size_t size;
398                 int disabled = 0, status;
399
400                 if ((*item)->type == RTE_FLOW_ITEM_TYPE_VOID)
401                         continue;
402
403                 status = flow_item_proto_preprocess(*item,
404                                 &spec,
405                                 &mask,
406                                 &size,
407                                 &disabled,
408                                 error);
409                 if (status)
410                         return status;
411
412                 if ((proto_mask & (1LLU << (*item)->type)) ||
413                                 !disabled)
414                         break;
415
416                 len += size;
417         }
418
419         if (length)
420                 *length = len;
421
422         return 0;
423 }
424
425 #define FLOW_ITEM_PROTO_IP \
426         ((1LLU << RTE_FLOW_ITEM_TYPE_IPV4) | \
427          (1LLU << RTE_FLOW_ITEM_TYPE_IPV6))
428
429 static void
430 flow_item_skip_void(const struct rte_flow_item **item)
431 {
432         for ( ; ; (*item)++)
433                 if ((*item)->type != RTE_FLOW_ITEM_TYPE_VOID)
434                         return;
435 }
436
437 #define IP_PROTOCOL_TCP 0x06
438 #define IP_PROTOCOL_UDP 0x11
439 #define IP_PROTOCOL_SCTP 0x84
440
441 static int
442 mask_to_depth(uint64_t mask,
443                 uint32_t *depth)
444 {
445         uint64_t n;
446
447         if (mask == UINT64_MAX) {
448                 if (depth)
449                         *depth = 64;
450
451                 return 0;
452         }
453
454         mask = ~mask;
455
456         if (mask & (mask + 1))
457                 return -1;
458
459         n = __builtin_popcountll(mask);
460         if (depth)
461                 *depth = (uint32_t)(64 - n);
462
463         return 0;
464 }
465
466 static int
467 ipv4_mask_to_depth(uint32_t mask,
468                 uint32_t *depth)
469 {
470         uint32_t d;
471         int status;
472
473         status = mask_to_depth(mask | (UINT64_MAX << 32), &d);
474         if (status)
475                 return status;
476
477         d -= 32;
478         if (depth)
479                 *depth = d;
480
481         return 0;
482 }
483
484 static int
485 ipv6_mask_to_depth(uint8_t *mask,
486         uint32_t *depth)
487 {
488         uint64_t *m = (uint64_t *)mask;
489         uint64_t m0 = rte_be_to_cpu_64(m[0]);
490         uint64_t m1 = rte_be_to_cpu_64(m[1]);
491         uint32_t d0, d1;
492         int status;
493
494         status = mask_to_depth(m0, &d0);
495         if (status)
496                 return status;
497
498         status = mask_to_depth(m1, &d1);
499         if (status)
500                 return status;
501
502         if (d0 < 64 && d1)
503                 return -1;
504
505         if (depth)
506                 *depth = d0 + d1;
507
508         return 0;
509 }
510
511 static int
512 port_mask_to_range(uint16_t port,
513         uint16_t port_mask,
514         uint16_t *port0,
515         uint16_t *port1)
516 {
517         int status;
518         uint16_t p0, p1;
519
520         status = mask_to_depth(port_mask | (UINT64_MAX << 16), NULL);
521         if (status)
522                 return -1;
523
524         p0 = port & port_mask;
525         p1 = p0 | ~port_mask;
526
527         if (port0)
528                 *port0 = p0;
529
530         if (port1)
531                 *port1 = p1;
532
533         return 0;
534 }
535
536 static int
537 flow_rule_match_acl_get(struct pmd_internals *softnic __rte_unused,
538                 struct pipeline *pipeline __rte_unused,
539                 struct softnic_table *table __rte_unused,
540                 const struct rte_flow_attr *attr,
541                 const struct rte_flow_item *item,
542                 struct softnic_table_rule_match *rule_match,
543                 struct rte_flow_error *error)
544 {
545         union flow_item spec, mask;
546         size_t size, length = 0;
547         int disabled = 0, status;
548         uint8_t ip_proto, ip_proto_mask;
549
550         memset(rule_match, 0, sizeof(*rule_match));
551         rule_match->match_type = TABLE_ACL;
552         rule_match->match.acl.priority = attr->priority;
553
554         /* VOID or disabled protos only, if any. */
555         status = flow_item_skip_disabled_protos(&item,
556                         FLOW_ITEM_PROTO_IP, &length, error);
557         if (status)
558                 return status;
559
560         /* IP only. */
561         status = flow_item_proto_preprocess(item, &spec, &mask,
562                         &size, &disabled, error);
563         if (status)
564                 return status;
565
566         switch (item->type) {
567         case RTE_FLOW_ITEM_TYPE_IPV4:
568         {
569                 uint32_t sa_depth, da_depth;
570
571                 status = ipv4_mask_to_depth(rte_ntohl(mask.ipv4.hdr.src_addr),
572                                 &sa_depth);
573                 if (status)
574                         return rte_flow_error_set(error,
575                                 EINVAL,
576                                 RTE_FLOW_ERROR_TYPE_ITEM,
577                                 item,
578                                 "ACL: Illegal IPv4 header source address mask");
579
580                 status = ipv4_mask_to_depth(rte_ntohl(mask.ipv4.hdr.dst_addr),
581                                 &da_depth);
582                 if (status)
583                         return rte_flow_error_set(error,
584                                 EINVAL,
585                                 RTE_FLOW_ERROR_TYPE_ITEM,
586                                 item,
587                                 "ACL: Illegal IPv4 header destination address mask");
588
589                 ip_proto = spec.ipv4.hdr.next_proto_id;
590                 ip_proto_mask = mask.ipv4.hdr.next_proto_id;
591
592                 rule_match->match.acl.ip_version = 1;
593                 rule_match->match.acl.ipv4.sa =
594                         rte_ntohl(spec.ipv4.hdr.src_addr);
595                 rule_match->match.acl.ipv4.da =
596                         rte_ntohl(spec.ipv4.hdr.dst_addr);
597                 rule_match->match.acl.sa_depth = sa_depth;
598                 rule_match->match.acl.da_depth = da_depth;
599                 rule_match->match.acl.proto = ip_proto;
600                 rule_match->match.acl.proto_mask = ip_proto_mask;
601                 break;
602         } /* RTE_FLOW_ITEM_TYPE_IPV4 */
603
604         case RTE_FLOW_ITEM_TYPE_IPV6:
605         {
606                 uint32_t sa_depth, da_depth;
607
608                 status = ipv6_mask_to_depth(mask.ipv6.hdr.src_addr, &sa_depth);
609                 if (status)
610                         return rte_flow_error_set(error,
611                                 EINVAL,
612                                 RTE_FLOW_ERROR_TYPE_ITEM,
613                                 item,
614                                 "ACL: Illegal IPv6 header source address mask");
615
616                 status = ipv6_mask_to_depth(mask.ipv6.hdr.dst_addr, &da_depth);
617                 if (status)
618                         return rte_flow_error_set(error,
619                                 EINVAL,
620                                 RTE_FLOW_ERROR_TYPE_ITEM,
621                                 item,
622                                 "ACL: Illegal IPv6 header destination address mask");
623
624                 ip_proto = spec.ipv6.hdr.proto;
625                 ip_proto_mask = mask.ipv6.hdr.proto;
626
627                 rule_match->match.acl.ip_version = 0;
628                 memcpy(rule_match->match.acl.ipv6.sa,
629                         spec.ipv6.hdr.src_addr,
630                         sizeof(spec.ipv6.hdr.src_addr));
631                 memcpy(rule_match->match.acl.ipv6.da,
632                         spec.ipv6.hdr.dst_addr,
633                         sizeof(spec.ipv6.hdr.dst_addr));
634                 rule_match->match.acl.sa_depth = sa_depth;
635                 rule_match->match.acl.da_depth = da_depth;
636                 rule_match->match.acl.proto = ip_proto;
637                 rule_match->match.acl.proto_mask = ip_proto_mask;
638                 break;
639         } /* RTE_FLOW_ITEM_TYPE_IPV6 */
640
641         default:
642                 return rte_flow_error_set(error,
643                         ENOTSUP,
644                         RTE_FLOW_ERROR_TYPE_ITEM,
645                         item,
646                         "ACL: IP protocol required");
647         } /* switch */
648
649         if (ip_proto_mask != UINT8_MAX)
650                 return rte_flow_error_set(error,
651                         EINVAL,
652                         RTE_FLOW_ERROR_TYPE_ITEM,
653                         item,
654                         "ACL: Illegal IP protocol mask");
655
656         item++;
657
658         /* VOID only, if any. */
659         flow_item_skip_void(&item);
660
661         /* TCP/UDP/SCTP only. */
662         status = flow_item_proto_preprocess(item, &spec, &mask,
663                         &size, &disabled, error);
664         if (status)
665                 return status;
666
667         switch (item->type) {
668         case RTE_FLOW_ITEM_TYPE_TCP:
669         {
670                 uint16_t sp0, sp1, dp0, dp1;
671
672                 if (ip_proto != IP_PROTOCOL_TCP)
673                         return rte_flow_error_set(error,
674                                 EINVAL,
675                                 RTE_FLOW_ERROR_TYPE_ITEM,
676                                 item,
677                                 "ACL: Item type is TCP, but IP protocol is not");
678
679                 status = port_mask_to_range(rte_ntohs(spec.tcp.hdr.src_port),
680                                 rte_ntohs(mask.tcp.hdr.src_port),
681                                 &sp0,
682                                 &sp1);
683
684                 if (status)
685                         return rte_flow_error_set(error,
686                                 EINVAL,
687                                 RTE_FLOW_ERROR_TYPE_ITEM,
688                                 item,
689                                 "ACL: Illegal TCP source port mask");
690
691                 status = port_mask_to_range(rte_ntohs(spec.tcp.hdr.dst_port),
692                                 rte_ntohs(mask.tcp.hdr.dst_port),
693                                 &dp0,
694                                 &dp1);
695
696                 if (status)
697                         return rte_flow_error_set(error,
698                                 EINVAL,
699                                 RTE_FLOW_ERROR_TYPE_ITEM,
700                                 item,
701                                 "ACL: Illegal TCP destination port mask");
702
703                 rule_match->match.acl.sp0 = sp0;
704                 rule_match->match.acl.sp1 = sp1;
705                 rule_match->match.acl.dp0 = dp0;
706                 rule_match->match.acl.dp1 = dp1;
707
708                 break;
709         } /* RTE_FLOW_ITEM_TYPE_TCP */
710
711         case RTE_FLOW_ITEM_TYPE_UDP:
712         {
713                 uint16_t sp0, sp1, dp0, dp1;
714
715                 if (ip_proto != IP_PROTOCOL_UDP)
716                         return rte_flow_error_set(error,
717                                 EINVAL,
718                                 RTE_FLOW_ERROR_TYPE_ITEM,
719                                 item,
720                                 "ACL: Item type is UDP, but IP protocol is not");
721
722                 status = port_mask_to_range(rte_ntohs(spec.udp.hdr.src_port),
723                         rte_ntohs(mask.udp.hdr.src_port),
724                         &sp0,
725                         &sp1);
726                 if (status)
727                         return rte_flow_error_set(error,
728                                 EINVAL,
729                                 RTE_FLOW_ERROR_TYPE_ITEM,
730                                 item,
731                                 "ACL: Illegal UDP source port mask");
732
733                 status = port_mask_to_range(rte_ntohs(spec.udp.hdr.dst_port),
734                         rte_ntohs(mask.udp.hdr.dst_port),
735                         &dp0,
736                         &dp1);
737                 if (status)
738                         return rte_flow_error_set(error,
739                                 EINVAL,
740                                 RTE_FLOW_ERROR_TYPE_ITEM,
741                                 item,
742                                 "ACL: Illegal UDP destination port mask");
743
744                 rule_match->match.acl.sp0 = sp0;
745                 rule_match->match.acl.sp1 = sp1;
746                 rule_match->match.acl.dp0 = dp0;
747                 rule_match->match.acl.dp1 = dp1;
748
749                 break;
750         } /* RTE_FLOW_ITEM_TYPE_UDP */
751
752         case RTE_FLOW_ITEM_TYPE_SCTP:
753         {
754                 uint16_t sp0, sp1, dp0, dp1;
755
756                 if (ip_proto != IP_PROTOCOL_SCTP)
757                         return rte_flow_error_set(error,
758                                 EINVAL,
759                                 RTE_FLOW_ERROR_TYPE_ITEM,
760                                 item,
761                                 "ACL: Item type is SCTP, but IP protocol is not");
762
763                 status = port_mask_to_range(rte_ntohs(spec.sctp.hdr.src_port),
764                         rte_ntohs(mask.sctp.hdr.src_port),
765                         &sp0,
766                         &sp1);
767
768                 if (status)
769                         return rte_flow_error_set(error,
770                                 EINVAL,
771                                 RTE_FLOW_ERROR_TYPE_ITEM,
772                                 item,
773                                 "ACL: Illegal SCTP source port mask");
774
775                 status = port_mask_to_range(rte_ntohs(spec.sctp.hdr.dst_port),
776                         rte_ntohs(mask.sctp.hdr.dst_port),
777                         &dp0,
778                         &dp1);
779                 if (status)
780                         return rte_flow_error_set(error,
781                                 EINVAL,
782                                 RTE_FLOW_ERROR_TYPE_ITEM,
783                                 item,
784                                 "ACL: Illegal SCTP destination port mask");
785
786                 rule_match->match.acl.sp0 = sp0;
787                 rule_match->match.acl.sp1 = sp1;
788                 rule_match->match.acl.dp0 = dp0;
789                 rule_match->match.acl.dp1 = dp1;
790
791                 break;
792         } /* RTE_FLOW_ITEM_TYPE_SCTP */
793
794         default:
795                 return rte_flow_error_set(error,
796                         ENOTSUP,
797                         RTE_FLOW_ERROR_TYPE_ITEM,
798                         item,
799                         "ACL: TCP/UDP/SCTP required");
800         } /* switch */
801
802         item++;
803
804         /* VOID or disabled protos only, if any. */
805         status = flow_item_skip_disabled_protos(&item, 0, NULL, error);
806         if (status)
807                 return status;
808
809         /* END only. */
810         if (item->type != RTE_FLOW_ITEM_TYPE_END)
811                 return rte_flow_error_set(error,
812                         EINVAL,
813                         RTE_FLOW_ERROR_TYPE_ITEM,
814                         item,
815                         "ACL: Expecting END item");
816
817         return 0;
818 }
819
820 /***
821  * Both *tmask* and *fmask* are byte arrays of size *tsize* and *fsize*
822  * respectively.
823  * They are located within a larger buffer at offsets *toffset* and *foffset*
824  * respectivelly. Both *tmask* and *fmask* represent bitmasks for the larger
825  * buffer.
826  * Question: are the two masks equivalent?
827  *
828  * Notes:
829  * 1. Offset basically indicates that the first offset bytes in the buffer
830  *    are "don't care", so offset is equivalent to pre-pending an "all-zeros"
831  *    array of *offset* bytes to the *mask*.
832  * 2. Each *mask* might contain a number of zero bytes at the beginning or
833  *    at the end.
834  * 3. Bytes in the larger buffer after the end of the *mask* are also considered
835  *    "don't care", so they are equivalent to appending an "all-zeros" array of
836  *    bytes to the *mask*.
837  *
838  * Example:
839  * Buffer = [xx xx xx xx xx xx xx xx], buffer size = 8 bytes
840  * tmask = [00 22 00 33 00], toffset = 2, tsize = 5
841  *    => buffer mask = [00 00 00 22 00 33 00 00]
842  * fmask = [22 00 33], foffset = 3, fsize = 3 =>
843  *    => buffer mask = [00 00 00 22 00 33 00 00]
844  * Therefore, the tmask and fmask from this example are equivalent.
845  */
846 static int
847 hash_key_mask_is_same(uint8_t *tmask,
848         size_t toffset,
849         size_t tsize,
850         uint8_t *fmask,
851         size_t foffset,
852         size_t fsize,
853         size_t *toffset_plus,
854         size_t *foffset_plus)
855 {
856         size_t tpos; /* Position of first non-zero byte in the tmask buffer. */
857         size_t fpos; /* Position of first non-zero byte in the fmask buffer. */
858
859         /* Compute tpos and fpos. */
860         for (tpos = 0; tmask[tpos] == 0; tpos++)
861                 ;
862         for (fpos = 0; fmask[fpos] == 0; fpos++)
863                 ;
864
865         if (toffset + tpos != foffset + fpos)
866                 return 0; /* FALSE */
867
868         tsize -= tpos;
869         fsize -= fpos;
870
871         if (tsize < fsize) {
872                 size_t i;
873
874                 for (i = 0; i < tsize; i++)
875                         if (tmask[tpos + i] != fmask[fpos + i])
876                                 return 0; /* FALSE */
877
878                 for ( ; i < fsize; i++)
879                         if (fmask[fpos + i])
880                                 return 0; /* FALSE */
881         } else {
882                 size_t i;
883
884                 for (i = 0; i < fsize; i++)
885                         if (tmask[tpos + i] != fmask[fpos + i])
886                                 return 0; /* FALSE */
887
888                 for ( ; i < tsize; i++)
889                         if (tmask[tpos + i])
890                                 return 0; /* FALSE */
891         }
892
893         if (toffset_plus)
894                 *toffset_plus = tpos;
895
896         if (foffset_plus)
897                 *foffset_plus = fpos;
898
899         return 1; /* TRUE */
900 }
901
902 static int
903 flow_rule_match_hash_get(struct pmd_internals *softnic __rte_unused,
904         struct pipeline *pipeline __rte_unused,
905         struct softnic_table *table,
906         const struct rte_flow_attr *attr __rte_unused,
907         const struct rte_flow_item *item,
908         struct softnic_table_rule_match *rule_match,
909         struct rte_flow_error *error)
910 {
911         struct softnic_table_rule_match_hash key, key_mask;
912         struct softnic_table_hash_params *params = &table->params.match.hash;
913         size_t offset = 0, length = 0, tpos, fpos;
914         int status;
915
916         memset(&key, 0, sizeof(key));
917         memset(&key_mask, 0, sizeof(key_mask));
918
919         /* VOID or disabled protos only, if any. */
920         status = flow_item_skip_disabled_protos(&item, 0, &offset, error);
921         if (status)
922                 return status;
923
924         if (item->type == RTE_FLOW_ITEM_TYPE_END)
925                 return rte_flow_error_set(error,
926                         EINVAL,
927                         RTE_FLOW_ERROR_TYPE_ITEM,
928                         item,
929                         "HASH: END detected too early");
930
931         /* VOID or any protocols (enabled or disabled). */
932         for ( ; item->type != RTE_FLOW_ITEM_TYPE_END; item++) {
933                 union flow_item spec, mask;
934                 size_t size;
935                 int disabled, status;
936
937                 if (item->type == RTE_FLOW_ITEM_TYPE_VOID)
938                         continue;
939
940                 status = flow_item_proto_preprocess(item,
941                         &spec,
942                         &mask,
943                         &size,
944                         &disabled,
945                         error);
946                 if (status)
947                         return status;
948
949                 if (length + size > sizeof(key)) {
950                         if (disabled)
951                                 break;
952
953                         return rte_flow_error_set(error,
954                                 ENOTSUP,
955                                 RTE_FLOW_ERROR_TYPE_ITEM,
956                                 item,
957                                 "HASH: Item too big");
958                 }
959
960                 memcpy(&key.key[length], &spec, size);
961                 memcpy(&key_mask.key[length], &mask, size);
962                 length += size;
963         }
964
965         if (item->type != RTE_FLOW_ITEM_TYPE_END) {
966                 /* VOID or disabled protos only, if any. */
967                 status = flow_item_skip_disabled_protos(&item, 0, NULL, error);
968                 if (status)
969                         return status;
970
971                 /* END only. */
972                 if (item->type != RTE_FLOW_ITEM_TYPE_END)
973                         return rte_flow_error_set(error,
974                                 EINVAL,
975                                 RTE_FLOW_ERROR_TYPE_ITEM,
976                                 item,
977                                 "HASH: Expecting END item");
978         }
979
980         /* Compare flow key mask against table key mask. */
981         offset += sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM;
982
983         if (!hash_key_mask_is_same(params->key_mask,
984                 params->key_offset,
985                 params->key_size,
986                 key_mask.key,
987                 offset,
988                 length,
989                 &tpos,
990                 &fpos))
991                 return rte_flow_error_set(error,
992                         EINVAL,
993                         RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
994                         NULL,
995                         "HASH: Item list is not observing the match format");
996
997         /* Rule match. */
998         memset(rule_match, 0, sizeof(*rule_match));
999         rule_match->match_type = TABLE_HASH;
1000         memcpy(&rule_match->match.hash.key[tpos],
1001                 &key.key[fpos],
1002                 RTE_MIN(sizeof(rule_match->match.hash.key) - tpos,
1003                         length - fpos));
1004
1005         return 0;
1006 }
1007
1008 static int
1009 flow_rule_match_get(struct pmd_internals *softnic,
1010                 struct pipeline *pipeline,
1011                 struct softnic_table *table,
1012                 const struct rte_flow_attr *attr,
1013                 const struct rte_flow_item *item,
1014                 struct softnic_table_rule_match *rule_match,
1015                 struct rte_flow_error *error)
1016 {
1017         switch (table->params.match_type) {
1018         case TABLE_ACL:
1019                 return flow_rule_match_acl_get(softnic,
1020                         pipeline,
1021                         table,
1022                         attr,
1023                         item,
1024                         rule_match,
1025                         error);
1026
1027                 /* FALLTHROUGH */
1028
1029         case TABLE_HASH:
1030                 return flow_rule_match_hash_get(softnic,
1031                         pipeline,
1032                         table,
1033                         attr,
1034                         item,
1035                         rule_match,
1036                         error);
1037
1038                 /* FALLTHROUGH */
1039
1040         default:
1041                 return rte_flow_error_set(error,
1042                         ENOTSUP,
1043                         RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1044                         NULL,
1045                         "Unsupported pipeline table match type");
1046         }
1047 }
1048
1049 static int
1050 flow_rule_action_get(struct pmd_internals *softnic,
1051         struct pipeline *pipeline,
1052         struct softnic_table *table,
1053         const struct rte_flow_attr *attr,
1054         const struct rte_flow_action *action,
1055         struct softnic_table_rule_action *rule_action,
1056         struct rte_flow_error *error __rte_unused)
1057 {
1058         struct softnic_table_action_profile *profile;
1059         struct softnic_table_action_profile_params *params;
1060         int n_jump_queue_rss_drop = 0;
1061         int n_count = 0;
1062
1063         profile = softnic_table_action_profile_find(softnic,
1064                 table->params.action_profile_name);
1065         if (profile == NULL)
1066                 return rte_flow_error_set(error,
1067                         EINVAL,
1068                         RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1069                         action,
1070                         "JUMP: Table action profile");
1071
1072         params = &profile->params;
1073
1074         for ( ; action->type != RTE_FLOW_ACTION_TYPE_END; action++) {
1075                 if (action->type == RTE_FLOW_ACTION_TYPE_VOID)
1076                         continue;
1077
1078                 switch (action->type) {
1079                 case RTE_FLOW_ACTION_TYPE_JUMP:
1080                 {
1081                         const struct rte_flow_action_jump *conf = action->conf;
1082                         struct flow_attr_map *map;
1083
1084                         if (conf == NULL)
1085                                 return rte_flow_error_set(error,
1086                                         EINVAL,
1087                                         RTE_FLOW_ERROR_TYPE_ACTION,
1088                                         action,
1089                                         "JUMP: Null configuration");
1090
1091                         if (n_jump_queue_rss_drop)
1092                                 return rte_flow_error_set(error,
1093                                         EINVAL,
1094                                         RTE_FLOW_ERROR_TYPE_ACTION,
1095                                         action,
1096                                         "Only one termination action is"
1097                                         " allowed per flow");
1098
1099                         if ((params->action_mask &
1100                                 (1LLU << RTE_TABLE_ACTION_FWD)) == 0)
1101                                 return rte_flow_error_set(error,
1102                                         EINVAL,
1103                                         RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1104                                         NULL,
1105                                         "JUMP action not enabled for this table");
1106
1107                         n_jump_queue_rss_drop = 1;
1108
1109                         map = flow_attr_map_get(softnic,
1110                                 conf->group,
1111                                 attr->ingress);
1112                         if (map == NULL || map->valid == 0)
1113                                 return rte_flow_error_set(error,
1114                                         EINVAL,
1115                                         RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1116                                         NULL,
1117                                         "JUMP: Invalid group mapping");
1118
1119                         if (strcmp(pipeline->name, map->pipeline_name) != 0)
1120                                 return rte_flow_error_set(error,
1121                                         ENOTSUP,
1122                                         RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1123                                         NULL,
1124                                         "JUMP: Jump to table in different pipeline");
1125
1126                         /* RTE_TABLE_ACTION_FWD */
1127                         rule_action->fwd.action = RTE_PIPELINE_ACTION_TABLE;
1128                         rule_action->fwd.id = map->table_id;
1129                         rule_action->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
1130                         break;
1131                 } /* RTE_FLOW_ACTION_TYPE_JUMP */
1132
1133                 case RTE_FLOW_ACTION_TYPE_QUEUE:
1134                 {
1135                         char name[NAME_SIZE];
1136                         struct rte_eth_dev *dev;
1137                         const struct rte_flow_action_queue *conf = action->conf;
1138                         uint32_t port_id;
1139                         int status;
1140
1141                         if (conf == NULL)
1142                                 return rte_flow_error_set(error,
1143                                         EINVAL,
1144                                         RTE_FLOW_ERROR_TYPE_ACTION,
1145                                         action,
1146                                         "QUEUE: Null configuration");
1147
1148                         if (n_jump_queue_rss_drop)
1149                                 return rte_flow_error_set(error,
1150                                         EINVAL,
1151                                         RTE_FLOW_ERROR_TYPE_ACTION,
1152                                         action,
1153                                         "Only one termination action is allowed"
1154                                         " per flow");
1155
1156                         if ((params->action_mask &
1157                                 (1LLU << RTE_TABLE_ACTION_FWD)) == 0)
1158                                 return rte_flow_error_set(error,
1159                                         EINVAL,
1160                                         RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1161                                         NULL,
1162                                         "QUEUE action not enabled for this table");
1163
1164                         n_jump_queue_rss_drop = 1;
1165
1166                         dev = ETHDEV(softnic);
1167                         if (dev == NULL ||
1168                                 conf->index >= dev->data->nb_rx_queues)
1169                                 return rte_flow_error_set(error,
1170                                         EINVAL,
1171                                         RTE_FLOW_ERROR_TYPE_ACTION,
1172                                         action,
1173                                         "QUEUE: Invalid RX queue ID");
1174
1175                         sprintf(name, "RXQ%u", (uint32_t)conf->index);
1176
1177                         status = softnic_pipeline_port_out_find(softnic,
1178                                 pipeline->name,
1179                                 name,
1180                                 &port_id);
1181                         if (status)
1182                                 return rte_flow_error_set(error,
1183                                         ENOTSUP,
1184                                         RTE_FLOW_ERROR_TYPE_ACTION,
1185                                         action,
1186                                         "QUEUE: RX queue not accessible from this pipeline");
1187
1188                         /* RTE_TABLE_ACTION_FWD */
1189                         rule_action->fwd.action = RTE_PIPELINE_ACTION_PORT;
1190                         rule_action->fwd.id = port_id;
1191                         rule_action->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
1192                         break;
1193                 } /*RTE_FLOW_ACTION_TYPE_QUEUE */
1194
1195                 case RTE_FLOW_ACTION_TYPE_RSS:
1196                 {
1197                         const struct rte_flow_action_rss *conf = action->conf;
1198                         uint32_t i;
1199
1200                         if (conf == NULL)
1201                                 return rte_flow_error_set(error,
1202                                         EINVAL,
1203                                         RTE_FLOW_ERROR_TYPE_ACTION,
1204                                         action,
1205                                         "RSS: Null configuration");
1206
1207                         if (!rte_is_power_of_2(conf->queue_num))
1208                                 return rte_flow_error_set(error,
1209                                         EINVAL,
1210                                         RTE_FLOW_ERROR_TYPE_ACTION_CONF,
1211                                         conf,
1212                                         "RSS: Number of queues must be a power of 2");
1213
1214                         if (conf->queue_num > RTE_DIM(rule_action->lb.out))
1215                                 return rte_flow_error_set(error,
1216                                         EINVAL,
1217                                         RTE_FLOW_ERROR_TYPE_ACTION_CONF,
1218                                         conf,
1219                                         "RSS: Number of queues too big");
1220
1221                         if (n_jump_queue_rss_drop)
1222                                 return rte_flow_error_set(error,
1223                                         EINVAL,
1224                                         RTE_FLOW_ERROR_TYPE_ACTION,
1225                                         action,
1226                                         "Only one termination action is allowed per flow");
1227
1228                         if (((params->action_mask &
1229                                 (1LLU << RTE_TABLE_ACTION_FWD)) == 0) ||
1230                                 ((params->action_mask &
1231                                 (1LLU << RTE_TABLE_ACTION_LB)) == 0))
1232                                 return rte_flow_error_set(error,
1233                                         ENOTSUP,
1234                                         RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1235                                         NULL,
1236                                         "RSS action not supported by this table");
1237
1238                         if (params->lb.out_offset !=
1239                                 pipeline->params.offset_port_id)
1240                                 return rte_flow_error_set(error,
1241                                         EINVAL,
1242                                         RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1243                                         NULL,
1244                                         "RSS action not supported by this pipeline");
1245
1246                         n_jump_queue_rss_drop = 1;
1247
1248                         /* RTE_TABLE_ACTION_LB */
1249                         for (i = 0; i < conf->queue_num; i++) {
1250                                 char name[NAME_SIZE];
1251                                 struct rte_eth_dev *dev;
1252                                 uint32_t port_id;
1253                                 int status;
1254
1255                                 dev = ETHDEV(softnic);
1256                                 if (dev == NULL ||
1257                                         conf->queue[i] >=
1258                                                 dev->data->nb_rx_queues)
1259                                         return rte_flow_error_set(error,
1260                                                 EINVAL,
1261                                                 RTE_FLOW_ERROR_TYPE_ACTION,
1262                                                 action,
1263                                                 "RSS: Invalid RX queue ID");
1264
1265                                 sprintf(name, "RXQ%u",
1266                                         (uint32_t)conf->queue[i]);
1267
1268                                 status = softnic_pipeline_port_out_find(softnic,
1269                                         pipeline->name,
1270                                         name,
1271                                         &port_id);
1272                                 if (status)
1273                                         return rte_flow_error_set(error,
1274                                                 ENOTSUP,
1275                                                 RTE_FLOW_ERROR_TYPE_ACTION,
1276                                                 action,
1277                                                 "RSS: RX queue not accessible from this pipeline");
1278
1279                                 rule_action->lb.out[i] = port_id;
1280                         }
1281
1282                         for ( ; i < RTE_DIM(rule_action->lb.out); i++)
1283                                 rule_action->lb.out[i] =
1284                                 rule_action->lb.out[i % conf->queue_num];
1285
1286                         rule_action->action_mask |= 1 << RTE_TABLE_ACTION_LB;
1287
1288                         /* RTE_TABLE_ACTION_FWD */
1289                         rule_action->fwd.action = RTE_PIPELINE_ACTION_PORT_META;
1290                         rule_action->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
1291                         break;
1292                 } /* RTE_FLOW_ACTION_TYPE_RSS */
1293
1294                 case RTE_FLOW_ACTION_TYPE_DROP:
1295                 {
1296                         const void *conf = action->conf;
1297
1298                         if (conf != NULL)
1299                                 return rte_flow_error_set(error,
1300                                         EINVAL,
1301                                         RTE_FLOW_ERROR_TYPE_ACTION,
1302                                         action,
1303                                         "DROP: No configuration required");
1304
1305                         if (n_jump_queue_rss_drop)
1306                                 return rte_flow_error_set(error,
1307                                         EINVAL,
1308                                         RTE_FLOW_ERROR_TYPE_ACTION,
1309                                         action,
1310                                         "Only one termination action is allowed per flow");
1311                         if ((params->action_mask &
1312                                 (1LLU << RTE_TABLE_ACTION_FWD)) == 0)
1313                                 return rte_flow_error_set(error,
1314                                         ENOTSUP,
1315                                         RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1316                                         NULL,
1317                                         "DROP action not supported by this table");
1318
1319                         n_jump_queue_rss_drop = 1;
1320
1321                         /* RTE_TABLE_ACTION_FWD */
1322                         rule_action->fwd.action = RTE_PIPELINE_ACTION_DROP;
1323                         rule_action->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
1324                         break;
1325                 } /* RTE_FLOW_ACTION_TYPE_DROP */
1326
1327                 case RTE_FLOW_ACTION_TYPE_COUNT:
1328                 {
1329                         const struct rte_flow_action_count *conf = action->conf;
1330
1331                         if (conf == NULL)
1332                                 return rte_flow_error_set(error,
1333                                         EINVAL,
1334                                         RTE_FLOW_ERROR_TYPE_ACTION,
1335                                         action,
1336                                         "COUNT: Null configuration");
1337
1338                         if (conf->shared)
1339                                 return rte_flow_error_set(error,
1340                                         ENOTSUP,
1341                                         RTE_FLOW_ERROR_TYPE_ACTION_CONF,
1342                                         conf,
1343                                         "COUNT: Shared counters not supported");
1344
1345                         if (n_count)
1346                                 return rte_flow_error_set(error,
1347                                         ENOTSUP,
1348                                         RTE_FLOW_ERROR_TYPE_ACTION,
1349                                         action,
1350                                         "Only one COUNT action per flow");
1351
1352                         if ((params->action_mask &
1353                                 (1LLU << RTE_TABLE_ACTION_STATS)) == 0)
1354                                 return rte_flow_error_set(error,
1355                                         ENOTSUP,
1356                                         RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1357                                         NULL,
1358                                         "COUNT action not supported by this table");
1359
1360                         n_count = 1;
1361
1362                         /* RTE_TABLE_ACTION_STATS */
1363                         rule_action->stats.n_packets = 0;
1364                         rule_action->stats.n_bytes = 0;
1365                         rule_action->action_mask |= 1 << RTE_TABLE_ACTION_STATS;
1366                         break;
1367                 } /* RTE_FLOW_ACTION_TYPE_COUNT */
1368
1369                 default:
1370                         return -ENOTSUP;
1371                 }
1372         }
1373
1374         if (n_jump_queue_rss_drop == 0)
1375                 return rte_flow_error_set(error,
1376                         EINVAL,
1377                         RTE_FLOW_ERROR_TYPE_ACTION,
1378                         action,
1379                         "Flow does not have any terminating action");
1380
1381         return 0;
1382 }
1383
1384 static int
1385 pmd_flow_validate(struct rte_eth_dev *dev,
1386                 const struct rte_flow_attr *attr,
1387                 const struct rte_flow_item item[],
1388                 const struct rte_flow_action action[],
1389                 struct rte_flow_error *error)
1390 {
1391         struct softnic_table_rule_match rule_match;
1392         struct softnic_table_rule_action rule_action;
1393
1394         struct pmd_internals *softnic = dev->data->dev_private;
1395         struct pipeline *pipeline;
1396         struct softnic_table *table;
1397         const char *pipeline_name = NULL;
1398         uint32_t table_id = 0;
1399         int status;
1400
1401         /* Check input parameters. */
1402         if (attr == NULL)
1403                 return rte_flow_error_set(error,
1404                                 EINVAL,
1405                                 RTE_FLOW_ERROR_TYPE_ATTR,
1406                                 NULL, "Null attr");
1407
1408         if (item == NULL)
1409                 return rte_flow_error_set(error,
1410                                 EINVAL,
1411                                 RTE_FLOW_ERROR_TYPE_ITEM,
1412                                 NULL,
1413                                 "Null item");
1414
1415         if (action == NULL)
1416                 return rte_flow_error_set(error,
1417                                 EINVAL,
1418                                 RTE_FLOW_ERROR_TYPE_ACTION,
1419                                 NULL,
1420                                 "Null action");
1421
1422         /* Identify the pipeline table to add this flow to. */
1423         status = flow_pipeline_table_get(softnic, attr, &pipeline_name,
1424                                         &table_id, error);
1425         if (status)
1426                 return status;
1427
1428         pipeline = softnic_pipeline_find(softnic, pipeline_name);
1429         if (pipeline == NULL)
1430                 return rte_flow_error_set(error,
1431                                 EINVAL,
1432                                 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1433                                 NULL,
1434                                 "Invalid pipeline name");
1435
1436         if (table_id >= pipeline->n_tables)
1437                 return rte_flow_error_set(error,
1438                                 EINVAL,
1439                                 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1440                                 NULL,
1441                                 "Invalid pipeline table ID");
1442
1443         table = &pipeline->table[table_id];
1444
1445         /* Rule match. */
1446         memset(&rule_match, 0, sizeof(rule_match));
1447         status = flow_rule_match_get(softnic,
1448                         pipeline,
1449                         table,
1450                         attr,
1451                         item,
1452                         &rule_match,
1453                         error);
1454         if (status)
1455                 return status;
1456
1457         /* Rule action. */
1458         memset(&rule_action, 0, sizeof(rule_action));
1459         status = flow_rule_action_get(softnic,
1460                 pipeline,
1461                 table,
1462                 attr,
1463                 action,
1464                 &rule_action,
1465                 error);
1466         if (status)
1467                 return status;
1468
1469         return 0;
1470 }
1471
1472 static struct rte_flow *
1473 pmd_flow_create(struct rte_eth_dev *dev,
1474         const struct rte_flow_attr *attr,
1475         const struct rte_flow_item item[],
1476         const struct rte_flow_action action[],
1477         struct rte_flow_error *error)
1478 {
1479         struct softnic_table_rule_match rule_match;
1480         struct softnic_table_rule_action rule_action;
1481         void *rule_data;
1482
1483         struct pmd_internals *softnic = dev->data->dev_private;
1484         struct pipeline *pipeline;
1485         struct softnic_table *table;
1486         struct rte_flow *flow;
1487         const char *pipeline_name = NULL;
1488         uint32_t table_id = 0;
1489         int new_flow, status;
1490
1491         /* Check input parameters. */
1492         if (attr == NULL) {
1493                 rte_flow_error_set(error,
1494                         EINVAL,
1495                         RTE_FLOW_ERROR_TYPE_ATTR,
1496                         NULL,
1497                         "Null attr");
1498                 return NULL;
1499         }
1500
1501         if (item == NULL) {
1502                 rte_flow_error_set(error,
1503                         EINVAL,
1504                         RTE_FLOW_ERROR_TYPE_ITEM,
1505                         NULL,
1506                         "Null item");
1507                 return NULL;
1508         }
1509
1510         if (action == NULL) {
1511                 rte_flow_error_set(error,
1512                         EINVAL,
1513                         RTE_FLOW_ERROR_TYPE_ACTION,
1514                         NULL,
1515                         "Null action");
1516                 return NULL;
1517         }
1518
1519         /* Identify the pipeline table to add this flow to. */
1520         status = flow_pipeline_table_get(softnic, attr, &pipeline_name,
1521                                         &table_id, error);
1522         if (status)
1523                 return NULL;
1524
1525         pipeline = softnic_pipeline_find(softnic, pipeline_name);
1526         if (pipeline == NULL) {
1527                 rte_flow_error_set(error,
1528                         EINVAL,
1529                         RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1530                         NULL,
1531                         "Invalid pipeline name");
1532                 return NULL;
1533         }
1534
1535         if (table_id >= pipeline->n_tables) {
1536                 rte_flow_error_set(error,
1537                         EINVAL,
1538                         RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1539                         NULL,
1540                         "Invalid pipeline table ID");
1541                 return NULL;
1542         }
1543
1544         table = &pipeline->table[table_id];
1545
1546         /* Rule match. */
1547         memset(&rule_match, 0, sizeof(rule_match));
1548         status = flow_rule_match_get(softnic,
1549                 pipeline,
1550                 table,
1551                 attr,
1552                 item,
1553                 &rule_match,
1554                 error);
1555         if (status)
1556                 return NULL;
1557
1558         /* Rule action. */
1559         memset(&rule_action, 0, sizeof(rule_action));
1560         status = flow_rule_action_get(softnic,
1561                 pipeline,
1562                 table,
1563                 attr,
1564                 action,
1565                 &rule_action,
1566                 error);
1567         if (status)
1568                 return NULL;
1569
1570         /* Flow find/allocate. */
1571         new_flow = 0;
1572         flow = softnic_flow_find(table, &rule_match);
1573         if (flow == NULL) {
1574                 new_flow = 1;
1575                 flow = calloc(1, sizeof(struct rte_flow));
1576                 if (flow == NULL) {
1577                         rte_flow_error_set(error,
1578                                 ENOMEM,
1579                                 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1580                                 NULL,
1581                                 "Not enough memory for new flow");
1582                         return NULL;
1583                 }
1584         }
1585
1586         /* Rule add. */
1587         status = softnic_pipeline_table_rule_add(softnic,
1588                 pipeline_name,
1589                 table_id,
1590                 &rule_match,
1591                 &rule_action,
1592                 &rule_data);
1593         if (status) {
1594                 if (new_flow)
1595                         free(flow);
1596
1597                 rte_flow_error_set(error,
1598                         EINVAL,
1599                         RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1600                         NULL,
1601                         "Pipeline table rule add failed");
1602                 return NULL;
1603         }
1604
1605         /* Flow fill in. */
1606         memcpy(&flow->match, &rule_match, sizeof(rule_match));
1607         memcpy(&flow->action, &rule_action, sizeof(rule_action));
1608         flow->data = rule_data;
1609         flow->pipeline = pipeline;
1610         flow->table_id = table_id;
1611
1612         /* Flow add to list. */
1613         if (new_flow)
1614                 TAILQ_INSERT_TAIL(&table->flows, flow, node);
1615
1616         return flow;
1617 }
1618
1619 const struct rte_flow_ops pmd_flow_ops = {
1620         .validate = pmd_flow_validate,
1621         .create = pmd_flow_create,
1622 };