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