xref: /dpdk/examples/ip_pipeline/cli.c (revision 8bfe22acde19653bb325360bed171661daf855f5)
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 
4743 static const char cmd_pipeline_table_rule_stats_read_help[] =
4744 "pipeline <pipeline_name> table <table_id> rule read stats [clear]\n"
4745 "     match <match>\n";
4746 
4747 static void
4748 cmd_pipeline_table_rule_stats_read(char **tokens,
4749 	uint32_t n_tokens,
4750 	char *out,
4751 	size_t out_size)
4752 {
4753 	struct table_rule_match m;
4754 	struct rte_table_action_stats_counters stats;
4755 	char *pipeline_name;
4756 	uint32_t table_id, n_tokens_parsed;
4757 	int clear = 0, status;
4758 
4759 	if (n_tokens < 7) {
4760 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4761 		return;
4762 	}
4763 
4764 	pipeline_name = tokens[1];
4765 
4766 	if (strcmp(tokens[2], "table") != 0) {
4767 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
4768 		return;
4769 	}
4770 
4771 	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
4772 		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
4773 		return;
4774 	}
4775 
4776 	if (strcmp(tokens[4], "rule") != 0) {
4777 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
4778 		return;
4779 	}
4780 
4781 	if (strcmp(tokens[5], "read") != 0) {
4782 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read");
4783 		return;
4784 	}
4785 
4786 	if (strcmp(tokens[6], "stats") != 0) {
4787 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
4788 		return;
4789 	}
4790 
4791 	n_tokens -= 7;
4792 	tokens += 7;
4793 
4794 	/* clear */
4795 	if (n_tokens && (strcmp(tokens[0], "clear") == 0)) {
4796 		clear = 1;
4797 
4798 		n_tokens--;
4799 		tokens++;
4800 	}
4801 
4802 	/* match */
4803 	if ((n_tokens == 0) || strcmp(tokens[0], "match")) {
4804 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match");
4805 		return;
4806 	}
4807 
4808 	n_tokens_parsed = parse_match(tokens,
4809 		n_tokens,
4810 		out,
4811 		out_size,
4812 		&m);
4813 	if (n_tokens_parsed == 0)
4814 		return;
4815 	n_tokens -= n_tokens_parsed;
4816 	tokens += n_tokens_parsed;
4817 
4818 	/* end */
4819 	if (n_tokens) {
4820 		snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
4821 		return;
4822 	}
4823 
4824 	/* Read table rule stats. */
4825 	status = pipeline_table_rule_stats_read(pipeline_name,
4826 		table_id,
4827 		&m,
4828 		&stats,
4829 		clear);
4830 	if (status) {
4831 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
4832 		return;
4833 	}
4834 
4835 	/* Print stats. */
4836 	if (stats.n_packets_valid && stats.n_bytes_valid)
4837 		snprintf(out, out_size, "Packets: %" PRIu64 "; Bytes: %" PRIu64 "\n",
4838 			stats.n_packets,
4839 			stats.n_bytes);
4840 
4841 	if (stats.n_packets_valid && !stats.n_bytes_valid)
4842 		snprintf(out, out_size, "Packets: %" PRIu64 "; Bytes: N/A\n",
4843 			stats.n_packets);
4844 
4845 	if (!stats.n_packets_valid && stats.n_bytes_valid)
4846 		snprintf(out, out_size, "Packets: N/A; Bytes: %" PRIu64 "\n",
4847 			stats.n_bytes);
4848 
4849 	if (!stats.n_packets_valid && !stats.n_bytes_valid)
4850 		snprintf(out, out_size, "Packets: N/A ; Bytes: N/A\n");
4851 }
4852 
4853 static const char cmd_pipeline_table_meter_profile_add_help[] =
4854 "pipeline <pipeline_name> table <table_id> meter profile <meter_profile_id>\n"
4855 "   add srtcm cir <cir> cbs <cbs> ebs <ebs>\n"
4856 "   | trtcm cir <cir> pir <pir> cbs <cbs> pbs <pbs>\n";
4857 
4858 static void
4859 cmd_pipeline_table_meter_profile_add(char **tokens,
4860 	uint32_t n_tokens,
4861 	char *out,
4862 	size_t out_size)
4863 {
4864 	struct rte_table_action_meter_profile p;
4865 	char *pipeline_name;
4866 	uint32_t table_id, meter_profile_id;
4867 	int status;
4868 
4869 	if (n_tokens < 9) {
4870 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4871 		return;
4872 	}
4873 
4874 	pipeline_name = tokens[1];
4875 
4876 	if (strcmp(tokens[2], "table") != 0) {
4877 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
4878 		return;
4879 	}
4880 
4881 	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
4882 		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
4883 		return;
4884 	}
4885 
4886 	if (strcmp(tokens[4], "meter") != 0) {
4887 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
4888 		return;
4889 	}
4890 
4891 	if (strcmp(tokens[5], "profile") != 0) {
4892 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
4893 		return;
4894 	}
4895 
4896 	if (parser_read_uint32(&meter_profile_id, tokens[6]) != 0) {
4897 		snprintf(out, out_size, MSG_ARG_INVALID, "meter_profile_id");
4898 		return;
4899 	}
4900 
4901 	if (strcmp(tokens[7], "add") != 0) {
4902 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
4903 		return;
4904 	}
4905 
4906 	if (strcmp(tokens[8], "srtcm") == 0) {
4907 		if (n_tokens != 15) {
4908 			snprintf(out, out_size, MSG_ARG_MISMATCH,
4909 				tokens[0]);
4910 			return;
4911 		}
4912 
4913 		p.alg = RTE_TABLE_ACTION_METER_SRTCM;
4914 
4915 		if (strcmp(tokens[9], "cir") != 0) {
4916 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cir");
4917 			return;
4918 		}
4919 
4920 		if (parser_read_uint64(&p.srtcm.cir, tokens[10]) != 0) {
4921 			snprintf(out, out_size, MSG_ARG_INVALID, "cir");
4922 			return;
4923 		}
4924 
4925 		if (strcmp(tokens[11], "cbs") != 0) {
4926 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cbs");
4927 			return;
4928 		}
4929 
4930 		if (parser_read_uint64(&p.srtcm.cbs, tokens[12]) != 0) {
4931 			snprintf(out, out_size, MSG_ARG_INVALID, "cbs");
4932 			return;
4933 		}
4934 
4935 		if (strcmp(tokens[13], "ebs") != 0) {
4936 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "ebs");
4937 			return;
4938 		}
4939 
4940 		if (parser_read_uint64(&p.srtcm.ebs, tokens[14]) != 0) {
4941 			snprintf(out, out_size, MSG_ARG_INVALID, "ebs");
4942 			return;
4943 		}
4944 	} else if (strcmp(tokens[8], "trtcm") == 0) {
4945 		if (n_tokens != 17) {
4946 			snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4947 			return;
4948 		}
4949 
4950 		p.alg = RTE_TABLE_ACTION_METER_TRTCM;
4951 
4952 		if (strcmp(tokens[9], "cir") != 0) {
4953 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cir");
4954 			return;
4955 		}
4956 
4957 		if (parser_read_uint64(&p.trtcm.cir, tokens[10]) != 0) {
4958 			snprintf(out, out_size, MSG_ARG_INVALID, "cir");
4959 			return;
4960 		}
4961 
4962 		if (strcmp(tokens[11], "pir") != 0) {
4963 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pir");
4964 			return;
4965 		}
4966 
4967 		if (parser_read_uint64(&p.trtcm.pir, tokens[12]) != 0) {
4968 			snprintf(out, out_size, MSG_ARG_INVALID, "pir");
4969 			return;
4970 		}
4971 		if (strcmp(tokens[13], "cbs") != 0) {
4972 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cbs");
4973 			return;
4974 		}
4975 
4976 		if (parser_read_uint64(&p.trtcm.cbs, tokens[14]) != 0) {
4977 			snprintf(out, out_size, MSG_ARG_INVALID, "cbs");
4978 			return;
4979 		}
4980 
4981 		if (strcmp(tokens[15], "pbs") != 0) {
4982 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pbs");
4983 			return;
4984 		}
4985 
4986 		if (parser_read_uint64(&p.trtcm.pbs, tokens[16]) != 0) {
4987 			snprintf(out, out_size, MSG_ARG_INVALID, "pbs");
4988 			return;
4989 		}
4990 	} else {
4991 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
4992 		return;
4993 	}
4994 
4995 	status = pipeline_table_mtr_profile_add(pipeline_name,
4996 		table_id,
4997 		meter_profile_id,
4998 		&p);
4999 	if (status) {
5000 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
5001 		return;
5002 	}
5003 }
5004 
5005 
5006 static const char cmd_pipeline_table_meter_profile_delete_help[] =
5007 "pipeline <pipeline_name> table <table_id>\n"
5008 "   meter profile <meter_profile_id> delete\n";
5009 
5010 static void
5011 cmd_pipeline_table_meter_profile_delete(char **tokens,
5012 	uint32_t n_tokens,
5013 	char *out,
5014 	size_t out_size)
5015 {
5016 	char *pipeline_name;
5017 	uint32_t table_id, meter_profile_id;
5018 	int status;
5019 
5020 	if (n_tokens != 8) {
5021 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5022 		return;
5023 	}
5024 
5025 	pipeline_name = tokens[1];
5026 
5027 	if (strcmp(tokens[2], "table") != 0) {
5028 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
5029 		return;
5030 	}
5031 
5032 	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
5033 		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
5034 		return;
5035 	}
5036 
5037 	if (strcmp(tokens[4], "meter") != 0) {
5038 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
5039 		return;
5040 	}
5041 
5042 	if (strcmp(tokens[5], "profile") != 0) {
5043 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
5044 		return;
5045 	}
5046 
5047 	if (parser_read_uint32(&meter_profile_id, tokens[6]) != 0) {
5048 		snprintf(out, out_size, MSG_ARG_INVALID, "meter_profile_id");
5049 		return;
5050 	}
5051 
5052 	if (strcmp(tokens[7], "delete") != 0) {
5053 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete");
5054 		return;
5055 	}
5056 
5057 	status = pipeline_table_mtr_profile_delete(pipeline_name,
5058 		table_id,
5059 		meter_profile_id);
5060 	if (status) {
5061 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
5062 		return;
5063 	}
5064 }
5065 
5066 
5067 static const char cmd_pipeline_table_rule_meter_read_help[] =
5068 "pipeline <pipeline_name> table <table_id> rule read meter [clear]\n"
5069 "     match <match>\n";
5070 
5071 static void
5072 cmd_pipeline_table_rule_meter_read(char **tokens,
5073 	uint32_t n_tokens,
5074 	char *out,
5075 	size_t out_size)
5076 {
5077 	struct table_rule_match m;
5078 	struct rte_table_action_mtr_counters stats;
5079 	char *pipeline_name;
5080 	uint32_t table_id, n_tokens_parsed;
5081 	int clear = 0, status;
5082 
5083 	if (n_tokens < 7) {
5084 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5085 		return;
5086 	}
5087 
5088 	pipeline_name = tokens[1];
5089 
5090 	if (strcmp(tokens[2], "table") != 0) {
5091 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
5092 		return;
5093 	}
5094 
5095 	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
5096 		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
5097 		return;
5098 	}
5099 
5100 	if (strcmp(tokens[4], "rule") != 0) {
5101 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
5102 		return;
5103 	}
5104 
5105 	if (strcmp(tokens[5], "read") != 0) {
5106 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read");
5107 		return;
5108 	}
5109 
5110 	if (strcmp(tokens[6], "meter") != 0) {
5111 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
5112 		return;
5113 	}
5114 
5115 	n_tokens -= 7;
5116 	tokens += 7;
5117 
5118 	/* clear */
5119 	if (n_tokens && (strcmp(tokens[0], "clear") == 0)) {
5120 		clear = 1;
5121 
5122 		n_tokens--;
5123 		tokens++;
5124 	}
5125 
5126 	/* match */
5127 	if ((n_tokens == 0) || strcmp(tokens[0], "match")) {
5128 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match");
5129 		return;
5130 	}
5131 
5132 	n_tokens_parsed = parse_match(tokens,
5133 		n_tokens,
5134 		out,
5135 		out_size,
5136 		&m);
5137 	if (n_tokens_parsed == 0)
5138 		return;
5139 	n_tokens -= n_tokens_parsed;
5140 	tokens += n_tokens_parsed;
5141 
5142 	/* end */
5143 	if (n_tokens) {
5144 		snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
5145 		return;
5146 	}
5147 
5148 	/* Read table rule meter stats. */
5149 	status = pipeline_table_rule_mtr_read(pipeline_name,
5150 		table_id,
5151 		&m,
5152 		&stats,
5153 		clear);
5154 	if (status) {
5155 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
5156 		return;
5157 	}
5158 
5159 	/* Print stats. */
5160 }
5161 
5162 
5163 static const char cmd_pipeline_table_dscp_help[] =
5164 "pipeline <pipeline_name> table <table_id> dscp <file_name>\n"
5165 "\n"
5166 " File <file_name>:\n"
5167 "   - exactly 64 lines\n"
5168 "   - line format: <tc_id> <tc_queue_id> <color>, with <color> as: g | y | r\n";
5169 
5170 static int
5171 load_dscp_table(struct rte_table_action_dscp_table *dscp_table,
5172 	const char *file_name,
5173 	uint32_t *line_number)
5174 {
5175 	FILE *f = NULL;
5176 	uint32_t dscp, l;
5177 
5178 	/* Check input arguments */
5179 	if ((dscp_table == NULL) ||
5180 		(file_name == NULL) ||
5181 		(line_number == NULL)) {
5182 		if (line_number)
5183 			*line_number = 0;
5184 		return -EINVAL;
5185 	}
5186 
5187 	/* Open input file */
5188 	f = fopen(file_name, "r");
5189 	if (f == NULL) {
5190 		*line_number = 0;
5191 		return -EINVAL;
5192 	}
5193 
5194 	/* Read file */
5195 	for (dscp = 0, l = 1; ; l++) {
5196 		char line[64];
5197 		char *tokens[3];
5198 		enum rte_meter_color color;
5199 		uint32_t tc_id, tc_queue_id, n_tokens = RTE_DIM(tokens);
5200 
5201 		if (fgets(line, sizeof(line), f) == NULL)
5202 			break;
5203 
5204 		if (is_comment(line))
5205 			continue;
5206 
5207 		if (parse_tokenize_string(line, tokens, &n_tokens)) {
5208 			*line_number = l;
5209 			fclose(f);
5210 			return -EINVAL;
5211 		}
5212 
5213 		if (n_tokens == 0)
5214 			continue;
5215 
5216 		if ((dscp >= RTE_DIM(dscp_table->entry)) ||
5217 			(n_tokens != RTE_DIM(tokens)) ||
5218 			parser_read_uint32(&tc_id, tokens[0]) ||
5219 			(tc_id >= RTE_TABLE_ACTION_TC_MAX) ||
5220 			parser_read_uint32(&tc_queue_id, tokens[1]) ||
5221 			(tc_queue_id >= RTE_TABLE_ACTION_TC_QUEUE_MAX) ||
5222 			(strlen(tokens[2]) != 1)) {
5223 			*line_number = l;
5224 			fclose(f);
5225 			return -EINVAL;
5226 		}
5227 
5228 		switch (tokens[2][0]) {
5229 		case 'g':
5230 		case 'G':
5231 			color = e_RTE_METER_GREEN;
5232 			break;
5233 
5234 		case 'y':
5235 		case 'Y':
5236 			color = e_RTE_METER_YELLOW;
5237 			break;
5238 
5239 		case 'r':
5240 		case 'R':
5241 			color = e_RTE_METER_RED;
5242 			break;
5243 
5244 		default:
5245 			*line_number = l;
5246 			fclose(f);
5247 			return -EINVAL;
5248 		}
5249 
5250 		dscp_table->entry[dscp].tc_id = tc_id;
5251 		dscp_table->entry[dscp].tc_queue_id = tc_queue_id;
5252 		dscp_table->entry[dscp].color = color;
5253 		dscp++;
5254 	}
5255 
5256 	/* Close file */
5257 	fclose(f);
5258 	return 0;
5259 }
5260 
5261 static void
5262 cmd_pipeline_table_dscp(char **tokens,
5263 	uint32_t n_tokens,
5264 	char *out,
5265 	size_t out_size)
5266 {
5267 	struct rte_table_action_dscp_table dscp_table;
5268 	char *pipeline_name, *file_name;
5269 	uint32_t table_id, line_number;
5270 	int status;
5271 
5272 	if (n_tokens != 6) {
5273 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5274 		return;
5275 	}
5276 
5277 	pipeline_name = tokens[1];
5278 
5279 	if (strcmp(tokens[2], "table") != 0) {
5280 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
5281 		return;
5282 	}
5283 
5284 	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
5285 		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
5286 		return;
5287 	}
5288 
5289 	if (strcmp(tokens[4], "dscp") != 0) {
5290 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "dscp");
5291 		return;
5292 	}
5293 
5294 	file_name = tokens[5];
5295 
5296 	status = load_dscp_table(&dscp_table, file_name, &line_number);
5297 	if (status) {
5298 		snprintf(out, out_size, MSG_FILE_ERR, file_name, line_number);
5299 		return;
5300 	}
5301 
5302 	status = pipeline_table_dscp_table_update(pipeline_name,
5303 		table_id,
5304 		UINT64_MAX,
5305 		&dscp_table);
5306 	if (status) {
5307 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
5308 		return;
5309 	}
5310 }
5311 
5312 
5313 static const char cmd_pipeline_table_rule_ttl_read_help[] =
5314 "pipeline <pipeline_name> table <table_id> rule read ttl [clear]\n"
5315 "     match <match>\n";
5316 
5317 static void
5318 cmd_pipeline_table_rule_ttl_read(char **tokens,
5319 	uint32_t n_tokens,
5320 	char *out,
5321 	size_t out_size)
5322 {
5323 	struct table_rule_match m;
5324 	struct rte_table_action_ttl_counters stats;
5325 	char *pipeline_name;
5326 	uint32_t table_id, n_tokens_parsed;
5327 	int clear = 0, status;
5328 
5329 	if (n_tokens < 7) {
5330 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5331 		return;
5332 	}
5333 
5334 	pipeline_name = tokens[1];
5335 
5336 	if (strcmp(tokens[2], "table") != 0) {
5337 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
5338 		return;
5339 	}
5340 
5341 	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
5342 		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
5343 		return;
5344 	}
5345 
5346 	if (strcmp(tokens[4], "rule") != 0) {
5347 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
5348 		return;
5349 	}
5350 
5351 	if (strcmp(tokens[5], "read") != 0) {
5352 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read");
5353 		return;
5354 	}
5355 
5356 	if (strcmp(tokens[6], "ttl") != 0) {
5357 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "ttl");
5358 		return;
5359 	}
5360 
5361 	n_tokens -= 7;
5362 	tokens += 7;
5363 
5364 	/* clear */
5365 	if (n_tokens && (strcmp(tokens[0], "clear") == 0)) {
5366 		clear = 1;
5367 
5368 		n_tokens--;
5369 		tokens++;
5370 	}
5371 
5372 	/* match */
5373 	if ((n_tokens == 0) || strcmp(tokens[0], "match")) {
5374 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match");
5375 		return;
5376 	}
5377 
5378 	n_tokens_parsed = parse_match(tokens,
5379 		n_tokens,
5380 		out,
5381 		out_size,
5382 		&m);
5383 	if (n_tokens_parsed == 0)
5384 		return;
5385 	n_tokens -= n_tokens_parsed;
5386 	tokens += n_tokens_parsed;
5387 
5388 	/* end */
5389 	if (n_tokens) {
5390 		snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
5391 		return;
5392 	}
5393 
5394 	/* Read table rule TTL stats. */
5395 	status = pipeline_table_rule_ttl_read(pipeline_name,
5396 		table_id,
5397 		&m,
5398 		&stats,
5399 		clear);
5400 	if (status) {
5401 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
5402 		return;
5403 	}
5404 
5405 	/* Print stats. */
5406 	snprintf(out, out_size, "Packets: %" PRIu64 "\n",
5407 		stats.n_packets);
5408 }
5409 
5410 
5411 static const char cmd_thread_pipeline_enable_help[] =
5412 "thread <thread_id> pipeline <pipeline_name> enable\n";
5413 
5414 static void
5415 cmd_thread_pipeline_enable(char **tokens,
5416 	uint32_t n_tokens,
5417 	char *out,
5418 	size_t out_size)
5419 {
5420 	char *pipeline_name;
5421 	uint32_t thread_id;
5422 	int status;
5423 
5424 	if (n_tokens != 5) {
5425 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5426 		return;
5427 	}
5428 
5429 	if (parser_read_uint32(&thread_id, tokens[1]) != 0) {
5430 		snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
5431 		return;
5432 	}
5433 
5434 	if (strcmp(tokens[2], "pipeline") != 0) {
5435 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
5436 		return;
5437 	}
5438 
5439 	pipeline_name = tokens[3];
5440 
5441 	if (strcmp(tokens[4], "enable") != 0) {
5442 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable");
5443 		return;
5444 	}
5445 
5446 	status = thread_pipeline_enable(thread_id, pipeline_name);
5447 	if (status) {
5448 		snprintf(out, out_size, MSG_CMD_FAIL, "thread pipeline enable");
5449 		return;
5450 	}
5451 }
5452 
5453 
5454 static const char cmd_thread_pipeline_disable_help[] =
5455 "thread <thread_id> pipeline <pipeline_name> disable\n";
5456 
5457 static void
5458 cmd_thread_pipeline_disable(char **tokens,
5459 	uint32_t n_tokens,
5460 	char *out,
5461 	size_t out_size)
5462 {
5463 	char *pipeline_name;
5464 	uint32_t thread_id;
5465 	int status;
5466 
5467 	if (n_tokens != 5) {
5468 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5469 		return;
5470 	}
5471 
5472 	if (parser_read_uint32(&thread_id, tokens[1]) != 0) {
5473 		snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
5474 		return;
5475 	}
5476 
5477 	if (strcmp(tokens[2], "pipeline") != 0) {
5478 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
5479 		return;
5480 	}
5481 
5482 	pipeline_name = tokens[3];
5483 
5484 	if (strcmp(tokens[4], "disable") != 0) {
5485 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable");
5486 		return;
5487 	}
5488 
5489 	status = thread_pipeline_disable(thread_id, pipeline_name);
5490 	if (status) {
5491 		snprintf(out, out_size, MSG_CMD_FAIL,
5492 			"thread pipeline disable");
5493 		return;
5494 	}
5495 }
5496 
5497 static void
5498 cmd_help(char **tokens, uint32_t n_tokens, char *out, size_t out_size)
5499 {
5500 	tokens++;
5501 	n_tokens--;
5502 
5503 	if (n_tokens == 0) {
5504 		snprintf(out, out_size,
5505 			"Type 'help <command>' for details on each command.\n\n"
5506 			"List of commands:\n"
5507 			"\tmempool\n"
5508 			"\tlink\n"
5509 			"\tswq\n"
5510 			"\ttmgr subport profile\n"
5511 			"\ttmgr pipe profile\n"
5512 			"\ttmgr\n"
5513 			"\ttmgr subport\n"
5514 			"\ttmgr subport pipe\n"
5515 			"\ttap\n"
5516 			"\tkni\n"
5517 			"\tport in action profile\n"
5518 			"\ttable action profile\n"
5519 			"\tpipeline\n"
5520 			"\tpipeline port in\n"
5521 			"\tpipeline port out\n"
5522 			"\tpipeline table\n"
5523 			"\tpipeline port in table\n"
5524 			"\tpipeline port in stats\n"
5525 			"\tpipeline port in enable\n"
5526 			"\tpipeline port in disable\n"
5527 			"\tpipeline port out stats\n"
5528 			"\tpipeline table stats\n"
5529 			"\tpipeline table rule add\n"
5530 			"\tpipeline table rule add default\n"
5531 			"\tpipeline table rule add bulk\n"
5532 			"\tpipeline table rule delete\n"
5533 			"\tpipeline table rule delete default\n"
5534 			"\tpipeline table rule stats read\n"
5535 			"\tpipeline table meter profile add\n"
5536 			"\tpipeline table meter profile delete\n"
5537 			"\tpipeline table rule meter read\n"
5538 			"\tpipeline table dscp\n"
5539 			"\tpipeline table rule ttl read\n"
5540 			"\tthread pipeline enable\n"
5541 			"\tthread pipeline disable\n\n");
5542 		return;
5543 	}
5544 
5545 	if (strcmp(tokens[0], "mempool") == 0) {
5546 		snprintf(out, out_size, "\n%s\n", cmd_mempool_help);
5547 		return;
5548 	}
5549 
5550 	if (strcmp(tokens[0], "link") == 0) {
5551 		snprintf(out, out_size, "\n%s\n", cmd_link_help);
5552 		return;
5553 	}
5554 
5555 	if (strcmp(tokens[0], "swq") == 0) {
5556 		snprintf(out, out_size, "\n%s\n", cmd_swq_help);
5557 		return;
5558 	}
5559 
5560 	if (strcmp(tokens[0], "tmgr") == 0) {
5561 		if (n_tokens == 1) {
5562 			snprintf(out, out_size, "\n%s\n", cmd_tmgr_help);
5563 			return;
5564 		}
5565 
5566 		if ((n_tokens == 2) &&
5567 			(strcmp(tokens[1], "subport")) == 0) {
5568 			snprintf(out, out_size, "\n%s\n", cmd_tmgr_subport_help);
5569 			return;
5570 		}
5571 
5572 		if ((n_tokens == 3) &&
5573 			(strcmp(tokens[1], "subport") == 0) &&
5574 			(strcmp(tokens[2], "profile") == 0)) {
5575 			snprintf(out, out_size, "\n%s\n",
5576 				cmd_tmgr_subport_profile_help);
5577 			return;
5578 		}
5579 
5580 		if ((n_tokens == 3) &&
5581 			(strcmp(tokens[1], "subport") == 0) &&
5582 			(strcmp(tokens[2], "pipe") == 0)) {
5583 			snprintf(out, out_size, "\n%s\n", cmd_tmgr_subport_pipe_help);
5584 			return;
5585 		}
5586 
5587 		if ((n_tokens == 3) &&
5588 			(strcmp(tokens[1], "pipe") == 0) &&
5589 			(strcmp(tokens[2], "profile") == 0)) {
5590 			snprintf(out, out_size, "\n%s\n", cmd_tmgr_pipe_profile_help);
5591 			return;
5592 		}
5593 	}
5594 
5595 	if (strcmp(tokens[0], "tap") == 0) {
5596 		snprintf(out, out_size, "\n%s\n", cmd_tap_help);
5597 		return;
5598 	}
5599 
5600 	if (strcmp(tokens[0], "kni") == 0) {
5601 		snprintf(out, out_size, "\n%s\n", cmd_kni_help);
5602 		return;
5603 	}
5604 
5605 	if (strcmp(tokens[0], "cryptodev") == 0) {
5606 		snprintf(out, out_size, "\n%s\n", cmd_cryptodev_help);
5607 		return;
5608 	}
5609 
5610 	if ((n_tokens == 4) &&
5611 		(strcmp(tokens[0], "port") == 0) &&
5612 		(strcmp(tokens[1], "in") == 0) &&
5613 		(strcmp(tokens[2], "action") == 0) &&
5614 		(strcmp(tokens[3], "profile") == 0)) {
5615 		snprintf(out, out_size, "\n%s\n", cmd_port_in_action_profile_help);
5616 		return;
5617 	}
5618 
5619 	if ((n_tokens == 3) &&
5620 		(strcmp(tokens[0], "table") == 0) &&
5621 		(strcmp(tokens[1], "action") == 0) &&
5622 		(strcmp(tokens[2], "profile") == 0)) {
5623 		snprintf(out, out_size, "\n%s\n", cmd_table_action_profile_help);
5624 		return;
5625 	}
5626 
5627 	if ((strcmp(tokens[0], "pipeline") == 0) && (n_tokens == 1)) {
5628 		snprintf(out, out_size, "\n%s\n", cmd_pipeline_help);
5629 		return;
5630 	}
5631 
5632 	if ((strcmp(tokens[0], "pipeline") == 0) &&
5633 		(strcmp(tokens[1], "port") == 0)) {
5634 		if ((n_tokens == 3) && (strcmp(tokens[2], "in")) == 0) {
5635 			snprintf(out, out_size, "\n%s\n", cmd_pipeline_port_in_help);
5636 			return;
5637 		}
5638 
5639 		if ((n_tokens == 3) && (strcmp(tokens[2], "out")) == 0) {
5640 			snprintf(out, out_size, "\n%s\n", cmd_pipeline_port_out_help);
5641 			return;
5642 		}
5643 
5644 		if ((n_tokens == 4) &&
5645 			(strcmp(tokens[2], "in") == 0) &&
5646 			(strcmp(tokens[3], "table") == 0)) {
5647 			snprintf(out, out_size, "\n%s\n",
5648 				cmd_pipeline_port_in_table_help);
5649 			return;
5650 		}
5651 
5652 		if ((n_tokens == 4) &&
5653 			(strcmp(tokens[2], "in") == 0) &&
5654 			(strcmp(tokens[3], "stats") == 0)) {
5655 			snprintf(out, out_size, "\n%s\n",
5656 				cmd_pipeline_port_in_stats_help);
5657 			return;
5658 		}
5659 
5660 		if ((n_tokens == 4) &&
5661 			(strcmp(tokens[2], "in") == 0) &&
5662 			(strcmp(tokens[3], "enable") == 0)) {
5663 			snprintf(out, out_size, "\n%s\n",
5664 				cmd_pipeline_port_in_enable_help);
5665 			return;
5666 		}
5667 
5668 		if ((n_tokens == 4) &&
5669 			(strcmp(tokens[2], "in") == 0) &&
5670 			(strcmp(tokens[3], "disable") == 0)) {
5671 			snprintf(out, out_size, "\n%s\n",
5672 				cmd_pipeline_port_in_disable_help);
5673 			return;
5674 		}
5675 
5676 		if ((n_tokens == 4) &&
5677 			(strcmp(tokens[2], "out") == 0) &&
5678 			(strcmp(tokens[3], "stats") == 0)) {
5679 			snprintf(out, out_size, "\n%s\n",
5680 				cmd_pipeline_port_out_stats_help);
5681 			return;
5682 		}
5683 	}
5684 
5685 	if ((strcmp(tokens[0], "pipeline") == 0) &&
5686 		(strcmp(tokens[1], "table") == 0)) {
5687 		if (n_tokens == 2) {
5688 			snprintf(out, out_size, "\n%s\n", cmd_pipeline_table_help);
5689 			return;
5690 		}
5691 
5692 		if ((n_tokens == 3) && strcmp(tokens[2], "stats") == 0) {
5693 			snprintf(out, out_size, "\n%s\n",
5694 				cmd_pipeline_table_stats_help);
5695 			return;
5696 		}
5697 
5698 		if ((n_tokens == 3) && strcmp(tokens[2], "dscp") == 0) {
5699 			snprintf(out, out_size, "\n%s\n",
5700 				cmd_pipeline_table_dscp_help);
5701 			return;
5702 		}
5703 
5704 		if ((n_tokens == 4) &&
5705 			(strcmp(tokens[2], "rule") == 0) &&
5706 			(strcmp(tokens[3], "add") == 0)) {
5707 			snprintf(out, out_size, "\n%s\n",
5708 				cmd_pipeline_table_rule_add_help);
5709 			return;
5710 		}
5711 
5712 		if ((n_tokens == 5) &&
5713 			(strcmp(tokens[2], "rule") == 0) &&
5714 			(strcmp(tokens[3], "add") == 0) &&
5715 			(strcmp(tokens[4], "default") == 0)) {
5716 			snprintf(out, out_size, "\n%s\n",
5717 				cmd_pipeline_table_rule_add_default_help);
5718 			return;
5719 		}
5720 
5721 		if ((n_tokens == 5) &&
5722 			(strcmp(tokens[2], "rule") == 0) &&
5723 			(strcmp(tokens[3], "add") == 0) &&
5724 			(strcmp(tokens[4], "bulk") == 0)) {
5725 			snprintf(out, out_size, "\n%s\n",
5726 				cmd_pipeline_table_rule_add_bulk_help);
5727 			return;
5728 		}
5729 
5730 		if ((n_tokens == 4) &&
5731 			(strcmp(tokens[2], "rule") == 0) &&
5732 			(strcmp(tokens[3], "delete") == 0)) {
5733 			snprintf(out, out_size, "\n%s\n",
5734 				cmd_pipeline_table_rule_delete_help);
5735 			return;
5736 		}
5737 
5738 		if ((n_tokens == 5) &&
5739 			(strcmp(tokens[2], "rule") == 0) &&
5740 			(strcmp(tokens[3], "delete") == 0) &&
5741 			(strcmp(tokens[4], "default") == 0)) {
5742 			snprintf(out, out_size, "\n%s\n",
5743 				cmd_pipeline_table_rule_delete_default_help);
5744 			return;
5745 		}
5746 
5747 		if ((n_tokens == 5) &&
5748 			(strcmp(tokens[2], "rule") == 0) &&
5749 			(strcmp(tokens[3], "stats") == 0) &&
5750 			(strcmp(tokens[4], "read") == 0)) {
5751 			snprintf(out, out_size, "\n%s\n",
5752 				cmd_pipeline_table_rule_stats_read_help);
5753 			return;
5754 		}
5755 
5756 		if ((n_tokens == 5) &&
5757 			(strcmp(tokens[2], "meter") == 0) &&
5758 			(strcmp(tokens[3], "profile") == 0) &&
5759 			(strcmp(tokens[4], "add") == 0)) {
5760 			snprintf(out, out_size, "\n%s\n",
5761 				cmd_pipeline_table_meter_profile_add_help);
5762 			return;
5763 		}
5764 
5765 		if ((n_tokens == 5) &&
5766 			(strcmp(tokens[2], "meter") == 0) &&
5767 			(strcmp(tokens[3], "profile") == 0) &&
5768 			(strcmp(tokens[4], "delete") == 0)) {
5769 			snprintf(out, out_size, "\n%s\n",
5770 				cmd_pipeline_table_meter_profile_delete_help);
5771 			return;
5772 		}
5773 
5774 		if ((n_tokens == 5) &&
5775 			(strcmp(tokens[2], "rule") == 0) &&
5776 			(strcmp(tokens[3], "meter") == 0) &&
5777 			(strcmp(tokens[4], "read") == 0)) {
5778 			snprintf(out, out_size, "\n%s\n",
5779 				cmd_pipeline_table_rule_meter_read_help);
5780 			return;
5781 		}
5782 
5783 		if ((n_tokens == 5) &&
5784 			(strcmp(tokens[2], "rule") == 0) &&
5785 			(strcmp(tokens[3], "ttl") == 0) &&
5786 			(strcmp(tokens[4], "read") == 0)) {
5787 			snprintf(out, out_size, "\n%s\n",
5788 				cmd_pipeline_table_rule_ttl_read_help);
5789 			return;
5790 		}
5791 	}
5792 
5793 	if ((n_tokens == 3) &&
5794 		(strcmp(tokens[0], "thread") == 0) &&
5795 		(strcmp(tokens[1], "pipeline") == 0)) {
5796 		if (strcmp(tokens[2], "enable") == 0) {
5797 			snprintf(out, out_size, "\n%s\n",
5798 				cmd_thread_pipeline_enable_help);
5799 			return;
5800 		}
5801 
5802 		if (strcmp(tokens[2], "disable") == 0) {
5803 			snprintf(out, out_size, "\n%s\n",
5804 				cmd_thread_pipeline_disable_help);
5805 			return;
5806 		}
5807 	}
5808 
5809 	snprintf(out, out_size, "Invalid command\n");
5810 }
5811 
5812 void
5813 cli_process(char *in, char *out, size_t out_size)
5814 {
5815 	char *tokens[CMD_MAX_TOKENS];
5816 	uint32_t n_tokens = RTE_DIM(tokens);
5817 	int status;
5818 
5819 	if (is_comment(in))
5820 		return;
5821 
5822 	status = parse_tokenize_string(in, tokens, &n_tokens);
5823 	if (status) {
5824 		snprintf(out, out_size, MSG_ARG_TOO_MANY, "");
5825 		return;
5826 	}
5827 
5828 	if (n_tokens == 0)
5829 		return;
5830 
5831 	if (strcmp(tokens[0], "help") == 0) {
5832 		cmd_help(tokens, n_tokens, out, out_size);
5833 		return;
5834 	}
5835 
5836 	if (strcmp(tokens[0], "mempool") == 0) {
5837 		cmd_mempool(tokens, n_tokens, out, out_size);
5838 		return;
5839 	}
5840 
5841 	if (strcmp(tokens[0], "link") == 0) {
5842 		if (strcmp(tokens[1], "show") == 0) {
5843 			cmd_link_show(tokens, n_tokens, out, out_size);
5844 			return;
5845 		}
5846 
5847 		cmd_link(tokens, n_tokens, out, out_size);
5848 		return;
5849 	}
5850 
5851 	if (strcmp(tokens[0], "swq") == 0) {
5852 		cmd_swq(tokens, n_tokens, out, out_size);
5853 		return;
5854 	}
5855 
5856 	if (strcmp(tokens[0], "tmgr") == 0) {
5857 		if ((n_tokens >= 3) &&
5858 			(strcmp(tokens[1], "subport") == 0) &&
5859 			(strcmp(tokens[2], "profile") == 0)) {
5860 			cmd_tmgr_subport_profile(tokens, n_tokens,
5861 				out, out_size);
5862 			return;
5863 		}
5864 
5865 		if ((n_tokens >= 3) &&
5866 			(strcmp(tokens[1], "pipe") == 0) &&
5867 			(strcmp(tokens[2], "profile") == 0)) {
5868 			cmd_tmgr_pipe_profile(tokens, n_tokens, out, out_size);
5869 			return;
5870 		}
5871 
5872 		if ((n_tokens >= 5) &&
5873 			(strcmp(tokens[2], "subport") == 0) &&
5874 			(strcmp(tokens[4], "profile") == 0)) {
5875 			cmd_tmgr_subport(tokens, n_tokens, out, out_size);
5876 			return;
5877 		}
5878 
5879 		if ((n_tokens >= 5) &&
5880 			(strcmp(tokens[2], "subport") == 0) &&
5881 			(strcmp(tokens[4], "pipe") == 0)) {
5882 			cmd_tmgr_subport_pipe(tokens, n_tokens, out, out_size);
5883 			return;
5884 		}
5885 
5886 		cmd_tmgr(tokens, n_tokens, out, out_size);
5887 		return;
5888 	}
5889 
5890 	if (strcmp(tokens[0], "tap") == 0) {
5891 		cmd_tap(tokens, n_tokens, out, out_size);
5892 		return;
5893 	}
5894 
5895 	if (strcmp(tokens[0], "kni") == 0) {
5896 		cmd_kni(tokens, n_tokens, out, out_size);
5897 		return;
5898 	}
5899 
5900 	if (strcmp(tokens[0], "cryptodev") == 0) {
5901 		cmd_cryptodev(tokens, n_tokens, out, out_size);
5902 		return;
5903 	}
5904 
5905 	if (strcmp(tokens[0], "port") == 0) {
5906 		cmd_port_in_action_profile(tokens, n_tokens, out, out_size);
5907 		return;
5908 	}
5909 
5910 	if (strcmp(tokens[0], "table") == 0) {
5911 		cmd_table_action_profile(tokens, n_tokens, out, out_size);
5912 		return;
5913 	}
5914 
5915 	if (strcmp(tokens[0], "pipeline") == 0) {
5916 		if ((n_tokens >= 3) &&
5917 			(strcmp(tokens[2], "period") == 0)) {
5918 			cmd_pipeline(tokens, n_tokens, out, out_size);
5919 			return;
5920 		}
5921 
5922 		if ((n_tokens >= 5) &&
5923 			(strcmp(tokens[2], "port") == 0) &&
5924 			(strcmp(tokens[3], "in") == 0) &&
5925 			(strcmp(tokens[4], "bsz") == 0)) {
5926 			cmd_pipeline_port_in(tokens, n_tokens, out, out_size);
5927 			return;
5928 		}
5929 
5930 		if ((n_tokens >= 5) &&
5931 			(strcmp(tokens[2], "port") == 0) &&
5932 			(strcmp(tokens[3], "out") == 0) &&
5933 			(strcmp(tokens[4], "bsz") == 0)) {
5934 			cmd_pipeline_port_out(tokens, n_tokens, out, out_size);
5935 			return;
5936 		}
5937 
5938 		if ((n_tokens >= 4) &&
5939 			(strcmp(tokens[2], "table") == 0) &&
5940 			(strcmp(tokens[3], "match") == 0)) {
5941 			cmd_pipeline_table(tokens, n_tokens, out, out_size);
5942 			return;
5943 		}
5944 
5945 		if ((n_tokens >= 6) &&
5946 			(strcmp(tokens[2], "port") == 0) &&
5947 			(strcmp(tokens[3], "in") == 0) &&
5948 			(strcmp(tokens[5], "table") == 0)) {
5949 			cmd_pipeline_port_in_table(tokens, n_tokens,
5950 				out, out_size);
5951 			return;
5952 		}
5953 
5954 		if ((n_tokens >= 6) &&
5955 			(strcmp(tokens[2], "port") == 0) &&
5956 			(strcmp(tokens[3], "in") == 0) &&
5957 			(strcmp(tokens[5], "stats") == 0)) {
5958 			cmd_pipeline_port_in_stats(tokens, n_tokens,
5959 				out, out_size);
5960 			return;
5961 		}
5962 
5963 		if ((n_tokens >= 6) &&
5964 			(strcmp(tokens[2], "port") == 0) &&
5965 			(strcmp(tokens[3], "in") == 0) &&
5966 			(strcmp(tokens[5], "enable") == 0)) {
5967 			cmd_pipeline_port_in_enable(tokens, n_tokens,
5968 				out, out_size);
5969 			return;
5970 		}
5971 
5972 		if ((n_tokens >= 6) &&
5973 			(strcmp(tokens[2], "port") == 0) &&
5974 			(strcmp(tokens[3], "in") == 0) &&
5975 			(strcmp(tokens[5], "disable") == 0)) {
5976 			cmd_pipeline_port_in_disable(tokens, n_tokens,
5977 				out, out_size);
5978 			return;
5979 		}
5980 
5981 		if ((n_tokens >= 6) &&
5982 			(strcmp(tokens[2], "port") == 0) &&
5983 			(strcmp(tokens[3], "out") == 0) &&
5984 			(strcmp(tokens[5], "stats") == 0)) {
5985 			cmd_pipeline_port_out_stats(tokens, n_tokens,
5986 				out, out_size);
5987 			return;
5988 		}
5989 
5990 		if ((n_tokens >= 5) &&
5991 			(strcmp(tokens[2], "table") == 0) &&
5992 			(strcmp(tokens[4], "stats") == 0)) {
5993 			cmd_pipeline_table_stats(tokens, n_tokens,
5994 				out, out_size);
5995 			return;
5996 		}
5997 
5998 		if ((n_tokens >= 7) &&
5999 			(strcmp(tokens[2], "table") == 0) &&
6000 			(strcmp(tokens[4], "rule") == 0) &&
6001 			(strcmp(tokens[5], "add") == 0) &&
6002 			(strcmp(tokens[6], "match") == 0)) {
6003 			if ((n_tokens >= 8) &&
6004 				(strcmp(tokens[7], "default") == 0)) {
6005 				cmd_pipeline_table_rule_add_default(tokens,
6006 					n_tokens, out, out_size);
6007 				return;
6008 			}
6009 
6010 			cmd_pipeline_table_rule_add(tokens, n_tokens,
6011 				out, out_size);
6012 			return;
6013 		}
6014 
6015 		if ((n_tokens >= 7) &&
6016 			(strcmp(tokens[2], "table") == 0) &&
6017 			(strcmp(tokens[4], "rule") == 0) &&
6018 			(strcmp(tokens[5], "add") == 0) &&
6019 			(strcmp(tokens[6], "bulk") == 0)) {
6020 			cmd_pipeline_table_rule_add_bulk(tokens,
6021 				n_tokens, out, out_size);
6022 			return;
6023 		}
6024 
6025 		if ((n_tokens >= 7) &&
6026 			(strcmp(tokens[2], "table") == 0) &&
6027 			(strcmp(tokens[4], "rule") == 0) &&
6028 			(strcmp(tokens[5], "delete") == 0) &&
6029 			(strcmp(tokens[6], "match") == 0)) {
6030 			if ((n_tokens >= 8) &&
6031 				(strcmp(tokens[7], "default") == 0)) {
6032 				cmd_pipeline_table_rule_delete_default(tokens,
6033 					n_tokens, out, out_size);
6034 				return;
6035 				}
6036 
6037 			cmd_pipeline_table_rule_delete(tokens, n_tokens,
6038 				out, out_size);
6039 			return;
6040 		}
6041 
6042 		if ((n_tokens >= 7) &&
6043 			(strcmp(tokens[2], "table") == 0) &&
6044 			(strcmp(tokens[4], "rule") == 0) &&
6045 			(strcmp(tokens[5], "read") == 0) &&
6046 			(strcmp(tokens[6], "stats") == 0)) {
6047 			cmd_pipeline_table_rule_stats_read(tokens, n_tokens,
6048 				out, out_size);
6049 			return;
6050 		}
6051 
6052 		if ((n_tokens >= 8) &&
6053 			(strcmp(tokens[2], "table") == 0) &&
6054 			(strcmp(tokens[4], "meter") == 0) &&
6055 			(strcmp(tokens[5], "profile") == 0) &&
6056 			(strcmp(tokens[7], "add") == 0)) {
6057 			cmd_pipeline_table_meter_profile_add(tokens, n_tokens,
6058 				out, out_size);
6059 			return;
6060 		}
6061 
6062 		if ((n_tokens >= 8) &&
6063 			(strcmp(tokens[2], "table") == 0) &&
6064 			(strcmp(tokens[4], "meter") == 0) &&
6065 			(strcmp(tokens[5], "profile") == 0) &&
6066 			(strcmp(tokens[7], "delete") == 0)) {
6067 			cmd_pipeline_table_meter_profile_delete(tokens,
6068 				n_tokens, out, out_size);
6069 			return;
6070 		}
6071 
6072 		if ((n_tokens >= 7) &&
6073 			(strcmp(tokens[2], "table") == 0) &&
6074 			(strcmp(tokens[4], "rule") == 0) &&
6075 			(strcmp(tokens[5], "read") == 0) &&
6076 			(strcmp(tokens[6], "meter") == 0)) {
6077 			cmd_pipeline_table_rule_meter_read(tokens, n_tokens,
6078 				out, out_size);
6079 			return;
6080 		}
6081 
6082 		if ((n_tokens >= 5) &&
6083 			(strcmp(tokens[2], "table") == 0) &&
6084 			(strcmp(tokens[4], "dscp") == 0)) {
6085 			cmd_pipeline_table_dscp(tokens, n_tokens,
6086 				out, out_size);
6087 			return;
6088 		}
6089 
6090 		if ((n_tokens >= 7) &&
6091 			(strcmp(tokens[2], "table") == 0) &&
6092 			(strcmp(tokens[4], "rule") == 0) &&
6093 			(strcmp(tokens[5], "read") == 0) &&
6094 			(strcmp(tokens[6], "ttl") == 0)) {
6095 			cmd_pipeline_table_rule_ttl_read(tokens, n_tokens,
6096 				out, out_size);
6097 			return;
6098 		}
6099 	}
6100 
6101 	if (strcmp(tokens[0], "thread") == 0) {
6102 		if ((n_tokens >= 5) &&
6103 			(strcmp(tokens[4], "enable") == 0)) {
6104 			cmd_thread_pipeline_enable(tokens, n_tokens,
6105 				out, out_size);
6106 			return;
6107 		}
6108 
6109 		if ((n_tokens >= 5) &&
6110 			(strcmp(tokens[4], "disable") == 0)) {
6111 			cmd_thread_pipeline_disable(tokens, n_tokens,
6112 				out, out_size);
6113 			return;
6114 		}
6115 	}
6116 
6117 	snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
6118 }
6119 
6120 int
6121 cli_script_process(const char *file_name,
6122 	size_t msg_in_len_max,
6123 	size_t msg_out_len_max)
6124 {
6125 	char *msg_in = NULL, *msg_out = NULL;
6126 	FILE *f = NULL;
6127 
6128 	/* Check input arguments */
6129 	if ((file_name == NULL) ||
6130 		(strlen(file_name) == 0) ||
6131 		(msg_in_len_max == 0) ||
6132 		(msg_out_len_max == 0))
6133 		return -EINVAL;
6134 
6135 	msg_in = malloc(msg_in_len_max + 1);
6136 	msg_out = malloc(msg_out_len_max + 1);
6137 	if ((msg_in == NULL) ||
6138 		(msg_out == NULL)) {
6139 		free(msg_out);
6140 		free(msg_in);
6141 		return -ENOMEM;
6142 	}
6143 
6144 	/* Open input file */
6145 	f = fopen(file_name, "r");
6146 	if (f == NULL) {
6147 		free(msg_out);
6148 		free(msg_in);
6149 		return -EIO;
6150 	}
6151 
6152 	/* Read file */
6153 	for ( ; ; ) {
6154 		if (fgets(msg_in, msg_in_len_max + 1, f) == NULL)
6155 			break;
6156 
6157 		printf("%s", msg_in);
6158 		msg_out[0] = 0;
6159 
6160 		cli_process(msg_in,
6161 			msg_out,
6162 			msg_out_len_max);
6163 
6164 		if (strlen(msg_out))
6165 			printf("%s", msg_out);
6166 	}
6167 
6168 	/* Close file */
6169 	fclose(f);
6170 	free(msg_out);
6171 	free(msg_in);
6172 	return 0;
6173 }
6174 
6175 static int
6176 cli_rule_file_process(const char *file_name,
6177 	size_t line_len_max,
6178 	struct table_rule_list **rule_list,
6179 	uint32_t *n_rules,
6180 	uint32_t *line_number,
6181 	char *out,
6182 	size_t out_size)
6183 {
6184 	struct table_rule_list *list = NULL;
6185 	char *line = NULL;
6186 	FILE *f = NULL;
6187 	uint32_t rule_id = 0, line_id = 0;
6188 	int status = 0;
6189 
6190 	/* Check input arguments */
6191 	if ((file_name == NULL) ||
6192 		(strlen(file_name) == 0) ||
6193 		(line_len_max == 0) ||
6194 		(rule_list == NULL) ||
6195 		(n_rules == NULL) ||
6196 		(line_number == NULL) ||
6197 		(out == NULL)) {
6198 		status = -EINVAL;
6199 		goto cli_rule_file_process_free;
6200 	}
6201 
6202 	/* Memory allocation */
6203 	list = malloc(sizeof(struct table_rule_list));
6204 	if (list == NULL) {
6205 		status = -ENOMEM;
6206 		goto cli_rule_file_process_free;
6207 	}
6208 
6209 	TAILQ_INIT(list);
6210 
6211 	line = malloc(line_len_max + 1);
6212 	if (line == NULL) {
6213 		status = -ENOMEM;
6214 		goto cli_rule_file_process_free;
6215 	}
6216 
6217 	/* Open file */
6218 	f = fopen(file_name, "r");
6219 	if (f == NULL) {
6220 		status = -EIO;
6221 		goto cli_rule_file_process_free;
6222 	}
6223 
6224 	/* Read file */
6225 	for (line_id = 1, rule_id = 0; ; line_id++) {
6226 		char *tokens[CMD_MAX_TOKENS];
6227 		struct table_rule *rule = NULL;
6228 		uint32_t n_tokens, n_tokens_parsed, t0;
6229 
6230 		/* Read next line from file. */
6231 		if (fgets(line, line_len_max + 1, f) == NULL)
6232 			break;
6233 
6234 		/* Comment. */
6235 		if (is_comment(line))
6236 			continue;
6237 
6238 		/* Parse line. */
6239 		n_tokens = RTE_DIM(tokens);
6240 		status = parse_tokenize_string(line, tokens, &n_tokens);
6241 		if (status) {
6242 			status = -EINVAL;
6243 			goto cli_rule_file_process_free;
6244 		}
6245 
6246 		/* Empty line. */
6247 		if (n_tokens == 0)
6248 			continue;
6249 		t0 = 0;
6250 
6251 		/* Rule alloc and insert. */
6252 		rule = calloc(1, sizeof(struct table_rule));
6253 		if (rule == NULL) {
6254 			status = -ENOMEM;
6255 			goto cli_rule_file_process_free;
6256 		}
6257 
6258 		TAILQ_INSERT_TAIL(list, rule, node);
6259 
6260 		/* Rule match. */
6261 		n_tokens_parsed = parse_match(tokens + t0,
6262 			n_tokens - t0,
6263 			out,
6264 			out_size,
6265 			&rule->match);
6266 		if (n_tokens_parsed == 0) {
6267 			status = -EINVAL;
6268 			goto cli_rule_file_process_free;
6269 		}
6270 		t0 += n_tokens_parsed;
6271 
6272 		/* Rule action. */
6273 		n_tokens_parsed = parse_table_action(tokens + t0,
6274 			n_tokens - t0,
6275 			out,
6276 			out_size,
6277 			&rule->action);
6278 		if (n_tokens_parsed == 0) {
6279 			status = -EINVAL;
6280 			goto cli_rule_file_process_free;
6281 		}
6282 		t0 += n_tokens_parsed;
6283 
6284 		/* Line completed. */
6285 		if (t0 < n_tokens) {
6286 			status = -EINVAL;
6287 			goto cli_rule_file_process_free;
6288 		}
6289 
6290 		/* Increment rule count */
6291 		rule_id++;
6292 	}
6293 
6294 	/* Close file */
6295 	fclose(f);
6296 
6297 	/* Memory free */
6298 	free(line);
6299 
6300 	*rule_list = list;
6301 	*n_rules = rule_id;
6302 	*line_number = line_id;
6303 	return 0;
6304 
6305 cli_rule_file_process_free:
6306 	*rule_list = NULL;
6307 	*n_rules = rule_id;
6308 	*line_number = line_id;
6309 
6310 	for ( ; ; ) {
6311 		struct table_rule *rule;
6312 
6313 		rule = TAILQ_FIRST(list);
6314 		if (rule == NULL)
6315 			break;
6316 
6317 		TAILQ_REMOVE(list, rule, node);
6318 		free(rule);
6319 	}
6320 
6321 	if (f)
6322 		fclose(f);
6323 	free(line);
6324 	free(list);
6325 
6326 	return status;
6327 }
6328