X-Git-Url: https://git.verplant.org/?a=blobdiff_plain;f=src%2Fdpdkstat.c;h=3e0ea046a083c8ddd94c34472b8f1dad8170da9c;hb=acbf4e5d5b848540c6fc0d9bfb235f6441564384;hp=e37c4ba40823aed695ed555d1d8ab89796348f4c;hpb=213986f665915ec5b4b811f94b56dd305125b7fd;p=collectd.git diff --git a/src/dpdkstat.c b/src/dpdkstat.c index e37c4ba4..3e0ea046 100644 --- a/src/dpdkstat.c +++ b/src/dpdkstat.c @@ -85,6 +85,7 @@ struct dpdk_config_s { cdtime_t interval; uint32_t eal_initialized; uint32_t enabled_port_mask; + char port_name[RTE_MAX_ETHPORTS][DATA_MAX_NAME_LEN]; uint32_t eal_argc; /* Helper info */ int collectd_reinit_shm; @@ -113,7 +114,7 @@ static int dpdk_config(oconfig_item_t *ci); static int dpdk_helper_init_eal(void); static int dpdk_helper_run(void); static int dpdk_helper_spawn(enum DPDK_HELPER_ACTION action); -static int dpdk_init (void); +static int dpdk_init(void); static int dpdk_read(user_data_t *ud); static int dpdk_shm_cleanup(void); static int dpdk_shm_init(size_t size); @@ -124,7 +125,8 @@ static void dpdk_config_init_default(void) g_configuration->interval = plugin_get_interval(); WARNING("dpdkstat: No time interval was configured, default value %lu ms is set\n", CDTIME_T_TO_MS(g_configuration->interval)); - g_configuration->enabled_port_mask = 0; + /* Default is all ports enabled */ + g_configuration->enabled_port_mask = ~0; g_configuration->eal_argc = 2; g_configuration->eal_initialized = 0; ssnprintf(g_configuration->coremask, DATA_MAX_NAME_LEN, "%s", "0xf"); @@ -132,11 +134,14 @@ static void dpdk_config_init_default(void) ssnprintf(g_configuration->process_type, DATA_MAX_NAME_LEN, "%s", "secondary"); ssnprintf(g_configuration->file_prefix, DATA_MAX_NAME_LEN, "%s", "/var/run/.rte_config"); + + for (int i = 0; i < RTE_MAX_ETHPORTS; i++) + g_configuration->port_name[i][0] = 0; } static int dpdk_config(oconfig_item_t *ci) { - int i = 0; + int port_counter = 0; /* Initialize a POSIX SHared Memory (SHM) object. */ int err = dpdk_shm_init(sizeof(dpdk_config_t)); @@ -148,7 +153,7 @@ static int dpdk_config(oconfig_item_t *ci) /* Set defaults for config, overwritten by loop if config item exists */ dpdk_config_init_default(); - for (i = 0; i < ci->children_num; i++) { + for (int i = 0; i < ci->children_num; i++) { oconfig_item_t *child = ci->children + i; if (strcasecmp("Interval", child->key) == 0) { @@ -183,11 +188,20 @@ static int dpdk_config(oconfig_item_t *ci) if (strcasecmp(g_configuration->file_prefix, "/var/run/.rte_config") != 0) { g_configuration->eal_argc+=1; } + } else if (strcasecmp("EnabledPortMask", child->key) == 0) { + g_configuration->enabled_port_mask = (uint32_t)child->values[0].value.number; + DEBUG("dpdkstat: Enabled Port Mask %u\n", g_configuration->enabled_port_mask); + } else if (strcasecmp("PortName", child->key) == 0) { + ssnprintf(g_configuration->port_name[port_counter], DATA_MAX_NAME_LEN, "%s", + child->values[0].value.string); + DEBUG("dpdkstat: Port %d Name: %s \n", port_counter, + g_configuration->port_name[port_counter]); + port_counter++; } else { WARNING ("dpdkstat: The config option \"%s\" is unknown.", child->key); } - } /* End for (i = 0; i < ci->children_num; i++)*/ + } /* End for (int i = 0; i < ci->children_num; i++)*/ g_configured = 1; /* Bypass configuration in dpdk_shm_init(). */ return 0; @@ -304,17 +318,17 @@ static int dpdk_init (void) static int dpdk_helper_exit(int reset) { g_configuration->helper_status = DPDK_HELPER_GRACEFUL_QUIT; - if(reset) { + if (reset) { g_configuration->eal_initialized = 0; g_configuration->num_ports = 0; memset(&g_configuration->xstats, 0, g_configuration->num_xstats* sizeof(struct rte_eth_xstats)); g_configuration->num_xstats = 0; - for(int i = 0; i < RTE_MAX_ETHPORTS; i++) + for (int i = 0; i < RTE_MAX_ETHPORTS; i++) g_configuration->num_stats_in_port[i] = 0; } close(g_configuration->helper_pipes[1]); int err = kill(g_configuration->helper_pid, SIGKILL); - if(err) { + if (err) { ERROR("dpdkstat: error sending kill to helper: %s\n", strerror(errno)); } @@ -329,7 +343,7 @@ static int dpdk_helper_spawn(enum DPDK_HELPER_ACTION action) * Create a pipe for helper stdout back to collectd. This is necessary for * logging EAL failures, as rte_eal_init() calls rte_panic(). */ - if(g_configuration->helper_pipes[1]) { + if (g_configuration->helper_pipes[1]) { DEBUG("dpdkstat: collectd closing helper pipe %d\n", g_configuration->helper_pipes[1]); } else { @@ -341,11 +355,16 @@ static int dpdk_helper_spawn(enum DPDK_HELPER_ACTION action) return -1; } - int pipe0_flags = fcntl(g_configuration->helper_pipes[1], F_GETFL, 0); - int pipe1_flags = fcntl(g_configuration->helper_pipes[0], F_GETFL, 0); - int p1err = fcntl(g_configuration->helper_pipes[1], F_SETFL, pipe1_flags | O_NONBLOCK); - int p2err = fcntl(g_configuration->helper_pipes[0], F_SETFL, pipe0_flags | O_NONBLOCK); - if (pipe0_flags == -1 || pipe1_flags == -1 || p1err == -1 || p2err == -1) { + int pipe0_flags = fcntl(g_configuration->helper_pipes[0], F_GETFL, 0); + int pipe1_flags = fcntl(g_configuration->helper_pipes[1], F_GETFL, 0); + if (pipe0_flags == -1 || pipe1_flags == -1) { + ERROR("dpdkstat: error setting up pipe flags: %s\n", strerror(errno)); + } + int pipe0_err = fcntl(g_configuration->helper_pipes[0], F_SETFL, pipe1_flags + | O_NONBLOCK); + int pipe1_err = fcntl(g_configuration->helper_pipes[1], F_SETFL, pipe0_flags + | O_NONBLOCK); + if (pipe0_err == -1 || pipe1_err == -1) { ERROR("dpdkstat: error setting up pipes: %s\n", strerror(errno)); } @@ -380,24 +399,24 @@ static int dpdk_helper_init_eal(void) int i = 0; argp[i++] = "collectd-dpdk"; - if(strcasecmp(g_configuration->coremask, "") != 0) { + if (strcasecmp(g_configuration->coremask, "") != 0) { argp[i++] = "-c"; argp[i++] = g_configuration->coremask; } - if(strcasecmp(g_configuration->memory_channels, "") != 0) { + if (strcasecmp(g_configuration->memory_channels, "") != 0) { argp[i++] = "-n"; argp[i++] = g_configuration->memory_channels; } - if(strcasecmp(g_configuration->socket_memory, "") != 0) { + if (strcasecmp(g_configuration->socket_memory, "") != 0) { argp[i++] = "--socket-mem"; argp[i++] = g_configuration->socket_memory; } - if(strcasecmp(g_configuration->file_prefix, "") != 0 && + if (strcasecmp(g_configuration->file_prefix, "") != 0 && strcasecmp(g_configuration->file_prefix, "/var/run/.rte_config") != 0) { argp[i++] = "--file-prefix"; argp[i++] = g_configuration->file_prefix; } - if(strcasecmp(g_configuration->process_type, "") != 0) { + if (strcasecmp(g_configuration->process_type, "") != 0) { argp[i++] = "--proc-type"; argp[i++] = g_configuration->process_type; } @@ -409,11 +428,11 @@ static int dpdk_helper_init_eal(void) g_configuration->eal_initialized = 0; printf("dpdkstat: ERROR initializing EAL ret = %d\n", ret); printf("dpdkstat: EAL arguments: "); - for (i=0; i< g_configuration->eal_argc; i++) { + for (i = 0; i < g_configuration->eal_argc; i++) { printf("%s ", argp[i]); } printf("\n"); - return -1; + return ret; } return 0; } @@ -423,7 +442,7 @@ static int dpdk_helper_run (void) pid_t ppid = getppid(); g_configuration->helper_status = DPDK_HELPER_WAITING_ON_PRIMARY; - while(1) { + while (1) { /* sem_timedwait() to avoid blocking forever */ struct timespec ts; cdtime_t now = cdtime(); @@ -431,12 +450,11 @@ static int dpdk_helper_run (void) CDTIME_T_TO_TIMESPEC(now + half_sec + g_configuration->interval *2, &ts); int ret = sem_timedwait(&g_configuration->sema_helper_get_stats, &ts); - if(ret == -1 && errno == ETIMEDOUT) { + if (ret == -1 && errno == ETIMEDOUT) { ERROR("dpdkstat-helper: sem timedwait()" " timeout, did collectd terminate?\n"); dpdk_helper_exit(RESET); } - /* Parent PID change means collectd died so quit the helper process. */ if (ppid != getppid()) { WARNING("dpdkstat-helper: parent PID changed, quitting.\n"); @@ -455,11 +473,13 @@ static int dpdk_helper_run (void) continue; } - if(!g_configuration->eal_initialized) { + if (!g_configuration->eal_initialized) { /* Initialize EAL. */ int ret = dpdk_helper_init_eal(); - if(ret != 0) + if(ret != 0) { + WARNING("ERROR INITIALIZING EAL\n"); dpdk_helper_exit(RESET); + } } g_configuration->helper_status = DPDK_HELPER_ALIVE_SENDING_STATS; @@ -473,12 +493,9 @@ static int dpdk_helper_run (void) if (nb_ports > RTE_MAX_ETHPORTS) nb_ports = RTE_MAX_ETHPORTS; - /* If no port mask was specified enable all ports*/ - if (g_configuration->enabled_port_mask == 0) - g_configuration->enabled_port_mask = 0xffff; int len = 0, enabled_port_count = 0, num_xstats = 0; - for (int i = 0; i < nb_ports; i++) { + for (uint8_t i = 0; i < nb_ports; i++) { if (g_configuration->enabled_port_mask & (1 << i)) { if(g_configuration->helper_action == DPDK_HELPER_ACTION_COUNT_STATS) { len = rte_eth_xstats_get(i, NULL, 0); @@ -506,7 +523,7 @@ static int dpdk_helper_run (void) } /* if (enabled_port_mask) */ } /* for (nb_ports) */ - if(g_configuration->helper_action == DPDK_HELPER_ACTION_COUNT_STATS) { + if (g_configuration->helper_action == DPDK_HELPER_ACTION_COUNT_STATS) { g_configuration->num_ports = enabled_port_count; g_configuration->num_xstats = num_xstats; DEBUG("dpdkstat-helper ports: %d, num stats: %d\n", @@ -532,7 +549,7 @@ static int dpdk_read (user_data_t *ud) * Check if SHM flag is set to be re-initialized. AKA DPDK ports have been * counted, so re-init SHM to be large enough to fit all the statistics. */ - if(g_configuration->collectd_reinit_shm) { + if (g_configuration->collectd_reinit_shm) { DEBUG("dpdkstat: read() now reinit SHM then launching send-thread\n"); dpdk_re_init_shm(); } @@ -542,14 +559,14 @@ static int dpdk_read (user_data_t *ud) * must be done in dpdk_read(), because the DPDK primary process may not be * alive at dpdk_init() time. */ - if(g_configuration->helper_status == DPDK_HELPER_NOT_INITIALIZED || + if (g_configuration->helper_status == DPDK_HELPER_NOT_INITIALIZED || g_configuration->helper_status == DPDK_HELPER_GRACEFUL_QUIT) { int action = DPDK_HELPER_ACTION_SEND_STATS; if(g_configuration->num_xstats == 0) action = DPDK_HELPER_ACTION_COUNT_STATS; /* Spawn the helper thread to count stats or to read stats. */ int err = dpdk_helper_spawn(action); - if(err) { + if (err) { ERROR("dpdkstat: error spawning helper %s\n", strerror(errno)); return -1; } @@ -562,7 +579,7 @@ static int dpdk_read (user_data_t *ud) * waitpid() fails, helper process died (or quit), so respawn */ int respawn_helper = 0; - if(ws != 0) { + if (ws != 0) { respawn_helper = 1; } @@ -574,15 +591,15 @@ static int dpdk_read (user_data_t *ud) fds.fd = g_configuration->helper_pipes[0]; fds.events = POLLIN; int data_avail = poll(&fds, 1, 0); - while(data_avail) { + while (data_avail) { int nbytes = read(g_configuration->helper_pipes[0], buf, sizeof(buf)); - if(nbytes <= 0) + if (nbytes <= 0) break; ssnprintf( out, nbytes, "%s", buf); DEBUG("dpdkstat: helper-proc: %s\n", out); } - if(respawn_helper) { + if (respawn_helper) { if (g_configuration->helper_pid) dpdk_helper_exit(RESET); dpdk_helper_spawn(DPDK_HELPER_ACTION_COUNT_STATS); @@ -597,26 +614,34 @@ static int dpdk_read (user_data_t *ud) cdtime_t now = cdtime(); CDTIME_T_TO_TIMESPEC(now + g_configuration->interval, &ts); ret = sem_timedwait(&g_configuration->sema_stats_in_shm, &ts); - if(ret == -1 && errno == ETIMEDOUT) { + if (ret == -1 && errno == ETIMEDOUT) { DEBUG("dpdkstat: timeout in collectd thread: is a DPDK Primary running? \n"); return 0; } /* Dispatch the stats.*/ - int count = 0; + int count = 0, port_num = 0; - for (int i = 0; i < g_configuration->num_ports; i++) { + for (uint32_t i = 0; i < g_configuration->num_ports; i++) { cdtime_t time = g_configuration->port_read_time[i]; char dev_name[64]; int len = g_configuration->num_stats_in_port[i]; - ssnprintf(dev_name, sizeof(dev_name), "port.%d", i); + + while(!(g_configuration->enabled_port_mask & (1 << port_num))) + port_num++; + + if (g_configuration->port_name[i][0] != 0) + ssnprintf(dev_name, sizeof(dev_name), "%s", g_configuration->port_name[i]); + else + ssnprintf(dev_name, sizeof(dev_name), "port.%d", port_num); struct rte_eth_xstats *xstats = (&g_configuration->xstats); xstats += count; /* pointer arithmetic to jump to each stats struct */ for (int j = 0; j < len; j++) { value_t dpdkstat_values[1]; value_list_t dpdkstat_vl = VALUE_LIST_INIT; + char *type_end; - dpdkstat_values[0].counter = xstats[j].value; + dpdkstat_values[0].derive = (derive_t) xstats[j].value; dpdkstat_vl.values = dpdkstat_values; dpdkstat_vl.values_len = 1; /* Submit stats one at a time */ dpdkstat_vl.time = time; @@ -624,13 +649,86 @@ static int dpdk_read (user_data_t *ud) sstrncpy (dpdkstat_vl.plugin, "dpdkstat", sizeof (dpdkstat_vl.plugin)); sstrncpy (dpdkstat_vl.plugin_instance, dev_name, sizeof (dpdkstat_vl.plugin_instance)); - sstrncpy (dpdkstat_vl.type, "counter", - sizeof (dpdkstat_vl.type)); + + type_end = strrchr(xstats[j].name, '_'); + + if ((type_end != NULL) && + (strncmp(xstats[j].name, "rx_", strlen("rx_")) == 0)) { + if (strncmp(type_end, "_errors", strlen("_errors")) == 0) { + sstrncpy (dpdkstat_vl.type, "if_rx_errors", + sizeof(dpdkstat_vl.type)); + } else if (strncmp(type_end, "_dropped", strlen("_dropped")) == 0) { + sstrncpy (dpdkstat_vl.type, "if_rx_dropped", + sizeof(dpdkstat_vl.type)); + } else if (strncmp(type_end, "_bytes", strlen("_bytes")) == 0) { + sstrncpy (dpdkstat_vl.type, "if_rx_octets", + sizeof(dpdkstat_vl.type)); + } else if (strncmp(type_end, "_packets", strlen("_packets")) == 0) { + sstrncpy (dpdkstat_vl.type, "if_rx_packets", + sizeof(dpdkstat_vl.type)); + } else if (strncmp(type_end, "_placement", strlen("_placement")) == 0) { + sstrncpy (dpdkstat_vl.type, "if_rx_errors", + sizeof(dpdkstat_vl.type)); + } else if (strncmp(type_end, "_buff", strlen("_buff")) == 0) { + sstrncpy (dpdkstat_vl.type, "if_rx_errors", + sizeof(dpdkstat_vl.type)); + } else { + /* Does not fit obvious type: use a more generic one */ + sstrncpy (dpdkstat_vl.type, "derive", + sizeof(dpdkstat_vl.type)); + } + + } else if ((type_end != NULL) && + (strncmp(xstats[j].name, "tx_", strlen("tx_"))) == 0) { + if (strncmp(type_end, "_errors", strlen("_errors")) == 0) { + sstrncpy (dpdkstat_vl.type, "if_tx_errors", + sizeof(dpdkstat_vl.type)); + } else if (strncmp(type_end, "_dropped", strlen("_dropped")) == 0) { + sstrncpy (dpdkstat_vl.type, "if_tx_dropped", + sizeof(dpdkstat_vl.type)); + } else if (strncmp(type_end, "_bytes", strlen("_bytes")) == 0) { + sstrncpy (dpdkstat_vl.type, "if_tx_octets", + sizeof(dpdkstat_vl.type)); + } else if (strncmp(type_end, "_packets", strlen("_packets")) == 0) { + sstrncpy (dpdkstat_vl.type, "if_tx_packets", + sizeof(dpdkstat_vl.type)); + } else { + /* Does not fit obvious type: use a more generic one */ + sstrncpy (dpdkstat_vl.type, "derive", + sizeof(dpdkstat_vl.type)); + } + } else if ((type_end != NULL) && + (strncmp(xstats[j].name, "flow_", strlen("flow_"))) == 0) { + + if (strncmp(type_end, "_filters", strlen("_filters")) == 0) { + sstrncpy (dpdkstat_vl.type, "operations", + sizeof(dpdkstat_vl.type)); + } else if (strncmp(type_end, "_errors", strlen("_errors")) == 0) { + sstrncpy (dpdkstat_vl.type, "errors", + sizeof(dpdkstat_vl.type)); + } else if (strncmp(type_end, "_filters", strlen("_filters")) == 0) { + sstrncpy (dpdkstat_vl.type, "filter_result", + sizeof(dpdkstat_vl.type)); + } + } else if ((type_end != NULL) && + (strncmp(xstats[j].name, "mac_", strlen("mac_"))) == 0) { + if (strncmp(type_end, "_errors", strlen("_errors")) == 0) { + sstrncpy (dpdkstat_vl.type, "errors", + sizeof(dpdkstat_vl.type)); + } + } else { + /* Does not fit obvious type, or strrchr error: + * use a more generic type */ + sstrncpy (dpdkstat_vl.type, "derive", + sizeof(dpdkstat_vl.type)); + } + sstrncpy (dpdkstat_vl.type_instance, xstats[j].name, sizeof (dpdkstat_vl.type_instance)); plugin_dispatch_values (&dpdkstat_vl); } count += len; + port_num++; } /* for each port */ return 0; } @@ -639,12 +737,12 @@ static int dpdk_shm_cleanup(void) { int ret = munmap(g_configuration, sizeof(dpdk_config_t)); g_configuration = 0; - if(ret) { + if (ret) { WARNING("dpdkstat: munmap returned %d\n", ret); return ret; } ret = shm_unlink(DPDK_SHM_NAME); - if(ret) { + if (ret) { WARNING("dpdkstat: shm_unlink returned %d\n", ret); return ret; }