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 \
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 \
--- /dev/null
+/*#############################################################################
+# #
+# 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;
+}
--- /dev/null
+/*#############################################################################
+# #
+# 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 */
#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"
&conntrack_source,
&contextswitches_source,
&df_source,
+ &ipfrag4_source,
&loadavg_source,
&memory_source,
&pressure_cpu_source,
--- /dev/null
+/*#############################################################################
+# #
+# 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,
+};
--- /dev/null
+/*#############################################################################
+# #
+# 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 */