1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2016-2017 Intel Corporation 3 */ 4 5 #include <stdio.h> 6 #include <stdlib.h> 7 #include <stdint.h> 8 #include <getopt.h> 9 #include <stdarg.h> 10 #include <errno.h> 11 12 #include <rte_memory.h> 13 #include <rte_string_fns.h> 14 15 #include "common.h" 16 #include "args.h" 17 #include "init.h" 18 19 /* 1M flows by default */ 20 #define DEFAULT_NUM_FLOWS 0x100000 21 22 /* global var for number of nodes - extern in header */ 23 uint8_t num_nodes; 24 /* global var for number of flows - extern in header */ 25 uint32_t num_flows = DEFAULT_NUM_FLOWS; 26 27 static const char *progname; 28 29 /** 30 * Prints out usage information to stdout 31 */ 32 static void 33 usage(void) 34 { 35 printf("%s [EAL options] -- -p PORTMASK -n NUM_NODES -f NUM_FLOWS\n" 36 " -p PORTMASK: hexadecimal bitmask of ports to use\n" 37 " -n NUM_NODES: number of node processes to use\n" 38 " -f NUM_FLOWS: number of flows to be added in the EFD table\n", 39 progname); 40 } 41 42 /** 43 * The ports to be used by the application are passed in 44 * the form of a bitmask. This function parses the bitmask 45 * and places the port numbers to be used into the port[] 46 * array variable 47 */ 48 static int 49 parse_portmask(uint8_t max_ports, const char *portmask) 50 { 51 char *end = NULL; 52 unsigned long pm; 53 uint8_t count = 0; 54 55 if (portmask == NULL || *portmask == '\0') 56 return -1; 57 58 /* convert parameter to a number and verify */ 59 pm = strtoul(portmask, &end, 16); 60 if (end == NULL || *end != '\0' || pm == 0) 61 return -1; 62 63 /* loop through bits of the mask and mark ports */ 64 while (pm != 0) { 65 if (pm & 0x01) { /* bit is set in mask, use port */ 66 if (count >= max_ports) 67 printf("WARNING: requested port %u not present" 68 " - ignoring\n", (unsigned int)count); 69 else 70 info->id[info->num_ports++] = count; 71 } 72 pm = (pm >> 1); 73 count++; 74 } 75 76 return 0; 77 } 78 79 /** 80 * Take the number of nodes parameter passed to the app 81 * and convert to a number to store in the num_nodes variable 82 */ 83 static int 84 parse_num_nodes(const char *nodes) 85 { 86 char *end = NULL; 87 unsigned long temp; 88 89 if (nodes == NULL || *nodes == '\0') 90 return -1; 91 92 temp = strtoul(nodes, &end, 10); 93 if (end == NULL || *end != '\0' || temp == 0) 94 return -1; 95 96 num_nodes = (uint8_t)temp; 97 return 0; 98 } 99 100 static int 101 parse_num_flows(const char *flows) 102 { 103 char *end = NULL; 104 105 /* parse hexadecimal string */ 106 num_flows = strtoul(flows, &end, 16); 107 if ((flows[0] == '\0') || (end == NULL) || (*end != '\0')) 108 return -1; 109 110 if (num_flows == 0) 111 return -1; 112 113 return 0; 114 } 115 116 /** 117 * The application specific arguments follow the DPDK-specific 118 * arguments which are stripped by the DPDK init. This function 119 * processes these application arguments, printing usage info 120 * on error. 121 */ 122 int 123 parse_app_args(uint8_t max_ports, int argc, char *argv[]) 124 { 125 int option_index, opt; 126 char **argvopt = argv; 127 static struct option lgopts[] = { /* no long options */ 128 {NULL, 0, 0, 0 } 129 }; 130 progname = argv[0]; 131 132 while ((opt = getopt_long(argc, argvopt, "n:f:p:", lgopts, 133 &option_index)) != EOF) { 134 switch (opt) { 135 case 'p': 136 if (parse_portmask(max_ports, optarg) != 0) { 137 usage(); 138 return -1; 139 } 140 break; 141 case 'n': 142 if (parse_num_nodes(optarg) != 0) { 143 usage(); 144 return -1; 145 } 146 break; 147 case 'f': 148 if (parse_num_flows(optarg) != 0) { 149 usage(); 150 return -1; 151 } 152 break; 153 default: 154 printf("ERROR: Unknown option '%c'\n", opt); 155 usage(); 156 return -1; 157 } 158 } 159 160 if (info->num_ports == 0 || num_nodes == 0) { 161 usage(); 162 return -1; 163 } 164 165 if (info->num_ports % 2 != 0) { 166 printf("ERROR: application requires an even " 167 "number of ports to use\n"); 168 return -1; 169 } 170 return 0; 171 } 172