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