The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
rlm_stats.c
Go to the documentation of this file.
1/*
2 * This program is is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or (at
5 * your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/**
18 * $Id: 4c28094fcf90c1f6056fcc1b0213c9a74a3be38d $
19 * @file rlm_stats.c
20 * @brief Keep RADIUS statistics. Eventually, also non-RADIUS statistics
21 *
22 * @copyright 2017 Network RADIUS SAS (license@networkradius.com)
23 */
24RCSID("$Id: 4c28094fcf90c1f6056fcc1b0213c9a74a3be38d $")
25
26#include <freeradius-devel/server/base.h>
27#include <freeradius-devel/server/module_rlm.h>
28#include <freeradius-devel/io/listen.h>
29#include <freeradius-devel/util/dlist.h>
30#include <freeradius-devel/util/debug.h>
31#include <freeradius-devel/radius/radius.h>
32
33#include <freeradius-devel/protocol/radius/freeradius.h>
34
35/*
36 * @todo - also get the statistics from the network side for
37 * that, though, we need a way to find other network
38 * sockets (i.e. not this one), and then query them for
39 * statistics.
40 */
41
42#include <pthread.h>
43
44typedef struct {
46 fr_dlist_head_t list; //!< for threads to know about each other
47 uint64_t stats[FR_RADIUS_CODE_MAX];
49
50/*
51 * @todo - MULTI_PROTOCOL - make this protocol agnostic.
52 * Perhaps keep stats in a hash table by (request->dict, request->code) ?
53 */
54
55typedef struct {
57 fr_dict_attr_t const *type_da; //!< FreeRADIUS-Stats4-Type
58 fr_dict_attr_t const *ipv4_da; //!< FreeRADIUS-Stats4-IPv4-Address
59 fr_dict_attr_t const *ipv6_da; //!< FreeRADIUS-Stats4-IPv6-Address
60
61
63
64typedef struct {
67 fr_ipaddr_t ipaddr; //!< IP address of this thing
68 fr_time_t created; //!< when it was created
69 fr_time_t last_packet; //!< when we last saw a packet
70 uint64_t stats[FR_RADIUS_CODE_MAX]; //!< actual statistic
72
73typedef struct {
75
77 fr_dlist_t entry; //!< for threads to know about each other
78
79 fr_time_t last_manage; //!< when we deleted old things
80
81 fr_rb_tree_t *src; //!< stats by source
82 fr_rb_tree_t *dst; //!< stats by destination
83
84 uint64_t stats[FR_RADIUS_CODE_MAX];
85
88
92
93static fr_dict_t const *dict_radius;
94
97 { .out = &dict_radius, .proto = "radius" },
98 { NULL }
99};
100
104
107 { .out = &attr_freeradius_stats4_ipv4_address, .name = "Vendor-Specific.FreeRADIUS.Stats4.Stats4-IPv4-Address", .type = FR_TYPE_IPV4_ADDR, .dict = &dict_radius },
108 { .out = &attr_freeradius_stats4_ipv6_address, .name = "Vendor-Specific.FreeRADIUS.Stats4.Stats4-IPv6-Address", .type = FR_TYPE_IPV6_ADDR, .dict = &dict_radius },
109 { .out = &attr_freeradius_stats4_type, .name = "Vendor-Specific.FreeRADIUS.Stats4.Stats4-Type", .type = FR_TYPE_UINT32, .dict = &dict_radius },
110 { NULL }
111};
112
113static void coalesce(uint64_t final_stats[FR_RADIUS_CODE_MAX], rlm_stats_thread_t *t,
114 size_t tree_offset, rlm_stats_data_t *mydata)
115{
116 rlm_stats_data_t *stats;
117 rlm_stats_thread_t *other;
118 fr_rb_tree_t **tree;
119 uint64_t local_stats[FR_RADIUS_CODE_MAX];
120
121 tree = (fr_rb_tree_t **) (((uint8_t *) t) + tree_offset);
122
123 /*
124 * Bootstrap with my statistics, where we don't need a
125 * lock.
126 */
127 stats = fr_rb_find(*tree, mydata);
128 if (!stats) {
129 memset(final_stats, 0, sizeof(uint64_t) * FR_RADIUS_CODE_MAX);
130 } else {
131 memcpy(final_stats, stats->stats, sizeof(stats->stats));
132 }
133
134 /*
135 * Loop over all of the other thread instances, locking
136 * them, and adding their statistics in.
137 */
138 pthread_mutex_lock(&t->inst->mutable->mutex);
139 for (other = fr_dlist_head(&t->inst->mutable->list);
140 other != NULL;
141 other = fr_dlist_next(&t->inst->mutable->list, other)) {
142 int i;
143
144 if (other == t) continue;
145
146 tree = (fr_rb_tree_t **) (((uint8_t *) other) + tree_offset);
147 pthread_mutex_lock(&other->mutex);
148 stats = fr_rb_find(*tree, mydata);
149
150 if (!stats) {
151 pthread_mutex_unlock(&other->mutex);
152 continue;
153 }
154 memcpy(&local_stats, stats->stats, sizeof(stats->stats));
155
156 for (i = 0; i < FR_RADIUS_CODE_MAX; i++) {
157 final_stats[i] += local_stats[i];
158 }
159
160 pthread_mutex_unlock(&other->mutex);
161 }
162 pthread_mutex_unlock(&t->inst->mutable->mutex);
163}
164
165
166/*
167 * Do the statistics
168 */
169static unlang_action_t CC_HINT(nonnull) mod_stats(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
170{
171 rlm_stats_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_stats_t);
172 rlm_stats_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_stats_thread_t);
173 int i;
174 uint32_t stats_type;
175
176
177 fr_pair_t *vp;
178 rlm_stats_data_t mydata;
179 char buffer[64];
180 uint64_t local_stats[NUM_ELEMENTS(inst->mutable->stats)];
181
182 /*
183 * Increment counters only in "send foo" sections.
184 *
185 * i.e. only when we have a reply to send.
186 *
187 * FIXME - Nothing sets request_state anymore
188 */
189#if 0
190 if (request->request_state == REQUEST_SEND) {
191 int src_code, dst_code;
192 rlm_stats_data_t *stats;
193
194 src_code = request->packet->code;
195 if (src_code >= FR_RADIUS_CODE_MAX) src_code = 0;
196
197 dst_code = request->reply->code;
198 if (dst_code >= FR_RADIUS_CODE_MAX) dst_code = 0;
199
200 pthread_mutex_lock(&t->mutex);
201 t->stats[src_code]++;
202 t->stats[dst_code]++;
203
204 /*
205 * Update source statistics
206 */
207 mydata.ipaddr = request->packet->socket.inet.src_ipaddr;
208 stats = fr_rb_find(t->src, &mydata);
209 if (!stats) {
210 MEM(stats = talloc_zero(t, rlm_stats_data_t));
211
212 stats->ipaddr = request->packet->socket.inet.src_ipaddr;
213 stats->created = request->async->recv_time;
214
215 (void) fr_rb_insert(t->src, stats);
216 }
217
218 stats->last_packet = request->async->recv_time;
219 stats->stats[src_code]++;
220 stats->stats[dst_code]++;
221
222 /*
223 * Update destination statistics
224 */
225 mydata.ipaddr = request->packet->socket.inet.dst_ipaddr;
226 stats = fr_rb_find(t->dst, &mydata);
227 if (!stats) {
228 MEM(stats = talloc_zero(t, rlm_stats_data_t));
229
230 stats->ipaddr = request->packet->socket.inet.dst_ipaddr;
231 stats->created = request->async->recv_time;
232
233 (void) fr_rb_insert(t->dst, stats);
234 }
235
236 stats->last_packet = request->async->recv_time;
237 stats->stats[src_code]++;
238 stats->stats[dst_code]++;
239 pthread_mutex_unlock(&t->mutex);
240
241 /*
242 * @todo - periodically clean up old entries.
243 */
244
245 if ((t->last_global_update + NSEC) > request->async->recv_time) {
247 }
248
249 t->last_global_update = request->async->recv_time;
250
251 pthread_mutex_lock(&inst->mutable->mutex);
252 for (i = 0; i < FR_RADIUS_CODE_MAX; i++) {
253 inst->mutable->stats[i] += t->stats[i];
254 t->stats[i] = 0;
255 }
256 pthread_mutex_unlock(&inst->mutable->mutex);
257
259 }
260#endif
261
262 /*
263 * Ignore "authenticate" and anything other than Status-Server
264 */
265 if ((request->packet->code != FR_RADIUS_CODE_STATUS_SERVER)) {
267 }
268
269 vp = fr_pair_find_by_da_nested(&request->request_pairs, NULL, attr_freeradius_stats4_type);
270 if (!vp) {
271 stats_type = FR_STATS4_TYPE_VALUE_GLOBAL;
272 } else {
273 stats_type = vp->vp_uint32;
274 }
275
276 /*
277 * Create attributes based on the statistics.
278 */
280 vp->vp_uint32 = stats_type;
281
282 switch (stats_type) {
283 case FR_STATS4_TYPE_VALUE_GLOBAL: /* global */
284 /*
285 * Merge our stats with the global stats, and then copy
286 * the global stats to a thread-local variable.
287 *
288 * The copy helps minimize mutex contention.
289 */
290 pthread_mutex_lock(&inst->mutable->mutex);
291 for (i = 0; i < FR_RADIUS_CODE_MAX; i++) {
292 inst->mutable->stats[i] += t->stats[i];
293 t->stats[i] = 0;
294 }
295 memcpy(&local_stats, inst->mutable->stats, sizeof(inst->mutable->stats));
296 pthread_mutex_unlock(&inst->mutable->mutex);
297 vp = NULL;
298 break;
299
300 case FR_STATS4_TYPE_VALUE_CLIENT: /* src */
301 vp = fr_pair_find_by_da_nested(&request->request_pairs, NULL, attr_freeradius_stats4_ipv4_address);
302 if (!vp) vp = fr_pair_find_by_da_nested(&request->request_pairs, NULL, attr_freeradius_stats4_ipv6_address);
304
305 mydata.ipaddr = vp->vp_ip;
306 coalesce(local_stats, t, offsetof(rlm_stats_thread_t, src), &mydata);
307 break;
308
309 case FR_STATS4_TYPE_VALUE_LISTENER: /* dst */
310 vp = fr_pair_find_by_da_nested(&request->request_pairs, NULL, attr_freeradius_stats4_ipv4_address);
311 if (!vp) vp = fr_pair_find_by_da_nested(&request->request_pairs, NULL, attr_freeradius_stats4_ipv6_address);
313
314 mydata.ipaddr = vp->vp_ip;
315 coalesce(local_stats, t, offsetof(rlm_stats_thread_t, dst), &mydata);
316 break;
317
318 default:
319 REDEBUG("Invalid value '%d' for FreeRADIUS-Stats4-type", stats_type);
321 }
322
323 if (vp ) {
324 vp = fr_pair_copy(request->reply_ctx, vp);
325 if (vp) {
326 fr_pair_append(&request->reply_pairs, vp);
327 }
328 }
329
330 /*
331 * @todo - do this only for RADIUS
332 * key off of packet ID, and Stats4-Packet-Counters TLV.
333 */
334 strcpy(buffer, "FreeRADIUS-Stats4-");
335
336 for (i = 0; i < FR_RADIUS_CODE_MAX; i++) {
337 fr_dict_attr_t const *da;
338
339 if (!local_stats[i]) continue;
340
341 strlcpy(buffer + 18, fr_radius_packet_name[i], sizeof(buffer) - 18);
343 if (!da) continue;
344
345 MEM(vp = fr_pair_afrom_da(request->reply_ctx, da));
346 vp->vp_uint64 = local_stats[i];
347
348 fr_pair_append(&request->reply_pairs, vp);
349 }
350
352}
353
354
355static int8_t data_cmp(const void *one, const void *two)
356{
357 rlm_stats_data_t const *a = one;
358 rlm_stats_data_t const *b = two;
359
360 return fr_ipaddr_cmp(&a->ipaddr, &b->ipaddr);
361}
362
363/** Instantiate thread data for the submodule.
364 *
365 */
367{
368 rlm_stats_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_stats_t);
369 rlm_stats_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_stats_thread_t);
370
371 (void) talloc_set_type(t, rlm_stats_thread_t);
372
373 t->inst = inst;
374
375 t->src = fr_rb_inline_talloc_alloc(t, rlm_stats_data_t, src_node, data_cmp, NULL);
376 if (unlikely(!t->src)) return -1;
377
378 t->dst = fr_rb_inline_talloc_alloc(t, rlm_stats_data_t, dst_node, data_cmp, NULL);
379 if (unlikely(!t->dst)) {
380 TALLOC_FREE(t->src);
381 return -1;
382 }
383
384 pthread_mutex_lock(&inst->mutable->mutex);
385 fr_dlist_insert_head(&inst->mutable->list, t);
386 pthread_mutex_unlock(&inst->mutable->mutex);
387
388 return 0;
389}
390
391
392/** Destroy thread data for the submodule.
393 *
394 */
396{
397 rlm_stats_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_stats_thread_t);
398 rlm_stats_t *inst = t->inst;
399 int i;
400
401 pthread_mutex_lock(&inst->mutable->mutex);
402 for (i = 0; i < FR_RADIUS_CODE_MAX; i++) {
403 inst->mutable->stats[i] += t->stats[i];
404 }
405 fr_dlist_remove(&inst->mutable->list, t);
406 pthread_mutex_unlock(&inst->mutable->mutex);
407 pthread_mutex_destroy(&t->mutex);
408
409 return 0;
410}
411
412static int mod_instantiate(module_inst_ctx_t const *mctx)
413{
414 rlm_stats_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_stats_t);
415
416 MEM(inst->mutable = talloc_zero(NULL, rlm_stats_mutable_t));
417 pthread_mutex_init(&inst->mutable->mutex, NULL);
418 fr_dlist_init(&inst->mutable->list, rlm_stats_thread_t, entry);
419
420 return 0;
421}
422
423/*
424 * Only free memory we allocated. The strings allocated via
425 * cf_section_parse() do not need to be freed.
426 */
427static int mod_detach(module_detach_ctx_t const *mctx)
428{
429 rlm_stats_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_stats_t);
430
431 pthread_mutex_destroy(&inst->mutable->mutex);
432 talloc_free(inst->mutable);
433
434 /* free things here */
435 return 0;
436}
437
438/*
439 * The module name should be the only globally exported symbol.
440 * That is, everything else should be 'static'.
441 *
442 * If the module needs to temporarily modify it's instantiation
443 * data, the type should be changed to MODULE_TYPE_THREAD_UNSAFE.
444 * The server will then take care of ensuring that the module
445 * is single-threaded.
446 */
448
450 .common = {
451 .magic = MODULE_MAGIC_INIT,
452 .name = "stats",
453 .inst_size = sizeof(rlm_stats_t),
454 .thread_inst_size = sizeof(rlm_stats_thread_t),
455 .config = module_config,
456 .instantiate = mod_instantiate,
457 .detach = mod_detach,
458 .thread_instantiate = mod_thread_instantiate,
459 .thread_detach = mod_thread_detach
460 },
461 .method_group = {
462 .bindings = (module_method_binding_t[]){
463 { .section = SECTION_NAME(CF_IDENT_ANY, CF_IDENT_ANY), .method = mod_stats },
465 }
466 }
467};
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
Definition action.h:35
static int const char char buffer[256]
Definition acutest.h:576
strcpy(log_entry->msg, buffer)
#define RCSID(id)
Definition build.h:483
#define unlikely(_x)
Definition build.h:381
#define NUM_ELEMENTS(_t)
Definition build.h:337
#define CONF_PARSER_TERMINATOR
Definition cf_parse.h:642
Defines a CONF_PAIR to C data type mapping.
Definition cf_parse.h:579
#define CF_IDENT_ANY
Definition cf_util.h:78
#define MEM(x)
Definition debug.h:36
@ FR_RADIUS_CODE_MAX
Maximum possible protocol code.
Definition defs.h:53
@ FR_RADIUS_CODE_STATUS_SERVER
RFC2865/RFC5997 - Status Server (request)
Definition defs.h:44
fr_dict_attr_t const * fr_dict_attr_by_name(fr_dict_attr_err_t *err, fr_dict_attr_t const *parent, char const *attr))
Locate a fr_dict_attr_t by its name.
Definition dict_util.c:3263
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition dict_util.c:2400
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
Definition dict.h:268
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition dict.h:281
Specifies an attribute which must be present for the module to function.
Definition dict.h:267
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition dict.h:280
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
Definition dl_module.h:63
#define fr_dlist_init(_head, _type, _field)
Initialise the head structure of a doubly linked list.
Definition dlist.h:260
static void * fr_dlist_head(fr_dlist_head_t const *list_head)
Return the HEAD item of a list or NULL if the list is empty.
Definition dlist.h:486
static void * fr_dlist_remove(fr_dlist_head_t *list_head, void *ptr)
Remove an item from the list.
Definition dlist.h:638
static int fr_dlist_insert_head(fr_dlist_head_t *list_head, void *ptr)
Insert an item into the head of a list.
Definition dlist.h:338
static void * fr_dlist_next(fr_dlist_head_t const *list_head, void const *ptr)
Get the next item in a list.
Definition dlist.h:555
Head of a doubly linked list.
Definition dlist.h:51
Entry in a doubly linked list.
Definition dlist.h:41
int8_t fr_ipaddr_cmp(fr_ipaddr_t const *a, fr_ipaddr_t const *b)
Compare two ip addresses.
Definition inet.c:1346
IPv4/6 prefix.
talloc_free(reap)
@ FR_TYPE_IPV4_ADDR
32 Bit IPv4 Address.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
@ FR_TYPE_IPV6_ADDR
128 Bit IPv6 Address.
unsigned int uint32_t
unsigned char uint8_t
module_instance_t const * mi
Instance of the module being instantiated.
Definition module_ctx.h:42
void * thread
Thread specific instance data.
Definition module_ctx.h:43
module_instance_t * mi
Module instance to detach.
Definition module_ctx.h:57
void * thread
Thread instance data.
Definition module_ctx.h:67
module_instance_t const * mi
Instance of the module being instantiated.
Definition module_ctx.h:64
module_instance_t * mi
Instance of the module being instantiated.
Definition module_ctx.h:51
Temporary structure to hold arguments for module calls.
Definition module_ctx.h:41
Temporary structure to hold arguments for detach calls.
Definition module_ctx.h:56
Temporary structure to hold arguments for instantiation calls.
Definition module_ctx.h:50
Temporary structure to hold arguments for thread_instantiation calls.
Definition module_ctx.h:63
module_t common
Common fields presented by all modules.
Definition module_rlm.h:39
fr_pair_t * fr_pair_find_by_da_nested(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *da)
Find a pair with a matching fr_dict_attr_t, by walking the nested fr_dict_attr_t tree.
Definition pair.c:770
int fr_pair_append(fr_pair_list_t *list, fr_pair_t *to_add)
Add a VP to the end of the list.
Definition pair.c:1345
fr_pair_t * fr_pair_afrom_da(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
Dynamically allocate a new attribute and assign a fr_dict_attr_t.
Definition pair.c:283
fr_pair_t * fr_pair_copy(TALLOC_CTX *ctx, fr_pair_t const *vp)
Copy a single valuepair.
Definition pair.c:489
char const * fr_radius_packet_name[FR_RADIUS_CODE_MAX]
Definition base.c:112
#define REDEBUG(fmt,...)
Definition radclient.h:52
void * fr_rb_find(fr_rb_tree_t const *tree, void const *data)
Find an element in the tree, returning the data, not the node.
Definition rb.c:577
bool fr_rb_insert(fr_rb_tree_t *tree, void const *data)
Insert data into a tree.
Definition rb.c:626
#define fr_rb_inline_talloc_alloc(_ctx, _type, _field, _data_cmp, _data_free)
Allocs a red black that verifies elements are of a specific talloc type.
Definition rb.h:246
The main red black tree structure.
Definition rb.h:73
#define RETURN_MODULE_NOOP
Definition rcode.h:62
#define RETURN_MODULE_OK
Definition rcode.h:57
#define RETURN_MODULE_FAIL
Definition rcode.h:56
#define RETURN_MODULE_UPDATED
Definition rcode.h:63
rlm_rcode_t
Return codes indicating the result of the module call.
Definition rcode.h:40
@ REQUEST_SEND
Definition request.h:71
fr_rb_tree_t * dst
stats by destination
Definition rlm_stats.c:82
static int mod_detach(module_detach_ctx_t const *mctx)
Definition rlm_stats.c:427
fr_dict_attr_autoload_t rlm_stats_dict_attr[]
Definition rlm_stats.c:106
fr_dict_attr_t const * ipv4_da
FreeRADIUS-Stats4-IPv4-Address.
Definition rlm_stats.c:58
rlm_stats_t * inst
Definition rlm_stats.c:74
fr_time_t created
when it was created
Definition rlm_stats.c:68
static int8_t data_cmp(const void *one, const void *two)
Definition rlm_stats.c:355
fr_dict_attr_t const * type_da
FreeRADIUS-Stats4-Type.
Definition rlm_stats.c:57
fr_dict_autoload_t rlm_stats_dict[]
Definition rlm_stats.c:96
fr_time_t last_packet
when we last saw a packet
Definition rlm_stats.c:69
uint64_t stats[FR_RADIUS_CODE_MAX]
Definition rlm_stats.c:84
static void coalesce(uint64_t final_stats[FR_RADIUS_CODE_MAX], rlm_stats_thread_t *t, size_t tree_offset, rlm_stats_data_t *mydata)
Definition rlm_stats.c:113
static fr_dict_attr_t const * attr_freeradius_stats4_ipv4_address
Definition rlm_stats.c:101
static fr_dict_t const * dict_radius
Definition rlm_stats.c:93
uint64_t stats[FR_RADIUS_CODE_MAX]
actual statistic
Definition rlm_stats.c:70
module_rlm_t rlm_stats
Definition rlm_stats.c:449
fr_rb_node_t dst_node
Definition rlm_stats.c:66
fr_dlist_head_t list
for threads to know about each other
Definition rlm_stats.c:46
fr_ipaddr_t ipaddr
IP address of this thing.
Definition rlm_stats.c:67
static fr_dict_attr_t const * attr_freeradius_stats4_ipv6_address
Definition rlm_stats.c:102
fr_rb_node_t src_node
Definition rlm_stats.c:65
static int mod_thread_instantiate(module_thread_inst_ctx_t const *mctx)
Instantiate thread data for the submodule.
Definition rlm_stats.c:366
pthread_mutex_t mutex
Definition rlm_stats.c:45
fr_dict_attr_t const * ipv6_da
FreeRADIUS-Stats4-IPv6-Address.
Definition rlm_stats.c:59
fr_dlist_t entry
for threads to know about each other
Definition rlm_stats.c:77
fr_rb_tree_t * src
stats by source
Definition rlm_stats.c:81
fr_time_t last_global_update
Definition rlm_stats.c:76
static fr_dict_attr_t const * attr_freeradius_stats4_type
Definition rlm_stats.c:103
static const conf_parser_t module_config[]
Definition rlm_stats.c:89
pthread_mutex_t mutex
Definition rlm_stats.c:86
static int mod_thread_detach(module_thread_inst_ctx_t const *mctx)
Destroy thread data for the submodule.
Definition rlm_stats.c:395
static int mod_instantiate(module_inst_ctx_t const *mctx)
Definition rlm_stats.c:412
rlm_stats_mutable_t * mutable
Definition rlm_stats.c:56
static unlang_action_t mod_stats(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Definition rlm_stats.c:169
fr_time_t last_manage
when we deleted old things
Definition rlm_stats.c:79
#define SECTION_NAME(_name1, _name2)
Define a section name consisting of a verb and a noun.
Definition section.h:40
size_t inst_size
Size of the module's instance data.
Definition module.h:203
void * data
Module's instance data.
Definition module.h:271
#define MODULE_BINDING_TERMINATOR
Terminate a module binding list.
Definition module.h:151
Named methods exported by a module.
Definition module.h:173
#define pair_update_reply(_attr, _da)
Return or allocate a fr_pair_t in the reply list.
Definition pair.h:129
eap_aka_sim_process_conf_t * inst
fr_pair_t * vp
size_t strlcpy(char *dst, char const *src, size_t siz)
Definition strlcpy.c:34
Stores an attribute, a value and various bits of other data.
Definition pair.h:68
#define NSEC
Definition time.h:379
"server local" time.
Definition time.h:69
int nonnull(2, 5))