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