*q = '\0';
}
-static void da_print_name(fr_dict_attr_t const *da)
+static void da_print_name(FILE *fp, fr_dict_attr_t const *da)
{
char buffer[FR_DICT_ATTR_MAX_NAME_LEN + 1];
da_normalize_name(da, buffer);
- printf("%s", buffer);
+ fprintf(fp, "%s", buffer);
}
+static const bool type_allowed[FR_TYPE_MAX] = {
+ [FR_TYPE_STRING] = true,
+ [FR_TYPE_OCTETS] = true,
+
+ [FR_TYPE_UINT16] = true,
+ [FR_TYPE_UINT32] = true,
+ [FR_TYPE_UINT64] = true,
+
+ [FR_TYPE_IPV4_ADDR] = true,
+ [FR_TYPE_IPV6_ADDR] = true,
+
+ [FR_TYPE_DATE] = true,
+ [FR_TYPE_TIME_DELTA] = true,
+
+};
+
+static bool children_ok(fr_dict_attr_t const *parent)
+{
+ int i;
+ fr_dict_attr_t const *da;
+
+ for (i = 1; (da = fr_dict_attr_child_by_num(parent, i)) != NULL; i++) {
+ if (!type_allowed[da->type]) return false;
+ }
+
+ return true;
+}
+
+#define CHECK_TYPE(_parent) \
+do { \
+ if ((parent->type != FR_TYPE_STRUCT) && (parent->type != FR_TYPE_TLV)) { \
+ fprintf(stderr, "%s is not a struct or tlv\n", parent->name); \
+ return; \
+ } \
+ if (!children_ok(parent)) fr_exit(EXIT_FAILURE); \
+} while (0)
+
/** Print structures and mappings, mainly for statistics.
*/
-static void da_print_struct(fr_dict_attr_t const *parent)
+static void da_print_struct(FILE *fp, fr_dict_attr_t const *parent)
{
int i;
fr_dict_attr_t const *da;
- if (parent->type != FR_TYPE_STRUCT) {
- fprintf(stderr, "%s is not a struct\n", parent->name);
- return;
- }
+ CHECK_TYPE(parent);
/*
* @todo - print full OID path and filename?
*/
- printf("/*\n *\t%s\n */\n", parent->name);
- printf("typedef struct {\n");
+ fprintf(fp, "/*\n *\t%s\n */\n", parent->name);
+ fprintf(fp, "typedef struct {\n");
for (i = 1; (da = fr_dict_attr_child_by_num(parent, i)) != NULL; i++) {
unsigned int length = 0;
* this is via a separate function that we call. But this shouldn't be necessary
* for statistics structures, as they shouldn't contain bitfields.
*/
- printf("\tunsigned int : %u\t", da->flags.length);
+ fprintf(fp, "\tunsigned int : %u\t", da->flags.length);
} else switch (da->type) {
case FR_TYPE_STRING:
+ if ((parent->type == FR_TYPE_TLV) && !da->flags.length) {
+ fprintf(fp, "\t%s\t*", type_to_c_type[da->type]);
+ break;
+ }
+ FALL_THROUGH;
+
case FR_TYPE_OCTETS:
fr_assert(da->flags.length > 0);
length = da->flags.length;
- printf("\t%s\t", type_to_c_type[da->type]);
+ fprintf(fp, "\t%s\t", type_to_c_type[da->type]);
break;
case FR_TYPE_DATE:
fr_assert(da->flags.length <= 8);
fr_assert(length_to_c_type[da->flags.length] != NULL);
- printf("\t%s\t", length_to_c_type[da->flags.length]);
+ fprintf(fp, "\t%s\t", length_to_c_type[da->flags.length]);
break;
default:
fr_assert(type_to_c_type[da->type] != NULL);
- printf("\t%s\t", type_to_c_type[da->type]);
+ fprintf(fp, "\t%s\t", type_to_c_type[da->type]);
break;
}
- da_print_name(da);
+ da_print_name(fp, da);
if (length) {
- printf("[%u]", length);
+ fprintf(fp, "[%u]", length);
}
- printf(";\n");
- }
-
- printf("} ");
-
- printf("fr_");
- da_print_name(fr_dict_root(parent->dict));
- printf("_");
- da_print_name(parent);
- printf("_t;\n");
-}
-
-static void da_print_stats_link(fr_dict_attr_t const *parent)
-{
- int i;
- fr_dict_attr_t const *da;
- char dict_name[FR_DICT_ATTR_MAX_NAME_LEN + 1];
- char parent_name[FR_DICT_ATTR_MAX_NAME_LEN + 1];
-
- if (parent->type != FR_TYPE_STRUCT) {
- fprintf(stderr, "%s is not a struct\n", parent->name);
- return;
+ fprintf(fp, ";\n");
}
- da_normalize_name(fr_dict_root(parent->dict), dict_name);
- da_normalize_name(parent, parent_name);
-
- printf("fr_stats_link_t const fr_%s_%s_stats_link_t[] = {\n", dict_name, parent_name);
-
- for (i = 1; (da = fr_dict_attr_child_by_num(parent, i)) != NULL; i++) {
- printf("\t{ &attr_%s_", parent_name);
- da_print_name(da);
- printf(", offsetof(fr_%s_%s_t, ", dict_name, parent_name);
- da_print_name(da);
- printf(") },\n");
- }
+ fprintf(fp, "} ");
- printf("};\n\n");
+ fprintf(fp, "fr_");
+ da_print_name(fp, fr_dict_root(parent->dict));
+ fprintf(fp, "_");
+ da_print_name(fp, parent);
+ fprintf(fp, "_t;\n");
}
-static void da_print_attr_def(fr_dict_attr_t const *parent)
+static void da_print_attr_def(FILE *fp, fr_dict_attr_t const *parent)
{
int i;
fr_dict_attr_t const *da;
char parent_name[FR_DICT_ATTR_MAX_NAME_LEN + 1];
- if (parent->type != FR_TYPE_STRUCT) {
- fprintf(stderr, "%s is not a struct\n", parent->name);
- return;
- }
+ CHECK_TYPE(parent);
da_normalize_name(parent, parent_name);
- printf("static fr_dict_attr_t const *attr_%s;\n", 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++) {
- printf("static fr_dict_attr_t const *attr_%s_", parent_name);
- da_print_name(da);
- printf(";\n");
+ fprintf(fp, "static fr_dict_attr_t const *attr_%s_", parent_name);
+ da_print_name(fp, da);
+ fprintf(fp, ";\n");
}
- printf("\n\n");
+ fprintf(fp, "\n\n");
}
/** Map data types to enum names representing those types
ENUM_NAME(FR_TYPE_ATTR),
};
-static void da_print_attr_autoload(fr_dict_attr_t const *parent)
+static void da_print_stats_link(FILE *fp, fr_dict_attr_t const *parent)
{
- int i;
+ int i, num_elements = 0;
fr_dict_attr_t const *da;
char dict_name[FR_DICT_ATTR_MAX_NAME_LEN + 1];
char parent_name[FR_DICT_ATTR_MAX_NAME_LEN + 1];
- if (parent->type != FR_TYPE_STRUCT) {
- fprintf(stderr, "%s is not a struct\n", parent->name);
- return;
+ CHECK_TYPE(parent);
+
+ da_normalize_name(fr_dict_root(parent->dict), dict_name);
+ da_normalize_name(parent, parent_name);
+
+ fprintf(fp, "fr_stats_link_t const fr_%s_%s_stats_link_t[] = {\n", dict_name, parent_name);
+
+ fprintf(fp, "\t.name = \"fr_%s_%s_t\",\n", dict_name, parent_name);
+ fprintf(fp, "\t.da_p = &attr_%s,\n", parent_name);
+ fprintf(fp, "\t.size = sizeof(fr_%s_%s_t),\n", dict_name, parent_name);
+
+ for (i = 1; fr_dict_attr_child_by_num(parent, i) != NULL; i++) {
+ num_elements = i;
+ }
+ fprintf(fp, "\t.num_elements = %d,\n", num_elements);
+
+ fprintf(fp, "\t.entry = {\n");
+
+ /*
+ * For locality, also print out data type and size. That way we _can_ dereference the da, but we
+ * don't _need_ to.
+ */
+ for (i = 1; (da = fr_dict_attr_child_by_num(parent, i)) != NULL; i++) {
+ fprintf(fp, "\t\t{\n");
+ fprintf(fp, "\t\t\t.da_p = &attr_%s_", parent_name);
+ da_print_name(fp, da);
+ fprintf(fp, ",\n");
+
+ fprintf(fp, "\t\t\t.type = %s,\n", fr_type_to_enum_name[da->type]);
+
+ fprintf(fp, "\t\t\t.offset = offsetof(fr_%s_%s_t, ", dict_name, parent_name);
+ da_print_name(fp, da);
+ fprintf(fp, "),\n");
+
+ fprintf(fp, "\t\t\t.size = %u,\n", da->flags.length);
+
+ fprintf(fp, "\t\t},\n");
}
+ fprintf(fp, "\t};\n");
+ fprintf(fp, "};\n\n");
+}
+
+static void da_print_attr_autoload(FILE *fp, fr_dict_attr_t const *parent)
+{
+ int i;
+ fr_dict_attr_t const *da;
+ char dict_name[FR_DICT_ATTR_MAX_NAME_LEN + 1];
+ char parent_name[FR_DICT_ATTR_MAX_NAME_LEN + 1];
+
+ CHECK_TYPE(parent);
+
da_normalize_name(fr_dict_root(parent->dict), dict_name);
da_normalize_name(parent, parent_name);
*
* @todo - print the enum for the data type
*/
- printf("{ .out = &attr_%s, .name = \"%s\", .type = %s, .dict = &dict_%s },\n",
+ fprintf(fp, "{ .out = &attr_%s, .name = \"%s\", .type = %s, .dict = &dict_%s },\n",
parent_name, parent->name, fr_type_to_enum_name[parent->type], dict_name);
for (i = 1; (da = fr_dict_attr_child_by_num(parent, i)) != NULL; i++) {
- printf("{ .out = &attr_%s_", parent_name);
- da_print_name(da);
- printf(", .name = \".%s\", .type = %s, .dict = &dict_%s },\n",
+ fprintf(fp, "{ .out = &attr_%s_", parent_name);
+ da_print_name(fp, da);
+ fprintf(fp, ", .name = \".%s\", .type = %s, .dict = &dict_%s },\n",
da->name, fr_type_to_enum_name[da->type], dict_name);
}
- printf("\n\n");
+ fprintf(fp, "\n\n");
}
static void _raddict_export(fr_dict_t const *dict, uint64_t *count, uintptr_t *low, uintptr_t *high, fr_dict_attr_t const *da, unsigned int lvl)
break;
case RADICT_OUT_STRUCT:
- da_print_struct(da);
+ da_print_struct(stdout, da);
break;
case RADICT_OUT_STATS_LINK:
- da_print_stats_link(da);
+ da_print_stats_link(stdout, da);
break;
case RADICT_OUT_ATTR_DEF:
- da_print_attr_def(da);
+ da_print_attr_def(stdout, da);
break;
case RADICT_OUT_ATTR_AUTOLOAD:
- da_print_attr_autoload(da);
+ da_print_attr_autoload(stdout, da);
break;
}
found = true;
#include <freeradius-devel/util/stats.h>
-/** Define dictionary attributes for a given statistics structure.
+// convert a set of pairs to a struct
+
+/** Convert a statistics structure to #fr_pair_t
*
- * @param parent the parent attribute under which statistics are defined
- * @param stats the statistics mapping structure.
- * @return
- * - <0 on error
- * - 0 on success
*/
-int fr_stats_attr_init(fr_dict_attr_t *parent, fr_stats_struct_t const *stats)
+int fr_stats_to_pairs(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_stats_instance_t const *inst)
{
- fr_stats_entry_t const *entry;
- fr_dict_t *dict;
+ size_t i;
+ fr_stats_link_t const *def = inst->def;
+ uint8_t const *in = inst->stats;
+ fr_pair_t *parent, *vp;
+
+ parent = fr_pair_afrom_da(ctx, *(def->root_p));
+ if (!parent) return -1;
+
+ for (i = 0; i < def->num_elements; i++) {
+ uint8_t const *field;
+
+ vp = fr_pair_afrom_da(parent, *(def->entry[i].da_p));
+ if (!vp) goto fail;
+
+ field = ((uint8_t const *) in) + def->entry[i].offset;
+
+ /*
+ * Strings of length 0 are "const char *".
+ *
+ * Everything else is an in-line field.
+ */
+ switch (def->entry[i].type) {
+ case FR_TYPE_STRING:
+ if (!def->entry[i].size) {
+ char const *str;
+
+ memcpy(&str, field, sizeof(str));
+
+ if (fr_pair_value_strdup(vp, str, false) < 0) goto fail;
+ break;
+ }
+ FALL_THROUGH;
+
+ case FR_TYPE_OCTETS:
+ case FR_TYPE_UINT16:
+ case FR_TYPE_UINT32:
+ case FR_TYPE_UINT64:
+ case FR_TYPE_IPV4_ADDR:
+ case FR_TYPE_IPV6_ADDR:
+ fr_assert(def->entry[i].size > 0);
+
+ if (fr_value_box_from_network(vp, &vp->data, def->entry[i].type, vp->da,
+ &FR_DBUFF_TMP(field, def->entry[i].size), def->entry[i].size, false) < 0) {
+ goto fail;
+ }
+ break;
- dict = fr_dict_unconst(fr_dict_by_da(parent));
+ case FR_TYPE_DATE:
+ memcpy(&vp->vp_date, field, sizeof(vp->vp_date));
+ break;
- for (entry = &stats->table[0]; entry->name != NULL; entry++) {
- fr_dict_attr_flags_t flags = {
- .internal = true,
- .counter = entry->flags.counter,
- };
+ case FR_TYPE_TIME_DELTA:
+ memcpy(&vp->vp_time_delta, field, sizeof(vp->vp_time_delta));
+ break;
- fr_assert(entry->number > 0);
- fr_assert((entry->type == FR_TYPE_TIME_DELTA) || (fr_type_is_integer(entry->type)));
+ default:
+ fr_strerror_printf("Unsupported data type '%s'", fr_type_to_str(def->entry[i].type));
+ return -1;
+ }
- if (fr_dict_attr_add(dict, parent, entry->name, entry->number, entry->type, &flags) < 0) return -1;
+ if (fr_pair_append(&parent->vp_group, vp) < 0) goto fail;
+ }
+
+ if (fr_pair_append(out, parent) < 0) {
+ fail:
+ talloc_free(parent);
+ return -1;
}
return 0;
}
-/** Add statistics VPs for a particular struct / context
+int fr_stats_from_pairs(TALLOC_CTX *ctx, fr_stats_instance_t *inst, fr_pair_list_t *in)
+{
+ size_t i;
+ fr_stats_link_t const *def = inst->def;
+ uint8_t *out = inst->stats;
+ fr_pair_t const *parent, *vp;
+
+ parent = fr_pair_find_by_da(in, NULL, *(def->root_p));
+ if (!parent) return -1;
+
+ memset(out, 0, inst->def->size);
+
+ for (i = 0; i < def->num_elements; i++) {
+ uint8_t *field;
+
+ vp = fr_pair_find_by_da(&parent->vp_group, NULL, *(def->entry[i].da_p));
+ if (!vp) continue;
+
+ field = ((uint8_t *) out) + def->entry[i].offset;
+
+ /*
+ * Strings of length 0 are "const char *".
+ *
+ * Everything else is an in-line field.
+ */
+ switch (def->entry[i].type) {
+ case FR_TYPE_STRING:
+ if (!def->entry[i].size) {
+ char const *str;
+
+ str = talloc_bstrndup(ctx, vp->vp_strvalue, vp->vp_length);
+ if (!str) return -1;
+
+ memcpy(&field, &str, sizeof(str));
+ break;
+ }
+ FALL_THROUGH;
+
+ case FR_TYPE_OCTETS:
+ if (vp->vp_length <= def->entry[i].size) {
+ memcpy(field, vp->vp_ptr, vp->vp_length);
+ } else {
+ memcpy(field, vp->vp_ptr, def->entry[i].size);
+ }
+ break;
+
+#undef COPY
+#define COPY(_type, _field) \
+ case _type: \
+ memcpy(field, &vp->vp_ ## _field, sizeof(vp->vp_ ##_field)); \
+ break
+
+ COPY(FR_TYPE_UINT16, uint16);
+ COPY(FR_TYPE_UINT32, uint32);
+ COPY(FR_TYPE_UINT64, uint64);
+
+ COPY(FR_TYPE_IPV4_ADDR, ipv4addr); /* struct in_addr, and not vp_ip */
+ COPY(FR_TYPE_IPV6_ADDR, ipv6addr); /* struct in6_addr, and not vp_ip */
+
+ COPY(FR_TYPE_DATE, date);
+ COPY(FR_TYPE_TIME_DELTA, time_delta);
+
+ default:
+ fr_strerror_printf("Unsupported data type '%s'", fr_type_to_str(def->entry[i].type));
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
+#undef add
+#define add(_type, _out, _in) \
+do { \
+ _type _a, _b, _sum; \
+ memcpy(&_a, &_out, sizeof(_a)); \
+ memcpy(&_b, &_in, sizeof(_b)); \
+ _sum = _a + _b; \
+ memcpy(&_out, &_sum, sizeof(_sum)); \
+} while (0)
+
+/** Merge to statistics structures
+ *
+ * @todo - ensure that the struct magic is the same as the def magic
*
- * @param parent structural vp where the children will be added
- * @param stats structure which maps between #fr_dict_attr_t and internal stats structures
- * @param ctx the internal structure holding the stastics
- * @return
- * - <0 on error
- * - 0 on success
*/
-int fr_stats_pair_add(fr_pair_t *parent, fr_stats_struct_t const *stats, void const *ctx)
+static int stats_merge_internal(fr_stats_link_t const *def, void *out, void const *in)
{
- fr_stats_entry_t const *entry;
+ size_t i;
- fr_assert(fr_type_is_structural(parent->vp_type));
+ for (i = 0; i < def->num_elements; i++) {
+ uint8_t const *field_in;
+ uint8_t const *field_out;
- for (entry = &stats->table[0]; entry->name != NULL; entry++) {
- fr_pair_t *vp;
- fr_dict_attr_t const *da;
+ field_in = ((uint8_t const *) in) + def->entry[i].offset;
+ field_out = ((uint8_t const *) out) + def->entry[i].offset;
- da = fr_dict_attr_child_by_num(parent->da, entry->number);
- if (!da) {
- fr_strerror_printf("Unknown child %d for parent %s", entry->number, parent->da->name);
- return -1;
+ switch (def->entry[i].type) {
+ case FR_TYPE_UINT16:
+ add(uint16_t, field_out, field_in);
+ break;
+
+ case FR_TYPE_UINT32:
+ add(uint32_t, field_out, field_in);
+ break;
+
+ case FR_TYPE_UINT64:
+ add(uint64_t, field_out, field_in);
+ break;
+
+ default:
+ break;
}
+ }
+
+ return 0;
+}
+
+/** Public API for merging two statistics structures
+ *
+ */
+int fr_stats_merge(fr_stats_instance_t *out, fr_stats_instance_t const *in)
+{
+ if (out->def != in->def) {
+ fr_strerror_printf("Cannot merge stats into structure %s from different structure %s",
+ out->def->name, in->def->name);
+ return -1;
+ }
- vp = fr_pair_afrom_da(parent, da);
- if (!vp) return -1;
+ return stats_merge_internal(out->def, out->stats, in->stats);
+}
- if (fr_value_box_memcpy_in(&vp->data, ((uint8_t const *) ctx) + entry->offset) < 0) return -1;
- fr_pair_append(&parent->vp_group, vp);
+void fr_stats_iter_init(fr_stats_instance_t const *in, fr_stats_iter_t *iter)
+{
+ iter->inst = in;
+ iter->current = 0;
+}
+
+bool fr_stats_iter_next(fr_stats_iter_t *iter)
+{
+ if (iter->current < iter->inst->def->num_elements) {
+ iter->current++;
+ return true;
}
+ return false;
+}
+
+int fr_stats_iter_to_value_box(TALLOC_CTX *ctx, fr_value_box_t **out, fr_stats_iter_t *iter)
+{
+ fr_value_box_t *box;
+ uint8_t const *field;
+ fr_dict_attr_t const *da;
+
+ fr_assert(iter->inst);
+ fr_assert(iter->current < iter->inst->def->num_elements);
+
+ da = *(iter->inst->def->entry[iter->current].da_p);
+ fr_assert(da != NULL);
+
+ box = fr_value_box_alloc(ctx, iter->inst->def->entry[iter->current].type, da);
+ if (!box) return -1;
+
+ field = ((uint8_t const *) iter->inst->stats) + iter->inst->def->entry[iter->current].offset;
+
+#undef COPY
+#define COPY(_type, _field) \
+ case _type: \
+ memcpy(&box->vb_ ## _field, field, sizeof(box->vb_ ## _field)); \
+ break
+
+ switch (box->type) {
+ case FR_TYPE_STRING:
+ if (!iter->inst->def->entry[iter->current].size) {
+ char const *str;
+
+ memcpy(&str, field, sizeof(str));
+
+ if (fr_value_box_strdup(box, box, da, str, false) < 0) {
+ fail:
+ talloc_free(box);
+ return -1;
+ }
+ } else {
+ uint8_t const *end;
+
+ /*
+ * Find the trailing NUL within the fixed-size field.
+ */
+ end = memchr(field, '\0', iter->inst->def->entry[iter->current].size);
+
+ if (fr_value_box_bstrndup(box, box, da, (char const *) field,
+ (size_t) (end - field), false) < 0) {
+ goto fail;
+ }
+ }
+ break;
+
+ case FR_TYPE_OCTETS:
+ if (fr_value_box_memdup(box, box, da, field,
+ iter->inst->def->entry[iter->current].size, false) < 0) {
+ goto fail;
+ }
+ break;
+
+ COPY(FR_TYPE_UINT16, uint16);
+ COPY(FR_TYPE_UINT32, uint32);
+ COPY(FR_TYPE_UINT64, uint64);
+
+ COPY(FR_TYPE_IPV4_ADDR, ipv4addr); /* struct in_addr, and not vp_ip */
+ COPY(FR_TYPE_IPV6_ADDR, ipv6addr); /* struct in6_addr, and not vp_ip */
+
+ COPY(FR_TYPE_DATE, date);
+ COPY(FR_TYPE_TIME_DELTA, time_delta);
+
+ default:
+ fr_strerror_printf("Unsupported data type '%s'", fr_type_to_str(box->type));
+ return -1;
+ }
+
+ *out = box;
return 0;
}
+
+
extern "C" {
#endif
-/** Define a statistics mapping between dictionary attribute and a field in an internal structure.
+/** Link a struct entry to an autoloaded #fr_dict_attr_t
*
- * Note that the data types used in the internal structure have to match the #fr_type_t.
*/
typedef struct {
- char const *name; //!< Attribute name
- fr_type_t type; //!< data type for this statistics
- int number; //!< attribute number, so that numbers are consistent
- struct {
- bool counter; //!< data type is a counter (can add them)
- bool gauge; //!< data type is a gauge (take the maximum)
- } flags;
+ fr_dict_attr_t const **da_p; //!< point to the autoload definition of the DA for this field
+ fr_type_t type; //!< cached for locality and simplicity
+ size_t offset; //!< from the start of the struct
+ size_t size; //!< size of this field
+} fr_stats_link_entry_t;
- size_t offset; //!< from start of the structure
-} fr_stats_entry_t;
+typedef struct {
+ char const *name; //!< name of the stats structure
+ fr_dict_attr_t const **root_p; //!< point to the autoload definition of the DA for this structure
+ size_t size; //!< overall size of the structure
+ size_t num_elements; //!< number of elements in the table. Note no "NULL" terminator
+ fr_stats_link_entry_t entry[]; //!< the field entries, in offset order
+} fr_stats_link_t;
+
+/** Common header for all statistics instances
+ *
+ * def pointer to the definition of the structure for this instance
+ * path the full path to this instance
+ * uctx for any necessary callbacks
+ * entry in the doubly linked list of statics which all use the same "def".
+ */
+#define STATS_HEADER_COMMON \
+ fr_stats_link_t const *def; \
+ char const *path; \
+ void *uctx; \
+ fr_dlist_t entry
+
+/** Generic statistics structure
+ *
+ */
+typedef struct {
+ STATS_HEADER_COMMON; //!< common header
-#define STATS_ENTRY_TERMINATOR { .attr = NULL }
+ uint8_t stats[]; //!< generic statistics data
+} fr_stats_instance_t;
-/** Define a statistics mapping between a public name and an entire internal structure
+/** Macro to define a typedef for a particular kind of statistics
*
*/
+#define FR_STATS_TYPEDEF(_name, _type) \
+ typedef struct { \
+ STATS_HEADER_COMMON; \
+ _type stats; \
+ } fr_stats_## _name ## _instance_t
+
+/** Macro used when declaring a variable which contains the statistics
+ *
+ */
+#define FR_STATS_ENTRY(_name) fr_stats_## _name ## _instance_t
+
+/** Macro used to increment one field in the statistics structure
+ *
+ */
+#define FR_STATS_INC(_var, _field) _var->stats._field++
+
typedef struct {
- char const *name; //!< of this structure for public consumption
- fr_stats_entry_t table[]; //!< of mappings
-} fr_stats_struct_t;
+ fr_stats_instance_t const *inst;
+ unsigned int current;
+} fr_stats_iter_t;
+
+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);
+int fr_stats_merge(fr_stats_instance_t *out, fr_stats_instance_t const *in) CC_HINT(nonnull);
-int fr_stats_attr_init(fr_dict_attr_t *parent, fr_stats_struct_t const *stats) CC_HINT(nonnull);
+void fr_stats_iter_init(fr_stats_instance_t const *in, fr_stats_iter_t *iter);
+bool fr_stats_iter_next(fr_stats_iter_t *iter);
+int fr_stats_iter_to_value_box(TALLOC_CTX *ctx, fr_value_box_t **out, fr_stats_iter_t *iter);
-int fr_stats_pair_add(fr_pair_t *parent, fr_stats_struct_t const *stats, void const *ctx) CC_HINT(nonnull);
#ifdef __cplusplus
}