#include <rte_config.h>
#include <rte_eal.h>
+#include <rte_ethdev.h>
#include "common.h"
#include "utils_dpdk.h"
};
#define DPDK_HELPER_TRACE(_name) \
- DEBUG("%s:%s:%d pid=%lu", _name, __FUNCTION__, __LINE__, (long)getpid())
-
-#define DPDK_HELPER_USE_PIPES
+ DEBUG("%s:%s:%d pid=%ld", _name, __FUNCTION__, __LINE__, (long)getpid())
struct dpdk_helper_ctx_s {
int eal_initialized;
size_t shm_size;
- const char *shm_name;
+ char shm_name[DATA_MAX_NAME_LEN];
sem_t sema_cmd_start;
sem_t sema_cmd_complete;
cdtime_t cmd_wait_time;
pid_t pid;
-#ifdef DPDK_HELPER_USE_PIPES
int pipes[2];
-#endif /* DPDK_HELPER_USE_PIPES */
int status;
int cmd;
};
static int dpdk_shm_init(const char *name, size_t size, void **map);
-static int dpdk_shm_cleanup(const char *name, size_t size, void *map);
+static void dpdk_shm_cleanup(const char *name, size_t size, void *map);
static int dpdk_helper_spawn(dpdk_helper_ctx_t *phc);
static int dpdk_helper_worker(dpdk_helper_ctx_t *phc);
DPDK_HELPER_TRACE(phc->shm_name);
- ssnprintf(phc->eal_config.coremask, DATA_MAX_NAME_LEN, "%s", "0xf");
- ssnprintf(phc->eal_config.memory_channels, DATA_MAX_NAME_LEN, "%s", "1");
- ssnprintf(phc->eal_config.process_type, DATA_MAX_NAME_LEN, "%s", "secondary");
- ssnprintf(phc->eal_config.file_prefix, DATA_MAX_NAME_LEN, "%s",
- DPDK_DEFAULT_RTE_CONFIG);
+ snprintf(phc->eal_config.coremask, DATA_MAX_NAME_LEN, "%s", "0xf");
+ snprintf(phc->eal_config.memory_channels, DATA_MAX_NAME_LEN, "%s", "1");
+ snprintf(phc->eal_config.file_prefix, DATA_MAX_NAME_LEN, "%s",
+ DPDK_DEFAULT_RTE_CONFIG);
}
int dpdk_helper_eal_config_set(dpdk_helper_ctx_t *phc, dpdk_eal_config_t *ec) {
return -EINVAL;
}
- memcpy(&phc->eal_config, ec, sizeof(dpdk_eal_config_t));
+ memcpy(&phc->eal_config, ec, sizeof(phc->eal_config));
return 0;
}
return -EINVAL;
}
- memcpy(ec, &phc->eal_config, sizeof(dpdk_eal_config_t));
+ memcpy(ec, &phc->eal_config, sizeof(*ec));
return 0;
}
return -EINVAL;
}
+ int status = 0;
for (int i = 0; i < ci->children_num; i++) {
oconfig_item_t *child = ci->children + i;
+
if (strcasecmp("Coremask", child->key) == 0) {
- cf_util_get_string_buffer(child, phc->eal_config.coremask,
- sizeof(phc->eal_config.coremask));
+ status = cf_util_get_string_buffer(child, phc->eal_config.coremask,
+ sizeof(phc->eal_config.coremask));
DEBUG("dpdk_common: EAL:Coremask %s", phc->eal_config.coremask);
} else if (strcasecmp("MemoryChannels", child->key) == 0) {
- cf_util_get_string_buffer(child, phc->eal_config.memory_channels,
- sizeof(phc->eal_config.memory_channels));
+ status =
+ cf_util_get_string_buffer(child, phc->eal_config.memory_channels,
+ sizeof(phc->eal_config.memory_channels));
DEBUG("dpdk_common: EAL:Memory Channels %s",
phc->eal_config.memory_channels);
} else if (strcasecmp("SocketMemory", child->key) == 0) {
- cf_util_get_string_buffer(child, phc->eal_config.socket_memory,
- sizeof(phc->eal_config.socket_memory));
+ status = cf_util_get_string_buffer(child, phc->eal_config.socket_memory,
+ sizeof(phc->eal_config.socket_memory));
DEBUG("dpdk_common: EAL:Socket memory %s", phc->eal_config.socket_memory);
- } else if (strcasecmp("ProcessType", child->key) == 0) {
- cf_util_get_string_buffer(child, phc->eal_config.process_type,
- sizeof(phc->eal_config.process_type));
- DEBUG("dpdk_common: EAL:Process type %s", phc->eal_config.process_type);
- } else if ((strcasecmp("FilePrefix", child->key) == 0) &&
- (child->values[0].type == OCONFIG_TYPE_STRING)) {
- ssnprintf(phc->eal_config.file_prefix, DATA_MAX_NAME_LEN,
- "/var/run/.%s_config", child->values[0].value.string);
- DEBUG("dpdk_common: EAL:File prefix %s", phc->eal_config.file_prefix);
+ } else if (strcasecmp("FilePrefix", child->key) == 0) {
+ char prefix[DATA_MAX_NAME_LEN];
+
+ status = cf_util_get_string_buffer(child, prefix, sizeof(prefix));
+ if (status == 0) {
+ snprintf(phc->eal_config.file_prefix, DATA_MAX_NAME_LEN,
+ "/var/run/.%s_config", prefix);
+ DEBUG("dpdk_common: EAL:File prefix %s", phc->eal_config.file_prefix);
+ }
+ } else {
+ ERROR("dpdk_common: Invalid '%s' configuration option", child->key);
+ status = -EINVAL;
+ }
+
+ if (status != 0) {
+ ERROR("dpdk_common: Parsing EAL configuration failed");
+ break;
}
}
- return 0;
+ return status;
}
static int dpdk_shm_init(const char *name, size_t size, void **map) {
int fd = shm_open(name, O_CREAT | O_TRUNC | O_RDWR, 0666);
if (fd < 0) {
- WARNING("dpdk_shm_init: Failed to open %s as SHM:%s\n", name,
+ WARNING("dpdk_shm_init: Failed to open %s as SHM:%s", name,
sstrerror(errno, errbuf, sizeof(errbuf)));
- goto fail;
+ *map = NULL;
+ return -1;
}
int ret = ftruncate(fd, size);
if (ret != 0) {
- WARNING("dpdk_shm_init: Failed to resize SHM:%s\n",
+ WARNING("dpdk_shm_init: Failed to resize SHM:%s",
sstrerror(errno, errbuf, sizeof(errbuf)));
- goto fail_close;
+ close(fd);
+ *map = NULL;
+ dpdk_shm_cleanup(name, size, NULL);
+ return -1;
}
*map = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (*map == MAP_FAILED) {
- WARNING("dpdk_shm_init:Failed to mmap SHM:%s\n",
+ WARNING("dpdk_shm_init:Failed to mmap SHM:%s",
sstrerror(errno, errbuf, sizeof(errbuf)));
- goto fail_close;
+ close(fd);
+ *map = NULL;
+ dpdk_shm_cleanup(name, size, NULL);
+ return -1;
}
- /*
- * Close the file descriptor, the shared memory object still exists
- * and can only be removed by calling shm_unlink().
- */
+ /* File descriptor no longer needed for shared memory operations */
close(fd);
-
memset(*map, 0, size);
return 0;
-
-fail_close:
- close(fd);
-fail:
- *map = NULL;
- return -1;
}
-static int dpdk_shm_cleanup(const char *name, size_t size, void *map) {
+static void dpdk_shm_cleanup(const char *name, size_t size, void *map) {
DPDK_HELPER_TRACE(name);
+ char errbuf[ERR_BUF_SIZE];
- int ret = munmap(map, size);
- if (ret) {
- ERROR("munmap returned %d\n", ret);
- }
+ /*
+ * Call shm_unlink first, as 'name' might be no longer accessible after munmap
+ */
+ if (shm_unlink(name))
+ ERROR("shm_unlink failure %s", sstrerror(errno, errbuf, sizeof(errbuf)));
- ret = shm_unlink(name);
- if (ret) {
- ERROR("shm_unlink returned %d\n", ret);
+ if (map != NULL) {
+ if (munmap(map, size))
+ ERROR("munmap failure %s", sstrerror(errno, errbuf, sizeof(errbuf)));
}
-
- return 0;
}
-inline void *dpdk_helper_priv_get(dpdk_helper_ctx_t *phc) {
+void *dpdk_helper_priv_get(dpdk_helper_ctx_t *phc) {
if (phc)
- return (void *)phc->priv_data;
+ return phc->priv_data;
return NULL;
}
return -EINVAL;
}
- return (phc->shm_size - sizeof(dpdk_helper_ctx_t));
+ return phc->shm_size - sizeof(dpdk_helper_ctx_t);
}
int dpdk_helper_init(const char *name, size_t data_size,
dpdk_helper_ctx_t **pphc) {
- int err = 0;
dpdk_helper_ctx_t *phc = NULL;
size_t shm_size = sizeof(dpdk_helper_ctx_t) + data_size;
char errbuf[ERR_BUF_SIZE];
/* Allocate dpdk_helper_ctx_t and
* initialize a POSIX SHared Memory (SHM) object.
*/
- err = dpdk_shm_init(name, shm_size, (void **)&phc);
+ int err = dpdk_shm_init(name, shm_size, (void **)&phc);
if (err != 0) {
return -errno;
}
err = sem_init(&phc->sema_cmd_start, 1, 0);
if (err != 0) {
- ERROR("sema_cmd_start semaphore init failed: %s\n",
+ ERROR("sema_cmd_start semaphore init failed: %s",
sstrerror(errno, errbuf, sizeof(errbuf)));
+ int errno_m = errno;
dpdk_shm_cleanup(name, shm_size, (void *)phc);
- return -errno;
+ return -errno_m;
}
err = sem_init(&phc->sema_cmd_complete, 1, 0);
if (err != 0) {
- ERROR("sema_cmd_complete semaphore init failed: %s\n",
+ ERROR("sema_cmd_complete semaphore init failed: %s",
sstrerror(errno, errbuf, sizeof(errbuf)));
sem_destroy(&phc->sema_cmd_start);
+ int errno_m = errno;
dpdk_shm_cleanup(name, shm_size, (void *)phc);
- return -errno;
+ return -errno_m;
}
phc->shm_size = shm_size;
- phc->shm_name = name;
+ sstrncpy(phc->shm_name, name, sizeof(phc->shm_name));
dpdk_helper_config_default(phc);
return 0;
}
-int dpdk_helper_shutdown(dpdk_helper_ctx_t *phc) {
- if (phc == NULL) {
- ERROR("%s:Invalid argument(phc)", __FUNCTION__);
- return -EINVAL;
- }
+void dpdk_helper_shutdown(dpdk_helper_ctx_t *phc) {
+ if (phc == NULL)
+ return;
DPDK_HELPER_TRACE(phc->shm_name);
-#ifdef DPDK_HELPER_USE_PIPES
close(phc->pipes[1]);
-#endif
if (phc->status != DPDK_HELPER_NOT_INITIALIZED) {
dpdk_helper_exit_command(phc, DPDK_HELPER_GRACEFUL_QUIT);
sem_destroy(&phc->sema_cmd_start);
sem_destroy(&phc->sema_cmd_complete);
dpdk_shm_cleanup(phc->shm_name, phc->shm_size, (void *)phc);
-
- return 0;
}
static int dpdk_helper_spawn(dpdk_helper_ctx_t *phc) {
phc->eal_initialized = 0;
phc->cmd_wait_time = MS_TO_CDTIME_T(DPDK_CDM_DEFAULT_TIMEOUT);
-#ifdef DPDK_HELPER_USE_PIPES
/*
* Create a pipe for helper stdout back to collectd. This is necessary for
* logging EAL failures, as rte_eal_init() calls rte_panic().
}
if (pipe(phc->pipes) != 0) {
- DEBUG("dpdk_helper_spawn: Could not create helper pipe: %s\n",
+ DEBUG("dpdk_helper_spawn: Could not create helper pipe: %s",
sstrerror(errno, errbuf, sizeof(errbuf)));
return -1;
}
WARNING("dpdk_helper_spawn: error setting up pipes: %s",
sstrerror(errno, errbuf, sizeof(errbuf)));
}
-#endif /* DPDK_HELPER_USE_PIPES */
pid_t pid = fork();
if (pid > 0) {
phc->pid = pid;
-#ifdef DPDK_HELPER_USE_PIPES
close(phc->pipes[1]);
-#endif /* DPDK_HELPER_USE_PIPES */
DEBUG("%s:dpdk_helper_spawn: helper pid %lu", phc->shm_name,
(long)phc->pid);
} else if (pid == 0) {
-#ifdef DPDK_HELPER_USE_PIPES
/* Replace stdout with a pipe to collectd. */
close(phc->pipes[0]);
close(STDOUT_FILENO);
dup2(phc->pipes[1], STDOUT_FILENO);
-#endif /* DPDK_HELPER_USE_PIPES */
DPDK_CHILD_TRACE(phc->shm_name);
dpdk_helper_worker(phc);
exit(0);
} else {
- ERROR("dpdk_helper_start: Failed to fork helper process: %s\n",
+ ERROR("dpdk_helper_start: Failed to fork helper process: %s",
sstrerror(errno, errbuf, sizeof(errbuf)));
return -1;
}
DPDK_CHILD_LOG("%s:%s:%d %s\n", phc->shm_name, __FUNCTION__, __LINE__,
dpdk_helper_status_str(status));
-#ifdef DPDK_HELPER_USE_PIPES
close(phc->pipes[1]);
-#endif /* DPDK_HELPER_USE_PIPES */
phc->status = status;
char errbuf[ERR_BUF_SIZE];
DPDK_HELPER_TRACE(phc->shm_name);
-#ifdef DPDK_HELPER_USE_PIPES
close(phc->pipes[1]);
-#endif /* DPDK_HELPER_USE_PIPES */
if (phc->status == DPDK_HELPER_ALIVE_SENDING_EVENTS) {
phc->status = status;
int err = kill(phc->pid, SIGKILL);
if (err) {
- ERROR("%s error sending kill to helper: %s\n", __FUNCTION__,
+ ERROR("%s error sending kill to helper: %s", __FUNCTION__,
sstrerror(errno, errbuf, sizeof(errbuf)));
}
}
int err = kill(phc->pid, SIGKILL);
if (err) {
- ERROR("%s error sending kill to helper: %s\n", __FUNCTION__,
+ ERROR("%s error sending kill to helper: %s", __FUNCTION__,
sstrerror(errno, errbuf, sizeof(errbuf)));
}
}
/* EAL config must be initialized */
assert(phc->eal_config.coremask[0] != 0);
assert(phc->eal_config.memory_channels[0] != 0);
- assert(phc->eal_config.process_type[0] != 0);
assert(phc->eal_config.file_prefix[0] != 0);
argp[argc++] = "collectd-dpdk";
}
argp[argc++] = "--proc-type";
- argp[argc++] = phc->eal_config.process_type;
+ argp[argc++] = "secondary";
assert(argc <= (DPDK_EAL_ARGC * 2 + 1));
return 0;
}
-#ifdef DPDK_HELPER_USE_PIPES
static void dpdk_helper_check_pipe(dpdk_helper_ctx_t *phc) {
char buf[DPDK_MAX_BUFFER_SIZE];
char out[DPDK_MAX_BUFFER_SIZE];
DEBUG("%s: helper process:\n%s", phc->shm_name, out);
}
}
-#endif /* DPDK_HELPER_USE_PIPES */
int dpdk_helper_command(dpdk_helper_ctx_t *phc, enum DPDK_CMD cmd, int *result,
cdtime_t cmd_wait_time) {
phc->cmd_wait_time = cmd_wait_time;
- int ret = 0;
-
- ret = dpdk_helper_status_check(phc);
+ int ret = dpdk_helper_status_check(phc);
-#ifdef DPDK_HELPER_USE_PIPES
dpdk_helper_check_pipe(phc);
-#endif /* DPDK_HELPER_USE_PIPES */
if (ret != 0) {
return ret;
int err = sem_post(&phc->sema_cmd_start);
if (err) {
char errbuf[ERR_BUF_SIZE];
- ERROR("dpdk_helper_worker: error posting sema_cmd_start semaphore (%s)\n",
+ ERROR("dpdk_helper_worker: error posting sema_cmd_start semaphore (%s)",
sstrerror(errno, errbuf, sizeof(errbuf)));
}
}
}
-#ifdef DPDK_HELPER_USE_PIPES
dpdk_helper_check_pipe(phc);
-#endif /* DPDK_HELPER_USE_PIPES */
DEBUG("%s: DPDK command complete (cmd=%d, result=%d)", phc->shm_name,
phc->cmd, phc->cmd_result);
uint128_t lcore_mask;
int err = 0;
- memset(&lcore_mask, 0, sizeof(uint128_t));
+ memset(&lcore_mask, 0, sizeof(lcore_mask));
if (len <= 2 || strncmp(str, "0x", 2) != 0) {
ERROR("%s Value %s should be represened in hexadecimal format",
__FUNCTION__, str);
return lcore_mask;
}
-
+ /* If str is <= 64 bit long ('0x' + 16 chars = 18 chars) then
+ * conversion is straightforward. Otherwise str is splitted into 64b long
+ * blocks */
if (len <= 18) {
lcore_mask.low = strtoull_safe(str, &err);
if (err)
- goto parse_out;
+ return lcore_mask;
} else {
char low_str[DATA_MAX_NAME_LEN];
char high_str[DATA_MAX_NAME_LEN];
lcore_mask.low = strtoull_safe(low_str, &err);
if (err)
- goto parse_out;
+ return lcore_mask;
lcore_mask.high = strtoull_safe(high_str, &err);
if (err) {
lcore_mask.low = 0;
- goto parse_out;
+ return lcore_mask;
}
}
-
-parse_out:
return lcore_mask;
}
+
+uint8_t dpdk_helper_eth_dev_count() {
+ uint8_t ports = rte_eth_dev_count();
+ if (ports == 0) {
+ ERROR(
+ "%s:%d: No DPDK ports available. Check bound devices to DPDK driver.\n",
+ __FUNCTION__, __LINE__);
+ return ports;
+ }
+
+ if (ports > RTE_MAX_ETHPORTS) {
+ ERROR("%s:%d: Number of DPDK ports (%u) is greater than "
+ "RTE_MAX_ETHPORTS=%d. Ignoring extra ports\n",
+ __FUNCTION__, __LINE__, ports, RTE_MAX_ETHPORTS);
+ ports = RTE_MAX_ETHPORTS;
+ }
+
+ return ports;
+}