From: Michael Tremer Date: Sun, 5 Oct 2025 13:27:31 +0000 (+0000) Subject: sources: Add sources for IPv4 fragmentation information X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=72700e548c5f6a24cd7a8f249019490b5541b213;p=telemetry.git sources: Add sources for IPv4 fragmentation information Signed-off-by: Michael Tremer --- diff --git a/Makefile.am b/Makefile.am index 58bd9cf..c581e96 100644 --- a/Makefile.am +++ b/Makefile.am @@ -120,6 +120,8 @@ dist_collectyd_SOURCES = \ src/daemon/main.c \ src/daemon/proc.c \ src/daemon/proc.h \ + src/daemon/proto.c \ + src/daemon/proto.h \ src/daemon/queue.c \ src/daemon/queue.h \ src/daemon/source.c \ @@ -132,6 +134,8 @@ dist_collectyd_SOURCES = \ src/daemon/sources/contextswitches.h \ src/daemon/sources/df.c \ src/daemon/sources/df.h \ + src/daemon/sources/ipfrag4.c \ + src/daemon/sources/ipfrag4.h \ src/daemon/sources/loadavg.c \ src/daemon/sources/loadavg.h \ src/daemon/sources/memory.c \ diff --git a/src/daemon/proto.c b/src/daemon/proto.c new file mode 100644 index 0000000..d655e73 --- /dev/null +++ b/src/daemon/proto.c @@ -0,0 +1,292 @@ +/*############################################################################# +# # +# collecty - A system statistics collection daemon for IPFire # +# Copyright (C) 2025 IPFire Development Team # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +#############################################################################*/ + +#include +#include +#include +#include +#include + +#include "ctx.h" +#include "proto.h" + +typedef struct collecty_proto_object { + STAILQ_ENTRY(collecty_proto_object) nodes; + + // Protocol + char proto[8]; + + // Key + char key[64]; + + // Value + uint64_t value; +} collecty_proto_object; + +struct collecty_proto { + collecty_ctx* ctx; + int nrefs; + + // Objects + STAILQ_HEAD(objects, collecty_proto_object) objects; +}; + +static void collecty_proto_free(collecty_proto* self) { + struct collecty_proto_object* o = NULL; + + // Cleanup the objects + for (;;) { + o = STAILQ_FIRST(&self->objects); + if (!o) + break; + + // Remove the object from the objects + STAILQ_REMOVE_HEAD(&self->objects, nodes); + + // Free the object + free(o); + } + + if (self->ctx) + collecty_ctx_unref(self->ctx); + free(self); +} + +int collecty_proto_create(collecty_proto** proto, collecty_ctx* ctx) { + collecty_proto* self = NULL; + + // Allocate some memory + self = calloc(1, sizeof(*self)); + if (!self) + return -errno; + + // Initialize the reference counter + self->nrefs = 1; + + // Store a reference to the context + self->ctx = collecty_ctx_ref(ctx); + + // Initialize the objects + STAILQ_INIT(&self->objects); + + // Return the pointer + *proto = self; + return 0; +} + +collecty_proto* collecty_proto_ref(collecty_proto* self) { + ++self->nrefs; + return self; +} + +collecty_proto* collecty_proto_unref(collecty_proto* self) { + if (--self->nrefs > 0) + return self; + + collecty_proto_free(self); + return NULL; +} + +static int collecty_proto_set(collecty_proto* self, + const char* proto, const char* key, uint64_t value) { + collecty_proto_object* o = NULL; + int r; + + // Allocate a new object + o = calloc(1, sizeof(*o)); + if (!o) + return -errno; + + // Store proto + r = snprintf(o->proto, sizeof(o->proto), "%s", proto); + if (r < 0) + goto ERROR; + + // Store key + r = snprintf(o->key, sizeof(o->key), "%s", key); + if (r < 0) + goto ERROR; + + // Store value + o->value = value; + + // Append the object + STAILQ_INSERT_TAIL(&self->objects, o, nodes); + + // Log action + DEBUG(self->ctx, "Stored %s: %s = %lu\n", o->proto, o->key, o->value); + + // Done + return 0; + +ERROR: + if (o) + free(o); + + return r; +} + +static int collecty_proto_read_one(collecty_proto* self, char* keys, char* values) { + char* e = NULL; + char proto[8]; + uint64_t n; + int r = 0; + + // Keys + char* pk = NULL; + char* k = NULL; + + // Values + char* pv = NULL; + char* v = NULL; + + size_t l = strlen(keys); + + // Remove any trailing newlines + if (keys[l - 1] == '\n') + keys[l - 1] = '\0'; + + // Parse the protocol in keys + k = strtok_r(keys, ":", &pk); + if (!k) + return -errno; + + // Parse the protocol in values + v = strtok_r(values, ":", &pv); + if (!v) + return -errno; + + // Store the protocol + r = snprintf(proto, sizeof(proto), "%s", k); + if (r < 0) + return -errno; + + // Iterate over all values + for (;;) { + // Parse the key + k = strtok_r(NULL, " ", &pk); + if (!k) + break; + + // Parse the value + v = strtok_r(NULL, " ", &pv); + if (!v) + break; + + // Convert the value to integer + n = strtoul(v, &e, 10); + + // Check if we could parse the entire value + switch (*e) { + case '\0': + case '\n': + break; + + default: + return -EINVAL; + } + + // Store the value + r = collecty_proto_set(self, proto, k, n); + if (r < 0) + break; + } + + return r; +} + +int collecty_proto_read(collecty_proto* self, const char* path) { + char* line = NULL; + size_t length = 0; + FILE* f = NULL; + int r; + + // Open the file + f = fopen(path, "r"); + if (!f) { + ERROR(self->ctx, "Failed to open %s: %m\n", path); + r = -errno; + goto ERROR; + } + + // Count the lines + unsigned int lineno = 0; + char keys[4096]; + + // Iterate over all lines + for (;;) { + // Fetch the next line + r = getline(&line, &length, f); + if (r < 0) + break; + + // Even lines have the keys, odd lines have all the values + switch (lineno++ % 2) { + // Even line + case 0: + // Just store the keys + r = snprintf(keys, sizeof(keys), "%s", line); + if (r < 0) + goto ERROR; + break; + + // Odd line + case 1: + r = collecty_proto_read_one(self, keys, line); + if (r < 0) + goto ERROR; + break; + } + } + + // Success + r = 0; + +ERROR: + if (line) + free(line); + if (f) + fclose(f); + + return r; +} + +int collecty_proto_get(collecty_proto* self, + const char* proto, const char* key, uint64_t* value) { + collecty_proto_object* o = NULL; + + // Walk through all objects + STAILQ_FOREACH(o, &self->objects, nodes) { + // Protocol must match + if (strcmp(o->proto, proto) != 0) + continue; + + // Key must match + if (strcmp(o->key, key) != 0) + continue; + + // Return the value + *value = o->value; + return 0; + } + + // Return not found + return -ENOENT; +} diff --git a/src/daemon/proto.h b/src/daemon/proto.h new file mode 100644 index 0000000..cdf03bd --- /dev/null +++ b/src/daemon/proto.h @@ -0,0 +1,40 @@ +/*############################################################################# +# # +# collecty - A system statistics collection daemon for IPFire # +# Copyright (C) 2025 IPFire Development Team # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +#############################################################################*/ + +#ifndef COLLECTY_PROTO_H +#define COLLECTY_PROTO_H + +#include + +typedef struct collecty_proto collecty_proto; + +#include "ctx.h" + +int collecty_proto_create(collecty_proto** proto, collecty_ctx* ctx); + +collecty_proto* collecty_proto_ref(collecty_proto* self); +collecty_proto* collecty_proto_unref(collecty_proto* self); + +int collecty_proto_read(collecty_proto* self, const char* path); + +int collecty_proto_get(collecty_proto* self, + const char* proto, const char* key, uint64_t* value); + +#endif /* COLLECTY_PROTO_H */ diff --git a/src/daemon/sources.c b/src/daemon/sources.c index 5381b61..423cda2 100644 --- a/src/daemon/sources.c +++ b/src/daemon/sources.c @@ -31,6 +31,7 @@ #include "sources/conntrack.h" #include "sources/contextswitches.h" #include "sources/df.h" +#include "sources/ipfrag4.h" #include "sources/loadavg.h" #include "sources/memory.h" #include "sources/pressure-cpu.h" @@ -46,6 +47,7 @@ static const collecty_source_impl* source_impls[] = { &conntrack_source, &contextswitches_source, &df_source, + &ipfrag4_source, &loadavg_source, &memory_source, &pressure_cpu_source, diff --git a/src/daemon/sources/ipfrag4.c b/src/daemon/sources/ipfrag4.c new file mode 100644 index 0000000..ca96dee --- /dev/null +++ b/src/daemon/sources/ipfrag4.c @@ -0,0 +1,117 @@ +/*############################################################################# +# # +# collecty - A system statistics collection daemon for IPFire # +# Copyright (C) 2025 IPFire Development Team # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +#############################################################################*/ + +#include "../ctx.h" +#include "../proto.h" +#include "../source.h" +#include "ipfrag4.h" + +static int ipfrag4_collect(collecty_ctx* ctx, collecty_source* source) { + collecty_proto* proto = NULL; + uint64_t frags_oks; + uint64_t frags_fails; + uint64_t frags_creates; + uint64_t reasm_timeout; + uint64_t reasm_reqds; + uint64_t reasm_oks; + uint64_t reasm_fails; + int r; + + // Create the protocol parser + r = collecty_proto_create(&proto, ctx); + if (r < 0) + goto ERROR; + + // Read /proc/net/snmp + r = collecty_proto_read(proto, "/proc/net/snmp"); + if (r < 0) + goto ERROR; + + // Read /proc/net/snmp + r = collecty_proto_read(proto, "/proc/net/netstat"); + if (r < 0) + goto ERROR; + + // Fetch FragOKs + r = collecty_proto_get(proto, "Ip", "FragOKs", &frags_oks); + if (r < 0) + goto ERROR; + + // Fetch FragFails + r = collecty_proto_get(proto, "Ip", "FragFails", &frags_fails); + if (r < 0) + goto ERROR; + + // Fetch FragFails + r = collecty_proto_get(proto, "Ip", "FragFails", &frags_creates); + if (r < 0) + goto ERROR; + + // Fetch ReasmTimeout + r = collecty_proto_get(proto, "Ip", "ReasmTimeout", &reasm_timeout); + if (r < 0) + goto ERROR; + + // Fetch ReasmReqds + r = collecty_proto_get(proto, "Ip", "ReasmReqds", &reasm_reqds); + if (r < 0) + goto ERROR; + + // Fetch ReasmOKs + r = collecty_proto_get(proto, "Ip", "ReasmOKs", &reasm_oks); + if (r < 0) + goto ERROR; + + // Fetch ReasmFails + r = collecty_proto_get(proto, "Ip", "ReasmFails", &reasm_fails); + if (r < 0) + goto ERROR; + + // Submit the values + r = collecty_source_submit(source, NULL, + "%lu:%lu:%lu:%lu:%lu:%lu:%lu", frags_oks, frags_fails, frags_creates, + reasm_timeout, reasm_reqds, reasm_oks, reasm_fails); + +ERROR: + if (proto) + collecty_proto_unref(proto); + + return r; +} + +const collecty_source_impl ipfrag4_source = { + .name = "ipfrag4", + + // RRD Data Sources + .rrd_dss = { + // Memory + { "ip4_frags_oks", "DERIVE", 0, -1, }, + { "ip4_frags_fails", "DERIVE", 0, -1, }, + { "ip4_frags_creates", "DERIVE", 0, -1, }, + { "ip4_reasm_timeout", "DERIVE", 0, -1, }, + { "ip4_reasm_reqds", "DERIVE", 0, -1, }, + { "ip4_reasm_oks", "DERIVE", 0, -1, }, + { "ip4_reasm_fails", "DERIVE", 0, -1, }, + { NULL }, + }, + + // Methods + .collect = ipfrag4_collect, +}; diff --git a/src/daemon/sources/ipfrag4.h b/src/daemon/sources/ipfrag4.h new file mode 100644 index 0000000..fb3c5d2 --- /dev/null +++ b/src/daemon/sources/ipfrag4.h @@ -0,0 +1,28 @@ +/*############################################################################# +# # +# collecty - A system statistics collection daemon for IPFire # +# Copyright (C) 2025 IPFire Development Team # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +#############################################################################*/ + +#ifndef COLLECTY_SOURCE_IPFRAG4_H +#define COLLECTY_SOURCE_IPFRAG4_H + +#include "../source.h" + +extern const collecty_source_impl ipfrag4_source; + +#endif /* COLLECTY_SOURCE_IPFRAG4_H */