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