#include <stdlib.h>
#include <unistd.h>
#include <string.h>
+#ifndef RTE_EXEC_ENV_WINDOWS
#include <syslog.h>
+#endif
#include <ctype.h>
#include <limits.h>
#include <errno.h>
#include <getopt.h>
+#ifndef RTE_EXEC_ENV_WINDOWS
#include <dlfcn.h>
+#include <libgen.h>
+#endif
#include <sys/types.h>
#include <sys/stat.h>
+#ifndef RTE_EXEC_ENV_WINDOWS
#include <dirent.h>
+#endif
+#include <rte_string_fns.h>
#include <rte_eal.h>
#include <rte_log.h>
#include <rte_lcore.h>
+#include <rte_memory.h>
#include <rte_tailq.h>
#include <rte_version.h>
#include <rte_devargs.h>
#include <rte_memcpy.h>
+#ifndef RTE_EXEC_ENV_WINDOWS
+#include <rte_telemetry.h>
+#endif
#include "eal_internal_cfg.h"
#include "eal_options.h"
#include "eal_filesystem.h"
#include "eal_private.h"
+#ifndef RTE_EXEC_ENV_WINDOWS
+#include "eal_trace.h"
+#endif
#define BITS_PER_HEX 4
#define LCORE_OPT_LST 1
{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 },
+ {OPT_TRACE, 1, NULL, OPT_TRACE_NUM },
+ {OPT_TRACE_DIR, 1, NULL, OPT_TRACE_DIR_NUM },
+ {OPT_TRACE_BUF_SIZE, 1, NULL, OPT_TRACE_BUF_SIZE_NUM },
+ {OPT_TRACE_MODE, 1, NULL, OPT_TRACE_MODE_NUM },
{OPT_MASTER_LCORE, 1, NULL, OPT_MASTER_LCORE_NUM },
{OPT_MBUF_POOL_OPS_NAME, 1, NULL, OPT_MBUF_POOL_OPS_NAME_NUM},
{OPT_NO_HPET, 0, NULL, OPT_NO_HPET_NUM },
{OPT_LEGACY_MEM, 0, NULL, OPT_LEGACY_MEM_NUM },
{OPT_SINGLE_FILE_SEGMENTS, 0, NULL, OPT_SINGLE_FILE_SEGMENTS_NUM},
{OPT_MATCH_ALLOCATIONS, 0, NULL, OPT_MATCH_ALLOCATIONS_NUM},
+ {OPT_TELEMETRY, 0, NULL, OPT_TELEMETRY_NUM },
+ {OPT_NO_TELEMETRY, 0, NULL, OPT_NO_TELEMETRY_NUM },
{0, 0, NULL, 0 }
};
static struct shared_driver_list solib_list =
TAILQ_HEAD_INITIALIZER(solib_list);
+#ifndef RTE_EXEC_ENV_WINDOWS
/* Default path of external loadable drivers */
static const char *default_solib_dir = RTE_EAL_PMD_PATH;
+#endif
/*
* Stringified version of solib path used by dpdk-pmdinfo.py
* Note: PLEASE DO NOT ALTER THIS without making a corresponding
* change to usertools/dpdk-pmdinfo.py
*/
-static const char dpdk_solib_path[] __attribute__((used)) =
+static const char dpdk_solib_path[] __rte_used =
"DPDK_PLUGIN_PATH=" RTE_EAL_PMD_PATH;
TAILQ_HEAD(device_option_list, device_option);
static int mem_parsed;
static int core_parsed;
+/* Allow the application to print its usage message too if set */
+static rte_usage_hook_t rte_application_usage_hook;
+
+/* Returns rte_usage_hook_t */
+rte_usage_hook_t
+eal_get_application_usage_hook(void)
+{
+ return rte_application_usage_hook;
+}
+
+/* Set a per-application usage message */
+rte_usage_hook_t
+rte_set_application_usage_hook(rte_usage_hook_t usage_func)
+{
+ rte_usage_hook_t old_func;
+
+ /* Will be NULL on the first call to denote the last usage routine. */
+ old_func = rte_application_usage_hook;
+ rte_application_usage_hook = usage_func;
+
+ return old_func;
+}
+
+#ifndef RTE_EXEC_ENV_WINDOWS
+static char **eal_args;
+static char **eal_app_args;
+
+#define EAL_PARAM_REQ "/eal/params"
+#define EAL_APP_PARAM_REQ "/eal/app_params"
+
+/* callback handler for telemetry library to report out EAL flags */
+int
+handle_eal_info_request(const char *cmd, const char *params __rte_unused,
+ struct rte_tel_data *d)
+{
+ char **args;
+ int used = 0;
+ int i = 0;
+
+ if (strcmp(cmd, EAL_PARAM_REQ) == 0)
+ args = eal_args;
+ else
+ args = eal_app_args;
+
+ rte_tel_data_start_array(d, RTE_TEL_STRING_VAL);
+ if (args == NULL || args[0] == NULL)
+ return 0;
+
+ for ( ; args[i] != NULL; i++)
+ used = rte_tel_data_add_array_string(d, args[i]);
+ return used;
+}
+
+int
+eal_save_args(int argc, char **argv)
+{
+ int i, j;
+
+ rte_telemetry_register_cmd(EAL_PARAM_REQ, handle_eal_info_request,
+ "Returns EAL commandline parameters used. Takes no parameters");
+ rte_telemetry_register_cmd(EAL_APP_PARAM_REQ, handle_eal_info_request,
+ "Returns app commandline parameters used. Takes no parameters");
+
+ /* clone argv to report out later. We overprovision, but
+ * this does not waste huge amounts of memory
+ */
+ eal_args = calloc(argc + 1, sizeof(*eal_args));
+ if (eal_args == NULL)
+ return -1;
+
+ for (i = 0; i < argc; i++) {
+ eal_args[i] = strdup(argv[i]);
+ if (strcmp(argv[i], "--") == 0)
+ break;
+ }
+ eal_args[i++] = NULL; /* always finish with NULL */
+
+ /* allow reporting of any app args we know about too */
+ if (i >= argc)
+ return 0;
+
+ eal_app_args = calloc(argc - i + 1, sizeof(*eal_args));
+ if (eal_app_args == NULL)
+ return -1;
+
+ for (j = 0; i < argc; j++, i++)
+ eal_app_args[j] = strdup(argv[i]);
+ eal_app_args[j] = NULL;
+
+ return 0;
+}
+#endif
+
static int
eal_option_device_add(enum rte_devtype type, const char *optarg)
{
}
devopt->type = type;
- ret = snprintf(devopt->arg, optlen, "%s", optarg);
+ ret = strlcpy(devopt->arg, optarg, optlen);
if (ret < 0) {
RTE_LOG(ERR, EAL, "Unable to copy device option\n");
free(devopt);
const char *
eal_get_hugefile_prefix(void)
{
- if (internal_config.hugefile_prefix != NULL)
- return internal_config.hugefile_prefix;
+ const struct internal_config *internal_conf =
+ eal_get_internal_configuration();
+
+ if (internal_conf->hugefile_prefix != NULL)
+ return internal_conf->hugefile_prefix;
return HUGEFILE_PREFIX_DEFAULT;
}
}
internal_cfg->base_virtaddr = 0;
+#ifdef LOG_DAEMON
internal_cfg->syslog_facility = LOG_DAEMON;
+#endif
/* if set to NONE, interrupt mode is determined automatically */
internal_cfg->vfio_intr_mode = RTE_INTR_MODE_NONE;
internal_cfg->create_uio_dev = 0;
internal_cfg->iova_mode = RTE_IOVA_DC;
internal_cfg->user_mbuf_pool_ops_name = NULL;
+ CPU_ZERO(&internal_cfg->ctrl_cpuset);
internal_cfg->init_complete = 0;
}
return -1;
}
memset(solib, 0, sizeof(*solib));
- strlcpy(solib->name, path, PATH_MAX-1);
- solib->name[PATH_MAX-1] = 0;
+ strlcpy(solib->name, path, PATH_MAX);
TAILQ_INSERT_TAIL(&solib_list, solib, next);
return 0;
}
+#ifdef RTE_EXEC_ENV_WINDOWS
+int
+eal_plugins_init(void)
+{
+ return 0;
+}
+#else
+
static int
eal_plugindir_init(const char *path)
{
while ((dent = readdir(d)) != NULL) {
struct stat sb;
+ int nlen = strnlen(dent->d_name, sizeof(dent->d_name));
+
+ /* check if name ends in .so */
+ if (strcmp(&dent->d_name[nlen - 3], ".so") != 0)
+ continue;
- snprintf(sopath, PATH_MAX-1, "%s/%s", path, dent->d_name);
- sopath[PATH_MAX-1] = 0;
+ snprintf(sopath, sizeof(sopath), "%s/%s", path, dent->d_name);
+ /* if a regular file, add to list to load */
if (!(stat(sopath, &sb) == 0 && S_ISREG(sb.st_mode)))
continue;
return (dent == NULL) ? 0 : -1;
}
+static int
+verify_perms(const char *dirpath)
+{
+ struct stat st;
+
+ /* if not root, check down one level first */
+ if (strcmp(dirpath, "/") != 0) {
+ static __thread char last_dir_checked[PATH_MAX];
+ char copy[PATH_MAX];
+ const char *dir;
+
+ strlcpy(copy, dirpath, PATH_MAX);
+ dir = dirname(copy);
+ if (strncmp(dir, last_dir_checked, PATH_MAX) != 0) {
+ if (verify_perms(dir) != 0)
+ return -1;
+ strlcpy(last_dir_checked, dir, PATH_MAX);
+ }
+ }
+
+ /* call stat to check for permissions and ensure not world writable */
+ if (stat(dirpath, &st) != 0) {
+ RTE_LOG(ERR, EAL, "Error with stat on %s, %s\n",
+ dirpath, strerror(errno));
+ return -1;
+ }
+ if (st.st_mode & S_IWOTH) {
+ RTE_LOG(ERR, EAL,
+ "Error, directory path %s is world-writable and insecure\n",
+ dirpath);
+ return -1;
+ }
+
+ return 0;
+}
+
+static void *
+eal_dlopen(const char *pathname)
+{
+ void *retval = NULL;
+ char *realp = realpath(pathname, NULL);
+
+ if (realp == NULL && errno == ENOENT) {
+ /* not a full or relative path, try a load from system dirs */
+ retval = dlopen(pathname, RTLD_NOW);
+ if (retval == NULL)
+ RTE_LOG(ERR, EAL, "%s\n", dlerror());
+ return retval;
+ }
+ if (realp == NULL) {
+ RTE_LOG(ERR, EAL, "Error with realpath for %s, %s\n",
+ pathname, strerror(errno));
+ goto out;
+ }
+ if (strnlen(realp, PATH_MAX) == PATH_MAX) {
+ RTE_LOG(ERR, EAL, "Error, driver path greater than PATH_MAX\n");
+ goto out;
+ }
+
+ /* do permissions checks */
+ if (verify_perms(realp) != 0)
+ goto out;
+
+ retval = dlopen(realp, RTLD_NOW);
+ if (retval == NULL)
+ RTE_LOG(ERR, EAL, "%s\n", dlerror());
+out:
+ free(realp);
+ return retval;
+}
+
int
eal_plugins_init(void)
{
struct shared_driver *solib = NULL;
struct stat sb;
- if (*default_solib_dir != '\0' && stat(default_solib_dir, &sb) == 0 &&
- S_ISDIR(sb.st_mode))
+ /* If we are not statically linked, add default driver loading
+ * path if it exists as a directory.
+ * (Using dlopen with NOLOAD flag on EAL, will return NULL if the EAL
+ * shared library is not already loaded i.e. it's statically linked.)
+ */
+ if (dlopen("librte_eal.so", RTLD_LAZY | RTLD_NOLOAD) != NULL &&
+ *default_solib_dir != '\0' &&
+ stat(default_solib_dir, &sb) == 0 &&
+ S_ISDIR(sb.st_mode))
eal_plugin_add(default_solib_dir);
TAILQ_FOREACH(solib, &solib_list, next) {
} else {
RTE_LOG(DEBUG, EAL, "open shared lib %s\n",
solib->name);
- solib->lib_handle = dlopen(solib->name, RTLD_NOW);
- if (solib->lib_handle == NULL) {
- RTE_LOG(ERR, EAL, "%s\n", dlerror());
+ solib->lib_handle = eal_dlopen(solib->name);
+ if (solib->lib_handle == NULL)
return -1;
- }
}
}
return 0;
}
+#endif
/*
* Parse the coremask given as argument (hexadecimal string) and fill
return -1;
}
- if (!lcore_config[idx].detected) {
+ if (eal_cpu_detected(idx) == 0) {
RTE_LOG(ERR, EAL,
"lcore %u unavailable\n", idx);
return -1;
}
static int
-eal_parse_coremask(const char *coremask)
+update_lcore_config(int *cores)
{
struct rte_config *cfg = rte_eal_get_configuration();
- int i, j, idx = 0;
+ unsigned int count = 0;
+ unsigned int i;
+ int ret = 0;
+
+ for (i = 0; i < RTE_MAX_LCORE; i++) {
+ if (cores[i] != -1) {
+ if (eal_cpu_detected(i) == 0) {
+ RTE_LOG(ERR, EAL, "lcore %u unavailable\n", i);
+ ret = -1;
+ continue;
+ }
+ cfg->lcore_role[i] = ROLE_RTE;
+ count++;
+ } else {
+ cfg->lcore_role[i] = ROLE_OFF;
+ }
+ lcore_config[i].core_index = cores[i];
+ }
+ if (!ret)
+ cfg->lcore_count = count;
+ return ret;
+}
+
+static int
+eal_parse_coremask(const char *coremask, int *cores)
+{
unsigned count = 0;
- char c;
+ int i, j, idx;
int val;
+ char c;
- if (eal_service_cores_parsed())
- RTE_LOG(WARNING, EAL,
- "Service cores parsed before dataplane cores. "
- "Please ensure -c is before -s or -S\n");
+ for (idx = 0; idx < RTE_MAX_LCORE; idx++)
+ cores[idx] = -1;
+ idx = 0;
- if (coremask == NULL)
- return -1;
/* Remove all blank characters ahead and after .
* Remove 0x/0X if exists.
*/
for (j = 0; j < BITS_PER_HEX && idx < RTE_MAX_LCORE; j++, idx++)
{
if ((1 << j) & val) {
- if (!lcore_config[idx].detected) {
- RTE_LOG(ERR, EAL, "lcore %u "
- "unavailable\n", idx);
- return -1;
- }
-
- cfg->lcore_role[idx] = ROLE_RTE;
- lcore_config[idx].core_index = count;
+ cores[idx] = count;
count++;
- } else {
- cfg->lcore_role[idx] = ROLE_OFF;
- lcore_config[idx].core_index = -1;
}
}
}
for (; i >= 0; i--)
if (coremask[i] != '0')
return -1;
- for (; idx < RTE_MAX_LCORE; idx++) {
- cfg->lcore_role[idx] = ROLE_OFF;
- lcore_config[idx].core_index = -1;
- }
if (count == 0)
return -1;
- /* Update the count of enabled logical cores of the EAL configuration */
- cfg->lcore_count = count;
return 0;
}
}
static int
-eal_parse_corelist(const char *corelist)
+eal_parse_corelist(const char *corelist, int *cores)
{
- struct rte_config *cfg = rte_eal_get_configuration();
- int i, idx = 0;
unsigned count = 0;
char *end = NULL;
int min, max;
+ int idx;
- if (eal_service_cores_parsed())
- RTE_LOG(WARNING, EAL,
- "Service cores parsed before dataplane cores. "
- "Please ensure -l is before -s or -S\n");
-
- if (corelist == NULL)
- return -1;
+ for (idx = 0; idx < RTE_MAX_LCORE; idx++)
+ cores[idx] = -1;
- /* Remove all blank characters ahead and after */
+ /* Remove all blank characters ahead */
while (isblank(*corelist))
corelist++;
- i = strlen(corelist);
- while ((i > 0) && isblank(corelist[i - 1]))
- i--;
-
- /* Reset config */
- for (idx = 0; idx < RTE_MAX_LCORE; idx++) {
- cfg->lcore_role[idx] = ROLE_OFF;
- lcore_config[idx].core_index = -1;
- }
/* Get list of cores */
min = RTE_MAX_LCORE;
if (*corelist == '\0')
return -1;
errno = 0;
- idx = strtoul(corelist, &end, 10);
+ idx = strtol(corelist, &end, 10);
if (errno || end == NULL)
return -1;
+ if (idx < 0 || idx >= RTE_MAX_LCORE)
+ return -1;
while (isblank(*end))
end++;
if (*end == '-') {
if (min == RTE_MAX_LCORE)
min = idx;
for (idx = min; idx <= max; idx++) {
- if (cfg->lcore_role[idx] != ROLE_RTE) {
- cfg->lcore_role[idx] = ROLE_RTE;
- lcore_config[idx].core_index = count;
+ if (cores[idx] == -1) {
+ cores[idx] = count;
count++;
}
}
if (count == 0)
return -1;
-
- /* Update the count of enabled logical cores of the EAL configuration */
- cfg->lcore_count = count;
-
return 0;
}
* ',' used for a single number.
*/
static int
-eal_parse_set(const char *input, uint16_t set[], unsigned num)
+eal_parse_set(const char *input, rte_cpuset_t *set)
{
unsigned idx;
const char *str = input;
char *end = NULL;
unsigned min, max;
- memset(set, 0, num * sizeof(uint16_t));
+ CPU_ZERO(set);
while (isblank(*str))
str++;
if (*str != '(') {
errno = 0;
idx = strtoul(str, &end, 10);
- if (errno || end == NULL || idx >= num)
+ if (errno || end == NULL || idx >= CPU_SETSIZE)
return -1;
else {
while (isblank(*end))
errno = 0;
idx = strtoul(end, &end, 10);
- if (errno || end == NULL || idx >= num)
+ if (errno || end == NULL || idx >= CPU_SETSIZE)
return -1;
max = idx;
while (isblank(*end))
for (idx = RTE_MIN(min, max);
idx <= RTE_MAX(min, max); idx++)
- set[idx] = 1;
+ CPU_SET(idx, set);
return end - input;
}
/* get the digit value */
errno = 0;
idx = strtoul(str, &end, 10);
- if (errno || end == NULL || idx >= num)
+ if (errno || end == NULL || idx >= CPU_SETSIZE)
return -1;
/* go ahead to separator '-',',' and ')' */
min = idx;
for (idx = RTE_MIN(min, max);
idx <= RTE_MAX(min, max); idx++)
- set[idx] = 1;
+ CPU_SET(idx, set);
min = RTE_MAX_LCORE;
} else
return str - input;
}
-/* convert from set array to cpuset bitmap */
static int
-convert_to_cpuset(rte_cpuset_t *cpusetp,
- uint16_t *set, unsigned num)
+check_cpuset(rte_cpuset_t *set)
{
- unsigned idx;
+ unsigned int idx;
- CPU_ZERO(cpusetp);
-
- for (idx = 0; idx < num; idx++) {
- if (!set[idx])
+ for (idx = 0; idx < CPU_SETSIZE; idx++) {
+ if (!CPU_ISSET(idx, set))
continue;
- if (!lcore_config[idx].detected) {
+ if (eal_cpu_detected(idx) == 0) {
RTE_LOG(ERR, EAL, "core %u "
"unavailable\n", idx);
return -1;
}
-
- CPU_SET(idx, cpusetp);
}
-
return 0;
}
eal_parse_lcores(const char *lcores)
{
struct rte_config *cfg = rte_eal_get_configuration();
- static uint16_t set[RTE_MAX_LCORE];
+ rte_cpuset_t lcore_set;
+ unsigned int set_count;
unsigned idx = 0;
unsigned count = 0;
const char *lcore_start = NULL;
lcores += strcspn(lcores, "@,");
if (*lcores == '@') {
- /* explicit assign cpu_set */
- offset = eal_parse_set(lcores + 1, set, RTE_DIM(set));
+ /* explicit assign cpuset and update the end cursor */
+ offset = eal_parse_set(lcores + 1, &cpuset);
if (offset < 0)
goto err;
-
- /* prepare cpu_set and update the end cursor */
- if (0 > convert_to_cpuset(&cpuset,
- set, RTE_DIM(set)))
- goto err;
end = lcores + 1 + offset;
} else { /* ',' or '\0' */
- /* haven't given cpu_set, current loop done */
+ /* haven't given cpuset, current loop done */
end = lcores;
/* go back to check <number>-<number> */
goto err;
/* parse lcore_set from start point */
- if (0 > eal_parse_set(lcore_start, set, RTE_DIM(set)))
+ if (eal_parse_set(lcore_start, &lcore_set) < 0)
goto err;
- /* without '@', by default using lcore_set as cpu_set */
- if (*lcores != '@' &&
- 0 > convert_to_cpuset(&cpuset, set, RTE_DIM(set)))
- goto err;
+ /* without '@', by default using lcore_set as cpuset */
+ if (*lcores != '@')
+ rte_memcpy(&cpuset, &lcore_set, sizeof(cpuset));
+ set_count = CPU_COUNT(&lcore_set);
/* start to update lcore_set */
for (idx = 0; idx < RTE_MAX_LCORE; idx++) {
- if (!set[idx])
+ if (!CPU_ISSET(idx, &lcore_set))
continue;
+ set_count--;
if (cfg->lcore_role[idx] != ROLE_RTE) {
lcore_config[idx].core_index = count;
CPU_ZERO(&cpuset);
CPU_SET(idx, &cpuset);
}
+
+ if (check_cpuset(&cpuset) < 0)
+ goto err;
rte_memcpy(&lcore_config[idx].cpuset, &cpuset,
sizeof(rte_cpuset_t));
}
+ /* some cores from the lcore_set can't be handled by EAL */
+ if (set_count != 0)
+ goto err;
+
lcores = end + 1;
} while (*end != '\0');
return ret;
}
+#ifndef RTE_EXEC_ENV_WINDOWS
static int
eal_parse_syslog(const char *facility, struct internal_config *conf)
{
}
return -1;
}
+#endif
static int
eal_parse_log_priority(const char *level)
if (regex) {
if (rte_log_set_level_regexp(regex, priority) < 0) {
fprintf(stderr, "cannot set log level %s,%d\n",
- pattern, priority);
+ regex, priority);
goto fail;
}
if (rte_log_save_regexp(regex, priority) < 0)
eal_parse_iova_mode(const char *name)
{
int mode;
+ struct internal_config *internal_conf =
+ eal_get_internal_configuration();
if (name == NULL)
return -1;
else
return -1;
- internal_config.iova_mode = mode;
+ internal_conf->iova_mode = mode;
+ return 0;
+}
+
+static int
+eal_parse_base_virtaddr(const char *arg)
+{
+ char *end;
+ uint64_t addr;
+ struct internal_config *internal_conf =
+ eal_get_internal_configuration();
+
+ errno = 0;
+ addr = strtoull(arg, &end, 16);
+
+ /* check for errors */
+ if ((errno != 0) || (arg[0] == '\0') || end == NULL || (*end != '\0'))
+ return -1;
+
+ /* make sure we don't exceed 32-bit boundary on 32-bit target */
+#ifndef RTE_ARCH_64
+ if (addr >= UINTPTR_MAX)
+ return -1;
+#endif
+
+ /* align the addr on 16M boundary, 16MB is the minimum huge page
+ * size on IBM Power architecture. If the addr is aligned to 16MB,
+ * it can align to 2MB for x86. So this alignment can also be used
+ * on x86 and other architectures.
+ */
+ internal_conf->base_virtaddr =
+ RTE_PTR_ALIGN_CEIL((uintptr_t)addr, (size_t)RTE_PGSIZE_16M);
+
return 0;
}
+/* caller is responsible for freeing the returned string */
+static char *
+available_cores(void)
+{
+ char *str = NULL;
+ int previous;
+ int sequence;
+ char *tmp;
+ int idx;
+
+ /* find the first available cpu */
+ for (idx = 0; idx < RTE_MAX_LCORE; idx++) {
+ if (eal_cpu_detected(idx) == 0)
+ continue;
+ break;
+ }
+ if (idx >= RTE_MAX_LCORE)
+ return NULL;
+
+ /* first sequence */
+ if (asprintf(&str, "%d", idx) < 0)
+ return NULL;
+ previous = idx;
+ sequence = 0;
+
+ for (idx++ ; idx < RTE_MAX_LCORE; idx++) {
+ if (eal_cpu_detected(idx) == 0)
+ continue;
+
+ if (idx == previous + 1) {
+ previous = idx;
+ sequence = 1;
+ continue;
+ }
+
+ /* finish current sequence */
+ if (sequence) {
+ if (asprintf(&tmp, "%s-%d", str, previous) < 0) {
+ free(str);
+ return NULL;
+ }
+ free(str);
+ str = tmp;
+ }
+
+ /* new sequence */
+ if (asprintf(&tmp, "%s,%d", str, idx) < 0) {
+ free(str);
+ return NULL;
+ }
+ free(str);
+ str = tmp;
+ previous = idx;
+ sequence = 0;
+ }
+
+ /* finish last sequence */
+ if (sequence) {
+ if (asprintf(&tmp, "%s-%d", str, previous) < 0) {
+ free(str);
+ return NULL;
+ }
+ free(str);
+ str = tmp;
+ }
+
+ return str;
+}
+
int
eal_parse_common_option(int opt, const char *optarg,
struct internal_config *conf)
w_used = 1;
break;
/* coremask */
- case 'c':
- if (eal_parse_coremask(optarg) < 0) {
- RTE_LOG(ERR, EAL, "invalid coremask\n");
+ case 'c': {
+ int lcore_indexes[RTE_MAX_LCORE];
+
+ if (eal_service_cores_parsed())
+ RTE_LOG(WARNING, EAL,
+ "Service cores parsed before dataplane cores. Please ensure -c is before -s or -S\n");
+ if (eal_parse_coremask(optarg, lcore_indexes) < 0) {
+ RTE_LOG(ERR, EAL, "invalid coremask syntax\n");
+ return -1;
+ }
+ if (update_lcore_config(lcore_indexes) < 0) {
+ char *available = available_cores();
+
+ RTE_LOG(ERR, EAL,
+ "invalid coremask, please check specified cores are part of %s\n",
+ available);
+ free(available);
return -1;
}
core_parsed = LCORE_OPT_MSK;
break;
+ }
/* corelist */
- case 'l':
- if (eal_parse_corelist(optarg) < 0) {
- RTE_LOG(ERR, EAL, "invalid core list\n");
+ case 'l': {
+ int lcore_indexes[RTE_MAX_LCORE];
+
+ if (eal_service_cores_parsed())
+ RTE_LOG(WARNING, EAL,
+ "Service cores parsed before dataplane cores. Please ensure -l is before -s or -S\n");
+
+ if (eal_parse_corelist(optarg, lcore_indexes) < 0) {
+ RTE_LOG(ERR, EAL, "invalid core list syntax\n");
+ return -1;
+ }
+ if (update_lcore_config(lcore_indexes) < 0) {
+ char *available = available_cores();
+
+ RTE_LOG(ERR, EAL,
+ "invalid core list, please check specified cores are part of %s\n",
+ available);
+ free(available);
return -1;
}
core_parsed = LCORE_OPT_LST;
break;
+ }
/* service coremask */
case 's':
if (eal_parse_service_coremask(optarg) < 0) {
}
break;
+#ifndef RTE_EXEC_ENV_WINDOWS
case OPT_SYSLOG_NUM:
if (eal_parse_syslog(optarg, conf) < 0) {
RTE_LOG(ERR, EAL, "invalid parameters for --"
return -1;
}
break;
+#endif
case OPT_LOG_LEVEL_NUM: {
if (eal_parse_log_level(optarg) < 0) {
}
break;
}
+
+#ifndef RTE_EXEC_ENV_WINDOWS
+ case OPT_TRACE_NUM: {
+ if (eal_trace_args_save(optarg) < 0) {
+ RTE_LOG(ERR, EAL, "invalid parameters for --"
+ OPT_TRACE "\n");
+ return -1;
+ }
+ break;
+ }
+
+ case OPT_TRACE_DIR_NUM: {
+ if (eal_trace_dir_args_save(optarg) < 0) {
+ RTE_LOG(ERR, EAL, "invalid parameters for --"
+ OPT_TRACE_DIR "\n");
+ return -1;
+ }
+ break;
+ }
+
+ case OPT_TRACE_BUF_SIZE_NUM: {
+ if (eal_trace_bufsz_args_save(optarg) < 0) {
+ RTE_LOG(ERR, EAL, "invalid parameters for --"
+ OPT_TRACE_BUF_SIZE "\n");
+ return -1;
+ }
+ break;
+ }
+
+ case OPT_TRACE_MODE_NUM: {
+ if (eal_trace_mode_args_save(optarg) < 0) {
+ RTE_LOG(ERR, EAL, "invalid parameters for --"
+ OPT_TRACE_MODE "\n");
+ return -1;
+ }
+ break;
+ }
+#endif /* !RTE_EXEC_ENV_WINDOWS */
+
case OPT_LCORES_NUM:
if (eal_parse_lcores(optarg) < 0) {
RTE_LOG(ERR, EAL, "invalid parameter for --"
return -1;
}
break;
+ case OPT_BASE_VIRTADDR_NUM:
+ if (eal_parse_base_virtaddr(optarg) < 0) {
+ RTE_LOG(ERR, EAL, "invalid parameter for --"
+ OPT_BASE_VIRTADDR "\n");
+ return -1;
+ }
+ break;
+ case OPT_TELEMETRY_NUM:
+ break;
+ case OPT_NO_TELEMETRY_NUM:
+ conf->no_telemetry = 1;
+ break;
/* don't know what to do, leave this to caller */
default:
unsigned int lcore_id;
unsigned int removed = 0;
rte_cpuset_t affinity_set;
- pthread_t tid = pthread_self();
- if (pthread_getaffinity_np(tid, sizeof(rte_cpuset_t),
- &affinity_set) < 0)
+ if (pthread_getaffinity_np(pthread_self(), sizeof(rte_cpuset_t),
+ &affinity_set))
CPU_ZERO(&affinity_set);
for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
cfg->lcore_count -= removed;
}
+static void
+compute_ctrl_threads_cpuset(struct internal_config *internal_cfg)
+{
+ rte_cpuset_t *cpuset = &internal_cfg->ctrl_cpuset;
+ rte_cpuset_t default_set;
+ unsigned int lcore_id;
+
+ for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
+ if (rte_lcore_has_role(lcore_id, ROLE_OFF))
+ continue;
+ RTE_CPU_OR(cpuset, cpuset, &lcore_config[lcore_id].cpuset);
+ }
+ RTE_CPU_NOT(cpuset, cpuset);
+
+ if (pthread_getaffinity_np(pthread_self(), sizeof(rte_cpuset_t),
+ &default_set))
+ CPU_ZERO(&default_set);
+
+ RTE_CPU_AND(cpuset, cpuset, &default_set);
+
+ /* if no remaining cpu, use master lcore cpu affinity */
+ if (!CPU_COUNT(cpuset)) {
+ memcpy(cpuset, &lcore_config[rte_get_master_lcore()].cpuset,
+ sizeof(*cpuset));
+ }
+}
+
int
eal_cleanup_config(struct internal_config *internal_cfg)
{
{
int i;
struct rte_config *cfg = rte_eal_get_configuration();
+ struct internal_config *internal_conf =
+ eal_get_internal_configuration();
if (!core_parsed)
eal_auto_detect_cores(cfg);
- if (internal_config.process_type == RTE_PROC_AUTO)
- internal_config.process_type = eal_proc_type_detect();
+ if (internal_conf->process_type == RTE_PROC_AUTO)
+ internal_conf->process_type = eal_proc_type_detect();
/* default master lcore is the first one */
if (!master_lcore_parsed) {
cfg->master_lcore = rte_get_next_lcore(-1, 0, 0);
+ if (cfg->master_lcore >= RTE_MAX_LCORE)
+ return -1;
lcore_config[cfg->master_lcore].core_role = ROLE_RTE;
}
+ compute_ctrl_threads_cpuset(internal_cfg);
+
/* if no memory amounts were requested, this will result in 0 and
* will be overridden later, right after eal_hugepage_info_init() */
for (i = 0; i < RTE_MAX_NUMA_NODES; i++)
eal_check_common_options(struct internal_config *internal_cfg)
{
struct rte_config *cfg = rte_eal_get_configuration();
+ const struct internal_config *internal_conf =
+ eal_get_internal_configuration();
if (cfg->lcore_role[cfg->master_lcore] != ROLE_RTE) {
RTE_LOG(ERR, EAL, "Master lcore is not enabled for DPDK\n");
RTE_LOG(ERR, EAL, "Invalid process type specified\n");
return -1;
}
+ if (internal_cfg->hugefile_prefix != NULL &&
+ strlen(internal_cfg->hugefile_prefix) < 1) {
+ RTE_LOG(ERR, EAL, "Invalid length of --" OPT_FILE_PREFIX " option\n");
+ return -1;
+ }
+ if (internal_cfg->hugepage_dir != NULL &&
+ strlen(internal_cfg->hugepage_dir) < 1) {
+ RTE_LOG(ERR, EAL, "Invalid length of --" OPT_HUGE_DIR" option\n");
+ return -1;
+ }
+ if (internal_cfg->user_mbuf_pool_ops_name != NULL &&
+ strlen(internal_cfg->user_mbuf_pool_ops_name) < 1) {
+ RTE_LOG(ERR, EAL, "Invalid length of --" OPT_MBUF_POOL_OPS_NAME" option\n");
+ return -1;
+ }
if (index(eal_get_hugefile_prefix(), '%') != NULL) {
RTE_LOG(ERR, EAL, "Invalid char, '%%', in --"OPT_FILE_PREFIX" "
"option\n");
"be specified together with --"OPT_NO_HUGE"\n");
return -1;
}
- if (internal_config.force_socket_limits && internal_config.legacy_mem) {
+ if (internal_conf->force_socket_limits && internal_conf->legacy_mem) {
RTE_LOG(ERR, EAL, "Option --"OPT_SOCKET_LIMIT
" is only supported in non-legacy memory mode\n");
}
"with --"OPT_MATCH_ALLOCATIONS"\n");
return -1;
}
+ if (internal_cfg->legacy_mem && internal_cfg->memory == 0) {
+ RTE_LOG(NOTICE, EAL, "Static memory layout is selected, "
+ "amount of reserved memory can be adjusted with "
+ "-m or --"OPT_SOCKET_MEM"\n");
+ }
return 0;
}
" (can be used multiple times)\n"
" --"OPT_VMWARE_TSC_MAP" Use VMware TSC map instead of native RDTSC\n"
" --"OPT_PROC_TYPE" Type of this process (primary|secondary|auto)\n"
+#ifndef RTE_EXEC_ENV_WINDOWS
" --"OPT_SYSLOG" Set syslog facility\n"
+#endif
" --"OPT_LOG_LEVEL"=<int> Set global log level\n"
" --"OPT_LOG_LEVEL"=<type-match>:<int>\n"
" Set specific log level\n"
+#ifndef RTE_EXEC_ENV_WINDOWS
+ " --"OPT_TRACE"=<regex-match>\n"
+ " Enable trace based on regular expression trace name.\n"
+ " By default, the trace is disabled.\n"
+ " User must specify this option to enable trace.\n"
+ " --"OPT_TRACE_DIR"=<directory path>\n"
+ " Specify trace directory for trace output.\n"
+ " By default, trace output will created at\n"
+ " $HOME directory and parameter must be\n"
+ " specified once only.\n"
+ " --"OPT_TRACE_BUF_SIZE"=<int>\n"
+ " Specify maximum size of allocated memory\n"
+ " for trace output for each thread. Valid\n"
+ " unit can be either 'B|K|M' for 'Bytes',\n"
+ " 'KBytes' and 'MBytes' respectively.\n"
+ " Default is 1MB and parameter must be\n"
+ " specified once only.\n"
+ " --"OPT_TRACE_MODE"=<o[verwrite] | d[iscard]>\n"
+ " Specify the mode of update of trace\n"
+ " output file. Either update on a file can\n"
+ " be wrapped or discarded when file size\n"
+ " reaches its maximum limit.\n"
+ " Default mode is 'overwrite' and parameter\n"
+ " must be specified once only.\n"
+#endif /* !RTE_EXEC_ENV_WINDOWS */
" -v Display version information on startup\n"
" -h, --help This help\n"
" --"OPT_IN_MEMORY" Operate entirely in memory. This will\n"
" disable secondary process support\n"
+ " --"OPT_BASE_VIRTADDR" Base virtual address\n"
+ " --"OPT_TELEMETRY" Enable telemetry support (on by default)\n"
+ " --"OPT_NO_TELEMETRY" Disable telemetry support\n"
"\nEAL options for DEBUG use only:\n"
" --"OPT_HUGE_UNLINK" Unlink hugepage files after init\n"
" --"OPT_NO_HUGE" Use malloc instead of hugetlbfs\n"