Imported Upstream version 16.07-rc1
[deb_dpdk.git] / examples / ip_pipeline / pipeline / pipeline_flow_actions.c
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2010-2015 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_actions.h"
51 #include "hash_func.h"
52 #include "parser.h"
53
54 /*
55  * Flow actions pipeline
56  */
57 #ifndef N_FLOWS_BULK
58 #define N_FLOWS_BULK                                    4096
59 #endif
60
61 struct app_pipeline_fa_flow {
62         struct pipeline_fa_flow_params params;
63         void *entry_ptr;
64 };
65
66 struct app_pipeline_fa_dscp {
67         uint32_t traffic_class;
68         enum rte_meter_color color;
69 };
70
71 struct app_pipeline_fa {
72         /* Parameters */
73         uint32_t n_ports_in;
74         uint32_t n_ports_out;
75         struct pipeline_fa_params params;
76
77         /* Flows */
78         struct app_pipeline_fa_dscp dscp[PIPELINE_FA_N_DSCP];
79         struct app_pipeline_fa_flow *flows;
80 } __rte_cache_aligned;
81
82 static void*
83 app_pipeline_fa_init(struct pipeline_params *params,
84         __rte_unused void *arg)
85 {
86         struct app_pipeline_fa *p;
87         uint32_t size, i;
88
89         /* Check input arguments */
90         if ((params == NULL) ||
91                 (params->n_ports_in == 0) ||
92                 (params->n_ports_out == 0))
93                 return NULL;
94
95         /* Memory allocation */
96         size = RTE_CACHE_LINE_ROUNDUP(sizeof(struct app_pipeline_fa));
97         p = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
98         if (p == NULL)
99                 return NULL;
100
101         /* Initialization */
102         p->n_ports_in = params->n_ports_in;
103         p->n_ports_out = params->n_ports_out;
104         if (pipeline_fa_parse_args(&p->params, params)) {
105                 rte_free(p);
106                 return NULL;
107         }
108
109         /* Memory allocation */
110         size = RTE_CACHE_LINE_ROUNDUP(
111                 p->params.n_flows * sizeof(struct app_pipeline_fa_flow));
112         p->flows = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
113         if (p->flows == NULL) {
114                 rte_free(p);
115                 return NULL;
116         }
117
118         /* Initialization of flow table */
119         for (i = 0; i < p->params.n_flows; i++)
120                 pipeline_fa_flow_params_set_default(&p->flows[i].params);
121
122         /* Initialization of DSCP table */
123         for (i = 0; i < RTE_DIM(p->dscp); i++) {
124                 p->dscp[i].traffic_class = 0;
125                 p->dscp[i].color = e_RTE_METER_GREEN;
126         }
127
128         return (void *) p;
129 }
130
131 static int
132 app_pipeline_fa_free(void *pipeline)
133 {
134         struct app_pipeline_fa *p = pipeline;
135
136         /* Check input arguments */
137         if (p == NULL)
138                 return -1;
139
140         /* Free resources */
141         rte_free(p->flows);
142         rte_free(p);
143
144         return 0;
145 }
146
147 static int
148 flow_params_check(struct app_pipeline_fa *p,
149         __rte_unused uint32_t meter_update_mask,
150         uint32_t policer_update_mask,
151         uint32_t port_update,
152         struct pipeline_fa_flow_params *params)
153 {
154         uint32_t mask, i;
155
156         /* Meter */
157
158         /* Policer */
159         for (i = 0, mask = 1; i < PIPELINE_FA_N_TC_MAX; i++, mask <<= 1) {
160                 struct pipeline_fa_policer_params *p = &params->p[i];
161                 uint32_t j;
162
163                 if ((mask & policer_update_mask) == 0)
164                         continue;
165
166                 for (j = 0; j < e_RTE_METER_COLORS; j++) {
167                         struct pipeline_fa_policer_action *action =
168                                 &p->action[j];
169
170                         if ((action->drop == 0) &&
171                                 (action->color >= e_RTE_METER_COLORS))
172                                 return -1;
173                 }
174         }
175
176         /* Port */
177         if (port_update && (params->port_id >= p->n_ports_out))
178                 return -1;
179
180         return 0;
181 }
182
183 int
184 app_pipeline_fa_flow_config(struct app_params *app,
185         uint32_t pipeline_id,
186         uint32_t flow_id,
187         uint32_t meter_update_mask,
188         uint32_t policer_update_mask,
189         uint32_t port_update,
190         struct pipeline_fa_flow_params *params)
191 {
192         struct app_pipeline_fa *p;
193         struct app_pipeline_fa_flow *flow;
194
195         struct pipeline_fa_flow_config_msg_req *req;
196         struct pipeline_fa_flow_config_msg_rsp *rsp;
197
198         uint32_t i, mask;
199
200         /* Check input arguments */
201         if ((app == NULL) ||
202                 ((meter_update_mask == 0) &&
203                 (policer_update_mask == 0) &&
204                 (port_update == 0)) ||
205                 (meter_update_mask >= (1 << PIPELINE_FA_N_TC_MAX)) ||
206                 (policer_update_mask >= (1 << PIPELINE_FA_N_TC_MAX)) ||
207                 (params == NULL))
208                 return -1;
209
210         p = app_pipeline_data_fe(app, pipeline_id,
211                 &pipeline_flow_actions);
212         if (p == NULL)
213                 return -1;
214
215         if (flow_params_check(p,
216                 meter_update_mask,
217                 policer_update_mask,
218                 port_update,
219                 params) != 0)
220                 return -1;
221
222         flow_id %= p->params.n_flows;
223         flow = &p->flows[flow_id];
224
225         /* Allocate and write request */
226         req = app_msg_alloc(app);
227         if (req == NULL)
228                 return -1;
229
230         req->type = PIPELINE_MSG_REQ_CUSTOM;
231         req->subtype = PIPELINE_FA_MSG_REQ_FLOW_CONFIG;
232         req->entry_ptr = flow->entry_ptr;
233         req->flow_id = flow_id;
234         req->meter_update_mask = meter_update_mask;
235         req->policer_update_mask = policer_update_mask;
236         req->port_update = port_update;
237         memcpy(&req->params, params, sizeof(*params));
238
239         /* Send request and wait for response */
240         rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
241         if (rsp == NULL)
242                 return -1;
243
244         /* Read response */
245         if (rsp->status ||
246                 (rsp->entry_ptr == NULL)) {
247                 app_msg_free(app, rsp);
248                 return -1;
249         }
250
251         /* Commit flow */
252         for (i = 0, mask = 1; i < PIPELINE_FA_N_TC_MAX; i++, mask <<= 1) {
253                 if ((mask & meter_update_mask) == 0)
254                         continue;
255
256                 memcpy(&flow->params.m[i], &params->m[i], sizeof(params->m[i]));
257         }
258
259         for (i = 0, mask = 1; i < PIPELINE_FA_N_TC_MAX; i++, mask <<= 1) {
260                 if ((mask & policer_update_mask) == 0)
261                         continue;
262
263                 memcpy(&flow->params.p[i], &params->p[i], sizeof(params->p[i]));
264         }
265
266         if (port_update)
267                 flow->params.port_id = params->port_id;
268
269         flow->entry_ptr = rsp->entry_ptr;
270
271         /* Free response */
272         app_msg_free(app, rsp);
273
274         return 0;
275 }
276
277 int
278 app_pipeline_fa_flow_config_bulk(struct app_params *app,
279         uint32_t pipeline_id,
280         uint32_t *flow_id,
281         uint32_t n_flows,
282         uint32_t meter_update_mask,
283         uint32_t policer_update_mask,
284         uint32_t port_update,
285         struct pipeline_fa_flow_params *params)
286 {
287         struct app_pipeline_fa *p;
288         struct pipeline_fa_flow_config_bulk_msg_req *req;
289         struct pipeline_fa_flow_config_bulk_msg_rsp *rsp;
290         void **req_entry_ptr;
291         uint32_t *req_flow_id;
292         uint32_t i;
293
294         /* Check input arguments */
295         if ((app == NULL) ||
296                 (flow_id == NULL) ||
297                 (n_flows == 0) ||
298                 ((meter_update_mask == 0) &&
299                 (policer_update_mask == 0) &&
300                 (port_update == 0)) ||
301                 (meter_update_mask >= (1 << PIPELINE_FA_N_TC_MAX)) ||
302                 (policer_update_mask >= (1 << PIPELINE_FA_N_TC_MAX)) ||
303                 (params == NULL))
304                 return -1;
305
306         p = app_pipeline_data_fe(app, pipeline_id,
307                 &pipeline_flow_actions);
308         if (p == NULL)
309                 return -1;
310
311         for (i = 0; i < n_flows; i++) {
312                 struct pipeline_fa_flow_params *flow_params = &params[i];
313
314                 if (flow_params_check(p,
315                         meter_update_mask,
316                         policer_update_mask,
317                         port_update,
318                         flow_params) != 0)
319                         return -1;
320         }
321
322         /* Allocate and write request */
323         req_entry_ptr = (void **) rte_malloc(NULL,
324                 n_flows * sizeof(void *),
325                 RTE_CACHE_LINE_SIZE);
326         if (req_entry_ptr == NULL)
327                 return -1;
328
329         req_flow_id = (uint32_t *) rte_malloc(NULL,
330                 n_flows * sizeof(uint32_t),
331                 RTE_CACHE_LINE_SIZE);
332         if (req_flow_id == NULL) {
333                 rte_free(req_entry_ptr);
334                 return -1;
335         }
336
337         for (i = 0; i < n_flows; i++) {
338                 uint32_t fid = flow_id[i] % p->params.n_flows;
339                 struct app_pipeline_fa_flow *flow = &p->flows[fid];
340
341                 req_flow_id[i] = fid;
342                 req_entry_ptr[i] = flow->entry_ptr;
343         }
344
345         req = app_msg_alloc(app);
346         if (req == NULL) {
347                 rte_free(req_flow_id);
348                 rte_free(req_entry_ptr);
349                 return -1;
350         }
351
352         req->type = PIPELINE_MSG_REQ_CUSTOM;
353         req->subtype = PIPELINE_FA_MSG_REQ_FLOW_CONFIG_BULK;
354         req->entry_ptr = req_entry_ptr;
355         req->flow_id = req_flow_id;
356         req->n_flows = n_flows;
357         req->meter_update_mask = meter_update_mask;
358         req->policer_update_mask = policer_update_mask;
359         req->port_update = port_update;
360         req->params = params;
361
362         /* Send request and wait for response */
363         rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
364         if (rsp == NULL) {
365                 rte_free(req_flow_id);
366                 rte_free(req_entry_ptr);
367                 return -1;
368         }
369
370         /* Read response */
371
372         /* Commit flows */
373         for (i = 0; i < rsp->n_flows; i++) {
374                 uint32_t fid = flow_id[i] % p->params.n_flows;
375                 struct app_pipeline_fa_flow *flow = &p->flows[fid];
376                 struct pipeline_fa_flow_params *flow_params = &params[i];
377                 void *entry_ptr = req_entry_ptr[i];
378                 uint32_t j, mask;
379
380                 for (j = 0, mask = 1; j < PIPELINE_FA_N_TC_MAX;
381                         j++, mask <<= 1) {
382                         if ((mask & meter_update_mask) == 0)
383                                 continue;
384
385                         memcpy(&flow->params.m[j],
386                                 &flow_params->m[j],
387                                 sizeof(flow_params->m[j]));
388                 }
389
390                 for (j = 0, mask = 1; j < PIPELINE_FA_N_TC_MAX;
391                         j++, mask <<= 1) {
392                         if ((mask & policer_update_mask) == 0)
393                                 continue;
394
395                         memcpy(&flow->params.p[j],
396                                 &flow_params->p[j],
397                                 sizeof(flow_params->p[j]));
398                 }
399
400                 if (port_update)
401                         flow->params.port_id = flow_params->port_id;
402
403                 flow->entry_ptr = entry_ptr;
404         }
405
406         /* Free response */
407         app_msg_free(app, rsp);
408         rte_free(req_flow_id);
409         rte_free(req_entry_ptr);
410
411         return (rsp->n_flows == n_flows) ? 0 : -1;
412 }
413
414 int
415 app_pipeline_fa_dscp_config(struct app_params *app,
416         uint32_t pipeline_id,
417         uint32_t dscp,
418         uint32_t traffic_class,
419         enum rte_meter_color color)
420 {
421         struct app_pipeline_fa *p;
422
423         struct pipeline_fa_dscp_config_msg_req *req;
424         struct pipeline_fa_dscp_config_msg_rsp *rsp;
425
426         /* Check input arguments */
427         if ((app == NULL) ||
428                 (dscp >= PIPELINE_FA_N_DSCP) ||
429                 (traffic_class >= PIPELINE_FA_N_TC_MAX) ||
430                 (color >= e_RTE_METER_COLORS))
431                 return -1;
432
433         p = app_pipeline_data_fe(app, pipeline_id,
434                 &pipeline_flow_actions);
435         if (p == NULL)
436                 return -1;
437
438         if (p->params.dscp_enabled == 0)
439                 return -1;
440
441         /* Allocate and write request */
442         req = app_msg_alloc(app);
443         if (req == NULL)
444                 return -1;
445
446         req->type = PIPELINE_MSG_REQ_CUSTOM;
447         req->subtype = PIPELINE_FA_MSG_REQ_DSCP_CONFIG;
448         req->dscp = dscp;
449         req->traffic_class = traffic_class;
450         req->color = color;
451
452         /* Send request and wait for response */
453         rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
454         if (rsp == NULL)
455                 return -1;
456
457         /* Read response */
458         if (rsp->status) {
459                 app_msg_free(app, rsp);
460                 return -1;
461         }
462
463         /* Commit DSCP */
464         p->dscp[dscp].traffic_class = traffic_class;
465         p->dscp[dscp].color = color;
466
467         /* Free response */
468         app_msg_free(app, rsp);
469
470         return 0;
471 }
472
473 int
474 app_pipeline_fa_flow_policer_stats_read(struct app_params *app,
475         uint32_t pipeline_id,
476         uint32_t flow_id,
477         uint32_t policer_id,
478         int clear,
479         struct pipeline_fa_policer_stats *stats)
480 {
481         struct app_pipeline_fa *p;
482         struct app_pipeline_fa_flow *flow;
483
484         struct pipeline_fa_policer_stats_msg_req *req;
485         struct pipeline_fa_policer_stats_msg_rsp *rsp;
486
487         /* Check input arguments */
488         if ((app == NULL) || (stats == NULL))
489                 return -1;
490
491         p = app_pipeline_data_fe(app, pipeline_id,
492                 &pipeline_flow_actions);
493         if (p == NULL)
494                 return -1;
495
496         flow_id %= p->params.n_flows;
497         flow = &p->flows[flow_id];
498
499         if ((policer_id >= p->params.n_meters_per_flow) ||
500                 (flow->entry_ptr == NULL))
501                 return -1;
502
503         /* Allocate and write request */
504         req = app_msg_alloc(app);
505         if (req == NULL)
506                 return -1;
507
508         req->type = PIPELINE_MSG_REQ_CUSTOM;
509         req->subtype = PIPELINE_FA_MSG_REQ_POLICER_STATS_READ;
510         req->entry_ptr = flow->entry_ptr;
511         req->policer_id = policer_id;
512         req->clear = clear;
513
514         /* Send request and wait for response */
515         rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
516         if (rsp == NULL)
517                 return -1;
518
519         /* Read response */
520         if (rsp->status) {
521                 app_msg_free(app, rsp);
522                 return -1;
523         }
524
525         memcpy(stats, &rsp->stats, sizeof(*stats));
526
527         /* Free response */
528         app_msg_free(app, rsp);
529
530         return 0;
531 }
532
533 static const char *
534 color_to_string(enum rte_meter_color color)
535 {
536         switch (color) {
537         case e_RTE_METER_GREEN: return "G";
538         case e_RTE_METER_YELLOW: return "Y";
539         case e_RTE_METER_RED: return "R";
540         default: return "?";
541         }
542 }
543
544 static int
545 string_to_color(char *s, enum rte_meter_color *c)
546 {
547         if (strcmp(s, "G") == 0) {
548                 *c = e_RTE_METER_GREEN;
549                 return 0;
550         }
551
552         if (strcmp(s, "Y") == 0) {
553                 *c = e_RTE_METER_YELLOW;
554                 return 0;
555         }
556
557         if (strcmp(s, "R") == 0) {
558                 *c = e_RTE_METER_RED;
559                 return 0;
560         }
561
562         return -1;
563 }
564
565 static const char *
566 policer_action_to_string(struct pipeline_fa_policer_action *a)
567 {
568         if (a->drop)
569                 return "D";
570
571         return color_to_string(a->color);
572 }
573
574 static int
575 string_to_policer_action(char *s, struct pipeline_fa_policer_action *a)
576 {
577         if (strcmp(s, "G") == 0) {
578                 a->drop = 0;
579                 a->color = e_RTE_METER_GREEN;
580                 return 0;
581         }
582
583         if (strcmp(s, "Y") == 0) {
584                 a->drop = 0;
585                 a->color = e_RTE_METER_YELLOW;
586                 return 0;
587         }
588
589         if (strcmp(s, "R") == 0) {
590                 a->drop = 0;
591                 a->color = e_RTE_METER_RED;
592                 return 0;
593         }
594
595         if (strcmp(s, "D") == 0) {
596                 a->drop = 1;
597                 a->color = e_RTE_METER_GREEN;
598                 return 0;
599         }
600
601         return -1;
602 }
603
604 static void
605 print_flow(struct app_pipeline_fa *p,
606         uint32_t flow_id,
607         struct app_pipeline_fa_flow *flow)
608 {
609         uint32_t i;
610
611         printf("Flow ID = %" PRIu32 "\n", flow_id);
612
613         for (i = 0; i < p->params.n_meters_per_flow; i++) {
614                 struct rte_meter_trtcm_params *meter = &flow->params.m[i];
615                 struct pipeline_fa_policer_params *policer = &flow->params.p[i];
616
617         printf("\ttrTCM [CIR = %" PRIu64
618                 ", CBS = %" PRIu64 ", PIR = %" PRIu64
619                 ", PBS = %" PRIu64      "] Policer [G : %s, Y : %s, R : %s]\n",
620                 meter->cir,
621                 meter->cbs,
622                 meter->pir,
623                 meter->pbs,
624                 policer_action_to_string(&policer->action[e_RTE_METER_GREEN]),
625                 policer_action_to_string(&policer->action[e_RTE_METER_YELLOW]),
626                 policer_action_to_string(&policer->action[e_RTE_METER_RED]));
627         }
628
629         printf("\tPort %u (entry_ptr = %p)\n",
630                 flow->params.port_id,
631                 flow->entry_ptr);
632 }
633
634
635 static int
636 app_pipeline_fa_flow_ls(struct app_params *app,
637                 uint32_t pipeline_id)
638 {
639         struct app_pipeline_fa *p;
640         uint32_t i;
641
642         /* Check input arguments */
643         if (app == NULL)
644                 return -1;
645
646         p = app_pipeline_data_fe(app, pipeline_id,
647                 &pipeline_flow_actions);
648         if (p == NULL)
649                 return -1;
650
651         for (i = 0; i < p->params.n_flows; i++) {
652                 struct app_pipeline_fa_flow *flow = &p->flows[i];
653
654                 print_flow(p, i, flow);
655         }
656
657         return 0;
658 }
659
660 static int
661 app_pipeline_fa_dscp_ls(struct app_params *app,
662                 uint32_t pipeline_id)
663 {
664         struct app_pipeline_fa *p;
665         uint32_t i;
666
667         /* Check input arguments */
668         if (app == NULL)
669                 return -1;
670
671         p = app_pipeline_data_fe(app, pipeline_id,
672                 &pipeline_flow_actions);
673         if (p == NULL)
674                 return -1;
675
676         if (p->params.dscp_enabled == 0)
677                 return -1;
678
679         for (i = 0; i < RTE_DIM(p->dscp); i++) {
680                 struct app_pipeline_fa_dscp *dscp =     &p->dscp[i];
681
682                 printf("DSCP = %2" PRIu32 ": Traffic class = %" PRIu32
683                         ", Color = %s\n",
684                         i,
685                         dscp->traffic_class,
686                         color_to_string(dscp->color));
687         }
688
689         return 0;
690 }
691
692 int
693 app_pipeline_fa_load_file(char *filename,
694         uint32_t *flow_ids,
695         struct pipeline_fa_flow_params *p,
696         uint32_t *n_flows,
697         uint32_t *line)
698 {
699         FILE *f = NULL;
700         char file_buf[1024];
701         uint32_t i, l;
702
703         /* Check input arguments */
704         if ((filename == NULL) ||
705                 (flow_ids == NULL) ||
706                 (p == NULL) ||
707                 (n_flows == NULL) ||
708                 (*n_flows == 0) ||
709                 (line == NULL)) {
710                 if (line)
711                         *line = 0;
712                 return -1;
713                 }
714
715         /* Open input file */
716         f = fopen(filename, "r");
717         if (f == NULL) {
718                 *line = 0;
719                 return -1;
720         }
721
722         /* Read file */
723         for (i = 0, l = 1; i < *n_flows; l++) {
724                 char *tokens[64];
725                 uint32_t n_tokens = RTE_DIM(tokens);
726
727                 int status;
728
729                 if (fgets(file_buf, sizeof(file_buf), f) == NULL)
730                         break;
731
732                 status = parse_tokenize_string(file_buf, tokens, &n_tokens);
733                 if (status)
734                         goto error1;
735
736                 if ((n_tokens == 0) || (tokens[0][0] == '#'))
737                         continue;
738
739
740                 if ((n_tokens != 64) ||
741                         /* flow */
742                         strcmp(tokens[0], "flow") ||
743                         parser_read_uint32(&flow_ids[i], tokens[1]) ||
744
745                         /* meter & policer 0 */
746                         strcmp(tokens[2], "meter") ||
747                         strcmp(tokens[3], "0") ||
748                         strcmp(tokens[4], "trtcm") ||
749                         parser_read_uint64(&p[i].m[0].cir, tokens[5]) ||
750                         parser_read_uint64(&p[i].m[0].pir, tokens[6]) ||
751                         parser_read_uint64(&p[i].m[0].cbs, tokens[7]) ||
752                         parser_read_uint64(&p[i].m[0].pbs, tokens[8]) ||
753                         strcmp(tokens[9], "policer") ||
754                         strcmp(tokens[10], "0") ||
755                         strcmp(tokens[11], "g") ||
756                         string_to_policer_action(tokens[12],
757                                 &p[i].p[0].action[e_RTE_METER_GREEN]) ||
758                         strcmp(tokens[13], "y") ||
759                         string_to_policer_action(tokens[14],
760                                 &p[i].p[0].action[e_RTE_METER_YELLOW]) ||
761                         strcmp(tokens[15], "r") ||
762                         string_to_policer_action(tokens[16],
763                                 &p[i].p[0].action[e_RTE_METER_RED]) ||
764
765                         /* meter & policer 1 */
766                         strcmp(tokens[17], "meter") ||
767                         strcmp(tokens[18], "1") ||
768                         strcmp(tokens[19], "trtcm") ||
769                         parser_read_uint64(&p[i].m[1].cir, tokens[20]) ||
770                         parser_read_uint64(&p[i].m[1].pir, tokens[21]) ||
771                         parser_read_uint64(&p[i].m[1].cbs, tokens[22]) ||
772                         parser_read_uint64(&p[i].m[1].pbs, tokens[23]) ||
773                         strcmp(tokens[24], "policer") ||
774                         strcmp(tokens[25], "1") ||
775                         strcmp(tokens[26], "g") ||
776                         string_to_policer_action(tokens[27],
777                                 &p[i].p[1].action[e_RTE_METER_GREEN]) ||
778                         strcmp(tokens[28], "y") ||
779                         string_to_policer_action(tokens[29],
780                                 &p[i].p[1].action[e_RTE_METER_YELLOW]) ||
781                         strcmp(tokens[30], "r") ||
782                         string_to_policer_action(tokens[31],
783                                 &p[i].p[1].action[e_RTE_METER_RED]) ||
784
785                         /* meter & policer 2 */
786                         strcmp(tokens[32], "meter") ||
787                         strcmp(tokens[33], "2") ||
788                         strcmp(tokens[34], "trtcm") ||
789                         parser_read_uint64(&p[i].m[2].cir, tokens[35]) ||
790                         parser_read_uint64(&p[i].m[2].pir, tokens[36]) ||
791                         parser_read_uint64(&p[i].m[2].cbs, tokens[37]) ||
792                         parser_read_uint64(&p[i].m[2].pbs, tokens[38]) ||
793                         strcmp(tokens[39], "policer") ||
794                         strcmp(tokens[40], "2") ||
795                         strcmp(tokens[41], "g") ||
796                         string_to_policer_action(tokens[42],
797                                 &p[i].p[2].action[e_RTE_METER_GREEN]) ||
798                         strcmp(tokens[43], "y") ||
799                         string_to_policer_action(tokens[44],
800                                 &p[i].p[2].action[e_RTE_METER_YELLOW]) ||
801                         strcmp(tokens[45], "r") ||
802                         string_to_policer_action(tokens[46],
803                                 &p[i].p[2].action[e_RTE_METER_RED]) ||
804
805                         /* meter & policer 3 */
806                         strcmp(tokens[47], "meter") ||
807                         strcmp(tokens[48], "3") ||
808                         strcmp(tokens[49], "trtcm") ||
809                         parser_read_uint64(&p[i].m[3].cir, tokens[50]) ||
810                         parser_read_uint64(&p[i].m[3].pir, tokens[51]) ||
811                         parser_read_uint64(&p[i].m[3].cbs, tokens[52]) ||
812                         parser_read_uint64(&p[i].m[3].pbs, tokens[53]) ||
813                         strcmp(tokens[54], "policer") ||
814                         strcmp(tokens[55], "3") ||
815                         strcmp(tokens[56], "g") ||
816                         string_to_policer_action(tokens[57],
817                                 &p[i].p[3].action[e_RTE_METER_GREEN]) ||
818                         strcmp(tokens[58], "y") ||
819                         string_to_policer_action(tokens[59],
820                                 &p[i].p[3].action[e_RTE_METER_YELLOW]) ||
821                         strcmp(tokens[60], "r") ||
822                         string_to_policer_action(tokens[61],
823                                 &p[i].p[3].action[e_RTE_METER_RED]) ||
824
825                         /* port */
826                         strcmp(tokens[62], "port") ||
827                         parser_read_uint32(&p[i].port_id, tokens[63]))
828                         goto error1;
829
830                 i++;
831         }
832
833         /* Close file */
834         *n_flows = i;
835         fclose(f);
836         return 0;
837
838 error1:
839         *line = l;
840         fclose(f);
841         return -1;
842 }
843
844 /*
845  * action
846  *
847  * flow meter, policer and output port configuration:
848  *    p <pipelineid> action flow <flowid> meter <meterid> trtcm <cir> <pir> <cbs> <pbs>
849  *
850  *    p <pipelineid> action flow <flowid> policer <policerid> g <gaction> y <yaction> r <raction>
851  *  <action> is one of the following:
852  *      G = recolor to green
853  *      Y = recolor as yellow
854  *      R = recolor as red
855  *      D = drop
856  *
857  *    p <pipelineid> action flow <flowid> port <port ID>
858  *
859  *    p <pipelineid> action flow bulk <file>
860  *
861  * flow policer stats read:
862  *    p <pipelineid> action flow <flowid> stats
863  *
864  * flow ls:
865  *    p <pipelineid> action flow ls
866  *
867  * dscp table configuration:
868  *    p <pipelineid> action dscp <dscpid> class <class ID> color <color>
869  *
870  * dscp table ls:
871  *    p <pipelineid> action dscp ls
872 **/
873
874 struct cmd_action_result {
875         cmdline_fixed_string_t p_string;
876         uint32_t pipeline_id;
877         cmdline_fixed_string_t action_string;
878         cmdline_multi_string_t multi_string;
879 };
880
881 static void
882 cmd_action_parsed(
883         void *parsed_result,
884         __rte_unused struct cmdline *cl,
885         void *data)
886 {
887         struct cmd_action_result *params = parsed_result;
888         struct app_params *app = data;
889
890         char *tokens[16];
891         uint32_t n_tokens = RTE_DIM(tokens);
892         int status;
893
894         status = parse_tokenize_string(params->multi_string, tokens, &n_tokens);
895         if (status != 0) {
896                 printf(CMD_MSG_TOO_MANY_ARGS, "action");
897                 return;
898         }
899
900         /* action flow meter */
901         if ((n_tokens >= 3) &&
902                 (strcmp(tokens[0], "flow") == 0) &&
903                 strcmp(tokens[1], "bulk") &&
904                 strcmp(tokens[1], "ls") &&
905                 (strcmp(tokens[2], "meter") == 0)) {
906                 struct pipeline_fa_flow_params flow_params;
907                 uint32_t flow_id, meter_id;
908
909                 if (n_tokens != 9) {
910                         printf(CMD_MSG_MISMATCH_ARGS, "action flow meter");
911                         return;
912                 }
913
914                 memset(&flow_params, 0, sizeof(flow_params));
915
916                 if (parser_read_uint32(&flow_id, tokens[1])) {
917                         printf(CMD_MSG_INVALID_ARG, "flowid");
918                         return;
919                 }
920
921                 if (parser_read_uint32(&meter_id, tokens[3]) ||
922                         (meter_id >= PIPELINE_FA_N_TC_MAX)) {
923                         printf(CMD_MSG_INVALID_ARG, "meterid");
924                         return;
925                 }
926
927                 if (strcmp(tokens[4], "trtcm")) {
928                         printf(CMD_MSG_ARG_NOT_FOUND, "trtcm");
929                         return;
930                 }
931
932                 if (parser_read_uint64(&flow_params.m[meter_id].cir, tokens[5])) {
933                         printf(CMD_MSG_INVALID_ARG, "cir");
934                         return;
935                 }
936
937                 if (parser_read_uint64(&flow_params.m[meter_id].pir, tokens[6])) {
938                         printf(CMD_MSG_INVALID_ARG, "pir");
939                         return;
940                 }
941
942                 if (parser_read_uint64(&flow_params.m[meter_id].cbs, tokens[7])) {
943                         printf(CMD_MSG_INVALID_ARG, "cbs");
944                         return;
945                 }
946
947                 if (parser_read_uint64(&flow_params.m[meter_id].pbs, tokens[8])) {
948                         printf(CMD_MSG_INVALID_ARG, "pbs");
949                         return;
950                 }
951
952                 status = app_pipeline_fa_flow_config(app,
953                         params->pipeline_id,
954                         flow_id,
955                         1 << meter_id,
956                         0,
957                         0,
958                         &flow_params);
959                 if (status)
960                         printf(CMD_MSG_FAIL, "action flow meter");
961
962                 return;
963         } /* action flow meter */
964
965         /* action flow policer */
966         if ((n_tokens >= 3) &&
967                 (strcmp(tokens[0], "flow") == 0) &&
968                 strcmp(tokens[1], "bulk") &&
969                 strcmp(tokens[1], "ls") &&
970                 (strcmp(tokens[2], "policer") == 0)) {
971                 struct pipeline_fa_flow_params flow_params;
972                 uint32_t flow_id, policer_id;
973
974                 if (n_tokens != 10) {
975                         printf(CMD_MSG_MISMATCH_ARGS, "action flow policer");
976                         return;
977                 }
978
979                 memset(&flow_params, 0, sizeof(flow_params));
980
981                 if (parser_read_uint32(&flow_id, tokens[1])) {
982                         printf(CMD_MSG_INVALID_ARG, "flowid");
983                         return;
984                 }
985
986                 if (parser_read_uint32(&policer_id, tokens[3]) ||
987                         (policer_id >= PIPELINE_FA_N_TC_MAX)) {
988                         printf(CMD_MSG_INVALID_ARG, "policerid");
989                         return;
990                 }
991
992                 if (strcmp(tokens[4], "g")) {
993                         printf(CMD_MSG_ARG_NOT_FOUND, "g");
994                         return;
995                 }
996
997                 if (string_to_policer_action(tokens[5],
998                         &flow_params.p[policer_id].action[e_RTE_METER_GREEN])) {
999                         printf(CMD_MSG_INVALID_ARG, "gaction");
1000                         return;
1001                 }
1002
1003                 if (strcmp(tokens[6], "y")) {
1004                         printf(CMD_MSG_ARG_NOT_FOUND, "y");
1005                         return;
1006                 }
1007
1008                 if (string_to_policer_action(tokens[7],
1009                         &flow_params.p[policer_id].action[e_RTE_METER_YELLOW])) {
1010                         printf(CMD_MSG_INVALID_ARG, "yaction");
1011                         return;
1012                 }
1013
1014                 if (strcmp(tokens[8], "r")) {
1015                         printf(CMD_MSG_ARG_NOT_FOUND, "r");
1016                         return;
1017                 }
1018
1019                 if (string_to_policer_action(tokens[9],
1020                         &flow_params.p[policer_id].action[e_RTE_METER_RED])) {
1021                         printf(CMD_MSG_INVALID_ARG, "raction");
1022                         return;
1023                 }
1024
1025                 status = app_pipeline_fa_flow_config(app,
1026                         params->pipeline_id,
1027                         flow_id,
1028                         0,
1029                         1 << policer_id,
1030                         0,
1031                         &flow_params);
1032                 if (status != 0)
1033                         printf(CMD_MSG_FAIL, "action flow policer");
1034
1035                 return;
1036         } /* action flow policer */
1037
1038         /* action flow port */
1039         if ((n_tokens >= 3) &&
1040                 (strcmp(tokens[0], "flow") == 0) &&
1041                 strcmp(tokens[1], "bulk") &&
1042                 strcmp(tokens[1], "ls") &&
1043                 (strcmp(tokens[2], "port") == 0)) {
1044                 struct pipeline_fa_flow_params flow_params;
1045                 uint32_t flow_id, port_id;
1046
1047                 if (n_tokens != 4) {
1048                         printf(CMD_MSG_MISMATCH_ARGS, "action flow port");
1049                         return;
1050                 }
1051
1052                 memset(&flow_params, 0, sizeof(flow_params));
1053
1054                 if (parser_read_uint32(&flow_id, tokens[1])) {
1055                         printf(CMD_MSG_INVALID_ARG, "flowid");
1056                         return;
1057                 }
1058
1059                 if (parser_read_uint32(&port_id, tokens[3])) {
1060                         printf(CMD_MSG_INVALID_ARG, "portid");
1061                         return;
1062                 }
1063
1064                 flow_params.port_id = port_id;
1065
1066                 status = app_pipeline_fa_flow_config(app,
1067                         params->pipeline_id,
1068                         flow_id,
1069                         0,
1070                         0,
1071                         1,
1072                         &flow_params);
1073                 if (status)
1074                         printf(CMD_MSG_FAIL, "action flow port");
1075
1076                 return;
1077         } /* action flow port */
1078
1079         /* action flow stats */
1080         if ((n_tokens >= 3) &&
1081                 (strcmp(tokens[0], "flow") == 0) &&
1082                 strcmp(tokens[1], "bulk") &&
1083                 strcmp(tokens[1], "ls") &&
1084                 (strcmp(tokens[2], "stats") == 0)) {
1085                 struct pipeline_fa_policer_stats stats;
1086                 uint32_t flow_id, policer_id;
1087
1088                 if (n_tokens != 3) {
1089                         printf(CMD_MSG_MISMATCH_ARGS, "action flow stats");
1090                         return;
1091                 }
1092
1093                 if (parser_read_uint32(&flow_id, tokens[1])) {
1094                         printf(CMD_MSG_INVALID_ARG, "flowid");
1095                         return;
1096                 }
1097
1098                 for (policer_id = 0;
1099                         policer_id < PIPELINE_FA_N_TC_MAX;
1100                         policer_id++) {
1101                         status = app_pipeline_fa_flow_policer_stats_read(app,
1102                                 params->pipeline_id,
1103                                 flow_id,
1104                                 policer_id,
1105                                 1,
1106                                 &stats);
1107                         if (status != 0) {
1108                                 printf(CMD_MSG_FAIL, "action flow stats");
1109                                 return;
1110                         }
1111
1112                         /* Display stats */
1113                         printf("\tPolicer: %" PRIu32
1114                                 "\tPkts G: %" PRIu64
1115                                 "\tPkts Y: %" PRIu64
1116                                 "\tPkts R: %" PRIu64
1117                                 "\tPkts D: %" PRIu64 "\n",
1118                                 policer_id,
1119                                 stats.n_pkts[e_RTE_METER_GREEN],
1120                                 stats.n_pkts[e_RTE_METER_YELLOW],
1121                                 stats.n_pkts[e_RTE_METER_RED],
1122                                 stats.n_pkts_drop);
1123                 }
1124
1125                 return;
1126         } /* action flow stats */
1127
1128         /* action flow bulk */
1129         if ((n_tokens >= 2) &&
1130                 (strcmp(tokens[0], "flow") == 0) &&
1131                 (strcmp(tokens[1], "bulk") == 0)) {
1132                 struct pipeline_fa_flow_params *flow_params;
1133                 uint32_t *flow_ids, n_flows, line;
1134                 char *filename;
1135
1136                 if (n_tokens != 3) {
1137                         printf(CMD_MSG_MISMATCH_ARGS, "action flow bulk");
1138                         return;
1139                 }
1140
1141                 filename = tokens[2];
1142
1143                 n_flows = APP_PIPELINE_FA_MAX_RECORDS_IN_FILE;
1144                 flow_ids = malloc(n_flows * sizeof(uint32_t));
1145                 if (flow_ids == NULL) {
1146                         printf(CMD_MSG_OUT_OF_MEMORY);
1147                         return;
1148                 }
1149
1150                 flow_params = malloc(n_flows * sizeof(struct pipeline_fa_flow_params));
1151                 if (flow_params == NULL) {
1152                         printf(CMD_MSG_OUT_OF_MEMORY);
1153                         free(flow_ids);
1154                         return;
1155                 }
1156
1157                 status = app_pipeline_fa_load_file(filename,
1158                         flow_ids,
1159                         flow_params,
1160                         &n_flows,
1161                         &line);
1162                 if (status) {
1163                         printf(CMD_MSG_FILE_ERR, filename, line);
1164                         free(flow_params);
1165                         free(flow_ids);
1166                         return;
1167                 }
1168
1169                 status = app_pipeline_fa_flow_config_bulk(app,
1170                         params->pipeline_id,
1171                         flow_ids,
1172                         n_flows,
1173                         0xF,
1174                         0xF,
1175                         1,
1176                         flow_params);
1177                 if (status)
1178                         printf(CMD_MSG_FAIL, "action flow bulk");
1179
1180                 free(flow_params);
1181                 free(flow_ids);
1182                 return;
1183         } /* action flow bulk */
1184
1185         /* action flow ls */
1186         if ((n_tokens >= 2) &&
1187                 (strcmp(tokens[0], "flow") == 0) &&
1188                 (strcmp(tokens[1], "ls") == 0)) {
1189                 if (n_tokens != 2) {
1190                         printf(CMD_MSG_MISMATCH_ARGS, "action flow ls");
1191                         return;
1192                 }
1193
1194                 status = app_pipeline_fa_flow_ls(app,
1195                         params->pipeline_id);
1196                 if (status)
1197                         printf(CMD_MSG_FAIL, "action flow ls");
1198
1199                 return;
1200         } /* action flow ls */
1201
1202         /* action dscp */
1203         if ((n_tokens >= 2) &&
1204                 (strcmp(tokens[0], "dscp") == 0) &&
1205                 strcmp(tokens[1], "ls")) {
1206                 uint32_t dscp_id, tc_id;
1207                 enum rte_meter_color color;
1208
1209                 if (n_tokens != 6) {
1210                         printf(CMD_MSG_MISMATCH_ARGS, "action dscp");
1211                         return;
1212                 }
1213
1214                 if (parser_read_uint32(&dscp_id, tokens[1])) {
1215                         printf(CMD_MSG_INVALID_ARG, "dscpid");
1216                         return;
1217                 }
1218
1219                 if (strcmp(tokens[2], "class")) {
1220                         printf(CMD_MSG_ARG_NOT_FOUND, "class");
1221                         return;
1222                 }
1223
1224                 if (parser_read_uint32(&tc_id, tokens[3])) {
1225                         printf(CMD_MSG_INVALID_ARG, "classid");
1226                         return;
1227                 }
1228
1229                 if (strcmp(tokens[4], "color")) {
1230                         printf(CMD_MSG_ARG_NOT_FOUND, "color");
1231                         return;
1232                 }
1233
1234                 if (string_to_color(tokens[5], &color)) {
1235                         printf(CMD_MSG_INVALID_ARG, "colorid");
1236                         return;
1237                 }
1238
1239                 status = app_pipeline_fa_dscp_config(app,
1240                         params->pipeline_id,
1241                         dscp_id,
1242                         tc_id,
1243                         color);
1244                 if (status != 0)
1245                         printf(CMD_MSG_FAIL, "action dscp");
1246
1247                 return;
1248         } /* action dscp */
1249
1250         /* action dscp ls */
1251         if ((n_tokens >= 2) &&
1252                 (strcmp(tokens[0], "dscp") == 0) &&
1253                 (strcmp(tokens[1], "ls") == 0)) {
1254                 if (n_tokens != 2) {
1255                         printf(CMD_MSG_MISMATCH_ARGS, "action dscp ls");
1256                         return;
1257                 }
1258
1259                 status = app_pipeline_fa_dscp_ls(app,
1260                         params->pipeline_id);
1261                 if (status)
1262                         printf(CMD_MSG_FAIL, "action dscp ls");
1263
1264                 return;
1265         } /* action dscp ls */
1266
1267         printf(CMD_MSG_FAIL, "action");
1268 }
1269
1270 static cmdline_parse_token_string_t cmd_action_p_string =
1271         TOKEN_STRING_INITIALIZER(struct cmd_action_result, p_string, "p");
1272
1273 static cmdline_parse_token_num_t cmd_action_pipeline_id =
1274         TOKEN_NUM_INITIALIZER(struct cmd_action_result, pipeline_id, UINT32);
1275
1276 static cmdline_parse_token_string_t cmd_action_action_string =
1277         TOKEN_STRING_INITIALIZER(struct cmd_action_result, action_string, "action");
1278
1279 static cmdline_parse_token_string_t cmd_action_multi_string =
1280         TOKEN_STRING_INITIALIZER(struct cmd_action_result, multi_string,
1281         TOKEN_STRING_MULTI);
1282
1283 cmdline_parse_inst_t cmd_action = {
1284         .f = cmd_action_parsed,
1285         .data = NULL,
1286         .help_str = "flow actions (meter, policer, policer stats, dscp table)",
1287         .tokens = {
1288                 (void *) &cmd_action_p_string,
1289                 (void *) &cmd_action_pipeline_id,
1290                 (void *) &cmd_action_action_string,
1291                 (void *) &cmd_action_multi_string,
1292                 NULL,
1293         },
1294 };
1295
1296 static cmdline_parse_ctx_t pipeline_cmds[] = {
1297         (cmdline_parse_inst_t *) &cmd_action,
1298         NULL,
1299 };
1300
1301 static struct pipeline_fe_ops pipeline_flow_actions_fe_ops = {
1302         .f_init = app_pipeline_fa_init,
1303         .f_post_init = NULL,
1304         .f_free = app_pipeline_fa_free,
1305         .f_track = app_pipeline_track_default,
1306         .cmds = pipeline_cmds,
1307 };
1308
1309 struct pipeline_type pipeline_flow_actions = {
1310         .name = "FLOW_ACTIONS",
1311         .be_ops = &pipeline_flow_actions_be_ops,
1312         .fe_ops = &pipeline_flow_actions_fe_ops,
1313 };