xref: /dpdk/examples/ip_pipeline/cli.c (revision a137d012a0dd7be982367687ea6cd10de6f12c69)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2010-2018 Intel Corporation
3  */
4 
5 #include <stdio.h>
6 #include <stdint.h>
7 #include <stdlib.h>
8 #include <string.h>
9 
10 #include <rte_common.h>
11 #include <rte_cycles.h>
12 #include <rte_ethdev.h>
13 
14 #include "cli.h"
15 
16 #include "cryptodev.h"
17 #include "kni.h"
18 #include "link.h"
19 #include "mempool.h"
20 #include "parser.h"
21 #include "pipeline.h"
22 #include "swq.h"
23 #include "tap.h"
24 #include "thread.h"
25 #include "tmgr.h"
26 
27 #ifndef CMD_MAX_TOKENS
28 #define CMD_MAX_TOKENS     256
29 #endif
30 
31 #define MSG_OUT_OF_MEMORY   "Not enough memory.\n"
32 #define MSG_CMD_UNKNOWN     "Unknown command \"%s\".\n"
33 #define MSG_CMD_UNIMPLEM    "Command \"%s\" not implemented.\n"
34 #define MSG_ARG_NOT_ENOUGH  "Not enough arguments for command \"%s\".\n"
35 #define MSG_ARG_TOO_MANY    "Too many arguments for command \"%s\".\n"
36 #define MSG_ARG_MISMATCH    "Wrong number of arguments for command \"%s\".\n"
37 #define MSG_ARG_NOT_FOUND   "Argument \"%s\" not found.\n"
38 #define MSG_ARG_INVALID     "Invalid value for argument \"%s\".\n"
39 #define MSG_FILE_ERR        "Error in file \"%s\" at line %u.\n"
40 #define MSG_FILE_NOT_ENOUGH "Not enough rules in file \"%s\".\n"
41 #define MSG_CMD_FAIL        "Command \"%s\" failed.\n"
42 
43 static int
44 is_comment(char *in)
45 {
46 	if ((strlen(in) && index("!#%;", in[0])) ||
47 		(strncmp(in, "//", 2) == 0) ||
48 		(strncmp(in, "--", 2) == 0))
49 		return 1;
50 
51 	return 0;
52 }
53 
54 static const char cmd_mempool_help[] =
55 "mempool <mempool_name>\n"
56 "   buffer <buffer_size>\n"
57 "   pool <pool_size>\n"
58 "   cache <cache_size>\n"
59 "   cpu <cpu_id>\n";
60 
61 static void
62 cmd_mempool(char **tokens,
63 	uint32_t n_tokens,
64 	char *out,
65 	size_t out_size)
66 {
67 	struct mempool_params p;
68 	char *name;
69 	struct mempool *mempool;
70 
71 	if (n_tokens != 10) {
72 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
73 		return;
74 	}
75 
76 	name = tokens[1];
77 
78 	if (strcmp(tokens[2], "buffer") != 0) {
79 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "buffer");
80 		return;
81 	}
82 
83 	if (parser_read_uint32(&p.buffer_size, tokens[3]) != 0) {
84 		snprintf(out, out_size, MSG_ARG_INVALID, "buffer_size");
85 		return;
86 	}
87 
88 	if (strcmp(tokens[4], "pool") != 0) {
89 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pool");
90 		return;
91 	}
92 
93 	if (parser_read_uint32(&p.pool_size, tokens[5]) != 0) {
94 		snprintf(out, out_size, MSG_ARG_INVALID, "pool_size");
95 		return;
96 	}
97 
98 	if (strcmp(tokens[6], "cache") != 0) {
99 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cache");
100 		return;
101 	}
102 
103 	if (parser_read_uint32(&p.cache_size, tokens[7]) != 0) {
104 		snprintf(out, out_size, MSG_ARG_INVALID, "cache_size");
105 		return;
106 	}
107 
108 	if (strcmp(tokens[8], "cpu") != 0) {
109 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu");
110 		return;
111 	}
112 
113 	if (parser_read_uint32(&p.cpu_id, tokens[9]) != 0) {
114 		snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id");
115 		return;
116 	}
117 
118 	mempool = mempool_create(name, &p);
119 	if (mempool == NULL) {
120 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
121 		return;
122 	}
123 }
124 
125 static const char cmd_link_help[] =
126 "link <link_name>\n"
127 "   dev <device_name> | port <port_id>\n"
128 "   rxq <n_queues> <queue_size> <mempool_name>\n"
129 "   txq <n_queues> <queue_size>\n"
130 "   promiscuous on | off\n"
131 "   [rss <qid_0> ... <qid_n>]\n";
132 
133 static void
134 cmd_link(char **tokens,
135 	uint32_t n_tokens,
136 	char *out,
137 	size_t out_size)
138 {
139 	struct link_params p;
140 	struct link_params_rss rss;
141 	struct link *link;
142 	char *name;
143 
144 	memset(&p, 0, sizeof(p));
145 
146 	if ((n_tokens < 13) || (n_tokens > 14 + LINK_RXQ_RSS_MAX)) {
147 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
148 		return;
149 	}
150 	name = tokens[1];
151 
152 	if (strcmp(tokens[2], "dev") == 0)
153 		p.dev_name = tokens[3];
154 	else if (strcmp(tokens[2], "port") == 0) {
155 		p.dev_name = NULL;
156 
157 		if (parser_read_uint16(&p.port_id, tokens[3]) != 0) {
158 			snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
159 			return;
160 		}
161 	} else {
162 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "dev or port");
163 		return;
164 	}
165 
166 	if (strcmp(tokens[4], "rxq") != 0) {
167 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rxq");
168 		return;
169 	}
170 
171 	if (parser_read_uint32(&p.rx.n_queues, tokens[5]) != 0) {
172 		snprintf(out, out_size, MSG_ARG_INVALID, "n_queues");
173 		return;
174 	}
175 	if (parser_read_uint32(&p.rx.queue_size, tokens[6]) != 0) {
176 		snprintf(out, out_size, MSG_ARG_INVALID, "queue_size");
177 		return;
178 	}
179 
180 	p.rx.mempool_name = tokens[7];
181 
182 	if (strcmp(tokens[8], "txq") != 0) {
183 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "txq");
184 		return;
185 	}
186 
187 	if (parser_read_uint32(&p.tx.n_queues, tokens[9]) != 0) {
188 		snprintf(out, out_size, MSG_ARG_INVALID, "n_queues");
189 		return;
190 	}
191 
192 	if (parser_read_uint32(&p.tx.queue_size, tokens[10]) != 0) {
193 		snprintf(out, out_size, MSG_ARG_INVALID, "queue_size");
194 		return;
195 	}
196 
197 	if (strcmp(tokens[11], "promiscuous") != 0) {
198 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "promiscuous");
199 		return;
200 	}
201 
202 	if (strcmp(tokens[12], "on") == 0)
203 		p.promiscuous = 1;
204 	else if (strcmp(tokens[12], "off") == 0)
205 		p.promiscuous = 0;
206 	else {
207 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "on or off");
208 		return;
209 	}
210 
211 	/* RSS */
212 	p.rx.rss = NULL;
213 	if (n_tokens > 13) {
214 		uint32_t queue_id, i;
215 
216 		if (strcmp(tokens[13], "rss") != 0) {
217 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rss");
218 			return;
219 		}
220 
221 		p.rx.rss = &rss;
222 
223 		rss.n_queues = 0;
224 		for (i = 14; i < n_tokens; i++) {
225 			if (parser_read_uint32(&queue_id, tokens[i]) != 0) {
226 				snprintf(out, out_size, MSG_ARG_INVALID,
227 					"queue_id");
228 				return;
229 			}
230 
231 			rss.queue_id[rss.n_queues] = queue_id;
232 			rss.n_queues++;
233 		}
234 	}
235 
236 	link = link_create(name, &p);
237 	if (link == NULL) {
238 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
239 		return;
240 	}
241 }
242 
243 /* Print the link stats and info */
244 static void
245 print_link_info(struct link *link, char *out, size_t out_size)
246 {
247 	struct rte_eth_stats stats;
248 	struct ether_addr mac_addr;
249 	struct rte_eth_link eth_link;
250 	uint16_t mtu;
251 
252 	memset(&stats, 0, sizeof(stats));
253 	rte_eth_stats_get(link->port_id, &stats);
254 
255 	rte_eth_macaddr_get(link->port_id, &mac_addr);
256 	rte_eth_link_get(link->port_id, &eth_link);
257 	rte_eth_dev_get_mtu(link->port_id, &mtu);
258 
259 	snprintf(out, out_size,
260 		"\n"
261 		"%s: flags=<%s> mtu %u\n"
262 		"\tether %02X:%02X:%02X:%02X:%02X:%02X rxqueues %u txqueues %u\n"
263 		"\tport# %u  speed %u Mbps\n"
264 		"\tRX packets %" PRIu64"  bytes %" PRIu64"\n"
265 		"\tRX errors %" PRIu64"  missed %" PRIu64"  no-mbuf %" PRIu64"\n"
266 		"\tTX packets %" PRIu64"  bytes %" PRIu64"\n"
267 		"\tTX errors %" PRIu64"\n",
268 		link->name,
269 		eth_link.link_status == 0 ? "DOWN" : "UP",
270 		mtu,
271 		mac_addr.addr_bytes[0], mac_addr.addr_bytes[1],
272 		mac_addr.addr_bytes[2], mac_addr.addr_bytes[3],
273 		mac_addr.addr_bytes[4], mac_addr.addr_bytes[5],
274 		link->n_rxq,
275 		link->n_txq,
276 		link->port_id,
277 		eth_link.link_speed,
278 		stats.ipackets,
279 		stats.ibytes,
280 		stats.ierrors,
281 		stats.imissed,
282 		stats.rx_nombuf,
283 		stats.opackets,
284 		stats.obytes,
285 		stats.oerrors);
286 }
287 
288 /*
289  * link show [<link_name>]
290  */
291 static void
292 cmd_link_show(char **tokens, uint32_t n_tokens, char *out, size_t out_size)
293 {
294 	struct link *link;
295 	char *link_name;
296 
297 	if (n_tokens != 2 && n_tokens != 3) {
298 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
299 		return;
300 	}
301 
302 	if (n_tokens == 2) {
303 		link = link_next(NULL);
304 
305 		while (link != NULL) {
306 			out_size = out_size - strlen(out);
307 			out = &out[strlen(out)];
308 
309 			print_link_info(link, out, out_size);
310 			link = link_next(link);
311 		}
312 	} else {
313 		out_size = out_size - strlen(out);
314 		out = &out[strlen(out)];
315 
316 		link_name = tokens[2];
317 		link = link_find(link_name);
318 
319 		if (link == NULL) {
320 			snprintf(out, out_size, MSG_ARG_INVALID,
321 					"Link does not exist");
322 			return;
323 		}
324 		print_link_info(link, out, out_size);
325 	}
326 }
327 
328 static const char cmd_swq_help[] =
329 "swq <swq_name>\n"
330 "   size <size>\n"
331 "   cpu <cpu_id>\n";
332 
333 static void
334 cmd_swq(char **tokens,
335 	uint32_t n_tokens,
336 	char *out,
337 	size_t out_size)
338 {
339 	struct swq_params p;
340 	char *name;
341 	struct swq *swq;
342 
343 	if (n_tokens != 6) {
344 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
345 		return;
346 	}
347 
348 	name = tokens[1];
349 
350 	if (strcmp(tokens[2], "size") != 0) {
351 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
352 		return;
353 	}
354 
355 	if (parser_read_uint32(&p.size, tokens[3]) != 0) {
356 		snprintf(out, out_size, MSG_ARG_INVALID, "size");
357 		return;
358 	}
359 
360 	if (strcmp(tokens[4], "cpu") != 0) {
361 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu");
362 		return;
363 	}
364 
365 	if (parser_read_uint32(&p.cpu_id, tokens[5]) != 0) {
366 		snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id");
367 		return;
368 	}
369 
370 	swq = swq_create(name, &p);
371 	if (swq == NULL) {
372 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
373 		return;
374 	}
375 }
376 
377 static const char cmd_tmgr_subport_profile_help[] =
378 "tmgr subport profile\n"
379 "   <tb_rate> <tb_size>\n"
380 "   <tc0_rate> <tc1_rate> <tc2_rate> <tc3_rate>\n"
381 "   <tc_period>\n";
382 
383 static void
384 cmd_tmgr_subport_profile(char **tokens,
385 	uint32_t n_tokens,
386 	char *out,
387 	size_t out_size)
388 {
389 	struct rte_sched_subport_params p;
390 	int status, i;
391 
392 	if (n_tokens != 10) {
393 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
394 		return;
395 	}
396 
397 	if (parser_read_uint32(&p.tb_rate, tokens[3]) != 0) {
398 		snprintf(out, out_size, MSG_ARG_INVALID, "tb_rate");
399 		return;
400 	}
401 
402 	if (parser_read_uint32(&p.tb_size, tokens[4]) != 0) {
403 		snprintf(out, out_size, MSG_ARG_INVALID, "tb_size");
404 		return;
405 	}
406 
407 	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
408 		if (parser_read_uint32(&p.tc_rate[i], tokens[5 + i]) != 0) {
409 			snprintf(out, out_size, MSG_ARG_INVALID, "tc_rate");
410 			return;
411 		}
412 
413 	if (parser_read_uint32(&p.tc_period, tokens[9]) != 0) {
414 		snprintf(out, out_size, MSG_ARG_INVALID, "tc_period");
415 		return;
416 	}
417 
418 	status = tmgr_subport_profile_add(&p);
419 	if (status != 0) {
420 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
421 		return;
422 	}
423 }
424 
425 static const char cmd_tmgr_pipe_profile_help[] =
426 "tmgr pipe profile\n"
427 "   <tb_rate> <tb_size>\n"
428 "   <tc0_rate> <tc1_rate> <tc2_rate> <tc3_rate>\n"
429 "   <tc_period>\n"
430 "   <tc_ov_weight>\n"
431 "   <wrr_weight0..15>\n";
432 
433 static void
434 cmd_tmgr_pipe_profile(char **tokens,
435 	uint32_t n_tokens,
436 	char *out,
437 	size_t out_size)
438 {
439 	struct rte_sched_pipe_params p;
440 	int status, i;
441 
442 	if (n_tokens != 27) {
443 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
444 		return;
445 	}
446 
447 	if (parser_read_uint32(&p.tb_rate, tokens[3]) != 0) {
448 		snprintf(out, out_size, MSG_ARG_INVALID, "tb_rate");
449 		return;
450 	}
451 
452 	if (parser_read_uint32(&p.tb_size, tokens[4]) != 0) {
453 		snprintf(out, out_size, MSG_ARG_INVALID, "tb_size");
454 		return;
455 	}
456 
457 	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
458 		if (parser_read_uint32(&p.tc_rate[i], tokens[5 + i]) != 0) {
459 			snprintf(out, out_size, MSG_ARG_INVALID, "tc_rate");
460 			return;
461 		}
462 
463 	if (parser_read_uint32(&p.tc_period, tokens[9]) != 0) {
464 		snprintf(out, out_size, MSG_ARG_INVALID, "tc_period");
465 		return;
466 	}
467 
468 #ifdef RTE_SCHED_SUBPORT_TC_OV
469 	if (parser_read_uint8(&p.tc_ov_weight, tokens[10]) != 0) {
470 		snprintf(out, out_size, MSG_ARG_INVALID, "tc_ov_weight");
471 		return;
472 	}
473 #endif
474 
475 	for (i = 0; i < RTE_SCHED_QUEUES_PER_PIPE; i++)
476 		if (parser_read_uint8(&p.wrr_weights[i], tokens[11 + i]) != 0) {
477 			snprintf(out, out_size, MSG_ARG_INVALID, "wrr_weights");
478 			return;
479 		}
480 
481 	status = tmgr_pipe_profile_add(&p);
482 	if (status != 0) {
483 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
484 		return;
485 	}
486 }
487 
488 static const char cmd_tmgr_help[] =
489 "tmgr <tmgr_name>\n"
490 "   rate <rate>\n"
491 "   spp <n_subports_per_port>\n"
492 "   pps <n_pipes_per_subport>\n"
493 "   qsize <qsize_tc0> <qsize_tc1> <qsize_tc2> <qsize_tc3>\n"
494 "   fo <frame_overhead>\n"
495 "   mtu <mtu>\n"
496 "   cpu <cpu_id>\n";
497 
498 static void
499 cmd_tmgr(char **tokens,
500 	uint32_t n_tokens,
501 	char *out,
502 	size_t out_size)
503 {
504 	struct tmgr_port_params p;
505 	char *name;
506 	struct tmgr_port *tmgr_port;
507 	int i;
508 
509 	if (n_tokens != 19) {
510 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
511 		return;
512 	}
513 
514 	name = tokens[1];
515 
516 	if (strcmp(tokens[2], "rate") != 0) {
517 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rate");
518 		return;
519 	}
520 
521 	if (parser_read_uint32(&p.rate, tokens[3]) != 0) {
522 		snprintf(out, out_size, MSG_ARG_INVALID, "rate");
523 		return;
524 	}
525 
526 	if (strcmp(tokens[4], "spp") != 0) {
527 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "spp");
528 		return;
529 	}
530 
531 	if (parser_read_uint32(&p.n_subports_per_port, tokens[5]) != 0) {
532 		snprintf(out, out_size, MSG_ARG_INVALID, "n_subports_per_port");
533 		return;
534 	}
535 
536 	if (strcmp(tokens[6], "pps") != 0) {
537 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pps");
538 		return;
539 	}
540 
541 	if (parser_read_uint32(&p.n_pipes_per_subport, tokens[7]) != 0) {
542 		snprintf(out, out_size, MSG_ARG_INVALID, "n_pipes_per_subport");
543 		return;
544 	}
545 
546 	if (strcmp(tokens[8], "qsize") != 0) {
547 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "qsize");
548 		return;
549 	}
550 
551 	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
552 		if (parser_read_uint16(&p.qsize[i], tokens[9 + i]) != 0) {
553 			snprintf(out, out_size, MSG_ARG_INVALID, "qsize");
554 			return;
555 		}
556 
557 	if (strcmp(tokens[13], "fo") != 0) {
558 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "fo");
559 		return;
560 	}
561 
562 	if (parser_read_uint32(&p.frame_overhead, tokens[14]) != 0) {
563 		snprintf(out, out_size, MSG_ARG_INVALID, "frame_overhead");
564 		return;
565 	}
566 
567 	if (strcmp(tokens[15], "mtu") != 0) {
568 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mtu");
569 		return;
570 	}
571 
572 	if (parser_read_uint32(&p.mtu, tokens[16]) != 0) {
573 		snprintf(out, out_size, MSG_ARG_INVALID, "mtu");
574 		return;
575 	}
576 
577 	if (strcmp(tokens[17], "cpu") != 0) {
578 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu");
579 		return;
580 	}
581 
582 	if (parser_read_uint32(&p.cpu_id, tokens[18]) != 0) {
583 		snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id");
584 		return;
585 	}
586 
587 	tmgr_port = tmgr_port_create(name, &p);
588 	if (tmgr_port == NULL) {
589 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
590 		return;
591 	}
592 }
593 
594 static const char cmd_tmgr_subport_help[] =
595 "tmgr <tmgr_name> subport <subport_id>\n"
596 "   profile <subport_profile_id>\n";
597 
598 static void
599 cmd_tmgr_subport(char **tokens,
600 	uint32_t n_tokens,
601 	char *out,
602 	size_t out_size)
603 {
604 	uint32_t subport_id, subport_profile_id;
605 	int status;
606 	char *name;
607 
608 	if (n_tokens != 6) {
609 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
610 		return;
611 	}
612 
613 	name = tokens[1];
614 
615 	if (parser_read_uint32(&subport_id, tokens[3]) != 0) {
616 		snprintf(out, out_size, MSG_ARG_INVALID, "subport_id");
617 		return;
618 	}
619 
620 	if (parser_read_uint32(&subport_profile_id, tokens[5]) != 0) {
621 		snprintf(out, out_size, MSG_ARG_INVALID, "subport_profile_id");
622 		return;
623 	}
624 
625 	status = tmgr_subport_config(name, subport_id, subport_profile_id);
626 	if (status) {
627 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
628 		return;
629 	}
630 }
631 
632 
633 static const char cmd_tmgr_subport_pipe_help[] =
634 "tmgr <tmgr_name> subport <subport_id> pipe\n"
635 "   from <pipe_id_first> to <pipe_id_last>\n"
636 "   profile <pipe_profile_id>\n";
637 
638 static void
639 cmd_tmgr_subport_pipe(char **tokens,
640 	uint32_t n_tokens,
641 	char *out,
642 	size_t out_size)
643 {
644 	uint32_t subport_id, pipe_id_first, pipe_id_last, pipe_profile_id;
645 	int status;
646 	char *name;
647 
648 	if (n_tokens != 11) {
649 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
650 		return;
651 	}
652 
653 	name = tokens[1];
654 
655 	if (parser_read_uint32(&subport_id, tokens[3]) != 0) {
656 		snprintf(out, out_size, MSG_ARG_INVALID, "subport_id");
657 		return;
658 	}
659 
660 	if (strcmp(tokens[4], "pipe") != 0) {
661 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipe");
662 		return;
663 	}
664 
665 	if (strcmp(tokens[5], "from") != 0) {
666 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "from");
667 		return;
668 	}
669 
670 	if (parser_read_uint32(&pipe_id_first, tokens[6]) != 0) {
671 		snprintf(out, out_size, MSG_ARG_INVALID, "pipe_id_first");
672 		return;
673 	}
674 
675 	if (strcmp(tokens[7], "to") != 0) {
676 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "to");
677 		return;
678 	}
679 
680 	if (parser_read_uint32(&pipe_id_last, tokens[8]) != 0) {
681 		snprintf(out, out_size, MSG_ARG_INVALID, "pipe_id_last");
682 		return;
683 	}
684 
685 	if (strcmp(tokens[9], "profile") != 0) {
686 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
687 		return;
688 	}
689 
690 	if (parser_read_uint32(&pipe_profile_id, tokens[10]) != 0) {
691 		snprintf(out, out_size, MSG_ARG_INVALID, "pipe_profile_id");
692 		return;
693 	}
694 
695 	status = tmgr_pipe_config(name, subport_id, pipe_id_first,
696 			pipe_id_last, pipe_profile_id);
697 	if (status) {
698 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
699 		return;
700 	}
701 }
702 
703 
704 static const char cmd_tap_help[] =
705 "tap <tap_name>\n";
706 
707 static void
708 cmd_tap(char **tokens,
709 	uint32_t n_tokens,
710 	char *out,
711 	size_t out_size)
712 {
713 	char *name;
714 	struct tap *tap;
715 
716 	if (n_tokens != 2) {
717 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
718 		return;
719 	}
720 
721 	name = tokens[1];
722 
723 	tap = tap_create(name);
724 	if (tap == NULL) {
725 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
726 		return;
727 	}
728 }
729 
730 static const char cmd_kni_help[] =
731 "kni <kni_name>\n"
732 "   link <link_name>\n"
733 "   mempool <mempool_name>\n"
734 "   [thread <thread_id>]\n";
735 
736 static void
737 cmd_kni(char **tokens,
738 	uint32_t n_tokens,
739 	char *out,
740 	size_t out_size)
741 {
742 	struct kni_params p;
743 	char *name;
744 	struct kni *kni;
745 
746 	memset(&p, 0, sizeof(p));
747 	if ((n_tokens != 6) && (n_tokens != 8)) {
748 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
749 		return;
750 	}
751 
752 	name = tokens[1];
753 
754 	if (strcmp(tokens[2], "link") != 0) {
755 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "link");
756 		return;
757 	}
758 
759 	p.link_name = tokens[3];
760 
761 	if (strcmp(tokens[4], "mempool") != 0) {
762 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mempool");
763 		return;
764 	}
765 
766 	p.mempool_name = tokens[5];
767 
768 	if (n_tokens == 8) {
769 		if (strcmp(tokens[6], "thread") != 0) {
770 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "thread");
771 			return;
772 		}
773 
774 		if (parser_read_uint32(&p.thread_id, tokens[7]) != 0) {
775 			snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
776 			return;
777 		}
778 
779 		p.force_bind = 1;
780 	} else
781 		p.force_bind = 0;
782 
783 	kni = kni_create(name, &p);
784 	if (kni == NULL) {
785 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
786 		return;
787 	}
788 }
789 
790 static const char cmd_cryptodev_help[] =
791 "cryptodev <cryptodev_name>\n"
792 "   dev <device_name> | dev_id <device_id>\n"
793 "   queue <n_queues> <queue_size>\n";
794 
795 static void
796 cmd_cryptodev(char **tokens,
797 	uint32_t n_tokens,
798 	char *out,
799 	size_t out_size)
800 {
801 	struct cryptodev_params params;
802 	char *name;
803 
804 	memset(&params, 0, sizeof(params));
805 	if (n_tokens != 7) {
806 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
807 		return;
808 	}
809 
810 	name = tokens[1];
811 
812 	if (strcmp(tokens[2], "dev") == 0)
813 		params.dev_name = tokens[3];
814 	else if (strcmp(tokens[2], "dev_id") == 0) {
815 		if (parser_read_uint32(&params.dev_id, tokens[3]) < 0) {
816 			snprintf(out, out_size,	MSG_ARG_INVALID,
817 				"dev_id");
818 			return;
819 		}
820 	} else {
821 		snprintf(out, out_size,	MSG_ARG_INVALID,
822 			"cryptodev");
823 		return;
824 	}
825 
826 	if (strcmp(tokens[4], "queue")) {
827 		snprintf(out, out_size,	MSG_ARG_NOT_FOUND,
828 			"4");
829 		return;
830 	}
831 
832 	if (parser_read_uint32(&params.n_queues, tokens[5]) < 0) {
833 		snprintf(out, out_size,	MSG_ARG_INVALID,
834 			"q");
835 		return;
836 	}
837 
838 	if (parser_read_uint32(&params.queue_size, tokens[6]) < 0) {
839 		snprintf(out, out_size,	MSG_ARG_INVALID,
840 			"queue_size");
841 		return;
842 	}
843 
844 	if (cryptodev_create(name, &params) == NULL) {
845 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
846 		return;
847 	}
848 }
849 
850 static const char cmd_port_in_action_profile_help[] =
851 "port in action profile <profile_name>\n"
852 "   [filter match | mismatch offset <key_offset> mask <key_mask> key <key_value> port <port_id>]\n"
853 "   [balance offset <key_offset> mask <key_mask> port <port_id0> ... <port_id15>]\n";
854 
855 static void
856 cmd_port_in_action_profile(char **tokens,
857 	uint32_t n_tokens,
858 	char *out,
859 	size_t out_size)
860 {
861 	struct port_in_action_profile_params p;
862 	struct port_in_action_profile *ap;
863 	char *name;
864 	uint32_t t0;
865 
866 	memset(&p, 0, sizeof(p));
867 
868 	if (n_tokens < 5) {
869 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
870 		return;
871 	}
872 
873 	if (strcmp(tokens[1], "in") != 0) {
874 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
875 		return;
876 	}
877 
878 	if (strcmp(tokens[2], "action") != 0) {
879 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "action");
880 		return;
881 	}
882 
883 	if (strcmp(tokens[3], "profile") != 0) {
884 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
885 		return;
886 	}
887 
888 	name = tokens[4];
889 
890 	t0 = 5;
891 
892 	if ((t0 < n_tokens) && (strcmp(tokens[t0], "filter") == 0)) {
893 		uint32_t size;
894 
895 		if (n_tokens < t0 + 10) {
896 			snprintf(out, out_size, MSG_ARG_MISMATCH, "port in action profile filter");
897 			return;
898 		}
899 
900 		if (strcmp(tokens[t0 + 1], "match") == 0)
901 			p.fltr.filter_on_match = 1;
902 		else if (strcmp(tokens[t0 + 1], "mismatch") == 0)
903 			p.fltr.filter_on_match = 0;
904 		else {
905 			snprintf(out, out_size, MSG_ARG_INVALID, "match or mismatch");
906 			return;
907 		}
908 
909 		if (strcmp(tokens[t0 + 2], "offset") != 0) {
910 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
911 			return;
912 		}
913 
914 		if (parser_read_uint32(&p.fltr.key_offset, tokens[t0 + 3]) != 0) {
915 			snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
916 			return;
917 		}
918 
919 		if (strcmp(tokens[t0 + 4], "mask") != 0) {
920 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask");
921 			return;
922 		}
923 
924 		size = RTE_PORT_IN_ACTION_FLTR_KEY_SIZE;
925 		if ((parse_hex_string(tokens[t0 + 5], p.fltr.key_mask, &size) != 0) ||
926 			(size != RTE_PORT_IN_ACTION_FLTR_KEY_SIZE)) {
927 			snprintf(out, out_size, MSG_ARG_INVALID, "key_mask");
928 			return;
929 		}
930 
931 		if (strcmp(tokens[t0 + 6], "key") != 0) {
932 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "key");
933 			return;
934 		}
935 
936 		size = RTE_PORT_IN_ACTION_FLTR_KEY_SIZE;
937 		if ((parse_hex_string(tokens[t0 + 7], p.fltr.key, &size) != 0) ||
938 			(size != RTE_PORT_IN_ACTION_FLTR_KEY_SIZE)) {
939 			snprintf(out, out_size, MSG_ARG_INVALID, "key_value");
940 			return;
941 		}
942 
943 		if (strcmp(tokens[t0 + 8], "port") != 0) {
944 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
945 			return;
946 		}
947 
948 		if (parser_read_uint32(&p.fltr.port_id, tokens[t0 + 9]) != 0) {
949 			snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
950 			return;
951 		}
952 
953 		p.action_mask |= 1LLU << RTE_PORT_IN_ACTION_FLTR;
954 		t0 += 10;
955 	} /* filter */
956 
957 	if ((t0 < n_tokens) && (strcmp(tokens[t0], "balance") == 0)) {
958 		uint32_t i;
959 
960 		if (n_tokens < t0 + 22) {
961 			snprintf(out, out_size, MSG_ARG_MISMATCH,
962 				"port in action profile balance");
963 			return;
964 		}
965 
966 		if (strcmp(tokens[t0 + 1], "offset") != 0) {
967 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
968 			return;
969 		}
970 
971 		if (parser_read_uint32(&p.lb.key_offset, tokens[t0 + 2]) != 0) {
972 			snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
973 			return;
974 		}
975 
976 		if (strcmp(tokens[t0 + 3], "mask") != 0) {
977 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask");
978 			return;
979 		}
980 
981 		p.lb.key_size = RTE_PORT_IN_ACTION_LB_KEY_SIZE_MAX;
982 		if (parse_hex_string(tokens[t0 + 4], p.lb.key_mask, &p.lb.key_size) != 0) {
983 			snprintf(out, out_size, MSG_ARG_INVALID, "key_mask");
984 			return;
985 		}
986 
987 		if (strcmp(tokens[t0 + 5], "port") != 0) {
988 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
989 			return;
990 		}
991 
992 		for (i = 0; i < 16; i++)
993 			if (parser_read_uint32(&p.lb.port_id[i], tokens[t0 + 6 + i]) != 0) {
994 				snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
995 				return;
996 			}
997 
998 		p.action_mask |= 1LLU << RTE_PORT_IN_ACTION_LB;
999 		t0 += 22;
1000 	} /* balance */
1001 
1002 	if (t0 < n_tokens) {
1003 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1004 		return;
1005 	}
1006 
1007 	ap = port_in_action_profile_create(name, &p);
1008 	if (ap == NULL) {
1009 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1010 		return;
1011 	}
1012 }
1013 
1014 
1015 static const char cmd_table_action_profile_help[] =
1016 "table action profile <profile_name>\n"
1017 "   ipv4 | ipv6\n"
1018 "   offset <ip_offset>\n"
1019 "   fwd\n"
1020 "   [balance offset <key_offset> mask <key_mask> outoffset <out_offset>]\n"
1021 "   [meter srtcm | trtcm\n"
1022 "       tc <n_tc>\n"
1023 "       stats none | pkts | bytes | both]\n"
1024 "   [tm spp <n_subports_per_port> pps <n_pipes_per_subport>]\n"
1025 "   [encap ether | vlan | qinq | mpls | pppoe |\n"
1026 "       vxlan offset <ether_offset> ipv4 | ipv6 vlan on | off]\n"
1027 "   [nat src | dst\n"
1028 "       proto udp | tcp]\n"
1029 "   [ttl drop | fwd\n"
1030 "       stats none | pkts]\n"
1031 "   [stats pkts | bytes | both]\n"
1032 "   [time]\n"
1033 "   [sym_crypto dev <CRYPTODEV_NAME> offset <op_offset> "
1034 "       mempool_create <mempool_name>\n"
1035 "       mempool_init <mempool_name>]\n"
1036 "   [tag]\n"
1037 "   [decap]\n";
1038 
1039 static void
1040 cmd_table_action_profile(char **tokens,
1041 	uint32_t n_tokens,
1042 	char *out,
1043 	size_t out_size)
1044 {
1045 	struct table_action_profile_params p;
1046 	struct table_action_profile *ap;
1047 	char *name;
1048 	uint32_t t0;
1049 
1050 	memset(&p, 0, sizeof(p));
1051 
1052 	if (n_tokens < 8) {
1053 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1054 		return;
1055 	}
1056 
1057 	if (strcmp(tokens[1], "action") != 0) {
1058 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "action");
1059 		return;
1060 	}
1061 
1062 	if (strcmp(tokens[2], "profile") != 0) {
1063 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
1064 		return;
1065 	}
1066 
1067 	name = tokens[3];
1068 
1069 	if (strcmp(tokens[4], "ipv4") == 0)
1070 		p.common.ip_version = 1;
1071 	else if (strcmp(tokens[4], "ipv6") == 0)
1072 		p.common.ip_version = 0;
1073 	else {
1074 		snprintf(out, out_size, MSG_ARG_INVALID, "ipv4 or ipv6");
1075 		return;
1076 	}
1077 
1078 	if (strcmp(tokens[5], "offset") != 0) {
1079 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
1080 		return;
1081 	}
1082 
1083 	if (parser_read_uint32(&p.common.ip_offset, tokens[6]) != 0) {
1084 		snprintf(out, out_size, MSG_ARG_INVALID, "ip_offset");
1085 		return;
1086 	}
1087 
1088 	if (strcmp(tokens[7], "fwd") != 0) {
1089 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "fwd");
1090 		return;
1091 	}
1092 
1093 	p.action_mask |= 1LLU << RTE_TABLE_ACTION_FWD;
1094 
1095 	t0 = 8;
1096 	if ((t0 < n_tokens) && (strcmp(tokens[t0], "balance") == 0)) {
1097 		if (n_tokens < t0 + 7) {
1098 			snprintf(out, out_size, MSG_ARG_MISMATCH, "table action profile balance");
1099 			return;
1100 		}
1101 
1102 		if (strcmp(tokens[t0 + 1], "offset") != 0) {
1103 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
1104 			return;
1105 		}
1106 
1107 		if (parser_read_uint32(&p.lb.key_offset, tokens[t0 + 2]) != 0) {
1108 			snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
1109 			return;
1110 		}
1111 
1112 		if (strcmp(tokens[t0 + 3], "mask") != 0) {
1113 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask");
1114 			return;
1115 		}
1116 
1117 		p.lb.key_size = RTE_PORT_IN_ACTION_LB_KEY_SIZE_MAX;
1118 		if (parse_hex_string(tokens[t0 + 4], p.lb.key_mask, &p.lb.key_size) != 0) {
1119 			snprintf(out, out_size, MSG_ARG_INVALID, "key_mask");
1120 			return;
1121 		}
1122 
1123 		if (strcmp(tokens[t0 + 5], "outoffset") != 0) {
1124 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "outoffset");
1125 			return;
1126 		}
1127 
1128 		if (parser_read_uint32(&p.lb.out_offset, tokens[t0 + 6]) != 0) {
1129 			snprintf(out, out_size, MSG_ARG_INVALID, "out_offset");
1130 			return;
1131 		}
1132 
1133 		p.action_mask |= 1LLU << RTE_TABLE_ACTION_LB;
1134 		t0 += 7;
1135 	} /* balance */
1136 
1137 	if ((t0 < n_tokens) && (strcmp(tokens[t0], "meter") == 0)) {
1138 		if (n_tokens < t0 + 6) {
1139 			snprintf(out, out_size, MSG_ARG_MISMATCH,
1140 				"table action profile meter");
1141 			return;
1142 		}
1143 
1144 		if (strcmp(tokens[t0 + 1], "srtcm") == 0)
1145 			p.mtr.alg = RTE_TABLE_ACTION_METER_SRTCM;
1146 		else if (strcmp(tokens[t0 + 1], "trtcm") == 0)
1147 			p.mtr.alg = RTE_TABLE_ACTION_METER_TRTCM;
1148 		else {
1149 			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1150 				"srtcm or trtcm");
1151 			return;
1152 		}
1153 
1154 		if (strcmp(tokens[t0 + 2], "tc") != 0) {
1155 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc");
1156 			return;
1157 		}
1158 
1159 		if (parser_read_uint32(&p.mtr.n_tc, tokens[t0 + 3]) != 0) {
1160 			snprintf(out, out_size, MSG_ARG_INVALID, "n_tc");
1161 			return;
1162 		}
1163 
1164 		if (strcmp(tokens[t0 + 4], "stats") != 0) {
1165 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
1166 			return;
1167 		}
1168 
1169 		if (strcmp(tokens[t0 + 5], "none") == 0) {
1170 			p.mtr.n_packets_enabled = 0;
1171 			p.mtr.n_bytes_enabled = 0;
1172 		} else if (strcmp(tokens[t0 + 5], "pkts") == 0) {
1173 			p.mtr.n_packets_enabled = 1;
1174 			p.mtr.n_bytes_enabled = 0;
1175 		} else if (strcmp(tokens[t0 + 5], "bytes") == 0) {
1176 			p.mtr.n_packets_enabled = 0;
1177 			p.mtr.n_bytes_enabled = 1;
1178 		} else if (strcmp(tokens[t0 + 5], "both") == 0) {
1179 			p.mtr.n_packets_enabled = 1;
1180 			p.mtr.n_bytes_enabled = 1;
1181 		} else {
1182 			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1183 				"none or pkts or bytes or both");
1184 			return;
1185 		}
1186 
1187 		p.action_mask |= 1LLU << RTE_TABLE_ACTION_MTR;
1188 		t0 += 6;
1189 	} /* meter */
1190 
1191 	if ((t0 < n_tokens) && (strcmp(tokens[t0], "tm") == 0)) {
1192 		if (n_tokens < t0 + 5) {
1193 			snprintf(out, out_size, MSG_ARG_MISMATCH,
1194 				"table action profile tm");
1195 			return;
1196 		}
1197 
1198 		if (strcmp(tokens[t0 + 1], "spp") != 0) {
1199 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "spp");
1200 			return;
1201 		}
1202 
1203 		if (parser_read_uint32(&p.tm.n_subports_per_port,
1204 			tokens[t0 + 2]) != 0) {
1205 			snprintf(out, out_size, MSG_ARG_INVALID,
1206 				"n_subports_per_port");
1207 			return;
1208 		}
1209 
1210 		if (strcmp(tokens[t0 + 3], "pps") != 0) {
1211 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pps");
1212 			return;
1213 		}
1214 
1215 		if (parser_read_uint32(&p.tm.n_pipes_per_subport,
1216 			tokens[t0 + 4]) != 0) {
1217 			snprintf(out, out_size, MSG_ARG_INVALID,
1218 				"n_pipes_per_subport");
1219 			return;
1220 		}
1221 
1222 		p.action_mask |= 1LLU << RTE_TABLE_ACTION_TM;
1223 		t0 += 5;
1224 	} /* tm */
1225 
1226 	if ((t0 < n_tokens) && (strcmp(tokens[t0], "encap") == 0)) {
1227 		uint32_t n_extra_tokens = 0;
1228 
1229 		if (n_tokens < t0 + 2) {
1230 			snprintf(out, out_size, MSG_ARG_MISMATCH,
1231 				"action profile encap");
1232 			return;
1233 		}
1234 
1235 		if (strcmp(tokens[t0 + 1], "ether") == 0)
1236 			p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_ETHER;
1237 		else if (strcmp(tokens[t0 + 1], "vlan") == 0)
1238 			p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_VLAN;
1239 		else if (strcmp(tokens[t0 + 1], "qinq") == 0)
1240 			p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_QINQ;
1241 		else if (strcmp(tokens[t0 + 1], "mpls") == 0)
1242 			p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_MPLS;
1243 		else if (strcmp(tokens[t0 + 1], "pppoe") == 0)
1244 			p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_PPPOE;
1245 		else if (strcmp(tokens[t0 + 1], "vxlan") == 0) {
1246 			if (n_tokens < t0 + 2 + 5) {
1247 				snprintf(out, out_size, MSG_ARG_MISMATCH,
1248 					"action profile encap vxlan");
1249 				return;
1250 			}
1251 
1252 			if (strcmp(tokens[t0 + 2], "offset") != 0) {
1253 				snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1254 					"vxlan: offset");
1255 				return;
1256 			}
1257 
1258 			if (parser_read_uint32(&p.encap.vxlan.data_offset,
1259 				tokens[t0 + 2 + 1]) != 0) {
1260 				snprintf(out, out_size, MSG_ARG_INVALID,
1261 					"vxlan: ether_offset");
1262 				return;
1263 			}
1264 
1265 			if (strcmp(tokens[t0 + 2 + 2], "ipv4") == 0)
1266 				p.encap.vxlan.ip_version = 1;
1267 			else if (strcmp(tokens[t0 + 2 + 2], "ipv6") == 0)
1268 				p.encap.vxlan.ip_version = 0;
1269 			else {
1270 				snprintf(out, out_size, MSG_ARG_INVALID,
1271 					"vxlan: ipv4 or ipv6");
1272 				return;
1273 			}
1274 
1275 			if (strcmp(tokens[t0 + 2 + 3], "vlan") != 0) {
1276 				snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1277 					"vxlan: vlan");
1278 				return;
1279 			}
1280 
1281 			if (strcmp(tokens[t0 + 2 + 4], "on") == 0)
1282 				p.encap.vxlan.vlan = 1;
1283 			else if (strcmp(tokens[t0 + 2 + 4], "off") == 0)
1284 				p.encap.vxlan.vlan = 0;
1285 			else {
1286 				snprintf(out, out_size, MSG_ARG_INVALID,
1287 					"vxlan: on or off");
1288 				return;
1289 			}
1290 
1291 			p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_VXLAN;
1292 			n_extra_tokens = 5;
1293 		} else {
1294 			snprintf(out, out_size, MSG_ARG_MISMATCH, "encap");
1295 			return;
1296 		}
1297 
1298 		p.action_mask |= 1LLU << RTE_TABLE_ACTION_ENCAP;
1299 		t0 += 2 + n_extra_tokens;
1300 	} /* encap */
1301 
1302 	if ((t0 < n_tokens) && (strcmp(tokens[t0], "nat") == 0)) {
1303 		if (n_tokens < t0 + 4) {
1304 			snprintf(out, out_size, MSG_ARG_MISMATCH,
1305 				"table action profile nat");
1306 			return;
1307 		}
1308 
1309 		if (strcmp(tokens[t0 + 1], "src") == 0)
1310 			p.nat.source_nat = 1;
1311 		else if (strcmp(tokens[t0 + 1], "dst") == 0)
1312 			p.nat.source_nat = 0;
1313 		else {
1314 			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1315 				"src or dst");
1316 			return;
1317 		}
1318 
1319 		if (strcmp(tokens[t0 + 2], "proto") != 0) {
1320 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "proto");
1321 			return;
1322 		}
1323 
1324 		if (strcmp(tokens[t0 + 3], "tcp") == 0)
1325 			p.nat.proto = 0x06;
1326 		else if (strcmp(tokens[t0 + 3], "udp") == 0)
1327 			p.nat.proto = 0x11;
1328 		else {
1329 			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1330 				"tcp or udp");
1331 			return;
1332 		}
1333 
1334 		p.action_mask |= 1LLU << RTE_TABLE_ACTION_NAT;
1335 		t0 += 4;
1336 	} /* nat */
1337 
1338 	if ((t0 < n_tokens) && (strcmp(tokens[t0], "ttl") == 0)) {
1339 		if (n_tokens < t0 + 4) {
1340 			snprintf(out, out_size, MSG_ARG_MISMATCH,
1341 				"table action profile ttl");
1342 			return;
1343 		}
1344 
1345 		if (strcmp(tokens[t0 + 1], "drop") == 0)
1346 			p.ttl.drop = 1;
1347 		else if (strcmp(tokens[t0 + 1], "fwd") == 0)
1348 			p.ttl.drop = 0;
1349 		else {
1350 			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1351 				"drop or fwd");
1352 			return;
1353 		}
1354 
1355 		if (strcmp(tokens[t0 + 2], "stats") != 0) {
1356 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
1357 			return;
1358 		}
1359 
1360 		if (strcmp(tokens[t0 + 3], "none") == 0)
1361 			p.ttl.n_packets_enabled = 0;
1362 		else if (strcmp(tokens[t0 + 3], "pkts") == 0)
1363 			p.ttl.n_packets_enabled = 1;
1364 		else {
1365 			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1366 				"none or pkts");
1367 			return;
1368 		}
1369 
1370 		p.action_mask |= 1LLU << RTE_TABLE_ACTION_TTL;
1371 		t0 += 4;
1372 	} /* ttl */
1373 
1374 	if ((t0 < n_tokens) && (strcmp(tokens[t0], "stats") == 0)) {
1375 		if (n_tokens < t0 + 2) {
1376 			snprintf(out, out_size, MSG_ARG_MISMATCH,
1377 				"table action profile stats");
1378 			return;
1379 		}
1380 
1381 		if (strcmp(tokens[t0 + 1], "pkts") == 0) {
1382 			p.stats.n_packets_enabled = 1;
1383 			p.stats.n_bytes_enabled = 0;
1384 		} else if (strcmp(tokens[t0 + 1], "bytes") == 0) {
1385 			p.stats.n_packets_enabled = 0;
1386 			p.stats.n_bytes_enabled = 1;
1387 		} else if (strcmp(tokens[t0 + 1], "both") == 0) {
1388 			p.stats.n_packets_enabled = 1;
1389 			p.stats.n_bytes_enabled = 1;
1390 		} else {
1391 			snprintf(out, out_size,	MSG_ARG_NOT_FOUND,
1392 				"pkts or bytes or both");
1393 			return;
1394 		}
1395 
1396 		p.action_mask |= 1LLU << RTE_TABLE_ACTION_STATS;
1397 		t0 += 2;
1398 	} /* stats */
1399 
1400 	if ((t0 < n_tokens) && (strcmp(tokens[t0], "time") == 0)) {
1401 		p.action_mask |= 1LLU << RTE_TABLE_ACTION_TIME;
1402 		t0 += 1;
1403 	} /* time */
1404 
1405 	if ((t0 < n_tokens) && (strcmp(tokens[t0], "sym_crypto") == 0)) {
1406 		struct cryptodev *cryptodev;
1407 		struct mempool *mempool;
1408 
1409 		if (n_tokens < t0 + 9 ||
1410 				strcmp(tokens[t0 + 1], "dev") ||
1411 				strcmp(tokens[t0 + 3], "offset") ||
1412 				strcmp(tokens[t0 + 5], "mempool_create") ||
1413 				strcmp(tokens[t0 + 7], "mempool_init")) {
1414 			snprintf(out, out_size, MSG_ARG_MISMATCH,
1415 				"table action profile sym_crypto");
1416 			return;
1417 		}
1418 
1419 		cryptodev = cryptodev_find(tokens[t0 + 2]);
1420 		if (cryptodev == NULL) {
1421 			snprintf(out, out_size, MSG_ARG_INVALID,
1422 				"table action profile sym_crypto");
1423 			return;
1424 		}
1425 
1426 		p.sym_crypto.cryptodev_id = cryptodev->dev_id;
1427 
1428 		if (parser_read_uint32(&p.sym_crypto.op_offset,
1429 				tokens[t0 + 4]) != 0) {
1430 			snprintf(out, out_size, MSG_ARG_INVALID,
1431 					"table action profile sym_crypto");
1432 			return;
1433 		}
1434 
1435 		mempool = mempool_find(tokens[t0 + 6]);
1436 		if (mempool == NULL) {
1437 			snprintf(out, out_size, MSG_ARG_INVALID,
1438 				"table action profile sym_crypto");
1439 			return;
1440 		}
1441 		p.sym_crypto.mp_create = mempool->m;
1442 
1443 		mempool = mempool_find(tokens[t0 + 8]);
1444 		if (mempool == NULL) {
1445 			snprintf(out, out_size, MSG_ARG_INVALID,
1446 				"table action profile sym_crypto");
1447 			return;
1448 		}
1449 		p.sym_crypto.mp_init = mempool->m;
1450 
1451 		p.action_mask |= 1LLU << RTE_TABLE_ACTION_SYM_CRYPTO;
1452 
1453 		t0 += 9;
1454 	} /* sym_crypto */
1455 
1456 	if ((t0 < n_tokens) && (strcmp(tokens[t0], "tag") == 0)) {
1457 		p.action_mask |= 1LLU << RTE_TABLE_ACTION_TAG;
1458 		t0 += 1;
1459 	} /* tag */
1460 
1461 	if ((t0 < n_tokens) && (strcmp(tokens[t0], "decap") == 0)) {
1462 		p.action_mask |= 1LLU << RTE_TABLE_ACTION_DECAP;
1463 		t0 += 1;
1464 	} /* decap */
1465 
1466 	if (t0 < n_tokens) {
1467 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1468 		return;
1469 	}
1470 
1471 	ap = table_action_profile_create(name, &p);
1472 	if (ap == NULL) {
1473 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1474 		return;
1475 	}
1476 }
1477 
1478 static const char cmd_pipeline_help[] =
1479 "pipeline <pipeline_name>\n"
1480 "   period <timer_period_ms>\n"
1481 "   offset_port_id <offset_port_id>\n"
1482 "   cpu <cpu_id>\n";
1483 
1484 static void
1485 cmd_pipeline(char **tokens,
1486 	uint32_t n_tokens,
1487 	char *out,
1488 	size_t out_size)
1489 {
1490 	struct pipeline_params p;
1491 	char *name;
1492 	struct pipeline *pipeline;
1493 
1494 	if (n_tokens != 8) {
1495 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1496 		return;
1497 	}
1498 
1499 	name = tokens[1];
1500 
1501 	if (strcmp(tokens[2], "period") != 0) {
1502 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "period");
1503 		return;
1504 	}
1505 
1506 	if (parser_read_uint32(&p.timer_period_ms, tokens[3]) != 0) {
1507 		snprintf(out, out_size, MSG_ARG_INVALID, "timer_period_ms");
1508 		return;
1509 	}
1510 
1511 	if (strcmp(tokens[4], "offset_port_id") != 0) {
1512 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset_port_id");
1513 		return;
1514 	}
1515 
1516 	if (parser_read_uint32(&p.offset_port_id, tokens[5]) != 0) {
1517 		snprintf(out, out_size, MSG_ARG_INVALID, "offset_port_id");
1518 		return;
1519 	}
1520 
1521 	if (strcmp(tokens[6], "cpu") != 0) {
1522 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu");
1523 		return;
1524 	}
1525 
1526 	if (parser_read_uint32(&p.cpu_id, tokens[7]) != 0) {
1527 		snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id");
1528 		return;
1529 	}
1530 
1531 	pipeline = pipeline_create(name, &p);
1532 	if (pipeline == NULL) {
1533 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1534 		return;
1535 	}
1536 }
1537 
1538 static const char cmd_pipeline_port_in_help[] =
1539 "pipeline <pipeline_name> port in\n"
1540 "   bsz <burst_size>\n"
1541 "   link <link_name> rxq <queue_id>\n"
1542 "   | swq <swq_name>\n"
1543 "   | tmgr <tmgr_name>\n"
1544 "   | tap <tap_name> mempool <mempool_name> mtu <mtu>\n"
1545 "   | kni <kni_name>\n"
1546 "   | source mempool <mempool_name> file <file_name> bpp <n_bytes_per_pkt>\n"
1547 "   | cryptodev <cryptodev_name> rxq <queue_id>\n"
1548 "   [action <port_in_action_profile_name>]\n"
1549 "   [disabled]\n";
1550 
1551 static void
1552 cmd_pipeline_port_in(char **tokens,
1553 	uint32_t n_tokens,
1554 	char *out,
1555 	size_t out_size)
1556 {
1557 	struct port_in_params p;
1558 	char *pipeline_name;
1559 	uint32_t t0;
1560 	int enabled, status;
1561 
1562 	if (n_tokens < 7) {
1563 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1564 		return;
1565 	}
1566 
1567 	pipeline_name = tokens[1];
1568 
1569 	if (strcmp(tokens[2], "port") != 0) {
1570 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
1571 		return;
1572 	}
1573 
1574 	if (strcmp(tokens[3], "in") != 0) {
1575 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
1576 		return;
1577 	}
1578 
1579 	if (strcmp(tokens[4], "bsz") != 0) {
1580 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
1581 		return;
1582 	}
1583 
1584 	if (parser_read_uint32(&p.burst_size, tokens[5]) != 0) {
1585 		snprintf(out, out_size, MSG_ARG_INVALID, "burst_size");
1586 		return;
1587 	}
1588 
1589 	t0 = 6;
1590 
1591 	if (strcmp(tokens[t0], "link") == 0) {
1592 		if (n_tokens < t0 + 4) {
1593 			snprintf(out, out_size, MSG_ARG_MISMATCH,
1594 				"pipeline port in link");
1595 			return;
1596 		}
1597 
1598 		p.type = PORT_IN_RXQ;
1599 
1600 		p.dev_name = tokens[t0 + 1];
1601 
1602 		if (strcmp(tokens[t0 + 2], "rxq") != 0) {
1603 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rxq");
1604 			return;
1605 		}
1606 
1607 		if (parser_read_uint16(&p.rxq.queue_id, tokens[t0 + 3]) != 0) {
1608 			snprintf(out, out_size, MSG_ARG_INVALID,
1609 				"queue_id");
1610 			return;
1611 		}
1612 		t0 += 4;
1613 	} else if (strcmp(tokens[t0], "swq") == 0) {
1614 		if (n_tokens < t0 + 2) {
1615 			snprintf(out, out_size, MSG_ARG_MISMATCH,
1616 				"pipeline port in swq");
1617 			return;
1618 		}
1619 
1620 		p.type = PORT_IN_SWQ;
1621 
1622 		p.dev_name = tokens[t0 + 1];
1623 
1624 		t0 += 2;
1625 	} else if (strcmp(tokens[t0], "tmgr") == 0) {
1626 		if (n_tokens < t0 + 2) {
1627 			snprintf(out, out_size, MSG_ARG_MISMATCH,
1628 				"pipeline port in tmgr");
1629 			return;
1630 		}
1631 
1632 		p.type = PORT_IN_TMGR;
1633 
1634 		p.dev_name = tokens[t0 + 1];
1635 
1636 		t0 += 2;
1637 	} else if (strcmp(tokens[t0], "tap") == 0) {
1638 		if (n_tokens < t0 + 6) {
1639 			snprintf(out, out_size, MSG_ARG_MISMATCH,
1640 				"pipeline port in tap");
1641 			return;
1642 		}
1643 
1644 		p.type = PORT_IN_TAP;
1645 
1646 		p.dev_name = tokens[t0 + 1];
1647 
1648 		if (strcmp(tokens[t0 + 2], "mempool") != 0) {
1649 			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1650 				"mempool");
1651 			return;
1652 		}
1653 
1654 		p.tap.mempool_name = tokens[t0 + 3];
1655 
1656 		if (strcmp(tokens[t0 + 4], "mtu") != 0) {
1657 			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1658 				"mtu");
1659 			return;
1660 		}
1661 
1662 		if (parser_read_uint32(&p.tap.mtu, tokens[t0 + 5]) != 0) {
1663 			snprintf(out, out_size, MSG_ARG_INVALID, "mtu");
1664 			return;
1665 		}
1666 
1667 		t0 += 6;
1668 	} else if (strcmp(tokens[t0], "kni") == 0) {
1669 		if (n_tokens < t0 + 2) {
1670 			snprintf(out, out_size, MSG_ARG_MISMATCH,
1671 				"pipeline port in kni");
1672 			return;
1673 		}
1674 
1675 		p.type = PORT_IN_KNI;
1676 
1677 		p.dev_name = tokens[t0 + 1];
1678 
1679 		t0 += 2;
1680 	} else if (strcmp(tokens[t0], "source") == 0) {
1681 		if (n_tokens < t0 + 6) {
1682 			snprintf(out, out_size, MSG_ARG_MISMATCH,
1683 				"pipeline port in source");
1684 			return;
1685 		}
1686 
1687 		p.type = PORT_IN_SOURCE;
1688 
1689 		p.dev_name = NULL;
1690 
1691 		if (strcmp(tokens[t0 + 1], "mempool") != 0) {
1692 			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1693 				"mempool");
1694 			return;
1695 		}
1696 
1697 		p.source.mempool_name = tokens[t0 + 2];
1698 
1699 		if (strcmp(tokens[t0 + 3], "file") != 0) {
1700 			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1701 				"file");
1702 			return;
1703 		}
1704 
1705 		p.source.file_name = tokens[t0 + 4];
1706 
1707 		if (strcmp(tokens[t0 + 5], "bpp") != 0) {
1708 			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1709 				"bpp");
1710 			return;
1711 		}
1712 
1713 		if (parser_read_uint32(&p.source.n_bytes_per_pkt, tokens[t0 + 6]) != 0) {
1714 			snprintf(out, out_size, MSG_ARG_INVALID,
1715 				"n_bytes_per_pkt");
1716 			return;
1717 		}
1718 
1719 		t0 += 7;
1720 	} else if (strcmp(tokens[t0], "cryptodev") == 0) {
1721 		if (n_tokens < t0 + 3) {
1722 			snprintf(out, out_size, MSG_ARG_MISMATCH,
1723 				"pipeline port in cryptodev");
1724 			return;
1725 		}
1726 
1727 		p.type = PORT_IN_CRYPTODEV;
1728 
1729 		p.dev_name = tokens[t0 + 1];
1730 		if (parser_read_uint16(&p.rxq.queue_id, tokens[t0 + 3]) != 0) {
1731 			snprintf(out, out_size, MSG_ARG_INVALID,
1732 				"rxq");
1733 			return;
1734 		}
1735 
1736 		p.cryptodev.arg_callback = NULL;
1737 		p.cryptodev.f_callback = NULL;
1738 
1739 		t0 += 4;
1740 	} else {
1741 		snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
1742 		return;
1743 	}
1744 
1745 	p.action_profile_name = NULL;
1746 	if ((n_tokens > t0) && (strcmp(tokens[t0], "action") == 0)) {
1747 		if (n_tokens < t0 + 2) {
1748 			snprintf(out, out_size, MSG_ARG_MISMATCH, "action");
1749 			return;
1750 		}
1751 
1752 		p.action_profile_name = tokens[t0 + 1];
1753 
1754 		t0 += 2;
1755 	}
1756 
1757 	enabled = 1;
1758 	if ((n_tokens > t0) &&
1759 		(strcmp(tokens[t0], "disabled") == 0)) {
1760 		enabled = 0;
1761 
1762 		t0 += 1;
1763 	}
1764 
1765 	if (n_tokens != t0) {
1766 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1767 		return;
1768 	}
1769 
1770 	status = pipeline_port_in_create(pipeline_name,
1771 		&p, enabled);
1772 	if (status) {
1773 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1774 		return;
1775 	}
1776 }
1777 
1778 static const char cmd_pipeline_port_out_help[] =
1779 "pipeline <pipeline_name> port out\n"
1780 "   bsz <burst_size>\n"
1781 "   link <link_name> txq <txq_id>\n"
1782 "   | swq <swq_name>\n"
1783 "   | tmgr <tmgr_name>\n"
1784 "   | tap <tap_name>\n"
1785 "   | kni <kni_name>\n"
1786 "   | sink [file <file_name> pkts <max_n_pkts>]\n"
1787 "   | cryptodev <cryptodev_name> txq <txq_id> offset <crypto_op_offset>\n";
1788 
1789 static void
1790 cmd_pipeline_port_out(char **tokens,
1791 	uint32_t n_tokens,
1792 	char *out,
1793 	size_t out_size)
1794 {
1795 	struct port_out_params p;
1796 	char *pipeline_name;
1797 	int status;
1798 
1799 	memset(&p, 0, sizeof(p));
1800 
1801 	if (n_tokens < 7) {
1802 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1803 		return;
1804 	}
1805 
1806 	pipeline_name = tokens[1];
1807 
1808 	if (strcmp(tokens[2], "port") != 0) {
1809 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
1810 		return;
1811 	}
1812 
1813 	if (strcmp(tokens[3], "out") != 0) {
1814 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "out");
1815 		return;
1816 	}
1817 
1818 	if (strcmp(tokens[4], "bsz") != 0) {
1819 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
1820 		return;
1821 	}
1822 
1823 	if (parser_read_uint32(&p.burst_size, tokens[5]) != 0) {
1824 		snprintf(out, out_size, MSG_ARG_INVALID, "burst_size");
1825 		return;
1826 	}
1827 
1828 	if (strcmp(tokens[6], "link") == 0) {
1829 		if (n_tokens != 10) {
1830 			snprintf(out, out_size, MSG_ARG_MISMATCH,
1831 				"pipeline port out link");
1832 			return;
1833 		}
1834 
1835 		p.type = PORT_OUT_TXQ;
1836 
1837 		p.dev_name = tokens[7];
1838 
1839 		if (strcmp(tokens[8], "txq") != 0) {
1840 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "txq");
1841 			return;
1842 		}
1843 
1844 		if (parser_read_uint16(&p.txq.queue_id, tokens[9]) != 0) {
1845 			snprintf(out, out_size, MSG_ARG_INVALID, "queue_id");
1846 			return;
1847 		}
1848 	} else if (strcmp(tokens[6], "swq") == 0) {
1849 		if (n_tokens != 8) {
1850 			snprintf(out, out_size, MSG_ARG_MISMATCH,
1851 				"pipeline port out swq");
1852 			return;
1853 		}
1854 
1855 		p.type = PORT_OUT_SWQ;
1856 
1857 		p.dev_name = tokens[7];
1858 	} else if (strcmp(tokens[6], "tmgr") == 0) {
1859 		if (n_tokens != 8) {
1860 			snprintf(out, out_size, MSG_ARG_MISMATCH,
1861 				"pipeline port out tmgr");
1862 			return;
1863 		}
1864 
1865 		p.type = PORT_OUT_TMGR;
1866 
1867 		p.dev_name = tokens[7];
1868 	} else if (strcmp(tokens[6], "tap") == 0) {
1869 		if (n_tokens != 8) {
1870 			snprintf(out, out_size, MSG_ARG_MISMATCH,
1871 				"pipeline port out tap");
1872 			return;
1873 		}
1874 
1875 		p.type = PORT_OUT_TAP;
1876 
1877 		p.dev_name = tokens[7];
1878 	} else if (strcmp(tokens[6], "kni") == 0) {
1879 		if (n_tokens != 8) {
1880 			snprintf(out, out_size, MSG_ARG_MISMATCH,
1881 				"pipeline port out kni");
1882 			return;
1883 		}
1884 
1885 		p.type = PORT_OUT_KNI;
1886 
1887 		p.dev_name = tokens[7];
1888 	} else if (strcmp(tokens[6], "sink") == 0) {
1889 		if ((n_tokens != 7) && (n_tokens != 11)) {
1890 			snprintf(out, out_size, MSG_ARG_MISMATCH,
1891 				"pipeline port out sink");
1892 			return;
1893 		}
1894 
1895 		p.type = PORT_OUT_SINK;
1896 
1897 		p.dev_name = NULL;
1898 
1899 		if (n_tokens == 7) {
1900 			p.sink.file_name = NULL;
1901 			p.sink.max_n_pkts = 0;
1902 		} else {
1903 			if (strcmp(tokens[7], "file") != 0) {
1904 				snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1905 					"file");
1906 				return;
1907 			}
1908 
1909 			p.sink.file_name = tokens[8];
1910 
1911 			if (strcmp(tokens[9], "pkts") != 0) {
1912 				snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pkts");
1913 				return;
1914 			}
1915 
1916 			if (parser_read_uint32(&p.sink.max_n_pkts, tokens[10]) != 0) {
1917 				snprintf(out, out_size, MSG_ARG_INVALID, "max_n_pkts");
1918 				return;
1919 			}
1920 		}
1921 
1922 	} else if (strcmp(tokens[6], "cryptodev") == 0) {
1923 		if (n_tokens != 12) {
1924 			snprintf(out, out_size, MSG_ARG_MISMATCH,
1925 				"pipeline port out cryptodev");
1926 			return;
1927 		}
1928 
1929 		p.type = PORT_OUT_CRYPTODEV;
1930 
1931 		p.dev_name = tokens[7];
1932 
1933 		if (strcmp(tokens[8], "txq")) {
1934 			snprintf(out, out_size, MSG_ARG_MISMATCH,
1935 				"pipeline port out cryptodev");
1936 			return;
1937 		}
1938 
1939 		if (parser_read_uint16(&p.cryptodev.queue_id, tokens[9])
1940 				!= 0) {
1941 			snprintf(out, out_size, MSG_ARG_INVALID, "queue_id");
1942 			return;
1943 		}
1944 
1945 		if (strcmp(tokens[10], "offset")) {
1946 			snprintf(out, out_size, MSG_ARG_MISMATCH,
1947 				"pipeline port out cryptodev");
1948 			return;
1949 		}
1950 
1951 		if (parser_read_uint32(&p.cryptodev.op_offset, tokens[11])
1952 				!= 0) {
1953 			snprintf(out, out_size, MSG_ARG_INVALID, "queue_id");
1954 			return;
1955 		}
1956 	} else {
1957 		snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
1958 		return;
1959 	}
1960 
1961 	status = pipeline_port_out_create(pipeline_name, &p);
1962 	if (status) {
1963 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1964 		return;
1965 	}
1966 }
1967 
1968 static const char cmd_pipeline_table_help[] =
1969 "pipeline <pipeline_name> table\n"
1970 "       match\n"
1971 "       acl\n"
1972 "           ipv4 | ipv6\n"
1973 "           offset <ip_header_offset>\n"
1974 "           size <n_rules>\n"
1975 "       | array\n"
1976 "           offset <key_offset>\n"
1977 "           size <n_keys>\n"
1978 "       | hash\n"
1979 "           ext | lru\n"
1980 "           key <key_size>\n"
1981 "           mask <key_mask>\n"
1982 "           offset <key_offset>\n"
1983 "           buckets <n_buckets>\n"
1984 "           size <n_keys>\n"
1985 "       | lpm\n"
1986 "           ipv4 | ipv6\n"
1987 "           offset <ip_header_offset>\n"
1988 "           size <n_rules>\n"
1989 "       | stub\n"
1990 "   [action <table_action_profile_name>]\n";
1991 
1992 static void
1993 cmd_pipeline_table(char **tokens,
1994 	uint32_t n_tokens,
1995 	char *out,
1996 	size_t out_size)
1997 {
1998 	uint8_t key_mask[TABLE_RULE_MATCH_SIZE_MAX];
1999 	struct table_params p;
2000 	char *pipeline_name;
2001 	uint32_t t0;
2002 	int status;
2003 
2004 	if (n_tokens < 5) {
2005 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2006 		return;
2007 	}
2008 
2009 	pipeline_name = tokens[1];
2010 
2011 	if (strcmp(tokens[2], "table") != 0) {
2012 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
2013 		return;
2014 	}
2015 
2016 	if (strcmp(tokens[3], "match") != 0) {
2017 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match");
2018 		return;
2019 	}
2020 
2021 	t0 = 4;
2022 	if (strcmp(tokens[t0], "acl") == 0) {
2023 		if (n_tokens < t0 + 6) {
2024 			snprintf(out, out_size, MSG_ARG_MISMATCH,
2025 				"pipeline table acl");
2026 			return;
2027 		}
2028 
2029 		p.match_type = TABLE_ACL;
2030 
2031 		if (strcmp(tokens[t0 + 1], "ipv4") == 0)
2032 			p.match.acl.ip_version = 1;
2033 		else if (strcmp(tokens[t0 + 1], "ipv6") == 0)
2034 			p.match.acl.ip_version = 0;
2035 		else {
2036 			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
2037 				"ipv4 or ipv6");
2038 			return;
2039 		}
2040 
2041 		if (strcmp(tokens[t0 + 2], "offset") != 0) {
2042 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
2043 			return;
2044 		}
2045 
2046 		if (parser_read_uint32(&p.match.acl.ip_header_offset,
2047 			tokens[t0 + 3]) != 0) {
2048 			snprintf(out, out_size, MSG_ARG_INVALID,
2049 				"ip_header_offset");
2050 			return;
2051 		}
2052 
2053 		if (strcmp(tokens[t0 + 4], "size") != 0) {
2054 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
2055 			return;
2056 		}
2057 
2058 		if (parser_read_uint32(&p.match.acl.n_rules,
2059 			tokens[t0 + 5]) != 0) {
2060 			snprintf(out, out_size, MSG_ARG_INVALID, "n_rules");
2061 			return;
2062 		}
2063 
2064 		t0 += 6;
2065 	} else if (strcmp(tokens[t0], "array") == 0) {
2066 		if (n_tokens < t0 + 5) {
2067 			snprintf(out, out_size, MSG_ARG_MISMATCH,
2068 				"pipeline table array");
2069 			return;
2070 		}
2071 
2072 		p.match_type = TABLE_ARRAY;
2073 
2074 		if (strcmp(tokens[t0 + 1], "offset") != 0) {
2075 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
2076 			return;
2077 		}
2078 
2079 		if (parser_read_uint32(&p.match.array.key_offset,
2080 			tokens[t0 + 2]) != 0) {
2081 			snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
2082 			return;
2083 		}
2084 
2085 		if (strcmp(tokens[t0 + 3], "size") != 0) {
2086 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
2087 			return;
2088 		}
2089 
2090 		if (parser_read_uint32(&p.match.array.n_keys,
2091 			tokens[t0 + 4]) != 0) {
2092 			snprintf(out, out_size, MSG_ARG_INVALID, "n_keys");
2093 			return;
2094 		}
2095 
2096 		t0 += 5;
2097 	} else if (strcmp(tokens[t0], "hash") == 0) {
2098 		uint32_t key_mask_size = TABLE_RULE_MATCH_SIZE_MAX;
2099 
2100 		if (n_tokens < t0 + 12) {
2101 			snprintf(out, out_size, MSG_ARG_MISMATCH,
2102 				"pipeline table hash");
2103 			return;
2104 		}
2105 
2106 		p.match_type = TABLE_HASH;
2107 
2108 		if (strcmp(tokens[t0 + 1], "ext") == 0)
2109 			p.match.hash.extendable_bucket = 1;
2110 		else if (strcmp(tokens[t0 + 1], "lru") == 0)
2111 			p.match.hash.extendable_bucket = 0;
2112 		else {
2113 			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
2114 				"ext or lru");
2115 			return;
2116 		}
2117 
2118 		if (strcmp(tokens[t0 + 2], "key") != 0) {
2119 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "key");
2120 			return;
2121 		}
2122 
2123 		if ((parser_read_uint32(&p.match.hash.key_size,
2124 			tokens[t0 + 3]) != 0) ||
2125 			(p.match.hash.key_size == 0) ||
2126 			(p.match.hash.key_size > TABLE_RULE_MATCH_SIZE_MAX)) {
2127 			snprintf(out, out_size, MSG_ARG_INVALID, "key_size");
2128 			return;
2129 		}
2130 
2131 		if (strcmp(tokens[t0 + 4], "mask") != 0) {
2132 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask");
2133 			return;
2134 		}
2135 
2136 		if ((parse_hex_string(tokens[t0 + 5],
2137 			key_mask, &key_mask_size) != 0) ||
2138 			(key_mask_size != p.match.hash.key_size)) {
2139 			snprintf(out, out_size, MSG_ARG_INVALID, "key_mask");
2140 			return;
2141 		}
2142 		p.match.hash.key_mask = key_mask;
2143 
2144 		if (strcmp(tokens[t0 + 6], "offset") != 0) {
2145 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
2146 			return;
2147 		}
2148 
2149 		if (parser_read_uint32(&p.match.hash.key_offset,
2150 			tokens[t0 + 7]) != 0) {
2151 			snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
2152 			return;
2153 		}
2154 
2155 		if (strcmp(tokens[t0 + 8], "buckets") != 0) {
2156 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "buckets");
2157 			return;
2158 		}
2159 
2160 		if (parser_read_uint32(&p.match.hash.n_buckets,
2161 			tokens[t0 + 9]) != 0) {
2162 			snprintf(out, out_size, MSG_ARG_INVALID, "n_buckets");
2163 			return;
2164 		}
2165 
2166 		if (strcmp(tokens[t0 + 10], "size") != 0) {
2167 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
2168 			return;
2169 		}
2170 
2171 		if (parser_read_uint32(&p.match.hash.n_keys,
2172 			tokens[t0 + 11]) != 0) {
2173 			snprintf(out, out_size, MSG_ARG_INVALID, "n_keys");
2174 			return;
2175 		}
2176 
2177 		t0 += 12;
2178 	} else if (strcmp(tokens[t0], "lpm") == 0) {
2179 		if (n_tokens < t0 + 6) {
2180 			snprintf(out, out_size, MSG_ARG_MISMATCH,
2181 				"pipeline table lpm");
2182 			return;
2183 		}
2184 
2185 		p.match_type = TABLE_LPM;
2186 
2187 		if (strcmp(tokens[t0 + 1], "ipv4") == 0)
2188 			p.match.lpm.key_size = 4;
2189 		else if (strcmp(tokens[t0 + 1], "ipv6") == 0)
2190 			p.match.lpm.key_size = 16;
2191 		else {
2192 			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
2193 				"ipv4 or ipv6");
2194 			return;
2195 		}
2196 
2197 		if (strcmp(tokens[t0 + 2], "offset") != 0) {
2198 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
2199 			return;
2200 		}
2201 
2202 		if (parser_read_uint32(&p.match.lpm.key_offset,
2203 			tokens[t0 + 3]) != 0) {
2204 			snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
2205 			return;
2206 		}
2207 
2208 		if (strcmp(tokens[t0 + 4], "size") != 0) {
2209 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
2210 			return;
2211 		}
2212 
2213 		if (parser_read_uint32(&p.match.lpm.n_rules,
2214 			tokens[t0 + 5]) != 0) {
2215 			snprintf(out, out_size, MSG_ARG_INVALID, "n_rules");
2216 			return;
2217 		}
2218 
2219 		t0 += 6;
2220 	} else if (strcmp(tokens[t0], "stub") == 0) {
2221 		p.match_type = TABLE_STUB;
2222 
2223 		t0 += 1;
2224 	} else {
2225 		snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
2226 		return;
2227 	}
2228 
2229 	p.action_profile_name = NULL;
2230 	if ((n_tokens > t0) && (strcmp(tokens[t0], "action") == 0)) {
2231 		if (n_tokens < t0 + 2) {
2232 			snprintf(out, out_size, MSG_ARG_MISMATCH, "action");
2233 			return;
2234 		}
2235 
2236 		p.action_profile_name = tokens[t0 + 1];
2237 
2238 		t0 += 2;
2239 	}
2240 
2241 	if (n_tokens > t0) {
2242 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2243 		return;
2244 	}
2245 
2246 	status = pipeline_table_create(pipeline_name, &p);
2247 	if (status) {
2248 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
2249 		return;
2250 	}
2251 }
2252 
2253 static const char cmd_pipeline_port_in_table_help[] =
2254 "pipeline <pipeline_name> port in <port_id> table <table_id>\n";
2255 
2256 static void
2257 cmd_pipeline_port_in_table(char **tokens,
2258 	uint32_t n_tokens,
2259 	char *out,
2260 	size_t out_size)
2261 {
2262 	char *pipeline_name;
2263 	uint32_t port_id, table_id;
2264 	int status;
2265 
2266 	if (n_tokens != 7) {
2267 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2268 		return;
2269 	}
2270 
2271 	pipeline_name = tokens[1];
2272 
2273 	if (strcmp(tokens[2], "port") != 0) {
2274 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
2275 		return;
2276 	}
2277 
2278 	if (strcmp(tokens[3], "in") != 0) {
2279 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
2280 		return;
2281 	}
2282 
2283 	if (parser_read_uint32(&port_id, tokens[4]) != 0) {
2284 		snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
2285 		return;
2286 	}
2287 
2288 	if (strcmp(tokens[5], "table") != 0) {
2289 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
2290 		return;
2291 	}
2292 
2293 	if (parser_read_uint32(&table_id, tokens[6]) != 0) {
2294 		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
2295 		return;
2296 	}
2297 
2298 	status = pipeline_port_in_connect_to_table(pipeline_name,
2299 		port_id,
2300 		table_id);
2301 	if (status) {
2302 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
2303 		return;
2304 	}
2305 }
2306 
2307 
2308 static const char cmd_pipeline_port_in_stats_help[] =
2309 "pipeline <pipeline_name> port in <port_id> stats read [clear]\n";
2310 
2311 #define MSG_PIPELINE_PORT_IN_STATS                         \
2312 	"Pkts in: %" PRIu64 "\n"                           \
2313 	"Pkts dropped by AH: %" PRIu64 "\n"                \
2314 	"Pkts dropped by other: %" PRIu64 "\n"
2315 
2316 static void
2317 cmd_pipeline_port_in_stats(char **tokens,
2318 	uint32_t n_tokens,
2319 	char *out,
2320 	size_t out_size)
2321 {
2322 	struct rte_pipeline_port_in_stats stats;
2323 	char *pipeline_name;
2324 	uint32_t port_id;
2325 	int clear, status;
2326 
2327 	if ((n_tokens != 7) && (n_tokens != 8)) {
2328 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2329 		return;
2330 	}
2331 
2332 	pipeline_name = tokens[1];
2333 
2334 	if (strcmp(tokens[2], "port") != 0) {
2335 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
2336 		return;
2337 	}
2338 
2339 	if (strcmp(tokens[3], "in") != 0) {
2340 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
2341 		return;
2342 	}
2343 
2344 	if (parser_read_uint32(&port_id, tokens[4]) != 0) {
2345 		snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
2346 		return;
2347 	}
2348 
2349 	if (strcmp(tokens[5], "stats") != 0) {
2350 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
2351 		return;
2352 	}
2353 
2354 	if (strcmp(tokens[6], "read") != 0) {
2355 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read");
2356 		return;
2357 	}
2358 
2359 	clear = 0;
2360 	if (n_tokens == 8) {
2361 		if (strcmp(tokens[7], "clear") != 0) {
2362 			snprintf(out, out_size, MSG_ARG_INVALID, "clear");
2363 			return;
2364 		}
2365 
2366 		clear = 1;
2367 	}
2368 
2369 	status = pipeline_port_in_stats_read(pipeline_name,
2370 		port_id,
2371 		&stats,
2372 		clear);
2373 	if (status) {
2374 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
2375 		return;
2376 	}
2377 
2378 	snprintf(out, out_size, MSG_PIPELINE_PORT_IN_STATS,
2379 		stats.stats.n_pkts_in,
2380 		stats.n_pkts_dropped_by_ah,
2381 		stats.stats.n_pkts_drop);
2382 }
2383 
2384 
2385 static const char cmd_pipeline_port_in_enable_help[] =
2386 "pipeline <pipeline_name> port in <port_id> enable\n";
2387 
2388 static void
2389 cmd_pipeline_port_in_enable(char **tokens,
2390 	uint32_t n_tokens,
2391 	char *out,
2392 	size_t out_size)
2393 {
2394 	char *pipeline_name;
2395 	uint32_t port_id;
2396 	int status;
2397 
2398 	if (n_tokens != 6) {
2399 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2400 		return;
2401 	}
2402 
2403 	pipeline_name = tokens[1];
2404 
2405 	if (strcmp(tokens[2], "port") != 0) {
2406 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
2407 		return;
2408 	}
2409 
2410 	if (strcmp(tokens[3], "in") != 0) {
2411 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
2412 		return;
2413 	}
2414 
2415 	if (parser_read_uint32(&port_id, tokens[4]) != 0) {
2416 		snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
2417 		return;
2418 	}
2419 
2420 	if (strcmp(tokens[5], "enable") != 0) {
2421 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable");
2422 		return;
2423 	}
2424 
2425 	status = pipeline_port_in_enable(pipeline_name, port_id);
2426 	if (status) {
2427 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
2428 		return;
2429 	}
2430 }
2431 
2432 
2433 static const char cmd_pipeline_port_in_disable_help[] =
2434 "pipeline <pipeline_name> port in <port_id> disable\n";
2435 
2436 static void
2437 cmd_pipeline_port_in_disable(char **tokens,
2438 	uint32_t n_tokens,
2439 	char *out,
2440 	size_t out_size)
2441 {
2442 	char *pipeline_name;
2443 	uint32_t port_id;
2444 	int status;
2445 
2446 	if (n_tokens != 6) {
2447 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2448 		return;
2449 	}
2450 
2451 	pipeline_name = tokens[1];
2452 
2453 	if (strcmp(tokens[2], "port") != 0) {
2454 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
2455 		return;
2456 	}
2457 
2458 	if (strcmp(tokens[3], "in") != 0) {
2459 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
2460 		return;
2461 	}
2462 
2463 	if (parser_read_uint32(&port_id, tokens[4]) != 0) {
2464 		snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
2465 		return;
2466 	}
2467 
2468 	if (strcmp(tokens[5], "disable") != 0) {
2469 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable");
2470 		return;
2471 	}
2472 
2473 	status = pipeline_port_in_disable(pipeline_name, port_id);
2474 	if (status) {
2475 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
2476 		return;
2477 	}
2478 }
2479 
2480 
2481 static const char cmd_pipeline_port_out_stats_help[] =
2482 "pipeline <pipeline_name> port out <port_id> stats read [clear]\n";
2483 
2484 #define MSG_PIPELINE_PORT_OUT_STATS                        \
2485 	"Pkts in: %" PRIu64 "\n"                           \
2486 	"Pkts dropped by AH: %" PRIu64 "\n"                \
2487 	"Pkts dropped by other: %" PRIu64 "\n"
2488 
2489 static void
2490 cmd_pipeline_port_out_stats(char **tokens,
2491 	uint32_t n_tokens,
2492 	char *out,
2493 	size_t out_size)
2494 {
2495 	struct rte_pipeline_port_out_stats stats;
2496 	char *pipeline_name;
2497 	uint32_t port_id;
2498 	int clear, status;
2499 
2500 	if ((n_tokens != 7) && (n_tokens != 8)) {
2501 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2502 		return;
2503 	}
2504 
2505 	pipeline_name = tokens[1];
2506 
2507 	if (strcmp(tokens[2], "port") != 0) {
2508 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
2509 		return;
2510 	}
2511 
2512 	if (strcmp(tokens[3], "out") != 0) {
2513 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "out");
2514 		return;
2515 	}
2516 
2517 	if (parser_read_uint32(&port_id, tokens[4]) != 0) {
2518 		snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
2519 		return;
2520 	}
2521 
2522 	if (strcmp(tokens[5], "stats") != 0) {
2523 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
2524 		return;
2525 	}
2526 
2527 	if (strcmp(tokens[6], "read") != 0) {
2528 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read");
2529 		return;
2530 	}
2531 
2532 	clear = 0;
2533 	if (n_tokens == 8) {
2534 		if (strcmp(tokens[7], "clear") != 0) {
2535 			snprintf(out, out_size, MSG_ARG_INVALID, "clear");
2536 			return;
2537 		}
2538 
2539 		clear = 1;
2540 	}
2541 
2542 	status = pipeline_port_out_stats_read(pipeline_name,
2543 		port_id,
2544 		&stats,
2545 		clear);
2546 	if (status) {
2547 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
2548 		return;
2549 	}
2550 
2551 	snprintf(out, out_size, MSG_PIPELINE_PORT_OUT_STATS,
2552 		stats.stats.n_pkts_in,
2553 		stats.n_pkts_dropped_by_ah,
2554 		stats.stats.n_pkts_drop);
2555 }
2556 
2557 
2558 static const char cmd_pipeline_table_stats_help[] =
2559 "pipeline <pipeline_name> table <table_id> stats read [clear]\n";
2560 
2561 #define MSG_PIPELINE_TABLE_STATS                                     \
2562 	"Pkts in: %" PRIu64 "\n"                                     \
2563 	"Pkts in with lookup miss: %" PRIu64 "\n"                    \
2564 	"Pkts in with lookup hit dropped by AH: %" PRIu64 "\n"       \
2565 	"Pkts in with lookup hit dropped by others: %" PRIu64 "\n"   \
2566 	"Pkts in with lookup miss dropped by AH: %" PRIu64 "\n"      \
2567 	"Pkts in with lookup miss dropped by others: %" PRIu64 "\n"
2568 
2569 static void
2570 cmd_pipeline_table_stats(char **tokens,
2571 	uint32_t n_tokens,
2572 	char *out,
2573 	size_t out_size)
2574 {
2575 	struct rte_pipeline_table_stats stats;
2576 	char *pipeline_name;
2577 	uint32_t table_id;
2578 	int clear, status;
2579 
2580 	if ((n_tokens != 6) && (n_tokens != 7)) {
2581 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2582 		return;
2583 	}
2584 
2585 	pipeline_name = tokens[1];
2586 
2587 	if (strcmp(tokens[2], "table") != 0) {
2588 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
2589 		return;
2590 	}
2591 
2592 	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
2593 		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
2594 		return;
2595 	}
2596 
2597 	if (strcmp(tokens[4], "stats") != 0) {
2598 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
2599 		return;
2600 	}
2601 
2602 	if (strcmp(tokens[5], "read") != 0) {
2603 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read");
2604 		return;
2605 	}
2606 
2607 	clear = 0;
2608 	if (n_tokens == 7) {
2609 		if (strcmp(tokens[6], "clear") != 0) {
2610 			snprintf(out, out_size, MSG_ARG_INVALID, "clear");
2611 			return;
2612 		}
2613 
2614 		clear = 1;
2615 	}
2616 
2617 	status = pipeline_table_stats_read(pipeline_name,
2618 		table_id,
2619 		&stats,
2620 		clear);
2621 	if (status) {
2622 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
2623 		return;
2624 	}
2625 
2626 	snprintf(out, out_size, MSG_PIPELINE_TABLE_STATS,
2627 		stats.stats.n_pkts_in,
2628 		stats.stats.n_pkts_lookup_miss,
2629 		stats.n_pkts_dropped_by_lkp_hit_ah,
2630 		stats.n_pkts_dropped_lkp_hit,
2631 		stats.n_pkts_dropped_by_lkp_miss_ah,
2632 		stats.n_pkts_dropped_lkp_miss);
2633 }
2634 
2635 /**
2636  * <match> ::=
2637  *
2638  * match
2639  *    acl
2640  *       priority <priority>
2641  *       ipv4 | ipv6 <sa> <sa_depth> <da> <da_depth>
2642  *       <sp0> <sp1> <dp0> <dp1> <proto>
2643  *    | array <pos>
2644  *    | hash
2645  *       raw <key>
2646  *       | ipv4_5tuple <sa> <da> <sp> <dp> <proto>
2647  *       | ipv6_5tuple <sa> <da> <sp> <dp> <proto>
2648  *       | ipv4_addr <addr>
2649  *       | ipv6_addr <addr>
2650  *       | qinq <svlan> <cvlan>
2651  *    | lpm
2652  *       ipv4 | ipv6 <addr> <depth>
2653  */
2654 struct pkt_key_qinq {
2655 	uint16_t ethertype_svlan;
2656 	uint16_t svlan;
2657 	uint16_t ethertype_cvlan;
2658 	uint16_t cvlan;
2659 } __attribute__((__packed__));
2660 
2661 struct pkt_key_ipv4_5tuple {
2662 	uint8_t time_to_live;
2663 	uint8_t proto;
2664 	uint16_t hdr_checksum;
2665 	uint32_t sa;
2666 	uint32_t da;
2667 	uint16_t sp;
2668 	uint16_t dp;
2669 } __attribute__((__packed__));
2670 
2671 struct pkt_key_ipv6_5tuple {
2672 	uint16_t payload_length;
2673 	uint8_t proto;
2674 	uint8_t hop_limit;
2675 	uint8_t sa[16];
2676 	uint8_t da[16];
2677 	uint16_t sp;
2678 	uint16_t dp;
2679 } __attribute__((__packed__));
2680 
2681 struct pkt_key_ipv4_addr {
2682 	uint32_t addr;
2683 } __attribute__((__packed__));
2684 
2685 struct pkt_key_ipv6_addr {
2686 	uint8_t addr[16];
2687 } __attribute__((__packed__));
2688 
2689 static uint32_t
2690 parse_match(char **tokens,
2691 	uint32_t n_tokens,
2692 	char *out,
2693 	size_t out_size,
2694 	struct table_rule_match *m)
2695 {
2696 	memset(m, 0, sizeof(*m));
2697 
2698 	if (n_tokens < 2)
2699 		return 0;
2700 
2701 	if (strcmp(tokens[0], "match") != 0) {
2702 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match");
2703 		return 0;
2704 	}
2705 
2706 	if (strcmp(tokens[1], "acl") == 0) {
2707 		if (n_tokens < 14) {
2708 			snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2709 			return 0;
2710 		}
2711 
2712 		m->match_type = TABLE_ACL;
2713 
2714 		if (strcmp(tokens[2], "priority") != 0) {
2715 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "priority");
2716 			return 0;
2717 		}
2718 
2719 		if (parser_read_uint32(&m->match.acl.priority,
2720 			tokens[3]) != 0) {
2721 			snprintf(out, out_size, MSG_ARG_INVALID, "priority");
2722 			return 0;
2723 		}
2724 
2725 		if (strcmp(tokens[4], "ipv4") == 0) {
2726 			struct in_addr saddr, daddr;
2727 
2728 			m->match.acl.ip_version = 1;
2729 
2730 			if (parse_ipv4_addr(tokens[5], &saddr) != 0) {
2731 				snprintf(out, out_size, MSG_ARG_INVALID, "sa");
2732 				return 0;
2733 			}
2734 			m->match.acl.ipv4.sa = rte_be_to_cpu_32(saddr.s_addr);
2735 
2736 			if (parse_ipv4_addr(tokens[7], &daddr) != 0) {
2737 				snprintf(out, out_size, MSG_ARG_INVALID, "da");
2738 				return 0;
2739 			}
2740 			m->match.acl.ipv4.da = rte_be_to_cpu_32(daddr.s_addr);
2741 		} else if (strcmp(tokens[4], "ipv6") == 0) {
2742 			struct in6_addr saddr, daddr;
2743 
2744 			m->match.acl.ip_version = 0;
2745 
2746 			if (parse_ipv6_addr(tokens[5], &saddr) != 0) {
2747 				snprintf(out, out_size, MSG_ARG_INVALID, "sa");
2748 				return 0;
2749 			}
2750 			memcpy(m->match.acl.ipv6.sa, saddr.s6_addr, 16);
2751 
2752 			if (parse_ipv6_addr(tokens[7], &daddr) != 0) {
2753 				snprintf(out, out_size, MSG_ARG_INVALID, "da");
2754 				return 0;
2755 			}
2756 			memcpy(m->match.acl.ipv6.da, daddr.s6_addr, 16);
2757 		} else {
2758 			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
2759 				"ipv4 or ipv6");
2760 			return 0;
2761 		}
2762 
2763 		if (parser_read_uint32(&m->match.acl.sa_depth,
2764 			tokens[6]) != 0) {
2765 			snprintf(out, out_size, MSG_ARG_INVALID, "sa_depth");
2766 			return 0;
2767 		}
2768 
2769 		if (parser_read_uint32(&m->match.acl.da_depth,
2770 			tokens[8]) != 0) {
2771 			snprintf(out, out_size, MSG_ARG_INVALID, "da_depth");
2772 			return 0;
2773 		}
2774 
2775 		if (parser_read_uint16(&m->match.acl.sp0, tokens[9]) != 0) {
2776 			snprintf(out, out_size, MSG_ARG_INVALID, "sp0");
2777 			return 0;
2778 		}
2779 
2780 		if (parser_read_uint16(&m->match.acl.sp1, tokens[10]) != 0) {
2781 			snprintf(out, out_size, MSG_ARG_INVALID, "sp1");
2782 			return 0;
2783 		}
2784 
2785 		if (parser_read_uint16(&m->match.acl.dp0, tokens[11]) != 0) {
2786 			snprintf(out, out_size, MSG_ARG_INVALID, "dp0");
2787 			return 0;
2788 		}
2789 
2790 		if (parser_read_uint16(&m->match.acl.dp1, tokens[12]) != 0) {
2791 			snprintf(out, out_size, MSG_ARG_INVALID, "dp1");
2792 			return 0;
2793 		}
2794 
2795 		if (parser_read_uint8(&m->match.acl.proto, tokens[13]) != 0) {
2796 			snprintf(out, out_size, MSG_ARG_INVALID, "proto");
2797 			return 0;
2798 		}
2799 
2800 		m->match.acl.proto_mask = 0xff;
2801 
2802 		return 14;
2803 	} /* acl */
2804 
2805 	if (strcmp(tokens[1], "array") == 0) {
2806 		if (n_tokens < 3) {
2807 			snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2808 			return 0;
2809 		}
2810 
2811 		m->match_type = TABLE_ARRAY;
2812 
2813 		if (parser_read_uint32(&m->match.array.pos, tokens[2]) != 0) {
2814 			snprintf(out, out_size, MSG_ARG_INVALID, "pos");
2815 			return 0;
2816 		}
2817 
2818 		return 3;
2819 	} /* array */
2820 
2821 	if (strcmp(tokens[1], "hash") == 0) {
2822 		if (n_tokens < 3) {
2823 			snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2824 			return 0;
2825 		}
2826 
2827 		m->match_type = TABLE_HASH;
2828 
2829 		if (strcmp(tokens[2], "raw") == 0) {
2830 			uint32_t key_size = TABLE_RULE_MATCH_SIZE_MAX;
2831 
2832 			if (n_tokens < 4) {
2833 				snprintf(out, out_size, MSG_ARG_MISMATCH,
2834 					tokens[0]);
2835 				return 0;
2836 			}
2837 
2838 			if (parse_hex_string(tokens[3],
2839 				m->match.hash.key, &key_size) != 0) {
2840 				snprintf(out, out_size, MSG_ARG_INVALID, "key");
2841 				return 0;
2842 			}
2843 
2844 			return 4;
2845 		} /* hash raw */
2846 
2847 		if (strcmp(tokens[2], "ipv4_5tuple") == 0) {
2848 			struct pkt_key_ipv4_5tuple *ipv4 =
2849 				(struct pkt_key_ipv4_5tuple *) m->match.hash.key;
2850 			struct in_addr saddr, daddr;
2851 			uint16_t sp, dp;
2852 			uint8_t proto;
2853 
2854 			if (n_tokens < 8) {
2855 				snprintf(out, out_size, MSG_ARG_MISMATCH,
2856 					tokens[0]);
2857 				return 0;
2858 			}
2859 
2860 			if (parse_ipv4_addr(tokens[3], &saddr) != 0) {
2861 				snprintf(out, out_size, MSG_ARG_INVALID, "sa");
2862 				return 0;
2863 			}
2864 
2865 			if (parse_ipv4_addr(tokens[4], &daddr) != 0) {
2866 				snprintf(out, out_size, MSG_ARG_INVALID, "da");
2867 				return 0;
2868 			}
2869 
2870 			if (parser_read_uint16(&sp, tokens[5]) != 0) {
2871 				snprintf(out, out_size, MSG_ARG_INVALID, "sp");
2872 				return 0;
2873 			}
2874 
2875 			if (parser_read_uint16(&dp, tokens[6]) != 0) {
2876 				snprintf(out, out_size, MSG_ARG_INVALID, "dp");
2877 				return 0;
2878 			}
2879 
2880 			if (parser_read_uint8(&proto, tokens[7]) != 0) {
2881 				snprintf(out, out_size, MSG_ARG_INVALID,
2882 					"proto");
2883 				return 0;
2884 			}
2885 
2886 			ipv4->sa = saddr.s_addr;
2887 			ipv4->da = daddr.s_addr;
2888 			ipv4->sp = rte_cpu_to_be_16(sp);
2889 			ipv4->dp = rte_cpu_to_be_16(dp);
2890 			ipv4->proto = proto;
2891 
2892 			return 8;
2893 		} /* hash ipv4_5tuple */
2894 
2895 		if (strcmp(tokens[2], "ipv6_5tuple") == 0) {
2896 			struct pkt_key_ipv6_5tuple *ipv6 =
2897 				(struct pkt_key_ipv6_5tuple *) m->match.hash.key;
2898 			struct in6_addr saddr, daddr;
2899 			uint16_t sp, dp;
2900 			uint8_t proto;
2901 
2902 			if (n_tokens < 8) {
2903 				snprintf(out, out_size, MSG_ARG_MISMATCH,
2904 					tokens[0]);
2905 				return 0;
2906 			}
2907 
2908 			if (parse_ipv6_addr(tokens[3], &saddr) != 0) {
2909 				snprintf(out, out_size, MSG_ARG_INVALID, "sa");
2910 				return 0;
2911 			}
2912 
2913 			if (parse_ipv6_addr(tokens[4], &daddr) != 0) {
2914 				snprintf(out, out_size, MSG_ARG_INVALID, "da");
2915 				return 0;
2916 			}
2917 
2918 			if (parser_read_uint16(&sp, tokens[5]) != 0) {
2919 				snprintf(out, out_size, MSG_ARG_INVALID, "sp");
2920 				return 0;
2921 			}
2922 
2923 			if (parser_read_uint16(&dp, tokens[6]) != 0) {
2924 				snprintf(out, out_size, MSG_ARG_INVALID, "dp");
2925 				return 0;
2926 			}
2927 
2928 			if (parser_read_uint8(&proto, tokens[7]) != 0) {
2929 				snprintf(out, out_size, MSG_ARG_INVALID,
2930 					"proto");
2931 				return 0;
2932 			}
2933 
2934 			memcpy(ipv6->sa, saddr.s6_addr, 16);
2935 			memcpy(ipv6->da, daddr.s6_addr, 16);
2936 			ipv6->sp = rte_cpu_to_be_16(sp);
2937 			ipv6->dp = rte_cpu_to_be_16(dp);
2938 			ipv6->proto = proto;
2939 
2940 			return 8;
2941 		} /* hash ipv6_5tuple */
2942 
2943 		if (strcmp(tokens[2], "ipv4_addr") == 0) {
2944 			struct pkt_key_ipv4_addr *ipv4_addr =
2945 				(struct pkt_key_ipv4_addr *) m->match.hash.key;
2946 			struct in_addr addr;
2947 
2948 			if (n_tokens < 4) {
2949 				snprintf(out, out_size, MSG_ARG_MISMATCH,
2950 					tokens[0]);
2951 				return 0;
2952 			}
2953 
2954 			if (parse_ipv4_addr(tokens[3], &addr) != 0) {
2955 				snprintf(out, out_size, MSG_ARG_INVALID,
2956 					"addr");
2957 				return 0;
2958 			}
2959 
2960 			ipv4_addr->addr = addr.s_addr;
2961 
2962 			return 4;
2963 		} /* hash ipv4_addr */
2964 
2965 		if (strcmp(tokens[2], "ipv6_addr") == 0) {
2966 			struct pkt_key_ipv6_addr *ipv6_addr =
2967 				(struct pkt_key_ipv6_addr *) m->match.hash.key;
2968 			struct in6_addr addr;
2969 
2970 			if (n_tokens < 4) {
2971 				snprintf(out, out_size, MSG_ARG_MISMATCH,
2972 					tokens[0]);
2973 				return 0;
2974 			}
2975 
2976 			if (parse_ipv6_addr(tokens[3], &addr) != 0) {
2977 				snprintf(out, out_size, MSG_ARG_INVALID,
2978 					"addr");
2979 				return 0;
2980 			}
2981 
2982 			memcpy(ipv6_addr->addr, addr.s6_addr, 16);
2983 
2984 			return 4;
2985 		} /* hash ipv6_5tuple */
2986 
2987 		if (strcmp(tokens[2], "qinq") == 0) {
2988 			struct pkt_key_qinq *qinq =
2989 				(struct pkt_key_qinq *) m->match.hash.key;
2990 			uint16_t svlan, cvlan;
2991 
2992 			if (n_tokens < 5) {
2993 				snprintf(out, out_size, MSG_ARG_MISMATCH,
2994 					tokens[0]);
2995 				return 0;
2996 			}
2997 
2998 			if ((parser_read_uint16(&svlan, tokens[3]) != 0) ||
2999 				(svlan > 0xFFF)) {
3000 				snprintf(out, out_size, MSG_ARG_INVALID,
3001 					"svlan");
3002 				return 0;
3003 			}
3004 
3005 			if ((parser_read_uint16(&cvlan, tokens[4]) != 0) ||
3006 				(cvlan > 0xFFF)) {
3007 				snprintf(out, out_size, MSG_ARG_INVALID,
3008 					"cvlan");
3009 				return 0;
3010 			}
3011 
3012 			qinq->svlan = rte_cpu_to_be_16(svlan);
3013 			qinq->cvlan = rte_cpu_to_be_16(cvlan);
3014 
3015 			return 5;
3016 		} /* hash qinq */
3017 
3018 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3019 		return 0;
3020 	} /* hash */
3021 
3022 	if (strcmp(tokens[1], "lpm") == 0) {
3023 		if (n_tokens < 5) {
3024 			snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
3025 			return 0;
3026 		}
3027 
3028 		m->match_type = TABLE_LPM;
3029 
3030 		if (strcmp(tokens[2], "ipv4") == 0) {
3031 			struct in_addr addr;
3032 
3033 			m->match.lpm.ip_version = 1;
3034 
3035 			if (parse_ipv4_addr(tokens[3], &addr) != 0) {
3036 				snprintf(out, out_size, MSG_ARG_INVALID,
3037 					"addr");
3038 				return 0;
3039 			}
3040 
3041 			m->match.lpm.ipv4 = rte_be_to_cpu_32(addr.s_addr);
3042 		} else if (strcmp(tokens[2], "ipv6") == 0) {
3043 			struct in6_addr addr;
3044 
3045 			m->match.lpm.ip_version = 0;
3046 
3047 			if (parse_ipv6_addr(tokens[3], &addr) != 0) {
3048 				snprintf(out, out_size, MSG_ARG_INVALID,
3049 					"addr");
3050 				return 0;
3051 			}
3052 
3053 			memcpy(m->match.lpm.ipv6, addr.s6_addr, 16);
3054 		} else {
3055 			snprintf(out, out_size, MSG_ARG_MISMATCH,
3056 				"ipv4 or ipv6");
3057 			return 0;
3058 		}
3059 
3060 		if (parser_read_uint8(&m->match.lpm.depth, tokens[4]) != 0) {
3061 			snprintf(out, out_size, MSG_ARG_INVALID, "depth");
3062 			return 0;
3063 		}
3064 
3065 		return 5;
3066 	} /* lpm */
3067 
3068 	snprintf(out, out_size, MSG_ARG_MISMATCH,
3069 		"acl or array or hash or lpm");
3070 	return 0;
3071 }
3072 
3073 /**
3074  * table_action ::=
3075  *
3076  * action
3077  *    fwd
3078  *       drop
3079  *       | port <port_id>
3080  *       | meta
3081  *       | table <table_id>
3082  *    [balance <out0> ... <out7>]
3083  *    [meter
3084  *       tc0 meter <meter_profile_id> policer g <pa> y <pa> r <pa>
3085  *       [tc1 meter <meter_profile_id> policer g <pa> y <pa> r <pa>
3086  *       tc2 meter <meter_profile_id> policer g <pa> y <pa> r <pa>
3087  *       tc3 meter <meter_profile_id> policer g <pa> y <pa> r <pa>]]
3088  *    [tm subport <subport_id> pipe <pipe_id>]
3089  *    [encap
3090  *       ether <da> <sa>
3091  *       | vlan <da> <sa> <pcp> <dei> <vid>
3092  *       | qinq <da> <sa> <pcp> <dei> <vid> <pcp> <dei> <vid>
3093  *       | mpls unicast | multicast
3094  *          <da> <sa>
3095  *          label0 <label> <tc> <ttl>
3096  *          [label1 <label> <tc> <ttl>
3097  *          [label2 <label> <tc> <ttl>
3098  *          [label3 <label> <tc> <ttl>]]]
3099  *       | pppoe <da> <sa> <session_id>
3100  *       | vxlan ether <da> <sa>
3101  *          [vlan <pcp> <dei> <vid>]
3102  *          ipv4 <sa> <da> <dscp> <ttl>
3103  *          | ipv6 <sa> <da> <flow_label> <dscp> <hop_limit>
3104  *          udp <sp> <dp>
3105  *          vxlan <vni>]
3106  *    [nat ipv4 | ipv6 <addr> <port>]
3107  *    [ttl dec | keep]
3108  *    [stats]
3109  *    [time]
3110  *    [sym_crypto
3111  *       encrypt | decrypt
3112  *       type
3113  *       | cipher
3114  *          cipher_algo <algo> cipher_key <key> cipher_iv <iv>
3115  *       | cipher_auth
3116  *          cipher_algo <algo> cipher_key <key> cipher_iv <iv>
3117  *          auth_algo <algo> auth_key <key> digest_size <size>
3118  *       | aead
3119  *          aead_algo <algo> aead_key <key> aead_iv <iv> aead_aad <aad>
3120  *          digest_size <size>
3121  *       data_offset <data_offset>]
3122  *    [tag <tag>]
3123  *    [decap <n>]
3124  *
3125  * where:
3126  *    <pa> ::= g | y | r | drop
3127  */
3128 static uint32_t
3129 parse_table_action_fwd(char **tokens,
3130 	uint32_t n_tokens,
3131 	struct table_rule_action *a)
3132 {
3133 	if ((n_tokens == 0) || (strcmp(tokens[0], "fwd") != 0))
3134 		return 0;
3135 
3136 	tokens++;
3137 	n_tokens--;
3138 
3139 	if (n_tokens && (strcmp(tokens[0], "drop") == 0)) {
3140 		a->fwd.action = RTE_PIPELINE_ACTION_DROP;
3141 		a->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
3142 		return 1 + 1;
3143 	}
3144 
3145 	if (n_tokens && (strcmp(tokens[0], "port") == 0)) {
3146 		uint32_t id;
3147 
3148 		if ((n_tokens < 2) ||
3149 			parser_read_uint32(&id, tokens[1]))
3150 			return 0;
3151 
3152 		a->fwd.action = RTE_PIPELINE_ACTION_PORT;
3153 		a->fwd.id = id;
3154 		a->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
3155 		return 1 + 2;
3156 	}
3157 
3158 	if (n_tokens && (strcmp(tokens[0], "meta") == 0)) {
3159 		a->fwd.action = RTE_PIPELINE_ACTION_PORT_META;
3160 		a->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
3161 		return 1 + 1;
3162 	}
3163 
3164 	if (n_tokens && (strcmp(tokens[0], "table") == 0)) {
3165 		uint32_t id;
3166 
3167 		if ((n_tokens < 2) ||
3168 			parser_read_uint32(&id, tokens[1]))
3169 			return 0;
3170 
3171 		a->fwd.action = RTE_PIPELINE_ACTION_TABLE;
3172 		a->fwd.id = id;
3173 		a->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
3174 		return 1 + 2;
3175 	}
3176 
3177 	return 0;
3178 }
3179 
3180 static uint32_t
3181 parse_table_action_balance(char **tokens,
3182 	uint32_t n_tokens,
3183 	struct table_rule_action *a)
3184 {
3185 	uint32_t i;
3186 
3187 	if ((n_tokens == 0) || (strcmp(tokens[0], "balance") != 0))
3188 		return 0;
3189 
3190 	tokens++;
3191 	n_tokens--;
3192 
3193 	if (n_tokens < RTE_TABLE_ACTION_LB_TABLE_SIZE)
3194 		return 0;
3195 
3196 	for (i = 0; i < RTE_TABLE_ACTION_LB_TABLE_SIZE; i++)
3197 		if (parser_read_uint32(&a->lb.out[i], tokens[i]) != 0)
3198 			return 0;
3199 
3200 	a->action_mask |= 1 << RTE_TABLE_ACTION_LB;
3201 	return 1 + RTE_TABLE_ACTION_LB_TABLE_SIZE;
3202 
3203 }
3204 
3205 static int
3206 parse_policer_action(char *token, enum rte_table_action_policer *a)
3207 {
3208 	if (strcmp(token, "g") == 0) {
3209 		*a = RTE_TABLE_ACTION_POLICER_COLOR_GREEN;
3210 		return 0;
3211 	}
3212 
3213 	if (strcmp(token, "y") == 0) {
3214 		*a = RTE_TABLE_ACTION_POLICER_COLOR_YELLOW;
3215 		return 0;
3216 	}
3217 
3218 	if (strcmp(token, "r") == 0) {
3219 		*a = RTE_TABLE_ACTION_POLICER_COLOR_RED;
3220 		return 0;
3221 	}
3222 
3223 	if (strcmp(token, "drop") == 0) {
3224 		*a = RTE_TABLE_ACTION_POLICER_DROP;
3225 		return 0;
3226 	}
3227 
3228 	return -1;
3229 }
3230 
3231 static uint32_t
3232 parse_table_action_meter_tc(char **tokens,
3233 	uint32_t n_tokens,
3234 	struct rte_table_action_mtr_tc_params *mtr)
3235 {
3236 	if ((n_tokens < 9) ||
3237 		strcmp(tokens[0], "meter") ||
3238 		parser_read_uint32(&mtr->meter_profile_id, tokens[1]) ||
3239 		strcmp(tokens[2], "policer") ||
3240 		strcmp(tokens[3], "g") ||
3241 		parse_policer_action(tokens[4], &mtr->policer[e_RTE_METER_GREEN]) ||
3242 		strcmp(tokens[5], "y") ||
3243 		parse_policer_action(tokens[6], &mtr->policer[e_RTE_METER_YELLOW]) ||
3244 		strcmp(tokens[7], "r") ||
3245 		parse_policer_action(tokens[8], &mtr->policer[e_RTE_METER_RED]))
3246 		return 0;
3247 
3248 	return 9;
3249 }
3250 
3251 static uint32_t
3252 parse_table_action_meter(char **tokens,
3253 	uint32_t n_tokens,
3254 	struct table_rule_action *a)
3255 {
3256 	if ((n_tokens == 0) || strcmp(tokens[0], "meter"))
3257 		return 0;
3258 
3259 	tokens++;
3260 	n_tokens--;
3261 
3262 	if ((n_tokens < 10) ||
3263 		strcmp(tokens[0], "tc0") ||
3264 		(parse_table_action_meter_tc(tokens + 1,
3265 			n_tokens - 1,
3266 			&a->mtr.mtr[0]) == 0))
3267 		return 0;
3268 
3269 	tokens += 10;
3270 	n_tokens -= 10;
3271 
3272 	if ((n_tokens == 0) || strcmp(tokens[0], "tc1")) {
3273 		a->mtr.tc_mask = 1;
3274 		a->action_mask |= 1 << RTE_TABLE_ACTION_MTR;
3275 		return 1 + 10;
3276 	}
3277 
3278 	if ((n_tokens < 30) ||
3279 		(parse_table_action_meter_tc(tokens + 1,
3280 			n_tokens - 1, &a->mtr.mtr[1]) == 0) ||
3281 		strcmp(tokens[10], "tc2") ||
3282 		(parse_table_action_meter_tc(tokens + 11,
3283 			n_tokens - 11, &a->mtr.mtr[2]) == 0) ||
3284 		strcmp(tokens[20], "tc3") ||
3285 		(parse_table_action_meter_tc(tokens + 21,
3286 			n_tokens - 21, &a->mtr.mtr[3]) == 0))
3287 		return 0;
3288 
3289 	a->mtr.tc_mask = 0xF;
3290 	a->action_mask |= 1 << RTE_TABLE_ACTION_MTR;
3291 	return 1 + 10 + 3 * 10;
3292 }
3293 
3294 static uint32_t
3295 parse_table_action_tm(char **tokens,
3296 	uint32_t n_tokens,
3297 	struct table_rule_action *a)
3298 {
3299 	uint32_t subport_id, pipe_id;
3300 
3301 	if ((n_tokens < 5) ||
3302 		strcmp(tokens[0], "tm") ||
3303 		strcmp(tokens[1], "subport") ||
3304 		parser_read_uint32(&subport_id, tokens[2]) ||
3305 		strcmp(tokens[3], "pipe") ||
3306 		parser_read_uint32(&pipe_id, tokens[4]))
3307 		return 0;
3308 
3309 	a->tm.subport_id = subport_id;
3310 	a->tm.pipe_id = pipe_id;
3311 	a->action_mask |= 1 << RTE_TABLE_ACTION_TM;
3312 	return 5;
3313 }
3314 
3315 static uint32_t
3316 parse_table_action_encap(char **tokens,
3317 	uint32_t n_tokens,
3318 	struct table_rule_action *a)
3319 {
3320 	if ((n_tokens == 0) || strcmp(tokens[0], "encap"))
3321 		return 0;
3322 
3323 	tokens++;
3324 	n_tokens--;
3325 
3326 	/* ether */
3327 	if (n_tokens && (strcmp(tokens[0], "ether") == 0)) {
3328 		if ((n_tokens < 3) ||
3329 			parse_mac_addr(tokens[1], &a->encap.ether.ether.da) ||
3330 			parse_mac_addr(tokens[2], &a->encap.ether.ether.sa))
3331 			return 0;
3332 
3333 		a->encap.type = RTE_TABLE_ACTION_ENCAP_ETHER;
3334 		a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3335 		return 1 + 3;
3336 	}
3337 
3338 	/* vlan */
3339 	if (n_tokens && (strcmp(tokens[0], "vlan") == 0)) {
3340 		uint32_t pcp, dei, vid;
3341 
3342 		if ((n_tokens < 6) ||
3343 			parse_mac_addr(tokens[1], &a->encap.vlan.ether.da) ||
3344 			parse_mac_addr(tokens[2], &a->encap.vlan.ether.sa) ||
3345 			parser_read_uint32(&pcp, tokens[3]) ||
3346 			(pcp > 0x7) ||
3347 			parser_read_uint32(&dei, tokens[4]) ||
3348 			(dei > 0x1) ||
3349 			parser_read_uint32(&vid, tokens[5]) ||
3350 			(vid > 0xFFF))
3351 			return 0;
3352 
3353 		a->encap.vlan.vlan.pcp = pcp & 0x7;
3354 		a->encap.vlan.vlan.dei = dei & 0x1;
3355 		a->encap.vlan.vlan.vid = vid & 0xFFF;
3356 		a->encap.type = RTE_TABLE_ACTION_ENCAP_VLAN;
3357 		a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3358 		return 1 + 6;
3359 	}
3360 
3361 	/* qinq */
3362 	if (n_tokens && (strcmp(tokens[0], "qinq") == 0)) {
3363 		uint32_t svlan_pcp, svlan_dei, svlan_vid;
3364 		uint32_t cvlan_pcp, cvlan_dei, cvlan_vid;
3365 
3366 		if ((n_tokens < 9) ||
3367 			parse_mac_addr(tokens[1], &a->encap.qinq.ether.da) ||
3368 			parse_mac_addr(tokens[2], &a->encap.qinq.ether.sa) ||
3369 			parser_read_uint32(&svlan_pcp, tokens[3]) ||
3370 			(svlan_pcp > 0x7) ||
3371 			parser_read_uint32(&svlan_dei, tokens[4]) ||
3372 			(svlan_dei > 0x1) ||
3373 			parser_read_uint32(&svlan_vid, tokens[5]) ||
3374 			(svlan_vid > 0xFFF) ||
3375 			parser_read_uint32(&cvlan_pcp, tokens[6]) ||
3376 			(cvlan_pcp > 0x7) ||
3377 			parser_read_uint32(&cvlan_dei, tokens[7]) ||
3378 			(cvlan_dei > 0x1) ||
3379 			parser_read_uint32(&cvlan_vid, tokens[8]) ||
3380 			(cvlan_vid > 0xFFF))
3381 			return 0;
3382 
3383 		a->encap.qinq.svlan.pcp = svlan_pcp & 0x7;
3384 		a->encap.qinq.svlan.dei = svlan_dei & 0x1;
3385 		a->encap.qinq.svlan.vid = svlan_vid & 0xFFF;
3386 		a->encap.qinq.cvlan.pcp = cvlan_pcp & 0x7;
3387 		a->encap.qinq.cvlan.dei = cvlan_dei & 0x1;
3388 		a->encap.qinq.cvlan.vid = cvlan_vid & 0xFFF;
3389 		a->encap.type = RTE_TABLE_ACTION_ENCAP_QINQ;
3390 		a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3391 		return 1 + 9;
3392 	}
3393 
3394 	/* mpls */
3395 	if (n_tokens && (strcmp(tokens[0], "mpls") == 0)) {
3396 		uint32_t label, tc, ttl;
3397 
3398 		if (n_tokens < 8)
3399 			return 0;
3400 
3401 		if (strcmp(tokens[1], "unicast") == 0)
3402 			a->encap.mpls.unicast = 1;
3403 		else if (strcmp(tokens[1], "multicast") == 0)
3404 			a->encap.mpls.unicast = 0;
3405 		else
3406 			return 0;
3407 
3408 		if (parse_mac_addr(tokens[2], &a->encap.mpls.ether.da) ||
3409 			parse_mac_addr(tokens[3], &a->encap.mpls.ether.sa) ||
3410 			strcmp(tokens[4], "label0") ||
3411 			parser_read_uint32(&label, tokens[5]) ||
3412 			(label > 0xFFFFF) ||
3413 			parser_read_uint32(&tc, tokens[6]) ||
3414 			(tc > 0x7) ||
3415 			parser_read_uint32(&ttl, tokens[7]) ||
3416 			(ttl > 0x3F))
3417 			return 0;
3418 
3419 		a->encap.mpls.mpls[0].label = label;
3420 		a->encap.mpls.mpls[0].tc = tc;
3421 		a->encap.mpls.mpls[0].ttl = ttl;
3422 
3423 		tokens += 8;
3424 		n_tokens -= 8;
3425 
3426 		if ((n_tokens == 0) || strcmp(tokens[0], "label1")) {
3427 			a->encap.mpls.mpls_count = 1;
3428 			a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS;
3429 			a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3430 			return 1 + 8;
3431 		}
3432 
3433 		if ((n_tokens < 4) ||
3434 			parser_read_uint32(&label, tokens[1]) ||
3435 			(label > 0xFFFFF) ||
3436 			parser_read_uint32(&tc, tokens[2]) ||
3437 			(tc > 0x7) ||
3438 			parser_read_uint32(&ttl, tokens[3]) ||
3439 			(ttl > 0x3F))
3440 			return 0;
3441 
3442 		a->encap.mpls.mpls[1].label = label;
3443 		a->encap.mpls.mpls[1].tc = tc;
3444 		a->encap.mpls.mpls[1].ttl = ttl;
3445 
3446 		tokens += 4;
3447 		n_tokens -= 4;
3448 
3449 		if ((n_tokens == 0) || strcmp(tokens[0], "label2")) {
3450 			a->encap.mpls.mpls_count = 2;
3451 			a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS;
3452 			a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3453 			return 1 + 8 + 4;
3454 		}
3455 
3456 		if ((n_tokens < 4) ||
3457 			parser_read_uint32(&label, tokens[1]) ||
3458 			(label > 0xFFFFF) ||
3459 			parser_read_uint32(&tc, tokens[2]) ||
3460 			(tc > 0x7) ||
3461 			parser_read_uint32(&ttl, tokens[3]) ||
3462 			(ttl > 0x3F))
3463 			return 0;
3464 
3465 		a->encap.mpls.mpls[2].label = label;
3466 		a->encap.mpls.mpls[2].tc = tc;
3467 		a->encap.mpls.mpls[2].ttl = ttl;
3468 
3469 		tokens += 4;
3470 		n_tokens -= 4;
3471 
3472 		if ((n_tokens == 0) || strcmp(tokens[0], "label3")) {
3473 			a->encap.mpls.mpls_count = 3;
3474 			a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS;
3475 			a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3476 			return 1 + 8 + 4 + 4;
3477 		}
3478 
3479 		if ((n_tokens < 4) ||
3480 			parser_read_uint32(&label, tokens[1]) ||
3481 			(label > 0xFFFFF) ||
3482 			parser_read_uint32(&tc, tokens[2]) ||
3483 			(tc > 0x7) ||
3484 			parser_read_uint32(&ttl, tokens[3]) ||
3485 			(ttl > 0x3F))
3486 			return 0;
3487 
3488 		a->encap.mpls.mpls[3].label = label;
3489 		a->encap.mpls.mpls[3].tc = tc;
3490 		a->encap.mpls.mpls[3].ttl = ttl;
3491 
3492 		a->encap.mpls.mpls_count = 4;
3493 		a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS;
3494 		a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3495 		return 1 + 8 + 4 + 4 + 4;
3496 	}
3497 
3498 	/* pppoe */
3499 	if (n_tokens && (strcmp(tokens[0], "pppoe") == 0)) {
3500 		if ((n_tokens < 4) ||
3501 			parse_mac_addr(tokens[1], &a->encap.pppoe.ether.da) ||
3502 			parse_mac_addr(tokens[2], &a->encap.pppoe.ether.sa) ||
3503 			parser_read_uint16(&a->encap.pppoe.pppoe.session_id,
3504 				tokens[3]))
3505 			return 0;
3506 
3507 		a->encap.type = RTE_TABLE_ACTION_ENCAP_PPPOE;
3508 		a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3509 		return 1 + 4;
3510 	}
3511 
3512 	/* vxlan */
3513 	if (n_tokens && (strcmp(tokens[0], "vxlan") == 0)) {
3514 		uint32_t n = 0;
3515 
3516 		n_tokens--;
3517 		tokens++;
3518 		n++;
3519 
3520 		/* ether <da> <sa> */
3521 		if ((n_tokens < 3) ||
3522 			strcmp(tokens[0], "ether") ||
3523 			parse_mac_addr(tokens[1], &a->encap.vxlan.ether.da) ||
3524 			parse_mac_addr(tokens[2], &a->encap.vxlan.ether.sa))
3525 			return 0;
3526 
3527 		n_tokens -= 3;
3528 		tokens += 3;
3529 		n += 3;
3530 
3531 		/* [vlan <pcp> <dei> <vid>] */
3532 		if (strcmp(tokens[0], "vlan") == 0) {
3533 			uint32_t pcp, dei, vid;
3534 
3535 			if ((n_tokens < 4) ||
3536 				parser_read_uint32(&pcp, tokens[1]) ||
3537 				(pcp > 7) ||
3538 				parser_read_uint32(&dei, tokens[2]) ||
3539 				(dei > 1) ||
3540 				parser_read_uint32(&vid, tokens[3]) ||
3541 				(vid > 0xFFF))
3542 				return 0;
3543 
3544 			a->encap.vxlan.vlan.pcp = pcp;
3545 			a->encap.vxlan.vlan.dei = dei;
3546 			a->encap.vxlan.vlan.vid = vid;
3547 
3548 			n_tokens -= 4;
3549 			tokens += 4;
3550 			n += 4;
3551 		}
3552 
3553 		/* ipv4 <sa> <da> <dscp> <ttl>
3554 		   | ipv6 <sa> <da> <flow_label> <dscp> <hop_limit> */
3555 		if (strcmp(tokens[0], "ipv4") == 0) {
3556 			struct in_addr sa, da;
3557 			uint8_t dscp, ttl;
3558 
3559 			if ((n_tokens < 5) ||
3560 				parse_ipv4_addr(tokens[1], &sa) ||
3561 				parse_ipv4_addr(tokens[2], &da) ||
3562 				parser_read_uint8(&dscp, tokens[3]) ||
3563 				(dscp > 64) ||
3564 				parser_read_uint8(&ttl, tokens[4]))
3565 				return 0;
3566 
3567 			a->encap.vxlan.ipv4.sa = rte_be_to_cpu_32(sa.s_addr);
3568 			a->encap.vxlan.ipv4.da = rte_be_to_cpu_32(da.s_addr);
3569 			a->encap.vxlan.ipv4.dscp = dscp;
3570 			a->encap.vxlan.ipv4.ttl = ttl;
3571 
3572 			n_tokens -= 5;
3573 			tokens += 5;
3574 			n += 5;
3575 		} else if (strcmp(tokens[0], "ipv6") == 0) {
3576 			struct in6_addr sa, da;
3577 			uint32_t flow_label;
3578 			uint8_t dscp, hop_limit;
3579 
3580 			if ((n_tokens < 6) ||
3581 				parse_ipv6_addr(tokens[1], &sa) ||
3582 				parse_ipv6_addr(tokens[2], &da) ||
3583 				parser_read_uint32(&flow_label, tokens[3]) ||
3584 				parser_read_uint8(&dscp, tokens[4]) ||
3585 				(dscp > 64) ||
3586 				parser_read_uint8(&hop_limit, tokens[5]))
3587 				return 0;
3588 
3589 			memcpy(a->encap.vxlan.ipv6.sa, sa.s6_addr, 16);
3590 			memcpy(a->encap.vxlan.ipv6.da, da.s6_addr, 16);
3591 			a->encap.vxlan.ipv6.flow_label = flow_label;
3592 			a->encap.vxlan.ipv6.dscp = dscp;
3593 			a->encap.vxlan.ipv6.hop_limit = hop_limit;
3594 
3595 			n_tokens -= 6;
3596 			tokens += 6;
3597 			n += 6;
3598 		} else
3599 			return 0;
3600 
3601 		/* udp <sp> <dp> */
3602 		if ((n_tokens < 3) ||
3603 			strcmp(tokens[0], "udp") ||
3604 			parser_read_uint16(&a->encap.vxlan.udp.sp, tokens[1]) ||
3605 			parser_read_uint16(&a->encap.vxlan.udp.dp, tokens[2]))
3606 			return 0;
3607 
3608 		n_tokens -= 3;
3609 		tokens += 3;
3610 		n += 3;
3611 
3612 		/* vxlan <vni> */
3613 		if ((n_tokens < 2) ||
3614 			strcmp(tokens[0], "vxlan") ||
3615 			parser_read_uint32(&a->encap.vxlan.vxlan.vni, tokens[1]) ||
3616 			(a->encap.vxlan.vxlan.vni > 0xFFFFFF))
3617 			return 0;
3618 
3619 		n_tokens -= 2;
3620 		tokens += 2;
3621 		n += 2;
3622 
3623 		a->encap.type = RTE_TABLE_ACTION_ENCAP_VXLAN;
3624 		a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
3625 		return 1 + n;
3626 	}
3627 
3628 	return 0;
3629 }
3630 
3631 static uint32_t
3632 parse_table_action_nat(char **tokens,
3633 	uint32_t n_tokens,
3634 	struct table_rule_action *a)
3635 {
3636 	if ((n_tokens < 4) ||
3637 		strcmp(tokens[0], "nat"))
3638 		return 0;
3639 
3640 	if (strcmp(tokens[1], "ipv4") == 0) {
3641 		struct in_addr addr;
3642 		uint16_t port;
3643 
3644 		if (parse_ipv4_addr(tokens[2], &addr) ||
3645 			parser_read_uint16(&port, tokens[3]))
3646 			return 0;
3647 
3648 		a->nat.ip_version = 1;
3649 		a->nat.addr.ipv4 = rte_be_to_cpu_32(addr.s_addr);
3650 		a->nat.port = port;
3651 		a->action_mask |= 1 << RTE_TABLE_ACTION_NAT;
3652 		return 4;
3653 	}
3654 
3655 	if (strcmp(tokens[1], "ipv6") == 0) {
3656 		struct in6_addr addr;
3657 		uint16_t port;
3658 
3659 		if (parse_ipv6_addr(tokens[2], &addr) ||
3660 			parser_read_uint16(&port, tokens[3]))
3661 			return 0;
3662 
3663 		a->nat.ip_version = 0;
3664 		memcpy(a->nat.addr.ipv6, addr.s6_addr, 16);
3665 		a->nat.port = port;
3666 		a->action_mask |= 1 << RTE_TABLE_ACTION_NAT;
3667 		return 4;
3668 	}
3669 
3670 	return 0;
3671 }
3672 
3673 static uint32_t
3674 parse_table_action_ttl(char **tokens,
3675 	uint32_t n_tokens,
3676 	struct table_rule_action *a)
3677 {
3678 	if ((n_tokens < 2) ||
3679 		strcmp(tokens[0], "ttl"))
3680 		return 0;
3681 
3682 	if (strcmp(tokens[1], "dec") == 0)
3683 		a->ttl.decrement = 1;
3684 	else if (strcmp(tokens[1], "keep") == 0)
3685 		a->ttl.decrement = 0;
3686 	else
3687 		return 0;
3688 
3689 	a->action_mask |= 1 << RTE_TABLE_ACTION_TTL;
3690 	return 2;
3691 }
3692 
3693 static uint32_t
3694 parse_table_action_stats(char **tokens,
3695 	uint32_t n_tokens,
3696 	struct table_rule_action *a)
3697 {
3698 	if ((n_tokens < 1) ||
3699 		strcmp(tokens[0], "stats"))
3700 		return 0;
3701 
3702 	a->stats.n_packets = 0;
3703 	a->stats.n_bytes = 0;
3704 	a->action_mask |= 1 << RTE_TABLE_ACTION_STATS;
3705 	return 1;
3706 }
3707 
3708 static uint32_t
3709 parse_table_action_time(char **tokens,
3710 	uint32_t n_tokens,
3711 	struct table_rule_action *a)
3712 {
3713 	if ((n_tokens < 1) ||
3714 		strcmp(tokens[0], "time"))
3715 		return 0;
3716 
3717 	a->time.time = rte_rdtsc();
3718 	a->action_mask |= 1 << RTE_TABLE_ACTION_TIME;
3719 	return 1;
3720 }
3721 
3722 static void
3723 parse_free_sym_crypto_param_data(struct rte_table_action_sym_crypto_params *p)
3724 {
3725 	struct rte_crypto_sym_xform *xform[2] = {NULL};
3726 	uint32_t i;
3727 
3728 	xform[0] = p->xform;
3729 	if (xform[0])
3730 		xform[1] = xform[0]->next;
3731 
3732 	for (i = 0; i < 2; i++) {
3733 		if (xform[i] == NULL)
3734 			continue;
3735 
3736 		switch (xform[i]->type) {
3737 		case RTE_CRYPTO_SYM_XFORM_CIPHER:
3738 			if (xform[i]->cipher.key.data)
3739 				free(xform[i]->cipher.key.data);
3740 			if (p->cipher_auth.cipher_iv.val)
3741 				free(p->cipher_auth.cipher_iv.val);
3742 			if (p->cipher_auth.cipher_iv_update.val)
3743 				free(p->cipher_auth.cipher_iv_update.val);
3744 			break;
3745 		case RTE_CRYPTO_SYM_XFORM_AUTH:
3746 			if (xform[i]->auth.key.data)
3747 				free(xform[i]->cipher.key.data);
3748 			if (p->cipher_auth.auth_iv.val)
3749 				free(p->cipher_auth.cipher_iv.val);
3750 			if (p->cipher_auth.auth_iv_update.val)
3751 				free(p->cipher_auth.cipher_iv_update.val);
3752 			break;
3753 		case RTE_CRYPTO_SYM_XFORM_AEAD:
3754 			if (xform[i]->aead.key.data)
3755 				free(xform[i]->cipher.key.data);
3756 			if (p->aead.iv.val)
3757 				free(p->aead.iv.val);
3758 			if (p->aead.aad.val)
3759 				free(p->aead.aad.val);
3760 			break;
3761 		default:
3762 			continue;
3763 		}
3764 	}
3765 
3766 }
3767 
3768 static struct rte_crypto_sym_xform *
3769 parse_table_action_cipher(struct rte_table_action_sym_crypto_params *p,
3770 		char **tokens, uint32_t n_tokens, uint32_t encrypt,
3771 		uint32_t *used_n_tokens)
3772 {
3773 	struct rte_crypto_sym_xform *xform_cipher;
3774 	int status;
3775 	size_t len;
3776 
3777 	if (n_tokens < 7 || strcmp(tokens[1], "cipher_algo") ||
3778 			strcmp(tokens[3], "cipher_key") ||
3779 			strcmp(tokens[5], "cipher_iv"))
3780 		return NULL;
3781 
3782 	xform_cipher = calloc(1, sizeof(*xform_cipher));
3783 	if (xform_cipher == NULL)
3784 		return NULL;
3785 
3786 	xform_cipher->type = RTE_CRYPTO_SYM_XFORM_CIPHER;
3787 	xform_cipher->cipher.op = encrypt ? RTE_CRYPTO_CIPHER_OP_ENCRYPT :
3788 			RTE_CRYPTO_CIPHER_OP_DECRYPT;
3789 
3790 	/* cipher_algo */
3791 	status = rte_cryptodev_get_cipher_algo_enum(
3792 			&xform_cipher->cipher.algo, tokens[2]);
3793 	if (status < 0)
3794 		goto error_exit;
3795 
3796 	/* cipher_key */
3797 	len = strlen(tokens[4]);
3798 	xform_cipher->cipher.key.data = calloc(1, len / 2 + 1);
3799 	if (xform_cipher->cipher.key.data == NULL)
3800 		goto error_exit;
3801 
3802 	status = parse_hex_string(tokens[4],
3803 			xform_cipher->cipher.key.data,
3804 			(uint32_t *)&len);
3805 	if (status < 0)
3806 		goto error_exit;
3807 
3808 	xform_cipher->cipher.key.length = (uint16_t)len;
3809 
3810 	/* cipher_iv */
3811 	len = strlen(tokens[6]);
3812 
3813 	p->cipher_auth.cipher_iv.val = calloc(1, len / 2 + 1);
3814 	if (p->cipher_auth.cipher_iv.val == NULL)
3815 		goto error_exit;
3816 
3817 	status = parse_hex_string(tokens[6],
3818 			p->cipher_auth.cipher_iv.val,
3819 			(uint32_t *)&len);
3820 	if (status < 0)
3821 		goto error_exit;
3822 
3823 	xform_cipher->cipher.iv.length = (uint16_t)len;
3824 	xform_cipher->cipher.iv.offset = RTE_TABLE_ACTION_SYM_CRYPTO_IV_OFFSET;
3825 	p->cipher_auth.cipher_iv.length = (uint32_t)len;
3826 	*used_n_tokens = 7;
3827 
3828 	return xform_cipher;
3829 
3830 error_exit:
3831 	if (xform_cipher->cipher.key.data)
3832 		free(xform_cipher->cipher.key.data);
3833 
3834 	if (p->cipher_auth.cipher_iv.val) {
3835 		free(p->cipher_auth.cipher_iv.val);
3836 		p->cipher_auth.cipher_iv.val = NULL;
3837 	}
3838 
3839 	free(xform_cipher);
3840 
3841 	return NULL;
3842 }
3843 
3844 static struct rte_crypto_sym_xform *
3845 parse_table_action_cipher_auth(struct rte_table_action_sym_crypto_params *p,
3846 		char **tokens, uint32_t n_tokens, uint32_t encrypt,
3847 		uint32_t *used_n_tokens)
3848 {
3849 	struct rte_crypto_sym_xform *xform_cipher;
3850 	struct rte_crypto_sym_xform *xform_auth;
3851 	int status;
3852 	size_t len;
3853 
3854 	if (n_tokens < 13 ||
3855 			strcmp(tokens[7], "auth_algo") ||
3856 			strcmp(tokens[9], "auth_key") ||
3857 			strcmp(tokens[11], "digest_size"))
3858 		return NULL;
3859 
3860 	xform_auth = calloc(1, sizeof(*xform_auth));
3861 	if (xform_auth == NULL)
3862 		return NULL;
3863 
3864 	xform_auth->type = RTE_CRYPTO_SYM_XFORM_AUTH;
3865 	xform_auth->auth.op = encrypt ? RTE_CRYPTO_AUTH_OP_GENERATE :
3866 			RTE_CRYPTO_AUTH_OP_VERIFY;
3867 
3868 	/* auth_algo */
3869 	status = rte_cryptodev_get_auth_algo_enum(&xform_auth->auth.algo,
3870 			tokens[8]);
3871 	if (status < 0)
3872 		goto error_exit;
3873 
3874 	/* auth_key */
3875 	len = strlen(tokens[10]);
3876 	xform_auth->auth.key.data = calloc(1, len / 2 + 1);
3877 	if (xform_auth->auth.key.data == NULL)
3878 		goto error_exit;
3879 
3880 	status = parse_hex_string(tokens[10],
3881 			xform_auth->auth.key.data, (uint32_t *)&len);
3882 	if (status < 0)
3883 		goto error_exit;
3884 
3885 	xform_auth->auth.key.length = (uint16_t)len;
3886 
3887 	if (strcmp(tokens[11], "digest_size"))
3888 		goto error_exit;
3889 
3890 	status = parser_read_uint16(&xform_auth->auth.digest_length,
3891 			tokens[12]);
3892 	if (status < 0)
3893 		goto error_exit;
3894 
3895 	xform_cipher = parse_table_action_cipher(p, tokens, 7, encrypt,
3896 			used_n_tokens);
3897 	if (xform_cipher == NULL)
3898 		goto error_exit;
3899 
3900 	*used_n_tokens += 6;
3901 
3902 	if (encrypt) {
3903 		xform_cipher->next = xform_auth;
3904 		return xform_cipher;
3905 	} else {
3906 		xform_auth->next = xform_cipher;
3907 		return xform_auth;
3908 	}
3909 
3910 error_exit:
3911 	if (xform_auth->auth.key.data)
3912 		free(xform_auth->auth.key.data);
3913 	if (p->cipher_auth.auth_iv.val) {
3914 		free(p->cipher_auth.auth_iv.val);
3915 		p->cipher_auth.auth_iv.val = 0;
3916 	}
3917 
3918 	free(xform_auth);
3919 
3920 	return NULL;
3921 }
3922 
3923 static struct rte_crypto_sym_xform *
3924 parse_table_action_aead(struct rte_table_action_sym_crypto_params *p,
3925 		char **tokens, uint32_t n_tokens, uint32_t encrypt,
3926 		uint32_t *used_n_tokens)
3927 {
3928 	struct rte_crypto_sym_xform *xform_aead;
3929 	int status;
3930 	size_t len;
3931 
3932 	if (n_tokens < 11 || strcmp(tokens[1], "aead_algo") ||
3933 			strcmp(tokens[3], "aead_key") ||
3934 			strcmp(tokens[5], "aead_iv") ||
3935 			strcmp(tokens[7], "aead_aad") ||
3936 			strcmp(tokens[9], "digest_size"))
3937 		return NULL;
3938 
3939 	xform_aead = calloc(1, sizeof(*xform_aead));
3940 	if (xform_aead == NULL)
3941 		return NULL;
3942 
3943 	xform_aead->type = RTE_CRYPTO_SYM_XFORM_AEAD;
3944 	xform_aead->aead.op = encrypt ? RTE_CRYPTO_AEAD_OP_ENCRYPT :
3945 			RTE_CRYPTO_AEAD_OP_DECRYPT;
3946 
3947 	/* aead_algo */
3948 	status = rte_cryptodev_get_aead_algo_enum(&xform_aead->aead.algo,
3949 			tokens[2]);
3950 	if (status < 0)
3951 		goto error_exit;
3952 
3953 	/* aead_key */
3954 	len = strlen(tokens[4]);
3955 	xform_aead->aead.key.data = calloc(1, len / 2 + 1);
3956 	if (xform_aead->aead.key.data == NULL)
3957 		goto error_exit;
3958 
3959 	status = parse_hex_string(tokens[4], xform_aead->aead.key.data,
3960 			(uint32_t *)&len);
3961 	if (status < 0)
3962 		goto error_exit;
3963 
3964 	xform_aead->aead.key.length = (uint16_t)len;
3965 
3966 	/* aead_iv */
3967 	len = strlen(tokens[6]);
3968 	p->aead.iv.val = calloc(1, len / 2 + 1);
3969 	if (p->aead.iv.val == NULL)
3970 		goto error_exit;
3971 
3972 	status = parse_hex_string(tokens[6], p->aead.iv.val,
3973 			(uint32_t *)&len);
3974 	if (status < 0)
3975 		goto error_exit;
3976 
3977 	xform_aead->aead.iv.length = (uint16_t)len;
3978 	xform_aead->aead.iv.offset = RTE_TABLE_ACTION_SYM_CRYPTO_IV_OFFSET;
3979 	p->aead.iv.length = (uint32_t)len;
3980 
3981 	/* aead_aad */
3982 	len = strlen(tokens[8]);
3983 	p->aead.aad.val = calloc(1, len / 2 + 1);
3984 	if (p->aead.aad.val == NULL)
3985 		goto error_exit;
3986 
3987 	status = parse_hex_string(tokens[8], p->aead.aad.val, (uint32_t *)&len);
3988 	if (status < 0)
3989 		goto error_exit;
3990 
3991 	xform_aead->aead.aad_length = (uint16_t)len;
3992 	p->aead.aad.length = (uint32_t)len;
3993 
3994 	/* digest_size */
3995 	status = parser_read_uint16(&xform_aead->aead.digest_length,
3996 			tokens[10]);
3997 	if (status < 0)
3998 		goto error_exit;
3999 
4000 	*used_n_tokens = 11;
4001 
4002 	return xform_aead;
4003 
4004 error_exit:
4005 	if (xform_aead->aead.key.data)
4006 		free(xform_aead->aead.key.data);
4007 	if (p->aead.iv.val) {
4008 		free(p->aead.iv.val);
4009 		p->aead.iv.val = NULL;
4010 	}
4011 	if (p->aead.aad.val) {
4012 		free(p->aead.aad.val);
4013 		p->aead.aad.val = NULL;
4014 	}
4015 
4016 	free(xform_aead);
4017 
4018 	return NULL;
4019 }
4020 
4021 
4022 static uint32_t
4023 parse_table_action_sym_crypto(char **tokens,
4024 	uint32_t n_tokens,
4025 	struct table_rule_action *a)
4026 {
4027 	struct rte_table_action_sym_crypto_params *p = &a->sym_crypto;
4028 	struct rte_crypto_sym_xform *xform = NULL;
4029 	uint32_t used_n_tokens;
4030 	uint32_t encrypt;
4031 	int status;
4032 
4033 	if ((n_tokens < 12) ||
4034 		strcmp(tokens[0], "sym_crypto") ||
4035 		strcmp(tokens[2], "type"))
4036 		return 0;
4037 
4038 	memset(p, 0, sizeof(*p));
4039 
4040 	if (strcmp(tokens[1], "encrypt") == 0)
4041 		encrypt = 1;
4042 	else
4043 		encrypt = 0;
4044 
4045 	status = parser_read_uint32(&p->data_offset, tokens[n_tokens - 1]);
4046 	if (status < 0)
4047 		return 0;
4048 
4049 	if (strcmp(tokens[3], "cipher") == 0) {
4050 		tokens += 3;
4051 		n_tokens -= 3;
4052 
4053 		xform = parse_table_action_cipher(p, tokens, n_tokens, encrypt,
4054 				&used_n_tokens);
4055 	} else if (strcmp(tokens[3], "cipher_auth") == 0) {
4056 		tokens += 3;
4057 		n_tokens -= 3;
4058 
4059 		xform = parse_table_action_cipher_auth(p, tokens, n_tokens,
4060 				encrypt, &used_n_tokens);
4061 	} else if (strcmp(tokens[3], "aead") == 0) {
4062 		tokens += 3;
4063 		n_tokens -= 3;
4064 
4065 		xform = parse_table_action_aead(p, tokens, n_tokens, encrypt,
4066 				&used_n_tokens);
4067 	}
4068 
4069 	if (xform == NULL)
4070 		return 0;
4071 
4072 	p->xform = xform;
4073 
4074 	if (strcmp(tokens[used_n_tokens], "data_offset")) {
4075 		parse_free_sym_crypto_param_data(p);
4076 		return 0;
4077 	}
4078 
4079 	a->action_mask |= 1 << RTE_TABLE_ACTION_SYM_CRYPTO;
4080 
4081 	return used_n_tokens + 5;
4082 }
4083 
4084 static uint32_t
4085 parse_table_action_tag(char **tokens,
4086 	uint32_t n_tokens,
4087 	struct table_rule_action *a)
4088 {
4089 	if ((n_tokens < 2) ||
4090 		strcmp(tokens[0], "tag"))
4091 		return 0;
4092 
4093 	if (parser_read_uint32(&a->tag.tag, tokens[1]))
4094 		return 0;
4095 
4096 	a->action_mask |= 1 << RTE_TABLE_ACTION_TAG;
4097 	return 2;
4098 }
4099 
4100 static uint32_t
4101 parse_table_action_decap(char **tokens,
4102 	uint32_t n_tokens,
4103 	struct table_rule_action *a)
4104 {
4105 	if ((n_tokens < 2) ||
4106 		strcmp(tokens[0], "decap"))
4107 		return 0;
4108 
4109 	if (parser_read_uint16(&a->decap.n, tokens[1]))
4110 		return 0;
4111 
4112 	a->action_mask |= 1 << RTE_TABLE_ACTION_DECAP;
4113 	return 2;
4114 }
4115 
4116 static uint32_t
4117 parse_table_action(char **tokens,
4118 	uint32_t n_tokens,
4119 	char *out,
4120 	size_t out_size,
4121 	struct table_rule_action *a)
4122 {
4123 	uint32_t n_tokens0 = n_tokens;
4124 
4125 	memset(a, 0, sizeof(*a));
4126 
4127 	if ((n_tokens < 2) ||
4128 		strcmp(tokens[0], "action"))
4129 		return 0;
4130 
4131 	tokens++;
4132 	n_tokens--;
4133 
4134 	if (n_tokens && (strcmp(tokens[0], "fwd") == 0)) {
4135 		uint32_t n;
4136 
4137 		n = parse_table_action_fwd(tokens, n_tokens, a);
4138 		if (n == 0) {
4139 			snprintf(out, out_size, MSG_ARG_INVALID,
4140 				"action fwd");
4141 			return 0;
4142 		}
4143 
4144 		tokens += n;
4145 		n_tokens -= n;
4146 	}
4147 
4148 	if (n_tokens && (strcmp(tokens[0], "balance") == 0)) {
4149 		uint32_t n;
4150 
4151 		n = parse_table_action_balance(tokens, n_tokens, a);
4152 		if (n == 0) {
4153 			snprintf(out, out_size, MSG_ARG_INVALID,
4154 				"action balance");
4155 			return 0;
4156 		}
4157 
4158 		tokens += n;
4159 		n_tokens -= n;
4160 	}
4161 
4162 	if (n_tokens && (strcmp(tokens[0], "meter") == 0)) {
4163 		uint32_t n;
4164 
4165 		n = parse_table_action_meter(tokens, n_tokens, a);
4166 		if (n == 0) {
4167 			snprintf(out, out_size, MSG_ARG_INVALID,
4168 				"action meter");
4169 			return 0;
4170 		}
4171 
4172 		tokens += n;
4173 		n_tokens -= n;
4174 	}
4175 
4176 	if (n_tokens && (strcmp(tokens[0], "tm") == 0)) {
4177 		uint32_t n;
4178 
4179 		n = parse_table_action_tm(tokens, n_tokens, a);
4180 		if (n == 0) {
4181 			snprintf(out, out_size, MSG_ARG_INVALID,
4182 				"action tm");
4183 			return 0;
4184 		}
4185 
4186 		tokens += n;
4187 		n_tokens -= n;
4188 	}
4189 
4190 	if (n_tokens && (strcmp(tokens[0], "encap") == 0)) {
4191 		uint32_t n;
4192 
4193 		n = parse_table_action_encap(tokens, n_tokens, a);
4194 		if (n == 0) {
4195 			snprintf(out, out_size, MSG_ARG_INVALID,
4196 				"action encap");
4197 			return 0;
4198 		}
4199 
4200 		tokens += n;
4201 		n_tokens -= n;
4202 	}
4203 
4204 	if (n_tokens && (strcmp(tokens[0], "nat") == 0)) {
4205 		uint32_t n;
4206 
4207 		n = parse_table_action_nat(tokens, n_tokens, a);
4208 		if (n == 0) {
4209 			snprintf(out, out_size, MSG_ARG_INVALID,
4210 				"action nat");
4211 			return 0;
4212 		}
4213 
4214 		tokens += n;
4215 		n_tokens -= n;
4216 	}
4217 
4218 	if (n_tokens && (strcmp(tokens[0], "ttl") == 0)) {
4219 		uint32_t n;
4220 
4221 		n = parse_table_action_ttl(tokens, n_tokens, a);
4222 		if (n == 0) {
4223 			snprintf(out, out_size, MSG_ARG_INVALID,
4224 				"action ttl");
4225 			return 0;
4226 		}
4227 
4228 		tokens += n;
4229 		n_tokens -= n;
4230 	}
4231 
4232 	if (n_tokens && (strcmp(tokens[0], "stats") == 0)) {
4233 		uint32_t n;
4234 
4235 		n = parse_table_action_stats(tokens, n_tokens, a);
4236 		if (n == 0) {
4237 			snprintf(out, out_size, MSG_ARG_INVALID,
4238 				"action stats");
4239 			return 0;
4240 		}
4241 
4242 		tokens += n;
4243 		n_tokens -= n;
4244 	}
4245 
4246 	if (n_tokens && (strcmp(tokens[0], "time") == 0)) {
4247 		uint32_t n;
4248 
4249 		n = parse_table_action_time(tokens, n_tokens, a);
4250 		if (n == 0) {
4251 			snprintf(out, out_size, MSG_ARG_INVALID,
4252 				"action time");
4253 			return 0;
4254 		}
4255 
4256 		tokens += n;
4257 		n_tokens -= n;
4258 	}
4259 
4260 	if (n_tokens && (strcmp(tokens[0], "sym_crypto") == 0)) {
4261 		uint32_t n;
4262 
4263 		n = parse_table_action_sym_crypto(tokens, n_tokens, a);
4264 		if (n == 0) {
4265 			snprintf(out, out_size, MSG_ARG_INVALID,
4266 				"action sym_crypto");
4267 		}
4268 
4269 		tokens += n;
4270 		n_tokens -= n;
4271 	}
4272 
4273 	if (n_tokens && (strcmp(tokens[0], "tag") == 0)) {
4274 		uint32_t n;
4275 
4276 		n = parse_table_action_tag(tokens, n_tokens, a);
4277 		if (n == 0) {
4278 			snprintf(out, out_size, MSG_ARG_INVALID,
4279 				"action tag");
4280 			return 0;
4281 		}
4282 
4283 		tokens += n;
4284 		n_tokens -= n;
4285 	}
4286 
4287 	if (n_tokens && (strcmp(tokens[0], "decap") == 0)) {
4288 		uint32_t n;
4289 
4290 		n = parse_table_action_decap(tokens, n_tokens, a);
4291 		if (n == 0) {
4292 			snprintf(out, out_size, MSG_ARG_INVALID,
4293 				"action decap");
4294 			return 0;
4295 		}
4296 
4297 		tokens += n;
4298 		n_tokens -= n;
4299 	}
4300 
4301 	if (n_tokens0 - n_tokens == 1) {
4302 		snprintf(out, out_size, MSG_ARG_INVALID, "action");
4303 		return 0;
4304 	}
4305 
4306 	return n_tokens0 - n_tokens;
4307 }
4308 
4309 
4310 static const char cmd_pipeline_table_rule_add_help[] =
4311 "pipeline <pipeline_name> table <table_id> rule add\n"
4312 "     match <match>\n"
4313 "     action <table_action>\n";
4314 
4315 static void
4316 cmd_pipeline_table_rule_add(char **tokens,
4317 	uint32_t n_tokens,
4318 	char *out,
4319 	size_t out_size)
4320 {
4321 	struct table_rule_match m;
4322 	struct table_rule_action a;
4323 	char *pipeline_name;
4324 	void *data;
4325 	uint32_t table_id, t0, n_tokens_parsed;
4326 	int status;
4327 
4328 	if (n_tokens < 8) {
4329 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4330 		return;
4331 	}
4332 
4333 	pipeline_name = tokens[1];
4334 
4335 	if (strcmp(tokens[2], "table") != 0) {
4336 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
4337 		return;
4338 	}
4339 
4340 	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
4341 		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
4342 		return;
4343 	}
4344 
4345 	if (strcmp(tokens[4], "rule") != 0) {
4346 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
4347 		return;
4348 	}
4349 
4350 	if (strcmp(tokens[5], "add") != 0) {
4351 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
4352 		return;
4353 	}
4354 
4355 	t0 = 6;
4356 
4357 	/* match */
4358 	n_tokens_parsed = parse_match(tokens + t0,
4359 		n_tokens - t0,
4360 		out,
4361 		out_size,
4362 		&m);
4363 	if (n_tokens_parsed == 0)
4364 		return;
4365 	t0 += n_tokens_parsed;
4366 
4367 	/* action */
4368 	n_tokens_parsed = parse_table_action(tokens + t0,
4369 		n_tokens - t0,
4370 		out,
4371 		out_size,
4372 		&a);
4373 	if (n_tokens_parsed == 0)
4374 		return;
4375 	t0 += n_tokens_parsed;
4376 
4377 	if (t0 != n_tokens) {
4378 		snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
4379 		return;
4380 	}
4381 
4382 	status = pipeline_table_rule_add(pipeline_name, table_id,
4383 		&m, &a, &data);
4384 	if (status) {
4385 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
4386 		return;
4387 	}
4388 
4389 	if (a.action_mask & 1 << RTE_TABLE_ACTION_SYM_CRYPTO)
4390 		parse_free_sym_crypto_param_data(&a.sym_crypto);
4391 }
4392 
4393 
4394 static const char cmd_pipeline_table_rule_add_default_help[] =
4395 "pipeline <pipeline_name> table <table_id> rule add\n"
4396 "     match\n"
4397 "        default\n"
4398 "     action\n"
4399 "        fwd\n"
4400 "           drop\n"
4401 "           | port <port_id>\n"
4402 "           | meta\n"
4403 "           | table <table_id>\n";
4404 
4405 static void
4406 cmd_pipeline_table_rule_add_default(char **tokens,
4407 	uint32_t n_tokens,
4408 	char *out,
4409 	size_t out_size)
4410 {
4411 	struct table_rule_action action;
4412 	void *data;
4413 	char *pipeline_name;
4414 	uint32_t table_id;
4415 	int status;
4416 
4417 	if ((n_tokens != 11) && (n_tokens != 12)) {
4418 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4419 		return;
4420 	}
4421 
4422 	pipeline_name = tokens[1];
4423 
4424 	if (strcmp(tokens[2], "table") != 0) {
4425 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
4426 		return;
4427 	}
4428 
4429 	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
4430 		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
4431 		return;
4432 	}
4433 
4434 	if (strcmp(tokens[4], "rule") != 0) {
4435 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
4436 		return;
4437 	}
4438 
4439 	if (strcmp(tokens[5], "add") != 0) {
4440 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
4441 		return;
4442 	}
4443 
4444 	if (strcmp(tokens[6], "match") != 0) {
4445 		snprintf(out, out_size, MSG_ARG_INVALID, "match");
4446 		return;
4447 	}
4448 
4449 	if (strcmp(tokens[7], "default") != 0) {
4450 		snprintf(out, out_size, MSG_ARG_INVALID, "default");
4451 		return;
4452 	}
4453 
4454 	if (strcmp(tokens[8], "action") != 0) {
4455 		snprintf(out, out_size, MSG_ARG_INVALID, "action");
4456 		return;
4457 	}
4458 
4459 	if (strcmp(tokens[9], "fwd") != 0) {
4460 		snprintf(out, out_size, MSG_ARG_INVALID, "fwd");
4461 		return;
4462 	}
4463 
4464 	action.action_mask = 1 << RTE_TABLE_ACTION_FWD;
4465 
4466 	if (strcmp(tokens[10], "drop") == 0) {
4467 		if (n_tokens != 11) {
4468 			snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4469 			return;
4470 		}
4471 
4472 		action.fwd.action = RTE_PIPELINE_ACTION_DROP;
4473 	} else if (strcmp(tokens[10], "port") == 0) {
4474 		uint32_t id;
4475 
4476 		if (n_tokens != 12) {
4477 			snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4478 			return;
4479 		}
4480 
4481 		if (parser_read_uint32(&id, tokens[11]) != 0) {
4482 			snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
4483 			return;
4484 		}
4485 
4486 		action.fwd.action = RTE_PIPELINE_ACTION_PORT;
4487 		action.fwd.id = id;
4488 	} else if (strcmp(tokens[10], "meta") == 0) {
4489 		if (n_tokens != 11) {
4490 			snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4491 			return;
4492 		}
4493 
4494 		action.fwd.action = RTE_PIPELINE_ACTION_PORT_META;
4495 	} else if (strcmp(tokens[10], "table") == 0) {
4496 		uint32_t id;
4497 
4498 		if (n_tokens != 12) {
4499 			snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4500 			return;
4501 		}
4502 
4503 		if (parser_read_uint32(&id, tokens[11]) != 0) {
4504 			snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
4505 			return;
4506 		}
4507 
4508 		action.fwd.action = RTE_PIPELINE_ACTION_TABLE;
4509 		action.fwd.id = id;
4510 	} else {
4511 		snprintf(out, out_size, MSG_ARG_INVALID,
4512 			"drop or port or meta or table");
4513 		return;
4514 	}
4515 
4516 	status = pipeline_table_rule_add_default(pipeline_name,
4517 		table_id,
4518 		&action,
4519 		&data);
4520 	if (status) {
4521 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
4522 		return;
4523 	}
4524 }
4525 
4526 
4527 static const char cmd_pipeline_table_rule_add_bulk_help[] =
4528 "pipeline <pipeline_name> table <table_id> rule add bulk <file_name> <n_rules>\n"
4529 "\n"
4530 "  File <file_name>:\n"
4531 "  - line format: match <match> action <action>\n";
4532 
4533 static int
4534 cli_rule_file_process(const char *file_name,
4535 	size_t line_len_max,
4536 	struct table_rule_match *m,
4537 	struct table_rule_action *a,
4538 	uint32_t *n_rules,
4539 	uint32_t *line_number,
4540 	char *out,
4541 	size_t out_size);
4542 
4543 static void
4544 cmd_pipeline_table_rule_add_bulk(char **tokens,
4545 	uint32_t n_tokens,
4546 	char *out,
4547 	size_t out_size)
4548 {
4549 	struct table_rule_match *match;
4550 	struct table_rule_action *action;
4551 	void **data;
4552 	char *pipeline_name, *file_name;
4553 	uint32_t table_id, n_rules, n_rules_parsed, line_number;
4554 	int status;
4555 
4556 	if (n_tokens != 9) {
4557 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4558 		return;
4559 	}
4560 
4561 	pipeline_name = tokens[1];
4562 
4563 	if (strcmp(tokens[2], "table") != 0) {
4564 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
4565 		return;
4566 	}
4567 
4568 	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
4569 		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
4570 		return;
4571 	}
4572 
4573 	if (strcmp(tokens[4], "rule") != 0) {
4574 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
4575 		return;
4576 	}
4577 
4578 	if (strcmp(tokens[5], "add") != 0) {
4579 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
4580 		return;
4581 	}
4582 
4583 	if (strcmp(tokens[6], "bulk") != 0) {
4584 		snprintf(out, out_size, MSG_ARG_INVALID, "bulk");
4585 		return;
4586 	}
4587 
4588 	file_name = tokens[7];
4589 
4590 	if ((parser_read_uint32(&n_rules, tokens[8]) != 0) ||
4591 		(n_rules == 0)) {
4592 		snprintf(out, out_size, MSG_ARG_INVALID, "n_rules");
4593 		return;
4594 	}
4595 
4596 	/* Memory allocation. */
4597 	match = calloc(n_rules, sizeof(struct table_rule_match));
4598 	action = calloc(n_rules, sizeof(struct table_rule_action));
4599 	data = calloc(n_rules, sizeof(void *));
4600 	if ((match == NULL) || (action == NULL) || (data == NULL)) {
4601 		snprintf(out, out_size, MSG_OUT_OF_MEMORY);
4602 		free(data);
4603 		free(action);
4604 		free(match);
4605 		return;
4606 	}
4607 
4608 	/* Load rule file */
4609 	n_rules_parsed = n_rules;
4610 	status = cli_rule_file_process(file_name,
4611 		1024,
4612 		match,
4613 		action,
4614 		&n_rules_parsed,
4615 		&line_number,
4616 		out,
4617 		out_size);
4618 	if (status) {
4619 		snprintf(out, out_size, MSG_FILE_ERR, file_name, line_number);
4620 		free(data);
4621 		free(action);
4622 		free(match);
4623 		return;
4624 	}
4625 	if (n_rules_parsed != n_rules) {
4626 		snprintf(out, out_size, MSG_FILE_NOT_ENOUGH, file_name);
4627 		free(data);
4628 		free(action);
4629 		free(match);
4630 		return;
4631 	}
4632 
4633 	/* Rule bulk add */
4634 	status = pipeline_table_rule_add_bulk(pipeline_name,
4635 		table_id,
4636 		match,
4637 		action,
4638 		data,
4639 		&n_rules);
4640 	if (status) {
4641 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
4642 		free(data);
4643 		free(action);
4644 		free(match);
4645 		return;
4646 	}
4647 
4648 	/* Memory free */
4649 	free(data);
4650 	free(action);
4651 	free(match);
4652 }
4653 
4654 
4655 static const char cmd_pipeline_table_rule_delete_help[] =
4656 "pipeline <pipeline_name> table <table_id> rule delete\n"
4657 "     match <match>\n";
4658 
4659 static void
4660 cmd_pipeline_table_rule_delete(char **tokens,
4661 	uint32_t n_tokens,
4662 	char *out,
4663 	size_t out_size)
4664 {
4665 	struct table_rule_match m;
4666 	char *pipeline_name;
4667 	uint32_t table_id, n_tokens_parsed, t0;
4668 	int status;
4669 
4670 	if (n_tokens < 8) {
4671 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4672 		return;
4673 	}
4674 
4675 	pipeline_name = tokens[1];
4676 
4677 	if (strcmp(tokens[2], "table") != 0) {
4678 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
4679 		return;
4680 	}
4681 
4682 	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
4683 		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
4684 		return;
4685 	}
4686 
4687 	if (strcmp(tokens[4], "rule") != 0) {
4688 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
4689 		return;
4690 	}
4691 
4692 	if (strcmp(tokens[5], "delete") != 0) {
4693 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete");
4694 		return;
4695 	}
4696 
4697 	t0 = 6;
4698 
4699 	/* match */
4700 	n_tokens_parsed = parse_match(tokens + t0,
4701 		n_tokens - t0,
4702 		out,
4703 		out_size,
4704 		&m);
4705 	if (n_tokens_parsed == 0)
4706 		return;
4707 	t0 += n_tokens_parsed;
4708 
4709 	if (n_tokens != t0) {
4710 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4711 		return;
4712 	}
4713 
4714 	status = pipeline_table_rule_delete(pipeline_name,
4715 		table_id,
4716 		&m);
4717 	if (status) {
4718 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
4719 		return;
4720 	}
4721 }
4722 
4723 
4724 static const char cmd_pipeline_table_rule_delete_default_help[] =
4725 "pipeline <pipeline_name> table <table_id> rule delete\n"
4726 "     match\n"
4727 "        default\n";
4728 
4729 static void
4730 cmd_pipeline_table_rule_delete_default(char **tokens,
4731 	uint32_t n_tokens,
4732 	char *out,
4733 	size_t out_size)
4734 {
4735 	char *pipeline_name;
4736 	uint32_t table_id;
4737 	int status;
4738 
4739 	if (n_tokens != 8) {
4740 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4741 		return;
4742 	}
4743 
4744 	pipeline_name = tokens[1];
4745 
4746 	if (strcmp(tokens[2], "table") != 0) {
4747 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
4748 		return;
4749 	}
4750 
4751 	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
4752 		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
4753 		return;
4754 	}
4755 
4756 	if (strcmp(tokens[4], "rule") != 0) {
4757 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
4758 		return;
4759 	}
4760 
4761 	if (strcmp(tokens[5], "delete") != 0) {
4762 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete");
4763 		return;
4764 	}
4765 
4766 	if (strcmp(tokens[6], "match") != 0) {
4767 		snprintf(out, out_size, MSG_ARG_INVALID, "match");
4768 		return;
4769 	}
4770 
4771 	if (strcmp(tokens[7], "default") != 0) {
4772 		snprintf(out, out_size, MSG_ARG_INVALID, "default");
4773 		return;
4774 	}
4775 
4776 	status = pipeline_table_rule_delete_default(pipeline_name,
4777 		table_id);
4778 	if (status) {
4779 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
4780 		return;
4781 	}
4782 }
4783 
4784 
4785 static const char cmd_pipeline_table_rule_stats_read_help[] =
4786 "pipeline <pipeline_name> table <table_id> rule read stats [clear]\n";
4787 
4788 static void
4789 cmd_pipeline_table_rule_stats_read(char **tokens,
4790 	uint32_t n_tokens __rte_unused,
4791 	char *out,
4792 	size_t out_size)
4793 {
4794 	snprintf(out, out_size, MSG_CMD_UNIMPLEM, tokens[0]);
4795 }
4796 
4797 
4798 static const char cmd_pipeline_table_meter_profile_add_help[] =
4799 "pipeline <pipeline_name> table <table_id> meter profile <meter_profile_id>\n"
4800 "   add srtcm cir <cir> cbs <cbs> ebs <ebs>\n"
4801 "   | trtcm cir <cir> pir <pir> cbs <cbs> pbs <pbs>\n";
4802 
4803 static void
4804 cmd_pipeline_table_meter_profile_add(char **tokens,
4805 	uint32_t n_tokens,
4806 	char *out,
4807 	size_t out_size)
4808 {
4809 	struct rte_table_action_meter_profile p;
4810 	char *pipeline_name;
4811 	uint32_t table_id, meter_profile_id;
4812 	int status;
4813 
4814 	if (n_tokens < 9) {
4815 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4816 		return;
4817 	}
4818 
4819 	pipeline_name = tokens[1];
4820 
4821 	if (strcmp(tokens[2], "table") != 0) {
4822 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
4823 		return;
4824 	}
4825 
4826 	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
4827 		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
4828 		return;
4829 	}
4830 
4831 	if (strcmp(tokens[4], "meter") != 0) {
4832 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
4833 		return;
4834 	}
4835 
4836 	if (strcmp(tokens[5], "profile") != 0) {
4837 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
4838 		return;
4839 	}
4840 
4841 	if (parser_read_uint32(&meter_profile_id, tokens[6]) != 0) {
4842 		snprintf(out, out_size, MSG_ARG_INVALID, "meter_profile_id");
4843 		return;
4844 	}
4845 
4846 	if (strcmp(tokens[7], "add") != 0) {
4847 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
4848 		return;
4849 	}
4850 
4851 	if (strcmp(tokens[8], "srtcm") == 0) {
4852 		if (n_tokens != 15) {
4853 			snprintf(out, out_size, MSG_ARG_MISMATCH,
4854 				tokens[0]);
4855 			return;
4856 		}
4857 
4858 		p.alg = RTE_TABLE_ACTION_METER_SRTCM;
4859 
4860 		if (strcmp(tokens[9], "cir") != 0) {
4861 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cir");
4862 			return;
4863 		}
4864 
4865 		if (parser_read_uint64(&p.srtcm.cir, tokens[10]) != 0) {
4866 			snprintf(out, out_size, MSG_ARG_INVALID, "cir");
4867 			return;
4868 		}
4869 
4870 		if (strcmp(tokens[11], "cbs") != 0) {
4871 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cbs");
4872 			return;
4873 		}
4874 
4875 		if (parser_read_uint64(&p.srtcm.cbs, tokens[12]) != 0) {
4876 			snprintf(out, out_size, MSG_ARG_INVALID, "cbs");
4877 			return;
4878 		}
4879 
4880 		if (strcmp(tokens[13], "ebs") != 0) {
4881 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "ebs");
4882 			return;
4883 		}
4884 
4885 		if (parser_read_uint64(&p.srtcm.ebs, tokens[14]) != 0) {
4886 			snprintf(out, out_size, MSG_ARG_INVALID, "ebs");
4887 			return;
4888 		}
4889 	} else if (strcmp(tokens[8], "trtcm") == 0) {
4890 		if (n_tokens != 17) {
4891 			snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4892 			return;
4893 		}
4894 
4895 		p.alg = RTE_TABLE_ACTION_METER_TRTCM;
4896 
4897 		if (strcmp(tokens[9], "cir") != 0) {
4898 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cir");
4899 			return;
4900 		}
4901 
4902 		if (parser_read_uint64(&p.trtcm.cir, tokens[10]) != 0) {
4903 			snprintf(out, out_size, MSG_ARG_INVALID, "cir");
4904 			return;
4905 		}
4906 
4907 		if (strcmp(tokens[11], "pir") != 0) {
4908 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pir");
4909 			return;
4910 		}
4911 
4912 		if (parser_read_uint64(&p.trtcm.pir, tokens[12]) != 0) {
4913 			snprintf(out, out_size, MSG_ARG_INVALID, "pir");
4914 			return;
4915 		}
4916 		if (strcmp(tokens[13], "cbs") != 0) {
4917 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cbs");
4918 			return;
4919 		}
4920 
4921 		if (parser_read_uint64(&p.trtcm.cbs, tokens[14]) != 0) {
4922 			snprintf(out, out_size, MSG_ARG_INVALID, "cbs");
4923 			return;
4924 		}
4925 
4926 		if (strcmp(tokens[15], "pbs") != 0) {
4927 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pbs");
4928 			return;
4929 		}
4930 
4931 		if (parser_read_uint64(&p.trtcm.pbs, tokens[16]) != 0) {
4932 			snprintf(out, out_size, MSG_ARG_INVALID, "pbs");
4933 			return;
4934 		}
4935 	} else {
4936 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4937 		return;
4938 	}
4939 
4940 	status = pipeline_table_mtr_profile_add(pipeline_name,
4941 		table_id,
4942 		meter_profile_id,
4943 		&p);
4944 	if (status) {
4945 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
4946 		return;
4947 	}
4948 }
4949 
4950 
4951 static const char cmd_pipeline_table_meter_profile_delete_help[] =
4952 "pipeline <pipeline_name> table <table_id>\n"
4953 "   meter profile <meter_profile_id> delete\n";
4954 
4955 static void
4956 cmd_pipeline_table_meter_profile_delete(char **tokens,
4957 	uint32_t n_tokens,
4958 	char *out,
4959 	size_t out_size)
4960 {
4961 	char *pipeline_name;
4962 	uint32_t table_id, meter_profile_id;
4963 	int status;
4964 
4965 	if (n_tokens != 8) {
4966 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4967 		return;
4968 	}
4969 
4970 	pipeline_name = tokens[1];
4971 
4972 	if (strcmp(tokens[2], "table") != 0) {
4973 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
4974 		return;
4975 	}
4976 
4977 	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
4978 		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
4979 		return;
4980 	}
4981 
4982 	if (strcmp(tokens[4], "meter") != 0) {
4983 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
4984 		return;
4985 	}
4986 
4987 	if (strcmp(tokens[5], "profile") != 0) {
4988 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
4989 		return;
4990 	}
4991 
4992 	if (parser_read_uint32(&meter_profile_id, tokens[6]) != 0) {
4993 		snprintf(out, out_size, MSG_ARG_INVALID, "meter_profile_id");
4994 		return;
4995 	}
4996 
4997 	if (strcmp(tokens[7], "delete") != 0) {
4998 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete");
4999 		return;
5000 	}
5001 
5002 	status = pipeline_table_mtr_profile_delete(pipeline_name,
5003 		table_id,
5004 		meter_profile_id);
5005 	if (status) {
5006 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
5007 		return;
5008 	}
5009 }
5010 
5011 
5012 static const char cmd_pipeline_table_rule_meter_read_help[] =
5013 "pipeline <pipeline_name> table <table_id> rule read meter [clear]\n";
5014 
5015 static void
5016 cmd_pipeline_table_rule_meter_read(char **tokens,
5017 	uint32_t n_tokens __rte_unused,
5018 	char *out,
5019 	size_t out_size)
5020 {
5021 	snprintf(out, out_size, MSG_CMD_UNIMPLEM, tokens[0]);
5022 }
5023 
5024 
5025 static const char cmd_pipeline_table_dscp_help[] =
5026 "pipeline <pipeline_name> table <table_id> dscp <file_name>\n"
5027 "\n"
5028 " File <file_name>:\n"
5029 "   - exactly 64 lines\n"
5030 "   - line format: <tc_id> <tc_queue_id> <color>, with <color> as: g | y | r\n";
5031 
5032 static int
5033 load_dscp_table(struct rte_table_action_dscp_table *dscp_table,
5034 	const char *file_name,
5035 	uint32_t *line_number)
5036 {
5037 	FILE *f = NULL;
5038 	uint32_t dscp, l;
5039 
5040 	/* Check input arguments */
5041 	if ((dscp_table == NULL) ||
5042 		(file_name == NULL) ||
5043 		(line_number == NULL)) {
5044 		if (line_number)
5045 			*line_number = 0;
5046 		return -EINVAL;
5047 	}
5048 
5049 	/* Open input file */
5050 	f = fopen(file_name, "r");
5051 	if (f == NULL) {
5052 		*line_number = 0;
5053 		return -EINVAL;
5054 	}
5055 
5056 	/* Read file */
5057 	for (dscp = 0, l = 1; ; l++) {
5058 		char line[64];
5059 		char *tokens[3];
5060 		enum rte_meter_color color;
5061 		uint32_t tc_id, tc_queue_id, n_tokens = RTE_DIM(tokens);
5062 
5063 		if (fgets(line, sizeof(line), f) == NULL)
5064 			break;
5065 
5066 		if (is_comment(line))
5067 			continue;
5068 
5069 		if (parse_tokenize_string(line, tokens, &n_tokens)) {
5070 			*line_number = l;
5071 			fclose(f);
5072 			return -EINVAL;
5073 		}
5074 
5075 		if (n_tokens == 0)
5076 			continue;
5077 
5078 		if ((dscp >= RTE_DIM(dscp_table->entry)) ||
5079 			(n_tokens != RTE_DIM(tokens)) ||
5080 			parser_read_uint32(&tc_id, tokens[0]) ||
5081 			(tc_id >= RTE_TABLE_ACTION_TC_MAX) ||
5082 			parser_read_uint32(&tc_queue_id, tokens[1]) ||
5083 			(tc_queue_id >= RTE_TABLE_ACTION_TC_QUEUE_MAX) ||
5084 			(strlen(tokens[2]) != 1)) {
5085 			*line_number = l;
5086 			fclose(f);
5087 			return -EINVAL;
5088 		}
5089 
5090 		switch (tokens[2][0]) {
5091 		case 'g':
5092 		case 'G':
5093 			color = e_RTE_METER_GREEN;
5094 			break;
5095 
5096 		case 'y':
5097 		case 'Y':
5098 			color = e_RTE_METER_YELLOW;
5099 			break;
5100 
5101 		case 'r':
5102 		case 'R':
5103 			color = e_RTE_METER_RED;
5104 			break;
5105 
5106 		default:
5107 			*line_number = l;
5108 			fclose(f);
5109 			return -EINVAL;
5110 		}
5111 
5112 		dscp_table->entry[dscp].tc_id = tc_id;
5113 		dscp_table->entry[dscp].tc_queue_id = tc_queue_id;
5114 		dscp_table->entry[dscp].color = color;
5115 		dscp++;
5116 	}
5117 
5118 	/* Close file */
5119 	fclose(f);
5120 	return 0;
5121 }
5122 
5123 static void
5124 cmd_pipeline_table_dscp(char **tokens,
5125 	uint32_t n_tokens,
5126 	char *out,
5127 	size_t out_size)
5128 {
5129 	struct rte_table_action_dscp_table dscp_table;
5130 	char *pipeline_name, *file_name;
5131 	uint32_t table_id, line_number;
5132 	int status;
5133 
5134 	if (n_tokens != 6) {
5135 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5136 		return;
5137 	}
5138 
5139 	pipeline_name = tokens[1];
5140 
5141 	if (strcmp(tokens[2], "table") != 0) {
5142 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
5143 		return;
5144 	}
5145 
5146 	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
5147 		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
5148 		return;
5149 	}
5150 
5151 	if (strcmp(tokens[4], "dscp") != 0) {
5152 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "dscp");
5153 		return;
5154 	}
5155 
5156 	file_name = tokens[5];
5157 
5158 	status = load_dscp_table(&dscp_table, file_name, &line_number);
5159 	if (status) {
5160 		snprintf(out, out_size, MSG_FILE_ERR, file_name, line_number);
5161 		return;
5162 	}
5163 
5164 	status = pipeline_table_dscp_table_update(pipeline_name,
5165 		table_id,
5166 		UINT64_MAX,
5167 		&dscp_table);
5168 	if (status) {
5169 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
5170 		return;
5171 	}
5172 }
5173 
5174 
5175 static const char cmd_pipeline_table_rule_ttl_read_help[] =
5176 "pipeline <pipeline_name> table <table_id> rule read ttl [clear]\n";
5177 
5178 static void
5179 cmd_pipeline_table_rule_ttl_read(char **tokens,
5180 	uint32_t n_tokens __rte_unused,
5181 	char *out,
5182 	size_t out_size)
5183 {
5184 	snprintf(out, out_size, MSG_CMD_UNIMPLEM, tokens[0]);
5185 }
5186 
5187 
5188 static const char cmd_thread_pipeline_enable_help[] =
5189 "thread <thread_id> pipeline <pipeline_name> enable\n";
5190 
5191 static void
5192 cmd_thread_pipeline_enable(char **tokens,
5193 	uint32_t n_tokens,
5194 	char *out,
5195 	size_t out_size)
5196 {
5197 	char *pipeline_name;
5198 	uint32_t thread_id;
5199 	int status;
5200 
5201 	if (n_tokens != 5) {
5202 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5203 		return;
5204 	}
5205 
5206 	if (parser_read_uint32(&thread_id, tokens[1]) != 0) {
5207 		snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
5208 		return;
5209 	}
5210 
5211 	if (strcmp(tokens[2], "pipeline") != 0) {
5212 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
5213 		return;
5214 	}
5215 
5216 	pipeline_name = tokens[3];
5217 
5218 	if (strcmp(tokens[4], "enable") != 0) {
5219 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable");
5220 		return;
5221 	}
5222 
5223 	status = thread_pipeline_enable(thread_id, pipeline_name);
5224 	if (status) {
5225 		snprintf(out, out_size, MSG_CMD_FAIL, "thread pipeline enable");
5226 		return;
5227 	}
5228 }
5229 
5230 
5231 static const char cmd_thread_pipeline_disable_help[] =
5232 "thread <thread_id> pipeline <pipeline_name> disable\n";
5233 
5234 static void
5235 cmd_thread_pipeline_disable(char **tokens,
5236 	uint32_t n_tokens,
5237 	char *out,
5238 	size_t out_size)
5239 {
5240 	char *pipeline_name;
5241 	uint32_t thread_id;
5242 	int status;
5243 
5244 	if (n_tokens != 5) {
5245 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5246 		return;
5247 	}
5248 
5249 	if (parser_read_uint32(&thread_id, tokens[1]) != 0) {
5250 		snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
5251 		return;
5252 	}
5253 
5254 	if (strcmp(tokens[2], "pipeline") != 0) {
5255 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
5256 		return;
5257 	}
5258 
5259 	pipeline_name = tokens[3];
5260 
5261 	if (strcmp(tokens[4], "disable") != 0) {
5262 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable");
5263 		return;
5264 	}
5265 
5266 	status = thread_pipeline_disable(thread_id, pipeline_name);
5267 	if (status) {
5268 		snprintf(out, out_size, MSG_CMD_FAIL,
5269 			"thread pipeline disable");
5270 		return;
5271 	}
5272 }
5273 
5274 static void
5275 cmd_help(char **tokens, uint32_t n_tokens, char *out, size_t out_size)
5276 {
5277 	tokens++;
5278 	n_tokens--;
5279 
5280 	if (n_tokens == 0) {
5281 		snprintf(out, out_size,
5282 			"Type 'help <command>' for details on each command.\n\n"
5283 			"List of commands:\n"
5284 			"\tmempool\n"
5285 			"\tlink\n"
5286 			"\tswq\n"
5287 			"\ttmgr subport profile\n"
5288 			"\ttmgr pipe profile\n"
5289 			"\ttmgr\n"
5290 			"\ttmgr subport\n"
5291 			"\ttmgr subport pipe\n"
5292 			"\ttap\n"
5293 			"\tkni\n"
5294 			"\tport in action profile\n"
5295 			"\ttable action profile\n"
5296 			"\tpipeline\n"
5297 			"\tpipeline port in\n"
5298 			"\tpipeline port out\n"
5299 			"\tpipeline table\n"
5300 			"\tpipeline port in table\n"
5301 			"\tpipeline port in stats\n"
5302 			"\tpipeline port in enable\n"
5303 			"\tpipeline port in disable\n"
5304 			"\tpipeline port out stats\n"
5305 			"\tpipeline table stats\n"
5306 			"\tpipeline table rule add\n"
5307 			"\tpipeline table rule add default\n"
5308 			"\tpipeline table rule add bulk\n"
5309 			"\tpipeline table rule delete\n"
5310 			"\tpipeline table rule delete default\n"
5311 			"\tpipeline table rule stats read\n"
5312 			"\tpipeline table meter profile add\n"
5313 			"\tpipeline table meter profile delete\n"
5314 			"\tpipeline table rule meter read\n"
5315 			"\tpipeline table dscp\n"
5316 			"\tpipeline table rule ttl read\n"
5317 			"\tthread pipeline enable\n"
5318 			"\tthread pipeline disable\n\n");
5319 		return;
5320 	}
5321 
5322 	if (strcmp(tokens[0], "mempool") == 0) {
5323 		snprintf(out, out_size, "\n%s\n", cmd_mempool_help);
5324 		return;
5325 	}
5326 
5327 	if (strcmp(tokens[0], "link") == 0) {
5328 		snprintf(out, out_size, "\n%s\n", cmd_link_help);
5329 		return;
5330 	}
5331 
5332 	if (strcmp(tokens[0], "swq") == 0) {
5333 		snprintf(out, out_size, "\n%s\n", cmd_swq_help);
5334 		return;
5335 	}
5336 
5337 	if (strcmp(tokens[0], "tmgr") == 0) {
5338 		if (n_tokens == 1) {
5339 			snprintf(out, out_size, "\n%s\n", cmd_tmgr_help);
5340 			return;
5341 		}
5342 
5343 		if ((n_tokens == 2) &&
5344 			(strcmp(tokens[1], "subport")) == 0) {
5345 			snprintf(out, out_size, "\n%s\n", cmd_tmgr_subport_help);
5346 			return;
5347 		}
5348 
5349 		if ((n_tokens == 3) &&
5350 			(strcmp(tokens[1], "subport") == 0) &&
5351 			(strcmp(tokens[2], "profile") == 0)) {
5352 			snprintf(out, out_size, "\n%s\n",
5353 				cmd_tmgr_subport_profile_help);
5354 			return;
5355 		}
5356 
5357 		if ((n_tokens == 3) &&
5358 			(strcmp(tokens[1], "subport") == 0) &&
5359 			(strcmp(tokens[2], "pipe") == 0)) {
5360 			snprintf(out, out_size, "\n%s\n", cmd_tmgr_subport_pipe_help);
5361 			return;
5362 		}
5363 
5364 		if ((n_tokens == 3) &&
5365 			(strcmp(tokens[1], "pipe") == 0) &&
5366 			(strcmp(tokens[2], "profile") == 0)) {
5367 			snprintf(out, out_size, "\n%s\n", cmd_tmgr_pipe_profile_help);
5368 			return;
5369 		}
5370 	}
5371 
5372 	if (strcmp(tokens[0], "tap") == 0) {
5373 		snprintf(out, out_size, "\n%s\n", cmd_tap_help);
5374 		return;
5375 	}
5376 
5377 	if (strcmp(tokens[0], "kni") == 0) {
5378 		snprintf(out, out_size, "\n%s\n", cmd_kni_help);
5379 		return;
5380 	}
5381 
5382 	if (strcmp(tokens[0], "cryptodev") == 0) {
5383 		snprintf(out, out_size, "\n%s\n", cmd_cryptodev_help);
5384 		return;
5385 	}
5386 
5387 	if ((n_tokens == 4) &&
5388 		(strcmp(tokens[0], "port") == 0) &&
5389 		(strcmp(tokens[1], "in") == 0) &&
5390 		(strcmp(tokens[2], "action") == 0) &&
5391 		(strcmp(tokens[3], "profile") == 0)) {
5392 		snprintf(out, out_size, "\n%s\n", cmd_port_in_action_profile_help);
5393 		return;
5394 	}
5395 
5396 	if ((n_tokens == 3) &&
5397 		(strcmp(tokens[0], "table") == 0) &&
5398 		(strcmp(tokens[1], "action") == 0) &&
5399 		(strcmp(tokens[2], "profile") == 0)) {
5400 		snprintf(out, out_size, "\n%s\n", cmd_table_action_profile_help);
5401 		return;
5402 	}
5403 
5404 	if ((strcmp(tokens[0], "pipeline") == 0) && (n_tokens == 1)) {
5405 		snprintf(out, out_size, "\n%s\n", cmd_pipeline_help);
5406 		return;
5407 	}
5408 
5409 	if ((strcmp(tokens[0], "pipeline") == 0) &&
5410 		(strcmp(tokens[1], "port") == 0)) {
5411 		if ((n_tokens == 3) && (strcmp(tokens[2], "in")) == 0) {
5412 			snprintf(out, out_size, "\n%s\n", cmd_pipeline_port_in_help);
5413 			return;
5414 		}
5415 
5416 		if ((n_tokens == 3) && (strcmp(tokens[2], "out")) == 0) {
5417 			snprintf(out, out_size, "\n%s\n", cmd_pipeline_port_out_help);
5418 			return;
5419 		}
5420 
5421 		if ((n_tokens == 4) &&
5422 			(strcmp(tokens[2], "in") == 0) &&
5423 			(strcmp(tokens[3], "table") == 0)) {
5424 			snprintf(out, out_size, "\n%s\n",
5425 				cmd_pipeline_port_in_table_help);
5426 			return;
5427 		}
5428 
5429 		if ((n_tokens == 4) &&
5430 			(strcmp(tokens[2], "in") == 0) &&
5431 			(strcmp(tokens[3], "stats") == 0)) {
5432 			snprintf(out, out_size, "\n%s\n",
5433 				cmd_pipeline_port_in_stats_help);
5434 			return;
5435 		}
5436 
5437 		if ((n_tokens == 4) &&
5438 			(strcmp(tokens[2], "in") == 0) &&
5439 			(strcmp(tokens[3], "enable") == 0)) {
5440 			snprintf(out, out_size, "\n%s\n",
5441 				cmd_pipeline_port_in_enable_help);
5442 			return;
5443 		}
5444 
5445 		if ((n_tokens == 4) &&
5446 			(strcmp(tokens[2], "in") == 0) &&
5447 			(strcmp(tokens[3], "disable") == 0)) {
5448 			snprintf(out, out_size, "\n%s\n",
5449 				cmd_pipeline_port_in_disable_help);
5450 			return;
5451 		}
5452 
5453 		if ((n_tokens == 4) &&
5454 			(strcmp(tokens[2], "out") == 0) &&
5455 			(strcmp(tokens[3], "stats") == 0)) {
5456 			snprintf(out, out_size, "\n%s\n",
5457 				cmd_pipeline_port_out_stats_help);
5458 			return;
5459 		}
5460 	}
5461 
5462 	if ((strcmp(tokens[0], "pipeline") == 0) &&
5463 		(strcmp(tokens[1], "table") == 0)) {
5464 		if (n_tokens == 2) {
5465 			snprintf(out, out_size, "\n%s\n", cmd_pipeline_table_help);
5466 			return;
5467 		}
5468 
5469 		if ((n_tokens == 3) && strcmp(tokens[2], "stats") == 0) {
5470 			snprintf(out, out_size, "\n%s\n",
5471 				cmd_pipeline_table_stats_help);
5472 			return;
5473 		}
5474 
5475 		if ((n_tokens == 3) && strcmp(tokens[2], "dscp") == 0) {
5476 			snprintf(out, out_size, "\n%s\n",
5477 				cmd_pipeline_table_dscp_help);
5478 			return;
5479 		}
5480 
5481 		if ((n_tokens == 4) &&
5482 			(strcmp(tokens[2], "rule") == 0) &&
5483 			(strcmp(tokens[3], "add") == 0)) {
5484 			snprintf(out, out_size, "\n%s\n",
5485 				cmd_pipeline_table_rule_add_help);
5486 			return;
5487 		}
5488 
5489 		if ((n_tokens == 5) &&
5490 			(strcmp(tokens[2], "rule") == 0) &&
5491 			(strcmp(tokens[3], "add") == 0) &&
5492 			(strcmp(tokens[4], "default") == 0)) {
5493 			snprintf(out, out_size, "\n%s\n",
5494 				cmd_pipeline_table_rule_add_default_help);
5495 			return;
5496 		}
5497 
5498 		if ((n_tokens == 5) &&
5499 			(strcmp(tokens[2], "rule") == 0) &&
5500 			(strcmp(tokens[3], "add") == 0) &&
5501 			(strcmp(tokens[4], "bulk") == 0)) {
5502 			snprintf(out, out_size, "\n%s\n",
5503 				cmd_pipeline_table_rule_add_bulk_help);
5504 			return;
5505 		}
5506 
5507 		if ((n_tokens == 4) &&
5508 			(strcmp(tokens[2], "rule") == 0) &&
5509 			(strcmp(tokens[3], "delete") == 0)) {
5510 			snprintf(out, out_size, "\n%s\n",
5511 				cmd_pipeline_table_rule_delete_help);
5512 			return;
5513 		}
5514 
5515 		if ((n_tokens == 5) &&
5516 			(strcmp(tokens[2], "rule") == 0) &&
5517 			(strcmp(tokens[3], "delete") == 0) &&
5518 			(strcmp(tokens[4], "default") == 0)) {
5519 			snprintf(out, out_size, "\n%s\n",
5520 				cmd_pipeline_table_rule_delete_default_help);
5521 			return;
5522 		}
5523 
5524 		if ((n_tokens == 5) &&
5525 			(strcmp(tokens[2], "rule") == 0) &&
5526 			(strcmp(tokens[3], "stats") == 0) &&
5527 			(strcmp(tokens[4], "read") == 0)) {
5528 			snprintf(out, out_size, "\n%s\n",
5529 				cmd_pipeline_table_rule_stats_read_help);
5530 			return;
5531 		}
5532 
5533 		if ((n_tokens == 5) &&
5534 			(strcmp(tokens[2], "meter") == 0) &&
5535 			(strcmp(tokens[3], "profile") == 0) &&
5536 			(strcmp(tokens[4], "add") == 0)) {
5537 			snprintf(out, out_size, "\n%s\n",
5538 				cmd_pipeline_table_meter_profile_add_help);
5539 			return;
5540 		}
5541 
5542 		if ((n_tokens == 5) &&
5543 			(strcmp(tokens[2], "meter") == 0) &&
5544 			(strcmp(tokens[3], "profile") == 0) &&
5545 			(strcmp(tokens[4], "delete") == 0)) {
5546 			snprintf(out, out_size, "\n%s\n",
5547 				cmd_pipeline_table_meter_profile_delete_help);
5548 			return;
5549 		}
5550 
5551 		if ((n_tokens == 5) &&
5552 			(strcmp(tokens[2], "rule") == 0) &&
5553 			(strcmp(tokens[3], "meter") == 0) &&
5554 			(strcmp(tokens[4], "read") == 0)) {
5555 			snprintf(out, out_size, "\n%s\n",
5556 				cmd_pipeline_table_rule_meter_read_help);
5557 			return;
5558 		}
5559 
5560 		if ((n_tokens == 5) &&
5561 			(strcmp(tokens[2], "rule") == 0) &&
5562 			(strcmp(tokens[3], "ttl") == 0) &&
5563 			(strcmp(tokens[4], "read") == 0)) {
5564 			snprintf(out, out_size, "\n%s\n",
5565 				cmd_pipeline_table_rule_ttl_read_help);
5566 			return;
5567 		}
5568 	}
5569 
5570 	if ((n_tokens == 3) &&
5571 		(strcmp(tokens[0], "thread") == 0) &&
5572 		(strcmp(tokens[1], "pipeline") == 0)) {
5573 		if (strcmp(tokens[2], "enable") == 0) {
5574 			snprintf(out, out_size, "\n%s\n",
5575 				cmd_thread_pipeline_enable_help);
5576 			return;
5577 		}
5578 
5579 		if (strcmp(tokens[2], "disable") == 0) {
5580 			snprintf(out, out_size, "\n%s\n",
5581 				cmd_thread_pipeline_disable_help);
5582 			return;
5583 		}
5584 	}
5585 
5586 	snprintf(out, out_size, "Invalid command\n");
5587 }
5588 
5589 void
5590 cli_process(char *in, char *out, size_t out_size)
5591 {
5592 	char *tokens[CMD_MAX_TOKENS];
5593 	uint32_t n_tokens = RTE_DIM(tokens);
5594 	int status;
5595 
5596 	if (is_comment(in))
5597 		return;
5598 
5599 	status = parse_tokenize_string(in, tokens, &n_tokens);
5600 	if (status) {
5601 		snprintf(out, out_size, MSG_ARG_TOO_MANY, "");
5602 		return;
5603 	}
5604 
5605 	if (n_tokens == 0)
5606 		return;
5607 
5608 	if (strcmp(tokens[0], "help") == 0) {
5609 		cmd_help(tokens, n_tokens, out, out_size);
5610 		return;
5611 	}
5612 
5613 	if (strcmp(tokens[0], "mempool") == 0) {
5614 		cmd_mempool(tokens, n_tokens, out, out_size);
5615 		return;
5616 	}
5617 
5618 	if (strcmp(tokens[0], "link") == 0) {
5619 		if (strcmp(tokens[1], "show") == 0) {
5620 			cmd_link_show(tokens, n_tokens, out, out_size);
5621 			return;
5622 		}
5623 
5624 		cmd_link(tokens, n_tokens, out, out_size);
5625 		return;
5626 	}
5627 
5628 	if (strcmp(tokens[0], "swq") == 0) {
5629 		cmd_swq(tokens, n_tokens, out, out_size);
5630 		return;
5631 	}
5632 
5633 	if (strcmp(tokens[0], "tmgr") == 0) {
5634 		if ((n_tokens >= 3) &&
5635 			(strcmp(tokens[1], "subport") == 0) &&
5636 			(strcmp(tokens[2], "profile") == 0)) {
5637 			cmd_tmgr_subport_profile(tokens, n_tokens,
5638 				out, out_size);
5639 			return;
5640 		}
5641 
5642 		if ((n_tokens >= 3) &&
5643 			(strcmp(tokens[1], "pipe") == 0) &&
5644 			(strcmp(tokens[2], "profile") == 0)) {
5645 			cmd_tmgr_pipe_profile(tokens, n_tokens, out, out_size);
5646 			return;
5647 		}
5648 
5649 		if ((n_tokens >= 5) &&
5650 			(strcmp(tokens[2], "subport") == 0) &&
5651 			(strcmp(tokens[4], "profile") == 0)) {
5652 			cmd_tmgr_subport(tokens, n_tokens, out, out_size);
5653 			return;
5654 		}
5655 
5656 		if ((n_tokens >= 5) &&
5657 			(strcmp(tokens[2], "subport") == 0) &&
5658 			(strcmp(tokens[4], "pipe") == 0)) {
5659 			cmd_tmgr_subport_pipe(tokens, n_tokens, out, out_size);
5660 			return;
5661 		}
5662 
5663 		cmd_tmgr(tokens, n_tokens, out, out_size);
5664 		return;
5665 	}
5666 
5667 	if (strcmp(tokens[0], "tap") == 0) {
5668 		cmd_tap(tokens, n_tokens, out, out_size);
5669 		return;
5670 	}
5671 
5672 	if (strcmp(tokens[0], "kni") == 0) {
5673 		cmd_kni(tokens, n_tokens, out, out_size);
5674 		return;
5675 	}
5676 
5677 	if (strcmp(tokens[0], "cryptodev") == 0) {
5678 		cmd_cryptodev(tokens, n_tokens, out, out_size);
5679 		return;
5680 	}
5681 
5682 	if (strcmp(tokens[0], "port") == 0) {
5683 		cmd_port_in_action_profile(tokens, n_tokens, out, out_size);
5684 		return;
5685 	}
5686 
5687 	if (strcmp(tokens[0], "table") == 0) {
5688 		cmd_table_action_profile(tokens, n_tokens, out, out_size);
5689 		return;
5690 	}
5691 
5692 	if (strcmp(tokens[0], "pipeline") == 0) {
5693 		if ((n_tokens >= 3) &&
5694 			(strcmp(tokens[2], "period") == 0)) {
5695 			cmd_pipeline(tokens, n_tokens, out, out_size);
5696 			return;
5697 		}
5698 
5699 		if ((n_tokens >= 5) &&
5700 			(strcmp(tokens[2], "port") == 0) &&
5701 			(strcmp(tokens[3], "in") == 0) &&
5702 			(strcmp(tokens[4], "bsz") == 0)) {
5703 			cmd_pipeline_port_in(tokens, n_tokens, out, out_size);
5704 			return;
5705 		}
5706 
5707 		if ((n_tokens >= 5) &&
5708 			(strcmp(tokens[2], "port") == 0) &&
5709 			(strcmp(tokens[3], "out") == 0) &&
5710 			(strcmp(tokens[4], "bsz") == 0)) {
5711 			cmd_pipeline_port_out(tokens, n_tokens, out, out_size);
5712 			return;
5713 		}
5714 
5715 		if ((n_tokens >= 4) &&
5716 			(strcmp(tokens[2], "table") == 0) &&
5717 			(strcmp(tokens[3], "match") == 0)) {
5718 			cmd_pipeline_table(tokens, n_tokens, out, out_size);
5719 			return;
5720 		}
5721 
5722 		if ((n_tokens >= 6) &&
5723 			(strcmp(tokens[2], "port") == 0) &&
5724 			(strcmp(tokens[3], "in") == 0) &&
5725 			(strcmp(tokens[5], "table") == 0)) {
5726 			cmd_pipeline_port_in_table(tokens, n_tokens,
5727 				out, out_size);
5728 			return;
5729 		}
5730 
5731 		if ((n_tokens >= 6) &&
5732 			(strcmp(tokens[2], "port") == 0) &&
5733 			(strcmp(tokens[3], "in") == 0) &&
5734 			(strcmp(tokens[5], "stats") == 0)) {
5735 			cmd_pipeline_port_in_stats(tokens, n_tokens,
5736 				out, out_size);
5737 			return;
5738 		}
5739 
5740 		if ((n_tokens >= 6) &&
5741 			(strcmp(tokens[2], "port") == 0) &&
5742 			(strcmp(tokens[3], "in") == 0) &&
5743 			(strcmp(tokens[5], "enable") == 0)) {
5744 			cmd_pipeline_port_in_enable(tokens, n_tokens,
5745 				out, out_size);
5746 			return;
5747 		}
5748 
5749 		if ((n_tokens >= 6) &&
5750 			(strcmp(tokens[2], "port") == 0) &&
5751 			(strcmp(tokens[3], "in") == 0) &&
5752 			(strcmp(tokens[5], "disable") == 0)) {
5753 			cmd_pipeline_port_in_disable(tokens, n_tokens,
5754 				out, out_size);
5755 			return;
5756 		}
5757 
5758 		if ((n_tokens >= 6) &&
5759 			(strcmp(tokens[2], "port") == 0) &&
5760 			(strcmp(tokens[3], "out") == 0) &&
5761 			(strcmp(tokens[5], "stats") == 0)) {
5762 			cmd_pipeline_port_out_stats(tokens, n_tokens,
5763 				out, out_size);
5764 			return;
5765 		}
5766 
5767 		if ((n_tokens >= 5) &&
5768 			(strcmp(tokens[2], "table") == 0) &&
5769 			(strcmp(tokens[4], "stats") == 0)) {
5770 			cmd_pipeline_table_stats(tokens, n_tokens,
5771 				out, out_size);
5772 			return;
5773 		}
5774 
5775 		if ((n_tokens >= 7) &&
5776 			(strcmp(tokens[2], "table") == 0) &&
5777 			(strcmp(tokens[4], "rule") == 0) &&
5778 			(strcmp(tokens[5], "add") == 0) &&
5779 			(strcmp(tokens[6], "match") == 0)) {
5780 			if ((n_tokens >= 8) &&
5781 				(strcmp(tokens[7], "default") == 0)) {
5782 				cmd_pipeline_table_rule_add_default(tokens,
5783 					n_tokens, out, out_size);
5784 				return;
5785 			}
5786 
5787 			cmd_pipeline_table_rule_add(tokens, n_tokens,
5788 				out, out_size);
5789 			return;
5790 		}
5791 
5792 		if ((n_tokens >= 7) &&
5793 			(strcmp(tokens[2], "table") == 0) &&
5794 			(strcmp(tokens[4], "rule") == 0) &&
5795 			(strcmp(tokens[5], "add") == 0) &&
5796 			(strcmp(tokens[6], "bulk") == 0)) {
5797 			cmd_pipeline_table_rule_add_bulk(tokens,
5798 				n_tokens, out, out_size);
5799 			return;
5800 		}
5801 
5802 		if ((n_tokens >= 7) &&
5803 			(strcmp(tokens[2], "table") == 0) &&
5804 			(strcmp(tokens[4], "rule") == 0) &&
5805 			(strcmp(tokens[5], "delete") == 0) &&
5806 			(strcmp(tokens[6], "match") == 0)) {
5807 			if ((n_tokens >= 8) &&
5808 				(strcmp(tokens[7], "default") == 0)) {
5809 				cmd_pipeline_table_rule_delete_default(tokens,
5810 					n_tokens, out, out_size);
5811 				return;
5812 				}
5813 
5814 			cmd_pipeline_table_rule_delete(tokens, n_tokens,
5815 				out, out_size);
5816 			return;
5817 		}
5818 
5819 		if ((n_tokens >= 7) &&
5820 			(strcmp(tokens[2], "table") == 0) &&
5821 			(strcmp(tokens[4], "rule") == 0) &&
5822 			(strcmp(tokens[5], "read") == 0) &&
5823 			(strcmp(tokens[6], "stats") == 0)) {
5824 			cmd_pipeline_table_rule_stats_read(tokens, n_tokens,
5825 				out, out_size);
5826 			return;
5827 		}
5828 
5829 		if ((n_tokens >= 8) &&
5830 			(strcmp(tokens[2], "table") == 0) &&
5831 			(strcmp(tokens[4], "meter") == 0) &&
5832 			(strcmp(tokens[5], "profile") == 0) &&
5833 			(strcmp(tokens[7], "add") == 0)) {
5834 			cmd_pipeline_table_meter_profile_add(tokens, n_tokens,
5835 				out, out_size);
5836 			return;
5837 		}
5838 
5839 		if ((n_tokens >= 8) &&
5840 			(strcmp(tokens[2], "table") == 0) &&
5841 			(strcmp(tokens[4], "meter") == 0) &&
5842 			(strcmp(tokens[5], "profile") == 0) &&
5843 			(strcmp(tokens[7], "delete") == 0)) {
5844 			cmd_pipeline_table_meter_profile_delete(tokens,
5845 				n_tokens, out, out_size);
5846 			return;
5847 		}
5848 
5849 		if ((n_tokens >= 7) &&
5850 			(strcmp(tokens[2], "table") == 0) &&
5851 			(strcmp(tokens[4], "rule") == 0) &&
5852 			(strcmp(tokens[5], "read") == 0) &&
5853 			(strcmp(tokens[6], "meter") == 0)) {
5854 			cmd_pipeline_table_rule_meter_read(tokens, n_tokens,
5855 				out, out_size);
5856 			return;
5857 		}
5858 
5859 		if ((n_tokens >= 5) &&
5860 			(strcmp(tokens[2], "table") == 0) &&
5861 			(strcmp(tokens[4], "dscp") == 0)) {
5862 			cmd_pipeline_table_dscp(tokens, n_tokens,
5863 				out, out_size);
5864 			return;
5865 		}
5866 
5867 		if ((n_tokens >= 7) &&
5868 			(strcmp(tokens[2], "table") == 0) &&
5869 			(strcmp(tokens[4], "rule") == 0) &&
5870 			(strcmp(tokens[5], "read") == 0) &&
5871 			(strcmp(tokens[6], "ttl") == 0)) {
5872 			cmd_pipeline_table_rule_ttl_read(tokens, n_tokens,
5873 				out, out_size);
5874 			return;
5875 		}
5876 	}
5877 
5878 	if (strcmp(tokens[0], "thread") == 0) {
5879 		if ((n_tokens >= 5) &&
5880 			(strcmp(tokens[4], "enable") == 0)) {
5881 			cmd_thread_pipeline_enable(tokens, n_tokens,
5882 				out, out_size);
5883 			return;
5884 		}
5885 
5886 		if ((n_tokens >= 5) &&
5887 			(strcmp(tokens[4], "disable") == 0)) {
5888 			cmd_thread_pipeline_disable(tokens, n_tokens,
5889 				out, out_size);
5890 			return;
5891 		}
5892 	}
5893 
5894 	snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
5895 }
5896 
5897 int
5898 cli_script_process(const char *file_name,
5899 	size_t msg_in_len_max,
5900 	size_t msg_out_len_max)
5901 {
5902 	char *msg_in = NULL, *msg_out = NULL;
5903 	FILE *f = NULL;
5904 
5905 	/* Check input arguments */
5906 	if ((file_name == NULL) ||
5907 		(strlen(file_name) == 0) ||
5908 		(msg_in_len_max == 0) ||
5909 		(msg_out_len_max == 0))
5910 		return -EINVAL;
5911 
5912 	msg_in = malloc(msg_in_len_max + 1);
5913 	msg_out = malloc(msg_out_len_max + 1);
5914 	if ((msg_in == NULL) ||
5915 		(msg_out == NULL)) {
5916 		free(msg_out);
5917 		free(msg_in);
5918 		return -ENOMEM;
5919 	}
5920 
5921 	/* Open input file */
5922 	f = fopen(file_name, "r");
5923 	if (f == NULL) {
5924 		free(msg_out);
5925 		free(msg_in);
5926 		return -EIO;
5927 	}
5928 
5929 	/* Read file */
5930 	for ( ; ; ) {
5931 		if (fgets(msg_in, msg_in_len_max + 1, f) == NULL)
5932 			break;
5933 
5934 		printf("%s", msg_in);
5935 		msg_out[0] = 0;
5936 
5937 		cli_process(msg_in,
5938 			msg_out,
5939 			msg_out_len_max);
5940 
5941 		if (strlen(msg_out))
5942 			printf("%s", msg_out);
5943 	}
5944 
5945 	/* Close file */
5946 	fclose(f);
5947 	free(msg_out);
5948 	free(msg_in);
5949 	return 0;
5950 }
5951 
5952 static int
5953 cli_rule_file_process(const char *file_name,
5954 	size_t line_len_max,
5955 	struct table_rule_match *m,
5956 	struct table_rule_action *a,
5957 	uint32_t *n_rules,
5958 	uint32_t *line_number,
5959 	char *out,
5960 	size_t out_size)
5961 {
5962 	FILE *f = NULL;
5963 	char *line = NULL;
5964 	uint32_t rule_id, line_id;
5965 	int status = 0;
5966 
5967 	/* Check input arguments */
5968 	if ((file_name == NULL) ||
5969 		(strlen(file_name) == 0) ||
5970 		(line_len_max == 0)) {
5971 		*line_number = 0;
5972 		return -EINVAL;
5973 	}
5974 
5975 	/* Memory allocation */
5976 	line = malloc(line_len_max + 1);
5977 	if (line == NULL) {
5978 		*line_number = 0;
5979 		return -ENOMEM;
5980 	}
5981 
5982 	/* Open file */
5983 	f = fopen(file_name, "r");
5984 	if (f == NULL) {
5985 		*line_number = 0;
5986 		free(line);
5987 		return -EIO;
5988 	}
5989 
5990 	/* Read file */
5991 	for (line_id = 1, rule_id = 0; rule_id < *n_rules; line_id++) {
5992 		char *tokens[CMD_MAX_TOKENS];
5993 		uint32_t n_tokens, n_tokens_parsed, t0;
5994 
5995 		/* Read next line from file. */
5996 		if (fgets(line, line_len_max + 1, f) == NULL)
5997 			break;
5998 
5999 		/* Comment. */
6000 		if (is_comment(line))
6001 			continue;
6002 
6003 		/* Parse line. */
6004 		n_tokens = RTE_DIM(tokens);
6005 		status = parse_tokenize_string(line, tokens, &n_tokens);
6006 		if (status) {
6007 			status = -EINVAL;
6008 			break;
6009 		}
6010 
6011 		/* Empty line. */
6012 		if (n_tokens == 0)
6013 			continue;
6014 		t0 = 0;
6015 
6016 		/* Rule match. */
6017 		n_tokens_parsed = parse_match(tokens + t0,
6018 			n_tokens - t0,
6019 			out,
6020 			out_size,
6021 			&m[rule_id]);
6022 		if (n_tokens_parsed == 0) {
6023 			status = -EINVAL;
6024 			break;
6025 		}
6026 		t0 += n_tokens_parsed;
6027 
6028 		/* Rule action. */
6029 		n_tokens_parsed = parse_table_action(tokens + t0,
6030 			n_tokens - t0,
6031 			out,
6032 			out_size,
6033 			&a[rule_id]);
6034 		if (n_tokens_parsed == 0) {
6035 			status = -EINVAL;
6036 			break;
6037 		}
6038 		t0 += n_tokens_parsed;
6039 
6040 		/* Line completed. */
6041 		if (t0 < n_tokens) {
6042 			status = -EINVAL;
6043 			break;
6044 		}
6045 
6046 		/* Increment rule count */
6047 		rule_id++;
6048 	}
6049 
6050 	/* Close file */
6051 	fclose(f);
6052 
6053 	/* Memory free */
6054 	free(line);
6055 
6056 	*n_rules = rule_id;
6057 	*line_number = line_id;
6058 	return status;
6059 }
6060