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