All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
stats.c
Go to the documentation of this file.
1 /*
2  * stats.c Internal statistics handling.
3  *
4  * Version: $Id: b502ea82b8b3ef8f76b1189c3d2782aac0806627 $
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * Copyright 2008 The FreeRADIUS server project
21  * Copyright 2008 Alan DeKok <aland@deployingradius.com>
22  */
23 
24 RCSID("$Id: b502ea82b8b3ef8f76b1189c3d2782aac0806627 $")
25 
26 #include <freeradius-devel/radiusd.h>
27 #include <freeradius-devel/rad_assert.h>
28 
29 #ifdef WITH_STATS
30 
31 #define USEC (1000000)
32 #define EMA_SCALE (100)
33 #define F_EMA_SCALE (1000000)
34 
35 static struct timeval start_time;
36 static struct timeval hup_time;
37 
38 #define FR_STATS_INIT { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
39  { 0, 0, 0, 0, 0, 0, 0, 0 }}
40 
42 #ifdef WITH_ACCOUNTING
44 #endif
45 #ifdef WITH_COA
48 #endif
49 
50 #ifdef WITH_PROXY
52 #ifdef WITH_ACCOUNTING
54 #endif
55 #ifdef WITH_COA
58 #endif
59 #endif
60 
61 static void tv_sub(struct timeval *end, struct timeval *start,
62  struct timeval *elapsed)
63 {
64  elapsed->tv_sec = end->tv_sec - start->tv_sec;
65  if (elapsed->tv_sec > 0) {
66  elapsed->tv_sec--;
67  elapsed->tv_usec = USEC;
68  } else {
69  elapsed->tv_usec = 0;
70  }
71  elapsed->tv_usec += end->tv_usec;
72  elapsed->tv_usec -= start->tv_usec;
73 
74  if (elapsed->tv_usec >= USEC) {
75  elapsed->tv_usec -= USEC;
76  elapsed->tv_sec++;
77  }
78 }
79 
80 static void stats_time(fr_stats_t *stats, struct timeval *start,
81  struct timeval *end)
82 {
83  struct timeval diff;
84  uint32_t delay;
85 
86  if ((start->tv_sec == 0) || (end->tv_sec == 0) ||
87  (end->tv_sec < start->tv_sec)) return;
88 
89  tv_sub(end, start, &diff);
90 
91  if (diff.tv_sec >= 10) {
92  stats->elapsed[7]++;
93  } else {
94  int i;
95  uint32_t cmp;
96 
97  delay = (diff.tv_sec * USEC) + diff.tv_usec;
98 
99  cmp = 10;
100  for (i = 0; i < 7; i++) {
101  if (delay < cmp) {
102  stats->elapsed[i]++;
103  break;
104  }
105  cmp *= 10;
106  }
107  }
108 }
109 
111 {
112  if (request->master_state == REQUEST_COUNTED) return;
113 
114  if (!request->listener) return;
115  if (!request->client) return;
116 
117  if ((request->listener->type != RAD_LISTEN_NONE) &&
118 #ifdef WITH_ACCOUNTING
119  (request->listener->type != RAD_LISTEN_ACCT) &&
120 #endif
121 #ifdef WITH_COA
122  (request->listener->type != RAD_LISTEN_COA) &&
123 #endif
124  (request->listener->type != RAD_LISTEN_AUTH)) return;
125 
126  /* don't count statistic requests */
127  if (request->packet->code == PW_CODE_STATUS_SERVER)
128  return;
129 
130 #undef INC_AUTH
131 #define INC_AUTH(_x) radius_auth_stats._x++;request->listener->stats._x++;request->client->auth._x++;
132 
133 #undef INC_ACCT
134 #ifdef WITH_ACCOUNTING
135 #define INC_ACCT(_x) radius_acct_stats._x++;request->listener->stats._x++;request->client->acct._x++
136 #else
137 #define INC_ACCT(_x)
138 #endif
139 
140 #undef INC_COA
141 #ifdef WITH_COA
142 #define INC_COA(_x) radius_coa_stats._x++;request->listener->stats._x++;request->client->coa._x++
143 #else
144 #define INC_COA(_x)
145 #endif
146 
147 #undef INC_DSC
148 #ifdef WITH_DSC
149 #define INC_DSC(_x) radius_dsc_stats._x++;request->listener->stats._x++;request->client->dsc._x++
150 #else
151 #define INC_DSC(_x)
152 #endif
153 
154  /*
155  * Update the statistics.
156  *
157  * Note that we do NOT do this in a child thread.
158  * Instead, we update the stats when a request is
159  * deleted, because only the main server thread calls
160  * this function, which makes it thread-safe.
161  */
162  if (request->reply && (request->packet->code != PW_CODE_STATUS_SERVER)) switch (request->reply->code) {
164  INC_AUTH(total_access_accepts);
165 
166  auth_stats:
167  INC_AUTH(total_responses);
168 
169  /*
170  * FIXME: Do the time calculations once...
171  */
172  stats_time(&radius_auth_stats,
173  &request->packet->timestamp,
174  &request->reply->timestamp);
175  stats_time(&request->client->auth,
176  &request->packet->timestamp,
177  &request->reply->timestamp);
178  stats_time(&request->listener->stats,
179  &request->packet->timestamp,
180  &request->reply->timestamp);
181  break;
182 
184  INC_AUTH(total_access_rejects);
185  goto auth_stats;
186 
188  INC_AUTH(total_access_challenges);
189  goto auth_stats;
190 
191 #ifdef WITH_ACCOUNTING
193  INC_ACCT(total_responses);
194  stats_time(&radius_acct_stats,
195  &request->packet->timestamp,
196  &request->reply->timestamp);
197  stats_time(&request->client->acct,
198  &request->packet->timestamp,
199  &request->reply->timestamp);
200  break;
201 #endif
202 
203 #ifdef WITH_COA
204  case PW_CODE_COA_ACK:
205  INC_COA(total_access_accepts);
206  coa_stats:
207  INC_COA(total_responses);
208  stats_time(&request->client->coa,
209  &request->packet->timestamp,
210  &request->reply->timestamp);
211  break;
212 
213  case PW_CODE_COA_NAK:
214  INC_COA(total_access_rejects);
215  goto coa_stats;
216 
218  INC_DSC(total_access_accepts);
219  dsc_stats:
220  INC_DSC(total_responses);
221  stats_time(&request->client->dsc,
222  &request->packet->timestamp,
223  &request->reply->timestamp);
224  break;
225 
227  INC_DSC(total_access_rejects);
228  goto dsc_stats;
229 #endif
230 
231  /*
232  * No response, it must have been a bad
233  * authenticator.
234  */
235  case 0:
236  if (request->packet->code == PW_CODE_ACCESS_REQUEST) {
237  if (request->reply->offset == -2) {
238  INC_AUTH(total_bad_authenticators);
239  } else {
240  INC_AUTH(total_packets_dropped);
241  }
242  } else if (request->packet->code == PW_CODE_ACCOUNTING_REQUEST) {
243  if (request->reply->offset == -2) {
244  INC_ACCT(total_bad_authenticators);
245  } else {
246  INC_ACCT(total_packets_dropped);
247  }
248  }
249  break;
250 
251  default:
252  break;
253  }
254 
255 #ifdef WITH_PROXY
256  if (!request->proxy || !request->home_server) goto done; /* simplifies formatting */
257 
258  switch (request->proxy->code) {
260  proxy_auth_stats.total_requests += request->num_proxied_requests;
262  break;
263 
264 #ifdef WITH_ACCOUNTING
266  proxy_acct_stats.total_requests += request->num_proxied_requests;
268  break;
269 #endif
270 
271 #ifdef WITH_COA
272  case PW_CODE_COA_REQUEST:
273  proxy_coa_stats.total_requests += request->num_proxied_requests;
275  break;
276 
278  proxy_dsc_stats.total_requests += request->num_proxied_requests;
280  break;
281 #endif
282 
283  default:
284  break;
285  }
286 
287  if (!request->proxy_reply) goto done; /* simplifies formatting */
288 
289 #undef INC
290 #define INC(_x) proxy_auth_stats._x += request->num_proxied_responses; request->home_server->stats._x += request->num_proxied_responses;
291 
292  switch (request->proxy_reply->code) {
294  INC(total_access_accepts);
295  proxy_stats:
296  INC(total_responses);
297  stats_time(&proxy_auth_stats,
298  &request->proxy->timestamp,
299  &request->proxy_reply->timestamp);
300  stats_time(&request->home_server->stats,
301  &request->proxy->timestamp,
302  &request->proxy_reply->timestamp);
303  break;
304 
306  INC(total_access_rejects);
307  goto proxy_stats;
308 
310  INC(total_access_challenges);
311  goto proxy_stats;
312 
313 #ifdef WITH_ACCOUNTING
315  proxy_acct_stats.total_responses++;
316  request->home_server->stats.total_responses++;
317  stats_time(&proxy_acct_stats,
318  &request->proxy->timestamp,
319  &request->proxy_reply->timestamp);
320  stats_time(&request->home_server->stats,
321  &request->proxy->timestamp,
322  &request->proxy_reply->timestamp);
323  break;
324 #endif
325 
326 #ifdef WITH_COA
327  case PW_CODE_COA_ACK:
328  case PW_CODE_COA_NAK:
329  proxy_coa_stats.total_responses++;
330  request->home_server->stats.total_responses++;
331  stats_time(&proxy_coa_stats,
332  &request->proxy->timestamp,
333  &request->proxy_reply->timestamp);
334  stats_time(&request->home_server->stats,
335  &request->proxy->timestamp,
336  &request->proxy_reply->timestamp);
337  break;
338 
341  proxy_dsc_stats.total_responses++;
342  request->home_server->stats.total_responses++;
343  stats_time(&proxy_dsc_stats,
344  &request->proxy->timestamp,
345  &request->proxy_reply->timestamp);
346  stats_time(&request->home_server->stats,
347  &request->proxy->timestamp,
348  &request->proxy_reply->timestamp);
349  break;
350 #endif
351 
352  default:
353  proxy_auth_stats.total_unknown_types++;
355  break;
356  }
357 
358  done:
359 #endif /* WITH_PROXY */
360 
361  request->master_state = REQUEST_COUNTED;
362 }
363 
364 typedef struct fr_stats2vp {
366  size_t offset;
367 } fr_stats2vp;
368 
369 /*
370  * Authentication
371  */
372 static fr_stats2vp authvp[] = {
373  { PW_FREERADIUS_TOTAL_ACCESS_REQUESTS, offsetof(fr_stats_t, total_requests) },
374  { PW_FREERADIUS_TOTAL_ACCESS_ACCEPTS, offsetof(fr_stats_t, total_access_accepts) },
375  { PW_FREERADIUS_TOTAL_ACCESS_REJECTS, offsetof(fr_stats_t, total_access_rejects) },
376  { PW_FREERADIUS_TOTAL_ACCESS_CHALLENGES, offsetof(fr_stats_t, total_access_challenges) },
377  { PW_FREERADIUS_TOTAL_AUTH_RESPONSES, offsetof(fr_stats_t, total_responses) },
378  { PW_FREERADIUS_TOTAL_AUTH_DUPLICATE_REQUESTS, offsetof(fr_stats_t, total_dup_requests) },
379  { PW_FREERADIUS_TOTAL_AUTH_MALFORMED_REQUESTS, offsetof(fr_stats_t, total_malformed_requests) },
380  { PW_FREERADIUS_TOTAL_AUTH_INVALID_REQUESTS, offsetof(fr_stats_t, total_bad_authenticators) },
381  { PW_FREERADIUS_TOTAL_AUTH_DROPPED_REQUESTS, offsetof(fr_stats_t, total_packets_dropped) },
382  { PW_FREERADIUS_TOTAL_AUTH_UNKNOWN_TYPES, offsetof(fr_stats_t, total_unknown_types) },
383  { 0, 0 }
384 };
385 
386 
387 #ifdef WITH_PROXY
388 /*
389  * Proxied authentication requests.
390  */
392  { PW_FREERADIUS_TOTAL_PROXY_ACCESS_REQUESTS, offsetof(fr_stats_t, total_requests) },
393  { PW_FREERADIUS_TOTAL_PROXY_ACCESS_ACCEPTS, offsetof(fr_stats_t, total_access_accepts) },
394  { PW_FREERADIUS_TOTAL_PROXY_ACCESS_REJECTS, offsetof(fr_stats_t, total_access_rejects) },
395  { PW_FREERADIUS_TOTAL_PROXY_ACCESS_CHALLENGES, offsetof(fr_stats_t, total_access_challenges) },
396  { PW_FREERADIUS_TOTAL_PROXY_AUTH_RESPONSES, offsetof(fr_stats_t, total_responses) },
397  { PW_FREERADIUS_TOTAL_PROXY_AUTH_DUPLICATE_REQUESTS, offsetof(fr_stats_t, total_dup_requests) },
398  { PW_FREERADIUS_TOTAL_PROXY_AUTH_MALFORMED_REQUESTS, offsetof(fr_stats_t, total_malformed_requests) },
399  { PW_FREERADIUS_TOTAL_PROXY_AUTH_INVALID_REQUESTS, offsetof(fr_stats_t, total_bad_authenticators) },
400  { PW_FREERADIUS_TOTAL_PROXY_AUTH_DROPPED_REQUESTS, offsetof(fr_stats_t, total_packets_dropped) },
401  { PW_FREERADIUS_TOTAL_PROXY_AUTH_UNKNOWN_TYPES, offsetof(fr_stats_t, total_unknown_types) },
402  { 0, 0 }
403 };
404 #endif
405 
406 
407 #ifdef WITH_ACCOUNTING
408 /*
409  * Accounting
410  */
411 static fr_stats2vp acctvp[] = {
412  { PW_FREERADIUS_TOTAL_ACCOUNTING_REQUESTS, offsetof(fr_stats_t, total_requests) },
413  { PW_FREERADIUS_TOTAL_ACCOUNTING_RESPONSES, offsetof(fr_stats_t, total_responses) },
414  { PW_FREERADIUS_TOTAL_ACCT_DUPLICATE_REQUESTS, offsetof(fr_stats_t, total_dup_requests) },
415  { PW_FREERADIUS_TOTAL_ACCT_MALFORMED_REQUESTS, offsetof(fr_stats_t, total_malformed_requests) },
416  { PW_FREERADIUS_TOTAL_ACCT_INVALID_REQUESTS, offsetof(fr_stats_t, total_bad_authenticators) },
417  { PW_FREERADIUS_TOTAL_ACCT_DROPPED_REQUESTS, offsetof(fr_stats_t, total_packets_dropped) },
418  { PW_FREERADIUS_TOTAL_ACCT_UNKNOWN_TYPES, offsetof(fr_stats_t, total_unknown_types) },
419  { 0, 0 }
420 };
421 
422 #ifdef WITH_PROXY
424  { PW_FREERADIUS_TOTAL_PROXY_ACCOUNTING_REQUESTS, offsetof(fr_stats_t, total_requests) },
425  { PW_FREERADIUS_TOTAL_PROXY_ACCOUNTING_RESPONSES, offsetof(fr_stats_t, total_responses) },
426  { PW_FREERADIUS_TOTAL_PROXY_ACCT_DUPLICATE_REQUESTS, offsetof(fr_stats_t, total_dup_requests) },
427  { PW_FREERADIUS_TOTAL_PROXY_ACCT_MALFORMED_REQUESTS, offsetof(fr_stats_t, total_malformed_requests) },
428  { PW_FREERADIUS_TOTAL_PROXY_ACCT_INVALID_REQUESTS, offsetof(fr_stats_t, total_bad_authenticators) },
429  { PW_FREERADIUS_TOTAL_PROXY_ACCT_DROPPED_REQUESTS, offsetof(fr_stats_t, total_packets_dropped) },
430  { PW_FREERADIUS_TOTAL_PROXY_ACCT_UNKNOWN_TYPES, offsetof(fr_stats_t, total_unknown_types) },
431  { 0, 0 }
432 };
433 #endif
434 #endif
435 
437  { PW_FREERADIUS_TOTAL_ACCESS_REQUESTS, offsetof(fr_stats_t, total_requests) },
438  { PW_FREERADIUS_TOTAL_ACCESS_ACCEPTS, offsetof(fr_stats_t, total_access_accepts) },
439  { PW_FREERADIUS_TOTAL_ACCESS_REJECTS, offsetof(fr_stats_t, total_access_rejects) },
440  { PW_FREERADIUS_TOTAL_ACCESS_CHALLENGES, offsetof(fr_stats_t, total_access_challenges) },
441  { PW_FREERADIUS_TOTAL_AUTH_RESPONSES, offsetof(fr_stats_t, total_responses) },
442  { PW_FREERADIUS_TOTAL_AUTH_DUPLICATE_REQUESTS, offsetof(fr_stats_t, total_dup_requests) },
443  { PW_FREERADIUS_TOTAL_AUTH_MALFORMED_REQUESTS, offsetof(fr_stats_t, total_malformed_requests) },
444  { PW_FREERADIUS_TOTAL_AUTH_INVALID_REQUESTS, offsetof(fr_stats_t, total_bad_authenticators) },
445  { PW_FREERADIUS_TOTAL_AUTH_DROPPED_REQUESTS, offsetof(fr_stats_t, total_packets_dropped) },
446  { PW_FREERADIUS_TOTAL_AUTH_UNKNOWN_TYPES, offsetof(fr_stats_t, total_unknown_types) },
447  { 0, 0 }
448 };
449 
450 #ifdef WITH_ACCOUNTING
452  { PW_FREERADIUS_TOTAL_ACCOUNTING_REQUESTS, offsetof(fr_stats_t, total_requests) },
453  { PW_FREERADIUS_TOTAL_ACCOUNTING_RESPONSES, offsetof(fr_stats_t, total_responses) },
454  { PW_FREERADIUS_TOTAL_ACCT_DUPLICATE_REQUESTS, offsetof(fr_stats_t, total_dup_requests) },
455  { PW_FREERADIUS_TOTAL_ACCT_MALFORMED_REQUESTS, offsetof(fr_stats_t, total_malformed_requests) },
456  { PW_FREERADIUS_TOTAL_ACCT_INVALID_REQUESTS, offsetof(fr_stats_t, total_bad_authenticators) },
457  { PW_FREERADIUS_TOTAL_ACCT_DROPPED_REQUESTS, offsetof(fr_stats_t, total_packets_dropped) },
458  { PW_FREERADIUS_TOTAL_ACCT_UNKNOWN_TYPES, offsetof(fr_stats_t, total_unknown_types) },
459  { 0, 0 }
460 };
461 #endif
462 
463 static void request_stats_addvp(REQUEST *request,
464  fr_stats2vp *table, fr_stats_t *stats)
465 {
466  int i;
467  fr_uint_t counter;
468  VALUE_PAIR *vp;
469 
470  for (i = 0; table[i].attribute != 0; i++) {
471  vp = radius_pair_create(request->reply, &request->reply->vps,
472  table[i].attribute, VENDORPEC_FREERADIUS);
473  if (!vp) continue;
474 
475  counter = *(fr_uint_t *) (((uint8_t *) stats) + table[i].offset);
476  vp->vp_integer = counter;
477  }
478 }
479 
480 
482 {
483  VALUE_PAIR *flag, *vp;
484 
485  /*
486  * Statistics are available ONLY on a "status" port.
487  */
489  rad_assert(request->listener->type == RAD_LISTEN_NONE);
490 
491  flag = fr_pair_find_by_num(request->packet->vps, VENDORPEC_FREERADIUS, PW_FREERADIUS_STATISTICS_TYPE, TAG_ANY);
492  if (!flag || (flag->vp_integer == 0)) return;
493 
494  /*
495  * Authentication.
496  */
497  if (((flag->vp_integer & 0x01) != 0) &&
498  ((flag->vp_integer & 0xc0) == 0)) {
499  request_stats_addvp(request, authvp, &radius_auth_stats);
500  }
501 
502 #ifdef WITH_ACCOUNTING
503  /*
504  * Accounting
505  */
506  if (((flag->vp_integer & 0x02) != 0) &&
507  ((flag->vp_integer & 0xc0) == 0)) {
508  request_stats_addvp(request, acctvp, &radius_acct_stats);
509  }
510 #endif
511 
512 #ifdef WITH_PROXY
513  /*
514  * Proxied authentication requests.
515  */
516  if (((flag->vp_integer & 0x04) != 0) &&
517  ((flag->vp_integer & 0x20) == 0)) {
518  request_stats_addvp(request, proxy_authvp, &proxy_auth_stats);
519  }
520 
521 #ifdef WITH_ACCOUNTING
522  /*
523  * Proxied accounting requests.
524  */
525  if (((flag->vp_integer & 0x08) != 0) &&
526  ((flag->vp_integer & 0x20) == 0)) {
527  request_stats_addvp(request, proxy_acctvp, &proxy_acct_stats);
528  }
529 #endif
530 #endif
531 
532  /*
533  * Internal server statistics
534  */
535  if ((flag->vp_integer & 0x10) != 0) {
536  vp = radius_pair_create(request->reply, &request->reply->vps,
537  PW_FREERADIUS_STATS_START_TIME, VENDORPEC_FREERADIUS);
538  if (vp) vp->vp_date = start_time.tv_sec;
539  vp = radius_pair_create(request->reply, &request->reply->vps,
540  PW_FREERADIUS_STATS_HUP_TIME, VENDORPEC_FREERADIUS);
541  if (vp) vp->vp_date = hup_time.tv_sec;
542 
543 #ifdef HAVE_PTHREAD_H
544  int i, array[RAD_LISTEN_MAX], pps[2];
545 
546  thread_pool_queue_stats(array, pps);
547 
548  for (i = 0; i <= 4; i++) {
549  vp = radius_pair_create(request->reply, &request->reply->vps,
550  PW_FREERADIUS_QUEUE_LEN_INTERNAL + i, VENDORPEC_FREERADIUS);
551 
552  if (!vp) continue;
553  vp->vp_integer = array[i];
554  }
555 
556  for (i = 0; i < 2; i++) {
557  vp = radius_pair_create(request->reply, &request->reply->vps,
558  PW_FREERADIUS_QUEUE_PPS_IN + i, VENDORPEC_FREERADIUS);
559 
560  if (!vp) continue;
561  vp->vp_integer = pps[i];
562  }
563 #endif
564  }
565 
566  /*
567  * For a particular client.
568  */
569  if ((flag->vp_integer & 0x20) != 0) {
570  fr_ipaddr_t ipaddr;
571  VALUE_PAIR *server_ip, *server_port = NULL;
572  RADCLIENT *client = NULL;
573  RADCLIENT_LIST *cl = NULL;
574 
575  /*
576  * See if we need to look up the client by server
577  * socket.
578  */
579  server_ip = fr_pair_find_by_num(request->packet->vps, VENDORPEC_FREERADIUS,
580  PW_FREERADIUS_STATS_SERVER_IP_ADDRESS, TAG_ANY);
581  if (server_ip) {
582  server_port = fr_pair_find_by_num(request->packet->vps, VENDORPEC_FREERADIUS,
583  PW_FREERADIUS_STATS_SERVER_PORT, TAG_ANY);
584 
585  if (server_port) {
586  ipaddr.af = AF_INET;
587  ipaddr.ipaddr.ip4addr.s_addr = server_ip->vp_ipaddr;
588  cl = listener_find_client_list(&ipaddr, server_port->vp_integer, IPPROTO_UDP);
589 
590  /*
591  * Not found: don't do anything
592  */
593  if (!cl) return;
594  }
595  }
596 
597 
599  PW_FREERADIUS_STATS_CLIENT_IP_ADDRESS, TAG_ANY);
600  if (vp) {
601  memset(&ipaddr, 0, sizeof(ipaddr));
602  ipaddr.af = AF_INET;
603  ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
604  client = client_find(cl, &ipaddr, IPPROTO_UDP);
605 #ifdef WITH_TCP
606  if (!client) {
607  client = client_find(cl, &ipaddr, IPPROTO_TCP);
608  }
609 #endif
610 
611  /*
612  * Else look it up by number.
613  */
614  } else if ((vp = fr_pair_find_by_num(request->packet->vps, VENDORPEC_FREERADIUS,
615  PW_FREERADIUS_STATS_CLIENT_NUMBER, TAG_ANY)) != NULL) {
616  client = client_findbynumber(cl, vp->vp_integer);
617  }
618 
619  if (client) {
620  /*
621  * If found, echo it back, along with
622  * the requested statistics.
623  */
624  fr_pair_add(&request->reply->vps, fr_pair_copy(request->reply, vp));
625 
626  /*
627  * When retrieving client by number, also
628  * echo back it's IP address.
629  */
630  if ((vp->da->type == PW_TYPE_INTEGER) &&
631  (client->ipaddr.af == AF_INET)) {
632  vp = radius_pair_create(request->reply,
633  &request->reply->vps,
634  PW_FREERADIUS_STATS_CLIENT_IP_ADDRESS, VENDORPEC_FREERADIUS);
635  if (vp) {
636  vp->vp_ipaddr = client->ipaddr.ipaddr.ip4addr.s_addr;
637  }
638 
639  if (client->ipaddr.prefix != 32) {
640  vp = radius_pair_create(request->reply,
641  &request->reply->vps,
642  PW_FREERADIUS_STATS_CLIENT_NETMASK, VENDORPEC_FREERADIUS);
643  if (vp) {
644  vp->vp_integer = client->ipaddr.prefix;
645  }
646  }
647  }
648 
649  if (server_ip) {
650  fr_pair_add(&request->reply->vps,
651  fr_pair_copy(request->reply, server_ip));
652  }
653  if (server_port) {
654  fr_pair_add(&request->reply->vps,
655  fr_pair_copy(request->reply, server_port));
656  }
657 
658  if ((flag->vp_integer & 0x01) != 0) {
659  request_stats_addvp(request, client_authvp,
660  &client->auth);
661  }
662 #ifdef WITH_ACCOUNTING
663  if ((flag->vp_integer & 0x01) != 0) {
664  request_stats_addvp(request, client_acctvp,
665  &client->acct);
666  }
667 #endif
668  } /* else client wasn't found, don't echo it back */
669  }
670 
671  /*
672  * For a particular "listen" socket.
673  */
674  if (((flag->vp_integer & 0x40) != 0) &&
675  ((flag->vp_integer & 0x03) != 0)) {
676  rad_listen_t *this;
677  VALUE_PAIR *server_ip, *server_port;
678  fr_ipaddr_t ipaddr;
679 
680  /*
681  * See if we need to look up the server by socket
682  * socket.
683  */
684  server_ip = fr_pair_find_by_num(request->packet->vps, VENDORPEC_FREERADIUS,
685  PW_FREERADIUS_STATS_SERVER_IP_ADDRESS, TAG_ANY);
686  if (!server_ip) return;
687 
688  server_port = fr_pair_find_by_num(request->packet->vps, VENDORPEC_FREERADIUS,
689  PW_FREERADIUS_STATS_SERVER_PORT, TAG_ANY);
690  if (!server_port) return;
691 
692  ipaddr.af = AF_INET;
693  ipaddr.ipaddr.ip4addr.s_addr = server_ip->vp_ipaddr;
694  this = listener_find_byipaddr(&ipaddr,
695  server_port->vp_integer,
696  IPPROTO_UDP);
697 
698  /*
699  * Not found: don't do anything
700  */
701  if (!this) return;
702 
703  fr_pair_add(&request->reply->vps,
704  fr_pair_copy(request->reply, server_ip));
705  fr_pair_add(&request->reply->vps,
706  fr_pair_copy(request->reply, server_port));
707 
708  if (((flag->vp_integer & 0x01) != 0) &&
709  ((request->listener->type == RAD_LISTEN_AUTH) ||
710  (request->listener->type == RAD_LISTEN_NONE))) {
711  request_stats_addvp(request, authvp, &this->stats);
712  }
713 
714 #ifdef WITH_ACCOUNTING
715  if (((flag->vp_integer & 0x02) != 0) &&
716  ((request->listener->type == RAD_LISTEN_ACCT) ||
717  (request->listener->type == RAD_LISTEN_NONE))) {
718  request_stats_addvp(request, acctvp, &this->stats);
719  }
720 #endif
721  }
722 
723 #ifdef WITH_PROXY
724  /*
725  * Home servers.
726  */
727  if (((flag->vp_integer & 0x80) != 0) &&
728  ((flag->vp_integer & 0x03) != 0)) {
729  home_server_t *home;
730  VALUE_PAIR *server_ip, *server_port;
731  fr_ipaddr_t ipaddr;
732 
733  /*
734  * See if we need to look up the server by socket
735  * socket.
736  */
737  server_ip = fr_pair_find_by_num(request->packet->vps, VENDORPEC_FREERADIUS,
738  PW_FREERADIUS_STATS_SERVER_IP_ADDRESS, TAG_ANY);
739  if (!server_ip) return;
740 
741  server_port = fr_pair_find_by_num(request->packet->vps, VENDORPEC_FREERADIUS,
742  PW_FREERADIUS_STATS_SERVER_PORT, TAG_ANY);
743  if (!server_port) return;
744 
745 #ifndef NDEBUG
746  memset(&ipaddr, 0, sizeof(ipaddr));
747 #endif
748  ipaddr.af = AF_INET;
749  ipaddr.ipaddr.ip4addr.s_addr = server_ip->vp_ipaddr;
750  home = home_server_find(&ipaddr, server_port->vp_integer,
751  IPPROTO_UDP);
752 
753  /*
754  * Not found: don't do anything
755  */
756  if (!home) return;
757 
758  fr_pair_add(&request->reply->vps,
759  fr_pair_copy(request->reply, server_ip));
760  fr_pair_add(&request->reply->vps,
761  fr_pair_copy(request->reply, server_port));
762 
763  vp = radius_pair_create(request->reply, &request->reply->vps,
764  PW_FREERADIUS_STATS_SERVER_OUTSTANDING_REQUESTS, VENDORPEC_FREERADIUS);
765  if (vp) vp->vp_integer = home->currently_outstanding;
766 
767  vp = radius_pair_create(request->reply, &request->reply->vps,
768  PW_FREERADIUS_STATS_SERVER_STATE, VENDORPEC_FREERADIUS);
769  if (vp) vp->vp_integer = home->state;
770 
771  if ((home->state == HOME_STATE_ALIVE) &&
772  (home->revive_time.tv_sec != 0)) {
773  vp = radius_pair_create(request->reply, &request->reply->vps,
774  PW_FREERADIUS_STATS_SERVER_TIME_OF_LIFE, VENDORPEC_FREERADIUS);
775  if (vp) vp->vp_date = home->revive_time.tv_sec;
776  }
777 
778  if ((home->state == HOME_STATE_ALIVE) &&
779  (home->ema.window > 0)) {
780  vp = radius_pair_create(request->reply,
781  &request->reply->vps,
782  PW_FREERADIUS_SERVER_EMA_WINDOW, VENDORPEC_FREERADIUS);
783  if (vp) vp->vp_integer = home->ema.window;
784  vp = radius_pair_create(request->reply,
785  &request->reply->vps,
786  PW_FREERADIUS_SERVER_EMA_USEC_WINDOW_1, VENDORPEC_FREERADIUS);
787  if (vp) vp->vp_integer = home->ema.ema1 / EMA_SCALE;
788  vp = radius_pair_create(request->reply,
789  &request->reply->vps,
790  PW_FREERADIUS_SERVER_EMA_USEC_WINDOW_10, VENDORPEC_FREERADIUS);
791  if (vp) vp->vp_integer = home->ema.ema10 / EMA_SCALE;
792 
793  }
794 
795  if (home->state == HOME_STATE_IS_DEAD) {
796  vp = radius_pair_create(request->reply, &request->reply->vps,
797  PW_FREERADIUS_STATS_SERVER_TIME_OF_DEATH, VENDORPEC_FREERADIUS);
798  if (vp) vp->vp_date = home->zombie_period_start.tv_sec + home->zombie_period;
799  }
800 
801  /*
802  * Show more information...
803  *
804  * FIXME: do this for clients, too!
805  */
806  vp = radius_pair_create(request->reply, &request->reply->vps,
807  PW_FREERADIUS_STATS_LAST_PACKET_RECV, VENDORPEC_FREERADIUS);
808  if (vp) vp->vp_date = home->last_packet_recv;
809 
810  vp = radius_pair_create(request->reply, &request->reply->vps,
811  PW_FREERADIUS_STATS_LAST_PACKET_SENT, VENDORPEC_FREERADIUS);
812  if (vp) vp->vp_date = home->last_packet_sent;
813 
814  if (((flag->vp_integer & 0x01) != 0) &&
815  (home->type == HOME_TYPE_AUTH)) {
816  request_stats_addvp(request, proxy_authvp,
817  &home->stats);
818  }
819 
820 #ifdef WITH_ACCOUNTING
821  if (((flag->vp_integer & 0x02) != 0) &&
822  (home->type == HOME_TYPE_ACCT)) {
823  request_stats_addvp(request, proxy_acctvp,
824  &home->stats);
825  }
826 #endif
827  }
828 #endif /* WITH_PROXY */
829 }
830 
831 void radius_stats_init(int flag)
832 {
833  if (!flag) {
834  gettimeofday(&start_time, NULL);
835  hup_time = start_time; /* it's just nicer this way */
836  } else {
837  gettimeofday(&hup_time, NULL);
838  }
839 }
840 
842  struct timeval *start, struct timeval *end)
843 {
844  int micro;
845  time_t tdiff;
846 #ifdef WITH_STATS_DEBUG
847  static int n = 0;
848 #endif
849  if (ema->window == 0) return;
850 
851  rad_assert(start->tv_sec <= end->tv_sec);
852 
853  /*
854  * Initialize it.
855  */
856  if (ema->f1 == 0) {
857  if (ema->window > 10000) ema->window = 10000;
858 
859  ema->f1 = (2 * F_EMA_SCALE) / (ema->window + 1);
860  ema->f10 = (2 * F_EMA_SCALE) / ((10 * ema->window) + 1);
861  }
862 
863 
864  tdiff = start->tv_sec;
865  tdiff -= end->tv_sec;
866 
867  micro = (int) tdiff;
868  if (micro > 40) micro = 40; /* don't overflow 32-bit ints */
869  micro *= USEC;
870  micro += start->tv_usec;
871  micro -= end->tv_usec;
872 
873  micro *= EMA_SCALE;
874 
875  if (ema->ema1 == 0) {
876  ema->ema1 = micro;
877  ema->ema10 = micro;
878  } else {
879  int diff;
880 
881  diff = ema->f1 * (micro - ema->ema1);
882  ema->ema1 += (diff / 1000000);
883 
884  diff = ema->f10 * (micro - ema->ema10);
885  ema->ema10 += (diff / 1000000);
886  }
887 
888 
889 #ifdef WITH_STATS_DEBUG
890  DEBUG("time %d %d.%06d\t%d.%06d\t%d.%06d\n",
891  n, micro / PREC, (micro / EMA_SCALE) % USEC,
892  ema->ema1 / PREC, (ema->ema1 / EMA_SCALE) % USEC,
893  ema->ema10 / PREC, (ema->ema10 / EMA_SCALE) % USEC);
894  n++;
895 #endif
896 }
897 
898 #endif /* WITH_STATS */
fr_stats_t coa
Change of Authorization stats.
Definition: clients.h:64
rad_master_state_t master_state
Set by the master thread to signal the child that's currently working with the request, to do something.
Definition: radiusd.h:259
struct timeval timestamp
When we received the packet.
Definition: libradius.h:159
RFC2865 - Access-Challenge.
Definition: radius.h:102
RADIUS_PACKET * proxy_reply
Incoming response from proxy server.
Definition: radiusd.h:238
void request_stats_reply(REQUEST *request)
Definition: stats.c:481
RAD_LISTEN_TYPE type
Definition: listen.h:76
#define INC_COA(_x)
#define EMA_SCALE
Definition: stats.c:32
fr_stats_t stats
Definition: realms.h:143
time_t last_packet_recv
Definition: realms.h:107
static struct cmp * cmp
Definition: pair.c:45
fr_stats_t proxy_acct_stats
Definition: stats.c:53
#define VENDORPEC_FREERADIUS
Definition: radius.h:201
uint8_t prefix
Prefix length - Between 0-32 for IPv4 and 0-128 for IPv6.
Definition: inet.h:47
fr_stats_t dsc
Disconnect-Request stats.
Definition: clients.h:65
VALUE_PAIR * radius_pair_create(TALLOC_CTX *ctx, VALUE_PAIR **vps, unsigned int attribute, unsigned int vendor)
Create a VALUE_PAIR and add it to a list of VALUE_PAIR s.
Definition: pair.c:704
static fr_stats2vp proxy_acctvp[]
Definition: stats.c:423
uint32_t ema1
Definition: stats.h:61
fr_stats_t proxy_dsc_stats
Definition: stats.c:57
fr_stats_t radius_coa_stats
Definition: stats.c:46
VALUE_PAIR * vps
Result of decoding the packet into VALUE_PAIRs.
Definition: libradius.h:162
static struct timeval hup_time
Definition: stats.c:36
struct fr_stats2vp fr_stats2vp
RADCLIENT RADCLIENT * client_find(RADCLIENT_LIST const *clients, fr_ipaddr_t const *ipaddr, int proto)
Definition: client.c:431
fr_stats_t auth
Authentication stats.
Definition: clients.h:59
rad_listen_t * listener
The listener that received the request.
Definition: radiusd.h:218
static void tv_sub(struct timeval *end, struct timeval *start, struct timeval *elapsed)
Definition: stats.c:61
RFC3575/RFC5176 - Disconnect-Ack (positive)
Definition: radius.h:106
fr_uint_t elapsed[8]
Definition: stats.h:54
rad_listen_t * listener_find_byipaddr(fr_ipaddr_t const *ipaddr, uint16_t port, int proto)
Find a listener associated with an IP address/port/transport proto.
Definition: listen.c:3302
static struct timeval start_time
Definition: stats.c:35
RFC2866 - Accounting-Response.
Definition: radius.h:96
uint32_t window
Definition: stats.h:58
RADIUS_PACKET * proxy
Outgoing request to proxy server.
Definition: radiusd.h:237
RFC2865 - Access-Reject.
Definition: radius.h:94
RFC3575/RFC5176 - CoA-Ack (positive)
Definition: radius.h:109
int af
Address family.
Definition: inet.h:42
static fr_stats2vp client_acctvp[]
Definition: stats.c:451
#define rad_assert(expr)
Definition: rad_assert.h:38
RFC2865 - Access-Request.
Definition: radius.h:92
static void request_stats_addvp(REQUEST *request, fr_stats2vp *table, fr_stats_t *stats)
Definition: stats.c:463
fr_stats_t radius_auth_stats
Definition: stats.c:41
#define FR_STATS_INIT
Definition: stats.c:38
size_t offset
Definition: stats.c:366
#define DEBUG(fmt,...)
Definition: log.h:175
#define INC_AUTH(_x)
static rc_stats_t stats
Definition: radclient.c:47
struct timeval revive_time
Definition: realms.h:109
void fr_pair_add(VALUE_PAIR **head, VALUE_PAIR *vp)
Add a VP to the end of the list.
Definition: pair.c:659
void request_stats_final(REQUEST *request)
Definition: stats.c:110
uint32_t num_proxied_requests
How many times this request was proxied.
Definition: radiusd.h:284
RFC2866 - Accounting-Request.
Definition: radius.h:95
static bool done
Definition: radclient.c:53
uint32_t fr_uint_t
Definition: stats.h:35
union fr_ipaddr_t::@1 ipaddr
RFC3575/RFC5176 - CoA-Nak (not willing to perform)
Definition: radius.h:110
unsigned int code
Packet code (type).
Definition: libradius.h:155
fr_stats_t stats
Definition: listen.h:106
int attribute
Definition: stats.c:365
RFC2865 - Access-Accept.
Definition: radius.h:93
fr_ipaddr_t ipaddr
IPv4/IPv6 address of the host.
Definition: clients.h:36
Stores an attribute, a value and various bits of other data.
Definition: pair.h:112
fr_stats_t radius_acct_stats
Definition: stats.c:43
RADIUS_PACKET * reply
Outgoing response.
Definition: radiusd.h:225
void radius_stats_ema(fr_stats_ema_t *ema, struct timeval *start, struct timeval *end)
Definition: stats.c:841
fr_stats_t proxy_coa_stats
Definition: stats.c:56
uint32_t f10
Definition: stats.h:60
fr_stats_t proxy_auth_stats
Definition: stats.c:51
static fr_stats2vp client_authvp[]
Definition: stats.c:436
#define INC(_x)
32 Bit unsigned integer.
Definition: radius.h:34
RFC3575/RFC5176 - CoA-Request.
Definition: radius.h:108
static fr_stats2vp acctvp[]
Definition: stats.c:411
fr_uint_t total_responses
Definition: stats.h:43
Describes a host allowed to send packets to the server.
Definition: clients.h:35
#define TAG_ANY
Definition: pair.h:191
RADCLIENT * client_findbynumber(RADCLIENT_LIST const *clients, int number)
Definition: client.c:402
void thread_pool_queue_stats(int array[RAD_LISTEN_MAX], int pps[2])
#define INC_DSC(_x)
int state
Definition: realms.h:113
RADIUS_PACKET * packet
Incoming request.
Definition: radiusd.h:221
static fr_stats2vp proxy_authvp[]
Definition: stats.c:391
#define INC_ACCT(_x)
uint32_t f1
Definition: stats.h:60
time_t last_packet_sent
Definition: realms.h:106
static fr_stats2vp authvp[]
Definition: stats.c:372
uint32_t currently_outstanding
Definition: realms.h:104
ssize_t offset
Definition: libradius.h:163
void radius_stats_init(int flag)
Definition: stats.c:831
static void stats_time(fr_stats_t *stats, struct timeval *start, struct timeval *end)
Definition: stats.c:80
VALUE_PAIR * fr_pair_copy(TALLOC_CTX *ctx, VALUE_PAIR const *vp)
Copy a single valuepair.
Definition: pair.c:129
VALUE_PAIR * fr_pair_find_by_num(VALUE_PAIR *head, unsigned int vendor, unsigned int attr, int8_t tag)
Find the pair with the matching attribute.
Definition: pair.c:639
home_server_t * home_server
Definition: radiusd.h:240
RFC2865/RFC5997 - Status Server (request)
Definition: radius.h:103
#define F_EMA_SCALE
Definition: stats.c:33
fr_stats_t acct
Accounting stats.
Definition: clients.h:61
IPv4/6 prefix.
Definition: inet.h:41
fr_dict_attr_t const * da
Dictionary attribute defines the attribute.
Definition: pair.h:113
struct timeval zombie_period_start
Definition: realms.h:110
home_server_t * home_server_find(fr_ipaddr_t *ipaddr, uint16_t port, int proto)
Definition: realms.c:2660
PW_TYPE type
Value type.
Definition: dict.h:80
uint32_t ema10
Definition: stats.h:61
RADCLIENT * client
The client that originally sent us the request.
Definition: radiusd.h:219
RFC3575/RFC5176 - Disconnect-Nak (not willing to perform)
Definition: radius.h:107
#define RCSID(id)
Definition: build.h:135
fr_uint_t total_unknown_types
Definition: stats.h:51
Accounting server.
Definition: realms.h:37
fr_stats_t radius_dsc_stats
Definition: stats.c:47
home_type_t type
Auth, Acct, CoA etc.
Definition: realms.h:82
fr_stats_ema_t ema
Definition: realms.h:145
RADCLIENT_LIST * listener_find_client_list(fr_ipaddr_t const *ipaddr, uint16_t port, int proto)
Find client list associated with a listener.
Definition: listen.c:3264
uint32_t zombie_period
Unresponsive for T, mark it dead.
Definition: realms.h:111
fr_uint_t total_requests
Definition: stats.h:40
Authentication server.
Definition: realms.h:36
#define USEC
Definition: stats.c:31
RFC3575/RFC5176 - Disconnect-Request.
Definition: radius.h:105
static uint16_t server_port
Definition: radclient.c:49