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