xref: /dpdk/drivers/net/softnic/rte_eth_softnic_cli.c (revision 96893df75bf50a82cabd8debe3492d564a5d13d5)
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 #include <unistd.h>
10 
11 #include <rte_common.h>
12 #include <rte_cycles.h>
13 #include <rte_string_fns.h>
14 
15 #include "rte_eth_softnic_internals.h"
16 
17 #ifndef CMD_MAX_TOKENS
18 #define CMD_MAX_TOKENS     256
19 #endif
20 
21 #ifndef MAX_LINE_SIZE
22 #define MAX_LINE_SIZE 2048
23 #endif
24 
25 #define MSG_OUT_OF_MEMORY   "Not enough memory.\n"
26 #define MSG_CMD_UNKNOWN     "Unknown command \"%s\".\n"
27 #define MSG_CMD_UNIMPLEM    "Command \"%s\" not implemented.\n"
28 #define MSG_ARG_NOT_ENOUGH  "Not enough arguments for command \"%s\".\n"
29 #define MSG_ARG_TOO_MANY    "Too many arguments for command \"%s\".\n"
30 #define MSG_ARG_MISMATCH    "Wrong number of arguments for command \"%s\".\n"
31 #define MSG_ARG_NOT_FOUND   "Argument \"%s\" not found.\n"
32 #define MSG_ARG_INVALID     "Invalid value for argument \"%s\".\n"
33 #define MSG_FILE_ERR        "Error in file \"%s\" at line %u.\n"
34 #define MSG_FILE_NOT_ENOUGH "Not enough rules in file \"%s\".\n"
35 #define MSG_CMD_FAIL        "Command \"%s\" failed.\n"
36 
37 static int
parser_read_uint64(uint64_t * value,char * p)38 parser_read_uint64(uint64_t *value, char *p)
39 {
40 	uint64_t val = 0;
41 
42 	if (!value || !p || !p[0])
43 		return -EINVAL;
44 
45 	val = strtoull(p, &p, 0);
46 	if (p[0])
47 		return -EINVAL;
48 
49 	*value = val;
50 	return 0;
51 }
52 
53 static int
parser_read_uint32(uint32_t * value,char * p)54 parser_read_uint32(uint32_t *value, char *p)
55 {
56 	uint32_t val = 0;
57 
58 	if (!value || !p || !p[0])
59 		return -EINVAL;
60 
61 	val = strtoul(p, &p, 0);
62 	if (p[0])
63 		return -EINVAL;
64 
65 	*value = val;
66 	return 0;
67 }
68 
69 #define PARSE_DELIMITER " \f\n\r\t\v"
70 
71 static int
parse_tokenize_string(char * string,char * tokens[],uint32_t * n_tokens)72 parse_tokenize_string(char *string, char *tokens[], uint32_t *n_tokens)
73 {
74 	uint32_t i;
75 
76 	if (!string || !tokens || !n_tokens || !*n_tokens)
77 		return -EINVAL;
78 
79 	for (i = 0; i < *n_tokens; i++) {
80 		tokens[i] = strtok_r(string, PARSE_DELIMITER, &string);
81 		if (!tokens[i])
82 			break;
83 	}
84 
85 	if (i == *n_tokens && strtok_r(string, PARSE_DELIMITER, &string))
86 		return -E2BIG;
87 
88 	*n_tokens = i;
89 	return 0;
90 }
91 
92 static int
is_comment(char * in)93 is_comment(char *in)
94 {
95 	if ((strlen(in) && index("!#%;", in[0])) ||
96 		(strncmp(in, "//", 2) == 0) ||
97 		(strncmp(in, "--", 2) == 0))
98 		return 1;
99 
100 	return 0;
101 }
102 
103 /**
104  * mempool <mempool_name>
105  *  buffer <buffer_size>
106  *  pool <pool_size>
107  *  cache <cache_size>
108  */
109 static void
cmd_mempool(struct pmd_internals * softnic,char ** tokens,uint32_t n_tokens,char * out,size_t out_size)110 cmd_mempool(struct pmd_internals *softnic,
111 	char **tokens,
112 	uint32_t n_tokens,
113 	char *out,
114 	size_t out_size)
115 {
116 	struct softnic_mempool_params p;
117 	char *name;
118 	struct softnic_mempool *mempool;
119 
120 	if (n_tokens != 8) {
121 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
122 		return;
123 	}
124 
125 	name = tokens[1];
126 
127 	if (strcmp(tokens[2], "buffer") != 0) {
128 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "buffer");
129 		return;
130 	}
131 
132 	if (parser_read_uint32(&p.buffer_size, tokens[3]) != 0) {
133 		snprintf(out, out_size, MSG_ARG_INVALID, "buffer_size");
134 		return;
135 	}
136 
137 	if (strcmp(tokens[4], "pool") != 0) {
138 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pool");
139 		return;
140 	}
141 
142 	if (parser_read_uint32(&p.pool_size, tokens[5]) != 0) {
143 		snprintf(out, out_size, MSG_ARG_INVALID, "pool_size");
144 		return;
145 	}
146 
147 	if (strcmp(tokens[6], "cache") != 0) {
148 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cache");
149 		return;
150 	}
151 
152 	if (parser_read_uint32(&p.cache_size, tokens[7]) != 0) {
153 		snprintf(out, out_size, MSG_ARG_INVALID, "cache_size");
154 		return;
155 	}
156 
157 	mempool = softnic_mempool_create(softnic, name, &p);
158 	if (mempool == NULL) {
159 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
160 		return;
161 	}
162 }
163 
164 /**
165  * swq <swq_name>
166  *  size <size>
167  */
168 static void
cmd_swq(struct pmd_internals * softnic,char ** tokens,uint32_t n_tokens,char * out,size_t out_size)169 cmd_swq(struct pmd_internals *softnic,
170 	char **tokens,
171 	uint32_t n_tokens,
172 	char *out,
173 	size_t out_size)
174 {
175 	struct softnic_swq_params p;
176 	char *name;
177 	struct softnic_swq *swq;
178 
179 	if (n_tokens != 4) {
180 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
181 		return;
182 	}
183 
184 	name = tokens[1];
185 
186 	if (strcmp(tokens[2], "size") != 0) {
187 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
188 		return;
189 	}
190 
191 	if (parser_read_uint32(&p.size, tokens[3]) != 0) {
192 		snprintf(out, out_size, MSG_ARG_INVALID, "size");
193 		return;
194 	}
195 
196 	swq = softnic_swq_create(softnic, name, &p);
197 	if (swq == NULL) {
198 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
199 		return;
200 	}
201 }
202 
203 /**
204  * pipeline codegen <spec_file> <code_file>
205  */
206 static void
cmd_softnic_pipeline_codegen(struct pmd_internals * softnic __rte_unused,char ** tokens,uint32_t n_tokens,char * out,size_t out_size)207 cmd_softnic_pipeline_codegen(struct pmd_internals *softnic __rte_unused,
208 	char **tokens,
209 	uint32_t n_tokens,
210 	char *out,
211 	size_t out_size)
212 {
213 	FILE *spec_file = NULL;
214 	FILE *code_file = NULL;
215 	uint32_t err_line;
216 	const char *err_msg;
217 	int status;
218 
219 	if (n_tokens != 4) {
220 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
221 		return;
222 	}
223 
224 	spec_file = fopen(tokens[2], "r");
225 	if (!spec_file) {
226 		snprintf(out, out_size, "Cannot open file %s.\n", tokens[2]);
227 		return;
228 	}
229 
230 	code_file = fopen(tokens[3], "w");
231 	if (!code_file) {
232 		snprintf(out, out_size, "Cannot open file %s.\n", tokens[3]);
233 		fclose(spec_file);
234 		return;
235 	}
236 
237 	status = rte_swx_pipeline_codegen(spec_file,
238 					  code_file,
239 					  &err_line,
240 					  &err_msg);
241 
242 	fclose(spec_file);
243 	fclose(code_file);
244 
245 	if (status) {
246 		snprintf(out, out_size, "Error %d at line %u: %s\n.",
247 			status, err_line, err_msg);
248 		return;
249 	}
250 }
251 
252 /**
253  * pipeline libbuild <code_file> <lib_file>
254  */
255 static void
cmd_softnic_pipeline_libbuild(struct pmd_internals * softnic __rte_unused,char ** tokens,uint32_t n_tokens,char * out,size_t out_size)256 cmd_softnic_pipeline_libbuild(struct pmd_internals *softnic __rte_unused,
257 	char **tokens,
258 	uint32_t n_tokens,
259 	char *out,
260 	size_t out_size)
261 {
262 	char *code_file, *lib_file, *obj_file = NULL, *log_file = NULL;
263 	char *install_dir, *cwd = NULL, *buffer = NULL;
264 	size_t length;
265 	int status = 0;
266 
267 	if (n_tokens != 4) {
268 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
269 		goto free;
270 	}
271 
272 	install_dir = getenv("RTE_INSTALL_DIR");
273 	if (!install_dir) {
274 		cwd = malloc(MAX_LINE_SIZE);
275 		if (!cwd) {
276 			snprintf(out, out_size, MSG_OUT_OF_MEMORY);
277 			goto free;
278 		}
279 
280 		install_dir = getcwd(cwd, MAX_LINE_SIZE);
281 		if (!install_dir) {
282 			snprintf(out, out_size, "Error: Path too long.\n");
283 			goto free;
284 		}
285 	}
286 
287 	snprintf(out, out_size, "Using DPDK source code from \"%s\".\n", install_dir);
288 	out_size -= strlen(out);
289 	out += strlen(out);
290 
291 	code_file = tokens[2];
292 	length = strnlen(code_file, MAX_LINE_SIZE);
293 	if (length < 3 ||
294 	    code_file[length - 2] != '.' ||
295 	    code_file[length - 1] != 'c') {
296 		snprintf(out, out_size, MSG_ARG_INVALID, "code_file");
297 		goto free;
298 	}
299 
300 	lib_file = tokens[3];
301 	length = strnlen(lib_file, MAX_LINE_SIZE);
302 	if (length < 4 ||
303 	    lib_file[length - 3] != '.' ||
304 	    lib_file[length - 2] != 's' ||
305 	    lib_file[length - 1] != 'o') {
306 		snprintf(out, out_size, MSG_ARG_INVALID, "lib_file");
307 		goto free;
308 	}
309 
310 	obj_file = malloc(length);
311 	log_file = malloc(length + 2);
312 	if (!obj_file || !log_file) {
313 		snprintf(out, out_size, MSG_OUT_OF_MEMORY);
314 		goto free;
315 	}
316 
317 	memcpy(obj_file, lib_file, length - 2);
318 	obj_file[length - 2] = 'o';
319 	obj_file[length - 1] = 0;
320 
321 	memcpy(log_file, lib_file, length - 2);
322 	log_file[length - 2] = 'l';
323 	log_file[length - 1] = 'o';
324 	log_file[length] = 'g';
325 	log_file[length + 1] = 0;
326 
327 	buffer = malloc(MAX_LINE_SIZE);
328 	if (!buffer) {
329 		snprintf(out, out_size, MSG_OUT_OF_MEMORY);
330 		goto free;
331 	}
332 
333 	snprintf(buffer,
334 		 MAX_LINE_SIZE,
335 		 "gcc -c -O3 -fpic -Wno-deprecated-declarations -o %s %s "
336 		 "-I %s/lib/pipeline "
337 		 "-I %s/lib/eal/include "
338 		 "-I %s/lib/eal/x86/include "
339 		 "-I %s/lib/eal/include/generic "
340 		 "-I %s/lib/log "
341 		 "-I %s/lib/meter "
342 		 "-I %s/lib/port "
343 		 "-I %s/lib/table "
344 		 "-I %s/lib/pipeline "
345 		 "-I %s/config "
346 		 "-I %s/build "
347 		 "-I %s/lib/eal/linux/include "
348 		 ">%s 2>&1 "
349 		 "&& "
350 		 "gcc -shared %s -o %s "
351 		 ">>%s 2>&1",
352 		 obj_file,
353 		 code_file,
354 		 install_dir,
355 		 install_dir,
356 		 install_dir,
357 		 install_dir,
358 		 install_dir,
359 		 install_dir,
360 		 install_dir,
361 		 install_dir,
362 		 install_dir,
363 		 install_dir,
364 		 install_dir,
365 		 install_dir,
366 		 log_file,
367 		 obj_file,
368 		 lib_file,
369 		 log_file);
370 
371 	status = system(buffer);
372 	if (status) {
373 		snprintf(out,
374 			 out_size,
375 			 "Library build failed, see file \"%s\" for details.\n",
376 			 log_file);
377 		goto free;
378 	}
379 
380 free:
381 	free(cwd);
382 	free(obj_file);
383 	free(log_file);
384 	free(buffer);
385 }
386 
387 /**
388  * pipeline <pipeline_name> build lib <lib_file> io <iospec_file> numa <numa_node>
389  */
390 static void
cmd_softnic_pipeline_build(struct pmd_internals * softnic,char ** tokens,uint32_t n_tokens,char * out,size_t out_size)391 cmd_softnic_pipeline_build(struct pmd_internals *softnic,
392 	char **tokens,
393 	uint32_t n_tokens,
394 	char *out,
395 	size_t out_size)
396 {
397 	struct pipeline *p = NULL;
398 	char *pipeline_name, *lib_file_name, *iospec_file_name;
399 	uint32_t numa_node = 0;
400 
401 	/* Parsing. */
402 	if (n_tokens != 9) {
403 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
404 		return;
405 	}
406 
407 	pipeline_name = tokens[1];
408 
409 	if (strcmp(tokens[2], "build")) {
410 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "build");
411 		return;
412 	}
413 
414 	if (strcmp(tokens[3], "lib")) {
415 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "lib");
416 		return;
417 	}
418 
419 	lib_file_name = tokens[4];
420 
421 	if (strcmp(tokens[5], "io")) {
422 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "io");
423 		return;
424 	}
425 
426 	iospec_file_name = tokens[6];
427 
428 	if (strcmp(tokens[7], "numa")) {
429 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "numa");
430 		return;
431 	}
432 
433 	if (parser_read_uint32(&numa_node, tokens[8])) {
434 		snprintf(out, out_size, MSG_ARG_INVALID, "numa_node");
435 		return;
436 	}
437 
438 	/* Pipeline create. */
439 	p = softnic_pipeline_create(softnic,
440 				    pipeline_name,
441 				    lib_file_name,
442 				    iospec_file_name,
443 				    (int)numa_node);
444 	if (!p)
445 		snprintf(out, out_size, "Pipeline creation failed.\n");
446 }
447 
448 static void
table_entry_free(struct rte_swx_table_entry * entry)449 table_entry_free(struct rte_swx_table_entry *entry)
450 {
451 	if (!entry)
452 		return;
453 
454 	free(entry->key);
455 	free(entry->key_mask);
456 	free(entry->action_data);
457 	free(entry);
458 }
459 
460 static int
pipeline_table_entries_add(struct rte_swx_ctl_pipeline * p,const char * table_name,FILE * file,uint32_t * file_line_number)461 pipeline_table_entries_add(struct rte_swx_ctl_pipeline *p,
462 			   const char *table_name,
463 			   FILE *file,
464 			   uint32_t *file_line_number)
465 {
466 	char *line = NULL;
467 	uint32_t line_id = 0;
468 	int status = 0;
469 
470 	/* Buffer allocation. */
471 	line = malloc(MAX_LINE_SIZE);
472 	if (!line)
473 		return -ENOMEM;
474 
475 	/* File read. */
476 	for (line_id = 1; ; line_id++) {
477 		struct rte_swx_table_entry *entry;
478 		int is_blank_or_comment;
479 
480 		if (fgets(line, MAX_LINE_SIZE, file) == NULL)
481 			break;
482 
483 		entry = rte_swx_ctl_pipeline_table_entry_read(p,
484 							      table_name,
485 							      line,
486 							      &is_blank_or_comment);
487 		if (!entry) {
488 			if (is_blank_or_comment)
489 				continue;
490 
491 			status = -EINVAL;
492 			goto error;
493 		}
494 
495 		status = rte_swx_ctl_pipeline_table_entry_add(p,
496 							      table_name,
497 							      entry);
498 		table_entry_free(entry);
499 		if (status)
500 			goto error;
501 	}
502 
503 error:
504 	free(line);
505 	*file_line_number = line_id;
506 	return status;
507 }
508 
509 /**
510  * pipeline <pipeline_name> table <table_name> add <file_name>
511  */
512 static void
cmd_softnic_pipeline_table_add(struct pmd_internals * softnic,char ** tokens,uint32_t n_tokens,char * out,size_t out_size)513 cmd_softnic_pipeline_table_add(struct pmd_internals *softnic,
514 	char **tokens,
515 	uint32_t n_tokens,
516 	char *out,
517 	size_t out_size)
518 {
519 	struct pipeline *p;
520 	char *pipeline_name, *table_name, *file_name;
521 	FILE *file = NULL;
522 	uint32_t file_line_number = 0;
523 	int status;
524 
525 	if (n_tokens != 6) {
526 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
527 		return;
528 	}
529 
530 	pipeline_name = tokens[1];
531 	p = softnic_pipeline_find(softnic, pipeline_name);
532 	if (!p) {
533 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
534 		return;
535 	}
536 
537 	table_name = tokens[3];
538 
539 	file_name = tokens[5];
540 	file = fopen(file_name, "r");
541 	if (!file) {
542 		snprintf(out, out_size, "Cannot open file %s.\n", file_name);
543 		return;
544 	}
545 
546 	status = pipeline_table_entries_add(p->ctl,
547 					    table_name,
548 					    file,
549 					    &file_line_number);
550 	if (status)
551 		snprintf(out, out_size, "Invalid entry in file %s at line %u\n",
552 			 file_name,
553 			 file_line_number);
554 
555 	fclose(file);
556 }
557 
558 static int
pipeline_table_entries_delete(struct rte_swx_ctl_pipeline * p,const char * table_name,FILE * file,uint32_t * file_line_number)559 pipeline_table_entries_delete(struct rte_swx_ctl_pipeline *p,
560 			      const char *table_name,
561 			      FILE *file,
562 			      uint32_t *file_line_number)
563 {
564 	char *line = NULL;
565 	uint32_t line_id = 0;
566 	int status = 0;
567 
568 	/* Buffer allocation. */
569 	line = malloc(MAX_LINE_SIZE);
570 	if (!line)
571 		return -ENOMEM;
572 
573 	/* File read. */
574 	for (line_id = 1; ; line_id++) {
575 		struct rte_swx_table_entry *entry;
576 		int is_blank_or_comment;
577 
578 		if (fgets(line, MAX_LINE_SIZE, file) == NULL)
579 			break;
580 
581 		entry = rte_swx_ctl_pipeline_table_entry_read(p,
582 							      table_name,
583 							      line,
584 							      &is_blank_or_comment);
585 		if (!entry) {
586 			if (is_blank_or_comment)
587 				continue;
588 
589 			status = -EINVAL;
590 			goto error;
591 		}
592 
593 		status = rte_swx_ctl_pipeline_table_entry_delete(p,
594 								 table_name,
595 								 entry);
596 		table_entry_free(entry);
597 		if (status)
598 			goto error;
599 	}
600 
601 error:
602 	*file_line_number = line_id;
603 	free(line);
604 	return status;
605 }
606 
607 /**
608  * pipeline <pipeline_name> table <table_name> delete <file_name>
609  */
610 static void
cmd_softnic_pipeline_table_delete(struct pmd_internals * softnic,char ** tokens,uint32_t n_tokens,char * out,size_t out_size)611 cmd_softnic_pipeline_table_delete(struct pmd_internals *softnic,
612 	char **tokens,
613 	uint32_t n_tokens,
614 	char *out,
615 	size_t out_size)
616 {
617 	struct pipeline *p;
618 	char *pipeline_name, *table_name, *file_name;
619 	FILE *file = NULL;
620 	uint32_t file_line_number = 0;
621 	int status;
622 
623 	if (n_tokens != 6) {
624 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
625 		return;
626 	}
627 
628 	pipeline_name = tokens[1];
629 	p = softnic_pipeline_find(softnic, pipeline_name);
630 	if (!p) {
631 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
632 		return;
633 	}
634 
635 	table_name = tokens[3];
636 
637 	file_name = tokens[5];
638 	file = fopen(file_name, "r");
639 	if (!file) {
640 		snprintf(out, out_size, "Cannot open file %s.\n", file_name);
641 		return;
642 	}
643 
644 	status = pipeline_table_entries_delete(p->ctl,
645 					       table_name,
646 					       file,
647 					       &file_line_number);
648 	if (status)
649 		snprintf(out, out_size, "Invalid entry in file %s at line %u\n",
650 			 file_name,
651 			 file_line_number);
652 
653 	fclose(file);
654 }
655 
656 static int
pipeline_table_default_entry_add(struct rte_swx_ctl_pipeline * p,const char * table_name,FILE * file,uint32_t * file_line_number)657 pipeline_table_default_entry_add(struct rte_swx_ctl_pipeline *p,
658 				 const char *table_name,
659 				 FILE *file,
660 				 uint32_t *file_line_number)
661 {
662 	char *line = NULL;
663 	uint32_t line_id = 0;
664 	int status = 0;
665 
666 	/* Buffer allocation. */
667 	line = malloc(MAX_LINE_SIZE);
668 	if (!line)
669 		return -ENOMEM;
670 
671 	/* File read. */
672 	for (line_id = 1; ; line_id++) {
673 		struct rte_swx_table_entry *entry;
674 		int is_blank_or_comment;
675 
676 		if (fgets(line, MAX_LINE_SIZE, file) == NULL)
677 			break;
678 
679 		entry = rte_swx_ctl_pipeline_table_entry_read(p,
680 							      table_name,
681 							      line,
682 							      &is_blank_or_comment);
683 		if (!entry) {
684 			if (is_blank_or_comment)
685 				continue;
686 
687 			status = -EINVAL;
688 			goto error;
689 		}
690 
691 		status = rte_swx_ctl_pipeline_table_default_entry_add(p,
692 								      table_name,
693 								      entry);
694 		table_entry_free(entry);
695 		if (status)
696 			goto error;
697 	}
698 
699 error:
700 	*file_line_number = line_id;
701 	free(line);
702 	return status;
703 }
704 
705 /**
706  * pipeline <pipeline_name> table <table_name> default <file_name>
707  */
708 static void
cmd_softnic_pipeline_table_default(struct pmd_internals * softnic,char ** tokens,uint32_t n_tokens,char * out,size_t out_size)709 cmd_softnic_pipeline_table_default(struct pmd_internals *softnic,
710 	char **tokens,
711 	uint32_t n_tokens,
712 	char *out,
713 	size_t out_size)
714 {
715 	struct pipeline *p;
716 	char *pipeline_name, *table_name, *file_name;
717 	FILE *file = NULL;
718 	uint32_t file_line_number = 0;
719 	int status;
720 
721 	if (n_tokens != 6) {
722 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
723 		return;
724 	}
725 
726 	pipeline_name = tokens[1];
727 	p = softnic_pipeline_find(softnic, pipeline_name);
728 	if (!p) {
729 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
730 		return;
731 	}
732 
733 	table_name = tokens[3];
734 
735 	file_name = tokens[5];
736 	file = fopen(file_name, "r");
737 	if (!file) {
738 		snprintf(out, out_size, "Cannot open file %s.\n", file_name);
739 		return;
740 	}
741 
742 	status = pipeline_table_default_entry_add(p->ctl,
743 						  table_name,
744 						  file,
745 						  &file_line_number);
746 	if (status)
747 		snprintf(out, out_size, "Invalid entry in file %s at line %u\n",
748 			 file_name,
749 			 file_line_number);
750 
751 	fclose(file);
752 }
753 
754 /**
755  * pipeline <pipeline_name> table <table_name> show [filename]
756  */
757 static void
cmd_softnic_pipeline_table_show(struct pmd_internals * softnic __rte_unused,char ** tokens,uint32_t n_tokens,char * out,size_t out_size)758 cmd_softnic_pipeline_table_show(struct pmd_internals *softnic __rte_unused,
759 	char **tokens,
760 	uint32_t n_tokens,
761 	char *out,
762 	size_t out_size)
763 {
764 	struct pipeline *p;
765 	char *pipeline_name, *table_name;
766 	FILE *file = NULL;
767 	int status;
768 
769 	if (n_tokens != 5 && n_tokens != 6) {
770 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
771 		return;
772 	}
773 
774 	pipeline_name = tokens[1];
775 	p = softnic_pipeline_find(softnic, pipeline_name);
776 	if (!p) {
777 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
778 		return;
779 	}
780 
781 	table_name = tokens[3];
782 	file = (n_tokens == 6) ? fopen(tokens[5], "w") : stdout;
783 	if (!file) {
784 		snprintf(out, out_size, "Cannot open file %s.\n", tokens[5]);
785 		return;
786 	}
787 
788 	status = rte_swx_ctl_pipeline_table_fprintf(file, p->ctl, table_name);
789 	if (status)
790 		snprintf(out, out_size, MSG_ARG_INVALID, "table_name");
791 
792 	if (file)
793 		fclose(file);
794 }
795 
796 /**
797  * pipeline <pipeline_name> selector <selector_name> group add
798  */
799 static void
cmd_softnic_pipeline_selector_group_add(struct pmd_internals * softnic,char ** tokens,uint32_t n_tokens,char * out,size_t out_size)800 cmd_softnic_pipeline_selector_group_add(struct pmd_internals *softnic,
801 	char **tokens,
802 	uint32_t n_tokens,
803 	char *out,
804 	size_t out_size)
805 {
806 	struct pipeline *p;
807 	char *pipeline_name, *selector_name;
808 	uint32_t group_id;
809 	int status;
810 
811 	if (n_tokens != 6) {
812 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
813 		return;
814 	}
815 
816 	pipeline_name = tokens[1];
817 	p = softnic_pipeline_find(softnic, pipeline_name);
818 	if (!p) {
819 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
820 		return;
821 	}
822 
823 	if (strcmp(tokens[2], "selector") != 0) {
824 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "selector");
825 		return;
826 	}
827 
828 	selector_name = tokens[3];
829 
830 	if (strcmp(tokens[4], "group") ||
831 		strcmp(tokens[5], "add")) {
832 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "group add");
833 		return;
834 	}
835 
836 	status = rte_swx_ctl_pipeline_selector_group_add(p->ctl,
837 		selector_name,
838 		&group_id);
839 	if (status)
840 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
841 	else
842 		snprintf(out, out_size, "Group ID: %u\n", group_id);
843 }
844 
845 /**
846  * pipeline <pipeline_name> selector <selector_name> group delete <group_id>
847  */
848 static void
cmd_softnic_pipeline_selector_group_delete(struct pmd_internals * softnic,char ** tokens,uint32_t n_tokens,char * out,size_t out_size)849 cmd_softnic_pipeline_selector_group_delete(struct pmd_internals *softnic,
850 	char **tokens,
851 	uint32_t n_tokens,
852 	char *out,
853 	size_t out_size)
854 {
855 	struct pipeline *p;
856 	char *pipeline_name, *selector_name;
857 	uint32_t group_id;
858 	int status;
859 
860 	if (n_tokens != 7) {
861 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
862 		return;
863 	}
864 
865 	pipeline_name = tokens[1];
866 	p = softnic_pipeline_find(softnic, pipeline_name);
867 	if (!p) {
868 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
869 		return;
870 	}
871 
872 	if (strcmp(tokens[2], "selector") != 0) {
873 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "selector");
874 		return;
875 	}
876 
877 	selector_name = tokens[3];
878 
879 	if (strcmp(tokens[4], "group") ||
880 		strcmp(tokens[5], "delete")) {
881 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "group delete");
882 		return;
883 	}
884 
885 	if (parser_read_uint32(&group_id, tokens[6]) != 0) {
886 		snprintf(out, out_size, MSG_ARG_INVALID, "group_id");
887 		return;
888 	}
889 
890 	status = rte_swx_ctl_pipeline_selector_group_delete(p->ctl,
891 		selector_name,
892 		group_id);
893 	if (status)
894 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
895 }
896 
897 #define GROUP_MEMBER_INFO_TOKENS_MAX 6
898 
899 static int
token_is_comment(const char * token)900 token_is_comment(const char *token)
901 {
902 	if ((token[0] == '#') ||
903 	    (token[0] == ';') ||
904 	    ((token[0] == '/') && (token[1] == '/')))
905 		return 1; /* TRUE. */
906 
907 	return 0; /* FALSE. */
908 }
909 
910 static int
pipeline_selector_group_member_read(const char * string,uint32_t * group_id,uint32_t * member_id,uint32_t * weight,int * is_blank_or_comment)911 pipeline_selector_group_member_read(const char *string,
912 				    uint32_t *group_id,
913 				    uint32_t *member_id,
914 				    uint32_t *weight,
915 				    int *is_blank_or_comment)
916 {
917 	char *token_array[GROUP_MEMBER_INFO_TOKENS_MAX], **tokens;
918 	char *s0 = NULL, *s;
919 	uint32_t n_tokens = 0, group_id_val = 0, member_id_val = 0, weight_val = 0;
920 	int blank_or_comment = 0;
921 
922 	/* Check input arguments. */
923 	if (!string || !string[0])
924 		goto error;
925 
926 	/* Memory allocation. */
927 	s0 = strdup(string);
928 	if (!s0)
929 		goto error;
930 
931 	/* Parse the string into tokens. */
932 	for (s = s0; ; ) {
933 		char *token;
934 
935 		token = strtok_r(s, " \f\n\r\t\v", &s);
936 		if (!token || token_is_comment(token))
937 			break;
938 
939 		if (n_tokens >= GROUP_MEMBER_INFO_TOKENS_MAX)
940 			goto error;
941 
942 		token_array[n_tokens] = token;
943 		n_tokens++;
944 	}
945 
946 	if (!n_tokens) {
947 		blank_or_comment = 1;
948 		goto error;
949 	}
950 
951 	tokens = token_array;
952 
953 	if (n_tokens < 4 ||
954 		strcmp(tokens[0], "group") ||
955 		strcmp(tokens[2], "member"))
956 		goto error;
957 
958 	/*
959 	 * Group ID.
960 	 */
961 	if (parser_read_uint32(&group_id_val, tokens[1]) != 0)
962 		goto error;
963 	*group_id = group_id_val;
964 
965 	/*
966 	 * Member ID.
967 	 */
968 	if (parser_read_uint32(&member_id_val, tokens[3]) != 0)
969 		goto error;
970 	*member_id = member_id_val;
971 
972 	tokens += 4;
973 	n_tokens -= 4;
974 
975 	/*
976 	 * Weight.
977 	 */
978 	if (n_tokens && !strcmp(tokens[0], "weight")) {
979 		if (n_tokens < 2)
980 			goto error;
981 
982 		if (parser_read_uint32(&weight_val, tokens[1]) != 0)
983 			goto error;
984 		*weight = weight_val;
985 
986 		tokens += 2;
987 		n_tokens -= 2;
988 	}
989 
990 	if (n_tokens)
991 		goto error;
992 
993 	free(s0);
994 	return 0;
995 
996 error:
997 	free(s0);
998 	if (is_blank_or_comment)
999 		*is_blank_or_comment = blank_or_comment;
1000 	return -EINVAL;
1001 }
1002 
1003 static int
pipeline_selector_group_members_add(struct rte_swx_ctl_pipeline * p,const char * selector_name,FILE * file,uint32_t * file_line_number)1004 pipeline_selector_group_members_add(struct rte_swx_ctl_pipeline *p,
1005 				    const char *selector_name,
1006 				    FILE *file,
1007 				    uint32_t *file_line_number)
1008 {
1009 	char *line = NULL;
1010 	uint32_t line_id = 0;
1011 	int status = 0;
1012 
1013 	/* Buffer allocation. */
1014 	line = malloc(MAX_LINE_SIZE);
1015 	if (!line)
1016 		return -ENOMEM;
1017 
1018 	/* File read. */
1019 	for (line_id = 1; ; line_id++) {
1020 		uint32_t group_id, member_id, weight;
1021 		int is_blank_or_comment;
1022 
1023 		if (fgets(line, MAX_LINE_SIZE, file) == NULL)
1024 			break;
1025 
1026 		status = pipeline_selector_group_member_read(line,
1027 							     &group_id,
1028 							     &member_id,
1029 							     &weight,
1030 							     &is_blank_or_comment);
1031 		if (status) {
1032 			if (is_blank_or_comment)
1033 				continue;
1034 
1035 			goto error;
1036 		}
1037 
1038 		status = rte_swx_ctl_pipeline_selector_group_member_add(p,
1039 			selector_name,
1040 			group_id,
1041 			member_id,
1042 			weight);
1043 		if (status)
1044 			goto error;
1045 	}
1046 
1047 error:
1048 	free(line);
1049 	*file_line_number = line_id;
1050 	return status;
1051 }
1052 
1053 /**
1054  * pipeline <pipeline_name> selector <selector_name> group member add <file_name>
1055  */
1056 static void
cmd_softnic_pipeline_selector_group_member_add(struct pmd_internals * softnic,char ** tokens,uint32_t n_tokens,char * out,size_t out_size)1057 cmd_softnic_pipeline_selector_group_member_add(struct pmd_internals *softnic,
1058 	char **tokens,
1059 	uint32_t n_tokens,
1060 	char *out,
1061 	size_t out_size)
1062 {
1063 	struct pipeline *p;
1064 	char *pipeline_name, *selector_name, *file_name;
1065 	FILE *file = NULL;
1066 	uint32_t file_line_number = 0;
1067 	int status;
1068 
1069 	if (n_tokens != 8) {
1070 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1071 		return;
1072 	}
1073 
1074 	pipeline_name = tokens[1];
1075 	p = softnic_pipeline_find(softnic, pipeline_name);
1076 	if (!p) {
1077 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
1078 		return;
1079 	}
1080 
1081 	if (strcmp(tokens[2], "selector") != 0) {
1082 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "selector");
1083 		return;
1084 	}
1085 
1086 	selector_name = tokens[3];
1087 
1088 	if (strcmp(tokens[4], "group") ||
1089 		strcmp(tokens[5], "member") ||
1090 		strcmp(tokens[6], "add")) {
1091 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "group member add");
1092 		return;
1093 	}
1094 
1095 	file_name = tokens[7];
1096 	file = fopen(file_name, "r");
1097 	if (!file) {
1098 		snprintf(out, out_size, "Cannot open file %s.\n", file_name);
1099 		return;
1100 	}
1101 
1102 	status = pipeline_selector_group_members_add(p->ctl,
1103 		selector_name,
1104 		file,
1105 		&file_line_number);
1106 	if (status)
1107 		snprintf(out, out_size, "Invalid entry in file %s at line %u\n",
1108 			 file_name,
1109 			 file_line_number);
1110 
1111 	fclose(file);
1112 }
1113 
1114 static int
pipeline_selector_group_members_delete(struct rte_swx_ctl_pipeline * p,const char * selector_name,FILE * file,uint32_t * file_line_number)1115 pipeline_selector_group_members_delete(struct rte_swx_ctl_pipeline *p,
1116 				       const char *selector_name,
1117 				       FILE *file,
1118 				       uint32_t *file_line_number)
1119 {
1120 	char *line = NULL;
1121 	uint32_t line_id = 0;
1122 	int status = 0;
1123 
1124 	/* Buffer allocation. */
1125 	line = malloc(MAX_LINE_SIZE);
1126 	if (!line)
1127 		return -ENOMEM;
1128 
1129 	/* File read. */
1130 	for (line_id = 1; ; line_id++) {
1131 		uint32_t group_id, member_id, weight;
1132 		int is_blank_or_comment;
1133 
1134 		if (fgets(line, MAX_LINE_SIZE, file) == NULL)
1135 			break;
1136 
1137 		status = pipeline_selector_group_member_read(line,
1138 							     &group_id,
1139 							     &member_id,
1140 							     &weight,
1141 							     &is_blank_or_comment);
1142 		if (status) {
1143 			if (is_blank_or_comment)
1144 				continue;
1145 
1146 			goto error;
1147 		}
1148 
1149 		status = rte_swx_ctl_pipeline_selector_group_member_delete(p,
1150 			selector_name,
1151 			group_id,
1152 			member_id);
1153 		if (status)
1154 			goto error;
1155 	}
1156 
1157 error:
1158 	free(line);
1159 	*file_line_number = line_id;
1160 	return status;
1161 }
1162 
1163 /**
1164  * pipeline <pipeline_name> selector <selector_name> group member delete <file_name>
1165  */
1166 static void
cmd_softnic_pipeline_selector_group_member_delete(struct pmd_internals * softnic,char ** tokens,uint32_t n_tokens,char * out,size_t out_size)1167 cmd_softnic_pipeline_selector_group_member_delete(struct pmd_internals *softnic,
1168 	char **tokens,
1169 	uint32_t n_tokens,
1170 	char *out,
1171 	size_t out_size)
1172 {
1173 	struct pipeline *p;
1174 	char *pipeline_name, *selector_name, *file_name;
1175 	FILE *file = NULL;
1176 	uint32_t file_line_number = 0;
1177 	int status;
1178 
1179 	if (n_tokens != 8) {
1180 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1181 		return;
1182 	}
1183 
1184 	pipeline_name = tokens[1];
1185 	p = softnic_pipeline_find(softnic, pipeline_name);
1186 	if (!p) {
1187 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
1188 		return;
1189 	}
1190 
1191 	if (strcmp(tokens[2], "selector") != 0) {
1192 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "selector");
1193 		return;
1194 	}
1195 
1196 	selector_name = tokens[3];
1197 
1198 	if (strcmp(tokens[4], "group") ||
1199 		strcmp(tokens[5], "member") ||
1200 		strcmp(tokens[6], "delete")) {
1201 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "group member delete");
1202 		return;
1203 	}
1204 
1205 	file_name = tokens[7];
1206 	file = fopen(file_name, "r");
1207 	if (!file) {
1208 		snprintf(out, out_size, "Cannot open file %s.\n", file_name);
1209 		return;
1210 	}
1211 
1212 	status = pipeline_selector_group_members_delete(p->ctl,
1213 							selector_name,
1214 							file,
1215 							&file_line_number);
1216 	if (status)
1217 		snprintf(out, out_size, "Invalid entry in file %s at line %u\n",
1218 			 file_name,
1219 			 file_line_number);
1220 
1221 	fclose(file);
1222 }
1223 
1224 /**
1225  * pipeline <pipeline_name> selector <selector_name> show [filename]
1226  */
1227 static void
cmd_softnic_pipeline_selector_show(struct pmd_internals * softnic,char ** tokens,uint32_t n_tokens,char * out,size_t out_size)1228 cmd_softnic_pipeline_selector_show(struct pmd_internals *softnic,
1229 	char **tokens,
1230 	uint32_t n_tokens,
1231 	char *out,
1232 	size_t out_size)
1233 {
1234 	struct pipeline *p;
1235 	char *pipeline_name, *selector_name;
1236 	FILE *file = NULL;
1237 	int status;
1238 
1239 	if (n_tokens != 5 && n_tokens != 6) {
1240 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1241 		return;
1242 	}
1243 
1244 	pipeline_name = tokens[1];
1245 	p = softnic_pipeline_find(softnic, pipeline_name);
1246 	if (!p) {
1247 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
1248 		return;
1249 	}
1250 
1251 	selector_name = tokens[3];
1252 
1253 	file = (n_tokens == 6) ? fopen(tokens[5], "w") : stdout;
1254 	if (!file) {
1255 		snprintf(out, out_size, "Cannot open file %s.\n", tokens[5]);
1256 		return;
1257 	}
1258 
1259 	status = rte_swx_ctl_pipeline_selector_fprintf(file, p->ctl, selector_name);
1260 	if (status)
1261 		snprintf(out, out_size, MSG_ARG_INVALID, "selector_name");
1262 
1263 	if (file)
1264 		fclose(file);
1265 }
1266 
1267 static int
pipeline_learner_default_entry_add(struct rte_swx_ctl_pipeline * p,const char * learner_name,FILE * file,uint32_t * file_line_number)1268 pipeline_learner_default_entry_add(struct rte_swx_ctl_pipeline *p,
1269 				   const char *learner_name,
1270 				   FILE *file,
1271 				   uint32_t *file_line_number)
1272 {
1273 	char *line = NULL;
1274 	uint32_t line_id = 0;
1275 	int status = 0;
1276 
1277 	/* Buffer allocation. */
1278 	line = malloc(MAX_LINE_SIZE);
1279 	if (!line)
1280 		return -ENOMEM;
1281 
1282 	/* File read. */
1283 	for (line_id = 1; ; line_id++) {
1284 		struct rte_swx_table_entry *entry;
1285 		int is_blank_or_comment;
1286 
1287 		if (fgets(line, MAX_LINE_SIZE, file) == NULL)
1288 			break;
1289 
1290 		entry = rte_swx_ctl_pipeline_learner_default_entry_read(p,
1291 									learner_name,
1292 									line,
1293 									&is_blank_or_comment);
1294 		if (!entry) {
1295 			if (is_blank_or_comment)
1296 				continue;
1297 
1298 			status = -EINVAL;
1299 			goto error;
1300 		}
1301 
1302 		status = rte_swx_ctl_pipeline_learner_default_entry_add(p,
1303 									learner_name,
1304 									entry);
1305 		table_entry_free(entry);
1306 		if (status)
1307 			goto error;
1308 	}
1309 
1310 error:
1311 	*file_line_number = line_id;
1312 	free(line);
1313 	return status;
1314 }
1315 
1316 /**
1317  * pipeline <pipeline_name> learner <learner_name> default <file_name>
1318  */
1319 static void
cmd_softnic_pipeline_learner_default(struct pmd_internals * softnic,char ** tokens,uint32_t n_tokens,char * out,size_t out_size)1320 cmd_softnic_pipeline_learner_default(struct pmd_internals *softnic,
1321 	char **tokens,
1322 	uint32_t n_tokens,
1323 	char *out,
1324 	size_t out_size)
1325 {
1326 	struct pipeline *p;
1327 	char *pipeline_name, *learner_name, *file_name;
1328 	FILE *file = NULL;
1329 	uint32_t file_line_number = 0;
1330 	int status;
1331 
1332 	if (n_tokens != 6) {
1333 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1334 		return;
1335 	}
1336 
1337 	pipeline_name = tokens[1];
1338 	p = softnic_pipeline_find(softnic, pipeline_name);
1339 	if (!p) {
1340 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
1341 		return;
1342 	}
1343 
1344 	learner_name = tokens[3];
1345 
1346 	file_name = tokens[5];
1347 	file = fopen(file_name, "r");
1348 	if (!file) {
1349 		snprintf(out, out_size, "Cannot open file %s.\n", file_name);
1350 		return;
1351 	}
1352 
1353 	status = pipeline_learner_default_entry_add(p->ctl,
1354 						    learner_name,
1355 						    file,
1356 						    &file_line_number);
1357 	if (status)
1358 		snprintf(out, out_size, "Invalid entry in file %s at line %u\n",
1359 			 file_name,
1360 			 file_line_number);
1361 
1362 	fclose(file);
1363 }
1364 
1365 /**
1366  * pipeline <pipeline_name> commit
1367  */
1368 static void
cmd_softnic_pipeline_commit(struct pmd_internals * softnic,char ** tokens,uint32_t n_tokens,char * out,size_t out_size)1369 cmd_softnic_pipeline_commit(struct pmd_internals *softnic,
1370 	char **tokens,
1371 	uint32_t n_tokens,
1372 	char *out,
1373 	size_t out_size)
1374 {
1375 	struct pipeline *p;
1376 	char *pipeline_name;
1377 	int status;
1378 
1379 	if (n_tokens != 3) {
1380 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1381 		return;
1382 	}
1383 
1384 	pipeline_name = tokens[1];
1385 	p = softnic_pipeline_find(softnic, pipeline_name);
1386 	if (!p) {
1387 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
1388 		return;
1389 	}
1390 
1391 	status = rte_swx_ctl_pipeline_commit(p->ctl, 1);
1392 	if (status)
1393 		snprintf(out, out_size, "Commit failed. "
1394 			"Use \"commit\" to retry or \"abort\" to discard the pending work.\n");
1395 }
1396 
1397 /**
1398  * pipeline <pipeline_name> abort
1399  */
1400 static void
cmd_softnic_pipeline_abort(struct pmd_internals * softnic,char ** tokens,uint32_t n_tokens,char * out,size_t out_size)1401 cmd_softnic_pipeline_abort(struct pmd_internals *softnic,
1402 	char **tokens,
1403 	uint32_t n_tokens,
1404 	char *out,
1405 	size_t out_size)
1406 {
1407 	struct pipeline *p;
1408 	char *pipeline_name;
1409 
1410 	if (n_tokens != 3) {
1411 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1412 		return;
1413 	}
1414 
1415 	pipeline_name = tokens[1];
1416 	p = softnic_pipeline_find(softnic, pipeline_name);
1417 	if (!p) {
1418 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
1419 		return;
1420 	}
1421 
1422 	rte_swx_ctl_pipeline_abort(p->ctl);
1423 }
1424 
1425 /**
1426  * pipeline <pipeline_name> regrd <register_array_name> <index>
1427  */
1428 static void
cmd_softnic_pipeline_regrd(struct pmd_internals * softnic,char ** tokens,uint32_t n_tokens,char * out,size_t out_size)1429 cmd_softnic_pipeline_regrd(struct pmd_internals *softnic,
1430 	char **tokens,
1431 	uint32_t n_tokens,
1432 	char *out,
1433 	size_t out_size)
1434 {
1435 	struct pipeline *p;
1436 	const char *pipeline_name, *name;
1437 	uint64_t value;
1438 	uint32_t idx;
1439 	int status;
1440 
1441 	if (n_tokens != 5) {
1442 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1443 		return;
1444 	}
1445 
1446 	pipeline_name = tokens[1];
1447 	p = softnic_pipeline_find(softnic, pipeline_name);
1448 	if (!p) {
1449 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
1450 		return;
1451 	}
1452 
1453 	if (strcmp(tokens[2], "regrd")) {
1454 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "regrd");
1455 		return;
1456 	}
1457 
1458 	name = tokens[3];
1459 
1460 	if (parser_read_uint32(&idx, tokens[4])) {
1461 		snprintf(out, out_size, MSG_ARG_INVALID, "index");
1462 		return;
1463 	}
1464 
1465 	status = rte_swx_ctl_pipeline_regarray_read(p->p, name, idx, &value);
1466 	if (status) {
1467 		snprintf(out, out_size, "Command failed.\n");
1468 		return;
1469 	}
1470 
1471 	snprintf(out, out_size, "0x%" PRIx64 "\n", value);
1472 }
1473 
1474 /**
1475  * pipeline <pipeline_name> regwr <register_array_name> <index> <value>
1476  */
1477 static void
cmd_softnic_pipeline_regwr(struct pmd_internals * softnic,char ** tokens,uint32_t n_tokens,char * out,size_t out_size)1478 cmd_softnic_pipeline_regwr(struct pmd_internals *softnic,
1479 	char **tokens,
1480 	uint32_t n_tokens,
1481 	char *out,
1482 	size_t out_size)
1483 {
1484 	struct pipeline *p;
1485 	const char *pipeline_name, *name;
1486 	uint64_t value;
1487 	uint32_t idx;
1488 	int status;
1489 
1490 	if (n_tokens != 6) {
1491 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1492 		return;
1493 	}
1494 
1495 	pipeline_name = tokens[1];
1496 	p = softnic_pipeline_find(softnic, pipeline_name);
1497 	if (!p) {
1498 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
1499 		return;
1500 	}
1501 
1502 	if (strcmp(tokens[2], "regwr")) {
1503 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "regwr");
1504 		return;
1505 	}
1506 
1507 	name = tokens[3];
1508 
1509 	if (parser_read_uint32(&idx, tokens[4])) {
1510 		snprintf(out, out_size, MSG_ARG_INVALID, "index");
1511 		return;
1512 	}
1513 
1514 	if (parser_read_uint64(&value, tokens[5])) {
1515 		snprintf(out, out_size, MSG_ARG_INVALID, "value");
1516 		return;
1517 	}
1518 
1519 	status = rte_swx_ctl_pipeline_regarray_write(p->p, name, idx, value);
1520 	if (status) {
1521 		snprintf(out, out_size, "Command failed.\n");
1522 		return;
1523 	}
1524 }
1525 
1526 /**
1527  * pipeline <pipeline_name> meter profile <profile_name> add cir <cir> pir <pir> cbs <cbs> pbs <pbs>
1528  */
1529 static void
cmd_softnic_pipeline_meter_profile_add(struct pmd_internals * softnic,char ** tokens,uint32_t n_tokens,char * out,size_t out_size)1530 cmd_softnic_pipeline_meter_profile_add(struct pmd_internals *softnic,
1531 	char **tokens,
1532 	uint32_t n_tokens,
1533 	char *out,
1534 	size_t out_size)
1535 {
1536 	struct rte_meter_trtcm_params params;
1537 	struct pipeline *p;
1538 	const char *profile_name;
1539 	int status;
1540 
1541 	if (n_tokens != 14) {
1542 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1543 		return;
1544 	}
1545 
1546 	p = softnic_pipeline_find(softnic, tokens[1]);
1547 	if (!p) {
1548 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
1549 		return;
1550 	}
1551 
1552 	if (strcmp(tokens[2], "meter")) {
1553 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
1554 		return;
1555 	}
1556 
1557 	if (strcmp(tokens[3], "profile")) {
1558 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
1559 		return;
1560 	}
1561 
1562 	profile_name = tokens[4];
1563 
1564 	if (strcmp(tokens[5], "add")) {
1565 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
1566 		return;
1567 	}
1568 
1569 	if (strcmp(tokens[6], "cir")) {
1570 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cir");
1571 		return;
1572 	}
1573 
1574 	if (parser_read_uint64(&params.cir, tokens[7])) {
1575 		snprintf(out, out_size, MSG_ARG_INVALID, "cir");
1576 		return;
1577 	}
1578 
1579 	if (strcmp(tokens[8], "pir")) {
1580 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pir");
1581 		return;
1582 	}
1583 
1584 	if (parser_read_uint64(&params.pir, tokens[9])) {
1585 		snprintf(out, out_size, MSG_ARG_INVALID, "pir");
1586 		return;
1587 	}
1588 
1589 	if (strcmp(tokens[10], "cbs")) {
1590 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cbs");
1591 		return;
1592 	}
1593 
1594 	if (parser_read_uint64(&params.cbs, tokens[11])) {
1595 		snprintf(out, out_size, MSG_ARG_INVALID, "cbs");
1596 		return;
1597 	}
1598 
1599 	if (strcmp(tokens[12], "pbs")) {
1600 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pbs");
1601 		return;
1602 	}
1603 
1604 	if (parser_read_uint64(&params.pbs, tokens[13])) {
1605 		snprintf(out, out_size, MSG_ARG_INVALID, "pbs");
1606 		return;
1607 	}
1608 
1609 	status = rte_swx_ctl_meter_profile_add(p->p, profile_name, &params);
1610 	if (status) {
1611 		snprintf(out, out_size, "Command failed.\n");
1612 		return;
1613 	}
1614 }
1615 
1616 /**
1617  * pipeline <pipeline_name> meter profile <profile_name> delete
1618  */
1619 static void
cmd_softnic_pipeline_meter_profile_delete(struct pmd_internals * softnic,char ** tokens,uint32_t n_tokens,char * out,size_t out_size)1620 cmd_softnic_pipeline_meter_profile_delete(struct pmd_internals *softnic,
1621 	char **tokens,
1622 	uint32_t n_tokens,
1623 	char *out,
1624 	size_t out_size)
1625 {
1626 	struct pipeline *p;
1627 	const char *profile_name;
1628 	int status;
1629 
1630 	if (n_tokens != 6) {
1631 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1632 		return;
1633 	}
1634 
1635 	p = softnic_pipeline_find(softnic, tokens[1]);
1636 	if (!p) {
1637 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
1638 		return;
1639 	}
1640 
1641 	if (strcmp(tokens[2], "meter")) {
1642 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
1643 		return;
1644 	}
1645 
1646 	if (strcmp(tokens[3], "profile")) {
1647 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
1648 		return;
1649 	}
1650 
1651 	profile_name = tokens[4];
1652 
1653 	if (strcmp(tokens[5], "delete")) {
1654 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete");
1655 		return;
1656 	}
1657 
1658 	status = rte_swx_ctl_meter_profile_delete(p->p, profile_name);
1659 	if (status) {
1660 		snprintf(out, out_size, "Command failed.\n");
1661 		return;
1662 	}
1663 }
1664 
1665 /**
1666  * pipeline <pipeline_name> meter <meter_array_name> from <index0> to <index1> reset
1667  */
1668 static void
cmd_softnic_pipeline_meter_reset(struct pmd_internals * softnic,char ** tokens,uint32_t n_tokens,char * out,size_t out_size)1669 cmd_softnic_pipeline_meter_reset(struct pmd_internals *softnic,
1670 	char **tokens,
1671 	uint32_t n_tokens,
1672 	char *out,
1673 	size_t out_size)
1674 {
1675 	struct pipeline *p;
1676 	const char *name;
1677 	uint32_t idx0 = 0, idx1 = 0;
1678 
1679 	if (n_tokens != 9) {
1680 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1681 		return;
1682 	}
1683 
1684 	p = softnic_pipeline_find(softnic, tokens[1]);
1685 	if (!p) {
1686 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
1687 		return;
1688 	}
1689 
1690 	if (strcmp(tokens[2], "meter")) {
1691 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
1692 		return;
1693 	}
1694 
1695 	name = tokens[3];
1696 
1697 	if (strcmp(tokens[4], "from")) {
1698 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "from");
1699 		return;
1700 	}
1701 
1702 	if (parser_read_uint32(&idx0, tokens[5])) {
1703 		snprintf(out, out_size, MSG_ARG_INVALID, "index0");
1704 		return;
1705 	}
1706 
1707 	if (strcmp(tokens[6], "to")) {
1708 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "to");
1709 		return;
1710 	}
1711 
1712 	if (parser_read_uint32(&idx1, tokens[7]) || idx1 < idx0) {
1713 		snprintf(out, out_size, MSG_ARG_INVALID, "index1");
1714 		return;
1715 	}
1716 
1717 	if (strcmp(tokens[8], "reset")) {
1718 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "reset");
1719 		return;
1720 	}
1721 
1722 	for ( ; idx0 <= idx1; idx0++) {
1723 		int status;
1724 
1725 		status = rte_swx_ctl_meter_reset(p->p, name, idx0);
1726 		if (status) {
1727 			snprintf(out, out_size, "Command failed for index %u.\n", idx0);
1728 			return;
1729 		}
1730 	}
1731 }
1732 
1733 /**
1734  * pipeline <pipeline_name> meter <meter_array_name> from <index0> to <index1> set
1735  *	profile <profile_name>
1736  */
1737 static void
cmd_softnic_pipeline_meter_set(struct pmd_internals * softnic,char ** tokens,uint32_t n_tokens,char * out,size_t out_size)1738 cmd_softnic_pipeline_meter_set(struct pmd_internals *softnic,
1739 	char **tokens,
1740 	uint32_t n_tokens,
1741 	char *out,
1742 	size_t out_size)
1743 {
1744 	struct pipeline *p;
1745 	const char *name, *profile_name;
1746 	uint32_t idx0 = 0, idx1 = 0;
1747 
1748 	if (n_tokens != 11) {
1749 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1750 		return;
1751 	}
1752 
1753 	p = softnic_pipeline_find(softnic, tokens[1]);
1754 	if (!p) {
1755 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
1756 		return;
1757 	}
1758 
1759 	if (strcmp(tokens[2], "meter")) {
1760 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
1761 		return;
1762 	}
1763 
1764 	name = tokens[3];
1765 
1766 	if (strcmp(tokens[4], "from")) {
1767 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "from");
1768 		return;
1769 	}
1770 
1771 	if (parser_read_uint32(&idx0, tokens[5])) {
1772 		snprintf(out, out_size, MSG_ARG_INVALID, "index0");
1773 		return;
1774 	}
1775 
1776 	if (strcmp(tokens[6], "to")) {
1777 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "to");
1778 		return;
1779 	}
1780 
1781 	if (parser_read_uint32(&idx1, tokens[7]) || idx1 < idx0) {
1782 		snprintf(out, out_size, MSG_ARG_INVALID, "index1");
1783 		return;
1784 	}
1785 
1786 	if (strcmp(tokens[8], "set")) {
1787 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "set");
1788 		return;
1789 	}
1790 
1791 	if (strcmp(tokens[9], "profile")) {
1792 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
1793 		return;
1794 	}
1795 
1796 	profile_name = tokens[10];
1797 
1798 	for ( ; idx0 <= idx1; idx0++) {
1799 		int status;
1800 
1801 		status = rte_swx_ctl_meter_set(p->p, name, idx0, profile_name);
1802 		if (status) {
1803 			snprintf(out, out_size, "Command failed for index %u.\n", idx0);
1804 			return;
1805 		}
1806 	}
1807 }
1808 
1809 /**
1810  * pipeline <pipeline_name> meter <meter_array_name> from <index0> to <index1> stats
1811  */
1812 static void
cmd_softnic_pipeline_meter_stats(struct pmd_internals * softnic,char ** tokens,uint32_t n_tokens,char * out,size_t out_size)1813 cmd_softnic_pipeline_meter_stats(struct pmd_internals *softnic,
1814 	char **tokens,
1815 	uint32_t n_tokens,
1816 	char *out,
1817 	size_t out_size)
1818 {
1819 	struct rte_swx_ctl_meter_stats stats;
1820 	struct pipeline *p;
1821 	const char *name;
1822 	uint32_t idx0 = 0, idx1 = 0;
1823 
1824 	if (n_tokens != 9) {
1825 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1826 		return;
1827 	}
1828 
1829 	p = softnic_pipeline_find(softnic, tokens[1]);
1830 	if (!p) {
1831 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
1832 		return;
1833 	}
1834 
1835 	if (strcmp(tokens[2], "meter")) {
1836 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
1837 		return;
1838 	}
1839 
1840 	name = tokens[3];
1841 
1842 	if (strcmp(tokens[4], "from")) {
1843 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "from");
1844 		return;
1845 	}
1846 
1847 	if (parser_read_uint32(&idx0, tokens[5])) {
1848 		snprintf(out, out_size, MSG_ARG_INVALID, "index0");
1849 		return;
1850 	}
1851 
1852 	if (strcmp(tokens[6], "to")) {
1853 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "to");
1854 		return;
1855 	}
1856 
1857 	if (parser_read_uint32(&idx1, tokens[7]) || idx1 < idx0) {
1858 		snprintf(out, out_size, MSG_ARG_INVALID, "index1");
1859 		return;
1860 	}
1861 
1862 	if (strcmp(tokens[8], "stats")) {
1863 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
1864 		return;
1865 	}
1866 
1867 	/* Table header. */
1868 	snprintf(out, out_size, "+-%7s-+-%16s-+-%16s-+-%16s-+-%16s-+-%16s-+-%16s-+\n",
1869 		 "-------",
1870 		 "----------------", "----------------", "----------------",
1871 		 "----------------", "----------------", "----------------");
1872 	out_size -= strlen(out);
1873 	out += strlen(out);
1874 
1875 	snprintf(out, out_size, "| %4s | %16s | %16s | %16s | %16s | %16s | %16s |\n",
1876 		 "METER #",
1877 		 "GREEN (packets)", "YELLOW (packets)", "RED (packets)",
1878 		 "GREEN (bytes)", "YELLOW (bytes)", "RED (bytes)");
1879 	out_size -= strlen(out);
1880 	out += strlen(out);
1881 
1882 	snprintf(out, out_size, "+-%7s-+-%16s-+-%16s-+-%16s-+-%16s-+-%16s-+-%16s-+\n",
1883 		 "-------",
1884 		 "----------------", "----------------", "----------------",
1885 		 "----------------", "----------------", "----------------");
1886 	out_size -= strlen(out);
1887 	out += strlen(out);
1888 
1889 	/* Table rows. */
1890 	for ( ; idx0 <= idx1; idx0++) {
1891 		int status;
1892 
1893 		status = rte_swx_ctl_meter_stats_read(p->p, name, idx0, &stats);
1894 		if (status) {
1895 			snprintf(out, out_size, "Pipeline meter stats error at index %u.\n", idx0);
1896 			out_size -= strlen(out);
1897 			out += strlen(out);
1898 			return;
1899 		}
1900 
1901 		snprintf(out, out_size, "| %7d | %16" PRIx64 " | %16" PRIx64 " | %16" PRIx64
1902 			 " | %16" PRIx64 " | %16" PRIx64 " | %16" PRIx64 " |\n",
1903 			 idx0,
1904 			 stats.n_pkts[RTE_COLOR_GREEN],
1905 			 stats.n_pkts[RTE_COLOR_YELLOW],
1906 			 stats.n_pkts[RTE_COLOR_RED],
1907 			 stats.n_bytes[RTE_COLOR_GREEN],
1908 			 stats.n_bytes[RTE_COLOR_YELLOW],
1909 			 stats.n_bytes[RTE_COLOR_RED]);
1910 		out_size -= strlen(out);
1911 		out += strlen(out);
1912 	}
1913 }
1914 
1915 /**
1916  * pipeline <pipeline_name> stats
1917  */
1918 static void
cmd_softnic_pipeline_stats(struct pmd_internals * softnic,char ** tokens,uint32_t n_tokens,char * out,size_t out_size)1919 cmd_softnic_pipeline_stats(struct pmd_internals *softnic,
1920 	char **tokens,
1921 	uint32_t n_tokens,
1922 	char *out,
1923 	size_t out_size)
1924 {
1925 	struct rte_swx_ctl_pipeline_info info;
1926 	struct pipeline *p;
1927 	uint32_t i;
1928 	int status;
1929 
1930 	if (n_tokens != 3) {
1931 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
1932 		return;
1933 	}
1934 
1935 	p = softnic_pipeline_find(softnic, tokens[1]);
1936 	if (!p) {
1937 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
1938 		return;
1939 	}
1940 
1941 	if (strcmp(tokens[2], "stats")) {
1942 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
1943 		return;
1944 	}
1945 
1946 	status = rte_swx_ctl_pipeline_info_get(p->p, &info);
1947 	if (status) {
1948 		snprintf(out, out_size, "Pipeline info get error.");
1949 		return;
1950 	}
1951 
1952 	snprintf(out, out_size, "Input ports:\n");
1953 	out_size -= strlen(out);
1954 	out += strlen(out);
1955 
1956 	for (i = 0; i < info.n_ports_in; i++) {
1957 		struct rte_swx_port_in_stats stats;
1958 
1959 		rte_swx_ctl_pipeline_port_in_stats_read(p->p, i, &stats);
1960 
1961 		snprintf(out, out_size, "\tPort %u:"
1962 			" packets %" PRIu64
1963 			" bytes %" PRIu64
1964 			" empty %" PRIu64 "\n",
1965 			i, stats.n_pkts, stats.n_bytes, stats.n_empty);
1966 		out_size -= strlen(out);
1967 		out += strlen(out);
1968 	}
1969 
1970 	snprintf(out, out_size, "\nOutput ports:\n");
1971 	out_size -= strlen(out);
1972 	out += strlen(out);
1973 
1974 	for (i = 0; i < info.n_ports_out; i++) {
1975 		struct rte_swx_port_out_stats stats;
1976 
1977 		rte_swx_ctl_pipeline_port_out_stats_read(p->p, i, &stats);
1978 
1979 		if (i != info.n_ports_out - 1)
1980 			snprintf(out, out_size, "\tPort %u:", i);
1981 		else
1982 			snprintf(out, out_size, "\tDROP:");
1983 
1984 		out_size -= strlen(out);
1985 		out += strlen(out);
1986 
1987 		snprintf(out,
1988 			out_size,
1989 			" packets %" PRIu64
1990 			" bytes %" PRIu64
1991 			" packets dropped %" PRIu64
1992 			" bytes dropped %" PRIu64
1993 			" clone %" PRIu64
1994 			" clonerr %" PRIu64 "\n",
1995 			stats.n_pkts,
1996 			stats.n_bytes,
1997 			stats.n_pkts_drop,
1998 			stats.n_bytes_drop,
1999 			stats.n_pkts_clone,
2000 			stats.n_pkts_clone_err);
2001 
2002 		out_size -= strlen(out);
2003 		out += strlen(out);
2004 	}
2005 
2006 	snprintf(out, out_size, "\nTables:\n");
2007 	out_size -= strlen(out);
2008 	out += strlen(out);
2009 
2010 	for (i = 0; i < info.n_tables; i++) {
2011 		struct rte_swx_ctl_table_info table_info;
2012 		uint64_t n_pkts_action[info.n_actions];
2013 		struct rte_swx_table_stats stats = {
2014 			.n_pkts_hit = 0,
2015 			.n_pkts_miss = 0,
2016 			.n_pkts_action = n_pkts_action,
2017 		};
2018 		uint32_t j;
2019 
2020 		status = rte_swx_ctl_table_info_get(p->p, i, &table_info);
2021 		if (status) {
2022 			snprintf(out, out_size, "Table info get error.");
2023 			return;
2024 		}
2025 
2026 		status = rte_swx_ctl_pipeline_table_stats_read(p->p, table_info.name, &stats);
2027 		if (status) {
2028 			snprintf(out, out_size, "Table stats read error.");
2029 			return;
2030 		}
2031 
2032 		snprintf(out, out_size, "\tTable %s:\n"
2033 			"\t\tHit (packets): %" PRIu64 "\n"
2034 			"\t\tMiss (packets): %" PRIu64 "\n",
2035 			table_info.name,
2036 			stats.n_pkts_hit,
2037 			stats.n_pkts_miss);
2038 		out_size -= strlen(out);
2039 		out += strlen(out);
2040 
2041 		for (j = 0; j < info.n_actions; j++) {
2042 			struct rte_swx_ctl_action_info action_info;
2043 
2044 			status = rte_swx_ctl_action_info_get(p->p, j, &action_info);
2045 			if (status) {
2046 				snprintf(out, out_size, "Action info get error.");
2047 				return;
2048 			}
2049 
2050 			snprintf(out, out_size, "\t\tAction %s (packets): %" PRIu64 "\n",
2051 				action_info.name,
2052 				stats.n_pkts_action[j]);
2053 			out_size -= strlen(out);
2054 			out += strlen(out);
2055 		}
2056 	}
2057 
2058 	snprintf(out, out_size, "\nLearner tables:\n");
2059 	out_size -= strlen(out);
2060 	out += strlen(out);
2061 
2062 	for (i = 0; i < info.n_learners; i++) {
2063 		struct rte_swx_ctl_learner_info learner_info;
2064 		uint64_t n_pkts_action[info.n_actions];
2065 		struct rte_swx_learner_stats stats = {
2066 			.n_pkts_hit = 0,
2067 			.n_pkts_miss = 0,
2068 			.n_pkts_action = n_pkts_action,
2069 		};
2070 		uint32_t j;
2071 
2072 		status = rte_swx_ctl_learner_info_get(p->p, i, &learner_info);
2073 		if (status) {
2074 			snprintf(out, out_size, "Learner table info get error.");
2075 			return;
2076 		}
2077 
2078 		status = rte_swx_ctl_pipeline_learner_stats_read(p->p, learner_info.name, &stats);
2079 		if (status) {
2080 			snprintf(out, out_size, "Learner table stats read error.");
2081 			return;
2082 		}
2083 
2084 		snprintf(out, out_size, "\tLearner table %s:\n"
2085 			"\t\tHit (packets): %" PRIu64 "\n"
2086 			"\t\tMiss (packets): %" PRIu64 "\n"
2087 			"\t\tLearn OK (packets): %" PRIu64 "\n"
2088 			"\t\tLearn error (packets): %" PRIu64 "\n"
2089 			"\t\tRearm (packets): %" PRIu64 "\n"
2090 			"\t\tForget (packets): %" PRIu64 "\n",
2091 			learner_info.name,
2092 			stats.n_pkts_hit,
2093 			stats.n_pkts_miss,
2094 			stats.n_pkts_learn_ok,
2095 			stats.n_pkts_learn_err,
2096 			stats.n_pkts_rearm,
2097 			stats.n_pkts_forget);
2098 		out_size -= strlen(out);
2099 		out += strlen(out);
2100 
2101 		for (j = 0; j < info.n_actions; j++) {
2102 			struct rte_swx_ctl_action_info action_info;
2103 
2104 			status = rte_swx_ctl_action_info_get(p->p, j, &action_info);
2105 			if (status) {
2106 				snprintf(out, out_size, "Action info get error.");
2107 				return;
2108 			}
2109 
2110 			snprintf(out, out_size, "\t\tAction %s (packets): %" PRIu64 "\n",
2111 				action_info.name,
2112 				stats.n_pkts_action[j]);
2113 			out_size -= strlen(out);
2114 			out += strlen(out);
2115 		}
2116 	}
2117 }
2118 
2119 /**
2120  * pipeline <pipeline_name> mirror session <session_id> port <port_id> clone fast | slow
2121  *	truncate <truncation_length>
2122  */
2123 static void
cmd_softnic_pipeline_mirror_session(struct pmd_internals * softnic,char ** tokens,uint32_t n_tokens,char * out,size_t out_size)2124 cmd_softnic_pipeline_mirror_session(struct pmd_internals *softnic,
2125 	char **tokens,
2126 	uint32_t n_tokens,
2127 	char *out,
2128 	size_t out_size)
2129 {
2130 	struct rte_swx_pipeline_mirroring_session_params params;
2131 	struct pipeline *p;
2132 	uint32_t session_id = 0;
2133 	int status;
2134 
2135 	if (n_tokens != 11) {
2136 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2137 		return;
2138 	}
2139 
2140 	if (strcmp(tokens[0], "pipeline")) {
2141 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
2142 		return;
2143 	}
2144 
2145 	p = softnic_pipeline_find(softnic, tokens[1]);
2146 	if (!p) {
2147 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
2148 		return;
2149 	}
2150 
2151 	if (strcmp(tokens[2], "mirror")) {
2152 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mirror");
2153 		return;
2154 	}
2155 
2156 	if (strcmp(tokens[3], "session")) {
2157 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "session");
2158 		return;
2159 	}
2160 
2161 	if (parser_read_uint32(&session_id, tokens[4])) {
2162 		snprintf(out, out_size, MSG_ARG_INVALID, "session_id");
2163 		return;
2164 	}
2165 
2166 	if (strcmp(tokens[5], "port")) {
2167 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
2168 		return;
2169 	}
2170 
2171 	if (parser_read_uint32(&params.port_id, tokens[6])) {
2172 		snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
2173 		return;
2174 	}
2175 
2176 	if (strcmp(tokens[7], "clone")) {
2177 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "clone");
2178 		return;
2179 	}
2180 
2181 	if (!strcmp(tokens[8], "fast")) {
2182 		params.fast_clone = 1;
2183 	} else if (!strcmp(tokens[8], "slow")) {
2184 		params.fast_clone = 0;
2185 	} else {
2186 		snprintf(out, out_size, MSG_ARG_INVALID, "clone");
2187 		return;
2188 	}
2189 
2190 	if (strcmp(tokens[9], "truncate")) {
2191 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "truncate");
2192 		return;
2193 	}
2194 
2195 	if (parser_read_uint32(&params.truncation_length, tokens[10])) {
2196 		snprintf(out, out_size, MSG_ARG_INVALID, "truncation_length");
2197 		return;
2198 	}
2199 
2200 	status = rte_swx_ctl_pipeline_mirroring_session_set(p->p, session_id, &params);
2201 	if (status) {
2202 		snprintf(out, out_size, "Command failed!\n");
2203 		return;
2204 	}
2205 }
2206 
2207 /**
2208  * thread <thread_id> pipeline <pipeline_name> enable [ period <timer_period_ms> ]
2209  */
2210 static void
cmd_softnic_thread_pipeline_enable(struct pmd_internals * softnic,char ** tokens,uint32_t n_tokens,char * out,size_t out_size)2211 cmd_softnic_thread_pipeline_enable(struct pmd_internals *softnic,
2212 	char **tokens,
2213 	uint32_t n_tokens,
2214 	char *out,
2215 	size_t out_size)
2216 {
2217 	char *pipeline_name;
2218 	struct pipeline *p;
2219 	uint32_t thread_id;
2220 	int status;
2221 
2222 	if (n_tokens != 5) {
2223 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2224 		return;
2225 	}
2226 
2227 	if (parser_read_uint32(&thread_id, tokens[1]) != 0) {
2228 		snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
2229 		return;
2230 	}
2231 
2232 	if (strcmp(tokens[2], "pipeline") != 0) {
2233 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
2234 		return;
2235 	}
2236 
2237 	pipeline_name = tokens[3];
2238 	p = softnic_pipeline_find(softnic, pipeline_name);
2239 	if (!p) {
2240 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
2241 		return;
2242 	}
2243 
2244 	if (strcmp(tokens[4], "enable") != 0) {
2245 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable");
2246 		return;
2247 	}
2248 
2249 	status = softnic_thread_pipeline_enable(softnic, thread_id, p);
2250 	if (status) {
2251 		snprintf(out, out_size, MSG_CMD_FAIL, "thread pipeline enable");
2252 		return;
2253 	}
2254 }
2255 
2256 /**
2257  * thread <thread_id> pipeline <pipeline_name> disable
2258  */
2259 static void
cmd_softnic_thread_pipeline_disable(struct pmd_internals * softnic,char ** tokens,uint32_t n_tokens,char * out,size_t out_size)2260 cmd_softnic_thread_pipeline_disable(struct pmd_internals *softnic,
2261 	char **tokens,
2262 	uint32_t n_tokens,
2263 	char *out,
2264 	size_t out_size)
2265 {
2266 	char *pipeline_name;
2267 	struct pipeline *p;
2268 	uint32_t thread_id;
2269 	int status;
2270 
2271 	if (n_tokens != 5) {
2272 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
2273 		return;
2274 	}
2275 
2276 	if (parser_read_uint32(&thread_id, tokens[1]) != 0) {
2277 		snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
2278 		return;
2279 	}
2280 
2281 	if (strcmp(tokens[2], "pipeline") != 0) {
2282 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
2283 		return;
2284 	}
2285 
2286 	pipeline_name = tokens[3];
2287 	p = softnic_pipeline_find(softnic, pipeline_name);
2288 	if (!p) {
2289 		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
2290 		return;
2291 	}
2292 
2293 	if (strcmp(tokens[4], "disable") != 0) {
2294 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable");
2295 		return;
2296 	}
2297 
2298 	status = softnic_thread_pipeline_disable(softnic, thread_id, p);
2299 	if (status) {
2300 		snprintf(out, out_size, MSG_CMD_FAIL,
2301 			"thread pipeline disable");
2302 		return;
2303 	}
2304 }
2305 
2306 void
softnic_cli_process(char * in,char * out,size_t out_size,void * arg)2307 softnic_cli_process(char *in, char *out, size_t out_size, void *arg)
2308 {
2309 	char *tokens[CMD_MAX_TOKENS];
2310 	uint32_t n_tokens = RTE_DIM(tokens);
2311 	struct pmd_internals *softnic = arg;
2312 	int status;
2313 
2314 	if (is_comment(in))
2315 		return;
2316 
2317 	status = parse_tokenize_string(in, tokens, &n_tokens);
2318 	if (status) {
2319 		snprintf(out, out_size, MSG_ARG_TOO_MANY, "");
2320 		return;
2321 	}
2322 
2323 	if (n_tokens == 0)
2324 		return;
2325 
2326 	if (strcmp(tokens[0], "mempool") == 0) {
2327 		cmd_mempool(softnic, tokens, n_tokens, out, out_size);
2328 		return;
2329 	}
2330 
2331 	if (strcmp(tokens[0], "swq") == 0) {
2332 		cmd_swq(softnic, tokens, n_tokens, out, out_size);
2333 		return;
2334 	}
2335 
2336 	if (!strcmp(tokens[0], "pipeline")) {
2337 		if (n_tokens >= 2 && !strcmp(tokens[1], "codegen")) {
2338 			cmd_softnic_pipeline_codegen(softnic, tokens, n_tokens, out, out_size);
2339 			return;
2340 		}
2341 
2342 		if (n_tokens >= 3 && !strcmp(tokens[1], "libbuild")) {
2343 			cmd_softnic_pipeline_libbuild(softnic, tokens, n_tokens, out, out_size);
2344 			return;
2345 		}
2346 
2347 		if (n_tokens >= 3 && !strcmp(tokens[2], "build")) {
2348 			cmd_softnic_pipeline_build(softnic, tokens, n_tokens, out, out_size);
2349 			return;
2350 		}
2351 
2352 		if (n_tokens >= 5 && !strcmp(tokens[2], "table") && !strcmp(tokens[4], "add")) {
2353 			cmd_softnic_pipeline_table_add(softnic, tokens, n_tokens, out, out_size);
2354 			return;
2355 		}
2356 
2357 		if (n_tokens >= 5 && !strcmp(tokens[2], "table") && !strcmp(tokens[4], "delete")) {
2358 			cmd_softnic_pipeline_table_delete(softnic, tokens, n_tokens,
2359 				out, out_size);
2360 			return;
2361 		}
2362 
2363 		if (n_tokens >= 5 && !strcmp(tokens[2], "table") && !strcmp(tokens[4], "default")) {
2364 			cmd_softnic_pipeline_table_default(softnic, tokens, n_tokens,
2365 				out, out_size);
2366 			return;
2367 		}
2368 
2369 		if (n_tokens >= 5 && !strcmp(tokens[2], "table") && !strcmp(tokens[4], "show")) {
2370 			cmd_softnic_pipeline_table_show(softnic, tokens, n_tokens, out, out_size);
2371 			return;
2372 		}
2373 
2374 		if (n_tokens >= 6 &&
2375 			!strcmp(tokens[2], "selector") &&
2376 			!strcmp(tokens[4], "group") &&
2377 			!strcmp(tokens[5], "add")) {
2378 			cmd_softnic_pipeline_selector_group_add(softnic, tokens, n_tokens,
2379 				out, out_size);
2380 			return;
2381 		}
2382 
2383 		if (n_tokens >= 6 &&
2384 			!strcmp(tokens[2], "selector") &&
2385 			!strcmp(tokens[4], "group") &&
2386 			!strcmp(tokens[5], "delete")) {
2387 			cmd_softnic_pipeline_selector_group_delete(softnic, tokens, n_tokens,
2388 				out, out_size);
2389 			return;
2390 		}
2391 
2392 		if (n_tokens >= 7 &&
2393 			!strcmp(tokens[2], "selector") &&
2394 			!strcmp(tokens[4], "group") &&
2395 			!strcmp(tokens[5], "member") &&
2396 			!strcmp(tokens[6], "add")) {
2397 			cmd_softnic_pipeline_selector_group_member_add(softnic, tokens, n_tokens,
2398 				out, out_size);
2399 			return;
2400 		}
2401 
2402 		if (n_tokens >= 7 &&
2403 			!strcmp(tokens[2], "selector") &&
2404 			!strcmp(tokens[4], "group") &&
2405 			!strcmp(tokens[5], "member") &&
2406 			!strcmp(tokens[6], "delete")) {
2407 			cmd_softnic_pipeline_selector_group_member_delete(softnic, tokens, n_tokens,
2408 				out, out_size);
2409 			return;
2410 		}
2411 
2412 		if (n_tokens >= 5 &&
2413 			!strcmp(tokens[2], "selector") &&
2414 			!strcmp(tokens[4], "show")) {
2415 			cmd_softnic_pipeline_selector_show(softnic, tokens, n_tokens,
2416 				out, out_size);
2417 			return;
2418 		}
2419 
2420 		if (n_tokens >= 5 &&
2421 			!strcmp(tokens[2], "learner") &&
2422 			!strcmp(tokens[4], "default")) {
2423 			cmd_softnic_pipeline_learner_default(softnic, tokens, n_tokens,
2424 				out, out_size);
2425 			return;
2426 		}
2427 
2428 		if (n_tokens >= 3 && !strcmp(tokens[2], "commit")) {
2429 			cmd_softnic_pipeline_commit(softnic, tokens, n_tokens, out, out_size);
2430 			return;
2431 		}
2432 
2433 		if (n_tokens >= 3 && !strcmp(tokens[2], "abort")) {
2434 			cmd_softnic_pipeline_abort(softnic, tokens, n_tokens, out, out_size);
2435 			return;
2436 		}
2437 
2438 		if (n_tokens >= 3 && !strcmp(tokens[2], "regrd")) {
2439 			cmd_softnic_pipeline_regrd(softnic, tokens, n_tokens, out, out_size);
2440 			return;
2441 		}
2442 
2443 		if (n_tokens >= 3 && !strcmp(tokens[2], "regwr")) {
2444 			cmd_softnic_pipeline_regwr(softnic, tokens, n_tokens, out, out_size);
2445 			return;
2446 		}
2447 
2448 		if (n_tokens >= 6 &&
2449 			!strcmp(tokens[2], "meter") &&
2450 			!strcmp(tokens[3], "profile") &&
2451 			!strcmp(tokens[5], "add")) {
2452 			cmd_softnic_pipeline_meter_profile_add(softnic, tokens, n_tokens,
2453 				out, out_size);
2454 			return;
2455 		}
2456 
2457 		if (n_tokens >= 6 &&
2458 			!strcmp(tokens[2], "meter") &&
2459 			!strcmp(tokens[3], "profile") &&
2460 			!strcmp(tokens[5], "delete")) {
2461 			cmd_softnic_pipeline_meter_profile_delete(softnic, tokens, n_tokens,
2462 				out, out_size);
2463 			return;
2464 		}
2465 
2466 		if (n_tokens >= 9 && !strcmp(tokens[2], "meter") && !strcmp(tokens[8], "reset")) {
2467 			cmd_softnic_pipeline_meter_reset(softnic, tokens, n_tokens, out, out_size);
2468 			return;
2469 		}
2470 
2471 		if (n_tokens >= 9 && !strcmp(tokens[2], "meter") && !strcmp(tokens[8], "set")) {
2472 			cmd_softnic_pipeline_meter_set(softnic, tokens, n_tokens, out, out_size);
2473 			return;
2474 		}
2475 
2476 		if (n_tokens >= 9 && !strcmp(tokens[2], "meter") && !strcmp(tokens[8], "stats")) {
2477 			cmd_softnic_pipeline_meter_stats(softnic, tokens, n_tokens, out, out_size);
2478 			return;
2479 		}
2480 
2481 		if (n_tokens >= 3 && !strcmp(tokens[2], "stats")) {
2482 			cmd_softnic_pipeline_stats(softnic, tokens, n_tokens, out, out_size);
2483 			return;
2484 		}
2485 
2486 		if (n_tokens >= 4 &&
2487 			!strcmp(tokens[2], "mirror") &&
2488 			!strcmp(tokens[3], "session")) {
2489 			cmd_softnic_pipeline_mirror_session(softnic, tokens, n_tokens,
2490 				out, out_size);
2491 			return;
2492 		}
2493 	}
2494 
2495 	if (strcmp(tokens[0], "thread") == 0) {
2496 		if (n_tokens >= 5 &&
2497 			(strcmp(tokens[4], "enable") == 0)) {
2498 			cmd_softnic_thread_pipeline_enable(softnic, tokens, n_tokens,
2499 				out, out_size);
2500 			return;
2501 		}
2502 
2503 		if (n_tokens >= 5 &&
2504 			(strcmp(tokens[4], "disable") == 0)) {
2505 			cmd_softnic_thread_pipeline_disable(softnic, tokens, n_tokens,
2506 				out, out_size);
2507 			return;
2508 		}
2509 	}
2510 
2511 	snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
2512 }
2513 
2514 int
softnic_cli_script_process(struct pmd_internals * softnic,const char * file_name,size_t msg_in_len_max,size_t msg_out_len_max)2515 softnic_cli_script_process(struct pmd_internals *softnic,
2516 	const char *file_name,
2517 	size_t msg_in_len_max,
2518 	size_t msg_out_len_max)
2519 {
2520 	char *msg_in = NULL, *msg_out = NULL;
2521 	FILE *f = NULL;
2522 
2523 	/* Check input arguments */
2524 	if (file_name == NULL ||
2525 		(strlen(file_name) == 0) ||
2526 		msg_in_len_max == 0 ||
2527 		msg_out_len_max == 0)
2528 		return -EINVAL;
2529 
2530 	msg_in = malloc(msg_in_len_max + 1);
2531 	msg_out = malloc(msg_out_len_max + 1);
2532 	if (msg_in == NULL ||
2533 		msg_out == NULL) {
2534 		free(msg_out);
2535 		free(msg_in);
2536 		return -ENOMEM;
2537 	}
2538 
2539 	/* Open input file */
2540 	f = fopen(file_name, "r");
2541 	if (f == NULL) {
2542 		free(msg_out);
2543 		free(msg_in);
2544 		return -EIO;
2545 	}
2546 
2547 	/* Read file */
2548 	for ( ; ; ) {
2549 		if (fgets(msg_in, msg_in_len_max + 1, f) == NULL)
2550 			break;
2551 
2552 		printf("%s", msg_in);
2553 		msg_out[0] = 0;
2554 
2555 		softnic_cli_process(msg_in,
2556 			msg_out,
2557 			msg_out_len_max,
2558 			softnic);
2559 
2560 		if (strlen(msg_out))
2561 			printf("%s", msg_out);
2562 	}
2563 
2564 	/* Close file */
2565 	fclose(f);
2566 	free(msg_out);
2567 	free(msg_in);
2568 	return 0;
2569 }
2570