The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
rlm_stats.c
Go to the documentation of this file.
1/*
2 * This program 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: f9f2362ee06f00c5485b1ace8d8fde27a330bcc5 $
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: f9f2362ee06f00c5485b1ace8d8fde27a330bcc5 $")
25
26#include <freeradius-devel/server/base.h>
27#include <freeradius-devel/server/module_rlm.h>
28#include <freeradius-devel/io/listen.h>
29
30#include <freeradius-devel/protocol/radius/freeradius.h>
31
32/*
33 * @todo - also get the statistics from the network side for
34 * that, though, we need a way to find other network
35 * sockets (i.e. not this one), and then query them for
36 * statistics.
37 */
38
39#include <pthread.h>
40
41typedef struct {
43 fr_dlist_head_t list; //!< for threads to know about each other
44 uint64_t stats[FR_RADIUS_CODE_MAX];
46
47/*
48 * @todo - MULTI_PROTOCOL - make this protocol agnostic.
49 * Perhaps keep stats in a hash table by (request->proto_dict, request->code) ?
50 */
51
52typedef struct {
54 fr_dict_attr_t const *type_da; //!< FreeRADIUS-Stats4-Type
55 fr_dict_attr_t const *ipv4_da; //!< FreeRADIUS-Stats4-IPv4-Address
56 fr_dict_attr_t const *ipv6_da; //!< FreeRADIUS-Stats4-IPv6-Address
57
58
60
61typedef struct {
64 fr_ipaddr_t ipaddr; //!< IP address of this thing
65 fr_time_t created; //!< when it was created
66 fr_time_t last_packet; //!< when we last saw a packet
67 uint64_t stats[FR_RADIUS_CODE_MAX]; //!< actual statistic
69
70typedef struct {
72
74 fr_dlist_t entry; //!< for threads to know about each other
75
76 fr_time_t last_manage; //!< when we deleted old things
77
78 fr_rb_tree_t *src; //!< stats by source
79 fr_rb_tree_t *dst; //!< stats by destination
80
81 uint64_t stats[FR_RADIUS_CODE_MAX];
82
85
89
90static fr_dict_t const *dict_radius;
91
94 { .out = &dict_radius, .proto = "radius" },
96};
97
102
105 { .out = &attr_freeradius_stats4_ipv4_address, .name = "Vendor-Specific.FreeRADIUS.Stats4.IPv4-Address", .type = FR_TYPE_IPV4_ADDR, .dict = &dict_radius },
106 { .out = &attr_freeradius_stats4_ipv6_address, .name = "Vendor-Specific.FreeRADIUS.Stats4.IPv6-Address", .type = FR_TYPE_IPV6_ADDR, .dict = &dict_radius },
107 { .out = &attr_freeradius_stats4_type, .name = "Vendor-Specific.FreeRADIUS.Stats4.Type", .type = FR_TYPE_UINT32, .dict = &dict_radius },
108 { .out = &attr_freeradius_stats4_packet_counters, .name = "Vendor-Specific.FreeRADIUS.Stats4.Packet-Counters", .type = FR_TYPE_TLV, .dict = &dict_radius },
110};
111
112static void coalesce(uint64_t final_stats[FR_RADIUS_CODE_MAX], rlm_stats_thread_t *t,
113 size_t tree_offset, rlm_stats_data_t *mydata)
114{
115 rlm_stats_data_t *stats;
116 rlm_stats_thread_t *other;
117 fr_rb_tree_t **tree;
118 uint64_t local_stats[FR_RADIUS_CODE_MAX];
119
120 tree = (fr_rb_tree_t **) (((uint8_t *) t) + tree_offset);
121
122 /*
123 * Bootstrap with my statistics, where we don't need a
124 * lock.
125 */
126 stats = fr_rb_find(*tree, mydata);
127 if (!stats) {
128 memset(final_stats, 0, sizeof(uint64_t) * FR_RADIUS_CODE_MAX);
129 } else {
130 memcpy(final_stats, stats->stats, sizeof(stats->stats));
131 }
132
133 /*
134 * Loop over all of the other thread instances, locking
135 * them, and adding their statistics in.
136 */
137 pthread_mutex_lock(&t->inst->mutable->mutex);
138 for (other = fr_dlist_head(&t->inst->mutable->list);
139 other != NULL;
140 other = fr_dlist_next(&t->inst->mutable->list, other)) {
141 int i;
142
143 if (other == t) continue;
144
145 tree = (fr_rb_tree_t **) (((uint8_t *) other) + tree_offset);
146 pthread_mutex_lock(&other->mutex);
147 stats = fr_rb_find(*tree, mydata);
148
149 if (!stats) {
150 pthread_mutex_unlock(&other->mutex);
151 continue;
152 }
153 memcpy(&local_stats, stats->stats, sizeof(stats->stats));
154
155 for (i = 0; i < FR_RADIUS_CODE_MAX; i++) {
156 final_stats[i] += local_stats[i];
157 }
158
159 pthread_mutex_unlock(&other->mutex);
160 }
161 pthread_mutex_unlock(&t->inst->mutable->mutex);
162}
163
164
165static unlang_action_t CC_HINT(nonnull) mod_stats_inc(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
166{
167 rlm_stats_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_stats_t);
168 rlm_stats_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_stats_thread_t);
169 int i, src_code, dst_code;
170 rlm_stats_data_t *stats;
171 rlm_stats_data_t mydata;
172
173 if (request->proto_dict != dict_radius) {
174 RWARN("%s can only be called in RADIUS virtual servers", mctx->mi->name);
176 }
177
178 src_code = request->packet->code;
179 if (src_code >= FR_RADIUS_CODE_MAX) src_code = 0;
180
181 dst_code = request->reply->code;
182 if (dst_code >= FR_RADIUS_CODE_MAX) dst_code = 0;
183
184 pthread_mutex_lock(&t->mutex);
185 t->stats[src_code]++;
186 t->stats[dst_code]++;
187
188 /*
189 * Update source statistics
190 */
191 mydata.ipaddr = request->packet->socket.inet.src_ipaddr;
192 stats = fr_rb_find(t->src, &mydata);
193 if (!stats) {
194 MEM(stats = talloc_zero(t, rlm_stats_data_t));
195
196 stats->ipaddr = request->packet->socket.inet.src_ipaddr;
197 stats->created = request->async->recv_time;
198
199 (void) fr_rb_insert(t->src, stats);
200 }
201
202 stats->last_packet = request->async->recv_time;
203 stats->stats[src_code]++;
204
205 /*
206 * Update destination statistics
207 */
208 mydata.ipaddr = request->packet->socket.inet.dst_ipaddr;
209 stats = fr_rb_find(t->dst, &mydata);
210 if (!stats) {
211 MEM(stats = talloc_zero(t, rlm_stats_data_t));
212
213 stats->ipaddr = request->packet->socket.inet.dst_ipaddr;
214 stats->created = request->async->recv_time;
215
216 (void) fr_rb_insert(t->dst, stats);
217 }
218
219 stats->last_packet = request->async->recv_time;
220 stats->stats[dst_code]++;
221 pthread_mutex_unlock(&t->mutex);
222
223 /*
224 * @todo - periodically clean up old entries.
225 */
226
227 if (fr_time_gt(fr_time_add(t->last_global_update, fr_time_delta_wrap(NSEC)), request->async->recv_time)) {
229 }
230
231 t->last_global_update = request->async->recv_time;
232
233 pthread_mutex_lock(&inst->mutable->mutex);
234 for (i = 0; i < FR_RADIUS_CODE_MAX; i++) {
235 inst->mutable->stats[i] += t->stats[i];
236 t->stats[i] = 0;
237 }
238 pthread_mutex_unlock(&inst->mutable->mutex);
239
241}
242
243/*
244 * Do the statistics
245 */
246static unlang_action_t CC_HINT(nonnull) mod_stats_read(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
247{
248 rlm_stats_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_stats_t);
249 rlm_stats_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_stats_thread_t);
250 int i;
251 uint32_t stats_type;
252
253
254 fr_pair_t *vp;
255 rlm_stats_data_t mydata;
256 uint64_t local_stats[NUM_ELEMENTS(inst->mutable->stats)];
257
258 if (request->proto_dict != dict_radius) {
259 RWARN("%s can only be called in RADIUS virtual servers", mctx->mi->name);
261 }
262
263 /*
264 * Ignore "authenticate" and anything other than Status-Server
265 */
266 if ((request->packet->code != FR_RADIUS_CODE_STATUS_SERVER)) {
268 }
269
270 vp = fr_pair_find_by_da_nested(&request->request_pairs, NULL, attr_freeradius_stats4_type);
271 if (!vp) {
272 stats_type = FR_TYPE_VALUE_GLOBAL;
273 } else {
274 stats_type = vp->vp_uint32;
275 }
276
277 /*
278 * Create attributes based on the statistics.
279 */
281 vp->vp_uint32 = stats_type;
282
283 switch (stats_type) {
284 case FR_TYPE_VALUE_GLOBAL: /* global */
285 /*
286 * Merge our stats with the global stats, and then copy
287 * the global stats to a thread-local variable.
288 *
289 * The copy helps minimize mutex contention.
290 */
291 pthread_mutex_lock(&inst->mutable->mutex);
292 for (i = 0; i < FR_RADIUS_CODE_MAX; i++) {
293 inst->mutable->stats[i] += t->stats[i];
294 t->stats[i] = 0;
295 }
296 memcpy(&local_stats, inst->mutable->stats, sizeof(inst->mutable->stats));
297 pthread_mutex_unlock(&inst->mutable->mutex);
298 vp = NULL;
299 break;
300
301 case FR_TYPE_VALUE_CLIENT: /* src */
302 vp = fr_pair_find_by_da_nested(&request->request_pairs, NULL, attr_freeradius_stats4_ipv4_address);
303 if (!vp) vp = fr_pair_find_by_da_nested(&request->request_pairs, NULL, attr_freeradius_stats4_ipv6_address);
305
306 mydata.ipaddr = vp->vp_ip;
307 coalesce(local_stats, t, offsetof(rlm_stats_thread_t, src), &mydata);
308 break;
309
310 case FR_TYPE_VALUE_LISTENER: /* dst */
311 vp = fr_pair_find_by_da_nested(&request->request_pairs, NULL, attr_freeradius_stats4_ipv4_address);
312 if (!vp) vp = fr_pair_find_by_da_nested(&request->request_pairs, NULL, attr_freeradius_stats4_ipv6_address);
314
315 mydata.ipaddr = vp->vp_ip;
316 coalesce(local_stats, t, offsetof(rlm_stats_thread_t, dst), &mydata);
317 break;
318
319 default:
320 REDEBUG("Invalid value '%d' for FreeRADIUS-Stats4-type", stats_type);
322 }
323
324 if (vp ) {
325 vp = fr_pair_copy(request->reply_ctx, vp);
326 if (vp) {
327 fr_pair_append(&request->reply_pairs, vp);
328 }
329 }
330
331 for (i = 0; i < FR_RADIUS_CODE_MAX; i++) {
332 fr_dict_attr_t const *da;
333
334 if (!local_stats[i]) continue;
335
337 if (!da) continue;
338
339 MEM(vp = fr_pair_afrom_da_nested(request->reply_ctx, &request->reply_pairs, da));
340 vp->vp_uint64 = local_stats[i];
341 }
342
344}
345
346
347static int8_t data_cmp(const void *one, const void *two)
348{
349 rlm_stats_data_t const *a = one;
350 rlm_stats_data_t const *b = two;
351
352 return fr_ipaddr_cmp(&a->ipaddr, &b->ipaddr);
353}
354
355/** Instantiate thread data for the submodule.
356 *
357 */
359{
360 rlm_stats_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_stats_t);
361 rlm_stats_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_stats_thread_t);
362
363 (void) talloc_set_type(t, rlm_stats_thread_t);
364
365 t->inst = inst;
366
367 t->src = fr_rb_inline_talloc_alloc(t, rlm_stats_data_t, src_node, data_cmp, NULL);
368 if (unlikely(!t->src)) return -1;
369
370 t->dst = fr_rb_inline_talloc_alloc(t, rlm_stats_data_t, dst_node, data_cmp, NULL);
371 if (unlikely(!t->dst)) {
372 TALLOC_FREE(t->src);
373 return -1;
374 }
375
376 pthread_mutex_init(&t->mutex, NULL);
377
378 pthread_mutex_lock(&inst->mutable->mutex);
379 fr_dlist_insert_head(&inst->mutable->list, t);
380 pthread_mutex_unlock(&inst->mutable->mutex);
381
382 return 0;
383}
384
385
386/** Destroy thread data for the submodule.
387 *
388 */
390{
391 rlm_stats_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_stats_thread_t);
392 rlm_stats_t *inst = t->inst;
393 int i;
394
395 pthread_mutex_lock(&inst->mutable->mutex);
396 for (i = 0; i < FR_RADIUS_CODE_MAX; i++) {
397 inst->mutable->stats[i] += t->stats[i];
398 }
399 fr_dlist_remove(&inst->mutable->list, t);
400 pthread_mutex_unlock(&inst->mutable->mutex);
401 pthread_mutex_destroy(&t->mutex);
402
403 return 0;
404}
405
406static int mod_instantiate(module_inst_ctx_t const *mctx)
407{
408 rlm_stats_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_stats_t);
409
410 MEM(inst->mutable = talloc_zero(NULL, rlm_stats_mutable_t));
411 pthread_mutex_init(&inst->mutable->mutex, NULL);
412 fr_dlist_init(&inst->mutable->list, rlm_stats_thread_t, entry);
413
414 return 0;
415}
416
417/*
418 * Only free memory we allocated. The strings allocated via
419 * cf_section_parse() do not need to be freed.
420 */
421static int mod_detach(module_detach_ctx_t const *mctx)
422{
423 rlm_stats_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_stats_t);
424
425 pthread_mutex_destroy(&inst->mutable->mutex);
426 talloc_free(inst->mutable);
427
428 /* free things here */
429 return 0;
430}
431
432/*
433 * The module name should be the only globally exported symbol.
434 * That is, everything else should be 'static'.
435 *
436 * If the module needs to temporarily modify it's instantiation
437 * data, the type should be changed to MODULE_TYPE_THREAD_UNSAFE.
438 * The server will then take care of ensuring that the module
439 * is single-threaded.
440 */
442
444 .common = {
445 .magic = MODULE_MAGIC_INIT,
446 .name = "stats",
447 .inst_size = sizeof(rlm_stats_t),
448 .thread_inst_size = sizeof(rlm_stats_thread_t),
449 .config = module_config,
450 .instantiate = mod_instantiate,
451 .detach = mod_detach,
452 .thread_instantiate = mod_thread_instantiate,
453 .thread_detach = mod_thread_detach
454 },
455 .method_group = {
456 .bindings = (module_method_binding_t[]){
457 { .section = SECTION_NAME("send", CF_IDENT_ANY), .method = mod_stats_inc },
458 { .section = SECTION_NAME("recv", "Status-Server"), .method = mod_stats_read },
460 }
461 }
462};
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:506
#define unlikely(_x)
Definition build.h:402
#define NUM_ELEMENTS(_t)
Definition build.h:358
#define CONF_PARSER_TERMINATOR
Definition cf_parse.h:657
Defines a CONF_PAIR to C data type mapping.
Definition cf_parse.h:594
#define CF_IDENT_ANY
Definition cf_util.h:75
#define MEM(x)
Definition debug.h:46
@ 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:3528
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
Definition dict.h:292
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition dict.h:305
#define DICT_AUTOLOAD_TERMINATOR
Definition dict.h:311
Specifies an attribute which must be present for the module to function.
Definition dict.h:291
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition dict.h:304
#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:1353
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:784
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:1352
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:115
#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:244
The main red black tree structure.
Definition rb.h:71
#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:79
static int mod_detach(module_detach_ctx_t const *mctx)
Definition rlm_stats.c:421
fr_dict_attr_autoload_t rlm_stats_dict_attr[]
Definition rlm_stats.c:104
fr_dict_attr_t const * ipv4_da
FreeRADIUS-Stats4-IPv4-Address.
Definition rlm_stats.c:55
rlm_stats_t * inst
Definition rlm_stats.c:71
fr_time_t created
when it was created
Definition rlm_stats.c:65
static int8_t data_cmp(const void *one, const void *two)
Definition rlm_stats.c:347
fr_dict_attr_t const * type_da
FreeRADIUS-Stats4-Type.
Definition rlm_stats.c:54
fr_dict_autoload_t rlm_stats_dict[]
Definition rlm_stats.c:93
fr_time_t last_packet
when we last saw a packet
Definition rlm_stats.c:66
uint64_t stats[FR_RADIUS_CODE_MAX]
Definition rlm_stats.c:81
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:112
static unlang_action_t mod_stats_inc(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
Definition rlm_stats.c:165
static fr_dict_attr_t const * attr_freeradius_stats4_ipv4_address
Definition rlm_stats.c:98
static fr_dict_t const * dict_radius
Definition rlm_stats.c:90
uint64_t stats[FR_RADIUS_CODE_MAX]
actual statistic
Definition rlm_stats.c:67
module_rlm_t rlm_stats
Definition rlm_stats.c:443
fr_rb_node_t dst_node
Definition rlm_stats.c:63
fr_dlist_head_t list
for threads to know about each other
Definition rlm_stats.c:43
static fr_dict_attr_t const * attr_freeradius_stats4_packet_counters
Definition rlm_stats.c:101
fr_ipaddr_t ipaddr
IP address of this thing.
Definition rlm_stats.c:64
static fr_dict_attr_t const * attr_freeradius_stats4_ipv6_address
Definition rlm_stats.c:99
fr_rb_node_t src_node
Definition rlm_stats.c:62
static unlang_action_t mod_stats_read(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
Definition rlm_stats.c:246
static int mod_thread_instantiate(module_thread_inst_ctx_t const *mctx)
Instantiate thread data for the submodule.
Definition rlm_stats.c:358
pthread_mutex_t mutex
Definition rlm_stats.c:42
fr_dict_attr_t const * ipv6_da
FreeRADIUS-Stats4-IPv6-Address.
Definition rlm_stats.c:56
fr_dlist_t entry
for threads to know about each other
Definition rlm_stats.c:74
fr_rb_tree_t * src
stats by source
Definition rlm_stats.c:78
fr_time_t last_global_update
Definition rlm_stats.c:73
static fr_dict_attr_t const * attr_freeradius_stats4_type
Definition rlm_stats.c:100
static const conf_parser_t module_config[]
Definition rlm_stats.c:86
pthread_mutex_t mutex
Definition rlm_stats.c:83
static int mod_thread_detach(module_thread_inst_ctx_t const *mctx)
Destroy thread data for the submodule.
Definition rlm_stats.c:389
static int mod_instantiate(module_inst_ctx_t const *mctx)
Definition rlm_stats.c:406
rlm_stats_mutable_t * mutable
Definition rlm_stats.c:53
fr_time_t last_manage
when we deleted old things
Definition rlm_stats.c:76
#define SECTION_NAME(_name1, _name2)
Define a section name consisting of a verb and a noun.
Definition section.h:39
char const * name
Instance name e.g. user_database.
Definition module.h:357
size_t inst_size
Size of the module's instance data.
Definition module.h:212
void * data
Module's instance data.
Definition module.h:293
#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))