#include <limits.h>
#include <errno.h>
#include <getopt.h>
+#include <dlfcn.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
#include <rte_eal.h>
#include <rte_log.h>
{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_LCORES, 1, NULL, OPT_LCORES_NUM },
{OPT_LOG_LEVEL, 1, NULL, OPT_LOG_LEVEL_NUM },
{OPT_MASTER_LCORE, 1, NULL, OPT_MASTER_LCORE_NUM },
{0, 0, NULL, 0 }
};
-static int lcores_parsed;
+TAILQ_HEAD(shared_driver_list, shared_driver);
+
+/* Definition for shared object drivers. */
+struct shared_driver {
+ TAILQ_ENTRY(shared_driver) next;
+
+ char name[PATH_MAX];
+ void* lib_handle;
+};
+
+/* List of external loadable drivers */
+static struct shared_driver_list solib_list =
+TAILQ_HEAD_INITIALIZER(solib_list);
+
+/* Default path of external loadable drivers */
+static const char *default_solib_dir = RTE_EAL_PMD_PATH;
+
+/*
+ * 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)) =
+"DPDK_PLUGIN_PATH=" RTE_EAL_PMD_PATH;
+
+
static int master_lcore_parsed;
static int mem_parsed;
+static int core_parsed;
void
eal_reset_internal_config(struct internal_config *internal_cfg)
internal_cfg->base_virtaddr = 0;
internal_cfg->syslog_facility = LOG_DAEMON;
- /* default value from build option */
- internal_cfg->log_level = RTE_LOG_LEVEL;
internal_cfg->xen_dom0_support = 0;
internal_cfg->create_uio_dev = 0;
}
+static int
+eal_plugin_add(const char *path)
+{
+ struct shared_driver *solib;
+
+ solib = malloc(sizeof(*solib));
+ if (solib == NULL) {
+ RTE_LOG(ERR, EAL, "malloc(solib) failed\n");
+ return -1;
+ }
+ memset(solib, 0, sizeof(*solib));
+ strncpy(solib->name, path, PATH_MAX-1);
+ solib->name[PATH_MAX-1] = 0;
+ TAILQ_INSERT_TAIL(&solib_list, solib, next);
+
+ return 0;
+}
+
+static int
+eal_plugindir_init(const char *path)
+{
+ DIR *d = NULL;
+ struct dirent *dent = NULL;
+ char sopath[PATH_MAX];
+
+ if (path == NULL || *path == '\0')
+ return 0;
+
+ d = opendir(path);
+ if (d == NULL) {
+ RTE_LOG(ERR, EAL, "failed to open directory %s: %s\n",
+ path, strerror(errno));
+ return -1;
+ }
+
+ while ((dent = readdir(d)) != NULL) {
+ struct stat sb;
+
+ snprintf(sopath, PATH_MAX-1, "%s/%s", path, dent->d_name);
+ sopath[PATH_MAX-1] = 0;
+
+ if (!(stat(sopath, &sb) == 0 && S_ISREG(sb.st_mode)))
+ continue;
+
+ if (eal_plugin_add(sopath) == -1)
+ break;
+ }
+
+ closedir(d);
+ /* XXX this ignores failures from readdir() itself */
+ return (dent == NULL) ? 0 : -1;
+}
+
+int
+eal_plugins_init(void)
+{
+ struct shared_driver *solib = NULL;
+
+ if (*default_solib_dir != '\0')
+ eal_plugin_add(default_solib_dir);
+
+ TAILQ_FOREACH(solib, &solib_list, next) {
+ struct stat sb;
+
+ if (stat(solib->name, &sb) == 0 && S_ISDIR(sb.st_mode)) {
+ if (eal_plugindir_init(solib->name) == -1) {
+ RTE_LOG(ERR, EAL,
+ "Cannot init plugin directory %s\n",
+ solib->name);
+ return -1;
+ }
+ } 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());
+ return -1;
+ }
+ }
+
+ }
+ return 0;
+}
+
/*
* Parse the coremask given as argument (hexadecimal string) and fill
* the global configuration (core role and core count) with the parsed
return -1;
/* Update the count of enabled logical cores of the EAL configuration */
cfg->lcore_count = count;
- lcores_parsed = 1;
return 0;
}
/* Update the count of enabled logical cores of the EAL configuration */
cfg->lcore_count = count;
- lcores_parsed = 1;
return 0;
}
str = end + 1;
} while (*end != '\0' && *end != ')');
+ /*
+ * to avoid failure that tail blank makes end character check fail
+ * in eal_parse_lcores( )
+ */
+ while (isblank(*str))
+ str++;
+
return str - input;
}
struct rte_config *cfg = rte_eal_get_configuration();
static uint16_t set[RTE_MAX_LCORE];
unsigned idx = 0;
- int i;
unsigned count = 0;
const char *lcore_start = NULL;
const char *end = NULL;
int offset;
rte_cpuset_t cpuset;
- int lflags = 0;
+ int lflags;
int ret = -1;
if (lcores == NULL)
/* Remove all blank characters ahead and after */
while (isblank(*lcores))
lcores++;
- i = strlen(lcores);
- while ((i > 0) && isblank(lcores[i - 1]))
- i--;
CPU_ZERO(&cpuset);
if (*lcores == '\0')
goto err;
+ lflags = 0;
+
/* record lcore_set start point */
lcore_start = lcores;
goto err;
cfg->lcore_count = count;
- lcores_parsed = 1;
ret = 0;
err:
}
static int
-eal_parse_log_level(const char *level, uint32_t *log_level)
+eal_parse_log_level(const char *arg)
{
- char *end;
+ char *end, *str, *type, *level;
unsigned long tmp;
+ str = strdup(arg);
+ if (str == NULL)
+ return -1;
+
+ if (strchr(str, ',') == NULL) {
+ type = NULL;
+ level = str;
+ } else {
+ type = strsep(&str, ",");
+ level = strsep(&str, ",");
+ }
+
errno = 0;
tmp = strtoul(level, &end, 0);
/* check for errors */
if ((errno != 0) || (level[0] == '\0') ||
- end == NULL || (*end != '\0'))
- return -1;
+ end == NULL || (*end != '\0'))
+ goto fail;
/* log_level is a uint32_t */
if (tmp >= UINT32_MAX)
- return -1;
+ goto fail;
+
+ if (type == NULL) {
+ rte_log_set_global_level(tmp);
+ } else if (rte_log_set_level_regexp(type, tmp) < 0) {
+ printf("cannot set log level %s,%lu\n",
+ type, tmp);
+ goto fail;
+ }
- *log_level = tmp;
+ free(str);
return 0;
+
+fail:
+ free(str);
+ return -1;
}
static enum rte_proc_type_t
RTE_LOG(ERR, EAL, "invalid coremask\n");
return -1;
}
+ core_parsed = 1;
break;
/* corelist */
case 'l':
RTE_LOG(ERR, EAL, "invalid core list\n");
return -1;
}
+ core_parsed = 1;
break;
/* size of memory */
case 'm':
/* force number of channels */
case 'n':
conf->force_nchannel = atoi(optarg);
- if (conf->force_nchannel == 0 ||
- conf->force_nchannel > 4) {
+ if (conf->force_nchannel == 0) {
RTE_LOG(ERR, EAL, "invalid channel number\n");
return -1;
}
return -1;
}
break;
+ /* force loading of external driver */
+ case 'd':
+ if (eal_plugin_add(optarg) == -1)
+ return -1;
+ break;
case 'v':
/* since message is explicitly requested by user, we
* write message at highest log level so it can always
break;
/* long options */
+ case OPT_HUGE_UNLINK_NUM:
+ conf->hugepage_unlink = 1;
+ break;
+
case OPT_NO_HUGE_NUM:
conf->no_hugetlbfs = 1;
break;
break;
case OPT_LOG_LEVEL_NUM: {
- uint32_t log;
-
- if (eal_parse_log_level(optarg, &log) < 0) {
+ if (eal_parse_log_level(optarg) < 0) {
RTE_LOG(ERR, EAL,
"invalid parameters for --"
OPT_LOG_LEVEL "\n");
return -1;
}
- conf->log_level = log;
break;
}
case OPT_LCORES_NUM:
OPT_LCORES "\n");
return -1;
}
+ core_parsed = 1;
break;
/* don't know what to do, leave this to caller */
return 0;
}
+static void
+eal_auto_detect_cores(struct rte_config *cfg)
+{
+ 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)
+ CPU_ZERO(&affinity_set);
+
+ for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
+ if (cfg->lcore_role[lcore_id] == ROLE_RTE &&
+ !CPU_ISSET(lcore_id, &affinity_set)) {
+ cfg->lcore_role[lcore_id] = ROLE_OFF;
+ removed++;
+ }
+ }
+
+ cfg->lcore_count -= removed;
+}
+
int
eal_adjust_config(struct internal_config *internal_cfg)
{
int i;
struct rte_config *cfg = rte_eal_get_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();
{
struct rte_config *cfg = rte_eal_get_configuration();
- if (!lcores_parsed) {
- RTE_LOG(ERR, EAL, "CPU cores must be enabled with options "
- "-c, -l or --lcores\n");
- return -1;
- }
if (cfg->lcore_role[cfg->master_lcore] != ROLE_RTE) {
RTE_LOG(ERR, EAL, "Master lcore is not enabled for DPDK\n");
return -1;
RTE_LOG(ERR, EAL, "Invalid process type specified\n");
return -1;
}
- if (internal_cfg->process_type == RTE_PROC_PRIMARY &&
- internal_cfg->force_nchannel == 0) {
- RTE_LOG(ERR, EAL, "Number of memory channels (-n) not "
- "specified\n");
- return -1;
- }
if (index(internal_cfg->hugefile_prefix, '%') != NULL) {
RTE_LOG(ERR, EAL, "Invalid char, '%%', in --"OPT_FILE_PREFIX" "
"option\n");
return -1;
}
+ if (internal_cfg->no_hugetlbfs && internal_cfg->hugepage_unlink) {
+ RTE_LOG(ERR, EAL, "Option --"OPT_HUGE_UNLINK" cannot "
+ "be specified together with --"OPT_NO_HUGE"\n");
+ return -1;
+ }
+
if (rte_eal_devargs_type_count(RTE_DEVTYPE_WHITELISTED_PCI) != 0 &&
rte_eal_devargs_type_count(RTE_DEVTYPE_BLACKLISTED_PCI) != 0) {
RTE_LOG(ERR, EAL, "Options blacklist (-b) and whitelist (-w) "
void
eal_common_usage(void)
{
- printf("-c COREMASK|-l CORELIST -n CHANNELS [options]\n\n"
+ printf("[options]\n\n"
"EAL common options:\n"
" -c COREMASK Hexadecimal bitmask of cores to run on\n"
" -l CORELIST List of cores to run on\n"
" [NOTE: PCI whitelist cannot be used with -b option]\n"
" --"OPT_VDEV" Add a virtual device.\n"
" The argument format is <driver><id>[,key=val,...]\n"
- " (ex: --vdev=eth_pcap0,iface=eth2).\n"
+ " (ex: --vdev=net_pcap0,iface=eth2).\n"
+ " -d LIB.so|DIR Add a driver or driver directory\n"
+ " (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"
" --"OPT_SYSLOG" Set syslog facility\n"
- " --"OPT_LOG_LEVEL" Set default log level\n"
+ " --"OPT_LOG_LEVEL"=<int> Set global log level\n"
+ " --"OPT_LOG_LEVEL"=<type-regexp>,<int>\n"
+ " Set specific log level\n"
" -v Display version information on startup\n"
" -h, --help This help\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"
" --"OPT_NO_PCI" Disable PCI\n"
" --"OPT_NO_HPET" Disable HPET\n"