LCOV - code coverage report
Current view: top level - spdk/lib/env_dpdk - init.c (source / functions) Hit Total Coverage
Test: Combined Lines: 228 334 68.3 %
Date: 2024-08-14 09:16:26 Functions: 13 13 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 158 298 53.0 %

           Branch data     Line data    Source code
       1                 :            : /*   SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  *   Copyright (C) 2017 Intel Corporation.
       3                 :            :  *   All rights reserved.
       4                 :            :  */
       5                 :            : 
       6                 :            : #include "spdk/stdinc.h"
       7                 :            : 
       8                 :            : #include "env_internal.h"
       9                 :            : 
      10                 :            : #include "spdk/version.h"
      11                 :            : #include "spdk/env_dpdk.h"
      12                 :            : #include "spdk/log.h"
      13                 :            : #include "spdk/config.h"
      14                 :            : 
      15                 :            : #include <openssl/ssl.h>
      16                 :            : #include <openssl/err.h>
      17                 :            : 
      18                 :            : #include <rte_config.h>
      19                 :            : #include <rte_eal.h>
      20                 :            : #include <rte_errno.h>
      21                 :            : #include <rte_vfio.h>
      22                 :            : 
      23                 :            : #define SPDK_ENV_DPDK_DEFAULT_NAME              "spdk"
      24                 :            : #define SPDK_ENV_DPDK_DEFAULT_SHM_ID            -1
      25                 :            : #define SPDK_ENV_DPDK_DEFAULT_MEM_SIZE          -1
      26                 :            : #define SPDK_ENV_DPDK_DEFAULT_MAIN_CORE         -1
      27                 :            : #define SPDK_ENV_DPDK_DEFAULT_MEM_CHANNEL       -1
      28                 :            : #define SPDK_ENV_DPDK_DEFAULT_CORE_MASK         "0x1"
      29                 :            : #define SPDK_ENV_DPDK_DEFAULT_BASE_VIRTADDR     0x200000000000
      30                 :            : 
      31                 :            : #define DPDK_ALLOW_PARAM        "--allow"
      32                 :            : #define DPDK_BLOCK_PARAM        "--block"
      33                 :            : #define DPDK_MAIN_CORE_PARAM    "--main-lcore"
      34                 :            : 
      35                 :            : static char **g_eal_cmdline;
      36                 :            : static int g_eal_cmdline_argcount;
      37                 :            : static bool g_external_init = true;
      38                 :            : 
      39                 :            : static char *
      40                 :      58245 : _sprintf_alloc(const char *format, ...)
      41                 :            : {
      42                 :      23594 :         va_list args;
      43                 :      23594 :         va_list args_copy;
      44                 :            :         char *buf;
      45                 :            :         size_t bufsize;
      46                 :            :         int rc;
      47                 :            : 
      48                 :      58245 :         va_start(args, format);
      49                 :            : 
      50                 :            :         /* Try with a small buffer first. */
      51                 :      58245 :         bufsize = 32;
      52                 :            : 
      53                 :            :         /* Limit maximum buffer size to something reasonable so we don't loop forever. */
      54         [ +  - ]:     133670 :         while (bufsize <= 1024 * 1024) {
      55                 :     133670 :                 buf = malloc(bufsize);
      56         [ -  + ]:     133670 :                 if (buf == NULL) {
      57                 :          0 :                         va_end(args);
      58                 :          0 :                         return NULL;
      59                 :            :                 }
      60                 :            : 
      61                 :     133670 :                 va_copy(args_copy, args);
      62         [ -  + ]:     133670 :                 rc = vsnprintf(buf, bufsize, format, args_copy);
      63                 :     133670 :                 va_end(args_copy);
      64                 :            : 
      65                 :            :                 /*
      66                 :            :                  * If vsnprintf() returned a count within our current buffer size, we are done.
      67                 :            :                  * The count does not include the \0 terminator, so rc == bufsize is not OK.
      68                 :            :                  */
      69   [ +  -  +  + ]:     133670 :                 if (rc >= 0 && (size_t)rc < bufsize) {
      70                 :      58245 :                         va_end(args);
      71                 :      58245 :                         return buf;
      72                 :            :                 }
      73                 :            : 
      74                 :            :                 /*
      75                 :            :                  * vsnprintf() should return the required space, but some libc versions do not
      76                 :            :                  * implement this correctly, so just double the buffer size and try again.
      77                 :            :                  *
      78                 :            :                  * We don't need the data in buf, so rather than realloc(), use free() and malloc()
      79                 :            :                  * again to avoid a copy.
      80                 :            :                  */
      81                 :      75425 :                 free(buf);
      82                 :      75425 :                 bufsize *= 2;
      83                 :            :         }
      84                 :            : 
      85                 :          0 :         va_end(args);
      86                 :          0 :         return NULL;
      87                 :            : }
      88                 :            : 
      89                 :            : void
      90                 :       5206 : spdk_env_opts_init(struct spdk_env_opts *opts)
      91                 :            : {
      92                 :            :         size_t opts_size;
      93                 :            : 
      94         [ -  + ]:       5206 :         if (!opts) {
      95                 :          0 :                 return;
      96                 :            :         }
      97                 :            : 
      98                 :       5206 :         opts_size = opts->opts_size;
      99         [ -  + ]:       5206 :         memset(opts, 0, sizeof(*opts));
     100                 :       5206 :         opts->opts_size = opts_size;
     101                 :            : 
     102                 :       5206 :         opts->name = SPDK_ENV_DPDK_DEFAULT_NAME;
     103                 :       5206 :         opts->core_mask = SPDK_ENV_DPDK_DEFAULT_CORE_MASK;
     104                 :       5206 :         opts->shm_id = SPDK_ENV_DPDK_DEFAULT_SHM_ID;
     105                 :       5206 :         opts->mem_size = SPDK_ENV_DPDK_DEFAULT_MEM_SIZE;
     106                 :       5206 :         opts->main_core = SPDK_ENV_DPDK_DEFAULT_MAIN_CORE;
     107                 :       5206 :         opts->mem_channel = SPDK_ENV_DPDK_DEFAULT_MEM_CHANNEL;
     108                 :       5206 :         opts->base_virtaddr = SPDK_ENV_DPDK_DEFAULT_BASE_VIRTADDR;
     109                 :            : 
     110                 :            : #define SET_FIELD(field, value) \
     111                 :            :         if (offsetof(struct spdk_env_opts, field) + sizeof(opts->field) <= opts->opts_size) { \
     112                 :            :                 opts->field = value; \
     113                 :            :         }
     114                 :            : 
     115                 :            : #undef SET_FIELD
     116                 :            : }
     117                 :            : 
     118                 :            : static void
     119                 :       2566 : free_args(char **args, int argcount)
     120                 :            : {
     121                 :            :         int i;
     122                 :            : 
     123         [ +  + ]:       2566 :         if (args == NULL) {
     124                 :         84 :                 return;
     125                 :            :         }
     126                 :            : 
     127         [ +  + ]:      34029 :         for (i = 0; i < argcount; i++) {
     128                 :      31547 :                 free(args[i]);
     129                 :            :         }
     130                 :            : 
     131         [ +  - ]:       2482 :         if (argcount) {
     132                 :       2482 :                 free(args);
     133                 :            :         }
     134                 :            : }
     135                 :            : 
     136                 :            : static char **
     137                 :      33042 : push_arg(char *args[], int *argcount, char *arg)
     138                 :            : {
     139                 :            :         char **tmp;
     140                 :            : 
     141         [ -  + ]:      33042 :         if (arg == NULL) {
     142                 :          0 :                 SPDK_ERRLOG("%s: NULL arg supplied\n", __func__);
     143                 :          0 :                 free_args(args, *argcount);
     144                 :          0 :                 return NULL;
     145                 :            :         }
     146                 :            : 
     147                 :      33042 :         tmp = realloc(args, sizeof(char *) * (*argcount + 1));
     148         [ -  + ]:      33042 :         if (tmp == NULL) {
     149                 :          0 :                 free(arg);
     150                 :          0 :                 free_args(args, *argcount);
     151                 :          0 :                 return NULL;
     152                 :            :         }
     153                 :            : 
     154                 :      33042 :         tmp[*argcount] = arg;
     155                 :      33042 :         (*argcount)++;
     156                 :            : 
     157                 :      33042 :         return tmp;
     158                 :            : }
     159                 :            : 
     160                 :            : #if defined(__linux__) && defined(__x86_64__)
     161                 :            : 
     162                 :            : /* TODO: Can likely get this value from rlimits in the future */
     163                 :            : #define SPDK_IOMMU_VA_REQUIRED_WIDTH 48
     164                 :            : #define VTD_CAP_MGAW_SHIFT 16
     165                 :            : #define VTD_CAP_MGAW_MASK (0x3F << VTD_CAP_MGAW_SHIFT)
     166                 :            : #define RD_AMD_CAP_VASIZE_SHIFT 15
     167                 :            : #define RD_AMD_CAP_VASIZE_MASK (0x7F << RD_AMD_CAP_VASIZE_SHIFT)
     168                 :            : 
     169                 :            : static int
     170                 :       2598 : get_iommu_width(void)
     171                 :            : {
     172                 :       2598 :         int width = 0;
     173                 :       2598 :         glob_t glob_results = {};
     174                 :            : 
     175                 :            :         /* Break * and / into separate strings to appease check_format.sh comment style check. */
     176                 :       2598 :         glob("/sys/devices/virtual/iommu/dmar*" "/intel-iommu/cap", 0, NULL, &glob_results);
     177                 :       2598 :         glob("/sys/class/iommu/ivhd*" "/amd-iommu/cap", GLOB_APPEND, NULL, &glob_results);
     178                 :            : 
     179         [ +  + ]:       6344 :         for (size_t i = 0; i < glob_results.gl_pathc; i++) {
     180                 :       3746 :                 const char *filename = glob_results.gl_pathv[0];
     181                 :       3746 :                 FILE *file = fopen(filename, "r");
     182                 :       3746 :                 uint64_t cap_reg = 0;
     183                 :            : 
     184         [ -  + ]:       3746 :                 if (file == NULL) {
     185                 :          0 :                         continue;
     186                 :            :                 }
     187                 :            : 
     188   [ +  -  #  # ]:       3746 :                 if (fscanf(file, "%" PRIx64, &cap_reg) == 1) {
     189   [ -  +  +  - ]:       3746 :                         if (strstr(filename, "intel-iommu") != NULL) {
     190                 :            :                                 /* We have an Intel IOMMU */
     191                 :       3746 :                                 int mgaw = ((cap_reg & VTD_CAP_MGAW_MASK) >> VTD_CAP_MGAW_SHIFT) + 1;
     192                 :            : 
     193   [ +  +  +  -  :       3746 :                                 if (width == 0 || (mgaw > 0 && mgaw < width)) {
                   -  + ]
     194                 :        822 :                                         width = mgaw;
     195                 :            :                                 }
     196   [ #  #  #  # ]:          0 :                         } else if (strstr(filename, "amd-iommu") != NULL) {
     197                 :            :                                 /* We have an AMD IOMMU */
     198                 :          0 :                                 int mgaw = ((cap_reg & RD_AMD_CAP_VASIZE_MASK) >> RD_AMD_CAP_VASIZE_SHIFT) + 1;
     199                 :            : 
     200   [ #  #  #  #  :          0 :                                 if (width == 0 || (mgaw > 0 && mgaw < width)) {
                   #  # ]
     201                 :          0 :                                         width = mgaw;
     202                 :            :                                 }
     203                 :            :                         }
     204                 :            :                 }
     205                 :            : 
     206         [ -  + ]:       3746 :                 fclose(file);
     207                 :            :         }
     208                 :            : 
     209                 :       2598 :         globfree(&glob_results);
     210                 :       2598 :         return width;
     211                 :            : }
     212                 :            : 
     213                 :            : #endif
     214                 :            : 
     215                 :            : static int
     216                 :       2604 : build_eal_cmdline(const struct spdk_env_opts *opts)
     217                 :            : {
     218                 :       2604 :         int argcount = 0;
     219                 :            :         char **args;
     220                 :            :         bool no_huge;
     221                 :            : 
     222                 :       2604 :         args = NULL;
     223   [ +  +  +  +  :       2604 :         no_huge = opts->no_huge || (opts->env_context && strstr(opts->env_context, "--no-huge") != NULL);
          +  +  -  +  -  
                      + ]
     224                 :            : 
     225                 :            :         /* set the program name */
     226                 :       2604 :         args = push_arg(args, &argcount, _sprintf_alloc("%s", opts->name));
     227         [ -  + ]:       2604 :         if (args == NULL) {
     228                 :          0 :                 return -1;
     229                 :            :         }
     230                 :            : 
     231                 :            :         /* disable shared configuration files when in single process mode. This allows for cleaner shutdown */
     232         [ +  + ]:       2604 :         if (opts->shm_id < 0) {
     233                 :       2111 :                 args = push_arg(args, &argcount, _sprintf_alloc("%s", "--no-shconf"));
     234         [ -  + ]:       2111 :                 if (args == NULL) {
     235                 :          0 :                         return -1;
     236                 :            :                 }
     237                 :            :         }
     238                 :            : 
     239                 :            :         /* Either lcore_map or core_mask must be set. If both, or none specified, fail */
     240         [ -  + ]:       2604 :         if ((opts->core_mask == NULL) == (opts->lcore_map == NULL)) {
     241   [ #  #  #  # ]:          0 :                 if (opts->core_mask && opts->lcore_map) {
     242         [ #  # ]:          0 :                         fprintf(stderr,
     243                 :            :                                 "Both, lcore map and core mask are provided, while only one can be set\n");
     244                 :            :                 } else {
     245         [ #  # ]:          0 :                         fprintf(stderr, "Core mask or lcore map must be specified\n");
     246                 :            :                 }
     247                 :          0 :                 free_args(args, argcount);
     248                 :          0 :                 return -1;
     249                 :            :         }
     250                 :            : 
     251         [ -  + ]:       2604 :         if (opts->lcore_map) {
     252                 :            :                 /* If lcore list is set, generate --lcores parameter */
     253                 :          0 :                 args = push_arg(args, &argcount, _sprintf_alloc("--lcores=%s", opts->lcore_map));
     254         [ -  + ]:       2604 :         } else if (opts->core_mask[0] == '-') {
     255                 :            :                 /*
     256                 :            :                  * Set the coremask:
     257                 :            :                  *
     258                 :            :                  * - if it starts with '-', we presume it's literal EAL arguments such
     259                 :            :                  *   as --lcores.
     260                 :            :                  *
     261                 :            :                  * - if it starts with '[', we presume it's a core list to use with the
     262                 :            :                  *   -l option.
     263                 :            :                  *
     264                 :            :                  * - otherwise, it's a CPU mask of the form "0xff.." as expected by the
     265                 :            :                  *   -c option.
     266                 :            :                  */
     267                 :          0 :                 args = push_arg(args, &argcount, _sprintf_alloc("%s", opts->core_mask));
     268         [ +  + ]:       2604 :         } else if (opts->core_mask[0] == '[') {
     269                 :         23 :                 char *l_arg = _sprintf_alloc("-l %s", opts->core_mask + 1);
     270                 :            : 
     271         [ +  - ]:         23 :                 if (l_arg != NULL) {
     272         [ -  + ]:         23 :                         int len = strlen(l_arg);
     273                 :            : 
     274         [ +  - ]:         23 :                         if (l_arg[len - 1] == ']') {
     275                 :         23 :                                 l_arg[len - 1] = '\0';
     276                 :            :                         }
     277                 :            :                 }
     278                 :         23 :                 args = push_arg(args, &argcount, l_arg);
     279                 :            :         } else {
     280                 :       2581 :                 args = push_arg(args, &argcount, _sprintf_alloc("-c %s", opts->core_mask));
     281                 :            :         }
     282                 :            : 
     283         [ -  + ]:       2604 :         if (args == NULL) {
     284                 :          0 :                 return -1;
     285                 :            :         }
     286                 :            : 
     287                 :            :         /* set the memory channel number */
     288         [ +  + ]:       2604 :         if (opts->mem_channel > 0) {
     289                 :         68 :                 args = push_arg(args, &argcount, _sprintf_alloc("-n %d", opts->mem_channel));
     290         [ -  + ]:         68 :                 if (args == NULL) {
     291                 :          0 :                         return -1;
     292                 :            :                 }
     293                 :            :         }
     294                 :            : 
     295                 :            :         /* set the memory size */
     296         [ +  + ]:       2604 :         if (opts->mem_size >= 0) {
     297                 :        243 :                 args = push_arg(args, &argcount, _sprintf_alloc("-m %d", opts->mem_size));
     298         [ -  + ]:        243 :                 if (args == NULL) {
     299                 :          0 :                         return -1;
     300                 :            :                 }
     301                 :            :         }
     302                 :            : 
     303                 :            :         /* set no huge pages */
     304   [ -  +  +  + ]:       2604 :         if (opts->no_huge) {
     305                 :          6 :                 mem_disable_huge_pages();
     306                 :            :         }
     307                 :            : 
     308                 :            :         /* set the main core */
     309         [ +  + ]:       2604 :         if (opts->main_core > 0) {
     310                 :         31 :                 args = push_arg(args, &argcount, _sprintf_alloc("%s=%d",
     311                 :         31 :                                 DPDK_MAIN_CORE_PARAM, opts->main_core));
     312         [ -  + ]:         31 :                 if (args == NULL) {
     313                 :          0 :                         return -1;
     314                 :            :                 }
     315                 :            :         }
     316                 :            : 
     317                 :            :         /* set no pci  if enabled */
     318   [ -  +  +  + ]:       2604 :         if (opts->no_pci) {
     319                 :        139 :                 args = push_arg(args, &argcount, _sprintf_alloc("--no-pci"));
     320         [ -  + ]:        139 :                 if (args == NULL) {
     321                 :          0 :                         return -1;
     322                 :            :                 }
     323                 :            :         }
     324                 :            : 
     325         [ +  + ]:       2604 :         if (no_huge) {
     326   [ -  +  +  -  :          6 :                 if (opts->hugepage_single_segments || opts->unlink_hugepage || opts->hugedir) {
          -  +  +  -  -  
                      + ]
     327         [ #  # ]:          0 :                         fprintf(stderr, "--no-huge invalid with other hugepage options\n");
     328                 :          0 :                         free_args(args, argcount);
     329                 :          0 :                         return -1;
     330                 :            :                 }
     331                 :            : 
     332         [ -  + ]:          6 :                 if (opts->mem_size < 0) {
     333         [ #  # ]:          0 :                         fprintf(stderr,
     334                 :            :                                 "Disabling hugepages requires specifying how much memory "
     335                 :            :                                 "will be allocated using -s parameter\n");
     336                 :          0 :                         free_args(args, argcount);
     337                 :          0 :                         return -1;
     338                 :            :                 }
     339                 :            : 
     340                 :            :                 /* iova-mode=pa is incompatible with no_huge */
     341         [ -  + ]:          6 :                 if (opts->iova_mode &&
     342   [ #  #  #  # ]:          0 :                     (strcmp(opts->iova_mode, "pa") == 0)) {
     343         [ #  # ]:          0 :                         fprintf(stderr, "iova-mode=pa is incompatible with specified "
     344                 :            :                                 "no-huge parameter\n");
     345                 :          0 :                         free_args(args, argcount);
     346                 :          0 :                         return -1;
     347                 :            :                 }
     348                 :            : 
     349                 :          6 :                 args = push_arg(args, &argcount, _sprintf_alloc("--no-huge"));
     350                 :          6 :                 args = push_arg(args, &argcount, _sprintf_alloc("--iova-mode=va"));
     351                 :            : 
     352                 :            :         } else {
     353                 :            :                 /* create just one hugetlbfs file */
     354   [ +  +  +  + ]:       2598 :                 if (opts->hugepage_single_segments) {
     355                 :         40 :                         args = push_arg(args, &argcount, _sprintf_alloc("--single-file-segments"));
     356         [ -  + ]:         40 :                         if (args == NULL) {
     357                 :          0 :                                 return -1;
     358                 :            :                         }
     359                 :            :                 }
     360                 :            : 
     361                 :            :                 /* unlink hugepages after initialization */
     362                 :            :                 /* Note: Automatically unlink hugepage when shm_id < 0, since it means we're not using
     363                 :            :                  * multi-process so we don't need the hugepage links anymore.  But we need to make sure
     364                 :            :                  * we don't specify --huge-unlink implicitly if --single-file-segments was specified since
     365                 :            :                  * DPDK doesn't support that.
     366                 :            :                  */
     367   [ +  +  +  + ]:       2598 :                 if (opts->unlink_hugepage ||
     368   [ +  +  +  +  :       2597 :                     (opts->shm_id < 0 && !opts->hugepage_single_segments)) {
                   +  + ]
     369                 :       2068 :                         args = push_arg(args, &argcount, _sprintf_alloc("--huge-unlink"));
     370         [ -  + ]:       2068 :                         if (args == NULL) {
     371                 :          0 :                                 return -1;
     372                 :            :                         }
     373                 :            :                 }
     374                 :            : 
     375                 :            :                 /* use a specific hugetlbfs mount */
     376         [ -  + ]:       2598 :                 if (opts->hugedir) {
     377                 :          0 :                         args = push_arg(args, &argcount, _sprintf_alloc("--huge-dir=%s", opts->hugedir));
     378         [ #  # ]:          0 :                         if (args == NULL) {
     379                 :          0 :                                 return -1;
     380                 :            :                         }
     381                 :            :                 }
     382                 :            :         }
     383                 :            : 
     384         [ -  + ]:       2604 :         if (opts->num_pci_addr) {
     385                 :            :                 size_t i;
     386                 :          0 :                 char bdf[32];
     387                 :          0 :                 struct spdk_pci_addr *pci_addr =
     388         [ #  # ]:          0 :                                 opts->pci_blocked ? opts->pci_blocked : opts->pci_allowed;
     389                 :            : 
     390         [ #  # ]:          0 :                 for (i = 0; i < opts->num_pci_addr; i++) {
     391                 :          0 :                         spdk_pci_addr_fmt(bdf, 32, &pci_addr[i]);
     392                 :          0 :                         args = push_arg(args, &argcount, _sprintf_alloc("%s=%s",
     393         [ #  # ]:          0 :                                         (opts->pci_blocked ? DPDK_BLOCK_PARAM : DPDK_ALLOW_PARAM),
     394                 :            :                                         bdf));
     395         [ #  # ]:          0 :                         if (args == NULL) {
     396                 :          0 :                                 return -1;
     397                 :            :                         }
     398                 :            :                 }
     399                 :            :         }
     400                 :            : 
     401                 :            :         /* Disable DPDK telemetry information by default, can be modified with env_context.
     402                 :            :          * Prevents creation of dpdk_telemetry socket and additional pthread for it.
     403                 :            :          */
     404                 :       2604 :         args = push_arg(args, &argcount, _sprintf_alloc("--no-telemetry"));
     405         [ -  + ]:       2604 :         if (args == NULL) {
     406                 :          0 :                 return -1;
     407                 :            :         }
     408                 :            : 
     409                 :            :         /* Lower default EAL loglevel to RTE_LOG_NOTICE - normal, but significant messages.
     410                 :            :          * This can be overridden by specifying the same option in opts->env_context
     411                 :            :          */
     412                 :       2604 :         args = push_arg(args, &argcount, strdup("--log-level=lib.eal:6"));
     413         [ -  + ]:       2604 :         if (args == NULL) {
     414                 :          0 :                 return -1;
     415                 :            :         }
     416                 :            : 
     417                 :            :         /* Lower default CRYPTO loglevel to RTE_LOG_WARNING to avoid a ton of init msgs.
     418                 :            :          * This can be overridden by specifying the same option in opts->env_context
     419                 :            :          */
     420                 :       2604 :         args = push_arg(args, &argcount, strdup("--log-level=lib.cryptodev:5"));
     421         [ -  + ]:       2604 :         if (args == NULL) {
     422                 :          0 :                 return -1;
     423                 :            :         }
     424                 :            : 
     425                 :            :         /* Lower default POWER loglevel to RTE_LOG_WARNING to avoid a ton of init msgs.
     426                 :            :          * This can be overridden by specifying the same option in opts->env_context
     427                 :            :          */
     428                 :       2604 :         args = push_arg(args, &argcount, strdup("--log-level=lib.power:5"));
     429         [ -  + ]:       2604 :         if (args == NULL) {
     430                 :          0 :                 return -1;
     431                 :            :         }
     432                 :            : 
     433                 :            :         /* `user1` log type is used by rte_vhost, which prints an INFO log for each received
     434                 :            :          * vhost user message. We don't want that. The same log type is also used by a couple
     435                 :            :          * of other DPDK libs, but none of which we make use right now. If necessary, this can
     436                 :            :          * be overridden via opts->env_context.
     437                 :            :          */
     438                 :       2604 :         args = push_arg(args, &argcount, strdup("--log-level=user1:6"));
     439         [ -  + ]:       2604 :         if (args == NULL) {
     440                 :          0 :                 return -1;
     441                 :            :         }
     442                 :            : 
     443                 :            : #ifdef __linux__
     444                 :            : 
     445         [ -  + ]:       2604 :         if (opts->iova_mode) {
     446                 :            :                 /* iova-mode=pa is incompatible with no_huge */
     447                 :          0 :                 args = push_arg(args, &argcount, _sprintf_alloc("--iova-mode=%s", opts->iova_mode));
     448         [ #  # ]:          0 :                 if (args == NULL) {
     449                 :          0 :                         return -1;
     450                 :            :                 }
     451                 :            :         } else {
     452                 :            :                 /* When using vfio with enable_unsafe_noiommu_mode=Y, we need iova-mode=pa,
     453                 :            :                  * but DPDK guesses it should be iova-mode=va. Add a check and force
     454                 :            :                  * iova-mode=pa here. */
     455   [ +  +  -  + ]:       2604 :                 if (!no_huge && rte_vfio_noiommu_is_enabled()) {
     456                 :          0 :                         args = push_arg(args, &argcount, _sprintf_alloc("--iova-mode=pa"));
     457         [ #  # ]:          0 :                         if (args == NULL) {
     458                 :          0 :                                 return -1;
     459                 :            :                         }
     460                 :            :                 }
     461                 :            : 
     462                 :            : #if defined(__x86_64__)
     463                 :            :                 /* DPDK by default guesses that it should be using iova-mode=va so that it can
     464                 :            :                  * support running as an unprivileged user. However, some systems (especially
     465                 :            :                  * virtual machines) don't have an IOMMU capable of handling the full virtual
     466                 :            :                  * address space and DPDK doesn't currently catch that. Add a check in SPDK
     467                 :            :                  * and force iova-mode=pa here. */
     468   [ +  +  +  + ]:       2604 :                 if (!no_huge && get_iommu_width() < SPDK_IOMMU_VA_REQUIRED_WIDTH) {
     469                 :       1776 :                         args = push_arg(args, &argcount, _sprintf_alloc("--iova-mode=pa"));
     470         [ -  + ]:       1776 :                         if (args == NULL) {
     471                 :          0 :                                 return -1;
     472                 :            :                         }
     473                 :            :                 }
     474                 :            : #elif defined(__PPC64__)
     475                 :            :                 /* On Linux + PowerPC, DPDK doesn't support VA mode at all. Unfortunately, it doesn't correctly
     476                 :            :                  * auto-detect at the moment, so we'll just force it here. */
     477                 :            :                 args = push_arg(args, &argcount, _sprintf_alloc("--iova-mode=pa"));
     478                 :            :                 if (args == NULL) {
     479                 :            :                         return -1;
     480                 :            :                 }
     481                 :            : #endif
     482                 :            :         }
     483                 :            : 
     484                 :            : 
     485                 :            :         /* Set the base virtual address - it must be an address that is not in the
     486                 :            :          * ASAN shadow region, otherwise ASAN-enabled builds will ignore the
     487                 :            :          * mmap hint.
     488                 :            :          *
     489                 :            :          * Ref: https://github.com/google/sanitizers/wiki/AddressSanitizerAlgorithm
     490                 :            :          */
     491                 :       2604 :         args = push_arg(args, &argcount, _sprintf_alloc("--base-virtaddr=0x%" PRIx64, opts->base_virtaddr));
     492         [ -  + ]:       2604 :         if (args == NULL) {
     493                 :          0 :                 return -1;
     494                 :            :         }
     495                 :            : 
     496                 :            :         /* --match-allocation prevents DPDK from merging or splitting system memory allocations under the hood.
     497                 :            :          * This is critical for RDMA when attempting to use an rte_mempool based buffer pool. If DPDK merges two
     498                 :            :          * physically or IOVA contiguous memory regions, then when we go to allocate a buffer pool, it can split
     499                 :            :          * the memory for a buffer over two allocations meaning the buffer will be split over a memory region.
     500                 :            :          */
     501                 :            : 
     502                 :            :         /* --no-huge is incompatible with --match-allocations
     503                 :            :          * Ref:  https://doc.dpdk.org/guides/prog_guide/env_abstraction_layer.html#hugepage-allocation-matching
     504                 :            :          */
     505         [ +  + ]:       2604 :         if (!no_huge &&
     506   [ +  +  +  +  :       2598 :             (!opts->env_context || strstr(opts->env_context, "--legacy-mem") == NULL)) {
                   +  - ]
     507                 :       2598 :                 args = push_arg(args, &argcount, _sprintf_alloc("%s", "--match-allocations"));
     508         [ -  + ]:       2598 :                 if (args == NULL) {
     509                 :          0 :                         return -1;
     510                 :            :                 }
     511                 :            :         }
     512                 :            : 
     513         [ +  + ]:       2604 :         if (opts->shm_id < 0) {
     514                 :       2111 :                 args = push_arg(args, &argcount, _sprintf_alloc("--file-prefix=spdk_pid%d",
     515                 :            :                                 getpid()));
     516         [ -  + ]:       2111 :                 if (args == NULL) {
     517                 :          0 :                         return -1;
     518                 :            :                 }
     519                 :            :         } else {
     520                 :        493 :                 args = push_arg(args, &argcount, _sprintf_alloc("--file-prefix=spdk%d",
     521                 :        493 :                                 opts->shm_id));
     522         [ -  + ]:        493 :                 if (args == NULL) {
     523                 :          0 :                         return -1;
     524                 :            :                 }
     525                 :            : 
     526                 :            :                 /* set the process type */
     527                 :        493 :                 args = push_arg(args, &argcount, _sprintf_alloc("--proc-type=auto"));
     528         [ -  + ]:        493 :                 if (args == NULL) {
     529                 :          0 :                         return -1;
     530                 :            :                 }
     531                 :            :         }
     532                 :            : 
     533                 :            :         /* --vfio-vf-token used for VF initialized by vfio_pci driver. */
     534         [ -  + ]:       2604 :         if (opts->vf_token) {
     535                 :          0 :                 args = push_arg(args, &argcount, _sprintf_alloc("--vfio-vf-token=%s",
     536                 :          0 :                                 opts->vf_token));
     537         [ #  # ]:          0 :                 if (args == NULL) {
     538                 :          0 :                         return -1;
     539                 :            :                 }
     540                 :            :         }
     541                 :            : #endif
     542                 :            : 
     543         [ +  + ]:       2604 :         if (opts->env_context) {
     544         [ -  + ]:         27 :                 char *ptr = strdup(opts->env_context);
     545                 :         27 :                 char *tok = strtok(ptr, " \t");
     546                 :            : 
     547                 :            :                 /* DPDK expects each argument as a separate string in the argv
     548                 :            :                  * array, so we need to tokenize here in case the caller
     549                 :            :                  * passed multiple arguments in the env_context string.
     550                 :            :                  */
     551         [ +  + ]:         54 :                 while (tok != NULL) {
     552         [ -  + ]:         27 :                         args = push_arg(args, &argcount, strdup(tok));
     553                 :         27 :                         tok = strtok(NULL, " \t");
     554                 :            :                 }
     555                 :            : 
     556                 :         27 :                 free(ptr);
     557                 :            :         }
     558                 :            : 
     559                 :       2604 :         g_eal_cmdline = args;
     560                 :       2604 :         g_eal_cmdline_argcount = argcount;
     561                 :       2604 :         return argcount;
     562                 :            : }
     563                 :            : 
     564                 :            : int
     565                 :       2625 : spdk_env_dpdk_post_init(bool legacy_mem)
     566                 :            : {
     567                 :            :         int rc;
     568                 :            : 
     569                 :       2625 :         rc = pci_env_init();
     570         [ -  + ]:       2625 :         if (rc < 0) {
     571                 :          0 :                 SPDK_ERRLOG("pci_env_init() failed\n");
     572                 :          0 :                 return rc;
     573                 :            :         }
     574                 :            : 
     575                 :       2625 :         rc = mem_map_init(legacy_mem);
     576         [ -  + ]:       2625 :         if (rc < 0) {
     577                 :          0 :                 SPDK_ERRLOG("Failed to allocate mem_map\n");
     578                 :          0 :                 return rc;
     579                 :            :         }
     580                 :            : 
     581                 :       2625 :         rc = vtophys_init();
     582         [ -  + ]:       2625 :         if (rc < 0) {
     583                 :          0 :                 SPDK_ERRLOG("Failed to initialize vtophys\n");
     584                 :          0 :                 return rc;
     585                 :            :         }
     586                 :            : 
     587                 :       2625 :         return 0;
     588                 :            : }
     589                 :            : 
     590                 :            : void
     591                 :       2566 : spdk_env_dpdk_post_fini(void)
     592                 :            : {
     593                 :       2566 :         pci_env_fini();
     594                 :            : 
     595                 :       2566 :         free_args(g_eal_cmdline, g_eal_cmdline_argcount);
     596                 :       2566 :         g_eal_cmdline = NULL;
     597                 :       2566 :         g_eal_cmdline_argcount = 0;
     598                 :       2566 : }
     599                 :            : 
     600                 :            : static void
     601                 :       2604 : env_copy_opts(struct spdk_env_opts *opts, const struct spdk_env_opts *opts_user,
     602                 :            :               size_t user_opts_size)
     603                 :            : {
     604                 :       2604 :         opts->opts_size = sizeof(*opts);
     605                 :       2604 :         spdk_env_opts_init(opts);
     606   [ -  +  -  + ]:       2604 :         memcpy(opts, opts_user, offsetof(struct spdk_env_opts, opts_size));
     607                 :            : 
     608                 :            : #define SET_FIELD(field) \
     609                 :            :         if (offsetof(struct spdk_env_opts, field) + sizeof(opts->field) <= user_opts_size) { \
     610                 :            :                 opts->field = opts_user->field; \
     611                 :            :         }
     612                 :            : 
     613                 :            : #undef SET_FIELD
     614                 :       2604 : }
     615                 :            : 
     616                 :            : int
     617                 :       2667 : spdk_env_init(const struct spdk_env_opts *opts_user)
     618                 :            : {
     619                 :       2667 :         struct spdk_env_opts opts_local = {};
     620                 :       2667 :         struct spdk_env_opts *opts = &opts_local;
     621                 :       2667 :         char **dpdk_args = NULL;
     622                 :       2667 :         char *args_print = NULL, *args_tmp = NULL;
     623                 :            :         OPENSSL_INIT_SETTINGS *settings;
     624                 :            :         int i, rc;
     625                 :            :         int orig_optind;
     626                 :            :         bool legacy_mem;
     627                 :            :         size_t min_opts_size, user_opts_size;
     628                 :            : 
     629                 :            :         /* If SPDK env has been initialized before, then only pci env requires
     630                 :            :          * reinitialization.
     631                 :            :          */
     632   [ +  +  +  + ]:       2667 :         if (g_external_init == false) {
     633         [ -  + ]:         63 :                 if (opts_user != NULL) {
     634         [ #  # ]:          0 :                         fprintf(stderr, "Invalid arguments to reinitialize SPDK env\n");
     635                 :          0 :                         return -EINVAL;
     636                 :            :                 }
     637                 :            : 
     638                 :         63 :                 printf("Starting %s / %s reinitialization...\n", SPDK_VERSION_STRING, rte_version());
     639                 :         63 :                 pci_env_reinit();
     640                 :            : 
     641                 :         63 :                 return 0;
     642                 :            :         }
     643                 :            : 
     644         [ -  + ]:       2604 :         if (opts_user == NULL) {
     645         [ #  # ]:          0 :                 fprintf(stderr, "NULL arguments to initialize DPDK\n");
     646                 :          0 :                 return -EINVAL;
     647                 :            :         }
     648                 :            : 
     649                 :       2604 :         min_opts_size = offsetof(struct spdk_env_opts, opts_size) + sizeof(opts->opts_size);
     650                 :       2604 :         user_opts_size = opts_user->opts_size;
     651         [ -  + ]:       2604 :         if (user_opts_size < min_opts_size) {
     652                 :          0 :                 fprintf(stderr, "Invalid opts->opts_size %d too small, please set opts_size correctly\n",
     653         [ #  # ]:          0 :                         (int)opts_user->opts_size);
     654                 :          0 :                 user_opts_size = min_opts_size;
     655                 :            :         }
     656                 :            : 
     657                 :       2604 :         env_copy_opts(opts, opts_user, user_opts_size);
     658                 :            : 
     659                 :       2604 :         settings = OPENSSL_INIT_new();
     660         [ -  + ]:       2604 :         if (!settings) {
     661         [ #  # ]:          0 :                 fprintf(stderr, "Failed to create openssl settings object\n");
     662                 :          0 :                 ERR_print_errors_fp(stderr);
     663                 :          0 :                 return -ENOMEM;
     664                 :            :         }
     665                 :            : 
     666                 :            : #if OPENSSL_VERSION_NUMBER >= 0x30000000 /* OPENSSL 3.0.0 */
     667                 :       2604 :         OPENSSL_INIT_set_config_file_flags(settings, 0);
     668                 :            : #endif
     669                 :       2604 :         rc = OPENSSL_init_ssl(OPENSSL_INIT_LOAD_CONFIG, settings);
     670         [ -  + ]:       2604 :         if (rc != 1) {
     671         [ #  # ]:          0 :                 fprintf(stderr, "Failed to initialize OpenSSL\n");
     672                 :          0 :                 ERR_print_errors_fp(stderr);
     673                 :          0 :                 return -EINVAL;
     674                 :            :         }
     675                 :       2604 :         OPENSSL_INIT_free(settings);
     676                 :            : 
     677                 :       2604 :         rc = build_eal_cmdline(opts);
     678         [ -  + ]:       2604 :         if (rc < 0) {
     679                 :          0 :                 SPDK_ERRLOG("Invalid arguments to initialize DPDK\n");
     680                 :          0 :                 return -EINVAL;
     681                 :            :         }
     682                 :            : 
     683                 :       2604 :         SPDK_PRINTF("Starting %s / %s initialization...\n", SPDK_VERSION_STRING, rte_version());
     684                 :            : 
     685                 :       2604 :         args_print = _sprintf_alloc("[ DPDK EAL parameters: ");
     686         [ -  + ]:       2604 :         if (args_print == NULL) {
     687                 :          0 :                 return -ENOMEM;
     688                 :            :         }
     689         [ +  + ]:      35646 :         for (i = 0; i < g_eal_cmdline_argcount; i++) {
     690                 :      33042 :                 args_tmp = args_print;
     691                 :      33042 :                 args_print = _sprintf_alloc("%s%s ", args_tmp, g_eal_cmdline[i]);
     692         [ -  + ]:      33042 :                 if (args_print == NULL) {
     693                 :          0 :                         free(args_tmp);
     694                 :          0 :                         return -ENOMEM;
     695                 :            :                 }
     696                 :      33042 :                 free(args_tmp);
     697                 :            :         }
     698                 :       2604 :         SPDK_PRINTF("%s]\n", args_print);
     699                 :       2604 :         free(args_print);
     700                 :            : 
     701                 :            :         /* DPDK rearranges the array we pass to it, so make a copy
     702                 :            :          * before passing so we can still free the individual strings
     703                 :            :          * correctly.
     704                 :            :          */
     705                 :       2604 :         dpdk_args = calloc(g_eal_cmdline_argcount, sizeof(char *));
     706         [ -  + ]:       2604 :         if (dpdk_args == NULL) {
     707                 :          0 :                 SPDK_ERRLOG("Failed to allocate dpdk_args\n");
     708                 :          0 :                 return -ENOMEM;
     709                 :            :         }
     710   [ -  +  -  + ]:       2604 :         memcpy(dpdk_args, g_eal_cmdline, sizeof(char *) * g_eal_cmdline_argcount);
     711                 :            : 
     712                 :       2604 :         fflush(stdout);
     713                 :       2604 :         orig_optind = optind;
     714                 :       2604 :         optind = 1;
     715                 :       2604 :         rc = rte_eal_init(g_eal_cmdline_argcount, dpdk_args);
     716                 :       2604 :         optind = orig_optind;
     717                 :            : 
     718                 :       2604 :         free(dpdk_args);
     719                 :            : 
     720         [ -  + ]:       2604 :         if (rc < 0) {
     721         [ #  # ]:          0 :                 if (rte_errno == EALREADY) {
     722                 :          0 :                         SPDK_ERRLOG("DPDK already initialized\n");
     723                 :            :                 } else {
     724                 :          0 :                         SPDK_ERRLOG("Failed to initialize DPDK\n");
     725                 :            :                 }
     726                 :          0 :                 return -rte_errno;
     727                 :            :         }
     728                 :            : 
     729                 :       2604 :         legacy_mem = false;
     730   [ +  +  -  +  :       2604 :         if (opts->env_context && strstr(opts->env_context, "--legacy-mem") != NULL) {
                   -  + ]
     731                 :          0 :                 legacy_mem = true;
     732                 :            :         }
     733                 :            : 
     734                 :       2604 :         rc = spdk_env_dpdk_post_init(legacy_mem);
     735         [ +  - ]:       2604 :         if (rc == 0) {
     736                 :       2604 :                 g_external_init = false;
     737                 :            :         }
     738                 :            : 
     739                 :       2604 :         return rc;
     740                 :            : }
     741                 :            : 
     742                 :            : /* We use priority 101 which is the highest priority level available
     743                 :            :  * to applications (the toolchains reserve 1 to 100 for internal usage).
     744                 :            :  * This ensures this destructor runs last, after any other destructors
     745                 :            :  * that might still need the environment up and running.
     746                 :            :  */
     747                 :            : __attribute__((destructor(101))) static void
     748                 :       2765 : dpdk_cleanup(void)
     749                 :            : {
     750                 :            :         /* Only call rte_eal_cleanup if the SPDK env library called rte_eal_init. */
     751   [ +  +  +  + ]:       2765 :         if (!g_external_init) {
     752                 :       2604 :                 rte_eal_cleanup();
     753                 :            :         }
     754                 :       2765 : }
     755                 :            : 
     756                 :            : void
     757                 :       2566 : spdk_env_fini(void)
     758                 :            : {
     759                 :       2566 :         spdk_env_dpdk_post_fini();
     760                 :       2566 : }
     761                 :            : 
     762                 :            : bool
     763                 :      35297 : spdk_env_dpdk_external_init(void)
     764                 :            : {
     765         [ -  + ]:      35297 :         return g_external_init;
     766                 :            : }

Generated by: LCOV version 1.14