4 * Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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.
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.
36 #include <sys/queue.h>
37 #include <netinet/in.h>
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>
49 #include "pipeline_common_fe.h"
50 #include "pipeline_flow_classification.h"
51 #include "hash_func.h"
59 uint16_t ethertype_svlan;
61 uint16_t ethertype_cvlan;
63 } __attribute__((__packed__));
65 struct pkt_key_ipv4_5tuple {
73 } __attribute__((__packed__));
75 struct pkt_key_ipv6_5tuple {
76 uint16_t payload_length;
83 } __attribute__((__packed__));
86 app_pipeline_fc_key_convert(struct pipeline_fc_key *key_in,
90 uint8_t buffer[PIPELINE_FC_FLOW_KEY_MAX_SIZE];
91 void *key_buffer = (key_out) ? key_out : buffer;
93 switch (key_in->type) {
96 struct pkt_key_qinq *qinq = key_buffer;
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);
104 *signature = (uint32_t) hash_default_key8(qinq, 8, 0);
108 case FLOW_KEY_IPV4_5TUPLE:
110 struct pkt_key_ipv4_5tuple *ipv4 = key_buffer;
113 ipv4->proto = key_in->key.ipv4_5tuple.proto;
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);
121 *signature = (uint32_t) hash_default_key16(ipv4, 16, 0);
125 case FLOW_KEY_IPV6_5TUPLE:
127 struct pkt_key_ipv6_5tuple *ipv6 = key_buffer;
130 ipv6->payload_length = 0;
131 ipv6->proto = key_in->key.ipv6_5tuple.proto;
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);
139 *signature = (uint32_t) hash_default_key64(ipv6, 64, 0);
149 * Flow classification pipeline
152 struct app_pipeline_fc_flow {
153 struct pipeline_fc_key key;
159 TAILQ_ENTRY(app_pipeline_fc_flow) node;
162 #define N_BUCKETS 65536
164 struct app_pipeline_fc {
167 uint32_t n_ports_out;
170 TAILQ_HEAD(, app_pipeline_fc_flow) flows[N_BUCKETS];
174 uint32_t default_flow_present;
175 uint32_t default_flow_port_id;
176 void *default_flow_entry_ptr;
179 static struct app_pipeline_fc_flow *
180 app_pipeline_fc_flow_find(struct app_pipeline_fc *p,
181 struct pipeline_fc_key *key)
183 struct app_pipeline_fc_flow *f;
184 uint32_t signature, bucket_id;
186 app_pipeline_fc_key_convert(key, NULL, &signature);
187 bucket_id = signature & (N_BUCKETS - 1);
189 TAILQ_FOREACH(f, &p->flows[bucket_id], node)
190 if ((signature == f->signature) &&
193 sizeof(struct pipeline_fc_key)) == 0))
200 app_pipeline_fc_init(struct pipeline_params *params,
201 __rte_unused void *arg)
203 struct app_pipeline_fc *p;
206 /* Check input arguments */
207 if ((params == NULL) ||
208 (params->n_ports_in == 0) ||
209 (params->n_ports_out == 0))
212 /* Memory allocation */
213 size = RTE_CACHE_LINE_ROUNDUP(sizeof(struct app_pipeline_fc));
214 p = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
219 p->n_ports_in = params->n_ports_in;
220 p->n_ports_out = params->n_ports_out;
222 for (i = 0; i < N_BUCKETS; i++)
223 TAILQ_INIT(&p->flows[i]);
230 app_pipeline_fc_free(void *pipeline)
232 struct app_pipeline_fc *p = pipeline;
235 /* Check input arguments */
240 for (i = 0; i < N_BUCKETS; i++)
241 while (!TAILQ_EMPTY(&p->flows[i])) {
242 struct app_pipeline_fc_flow *flow;
244 flow = TAILQ_FIRST(&p->flows[i]);
245 TAILQ_REMOVE(&p->flows[i], flow, node);
254 app_pipeline_fc_key_check(struct pipeline_fc_key *key)
259 uint16_t svlan = key->key.qinq.svlan;
260 uint16_t cvlan = key->key.qinq.cvlan;
262 if ((svlan & 0xF000) ||
269 case FLOW_KEY_IPV4_5TUPLE:
272 case FLOW_KEY_IPV6_5TUPLE:
281 app_pipeline_fc_load_file_qinq(char *filename,
282 struct pipeline_fc_key *keys,
292 /* Check input arguments */
293 if ((filename == NULL) ||
295 (port_ids == NULL) ||
296 (flow_ids == NULL) ||
305 /* Open input file */
306 f = fopen(filename, "r");
313 for (i = 0, l = 1; i < *n_keys; l++) {
315 uint32_t n_tokens = RTE_DIM(tokens);
317 uint16_t svlan, cvlan;
318 uint32_t portid, flowid;
321 if (fgets(file_buf, sizeof(file_buf), f) == NULL)
324 status = parse_tokenize_string(file_buf, tokens, &n_tokens);
328 if ((n_tokens == 0) || (tokens[0][0] == '#'))
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]))
341 keys[i].type = FLOW_KEY_QINQ;
342 keys[i].key.qinq.svlan = svlan;
343 keys[i].key.qinq.cvlan = cvlan;
345 port_ids[i] = portid;
346 flow_ids[i] = flowid;
348 if (app_pipeline_fc_key_check(&keys[i]))
366 app_pipeline_fc_load_file_ipv4(char *filename,
367 struct pipeline_fc_key *keys,
377 /* Check input arguments */
378 if ((filename == NULL) ||
380 (port_ids == NULL) ||
381 (flow_ids == NULL) ||
390 /* Open input file */
391 f = fopen(filename, "r");
398 for (i = 0, l = 1; i < *n_keys; l++) {
400 uint32_t n_tokens = RTE_DIM(tokens);
402 struct in_addr sipaddr, dipaddr;
403 uint16_t sport, dport;
405 uint32_t portid, flowid;
408 if (fgets(file_buf, sizeof(file_buf), f) == NULL)
411 status = parse_tokenize_string(file_buf, tokens, &n_tokens);
415 if ((n_tokens == 0) || (tokens[0][0] == '#'))
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]))
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;
438 port_ids[i] = portid;
439 flow_ids[i] = flowid;
441 if (app_pipeline_fc_key_check(&keys[i]))
459 app_pipeline_fc_load_file_ipv6(char *filename,
460 struct pipeline_fc_key *keys,
470 /* Check input arguments */
471 if ((filename == NULL) ||
473 (port_ids == NULL) ||
474 (flow_ids == NULL) ||
483 /* Open input file */
484 f = fopen(filename, "r");
491 for (i = 0, l = 1; i < *n_keys; l++) {
493 uint32_t n_tokens = RTE_DIM(tokens);
495 struct in6_addr sipaddr, dipaddr;
496 uint16_t sport, dport;
498 uint32_t portid, flowid;
501 if (fgets(file_buf, sizeof(file_buf), f) == NULL)
504 status = parse_tokenize_string(file_buf, tokens, &n_tokens);
508 if ((n_tokens == 0) || (tokens[0][0] == '#'))
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]))
524 keys[i].type = FLOW_KEY_IPV6_5TUPLE;
525 memcpy(keys[i].key.ipv6_5tuple.ip_src,
527 sizeof(sipaddr.s6_addr));
528 memcpy(keys[i].key.ipv6_5tuple.ip_dst,
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;
535 port_ids[i] = portid;
536 flow_ids[i] = flowid;
538 if (app_pipeline_fc_key_check(&keys[i]))
558 app_pipeline_fc_add(struct app_params *app,
559 uint32_t pipeline_id,
560 struct pipeline_fc_key *key,
564 struct app_pipeline_fc *p;
565 struct app_pipeline_fc_flow *flow;
567 struct pipeline_fc_add_msg_req *req;
568 struct pipeline_fc_add_msg_rsp *rsp;
573 /* Check input arguments */
578 p = app_pipeline_data_fe(app, pipeline_id, &pipeline_flow_classification);
582 if (port_id >= p->n_ports_out)
585 if (app_pipeline_fc_key_check(key) != 0)
588 /* Find existing flow or allocate new flow */
589 flow = app_pipeline_fc_flow_find(p, key);
590 new_flow = (flow == NULL);
592 flow = rte_malloc(NULL, sizeof(*flow), RTE_CACHE_LINE_SIZE);
598 /* Allocate and write request */
599 req = app_msg_alloc(app);
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;
609 /* Send request and wait for response */
610 rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
617 /* Read response and write flow */
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);
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;
637 uint32_t bucket_id = signature & (N_BUCKETS - 1);
639 TAILQ_INSERT_TAIL(&p->flows[bucket_id], flow, node);
644 app_msg_free(app, rsp);
650 app_pipeline_fc_add_bulk(struct app_params *app,
651 uint32_t pipeline_id,
652 struct pipeline_fc_key *key,
657 struct app_pipeline_fc *p;
658 struct pipeline_fc_add_bulk_msg_req *req;
659 struct pipeline_fc_add_bulk_msg_rsp *rsp;
661 struct app_pipeline_fc_flow **flow;
664 struct pipeline_fc_add_bulk_flow_req *flow_req;
665 struct pipeline_fc_add_bulk_flow_rsp *flow_rsp;
670 /* Check input arguments */
678 p = app_pipeline_data_fe(app, pipeline_id, &pipeline_flow_classification);
682 for (i = 0; i < n_keys; i++)
683 if (port_id[i] >= p->n_ports_out)
686 for (i = 0; i < n_keys; i++)
687 if (app_pipeline_fc_key_check(&key[i]) != 0)
690 /* Memory allocation */
691 flow = rte_malloc(NULL,
692 n_keys * sizeof(struct app_pipeline_fc_flow *),
693 RTE_CACHE_LINE_SIZE);
697 signature = rte_malloc(NULL,
698 n_keys * sizeof(uint32_t),
699 RTE_CACHE_LINE_SIZE);
700 if (signature == NULL) {
705 new_flow = rte_malloc(
707 n_keys * sizeof(int),
708 RTE_CACHE_LINE_SIZE);
709 if (new_flow == NULL) {
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) {
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) {
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);
745 if (flow[i] == NULL) {
748 for (j = 0; j < i; j++)
762 /* Allocate and write request */
763 req = app_msg_alloc(app);
765 for (i = 0; i < n_keys; i++)
777 for (i = 0; i < n_keys; i++) {
778 app_pipeline_fc_key_convert(&key[i],
781 flow_req[i].port_id = port_id[i];
782 flow_req[i].flow_id = flow_id[i];
785 req->type = PIPELINE_MSG_REQ_CUSTOM;
786 req->subtype = PIPELINE_FC_MSG_REQ_FLOW_ADD_BULK;
789 req->n_keys = n_keys;
791 /* Send request and wait for response */
792 rsp = app_msg_send_recv(app, pipeline_id, req, 10000);
794 for (i = 0; i < n_keys; i++)
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)))
815 if (rsp->n_keys < n_keys)
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;
827 uint32_t bucket_id = signature[i] & (N_BUCKETS - 1);
829 TAILQ_INSERT_TAIL(&p->flows[bucket_id], flow[i], node);
835 app_msg_free(app, rsp);
837 for (i = rsp->n_keys; i < n_keys; i++)
851 app_pipeline_fc_del(struct app_params *app,
852 uint32_t pipeline_id,
853 struct pipeline_fc_key *key)
855 struct app_pipeline_fc *p;
856 struct app_pipeline_fc_flow *flow;
858 struct pipeline_fc_del_msg_req *req;
859 struct pipeline_fc_del_msg_rsp *rsp;
861 uint32_t signature, bucket_id;
863 /* Check input arguments */
868 p = app_pipeline_data_fe(app, pipeline_id, &pipeline_flow_classification);
872 if (app_pipeline_fc_key_check(key) != 0)
876 flow = app_pipeline_fc_flow_find(p, key);
880 /* Allocate and write request */
881 req = app_msg_alloc(app);
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);
889 /* Send request and wait for response */
890 rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
895 if (rsp->status || !rsp->key_found) {
896 app_msg_free(app, rsp);
901 bucket_id = signature & (N_BUCKETS - 1);
902 TAILQ_REMOVE(&p->flows[bucket_id], flow, node);
907 app_msg_free(app, rsp);
913 app_pipeline_fc_add_default(struct app_params *app,
914 uint32_t pipeline_id,
917 struct app_pipeline_fc *p;
919 struct pipeline_fc_add_default_msg_req *req;
920 struct pipeline_fc_add_default_msg_rsp *rsp;
922 /* Check input arguments */
926 p = app_pipeline_data_fe(app, pipeline_id, &pipeline_flow_classification);
930 if (port_id >= p->n_ports_out)
933 /* Allocate and write request */
934 req = app_msg_alloc(app);
938 req->type = PIPELINE_MSG_REQ_CUSTOM;
939 req->subtype = PIPELINE_FC_MSG_REQ_FLOW_ADD_DEFAULT;
940 req->port_id = port_id;
942 /* Send request and wait for response */
943 rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
947 /* Read response and write flow */
948 if (rsp->status || (rsp->entry_ptr == NULL)) {
949 app_msg_free(app, rsp);
953 p->default_flow_port_id = port_id;
954 p->default_flow_entry_ptr = rsp->entry_ptr;
957 p->default_flow_present = 1;
960 app_msg_free(app, rsp);
966 app_pipeline_fc_del_default(struct app_params *app,
967 uint32_t pipeline_id)
969 struct app_pipeline_fc *p;
971 struct pipeline_fc_del_default_msg_req *req;
972 struct pipeline_fc_del_default_msg_rsp *rsp;
974 /* Check input arguments */
978 p = app_pipeline_data_fe(app, pipeline_id, &pipeline_flow_classification);
982 /* Allocate and write request */
983 req = app_msg_alloc(app);
987 req->type = PIPELINE_MSG_REQ_CUSTOM;
988 req->subtype = PIPELINE_FC_MSG_REQ_FLOW_DEL_DEFAULT;
990 /* Send request and wait for response */
991 rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
997 app_msg_free(app, rsp);
1002 p->default_flow_present = 0;
1005 app_msg_free(app, rsp);
1015 print_fc_qinq_flow(struct app_pipeline_fc_flow *flow)
1017 printf("(SVLAN = %" PRIu32 ", "
1018 "CVLAN = %" PRIu32 ") => "
1019 "Port = %" PRIu32 ", "
1020 "Flow ID = %" PRIu32 ", "
1021 "(signature = 0x%08" PRIx32 ", "
1022 "entry_ptr = %p)\n",
1024 flow->key.key.qinq.svlan,
1025 flow->key.key.qinq.cvlan,
1033 print_fc_ipv4_5tuple_flow(struct app_pipeline_fc_flow *flow)
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",
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,
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,
1055 flow->key.key.ipv4_5tuple.port_src,
1056 flow->key.key.ipv4_5tuple.port_dst,
1058 flow->key.key.ipv4_5tuple.proto,
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 ", "
1078 "Proto = %" PRIu32 " "
1079 "=> Port = %" PRIu32 ", "
1080 "Flow ID = %" PRIu32 " "
1081 "(signature = 0x%08" PRIx32 ", "
1082 "entry_ptr = %p)\n",
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],
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],
1118 flow->key.key.ipv6_5tuple.port_src,
1119 flow->key.key.ipv6_5tuple.port_dst,
1121 flow->key.key.ipv6_5tuple.proto,
1130 print_fc_flow(struct app_pipeline_fc_flow *flow)
1132 switch (flow->key.type) {
1134 print_fc_qinq_flow(flow);
1137 case FLOW_KEY_IPV4_5TUPLE:
1138 print_fc_ipv4_5tuple_flow(flow);
1141 case FLOW_KEY_IPV6_5TUPLE:
1142 print_fc_ipv6_5tuple_flow(flow);
1148 app_pipeline_fc_ls(struct app_params *app,
1149 uint32_t pipeline_id)
1151 struct app_pipeline_fc *p;
1152 struct app_pipeline_fc_flow *flow;
1155 /* Check input arguments */
1159 p = app_pipeline_data_fe(app, pipeline_id, &pipeline_flow_classification);
1163 for (i = 0; i < N_BUCKETS; i++)
1164 TAILQ_FOREACH(flow, &p->flows[i], node)
1165 print_fc_flow(flow);
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);
1172 printf("Default: DROP\n");
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>
1188 * p <pipelineid> flow add default <portid>
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>
1196 * p <pipelineid> flow del default
1199 * p <pipelineid> flow ls
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;
1210 cmd_flow_parsed(void *parsed_result,
1211 __attribute__((unused)) struct cmdline *cl,
1214 struct cmd_flow_result *results = parsed_result;
1215 struct app_params *app = data;
1218 uint32_t n_tokens = RTE_DIM(tokens);
1221 status = parse_tokenize_string(results->multi_string, tokens, &n_tokens);
1223 printf(CMD_MSG_TOO_MANY_ARGS, "flow");
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;
1238 memset(&key, 0, sizeof(key));
1240 if (n_tokens != 8) {
1241 printf(CMD_MSG_MISMATCH_ARGS, "flow add qinq");
1245 if (parser_read_uint32(&svlan, tokens[2]) != 0) {
1246 printf(CMD_MSG_INVALID_ARG, "svlan");
1250 if (parser_read_uint32(&cvlan, tokens[3]) != 0) {
1251 printf(CMD_MSG_INVALID_ARG, "cvlan");
1255 if (strcmp(tokens[4], "port") != 0) {
1256 printf(CMD_MSG_ARG_NOT_FOUND, "port");
1260 if (parser_read_uint32(&port_id, tokens[5]) != 0) {
1261 printf(CMD_MSG_INVALID_ARG, "portid");
1265 if (strcmp(tokens[6], "id") != 0) {
1266 printf(CMD_MSG_ARG_NOT_FOUND, "id");
1270 if (parser_read_uint32(&flow_id, tokens[7]) != 0) {
1271 printf(CMD_MSG_INVALID_ARG, "flowid");
1275 key.type = FLOW_KEY_QINQ;
1276 key.key.qinq.svlan = svlan;
1277 key.key.qinq.cvlan = cvlan;
1279 status = app_pipeline_fc_add(app,
1280 results->pipeline_id,
1285 printf(CMD_MSG_FAIL, "flow add qinq");
1288 } /* flow add qinq */
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;
1304 memset(&key, 0, sizeof(key));
1306 if (n_tokens != 11) {
1307 printf(CMD_MSG_MISMATCH_ARGS, "flow add ipv4");
1311 if (parse_ipv4_addr(tokens[2], &sipaddr) != 0) {
1312 printf(CMD_MSG_INVALID_ARG, "sipv4addr");
1315 if (parse_ipv4_addr(tokens[3], &dipaddr) != 0) {
1316 printf(CMD_MSG_INVALID_ARG, "dipv4addr");
1320 if (parser_read_uint32(&sport, tokens[4]) != 0) {
1321 printf(CMD_MSG_INVALID_ARG, "sport");
1325 if (parser_read_uint32(&dport, tokens[5]) != 0) {
1326 printf(CMD_MSG_INVALID_ARG, "dport");
1330 if (parser_read_uint32(&proto, tokens[6]) != 0) {
1331 printf(CMD_MSG_INVALID_ARG, "proto");
1335 if (strcmp(tokens[7], "port") != 0) {
1336 printf(CMD_MSG_ARG_NOT_FOUND, "port");
1340 if (parser_read_uint32(&port_id, tokens[8]) != 0) {
1341 printf(CMD_MSG_INVALID_ARG, "portid");
1345 if (strcmp(tokens[9], "id") != 0) {
1346 printf(CMD_MSG_ARG_NOT_FOUND, "id");
1350 if (parser_read_uint32(&flow_id, tokens[10]) != 0) {
1351 printf(CMD_MSG_INVALID_ARG, "flowid");
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;
1362 status = app_pipeline_fc_add(app,
1363 results->pipeline_id,
1368 printf(CMD_MSG_FAIL, "flow add ipv4");
1371 } /* flow add ipv4 */
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;
1387 memset(&key, 0, sizeof(key));
1389 if (n_tokens != 11) {
1390 printf(CMD_MSG_MISMATCH_ARGS, "flow add ipv6");
1394 if (parse_ipv6_addr(tokens[2], &sipaddr) != 0) {
1395 printf(CMD_MSG_INVALID_ARG, "sipv6addr");
1398 if (parse_ipv6_addr(tokens[3], &dipaddr) != 0) {
1399 printf(CMD_MSG_INVALID_ARG, "dipv6addr");
1403 if (parser_read_uint32(&sport, tokens[4]) != 0) {
1404 printf(CMD_MSG_INVALID_ARG, "sport");
1408 if (parser_read_uint32(&dport, tokens[5]) != 0) {
1409 printf(CMD_MSG_INVALID_ARG, "dport");
1413 if (parser_read_uint32(&proto, tokens[6]) != 0) {
1414 printf(CMD_MSG_INVALID_ARG, "proto");
1418 if (strcmp(tokens[7], "port") != 0) {
1419 printf(CMD_MSG_ARG_NOT_FOUND, "port");
1423 if (parser_read_uint32(&port_id, tokens[8]) != 0) {
1424 printf(CMD_MSG_INVALID_ARG, "portid");
1428 if (strcmp(tokens[9], "id") != 0) {
1429 printf(CMD_MSG_ARG_NOT_FOUND, "id");
1433 if (parser_read_uint32(&flow_id, tokens[10]) != 0) {
1434 printf(CMD_MSG_INVALID_ARG, "flowid");
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;
1445 status = app_pipeline_fc_add(app,
1446 results->pipeline_id,
1451 printf(CMD_MSG_FAIL, "flow add ipv6");
1454 } /* flow add ipv6 */
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;
1465 if (n_tokens != 4) {
1466 printf(CMD_MSG_MISMATCH_ARGS, "flow add qinq bulk");
1470 filename = tokens[3];
1472 n_keys = APP_PIPELINE_FC_MAX_FLOWS_IN_FILE;
1473 keys = malloc(n_keys * sizeof(struct pipeline_fc_key));
1476 memset(keys, 0, n_keys * sizeof(struct pipeline_fc_key));
1478 port_ids = malloc(n_keys * sizeof(uint32_t));
1479 if (port_ids == NULL) {
1484 flow_ids = malloc(n_keys * sizeof(uint32_t));
1485 if (flow_ids == NULL) {
1491 status = app_pipeline_fc_load_file_qinq(filename,
1498 printf(CMD_MSG_FILE_ERR, filename, line);
1505 status = app_pipeline_fc_add_bulk(app,
1506 results->pipeline_id,
1512 printf(CMD_MSG_FAIL, "flow add qinq bulk");
1518 } /* flow add qinq bulk */
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;
1529 if (n_tokens != 4) {
1530 printf(CMD_MSG_MISMATCH_ARGS, "flow add ipv4 bulk");
1534 filename = tokens[3];
1536 n_keys = APP_PIPELINE_FC_MAX_FLOWS_IN_FILE;
1537 keys = malloc(n_keys * sizeof(struct pipeline_fc_key));
1540 memset(keys, 0, n_keys * sizeof(struct pipeline_fc_key));
1542 port_ids = malloc(n_keys * sizeof(uint32_t));
1543 if (port_ids == NULL) {
1548 flow_ids = malloc(n_keys * sizeof(uint32_t));
1549 if (flow_ids == NULL) {
1555 status = app_pipeline_fc_load_file_ipv4(filename,
1562 printf(CMD_MSG_FILE_ERR, filename, line);
1569 status = app_pipeline_fc_add_bulk(app,
1570 results->pipeline_id,
1576 printf(CMD_MSG_FAIL, "flow add ipv4 bulk");
1582 } /* flow add ipv4 bulk */
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;
1593 if (n_tokens != 4) {
1594 printf(CMD_MSG_MISMATCH_ARGS, "flow add ipv6 bulk");
1598 filename = tokens[3];
1600 n_keys = APP_PIPELINE_FC_MAX_FLOWS_IN_FILE;
1601 keys = malloc(n_keys * sizeof(struct pipeline_fc_key));
1604 memset(keys, 0, n_keys * sizeof(struct pipeline_fc_key));
1606 port_ids = malloc(n_keys * sizeof(uint32_t));
1607 if (port_ids == NULL) {
1612 flow_ids = malloc(n_keys * sizeof(uint32_t));
1613 if (flow_ids == NULL) {
1619 status = app_pipeline_fc_load_file_ipv6(filename,
1626 printf(CMD_MSG_FILE_ERR, filename, line);
1633 status = app_pipeline_fc_add_bulk(app,
1634 results->pipeline_id,
1640 printf(CMD_MSG_FAIL, "flow add ipv6 bulk");
1646 } /* flow add ipv6 bulk */
1648 /* flow add default*/
1649 if ((n_tokens >= 2) &&
1650 (strcmp(tokens[0], "add") == 0) &&
1651 (strcmp(tokens[1], "default") == 0)) {
1654 if (n_tokens != 3) {
1655 printf(CMD_MSG_MISMATCH_ARGS, "flow add default");
1659 if (parser_read_uint32(&port_id, tokens[2]) != 0) {
1660 printf(CMD_MSG_INVALID_ARG, "portid");
1664 status = app_pipeline_fc_add_default(app,
1665 results->pipeline_id,
1668 printf(CMD_MSG_FAIL, "flow add default");
1671 } /* flow add default */
1674 if ((n_tokens >= 2) &&
1675 (strcmp(tokens[0], "del") == 0) &&
1676 (strcmp(tokens[1], "qinq") == 0)) {
1677 struct pipeline_fc_key key;
1681 memset(&key, 0, sizeof(key));
1683 if (n_tokens != 4) {
1684 printf(CMD_MSG_MISMATCH_ARGS, "flow del qinq");
1688 if (parser_read_uint32(&svlan, tokens[2]) != 0) {
1689 printf(CMD_MSG_INVALID_ARG, "svlan");
1693 if (parser_read_uint32(&cvlan, tokens[3]) != 0) {
1694 printf(CMD_MSG_INVALID_ARG, "cvlan");
1698 key.type = FLOW_KEY_QINQ;
1699 key.key.qinq.svlan = svlan;
1700 key.key.qinq.cvlan = cvlan;
1702 status = app_pipeline_fc_del(app,
1703 results->pipeline_id,
1706 printf(CMD_MSG_FAIL, "flow del qinq");
1709 } /* flow del qinq */
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;
1722 memset(&key, 0, sizeof(key));
1724 if (n_tokens != 7) {
1725 printf(CMD_MSG_MISMATCH_ARGS, "flow del ipv4");
1729 if (parse_ipv4_addr(tokens[2], &sipaddr) != 0) {
1730 printf(CMD_MSG_INVALID_ARG, "sipv4addr");
1733 if (parse_ipv4_addr(tokens[3], &dipaddr) != 0) {
1734 printf(CMD_MSG_INVALID_ARG, "dipv4addr");
1738 if (parser_read_uint32(&sport, tokens[4]) != 0) {
1739 printf(CMD_MSG_INVALID_ARG, "sport");
1743 if (parser_read_uint32(&dport, tokens[5]) != 0) {
1744 printf(CMD_MSG_INVALID_ARG, "dport");
1748 if (parser_read_uint32(&proto, tokens[6]) != 0) {
1749 printf(CMD_MSG_INVALID_ARG, "proto");
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;
1760 status = app_pipeline_fc_del(app,
1761 results->pipeline_id,
1764 printf(CMD_MSG_FAIL, "flow del ipv4");
1767 } /* flow del ipv4 */
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;
1780 memset(&key, 0, sizeof(key));
1782 if (n_tokens != 7) {
1783 printf(CMD_MSG_MISMATCH_ARGS, "flow del ipv6");
1787 if (parse_ipv6_addr(tokens[2], &sipaddr) != 0) {
1788 printf(CMD_MSG_INVALID_ARG, "sipv6addr");
1792 if (parse_ipv6_addr(tokens[3], &dipaddr) != 0) {
1793 printf(CMD_MSG_INVALID_ARG, "dipv6addr");
1797 if (parser_read_uint32(&sport, tokens[4]) != 0) {
1798 printf(CMD_MSG_INVALID_ARG, "sport");
1802 if (parser_read_uint32(&dport, tokens[5]) != 0) {
1803 printf(CMD_MSG_INVALID_ARG, "dport");
1807 if (parser_read_uint32(&proto, tokens[6]) != 0) {
1808 printf(CMD_MSG_INVALID_ARG, "proto");
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;
1819 status = app_pipeline_fc_del(app,
1820 results->pipeline_id,
1823 printf(CMD_MSG_FAIL, "flow del ipv6");
1826 } /* flow del ipv6 */
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");
1837 status = app_pipeline_fc_del_default(app,
1838 results->pipeline_id);
1840 printf(CMD_MSG_FAIL, "flow del default");
1843 } /* flow del default */
1846 if ((n_tokens >= 1) && (strcmp(tokens[0], "ls") == 0)) {
1847 if (n_tokens != 1) {
1848 printf(CMD_MSG_MISMATCH_ARGS, "flow ls");
1852 status = app_pipeline_fc_ls(app, results->pipeline_id);
1854 printf(CMD_MSG_FAIL, "flow ls");
1859 printf(CMD_MSG_MISMATCH_ARGS, "flow");
1862 static cmdline_parse_token_string_t cmd_flow_p_string =
1863 TOKEN_STRING_INITIALIZER(struct cmd_flow_result, p_string, "p");
1865 static cmdline_parse_token_num_t cmd_flow_pipeline_id =
1866 TOKEN_NUM_INITIALIZER(struct cmd_flow_result, pipeline_id, UINT32);
1868 static cmdline_parse_token_string_t cmd_flow_flow_string =
1869 TOKEN_STRING_INITIALIZER(struct cmd_flow_result, flow_string, "flow");
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);
1875 static cmdline_parse_inst_t cmd_flow = {
1876 .f = cmd_flow_parsed,
1878 .help_str = "flow add / add bulk / add default / del / del default / ls",
1880 (void *) &cmd_flow_p_string,
1881 (void *) &cmd_flow_pipeline_id,
1882 (void *) &cmd_flow_flow_string,
1883 (void *) &cmd_flow_multi_string,
1888 static cmdline_parse_ctx_t pipeline_cmds[] = {
1889 (cmdline_parse_inst_t *) &cmd_flow,
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,
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,