1 /*- 2 * BSD LICENSE 3 * 4 * Copyright (c) Intel Corporation. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of Intel Corporation nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include "spdk/stdinc.h" 35 36 #include "env_internal.h" 37 38 #include <rte_config.h> 39 #include <rte_eal.h> 40 41 #define SPDK_ENV_DPDK_DEFAULT_NAME "spdk" 42 #define SPDK_ENV_DPDK_DEFAULT_SHM_ID -1 43 #define SPDK_ENV_DPDK_DEFAULT_MEM_SIZE -1 44 #define SPDK_ENV_DPDK_DEFAULT_MASTER_CORE -1 45 #define SPDK_ENV_DPDK_DEFAULT_MEM_CHANNEL -1 46 #define SPDK_ENV_DPDK_DEFAULT_CORE_MASK "0x1" 47 48 static char * 49 _sprintf_alloc(const char *format, ...) 50 { 51 va_list args; 52 va_list args_copy; 53 char *buf; 54 size_t bufsize; 55 int rc; 56 57 va_start(args, format); 58 59 /* Try with a small buffer first. */ 60 bufsize = 32; 61 62 /* Limit maximum buffer size to something reasonable so we don't loop forever. */ 63 while (bufsize <= 1024 * 1024) { 64 buf = malloc(bufsize); 65 if (buf == NULL) { 66 va_end(args); 67 return NULL; 68 } 69 70 va_copy(args_copy, args); 71 rc = vsnprintf(buf, bufsize, format, args_copy); 72 va_end(args_copy); 73 74 /* 75 * If vsnprintf() returned a count within our current buffer size, we are done. 76 * The count does not include the \0 terminator, so rc == bufsize is not OK. 77 */ 78 if (rc >= 0 && (size_t)rc < bufsize) { 79 va_end(args); 80 return buf; 81 } 82 83 /* 84 * vsnprintf() should return the required space, but some libc versions do not 85 * implement this correctly, so just double the buffer size and try again. 86 * 87 * We don't need the data in buf, so rather than realloc(), use free() and malloc() 88 * again to avoid a copy. 89 */ 90 free(buf); 91 bufsize *= 2; 92 } 93 94 va_end(args); 95 return NULL; 96 } 97 98 void 99 spdk_env_opts_init(struct spdk_env_opts *opts) 100 { 101 if (!opts) { 102 return; 103 } 104 105 memset(opts, 0, sizeof(*opts)); 106 107 opts->name = SPDK_ENV_DPDK_DEFAULT_NAME; 108 opts->core_mask = SPDK_ENV_DPDK_DEFAULT_CORE_MASK; 109 opts->shm_id = SPDK_ENV_DPDK_DEFAULT_SHM_ID; 110 opts->mem_size = SPDK_ENV_DPDK_DEFAULT_MEM_SIZE; 111 opts->master_core = SPDK_ENV_DPDK_DEFAULT_MASTER_CORE; 112 opts->mem_channel = SPDK_ENV_DPDK_DEFAULT_MEM_CHANNEL; 113 } 114 115 static void 116 spdk_free_args(char **args, int argcount) 117 { 118 int i; 119 120 assert(args != NULL); 121 122 for (i = 0; i < argcount; i++) { 123 assert(args[i] != NULL); 124 free(args[i]); 125 } 126 127 free(args); 128 } 129 130 static char ** 131 spdk_push_arg(char *args[], int *argcount, char *arg) 132 { 133 char **tmp; 134 135 if (arg == NULL) { 136 return NULL; 137 } 138 139 tmp = realloc(args, sizeof(char *) * (*argcount + 1)); 140 if (tmp == NULL) { 141 spdk_free_args(args, *argcount); 142 return NULL; 143 } 144 145 tmp[*argcount] = arg; 146 (*argcount)++; 147 148 return tmp; 149 } 150 151 static int 152 spdk_build_eal_cmdline(const struct spdk_env_opts *opts, char **out[]) 153 { 154 int argcount = 0; 155 char **args; 156 157 if (out == NULL) { 158 return -1; 159 } 160 161 *out = NULL; 162 args = NULL; 163 164 /* set the program name */ 165 args = spdk_push_arg(args, &argcount, _sprintf_alloc("%s", opts->name)); 166 if (args == NULL) { 167 return -1; 168 } 169 170 /* set the coremask */ 171 args = spdk_push_arg(args, &argcount, _sprintf_alloc("-c %s", opts->core_mask)); 172 if (args == NULL) { 173 return -1; 174 } 175 176 /* set the memory channel number */ 177 if (opts->mem_channel > 0) { 178 args = spdk_push_arg(args, &argcount, _sprintf_alloc("-n %d", opts->mem_channel)); 179 if (args == NULL) { 180 return -1; 181 } 182 } 183 184 /* set the memory size */ 185 if (opts->mem_size > 0) { 186 args = spdk_push_arg(args, &argcount, _sprintf_alloc("-m %d", opts->mem_size)); 187 if (args == NULL) { 188 return -1; 189 } 190 } 191 192 /* set the master core */ 193 if (opts->master_core > 0) { 194 args = spdk_push_arg(args, &argcount, _sprintf_alloc("--master-lcore=%d", 195 opts->master_core)); 196 if (args == NULL) { 197 return -1; 198 } 199 } 200 201 /* set no pci if enabled */ 202 if (opts->no_pci) { 203 args = spdk_push_arg(args, &argcount, _sprintf_alloc("--no-pci")); 204 if (args == NULL) { 205 return -1; 206 } 207 } 208 209 #ifdef __linux__ 210 if (opts->shm_id < 0) { 211 args = spdk_push_arg(args, &argcount, _sprintf_alloc("--file-prefix=spdk_pid%d", 212 getpid())); 213 if (args == NULL) { 214 return -1; 215 } 216 } else { 217 args = spdk_push_arg(args, &argcount, _sprintf_alloc("--file-prefix=spdk%d", 218 opts->shm_id)); 219 if (args == NULL) { 220 return -1; 221 } 222 223 /* set the base virtual address */ 224 args = spdk_push_arg(args, &argcount, _sprintf_alloc("--base-virtaddr=0x1000000000")); 225 if (args == NULL) { 226 return -1; 227 } 228 229 /* set the process type */ 230 args = spdk_push_arg(args, &argcount, _sprintf_alloc("--proc-type=auto")); 231 if (args == NULL) { 232 return -1; 233 } 234 } 235 #endif 236 237 *out = args; 238 239 return argcount; 240 } 241 242 void spdk_env_init(const struct spdk_env_opts *opts) 243 { 244 char **args = NULL; 245 char **dpdk_args = NULL; 246 int argcount, i, rc; 247 int orig_optind; 248 249 argcount = spdk_build_eal_cmdline(opts, &args); 250 if (argcount <= 0) { 251 fprintf(stderr, "Invalid arguments to initialize DPDK\n"); 252 exit(-1); 253 } 254 255 printf("Starting %s initialization...\n", rte_version()); 256 printf("[ DPDK EAL parameters: "); 257 for (i = 0; i < argcount; i++) { 258 printf("%s ", args[i]); 259 } 260 printf("]\n"); 261 262 /* DPDK rearranges the array we pass to it, so make a copy 263 * before passing so we can still free the individual strings 264 * correctly. 265 */ 266 dpdk_args = calloc(argcount, sizeof(char *)); 267 if (dpdk_args == NULL) { 268 fprintf(stderr, "Failed to allocate dpdk_args\n"); 269 exit(-1); 270 } 271 memcpy(dpdk_args, args, sizeof(char *) * argcount); 272 273 fflush(stdout); 274 orig_optind = optind; 275 optind = 1; 276 rc = rte_eal_init(argcount, dpdk_args); 277 optind = orig_optind; 278 279 spdk_free_args(args, argcount); 280 free(dpdk_args); 281 282 if (rc < 0) { 283 fprintf(stderr, "Failed to initialize DPDK\n"); 284 exit(-1); 285 } 286 287 spdk_mem_map_init(); 288 spdk_vtophys_init(); 289 } 290