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: 5e1c489c3bd3d972628c089c35d4e0d67d5c3364 $
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: 5e1c489c3bd3d972628c089c35d4e0d67d5c3364 $")
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->proto_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" },
99};
100
105
108 { .out = &attr_freeradius_stats4_ipv4_address, .name = "Vendor-Specific.FreeRADIUS.Stats4.IPv4-Address", .type = FR_TYPE_IPV4_ADDR, .dict = &dict_radius },
109 { .out = &attr_freeradius_stats4_ipv6_address, .name = "Vendor-Specific.FreeRADIUS.Stats4.IPv6-Address", .type = FR_TYPE_IPV6_ADDR, .dict = &dict_radius },
110 { .out = &attr_freeradius_stats4_type, .name = "Vendor-Specific.FreeRADIUS.Stats4.Type", .type = FR_TYPE_UINT32, .dict = &dict_radius },
111 { .out = &attr_freeradius_stats4_packet_counters, .name = "Vendor-Specific.FreeRADIUS.Stats4.Packet-Counters", .type = FR_TYPE_TLV, .dict = &dict_radius },
113};
114
115static void coalesce(uint64_t final_stats[FR_RADIUS_CODE_MAX], rlm_stats_thread_t *t,
116 size_t tree_offset, rlm_stats_data_t *mydata)
117{
118 rlm_stats_data_t *stats;
119 rlm_stats_thread_t *other;
120 fr_rb_tree_t **tree;
121 uint64_t local_stats[FR_RADIUS_CODE_MAX];
122
123 tree = (fr_rb_tree_t **) (((uint8_t *) t) + tree_offset);
124
125 /*
126 * Bootstrap with my statistics, where we don't need a
127 * lock.
128 */
129 stats = fr_rb_find(*tree, mydata);
130 if (!stats) {
131 memset(final_stats, 0, sizeof(uint64_t) * FR_RADIUS_CODE_MAX);
132 } else {
133 memcpy(final_stats, stats->stats, sizeof(stats->stats));
134 }
135
136 /*
137 * Loop over all of the other thread instances, locking
138 * them, and adding their statistics in.
139 */
140 pthread_mutex_lock(&t->inst->mutable->mutex);
141 for (other = fr_dlist_head(&t->inst->mutable->list);
142 other != NULL;
143 other = fr_dlist_next(&t->inst->mutable->list, other)) {
144 int i;
145
146 if (other == t) continue;
147
148 tree = (fr_rb_tree_t **) (((uint8_t *) other) + tree_offset);
149 pthread_mutex_lock(&other->mutex);
150 stats = fr_rb_find(*tree, mydata);
151
152 if (!stats) {
153 pthread_mutex_unlock(&other->mutex);
154 continue;
155 }
156 memcpy(&local_stats, stats->stats, sizeof(stats->stats));
157
158 for (i = 0; i < FR_RADIUS_CODE_MAX; i++) {
159 final_stats[i] += local_stats[i];
160 }
161
162 pthread_mutex_unlock(&other->mutex);
163 }
164 pthread_mutex_unlock(&t->inst->mutable->mutex);
165}
166
167
168static unlang_action_t CC_HINT(nonnull) mod_stats_inc(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
169{
170 rlm_stats_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_stats_t);
171 rlm_stats_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_stats_thread_t);
172 int i, src_code, dst_code;
173 rlm_stats_data_t *stats;
174 rlm_stats_data_t mydata;
175
176 if (request->proto_dict != dict_radius) {
177 RWARN("%s can only be called in RADIUS virtual servers", mctx->mi->name);
179 }
180
181 src_code = request->packet->code;
182 if (src_code >= FR_RADIUS_CODE_MAX) src_code = 0;
183
184 dst_code = request->reply->code;
185 if (dst_code >= FR_RADIUS_CODE_MAX) dst_code = 0;
186
187 pthread_mutex_lock(&t->mutex);
188 t->stats[src_code]++;
189 t->stats[dst_code]++;
190
191 /*
192 * Update source statistics
193 */
194 mydata.ipaddr = request->packet->socket.inet.src_ipaddr;
195 stats = fr_rb_find(t->src, &mydata);
196 if (!stats) {
197 MEM(stats = talloc_zero(t, rlm_stats_data_t));
198
199 stats->ipaddr = request->packet->socket.inet.src_ipaddr;
200 stats->created = request->async->recv_time;
201
202 (void) fr_rb_insert(t->src, stats);
203 }
204
205 stats->last_packet = request->async->recv_time;
206 stats->stats[src_code]++;
207
208 /*
209 * Update destination statistics
210 */
211 mydata.ipaddr = request->packet->socket.inet.dst_ipaddr;
212 stats = fr_rb_find(t->dst, &mydata);
213 if (!stats) {
214 MEM(stats = talloc_zero(t, rlm_stats_data_t));
215
216 stats->ipaddr = request->packet->socket.inet.dst_ipaddr;
217 stats->created = request->async->recv_time;
218
219 (void) fr_rb_insert(t->dst, stats);
220 }
221
222 stats->last_packet = request->async->recv_time;
223 stats->stats[dst_code]++;
224 pthread_mutex_unlock(&t->mutex);
225
226 /*
227 * @todo - periodically clean up old entries.
228 */
229
230 if (fr_time_gt(fr_time_add(t->last_global_update, fr_time_delta_wrap(NSEC)), request->async->recv_time)) {
232 }
233
234 t->last_global_update = request->async->recv_time;
235
236 pthread_mutex_lock(&inst->mutable->mutex);
237 for (i = 0; i < FR_RADIUS_CODE_MAX; i++) {
238 inst->mutable->stats[i] += t->stats[i];
239 t->stats[i] = 0;
240 }
241 pthread_mutex_unlock(&inst->mutable->mutex);
242
244}
245
246/*
247 * Do the statistics
248 */
249static unlang_action_t CC_HINT(nonnull) mod_stats_read(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
250{
251 rlm_stats_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_stats_t);
252 rlm_stats_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_stats_thread_t);
253 int i;
254 uint32_t stats_type;
255
256
257 fr_pair_t *vp;
258 rlm_stats_data_t mydata;
259 uint64_t local_stats[NUM_ELEMENTS(inst->mutable->stats)];
260
261 if (request->proto_dict != dict_radius) {
262 RWARN("%s can only be called in RADIUS virtual servers", mctx->mi->name);
264 }
265
266 /*
267 * Ignore "authenticate" and anything other than Status-Server
268 */
269 if ((request->packet->code != FR_RADIUS_CODE_STATUS_SERVER)) {
271 }
272
273 vp = fr_pair_find_by_da_nested(&request->request_pairs, NULL, attr_freeradius_stats4_type);
274 if (!vp) {
275 stats_type = FR_TYPE_VALUE_GLOBAL;
276 } else {
277 stats_type = vp->vp_uint32;
278 }
279
280 /*
281 * Create attributes based on the statistics.
282 */
284 vp->vp_uint32 = stats_type;
285
286 switch (stats_type) {
287 case FR_TYPE_VALUE_GLOBAL: /* global */
288 /*
289 * Merge our stats with the global stats, and then copy
290 * the global stats to a thread-local variable.
291 *
292 * The copy helps minimize mutex contention.
293 */
294 pthread_mutex_lock(&inst->mutable->mutex);
295 for (i = 0; i < FR_RADIUS_CODE_MAX; i++) {
296 inst->mutable->stats[i] += t->stats[i];
297 t->stats[i] = 0;
298 }
299 memcpy(&local_stats, inst->mutable->stats, sizeof(inst->mutable->stats));
300 pthread_mutex_unlock(&inst->mutable->mutex);
301 vp = NULL;
302 break;
303
304 case FR_TYPE_VALUE_CLIENT: /* src */
305 vp = fr_pair_find_by_da_nested(&request->request_pairs, NULL, attr_freeradius_stats4_ipv4_address);
306 if (!vp) vp = fr_pair_find_by_da_nested(&request->request_pairs, NULL, attr_freeradius_stats4_ipv6_address);
308
309 mydata.ipaddr = vp->vp_ip;
310 coalesce(local_stats, t, offsetof(rlm_stats_thread_t, src), &mydata);
311 break;
312
313 case FR_TYPE_VALUE_LISTENER: /* dst */
314 vp = fr_pair_find_by_da_nested(&request->request_pairs, NULL, attr_freeradius_stats4_ipv4_address);
315 if (!vp) vp = fr_pair_find_by_da_nested(&request->request_pairs, NULL, attr_freeradius_stats4_ipv6_address);
317
318 mydata.ipaddr = vp->vp_ip;
319 coalesce(local_stats, t, offsetof(rlm_stats_thread_t, dst), &mydata);
320 break;
321
322 default:
323 REDEBUG("Invalid value '%d' for FreeRADIUS-Stats4-type", stats_type);
325 }
326
327 if (vp ) {
328 vp = fr_pair_copy(request->reply_ctx, vp);
329 if (vp) {
330 fr_pair_append(&request->reply_pairs, vp);
331 }
332 }
333
334 for (i = 0; i < FR_RADIUS_CODE_MAX; i++) {
335 fr_dict_attr_t const *da;
336
337 if (!local_stats[i]) continue;
338
340 if (!da) continue;
341
342 MEM(vp = fr_pair_afrom_da_nested(request->reply_ctx, &request->reply_pairs, da));
343 vp->vp_uint64 = local_stats[i];
344 }
345
347}
348
349
350static int8_t data_cmp(const void *one, const void *two)
351{
352 rlm_stats_data_t const *a = one;
353 rlm_stats_data_t const *b = two;
354
355 return fr_ipaddr_cmp(&a->ipaddr, &b->ipaddr);
356}
357
358/** Instantiate thread data for the submodule.
359 *
360 */
362{
363 rlm_stats_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_stats_t);
364 rlm_stats_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_stats_thread_t);
365
366 (void) talloc_set_type(t, rlm_stats_thread_t);
367
368 t->inst = inst;
369
370 t->src = fr_rb_inline_talloc_alloc(t, rlm_stats_data_t, src_node, data_cmp, NULL);
371 if (unlikely(!t->src)) return -1;
372
373 t->dst = fr_rb_inline_talloc_alloc(t, rlm_stats_data_t, dst_node, data_cmp, NULL);
374 if (unlikely(!t->dst)) {
375 TALLOC_FREE(t->src);
376 return -1;
377 }
378
379 pthread_mutex_init(&t->mutex, NULL);
380
381 pthread_mutex_lock(&inst->mutable->mutex);
382 fr_dlist_insert_head(&inst->mutable->list, t);
383 pthread_mutex_unlock(&inst->mutable->mutex);
384
385 return 0;
386}
387
388
389/** Destroy thread data for the submodule.
390 *
391 */
393{
394 rlm_stats_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_stats_thread_t);
395 rlm_stats_t *inst = t->inst;
396 int i;
397
398 pthread_mutex_lock(&inst->mutable->mutex);
399 for (i = 0; i < FR_RADIUS_CODE_MAX; i++) {
400 inst->mutable->stats[i] += t->stats[i];
401 }
402 fr_dlist_remove(&inst->mutable->list, t);
403 pthread_mutex_unlock(&inst->mutable->mutex);
404 pthread_mutex_destroy(&t->mutex);
405
406 return 0;
407}
408
409static int mod_instantiate(module_inst_ctx_t const *mctx)
410{
411 rlm_stats_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_stats_t);
412
413 MEM(inst->mutable = talloc_zero(NULL, rlm_stats_mutable_t));
414 pthread_mutex_init(&inst->mutable->mutex, NULL);
415 fr_dlist_init(&inst->mutable->list, rlm_stats_thread_t, entry);
416
417 return 0;
418}
419
420/*
421 * Only free memory we allocated. The strings allocated via
422 * cf_section_parse() do not need to be freed.
423 */
424static int mod_detach(module_detach_ctx_t const *mctx)
425{
426 rlm_stats_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_stats_t);
427
428 pthread_mutex_destroy(&inst->mutable->mutex);
429 talloc_free(inst->mutable);
430
431 /* free things here */
432 return 0;
433}
434
435/*
436 * The module name should be the only globally exported symbol.
437 * That is, everything else should be 'static'.
438 *
439 * If the module needs to temporarily modify it's instantiation
440 * data, the type should be changed to MODULE_TYPE_THREAD_UNSAFE.
441 * The server will then take care of ensuring that the module
442 * is single-threaded.
443 */
445
447 .common = {
448 .magic = MODULE_MAGIC_INIT,
449 .name = "stats",
450 .inst_size = sizeof(rlm_stats_t),
451 .thread_inst_size = sizeof(rlm_stats_thread_t),
452 .config = module_config,
453 .instantiate = mod_instantiate,
454 .detach = mod_detach,
455 .thread_instantiate = mod_thread_instantiate,
456 .thread_detach = mod_thread_detach
457 },
458 .method_group = {
459 .bindings = (module_method_binding_t[]){
460 { .section = SECTION_NAME("send", CF_IDENT_ANY), .method = mod_stats_inc },
461 { .section = SECTION_NAME("recv", "Status-Server"), .method = mod_stats_read },
463 }
464 }
465};
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
Definition action.h:35
#define RCSID(id)
Definition build.h:487
#define unlikely(_x)
Definition build.h:383
#define NUM_ELEMENTS(_t)
Definition build.h:339
#define CONF_PARSER_TERMINATOR
Definition cf_parse.h:660
Defines a CONF_PAIR to C data type mapping.
Definition cf_parse.h:597
#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:3529
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
Definition dict.h:294
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition dict.h:307
#define DICT_AUTOLOAD_TERMINATOR
Definition dict.h:313
Specifies an attribute which must be present for the module to function.
Definition dict.h:293
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition dict.h:306
#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:242
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:468
static void * fr_dlist_remove(fr_dlist_head_t *list_head, void *ptr)
Remove an item from the list.
Definition dlist.h:620
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:320
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:537
Head of a doubly linked list.
Definition dlist.h:51
Entry in a doubly linked list.
Definition dlist.h:41
talloc_free(hp)
int8_t fr_ipaddr_cmp(fr_ipaddr_t const *a, fr_ipaddr_t const *b)
Compare two ip addresses.
Definition inet.c:1354
IPv4/6 prefix.
#define RWARN(fmt,...)
Definition log.h:309
@ FR_TYPE_IPV4_ADDR
32 Bit IPv4 Address.
@ FR_TYPE_TLV
Contains nested attributes.
@ 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:786
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:1354
fr_pair_t * fr_pair_copy(TALLOC_CTX *ctx, fr_pair_t const *vp)
Copy a single valuepair.
Definition pair.c:503
fr_pair_t * fr_pair_afrom_da_nested(TALLOC_CTX *ctx, fr_pair_list_t *list, fr_dict_attr_t const *da)
Create a pair (and all intermediate parents), and append it to the list.
Definition pair.c:480
char const * fr_radius_packet_name[FR_RADIUS_CODE_MAX]
Definition base.c:116
#define REDEBUG(fmt,...)
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_UNLANG_UPDATED
Definition rcode.h:70
#define RETURN_UNLANG_FAIL
Definition rcode.h:63
#define RETURN_UNLANG_OK
Definition rcode.h:64
#define RETURN_UNLANG_NOOP
Definition rcode.h:69
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:424
fr_dict_attr_autoload_t rlm_stats_dict_attr[]
Definition rlm_stats.c:107
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:350
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:115
static unlang_action_t mod_stats_inc(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
Definition rlm_stats.c:168
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:446
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
static fr_dict_attr_t const * attr_freeradius_stats4_packet_counters
Definition rlm_stats.c:104
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 unlang_action_t mod_stats_read(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
Definition rlm_stats.c:249
static int mod_thread_instantiate(module_thread_inst_ctx_t const *mctx)
Instantiate thread data for the submodule.
Definition rlm_stats.c:361
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:392
static int mod_instantiate(module_inst_ctx_t const *mctx)
Definition rlm_stats.c:409
rlm_stats_mutable_t * mutable
Definition rlm_stats.c:56
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
char const * name
Instance name e.g. user_database.
Definition module.h:355
size_t inst_size
Size of the module's instance data.
Definition module.h:212
void * data
Module's instance data.
Definition module.h:291
#define MODULE_BINDING_TERMINATOR
Terminate a module binding list.
Definition module.h:152
Named methods exported by a module.
Definition module.h:174
#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
Stores an attribute, a value and various bits of other data.
Definition pair.h:68
#define fr_time_delta_wrap(_time)
Definition time.h:152
#define NSEC
Definition time.h:379
#define fr_time_add(_a, _b)
Add a time/time delta together.
Definition time.h:196
#define fr_time_gt(_a, _b)
Definition time.h:237
"server local" time.
Definition time.h:69
int nonnull(2, 5))