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