]> git.ipfire.org Git - collecty.git/commitdiff
sources: Add sources for IPv4 fragmentation information
authorMichael Tremer <michael.tremer@ipfire.org>
Sun, 5 Oct 2025 13:27:31 +0000 (13:27 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Sun, 5 Oct 2025 13:27:31 +0000 (13:27 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
Makefile.am
src/daemon/proto.c [new file with mode: 0644]
src/daemon/proto.h [new file with mode: 0644]
src/daemon/sources.c
src/daemon/sources/ipfrag4.c [new file with mode: 0644]
src/daemon/sources/ipfrag4.h [new file with mode: 0644]

index 58bd9cf5348fec7c29cfa0c5e580d7e2c44f6f6e..c581e96f27382036072897958955042e967978b8 100644 (file)
@@ -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 (file)
index 0000000..d655e73
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.       #
+#                                                                             #
+#############################################################################*/
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/queue.h>
+
+#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 (file)
index 0000000..cdf03bd
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.       #
+#                                                                             #
+#############################################################################*/
+
+#ifndef COLLECTY_PROTO_H
+#define COLLECTY_PROTO_H
+
+#include <stdint.h>
+
+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 */
index 5381b61ccf7e6c6916da05201735f09ba7ed11f8..423cda2a65c399a2784a65d765188f17dddb0dd1 100644 (file)
@@ -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 (file)
index 0000000..ca96dee
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.       #
+#                                                                             #
+#############################################################################*/
+
+#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 (file)
index 0000000..fb3c5d2
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.       #
+#                                                                             #
+#############################################################################*/
+
+#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 */