1*d30ea906Sjfb8856606 /* SPDX-License-Identifier: BSD-3-Clause
2*d30ea906Sjfb8856606  * Copyright(c) 2016-2017 Intel Corporation
32bfe3f2eSlogwang  */
42bfe3f2eSlogwang 
52bfe3f2eSlogwang #include <stdio.h>
62bfe3f2eSlogwang #include <stdlib.h>
72bfe3f2eSlogwang #include <stdint.h>
82bfe3f2eSlogwang #include <getopt.h>
92bfe3f2eSlogwang #include <stdarg.h>
102bfe3f2eSlogwang #include <errno.h>
112bfe3f2eSlogwang 
122bfe3f2eSlogwang #include <rte_memory.h>
132bfe3f2eSlogwang #include <rte_string_fns.h>
142bfe3f2eSlogwang 
152bfe3f2eSlogwang #include "common.h"
162bfe3f2eSlogwang #include "args.h"
172bfe3f2eSlogwang #include "init.h"
182bfe3f2eSlogwang 
192bfe3f2eSlogwang /* 1M flows by default */
202bfe3f2eSlogwang #define DEFAULT_NUM_FLOWS    0x100000
212bfe3f2eSlogwang 
222bfe3f2eSlogwang /* global var for number of nodes - extern in header */
232bfe3f2eSlogwang uint8_t num_nodes;
242bfe3f2eSlogwang /* global var for number of flows - extern in header */
252bfe3f2eSlogwang uint32_t num_flows = DEFAULT_NUM_FLOWS;
262bfe3f2eSlogwang 
272bfe3f2eSlogwang static const char *progname;
282bfe3f2eSlogwang 
292bfe3f2eSlogwang /**
302bfe3f2eSlogwang  * Prints out usage information to stdout
312bfe3f2eSlogwang  */
322bfe3f2eSlogwang static void
usage(void)332bfe3f2eSlogwang usage(void)
342bfe3f2eSlogwang {
352bfe3f2eSlogwang 	printf("%s [EAL options] -- -p PORTMASK -n NUM_NODES -f NUM_FLOWS\n"
362bfe3f2eSlogwang 		" -p PORTMASK: hexadecimal bitmask of ports to use\n"
372bfe3f2eSlogwang 		" -n NUM_NODES: number of node processes to use\n"
382bfe3f2eSlogwang 		" -f NUM_FLOWS: number of flows to be added in the EFD table\n",
392bfe3f2eSlogwang 		progname);
402bfe3f2eSlogwang }
412bfe3f2eSlogwang 
422bfe3f2eSlogwang /**
432bfe3f2eSlogwang  * The ports to be used by the application are passed in
442bfe3f2eSlogwang  * the form of a bitmask. This function parses the bitmask
452bfe3f2eSlogwang  * and places the port numbers to be used into the port[]
462bfe3f2eSlogwang  * array variable
472bfe3f2eSlogwang  */
482bfe3f2eSlogwang static int
parse_portmask(uint8_t max_ports,const char * portmask)492bfe3f2eSlogwang parse_portmask(uint8_t max_ports, const char *portmask)
502bfe3f2eSlogwang {
512bfe3f2eSlogwang 	char *end = NULL;
522bfe3f2eSlogwang 	unsigned long pm;
532bfe3f2eSlogwang 	uint8_t count = 0;
542bfe3f2eSlogwang 
552bfe3f2eSlogwang 	if (portmask == NULL || *portmask == '\0')
562bfe3f2eSlogwang 		return -1;
572bfe3f2eSlogwang 
582bfe3f2eSlogwang 	/* convert parameter to a number and verify */
592bfe3f2eSlogwang 	pm = strtoul(portmask, &end, 16);
602bfe3f2eSlogwang 	if (end == NULL || *end != '\0' || pm == 0)
612bfe3f2eSlogwang 		return -1;
622bfe3f2eSlogwang 
632bfe3f2eSlogwang 	/* loop through bits of the mask and mark ports */
642bfe3f2eSlogwang 	while (pm != 0) {
652bfe3f2eSlogwang 		if (pm & 0x01) { /* bit is set in mask, use port */
662bfe3f2eSlogwang 			if (count >= max_ports)
672bfe3f2eSlogwang 				printf("WARNING: requested port %u not present"
682bfe3f2eSlogwang 				" - ignoring\n", (unsigned int)count);
692bfe3f2eSlogwang 			else
702bfe3f2eSlogwang 			    info->id[info->num_ports++] = count;
712bfe3f2eSlogwang 		}
722bfe3f2eSlogwang 		pm = (pm >> 1);
732bfe3f2eSlogwang 		count++;
742bfe3f2eSlogwang 	}
752bfe3f2eSlogwang 
762bfe3f2eSlogwang 	return 0;
772bfe3f2eSlogwang }
782bfe3f2eSlogwang 
792bfe3f2eSlogwang /**
802bfe3f2eSlogwang  * Take the number of nodes parameter passed to the app
812bfe3f2eSlogwang  * and convert to a number to store in the num_nodes variable
822bfe3f2eSlogwang  */
832bfe3f2eSlogwang static int
parse_num_nodes(const char * nodes)842bfe3f2eSlogwang parse_num_nodes(const char *nodes)
852bfe3f2eSlogwang {
862bfe3f2eSlogwang 	char *end = NULL;
872bfe3f2eSlogwang 	unsigned long temp;
882bfe3f2eSlogwang 
892bfe3f2eSlogwang 	if (nodes == NULL || *nodes == '\0')
902bfe3f2eSlogwang 		return -1;
912bfe3f2eSlogwang 
922bfe3f2eSlogwang 	temp = strtoul(nodes, &end, 10);
932bfe3f2eSlogwang 	if (end == NULL || *end != '\0' || temp == 0)
942bfe3f2eSlogwang 		return -1;
952bfe3f2eSlogwang 
962bfe3f2eSlogwang 	num_nodes = (uint8_t)temp;
972bfe3f2eSlogwang 	return 0;
982bfe3f2eSlogwang }
992bfe3f2eSlogwang 
1002bfe3f2eSlogwang static int
parse_num_flows(const char * flows)1012bfe3f2eSlogwang parse_num_flows(const char *flows)
1022bfe3f2eSlogwang {
1032bfe3f2eSlogwang 	char *end = NULL;
1042bfe3f2eSlogwang 
1052bfe3f2eSlogwang 	/* parse hexadecimal string */
1062bfe3f2eSlogwang 	num_flows = strtoul(flows, &end, 16);
1072bfe3f2eSlogwang 	if ((flows[0] == '\0') || (end == NULL) || (*end != '\0'))
1082bfe3f2eSlogwang 		return -1;
1092bfe3f2eSlogwang 
1102bfe3f2eSlogwang 	if (num_flows == 0)
1112bfe3f2eSlogwang 		return -1;
1122bfe3f2eSlogwang 
1132bfe3f2eSlogwang 	return 0;
1142bfe3f2eSlogwang }
1152bfe3f2eSlogwang 
1162bfe3f2eSlogwang /**
1172bfe3f2eSlogwang  * The application specific arguments follow the DPDK-specific
1182bfe3f2eSlogwang  * arguments which are stripped by the DPDK init. This function
1192bfe3f2eSlogwang  * processes these application arguments, printing usage info
1202bfe3f2eSlogwang  * on error.
1212bfe3f2eSlogwang  */
1222bfe3f2eSlogwang int
parse_app_args(uint8_t max_ports,int argc,char * argv[])1232bfe3f2eSlogwang parse_app_args(uint8_t max_ports, int argc, char *argv[])
1242bfe3f2eSlogwang {
1252bfe3f2eSlogwang 	int option_index, opt;
1262bfe3f2eSlogwang 	char **argvopt = argv;
1272bfe3f2eSlogwang 	static struct option lgopts[] = { /* no long options */
1282bfe3f2eSlogwang 		{NULL, 0, 0, 0 }
1292bfe3f2eSlogwang 	};
1302bfe3f2eSlogwang 	progname = argv[0];
1312bfe3f2eSlogwang 
1322bfe3f2eSlogwang 	while ((opt = getopt_long(argc, argvopt, "n:f:p:", lgopts,
1332bfe3f2eSlogwang 			&option_index)) != EOF) {
1342bfe3f2eSlogwang 		switch (opt) {
1352bfe3f2eSlogwang 		case 'p':
1362bfe3f2eSlogwang 			if (parse_portmask(max_ports, optarg) != 0) {
1372bfe3f2eSlogwang 				usage();
1382bfe3f2eSlogwang 				return -1;
1392bfe3f2eSlogwang 			}
1402bfe3f2eSlogwang 			break;
1412bfe3f2eSlogwang 		case 'n':
1422bfe3f2eSlogwang 			if (parse_num_nodes(optarg) != 0) {
1432bfe3f2eSlogwang 				usage();
1442bfe3f2eSlogwang 				return -1;
1452bfe3f2eSlogwang 			}
1462bfe3f2eSlogwang 			break;
1472bfe3f2eSlogwang 		case 'f':
1482bfe3f2eSlogwang 			if (parse_num_flows(optarg) != 0) {
1492bfe3f2eSlogwang 				usage();
1502bfe3f2eSlogwang 				return -1;
1512bfe3f2eSlogwang 			}
1522bfe3f2eSlogwang 			break;
1532bfe3f2eSlogwang 		default:
1542bfe3f2eSlogwang 			printf("ERROR: Unknown option '%c'\n", opt);
1552bfe3f2eSlogwang 			usage();
1562bfe3f2eSlogwang 			return -1;
1572bfe3f2eSlogwang 		}
1582bfe3f2eSlogwang 	}
1592bfe3f2eSlogwang 
1602bfe3f2eSlogwang 	if (info->num_ports == 0 || num_nodes == 0) {
1612bfe3f2eSlogwang 		usage();
1622bfe3f2eSlogwang 		return -1;
1632bfe3f2eSlogwang 	}
1642bfe3f2eSlogwang 
1652bfe3f2eSlogwang 	if (info->num_ports % 2 != 0) {
1662bfe3f2eSlogwang 		printf("ERROR: application requires an even "
1672bfe3f2eSlogwang 				"number of ports to use\n");
1682bfe3f2eSlogwang 		return -1;
1692bfe3f2eSlogwang 	}
1702bfe3f2eSlogwang 	return 0;
1712bfe3f2eSlogwang }
172