New upstream version 18.02
[deb_dpdk.git] / examples / ip_pipeline / pipeline / pipeline_flow_classification.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2010-2016 Intel Corporation
3  */
4
5 #include <stdio.h>
6 #include <string.h>
7 #include <sys/queue.h>
8 #include <netinet/in.h>
9 #include <unistd.h>
10
11 #include <rte_common.h>
12 #include <rte_hexdump.h>
13 #include <rte_malloc.h>
14 #include <cmdline_rdline.h>
15 #include <cmdline_parse.h>
16 #include <cmdline_parse_num.h>
17 #include <cmdline_parse_string.h>
18
19 #include "app.h"
20 #include "pipeline_common_fe.h"
21 #include "pipeline_flow_classification.h"
22 #include "hash_func.h"
23 #include "parser.h"
24
25 /*
26  * Key conversion
27  */
28
29 struct pkt_key_qinq {
30         uint16_t ethertype_svlan;
31         uint16_t svlan;
32         uint16_t ethertype_cvlan;
33         uint16_t cvlan;
34 } __attribute__((__packed__));
35
36 struct pkt_key_ipv4_5tuple {
37         uint8_t ttl;
38         uint8_t proto;
39         uint16_t checksum;
40         uint32_t ip_src;
41         uint32_t ip_dst;
42         uint16_t port_src;
43         uint16_t port_dst;
44 } __attribute__((__packed__));
45
46 struct pkt_key_ipv6_5tuple {
47         uint16_t payload_length;
48         uint8_t proto;
49         uint8_t hop_limit;
50         uint8_t ip_src[16];
51         uint8_t ip_dst[16];
52         uint16_t port_src;
53         uint16_t port_dst;
54 } __attribute__((__packed__));
55
56 static int
57 app_pipeline_fc_key_convert(struct pipeline_fc_key *key_in,
58         uint8_t *key_out,
59         uint32_t *signature)
60 {
61         uint8_t buffer[PIPELINE_FC_FLOW_KEY_MAX_SIZE];
62         uint8_t m[PIPELINE_FC_FLOW_KEY_MAX_SIZE]; /* key mask */
63         void *key_buffer = (key_out) ? key_out : buffer;
64
65         memset(m, 0xFF, sizeof(m));
66         switch (key_in->type) {
67         case FLOW_KEY_QINQ:
68         {
69                 struct pkt_key_qinq *qinq = key_buffer;
70
71                 qinq->ethertype_svlan = 0;
72                 qinq->svlan = rte_cpu_to_be_16(key_in->key.qinq.svlan);
73                 qinq->ethertype_cvlan = 0;
74                 qinq->cvlan = rte_cpu_to_be_16(key_in->key.qinq.cvlan);
75
76                 if (signature)
77                         *signature = (uint32_t) hash_default_key8(qinq, m, 8, 0);
78                 return 0;
79         }
80
81         case FLOW_KEY_IPV4_5TUPLE:
82         {
83                 struct pkt_key_ipv4_5tuple *ipv4 = key_buffer;
84
85                 ipv4->ttl = 0;
86                 ipv4->proto = key_in->key.ipv4_5tuple.proto;
87                 ipv4->checksum = 0;
88                 ipv4->ip_src = rte_cpu_to_be_32(key_in->key.ipv4_5tuple.ip_src);
89                 ipv4->ip_dst = rte_cpu_to_be_32(key_in->key.ipv4_5tuple.ip_dst);
90                 ipv4->port_src = rte_cpu_to_be_16(key_in->key.ipv4_5tuple.port_src);
91                 ipv4->port_dst = rte_cpu_to_be_16(key_in->key.ipv4_5tuple.port_dst);
92
93                 if (signature)
94                         *signature = (uint32_t) hash_default_key16(ipv4, m, 16, 0);
95                 return 0;
96         }
97
98         case FLOW_KEY_IPV6_5TUPLE:
99         {
100                 struct pkt_key_ipv6_5tuple *ipv6 = key_buffer;
101
102                 memset(ipv6, 0, 64);
103                 ipv6->payload_length = 0;
104                 ipv6->proto = key_in->key.ipv6_5tuple.proto;
105                 ipv6->hop_limit = 0;
106                 memcpy(&ipv6->ip_src, &key_in->key.ipv6_5tuple.ip_src, 16);
107                 memcpy(&ipv6->ip_dst, &key_in->key.ipv6_5tuple.ip_dst, 16);
108                 ipv6->port_src = rte_cpu_to_be_16(key_in->key.ipv6_5tuple.port_src);
109                 ipv6->port_dst = rte_cpu_to_be_16(key_in->key.ipv6_5tuple.port_dst);
110
111                 if (signature)
112                         *signature = (uint32_t) hash_default_key64(ipv6, m, 64, 0);
113                 return 0;
114         }
115
116         default:
117                 return -1;
118         }
119 }
120
121 /*
122  * Flow classification pipeline
123  */
124
125 struct app_pipeline_fc_flow {
126         struct pipeline_fc_key key;
127         uint32_t port_id;
128         uint32_t flow_id;
129         uint32_t signature;
130         void *entry_ptr;
131
132         TAILQ_ENTRY(app_pipeline_fc_flow) node;
133 };
134
135 #define N_BUCKETS                                65536
136
137 struct app_pipeline_fc {
138         /* Parameters */
139         uint32_t n_ports_in;
140         uint32_t n_ports_out;
141
142         /* Flows */
143         TAILQ_HEAD(, app_pipeline_fc_flow) flows[N_BUCKETS];
144         uint32_t n_flows;
145
146         /* Default flow */
147         uint32_t default_flow_present;
148         uint32_t default_flow_port_id;
149         void *default_flow_entry_ptr;
150 };
151
152 static struct app_pipeline_fc_flow *
153 app_pipeline_fc_flow_find(struct app_pipeline_fc *p,
154         struct pipeline_fc_key *key)
155 {
156         struct app_pipeline_fc_flow *f;
157         uint32_t signature, bucket_id;
158
159         app_pipeline_fc_key_convert(key, NULL, &signature);
160         bucket_id = signature & (N_BUCKETS - 1);
161
162         TAILQ_FOREACH(f, &p->flows[bucket_id], node)
163                 if ((signature == f->signature) &&
164                         (memcmp(key,
165                                 &f->key,
166                                 sizeof(struct pipeline_fc_key)) == 0))
167                         return f;
168
169         return NULL;
170 }
171
172 static void*
173 app_pipeline_fc_init(struct pipeline_params *params,
174         __rte_unused void *arg)
175 {
176         struct app_pipeline_fc *p;
177         uint32_t size, i;
178
179         /* Check input arguments */
180         if ((params == NULL) ||
181                 (params->n_ports_in == 0) ||
182                 (params->n_ports_out == 0))
183                 return NULL;
184
185         /* Memory allocation */
186         size = RTE_CACHE_LINE_ROUNDUP(sizeof(struct app_pipeline_fc));
187         p = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
188         if (p == NULL)
189                 return NULL;
190
191         /* Initialization */
192         p->n_ports_in = params->n_ports_in;
193         p->n_ports_out = params->n_ports_out;
194
195         for (i = 0; i < N_BUCKETS; i++)
196                 TAILQ_INIT(&p->flows[i]);
197         p->n_flows = 0;
198
199         return (void *) p;
200 }
201
202 static int
203 app_pipeline_fc_free(void *pipeline)
204 {
205         struct app_pipeline_fc *p = pipeline;
206         uint32_t i;
207
208         /* Check input arguments */
209         if (p == NULL)
210                 return -1;
211
212         /* Free resources */
213         for (i = 0; i < N_BUCKETS; i++)
214                 while (!TAILQ_EMPTY(&p->flows[i])) {
215                         struct app_pipeline_fc_flow *flow;
216
217                         flow = TAILQ_FIRST(&p->flows[i]);
218                         TAILQ_REMOVE(&p->flows[i], flow, node);
219                         rte_free(flow);
220                 }
221
222         rte_free(p);
223         return 0;
224 }
225
226 static int
227 app_pipeline_fc_key_check(struct pipeline_fc_key *key)
228 {
229         switch (key->type) {
230         case FLOW_KEY_QINQ:
231         {
232                 uint16_t svlan = key->key.qinq.svlan;
233                 uint16_t cvlan = key->key.qinq.cvlan;
234
235                 if ((svlan & 0xF000) ||
236                         (cvlan & 0xF000))
237                         return -1;
238
239                 return 0;
240         }
241
242         case FLOW_KEY_IPV4_5TUPLE:
243                 return 0;
244
245         case FLOW_KEY_IPV6_5TUPLE:
246                 return 0;
247
248         default:
249                 return -1;
250         }
251 }
252
253 int
254 app_pipeline_fc_load_file_qinq(char *filename,
255         struct pipeline_fc_key *keys,
256         uint32_t *port_ids,
257         uint32_t *flow_ids,
258         uint32_t *n_keys,
259         uint32_t *line)
260 {
261         FILE *f = NULL;
262         char file_buf[1024];
263         uint32_t i, l;
264
265         /* Check input arguments */
266         if ((filename == NULL) ||
267                 (keys == NULL) ||
268                 (port_ids == NULL) ||
269                 (flow_ids == NULL) ||
270                 (n_keys == NULL) ||
271                 (*n_keys == 0) ||
272                 (line == NULL)) {
273                 if (line)
274                         *line = 0;
275                 return -1;
276                 }
277
278         /* Open input file */
279         f = fopen(filename, "r");
280         if (f == NULL) {
281                 *line = 0;
282                 return -1;
283         }
284
285         /* Read file */
286         for (i = 0, l = 1; i < *n_keys; l++) {
287                 char *tokens[32];
288                 uint32_t n_tokens = RTE_DIM(tokens);
289
290                 uint16_t svlan, cvlan;
291                 uint32_t portid, flowid;
292                 int status;
293
294                 if (fgets(file_buf, sizeof(file_buf), f) == NULL)
295                         break;
296
297                 status = parse_tokenize_string(file_buf, tokens, &n_tokens);
298                 if (status)
299                         goto error1;
300
301                 if ((n_tokens == 0) || (tokens[0][0] == '#'))
302                         continue;
303
304                 if ((n_tokens != 7) ||
305                         strcmp(tokens[0], "qinq") ||
306                         parser_read_uint16(&svlan, tokens[1]) ||
307                         parser_read_uint16(&cvlan, tokens[2]) ||
308                         strcmp(tokens[3], "port") ||
309                         parser_read_uint32(&portid, tokens[4]) ||
310                         strcmp(tokens[5], "id") ||
311                         parser_read_uint32(&flowid, tokens[6]))
312                         goto error1;
313
314                 keys[i].type = FLOW_KEY_QINQ;
315                 keys[i].key.qinq.svlan = svlan;
316                 keys[i].key.qinq.cvlan = cvlan;
317
318                 port_ids[i] = portid;
319                 flow_ids[i] = flowid;
320
321                 if (app_pipeline_fc_key_check(&keys[i]))
322                         goto error1;
323
324                 i++;
325         }
326
327         /* Close file */
328         *n_keys = i;
329         fclose(f);
330         return 0;
331
332 error1:
333         *line = l;
334         fclose(f);
335         return -1;
336 }
337
338 int
339 app_pipeline_fc_load_file_ipv4(char *filename,
340         struct pipeline_fc_key *keys,
341         uint32_t *port_ids,
342         uint32_t *flow_ids,
343         uint32_t *n_keys,
344         uint32_t *line)
345 {
346         FILE *f = NULL;
347         char file_buf[1024];
348         uint32_t i, l;
349
350         /* Check input arguments */
351         if ((filename == NULL) ||
352                 (keys == NULL) ||
353                 (port_ids == NULL) ||
354                 (flow_ids == NULL) ||
355                 (n_keys == NULL) ||
356                 (*n_keys == 0) ||
357                 (line == NULL)) {
358                 if (line)
359                         *line = 0;
360                 return -1;
361                 }
362
363         /* Open input file */
364         f = fopen(filename, "r");
365         if (f == NULL) {
366                 *line = 0;
367                 return -1;
368         }
369
370         /* Read file */
371         for (i = 0, l = 1; i < *n_keys; l++) {
372                 char *tokens[32];
373                 uint32_t n_tokens = RTE_DIM(tokens);
374
375                 struct in_addr sipaddr, dipaddr;
376                 uint16_t sport, dport;
377                 uint8_t proto;
378                 uint32_t portid, flowid;
379                 int status;
380
381                 if (fgets(file_buf, sizeof(file_buf), f) == NULL)
382                         break;
383
384                 status = parse_tokenize_string(file_buf, tokens, &n_tokens);
385                 if (status)
386                         goto error2;
387
388                 if ((n_tokens == 0) || (tokens[0][0] == '#'))
389                         continue;
390
391                 if ((n_tokens != 10) ||
392                         strcmp(tokens[0], "ipv4") ||
393                         parse_ipv4_addr(tokens[1], &sipaddr) ||
394                         parse_ipv4_addr(tokens[2], &dipaddr) ||
395                         parser_read_uint16(&sport, tokens[3]) ||
396                         parser_read_uint16(&dport, tokens[4]) ||
397                         parser_read_uint8(&proto, tokens[5]) ||
398                         strcmp(tokens[6], "port") ||
399                         parser_read_uint32(&portid, tokens[7]) ||
400                         strcmp(tokens[8], "id") ||
401                         parser_read_uint32(&flowid, tokens[9]))
402                         goto error2;
403
404                 keys[i].type = FLOW_KEY_IPV4_5TUPLE;
405                 keys[i].key.ipv4_5tuple.ip_src = rte_be_to_cpu_32(sipaddr.s_addr);
406                 keys[i].key.ipv4_5tuple.ip_dst = rte_be_to_cpu_32(dipaddr.s_addr);
407                 keys[i].key.ipv4_5tuple.port_src = sport;
408                 keys[i].key.ipv4_5tuple.port_dst = dport;
409                 keys[i].key.ipv4_5tuple.proto = proto;
410
411                 port_ids[i] = portid;
412                 flow_ids[i] = flowid;
413
414                 if (app_pipeline_fc_key_check(&keys[i]))
415                         goto error2;
416
417                 i++;
418         }
419
420         /* Close file */
421         *n_keys = i;
422         fclose(f);
423         return 0;
424
425 error2:
426         *line = l;
427         fclose(f);
428         return -1;
429 }
430
431 int
432 app_pipeline_fc_load_file_ipv6(char *filename,
433         struct pipeline_fc_key *keys,
434         uint32_t *port_ids,
435         uint32_t *flow_ids,
436         uint32_t *n_keys,
437         uint32_t *line)
438 {
439         FILE *f = NULL;
440         char file_buf[1024];
441         uint32_t i, l;
442
443         /* Check input arguments */
444         if ((filename == NULL) ||
445                 (keys == NULL) ||
446                 (port_ids == NULL) ||
447                 (flow_ids == NULL) ||
448                 (n_keys == NULL) ||
449                 (*n_keys == 0) ||
450                 (line == NULL)) {
451                 if (line)
452                         *line = 0;
453                 return -1;
454                 }
455
456         /* Open input file */
457         f = fopen(filename, "r");
458         if (f == NULL) {
459                 *line = 0;
460                 return -1;
461         }
462
463         /* Read file */
464         for (i = 0, l = 1; i < *n_keys; l++) {
465                 char *tokens[32];
466                 uint32_t n_tokens = RTE_DIM(tokens);
467
468                 struct in6_addr sipaddr, dipaddr;
469                 uint16_t sport, dport;
470                 uint8_t proto;
471                 uint32_t portid, flowid;
472                 int status;
473
474                 if (fgets(file_buf, sizeof(file_buf), f) == NULL)
475                         break;
476
477                 status = parse_tokenize_string(file_buf, tokens, &n_tokens);
478                 if (status)
479                         goto error3;
480
481                 if ((n_tokens == 0) || (tokens[0][0] == '#'))
482                         continue;
483
484                 if ((n_tokens != 10) ||
485                         strcmp(tokens[0], "ipv6") ||
486                         parse_ipv6_addr(tokens[1], &sipaddr) ||
487                         parse_ipv6_addr(tokens[2], &dipaddr) ||
488                         parser_read_uint16(&sport, tokens[3]) ||
489                         parser_read_uint16(&dport, tokens[4]) ||
490                         parser_read_uint8(&proto, tokens[5]) ||
491                         strcmp(tokens[6], "port") ||
492                         parser_read_uint32(&portid, tokens[7]) ||
493                         strcmp(tokens[8], "id") ||
494                         parser_read_uint32(&flowid, tokens[9]))
495                         goto error3;
496
497                 keys[i].type = FLOW_KEY_IPV6_5TUPLE;
498                 memcpy(keys[i].key.ipv6_5tuple.ip_src,
499                         sipaddr.s6_addr,
500                         sizeof(sipaddr.s6_addr));
501                 memcpy(keys[i].key.ipv6_5tuple.ip_dst,
502                         dipaddr.s6_addr,
503                         sizeof(dipaddr.s6_addr));
504                 keys[i].key.ipv6_5tuple.port_src = sport;
505                 keys[i].key.ipv6_5tuple.port_dst = dport;
506                 keys[i].key.ipv6_5tuple.proto = proto;
507
508                 port_ids[i] = portid;
509                 flow_ids[i] = flowid;
510
511                 if (app_pipeline_fc_key_check(&keys[i]))
512                         goto error3;
513
514                 i++;
515         }
516
517         /* Close file */
518         *n_keys = i;
519         fclose(f);
520         return 0;
521
522 error3:
523         *line = l;
524         fclose(f);
525         return -1;
526 }
527
528
529
530 int
531 app_pipeline_fc_add(struct app_params *app,
532         uint32_t pipeline_id,
533         struct pipeline_fc_key *key,
534         uint32_t port_id,
535         uint32_t flow_id)
536 {
537         struct app_pipeline_fc *p;
538         struct app_pipeline_fc_flow *flow;
539
540         struct pipeline_fc_add_msg_req *req;
541         struct pipeline_fc_add_msg_rsp *rsp;
542
543         uint32_t signature;
544         int new_flow;
545
546         /* Check input arguments */
547         if ((app == NULL) ||
548                 (key == NULL))
549                 return -1;
550
551         p = app_pipeline_data_fe(app, pipeline_id, &pipeline_flow_classification);
552         if (p == NULL)
553                 return -1;
554
555         if (port_id >= p->n_ports_out)
556                 return -1;
557
558         if (app_pipeline_fc_key_check(key) != 0)
559                 return -1;
560
561         /* Find existing flow or allocate new flow */
562         flow = app_pipeline_fc_flow_find(p, key);
563         new_flow = (flow == NULL);
564         if (flow == NULL) {
565                 flow = rte_malloc(NULL, sizeof(*flow), RTE_CACHE_LINE_SIZE);
566
567                 if (flow == NULL)
568                         return -1;
569         }
570
571         /* Allocate and write request */
572         req = app_msg_alloc(app);
573         if (req == NULL)
574                 return -1;
575
576         req->type = PIPELINE_MSG_REQ_CUSTOM;
577         req->subtype = PIPELINE_FC_MSG_REQ_FLOW_ADD;
578         app_pipeline_fc_key_convert(key, req->key, &signature);
579         req->port_id = port_id;
580         req->flow_id = flow_id;
581
582         /* Send request and wait for response */
583         rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
584         if (rsp == NULL) {
585                 if (new_flow)
586                         rte_free(flow);
587                 return -1;
588         }
589
590         /* Read response and write flow */
591         if (rsp->status ||
592                 (rsp->entry_ptr == NULL) ||
593                 ((new_flow == 0) && (rsp->key_found == 0)) ||
594                 ((new_flow == 1) && (rsp->key_found == 1))) {
595                 app_msg_free(app, rsp);
596                 if (new_flow)
597                         rte_free(flow);
598                 return -1;
599         }
600
601         memset(&flow->key, 0, sizeof(flow->key));
602         memcpy(&flow->key, key, sizeof(flow->key));
603         flow->port_id = port_id;
604         flow->flow_id = flow_id;
605         flow->signature = signature;
606         flow->entry_ptr = rsp->entry_ptr;
607
608         /* Commit rule */
609         if (new_flow) {
610                 uint32_t bucket_id = signature & (N_BUCKETS - 1);
611
612                 TAILQ_INSERT_TAIL(&p->flows[bucket_id], flow, node);
613                 p->n_flows++;
614         }
615
616         /* Free response */
617         app_msg_free(app, rsp);
618
619         return 0;
620 }
621
622 int
623 app_pipeline_fc_add_bulk(struct app_params *app,
624         uint32_t pipeline_id,
625         struct pipeline_fc_key *key,
626         uint32_t *port_id,
627         uint32_t *flow_id,
628         uint32_t n_keys)
629 {
630         struct app_pipeline_fc *p;
631         struct pipeline_fc_add_bulk_msg_req *req;
632         struct pipeline_fc_add_bulk_msg_rsp *rsp;
633
634         struct app_pipeline_fc_flow **flow;
635         uint32_t *signature;
636         int *new_flow;
637         struct pipeline_fc_add_bulk_flow_req *flow_req;
638         struct pipeline_fc_add_bulk_flow_rsp *flow_rsp;
639
640         uint32_t i;
641         int status;
642
643         /* Check input arguments */
644         if ((app == NULL) ||
645                 (key == NULL) ||
646                 (port_id == NULL) ||
647                 (flow_id == NULL) ||
648                 (n_keys == 0))
649                 return -1;
650
651         p = app_pipeline_data_fe(app, pipeline_id, &pipeline_flow_classification);
652         if (p == NULL)
653                 return -1;
654
655         for (i = 0; i < n_keys; i++)
656                 if (port_id[i] >= p->n_ports_out)
657                         return -1;
658
659         for (i = 0; i < n_keys; i++)
660                 if (app_pipeline_fc_key_check(&key[i]) != 0)
661                         return -1;
662
663         /* Memory allocation */
664         flow = rte_malloc(NULL,
665                 n_keys * sizeof(struct app_pipeline_fc_flow *),
666                 RTE_CACHE_LINE_SIZE);
667         if (flow == NULL)
668                 return -1;
669
670         signature = rte_malloc(NULL,
671                 n_keys * sizeof(uint32_t),
672                 RTE_CACHE_LINE_SIZE);
673         if (signature == NULL) {
674                 rte_free(flow);
675                 return -1;
676         }
677
678         new_flow = rte_malloc(
679                 NULL,
680                 n_keys * sizeof(int),
681                 RTE_CACHE_LINE_SIZE);
682         if (new_flow == NULL) {
683                 rte_free(signature);
684                 rte_free(flow);
685                 return -1;
686         }
687
688         flow_req = rte_malloc(NULL,
689                 n_keys * sizeof(struct pipeline_fc_add_bulk_flow_req),
690                 RTE_CACHE_LINE_SIZE);
691         if (flow_req == NULL) {
692                 rte_free(new_flow);
693                 rte_free(signature);
694                 rte_free(flow);
695                 return -1;
696         }
697
698         flow_rsp = rte_malloc(NULL,
699                 n_keys * sizeof(struct pipeline_fc_add_bulk_flow_rsp),
700                 RTE_CACHE_LINE_SIZE);
701         if (flow_rsp == NULL) {
702                 rte_free(flow_req);
703                 rte_free(new_flow);
704                 rte_free(signature);
705                 rte_free(flow);
706                 return -1;
707         }
708
709         /* Find existing flow or allocate new flow */
710         for (i = 0; i < n_keys; i++) {
711                 flow[i] = app_pipeline_fc_flow_find(p, &key[i]);
712                 new_flow[i] = (flow[i] == NULL);
713                 if (flow[i] == NULL) {
714                         flow[i] = rte_zmalloc(NULL,
715                                 sizeof(struct app_pipeline_fc_flow),
716                                 RTE_CACHE_LINE_SIZE);
717
718                         if (flow[i] == NULL) {
719                                 uint32_t j;
720
721                                 for (j = 0; j < i; j++)
722                                         if (new_flow[j])
723                                                 rte_free(flow[j]);
724
725                                 rte_free(flow_rsp);
726                                 rte_free(flow_req);
727                                 rte_free(new_flow);
728                                 rte_free(signature);
729                                 rte_free(flow);
730                                 return -1;
731                         }
732                 }
733         }
734
735         /* Allocate and write request */
736         req = app_msg_alloc(app);
737         if (req == NULL) {
738                 for (i = 0; i < n_keys; i++)
739                         if (new_flow[i])
740                                 rte_free(flow[i]);
741
742                 rte_free(flow_rsp);
743                 rte_free(flow_req);
744                 rte_free(new_flow);
745                 rte_free(signature);
746                 rte_free(flow);
747                 return -1;
748         }
749
750         for (i = 0; i < n_keys; i++) {
751                 app_pipeline_fc_key_convert(&key[i],
752                         flow_req[i].key,
753                         &signature[i]);
754                 flow_req[i].port_id = port_id[i];
755                 flow_req[i].flow_id = flow_id[i];
756         }
757
758         req->type = PIPELINE_MSG_REQ_CUSTOM;
759         req->subtype = PIPELINE_FC_MSG_REQ_FLOW_ADD_BULK;
760         req->req = flow_req;
761         req->rsp = flow_rsp;
762         req->n_keys = n_keys;
763
764         /* Send request and wait for response */
765         rsp = app_msg_send_recv(app, pipeline_id, req, 10000);
766         if (rsp == NULL) {
767                 for (i = 0; i < n_keys; i++)
768                         if (new_flow[i])
769                                 rte_free(flow[i]);
770
771                 rte_free(flow_rsp);
772                 rte_free(flow_req);
773                 rte_free(new_flow);
774                 rte_free(signature);
775                 rte_free(flow);
776                 return -1;
777         }
778
779         /* Read response */
780         status = 0;
781
782         for (i = 0; i < rsp->n_keys; i++)
783                 if ((flow_rsp[i].entry_ptr == NULL) ||
784                         ((new_flow[i] == 0) && (flow_rsp[i].key_found == 0)) ||
785                         ((new_flow[i] == 1) && (flow_rsp[i].key_found == 1)))
786                         status = -1;
787
788         if (rsp->n_keys < n_keys)
789                 status = -1;
790
791         /* Commit flows */
792         for (i = 0; i < rsp->n_keys; i++) {
793                 memcpy(&flow[i]->key, &key[i], sizeof(flow[i]->key));
794                 flow[i]->port_id = port_id[i];
795                 flow[i]->flow_id = flow_id[i];
796                 flow[i]->signature = signature[i];
797                 flow[i]->entry_ptr = flow_rsp[i].entry_ptr;
798
799                 if (new_flow[i]) {
800                         uint32_t bucket_id = signature[i] & (N_BUCKETS - 1);
801
802                         TAILQ_INSERT_TAIL(&p->flows[bucket_id], flow[i], node);
803                         p->n_flows++;
804                 }
805         }
806
807         /* Free resources */
808
809         for (i = rsp->n_keys; i < n_keys; i++)
810                 if (new_flow[i])
811                         rte_free(flow[i]);
812
813         app_msg_free(app, rsp);
814         rte_free(flow_rsp);
815         rte_free(flow_req);
816         rte_free(new_flow);
817         rte_free(signature);
818         rte_free(flow);
819
820         return status;
821 }
822
823 int
824 app_pipeline_fc_del(struct app_params *app,
825         uint32_t pipeline_id,
826         struct pipeline_fc_key *key)
827 {
828         struct app_pipeline_fc *p;
829         struct app_pipeline_fc_flow *flow;
830
831         struct pipeline_fc_del_msg_req *req;
832         struct pipeline_fc_del_msg_rsp *rsp;
833
834         uint32_t signature, bucket_id;
835
836         /* Check input arguments */
837         if ((app == NULL) ||
838                 (key == NULL))
839                 return -1;
840
841         p = app_pipeline_data_fe(app, pipeline_id, &pipeline_flow_classification);
842         if (p == NULL)
843                 return -1;
844
845         if (app_pipeline_fc_key_check(key) != 0)
846                 return -1;
847
848         /* Find rule */
849         flow = app_pipeline_fc_flow_find(p, key);
850         if (flow == NULL)
851                 return 0;
852
853         /* Allocate and write request */
854         req = app_msg_alloc(app);
855         if (req == NULL)
856                 return -1;
857
858         req->type = PIPELINE_MSG_REQ_CUSTOM;
859         req->subtype = PIPELINE_FC_MSG_REQ_FLOW_DEL;
860         app_pipeline_fc_key_convert(key, req->key, &signature);
861
862         /* Send request and wait for response */
863         rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
864         if (rsp == NULL)
865                 return -1;
866
867         /* Read response */
868         if (rsp->status || !rsp->key_found) {
869                 app_msg_free(app, rsp);
870                 return -1;
871         }
872
873         /* Remove rule */
874         bucket_id = signature & (N_BUCKETS - 1);
875         TAILQ_REMOVE(&p->flows[bucket_id], flow, node);
876         p->n_flows--;
877         rte_free(flow);
878
879         /* Free response */
880         app_msg_free(app, rsp);
881
882         return 0;
883 }
884
885 int
886 app_pipeline_fc_add_default(struct app_params *app,
887         uint32_t pipeline_id,
888         uint32_t port_id)
889 {
890         struct app_pipeline_fc *p;
891
892         struct pipeline_fc_add_default_msg_req *req;
893         struct pipeline_fc_add_default_msg_rsp *rsp;
894
895         /* Check input arguments */
896         if (app == NULL)
897                 return -1;
898
899         p = app_pipeline_data_fe(app, pipeline_id, &pipeline_flow_classification);
900         if (p == NULL)
901                 return -1;
902
903         if (port_id >= p->n_ports_out)
904                 return -1;
905
906         /* Allocate and write request */
907         req = app_msg_alloc(app);
908         if (req == NULL)
909                 return -1;
910
911         req->type = PIPELINE_MSG_REQ_CUSTOM;
912         req->subtype = PIPELINE_FC_MSG_REQ_FLOW_ADD_DEFAULT;
913         req->port_id = port_id;
914
915         /* Send request and wait for response */
916         rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
917         if (rsp == NULL)
918                 return -1;
919
920         /* Read response and write flow */
921         if (rsp->status || (rsp->entry_ptr == NULL)) {
922                 app_msg_free(app, rsp);
923                 return -1;
924         }
925
926         p->default_flow_port_id = port_id;
927         p->default_flow_entry_ptr = rsp->entry_ptr;
928
929         /* Commit route */
930         p->default_flow_present = 1;
931
932         /* Free response */
933         app_msg_free(app, rsp);
934
935         return 0;
936 }
937
938 int
939 app_pipeline_fc_del_default(struct app_params *app,
940         uint32_t pipeline_id)
941 {
942         struct app_pipeline_fc *p;
943
944         struct pipeline_fc_del_default_msg_req *req;
945         struct pipeline_fc_del_default_msg_rsp *rsp;
946
947         /* Check input arguments */
948         if (app == NULL)
949                 return -1;
950
951         p = app_pipeline_data_fe(app, pipeline_id, &pipeline_flow_classification);
952         if (p == NULL)
953                 return -EINVAL;
954
955         /* Allocate and write request */
956         req = app_msg_alloc(app);
957         if (req == NULL)
958                 return -1;
959
960         req->type = PIPELINE_MSG_REQ_CUSTOM;
961         req->subtype = PIPELINE_FC_MSG_REQ_FLOW_DEL_DEFAULT;
962
963         /* Send request and wait for response */
964         rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
965         if (rsp == NULL)
966                 return -1;
967
968         /* Read response */
969         if (rsp->status) {
970                 app_msg_free(app, rsp);
971                 return -1;
972         }
973
974         /* Commit route */
975         p->default_flow_present = 0;
976
977         /* Free response */
978         app_msg_free(app, rsp);
979
980         return 0;
981 }
982
983 /*
984  * Flow ls
985  */
986
987 static void
988 print_fc_qinq_flow(struct app_pipeline_fc_flow *flow)
989 {
990         printf("(SVLAN = %" PRIu32 ", "
991                 "CVLAN = %" PRIu32 ") => "
992                 "Port = %" PRIu32 ", "
993                 "Flow ID = %" PRIu32 ", "
994                 "(signature = 0x%08" PRIx32 ", "
995                 "entry_ptr = %p)\n",
996
997                 flow->key.key.qinq.svlan,
998                 flow->key.key.qinq.cvlan,
999                 flow->port_id,
1000                 flow->flow_id,
1001                 flow->signature,
1002                 flow->entry_ptr);
1003 }
1004
1005 static void
1006 print_fc_ipv4_5tuple_flow(struct app_pipeline_fc_flow *flow)
1007 {
1008         printf("(SA = %" PRIu32 ".%" PRIu32 ".%" PRIu32 ".%" PRIu32 ", "
1009                    "DA = %" PRIu32 ".%" PRIu32 ".%" PRIu32 ".%" PRIu32 ", "
1010                    "SP = %" PRIu32 ", "
1011                    "DP = %" PRIu32 ", "
1012                    "Proto = %" PRIu32 ") => "
1013                    "Port = %" PRIu32 ", "
1014                    "Flow ID = %" PRIu32 " "
1015                    "(signature = 0x%08" PRIx32 ", "
1016                    "entry_ptr = %p)\n",
1017
1018                    (flow->key.key.ipv4_5tuple.ip_src >> 24) & 0xFF,
1019                    (flow->key.key.ipv4_5tuple.ip_src >> 16) & 0xFF,
1020                    (flow->key.key.ipv4_5tuple.ip_src >> 8) & 0xFF,
1021                    flow->key.key.ipv4_5tuple.ip_src & 0xFF,
1022
1023                    (flow->key.key.ipv4_5tuple.ip_dst >> 24) & 0xFF,
1024                    (flow->key.key.ipv4_5tuple.ip_dst >> 16) & 0xFF,
1025                    (flow->key.key.ipv4_5tuple.ip_dst >> 8) & 0xFF,
1026                    flow->key.key.ipv4_5tuple.ip_dst & 0xFF,
1027
1028                    flow->key.key.ipv4_5tuple.port_src,
1029                    flow->key.key.ipv4_5tuple.port_dst,
1030
1031                    flow->key.key.ipv4_5tuple.proto,
1032
1033                    flow->port_id,
1034                    flow->flow_id,
1035                    flow->signature,
1036                    flow->entry_ptr);
1037 }
1038
1039 static void
1040 print_fc_ipv6_5tuple_flow(struct app_pipeline_fc_flow *flow) {
1041         printf("(SA = %02" PRIx32 "%02" PRIx32 ":%02" PRIx32 "%02" PRIx32
1042                 ":%02" PRIx32 "%02" PRIx32 ":%02" PRIx32 "%02" PRIx32
1043                 ":%02" PRIx32 "%02" PRIx32 ":%02" PRIx32 "%02" PRIx32
1044                 ":%02" PRIx32 "%02" PRIx32 ":%02" PRIx32 "%02" PRIx32 ", "
1045                 "DA = %02" PRIx32 "%02" PRIx32 ":%02" PRIx32 "%02" PRIx32
1046                 ":%02" PRIx32 "%02" PRIx32 ":%02" PRIx32 "%02" PRIx32
1047                 ":%02" PRIx32 "%02" PRIx32 ":%02" PRIx32 "%02" PRIx32
1048                 ":%02" PRIx32 "%02" PRIx32 ":%02" PRIx32 "%02" PRIx32 ", "
1049                 "SP = %" PRIu32 ", "
1050                 "DP = %" PRIu32 " "
1051                 "Proto = %" PRIu32 " "
1052                 "=> Port = %" PRIu32 ", "
1053                 "Flow ID = %" PRIu32 " "
1054                 "(signature = 0x%08" PRIx32 ", "
1055                 "entry_ptr = %p)\n",
1056
1057                 flow->key.key.ipv6_5tuple.ip_src[0],
1058                 flow->key.key.ipv6_5tuple.ip_src[1],
1059                 flow->key.key.ipv6_5tuple.ip_src[2],
1060                 flow->key.key.ipv6_5tuple.ip_src[3],
1061                 flow->key.key.ipv6_5tuple.ip_src[4],
1062                 flow->key.key.ipv6_5tuple.ip_src[5],
1063                 flow->key.key.ipv6_5tuple.ip_src[6],
1064                 flow->key.key.ipv6_5tuple.ip_src[7],
1065                 flow->key.key.ipv6_5tuple.ip_src[8],
1066                 flow->key.key.ipv6_5tuple.ip_src[9],
1067                 flow->key.key.ipv6_5tuple.ip_src[10],
1068                 flow->key.key.ipv6_5tuple.ip_src[11],
1069                 flow->key.key.ipv6_5tuple.ip_src[12],
1070                 flow->key.key.ipv6_5tuple.ip_src[13],
1071                 flow->key.key.ipv6_5tuple.ip_src[14],
1072                 flow->key.key.ipv6_5tuple.ip_src[15],
1073
1074                 flow->key.key.ipv6_5tuple.ip_dst[0],
1075                 flow->key.key.ipv6_5tuple.ip_dst[1],
1076                 flow->key.key.ipv6_5tuple.ip_dst[2],
1077                 flow->key.key.ipv6_5tuple.ip_dst[3],
1078                 flow->key.key.ipv6_5tuple.ip_dst[4],
1079                 flow->key.key.ipv6_5tuple.ip_dst[5],
1080                 flow->key.key.ipv6_5tuple.ip_dst[6],
1081                 flow->key.key.ipv6_5tuple.ip_dst[7],
1082                 flow->key.key.ipv6_5tuple.ip_dst[8],
1083                 flow->key.key.ipv6_5tuple.ip_dst[9],
1084                 flow->key.key.ipv6_5tuple.ip_dst[10],
1085                 flow->key.key.ipv6_5tuple.ip_dst[11],
1086                 flow->key.key.ipv6_5tuple.ip_dst[12],
1087                 flow->key.key.ipv6_5tuple.ip_dst[13],
1088                 flow->key.key.ipv6_5tuple.ip_dst[14],
1089                 flow->key.key.ipv6_5tuple.ip_dst[15],
1090
1091                 flow->key.key.ipv6_5tuple.port_src,
1092                 flow->key.key.ipv6_5tuple.port_dst,
1093
1094                 flow->key.key.ipv6_5tuple.proto,
1095
1096                 flow->port_id,
1097                 flow->flow_id,
1098                 flow->signature,
1099                 flow->entry_ptr);
1100 }
1101
1102 static void
1103 print_fc_flow(struct app_pipeline_fc_flow *flow)
1104 {
1105         switch (flow->key.type) {
1106         case FLOW_KEY_QINQ:
1107                 print_fc_qinq_flow(flow);
1108                 break;
1109
1110         case FLOW_KEY_IPV4_5TUPLE:
1111                 print_fc_ipv4_5tuple_flow(flow);
1112                 break;
1113
1114         case FLOW_KEY_IPV6_5TUPLE:
1115                 print_fc_ipv6_5tuple_flow(flow);
1116                 break;
1117         }
1118 }
1119
1120 static int
1121 app_pipeline_fc_ls(struct app_params *app,
1122                 uint32_t pipeline_id)
1123 {
1124         struct app_pipeline_fc *p;
1125         struct app_pipeline_fc_flow *flow;
1126         uint32_t i;
1127
1128         /* Check input arguments */
1129         if (app == NULL)
1130                 return -1;
1131
1132         p = app_pipeline_data_fe(app, pipeline_id, &pipeline_flow_classification);
1133         if (p == NULL)
1134                 return -1;
1135
1136         for (i = 0; i < N_BUCKETS; i++)
1137                 TAILQ_FOREACH(flow, &p->flows[i], node)
1138                         print_fc_flow(flow);
1139
1140         if (p->default_flow_present)
1141                 printf("Default flow: port %" PRIu32 " (entry ptr = %p)\n",
1142                         p->default_flow_port_id,
1143                         p->default_flow_entry_ptr);
1144         else
1145                 printf("Default: DROP\n");
1146
1147         return 0;
1148 }
1149 /*
1150  * flow
1151  *
1152  * flow add:
1153  *    p <pipelineid> flow add qinq <svlan> <cvlan> port <portid> id <flowid>
1154  *    p <pipelineid> flow add qinq bulk <file>
1155  *    p <pipelineid> flow add ipv4 <sipaddr> <dipaddr> <sport> <dport> <proto> port <port ID> id <flowid>
1156  *    p <pipelineid> flow add ipv4 bulk <file>
1157  *    p <pipelineid> flow add ipv6 <sipaddr> <dipaddr> <sport> <dport> <proto> port <port ID> id <flowid>
1158  *    p <pipelineid> flow add ipv6 bulk <file>
1159  *
1160  * flow add default:
1161  *    p <pipelineid> flow add default <portid>
1162  *
1163  * flow del:
1164  *    p <pipelineid> flow del qinq <svlan> <cvlan>
1165  *    p <pipelineid> flow del ipv4 <sipaddr> <dipaddr> <sport> <dport> <proto>
1166  *    p <pipelineid> flow del ipv6 <sipaddr> <dipaddr> <sport> <dport> <proto>
1167  *
1168  * flow del default:
1169  *    p <pipelineid> flow del default
1170  *
1171  * flow ls:
1172  *    p <pipelineid> flow ls
1173  */
1174
1175 struct cmd_flow_result {
1176         cmdline_fixed_string_t p_string;
1177         uint32_t pipeline_id;
1178         cmdline_fixed_string_t flow_string;
1179         cmdline_multi_string_t multi_string;
1180 };
1181
1182 static void
1183 cmd_flow_parsed(void *parsed_result,
1184         __attribute__((unused)) struct cmdline *cl,
1185         void *data)
1186 {
1187         struct cmd_flow_result *results = parsed_result;
1188         struct app_params *app = data;
1189
1190         char *tokens[16];
1191         uint32_t n_tokens = RTE_DIM(tokens);
1192         int status;
1193
1194         status = parse_tokenize_string(results->multi_string, tokens, &n_tokens);
1195         if (status) {
1196                 printf(CMD_MSG_TOO_MANY_ARGS, "flow");
1197                 return;
1198         }
1199
1200         /* flow add qinq */
1201         if ((n_tokens >= 3) &&
1202                 (strcmp(tokens[0], "add") == 0) &&
1203                 (strcmp(tokens[1], "qinq") == 0) &&
1204                 strcmp(tokens[2], "bulk")) {
1205                 struct pipeline_fc_key key;
1206                 uint32_t svlan;
1207                 uint32_t cvlan;
1208                 uint32_t port_id;
1209                 uint32_t flow_id;
1210
1211                 memset(&key, 0, sizeof(key));
1212
1213                 if (n_tokens != 8) {
1214                         printf(CMD_MSG_MISMATCH_ARGS, "flow add qinq");
1215                         return;
1216                 }
1217
1218                 if (parser_read_uint32(&svlan, tokens[2]) != 0) {
1219                         printf(CMD_MSG_INVALID_ARG, "svlan");
1220                         return;
1221                 }
1222
1223                 if (parser_read_uint32(&cvlan, tokens[3]) != 0) {
1224                         printf(CMD_MSG_INVALID_ARG, "cvlan");
1225                         return;
1226                 }
1227
1228                 if (strcmp(tokens[4], "port") != 0) {
1229                         printf(CMD_MSG_ARG_NOT_FOUND, "port");
1230                         return;
1231                 }
1232
1233                 if (parser_read_uint32(&port_id, tokens[5]) != 0) {
1234                         printf(CMD_MSG_INVALID_ARG, "portid");
1235                         return;
1236                 }
1237
1238                 if (strcmp(tokens[6], "id") != 0) {
1239                         printf(CMD_MSG_ARG_NOT_FOUND, "id");
1240                         return;
1241                 }
1242
1243                 if (parser_read_uint32(&flow_id, tokens[7]) != 0) {
1244                         printf(CMD_MSG_INVALID_ARG, "flowid");
1245                         return;
1246                 }
1247
1248                 key.type = FLOW_KEY_QINQ;
1249                 key.key.qinq.svlan = svlan;
1250                 key.key.qinq.cvlan = cvlan;
1251
1252                 status = app_pipeline_fc_add(app,
1253                         results->pipeline_id,
1254                         &key,
1255                         port_id,
1256                         flow_id);
1257                 if (status)
1258                         printf(CMD_MSG_FAIL, "flow add qinq");
1259
1260                 return;
1261         } /* flow add qinq */
1262
1263         /* flow add ipv4 */
1264         if ((n_tokens >= 3) &&
1265                 (strcmp(tokens[0], "add") == 0) &&
1266                 (strcmp(tokens[1], "ipv4") == 0) &&
1267                 strcmp(tokens[2], "bulk")) {
1268                 struct pipeline_fc_key key;
1269                 struct in_addr sipaddr;
1270                 struct in_addr dipaddr;
1271                 uint32_t sport;
1272                 uint32_t dport;
1273                 uint32_t proto;
1274                 uint32_t port_id;
1275                 uint32_t flow_id;
1276
1277                 memset(&key, 0, sizeof(key));
1278
1279                 if (n_tokens != 11) {
1280                         printf(CMD_MSG_MISMATCH_ARGS, "flow add ipv4");
1281                         return;
1282                 }
1283
1284                 if (parse_ipv4_addr(tokens[2], &sipaddr) != 0) {
1285                         printf(CMD_MSG_INVALID_ARG, "sipv4addr");
1286                         return;
1287                 }
1288                 if (parse_ipv4_addr(tokens[3], &dipaddr) != 0) {
1289                         printf(CMD_MSG_INVALID_ARG, "dipv4addr");
1290                         return;
1291                 }
1292
1293                 if (parser_read_uint32(&sport, tokens[4]) != 0) {
1294                         printf(CMD_MSG_INVALID_ARG, "sport");
1295                         return;
1296                 }
1297
1298                 if (parser_read_uint32(&dport, tokens[5]) != 0) {
1299                         printf(CMD_MSG_INVALID_ARG, "dport");
1300                         return;
1301                 }
1302
1303                 if (parser_read_uint32(&proto, tokens[6]) != 0) {
1304                         printf(CMD_MSG_INVALID_ARG, "proto");
1305                         return;
1306                 }
1307
1308                 if (strcmp(tokens[7], "port") != 0) {
1309                         printf(CMD_MSG_ARG_NOT_FOUND, "port");
1310                         return;
1311                 }
1312
1313                 if (parser_read_uint32(&port_id, tokens[8]) != 0) {
1314                         printf(CMD_MSG_INVALID_ARG, "portid");
1315                         return;
1316                 }
1317
1318                 if (strcmp(tokens[9], "id") != 0) {
1319                         printf(CMD_MSG_ARG_NOT_FOUND, "id");
1320                         return;
1321                 }
1322
1323                 if (parser_read_uint32(&flow_id, tokens[10]) != 0) {
1324                         printf(CMD_MSG_INVALID_ARG, "flowid");
1325                         return;
1326                 }
1327
1328                 key.type = FLOW_KEY_IPV4_5TUPLE;
1329                 key.key.ipv4_5tuple.ip_src = rte_be_to_cpu_32(sipaddr.s_addr);
1330                 key.key.ipv4_5tuple.ip_dst = rte_be_to_cpu_32(dipaddr.s_addr);
1331                 key.key.ipv4_5tuple.port_src = sport;
1332                 key.key.ipv4_5tuple.port_dst = dport;
1333                 key.key.ipv4_5tuple.proto = proto;
1334
1335                 status = app_pipeline_fc_add(app,
1336                         results->pipeline_id,
1337                         &key,
1338                         port_id,
1339                         flow_id);
1340                 if (status)
1341                         printf(CMD_MSG_FAIL, "flow add ipv4");
1342
1343                 return;
1344         } /* flow add ipv4 */
1345
1346         /* flow add ipv6 */
1347         if ((n_tokens >= 3) &&
1348                 (strcmp(tokens[0], "add") == 0) &&
1349                 (strcmp(tokens[1], "ipv6") == 0) &&
1350                 strcmp(tokens[2], "bulk")) {
1351                 struct pipeline_fc_key key;
1352                 struct in6_addr sipaddr;
1353                 struct in6_addr dipaddr;
1354                 uint32_t sport;
1355                 uint32_t dport;
1356                 uint32_t proto;
1357                 uint32_t port_id;
1358                 uint32_t flow_id;
1359
1360                 memset(&key, 0, sizeof(key));
1361
1362                 if (n_tokens != 11) {
1363                         printf(CMD_MSG_MISMATCH_ARGS, "flow add ipv6");
1364                         return;
1365                 }
1366
1367                 if (parse_ipv6_addr(tokens[2], &sipaddr) != 0) {
1368                         printf(CMD_MSG_INVALID_ARG, "sipv6addr");
1369                         return;
1370                 }
1371                 if (parse_ipv6_addr(tokens[3], &dipaddr) != 0) {
1372                         printf(CMD_MSG_INVALID_ARG, "dipv6addr");
1373                         return;
1374                 }
1375
1376                 if (parser_read_uint32(&sport, tokens[4]) != 0) {
1377                         printf(CMD_MSG_INVALID_ARG, "sport");
1378                         return;
1379                 }
1380
1381                 if (parser_read_uint32(&dport, tokens[5]) != 0) {
1382                         printf(CMD_MSG_INVALID_ARG, "dport");
1383                         return;
1384                 }
1385
1386                 if (parser_read_uint32(&proto, tokens[6]) != 0) {
1387                         printf(CMD_MSG_INVALID_ARG, "proto");
1388                         return;
1389                 }
1390
1391                 if (strcmp(tokens[7], "port") != 0) {
1392                         printf(CMD_MSG_ARG_NOT_FOUND, "port");
1393                         return;
1394                 }
1395
1396                 if (parser_read_uint32(&port_id, tokens[8]) != 0) {
1397                         printf(CMD_MSG_INVALID_ARG, "portid");
1398                         return;
1399                 }
1400
1401                 if (strcmp(tokens[9], "id") != 0) {
1402                         printf(CMD_MSG_ARG_NOT_FOUND, "id");
1403                         return;
1404                 }
1405
1406                 if (parser_read_uint32(&flow_id, tokens[10]) != 0) {
1407                         printf(CMD_MSG_INVALID_ARG, "flowid");
1408                         return;
1409                 }
1410
1411                 key.type = FLOW_KEY_IPV6_5TUPLE;
1412                 memcpy(key.key.ipv6_5tuple.ip_src, (void *)&sipaddr, 16);
1413                 memcpy(key.key.ipv6_5tuple.ip_dst, (void *)&dipaddr, 16);
1414                 key.key.ipv6_5tuple.port_src = sport;
1415                 key.key.ipv6_5tuple.port_dst = dport;
1416                 key.key.ipv6_5tuple.proto = proto;
1417
1418                 status = app_pipeline_fc_add(app,
1419                         results->pipeline_id,
1420                         &key,
1421                         port_id,
1422                         flow_id);
1423                 if (status)
1424                         printf(CMD_MSG_FAIL, "flow add ipv6");
1425
1426                 return;
1427         } /* flow add ipv6 */
1428
1429         /* flow add qinq bulk */
1430         if ((n_tokens >= 3) &&
1431                 (strcmp(tokens[0], "add") == 0) &&
1432                 (strcmp(tokens[1], "qinq") == 0) &&
1433                 (strcmp(tokens[2], "bulk") == 0)) {
1434                 struct pipeline_fc_key *keys;
1435                 uint32_t *port_ids, *flow_ids, n_keys, line;
1436                 char *filename;
1437
1438                 if (n_tokens != 4) {
1439                         printf(CMD_MSG_MISMATCH_ARGS, "flow add qinq bulk");
1440                         return;
1441                 }
1442
1443                 filename = tokens[3];
1444
1445                 n_keys = APP_PIPELINE_FC_MAX_FLOWS_IN_FILE;
1446                 keys = malloc(n_keys * sizeof(struct pipeline_fc_key));
1447                 if (keys == NULL)
1448                         return;
1449                 memset(keys, 0, n_keys * sizeof(struct pipeline_fc_key));
1450
1451                 port_ids = malloc(n_keys * sizeof(uint32_t));
1452                 if (port_ids == NULL) {
1453                         free(keys);
1454                         return;
1455                 }
1456
1457                 flow_ids = malloc(n_keys * sizeof(uint32_t));
1458                 if (flow_ids == NULL) {
1459                         free(port_ids);
1460                         free(keys);
1461                         return;
1462                 }
1463
1464                 status = app_pipeline_fc_load_file_qinq(filename,
1465                         keys,
1466                         port_ids,
1467                         flow_ids,
1468                         &n_keys,
1469                         &line);
1470                 if (status != 0) {
1471                         printf(CMD_MSG_FILE_ERR, filename, line);
1472                         free(flow_ids);
1473                         free(port_ids);
1474                         free(keys);
1475                         return;
1476                 }
1477
1478                 status = app_pipeline_fc_add_bulk(app,
1479                         results->pipeline_id,
1480                         keys,
1481                         port_ids,
1482                         flow_ids,
1483                         n_keys);
1484                 if (status)
1485                         printf(CMD_MSG_FAIL, "flow add qinq bulk");
1486
1487                 free(flow_ids);
1488                 free(port_ids);
1489                 free(keys);
1490                 return;
1491         } /* flow add qinq bulk */
1492
1493         /* flow add ipv4 bulk */
1494         if ((n_tokens >= 3) &&
1495                 (strcmp(tokens[0], "add") == 0) &&
1496                 (strcmp(tokens[1], "ipv4") == 0) &&
1497                 (strcmp(tokens[2], "bulk") == 0)) {
1498                 struct pipeline_fc_key *keys;
1499                 uint32_t *port_ids, *flow_ids, n_keys, line;
1500                 char *filename;
1501
1502                 if (n_tokens != 4) {
1503                         printf(CMD_MSG_MISMATCH_ARGS, "flow add ipv4 bulk");
1504                         return;
1505                 }
1506
1507                 filename = tokens[3];
1508
1509                 n_keys = APP_PIPELINE_FC_MAX_FLOWS_IN_FILE;
1510                 keys = malloc(n_keys * sizeof(struct pipeline_fc_key));
1511                 if (keys == NULL)
1512                         return;
1513                 memset(keys, 0, n_keys * sizeof(struct pipeline_fc_key));
1514
1515                 port_ids = malloc(n_keys * sizeof(uint32_t));
1516                 if (port_ids == NULL) {
1517                         free(keys);
1518                         return;
1519                 }
1520
1521                 flow_ids = malloc(n_keys * sizeof(uint32_t));
1522                 if (flow_ids == NULL) {
1523                         free(port_ids);
1524                         free(keys);
1525                         return;
1526                 }
1527
1528                 status = app_pipeline_fc_load_file_ipv4(filename,
1529                         keys,
1530                         port_ids,
1531                         flow_ids,
1532                         &n_keys,
1533                         &line);
1534                 if (status != 0) {
1535                         printf(CMD_MSG_FILE_ERR, filename, line);
1536                         free(flow_ids);
1537                         free(port_ids);
1538                         free(keys);
1539                         return;
1540                 }
1541
1542                 status = app_pipeline_fc_add_bulk(app,
1543                         results->pipeline_id,
1544                         keys,
1545                         port_ids,
1546                         flow_ids,
1547                         n_keys);
1548                 if (status)
1549                         printf(CMD_MSG_FAIL, "flow add ipv4 bulk");
1550
1551                 free(flow_ids);
1552                 free(port_ids);
1553                 free(keys);
1554                 return;
1555         } /* flow add ipv4 bulk */
1556
1557         /* flow add ipv6 bulk */
1558         if ((n_tokens >= 3) &&
1559                 (strcmp(tokens[0], "add") == 0) &&
1560                 (strcmp(tokens[1], "ipv6") == 0) &&
1561                 (strcmp(tokens[2], "bulk") == 0)) {
1562                 struct pipeline_fc_key *keys;
1563                 uint32_t *port_ids, *flow_ids, n_keys, line;
1564                 char *filename;
1565
1566                 if (n_tokens != 4) {
1567                         printf(CMD_MSG_MISMATCH_ARGS, "flow add ipv6 bulk");
1568                         return;
1569                 }
1570
1571                 filename = tokens[3];
1572
1573                 n_keys = APP_PIPELINE_FC_MAX_FLOWS_IN_FILE;
1574                 keys = malloc(n_keys * sizeof(struct pipeline_fc_key));
1575                 if (keys == NULL)
1576                         return;
1577                 memset(keys, 0, n_keys * sizeof(struct pipeline_fc_key));
1578
1579                 port_ids = malloc(n_keys * sizeof(uint32_t));
1580                 if (port_ids == NULL) {
1581                         free(keys);
1582                         return;
1583                 }
1584
1585                 flow_ids = malloc(n_keys * sizeof(uint32_t));
1586                 if (flow_ids == NULL) {
1587                         free(port_ids);
1588                         free(keys);
1589                         return;
1590                 }
1591
1592                 status = app_pipeline_fc_load_file_ipv6(filename,
1593                         keys,
1594                         port_ids,
1595                         flow_ids,
1596                         &n_keys,
1597                         &line);
1598                 if (status != 0) {
1599                         printf(CMD_MSG_FILE_ERR, filename, line);
1600                         free(flow_ids);
1601                         free(port_ids);
1602                         free(keys);
1603                         return;
1604                 }
1605
1606                 status = app_pipeline_fc_add_bulk(app,
1607                         results->pipeline_id,
1608                         keys,
1609                         port_ids,
1610                         flow_ids,
1611                         n_keys);
1612                 if (status)
1613                         printf(CMD_MSG_FAIL, "flow add ipv6 bulk");
1614
1615                 free(flow_ids);
1616                 free(port_ids);
1617                 free(keys);
1618                 return;
1619         } /* flow add ipv6 bulk */
1620
1621         /* flow add default*/
1622         if ((n_tokens >= 2) &&
1623                 (strcmp(tokens[0], "add") == 0) &&
1624                 (strcmp(tokens[1], "default") == 0)) {
1625                 uint32_t port_id;
1626
1627                 if (n_tokens != 3) {
1628                         printf(CMD_MSG_MISMATCH_ARGS, "flow add default");
1629                         return;
1630                 }
1631
1632                 if (parser_read_uint32(&port_id, tokens[2]) != 0) {
1633                         printf(CMD_MSG_INVALID_ARG, "portid");
1634                         return;
1635                 }
1636
1637                 status = app_pipeline_fc_add_default(app,
1638                         results->pipeline_id,
1639                         port_id);
1640                 if (status)
1641                         printf(CMD_MSG_FAIL, "flow add default");
1642
1643                 return;
1644         } /* flow add default */
1645
1646         /* flow del qinq */
1647         if ((n_tokens >= 2) &&
1648                 (strcmp(tokens[0], "del") == 0) &&
1649                 (strcmp(tokens[1], "qinq") == 0)) {
1650                 struct pipeline_fc_key key;
1651                 uint32_t svlan;
1652                 uint32_t cvlan;
1653
1654                 memset(&key, 0, sizeof(key));
1655
1656                 if (n_tokens != 4) {
1657                         printf(CMD_MSG_MISMATCH_ARGS, "flow del qinq");
1658                         return;
1659                 }
1660
1661                 if (parser_read_uint32(&svlan, tokens[2]) != 0) {
1662                         printf(CMD_MSG_INVALID_ARG, "svlan");
1663                         return;
1664                 }
1665
1666                 if (parser_read_uint32(&cvlan, tokens[3]) != 0) {
1667                         printf(CMD_MSG_INVALID_ARG, "cvlan");
1668                         return;
1669                 }
1670
1671                 key.type = FLOW_KEY_QINQ;
1672                 key.key.qinq.svlan = svlan;
1673                 key.key.qinq.cvlan = cvlan;
1674
1675                 status = app_pipeline_fc_del(app,
1676                         results->pipeline_id,
1677                         &key);
1678                 if (status)
1679                         printf(CMD_MSG_FAIL, "flow del qinq");
1680
1681                 return;
1682         } /* flow del qinq */
1683
1684         /* flow del ipv4 */
1685         if ((n_tokens >= 2) &&
1686                 (strcmp(tokens[0], "del") == 0) &&
1687                 (strcmp(tokens[1], "ipv4") == 0)) {
1688                 struct pipeline_fc_key key;
1689                 struct in_addr sipaddr;
1690                 struct in_addr dipaddr;
1691                 uint32_t sport;
1692                 uint32_t dport;
1693                 uint32_t proto;
1694
1695                 memset(&key, 0, sizeof(key));
1696
1697                 if (n_tokens != 7) {
1698                         printf(CMD_MSG_MISMATCH_ARGS, "flow del ipv4");
1699                         return;
1700                 }
1701
1702                 if (parse_ipv4_addr(tokens[2], &sipaddr) != 0) {
1703                         printf(CMD_MSG_INVALID_ARG, "sipv4addr");
1704                         return;
1705                 }
1706                 if (parse_ipv4_addr(tokens[3], &dipaddr) != 0) {
1707                         printf(CMD_MSG_INVALID_ARG, "dipv4addr");
1708                         return;
1709                 }
1710
1711                 if (parser_read_uint32(&sport, tokens[4]) != 0) {
1712                         printf(CMD_MSG_INVALID_ARG, "sport");
1713                         return;
1714                 }
1715
1716                 if (parser_read_uint32(&dport, tokens[5]) != 0) {
1717                         printf(CMD_MSG_INVALID_ARG, "dport");
1718                         return;
1719                 }
1720
1721                 if (parser_read_uint32(&proto, tokens[6]) != 0) {
1722                         printf(CMD_MSG_INVALID_ARG, "proto");
1723                         return;
1724                 }
1725
1726                 key.type = FLOW_KEY_IPV4_5TUPLE;
1727                 key.key.ipv4_5tuple.ip_src = rte_be_to_cpu_32(sipaddr.s_addr);
1728                 key.key.ipv4_5tuple.ip_dst = rte_be_to_cpu_32(dipaddr.s_addr);
1729                 key.key.ipv4_5tuple.port_src = sport;
1730                 key.key.ipv4_5tuple.port_dst = dport;
1731                 key.key.ipv4_5tuple.proto = proto;
1732
1733                 status = app_pipeline_fc_del(app,
1734                         results->pipeline_id,
1735                         &key);
1736                 if (status)
1737                         printf(CMD_MSG_FAIL, "flow del ipv4");
1738
1739                 return;
1740         } /* flow del ipv4 */
1741
1742         /* flow del ipv6 */
1743         if ((n_tokens >= 2) &&
1744                 (strcmp(tokens[0], "del") == 0) &&
1745                 (strcmp(tokens[1], "ipv6") == 0)) {
1746                 struct pipeline_fc_key key;
1747                 struct in6_addr sipaddr;
1748                 struct in6_addr dipaddr;
1749                 uint32_t sport;
1750                 uint32_t dport;
1751                 uint32_t proto;
1752
1753                 memset(&key, 0, sizeof(key));
1754
1755                 if (n_tokens != 7) {
1756                         printf(CMD_MSG_MISMATCH_ARGS, "flow del ipv6");
1757                         return;
1758                 }
1759
1760                 if (parse_ipv6_addr(tokens[2], &sipaddr) != 0) {
1761                         printf(CMD_MSG_INVALID_ARG, "sipv6addr");
1762                         return;
1763                 }
1764
1765                 if (parse_ipv6_addr(tokens[3], &dipaddr) != 0) {
1766                         printf(CMD_MSG_INVALID_ARG, "dipv6addr");
1767                         return;
1768                 }
1769
1770                 if (parser_read_uint32(&sport, tokens[4]) != 0) {
1771                         printf(CMD_MSG_INVALID_ARG, "sport");
1772                         return;
1773                 }
1774
1775                 if (parser_read_uint32(&dport, tokens[5]) != 0) {
1776                         printf(CMD_MSG_INVALID_ARG, "dport");
1777                         return;
1778                 }
1779
1780                 if (parser_read_uint32(&proto, tokens[6]) != 0) {
1781                         printf(CMD_MSG_INVALID_ARG, "proto");
1782                         return;
1783                 }
1784
1785                 key.type = FLOW_KEY_IPV6_5TUPLE;
1786                 memcpy(key.key.ipv6_5tuple.ip_src, &sipaddr, 16);
1787                 memcpy(key.key.ipv6_5tuple.ip_dst, &dipaddr, 16);
1788                 key.key.ipv6_5tuple.port_src = sport;
1789                 key.key.ipv6_5tuple.port_dst = dport;
1790                 key.key.ipv6_5tuple.proto = proto;
1791
1792                 status = app_pipeline_fc_del(app,
1793                         results->pipeline_id,
1794                         &key);
1795                 if (status)
1796                         printf(CMD_MSG_FAIL, "flow del ipv6");
1797
1798                 return;
1799         } /* flow del ipv6 */
1800
1801         /* flow del default*/
1802         if ((n_tokens >= 2) &&
1803                 (strcmp(tokens[0], "del") == 0) &&
1804                 (strcmp(tokens[1], "default") == 0)) {
1805                 if (n_tokens != 2) {
1806                         printf(CMD_MSG_MISMATCH_ARGS, "flow del default");
1807                         return;
1808                 }
1809
1810                 status = app_pipeline_fc_del_default(app,
1811                         results->pipeline_id);
1812                 if (status)
1813                         printf(CMD_MSG_FAIL, "flow del default");
1814
1815                 return;
1816         } /* flow del default */
1817
1818         /* flow ls */
1819         if ((n_tokens >= 1) && (strcmp(tokens[0], "ls") == 0)) {
1820                 if (n_tokens != 1) {
1821                         printf(CMD_MSG_MISMATCH_ARGS, "flow ls");
1822                         return;
1823                 }
1824
1825                 status = app_pipeline_fc_ls(app, results->pipeline_id);
1826                 if (status)
1827                         printf(CMD_MSG_FAIL, "flow ls");
1828
1829                 return;
1830         } /* flow ls */
1831
1832         printf(CMD_MSG_MISMATCH_ARGS, "flow");
1833 }
1834
1835 static cmdline_parse_token_string_t cmd_flow_p_string =
1836         TOKEN_STRING_INITIALIZER(struct cmd_flow_result, p_string, "p");
1837
1838 static cmdline_parse_token_num_t cmd_flow_pipeline_id =
1839         TOKEN_NUM_INITIALIZER(struct cmd_flow_result, pipeline_id, UINT32);
1840
1841 static cmdline_parse_token_string_t cmd_flow_flow_string =
1842         TOKEN_STRING_INITIALIZER(struct cmd_flow_result, flow_string, "flow");
1843
1844 static cmdline_parse_token_string_t cmd_flow_multi_string =
1845         TOKEN_STRING_INITIALIZER(struct cmd_flow_result, multi_string,
1846                 TOKEN_STRING_MULTI);
1847
1848 static cmdline_parse_inst_t cmd_flow = {
1849         .f = cmd_flow_parsed,
1850         .data = NULL,
1851         .help_str = "flow add / add bulk / add default / del / del default / ls",
1852         .tokens = {
1853                 (void *) &cmd_flow_p_string,
1854                 (void *) &cmd_flow_pipeline_id,
1855                 (void *) &cmd_flow_flow_string,
1856                 (void *) &cmd_flow_multi_string,
1857                 NULL,
1858         },
1859 };
1860
1861 static cmdline_parse_ctx_t pipeline_cmds[] = {
1862         (cmdline_parse_inst_t *) &cmd_flow,
1863         NULL,
1864 };
1865
1866 static struct pipeline_fe_ops pipeline_flow_classification_fe_ops = {
1867         .f_init = app_pipeline_fc_init,
1868         .f_post_init = NULL,
1869         .f_free = app_pipeline_fc_free,
1870         .f_track = app_pipeline_track_default,
1871         .cmds = pipeline_cmds,
1872 };
1873
1874 struct pipeline_type pipeline_flow_classification = {
1875         .name = "FLOW_CLASSIFICATION",
1876         .be_ops = &pipeline_flow_classification_be_ops,
1877         .fe_ops = &pipeline_flow_classification_fe_ops,
1878 };