xref: /dpdk/drivers/net/softnic/rte_eth_softnic_cli.c (revision 202905f3ee4db9df45f00da90da99e0655e60ef6)
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_eth_softnic_internals.h"
11 #include "parser.h"
12 
13 #ifndef CMD_MAX_TOKENS
14 #define CMD_MAX_TOKENS     256
15 #endif
16 
17 #define MSG_OUT_OF_MEMORY   "Not enough memory.\n"
18 #define MSG_CMD_UNKNOWN     "Unknown command \"%s\".\n"
19 #define MSG_CMD_UNIMPLEM    "Command \"%s\" not implemented.\n"
20 #define MSG_ARG_NOT_ENOUGH  "Not enough arguments for command \"%s\".\n"
21 #define MSG_ARG_TOO_MANY    "Too many arguments for command \"%s\".\n"
22 #define MSG_ARG_MISMATCH    "Wrong number of arguments for command \"%s\".\n"
23 #define MSG_ARG_NOT_FOUND   "Argument \"%s\" not found.\n"
24 #define MSG_ARG_INVALID     "Invalid value for argument \"%s\".\n"
25 #define MSG_FILE_ERR        "Error in file \"%s\" at line %u.\n"
26 #define MSG_FILE_NOT_ENOUGH "Not enough rules in file \"%s\".\n"
27 #define MSG_CMD_FAIL        "Command \"%s\" failed.\n"
28 
29 static int
30 is_comment(char *in)
31 {
32 	if ((strlen(in) && index("!#%;", in[0])) ||
33 		(strncmp(in, "//", 2) == 0) ||
34 		(strncmp(in, "--", 2) == 0))
35 		return 1;
36 
37 	return 0;
38 }
39 
40 /**
41  * mempool <mempool_name>
42  *  buffer <buffer_size>
43  *  pool <pool_size>
44  *  cache <cache_size>
45  */
46 static void
47 cmd_mempool(struct pmd_internals *softnic,
48 	char **tokens,
49 	uint32_t n_tokens,
50 	char *out,
51 	size_t out_size)
52 {
53 	struct softnic_mempool_params p;
54 	char *name;
55 	struct softnic_mempool *mempool;
56 
57 	if (n_tokens != 8) {
58 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
59 		return;
60 	}
61 
62 	name = tokens[1];
63 
64 	if (strcmp(tokens[2], "buffer") != 0) {
65 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "buffer");
66 		return;
67 	}
68 
69 	if (softnic_parser_read_uint32(&p.buffer_size, tokens[3]) != 0) {
70 		snprintf(out, out_size, MSG_ARG_INVALID, "buffer_size");
71 		return;
72 	}
73 
74 	if (strcmp(tokens[4], "pool") != 0) {
75 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pool");
76 		return;
77 	}
78 
79 	if (softnic_parser_read_uint32(&p.pool_size, tokens[5]) != 0) {
80 		snprintf(out, out_size, MSG_ARG_INVALID, "pool_size");
81 		return;
82 	}
83 
84 	if (strcmp(tokens[6], "cache") != 0) {
85 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cache");
86 		return;
87 	}
88 
89 	if (softnic_parser_read_uint32(&p.cache_size, tokens[7]) != 0) {
90 		snprintf(out, out_size, MSG_ARG_INVALID, "cache_size");
91 		return;
92 	}
93 
94 	mempool = softnic_mempool_create(softnic, name, &p);
95 	if (mempool == NULL) {
96 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
97 		return;
98 	}
99 }
100 
101 /**
102  * link <link_name>
103  *    dev <device_name> | port <port_id>
104  */
105 static void
106 cmd_link(struct pmd_internals *softnic,
107 	char **tokens,
108 	uint32_t n_tokens,
109 	char *out,
110 	size_t out_size)
111 {
112 	struct softnic_link_params p;
113 	struct softnic_link *link;
114 	char *name;
115 
116 	memset(&p, 0, sizeof(p));
117 
118 	if (n_tokens != 4) {
119 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
120 		return;
121 	}
122 	name = tokens[1];
123 
124 	if (strcmp(tokens[2], "dev") == 0) {
125 		p.dev_name = tokens[3];
126 	} else if (strcmp(tokens[2], "port") == 0) {
127 		p.dev_name = NULL;
128 
129 		if (softnic_parser_read_uint16(&p.port_id, tokens[3]) != 0) {
130 			snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
131 			return;
132 		}
133 	} else {
134 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "dev or port");
135 		return;
136 	}
137 
138 	link = softnic_link_create(softnic, name, &p);
139 	if (link == NULL) {
140 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
141 		return;
142 	}
143 }
144 
145 /**
146  * swq <swq_name>
147  *  size <size>
148  */
149 static void
150 cmd_swq(struct pmd_internals *softnic,
151 	char **tokens,
152 	uint32_t n_tokens,
153 	char *out,
154 	size_t out_size)
155 {
156 	struct softnic_swq_params p;
157 	char *name;
158 	struct softnic_swq *swq;
159 
160 	if (n_tokens != 4) {
161 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
162 		return;
163 	}
164 
165 	name = tokens[1];
166 
167 	if (strcmp(tokens[2], "size") != 0) {
168 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
169 		return;
170 	}
171 
172 	if (softnic_parser_read_uint32(&p.size, tokens[3]) != 0) {
173 		snprintf(out, out_size, MSG_ARG_INVALID, "size");
174 		return;
175 	}
176 
177 	swq = softnic_swq_create(softnic, name, &p);
178 	if (swq == NULL) {
179 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
180 		return;
181 	}
182 }
183 
184 /**
185  * tap <tap_name>
186  */
187 static void
188 cmd_tap(struct pmd_internals *softnic,
189 	char **tokens,
190 	uint32_t n_tokens,
191 	char *out,
192 	size_t out_size)
193 {
194 	char *name;
195 	struct softnic_tap *tap;
196 
197 	if (n_tokens != 2) {
198 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
199 		return;
200 	}
201 
202 	name = tokens[1];
203 
204 	tap = softnic_tap_create(softnic, name);
205 	if (tap == NULL) {
206 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
207 		return;
208 	}
209 }
210 
211 /**
212  * port in action profile <profile_name>
213  *  [filter match | mismatch offset <key_offset> mask <key_mask> key <key_value> port <port_id>]
214  *  [balance offset <key_offset> mask <key_mask> port <port_id0> ... <port_id15>]
215  */
216 static void
217 cmd_port_in_action_profile(struct pmd_internals *softnic,
218 	char **tokens,
219 	uint32_t n_tokens,
220 	char *out,
221 	size_t out_size)
222 {
223 	struct softnic_port_in_action_profile_params p;
224 	struct softnic_port_in_action_profile *ap;
225 	char *name;
226 	uint32_t t0;
227 
228 	memset(&p, 0, sizeof(p));
229 
230 	if (n_tokens < 5) {
231 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
232 		return;
233 	}
234 
235 	if (strcmp(tokens[1], "in") != 0) {
236 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
237 		return;
238 	}
239 
240 	if (strcmp(tokens[2], "action") != 0) {
241 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "action");
242 		return;
243 	}
244 
245 	if (strcmp(tokens[3], "profile") != 0) {
246 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
247 		return;
248 	}
249 
250 	name = tokens[4];
251 
252 	t0 = 5;
253 
254 	if (t0 < n_tokens &&
255 		(strcmp(tokens[t0], "filter") == 0)) {
256 		uint32_t size;
257 
258 		if (n_tokens < t0 + 10) {
259 			snprintf(out, out_size, MSG_ARG_MISMATCH, "port in action profile filter");
260 			return;
261 		}
262 
263 		if (strcmp(tokens[t0 + 1], "match") == 0) {
264 			p.fltr.filter_on_match = 1;
265 		} else if (strcmp(tokens[t0 + 1], "mismatch") == 0) {
266 			p.fltr.filter_on_match = 0;
267 		} else {
268 			snprintf(out, out_size, MSG_ARG_INVALID, "match or mismatch");
269 			return;
270 		}
271 
272 		if (strcmp(tokens[t0 + 2], "offset") != 0) {
273 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
274 			return;
275 		}
276 
277 		if (softnic_parser_read_uint32(&p.fltr.key_offset,
278 			tokens[t0 + 3]) != 0) {
279 			snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
280 			return;
281 		}
282 
283 		if (strcmp(tokens[t0 + 4], "mask") != 0) {
284 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask");
285 			return;
286 		}
287 
288 		size = RTE_PORT_IN_ACTION_FLTR_KEY_SIZE;
289 		if ((softnic_parse_hex_string(tokens[t0 + 5],
290 			p.fltr.key_mask, &size) != 0) ||
291 			size != RTE_PORT_IN_ACTION_FLTR_KEY_SIZE) {
292 			snprintf(out, out_size, MSG_ARG_INVALID, "key_mask");
293 			return;
294 		}
295 
296 		if (strcmp(tokens[t0 + 6], "key") != 0) {
297 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "key");
298 			return;
299 		}
300 
301 		size = RTE_PORT_IN_ACTION_FLTR_KEY_SIZE;
302 		if ((softnic_parse_hex_string(tokens[t0 + 7],
303 			p.fltr.key, &size) != 0) ||
304 			size != RTE_PORT_IN_ACTION_FLTR_KEY_SIZE) {
305 			snprintf(out, out_size, MSG_ARG_INVALID, "key_value");
306 			return;
307 		}
308 
309 		if (strcmp(tokens[t0 + 8], "port") != 0) {
310 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
311 			return;
312 		}
313 
314 		if (softnic_parser_read_uint32(&p.fltr.port_id,
315 			tokens[t0 + 9]) != 0) {
316 			snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
317 			return;
318 		}
319 
320 		p.action_mask |= 1LLU << RTE_PORT_IN_ACTION_FLTR;
321 		t0 += 10;
322 	} /* filter */
323 
324 	if (t0 < n_tokens &&
325 		(strcmp(tokens[t0], "balance") == 0)) {
326 		uint32_t i;
327 
328 		if (n_tokens < t0 + 22) {
329 			snprintf(out, out_size, MSG_ARG_MISMATCH,
330 				"port in action profile balance");
331 			return;
332 		}
333 
334 		if (strcmp(tokens[t0 + 1], "offset") != 0) {
335 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
336 			return;
337 		}
338 
339 		if (softnic_parser_read_uint32(&p.lb.key_offset,
340 			tokens[t0 + 2]) != 0) {
341 			snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
342 			return;
343 		}
344 
345 		if (strcmp(tokens[t0 + 3], "mask") != 0) {
346 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask");
347 			return;
348 		}
349 
350 		p.lb.key_size = RTE_PORT_IN_ACTION_LB_KEY_SIZE_MAX;
351 		if (softnic_parse_hex_string(tokens[t0 + 4],
352 			p.lb.key_mask, &p.lb.key_size) != 0) {
353 			snprintf(out, out_size, MSG_ARG_INVALID, "key_mask");
354 			return;
355 		}
356 
357 		if (strcmp(tokens[t0 + 5], "port") != 0) {
358 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
359 			return;
360 		}
361 
362 		for (i = 0; i < 16; i++)
363 			if (softnic_parser_read_uint32(&p.lb.port_id[i],
364 			tokens[t0 + 6 + i]) != 0) {
365 				snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
366 				return;
367 			}
368 
369 		p.action_mask |= 1LLU << RTE_PORT_IN_ACTION_LB;
370 		t0 += 22;
371 	} /* balance */
372 
373 	if (t0 < n_tokens) {
374 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
375 		return;
376 	}
377 
378 	ap = softnic_port_in_action_profile_create(softnic, name, &p);
379 	if (ap == NULL) {
380 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
381 		return;
382 	}
383 }
384 
385 /**
386  * table action profile <profile_name>
387  *  ipv4 | ipv6
388  *  offset <ip_offset>
389  *  fwd
390  *  [balance offset <key_offset> mask <key_mask> outoffset <out_offset>]
391  *  [meter srtcm | trtcm
392  *      tc <n_tc>
393  *      stats none | pkts | bytes | both]
394  *  [tm spp <n_subports_per_port> pps <n_pipes_per_subport>]
395  *  [encap ether | vlan | qinq | mpls | pppoe]
396  *  [nat src | dst
397  *      proto udp | tcp]
398  *  [ttl drop | fwd
399  *      stats none | pkts]
400  *  [stats pkts | bytes | both]
401  *  [time]
402  */
403 static void
404 cmd_table_action_profile(struct pmd_internals *softnic,
405 	char **tokens,
406 	uint32_t n_tokens,
407 	char *out,
408 	size_t out_size)
409 {
410 	struct softnic_table_action_profile_params p;
411 	struct softnic_table_action_profile *ap;
412 	char *name;
413 	uint32_t t0;
414 
415 	memset(&p, 0, sizeof(p));
416 
417 	if (n_tokens < 8) {
418 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
419 		return;
420 	}
421 
422 	if (strcmp(tokens[1], "action") != 0) {
423 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "action");
424 		return;
425 	}
426 
427 	if (strcmp(tokens[2], "profile") != 0) {
428 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
429 		return;
430 	}
431 
432 	name = tokens[3];
433 
434 	if (strcmp(tokens[4], "ipv4") == 0) {
435 		p.common.ip_version = 1;
436 	} else if (strcmp(tokens[4], "ipv6") == 0) {
437 		p.common.ip_version = 0;
438 	} else {
439 		snprintf(out, out_size, MSG_ARG_INVALID, "ipv4 or ipv6");
440 		return;
441 	}
442 
443 	if (strcmp(tokens[5], "offset") != 0) {
444 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
445 		return;
446 	}
447 
448 	if (softnic_parser_read_uint32(&p.common.ip_offset,
449 		tokens[6]) != 0) {
450 		snprintf(out, out_size, MSG_ARG_INVALID, "ip_offset");
451 		return;
452 	}
453 
454 	if (strcmp(tokens[7], "fwd") != 0) {
455 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "fwd");
456 		return;
457 	}
458 
459 	p.action_mask |= 1LLU << RTE_TABLE_ACTION_FWD;
460 
461 	t0 = 8;
462 	if (t0 < n_tokens &&
463 		(strcmp(tokens[t0], "balance") == 0)) {
464 		if (n_tokens < t0 + 7) {
465 			snprintf(out, out_size, MSG_ARG_MISMATCH, "table action profile balance");
466 			return;
467 		}
468 
469 		if (strcmp(tokens[t0 + 1], "offset") != 0) {
470 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
471 			return;
472 		}
473 
474 		if (softnic_parser_read_uint32(&p.lb.key_offset,
475 			tokens[t0 + 2]) != 0) {
476 			snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
477 			return;
478 		}
479 
480 		if (strcmp(tokens[t0 + 3], "mask") != 0) {
481 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask");
482 			return;
483 		}
484 
485 		p.lb.key_size = RTE_PORT_IN_ACTION_LB_KEY_SIZE_MAX;
486 		if (softnic_parse_hex_string(tokens[t0 + 4],
487 			p.lb.key_mask, &p.lb.key_size) != 0) {
488 			snprintf(out, out_size, MSG_ARG_INVALID, "key_mask");
489 			return;
490 		}
491 
492 		if (strcmp(tokens[t0 + 5], "outoffset") != 0) {
493 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "outoffset");
494 			return;
495 		}
496 
497 		if (softnic_parser_read_uint32(&p.lb.out_offset,
498 			tokens[t0 + 6]) != 0) {
499 			snprintf(out, out_size, MSG_ARG_INVALID, "out_offset");
500 			return;
501 		}
502 
503 		p.action_mask |= 1LLU << RTE_TABLE_ACTION_LB;
504 		t0 += 7;
505 	} /* balance */
506 
507 	if (t0 < n_tokens &&
508 		(strcmp(tokens[t0], "meter") == 0)) {
509 		if (n_tokens < t0 + 6) {
510 			snprintf(out, out_size, MSG_ARG_MISMATCH,
511 				"table action profile meter");
512 			return;
513 		}
514 
515 		if (strcmp(tokens[t0 + 1], "srtcm") == 0) {
516 			p.mtr.alg = RTE_TABLE_ACTION_METER_SRTCM;
517 		} else if (strcmp(tokens[t0 + 1], "trtcm") == 0) {
518 			p.mtr.alg = RTE_TABLE_ACTION_METER_TRTCM;
519 		} else {
520 			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
521 				"srtcm or trtcm");
522 			return;
523 		}
524 
525 		if (strcmp(tokens[t0 + 2], "tc") != 0) {
526 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc");
527 			return;
528 		}
529 
530 		if (softnic_parser_read_uint32(&p.mtr.n_tc,
531 			tokens[t0 + 3]) != 0) {
532 			snprintf(out, out_size, MSG_ARG_INVALID, "n_tc");
533 			return;
534 		}
535 
536 		if (strcmp(tokens[t0 + 4], "stats") != 0) {
537 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
538 			return;
539 		}
540 
541 		if (strcmp(tokens[t0 + 5], "none") == 0) {
542 			p.mtr.n_packets_enabled = 0;
543 			p.mtr.n_bytes_enabled = 0;
544 		} else if (strcmp(tokens[t0 + 5], "pkts") == 0) {
545 			p.mtr.n_packets_enabled = 1;
546 			p.mtr.n_bytes_enabled = 0;
547 		} else if (strcmp(tokens[t0 + 5], "bytes") == 0) {
548 			p.mtr.n_packets_enabled = 0;
549 			p.mtr.n_bytes_enabled = 1;
550 		} else if (strcmp(tokens[t0 + 5], "both") == 0) {
551 			p.mtr.n_packets_enabled = 1;
552 			p.mtr.n_bytes_enabled = 1;
553 		} else {
554 			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
555 				"none or pkts or bytes or both");
556 			return;
557 		}
558 
559 		p.action_mask |= 1LLU << RTE_TABLE_ACTION_MTR;
560 		t0 += 6;
561 	} /* meter */
562 
563 	if (t0 < n_tokens &&
564 		(strcmp(tokens[t0], "tm") == 0)) {
565 		if (n_tokens < t0 + 5) {
566 			snprintf(out, out_size, MSG_ARG_MISMATCH,
567 				"table action profile tm");
568 			return;
569 		}
570 
571 		if (strcmp(tokens[t0 + 1], "spp") != 0) {
572 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "spp");
573 			return;
574 		}
575 
576 		if (softnic_parser_read_uint32(&p.tm.n_subports_per_port,
577 			tokens[t0 + 2]) != 0) {
578 			snprintf(out, out_size, MSG_ARG_INVALID,
579 				"n_subports_per_port");
580 			return;
581 		}
582 
583 		if (strcmp(tokens[t0 + 3], "pps") != 0) {
584 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pps");
585 			return;
586 		}
587 
588 		if (softnic_parser_read_uint32(&p.tm.n_pipes_per_subport,
589 			tokens[t0 + 4]) != 0) {
590 			snprintf(out, out_size, MSG_ARG_INVALID,
591 				"n_pipes_per_subport");
592 			return;
593 		}
594 
595 		p.action_mask |= 1LLU << RTE_TABLE_ACTION_TM;
596 		t0 += 5;
597 	} /* tm */
598 
599 	if (t0 < n_tokens &&
600 		(strcmp(tokens[t0], "encap") == 0)) {
601 		if (n_tokens < t0 + 2) {
602 			snprintf(out, out_size, MSG_ARG_MISMATCH,
603 				"action profile encap");
604 			return;
605 		}
606 
607 		if (strcmp(tokens[t0 + 1], "ether") == 0) {
608 			p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_ETHER;
609 		} else if (strcmp(tokens[t0 + 1], "vlan") == 0) {
610 			p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_VLAN;
611 		} else if (strcmp(tokens[t0 + 1], "qinq") == 0) {
612 			p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_QINQ;
613 		} else if (strcmp(tokens[t0 + 1], "mpls") == 0) {
614 			p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_MPLS;
615 		} else if (strcmp(tokens[t0 + 1], "pppoe") == 0) {
616 			p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_PPPOE;
617 		} else {
618 			snprintf(out, out_size, MSG_ARG_MISMATCH, "encap");
619 			return;
620 		}
621 
622 		p.action_mask |= 1LLU << RTE_TABLE_ACTION_ENCAP;
623 		t0 += 2;
624 	} /* encap */
625 
626 	if (t0 < n_tokens &&
627 		(strcmp(tokens[t0], "nat") == 0)) {
628 		if (n_tokens < t0 + 4) {
629 			snprintf(out, out_size, MSG_ARG_MISMATCH,
630 				"table action profile nat");
631 			return;
632 		}
633 
634 		if (strcmp(tokens[t0 + 1], "src") == 0) {
635 			p.nat.source_nat = 1;
636 		} else if (strcmp(tokens[t0 + 1], "dst") == 0) {
637 			p.nat.source_nat = 0;
638 		} else {
639 			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
640 				"src or dst");
641 			return;
642 		}
643 
644 		if (strcmp(tokens[t0 + 2], "proto") != 0) {
645 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "proto");
646 			return;
647 		}
648 
649 		if (strcmp(tokens[t0 + 3], "tcp") == 0) {
650 			p.nat.proto = 0x06;
651 		} else if (strcmp(tokens[t0 + 3], "udp") == 0) {
652 			p.nat.proto = 0x11;
653 		} else {
654 			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
655 				"tcp or udp");
656 			return;
657 		}
658 
659 		p.action_mask |= 1LLU << RTE_TABLE_ACTION_NAT;
660 		t0 += 4;
661 	} /* nat */
662 
663 	if (t0 < n_tokens &&
664 		(strcmp(tokens[t0], "ttl") == 0)) {
665 		if (n_tokens < t0 + 4) {
666 			snprintf(out, out_size, MSG_ARG_MISMATCH,
667 				"table action profile ttl");
668 			return;
669 		}
670 
671 		if (strcmp(tokens[t0 + 1], "drop") == 0) {
672 			p.ttl.drop = 1;
673 		} else if (strcmp(tokens[t0 + 1], "fwd") == 0) {
674 			p.ttl.drop = 0;
675 		} else {
676 			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
677 				"drop or fwd");
678 			return;
679 		}
680 
681 		if (strcmp(tokens[t0 + 2], "stats") != 0) {
682 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
683 			return;
684 		}
685 
686 		if (strcmp(tokens[t0 + 3], "none") == 0) {
687 			p.ttl.n_packets_enabled = 0;
688 		} else if (strcmp(tokens[t0 + 3], "pkts") == 0) {
689 			p.ttl.n_packets_enabled = 1;
690 		} else {
691 			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
692 				"none or pkts");
693 			return;
694 		}
695 
696 		p.action_mask |= 1LLU << RTE_TABLE_ACTION_TTL;
697 		t0 += 4;
698 	} /* ttl */
699 
700 	if (t0 < n_tokens &&
701 		(strcmp(tokens[t0], "stats") == 0)) {
702 		if (n_tokens < t0 + 2) {
703 			snprintf(out, out_size, MSG_ARG_MISMATCH,
704 				"table action profile stats");
705 			return;
706 		}
707 
708 		if (strcmp(tokens[t0 + 1], "pkts") == 0) {
709 			p.stats.n_packets_enabled = 1;
710 			p.stats.n_bytes_enabled = 0;
711 		} else if (strcmp(tokens[t0 + 1], "bytes") == 0) {
712 			p.stats.n_packets_enabled = 0;
713 			p.stats.n_bytes_enabled = 1;
714 		} else if (strcmp(tokens[t0 + 1], "both") == 0) {
715 			p.stats.n_packets_enabled = 1;
716 			p.stats.n_bytes_enabled = 1;
717 		} else {
718 			snprintf(out, out_size,	MSG_ARG_NOT_FOUND,
719 				"pkts or bytes or both");
720 			return;
721 		}
722 
723 		p.action_mask |= 1LLU << RTE_TABLE_ACTION_STATS;
724 		t0 += 2;
725 	} /* stats */
726 
727 	if (t0 < n_tokens &&
728 		(strcmp(tokens[t0], "time") == 0)) {
729 		p.action_mask |= 1LLU << RTE_TABLE_ACTION_TIME;
730 		t0 += 1;
731 	} /* time */
732 
733 	if (t0 < n_tokens) {
734 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
735 		return;
736 	}
737 
738 	ap = softnic_table_action_profile_create(softnic, name, &p);
739 	if (ap == NULL) {
740 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
741 		return;
742 	}
743 }
744 
745 /**
746  * pipeline <pipeline_name>
747  *  period <timer_period_ms>
748  *  offset_port_id <offset_port_id>
749  */
750 static void
751 cmd_pipeline(struct pmd_internals *softnic,
752 	char **tokens,
753 	uint32_t n_tokens,
754 	char *out,
755 	size_t out_size)
756 {
757 	struct pipeline_params p;
758 	char *name;
759 	struct pipeline *pipeline;
760 
761 	if (n_tokens != 6) {
762 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
763 		return;
764 	}
765 
766 	name = tokens[1];
767 
768 	if (strcmp(tokens[2], "period") != 0) {
769 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "period");
770 		return;
771 	}
772 
773 	if (softnic_parser_read_uint32(&p.timer_period_ms,
774 		tokens[3]) != 0) {
775 		snprintf(out, out_size, MSG_ARG_INVALID, "timer_period_ms");
776 		return;
777 	}
778 
779 	if (strcmp(tokens[4], "offset_port_id") != 0) {
780 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset_port_id");
781 		return;
782 	}
783 
784 	if (softnic_parser_read_uint32(&p.offset_port_id,
785 		tokens[5]) != 0) {
786 		snprintf(out, out_size, MSG_ARG_INVALID, "offset_port_id");
787 		return;
788 	}
789 
790 	pipeline = softnic_pipeline_create(softnic, name, &p);
791 	if (pipeline == NULL) {
792 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
793 		return;
794 	}
795 }
796 
797 /**
798  * pipeline <pipeline_name> port in
799  *  bsz <burst_size>
800  *  link <link_name> rxq <queue_id>
801  *  | swq <swq_name>
802  *  | tmgr <tmgr_name>
803  *  | tap <tap_name> mempool <mempool_name> mtu <mtu>
804  *  | source mempool <mempool_name> file <file_name> bpp <n_bytes_per_pkt>
805  *  [action <port_in_action_profile_name>]
806  *  [disabled]
807  */
808 static void
809 cmd_pipeline_port_in(struct pmd_internals *softnic,
810 	char **tokens,
811 	uint32_t n_tokens,
812 	char *out,
813 	size_t out_size)
814 {
815 	struct softnic_port_in_params p;
816 	char *pipeline_name;
817 	uint32_t t0;
818 	int enabled, status;
819 
820 	if (n_tokens < 7) {
821 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
822 		return;
823 	}
824 
825 	pipeline_name = tokens[1];
826 
827 	if (strcmp(tokens[2], "port") != 0) {
828 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
829 		return;
830 	}
831 
832 	if (strcmp(tokens[3], "in") != 0) {
833 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
834 		return;
835 	}
836 
837 	if (strcmp(tokens[4], "bsz") != 0) {
838 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
839 		return;
840 	}
841 
842 	if (softnic_parser_read_uint32(&p.burst_size, tokens[5]) != 0) {
843 		snprintf(out, out_size, MSG_ARG_INVALID, "burst_size");
844 		return;
845 	}
846 
847 	t0 = 6;
848 
849 	if (strcmp(tokens[t0], "link") == 0) {
850 		if (n_tokens < t0 + 4) {
851 			snprintf(out, out_size, MSG_ARG_MISMATCH,
852 				"pipeline port in link");
853 			return;
854 		}
855 
856 		p.type = PORT_IN_RXQ;
857 
858 		p.dev_name = tokens[t0 + 1];
859 
860 		if (strcmp(tokens[t0 + 2], "rxq") != 0) {
861 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rxq");
862 			return;
863 		}
864 
865 		if (softnic_parser_read_uint16(&p.rxq.queue_id,
866 			tokens[t0 + 3]) != 0) {
867 			snprintf(out, out_size, MSG_ARG_INVALID,
868 				"queue_id");
869 			return;
870 		}
871 		t0 += 4;
872 	} else if (strcmp(tokens[t0], "swq") == 0) {
873 		if (n_tokens < t0 + 2) {
874 			snprintf(out, out_size, MSG_ARG_MISMATCH,
875 				"pipeline port in swq");
876 			return;
877 		}
878 
879 		p.type = PORT_IN_SWQ;
880 
881 		p.dev_name = tokens[t0 + 1];
882 
883 		t0 += 2;
884 	} else if (strcmp(tokens[t0], "tmgr") == 0) {
885 		if (n_tokens < t0 + 2) {
886 			snprintf(out, out_size, MSG_ARG_MISMATCH,
887 				"pipeline port in tmgr");
888 			return;
889 		}
890 
891 		p.type = PORT_IN_TMGR;
892 
893 		p.dev_name = tokens[t0 + 1];
894 
895 		t0 += 2;
896 	} else if (strcmp(tokens[t0], "tap") == 0) {
897 		if (n_tokens < t0 + 6) {
898 			snprintf(out, out_size, MSG_ARG_MISMATCH,
899 				"pipeline port in tap");
900 			return;
901 		}
902 
903 		p.type = PORT_IN_TAP;
904 
905 		p.dev_name = tokens[t0 + 1];
906 
907 		if (strcmp(tokens[t0 + 2], "mempool") != 0) {
908 			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
909 				"mempool");
910 			return;
911 		}
912 
913 		p.tap.mempool_name = tokens[t0 + 3];
914 
915 		if (strcmp(tokens[t0 + 4], "mtu") != 0) {
916 			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
917 				"mtu");
918 			return;
919 		}
920 
921 		if (softnic_parser_read_uint32(&p.tap.mtu,
922 			tokens[t0 + 5]) != 0) {
923 			snprintf(out, out_size, MSG_ARG_INVALID, "mtu");
924 			return;
925 		}
926 
927 		t0 += 6;
928 	} else if (strcmp(tokens[t0], "source") == 0) {
929 		if (n_tokens < t0 + 6) {
930 			snprintf(out, out_size, MSG_ARG_MISMATCH,
931 				"pipeline port in source");
932 			return;
933 		}
934 
935 		p.type = PORT_IN_SOURCE;
936 
937 		p.dev_name = NULL;
938 
939 		if (strcmp(tokens[t0 + 1], "mempool") != 0) {
940 			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
941 				"mempool");
942 			return;
943 		}
944 
945 		p.source.mempool_name = tokens[t0 + 2];
946 
947 		if (strcmp(tokens[t0 + 3], "file") != 0) {
948 			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
949 				"file");
950 			return;
951 		}
952 
953 		p.source.file_name = tokens[t0 + 4];
954 
955 		if (strcmp(tokens[t0 + 5], "bpp") != 0) {
956 			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
957 				"bpp");
958 			return;
959 		}
960 
961 		if (softnic_parser_read_uint32(&p.source.n_bytes_per_pkt,
962 			tokens[t0 + 6]) != 0) {
963 			snprintf(out, out_size, MSG_ARG_INVALID,
964 				"n_bytes_per_pkt");
965 			return;
966 		}
967 
968 		t0 += 7;
969 	} else {
970 		snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
971 		return;
972 	}
973 
974 	p.action_profile_name = NULL;
975 	if (n_tokens > t0 &&
976 		(strcmp(tokens[t0], "action") == 0)) {
977 		if (n_tokens < t0 + 2) {
978 			snprintf(out, out_size, MSG_ARG_MISMATCH, "action");
979 			return;
980 		}
981 
982 		p.action_profile_name = tokens[t0 + 1];
983 
984 		t0 += 2;
985 	}
986 
987 	enabled = 1;
988 	if (n_tokens > t0 &&
989 		(strcmp(tokens[t0], "disabled") == 0)) {
990 		enabled = 0;
991 
992 		t0 += 1;
993 	}
994 
995 	if (n_tokens != t0) {
996 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
997 		return;
998 	}
999 
1000 	status = softnic_pipeline_port_in_create(softnic,
1001 		pipeline_name,
1002 		&p,
1003 		enabled);
1004 	if (status) {
1005 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1006 		return;
1007 	}
1008 }
1009 
1010 /**
1011  * pipeline <pipeline_name> port out
1012  *  bsz <burst_size>
1013  *  link <link_name> txq <txq_id>
1014  *  | swq <swq_name>
1015  *  | tmgr <tmgr_name>
1016  *  | tap <tap_name>
1017  *  | sink [file <file_name> pkts <max_n_pkts>]
1018  */
1019 static void
1020 cmd_pipeline_port_out(struct pmd_internals *softnic,
1021 	char **tokens,
1022 	uint32_t n_tokens,
1023 	char *out,
1024 	size_t out_size)
1025 {
1026 	struct softnic_port_out_params p;
1027 	char *pipeline_name;
1028 	int status;
1029 
1030 	memset(&p, 0, sizeof(p));
1031 
1032 	if (n_tokens < 7) {
1033 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1034 		return;
1035 	}
1036 
1037 	pipeline_name = tokens[1];
1038 
1039 	if (strcmp(tokens[2], "port") != 0) {
1040 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
1041 		return;
1042 	}
1043 
1044 	if (strcmp(tokens[3], "out") != 0) {
1045 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "out");
1046 		return;
1047 	}
1048 
1049 	if (strcmp(tokens[4], "bsz") != 0) {
1050 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
1051 		return;
1052 	}
1053 
1054 	if (softnic_parser_read_uint32(&p.burst_size, tokens[5]) != 0) {
1055 		snprintf(out, out_size, MSG_ARG_INVALID, "burst_size");
1056 		return;
1057 	}
1058 
1059 	if (strcmp(tokens[6], "link") == 0) {
1060 		if (n_tokens != 10) {
1061 			snprintf(out, out_size, MSG_ARG_MISMATCH,
1062 				"pipeline port out link");
1063 			return;
1064 		}
1065 
1066 		p.type = PORT_OUT_TXQ;
1067 
1068 		p.dev_name = tokens[7];
1069 
1070 		if (strcmp(tokens[8], "txq") != 0) {
1071 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "txq");
1072 			return;
1073 		}
1074 
1075 		if (softnic_parser_read_uint16(&p.txq.queue_id,
1076 			tokens[9]) != 0) {
1077 			snprintf(out, out_size, MSG_ARG_INVALID, "queue_id");
1078 			return;
1079 		}
1080 	} else if (strcmp(tokens[6], "swq") == 0) {
1081 		if (n_tokens != 8) {
1082 			snprintf(out, out_size, MSG_ARG_MISMATCH,
1083 				"pipeline port out swq");
1084 			return;
1085 		}
1086 
1087 		p.type = PORT_OUT_SWQ;
1088 
1089 		p.dev_name = tokens[7];
1090 	} else if (strcmp(tokens[6], "tmgr") == 0) {
1091 		if (n_tokens != 8) {
1092 			snprintf(out, out_size, MSG_ARG_MISMATCH,
1093 				"pipeline port out tmgr");
1094 			return;
1095 		}
1096 
1097 		p.type = PORT_OUT_TMGR;
1098 
1099 		p.dev_name = tokens[7];
1100 	} else if (strcmp(tokens[6], "tap") == 0) {
1101 		if (n_tokens != 8) {
1102 			snprintf(out, out_size, MSG_ARG_MISMATCH,
1103 				"pipeline port out tap");
1104 			return;
1105 		}
1106 
1107 		p.type = PORT_OUT_TAP;
1108 
1109 		p.dev_name = tokens[7];
1110 	} else if (strcmp(tokens[6], "sink") == 0) {
1111 		if ((n_tokens != 7) && (n_tokens != 11)) {
1112 			snprintf(out, out_size, MSG_ARG_MISMATCH,
1113 				"pipeline port out sink");
1114 			return;
1115 		}
1116 
1117 		p.type = PORT_OUT_SINK;
1118 
1119 		p.dev_name = NULL;
1120 
1121 		if (n_tokens == 7) {
1122 			p.sink.file_name = NULL;
1123 			p.sink.max_n_pkts = 0;
1124 		} else {
1125 			if (strcmp(tokens[7], "file") != 0) {
1126 				snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1127 					"file");
1128 				return;
1129 			}
1130 
1131 			p.sink.file_name = tokens[8];
1132 
1133 			if (strcmp(tokens[9], "pkts") != 0) {
1134 				snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pkts");
1135 				return;
1136 			}
1137 
1138 			if (softnic_parser_read_uint32(&p.sink.max_n_pkts,
1139 				tokens[10]) != 0) {
1140 				snprintf(out, out_size, MSG_ARG_INVALID, "max_n_pkts");
1141 				return;
1142 			}
1143 		}
1144 	} else {
1145 		snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
1146 		return;
1147 	}
1148 
1149 	status = softnic_pipeline_port_out_create(softnic, pipeline_name, &p);
1150 	if (status) {
1151 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1152 		return;
1153 	}
1154 }
1155 
1156 /**
1157  * pipeline <pipeline_name> table
1158  *      match
1159  *      acl
1160  *          ipv4 | ipv6
1161  *          offset <ip_header_offset>
1162  *          size <n_rules>
1163  *      | array
1164  *          offset <key_offset>
1165  *          size <n_keys>
1166  *      | hash
1167  *          ext | lru
1168  *          key <key_size>
1169  *          mask <key_mask>
1170  *          offset <key_offset>
1171  *          buckets <n_buckets>
1172  *          size <n_keys>
1173  *      | lpm
1174  *          ipv4 | ipv6
1175  *          offset <ip_header_offset>
1176  *          size <n_rules>
1177  *      | stub
1178  *  [action <table_action_profile_name>]
1179  */
1180 static void
1181 cmd_pipeline_table(struct pmd_internals *softnic,
1182 	char **tokens,
1183 	uint32_t n_tokens,
1184 	char *out,
1185 	size_t out_size)
1186 {
1187 	uint8_t key_mask[TABLE_RULE_MATCH_SIZE_MAX];
1188 	struct softnic_table_params p;
1189 	char *pipeline_name;
1190 	uint32_t t0;
1191 	int status;
1192 
1193 	if (n_tokens < 5) {
1194 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1195 		return;
1196 	}
1197 
1198 	pipeline_name = tokens[1];
1199 
1200 	if (strcmp(tokens[2], "table") != 0) {
1201 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
1202 		return;
1203 	}
1204 
1205 	if (strcmp(tokens[3], "match") != 0) {
1206 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match");
1207 		return;
1208 	}
1209 
1210 	t0 = 4;
1211 	if (strcmp(tokens[t0], "acl") == 0) {
1212 		if (n_tokens < t0 + 6) {
1213 			snprintf(out, out_size, MSG_ARG_MISMATCH,
1214 				"pipeline table acl");
1215 			return;
1216 		}
1217 
1218 		p.match_type = TABLE_ACL;
1219 
1220 		if (strcmp(tokens[t0 + 1], "ipv4") == 0) {
1221 			p.match.acl.ip_version = 1;
1222 		} else if (strcmp(tokens[t0 + 1], "ipv6") == 0) {
1223 			p.match.acl.ip_version = 0;
1224 		} else {
1225 			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1226 				"ipv4 or ipv6");
1227 			return;
1228 		}
1229 
1230 		if (strcmp(tokens[t0 + 2], "offset") != 0) {
1231 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
1232 			return;
1233 		}
1234 
1235 		if (softnic_parser_read_uint32(&p.match.acl.ip_header_offset,
1236 			tokens[t0 + 3]) != 0) {
1237 			snprintf(out, out_size, MSG_ARG_INVALID,
1238 				"ip_header_offset");
1239 			return;
1240 		}
1241 
1242 		if (strcmp(tokens[t0 + 4], "size") != 0) {
1243 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
1244 			return;
1245 		}
1246 
1247 		if (softnic_parser_read_uint32(&p.match.acl.n_rules,
1248 			tokens[t0 + 5]) != 0) {
1249 			snprintf(out, out_size, MSG_ARG_INVALID, "n_rules");
1250 			return;
1251 		}
1252 
1253 		t0 += 6;
1254 	} else if (strcmp(tokens[t0], "array") == 0) {
1255 		if (n_tokens < t0 + 5) {
1256 			snprintf(out, out_size, MSG_ARG_MISMATCH,
1257 				"pipeline table array");
1258 			return;
1259 		}
1260 
1261 		p.match_type = TABLE_ARRAY;
1262 
1263 		if (strcmp(tokens[t0 + 1], "offset") != 0) {
1264 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
1265 			return;
1266 		}
1267 
1268 		if (softnic_parser_read_uint32(&p.match.array.key_offset,
1269 			tokens[t0 + 2]) != 0) {
1270 			snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
1271 			return;
1272 		}
1273 
1274 		if (strcmp(tokens[t0 + 3], "size") != 0) {
1275 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
1276 			return;
1277 		}
1278 
1279 		if (softnic_parser_read_uint32(&p.match.array.n_keys,
1280 			tokens[t0 + 4]) != 0) {
1281 			snprintf(out, out_size, MSG_ARG_INVALID, "n_keys");
1282 			return;
1283 		}
1284 
1285 		t0 += 5;
1286 	} else if (strcmp(tokens[t0], "hash") == 0) {
1287 		uint32_t key_mask_size = TABLE_RULE_MATCH_SIZE_MAX;
1288 
1289 		if (n_tokens < t0 + 12) {
1290 			snprintf(out, out_size, MSG_ARG_MISMATCH,
1291 				"pipeline table hash");
1292 			return;
1293 		}
1294 
1295 		p.match_type = TABLE_HASH;
1296 
1297 		if (strcmp(tokens[t0 + 1], "ext") == 0) {
1298 			p.match.hash.extendable_bucket = 1;
1299 		} else if (strcmp(tokens[t0 + 1], "lru") == 0) {
1300 			p.match.hash.extendable_bucket = 0;
1301 		} else {
1302 			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1303 				"ext or lru");
1304 			return;
1305 		}
1306 
1307 		if (strcmp(tokens[t0 + 2], "key") != 0) {
1308 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "key");
1309 			return;
1310 		}
1311 
1312 		if ((softnic_parser_read_uint32(&p.match.hash.key_size,
1313 			tokens[t0 + 3]) != 0) ||
1314 			p.match.hash.key_size == 0 ||
1315 			p.match.hash.key_size > TABLE_RULE_MATCH_SIZE_MAX) {
1316 			snprintf(out, out_size, MSG_ARG_INVALID, "key_size");
1317 			return;
1318 		}
1319 
1320 		if (strcmp(tokens[t0 + 4], "mask") != 0) {
1321 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask");
1322 			return;
1323 		}
1324 
1325 		if ((softnic_parse_hex_string(tokens[t0 + 5],
1326 			key_mask, &key_mask_size) != 0) ||
1327 			key_mask_size != p.match.hash.key_size) {
1328 			snprintf(out, out_size, MSG_ARG_INVALID, "key_mask");
1329 			return;
1330 		}
1331 		p.match.hash.key_mask = key_mask;
1332 
1333 		if (strcmp(tokens[t0 + 6], "offset") != 0) {
1334 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
1335 			return;
1336 		}
1337 
1338 		if (softnic_parser_read_uint32(&p.match.hash.key_offset,
1339 			tokens[t0 + 7]) != 0) {
1340 			snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
1341 			return;
1342 		}
1343 
1344 		if (strcmp(tokens[t0 + 8], "buckets") != 0) {
1345 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "buckets");
1346 			return;
1347 		}
1348 
1349 		if (softnic_parser_read_uint32(&p.match.hash.n_buckets,
1350 			tokens[t0 + 9]) != 0) {
1351 			snprintf(out, out_size, MSG_ARG_INVALID, "n_buckets");
1352 			return;
1353 		}
1354 
1355 		if (strcmp(tokens[t0 + 10], "size") != 0) {
1356 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
1357 			return;
1358 		}
1359 
1360 		if (softnic_parser_read_uint32(&p.match.hash.n_keys,
1361 			tokens[t0 + 11]) != 0) {
1362 			snprintf(out, out_size, MSG_ARG_INVALID, "n_keys");
1363 			return;
1364 		}
1365 
1366 		t0 += 12;
1367 	} else if (strcmp(tokens[t0], "lpm") == 0) {
1368 		if (n_tokens < t0 + 6) {
1369 			snprintf(out, out_size, MSG_ARG_MISMATCH,
1370 				"pipeline table lpm");
1371 			return;
1372 		}
1373 
1374 		p.match_type = TABLE_LPM;
1375 
1376 		if (strcmp(tokens[t0 + 1], "ipv4") == 0) {
1377 			p.match.lpm.key_size = 4;
1378 		} else if (strcmp(tokens[t0 + 1], "ipv6") == 0) {
1379 			p.match.lpm.key_size = 16;
1380 		} else {
1381 			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
1382 				"ipv4 or ipv6");
1383 			return;
1384 		}
1385 
1386 		if (strcmp(tokens[t0 + 2], "offset") != 0) {
1387 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
1388 			return;
1389 		}
1390 
1391 		if (softnic_parser_read_uint32(&p.match.lpm.key_offset,
1392 			tokens[t0 + 3]) != 0) {
1393 			snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
1394 			return;
1395 		}
1396 
1397 		if (strcmp(tokens[t0 + 4], "size") != 0) {
1398 			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
1399 			return;
1400 		}
1401 
1402 		if (softnic_parser_read_uint32(&p.match.lpm.n_rules,
1403 			tokens[t0 + 5]) != 0) {
1404 			snprintf(out, out_size, MSG_ARG_INVALID, "n_rules");
1405 			return;
1406 		}
1407 
1408 		t0 += 6;
1409 	} else if (strcmp(tokens[t0], "stub") == 0) {
1410 		p.match_type = TABLE_STUB;
1411 
1412 		t0 += 1;
1413 	} else {
1414 		snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
1415 		return;
1416 	}
1417 
1418 	p.action_profile_name = NULL;
1419 	if (n_tokens > t0 &&
1420 		(strcmp(tokens[t0], "action") == 0)) {
1421 		if (n_tokens < t0 + 2) {
1422 			snprintf(out, out_size, MSG_ARG_MISMATCH, "action");
1423 			return;
1424 		}
1425 
1426 		p.action_profile_name = tokens[t0 + 1];
1427 
1428 		t0 += 2;
1429 	}
1430 
1431 	if (n_tokens > t0) {
1432 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1433 		return;
1434 	}
1435 
1436 	status = softnic_pipeline_table_create(softnic, pipeline_name, &p);
1437 	if (status) {
1438 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1439 		return;
1440 	}
1441 }
1442 
1443 /**
1444  * pipeline <pipeline_name> port in <port_id> table <table_id>
1445  */
1446 static void
1447 cmd_pipeline_port_in_table(struct pmd_internals *softnic,
1448 	char **tokens,
1449 	uint32_t n_tokens,
1450 	char *out,
1451 	size_t out_size)
1452 {
1453 	char *pipeline_name;
1454 	uint32_t port_id, table_id;
1455 	int status;
1456 
1457 	if (n_tokens != 7) {
1458 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1459 		return;
1460 	}
1461 
1462 	pipeline_name = tokens[1];
1463 
1464 	if (strcmp(tokens[2], "port") != 0) {
1465 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
1466 		return;
1467 	}
1468 
1469 	if (strcmp(tokens[3], "in") != 0) {
1470 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
1471 		return;
1472 	}
1473 
1474 	if (softnic_parser_read_uint32(&port_id, tokens[4]) != 0) {
1475 		snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
1476 		return;
1477 	}
1478 
1479 	if (strcmp(tokens[5], "table") != 0) {
1480 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
1481 		return;
1482 	}
1483 
1484 	if (softnic_parser_read_uint32(&table_id, tokens[6]) != 0) {
1485 		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
1486 		return;
1487 	}
1488 
1489 	status = softnic_pipeline_port_in_connect_to_table(softnic,
1490 		pipeline_name,
1491 		port_id,
1492 		table_id);
1493 	if (status) {
1494 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1495 		return;
1496 	}
1497 }
1498 
1499 /**
1500  * pipeline <pipeline_name> port in <port_id> enable
1501  */
1502 static void
1503 cmd_softnic_pipeline_port_in_enable(struct pmd_internals *softnic,
1504 	char **tokens,
1505 	uint32_t n_tokens,
1506 	char *out,
1507 	size_t out_size)
1508 {
1509 	char *pipeline_name;
1510 	uint32_t port_id;
1511 	int status;
1512 
1513 	if (n_tokens != 6) {
1514 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1515 		return;
1516 	}
1517 
1518 	pipeline_name = tokens[1];
1519 
1520 	if (strcmp(tokens[2], "port") != 0) {
1521 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
1522 		return;
1523 	}
1524 
1525 	if (strcmp(tokens[3], "in") != 0) {
1526 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
1527 		return;
1528 	}
1529 
1530 	if (softnic_parser_read_uint32(&port_id, tokens[4]) != 0) {
1531 		snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
1532 		return;
1533 	}
1534 
1535 	if (strcmp(tokens[5], "enable") != 0) {
1536 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable");
1537 		return;
1538 	}
1539 
1540 	status = softnic_pipeline_port_in_enable(softnic, pipeline_name, port_id);
1541 	if (status) {
1542 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1543 		return;
1544 	}
1545 }
1546 
1547 /**
1548  * pipeline <pipeline_name> port in <port_id> disable
1549  */
1550 static void
1551 cmd_softnic_pipeline_port_in_disable(struct pmd_internals *softnic,
1552 	char **tokens,
1553 	uint32_t n_tokens,
1554 	char *out,
1555 	size_t out_size)
1556 {
1557 	char *pipeline_name;
1558 	uint32_t port_id;
1559 	int status;
1560 
1561 	if (n_tokens != 6) {
1562 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1563 		return;
1564 	}
1565 
1566 	pipeline_name = tokens[1];
1567 
1568 	if (strcmp(tokens[2], "port") != 0) {
1569 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
1570 		return;
1571 	}
1572 
1573 	if (strcmp(tokens[3], "in") != 0) {
1574 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
1575 		return;
1576 	}
1577 
1578 	if (softnic_parser_read_uint32(&port_id, tokens[4]) != 0) {
1579 		snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
1580 		return;
1581 	}
1582 
1583 	if (strcmp(tokens[5], "disable") != 0) {
1584 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable");
1585 		return;
1586 	}
1587 
1588 	status = softnic_pipeline_port_in_disable(softnic, pipeline_name, port_id);
1589 	if (status) {
1590 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
1591 		return;
1592 	}
1593 }
1594 
1595 void
1596 softnic_cli_process(char *in, char *out, size_t out_size, void *arg)
1597 {
1598 	char *tokens[CMD_MAX_TOKENS];
1599 	uint32_t n_tokens = RTE_DIM(tokens);
1600 	struct pmd_internals *softnic = arg;
1601 	int status;
1602 
1603 	if (is_comment(in))
1604 		return;
1605 
1606 	status = softnic_parse_tokenize_string(in, tokens, &n_tokens);
1607 	if (status) {
1608 		snprintf(out, out_size, MSG_ARG_TOO_MANY, "");
1609 		return;
1610 	}
1611 
1612 	if (n_tokens == 0)
1613 		return;
1614 
1615 	if (strcmp(tokens[0], "mempool") == 0) {
1616 		cmd_mempool(softnic, tokens, n_tokens, out, out_size);
1617 		return;
1618 	}
1619 
1620 	if (strcmp(tokens[0], "link") == 0) {
1621 		cmd_link(softnic, tokens, n_tokens, out, out_size);
1622 		return;
1623 	}
1624 
1625 	if (strcmp(tokens[0], "swq") == 0) {
1626 		cmd_swq(softnic, tokens, n_tokens, out, out_size);
1627 		return;
1628 	}
1629 
1630 	if (strcmp(tokens[0], "tap") == 0) {
1631 		cmd_tap(softnic, tokens, n_tokens, out, out_size);
1632 		return;
1633 	}
1634 
1635 	if (strcmp(tokens[0], "port") == 0) {
1636 		cmd_port_in_action_profile(softnic, tokens, n_tokens, out, out_size);
1637 		return;
1638 	}
1639 
1640 	if (strcmp(tokens[0], "table") == 0) {
1641 		cmd_table_action_profile(softnic, tokens, n_tokens, out, out_size);
1642 		return;
1643 	}
1644 
1645 	if (strcmp(tokens[0], "pipeline") == 0) {
1646 		if (n_tokens >= 3 &&
1647 			(strcmp(tokens[2], "period") == 0)) {
1648 			cmd_pipeline(softnic, tokens, n_tokens, out, out_size);
1649 			return;
1650 		}
1651 
1652 		if (n_tokens >= 5 &&
1653 			(strcmp(tokens[2], "port") == 0) &&
1654 			(strcmp(tokens[3], "in") == 0) &&
1655 			(strcmp(tokens[4], "bsz") == 0)) {
1656 			cmd_pipeline_port_in(softnic, tokens, n_tokens, out, out_size);
1657 			return;
1658 		}
1659 
1660 		if (n_tokens >= 5 &&
1661 			(strcmp(tokens[2], "port") == 0) &&
1662 			(strcmp(tokens[3], "out") == 0) &&
1663 			(strcmp(tokens[4], "bsz") == 0)) {
1664 			cmd_pipeline_port_out(softnic, tokens, n_tokens, out, out_size);
1665 			return;
1666 		}
1667 
1668 		if (n_tokens >= 4 &&
1669 			(strcmp(tokens[2], "table") == 0) &&
1670 			(strcmp(tokens[3], "match") == 0)) {
1671 			cmd_pipeline_table(softnic, tokens, n_tokens, out, out_size);
1672 			return;
1673 		}
1674 
1675 		if (n_tokens >= 6 &&
1676 			(strcmp(tokens[2], "port") == 0) &&
1677 			(strcmp(tokens[3], "in") == 0) &&
1678 			(strcmp(tokens[5], "table") == 0)) {
1679 			cmd_pipeline_port_in_table(softnic, tokens, n_tokens,
1680 				out, out_size);
1681 			return;
1682 		}
1683 
1684 		if (n_tokens >= 6 &&
1685 			(strcmp(tokens[2], "port") == 0) &&
1686 			(strcmp(tokens[3], "in") == 0) &&
1687 			(strcmp(tokens[5], "enable") == 0)) {
1688 			cmd_softnic_pipeline_port_in_enable(softnic, tokens, n_tokens,
1689 				out, out_size);
1690 			return;
1691 		}
1692 
1693 		if (n_tokens >= 6 &&
1694 			(strcmp(tokens[2], "port") == 0) &&
1695 			(strcmp(tokens[3], "in") == 0) &&
1696 			(strcmp(tokens[5], "disable") == 0)) {
1697 			cmd_softnic_pipeline_port_in_disable(softnic, tokens, n_tokens,
1698 				out, out_size);
1699 			return;
1700 		}
1701 	}
1702 
1703 	snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
1704 }
1705 
1706 int
1707 softnic_cli_script_process(struct pmd_internals *softnic,
1708 	const char *file_name,
1709 	size_t msg_in_len_max,
1710 	size_t msg_out_len_max)
1711 {
1712 	char *msg_in = NULL, *msg_out = NULL;
1713 	FILE *f = NULL;
1714 
1715 	/* Check input arguments */
1716 	if (file_name == NULL ||
1717 		strlen(file_name) == 0 ||
1718 		msg_in_len_max == 0 ||
1719 		msg_out_len_max == 0)
1720 		return -EINVAL;
1721 
1722 	msg_in = malloc(msg_in_len_max + 1);
1723 	msg_out = malloc(msg_out_len_max + 1);
1724 	if (msg_in == NULL ||
1725 		msg_out == NULL) {
1726 		free(msg_out);
1727 		free(msg_in);
1728 		return -ENOMEM;
1729 	}
1730 
1731 	/* Open input file */
1732 	f = fopen(file_name, "r");
1733 	if (f == NULL) {
1734 		free(msg_out);
1735 		free(msg_in);
1736 		return -EIO;
1737 	}
1738 
1739 	/* Read file */
1740 	for ( ; ; ) {
1741 		if (fgets(msg_in, msg_in_len_max + 1, f) == NULL)
1742 			break;
1743 
1744 		printf("%s", msg_in);
1745 		msg_out[0] = 0;
1746 
1747 		softnic_cli_process(msg_in,
1748 			msg_out,
1749 			msg_out_len_max,
1750 			softnic);
1751 
1752 		if (strlen(msg_out))
1753 			printf("%s", msg_out);
1754 	}
1755 
1756 	/* Close file */
1757 	fclose(f);
1758 	free(msg_out);
1759 	free(msg_in);
1760 	return 0;
1761 }
1762