listen/all.mk \
process/all.mk \
modules/all.mk \
- bin/all.mk
+ bin/all.mk \
+ stats/all.mk
#
# The default is to just build the source code. We skip running the
RADICT_OUT_DICT,
RADICT_OUT_STRUCT,
RADICT_OUT_STATS_LINK,
- RADICT_OUT_ATTRS_H,
RADICT_OUT_BASE_C_DA_DEF,
RADICT_OUT_ATTR_AUTOLOAD,
RADICT_OUT_STATS_H,
fprintf(fp, "_t;\n");
}
-static void da_print_attr_def(FILE *fp, fr_dict_attr_t const *parent, char const *prefix)
+static void da_print_base_c_da_def(FILE *fp, fr_dict_attr_t const *parent)
{
int i;
fr_dict_attr_t const *da;
da_normalize_name(parent, parent_name);
- fprintf(fp, "%sfr_dict_attr_t const *attr_%s;\n", prefix, parent_name);
+ fprintf(fp, "static fr_dict_attr_t const *attr_%s;\n", parent_name);
for (i = 1; (da = fr_dict_attr_child_by_num(parent, i)) != NULL; i++) {
- fprintf(fp, "%sfr_dict_attr_t const *attr_%s_", prefix, parent_name);
+ fprintf(fp, "static fr_dict_attr_t const *attr_%s_", parent_name);
da_print_name(fp, da);
fprintf(fp, ";\n");
}
fprintf(fp, "\n\n");
}
-static void da_print_attrs_h(FILE *fp, fr_dict_attr_t const *parent)
-{
- da_print_attr_def(fp, parent, "extern HIDDEN ");
-}
-
-static void da_print_base_c_da_def(FILE *fp, fr_dict_attr_t const *parent)
-{
- da_print_attr_def(fp, parent, "");
-}
/** Map data types to enum names representing those types
*/
}
fprintf(fp, "\t.num_elements = %d,\n", num_elements);
- fprintf(fp, "\t.entry = (fr_stats_link_entry_t[]) { /* -Wgnu-flexible-array-initializer */\n");
+ fprintf(fp, "\t.entry = {\n");
/*
* For locality, also print out data type and size. That way we _can_ dereference the da, but we
fprintf(fp, "\n");
+ fprintf(fp, "FR_STATS_TYPEDEF(%s_%s);\n\n", dict_name, parent_name);
+
fprintf(fp, "extern fr_stats_link_t const fr_stats_link_%s_%s;\n\n", dict_name, parent_name);
}
{ L("dict"), RADICT_OUT_DICT },
{ L("struct"), RADICT_OUT_STRUCT },
{ L("stats_link"), RADICT_OUT_STATS_LINK },
- { L("attrs.h"), RADICT_OUT_ATTRS_H },
{ L("da_def"), RADICT_OUT_BASE_C_DA_DEF },
{ L("attr_autoload"), RADICT_OUT_ATTR_AUTOLOAD },
{ L("stats.h"), RADICT_OUT_STATS_H },
{ L("dict"), NULL },
{ L("struct"), (void *) da_print_struct },
{ L("stats_link"), (void *) da_print_stats_link },
- { L("attrs.h"), (void *) da_print_attrs_h },
{ L("da_def"), (void *) da_print_base_c_da_def },
{ L("attr_autoload"), (void *) da_print_attr_autoload },
{ L("stats.h"), (void *) da_print_stats_h },
uint8_t stats[]; //!< generic statistics data
} fr_stats_instance_t;
-/** Macro to define a typedef for a particular kind of statistics
+/** Iterator for a statistics structure.
*
+ * This is used internally, and there's no real need for code outside of the statistics library to use it.
*/
-#define FR_STATS_TYPEDEF(_name, _type) \
+typedef struct {
+ fr_stats_instance_t const *inst;
+ unsigned int current;
+} fr_stats_iter_t;
+
+
+/** Macro to define a typedef for a particular instance of statistics
+ *
+ * Defines fr_stats_name_instance_t which contains an instance of the statistics for fr_stats_name_t, and
+ * which points to the linking structure fr_stats_link_name_t.
+ *
+ * Note that nothing needs to refer to the base statistics structure: fr_stats_name_t. All of that is
+ * wrapped in an instance definition.
+ *
+ * This is used internally, and there's no real need for code outside of the statistics library to use it.
+ */
+#define FR_STATS_TYPEDEF(_name) \
typedef struct { \
STATS_HEADER_COMMON; \
- _type stats; \
- } fr_stats_## _name ## _instance_t
+ fr_stats_ ## _name ## _t stats; \
+ } fr_stats_ ## _name ## _instance_t
-/** Macro used when declaring a variable which contains the statistics
+/** Macro used when referencing a linking structure
+ *
+ * .def = FR_STATS_LINK_NAME(radius_auth_serv),
*
+ * This is used internally, and there's no real need for code outside of the statistics library to use it.
*/
-#define FR_STATS_ENTRY_DECL(_name, _var) fr_stats_## _name ## _instance_t _var;
+#define FR_STATS_LINK_NAME(_name) fr_stats_link_ ## _name ## _t
-/** Macro used when initializing a variable which contains the statistics
+/** Macro used when declaring a variable which contains an instance of the statistics
+ *
+ * Defines "fr_stats_name_instance_t var", which can be used in a structure
*
+ * Code which needs to use some statistics can use this macro to declare a variable which contains stats for
+ * the local module / etc.
+ */
+#define FR_STATS_ENTRY_DECL(_name, _var) fr_stats_ ## _name ## _instance_t _var
+
+/** Macro used when initializing a variable which contains an instance of the statistics
+ *
+ * var = .... initializer for the stats instance ...
+ *
+ * Code which needs to use some statistics can use this macro to initialize a variable which contains stats
+ * for the local module / etc.
*/
#define FR_STATS_ENTRY_INIT(_name, _var, _mib) \
- _var = (fr_stats_## _name ## _instance_t) { \
+ _var = (fr_stats_ ## _name ## _instance_t) { \
.def = fr_stats_link_ ## _name ## _t, \
.mib = _mib, \
- fr_stats_## _name ## _t stats = {}, \
+ fr_stats_ ## _name ## _t stats = {}, \
}
-
-/** Macro used when referencing a linking structure
- *
- * .def = FR_STATS_LINK_NAME(radius_auth_serv),
- */
-#define FR_STATS_LINK_NAME(_name) fr_stats_link_ ## _name ## _t
/** Macro used to increment one field in the statistics structure
*
+ * Code which needs to update some statistics can use this macro to increment a variable which contains
+ * stats for the local module / etc.
*/
-#define FR_STATS_INC(_var, _field) _var->stats._field++
+#define FR_STATS_INC(_var, _field) ((_var)->stats.(_field))++
-typedef struct {
- fr_stats_instance_t const *inst;
- unsigned int current;
-} fr_stats_iter_t;
+/** Macro used to reference a field in the statistics structure
+ *
+ * Code which needs to mangle a field of the statistics can use this macro to get the correct field name.
+ */
+#define FR_STATS_FIELD(_var, _field) (_var)->stats.(_field)
int fr_stats_to_pairs(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_stats_instance_t const *in) CC_HINT(nonnull);
int fr_stats_from_pairs(TALLOC_CTX *ctx, fr_stats_instance_t *out, fr_pair_list_t *in) CC_HINT(nonnull);
--- /dev/null
+RADICT := $(BUILD_DIR)/make/jlibtool --silent --mode=execute $(BUILD_DIR)/bin/local/radict -D share/dictionary
+
+#
+# $(eval $(call DICT_STATS,radius,auth_serv,mib-2.radiusAuthServ,1.3.6.1.2.1.67.1.1.1.1))
+#
+# We don't want the outputs to be updated if the build fails. So we use an intermediate filename.
+# And we use ".cache", because that's ignored by the top level ".gitignore"
+#
+define DICT_STATS
+
+#
+# Re-build the files if the dictionary changes.
+#
+# Ensure that the protocol library is built before the statistics
+# library, as radict needs it.
+#
+# Ensure that radict is built before the statistics library, as we
+# run radict to generate the output files.
+#
+
+#
+# Define the structures and declare the extern variables
+#
+src/stats/${1}/${2}_stats.h: share/dictionary/${1}/dictionary.stats $(BUILD_DIR)/lib/local/libfreeradius-${1}.la $(BUILD_DIR)/bin/local/radict$(E)
+ @echo STATS ${1} ${2} - structs
+ ${Q}$(RADICT) -F stats.h -M ${4} -p ${1} ${3} > $$@.cache && mv $$@.cache $$@
+
+#
+# define the "attr_foo" definitions for the dictionary autoload to populate
+#
+src/stats/${1}/${2}_da_def.c: share/dictionary/${1}/dictionary.stats $(BUILD_DIR)/lib/local/libfreeradius-${1}.la $(BUILD_DIR)/bin/local/radict$(E)
+ @echo STATS ${1} ${2} - define variables
+ ${Q}$(RADICT) -F da_def -M ${4} -p ${1} ${3} > $$@.cache && mv $$@.cache $$@
+
+#
+# define the autoload structures which point to the "attr_foo" defintions
+#
+src/stats/${1}/${2}_da_autoload.c: share/dictionary/${1}/dictionary.stats $(BUILD_DIR)/lib/local/libfreeradius-${1}.la $(BUILD_DIR)/bin/local/radict$(E)
+ @echo STATS ${1} ${2} - autoload
+ ${Q}$(RADICT) -F attr_autoload -M ${4} -p ${1} ${3} > $$@.cache && mv $$@.cache $$@
+
+#
+# define the linking structure between the statistics structure and the DAs.
+#
+src/stats/${1}/${2}_stats.c: share/dictionary/${1}/dictionary.stats $(BUILD_DIR)/lib/local/libfreeradius-${1}.la $(BUILD_DIR)/bin/local/radict$(E)
+ @echo STATS ${1} ${2} - link
+ ${Q}$(RADICT) -F stats_link -M ${4} -p ${1} ${3} > $$@.cache && mv $$@.cache $$@
+
+#
+# The output OBJ has to be rebuilt if any of the input files have changed.
+#
+$(BUILD_DIR)/objs/src/stats/${1}/base.${OBJ_EXT}: src/stats/${1}/${2}_stats.h src/stats/${1}/${2}_da_def.c src/stats/${1}/${2}_da_autoload.c src/stats/${1}/${2}_stats.c
+
+endef
+
+SUBMAKEFILES := $(wildcard ${top_srcdir}/src/stats/*/all.mk)
--- /dev/null
+#
+# Makefile
+#
+# Version: $Id$
+#
+TARGET := libfreeradius-radius-stats$(L)
+
+SOURCES := base.c
+
+TGT_PREREQS := libfreeradius-util$(L) libfreeradius-radius$(L)
+
+TGT_POSTCLEAN := $(wildcard src/stats/radius/*.cache)
+
+$(eval $(call DICT_STATS,radius,auth_serv,mib-2.radiusAuthServ,1.3.6.1.2.1.67.1.1.1.1))
--- /dev/null
+{ .out = &attr_auth_serv, .name = "mib-2.radiusAuthServ", .type = FR_TYPE_TLV, .dict = &dict_radius },
+{ .out = &attr_auth_serv_ident, .name = ".radiusAuthServIdent", .type = FR_TYPE_STRING, .dict = &dict_radius },
+{ .out = &attr_auth_serv_up_time, .name = ".radiusAuthServUpTime", .type = FR_TYPE_TIME_DELTA, .dict = &dict_radius },
+{ .out = &attr_auth_serv_reset_time, .name = ".radiusAuthServResetTime", .type = FR_TYPE_TIME_DELTA, .dict = &dict_radius },
+{ .out = &attr_auth_serv_config_reset, .name = ".radiusAuthServConfigReset", .type = FR_TYPE_UINT32, .dict = &dict_radius },
+{ .out = &attr_auth_serv_total_access_requests, .name = ".radiusAuthServTotalAccessRequests", .type = FR_TYPE_UINT32, .dict = &dict_radius },
+{ .out = &attr_auth_serv_total_invalid_requests, .name = ".radiusAuthServTotalInvalidRequests", .type = FR_TYPE_UINT32, .dict = &dict_radius },
+{ .out = &attr_auth_serv_total_dup_access_requests, .name = ".radiusAuthServTotalDupAccessRequests", .type = FR_TYPE_UINT32, .dict = &dict_radius },
+{ .out = &attr_auth_serv_total_access_accepts, .name = ".radiusAuthServTotalAccessAccepts", .type = FR_TYPE_UINT32, .dict = &dict_radius },
+{ .out = &attr_auth_serv_total_access_rejects, .name = ".radiusAuthServTotalAccessRejects", .type = FR_TYPE_UINT32, .dict = &dict_radius },
+{ .out = &attr_auth_serv_total_access_challenges, .name = ".radiusAuthServTotalAccessChallenges", .type = FR_TYPE_UINT32, .dict = &dict_radius },
+{ .out = &attr_auth_serv_total_malformed_access_requests, .name = ".radiusAuthServTotalMalformedAccessRequests", .type = FR_TYPE_UINT32, .dict = &dict_radius },
+{ .out = &attr_auth_serv_total_bad_authenticators, .name = ".radiusAuthServTotalBadAuthenticators", .type = FR_TYPE_UINT32, .dict = &dict_radius },
+{ .out = &attr_auth_serv_total_packets_dropped, .name = ".radiusAuthServTotalPacketsDropped", .type = FR_TYPE_UINT32, .dict = &dict_radius },
+{ .out = &attr_auth_serv_total_unknown_types, .name = ".radiusAuthServTotalUnknownTypes", .type = FR_TYPE_UINT32, .dict = &dict_radius },
+
+
--- /dev/null
+static fr_dict_attr_t const *attr_auth_serv;
+static fr_dict_attr_t const *attr_auth_serv_ident;
+static fr_dict_attr_t const *attr_auth_serv_up_time;
+static fr_dict_attr_t const *attr_auth_serv_reset_time;
+static fr_dict_attr_t const *attr_auth_serv_config_reset;
+static fr_dict_attr_t const *attr_auth_serv_total_access_requests;
+static fr_dict_attr_t const *attr_auth_serv_total_invalid_requests;
+static fr_dict_attr_t const *attr_auth_serv_total_dup_access_requests;
+static fr_dict_attr_t const *attr_auth_serv_total_access_accepts;
+static fr_dict_attr_t const *attr_auth_serv_total_access_rejects;
+static fr_dict_attr_t const *attr_auth_serv_total_access_challenges;
+static fr_dict_attr_t const *attr_auth_serv_total_malformed_access_requests;
+static fr_dict_attr_t const *attr_auth_serv_total_bad_authenticators;
+static fr_dict_attr_t const *attr_auth_serv_total_packets_dropped;
+static fr_dict_attr_t const *attr_auth_serv_total_unknown_types;
+
+
--- /dev/null
+fr_stats_link_t const fr_stats_link_radius_auth_serv = {
+ .name = "fr_stats_radius_auth_serv_t",
+ .root_p = &attr_auth_serv,
+ .mib = "1.3.6.1.2.1.67.1.1.1.1",
+ .size = sizeof(fr_stats_radius_auth_serv_t),
+ .num_elements = 14,
+ .entry = {
+ {
+ .da_p = &attr_auth_serv_ident,
+ .type = FR_TYPE_STRING,
+ .offset = offsetof(fr_stats_radius_auth_serv_t, ident),
+ .size = 0,
+ },
+ {
+ .da_p = &attr_auth_serv_up_time,
+ .type = FR_TYPE_TIME_DELTA,
+ .offset = offsetof(fr_stats_radius_auth_serv_t, up_time),
+ .size = 4,
+ },
+ {
+ .da_p = &attr_auth_serv_reset_time,
+ .type = FR_TYPE_TIME_DELTA,
+ .offset = offsetof(fr_stats_radius_auth_serv_t, reset_time),
+ .size = 4,
+ },
+ {
+ .da_p = &attr_auth_serv_config_reset,
+ .type = FR_TYPE_UINT32,
+ .offset = offsetof(fr_stats_radius_auth_serv_t, config_reset),
+ .size = 4,
+ },
+ {
+ .da_p = &attr_auth_serv_total_access_requests,
+ .type = FR_TYPE_UINT32,
+ .offset = offsetof(fr_stats_radius_auth_serv_t, total_access_requests),
+ .size = 4,
+ },
+ {
+ .da_p = &attr_auth_serv_total_invalid_requests,
+ .type = FR_TYPE_UINT32,
+ .offset = offsetof(fr_stats_radius_auth_serv_t, total_invalid_requests),
+ .size = 4,
+ },
+ {
+ .da_p = &attr_auth_serv_total_dup_access_requests,
+ .type = FR_TYPE_UINT32,
+ .offset = offsetof(fr_stats_radius_auth_serv_t, total_dup_access_requests),
+ .size = 4,
+ },
+ {
+ .da_p = &attr_auth_serv_total_access_accepts,
+ .type = FR_TYPE_UINT32,
+ .offset = offsetof(fr_stats_radius_auth_serv_t, total_access_accepts),
+ .size = 4,
+ },
+ {
+ .da_p = &attr_auth_serv_total_access_rejects,
+ .type = FR_TYPE_UINT32,
+ .offset = offsetof(fr_stats_radius_auth_serv_t, total_access_rejects),
+ .size = 4,
+ },
+ {
+ .da_p = &attr_auth_serv_total_access_challenges,
+ .type = FR_TYPE_UINT32,
+ .offset = offsetof(fr_stats_radius_auth_serv_t, total_access_challenges),
+ .size = 4,
+ },
+ {
+ .da_p = &attr_auth_serv_total_malformed_access_requests,
+ .type = FR_TYPE_UINT32,
+ .offset = offsetof(fr_stats_radius_auth_serv_t, total_malformed_access_requests),
+ .size = 4,
+ },
+ {
+ .da_p = &attr_auth_serv_total_bad_authenticators,
+ .type = FR_TYPE_UINT32,
+ .offset = offsetof(fr_stats_radius_auth_serv_t, total_bad_authenticators),
+ .size = 4,
+ },
+ {
+ .da_p = &attr_auth_serv_total_packets_dropped,
+ .type = FR_TYPE_UINT32,
+ .offset = offsetof(fr_stats_radius_auth_serv_t, total_packets_dropped),
+ .size = 4,
+ },
+ {
+ .da_p = &attr_auth_serv_total_unknown_types,
+ .type = FR_TYPE_UINT32,
+ .offset = offsetof(fr_stats_radius_auth_serv_t, total_unknown_types),
+ .size = 4,
+ },
+ },
+};
+
--- /dev/null
+/*
+ * radiusAuthServ
+ */
+typedef struct {
+ char *ident;
+ fr_time_delta_t up_time;
+ fr_time_delta_t reset_time;
+ uint32_t config_reset;
+ uint32_t total_access_requests;
+ uint32_t total_invalid_requests;
+ uint32_t total_dup_access_requests;
+ uint32_t total_access_accepts;
+ uint32_t total_access_rejects;
+ uint32_t total_access_challenges;
+ uint32_t total_malformed_access_requests;
+ uint32_t total_bad_authenticators;
+ uint32_t total_packets_dropped;
+ uint32_t total_unknown_types;
+} fr_stats_radius_auth_serv_t;
+
+FR_STATS_TYPEDEF(radius_auth_serv);
+
+extern fr_stats_link_t const fr_stats_link_radius_auth_serv;
+
--- /dev/null
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * $Id$
+ *
+ * @file protocols/radius/stats/stats.c
+ * @brief Functions for RADIUS statistics
+ *
+ * @copyright 2026 Network RADIUS SAS (legal@networkradius.com)
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/util/dict.h>
+#include "stats.h"
+
+static fr_dict_t const *dict_radius;
+
+/*
+ * static fr_dict_attr_t const *attr_foo;
+ */
+#include "auth_serv_da_def.c"
+
+extern fr_dict_autoload_t libfreeradius_radius_stats_dict[];
+fr_dict_autoload_t libfreeradius_radius_stats_dict[] = {
+ { .out = &dict_radius, .proto = "radius" },
+
+ DICT_AUTOLOAD_TERMINATOR
+};
+
+extern fr_dict_attr_autoload_t libfreeradius_radius_stats_dict_attr[];
+fr_dict_attr_autoload_t libfreeradius_radius_stats_dict_attr[] = {
+
+#include "auth_serv_da_autoload.c"
+
+ DICT_AUTOLOAD_TERMINATOR
+};
+
+/*
+ * Clang accepts this DIAG, but complains about the code unless we have it.
+ *
+ * GCC doesn't accept this DIAG, but doesn't complain about the code.
+ */
+#if defined(__clang__)
+DIAG_OFF(gnu-flexible-array-initializer)
+#endif
+
+/*
+ * Define the fr_stats_link_t for the statistics data structures.
+ */
+#include "auth_serv_stats.c"
--- /dev/null
+#pragma once
+/*
+ * 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 2 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/*
+ * $Id$
+ *
+ * @file protocols/radius/stats/stats.h
+ * @brief Structures and prototypes for RADIUS statistics
+ *
+ * @copyright 2026 Network RADIUS SAS (legal@networkradius.com)
+ */
+#include <freeradius-devel/util/stats.h>
+
+/*
+ * The included file defines:
+ *
+ * fr_stats_radius_auth_serv_t - the base statistics structure
+ *
+ * fr_stats_link_radius_auth_serv - the structure linking the base stats structure to the dictionary
+ * attributes.
+ *
+ * fr_stats_radius_auth_serv_t
+ */
+#include "auth_serv_stats.h"