sched: move grinder configuration
[dpdk.git] / lib / eal / common / eal_common_options.c
index 6ecf5fd..f247a42 100644 (file)
@@ -4,7 +4,6 @@
  */
 
 #include <stdlib.h>
-#include <unistd.h>
 #include <string.h>
 #ifndef RTE_EXEC_ENV_WINDOWS
 #include <syslog.h>
@@ -17,7 +16,6 @@
 #include <dlfcn.h>
 #include <libgen.h>
 #endif
-#include <sys/types.h>
 #include <sys/stat.h>
 #ifndef RTE_EXEC_ENV_WINDOWS
 #include <dirent.h>
@@ -74,7 +72,7 @@ eal_long_options[] = {
        {OPT_FILE_PREFIX,       1, NULL, OPT_FILE_PREFIX_NUM      },
        {OPT_HELP,              0, NULL, OPT_HELP_NUM             },
        {OPT_HUGE_DIR,          1, NULL, OPT_HUGE_DIR_NUM         },
-       {OPT_HUGE_UNLINK,       0, NULL, OPT_HUGE_UNLINK_NUM      },
+       {OPT_HUGE_UNLINK,       2, NULL, OPT_HUGE_UNLINK_NUM      },
        {OPT_IOVA_MODE,         1, NULL, OPT_IOVA_MODE_NUM        },
        {OPT_LCORES,            1, NULL, OPT_LCORES_NUM           },
        {OPT_LOG_LEVEL,         1, NULL, OPT_LOG_LEVEL_NUM        },
@@ -223,9 +221,9 @@ eal_save_args(int argc, char **argv)
                return -1;
 
        for (i = 0; i < argc; i++) {
-               eal_args[i] = strdup(argv[i]);
                if (strcmp(argv[i], "--") == 0)
                        break;
+               eal_args[i] = strdup(argv[i]);
        }
        eal_args[i++] = NULL; /* always finish with NULL */
 
@@ -277,7 +275,7 @@ eal_option_device_parse(void)
        void *tmp;
        int ret = 0;
 
-       TAILQ_FOREACH_SAFE(devopt, &devopt_list, next, tmp) {
+       RTE_TAILQ_FOREACH_SAFE(devopt, &devopt_list, next, tmp) {
                if (ret == 0) {
                        ret = rte_devargs_add(devopt->type, devopt->arg);
                        if (ret)
@@ -311,6 +309,8 @@ eal_reset_internal_config(struct internal_config *internal_cfg)
        internal_cfg->force_nchannel = 0;
        internal_cfg->hugefile_prefix = NULL;
        internal_cfg->hugepage_dir = NULL;
+       internal_cfg->hugepage_file.unlink_before_mapping = false;
+       internal_cfg->hugepage_file.unlink_existing = true;
        internal_cfg->force_sockets = 0;
        /* zero out the NUMA config */
        for (i = 0; i < RTE_MAX_NUMA_NODES; i++)
@@ -703,10 +703,50 @@ update_lcore_config(int *cores)
        return ret;
 }
 
+static int
+check_core_list(int *lcores, unsigned int count)
+{
+       char lcorestr[RTE_MAX_LCORE * 10];
+       bool overflow = false;
+       int len = 0, ret;
+       unsigned int i;
+
+       for (i = 0; i < count; i++) {
+               if (lcores[i] < RTE_MAX_LCORE)
+                       continue;
+
+               RTE_LOG(ERR, EAL, "lcore %d >= RTE_MAX_LCORE (%d)\n",
+                       lcores[i], RTE_MAX_LCORE);
+               overflow = true;
+       }
+       if (!overflow)
+               return 0;
+
+       /*
+        * We've encountered a core that's greater than RTE_MAX_LCORE,
+        * suggest using --lcores option to map lcores onto physical cores
+        * greater than RTE_MAX_LCORE.
+        */
+       for (i = 0; i < count; i++) {
+               ret = snprintf(&lcorestr[len], sizeof(lcorestr) - len,
+                       "%d@%d,", i, lcores[i]);
+               if (ret > 0)
+                       len = len + ret;
+       }
+       if (len > 0)
+               lcorestr[len - 1] = 0;
+       RTE_LOG(ERR, EAL, "To use high physical core ids, "
+               "please use --lcores to map them to lcore ids below RTE_MAX_LCORE, "
+               "e.g. --lcores %s\n", lcorestr);
+       return -1;
+}
+
 static int
 eal_parse_coremask(const char *coremask, int *cores)
 {
-       unsigned count = 0;
+       const char *coremask_orig = coremask;
+       int lcores[RTE_MAX_LCORE];
+       unsigned int count = 0;
        int i, j, idx;
        int val;
        char c;
@@ -726,29 +766,52 @@ eal_parse_coremask(const char *coremask, int *cores)
        i = strlen(coremask);
        while ((i > 0) && isblank(coremask[i - 1]))
                i--;
-       if (i == 0)
+       if (i == 0) {
+               RTE_LOG(ERR, EAL, "No lcores in coremask: [%s]\n",
+                       coremask_orig);
                return -1;
+       }
 
-       for (i = i - 1; i >= 0 && idx < RTE_MAX_LCORE; i--) {
+       for (i = i - 1; i >= 0; i--) {
                c = coremask[i];
                if (isxdigit(c) == 0) {
                        /* invalid characters */
+                       RTE_LOG(ERR, EAL, "invalid characters in coremask: [%s]\n",
+                               coremask_orig);
                        return -1;
                }
                val = xdigit2val(c);
-               for (j = 0; j < BITS_PER_HEX && idx < RTE_MAX_LCORE; j++, idx++)
+               for (j = 0; j < BITS_PER_HEX; j++, idx++)
                {
                        if ((1 << j) & val) {
-                               cores[idx] = count;
-                               count++;
+                               if (count >= RTE_MAX_LCORE) {
+                                       RTE_LOG(ERR, EAL, "Too many lcores provided. Cannot exceed RTE_MAX_LCORE (%d)\n",
+                                               RTE_MAX_LCORE);
+                                       return -1;
+                               }
+                               lcores[count++] = idx;
                        }
                }
        }
-       for (; i >= 0; i--)
-               if (coremask[i] != '0')
-                       return -1;
-       if (count == 0)
+       if (count == 0) {
+               RTE_LOG(ERR, EAL, "No lcores in coremask: [%s]\n",
+                       coremask_orig);
+               return -1;
+       }
+
+       if (check_core_list(lcores, count))
                return -1;
+
+       /*
+        * Now that we've got a list of cores no longer than RTE_MAX_LCORE,
+        * and no lcore in that list is greater than RTE_MAX_LCORE, populate
+        * the cores array.
+        */
+       do {
+               count--;
+               cores[lcores[count]] = count;
+       } while (count != 0);
+
        return 0;
 }
 
@@ -833,7 +896,8 @@ eal_parse_service_corelist(const char *corelist)
 static int
 eal_parse_corelist(const char *corelist, int *cores)
 {
-       unsigned count = 0;
+       unsigned int count = 0, i;
+       int lcores[RTE_MAX_LCORE];
        char *end = NULL;
        int min, max;
        int idx;
@@ -846,7 +910,7 @@ eal_parse_corelist(const char *corelist, int *cores)
                corelist++;
 
        /* Get list of cores */
-       min = RTE_MAX_LCORE;
+       min = -1;
        do {
                while (isblank(*corelist))
                        corelist++;
@@ -856,7 +920,7 @@ eal_parse_corelist(const char *corelist, int *cores)
                idx = strtol(corelist, &end, 10);
                if (errno || end == NULL)
                        return -1;
-               if (idx < 0 || idx >= RTE_MAX_LCORE)
+               if (idx < 0)
                        return -1;
                while (isblank(*end))
                        end++;
@@ -864,15 +928,26 @@ eal_parse_corelist(const char *corelist, int *cores)
                        min = idx;
                } else if ((*end == ',') || (*end == '\0')) {
                        max = idx;
-                       if (min == RTE_MAX_LCORE)
+                       if (min == -1)
                                min = idx;
                        for (idx = min; idx <= max; idx++) {
-                               if (cores[idx] == -1) {
-                                       cores[idx] = count;
-                                       count++;
+                               bool dup = false;
+
+                               /* Check if this idx is already present */
+                               for (i = 0; i < count; i++) {
+                                       if (lcores[i] == idx)
+                                               dup = true;
+                               }
+                               if (dup)
+                                       continue;
+                               if (count >= RTE_MAX_LCORE) {
+                                       RTE_LOG(ERR, EAL, "Too many lcores provided. Cannot exceed RTE_MAX_LCORE (%d)\n",
+                                               RTE_MAX_LCORE);
+                                       return -1;
                                }
+                               lcores[count++] = idx;
                        }
-                       min = RTE_MAX_LCORE;
+                       min = -1;
                } else
                        return -1;
                corelist = end + 1;
@@ -880,6 +955,20 @@ eal_parse_corelist(const char *corelist, int *cores)
 
        if (count == 0)
                return -1;
+
+       if (check_core_list(lcores, count))
+               return -1;
+
+       /*
+        * Now that we've got a list of cores no longer than RTE_MAX_LCORE,
+        * and no lcore in that list is greater than RTE_MAX_LCORE, populate
+        * the cores array.
+        */
+       do {
+               count--;
+               cores[lcores[count]] = count;
+       } while (count != 0);
+
        return 0;
 }
 
@@ -1507,6 +1596,28 @@ available_cores(void)
        return str;
 }
 
+#define HUGE_UNLINK_NEVER "never"
+
+static int
+eal_parse_huge_unlink(const char *arg, struct hugepage_file_discipline *out)
+{
+       if (arg == NULL || strcmp(arg, "always") == 0) {
+               out->unlink_before_mapping = true;
+               return 0;
+       }
+       if (strcmp(arg, "existing") == 0) {
+               /* same as not specifying the option */
+               return 0;
+       }
+       if (strcmp(arg, HUGE_UNLINK_NEVER) == 0) {
+               RTE_LOG(WARNING, EAL, "Using --"OPT_HUGE_UNLINK"="
+                       HUGE_UNLINK_NEVER" may create data leaks.\n");
+               out->unlink_existing = false;
+               return 0;
+       }
+       return -1;
+}
+
 int
 eal_parse_common_option(int opt, const char *optarg,
                        struct internal_config *conf)
@@ -1648,7 +1759,10 @@ eal_parse_common_option(int opt, const char *optarg,
 
        /* long options */
        case OPT_HUGE_UNLINK_NUM:
-               conf->hugepage_unlink = 1;
+               if (eal_parse_huge_unlink(optarg, &conf->hugepage_file) < 0) {
+                       RTE_LOG(ERR, EAL, "invalid --"OPT_HUGE_UNLINK" option\n");
+                       return -1;
+               }
                break;
 
        case OPT_NO_HUGE_NUM:
@@ -1677,7 +1791,7 @@ eal_parse_common_option(int opt, const char *optarg,
                conf->in_memory = 1;
                /* in-memory is a superset of noshconf and huge-unlink */
                conf->no_shconf = 1;
-               conf->hugepage_unlink = 1;
+               conf->hugepage_file.unlink_before_mapping = true;
                break;
 
        case OPT_PROC_TYPE_NUM:
@@ -1873,12 +1987,9 @@ compute_ctrl_threads_cpuset(struct internal_config *internal_cfg)
 int
 eal_cleanup_config(struct internal_config *internal_cfg)
 {
-       if (internal_cfg->hugefile_prefix != NULL)
-               free(internal_cfg->hugefile_prefix);
-       if (internal_cfg->hugepage_dir != NULL)
-               free(internal_cfg->hugepage_dir);
-       if (internal_cfg->user_mbuf_pool_ops_name != NULL)
-               free(internal_cfg->user_mbuf_pool_ops_name);
+       free(internal_cfg->hugefile_prefix);
+       free(internal_cfg->hugepage_dir);
+       free(internal_cfg->user_mbuf_pool_ops_name);
 
        return 0;
 }
@@ -1961,7 +2072,8 @@ eal_check_common_options(struct internal_config *internal_cfg)
                        "be specified together with --"OPT_NO_HUGE"\n");
                return -1;
        }
-       if (internal_cfg->no_hugetlbfs && internal_cfg->hugepage_unlink &&
+       if (internal_cfg->no_hugetlbfs &&
+                       internal_cfg->hugepage_file.unlink_before_mapping &&
                        !internal_cfg->in_memory) {
                RTE_LOG(ERR, EAL, "Option --"OPT_HUGE_UNLINK" cannot "
                        "be specified together with --"OPT_NO_HUGE"\n");
@@ -1972,12 +2084,18 @@ eal_check_common_options(struct internal_config *internal_cfg)
                        " is only supported in non-legacy memory mode\n");
        }
        if (internal_cfg->single_file_segments &&
-                       internal_cfg->hugepage_unlink &&
+                       internal_cfg->hugepage_file.unlink_before_mapping &&
                        !internal_cfg->in_memory) {
                RTE_LOG(ERR, EAL, "Option --"OPT_SINGLE_FILE_SEGMENTS" is "
                        "not compatible with --"OPT_HUGE_UNLINK"\n");
                return -1;
        }
+       if (!internal_cfg->hugepage_file.unlink_existing &&
+                       internal_cfg->in_memory) {
+               RTE_LOG(ERR, EAL, "Option --"OPT_IN_MEMORY" is not compatible "
+                       "with --"OPT_HUGE_UNLINK"="HUGE_UNLINK_NEVER"\n");
+               return -1;
+       }
        if (internal_cfg->legacy_mem &&
                        internal_cfg->in_memory) {
                RTE_LOG(ERR, EAL, "Option --"OPT_LEGACY_MEM" is not compatible "
@@ -2110,7 +2228,9 @@ eal_common_usage(void)
               "  --"OPT_NO_TELEMETRY"   Disable telemetry support\n"
               "  --"OPT_FORCE_MAX_SIMD_BITWIDTH" Force the max SIMD bitwidth\n"
               "\nEAL options for DEBUG use only:\n"
-              "  --"OPT_HUGE_UNLINK"       Unlink hugepage files after init\n"
+              "  --"OPT_HUGE_UNLINK"[=existing|always|never]\n"
+              "                      When to unlink files in hugetlbfs\n"
+              "                      ('existing' by default, no value means 'always')\n"
               "  --"OPT_NO_HUGE"           Use malloc instead of hugetlbfs\n"
               "  --"OPT_NO_PCI"            Disable PCI\n"
               "  --"OPT_NO_HPET"           Disable HPET\n"