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