# The dpdkstat plugin
+ This plugin is optional and only has a specific use case: monitoring DPDK applications
+ that don't expose stats in any other way than the DPDK xstats API.
+
**Data Plane Development Kit** (DPDK) is a set of drivers and libraries for fast
- packet processing.
+ packet processing. Please note that this plugin is a polling based plugin rather
+ than an events based plugin (using it will drive up core utilization on a system).
+
+ **PLEASE DO NOT USE THIS PLUGIN FOR OVS-DPDK**. dpdkstat is really for DPDK
+ applications that have no other way of exposing stats. For OVS or OVS-with-DPDK the
+ Open vSwitch plugins available in collectd 5.8.0 should be used for
+ collecting stats and events. In addition the OVS plugin is events based rather
+ than polling based and will have a smaller footprint on the system.
## Summary
* Run `ldconfig` to update the shared library cache.
-### Static library
-
-To build static DPDK library for use with collectd:
-
- * To configure DPDK to build the combined static library `libdpdk.a` ensure
- that `CONFIG_RTE_BUILD_SHARED_LIB` is set to ānā in `config/common_base` in
- your DPDK as follows:
-
- #
- # Compile to share library
- #
- CONFIG_RTE_BUILD_SHARED_LIB=n
-
- * Prepare the configuration for the appropriate target as specified at:
- http://dpdk.org/doc/guides/linux_gsg/build_dpdk.html.
-
- For example:
-
- make config T=x86_64-native-linuxapp-gcc
-
- * Build the target using `-fPIC`:
-
- make EXTRA_CFLAGS=-fPIC -j
-
- * Install DPDK to `/usr`:
-
- sudo make install prefix=/usr
-
## Build collectd with DPDK
**Note:** DPDK 16.04 is the minimum version and currently supported version of
See also: http://dpdk.org/doc/guides/prog_guide/multi_proc_support.html
* Generate the build script as specified below. (i.e. run `build.sh`).
- * Configure collectd with the DPDK shared library:
-
- ./configure --with-libdpdk=/usr
+ * Configure collectd with the DPDK shared library. If DPDK is installed in
+ custom installation path you can specify headers include path using
+ LIBDPDK_CPPFLAGS variable and libraries path with LIBDPDK_LDFLAGS.
+ Example:
-### Build with the static DPDK library
+ ./configure
-To configure collectd with the DPDK static library:
+ or for custom DPKD installation:
- * Run *configure* with the following CFLAGS:
+ ./configure LIBDPDK_CPPFLAGS="-I/home/joe/include/dpdk" LIBDPDK_LDFLAGS="-L/home/joe/usr/lib"
- ./configure --with-libdpdk=/usr CFLAGS=" -lpthread -Wl,--whole-archive -Wl,-ldpdk -Wl,-lm -Wl,-lrt -Wl,-lpcap -Wl,-ldl -Wl,--no-whole-archive"
-
- * Make sure that dpdk and dpdkstat are enabled in the *configure* output.
+ * Make sure that libdpdk and dpdkstat are enabled in the *configure* output.
Expected output:
Libraries:
...
libdpdk . . . . . . . . yes
-
+
Modules:
...
dpdkstat . . . . . . .yes
* Build collectd:
- make -j && make -j install.
+ make -j && make -j install
**Note:** As mentioned above, if you are building on Ubuntu 14.04 with
GCC <= 4.8.X, you need to use:
* The same PCI device configuration should be passed to the primary process as
the secondary process uses the same port indexes as the primary.
* A blacklist / whitelist of NICs isn't supported yet.
+ * Plugin initialization time depends on read interval. It requires 5 read
+ cycles to set up internal buffers and states. During that time no statistics
+ are submitted.
+ * If number of DPDK ports is increased while plugin is running, internal
+ buffers are resized. That requires 3 read cycles and no port statistics
+ are submitted in that time.
## License
}
#endif
+ static rd_kafka_resp_err_t kafka_error() {
+ #if RD_KAFKA_VERSION >= 0x000b00ff
+ return rd_kafka_last_error();
+ #else
+ return rd_kafka_errno2err(errno);
+ #endif
+ }
+
static uint32_t kafka_hash(const char *keydata, size_t keylen) {
uint32_t hash = 5381;
for (; keylen > 0; keylen--)
#define KAFKA_RANDOM_KEY_BUFFER \
(char[KAFKA_RANDOM_KEY_SIZE]) { "" }
static char *kafka_random_key(char buffer[static KAFKA_RANDOM_KEY_SIZE]) {
- ssnprintf(buffer, KAFKA_RANDOM_KEY_SIZE, "%08" PRIX32, cdrand_u());
+ snprintf(buffer, KAFKA_RANDOM_KEY_SIZE, "%08" PRIX32, cdrand_u());
return buffer;
}
rd_kafka_topic_conf_t *topic_conf;
if (ctx->kafka != NULL && ctx->topic != NULL)
- return (0);
+ return 0;
if (ctx->kafka == NULL) {
if ((conf = rd_kafka_conf_dup(ctx->kafka_conf)) == NULL) {
ERROR("write_kafka plugin: cannot duplicate kafka config");
- return (1);
+ return 1;
}
if ((ctx->kafka = rd_kafka_new(RD_KAFKA_PRODUCER, conf, errbuf,
if ((ctx->topic = rd_kafka_topic_new(ctx->kafka, ctx->topic_name,
topic_conf)) == NULL) {
ERROR("write_kafka plugin: cannot create topic : %s\n",
- rd_kafka_err2str(rd_kafka_errno2err(errno)));
+ rd_kafka_err2str(kafka_error()));
return errno;
}
rd_kafka_topic_name(ctx->topic));
}
- return (0);
+ return 0;
} /* }}} int kafka_handle */
rd_kafka_topic_conf_set_partitioner_cb(tctx->conf, kafka_partition);
rd_kafka_topic_conf_set_opaque(tctx->conf, tctx);
- ssnprintf(callback_name, sizeof(callback_name), "write_kafka/%s",
- tctx->topic_name);
+ snprintf(callback_name, sizeof(callback_name), "write_kafka/%s",
+ tctx->topic_name);
status = plugin_register_write(
callback_name, kafka_write,
}
if (conf != NULL)
rd_kafka_conf_destroy(conf);
- return (0);
+ return 0;
errout:
if (conf != NULL)
rd_kafka_conf_destroy(conf);
* know that they are sane. */
for (size_t i = 0; i < m->n_label; i++) {
char value[LABEL_VALUE_SIZE];
- ssnprintf(labels[i], LABEL_BUFFER_SIZE, "%s=\"%s\"", m->label[i]->name,
- escape_label_value(value, sizeof(value), m->label[i]->value));
+ snprintf(labels[i], LABEL_BUFFER_SIZE, "%s=\"%s\"", m->label[i]->name,
+ escape_label_value(value, sizeof(value), m->label[i]->value));
}
strjoin(buffer, buffer_size, labels, m->n_label, ",");
while (c_avl_iterator_next(iter, (void *)&unused_name, (void *)&fam) == 0) {
char line[1024]; /* 4x DATA_MAX_NAME_LEN? */
- ssnprintf(line, sizeof(line), "# HELP %s %s\n", fam->name, fam->help);
+ snprintf(line, sizeof(line), "# HELP %s %s\n", fam->name, fam->help);
buffer->append(buffer, strlen(line), (uint8_t *)line);
- ssnprintf(line, sizeof(line), "# TYPE %s %s\n", fam->name,
- (fam->type == IO__PROMETHEUS__CLIENT__METRIC_TYPE__GAUGE)
- ? "gauge"
- : "counter");
+ snprintf(line, sizeof(line), "# TYPE %s %s\n", fam->name,
+ (fam->type == IO__PROMETHEUS__CLIENT__METRIC_TYPE__GAUGE)
+ ? "gauge"
+ : "counter");
buffer->append(buffer, strlen(line), (uint8_t *)line);
for (size_t i = 0; i < fam->n_metric; i++) {
char timestamp_ms[24] = "";
if (m->has_timestamp_ms)
- ssnprintf(timestamp_ms, sizeof(timestamp_ms), " %" PRIi64,
- m->timestamp_ms);
+ snprintf(timestamp_ms, sizeof(timestamp_ms), " %" PRIi64,
+ m->timestamp_ms);
if (fam->type == IO__PROMETHEUS__CLIENT__METRIC_TYPE__GAUGE)
- ssnprintf(line, sizeof(line), "%s{%s} " GAUGE_FORMAT "%s\n", fam->name,
- format_labels(labels, sizeof(labels), m), m->gauge->value,
- timestamp_ms);
+ snprintf(line, sizeof(line), "%s{%s} " GAUGE_FORMAT "%s\n", fam->name,
+ format_labels(labels, sizeof(labels), m), m->gauge->value,
+ timestamp_ms);
else /* if (fam->type == IO__PROMETHEUS__CLIENT__METRIC_TYPE__COUNTER) */
- ssnprintf(line, sizeof(line), "%s{%s} %.0f%s\n", fam->name,
- format_labels(labels, sizeof(labels), m), m->counter->value,
- timestamp_ms);
+ snprintf(line, sizeof(line), "%s{%s} %.0f%s\n", fam->name,
+ format_labels(labels, sizeof(labels), m), m->counter->value,
+ timestamp_ms);
buffer->append(buffer, strlen(line), (uint8_t *)line);
}
c_avl_iterator_destroy(iter);
char server[1024];
- ssnprintf(server, sizeof(server), "\n# collectd/write_prometheus %s at %s\n",
- PACKAGE_VERSION, hostname_g);
+ snprintf(server, sizeof(server), "\n# collectd/write_prometheus %s at %s\n",
+ PACKAGE_VERSION, hostname_g);
buffer->append(buffer, strlen(server), (uint8_t *)server);
pthread_mutex_unlock(&metrics_lock);
msg->name = name;
char help[1024];
- ssnprintf(
+ snprintf(
help, sizeof(help),
"write_prometheus plugin: '%s' Type: '%s', Dstype: '%s', Dsname: '%s'",
vl->plugin, vl->type, DS_TYPE_TO_STRING(ds->ds[ds_index].type),
if (fd == -1)
continue;
+ int tmp = 1;
+ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp)) != 0) {
+ char errbuf[1024];
+ WARNING("write_prometheus: setsockopt(SO_REUSEADDR) failed: %s",
+ sstrerror(errno, errbuf, sizeof(errbuf)));
+ close(fd);
+ fd = -1;
+ continue;
+ }
+
if (bind(fd, ai->ai_addr, ai->ai_addrlen) != 0) {
close(fd);
fd = -1;
/* user data = */ NULL);
plugin_register_shutdown("write_prometheus", prom_shutdown);
}
-
-/* vim: set sw=2 sts=2 et fdm=marker : */