xref: /dpdk/examples/ip_pipeline/cli.c (revision 2fbdf8348a0ea5af1ae9b982e6fcdc2c8cf9100f)
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 	uint32_t table_id, t0, n_tokens_parsed;
4325 	int status;
4326 
4327 	if (n_tokens < 8) {
4328 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4329 		return;
4330 	}
4331 
4332 	pipeline_name = tokens[1];
4333 
4334 	if (strcmp(tokens[2], "table") != 0) {
4335 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
4336 		return;
4337 	}
4338 
4339 	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
4340 		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
4341 		return;
4342 	}
4343 
4344 	if (strcmp(tokens[4], "rule") != 0) {
4345 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
4346 		return;
4347 	}
4348 
4349 	if (strcmp(tokens[5], "add") != 0) {
4350 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
4351 		return;
4352 	}
4353 
4354 	t0 = 6;
4355 
4356 	/* match */
4357 	n_tokens_parsed = parse_match(tokens + t0,
4358 		n_tokens - t0,
4359 		out,
4360 		out_size,
4361 		&m);
4362 	if (n_tokens_parsed == 0)
4363 		return;
4364 	t0 += n_tokens_parsed;
4365 
4366 	/* action */
4367 	n_tokens_parsed = parse_table_action(tokens + t0,
4368 		n_tokens - t0,
4369 		out,
4370 		out_size,
4371 		&a);
4372 	if (n_tokens_parsed == 0)
4373 		return;
4374 	t0 += n_tokens_parsed;
4375 
4376 	if (t0 != n_tokens) {
4377 		snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
4378 		return;
4379 	}
4380 
4381 	status = pipeline_table_rule_add(pipeline_name, table_id, &m, &a);
4382 	if (status) {
4383 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
4384 		return;
4385 	}
4386 
4387 	if (a.action_mask & 1 << RTE_TABLE_ACTION_SYM_CRYPTO)
4388 		parse_free_sym_crypto_param_data(&a.sym_crypto);
4389 }
4390 
4391 
4392 static const char cmd_pipeline_table_rule_add_default_help[] =
4393 "pipeline <pipeline_name> table <table_id> rule add\n"
4394 "     match\n"
4395 "        default\n"
4396 "     action\n"
4397 "        fwd\n"
4398 "           drop\n"
4399 "           | port <port_id>\n"
4400 "           | meta\n"
4401 "           | table <table_id>\n";
4402 
4403 static void
4404 cmd_pipeline_table_rule_add_default(char **tokens,
4405 	uint32_t n_tokens,
4406 	char *out,
4407 	size_t out_size)
4408 {
4409 	struct table_rule_action action;
4410 	char *pipeline_name;
4411 	uint32_t table_id;
4412 	int status;
4413 
4414 	if ((n_tokens != 11) && (n_tokens != 12)) {
4415 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4416 		return;
4417 	}
4418 
4419 	pipeline_name = tokens[1];
4420 
4421 	if (strcmp(tokens[2], "table") != 0) {
4422 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
4423 		return;
4424 	}
4425 
4426 	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
4427 		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
4428 		return;
4429 	}
4430 
4431 	if (strcmp(tokens[4], "rule") != 0) {
4432 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
4433 		return;
4434 	}
4435 
4436 	if (strcmp(tokens[5], "add") != 0) {
4437 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
4438 		return;
4439 	}
4440 
4441 	if (strcmp(tokens[6], "match") != 0) {
4442 		snprintf(out, out_size, MSG_ARG_INVALID, "match");
4443 		return;
4444 	}
4445 
4446 	if (strcmp(tokens[7], "default") != 0) {
4447 		snprintf(out, out_size, MSG_ARG_INVALID, "default");
4448 		return;
4449 	}
4450 
4451 	if (strcmp(tokens[8], "action") != 0) {
4452 		snprintf(out, out_size, MSG_ARG_INVALID, "action");
4453 		return;
4454 	}
4455 
4456 	if (strcmp(tokens[9], "fwd") != 0) {
4457 		snprintf(out, out_size, MSG_ARG_INVALID, "fwd");
4458 		return;
4459 	}
4460 
4461 	action.action_mask = 1 << RTE_TABLE_ACTION_FWD;
4462 
4463 	if (strcmp(tokens[10], "drop") == 0) {
4464 		if (n_tokens != 11) {
4465 			snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4466 			return;
4467 		}
4468 
4469 		action.fwd.action = RTE_PIPELINE_ACTION_DROP;
4470 	} else if (strcmp(tokens[10], "port") == 0) {
4471 		uint32_t id;
4472 
4473 		if (n_tokens != 12) {
4474 			snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4475 			return;
4476 		}
4477 
4478 		if (parser_read_uint32(&id, tokens[11]) != 0) {
4479 			snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
4480 			return;
4481 		}
4482 
4483 		action.fwd.action = RTE_PIPELINE_ACTION_PORT;
4484 		action.fwd.id = id;
4485 	} else if (strcmp(tokens[10], "meta") == 0) {
4486 		if (n_tokens != 11) {
4487 			snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4488 			return;
4489 		}
4490 
4491 		action.fwd.action = RTE_PIPELINE_ACTION_PORT_META;
4492 	} else if (strcmp(tokens[10], "table") == 0) {
4493 		uint32_t id;
4494 
4495 		if (n_tokens != 12) {
4496 			snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4497 			return;
4498 		}
4499 
4500 		if (parser_read_uint32(&id, tokens[11]) != 0) {
4501 			snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
4502 			return;
4503 		}
4504 
4505 		action.fwd.action = RTE_PIPELINE_ACTION_TABLE;
4506 		action.fwd.id = id;
4507 	} else {
4508 		snprintf(out, out_size, MSG_ARG_INVALID,
4509 			"drop or port or meta or table");
4510 		return;
4511 	}
4512 
4513 	status = pipeline_table_rule_add_default(pipeline_name,
4514 		table_id,
4515 		&action);
4516 	if (status) {
4517 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
4518 		return;
4519 	}
4520 }
4521 
4522 
4523 static const char cmd_pipeline_table_rule_add_bulk_help[] =
4524 "pipeline <pipeline_name> table <table_id> rule add bulk <file_name>\n"
4525 "\n"
4526 "  File <file_name>:\n"
4527 "  - line format: match <match> action <action>\n";
4528 
4529 static int
4530 cli_rule_file_process(const char *file_name,
4531 	size_t line_len_max,
4532 	struct table_rule_list **rule_list,
4533 	uint32_t *n_rules,
4534 	uint32_t *line_number,
4535 	char *out,
4536 	size_t out_size);
4537 
4538 static void
4539 cmd_pipeline_table_rule_add_bulk(char **tokens,
4540 	uint32_t n_tokens,
4541 	char *out,
4542 	size_t out_size)
4543 {
4544 	struct table_rule_list *list = NULL;
4545 	char *pipeline_name, *file_name;
4546 	uint32_t table_id, n_rules, n_rules_added, n_rules_not_added, line_number;
4547 	int status;
4548 
4549 	if (n_tokens != 8) {
4550 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4551 		return;
4552 	}
4553 
4554 	pipeline_name = tokens[1];
4555 
4556 	if (strcmp(tokens[2], "table") != 0) {
4557 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
4558 		return;
4559 	}
4560 
4561 	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
4562 		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
4563 		return;
4564 	}
4565 
4566 	if (strcmp(tokens[4], "rule") != 0) {
4567 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
4568 		return;
4569 	}
4570 
4571 	if (strcmp(tokens[5], "add") != 0) {
4572 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
4573 		return;
4574 	}
4575 
4576 	if (strcmp(tokens[6], "bulk") != 0) {
4577 		snprintf(out, out_size, MSG_ARG_INVALID, "bulk");
4578 		return;
4579 	}
4580 
4581 	file_name = tokens[7];
4582 
4583 	/* Load rules from file. */
4584 	status = cli_rule_file_process(file_name,
4585 		1024,
4586 		&list,
4587 		&n_rules,
4588 		&line_number,
4589 		out,
4590 		out_size);
4591 	if (status) {
4592 		snprintf(out, out_size, MSG_FILE_ERR, file_name, line_number);
4593 		return;
4594 	}
4595 
4596 	/* Rule bulk add */
4597 	status = pipeline_table_rule_add_bulk(pipeline_name,
4598 		table_id,
4599 		list,
4600 		&n_rules_added,
4601 		&n_rules_not_added);
4602 	if (status) {
4603 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
4604 		return;
4605 	}
4606 
4607 	snprintf(out, out_size, "Added %u rules out of %u.\n",
4608 		n_rules_added,
4609 		n_rules);
4610 }
4611 
4612 
4613 static const char cmd_pipeline_table_rule_delete_help[] =
4614 "pipeline <pipeline_name> table <table_id> rule delete\n"
4615 "     match <match>\n";
4616 
4617 static void
4618 cmd_pipeline_table_rule_delete(char **tokens,
4619 	uint32_t n_tokens,
4620 	char *out,
4621 	size_t out_size)
4622 {
4623 	struct table_rule_match m;
4624 	char *pipeline_name;
4625 	uint32_t table_id, n_tokens_parsed, t0;
4626 	int status;
4627 
4628 	if (n_tokens < 8) {
4629 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4630 		return;
4631 	}
4632 
4633 	pipeline_name = tokens[1];
4634 
4635 	if (strcmp(tokens[2], "table") != 0) {
4636 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
4637 		return;
4638 	}
4639 
4640 	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
4641 		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
4642 		return;
4643 	}
4644 
4645 	if (strcmp(tokens[4], "rule") != 0) {
4646 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
4647 		return;
4648 	}
4649 
4650 	if (strcmp(tokens[5], "delete") != 0) {
4651 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete");
4652 		return;
4653 	}
4654 
4655 	t0 = 6;
4656 
4657 	/* match */
4658 	n_tokens_parsed = parse_match(tokens + t0,
4659 		n_tokens - t0,
4660 		out,
4661 		out_size,
4662 		&m);
4663 	if (n_tokens_parsed == 0)
4664 		return;
4665 	t0 += n_tokens_parsed;
4666 
4667 	if (n_tokens != t0) {
4668 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4669 		return;
4670 	}
4671 
4672 	status = pipeline_table_rule_delete(pipeline_name,
4673 		table_id,
4674 		&m);
4675 	if (status) {
4676 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
4677 		return;
4678 	}
4679 }
4680 
4681 
4682 static const char cmd_pipeline_table_rule_delete_default_help[] =
4683 "pipeline <pipeline_name> table <table_id> rule delete\n"
4684 "     match\n"
4685 "        default\n";
4686 
4687 static void
4688 cmd_pipeline_table_rule_delete_default(char **tokens,
4689 	uint32_t n_tokens,
4690 	char *out,
4691 	size_t out_size)
4692 {
4693 	char *pipeline_name;
4694 	uint32_t table_id;
4695 	int status;
4696 
4697 	if (n_tokens != 8) {
4698 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4699 		return;
4700 	}
4701 
4702 	pipeline_name = tokens[1];
4703 
4704 	if (strcmp(tokens[2], "table") != 0) {
4705 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
4706 		return;
4707 	}
4708 
4709 	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
4710 		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
4711 		return;
4712 	}
4713 
4714 	if (strcmp(tokens[4], "rule") != 0) {
4715 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
4716 		return;
4717 	}
4718 
4719 	if (strcmp(tokens[5], "delete") != 0) {
4720 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete");
4721 		return;
4722 	}
4723 
4724 	if (strcmp(tokens[6], "match") != 0) {
4725 		snprintf(out, out_size, MSG_ARG_INVALID, "match");
4726 		return;
4727 	}
4728 
4729 	if (strcmp(tokens[7], "default") != 0) {
4730 		snprintf(out, out_size, MSG_ARG_INVALID, "default");
4731 		return;
4732 	}
4733 
4734 	status = pipeline_table_rule_delete_default(pipeline_name,
4735 		table_id);
4736 	if (status) {
4737 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
4738 		return;
4739 	}
4740 }
4741 
4742 static void
4743 ether_addr_show(FILE *f, struct ether_addr *addr)
4744 {
4745 	fprintf(f, "%02x:%02x:%02x:%02x:%02x:%02x",
4746 		(uint32_t)addr->addr_bytes[0], (uint32_t)addr->addr_bytes[1],
4747 		(uint32_t)addr->addr_bytes[2], (uint32_t)addr->addr_bytes[3],
4748 		(uint32_t)addr->addr_bytes[4], (uint32_t)addr->addr_bytes[5]);
4749 }
4750 
4751 static void
4752 ipv4_addr_show(FILE *f, uint32_t addr)
4753 {
4754 	fprintf(f, "%u.%u.%u.%u",
4755 		addr >> 24,
4756 		(addr >> 16) & 0xFF,
4757 		(addr >> 8) & 0xFF,
4758 		addr & 0xFF);
4759 }
4760 
4761 static void
4762 ipv6_addr_show(FILE *f, uint8_t *addr)
4763 {
4764 	fprintf(f, "%02x%02x:%02x%02x:%02x%02x:%02x%02x:"
4765 		"%02x%02x:%02x%02x:%02x%02x:%02x%02x:",
4766 		(uint32_t)addr[0], (uint32_t)addr[1],
4767 		(uint32_t)addr[2], (uint32_t)addr[3],
4768 		(uint32_t)addr[4], (uint32_t)addr[5],
4769 		(uint32_t)addr[6], (uint32_t)addr[7],
4770 		(uint32_t)addr[8], (uint32_t)addr[9],
4771 		(uint32_t)addr[10], (uint32_t)addr[11],
4772 		(uint32_t)addr[12], (uint32_t)addr[13],
4773 		(uint32_t)addr[14], (uint32_t)addr[15]);
4774 }
4775 
4776 static const char *
4777 policer_action_string(enum rte_table_action_policer action) {
4778 	switch (action) {
4779 		case RTE_TABLE_ACTION_POLICER_COLOR_GREEN: return "G";
4780 		case RTE_TABLE_ACTION_POLICER_COLOR_YELLOW: return "Y";
4781 		case RTE_TABLE_ACTION_POLICER_COLOR_RED: return "R";
4782 		case RTE_TABLE_ACTION_POLICER_DROP: return "D";
4783 		default: return "?";
4784 	}
4785 }
4786 
4787 static int
4788 table_rule_show(const char *pipeline_name,
4789 	uint32_t table_id,
4790 	const char *file_name)
4791 {
4792 	struct pipeline *p;
4793 	struct table *table;
4794 	struct table_rule *rule;
4795 	FILE *f = NULL;
4796 	uint32_t i;
4797 
4798 	/* Check input params. */
4799 	if ((pipeline_name == NULL) ||
4800 		(file_name == NULL))
4801 		return -1;
4802 
4803 	p = pipeline_find(pipeline_name);
4804 	if ((p == NULL) ||
4805 		(table_id >= p->n_tables))
4806 		return -1;
4807 
4808 	table = &p->table[table_id];
4809 
4810 	/* Open file. */
4811 	f = fopen(file_name, "w");
4812 	if (f == NULL)
4813 		return -1;
4814 
4815 	/* Write table rules to file. */
4816 	TAILQ_FOREACH(rule, &table->rules, node) {
4817 		struct table_rule_match *m = &rule->match;
4818 		struct table_rule_action *a = &rule->action;
4819 
4820 		fprintf(f, "match ");
4821 		switch (m->match_type) {
4822 		case TABLE_ACL:
4823 			fprintf(f, "acl priority %u ",
4824 				m->match.acl.priority);
4825 
4826 			fprintf(f, m->match.acl.ip_version ? "ipv4 " : "ipv6 ");
4827 
4828 			if (m->match.acl.ip_version)
4829 				ipv4_addr_show(f, m->match.acl.ipv4.sa);
4830 			else
4831 				ipv6_addr_show(f, m->match.acl.ipv6.sa);
4832 
4833 			fprintf(f, "%u",	m->match.acl.sa_depth);
4834 
4835 			if (m->match.acl.ip_version)
4836 				ipv4_addr_show(f, m->match.acl.ipv4.da);
4837 			else
4838 				ipv6_addr_show(f, m->match.acl.ipv6.da);
4839 
4840 			fprintf(f, "%u",	m->match.acl.da_depth);
4841 
4842 			fprintf(f, "%u %u %u %u %u ",
4843 				(uint32_t)m->match.acl.sp0,
4844 				(uint32_t)m->match.acl.sp1,
4845 				(uint32_t)m->match.acl.dp0,
4846 				(uint32_t)m->match.acl.dp1,
4847 				(uint32_t)m->match.acl.proto);
4848 			break;
4849 
4850 		case TABLE_ARRAY:
4851 			fprintf(f, "array %u ",
4852 				m->match.array.pos);
4853 			break;
4854 
4855 		case TABLE_HASH:
4856 			fprintf(f, "hash raw ");
4857 			for (i = 0; i < table->params.match.hash.key_size; i++)
4858 				fprintf(f, "%02x", m->match.hash.key[i]);
4859 			fprintf(f, " ");
4860 			break;
4861 
4862 		case TABLE_LPM:
4863 			fprintf(f, "lpm ");
4864 
4865 			fprintf(f, m->match.lpm.ip_version ? "ipv4 " : "ipv6 ");
4866 
4867 			if (m->match.acl.ip_version)
4868 				ipv4_addr_show(f, m->match.lpm.ipv4);
4869 			else
4870 				ipv6_addr_show(f, m->match.lpm.ipv6);
4871 
4872 			fprintf(f, "%u ",
4873 				(uint32_t)m->match.lpm.depth);
4874 			break;
4875 
4876 		default:
4877 			fprintf(f, "unknown ");
4878 		}
4879 
4880 		fprintf(f, "action ");
4881 		if (a->action_mask & (1LLU << RTE_TABLE_ACTION_FWD)) {
4882 			fprintf(f, "fwd ");
4883 			switch (a->fwd.action) {
4884 			case RTE_PIPELINE_ACTION_DROP:
4885 				fprintf(f, "drop ");
4886 				break;
4887 
4888 			case RTE_PIPELINE_ACTION_PORT:
4889 				fprintf(f, "port %u ", a->fwd.id);
4890 				break;
4891 
4892 			case RTE_PIPELINE_ACTION_PORT_META:
4893 				fprintf(f, "meta ");
4894 				break;
4895 
4896 			case RTE_PIPELINE_ACTION_TABLE:
4897 			default:
4898 				fprintf(f, "table %u ", a->fwd.id);
4899 			}
4900 		}
4901 
4902 		if (a->action_mask & (1LLU << RTE_TABLE_ACTION_LB)) {
4903 			fprintf(f, "balance ");
4904 			for (i = 0; i < RTE_DIM(a->lb.out); i++)
4905 				fprintf(f, "%u ", a->lb.out[i]);
4906 		}
4907 
4908 		if (a->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) {
4909 			fprintf(f, "mtr ");
4910 			for (i = 0; i < RTE_TABLE_ACTION_TC_MAX; i++)
4911 				if (a->mtr.tc_mask & (1 << i)) {
4912 					struct rte_table_action_mtr_tc_params *p =
4913 						&a->mtr.mtr[i];
4914 					enum rte_table_action_policer ga =
4915 						p->policer[e_RTE_METER_GREEN];
4916 					enum rte_table_action_policer ya =
4917 						p->policer[e_RTE_METER_YELLOW];
4918 					enum rte_table_action_policer ra =
4919 						p->policer[e_RTE_METER_RED];
4920 
4921 					fprintf(f, "tc%u meter %u policer g %s y %s r %s ",
4922 						i,
4923 						a->mtr.mtr[i].meter_profile_id,
4924 						policer_action_string(ga),
4925 						policer_action_string(ya),
4926 						policer_action_string(ra));
4927 				}
4928 		}
4929 
4930 		if (a->action_mask & (1LLU << RTE_TABLE_ACTION_TM))
4931 			fprintf(f, "tm subport %u pipe %u ",
4932 				a->tm.subport_id,
4933 				a->tm.pipe_id);
4934 
4935 		if (a->action_mask & (1LLU << RTE_TABLE_ACTION_ENCAP)) {
4936 			fprintf(f, "encap ");
4937 			switch (a->encap.type) {
4938 			case RTE_TABLE_ACTION_ENCAP_ETHER:
4939 				fprintf(f, "ether ");
4940 				ether_addr_show(f, &a->encap.ether.ether.da);
4941 				fprintf(f, " ");
4942 				ether_addr_show(f, &a->encap.ether.ether.sa);
4943 				fprintf(f, " ");
4944 				break;
4945 
4946 			case RTE_TABLE_ACTION_ENCAP_VLAN:
4947 				fprintf(f, "vlan ");
4948 				ether_addr_show(f, &a->encap.vlan.ether.da);
4949 				fprintf(f, " ");
4950 				ether_addr_show(f, &a->encap.vlan.ether.sa);
4951 				fprintf(f, " pcp %u dei %u vid %u ",
4952 					a->encap.vlan.vlan.pcp,
4953 					a->encap.vlan.vlan.dei,
4954 					a->encap.vlan.vlan.vid);
4955 				break;
4956 
4957 			case RTE_TABLE_ACTION_ENCAP_QINQ:
4958 				fprintf(f, "qinq ");
4959 				ether_addr_show(f, &a->encap.qinq.ether.da);
4960 				fprintf(f, " ");
4961 				ether_addr_show(f, &a->encap.qinq.ether.sa);
4962 				fprintf(f, " pcp %u dei %u vid %u pcp %u dei %u vid %u ",
4963 					a->encap.qinq.svlan.pcp,
4964 					a->encap.qinq.svlan.dei,
4965 					a->encap.qinq.svlan.vid,
4966 					a->encap.qinq.cvlan.pcp,
4967 					a->encap.qinq.cvlan.dei,
4968 					a->encap.qinq.cvlan.vid);
4969 				break;
4970 
4971 			case RTE_TABLE_ACTION_ENCAP_MPLS:
4972 				fprintf(f, "mpls %s ", (a->encap.mpls.unicast) ?
4973 					"unicast " : "multicast ");
4974 				ether_addr_show(f, &a->encap.mpls.ether.da);
4975 				fprintf(f, " ");
4976 				ether_addr_show(f, &a->encap.mpls.ether.sa);
4977 				fprintf(f, " ");
4978 				for (i = 0; i < a->encap.mpls.mpls_count; i++) {
4979 					struct rte_table_action_mpls_hdr *l =
4980 						&a->encap.mpls.mpls[i];
4981 
4982 					fprintf(f, "label%u %u %u %u ",
4983 						i,
4984 						l->label,
4985 						l->tc,
4986 						l->ttl);
4987 				}
4988 				break;
4989 
4990 			case RTE_TABLE_ACTION_ENCAP_PPPOE:
4991 				fprintf(f, "pppoe ");
4992 				ether_addr_show(f, &a->encap.pppoe.ether.da);
4993 				fprintf(f, " ");
4994 				ether_addr_show(f, &a->encap.pppoe.ether.sa);
4995 				fprintf(f, " %u ", a->encap.pppoe.pppoe.session_id);
4996 				break;
4997 
4998 			case RTE_TABLE_ACTION_ENCAP_VXLAN:
4999 				fprintf(f, "vxlan ether ");
5000 				ether_addr_show(f, &a->encap.vxlan.ether.da);
5001 				fprintf(f, " ");
5002 				ether_addr_show(f, &a->encap.vxlan.ether.sa);
5003 				if (table->ap->params.encap.vxlan.vlan)
5004 					fprintf(f, " vlan pcp %u dei %u vid %u ",
5005 						a->encap.vxlan.vlan.pcp,
5006 						a->encap.vxlan.vlan.dei,
5007 						a->encap.vxlan.vlan.vid);
5008 				if (table->ap->params.encap.vxlan.ip_version) {
5009 					fprintf(f, " ipv4 ");
5010 					ipv4_addr_show(f, a->encap.vxlan.ipv4.sa);
5011 					fprintf(f, " ");
5012 					ipv4_addr_show(f, a->encap.vxlan.ipv4.da);
5013 					fprintf(f, " %u %u ",
5014 						(uint32_t)a->encap.vxlan.ipv4.dscp,
5015 						(uint32_t)a->encap.vxlan.ipv4.ttl);
5016 				} else {
5017 					fprintf(f, " ipv6 ");
5018 					ipv6_addr_show(f, a->encap.vxlan.ipv6.sa);
5019 					fprintf(f, " ");
5020 					ipv6_addr_show(f, a->encap.vxlan.ipv6.da);
5021 					fprintf(f, " %u %u %u ",
5022 						a->encap.vxlan.ipv6.flow_label,
5023 						(uint32_t)a->encap.vxlan.ipv6.dscp,
5024 						(uint32_t)a->encap.vxlan.ipv6.hop_limit);
5025 					fprintf(f, " udp %u %u vxlan %u ",
5026 						a->encap.vxlan.udp.sp,
5027 						a->encap.vxlan.udp.dp,
5028 						a->encap.vxlan.vxlan.vni);
5029 				}
5030 				break;
5031 
5032 			default:
5033 				fprintf(f, "unknown ");
5034 			}
5035 		}
5036 
5037 		if (a->action_mask & (1LLU << RTE_TABLE_ACTION_NAT)) {
5038 			fprintf(f, "nat %s ", (a->nat.ip_version) ? "ipv4 " : "ipv6 ");
5039 			if (a->nat.ip_version)
5040 				ipv4_addr_show(f, a->nat.addr.ipv4);
5041 			else
5042 				ipv6_addr_show(f, a->nat.addr.ipv6);
5043 			fprintf(f, " %u ", (uint32_t)(a->nat.port));
5044 		}
5045 
5046 		if (a->action_mask & (1LLU << RTE_TABLE_ACTION_TTL))
5047 			fprintf(f, "ttl %s ", (a->ttl.decrement) ? "dec" : "keep");
5048 
5049 		if (a->action_mask & (1LLU << RTE_TABLE_ACTION_STATS))
5050 			fprintf(f, "stats ");
5051 
5052 		if (a->action_mask & (1LLU << RTE_TABLE_ACTION_TIME))
5053 			fprintf(f, "time ");
5054 
5055 		if (a->action_mask & (1LLU << RTE_TABLE_ACTION_SYM_CRYPTO))
5056 			fprintf(f, "sym_crypto ");
5057 
5058 		if (a->action_mask & (1LLU << RTE_TABLE_ACTION_TAG))
5059 			fprintf(f, "tag %u ", a->tag.tag);
5060 
5061 		if (a->action_mask & (1LLU << RTE_TABLE_ACTION_DECAP))
5062 			fprintf(f, "decap %u ", a->decap.n);
5063 
5064 		/* end */
5065 		fprintf(f, "\n");
5066 	}
5067 
5068 	/* Write table default rule to file. */
5069 	if (table->rule_default) {
5070 		struct table_rule_action *a = &table->rule_default->action;
5071 
5072 		fprintf(f, "# match default action fwd ");
5073 
5074 		switch (a->fwd.action) {
5075 		case RTE_PIPELINE_ACTION_DROP:
5076 			fprintf(f, "drop ");
5077 			break;
5078 
5079 		case RTE_PIPELINE_ACTION_PORT:
5080 			fprintf(f, "port %u ", a->fwd.id);
5081 			break;
5082 
5083 		case RTE_PIPELINE_ACTION_PORT_META:
5084 			fprintf(f, "meta ");
5085 			break;
5086 
5087 		case RTE_PIPELINE_ACTION_TABLE:
5088 		default:
5089 			fprintf(f, "table %u ", a->fwd.id);
5090 		}
5091 	} else
5092 		fprintf(f, "# match default action fwd drop ");
5093 
5094 	fprintf(f, "\n");
5095 
5096 	/* Close file. */
5097 	fclose(f);
5098 
5099 	return 0;
5100 }
5101 
5102 static const char cmd_pipeline_table_rule_show_help[] =
5103 "pipeline <pipeline_name> table <table_id> rule show\n"
5104 "     file <file_name>\n";
5105 
5106 static void
5107 cmd_pipeline_table_rule_show(char **tokens,
5108 	uint32_t n_tokens,
5109 	char *out,
5110 	size_t out_size)
5111 {
5112 	char *file_name = NULL, *pipeline_name;
5113 	uint32_t table_id;
5114 	int status;
5115 
5116 	if (n_tokens != 8) {
5117 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5118 		return;
5119 	}
5120 
5121 	pipeline_name = tokens[1];
5122 
5123 	if (strcmp(tokens[2], "table") != 0) {
5124 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
5125 		return;
5126 	}
5127 
5128 	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
5129 		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
5130 		return;
5131 	}
5132 
5133 	if (strcmp(tokens[4], "rule") != 0) {
5134 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
5135 		return;
5136 	}
5137 
5138 	if (strcmp(tokens[5], "show") != 0) {
5139 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "show");
5140 		return;
5141 	}
5142 
5143 	if (strcmp(tokens[6], "file") != 0) {
5144 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "file");
5145 		return;
5146 	}
5147 
5148 	file_name = tokens[7];
5149 
5150 	status = table_rule_show(pipeline_name, table_id, file_name);
5151 	if (status) {
5152 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
5153 		return;
5154 	}
5155 }
5156 
5157 static const char cmd_pipeline_table_rule_stats_read_help[] =
5158 "pipeline <pipeline_name> table <table_id> rule read stats [clear]\n"
5159 "     match <match>\n";
5160 
5161 static void
5162 cmd_pipeline_table_rule_stats_read(char **tokens,
5163 	uint32_t n_tokens,
5164 	char *out,
5165 	size_t out_size)
5166 {
5167 	struct table_rule_match m;
5168 	struct rte_table_action_stats_counters stats;
5169 	char *pipeline_name;
5170 	uint32_t table_id, n_tokens_parsed;
5171 	int clear = 0, status;
5172 
5173 	if (n_tokens < 7) {
5174 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5175 		return;
5176 	}
5177 
5178 	pipeline_name = tokens[1];
5179 
5180 	if (strcmp(tokens[2], "table") != 0) {
5181 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
5182 		return;
5183 	}
5184 
5185 	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
5186 		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
5187 		return;
5188 	}
5189 
5190 	if (strcmp(tokens[4], "rule") != 0) {
5191 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
5192 		return;
5193 	}
5194 
5195 	if (strcmp(tokens[5], "read") != 0) {
5196 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read");
5197 		return;
5198 	}
5199 
5200 	if (strcmp(tokens[6], "stats") != 0) {
5201 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
5202 		return;
5203 	}
5204 
5205 	n_tokens -= 7;
5206 	tokens += 7;
5207 
5208 	/* clear */
5209 	if (n_tokens && (strcmp(tokens[0], "clear") == 0)) {
5210 		clear = 1;
5211 
5212 		n_tokens--;
5213 		tokens++;
5214 	}
5215 
5216 	/* match */
5217 	if ((n_tokens == 0) || strcmp(tokens[0], "match")) {
5218 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match");
5219 		return;
5220 	}
5221 
5222 	n_tokens_parsed = parse_match(tokens,
5223 		n_tokens,
5224 		out,
5225 		out_size,
5226 		&m);
5227 	if (n_tokens_parsed == 0)
5228 		return;
5229 	n_tokens -= n_tokens_parsed;
5230 	tokens += n_tokens_parsed;
5231 
5232 	/* end */
5233 	if (n_tokens) {
5234 		snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
5235 		return;
5236 	}
5237 
5238 	/* Read table rule stats. */
5239 	status = pipeline_table_rule_stats_read(pipeline_name,
5240 		table_id,
5241 		&m,
5242 		&stats,
5243 		clear);
5244 	if (status) {
5245 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
5246 		return;
5247 	}
5248 
5249 	/* Print stats. */
5250 	if (stats.n_packets_valid && stats.n_bytes_valid)
5251 		snprintf(out, out_size, "Packets: %" PRIu64 "; Bytes: %" PRIu64 "\n",
5252 			stats.n_packets,
5253 			stats.n_bytes);
5254 
5255 	if (stats.n_packets_valid && !stats.n_bytes_valid)
5256 		snprintf(out, out_size, "Packets: %" PRIu64 "; Bytes: N/A\n",
5257 			stats.n_packets);
5258 
5259 	if (!stats.n_packets_valid && stats.n_bytes_valid)
5260 		snprintf(out, out_size, "Packets: N/A; Bytes: %" PRIu64 "\n",
5261 			stats.n_bytes);
5262 
5263 	if (!stats.n_packets_valid && !stats.n_bytes_valid)
5264 		snprintf(out, out_size, "Packets: N/A ; Bytes: N/A\n");
5265 }
5266 
5267 static const char cmd_pipeline_table_meter_profile_add_help[] =
5268 "pipeline <pipeline_name> table <table_id> meter profile <meter_profile_id>\n"
5269 "   add srtcm cir <cir> cbs <cbs> ebs <ebs>\n"
5270 "   | trtcm cir <cir> pir <pir> cbs <cbs> pbs <pbs>\n";
5271 
5272 static void
5273 cmd_pipeline_table_meter_profile_add(char **tokens,
5274 	uint32_t n_tokens,
5275 	char *out,
5276 	size_t out_size)
5277 {
5278 	struct rte_table_action_meter_profile p;
5279 	char *pipeline_name;
5280 	uint32_t table_id, meter_profile_id;
5281 	int status;
5282 
5283 	if (n_tokens < 9) {
5284 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5285 		return;
5286 	}
5287 
5288 	pipeline_name = tokens[1];
5289 
5290 	if (strcmp(tokens[2], "table") != 0) {
5291 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
5292 		return;
5293 	}
5294 
5295 	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
5296 		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
5297 		return;
5298 	}
5299 
5300 	if (strcmp(tokens[4], "meter") != 0) {
5301 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
5302 		return;
5303 	}
5304 
5305 	if (strcmp(tokens[5], "profile") != 0) {
5306 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
5307 		return;
5308 	}
5309 
5310 	if (parser_read_uint32(&meter_profile_id, tokens[6]) != 0) {
5311 		snprintf(out, out_size, MSG_ARG_INVALID, "meter_profile_id");
5312 		return;
5313 	}
5314 
5315 	if (strcmp(tokens[7], "add") != 0) {
5316 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
5317 		return;
5318 	}
5319 
5320 	if (strcmp(tokens[8], "srtcm") == 0) {
5321 		if (n_tokens != 15) {
5322 			snprintf(out, out_size, MSG_ARG_MISMATCH,
5323 				tokens[0]);
5324 			return;
5325 		}
5326 
5327 		p.alg = RTE_TABLE_ACTION_METER_SRTCM;
5328 
5329 		if (strcmp(tokens[9], "cir") != 0) {
5330 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cir");
5331 			return;
5332 		}
5333 
5334 		if (parser_read_uint64(&p.srtcm.cir, tokens[10]) != 0) {
5335 			snprintf(out, out_size, MSG_ARG_INVALID, "cir");
5336 			return;
5337 		}
5338 
5339 		if (strcmp(tokens[11], "cbs") != 0) {
5340 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cbs");
5341 			return;
5342 		}
5343 
5344 		if (parser_read_uint64(&p.srtcm.cbs, tokens[12]) != 0) {
5345 			snprintf(out, out_size, MSG_ARG_INVALID, "cbs");
5346 			return;
5347 		}
5348 
5349 		if (strcmp(tokens[13], "ebs") != 0) {
5350 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "ebs");
5351 			return;
5352 		}
5353 
5354 		if (parser_read_uint64(&p.srtcm.ebs, tokens[14]) != 0) {
5355 			snprintf(out, out_size, MSG_ARG_INVALID, "ebs");
5356 			return;
5357 		}
5358 	} else if (strcmp(tokens[8], "trtcm") == 0) {
5359 		if (n_tokens != 17) {
5360 			snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5361 			return;
5362 		}
5363 
5364 		p.alg = RTE_TABLE_ACTION_METER_TRTCM;
5365 
5366 		if (strcmp(tokens[9], "cir") != 0) {
5367 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cir");
5368 			return;
5369 		}
5370 
5371 		if (parser_read_uint64(&p.trtcm.cir, tokens[10]) != 0) {
5372 			snprintf(out, out_size, MSG_ARG_INVALID, "cir");
5373 			return;
5374 		}
5375 
5376 		if (strcmp(tokens[11], "pir") != 0) {
5377 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pir");
5378 			return;
5379 		}
5380 
5381 		if (parser_read_uint64(&p.trtcm.pir, tokens[12]) != 0) {
5382 			snprintf(out, out_size, MSG_ARG_INVALID, "pir");
5383 			return;
5384 		}
5385 		if (strcmp(tokens[13], "cbs") != 0) {
5386 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cbs");
5387 			return;
5388 		}
5389 
5390 		if (parser_read_uint64(&p.trtcm.cbs, tokens[14]) != 0) {
5391 			snprintf(out, out_size, MSG_ARG_INVALID, "cbs");
5392 			return;
5393 		}
5394 
5395 		if (strcmp(tokens[15], "pbs") != 0) {
5396 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pbs");
5397 			return;
5398 		}
5399 
5400 		if (parser_read_uint64(&p.trtcm.pbs, tokens[16]) != 0) {
5401 			snprintf(out, out_size, MSG_ARG_INVALID, "pbs");
5402 			return;
5403 		}
5404 	} else {
5405 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5406 		return;
5407 	}
5408 
5409 	status = pipeline_table_mtr_profile_add(pipeline_name,
5410 		table_id,
5411 		meter_profile_id,
5412 		&p);
5413 	if (status) {
5414 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
5415 		return;
5416 	}
5417 }
5418 
5419 
5420 static const char cmd_pipeline_table_meter_profile_delete_help[] =
5421 "pipeline <pipeline_name> table <table_id>\n"
5422 "   meter profile <meter_profile_id> delete\n";
5423 
5424 static void
5425 cmd_pipeline_table_meter_profile_delete(char **tokens,
5426 	uint32_t n_tokens,
5427 	char *out,
5428 	size_t out_size)
5429 {
5430 	char *pipeline_name;
5431 	uint32_t table_id, meter_profile_id;
5432 	int status;
5433 
5434 	if (n_tokens != 8) {
5435 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5436 		return;
5437 	}
5438 
5439 	pipeline_name = tokens[1];
5440 
5441 	if (strcmp(tokens[2], "table") != 0) {
5442 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
5443 		return;
5444 	}
5445 
5446 	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
5447 		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
5448 		return;
5449 	}
5450 
5451 	if (strcmp(tokens[4], "meter") != 0) {
5452 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
5453 		return;
5454 	}
5455 
5456 	if (strcmp(tokens[5], "profile") != 0) {
5457 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
5458 		return;
5459 	}
5460 
5461 	if (parser_read_uint32(&meter_profile_id, tokens[6]) != 0) {
5462 		snprintf(out, out_size, MSG_ARG_INVALID, "meter_profile_id");
5463 		return;
5464 	}
5465 
5466 	if (strcmp(tokens[7], "delete") != 0) {
5467 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete");
5468 		return;
5469 	}
5470 
5471 	status = pipeline_table_mtr_profile_delete(pipeline_name,
5472 		table_id,
5473 		meter_profile_id);
5474 	if (status) {
5475 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
5476 		return;
5477 	}
5478 }
5479 
5480 
5481 static const char cmd_pipeline_table_rule_meter_read_help[] =
5482 "pipeline <pipeline_name> table <table_id> rule read meter [clear]\n"
5483 "     match <match>\n";
5484 
5485 static void
5486 cmd_pipeline_table_rule_meter_read(char **tokens,
5487 	uint32_t n_tokens,
5488 	char *out,
5489 	size_t out_size)
5490 {
5491 	struct table_rule_match m;
5492 	struct rte_table_action_mtr_counters stats;
5493 	char *pipeline_name;
5494 	uint32_t table_id, n_tokens_parsed;
5495 	int clear = 0, status;
5496 
5497 	if (n_tokens < 7) {
5498 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5499 		return;
5500 	}
5501 
5502 	pipeline_name = tokens[1];
5503 
5504 	if (strcmp(tokens[2], "table") != 0) {
5505 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
5506 		return;
5507 	}
5508 
5509 	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
5510 		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
5511 		return;
5512 	}
5513 
5514 	if (strcmp(tokens[4], "rule") != 0) {
5515 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
5516 		return;
5517 	}
5518 
5519 	if (strcmp(tokens[5], "read") != 0) {
5520 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read");
5521 		return;
5522 	}
5523 
5524 	if (strcmp(tokens[6], "meter") != 0) {
5525 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
5526 		return;
5527 	}
5528 
5529 	n_tokens -= 7;
5530 	tokens += 7;
5531 
5532 	/* clear */
5533 	if (n_tokens && (strcmp(tokens[0], "clear") == 0)) {
5534 		clear = 1;
5535 
5536 		n_tokens--;
5537 		tokens++;
5538 	}
5539 
5540 	/* match */
5541 	if ((n_tokens == 0) || strcmp(tokens[0], "match")) {
5542 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match");
5543 		return;
5544 	}
5545 
5546 	n_tokens_parsed = parse_match(tokens,
5547 		n_tokens,
5548 		out,
5549 		out_size,
5550 		&m);
5551 	if (n_tokens_parsed == 0)
5552 		return;
5553 	n_tokens -= n_tokens_parsed;
5554 	tokens += n_tokens_parsed;
5555 
5556 	/* end */
5557 	if (n_tokens) {
5558 		snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
5559 		return;
5560 	}
5561 
5562 	/* Read table rule meter stats. */
5563 	status = pipeline_table_rule_mtr_read(pipeline_name,
5564 		table_id,
5565 		&m,
5566 		&stats,
5567 		clear);
5568 	if (status) {
5569 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
5570 		return;
5571 	}
5572 
5573 	/* Print stats. */
5574 }
5575 
5576 
5577 static const char cmd_pipeline_table_dscp_help[] =
5578 "pipeline <pipeline_name> table <table_id> dscp <file_name>\n"
5579 "\n"
5580 " File <file_name>:\n"
5581 "   - exactly 64 lines\n"
5582 "   - line format: <tc_id> <tc_queue_id> <color>, with <color> as: g | y | r\n";
5583 
5584 static int
5585 load_dscp_table(struct rte_table_action_dscp_table *dscp_table,
5586 	const char *file_name,
5587 	uint32_t *line_number)
5588 {
5589 	FILE *f = NULL;
5590 	uint32_t dscp, l;
5591 
5592 	/* Check input arguments */
5593 	if ((dscp_table == NULL) ||
5594 		(file_name == NULL) ||
5595 		(line_number == NULL)) {
5596 		if (line_number)
5597 			*line_number = 0;
5598 		return -EINVAL;
5599 	}
5600 
5601 	/* Open input file */
5602 	f = fopen(file_name, "r");
5603 	if (f == NULL) {
5604 		*line_number = 0;
5605 		return -EINVAL;
5606 	}
5607 
5608 	/* Read file */
5609 	for (dscp = 0, l = 1; ; l++) {
5610 		char line[64];
5611 		char *tokens[3];
5612 		enum rte_meter_color color;
5613 		uint32_t tc_id, tc_queue_id, n_tokens = RTE_DIM(tokens);
5614 
5615 		if (fgets(line, sizeof(line), f) == NULL)
5616 			break;
5617 
5618 		if (is_comment(line))
5619 			continue;
5620 
5621 		if (parse_tokenize_string(line, tokens, &n_tokens)) {
5622 			*line_number = l;
5623 			fclose(f);
5624 			return -EINVAL;
5625 		}
5626 
5627 		if (n_tokens == 0)
5628 			continue;
5629 
5630 		if ((dscp >= RTE_DIM(dscp_table->entry)) ||
5631 			(n_tokens != RTE_DIM(tokens)) ||
5632 			parser_read_uint32(&tc_id, tokens[0]) ||
5633 			(tc_id >= RTE_TABLE_ACTION_TC_MAX) ||
5634 			parser_read_uint32(&tc_queue_id, tokens[1]) ||
5635 			(tc_queue_id >= RTE_TABLE_ACTION_TC_QUEUE_MAX) ||
5636 			(strlen(tokens[2]) != 1)) {
5637 			*line_number = l;
5638 			fclose(f);
5639 			return -EINVAL;
5640 		}
5641 
5642 		switch (tokens[2][0]) {
5643 		case 'g':
5644 		case 'G':
5645 			color = e_RTE_METER_GREEN;
5646 			break;
5647 
5648 		case 'y':
5649 		case 'Y':
5650 			color = e_RTE_METER_YELLOW;
5651 			break;
5652 
5653 		case 'r':
5654 		case 'R':
5655 			color = e_RTE_METER_RED;
5656 			break;
5657 
5658 		default:
5659 			*line_number = l;
5660 			fclose(f);
5661 			return -EINVAL;
5662 		}
5663 
5664 		dscp_table->entry[dscp].tc_id = tc_id;
5665 		dscp_table->entry[dscp].tc_queue_id = tc_queue_id;
5666 		dscp_table->entry[dscp].color = color;
5667 		dscp++;
5668 	}
5669 
5670 	/* Close file */
5671 	fclose(f);
5672 	return 0;
5673 }
5674 
5675 static void
5676 cmd_pipeline_table_dscp(char **tokens,
5677 	uint32_t n_tokens,
5678 	char *out,
5679 	size_t out_size)
5680 {
5681 	struct rte_table_action_dscp_table dscp_table;
5682 	char *pipeline_name, *file_name;
5683 	uint32_t table_id, line_number;
5684 	int status;
5685 
5686 	if (n_tokens != 6) {
5687 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5688 		return;
5689 	}
5690 
5691 	pipeline_name = tokens[1];
5692 
5693 	if (strcmp(tokens[2], "table") != 0) {
5694 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
5695 		return;
5696 	}
5697 
5698 	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
5699 		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
5700 		return;
5701 	}
5702 
5703 	if (strcmp(tokens[4], "dscp") != 0) {
5704 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "dscp");
5705 		return;
5706 	}
5707 
5708 	file_name = tokens[5];
5709 
5710 	status = load_dscp_table(&dscp_table, file_name, &line_number);
5711 	if (status) {
5712 		snprintf(out, out_size, MSG_FILE_ERR, file_name, line_number);
5713 		return;
5714 	}
5715 
5716 	status = pipeline_table_dscp_table_update(pipeline_name,
5717 		table_id,
5718 		UINT64_MAX,
5719 		&dscp_table);
5720 	if (status) {
5721 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
5722 		return;
5723 	}
5724 }
5725 
5726 
5727 static const char cmd_pipeline_table_rule_ttl_read_help[] =
5728 "pipeline <pipeline_name> table <table_id> rule read ttl [clear]\n"
5729 "     match <match>\n";
5730 
5731 static void
5732 cmd_pipeline_table_rule_ttl_read(char **tokens,
5733 	uint32_t n_tokens,
5734 	char *out,
5735 	size_t out_size)
5736 {
5737 	struct table_rule_match m;
5738 	struct rte_table_action_ttl_counters stats;
5739 	char *pipeline_name;
5740 	uint32_t table_id, n_tokens_parsed;
5741 	int clear = 0, status;
5742 
5743 	if (n_tokens < 7) {
5744 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5745 		return;
5746 	}
5747 
5748 	pipeline_name = tokens[1];
5749 
5750 	if (strcmp(tokens[2], "table") != 0) {
5751 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
5752 		return;
5753 	}
5754 
5755 	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
5756 		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
5757 		return;
5758 	}
5759 
5760 	if (strcmp(tokens[4], "rule") != 0) {
5761 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
5762 		return;
5763 	}
5764 
5765 	if (strcmp(tokens[5], "read") != 0) {
5766 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read");
5767 		return;
5768 	}
5769 
5770 	if (strcmp(tokens[6], "ttl") != 0) {
5771 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "ttl");
5772 		return;
5773 	}
5774 
5775 	n_tokens -= 7;
5776 	tokens += 7;
5777 
5778 	/* clear */
5779 	if (n_tokens && (strcmp(tokens[0], "clear") == 0)) {
5780 		clear = 1;
5781 
5782 		n_tokens--;
5783 		tokens++;
5784 	}
5785 
5786 	/* match */
5787 	if ((n_tokens == 0) || strcmp(tokens[0], "match")) {
5788 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match");
5789 		return;
5790 	}
5791 
5792 	n_tokens_parsed = parse_match(tokens,
5793 		n_tokens,
5794 		out,
5795 		out_size,
5796 		&m);
5797 	if (n_tokens_parsed == 0)
5798 		return;
5799 	n_tokens -= n_tokens_parsed;
5800 	tokens += n_tokens_parsed;
5801 
5802 	/* end */
5803 	if (n_tokens) {
5804 		snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
5805 		return;
5806 	}
5807 
5808 	/* Read table rule TTL stats. */
5809 	status = pipeline_table_rule_ttl_read(pipeline_name,
5810 		table_id,
5811 		&m,
5812 		&stats,
5813 		clear);
5814 	if (status) {
5815 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
5816 		return;
5817 	}
5818 
5819 	/* Print stats. */
5820 	snprintf(out, out_size, "Packets: %" PRIu64 "\n",
5821 		stats.n_packets);
5822 }
5823 
5824 static const char cmd_pipeline_table_rule_time_read_help[] =
5825 "pipeline <pipeline_name> table <table_id> rule read time\n"
5826 "     match <match>\n";
5827 
5828 static void
5829 cmd_pipeline_table_rule_time_read(char **tokens,
5830 	uint32_t n_tokens,
5831 	char *out,
5832 	size_t out_size)
5833 {
5834 	struct table_rule_match m;
5835 	char *pipeline_name;
5836 	uint64_t timestamp;
5837 	uint32_t table_id, n_tokens_parsed;
5838 	int status;
5839 
5840 	if (n_tokens < 7) {
5841 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5842 		return;
5843 	}
5844 
5845 	pipeline_name = tokens[1];
5846 
5847 	if (strcmp(tokens[2], "table") != 0) {
5848 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
5849 		return;
5850 	}
5851 
5852 	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
5853 		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
5854 		return;
5855 	}
5856 
5857 	if (strcmp(tokens[4], "rule") != 0) {
5858 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
5859 		return;
5860 	}
5861 
5862 	if (strcmp(tokens[5], "read") != 0) {
5863 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read");
5864 		return;
5865 	}
5866 
5867 	if (strcmp(tokens[6], "time") != 0) {
5868 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "time");
5869 		return;
5870 	}
5871 
5872 	n_tokens -= 7;
5873 	tokens += 7;
5874 
5875 	/* match */
5876 	if ((n_tokens == 0) || strcmp(tokens[0], "match")) {
5877 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match");
5878 		return;
5879 	}
5880 
5881 	n_tokens_parsed = parse_match(tokens,
5882 		n_tokens,
5883 		out,
5884 		out_size,
5885 		&m);
5886 	if (n_tokens_parsed == 0)
5887 		return;
5888 	n_tokens -= n_tokens_parsed;
5889 	tokens += n_tokens_parsed;
5890 
5891 	/* end */
5892 	if (n_tokens) {
5893 		snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
5894 		return;
5895 	}
5896 
5897 	/* Read table rule timestamp. */
5898 	status = pipeline_table_rule_time_read(pipeline_name,
5899 		table_id,
5900 		&m,
5901 		&timestamp);
5902 	if (status) {
5903 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
5904 		return;
5905 	}
5906 
5907 	/* Print stats. */
5908 	snprintf(out, out_size, "Packets: %" PRIu64 "\n", timestamp);
5909 }
5910 
5911 static const char cmd_thread_pipeline_enable_help[] =
5912 "thread <thread_id> pipeline <pipeline_name> enable\n";
5913 
5914 static void
5915 cmd_thread_pipeline_enable(char **tokens,
5916 	uint32_t n_tokens,
5917 	char *out,
5918 	size_t out_size)
5919 {
5920 	char *pipeline_name;
5921 	uint32_t thread_id;
5922 	int status;
5923 
5924 	if (n_tokens != 5) {
5925 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5926 		return;
5927 	}
5928 
5929 	if (parser_read_uint32(&thread_id, tokens[1]) != 0) {
5930 		snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
5931 		return;
5932 	}
5933 
5934 	if (strcmp(tokens[2], "pipeline") != 0) {
5935 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
5936 		return;
5937 	}
5938 
5939 	pipeline_name = tokens[3];
5940 
5941 	if (strcmp(tokens[4], "enable") != 0) {
5942 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable");
5943 		return;
5944 	}
5945 
5946 	status = thread_pipeline_enable(thread_id, pipeline_name);
5947 	if (status) {
5948 		snprintf(out, out_size, MSG_CMD_FAIL, "thread pipeline enable");
5949 		return;
5950 	}
5951 }
5952 
5953 
5954 static const char cmd_thread_pipeline_disable_help[] =
5955 "thread <thread_id> pipeline <pipeline_name> disable\n";
5956 
5957 static void
5958 cmd_thread_pipeline_disable(char **tokens,
5959 	uint32_t n_tokens,
5960 	char *out,
5961 	size_t out_size)
5962 {
5963 	char *pipeline_name;
5964 	uint32_t thread_id;
5965 	int status;
5966 
5967 	if (n_tokens != 5) {
5968 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5969 		return;
5970 	}
5971 
5972 	if (parser_read_uint32(&thread_id, tokens[1]) != 0) {
5973 		snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
5974 		return;
5975 	}
5976 
5977 	if (strcmp(tokens[2], "pipeline") != 0) {
5978 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
5979 		return;
5980 	}
5981 
5982 	pipeline_name = tokens[3];
5983 
5984 	if (strcmp(tokens[4], "disable") != 0) {
5985 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable");
5986 		return;
5987 	}
5988 
5989 	status = thread_pipeline_disable(thread_id, pipeline_name);
5990 	if (status) {
5991 		snprintf(out, out_size, MSG_CMD_FAIL,
5992 			"thread pipeline disable");
5993 		return;
5994 	}
5995 }
5996 
5997 static void
5998 cmd_help(char **tokens, uint32_t n_tokens, char *out, size_t out_size)
5999 {
6000 	tokens++;
6001 	n_tokens--;
6002 
6003 	if (n_tokens == 0) {
6004 		snprintf(out, out_size,
6005 			"Type 'help <command>' for details on each command.\n\n"
6006 			"List of commands:\n"
6007 			"\tmempool\n"
6008 			"\tlink\n"
6009 			"\tswq\n"
6010 			"\ttmgr subport profile\n"
6011 			"\ttmgr pipe profile\n"
6012 			"\ttmgr\n"
6013 			"\ttmgr subport\n"
6014 			"\ttmgr subport pipe\n"
6015 			"\ttap\n"
6016 			"\tkni\n"
6017 			"\tport in action profile\n"
6018 			"\ttable action profile\n"
6019 			"\tpipeline\n"
6020 			"\tpipeline port in\n"
6021 			"\tpipeline port out\n"
6022 			"\tpipeline table\n"
6023 			"\tpipeline port in table\n"
6024 			"\tpipeline port in stats\n"
6025 			"\tpipeline port in enable\n"
6026 			"\tpipeline port in disable\n"
6027 			"\tpipeline port out stats\n"
6028 			"\tpipeline table stats\n"
6029 			"\tpipeline table rule add\n"
6030 			"\tpipeline table rule add default\n"
6031 			"\tpipeline table rule add bulk\n"
6032 			"\tpipeline table rule delete\n"
6033 			"\tpipeline table rule delete default\n"
6034 			"\tpipeline table rule show\n"
6035 			"\tpipeline table rule stats read\n"
6036 			"\tpipeline table meter profile add\n"
6037 			"\tpipeline table meter profile delete\n"
6038 			"\tpipeline table rule meter read\n"
6039 			"\tpipeline table dscp\n"
6040 			"\tpipeline table rule ttl read\n"
6041 			"\tpipeline table rule time read\n"
6042 			"\tthread pipeline enable\n"
6043 			"\tthread pipeline disable\n\n");
6044 		return;
6045 	}
6046 
6047 	if (strcmp(tokens[0], "mempool") == 0) {
6048 		snprintf(out, out_size, "\n%s\n", cmd_mempool_help);
6049 		return;
6050 	}
6051 
6052 	if (strcmp(tokens[0], "link") == 0) {
6053 		snprintf(out, out_size, "\n%s\n", cmd_link_help);
6054 		return;
6055 	}
6056 
6057 	if (strcmp(tokens[0], "swq") == 0) {
6058 		snprintf(out, out_size, "\n%s\n", cmd_swq_help);
6059 		return;
6060 	}
6061 
6062 	if (strcmp(tokens[0], "tmgr") == 0) {
6063 		if (n_tokens == 1) {
6064 			snprintf(out, out_size, "\n%s\n", cmd_tmgr_help);
6065 			return;
6066 		}
6067 
6068 		if ((n_tokens == 2) &&
6069 			(strcmp(tokens[1], "subport")) == 0) {
6070 			snprintf(out, out_size, "\n%s\n", cmd_tmgr_subport_help);
6071 			return;
6072 		}
6073 
6074 		if ((n_tokens == 3) &&
6075 			(strcmp(tokens[1], "subport") == 0) &&
6076 			(strcmp(tokens[2], "profile") == 0)) {
6077 			snprintf(out, out_size, "\n%s\n",
6078 				cmd_tmgr_subport_profile_help);
6079 			return;
6080 		}
6081 
6082 		if ((n_tokens == 3) &&
6083 			(strcmp(tokens[1], "subport") == 0) &&
6084 			(strcmp(tokens[2], "pipe") == 0)) {
6085 			snprintf(out, out_size, "\n%s\n", cmd_tmgr_subport_pipe_help);
6086 			return;
6087 		}
6088 
6089 		if ((n_tokens == 3) &&
6090 			(strcmp(tokens[1], "pipe") == 0) &&
6091 			(strcmp(tokens[2], "profile") == 0)) {
6092 			snprintf(out, out_size, "\n%s\n", cmd_tmgr_pipe_profile_help);
6093 			return;
6094 		}
6095 	}
6096 
6097 	if (strcmp(tokens[0], "tap") == 0) {
6098 		snprintf(out, out_size, "\n%s\n", cmd_tap_help);
6099 		return;
6100 	}
6101 
6102 	if (strcmp(tokens[0], "kni") == 0) {
6103 		snprintf(out, out_size, "\n%s\n", cmd_kni_help);
6104 		return;
6105 	}
6106 
6107 	if (strcmp(tokens[0], "cryptodev") == 0) {
6108 		snprintf(out, out_size, "\n%s\n", cmd_cryptodev_help);
6109 		return;
6110 	}
6111 
6112 	if ((n_tokens == 4) &&
6113 		(strcmp(tokens[0], "port") == 0) &&
6114 		(strcmp(tokens[1], "in") == 0) &&
6115 		(strcmp(tokens[2], "action") == 0) &&
6116 		(strcmp(tokens[3], "profile") == 0)) {
6117 		snprintf(out, out_size, "\n%s\n", cmd_port_in_action_profile_help);
6118 		return;
6119 	}
6120 
6121 	if ((n_tokens == 3) &&
6122 		(strcmp(tokens[0], "table") == 0) &&
6123 		(strcmp(tokens[1], "action") == 0) &&
6124 		(strcmp(tokens[2], "profile") == 0)) {
6125 		snprintf(out, out_size, "\n%s\n", cmd_table_action_profile_help);
6126 		return;
6127 	}
6128 
6129 	if ((strcmp(tokens[0], "pipeline") == 0) && (n_tokens == 1)) {
6130 		snprintf(out, out_size, "\n%s\n", cmd_pipeline_help);
6131 		return;
6132 	}
6133 
6134 	if ((strcmp(tokens[0], "pipeline") == 0) &&
6135 		(strcmp(tokens[1], "port") == 0)) {
6136 		if ((n_tokens == 3) && (strcmp(tokens[2], "in")) == 0) {
6137 			snprintf(out, out_size, "\n%s\n", cmd_pipeline_port_in_help);
6138 			return;
6139 		}
6140 
6141 		if ((n_tokens == 3) && (strcmp(tokens[2], "out")) == 0) {
6142 			snprintf(out, out_size, "\n%s\n", cmd_pipeline_port_out_help);
6143 			return;
6144 		}
6145 
6146 		if ((n_tokens == 4) &&
6147 			(strcmp(tokens[2], "in") == 0) &&
6148 			(strcmp(tokens[3], "table") == 0)) {
6149 			snprintf(out, out_size, "\n%s\n",
6150 				cmd_pipeline_port_in_table_help);
6151 			return;
6152 		}
6153 
6154 		if ((n_tokens == 4) &&
6155 			(strcmp(tokens[2], "in") == 0) &&
6156 			(strcmp(tokens[3], "stats") == 0)) {
6157 			snprintf(out, out_size, "\n%s\n",
6158 				cmd_pipeline_port_in_stats_help);
6159 			return;
6160 		}
6161 
6162 		if ((n_tokens == 4) &&
6163 			(strcmp(tokens[2], "in") == 0) &&
6164 			(strcmp(tokens[3], "enable") == 0)) {
6165 			snprintf(out, out_size, "\n%s\n",
6166 				cmd_pipeline_port_in_enable_help);
6167 			return;
6168 		}
6169 
6170 		if ((n_tokens == 4) &&
6171 			(strcmp(tokens[2], "in") == 0) &&
6172 			(strcmp(tokens[3], "disable") == 0)) {
6173 			snprintf(out, out_size, "\n%s\n",
6174 				cmd_pipeline_port_in_disable_help);
6175 			return;
6176 		}
6177 
6178 		if ((n_tokens == 4) &&
6179 			(strcmp(tokens[2], "out") == 0) &&
6180 			(strcmp(tokens[3], "stats") == 0)) {
6181 			snprintf(out, out_size, "\n%s\n",
6182 				cmd_pipeline_port_out_stats_help);
6183 			return;
6184 		}
6185 	}
6186 
6187 	if ((strcmp(tokens[0], "pipeline") == 0) &&
6188 		(strcmp(tokens[1], "table") == 0)) {
6189 		if (n_tokens == 2) {
6190 			snprintf(out, out_size, "\n%s\n", cmd_pipeline_table_help);
6191 			return;
6192 		}
6193 
6194 		if ((n_tokens == 3) && strcmp(tokens[2], "stats") == 0) {
6195 			snprintf(out, out_size, "\n%s\n",
6196 				cmd_pipeline_table_stats_help);
6197 			return;
6198 		}
6199 
6200 		if ((n_tokens == 3) && strcmp(tokens[2], "dscp") == 0) {
6201 			snprintf(out, out_size, "\n%s\n",
6202 				cmd_pipeline_table_dscp_help);
6203 			return;
6204 		}
6205 
6206 		if ((n_tokens == 4) &&
6207 			(strcmp(tokens[2], "rule") == 0) &&
6208 			(strcmp(tokens[3], "add") == 0)) {
6209 			snprintf(out, out_size, "\n%s\n",
6210 				cmd_pipeline_table_rule_add_help);
6211 			return;
6212 		}
6213 
6214 		if ((n_tokens == 5) &&
6215 			(strcmp(tokens[2], "rule") == 0) &&
6216 			(strcmp(tokens[3], "add") == 0) &&
6217 			(strcmp(tokens[4], "default") == 0)) {
6218 			snprintf(out, out_size, "\n%s\n",
6219 				cmd_pipeline_table_rule_add_default_help);
6220 			return;
6221 		}
6222 
6223 		if ((n_tokens == 5) &&
6224 			(strcmp(tokens[2], "rule") == 0) &&
6225 			(strcmp(tokens[3], "add") == 0) &&
6226 			(strcmp(tokens[4], "bulk") == 0)) {
6227 			snprintf(out, out_size, "\n%s\n",
6228 				cmd_pipeline_table_rule_add_bulk_help);
6229 			return;
6230 		}
6231 
6232 		if ((n_tokens == 4) &&
6233 			(strcmp(tokens[2], "rule") == 0) &&
6234 			(strcmp(tokens[3], "delete") == 0)) {
6235 			snprintf(out, out_size, "\n%s\n",
6236 				cmd_pipeline_table_rule_delete_help);
6237 			return;
6238 		}
6239 
6240 		if ((n_tokens == 5) &&
6241 			(strcmp(tokens[2], "rule") == 0) &&
6242 			(strcmp(tokens[3], "delete") == 0) &&
6243 			(strcmp(tokens[4], "default") == 0)) {
6244 			snprintf(out, out_size, "\n%s\n",
6245 				cmd_pipeline_table_rule_delete_default_help);
6246 			return;
6247 		}
6248 
6249 		if ((n_tokens == 4) &&
6250 			(strcmp(tokens[2], "rule") == 0) &&
6251 			(strcmp(tokens[3], "show") == 0)) {
6252 			snprintf(out, out_size, "\n%s\n",
6253 				cmd_pipeline_table_rule_show_help);
6254 			return;
6255 		}
6256 
6257 		if ((n_tokens == 5) &&
6258 			(strcmp(tokens[2], "rule") == 0) &&
6259 			(strcmp(tokens[3], "stats") == 0) &&
6260 			(strcmp(tokens[4], "read") == 0)) {
6261 			snprintf(out, out_size, "\n%s\n",
6262 				cmd_pipeline_table_rule_stats_read_help);
6263 			return;
6264 		}
6265 
6266 		if ((n_tokens == 5) &&
6267 			(strcmp(tokens[2], "meter") == 0) &&
6268 			(strcmp(tokens[3], "profile") == 0) &&
6269 			(strcmp(tokens[4], "add") == 0)) {
6270 			snprintf(out, out_size, "\n%s\n",
6271 				cmd_pipeline_table_meter_profile_add_help);
6272 			return;
6273 		}
6274 
6275 		if ((n_tokens == 5) &&
6276 			(strcmp(tokens[2], "meter") == 0) &&
6277 			(strcmp(tokens[3], "profile") == 0) &&
6278 			(strcmp(tokens[4], "delete") == 0)) {
6279 			snprintf(out, out_size, "\n%s\n",
6280 				cmd_pipeline_table_meter_profile_delete_help);
6281 			return;
6282 		}
6283 
6284 		if ((n_tokens == 5) &&
6285 			(strcmp(tokens[2], "rule") == 0) &&
6286 			(strcmp(tokens[3], "meter") == 0) &&
6287 			(strcmp(tokens[4], "read") == 0)) {
6288 			snprintf(out, out_size, "\n%s\n",
6289 				cmd_pipeline_table_rule_meter_read_help);
6290 			return;
6291 		}
6292 
6293 		if ((n_tokens == 5) &&
6294 			(strcmp(tokens[2], "rule") == 0) &&
6295 			(strcmp(tokens[3], "ttl") == 0) &&
6296 			(strcmp(tokens[4], "read") == 0)) {
6297 			snprintf(out, out_size, "\n%s\n",
6298 				cmd_pipeline_table_rule_ttl_read_help);
6299 			return;
6300 		}
6301 
6302 		if ((n_tokens == 5) &&
6303 			(strcmp(tokens[2], "rule") == 0) &&
6304 			(strcmp(tokens[3], "time") == 0) &&
6305 			(strcmp(tokens[4], "read") == 0)) {
6306 			snprintf(out, out_size, "\n%s\n",
6307 				cmd_pipeline_table_rule_time_read_help);
6308 			return;
6309 		}
6310 	}
6311 
6312 	if ((n_tokens == 3) &&
6313 		(strcmp(tokens[0], "thread") == 0) &&
6314 		(strcmp(tokens[1], "pipeline") == 0)) {
6315 		if (strcmp(tokens[2], "enable") == 0) {
6316 			snprintf(out, out_size, "\n%s\n",
6317 				cmd_thread_pipeline_enable_help);
6318 			return;
6319 		}
6320 
6321 		if (strcmp(tokens[2], "disable") == 0) {
6322 			snprintf(out, out_size, "\n%s\n",
6323 				cmd_thread_pipeline_disable_help);
6324 			return;
6325 		}
6326 	}
6327 
6328 	snprintf(out, out_size, "Invalid command\n");
6329 }
6330 
6331 void
6332 cli_process(char *in, char *out, size_t out_size)
6333 {
6334 	char *tokens[CMD_MAX_TOKENS];
6335 	uint32_t n_tokens = RTE_DIM(tokens);
6336 	int status;
6337 
6338 	if (is_comment(in))
6339 		return;
6340 
6341 	status = parse_tokenize_string(in, tokens, &n_tokens);
6342 	if (status) {
6343 		snprintf(out, out_size, MSG_ARG_TOO_MANY, "");
6344 		return;
6345 	}
6346 
6347 	if (n_tokens == 0)
6348 		return;
6349 
6350 	if (strcmp(tokens[0], "help") == 0) {
6351 		cmd_help(tokens, n_tokens, out, out_size);
6352 		return;
6353 	}
6354 
6355 	if (strcmp(tokens[0], "mempool") == 0) {
6356 		cmd_mempool(tokens, n_tokens, out, out_size);
6357 		return;
6358 	}
6359 
6360 	if (strcmp(tokens[0], "link") == 0) {
6361 		if (strcmp(tokens[1], "show") == 0) {
6362 			cmd_link_show(tokens, n_tokens, out, out_size);
6363 			return;
6364 		}
6365 
6366 		cmd_link(tokens, n_tokens, out, out_size);
6367 		return;
6368 	}
6369 
6370 	if (strcmp(tokens[0], "swq") == 0) {
6371 		cmd_swq(tokens, n_tokens, out, out_size);
6372 		return;
6373 	}
6374 
6375 	if (strcmp(tokens[0], "tmgr") == 0) {
6376 		if ((n_tokens >= 3) &&
6377 			(strcmp(tokens[1], "subport") == 0) &&
6378 			(strcmp(tokens[2], "profile") == 0)) {
6379 			cmd_tmgr_subport_profile(tokens, n_tokens,
6380 				out, out_size);
6381 			return;
6382 		}
6383 
6384 		if ((n_tokens >= 3) &&
6385 			(strcmp(tokens[1], "pipe") == 0) &&
6386 			(strcmp(tokens[2], "profile") == 0)) {
6387 			cmd_tmgr_pipe_profile(tokens, n_tokens, out, out_size);
6388 			return;
6389 		}
6390 
6391 		if ((n_tokens >= 5) &&
6392 			(strcmp(tokens[2], "subport") == 0) &&
6393 			(strcmp(tokens[4], "profile") == 0)) {
6394 			cmd_tmgr_subport(tokens, n_tokens, out, out_size);
6395 			return;
6396 		}
6397 
6398 		if ((n_tokens >= 5) &&
6399 			(strcmp(tokens[2], "subport") == 0) &&
6400 			(strcmp(tokens[4], "pipe") == 0)) {
6401 			cmd_tmgr_subport_pipe(tokens, n_tokens, out, out_size);
6402 			return;
6403 		}
6404 
6405 		cmd_tmgr(tokens, n_tokens, out, out_size);
6406 		return;
6407 	}
6408 
6409 	if (strcmp(tokens[0], "tap") == 0) {
6410 		cmd_tap(tokens, n_tokens, out, out_size);
6411 		return;
6412 	}
6413 
6414 	if (strcmp(tokens[0], "kni") == 0) {
6415 		cmd_kni(tokens, n_tokens, out, out_size);
6416 		return;
6417 	}
6418 
6419 	if (strcmp(tokens[0], "cryptodev") == 0) {
6420 		cmd_cryptodev(tokens, n_tokens, out, out_size);
6421 		return;
6422 	}
6423 
6424 	if (strcmp(tokens[0], "port") == 0) {
6425 		cmd_port_in_action_profile(tokens, n_tokens, out, out_size);
6426 		return;
6427 	}
6428 
6429 	if (strcmp(tokens[0], "table") == 0) {
6430 		cmd_table_action_profile(tokens, n_tokens, out, out_size);
6431 		return;
6432 	}
6433 
6434 	if (strcmp(tokens[0], "pipeline") == 0) {
6435 		if ((n_tokens >= 3) &&
6436 			(strcmp(tokens[2], "period") == 0)) {
6437 			cmd_pipeline(tokens, n_tokens, out, out_size);
6438 			return;
6439 		}
6440 
6441 		if ((n_tokens >= 5) &&
6442 			(strcmp(tokens[2], "port") == 0) &&
6443 			(strcmp(tokens[3], "in") == 0) &&
6444 			(strcmp(tokens[4], "bsz") == 0)) {
6445 			cmd_pipeline_port_in(tokens, n_tokens, out, out_size);
6446 			return;
6447 		}
6448 
6449 		if ((n_tokens >= 5) &&
6450 			(strcmp(tokens[2], "port") == 0) &&
6451 			(strcmp(tokens[3], "out") == 0) &&
6452 			(strcmp(tokens[4], "bsz") == 0)) {
6453 			cmd_pipeline_port_out(tokens, n_tokens, out, out_size);
6454 			return;
6455 		}
6456 
6457 		if ((n_tokens >= 4) &&
6458 			(strcmp(tokens[2], "table") == 0) &&
6459 			(strcmp(tokens[3], "match") == 0)) {
6460 			cmd_pipeline_table(tokens, n_tokens, out, out_size);
6461 			return;
6462 		}
6463 
6464 		if ((n_tokens >= 6) &&
6465 			(strcmp(tokens[2], "port") == 0) &&
6466 			(strcmp(tokens[3], "in") == 0) &&
6467 			(strcmp(tokens[5], "table") == 0)) {
6468 			cmd_pipeline_port_in_table(tokens, n_tokens,
6469 				out, out_size);
6470 			return;
6471 		}
6472 
6473 		if ((n_tokens >= 6) &&
6474 			(strcmp(tokens[2], "port") == 0) &&
6475 			(strcmp(tokens[3], "in") == 0) &&
6476 			(strcmp(tokens[5], "stats") == 0)) {
6477 			cmd_pipeline_port_in_stats(tokens, n_tokens,
6478 				out, out_size);
6479 			return;
6480 		}
6481 
6482 		if ((n_tokens >= 6) &&
6483 			(strcmp(tokens[2], "port") == 0) &&
6484 			(strcmp(tokens[3], "in") == 0) &&
6485 			(strcmp(tokens[5], "enable") == 0)) {
6486 			cmd_pipeline_port_in_enable(tokens, n_tokens,
6487 				out, out_size);
6488 			return;
6489 		}
6490 
6491 		if ((n_tokens >= 6) &&
6492 			(strcmp(tokens[2], "port") == 0) &&
6493 			(strcmp(tokens[3], "in") == 0) &&
6494 			(strcmp(tokens[5], "disable") == 0)) {
6495 			cmd_pipeline_port_in_disable(tokens, n_tokens,
6496 				out, out_size);
6497 			return;
6498 		}
6499 
6500 		if ((n_tokens >= 6) &&
6501 			(strcmp(tokens[2], "port") == 0) &&
6502 			(strcmp(tokens[3], "out") == 0) &&
6503 			(strcmp(tokens[5], "stats") == 0)) {
6504 			cmd_pipeline_port_out_stats(tokens, n_tokens,
6505 				out, out_size);
6506 			return;
6507 		}
6508 
6509 		if ((n_tokens >= 5) &&
6510 			(strcmp(tokens[2], "table") == 0) &&
6511 			(strcmp(tokens[4], "stats") == 0)) {
6512 			cmd_pipeline_table_stats(tokens, n_tokens,
6513 				out, out_size);
6514 			return;
6515 		}
6516 
6517 		if ((n_tokens >= 7) &&
6518 			(strcmp(tokens[2], "table") == 0) &&
6519 			(strcmp(tokens[4], "rule") == 0) &&
6520 			(strcmp(tokens[5], "add") == 0) &&
6521 			(strcmp(tokens[6], "match") == 0)) {
6522 			if ((n_tokens >= 8) &&
6523 				(strcmp(tokens[7], "default") == 0)) {
6524 				cmd_pipeline_table_rule_add_default(tokens,
6525 					n_tokens, out, out_size);
6526 				return;
6527 			}
6528 
6529 			cmd_pipeline_table_rule_add(tokens, n_tokens,
6530 				out, out_size);
6531 			return;
6532 		}
6533 
6534 		if ((n_tokens >= 7) &&
6535 			(strcmp(tokens[2], "table") == 0) &&
6536 			(strcmp(tokens[4], "rule") == 0) &&
6537 			(strcmp(tokens[5], "add") == 0) &&
6538 			(strcmp(tokens[6], "bulk") == 0)) {
6539 			cmd_pipeline_table_rule_add_bulk(tokens,
6540 				n_tokens, out, out_size);
6541 			return;
6542 		}
6543 
6544 		if ((n_tokens >= 7) &&
6545 			(strcmp(tokens[2], "table") == 0) &&
6546 			(strcmp(tokens[4], "rule") == 0) &&
6547 			(strcmp(tokens[5], "delete") == 0) &&
6548 			(strcmp(tokens[6], "match") == 0)) {
6549 			if ((n_tokens >= 8) &&
6550 				(strcmp(tokens[7], "default") == 0)) {
6551 				cmd_pipeline_table_rule_delete_default(tokens,
6552 					n_tokens, out, out_size);
6553 				return;
6554 				}
6555 
6556 			cmd_pipeline_table_rule_delete(tokens, n_tokens,
6557 				out, out_size);
6558 			return;
6559 		}
6560 
6561 		if ((n_tokens >= 6) &&
6562 			(strcmp(tokens[2], "table") == 0) &&
6563 			(strcmp(tokens[4], "rule") == 0) &&
6564 			(strcmp(tokens[5], "show") == 0)) {
6565 			cmd_pipeline_table_rule_show(tokens, n_tokens,
6566 				out, out_size);
6567 			return;
6568 		}
6569 
6570 		if ((n_tokens >= 7) &&
6571 			(strcmp(tokens[2], "table") == 0) &&
6572 			(strcmp(tokens[4], "rule") == 0) &&
6573 			(strcmp(tokens[5], "read") == 0) &&
6574 			(strcmp(tokens[6], "stats") == 0)) {
6575 			cmd_pipeline_table_rule_stats_read(tokens, n_tokens,
6576 				out, out_size);
6577 			return;
6578 		}
6579 
6580 		if ((n_tokens >= 8) &&
6581 			(strcmp(tokens[2], "table") == 0) &&
6582 			(strcmp(tokens[4], "meter") == 0) &&
6583 			(strcmp(tokens[5], "profile") == 0) &&
6584 			(strcmp(tokens[7], "add") == 0)) {
6585 			cmd_pipeline_table_meter_profile_add(tokens, n_tokens,
6586 				out, out_size);
6587 			return;
6588 		}
6589 
6590 		if ((n_tokens >= 8) &&
6591 			(strcmp(tokens[2], "table") == 0) &&
6592 			(strcmp(tokens[4], "meter") == 0) &&
6593 			(strcmp(tokens[5], "profile") == 0) &&
6594 			(strcmp(tokens[7], "delete") == 0)) {
6595 			cmd_pipeline_table_meter_profile_delete(tokens,
6596 				n_tokens, out, out_size);
6597 			return;
6598 		}
6599 
6600 		if ((n_tokens >= 7) &&
6601 			(strcmp(tokens[2], "table") == 0) &&
6602 			(strcmp(tokens[4], "rule") == 0) &&
6603 			(strcmp(tokens[5], "read") == 0) &&
6604 			(strcmp(tokens[6], "meter") == 0)) {
6605 			cmd_pipeline_table_rule_meter_read(tokens, n_tokens,
6606 				out, out_size);
6607 			return;
6608 		}
6609 
6610 		if ((n_tokens >= 5) &&
6611 			(strcmp(tokens[2], "table") == 0) &&
6612 			(strcmp(tokens[4], "dscp") == 0)) {
6613 			cmd_pipeline_table_dscp(tokens, n_tokens,
6614 				out, out_size);
6615 			return;
6616 		}
6617 
6618 		if ((n_tokens >= 7) &&
6619 			(strcmp(tokens[2], "table") == 0) &&
6620 			(strcmp(tokens[4], "rule") == 0) &&
6621 			(strcmp(tokens[5], "read") == 0) &&
6622 			(strcmp(tokens[6], "ttl") == 0)) {
6623 			cmd_pipeline_table_rule_ttl_read(tokens, n_tokens,
6624 				out, out_size);
6625 			return;
6626 		}
6627 
6628 		if ((n_tokens >= 7) &&
6629 			(strcmp(tokens[2], "table") == 0) &&
6630 			(strcmp(tokens[4], "rule") == 0) &&
6631 			(strcmp(tokens[5], "read") == 0) &&
6632 			(strcmp(tokens[6], "time") == 0)) {
6633 			cmd_pipeline_table_rule_time_read(tokens, n_tokens,
6634 				out, out_size);
6635 			return;
6636 		}
6637 	}
6638 
6639 	if (strcmp(tokens[0], "thread") == 0) {
6640 		if ((n_tokens >= 5) &&
6641 			(strcmp(tokens[4], "enable") == 0)) {
6642 			cmd_thread_pipeline_enable(tokens, n_tokens,
6643 				out, out_size);
6644 			return;
6645 		}
6646 
6647 		if ((n_tokens >= 5) &&
6648 			(strcmp(tokens[4], "disable") == 0)) {
6649 			cmd_thread_pipeline_disable(tokens, n_tokens,
6650 				out, out_size);
6651 			return;
6652 		}
6653 	}
6654 
6655 	snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
6656 }
6657 
6658 int
6659 cli_script_process(const char *file_name,
6660 	size_t msg_in_len_max,
6661 	size_t msg_out_len_max)
6662 {
6663 	char *msg_in = NULL, *msg_out = NULL;
6664 	FILE *f = NULL;
6665 
6666 	/* Check input arguments */
6667 	if ((file_name == NULL) ||
6668 		(strlen(file_name) == 0) ||
6669 		(msg_in_len_max == 0) ||
6670 		(msg_out_len_max == 0))
6671 		return -EINVAL;
6672 
6673 	msg_in = malloc(msg_in_len_max + 1);
6674 	msg_out = malloc(msg_out_len_max + 1);
6675 	if ((msg_in == NULL) ||
6676 		(msg_out == NULL)) {
6677 		free(msg_out);
6678 		free(msg_in);
6679 		return -ENOMEM;
6680 	}
6681 
6682 	/* Open input file */
6683 	f = fopen(file_name, "r");
6684 	if (f == NULL) {
6685 		free(msg_out);
6686 		free(msg_in);
6687 		return -EIO;
6688 	}
6689 
6690 	/* Read file */
6691 	for ( ; ; ) {
6692 		if (fgets(msg_in, msg_in_len_max + 1, f) == NULL)
6693 			break;
6694 
6695 		printf("%s", msg_in);
6696 		msg_out[0] = 0;
6697 
6698 		cli_process(msg_in,
6699 			msg_out,
6700 			msg_out_len_max);
6701 
6702 		if (strlen(msg_out))
6703 			printf("%s", msg_out);
6704 	}
6705 
6706 	/* Close file */
6707 	fclose(f);
6708 	free(msg_out);
6709 	free(msg_in);
6710 	return 0;
6711 }
6712 
6713 static int
6714 cli_rule_file_process(const char *file_name,
6715 	size_t line_len_max,
6716 	struct table_rule_list **rule_list,
6717 	uint32_t *n_rules,
6718 	uint32_t *line_number,
6719 	char *out,
6720 	size_t out_size)
6721 {
6722 	struct table_rule_list *list = NULL;
6723 	char *line = NULL;
6724 	FILE *f = NULL;
6725 	uint32_t rule_id = 0, line_id = 0;
6726 	int status = 0;
6727 
6728 	/* Check input arguments */
6729 	if ((file_name == NULL) ||
6730 		(strlen(file_name) == 0) ||
6731 		(line_len_max == 0) ||
6732 		(rule_list == NULL) ||
6733 		(n_rules == NULL) ||
6734 		(line_number == NULL) ||
6735 		(out == NULL)) {
6736 		status = -EINVAL;
6737 		goto cli_rule_file_process_free;
6738 	}
6739 
6740 	/* Memory allocation */
6741 	list = malloc(sizeof(struct table_rule_list));
6742 	if (list == NULL) {
6743 		status = -ENOMEM;
6744 		goto cli_rule_file_process_free;
6745 	}
6746 
6747 	TAILQ_INIT(list);
6748 
6749 	line = malloc(line_len_max + 1);
6750 	if (line == NULL) {
6751 		status = -ENOMEM;
6752 		goto cli_rule_file_process_free;
6753 	}
6754 
6755 	/* Open file */
6756 	f = fopen(file_name, "r");
6757 	if (f == NULL) {
6758 		status = -EIO;
6759 		goto cli_rule_file_process_free;
6760 	}
6761 
6762 	/* Read file */
6763 	for (line_id = 1, rule_id = 0; ; line_id++) {
6764 		char *tokens[CMD_MAX_TOKENS];
6765 		struct table_rule *rule = NULL;
6766 		uint32_t n_tokens, n_tokens_parsed, t0;
6767 
6768 		/* Read next line from file. */
6769 		if (fgets(line, line_len_max + 1, f) == NULL)
6770 			break;
6771 
6772 		/* Comment. */
6773 		if (is_comment(line))
6774 			continue;
6775 
6776 		/* Parse line. */
6777 		n_tokens = RTE_DIM(tokens);
6778 		status = parse_tokenize_string(line, tokens, &n_tokens);
6779 		if (status) {
6780 			status = -EINVAL;
6781 			goto cli_rule_file_process_free;
6782 		}
6783 
6784 		/* Empty line. */
6785 		if (n_tokens == 0)
6786 			continue;
6787 		t0 = 0;
6788 
6789 		/* Rule alloc and insert. */
6790 		rule = calloc(1, sizeof(struct table_rule));
6791 		if (rule == NULL) {
6792 			status = -ENOMEM;
6793 			goto cli_rule_file_process_free;
6794 		}
6795 
6796 		TAILQ_INSERT_TAIL(list, rule, node);
6797 
6798 		/* Rule match. */
6799 		n_tokens_parsed = parse_match(tokens + t0,
6800 			n_tokens - t0,
6801 			out,
6802 			out_size,
6803 			&rule->match);
6804 		if (n_tokens_parsed == 0) {
6805 			status = -EINVAL;
6806 			goto cli_rule_file_process_free;
6807 		}
6808 		t0 += n_tokens_parsed;
6809 
6810 		/* Rule action. */
6811 		n_tokens_parsed = parse_table_action(tokens + t0,
6812 			n_tokens - t0,
6813 			out,
6814 			out_size,
6815 			&rule->action);
6816 		if (n_tokens_parsed == 0) {
6817 			status = -EINVAL;
6818 			goto cli_rule_file_process_free;
6819 		}
6820 		t0 += n_tokens_parsed;
6821 
6822 		/* Line completed. */
6823 		if (t0 < n_tokens) {
6824 			status = -EINVAL;
6825 			goto cli_rule_file_process_free;
6826 		}
6827 
6828 		/* Increment rule count */
6829 		rule_id++;
6830 	}
6831 
6832 	/* Close file */
6833 	fclose(f);
6834 
6835 	/* Memory free */
6836 	free(line);
6837 
6838 	*rule_list = list;
6839 	*n_rules = rule_id;
6840 	*line_number = line_id;
6841 	return 0;
6842 
6843 cli_rule_file_process_free:
6844 	*rule_list = NULL;
6845 	*n_rules = rule_id;
6846 	*line_number = line_id;
6847 
6848 	for ( ; ; ) {
6849 		struct table_rule *rule;
6850 
6851 		rule = TAILQ_FIRST(list);
6852 		if (rule == NULL)
6853 			break;
6854 
6855 		TAILQ_REMOVE(list, rule, node);
6856 		free(rule);
6857 	}
6858 
6859 	if (f)
6860 		fclose(f);
6861 	free(line);
6862 	free(list);
6863 
6864 	return status;
6865 }
6866