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