int dpdk_helper_command_handler(dpdk_helper_ctx_t *phc, enum DPDK_CMD cmd) { /* this function is called from helper context */ if (phc == NULL) { DPDK_CHILD_LOG("%s: Invalid argument(phc)\n", DPDK_STATS_PLUGIN); return -EINVAL; } if (cmd != DPDK_CMD_GET_STATS) { DPDK_CHILD_LOG("%s: Unknown command (cmd=%d)\n", DPDK_STATS_PLUGIN, cmd); return -EINVAL; } int stats_count = dpdk_helper_stats_count_get(phc); if (stats_count < 0) { return stats_count; } DPDK_STATS_CTX_GET(phc)->stats_count = stats_count; int stats_size = stats_count * DPDK_STATS_CTX_GET_XSTAT_SIZE; if (dpdk_stats_get_size(phc) < stats_size) { DPDK_CHILD_LOG( DPDK_STATS_PLUGIN ":%s:%d not enough space for stats (available=%d, needed=%d)\n", __FUNCTION__, __LINE__, (int)dpdk_stats_get_size(phc), stats_size); return -ENOBUFS; } return dpdk_helper_stats_get(phc); }
static int dpdk_stats_read(user_data_t *ud) { DPDK_STATS_TRACE(); int ret = 0; if (g_hc == NULL) { ERROR("dpdk stats plugin not initialized"); return -EINVAL; } dpdk_stats_ctx_t *ctx = DPDK_STATS_CTX_GET(g_hc); int result = 0; ret = dpdk_helper_command(g_hc, DPDK_CMD_GET_STATS, &result, ctx->config.interval); if (ret != 0) { return 0; } if (result == -ENOBUFS) { dpdk_stats_reinit_helper(); } else if (result == -ENODEV) { dpdk_helper_shutdown(g_hc); } else if (result == 0) { dpdk_stats_counters_dispatch(g_hc); } return 0; }
static int dpdk_helper_stats_count_get(dpdk_helper_ctx_t *phc) { uint8_t ports = dpdk_helper_eth_dev_count(); if (ports == 0) return -ENODEV; dpdk_stats_ctx_t *ctx = DPDK_STATS_CTX_GET(phc); ctx->ports_count = ports; int len = 0; int stats_count = 0; for (int i = 0; i < ports; i++) { if (!(ctx->config.enabled_port_mask & (1 << i))) continue; #if RTE_VERSION >= RTE_VERSION_16_07 len = rte_eth_xstats_get_names(i, NULL, 0); #else len = rte_eth_xstats_get(i, NULL, 0); #endif if (len < 0) { DPDK_CHILD_LOG("%s: Cannot get stats count\n", DPDK_STATS_PLUGIN); return -1; } ctx->port_stats_count[i] = len; stats_count += len; } DPDK_CHILD_LOG("%s:%s:%d stats_count=%d\n", DPDK_STATS_PLUGIN, __FUNCTION__, __LINE__, stats_count); return stats_count; }
static void dpdk_stats_default_config(void) { dpdk_stats_ctx_t *ec = DPDK_STATS_CTX_GET(g_hc); ec->config.interval = plugin_get_interval(); for (int i = 0; i < RTE_MAX_ETHPORTS; i++) { ec->config.port_name[i][0] = 0; } /* Enable all ports by default */ ec->config.enabled_port_mask = ~0; }
static int dpdk_stats_config(oconfig_item_t *ci) { DPDK_STATS_TRACE(); int ret = dpdk_stats_preinit(); if (ret) return ret; dpdk_stats_ctx_t *ctx = DPDK_STATS_CTX_GET(g_hc); for (int i = 0; i < ci->children_num; i++) { oconfig_item_t *child = ci->children + i; if ((strcasecmp("EnabledPortMask", child->key) == 0) && (child->values[0].type == OCONFIG_TYPE_NUMBER)) { ctx->config.enabled_port_mask = child->values[0].value.number; DEBUG("%s: Enabled Port Mask 0x%X", DPDK_STATS_PLUGIN, ctx->config.enabled_port_mask); } else if (strcasecmp("SharedMemObj", child->key) == 0) { cf_util_get_string_buffer(child, g_shm_name, sizeof(g_shm_name)); DEBUG("%s: Shared memory object %s", DPDK_STATS_PLUGIN, g_shm_name); dpdk_stats_reinit_helper(); } else if (strcasecmp("EAL", child->key) == 0) { ret = dpdk_helper_eal_config_parse(g_hc, child); if (ret) return ret; } } int port_num = 0; /* parse port names after EnabledPortMask was parsed */ for (int i = 0; i < ci->children_num; i++) { oconfig_item_t *child = ci->children + i; if (strcasecmp("PortName", child->key) == 0) { while (!(ctx->config.enabled_port_mask & (1 << port_num))) port_num++; cf_util_get_string_buffer(child, ctx->config.port_name[port_num], sizeof(ctx->config.port_name[port_num])); DEBUG("%s: Port %d Name: %s", DPDK_STATS_PLUGIN, port_num, ctx->config.port_name[port_num]); port_num++; } } return ret; }
static int dpdk_stats_reinit_helper() { DPDK_STATS_TRACE(); dpdk_stats_ctx_t *ctx = DPDK_STATS_CTX_GET(g_hc); size_t data_size = sizeof(dpdk_stats_ctx_t) + (ctx->stats_count * DPDK_STATS_CTX_GET_XSTAT_SIZE); DEBUG("%s:%d helper reinit (new_size=%zu)", __FUNCTION__, __LINE__, data_size); dpdk_stats_ctx_t tmp_ctx; dpdk_eal_config_t tmp_eal; memcpy(&tmp_ctx, ctx, sizeof(dpdk_stats_ctx_t)); dpdk_helper_eal_config_get(g_hc, &tmp_eal); dpdk_helper_shutdown(g_hc); g_hc = NULL; int ret; ret = dpdk_helper_init(g_shm_name, data_size, &g_hc); if (ret != 0) { char errbuf[ERR_BUF_SIZE]; ERROR("%s: failed to initialize %s helper(error: %s)", DPDK_STATS_PLUGIN, g_shm_name, sstrerror(errno, errbuf, sizeof(errbuf))); return ret; } ctx = DPDK_STATS_CTX_GET(g_hc); memcpy(ctx, &tmp_ctx, sizeof(dpdk_stats_ctx_t)); DPDK_STATS_CTX_INIT(ctx); dpdk_helper_eal_config_set(g_hc, &tmp_eal); return ret; }
static int dpdk_stats_counters_dispatch(dpdk_helper_ctx_t *phc) { dpdk_stats_ctx_t *ctx = DPDK_STATS_CTX_GET(phc); /* dispatch stats values to collectd */ DEBUG("%s:%s:%d ports=%u", DPDK_STATS_PLUGIN, __FUNCTION__, __LINE__, ctx->ports_count); int stats_count = 0; for (int i = 0; i < ctx->ports_count; i++) { if (!(ctx->config.enabled_port_mask & (1 << i))) continue; char dev_name[64]; if (ctx->config.port_name[i][0] != 0) { snprintf(dev_name, sizeof(dev_name), "%s", ctx->config.port_name[i]); } else { snprintf(dev_name, sizeof(dev_name), "port.%d", i); } DEBUG(" === Dispatch stats for port %d (name=%s; stats_count=%d)", i, dev_name, ctx->port_stats_count[i]); for (int j = 0; j < ctx->port_stats_count[i]; j++) { const char *cnt_name = DPDK_STATS_XSTAT_GET_NAME(ctx, stats_count); if (cnt_name == NULL) WARNING("dpdkstat: Invalid counter name"); else dpdk_stats_counter_submit( dev_name, cnt_name, (derive_t)DPDK_STATS_XSTAT_GET_VALUE(ctx, stats_count), ctx->port_read_time[i]); stats_count++; assert(stats_count <= ctx->stats_count); } } return 0; }
static int dpdk_helper_stats_get(dpdk_helper_ctx_t *phc) { int len = 0; int ret = 0; int stats = 0; dpdk_stats_ctx_t *ctx = DPDK_STATS_CTX_GET(phc); /* get stats from DPDK */ for (uint8_t i = 0; i < ctx->ports_count; i++) { if (!(ctx->config.enabled_port_mask & (1 << i))) continue; ctx->port_read_time[i] = cdtime(); /* Store available stats array length for port */ len = ctx->port_stats_count[i]; ret = rte_eth_xstats_get(i, &ctx->xstats[stats], len); if (ret < 0 || ret > len) { DPDK_CHILD_LOG(DPDK_STATS_PLUGIN ": Error reading stats (port=%d; len=%d, ret=%d)\n", i, len, ret); ctx->port_stats_count[i] = 0; return -1; } #if RTE_VERSION >= RTE_VERSION_16_07 ret = rte_eth_xstats_get_names(i, &ctx->xnames[stats], len); if (ret < 0 || ret > len) { DPDK_CHILD_LOG(DPDK_STATS_PLUGIN ": Error reading stat names (port=%d; len=%d ret=%d)\n", i, len, ret); ctx->port_stats_count[i] = 0; return -1; } #endif ctx->port_stats_count[i] = ret; stats += ctx->port_stats_count[i]; } assert(stats <= ctx->stats_count); return 0; }
static int dpdk_stats_config(oconfig_item_t *ci) { DPDK_STATS_TRACE(); int ret = dpdk_stats_preinit(); if (ret) { g_state = DPDK_STAT_STATE_CFG_ERR; return 0; } dpdk_stats_ctx_t *ctx = DPDK_STATS_CTX_GET(g_hc); for (int i = 0; i < ci->children_num; i++) { oconfig_item_t *child = ci->children + i; if (strcasecmp("EnabledPortMask", child->key) == 0) ret = cf_util_get_int(child, (int *)&ctx->config.enabled_port_mask); else if (strcasecmp("SharedMemObj", child->key) == 0) { ret = cf_util_get_string_buffer(child, g_shm_name, sizeof(g_shm_name)); if (ret == 0) ret = dpdk_stats_reinit_helper(); } else if (strcasecmp("EAL", child->key) == 0) ret = dpdk_helper_eal_config_parse(g_hc, child); else if (strcasecmp("PortName", child->key) != 0) { ERROR(DPDK_STATS_PLUGIN ": unrecognized configuration option %s", child->key); ret = -1; } if (ret != 0) { g_state = DPDK_STAT_STATE_CFG_ERR; return 0; } } DEBUG(DPDK_STATS_PLUGIN ": Enabled Port Mask 0x%X", ctx->config.enabled_port_mask); DEBUG(DPDK_STATS_PLUGIN ": Shared memory object %s", g_shm_name); int port_num = 0; /* parse port names after EnabledPortMask was parsed */ for (int i = 0; i < ci->children_num; i++) { oconfig_item_t *child = ci->children + i; if (strcasecmp("PortName", child->key) == 0) { while (!(ctx->config.enabled_port_mask & (1 << port_num))) port_num++; if (cf_util_get_string_buffer(child, ctx->config.port_name[port_num], sizeof(ctx->config.port_name[port_num]))) { g_state = DPDK_STAT_STATE_CFG_ERR; return 0; } DEBUG(DPDK_STATS_PLUGIN ": Port %d Name: %s", port_num, ctx->config.port_name[port_num]); port_num++; } } return 0; }