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