]> git.proxmox.com Git - ceph.git/blob - ceph/src/seastar/dpdk/examples/ip_pipeline/pipeline/pipeline_flow_actions.c
update download target update for octopus release
[ceph.git] / ceph / src / seastar / dpdk / 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 };