1d30ea906Sjfb8856606 /* SPDX-License-Identifier: BSD-3-Clause
2d30ea906Sjfb8856606  * Copyright(c) 2010-2014 Intel Corporation
3a9643ea8Slogwang  */
4a9643ea8Slogwang 
5a9643ea8Slogwang #include <stdio.h>
6a9643ea8Slogwang #include <stdlib.h>
7a9643ea8Slogwang #include <stdint.h>
8a9643ea8Slogwang #include <getopt.h>
9a9643ea8Slogwang #include <stdarg.h>
10a9643ea8Slogwang #include <errno.h>
11a9643ea8Slogwang 
12a9643ea8Slogwang #include <rte_memory.h>
13*4418919fSjohnjiang #include <rte_ethdev.h>
14a9643ea8Slogwang #include <rte_string_fns.h>
15a9643ea8Slogwang 
16a9643ea8Slogwang #include "common.h"
17a9643ea8Slogwang #include "args.h"
18a9643ea8Slogwang #include "init.h"
19a9643ea8Slogwang 
20a9643ea8Slogwang /* global var for number of clients - extern in header */
21a9643ea8Slogwang uint8_t num_clients;
22a9643ea8Slogwang 
23a9643ea8Slogwang static const char *progname;
24a9643ea8Slogwang 
25a9643ea8Slogwang /**
26a9643ea8Slogwang  * Prints out usage information to stdout
27a9643ea8Slogwang  */
28a9643ea8Slogwang static void
usage(void)29a9643ea8Slogwang usage(void)
30a9643ea8Slogwang {
31a9643ea8Slogwang 	printf(
32a9643ea8Slogwang 	    "%s [EAL options] -- -p PORTMASK -n NUM_CLIENTS [-s NUM_SOCKETS]\n"
33a9643ea8Slogwang 	    " -p PORTMASK: hexadecimal bitmask of ports to use\n"
34a9643ea8Slogwang 	    " -n NUM_CLIENTS: number of client processes to use\n"
35a9643ea8Slogwang 	    , progname);
36a9643ea8Slogwang }
37a9643ea8Slogwang 
38a9643ea8Slogwang /**
39a9643ea8Slogwang  * The ports to be used by the application are passed in
40a9643ea8Slogwang  * the form of a bitmask. This function parses the bitmask
41a9643ea8Slogwang  * and places the port numbers to be used into the port[]
42a9643ea8Slogwang  * array variable
43a9643ea8Slogwang  */
44a9643ea8Slogwang static int
parse_portmask(const char * portmask)45*4418919fSjohnjiang parse_portmask(const char *portmask)
46a9643ea8Slogwang {
47a9643ea8Slogwang 	char *end = NULL;
48*4418919fSjohnjiang 	unsigned long long pm;
49*4418919fSjohnjiang 	uint16_t id;
50a9643ea8Slogwang 
51a9643ea8Slogwang 	if (portmask == NULL || *portmask == '\0')
52a9643ea8Slogwang 		return -1;
53a9643ea8Slogwang 
54a9643ea8Slogwang 	/* convert parameter to a number and verify */
55*4418919fSjohnjiang 	errno = 0;
56*4418919fSjohnjiang 	pm = strtoull(portmask, &end, 16);
57*4418919fSjohnjiang 	if (errno != 0 || end == NULL || *end != '\0')
58a9643ea8Slogwang 		return -1;
59a9643ea8Slogwang 
60*4418919fSjohnjiang 	RTE_ETH_FOREACH_DEV(id) {
61*4418919fSjohnjiang 		unsigned long msk = 1u << id;
62*4418919fSjohnjiang 
63*4418919fSjohnjiang 		if ((pm & msk) == 0)
64*4418919fSjohnjiang 			continue;
65*4418919fSjohnjiang 
66*4418919fSjohnjiang 		pm &= ~msk;
67*4418919fSjohnjiang 		ports->id[ports->num_ports++] = id;
68a9643ea8Slogwang 	}
69*4418919fSjohnjiang 
70*4418919fSjohnjiang 	if (pm != 0) {
71*4418919fSjohnjiang 		printf("WARNING: leftover ports in mask %#llx - ignoring\n",
72*4418919fSjohnjiang 		       pm);
73a9643ea8Slogwang 	}
74a9643ea8Slogwang 
75a9643ea8Slogwang 	return 0;
76a9643ea8Slogwang }
77a9643ea8Slogwang 
78a9643ea8Slogwang /**
79a9643ea8Slogwang  * Take the number of clients parameter passed to the app
80a9643ea8Slogwang  * and convert to a number to store in the num_clients variable
81a9643ea8Slogwang  */
82a9643ea8Slogwang static int
parse_num_clients(const char * clients)83a9643ea8Slogwang parse_num_clients(const char *clients)
84a9643ea8Slogwang {
85a9643ea8Slogwang 	char *end = NULL;
86a9643ea8Slogwang 	unsigned long temp;
87a9643ea8Slogwang 
88a9643ea8Slogwang 	if (clients == NULL || *clients == '\0')
89a9643ea8Slogwang 		return -1;
90a9643ea8Slogwang 
91a9643ea8Slogwang 	temp = strtoul(clients, &end, 10);
92a9643ea8Slogwang 	if (end == NULL || *end != '\0' || temp == 0)
93a9643ea8Slogwang 		return -1;
94a9643ea8Slogwang 
95a9643ea8Slogwang 	num_clients = (uint8_t)temp;
96a9643ea8Slogwang 	return 0;
97a9643ea8Slogwang }
98a9643ea8Slogwang 
99a9643ea8Slogwang /**
100a9643ea8Slogwang  * The application specific arguments follow the DPDK-specific
101a9643ea8Slogwang  * arguments which are stripped by the DPDK init. This function
102a9643ea8Slogwang  * processes these application arguments, printing usage info
103a9643ea8Slogwang  * on error.
104a9643ea8Slogwang  */
105a9643ea8Slogwang int
parse_app_args(int argc,char * argv[])106*4418919fSjohnjiang parse_app_args(int argc, char *argv[])
107a9643ea8Slogwang {
108a9643ea8Slogwang 	int option_index, opt;
109a9643ea8Slogwang 	char **argvopt = argv;
110a9643ea8Slogwang 	static struct option lgopts[] = { /* no long options */
111a9643ea8Slogwang 		{NULL, 0, 0, 0 }
112a9643ea8Slogwang 	};
113a9643ea8Slogwang 	progname = argv[0];
114a9643ea8Slogwang 
115a9643ea8Slogwang 	while ((opt = getopt_long(argc, argvopt, "n:p:", lgopts,
116a9643ea8Slogwang 		&option_index)) != EOF){
117a9643ea8Slogwang 		switch (opt){
118a9643ea8Slogwang 			case 'p':
119*4418919fSjohnjiang 				if (parse_portmask(optarg) != 0) {
120a9643ea8Slogwang 					usage();
121a9643ea8Slogwang 					return -1;
122a9643ea8Slogwang 				}
123a9643ea8Slogwang 				break;
124a9643ea8Slogwang 			case 'n':
125a9643ea8Slogwang 				if (parse_num_clients(optarg) != 0){
126a9643ea8Slogwang 					usage();
127a9643ea8Slogwang 					return -1;
128a9643ea8Slogwang 				}
129a9643ea8Slogwang 				break;
130a9643ea8Slogwang 			default:
131a9643ea8Slogwang 				printf("ERROR: Unknown option '%c'\n", opt);
132a9643ea8Slogwang 				usage();
133a9643ea8Slogwang 				return -1;
134a9643ea8Slogwang 		}
135a9643ea8Slogwang 	}
136a9643ea8Slogwang 
137a9643ea8Slogwang 	if (ports->num_ports == 0 || num_clients == 0){
138a9643ea8Slogwang 		usage();
139a9643ea8Slogwang 		return -1;
140a9643ea8Slogwang 	}
141a9643ea8Slogwang 
142a9643ea8Slogwang 	if (ports->num_ports % 2 != 0){
143a9643ea8Slogwang 		printf("ERROR: application requires an even number of ports to use\n");
144a9643ea8Slogwang 		return -1;
145a9643ea8Slogwang 	}
146a9643ea8Slogwang 	return 0;
147a9643ea8Slogwang }
148