The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
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  */
24 RCSID("$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 
44 typedef struct {
46  fr_dlist_head_t list; //!< for threads to know about each other
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 
55 typedef 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 
62 } rlm_stats_t;
63 
64 typedef 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 
73 typedef 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 
85 
88 
89 static const conf_parser_t module_config[] = {
91 };
92 
93 static 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 
113 static 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 {
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  */
169 static 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;
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);
303  if (!vp) RETURN_MODULE_NOOP;
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);
312  if (!vp) RETURN_MODULE_NOOP;
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 
355 static 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 
412 static 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  */
427 static 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  */
447 extern module_rlm_t rlm_stats;
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:574
strcpy(log_entry->msg, buffer)
#define RCSID(id)
Definition: build.h:481
#define unlikely(_x)
Definition: build.h:379
#define NUM_ELEMENTS(_t)
Definition: build.h:335
#define CONF_PARSER_TERMINATOR
Definition: cf_parse.h:627
Defines a CONF_PAIR to C data type mapping.
Definition: cf_parse.h:564
#define CF_IDENT_ANY
Definition: cf_util.h:78
@ 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 ** out
Where to write a pointer to the resolved fr_dict_attr_t.
Definition: dict.h:267
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition: dict.h:280
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
Specifies an attribute which must be present for the module to function.
Definition: dict.h:266
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition: dict.h:279
#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_next(fr_dlist_head_t const *list_head, void const *ptr)
Get the next item in a list.
Definition: dlist.h:555
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
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.
Definition: merged_model.c:272
talloc_free(reap)
@ FR_TYPE_IPV4_ADDR
32 Bit IPv4 Address.
Definition: merged_model.c:86
@ FR_TYPE_UINT32
32 Bit unsigned integer.
Definition: merged_model.c:99
@ FR_TYPE_IPV6_ADDR
128 Bit IPv6 Address.
Definition: merged_model.c:88
unsigned int uint32_t
Definition: merged_model.c:33
unsigned char uint8_t
Definition: merged_model.c:30
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_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
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_copy(TALLOC_CTX *ctx, fr_pair_t const *vp)
Copy a single valuepair.
Definition: pair.c:489
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
char const * fr_radius_packet_name[FR_RADIUS_CODE_MAX]
Definition: base.c:112
static rc_stats_t stats
Definition: radclient-ng.c:74
#define REDEBUG(fmt,...)
Definition: radclient.h:52
#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
bool fr_rb_insert(fr_rb_tree_t *tree, void const *data)
void * fr_rb_find(fr_rb_tree_t const *tree, void const *data)
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_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
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
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
RETURN_MODULE_FAIL
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
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))