xref: /dpdk/examples/ip_pipeline/cli.c (revision 93998f3c5f22747e4f2c5e8714fa5cbe6c9d1574)
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 } __rte_packed;
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 } __rte_packed;
2585 
2586 struct pkt_key_ipv6_5tuple {
2587 	uint16_t payload_length;
2588 	uint8_t proto;
2589 	uint8_t hop_limit;
2590 	uint8_t sa[16];
2591 	uint8_t da[16];
2592 	uint16_t sp;
2593 	uint16_t dp;
2594 } __rte_packed;
2595 
2596 struct pkt_key_ipv4_addr {
2597 	uint32_t addr;
2598 } __rte_packed;
2599 
2600 struct pkt_key_ipv6_addr {
2601 	uint8_t addr[16];
2602 } __rte_packed;
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 in6_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 			memcpy(m->match.acl.ipv6.sa, saddr.s6_addr, 16);
2666 
2667 			if (parse_ipv6_addr(tokens[7], &daddr) != 0) {
2668 				snprintf(out, out_size, MSG_ARG_INVALID, "da");
2669 				return 0;
2670 			}
2671 			memcpy(m->match.acl.ipv6.da, daddr.s6_addr, 16);
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 in6_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 			memcpy(ipv6->sa, saddr.s6_addr, 16);
2850 			memcpy(ipv6->da, daddr.s6_addr, 16);
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 in6_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 			memcpy(ipv6_addr->addr, addr.s6_addr, 16);
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 in6_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 			memcpy(m->match.lpm.ipv6, addr.s6_addr, 16);
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 in6_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 			memcpy(a->encap.vxlan.ipv6.sa, sa.s6_addr, 16);
3544 			memcpy(a->encap.vxlan.ipv6.da, da.s6_addr, 16);
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 in6_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 		memcpy(a->nat.addr.ipv6, addr.s6_addr, 16);
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, uint8_t *addr)
4704 {
4705 	fprintf(f, "%02x%02x:%02x%02x:%02x%02x:%02x%02x:"
4706 		"%02x%02x:%02x%02x:%02x%02x:%02x%02x:",
4707 		(uint32_t)addr[0], (uint32_t)addr[1],
4708 		(uint32_t)addr[2], (uint32_t)addr[3],
4709 		(uint32_t)addr[4], (uint32_t)addr[5],
4710 		(uint32_t)addr[6], (uint32_t)addr[7],
4711 		(uint32_t)addr[8], (uint32_t)addr[9],
4712 		(uint32_t)addr[10], (uint32_t)addr[11],
4713 		(uint32_t)addr[12], (uint32_t)addr[13],
4714 		(uint32_t)addr[14], (uint32_t)addr[15]);
4715 }
4716 
4717 static const char *
4718 policer_action_string(enum rte_table_action_policer action) {
4719 	switch (action) {
4720 		case RTE_TABLE_ACTION_POLICER_COLOR_GREEN: return "G";
4721 		case RTE_TABLE_ACTION_POLICER_COLOR_YELLOW: return "Y";
4722 		case RTE_TABLE_ACTION_POLICER_COLOR_RED: return "R";
4723 		case RTE_TABLE_ACTION_POLICER_DROP: return "D";
4724 		default: return "?";
4725 	}
4726 }
4727 
4728 static int
4729 table_rule_show(const char *pipeline_name,
4730 	uint32_t table_id,
4731 	const char *file_name)
4732 {
4733 	struct pipeline *p;
4734 	struct table *table;
4735 	struct table_rule *rule;
4736 	FILE *f = NULL;
4737 	uint32_t i;
4738 
4739 	/* Check input params. */
4740 	if ((pipeline_name == NULL) ||
4741 		(file_name == NULL))
4742 		return -1;
4743 
4744 	p = pipeline_find(pipeline_name);
4745 	if ((p == NULL) ||
4746 		(table_id >= p->n_tables))
4747 		return -1;
4748 
4749 	table = &p->table[table_id];
4750 
4751 	/* Open file. */
4752 	f = fopen(file_name, "w");
4753 	if (f == NULL)
4754 		return -1;
4755 
4756 	/* Write table rules to file. */
4757 	TAILQ_FOREACH(rule, &table->rules, node) {
4758 		struct table_rule_match *m = &rule->match;
4759 		struct table_rule_action *a = &rule->action;
4760 
4761 		fprintf(f, "match ");
4762 		switch (m->match_type) {
4763 		case TABLE_ACL:
4764 			fprintf(f, "acl priority %u ",
4765 				m->match.acl.priority);
4766 
4767 			fprintf(f, m->match.acl.ip_version ? "ipv4 " : "ipv6 ");
4768 
4769 			if (m->match.acl.ip_version)
4770 				ipv4_addr_show(f, m->match.acl.ipv4.sa);
4771 			else
4772 				ipv6_addr_show(f, m->match.acl.ipv6.sa);
4773 
4774 			fprintf(f, "%u",	m->match.acl.sa_depth);
4775 
4776 			if (m->match.acl.ip_version)
4777 				ipv4_addr_show(f, m->match.acl.ipv4.da);
4778 			else
4779 				ipv6_addr_show(f, m->match.acl.ipv6.da);
4780 
4781 			fprintf(f, "%u",	m->match.acl.da_depth);
4782 
4783 			fprintf(f, "%u %u %u %u %u ",
4784 				(uint32_t)m->match.acl.sp0,
4785 				(uint32_t)m->match.acl.sp1,
4786 				(uint32_t)m->match.acl.dp0,
4787 				(uint32_t)m->match.acl.dp1,
4788 				(uint32_t)m->match.acl.proto);
4789 			break;
4790 
4791 		case TABLE_ARRAY:
4792 			fprintf(f, "array %u ",
4793 				m->match.array.pos);
4794 			break;
4795 
4796 		case TABLE_HASH:
4797 			fprintf(f, "hash raw ");
4798 			for (i = 0; i < table->params.match.hash.key_size; i++)
4799 				fprintf(f, "%02x", m->match.hash.key[i]);
4800 			fprintf(f, " ");
4801 			break;
4802 
4803 		case TABLE_LPM:
4804 			fprintf(f, "lpm ");
4805 
4806 			fprintf(f, m->match.lpm.ip_version ? "ipv4 " : "ipv6 ");
4807 
4808 			if (m->match.acl.ip_version)
4809 				ipv4_addr_show(f, m->match.lpm.ipv4);
4810 			else
4811 				ipv6_addr_show(f, m->match.lpm.ipv6);
4812 
4813 			fprintf(f, "%u ",
4814 				(uint32_t)m->match.lpm.depth);
4815 			break;
4816 
4817 		default:
4818 			fprintf(f, "unknown ");
4819 		}
4820 
4821 		fprintf(f, "action ");
4822 		if (a->action_mask & (1LLU << RTE_TABLE_ACTION_FWD)) {
4823 			fprintf(f, "fwd ");
4824 			switch (a->fwd.action) {
4825 			case RTE_PIPELINE_ACTION_DROP:
4826 				fprintf(f, "drop ");
4827 				break;
4828 
4829 			case RTE_PIPELINE_ACTION_PORT:
4830 				fprintf(f, "port %u ", a->fwd.id);
4831 				break;
4832 
4833 			case RTE_PIPELINE_ACTION_PORT_META:
4834 				fprintf(f, "meta ");
4835 				break;
4836 
4837 			case RTE_PIPELINE_ACTION_TABLE:
4838 			default:
4839 				fprintf(f, "table %u ", a->fwd.id);
4840 			}
4841 		}
4842 
4843 		if (a->action_mask & (1LLU << RTE_TABLE_ACTION_LB)) {
4844 			fprintf(f, "balance ");
4845 			for (i = 0; i < RTE_DIM(a->lb.out); i++)
4846 				fprintf(f, "%u ", a->lb.out[i]);
4847 		}
4848 
4849 		if (a->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) {
4850 			fprintf(f, "mtr ");
4851 			for (i = 0; i < RTE_TABLE_ACTION_TC_MAX; i++)
4852 				if (a->mtr.tc_mask & (1 << i)) {
4853 					struct rte_table_action_mtr_tc_params *p =
4854 						&a->mtr.mtr[i];
4855 					enum rte_table_action_policer ga =
4856 						p->policer[RTE_COLOR_GREEN];
4857 					enum rte_table_action_policer ya =
4858 						p->policer[RTE_COLOR_YELLOW];
4859 					enum rte_table_action_policer ra =
4860 						p->policer[RTE_COLOR_RED];
4861 
4862 					fprintf(f, "tc%u meter %u policer g %s y %s r %s ",
4863 						i,
4864 						a->mtr.mtr[i].meter_profile_id,
4865 						policer_action_string(ga),
4866 						policer_action_string(ya),
4867 						policer_action_string(ra));
4868 				}
4869 		}
4870 
4871 		if (a->action_mask & (1LLU << RTE_TABLE_ACTION_TM))
4872 			fprintf(f, "tm subport %u pipe %u ",
4873 				a->tm.subport_id,
4874 				a->tm.pipe_id);
4875 
4876 		if (a->action_mask & (1LLU << RTE_TABLE_ACTION_ENCAP)) {
4877 			fprintf(f, "encap ");
4878 			switch (a->encap.type) {
4879 			case RTE_TABLE_ACTION_ENCAP_ETHER:
4880 				fprintf(f, "ether ");
4881 				ether_addr_show(f, &a->encap.ether.ether.da);
4882 				fprintf(f, " ");
4883 				ether_addr_show(f, &a->encap.ether.ether.sa);
4884 				fprintf(f, " ");
4885 				break;
4886 
4887 			case RTE_TABLE_ACTION_ENCAP_VLAN:
4888 				fprintf(f, "vlan ");
4889 				ether_addr_show(f, &a->encap.vlan.ether.da);
4890 				fprintf(f, " ");
4891 				ether_addr_show(f, &a->encap.vlan.ether.sa);
4892 				fprintf(f, " pcp %u dei %u vid %u ",
4893 					a->encap.vlan.vlan.pcp,
4894 					a->encap.vlan.vlan.dei,
4895 					a->encap.vlan.vlan.vid);
4896 				break;
4897 
4898 			case RTE_TABLE_ACTION_ENCAP_QINQ:
4899 				fprintf(f, "qinq ");
4900 				ether_addr_show(f, &a->encap.qinq.ether.da);
4901 				fprintf(f, " ");
4902 				ether_addr_show(f, &a->encap.qinq.ether.sa);
4903 				fprintf(f, " pcp %u dei %u vid %u pcp %u dei %u vid %u ",
4904 					a->encap.qinq.svlan.pcp,
4905 					a->encap.qinq.svlan.dei,
4906 					a->encap.qinq.svlan.vid,
4907 					a->encap.qinq.cvlan.pcp,
4908 					a->encap.qinq.cvlan.dei,
4909 					a->encap.qinq.cvlan.vid);
4910 				break;
4911 
4912 			case RTE_TABLE_ACTION_ENCAP_MPLS:
4913 				fprintf(f, "mpls %s ", (a->encap.mpls.unicast) ?
4914 					"unicast " : "multicast ");
4915 				ether_addr_show(f, &a->encap.mpls.ether.da);
4916 				fprintf(f, " ");
4917 				ether_addr_show(f, &a->encap.mpls.ether.sa);
4918 				fprintf(f, " ");
4919 				for (i = 0; i < a->encap.mpls.mpls_count; i++) {
4920 					struct rte_table_action_mpls_hdr *l =
4921 						&a->encap.mpls.mpls[i];
4922 
4923 					fprintf(f, "label%u %u %u %u ",
4924 						i,
4925 						l->label,
4926 						l->tc,
4927 						l->ttl);
4928 				}
4929 				break;
4930 
4931 			case RTE_TABLE_ACTION_ENCAP_PPPOE:
4932 				fprintf(f, "pppoe ");
4933 				ether_addr_show(f, &a->encap.pppoe.ether.da);
4934 				fprintf(f, " ");
4935 				ether_addr_show(f, &a->encap.pppoe.ether.sa);
4936 				fprintf(f, " %u ", a->encap.pppoe.pppoe.session_id);
4937 				break;
4938 
4939 			case RTE_TABLE_ACTION_ENCAP_VXLAN:
4940 				fprintf(f, "vxlan ether ");
4941 				ether_addr_show(f, &a->encap.vxlan.ether.da);
4942 				fprintf(f, " ");
4943 				ether_addr_show(f, &a->encap.vxlan.ether.sa);
4944 				if (table->ap->params.encap.vxlan.vlan)
4945 					fprintf(f, " vlan pcp %u dei %u vid %u ",
4946 						a->encap.vxlan.vlan.pcp,
4947 						a->encap.vxlan.vlan.dei,
4948 						a->encap.vxlan.vlan.vid);
4949 				if (table->ap->params.encap.vxlan.ip_version) {
4950 					fprintf(f, " ipv4 ");
4951 					ipv4_addr_show(f, a->encap.vxlan.ipv4.sa);
4952 					fprintf(f, " ");
4953 					ipv4_addr_show(f, a->encap.vxlan.ipv4.da);
4954 					fprintf(f, " %u %u ",
4955 						(uint32_t)a->encap.vxlan.ipv4.dscp,
4956 						(uint32_t)a->encap.vxlan.ipv4.ttl);
4957 				} else {
4958 					fprintf(f, " ipv6 ");
4959 					ipv6_addr_show(f, a->encap.vxlan.ipv6.sa);
4960 					fprintf(f, " ");
4961 					ipv6_addr_show(f, a->encap.vxlan.ipv6.da);
4962 					fprintf(f, " %u %u %u ",
4963 						a->encap.vxlan.ipv6.flow_label,
4964 						(uint32_t)a->encap.vxlan.ipv6.dscp,
4965 						(uint32_t)a->encap.vxlan.ipv6.hop_limit);
4966 					fprintf(f, " udp %u %u vxlan %u ",
4967 						a->encap.vxlan.udp.sp,
4968 						a->encap.vxlan.udp.dp,
4969 						a->encap.vxlan.vxlan.vni);
4970 				}
4971 				break;
4972 
4973 			default:
4974 				fprintf(f, "unknown ");
4975 			}
4976 		}
4977 
4978 		if (a->action_mask & (1LLU << RTE_TABLE_ACTION_NAT)) {
4979 			fprintf(f, "nat %s ", (a->nat.ip_version) ? "ipv4 " : "ipv6 ");
4980 			if (a->nat.ip_version)
4981 				ipv4_addr_show(f, a->nat.addr.ipv4);
4982 			else
4983 				ipv6_addr_show(f, a->nat.addr.ipv6);
4984 			fprintf(f, " %u ", (uint32_t)(a->nat.port));
4985 		}
4986 
4987 		if (a->action_mask & (1LLU << RTE_TABLE_ACTION_TTL))
4988 			fprintf(f, "ttl %s ", (a->ttl.decrement) ? "dec" : "keep");
4989 
4990 		if (a->action_mask & (1LLU << RTE_TABLE_ACTION_STATS))
4991 			fprintf(f, "stats ");
4992 
4993 		if (a->action_mask & (1LLU << RTE_TABLE_ACTION_TIME))
4994 			fprintf(f, "time ");
4995 
4996 		if (a->action_mask & (1LLU << RTE_TABLE_ACTION_SYM_CRYPTO))
4997 			fprintf(f, "sym_crypto ");
4998 
4999 		if (a->action_mask & (1LLU << RTE_TABLE_ACTION_TAG))
5000 			fprintf(f, "tag %u ", a->tag.tag);
5001 
5002 		if (a->action_mask & (1LLU << RTE_TABLE_ACTION_DECAP))
5003 			fprintf(f, "decap %u ", a->decap.n);
5004 
5005 		/* end */
5006 		fprintf(f, "\n");
5007 	}
5008 
5009 	/* Write table default rule to file. */
5010 	if (table->rule_default) {
5011 		struct table_rule_action *a = &table->rule_default->action;
5012 
5013 		fprintf(f, "# match default action fwd ");
5014 
5015 		switch (a->fwd.action) {
5016 		case RTE_PIPELINE_ACTION_DROP:
5017 			fprintf(f, "drop ");
5018 			break;
5019 
5020 		case RTE_PIPELINE_ACTION_PORT:
5021 			fprintf(f, "port %u ", a->fwd.id);
5022 			break;
5023 
5024 		case RTE_PIPELINE_ACTION_PORT_META:
5025 			fprintf(f, "meta ");
5026 			break;
5027 
5028 		case RTE_PIPELINE_ACTION_TABLE:
5029 		default:
5030 			fprintf(f, "table %u ", a->fwd.id);
5031 		}
5032 	} else
5033 		fprintf(f, "# match default action fwd drop ");
5034 
5035 	fprintf(f, "\n");
5036 
5037 	/* Close file. */
5038 	fclose(f);
5039 
5040 	return 0;
5041 }
5042 
5043 static const char cmd_pipeline_table_rule_show_help[] =
5044 "pipeline <pipeline_name> table <table_id> rule show\n"
5045 "     file <file_name>\n";
5046 
5047 static void
5048 cmd_pipeline_table_rule_show(char **tokens,
5049 	uint32_t n_tokens,
5050 	char *out,
5051 	size_t out_size)
5052 {
5053 	char *file_name = NULL, *pipeline_name;
5054 	uint32_t table_id;
5055 	int status;
5056 
5057 	if (n_tokens != 8) {
5058 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5059 		return;
5060 	}
5061 
5062 	pipeline_name = tokens[1];
5063 
5064 	if (strcmp(tokens[2], "table") != 0) {
5065 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
5066 		return;
5067 	}
5068 
5069 	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
5070 		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
5071 		return;
5072 	}
5073 
5074 	if (strcmp(tokens[4], "rule") != 0) {
5075 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
5076 		return;
5077 	}
5078 
5079 	if (strcmp(tokens[5], "show") != 0) {
5080 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "show");
5081 		return;
5082 	}
5083 
5084 	if (strcmp(tokens[6], "file") != 0) {
5085 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "file");
5086 		return;
5087 	}
5088 
5089 	file_name = tokens[7];
5090 
5091 	status = table_rule_show(pipeline_name, table_id, file_name);
5092 	if (status) {
5093 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
5094 		return;
5095 	}
5096 }
5097 
5098 static const char cmd_pipeline_table_rule_stats_read_help[] =
5099 "pipeline <pipeline_name> table <table_id> rule read stats [clear]\n"
5100 "     match <match>\n";
5101 
5102 static void
5103 cmd_pipeline_table_rule_stats_read(char **tokens,
5104 	uint32_t n_tokens,
5105 	char *out,
5106 	size_t out_size)
5107 {
5108 	struct table_rule_match m;
5109 	struct rte_table_action_stats_counters stats;
5110 	char *pipeline_name;
5111 	uint32_t table_id, n_tokens_parsed;
5112 	int clear = 0, status;
5113 
5114 	if (n_tokens < 7) {
5115 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5116 		return;
5117 	}
5118 
5119 	pipeline_name = tokens[1];
5120 
5121 	if (strcmp(tokens[2], "table") != 0) {
5122 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
5123 		return;
5124 	}
5125 
5126 	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
5127 		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
5128 		return;
5129 	}
5130 
5131 	if (strcmp(tokens[4], "rule") != 0) {
5132 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
5133 		return;
5134 	}
5135 
5136 	if (strcmp(tokens[5], "read") != 0) {
5137 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read");
5138 		return;
5139 	}
5140 
5141 	if (strcmp(tokens[6], "stats") != 0) {
5142 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
5143 		return;
5144 	}
5145 
5146 	n_tokens -= 7;
5147 	tokens += 7;
5148 
5149 	/* clear */
5150 	if (n_tokens && (strcmp(tokens[0], "clear") == 0)) {
5151 		clear = 1;
5152 
5153 		n_tokens--;
5154 		tokens++;
5155 	}
5156 
5157 	/* match */
5158 	if ((n_tokens == 0) || strcmp(tokens[0], "match")) {
5159 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match");
5160 		return;
5161 	}
5162 
5163 	n_tokens_parsed = parse_match(tokens,
5164 		n_tokens,
5165 		out,
5166 		out_size,
5167 		&m);
5168 	if (n_tokens_parsed == 0)
5169 		return;
5170 	n_tokens -= n_tokens_parsed;
5171 	tokens += n_tokens_parsed;
5172 
5173 	/* end */
5174 	if (n_tokens) {
5175 		snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
5176 		return;
5177 	}
5178 
5179 	/* Read table rule stats. */
5180 	status = pipeline_table_rule_stats_read(pipeline_name,
5181 		table_id,
5182 		&m,
5183 		&stats,
5184 		clear);
5185 	if (status) {
5186 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
5187 		return;
5188 	}
5189 
5190 	/* Print stats. */
5191 	if (stats.n_packets_valid && stats.n_bytes_valid)
5192 		snprintf(out, out_size, "Packets: %" PRIu64 "; Bytes: %" PRIu64 "\n",
5193 			stats.n_packets,
5194 			stats.n_bytes);
5195 
5196 	if (stats.n_packets_valid && !stats.n_bytes_valid)
5197 		snprintf(out, out_size, "Packets: %" PRIu64 "; Bytes: N/A\n",
5198 			stats.n_packets);
5199 
5200 	if (!stats.n_packets_valid && stats.n_bytes_valid)
5201 		snprintf(out, out_size, "Packets: N/A; Bytes: %" PRIu64 "\n",
5202 			stats.n_bytes);
5203 
5204 	if (!stats.n_packets_valid && !stats.n_bytes_valid)
5205 		snprintf(out, out_size, "Packets: N/A ; Bytes: N/A\n");
5206 }
5207 
5208 static const char cmd_pipeline_table_meter_profile_add_help[] =
5209 "pipeline <pipeline_name> table <table_id> meter profile <meter_profile_id>\n"
5210 "   add srtcm cir <cir> cbs <cbs> ebs <ebs>\n"
5211 "   | trtcm cir <cir> pir <pir> cbs <cbs> pbs <pbs>\n";
5212 
5213 static void
5214 cmd_pipeline_table_meter_profile_add(char **tokens,
5215 	uint32_t n_tokens,
5216 	char *out,
5217 	size_t out_size)
5218 {
5219 	struct rte_table_action_meter_profile p;
5220 	char *pipeline_name;
5221 	uint32_t table_id, meter_profile_id;
5222 	int status;
5223 
5224 	if (n_tokens < 9) {
5225 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5226 		return;
5227 	}
5228 
5229 	pipeline_name = tokens[1];
5230 
5231 	if (strcmp(tokens[2], "table") != 0) {
5232 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
5233 		return;
5234 	}
5235 
5236 	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
5237 		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
5238 		return;
5239 	}
5240 
5241 	if (strcmp(tokens[4], "meter") != 0) {
5242 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
5243 		return;
5244 	}
5245 
5246 	if (strcmp(tokens[5], "profile") != 0) {
5247 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
5248 		return;
5249 	}
5250 
5251 	if (parser_read_uint32(&meter_profile_id, tokens[6]) != 0) {
5252 		snprintf(out, out_size, MSG_ARG_INVALID, "meter_profile_id");
5253 		return;
5254 	}
5255 
5256 	if (strcmp(tokens[7], "add") != 0) {
5257 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
5258 		return;
5259 	}
5260 
5261 	if (strcmp(tokens[8], "srtcm") == 0) {
5262 		if (n_tokens != 15) {
5263 			snprintf(out, out_size, MSG_ARG_MISMATCH,
5264 				tokens[0]);
5265 			return;
5266 		}
5267 
5268 		p.alg = RTE_TABLE_ACTION_METER_SRTCM;
5269 
5270 		if (strcmp(tokens[9], "cir") != 0) {
5271 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cir");
5272 			return;
5273 		}
5274 
5275 		if (parser_read_uint64(&p.srtcm.cir, tokens[10]) != 0) {
5276 			snprintf(out, out_size, MSG_ARG_INVALID, "cir");
5277 			return;
5278 		}
5279 
5280 		if (strcmp(tokens[11], "cbs") != 0) {
5281 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cbs");
5282 			return;
5283 		}
5284 
5285 		if (parser_read_uint64(&p.srtcm.cbs, tokens[12]) != 0) {
5286 			snprintf(out, out_size, MSG_ARG_INVALID, "cbs");
5287 			return;
5288 		}
5289 
5290 		if (strcmp(tokens[13], "ebs") != 0) {
5291 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "ebs");
5292 			return;
5293 		}
5294 
5295 		if (parser_read_uint64(&p.srtcm.ebs, tokens[14]) != 0) {
5296 			snprintf(out, out_size, MSG_ARG_INVALID, "ebs");
5297 			return;
5298 		}
5299 	} else if (strcmp(tokens[8], "trtcm") == 0) {
5300 		if (n_tokens != 17) {
5301 			snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5302 			return;
5303 		}
5304 
5305 		p.alg = RTE_TABLE_ACTION_METER_TRTCM;
5306 
5307 		if (strcmp(tokens[9], "cir") != 0) {
5308 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cir");
5309 			return;
5310 		}
5311 
5312 		if (parser_read_uint64(&p.trtcm.cir, tokens[10]) != 0) {
5313 			snprintf(out, out_size, MSG_ARG_INVALID, "cir");
5314 			return;
5315 		}
5316 
5317 		if (strcmp(tokens[11], "pir") != 0) {
5318 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pir");
5319 			return;
5320 		}
5321 
5322 		if (parser_read_uint64(&p.trtcm.pir, tokens[12]) != 0) {
5323 			snprintf(out, out_size, MSG_ARG_INVALID, "pir");
5324 			return;
5325 		}
5326 		if (strcmp(tokens[13], "cbs") != 0) {
5327 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cbs");
5328 			return;
5329 		}
5330 
5331 		if (parser_read_uint64(&p.trtcm.cbs, tokens[14]) != 0) {
5332 			snprintf(out, out_size, MSG_ARG_INVALID, "cbs");
5333 			return;
5334 		}
5335 
5336 		if (strcmp(tokens[15], "pbs") != 0) {
5337 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pbs");
5338 			return;
5339 		}
5340 
5341 		if (parser_read_uint64(&p.trtcm.pbs, tokens[16]) != 0) {
5342 			snprintf(out, out_size, MSG_ARG_INVALID, "pbs");
5343 			return;
5344 		}
5345 	} else {
5346 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5347 		return;
5348 	}
5349 
5350 	status = pipeline_table_mtr_profile_add(pipeline_name,
5351 		table_id,
5352 		meter_profile_id,
5353 		&p);
5354 	if (status) {
5355 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
5356 		return;
5357 	}
5358 }
5359 
5360 
5361 static const char cmd_pipeline_table_meter_profile_delete_help[] =
5362 "pipeline <pipeline_name> table <table_id>\n"
5363 "   meter profile <meter_profile_id> delete\n";
5364 
5365 static void
5366 cmd_pipeline_table_meter_profile_delete(char **tokens,
5367 	uint32_t n_tokens,
5368 	char *out,
5369 	size_t out_size)
5370 {
5371 	char *pipeline_name;
5372 	uint32_t table_id, meter_profile_id;
5373 	int status;
5374 
5375 	if (n_tokens != 8) {
5376 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5377 		return;
5378 	}
5379 
5380 	pipeline_name = tokens[1];
5381 
5382 	if (strcmp(tokens[2], "table") != 0) {
5383 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
5384 		return;
5385 	}
5386 
5387 	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
5388 		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
5389 		return;
5390 	}
5391 
5392 	if (strcmp(tokens[4], "meter") != 0) {
5393 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
5394 		return;
5395 	}
5396 
5397 	if (strcmp(tokens[5], "profile") != 0) {
5398 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
5399 		return;
5400 	}
5401 
5402 	if (parser_read_uint32(&meter_profile_id, tokens[6]) != 0) {
5403 		snprintf(out, out_size, MSG_ARG_INVALID, "meter_profile_id");
5404 		return;
5405 	}
5406 
5407 	if (strcmp(tokens[7], "delete") != 0) {
5408 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete");
5409 		return;
5410 	}
5411 
5412 	status = pipeline_table_mtr_profile_delete(pipeline_name,
5413 		table_id,
5414 		meter_profile_id);
5415 	if (status) {
5416 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
5417 		return;
5418 	}
5419 }
5420 
5421 
5422 static const char cmd_pipeline_table_rule_meter_read_help[] =
5423 "pipeline <pipeline_name> table <table_id> rule read meter [clear]\n"
5424 "     match <match>\n";
5425 
5426 static void
5427 cmd_pipeline_table_rule_meter_read(char **tokens,
5428 	uint32_t n_tokens,
5429 	char *out,
5430 	size_t out_size)
5431 {
5432 	struct table_rule_match m;
5433 	struct rte_table_action_mtr_counters stats;
5434 	char *pipeline_name;
5435 	uint32_t table_id, n_tokens_parsed;
5436 	int clear = 0, status;
5437 
5438 	if (n_tokens < 7) {
5439 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5440 		return;
5441 	}
5442 
5443 	pipeline_name = tokens[1];
5444 
5445 	if (strcmp(tokens[2], "table") != 0) {
5446 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
5447 		return;
5448 	}
5449 
5450 	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
5451 		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
5452 		return;
5453 	}
5454 
5455 	if (strcmp(tokens[4], "rule") != 0) {
5456 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
5457 		return;
5458 	}
5459 
5460 	if (strcmp(tokens[5], "read") != 0) {
5461 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read");
5462 		return;
5463 	}
5464 
5465 	if (strcmp(tokens[6], "meter") != 0) {
5466 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
5467 		return;
5468 	}
5469 
5470 	n_tokens -= 7;
5471 	tokens += 7;
5472 
5473 	/* clear */
5474 	if (n_tokens && (strcmp(tokens[0], "clear") == 0)) {
5475 		clear = 1;
5476 
5477 		n_tokens--;
5478 		tokens++;
5479 	}
5480 
5481 	/* match */
5482 	if ((n_tokens == 0) || strcmp(tokens[0], "match")) {
5483 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match");
5484 		return;
5485 	}
5486 
5487 	n_tokens_parsed = parse_match(tokens,
5488 		n_tokens,
5489 		out,
5490 		out_size,
5491 		&m);
5492 	if (n_tokens_parsed == 0)
5493 		return;
5494 	n_tokens -= n_tokens_parsed;
5495 	tokens += n_tokens_parsed;
5496 
5497 	/* end */
5498 	if (n_tokens) {
5499 		snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
5500 		return;
5501 	}
5502 
5503 	/* Read table rule meter stats. */
5504 	status = pipeline_table_rule_mtr_read(pipeline_name,
5505 		table_id,
5506 		&m,
5507 		&stats,
5508 		clear);
5509 	if (status) {
5510 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
5511 		return;
5512 	}
5513 
5514 	/* Print stats. */
5515 }
5516 
5517 
5518 static const char cmd_pipeline_table_dscp_help[] =
5519 "pipeline <pipeline_name> table <table_id> dscp <file_name>\n"
5520 "\n"
5521 " File <file_name>:\n"
5522 "   - exactly 64 lines\n"
5523 "   - line format: <tc_id> <tc_queue_id> <color>, with <color> as: g | y | r\n";
5524 
5525 static int
5526 load_dscp_table(struct rte_table_action_dscp_table *dscp_table,
5527 	const char *file_name,
5528 	uint32_t *line_number)
5529 {
5530 	FILE *f = NULL;
5531 	uint32_t dscp, l;
5532 
5533 	/* Check input arguments */
5534 	if ((dscp_table == NULL) ||
5535 		(file_name == NULL) ||
5536 		(line_number == NULL)) {
5537 		if (line_number)
5538 			*line_number = 0;
5539 		return -EINVAL;
5540 	}
5541 
5542 	/* Open input file */
5543 	f = fopen(file_name, "r");
5544 	if (f == NULL) {
5545 		*line_number = 0;
5546 		return -EINVAL;
5547 	}
5548 
5549 	/* Read file */
5550 	for (dscp = 0, l = 1; ; l++) {
5551 		char line[64];
5552 		char *tokens[3];
5553 		enum rte_color color;
5554 		uint32_t tc_id, tc_queue_id, n_tokens = RTE_DIM(tokens);
5555 
5556 		if (fgets(line, sizeof(line), f) == NULL)
5557 			break;
5558 
5559 		if (is_comment(line))
5560 			continue;
5561 
5562 		if (parse_tokenize_string(line, tokens, &n_tokens)) {
5563 			*line_number = l;
5564 			fclose(f);
5565 			return -EINVAL;
5566 		}
5567 
5568 		if (n_tokens == 0)
5569 			continue;
5570 
5571 		if ((dscp >= RTE_DIM(dscp_table->entry)) ||
5572 			(n_tokens != RTE_DIM(tokens)) ||
5573 			parser_read_uint32(&tc_id, tokens[0]) ||
5574 			(tc_id >= RTE_TABLE_ACTION_TC_MAX) ||
5575 			parser_read_uint32(&tc_queue_id, tokens[1]) ||
5576 			(tc_queue_id >= RTE_TABLE_ACTION_TC_QUEUE_MAX) ||
5577 			(strlen(tokens[2]) != 1)) {
5578 			*line_number = l;
5579 			fclose(f);
5580 			return -EINVAL;
5581 		}
5582 
5583 		switch (tokens[2][0]) {
5584 		case 'g':
5585 		case 'G':
5586 			color = RTE_COLOR_GREEN;
5587 			break;
5588 
5589 		case 'y':
5590 		case 'Y':
5591 			color = RTE_COLOR_YELLOW;
5592 			break;
5593 
5594 		case 'r':
5595 		case 'R':
5596 			color = RTE_COLOR_RED;
5597 			break;
5598 
5599 		default:
5600 			*line_number = l;
5601 			fclose(f);
5602 			return -EINVAL;
5603 		}
5604 
5605 		dscp_table->entry[dscp].tc_id = tc_id;
5606 		dscp_table->entry[dscp].tc_queue_id = tc_queue_id;
5607 		dscp_table->entry[dscp].color = color;
5608 		dscp++;
5609 	}
5610 
5611 	/* Close file */
5612 	fclose(f);
5613 	return 0;
5614 }
5615 
5616 static void
5617 cmd_pipeline_table_dscp(char **tokens,
5618 	uint32_t n_tokens,
5619 	char *out,
5620 	size_t out_size)
5621 {
5622 	struct rte_table_action_dscp_table dscp_table;
5623 	char *pipeline_name, *file_name;
5624 	uint32_t table_id, line_number;
5625 	int status;
5626 
5627 	if (n_tokens != 6) {
5628 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5629 		return;
5630 	}
5631 
5632 	pipeline_name = tokens[1];
5633 
5634 	if (strcmp(tokens[2], "table") != 0) {
5635 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
5636 		return;
5637 	}
5638 
5639 	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
5640 		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
5641 		return;
5642 	}
5643 
5644 	if (strcmp(tokens[4], "dscp") != 0) {
5645 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "dscp");
5646 		return;
5647 	}
5648 
5649 	file_name = tokens[5];
5650 
5651 	status = load_dscp_table(&dscp_table, file_name, &line_number);
5652 	if (status) {
5653 		snprintf(out, out_size, MSG_FILE_ERR, file_name, line_number);
5654 		return;
5655 	}
5656 
5657 	status = pipeline_table_dscp_table_update(pipeline_name,
5658 		table_id,
5659 		UINT64_MAX,
5660 		&dscp_table);
5661 	if (status) {
5662 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
5663 		return;
5664 	}
5665 }
5666 
5667 
5668 static const char cmd_pipeline_table_rule_ttl_read_help[] =
5669 "pipeline <pipeline_name> table <table_id> rule read ttl [clear]\n"
5670 "     match <match>\n";
5671 
5672 static void
5673 cmd_pipeline_table_rule_ttl_read(char **tokens,
5674 	uint32_t n_tokens,
5675 	char *out,
5676 	size_t out_size)
5677 {
5678 	struct table_rule_match m;
5679 	struct rte_table_action_ttl_counters stats;
5680 	char *pipeline_name;
5681 	uint32_t table_id, n_tokens_parsed;
5682 	int clear = 0, status;
5683 
5684 	if (n_tokens < 7) {
5685 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5686 		return;
5687 	}
5688 
5689 	pipeline_name = tokens[1];
5690 
5691 	if (strcmp(tokens[2], "table") != 0) {
5692 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
5693 		return;
5694 	}
5695 
5696 	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
5697 		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
5698 		return;
5699 	}
5700 
5701 	if (strcmp(tokens[4], "rule") != 0) {
5702 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
5703 		return;
5704 	}
5705 
5706 	if (strcmp(tokens[5], "read") != 0) {
5707 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read");
5708 		return;
5709 	}
5710 
5711 	if (strcmp(tokens[6], "ttl") != 0) {
5712 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "ttl");
5713 		return;
5714 	}
5715 
5716 	n_tokens -= 7;
5717 	tokens += 7;
5718 
5719 	/* clear */
5720 	if (n_tokens && (strcmp(tokens[0], "clear") == 0)) {
5721 		clear = 1;
5722 
5723 		n_tokens--;
5724 		tokens++;
5725 	}
5726 
5727 	/* match */
5728 	if ((n_tokens == 0) || strcmp(tokens[0], "match")) {
5729 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match");
5730 		return;
5731 	}
5732 
5733 	n_tokens_parsed = parse_match(tokens,
5734 		n_tokens,
5735 		out,
5736 		out_size,
5737 		&m);
5738 	if (n_tokens_parsed == 0)
5739 		return;
5740 	n_tokens -= n_tokens_parsed;
5741 	tokens += n_tokens_parsed;
5742 
5743 	/* end */
5744 	if (n_tokens) {
5745 		snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
5746 		return;
5747 	}
5748 
5749 	/* Read table rule TTL stats. */
5750 	status = pipeline_table_rule_ttl_read(pipeline_name,
5751 		table_id,
5752 		&m,
5753 		&stats,
5754 		clear);
5755 	if (status) {
5756 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
5757 		return;
5758 	}
5759 
5760 	/* Print stats. */
5761 	snprintf(out, out_size, "Packets: %" PRIu64 "\n",
5762 		stats.n_packets);
5763 }
5764 
5765 static const char cmd_pipeline_table_rule_time_read_help[] =
5766 "pipeline <pipeline_name> table <table_id> rule read time\n"
5767 "     match <match>\n";
5768 
5769 static void
5770 cmd_pipeline_table_rule_time_read(char **tokens,
5771 	uint32_t n_tokens,
5772 	char *out,
5773 	size_t out_size)
5774 {
5775 	struct table_rule_match m;
5776 	char *pipeline_name;
5777 	uint64_t timestamp;
5778 	uint32_t table_id, n_tokens_parsed;
5779 	int status;
5780 
5781 	if (n_tokens < 7) {
5782 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5783 		return;
5784 	}
5785 
5786 	pipeline_name = tokens[1];
5787 
5788 	if (strcmp(tokens[2], "table") != 0) {
5789 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
5790 		return;
5791 	}
5792 
5793 	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
5794 		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
5795 		return;
5796 	}
5797 
5798 	if (strcmp(tokens[4], "rule") != 0) {
5799 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
5800 		return;
5801 	}
5802 
5803 	if (strcmp(tokens[5], "read") != 0) {
5804 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read");
5805 		return;
5806 	}
5807 
5808 	if (strcmp(tokens[6], "time") != 0) {
5809 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "time");
5810 		return;
5811 	}
5812 
5813 	n_tokens -= 7;
5814 	tokens += 7;
5815 
5816 	/* match */
5817 	if ((n_tokens == 0) || strcmp(tokens[0], "match")) {
5818 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match");
5819 		return;
5820 	}
5821 
5822 	n_tokens_parsed = parse_match(tokens,
5823 		n_tokens,
5824 		out,
5825 		out_size,
5826 		&m);
5827 	if (n_tokens_parsed == 0)
5828 		return;
5829 	n_tokens -= n_tokens_parsed;
5830 	tokens += n_tokens_parsed;
5831 
5832 	/* end */
5833 	if (n_tokens) {
5834 		snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
5835 		return;
5836 	}
5837 
5838 	/* Read table rule timestamp. */
5839 	status = pipeline_table_rule_time_read(pipeline_name,
5840 		table_id,
5841 		&m,
5842 		&timestamp);
5843 	if (status) {
5844 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
5845 		return;
5846 	}
5847 
5848 	/* Print stats. */
5849 	snprintf(out, out_size, "Packets: %" PRIu64 "\n", timestamp);
5850 }
5851 
5852 static const char cmd_thread_pipeline_enable_help[] =
5853 "thread <thread_id> pipeline <pipeline_name> enable\n";
5854 
5855 static void
5856 cmd_thread_pipeline_enable(char **tokens,
5857 	uint32_t n_tokens,
5858 	char *out,
5859 	size_t out_size)
5860 {
5861 	char *pipeline_name;
5862 	uint32_t thread_id;
5863 	int status;
5864 
5865 	if (n_tokens != 5) {
5866 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5867 		return;
5868 	}
5869 
5870 	if (parser_read_uint32(&thread_id, tokens[1]) != 0) {
5871 		snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
5872 		return;
5873 	}
5874 
5875 	if (strcmp(tokens[2], "pipeline") != 0) {
5876 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
5877 		return;
5878 	}
5879 
5880 	pipeline_name = tokens[3];
5881 
5882 	if (strcmp(tokens[4], "enable") != 0) {
5883 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable");
5884 		return;
5885 	}
5886 
5887 	status = thread_pipeline_enable(thread_id, pipeline_name);
5888 	if (status) {
5889 		snprintf(out, out_size, MSG_CMD_FAIL, "thread pipeline enable");
5890 		return;
5891 	}
5892 }
5893 
5894 
5895 static const char cmd_thread_pipeline_disable_help[] =
5896 "thread <thread_id> pipeline <pipeline_name> disable\n";
5897 
5898 static void
5899 cmd_thread_pipeline_disable(char **tokens,
5900 	uint32_t n_tokens,
5901 	char *out,
5902 	size_t out_size)
5903 {
5904 	char *pipeline_name;
5905 	uint32_t thread_id;
5906 	int status;
5907 
5908 	if (n_tokens != 5) {
5909 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
5910 		return;
5911 	}
5912 
5913 	if (parser_read_uint32(&thread_id, tokens[1]) != 0) {
5914 		snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
5915 		return;
5916 	}
5917 
5918 	if (strcmp(tokens[2], "pipeline") != 0) {
5919 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
5920 		return;
5921 	}
5922 
5923 	pipeline_name = tokens[3];
5924 
5925 	if (strcmp(tokens[4], "disable") != 0) {
5926 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable");
5927 		return;
5928 	}
5929 
5930 	status = thread_pipeline_disable(thread_id, pipeline_name);
5931 	if (status) {
5932 		snprintf(out, out_size, MSG_CMD_FAIL,
5933 			"thread pipeline disable");
5934 		return;
5935 	}
5936 }
5937 
5938 static void
5939 cmd_help(char **tokens, uint32_t n_tokens, char *out, size_t out_size)
5940 {
5941 	tokens++;
5942 	n_tokens--;
5943 
5944 	if (n_tokens == 0) {
5945 		snprintf(out, out_size,
5946 			"Type 'help <command>' for details on each command.\n\n"
5947 			"List of commands:\n"
5948 			"\tmempool\n"
5949 			"\tlink\n"
5950 			"\tswq\n"
5951 			"\ttmgr subport profile\n"
5952 			"\ttmgr pipe profile\n"
5953 			"\ttmgr\n"
5954 			"\ttmgr subport\n"
5955 			"\ttmgr subport pipe\n"
5956 			"\ttap\n"
5957 			"\tport in action profile\n"
5958 			"\ttable action profile\n"
5959 			"\tpipeline\n"
5960 			"\tpipeline port in\n"
5961 			"\tpipeline port out\n"
5962 			"\tpipeline table\n"
5963 			"\tpipeline port in table\n"
5964 			"\tpipeline port in stats\n"
5965 			"\tpipeline port in enable\n"
5966 			"\tpipeline port in disable\n"
5967 			"\tpipeline port out stats\n"
5968 			"\tpipeline table stats\n"
5969 			"\tpipeline table rule add\n"
5970 			"\tpipeline table rule add default\n"
5971 			"\tpipeline table rule add bulk\n"
5972 			"\tpipeline table rule delete\n"
5973 			"\tpipeline table rule delete default\n"
5974 			"\tpipeline table rule show\n"
5975 			"\tpipeline table rule stats read\n"
5976 			"\tpipeline table meter profile add\n"
5977 			"\tpipeline table meter profile delete\n"
5978 			"\tpipeline table rule meter read\n"
5979 			"\tpipeline table dscp\n"
5980 			"\tpipeline table rule ttl read\n"
5981 			"\tpipeline table rule time read\n"
5982 			"\tthread pipeline enable\n"
5983 			"\tthread pipeline disable\n\n");
5984 		return;
5985 	}
5986 
5987 	if (strcmp(tokens[0], "mempool") == 0) {
5988 		snprintf(out, out_size, "\n%s\n", cmd_mempool_help);
5989 		return;
5990 	}
5991 
5992 	if (strcmp(tokens[0], "link") == 0) {
5993 		snprintf(out, out_size, "\n%s\n", cmd_link_help);
5994 		return;
5995 	}
5996 
5997 	if (strcmp(tokens[0], "swq") == 0) {
5998 		snprintf(out, out_size, "\n%s\n", cmd_swq_help);
5999 		return;
6000 	}
6001 
6002 	if (strcmp(tokens[0], "tmgr") == 0) {
6003 		if (n_tokens == 1) {
6004 			snprintf(out, out_size, "\n%s\n", cmd_tmgr_help);
6005 			return;
6006 		}
6007 
6008 		if ((n_tokens == 2) &&
6009 			(strcmp(tokens[1], "subport")) == 0) {
6010 			snprintf(out, out_size, "\n%s\n", cmd_tmgr_subport_help);
6011 			return;
6012 		}
6013 
6014 		if ((n_tokens == 3) &&
6015 			(strcmp(tokens[1], "subport") == 0) &&
6016 			(strcmp(tokens[2], "profile") == 0)) {
6017 			snprintf(out, out_size, "\n%s\n",
6018 				cmd_tmgr_subport_profile_help);
6019 			return;
6020 		}
6021 
6022 		if ((n_tokens == 3) &&
6023 			(strcmp(tokens[1], "subport") == 0) &&
6024 			(strcmp(tokens[2], "pipe") == 0)) {
6025 			snprintf(out, out_size, "\n%s\n", cmd_tmgr_subport_pipe_help);
6026 			return;
6027 		}
6028 
6029 		if ((n_tokens == 3) &&
6030 			(strcmp(tokens[1], "pipe") == 0) &&
6031 			(strcmp(tokens[2], "profile") == 0)) {
6032 			snprintf(out, out_size, "\n%s\n", cmd_tmgr_pipe_profile_help);
6033 			return;
6034 		}
6035 	}
6036 
6037 	if (strcmp(tokens[0], "tap") == 0) {
6038 		snprintf(out, out_size, "\n%s\n", cmd_tap_help);
6039 		return;
6040 	}
6041 
6042 	if (strcmp(tokens[0], "cryptodev") == 0) {
6043 		snprintf(out, out_size, "\n%s\n", cmd_cryptodev_help);
6044 		return;
6045 	}
6046 
6047 	if ((n_tokens == 4) &&
6048 		(strcmp(tokens[0], "port") == 0) &&
6049 		(strcmp(tokens[1], "in") == 0) &&
6050 		(strcmp(tokens[2], "action") == 0) &&
6051 		(strcmp(tokens[3], "profile") == 0)) {
6052 		snprintf(out, out_size, "\n%s\n", cmd_port_in_action_profile_help);
6053 		return;
6054 	}
6055 
6056 	if ((n_tokens == 3) &&
6057 		(strcmp(tokens[0], "table") == 0) &&
6058 		(strcmp(tokens[1], "action") == 0) &&
6059 		(strcmp(tokens[2], "profile") == 0)) {
6060 		snprintf(out, out_size, "\n%s\n", cmd_table_action_profile_help);
6061 		return;
6062 	}
6063 
6064 	if ((strcmp(tokens[0], "pipeline") == 0) && (n_tokens == 1)) {
6065 		snprintf(out, out_size, "\n%s\n", cmd_pipeline_help);
6066 		return;
6067 	}
6068 
6069 	if ((strcmp(tokens[0], "pipeline") == 0) &&
6070 		(strcmp(tokens[1], "port") == 0)) {
6071 		if ((n_tokens == 3) && (strcmp(tokens[2], "in")) == 0) {
6072 			snprintf(out, out_size, "\n%s\n", cmd_pipeline_port_in_help);
6073 			return;
6074 		}
6075 
6076 		if ((n_tokens == 3) && (strcmp(tokens[2], "out")) == 0) {
6077 			snprintf(out, out_size, "\n%s\n", cmd_pipeline_port_out_help);
6078 			return;
6079 		}
6080 
6081 		if ((n_tokens == 4) &&
6082 			(strcmp(tokens[2], "in") == 0) &&
6083 			(strcmp(tokens[3], "table") == 0)) {
6084 			snprintf(out, out_size, "\n%s\n",
6085 				cmd_pipeline_port_in_table_help);
6086 			return;
6087 		}
6088 
6089 		if ((n_tokens == 4) &&
6090 			(strcmp(tokens[2], "in") == 0) &&
6091 			(strcmp(tokens[3], "stats") == 0)) {
6092 			snprintf(out, out_size, "\n%s\n",
6093 				cmd_pipeline_port_in_stats_help);
6094 			return;
6095 		}
6096 
6097 		if ((n_tokens == 4) &&
6098 			(strcmp(tokens[2], "in") == 0) &&
6099 			(strcmp(tokens[3], "enable") == 0)) {
6100 			snprintf(out, out_size, "\n%s\n",
6101 				cmd_pipeline_port_in_enable_help);
6102 			return;
6103 		}
6104 
6105 		if ((n_tokens == 4) &&
6106 			(strcmp(tokens[2], "in") == 0) &&
6107 			(strcmp(tokens[3], "disable") == 0)) {
6108 			snprintf(out, out_size, "\n%s\n",
6109 				cmd_pipeline_port_in_disable_help);
6110 			return;
6111 		}
6112 
6113 		if ((n_tokens == 4) &&
6114 			(strcmp(tokens[2], "out") == 0) &&
6115 			(strcmp(tokens[3], "stats") == 0)) {
6116 			snprintf(out, out_size, "\n%s\n",
6117 				cmd_pipeline_port_out_stats_help);
6118 			return;
6119 		}
6120 	}
6121 
6122 	if ((strcmp(tokens[0], "pipeline") == 0) &&
6123 		(strcmp(tokens[1], "table") == 0)) {
6124 		if (n_tokens == 2) {
6125 			snprintf(out, out_size, "\n%s\n", cmd_pipeline_table_help);
6126 			return;
6127 		}
6128 
6129 		if ((n_tokens == 3) && strcmp(tokens[2], "stats") == 0) {
6130 			snprintf(out, out_size, "\n%s\n",
6131 				cmd_pipeline_table_stats_help);
6132 			return;
6133 		}
6134 
6135 		if ((n_tokens == 3) && strcmp(tokens[2], "dscp") == 0) {
6136 			snprintf(out, out_size, "\n%s\n",
6137 				cmd_pipeline_table_dscp_help);
6138 			return;
6139 		}
6140 
6141 		if ((n_tokens == 4) &&
6142 			(strcmp(tokens[2], "rule") == 0) &&
6143 			(strcmp(tokens[3], "add") == 0)) {
6144 			snprintf(out, out_size, "\n%s\n",
6145 				cmd_pipeline_table_rule_add_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], "default") == 0)) {
6153 			snprintf(out, out_size, "\n%s\n",
6154 				cmd_pipeline_table_rule_add_default_help);
6155 			return;
6156 		}
6157 
6158 		if ((n_tokens == 5) &&
6159 			(strcmp(tokens[2], "rule") == 0) &&
6160 			(strcmp(tokens[3], "add") == 0) &&
6161 			(strcmp(tokens[4], "bulk") == 0)) {
6162 			snprintf(out, out_size, "\n%s\n",
6163 				cmd_pipeline_table_rule_add_bulk_help);
6164 			return;
6165 		}
6166 
6167 		if ((n_tokens == 4) &&
6168 			(strcmp(tokens[2], "rule") == 0) &&
6169 			(strcmp(tokens[3], "delete") == 0)) {
6170 			snprintf(out, out_size, "\n%s\n",
6171 				cmd_pipeline_table_rule_delete_help);
6172 			return;
6173 		}
6174 
6175 		if ((n_tokens == 5) &&
6176 			(strcmp(tokens[2], "rule") == 0) &&
6177 			(strcmp(tokens[3], "delete") == 0) &&
6178 			(strcmp(tokens[4], "default") == 0)) {
6179 			snprintf(out, out_size, "\n%s\n",
6180 				cmd_pipeline_table_rule_delete_default_help);
6181 			return;
6182 		}
6183 
6184 		if ((n_tokens == 4) &&
6185 			(strcmp(tokens[2], "rule") == 0) &&
6186 			(strcmp(tokens[3], "show") == 0)) {
6187 			snprintf(out, out_size, "\n%s\n",
6188 				cmd_pipeline_table_rule_show_help);
6189 			return;
6190 		}
6191 
6192 		if ((n_tokens == 5) &&
6193 			(strcmp(tokens[2], "rule") == 0) &&
6194 			(strcmp(tokens[3], "stats") == 0) &&
6195 			(strcmp(tokens[4], "read") == 0)) {
6196 			snprintf(out, out_size, "\n%s\n",
6197 				cmd_pipeline_table_rule_stats_read_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], "add") == 0)) {
6205 			snprintf(out, out_size, "\n%s\n",
6206 				cmd_pipeline_table_meter_profile_add_help);
6207 			return;
6208 		}
6209 
6210 		if ((n_tokens == 5) &&
6211 			(strcmp(tokens[2], "meter") == 0) &&
6212 			(strcmp(tokens[3], "profile") == 0) &&
6213 			(strcmp(tokens[4], "delete") == 0)) {
6214 			snprintf(out, out_size, "\n%s\n",
6215 				cmd_pipeline_table_meter_profile_delete_help);
6216 			return;
6217 		}
6218 
6219 		if ((n_tokens == 5) &&
6220 			(strcmp(tokens[2], "rule") == 0) &&
6221 			(strcmp(tokens[3], "meter") == 0) &&
6222 			(strcmp(tokens[4], "read") == 0)) {
6223 			snprintf(out, out_size, "\n%s\n",
6224 				cmd_pipeline_table_rule_meter_read_help);
6225 			return;
6226 		}
6227 
6228 		if ((n_tokens == 5) &&
6229 			(strcmp(tokens[2], "rule") == 0) &&
6230 			(strcmp(tokens[3], "ttl") == 0) &&
6231 			(strcmp(tokens[4], "read") == 0)) {
6232 			snprintf(out, out_size, "\n%s\n",
6233 				cmd_pipeline_table_rule_ttl_read_help);
6234 			return;
6235 		}
6236 
6237 		if ((n_tokens == 5) &&
6238 			(strcmp(tokens[2], "rule") == 0) &&
6239 			(strcmp(tokens[3], "time") == 0) &&
6240 			(strcmp(tokens[4], "read") == 0)) {
6241 			snprintf(out, out_size, "\n%s\n",
6242 				cmd_pipeline_table_rule_time_read_help);
6243 			return;
6244 		}
6245 	}
6246 
6247 	if ((n_tokens == 3) &&
6248 		(strcmp(tokens[0], "thread") == 0) &&
6249 		(strcmp(tokens[1], "pipeline") == 0)) {
6250 		if (strcmp(tokens[2], "enable") == 0) {
6251 			snprintf(out, out_size, "\n%s\n",
6252 				cmd_thread_pipeline_enable_help);
6253 			return;
6254 		}
6255 
6256 		if (strcmp(tokens[2], "disable") == 0) {
6257 			snprintf(out, out_size, "\n%s\n",
6258 				cmd_thread_pipeline_disable_help);
6259 			return;
6260 		}
6261 	}
6262 
6263 	snprintf(out, out_size, "Invalid command\n");
6264 }
6265 
6266 void
6267 cli_process(char *in, char *out, size_t out_size)
6268 {
6269 	char *tokens[CMD_MAX_TOKENS];
6270 	uint32_t n_tokens = RTE_DIM(tokens);
6271 	int status;
6272 
6273 	if (is_comment(in))
6274 		return;
6275 
6276 	status = parse_tokenize_string(in, tokens, &n_tokens);
6277 	if (status) {
6278 		snprintf(out, out_size, MSG_ARG_TOO_MANY, "");
6279 		return;
6280 	}
6281 
6282 	if (n_tokens == 0)
6283 		return;
6284 
6285 	if (strcmp(tokens[0], "help") == 0) {
6286 		cmd_help(tokens, n_tokens, out, out_size);
6287 		return;
6288 	}
6289 
6290 	if (strcmp(tokens[0], "mempool") == 0) {
6291 		cmd_mempool(tokens, n_tokens, out, out_size);
6292 		return;
6293 	}
6294 
6295 	if (strcmp(tokens[0], "link") == 0) {
6296 		if (strcmp(tokens[1], "show") == 0) {
6297 			cmd_link_show(tokens, n_tokens, out, out_size);
6298 			return;
6299 		}
6300 
6301 		cmd_link(tokens, n_tokens, out, out_size);
6302 		return;
6303 	}
6304 
6305 	if (strcmp(tokens[0], "swq") == 0) {
6306 		cmd_swq(tokens, n_tokens, out, out_size);
6307 		return;
6308 	}
6309 
6310 	if (strcmp(tokens[0], "tmgr") == 0) {
6311 		if ((n_tokens >= 3) &&
6312 			(strcmp(tokens[1], "subport") == 0) &&
6313 			(strcmp(tokens[2], "profile") == 0)) {
6314 			cmd_tmgr_subport_profile(tokens, n_tokens,
6315 				out, out_size);
6316 			return;
6317 		}
6318 
6319 		if ((n_tokens >= 3) &&
6320 			(strcmp(tokens[1], "pipe") == 0) &&
6321 			(strcmp(tokens[2], "profile") == 0)) {
6322 			cmd_tmgr_pipe_profile(tokens, n_tokens, out, out_size);
6323 			return;
6324 		}
6325 
6326 		if ((n_tokens >= 5) &&
6327 			(strcmp(tokens[2], "subport") == 0) &&
6328 			(strcmp(tokens[4], "profile") == 0)) {
6329 			cmd_tmgr_subport(tokens, n_tokens, out, out_size);
6330 			return;
6331 		}
6332 
6333 		if ((n_tokens >= 5) &&
6334 			(strcmp(tokens[2], "subport") == 0) &&
6335 			(strcmp(tokens[4], "pipe") == 0)) {
6336 			cmd_tmgr_subport_pipe(tokens, n_tokens, out, out_size);
6337 			return;
6338 		}
6339 
6340 		cmd_tmgr(tokens, n_tokens, out, out_size);
6341 		return;
6342 	}
6343 
6344 	if (strcmp(tokens[0], "tap") == 0) {
6345 		cmd_tap(tokens, n_tokens, out, out_size);
6346 		return;
6347 	}
6348 
6349 	if (strcmp(tokens[0], "cryptodev") == 0) {
6350 		cmd_cryptodev(tokens, n_tokens, out, out_size);
6351 		return;
6352 	}
6353 
6354 	if (strcmp(tokens[0], "port") == 0) {
6355 		cmd_port_in_action_profile(tokens, n_tokens, out, out_size);
6356 		return;
6357 	}
6358 
6359 	if (strcmp(tokens[0], "table") == 0) {
6360 		cmd_table_action_profile(tokens, n_tokens, out, out_size);
6361 		return;
6362 	}
6363 
6364 	if (strcmp(tokens[0], "pipeline") == 0) {
6365 		if ((n_tokens >= 3) &&
6366 			(strcmp(tokens[2], "period") == 0)) {
6367 			cmd_pipeline(tokens, n_tokens, out, out_size);
6368 			return;
6369 		}
6370 
6371 		if ((n_tokens >= 5) &&
6372 			(strcmp(tokens[2], "port") == 0) &&
6373 			(strcmp(tokens[3], "in") == 0) &&
6374 			(strcmp(tokens[4], "bsz") == 0)) {
6375 			cmd_pipeline_port_in(tokens, n_tokens, out, out_size);
6376 			return;
6377 		}
6378 
6379 		if ((n_tokens >= 5) &&
6380 			(strcmp(tokens[2], "port") == 0) &&
6381 			(strcmp(tokens[3], "out") == 0) &&
6382 			(strcmp(tokens[4], "bsz") == 0)) {
6383 			cmd_pipeline_port_out(tokens, n_tokens, out, out_size);
6384 			return;
6385 		}
6386 
6387 		if ((n_tokens >= 4) &&
6388 			(strcmp(tokens[2], "table") == 0) &&
6389 			(strcmp(tokens[3], "match") == 0)) {
6390 			cmd_pipeline_table(tokens, n_tokens, 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], "table") == 0)) {
6398 			cmd_pipeline_port_in_table(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], "stats") == 0)) {
6407 			cmd_pipeline_port_in_stats(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], "enable") == 0)) {
6416 			cmd_pipeline_port_in_enable(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], "in") == 0) &&
6424 			(strcmp(tokens[5], "disable") == 0)) {
6425 			cmd_pipeline_port_in_disable(tokens, n_tokens,
6426 				out, out_size);
6427 			return;
6428 		}
6429 
6430 		if ((n_tokens >= 6) &&
6431 			(strcmp(tokens[2], "port") == 0) &&
6432 			(strcmp(tokens[3], "out") == 0) &&
6433 			(strcmp(tokens[5], "stats") == 0)) {
6434 			cmd_pipeline_port_out_stats(tokens, n_tokens,
6435 				out, out_size);
6436 			return;
6437 		}
6438 
6439 		if ((n_tokens >= 5) &&
6440 			(strcmp(tokens[2], "table") == 0) &&
6441 			(strcmp(tokens[4], "stats") == 0)) {
6442 			cmd_pipeline_table_stats(tokens, n_tokens,
6443 				out, out_size);
6444 			return;
6445 		}
6446 
6447 		if ((n_tokens >= 7) &&
6448 			(strcmp(tokens[2], "table") == 0) &&
6449 			(strcmp(tokens[4], "rule") == 0) &&
6450 			(strcmp(tokens[5], "add") == 0) &&
6451 			(strcmp(tokens[6], "match") == 0)) {
6452 			if ((n_tokens >= 8) &&
6453 				(strcmp(tokens[7], "default") == 0)) {
6454 				cmd_pipeline_table_rule_add_default(tokens,
6455 					n_tokens, out, out_size);
6456 				return;
6457 			}
6458 
6459 			cmd_pipeline_table_rule_add(tokens, n_tokens,
6460 				out, out_size);
6461 			return;
6462 		}
6463 
6464 		if ((n_tokens >= 7) &&
6465 			(strcmp(tokens[2], "table") == 0) &&
6466 			(strcmp(tokens[4], "rule") == 0) &&
6467 			(strcmp(tokens[5], "add") == 0) &&
6468 			(strcmp(tokens[6], "bulk") == 0)) {
6469 			cmd_pipeline_table_rule_add_bulk(tokens,
6470 				n_tokens, out, out_size);
6471 			return;
6472 		}
6473 
6474 		if ((n_tokens >= 7) &&
6475 			(strcmp(tokens[2], "table") == 0) &&
6476 			(strcmp(tokens[4], "rule") == 0) &&
6477 			(strcmp(tokens[5], "delete") == 0) &&
6478 			(strcmp(tokens[6], "match") == 0)) {
6479 			if ((n_tokens >= 8) &&
6480 				(strcmp(tokens[7], "default") == 0)) {
6481 				cmd_pipeline_table_rule_delete_default(tokens,
6482 					n_tokens, out, out_size);
6483 				return;
6484 				}
6485 
6486 			cmd_pipeline_table_rule_delete(tokens, n_tokens,
6487 				out, out_size);
6488 			return;
6489 		}
6490 
6491 		if ((n_tokens >= 6) &&
6492 			(strcmp(tokens[2], "table") == 0) &&
6493 			(strcmp(tokens[4], "rule") == 0) &&
6494 			(strcmp(tokens[5], "show") == 0)) {
6495 			cmd_pipeline_table_rule_show(tokens, n_tokens,
6496 				out, out_size);
6497 			return;
6498 		}
6499 
6500 		if ((n_tokens >= 7) &&
6501 			(strcmp(tokens[2], "table") == 0) &&
6502 			(strcmp(tokens[4], "rule") == 0) &&
6503 			(strcmp(tokens[5], "read") == 0) &&
6504 			(strcmp(tokens[6], "stats") == 0)) {
6505 			cmd_pipeline_table_rule_stats_read(tokens, n_tokens,
6506 				out, out_size);
6507 			return;
6508 		}
6509 
6510 		if ((n_tokens >= 8) &&
6511 			(strcmp(tokens[2], "table") == 0) &&
6512 			(strcmp(tokens[4], "meter") == 0) &&
6513 			(strcmp(tokens[5], "profile") == 0) &&
6514 			(strcmp(tokens[7], "add") == 0)) {
6515 			cmd_pipeline_table_meter_profile_add(tokens, n_tokens,
6516 				out, out_size);
6517 			return;
6518 		}
6519 
6520 		if ((n_tokens >= 8) &&
6521 			(strcmp(tokens[2], "table") == 0) &&
6522 			(strcmp(tokens[4], "meter") == 0) &&
6523 			(strcmp(tokens[5], "profile") == 0) &&
6524 			(strcmp(tokens[7], "delete") == 0)) {
6525 			cmd_pipeline_table_meter_profile_delete(tokens,
6526 				n_tokens, out, out_size);
6527 			return;
6528 		}
6529 
6530 		if ((n_tokens >= 7) &&
6531 			(strcmp(tokens[2], "table") == 0) &&
6532 			(strcmp(tokens[4], "rule") == 0) &&
6533 			(strcmp(tokens[5], "read") == 0) &&
6534 			(strcmp(tokens[6], "meter") == 0)) {
6535 			cmd_pipeline_table_rule_meter_read(tokens, n_tokens,
6536 				out, out_size);
6537 			return;
6538 		}
6539 
6540 		if ((n_tokens >= 5) &&
6541 			(strcmp(tokens[2], "table") == 0) &&
6542 			(strcmp(tokens[4], "dscp") == 0)) {
6543 			cmd_pipeline_table_dscp(tokens, n_tokens,
6544 				out, out_size);
6545 			return;
6546 		}
6547 
6548 		if ((n_tokens >= 7) &&
6549 			(strcmp(tokens[2], "table") == 0) &&
6550 			(strcmp(tokens[4], "rule") == 0) &&
6551 			(strcmp(tokens[5], "read") == 0) &&
6552 			(strcmp(tokens[6], "ttl") == 0)) {
6553 			cmd_pipeline_table_rule_ttl_read(tokens, n_tokens,
6554 				out, out_size);
6555 			return;
6556 		}
6557 
6558 		if ((n_tokens >= 7) &&
6559 			(strcmp(tokens[2], "table") == 0) &&
6560 			(strcmp(tokens[4], "rule") == 0) &&
6561 			(strcmp(tokens[5], "read") == 0) &&
6562 			(strcmp(tokens[6], "time") == 0)) {
6563 			cmd_pipeline_table_rule_time_read(tokens, n_tokens,
6564 				out, out_size);
6565 			return;
6566 		}
6567 	}
6568 
6569 	if (strcmp(tokens[0], "thread") == 0) {
6570 		if ((n_tokens >= 5) &&
6571 			(strcmp(tokens[4], "enable") == 0)) {
6572 			cmd_thread_pipeline_enable(tokens, n_tokens,
6573 				out, out_size);
6574 			return;
6575 		}
6576 
6577 		if ((n_tokens >= 5) &&
6578 			(strcmp(tokens[4], "disable") == 0)) {
6579 			cmd_thread_pipeline_disable(tokens, n_tokens,
6580 				out, out_size);
6581 			return;
6582 		}
6583 	}
6584 
6585 	snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
6586 }
6587 
6588 int
6589 cli_script_process(const char *file_name,
6590 	size_t msg_in_len_max,
6591 	size_t msg_out_len_max)
6592 {
6593 	char *msg_in = NULL, *msg_out = NULL;
6594 	FILE *f = NULL;
6595 
6596 	/* Check input arguments */
6597 	if ((file_name == NULL) ||
6598 		(strlen(file_name) == 0) ||
6599 		(msg_in_len_max == 0) ||
6600 		(msg_out_len_max == 0))
6601 		return -EINVAL;
6602 
6603 	msg_in = malloc(msg_in_len_max + 1);
6604 	msg_out = malloc(msg_out_len_max + 1);
6605 	if ((msg_in == NULL) ||
6606 		(msg_out == NULL)) {
6607 		free(msg_out);
6608 		free(msg_in);
6609 		return -ENOMEM;
6610 	}
6611 
6612 	/* Open input file */
6613 	f = fopen(file_name, "r");
6614 	if (f == NULL) {
6615 		free(msg_out);
6616 		free(msg_in);
6617 		return -EIO;
6618 	}
6619 
6620 	/* Read file */
6621 	for ( ; ; ) {
6622 		if (fgets(msg_in, msg_in_len_max + 1, f) == NULL)
6623 			break;
6624 
6625 		printf("%s", msg_in);
6626 		msg_out[0] = 0;
6627 
6628 		cli_process(msg_in,
6629 			msg_out,
6630 			msg_out_len_max);
6631 
6632 		if (strlen(msg_out))
6633 			printf("%s", msg_out);
6634 	}
6635 
6636 	/* Close file */
6637 	fclose(f);
6638 	free(msg_out);
6639 	free(msg_in);
6640 	return 0;
6641 }
6642 
6643 static int
6644 cli_rule_file_process(const char *file_name,
6645 	size_t line_len_max,
6646 	struct table_rule_list **rule_list,
6647 	uint32_t *n_rules,
6648 	uint32_t *line_number,
6649 	char *out,
6650 	size_t out_size)
6651 {
6652 	struct table_rule_list *list = NULL;
6653 	char *line = NULL;
6654 	FILE *f = NULL;
6655 	uint32_t rule_id = 0, line_id = 0;
6656 	int status = 0;
6657 
6658 	/* Check input arguments */
6659 	if ((file_name == NULL) ||
6660 		(strlen(file_name) == 0) ||
6661 		(line_len_max == 0) ||
6662 		(rule_list == NULL) ||
6663 		(n_rules == NULL) ||
6664 		(line_number == NULL) ||
6665 		(out == NULL)) {
6666 		status = -EINVAL;
6667 		goto cli_rule_file_process_free;
6668 	}
6669 
6670 	/* Memory allocation */
6671 	list = malloc(sizeof(struct table_rule_list));
6672 	if (list == NULL) {
6673 		status = -ENOMEM;
6674 		goto cli_rule_file_process_free;
6675 	}
6676 
6677 	TAILQ_INIT(list);
6678 
6679 	line = malloc(line_len_max + 1);
6680 	if (line == NULL) {
6681 		status = -ENOMEM;
6682 		goto cli_rule_file_process_free;
6683 	}
6684 
6685 	/* Open file */
6686 	f = fopen(file_name, "r");
6687 	if (f == NULL) {
6688 		status = -EIO;
6689 		goto cli_rule_file_process_free;
6690 	}
6691 
6692 	/* Read file */
6693 	for (line_id = 1, rule_id = 0; ; line_id++) {
6694 		char *tokens[CMD_MAX_TOKENS];
6695 		struct table_rule *rule = NULL;
6696 		uint32_t n_tokens, n_tokens_parsed, t0;
6697 
6698 		/* Read next line from file. */
6699 		if (fgets(line, line_len_max + 1, f) == NULL)
6700 			break;
6701 
6702 		/* Comment. */
6703 		if (is_comment(line))
6704 			continue;
6705 
6706 		/* Parse line. */
6707 		n_tokens = RTE_DIM(tokens);
6708 		status = parse_tokenize_string(line, tokens, &n_tokens);
6709 		if (status) {
6710 			status = -EINVAL;
6711 			goto cli_rule_file_process_free;
6712 		}
6713 
6714 		/* Empty line. */
6715 		if (n_tokens == 0)
6716 			continue;
6717 		t0 = 0;
6718 
6719 		/* Rule alloc and insert. */
6720 		rule = calloc(1, sizeof(struct table_rule));
6721 		if (rule == NULL) {
6722 			status = -ENOMEM;
6723 			goto cli_rule_file_process_free;
6724 		}
6725 
6726 		TAILQ_INSERT_TAIL(list, rule, node);
6727 
6728 		/* Rule match. */
6729 		n_tokens_parsed = parse_match(tokens + t0,
6730 			n_tokens - t0,
6731 			out,
6732 			out_size,
6733 			&rule->match);
6734 		if (n_tokens_parsed == 0) {
6735 			status = -EINVAL;
6736 			goto cli_rule_file_process_free;
6737 		}
6738 		t0 += n_tokens_parsed;
6739 
6740 		/* Rule action. */
6741 		n_tokens_parsed = parse_table_action(tokens + t0,
6742 			n_tokens - t0,
6743 			out,
6744 			out_size,
6745 			&rule->action);
6746 		if (n_tokens_parsed == 0) {
6747 			status = -EINVAL;
6748 			goto cli_rule_file_process_free;
6749 		}
6750 		t0 += n_tokens_parsed;
6751 
6752 		/* Line completed. */
6753 		if (t0 < n_tokens) {
6754 			status = -EINVAL;
6755 			goto cli_rule_file_process_free;
6756 		}
6757 
6758 		/* Increment rule count */
6759 		rule_id++;
6760 	}
6761 
6762 	/* Close file */
6763 	fclose(f);
6764 
6765 	/* Memory free */
6766 	free(line);
6767 
6768 	*rule_list = list;
6769 	*n_rules = rule_id;
6770 	*line_number = line_id;
6771 	return 0;
6772 
6773 cli_rule_file_process_free:
6774 	if (rule_list != NULL)
6775 		*rule_list = NULL;
6776 
6777 	if (n_rules != NULL)
6778 		*n_rules = rule_id;
6779 
6780 	if (line_number != NULL)
6781 		*line_number = line_id;
6782 
6783 	if (list != NULL)
6784 		for ( ; ; ) {
6785 			struct table_rule *rule;
6786 
6787 			rule = TAILQ_FIRST(list);
6788 			if (rule == NULL)
6789 				break;
6790 
6791 			TAILQ_REMOVE(list, rule, node);
6792 			free(rule);
6793 		}
6794 
6795 	if (f)
6796 		fclose(f);
6797 	free(line);
6798 	free(list);
6799 
6800 	return status;
6801 }
6802