2 * stats.c Internal statistics handling.
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.
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.
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
20 * Copyright 2008 The FreeRADIUS server project
21 * Copyright 2008 Alan DeKok <aland@deployingradius.com>
26 #include <freeradius-devel/radiusd.h>
27 #include <freeradius-devel/rad_assert.h>
31 #define USEC (1000000)
32 #define EMA_SCALE (100)
33 #define F_EMA_SCALE (1000000)
35 static struct timeval start_time;
36 static struct timeval hup_time;
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 }}
41 fr_stats_t radius_auth_stats = FR_STATS_INIT;
42 #ifdef WITH_ACCOUNTING
43 fr_stats_t radius_acct_stats = FR_STATS_INIT;
46 fr_stats_t radius_coa_stats = FR_STATS_INIT;
47 fr_stats_t radius_dsc_stats = FR_STATS_INIT;
51 fr_stats_t proxy_auth_stats = FR_STATS_INIT;
52 #ifdef WITH_ACCOUNTING
53 fr_stats_t proxy_acct_stats = FR_STATS_INIT;
56 fr_stats_t proxy_coa_stats = FR_STATS_INIT;
57 fr_stats_t proxy_dsc_stats = FR_STATS_INIT;
61 static void tv_sub(struct timeval *end, struct timeval *start,
62 struct timeval *elapsed)
64 elapsed->tv_sec = end->tv_sec - start->tv_sec;
65 if (elapsed->tv_sec > 0) {
67 elapsed->tv_usec = USEC;
71 elapsed->tv_usec += end->tv_usec;
72 elapsed->tv_usec -= start->tv_usec;
74 if (elapsed->tv_usec >= USEC) {
75 elapsed->tv_usec -= USEC;
80 static void stats_time(fr_stats_t *stats, struct timeval *start,
86 if ((start->tv_sec == 0) || (end->tv_sec == 0) ||
87 (end->tv_sec < start->tv_sec)) return;
89 tv_sub(end, start, &diff);
91 if (diff.tv_sec >= 10) {
97 delay = (diff.tv_sec * USEC) + diff.tv_usec;
100 for (i = 0; i < 7; i++) {
110 void request_stats_final(REQUEST *request)
112 if (request->master_state == REQUEST_COUNTED) return;
114 if (!request->listener) return;
115 if (!request->client) return;
117 if ((request->listener->type != RAD_LISTEN_NONE) &&
118 #ifdef WITH_ACCOUNTING
119 (request->listener->type != RAD_LISTEN_ACCT) &&
122 (request->listener->type != RAD_LISTEN_COA) &&
124 (request->listener->type != RAD_LISTEN_AUTH)) return;
126 /* don't count statistic requests */
127 if (request->packet->code == PW_CODE_STATUS_SERVER)
131 #define INC_AUTH(_x) radius_auth_stats._x++;request->listener->stats._x++;request->client->auth._x++;
134 #ifdef WITH_ACCOUNTING
135 #define INC_ACCT(_x) radius_acct_stats._x++;request->listener->stats._x++;request->client->acct._x++
142 #define INC_COA(_x) radius_coa_stats._x++;request->listener->stats._x++;request->client->coa._x++
149 #define INC_DSC(_x) radius_dsc_stats._x++;request->listener->stats._x++;request->client->dsc._x++
155 * Update the statistics.
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.
162 if (request->reply && (request->packet->code != PW_CODE_STATUS_SERVER)) switch (request->reply->code) {
163 case PW_CODE_ACCESS_ACCEPT:
164 INC_AUTH(total_access_accepts);
167 INC_AUTH(total_responses);
170 * FIXME: Do the time calculations once...
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);
183 case PW_CODE_ACCESS_REJECT:
184 INC_AUTH(total_access_rejects);
187 case PW_CODE_ACCESS_CHALLENGE:
188 INC_AUTH(total_access_challenges);
191 #ifdef WITH_ACCOUNTING
192 case PW_CODE_ACCOUNTING_RESPONSE:
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);
204 case PW_CODE_COA_ACK:
205 INC_COA(total_access_accepts);
207 INC_COA(total_responses);
208 stats_time(&request->client->coa,
209 &request->packet->timestamp,
210 &request->reply->timestamp);
213 case PW_CODE_COA_NAK:
214 INC_COA(total_access_rejects);
217 case PW_CODE_DISCONNECT_ACK:
218 INC_DSC(total_access_accepts);
220 INC_DSC(total_responses);
221 stats_time(&request->client->dsc,
222 &request->packet->timestamp,
223 &request->reply->timestamp);
226 case PW_CODE_DISCONNECT_NAK:
227 INC_DSC(total_access_rejects);
232 * No response, it must have been a bad
236 if (request->packet->code == PW_CODE_ACCESS_REQUEST) {
237 if (request->reply->offset == -2) {
238 INC_AUTH(total_bad_authenticators);
240 INC_AUTH(total_packets_dropped);
242 } else if (request->packet->code == PW_CODE_ACCOUNTING_REQUEST) {
243 if (request->reply->offset == -2) {
244 INC_ACCT(total_bad_authenticators);
246 INC_ACCT(total_packets_dropped);
256 if (!request->proxy || !request->home_server) goto done; /* simplifies formatting */
258 switch (request->proxy->code) {
259 case PW_CODE_ACCESS_REQUEST:
260 proxy_auth_stats.total_requests += request->num_proxied_requests;
261 request->home_server->stats.total_requests += request->num_proxied_requests;
264 #ifdef WITH_ACCOUNTING
265 case PW_CODE_ACCOUNTING_REQUEST:
266 proxy_acct_stats.total_requests += request->num_proxied_requests;
267 request->home_server->stats.total_requests += request->num_proxied_requests;
272 case PW_CODE_COA_REQUEST:
273 proxy_coa_stats.total_requests += request->num_proxied_requests;
274 request->home_server->stats.total_requests += request->num_proxied_requests;
277 case PW_CODE_DISCONNECT_REQUEST:
278 proxy_dsc_stats.total_requests += request->num_proxied_requests;
279 request->home_server->stats.total_requests += request->num_proxied_requests;
287 if (!request->proxy_reply) goto done; /* simplifies formatting */
290 #define INC(_x) proxy_auth_stats._x += request->num_proxied_responses; request->home_server->stats._x += request->num_proxied_responses;
292 switch (request->proxy_reply->code) {
293 case PW_CODE_ACCESS_ACCEPT:
294 INC(total_access_accepts);
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);
305 case PW_CODE_ACCESS_REJECT:
306 INC(total_access_rejects);
309 case PW_CODE_ACCESS_CHALLENGE:
310 INC(total_access_challenges);
313 #ifdef WITH_ACCOUNTING
314 case PW_CODE_ACCOUNTING_RESPONSE:
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);
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);
339 case PW_CODE_DISCONNECT_ACK:
340 case PW_CODE_DISCONNECT_NAK:
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);
353 proxy_auth_stats.total_unknown_types++;
354 request->home_server->stats.total_unknown_types++;
359 #endif /* WITH_PROXY */
361 request->master_state = REQUEST_COUNTED;
364 typedef struct fr_stats2vp {
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) },
389 * Proxied authentication requests.
391 static fr_stats2vp proxy_authvp[] = {
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) },
407 #ifdef WITH_ACCOUNTING
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) },
423 static fr_stats2vp proxy_acctvp[] = {
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) },
436 static fr_stats2vp client_authvp[] = {
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) },
450 #ifdef WITH_ACCOUNTING
451 static fr_stats2vp client_acctvp[] = {
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) },
463 static void request_stats_addvp(REQUEST *request,
464 fr_stats2vp *table, fr_stats_t *stats)
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);
475 counter = *(fr_uint_t *) (((uint8_t *) stats) + table[i].offset);
476 vp->vp_integer = counter;
481 void request_stats_reply(REQUEST *request)
483 VALUE_PAIR *flag, *vp;
486 * Statistics are available ONLY on a "status" port.
488 rad_assert(request->packet->code == PW_CODE_STATUS_SERVER);
489 rad_assert(request->listener->type == RAD_LISTEN_NONE);
491 flag = fr_pair_find_by_num(request->packet->vps, PW_FREERADIUS_STATISTICS_TYPE, VENDORPEC_FREERADIUS, TAG_ANY);
492 if (!flag || (flag->vp_integer == 0)) return;
497 if (((flag->vp_integer & 0x01) != 0) &&
498 ((flag->vp_integer & 0xc0) == 0)) {
499 request_stats_addvp(request, authvp, &radius_auth_stats);
502 #ifdef WITH_ACCOUNTING
506 if (((flag->vp_integer & 0x02) != 0) &&
507 ((flag->vp_integer & 0xc0) == 0)) {
508 request_stats_addvp(request, acctvp, &radius_acct_stats);
514 * Proxied authentication requests.
516 if (((flag->vp_integer & 0x04) != 0) &&
517 ((flag->vp_integer & 0x20) == 0)) {
518 request_stats_addvp(request, proxy_authvp, &proxy_auth_stats);
521 #ifdef WITH_ACCOUNTING
523 * Proxied accounting requests.
525 if (((flag->vp_integer & 0x08) != 0) &&
526 ((flag->vp_integer & 0x20) == 0)) {
527 request_stats_addvp(request, proxy_acctvp, &proxy_acct_stats);
533 * Internal server statistics
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;
543 #ifdef HAVE_PTHREAD_H
544 int i, array[RAD_LISTEN_MAX], pps[2];
546 thread_pool_queue_stats(array, pps);
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);
553 vp->vp_integer = array[i];
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);
561 vp->vp_integer = pps[i];
567 * For a particular client.
569 if ((flag->vp_integer & 0x20) != 0) {
571 VALUE_PAIR *server_ip, *server_port = NULL;
572 RADCLIENT *client = NULL;
573 RADCLIENT_LIST *cl = NULL;
576 * See if we need to look up the client by server
579 server_ip = fr_pair_find_by_num(request->packet->vps, PW_FREERADIUS_STATS_SERVER_IP_ADDRESS, VENDORPEC_FREERADIUS, TAG_ANY);
581 server_port = fr_pair_find_by_num(request->packet->vps, PW_FREERADIUS_STATS_SERVER_PORT, VENDORPEC_FREERADIUS, TAG_ANY);
585 ipaddr.ipaddr.ip4addr.s_addr = server_ip->vp_ipaddr;
586 cl = listener_find_client_list(&ipaddr, server_port->vp_integer, IPPROTO_UDP);
589 * Not found: don't do anything
596 vp = fr_pair_find_by_num(request->packet->vps, PW_FREERADIUS_STATS_CLIENT_IP_ADDRESS, VENDORPEC_FREERADIUS, TAG_ANY);
598 memset(&ipaddr, 0, sizeof(ipaddr));
600 ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
601 client = client_find(cl, &ipaddr, IPPROTO_UDP);
604 client = client_find(cl, &ipaddr, IPPROTO_TCP);
609 * Else look it up by number.
611 } else if ((vp = fr_pair_find_by_num(request->packet->vps, PW_FREERADIUS_STATS_CLIENT_NUMBER, VENDORPEC_FREERADIUS, TAG_ANY)) != NULL) {
612 client = client_findbynumber(cl, vp->vp_integer);
617 * If found, echo it back, along with
618 * the requested statistics.
620 fr_pair_add(&request->reply->vps, fr_pair_copy(request->reply, vp));
623 * When retrieving client by number, also
624 * echo back it's IP address.
626 if ((vp->da->type == PW_TYPE_INTEGER) &&
627 (client->ipaddr.af == AF_INET)) {
628 vp = radius_pair_create(request->reply,
629 &request->reply->vps,
630 PW_FREERADIUS_STATS_CLIENT_IP_ADDRESS, VENDORPEC_FREERADIUS);
632 vp->vp_ipaddr = client->ipaddr.ipaddr.ip4addr.s_addr;
635 if (client->ipaddr.prefix != 32) {
636 vp = radius_pair_create(request->reply,
637 &request->reply->vps,
638 PW_FREERADIUS_STATS_CLIENT_NETMASK, VENDORPEC_FREERADIUS);
640 vp->vp_integer = client->ipaddr.prefix;
646 fr_pair_add(&request->reply->vps,
647 fr_pair_copy(request->reply, server_ip));
650 fr_pair_add(&request->reply->vps,
651 fr_pair_copy(request->reply, server_port));
654 if ((flag->vp_integer & 0x01) != 0) {
655 request_stats_addvp(request, client_authvp,
658 #ifdef WITH_ACCOUNTING
659 if ((flag->vp_integer & 0x02) != 0) {
660 request_stats_addvp(request, client_acctvp,
664 } /* else client wasn't found, don't echo it back */
668 * For a particular "listen" socket.
670 if (((flag->vp_integer & 0x40) != 0) &&
671 ((flag->vp_integer & 0x03) != 0)) {
673 VALUE_PAIR *server_ip, *server_port;
677 * See if we need to look up the server by socket
680 server_ip = fr_pair_find_by_num(request->packet->vps, PW_FREERADIUS_STATS_SERVER_IP_ADDRESS, VENDORPEC_FREERADIUS, TAG_ANY);
681 if (!server_ip) return;
683 server_port = fr_pair_find_by_num(request->packet->vps, PW_FREERADIUS_STATS_SERVER_PORT, VENDORPEC_FREERADIUS, TAG_ANY);
684 if (!server_port) return;
687 ipaddr.ipaddr.ip4addr.s_addr = server_ip->vp_ipaddr;
688 this = listener_find_byipaddr(&ipaddr,
689 server_port->vp_integer,
693 * Not found: don't do anything
697 fr_pair_add(&request->reply->vps,
698 fr_pair_copy(request->reply, server_ip));
699 fr_pair_add(&request->reply->vps,
700 fr_pair_copy(request->reply, server_port));
702 if (((flag->vp_integer & 0x01) != 0) &&
703 ((request->listener->type == RAD_LISTEN_AUTH) ||
704 (request->listener->type == RAD_LISTEN_NONE))) {
705 request_stats_addvp(request, authvp, &this->stats);
708 #ifdef WITH_ACCOUNTING
709 if (((flag->vp_integer & 0x02) != 0) &&
710 ((request->listener->type == RAD_LISTEN_ACCT) ||
711 (request->listener->type == RAD_LISTEN_NONE))) {
712 request_stats_addvp(request, acctvp, &this->stats);
721 if (((flag->vp_integer & 0x80) != 0) &&
722 ((flag->vp_integer & 0x03) != 0)) {
724 VALUE_PAIR *server_ip, *server_port;
728 * See if we need to look up the server by socket
731 server_ip = fr_pair_find_by_num(request->packet->vps, PW_FREERADIUS_STATS_SERVER_IP_ADDRESS, VENDORPEC_FREERADIUS, TAG_ANY);
732 if (!server_ip) return;
734 server_port = fr_pair_find_by_num(request->packet->vps, PW_FREERADIUS_STATS_SERVER_PORT, VENDORPEC_FREERADIUS, TAG_ANY);
735 if (!server_port) return;
738 memset(&ipaddr, 0, sizeof(ipaddr));
741 ipaddr.ipaddr.ip4addr.s_addr = server_ip->vp_ipaddr;
742 home = home_server_find(&ipaddr, server_port->vp_integer,
746 * Not found: don't do anything
750 fr_pair_add(&request->reply->vps,
751 fr_pair_copy(request->reply, server_ip));
752 fr_pair_add(&request->reply->vps,
753 fr_pair_copy(request->reply, server_port));
755 vp = radius_pair_create(request->reply, &request->reply->vps,
756 PW_FREERADIUS_STATS_SERVER_OUTSTANDING_REQUESTS, VENDORPEC_FREERADIUS);
757 if (vp) vp->vp_integer = home->currently_outstanding;
759 vp = radius_pair_create(request->reply, &request->reply->vps,
760 PW_FREERADIUS_STATS_SERVER_STATE, VENDORPEC_FREERADIUS);
761 if (vp) vp->vp_integer = home->state;
763 if ((home->state == HOME_STATE_ALIVE) &&
764 (home->revive_time.tv_sec != 0)) {
765 vp = radius_pair_create(request->reply, &request->reply->vps,
766 PW_FREERADIUS_STATS_SERVER_TIME_OF_LIFE, VENDORPEC_FREERADIUS);
767 if (vp) vp->vp_date = home->revive_time.tv_sec;
770 if ((home->state == HOME_STATE_ALIVE) &&
771 (home->ema.window > 0)) {
772 vp = radius_pair_create(request->reply,
773 &request->reply->vps,
774 PW_FREERADIUS_SERVER_EMA_WINDOW, VENDORPEC_FREERADIUS);
775 if (vp) vp->vp_integer = home->ema.window;
776 vp = radius_pair_create(request->reply,
777 &request->reply->vps,
778 PW_FREERADIUS_SERVER_EMA_USEC_WINDOW_1, VENDORPEC_FREERADIUS);
779 if (vp) vp->vp_integer = home->ema.ema1 / EMA_SCALE;
780 vp = radius_pair_create(request->reply,
781 &request->reply->vps,
782 PW_FREERADIUS_SERVER_EMA_USEC_WINDOW_10, VENDORPEC_FREERADIUS);
783 if (vp) vp->vp_integer = home->ema.ema10 / EMA_SCALE;
787 if (home->state == HOME_STATE_IS_DEAD) {
788 vp = radius_pair_create(request->reply, &request->reply->vps,
789 PW_FREERADIUS_STATS_SERVER_TIME_OF_DEATH, VENDORPEC_FREERADIUS);
790 if (vp) vp->vp_date = home->zombie_period_start.tv_sec + home->zombie_period;
794 * Show more information...
796 * FIXME: do this for clients, too!
798 vp = radius_pair_create(request->reply, &request->reply->vps,
799 PW_FREERADIUS_STATS_LAST_PACKET_RECV, VENDORPEC_FREERADIUS);
800 if (vp) vp->vp_date = home->last_packet_recv;
802 vp = radius_pair_create(request->reply, &request->reply->vps,
803 PW_FREERADIUS_STATS_LAST_PACKET_SENT, VENDORPEC_FREERADIUS);
804 if (vp) vp->vp_date = home->last_packet_sent;
806 if (((flag->vp_integer & 0x01) != 0) &&
807 (home->type == HOME_TYPE_AUTH)) {
808 request_stats_addvp(request, proxy_authvp,
812 #ifdef WITH_ACCOUNTING
813 if (((flag->vp_integer & 0x02) != 0) &&
814 (home->type == HOME_TYPE_ACCT)) {
815 request_stats_addvp(request, proxy_acctvp,
820 #endif /* WITH_PROXY */
823 void radius_stats_init(int flag)
826 gettimeofday(&start_time, NULL);
827 hup_time = start_time; /* it's just nicer this way */
829 gettimeofday(&hup_time, NULL);
833 void radius_stats_ema(fr_stats_ema_t *ema,
834 struct timeval *start, struct timeval *end)
838 #ifdef WITH_STATS_DEBUG
841 if (ema->window == 0) return;
843 rad_assert(start->tv_sec <= end->tv_sec);
849 if (ema->window > 10000) ema->window = 10000;
851 ema->f1 = (2 * F_EMA_SCALE) / (ema->window + 1);
852 ema->f10 = (2 * F_EMA_SCALE) / ((10 * ema->window) + 1);
856 tdiff = start->tv_sec;
857 tdiff -= end->tv_sec;
860 if (micro > 40) micro = 40; /* don't overflow 32-bit ints */
862 micro += start->tv_usec;
863 micro -= end->tv_usec;
867 if (ema->ema1 == 0) {
873 diff = ema->f1 * (micro - ema->ema1);
874 ema->ema1 += (diff / 1000000);
876 diff = ema->f10 * (micro - ema->ema10);
877 ema->ema10 += (diff / 1000000);
881 #ifdef WITH_STATS_DEBUG
882 DEBUG("time %d %d.%06d\t%d.%06d\t%d.%06d\n",
883 n, micro / PREC, (micro / EMA_SCALE) % USEC,
884 ema->ema1 / PREC, (ema->ema1 / EMA_SCALE) % USEC,
885 ema->ema10 / PREC, (ema->ema10 / EMA_SCALE) % USEC);
890 #endif /* WITH_STATS */