]> git.proxmox.com Git - ceph.git/blame - ceph/src/dpdk/examples/ip_pipeline/pipeline/pipeline_flow_classification.c
bump version to 12.2.12-pve1
[ceph.git] / ceph / src / dpdk / examples / ip_pipeline / pipeline / pipeline_flow_classification.c
CommitLineData
7c673cae
FG
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
58struct 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
65struct 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
75struct 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
85static int
86app_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
152struct 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
164struct 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
179static struct app_pipeline_fc_flow *
180app_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
199static void*
200app_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
229static int
230app_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
253static int
254app_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
280int
281app_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
359error1:
360 *line = l;
361 fclose(f);
362 return -1;
363}
364
365int
366app_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
452error2:
453 *line = l;
454 fclose(f);
455 return -1;
456}
457
458int
459app_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
549error3:
550 *line = l;
551 fclose(f);
552 return -1;
553}
554
555
556
557int
558app_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
649int
650app_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
850int
851app_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
912int
913app_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
965int
966app_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
1014static void
1015print_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
1032static void
1033print_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
1066static void
1067print_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
1129static void
1130print_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
1147static int
1148app_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
1202struct 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
1209static void
1210cmd_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
1862static cmdline_parse_token_string_t cmd_flow_p_string =
1863 TOKEN_STRING_INITIALIZER(struct cmd_flow_result, p_string, "p");
1864
1865static cmdline_parse_token_num_t cmd_flow_pipeline_id =
1866 TOKEN_NUM_INITIALIZER(struct cmd_flow_result, pipeline_id, UINT32);
1867
1868static cmdline_parse_token_string_t cmd_flow_flow_string =
1869 TOKEN_STRING_INITIALIZER(struct cmd_flow_result, flow_string, "flow");
1870
1871static cmdline_parse_token_string_t cmd_flow_multi_string =
1872 TOKEN_STRING_INITIALIZER(struct cmd_flow_result, multi_string,
1873 TOKEN_STRING_MULTI);
1874
1875static 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
1888static cmdline_parse_ctx_t pipeline_cmds[] = {
1889 (cmdline_parse_inst_t *) &cmd_flow,
1890 NULL,
1891};
1892
1893static 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
1901struct 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};