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 **eal_cmdline; 49 static int eal_cmdline_argcount; 50 51 static char * 52 _sprintf_alloc(const char *format, ...) 53 { 54 va_list args; 55 va_list args_copy; 56 char *buf; 57 size_t bufsize; 58 int rc; 59 60 va_start(args, format); 61 62 /* Try with a small buffer first. */ 63 bufsize = 32; 64 65 /* Limit maximum buffer size to something reasonable so we don't loop forever. */ 66 while (bufsize <= 1024 * 1024) { 67 buf = malloc(bufsize); 68 if (buf == NULL) { 69 va_end(args); 70 return NULL; 71 } 72 73 va_copy(args_copy, args); 74 rc = vsnprintf(buf, bufsize, format, args_copy); 75 va_end(args_copy); 76 77 /* 78 * If vsnprintf() returned a count within our current buffer size, we are done. 79 * The count does not include the \0 terminator, so rc == bufsize is not OK. 80 */ 81 if (rc >= 0 && (size_t)rc < bufsize) { 82 va_end(args); 83 return buf; 84 } 85 86 /* 87 * vsnprintf() should return the required space, but some libc versions do not 88 * implement this correctly, so just double the buffer size and try again. 89 * 90 * We don't need the data in buf, so rather than realloc(), use free() and malloc() 91 * again to avoid a copy. 92 */ 93 free(buf); 94 bufsize *= 2; 95 } 96 97 va_end(args); 98 return NULL; 99 } 100 101 static void 102 spdk_env_unlink_shared_files(void) 103 { 104 char buffer[PATH_MAX]; 105 106 snprintf(buffer, PATH_MAX, "/var/run/.spdk_pid%d_config", getpid()); 107 if (unlink(buffer)) { 108 fprintf(stderr, "Unable to unlink shared memory file: %s. Error code: %d\n", buffer, errno); 109 } 110 111 snprintf(buffer, PATH_MAX, "/var/run/.spdk_pid%d_hugepage_info", getpid()); 112 if (unlink(buffer)) { 113 fprintf(stderr, "Unable to unlink shared memory file: %s. Error code: %d\n", buffer, errno); 114 } 115 } 116 117 void 118 spdk_env_opts_init(struct spdk_env_opts *opts) 119 { 120 if (!opts) { 121 return; 122 } 123 124 memset(opts, 0, sizeof(*opts)); 125 126 opts->name = SPDK_ENV_DPDK_DEFAULT_NAME; 127 opts->core_mask = SPDK_ENV_DPDK_DEFAULT_CORE_MASK; 128 opts->shm_id = SPDK_ENV_DPDK_DEFAULT_SHM_ID; 129 opts->mem_size = SPDK_ENV_DPDK_DEFAULT_MEM_SIZE; 130 opts->master_core = SPDK_ENV_DPDK_DEFAULT_MASTER_CORE; 131 opts->mem_channel = SPDK_ENV_DPDK_DEFAULT_MEM_CHANNEL; 132 } 133 134 static void 135 spdk_free_args(char **args, int argcount) 136 { 137 int i; 138 139 for (i = 0; i < argcount; i++) { 140 free(args[i]); 141 } 142 143 free(args); 144 } 145 146 static char ** 147 spdk_push_arg(char *args[], int *argcount, char *arg) 148 { 149 char **tmp; 150 151 if (arg == NULL) { 152 return NULL; 153 } 154 155 tmp = realloc(args, sizeof(char *) * (*argcount + 1)); 156 if (tmp == NULL) { 157 spdk_free_args(args, *argcount); 158 return NULL; 159 } 160 161 tmp[*argcount] = arg; 162 (*argcount)++; 163 164 return tmp; 165 } 166 167 static void 168 spdk_destruct_eal_cmdline(void) 169 { 170 spdk_free_args(eal_cmdline, eal_cmdline_argcount); 171 } 172 173 174 static int 175 spdk_build_eal_cmdline(const struct spdk_env_opts *opts) 176 { 177 int argcount = 0; 178 char **args; 179 180 args = NULL; 181 182 /* set the program name */ 183 args = spdk_push_arg(args, &argcount, _sprintf_alloc("%s", opts->name)); 184 if (args == NULL) { 185 return -1; 186 } 187 188 /* set the coremask */ 189 args = spdk_push_arg(args, &argcount, _sprintf_alloc("-c %s", opts->core_mask)); 190 if (args == NULL) { 191 return -1; 192 } 193 194 /* set the memory channel number */ 195 if (opts->mem_channel > 0) { 196 args = spdk_push_arg(args, &argcount, _sprintf_alloc("-n %d", opts->mem_channel)); 197 if (args == NULL) { 198 return -1; 199 } 200 } 201 202 /* set the memory size */ 203 if (opts->mem_size > 0) { 204 args = spdk_push_arg(args, &argcount, _sprintf_alloc("-m %d", opts->mem_size)); 205 if (args == NULL) { 206 return -1; 207 } 208 } 209 210 /* set the master core */ 211 if (opts->master_core > 0) { 212 args = spdk_push_arg(args, &argcount, _sprintf_alloc("--master-lcore=%d", 213 opts->master_core)); 214 if (args == NULL) { 215 return -1; 216 } 217 } 218 219 /* set no pci if enabled */ 220 if (opts->no_pci) { 221 args = spdk_push_arg(args, &argcount, _sprintf_alloc("--no-pci")); 222 if (args == NULL) { 223 return -1; 224 } 225 } 226 227 #ifdef __linux__ 228 if (opts->shm_id < 0) { 229 args = spdk_push_arg(args, &argcount, _sprintf_alloc("--file-prefix=spdk_pid%d", 230 getpid())); 231 if (args == NULL) { 232 return -1; 233 } 234 } else { 235 args = spdk_push_arg(args, &argcount, _sprintf_alloc("--file-prefix=spdk%d", 236 opts->shm_id)); 237 if (args == NULL) { 238 return -1; 239 } 240 241 /* set the base virtual address */ 242 args = spdk_push_arg(args, &argcount, _sprintf_alloc("--base-virtaddr=0x1000000000")); 243 if (args == NULL) { 244 return -1; 245 } 246 247 /* set the process type */ 248 args = spdk_push_arg(args, &argcount, _sprintf_alloc("--proc-type=auto")); 249 if (args == NULL) { 250 return -1; 251 } 252 } 253 #endif 254 255 eal_cmdline = args; 256 eal_cmdline_argcount = argcount; 257 if (atexit(spdk_destruct_eal_cmdline) != 0) { 258 fprintf(stderr, "Failed to register cleanup handler\n"); 259 } 260 261 return argcount; 262 } 263 264 void spdk_env_init(const struct spdk_env_opts *opts) 265 { 266 char **dpdk_args = NULL; 267 int i, rc; 268 int orig_optind; 269 270 rc = spdk_build_eal_cmdline(opts); 271 if (rc < 0) { 272 fprintf(stderr, "Invalid arguments to initialize DPDK\n"); 273 exit(-1); 274 } 275 276 printf("Starting %s initialization...\n", rte_version()); 277 printf("[ DPDK EAL parameters: "); 278 for (i = 0; i < eal_cmdline_argcount; i++) { 279 printf("%s ", eal_cmdline[i]); 280 } 281 printf("]\n"); 282 283 /* DPDK rearranges the array we pass to it, so make a copy 284 * before passing so we can still free the individual strings 285 * correctly. 286 */ 287 dpdk_args = calloc(eal_cmdline_argcount, sizeof(char *)); 288 if (dpdk_args == NULL) { 289 fprintf(stderr, "Failed to allocate dpdk_args\n"); 290 exit(-1); 291 } 292 memcpy(dpdk_args, eal_cmdline, sizeof(char *) * eal_cmdline_argcount); 293 294 fflush(stdout); 295 orig_optind = optind; 296 optind = 1; 297 rc = rte_eal_init(eal_cmdline_argcount, dpdk_args); 298 optind = orig_optind; 299 300 free(dpdk_args); 301 302 if (rc < 0) { 303 fprintf(stderr, "Failed to initialize DPDK\n"); 304 exit(-1); 305 } 306 307 if (opts->shm_id < 0) { 308 /* 309 * Unlink hugepage and config info files after init. This will ensure they get 310 * deleted on app exit, even if the app crashes and does not exit normally. 311 * Only do this when not in multi-process mode, since for multi-process other 312 * apps will need to open these files. 313 */ 314 spdk_env_unlink_shared_files(); 315 } 316 317 spdk_mem_map_init(); 318 spdk_vtophys_init(); 319 } 320