Namespace cleanup of scheduler, remove "polling" sockets
[olsrd.git] / lib / debuginfo / src / olsrd_debuginfo.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon(olsrd)
4  * Copyright (c) 2004-2009, the olsr.org team - see HISTORY file
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  *   notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above copyright
14  *   notice, this list of conditions and the following disclaimer in
15  *   the documentation and/or other materials provided with the
16  *   distribution.
17  * * Neither the name of olsr.org, olsrd nor the names of its
18  *   contributors may be used to endorse or promote products derived
19  *   from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  * Visit http://www.olsr.org for more information.
35  *
36  * If you find this software useful feel free to make a donation
37  * to the project. For more information see the website or contact
38  * the copyright holders.
39  *
40  */
41
42 /*
43  * Dynamic linked library for the olsr.org olsr daemon
44  */
45
46 #include <stdlib.h>
47
48 #include "olsr.h"
49 #include "ipcalc.h"
50 #include "neighbor_table.h"
51 #include "tc_set.h"
52 #include "hna_set.h"
53 #include "mid_set.h"
54 #include "routing_table.h"
55 #include "olsr_logging.h"
56 #include "olsr_ip_prefix_list.h"
57 #include "parser.h"
58 #include "olsr_comport_txt.h"
59 #include "olsrd_debuginfo.h"
60 #include "olsr_types.h"
61 #include "defs.h"
62
63 #include "common/autobuf.h"
64
65 #define PLUGIN_DESCR    "OLSRD debuginfo plugin"
66 #define PLUGIN_AUTHOR   "Henning Rogge"
67
68 struct debuginfo_cmd {
69   const char *name;
70   olsr_txthandler handler;
71   struct olsr_txtcommand *cmd;
72 };
73
74 static int debuginfo_init(void);
75 static int debuginfo_enable(void);
76 static int debuginfo_exit(void);
77
78
79 static enum olsr_txtcommand_result debuginfo_msgstat(struct comport_connection *con,
80     const char *cmd, const char *param);
81 static enum olsr_txtcommand_result debuginfo_pktstat(struct comport_connection *con,
82     const char *cmd, const char *param);
83 static enum olsr_txtcommand_result debuginfo_cookies(struct comport_connection *con,
84     const char *cmd, const char *param);
85
86 static void update_statistics_ptr(void *);
87 static void olsr_msg_statistics(struct olsr_message *,
88     struct interface *, union olsr_ip_addr *, enum duplicate_status);
89 static uint8_t *olsr_packet_statistics(uint8_t *binary,
90     struct interface *interface, union olsr_ip_addr *ip, int *length);
91
92 static void update_statistics_ptr(void *data __attribute__ ((unused)));
93
94 /* plugin configuration */
95 static struct ip_acl allowed_nets;
96 static uint32_t traffic_interval, traffic_slots, current_slot;
97
98 /* plugin parameters */
99 static const struct olsrd_plugin_parameters plugin_parameters[] = {
100   {.name = IP_ACL_ACCEPT_PARAP,.set_plugin_parameter = &ip_acl_add_plugin_accept,.data = &allowed_nets},
101   {.name = IP_ACL_REJECT_PARAM,.set_plugin_parameter = &ip_acl_add_plugin_reject,.data = &allowed_nets},
102   {.name = IP_ACL_CHECKFIRST_PARAM,.set_plugin_parameter = &ip_acl_add_plugin_checkFirst,.data = &allowed_nets},
103   {.name = IP_ACL_DEFAULTPOLICY_PARAM,.set_plugin_parameter = &ip_acl_add_plugin_defaultPolicy,.data = &allowed_nets},
104   {.name = "stat_interval", .set_plugin_parameter = &set_plugin_int, .data = &traffic_interval},
105   {.name = "stat_slots", .set_plugin_parameter = &set_plugin_int, .data = &traffic_slots},
106 };
107
108 OLSR_PLUGIN6(plugin_parameters) {
109   .descr = PLUGIN_DESCR,
110   .author = PLUGIN_AUTHOR,
111   .init = debuginfo_init,
112   .enable = debuginfo_enable,
113   .exit = debuginfo_exit,
114   .deactivate = false
115 };
116
117 /* command callbacks and names */
118 static struct debuginfo_cmd commands[] = {
119     {"msgstat", &debuginfo_msgstat, NULL},
120     {"pktstat", &debuginfo_pktstat, NULL},
121     {"cookies", &debuginfo_cookies, NULL}
122 };
123
124 /* variables for statistics */
125 static struct avl_tree stat_msg_tree, stat_pkt_tree;
126
127 static struct debug_msgtraffic_count total_msg_traffic;
128 static struct debug_pkttraffic_count total_pkt_traffic;
129
130 static struct olsr_memcookie_info *statistics_msg_mem = NULL;
131 static struct olsr_memcookie_info *statistics_pkt_mem = NULL;
132
133 static struct olsr_timer_info *statistics_timer = NULL;
134
135 static union olsr_ip_addr total_ip_addr;
136
137
138 /**
139  *Constructor
140  */
141 static int
142 debuginfo_init(void)
143 {
144   ip_acl_init(&allowed_nets);
145
146   traffic_interval = 5; /* seconds */
147   traffic_slots = 12;      /* number of 5000 second slots */
148   current_slot = 0;
149
150   memset(&total_ip_addr, 255, sizeof(total_ip_addr));
151   return 0;
152 }
153
154 /**
155  *Destructor
156  */
157 static int
158 debuginfo_exit(void)
159 {
160   size_t i;
161
162   for (i=0; i<ARRAYSIZE(commands); i++) {
163     olsr_com_remove_normal_txtcommand(commands[i].cmd);
164   }
165   olsr_parser_remove_function(&olsr_msg_statistics);
166   olsr_preprocessor_remove_function(&olsr_packet_statistics);
167   ip_acl_flush(&allowed_nets);
168   return 0;
169 }
170
171 static int
172 debuginfo_enable(void)
173 {
174   size_t i;
175
176   /* always allow localhost */
177   if (olsr_cnf->ip_version == AF_INET) {
178     union olsr_ip_addr ip;
179
180     ip.v4.s_addr = ntohl(INADDR_LOOPBACK);
181     ip_acl_add(&allowed_nets, &ip, 32, false);
182   } else {
183     ip_acl_add(&allowed_nets, (const union olsr_ip_addr *)&in6addr_loopback, 128, false);
184     ip_acl_add(&allowed_nets, (const union olsr_ip_addr *)&in6addr_v4mapped_loopback, 128, false);
185   }
186
187   for (i=0; i<ARRAYSIZE(commands); i++) {
188     commands[i].cmd = olsr_com_add_normal_txtcommand(commands[i].name, commands[i].handler);
189     commands[i].cmd->acl = &allowed_nets;
190   }
191
192   statistics_timer = olsr_timer_add("debuginfo timer", &update_statistics_ptr, true);
193   olsr_timer_start(traffic_interval * 1000, 0, NULL, statistics_timer);
194
195   statistics_msg_mem = olsr_memcookie_add("debuginfo msgstat",
196       sizeof(struct debug_msgtraffic) + sizeof(struct debug_msgtraffic_count) * traffic_slots);
197
198   statistics_pkt_mem = olsr_memcookie_add("debuginfo pktstat",
199       sizeof(struct debug_pkttraffic) + sizeof(struct debug_pkttraffic_count) * traffic_slots);
200
201   memset(&total_msg_traffic, 0, sizeof(total_msg_traffic));
202   memset(&total_pkt_traffic, 0, sizeof(total_pkt_traffic));
203   avl_init(&stat_msg_tree, avl_comp_default, false, NULL);
204   avl_init(&stat_pkt_tree, avl_comp_default, false, NULL);
205
206   olsr_parser_add_function(&olsr_msg_statistics, PROMISCUOUS);
207   olsr_preprocessor_add_function(&olsr_packet_statistics);
208   return 0;
209 }
210
211 static struct debug_msgtraffic *get_msgtraffic_entry(union olsr_ip_addr *ip) {
212   struct debug_msgtraffic *tr;
213   tr = (struct debug_msgtraffic *) avl_find(&stat_msg_tree, ip);
214   if (tr == NULL) {
215     tr = olsr_memcookie_malloc(statistics_msg_mem);
216
217     memcpy(&tr->ip, ip, sizeof(union olsr_ip_addr));
218     tr->node.key = &tr->ip;
219
220     avl_insert(&stat_msg_tree, &tr->node);
221   }
222   return tr;
223 }
224
225 static struct debug_pkttraffic *get_pkttraffic_entry(union olsr_ip_addr *ip, struct interface *in) {
226   struct debug_pkttraffic *tr;
227   tr = (struct debug_pkttraffic *) avl_find(&stat_pkt_tree, ip);
228   if (tr == NULL) {
229     tr = olsr_memcookie_malloc(statistics_pkt_mem);
230
231     memcpy(&tr->ip, ip, sizeof(union olsr_ip_addr));
232     tr->node.key = &tr->ip;
233
234     tr->int_name = strdup(in ? in->int_name : "---");
235
236     avl_insert(&stat_pkt_tree, &tr->node);
237   }
238   return tr;
239 }
240
241 static void
242 update_statistics_ptr(void *data __attribute__ ((unused)))
243 {
244   struct debug_msgtraffic *msg, *msg_iterator;
245   struct debug_pkttraffic *pkt, *pkt_iterator;
246   uint32_t last_slot, i;
247
248   last_slot = current_slot;
249   current_slot++;
250   if (current_slot == traffic_slots) {
251     current_slot = 0;
252   }
253
254   /* move data from "current" template to slot array */
255   OLSR_FOR_ALL_MSGTRAFFIC_ENTRIES(msg, msg_iterator) {
256     /* subtract old values from node count and total count */
257     for (i=0; i<DTR_MSG_COUNT; i++) {
258       msg->total.data[i] -= msg->traffic[current_slot].data[i];
259     }
260
261     /* copy new traffic into slot */
262     msg->traffic[current_slot] = msg->current;
263
264     /* add new values to node count and total count */
265     for (i=0; i<DTR_MSG_COUNT; i++) {
266       msg->total.data[i] += msg->current.data[i];
267     }
268
269     /* erase new traffic */
270     memset(&msg->current, 0, sizeof(msg->current));
271
272     if (msg->total.data[DTR_MESSAGES] == 0) {
273       /* no traffic left, cleanup ! */
274
275       avl_delete(&stat_msg_tree, &msg->node);
276       olsr_memcookie_free(statistics_msg_mem, msg);
277     }
278   }
279
280   OLSR_FOR_ALL_PKTTRAFFIC_ENTRIES(pkt, pkt_iterator) {
281     /* subtract old values from node count and total count */
282     for (i=0; i<DTR_PKT_COUNT; i++) {
283       pkt->total.data[i] -= pkt->traffic[current_slot].data[i];
284     }
285
286     /* copy new traffic into slot */
287     pkt->traffic[current_slot] = pkt->current;
288
289     /* add new values to node count and total count */
290     for (i=0; i<DTR_PKT_COUNT; i++) {
291       pkt->total.data[i] += pkt->current.data[i];
292     }
293
294     /* erase new traffic */
295     memset(&pkt->current, 0, sizeof(pkt->current));
296
297     if (pkt->total.data[DTR_PACKETS] == 0) {
298       /* no traffic left, cleanup ! */
299
300       avl_delete(&stat_pkt_tree, &pkt->node);
301       free(pkt->int_name);
302       olsr_memcookie_free(statistics_pkt_mem, pkt);
303     }
304   }
305 }
306
307 /* update message statistics */
308 static void
309 olsr_msg_statistics(struct olsr_message *msg,
310     struct interface *input_if __attribute__ ((unused)),
311     union olsr_ip_addr *from_addr __attribute__ ((unused)), enum duplicate_status status  __attribute__ ((unused)))
312 {
313   enum debug_msgtraffic_type type;
314   struct debug_msgtraffic *tr;
315 #if !defined REMOVE_LOG_DEBUG
316   struct ipaddr_str buf;
317 #endif
318
319   switch (msg->type) {
320   case HELLO_MESSAGE:
321     type = DTR_HELLO;
322     break;
323   case TC_MESSAGE:
324     type = DTR_TC;
325     break;
326   case MID_MESSAGE:
327     type = DTR_MID;
328     break;
329   case HNA_MESSAGE:
330     type = DTR_HNA;
331     break;
332   case LQ_HELLO_MESSAGE:
333     type = DTR_HELLO;
334     break;
335   case LQ_TC_MESSAGE:
336     type = DTR_TC;
337     break;
338   default:
339     type = DTR_OTHER;
340     break;
341   }
342
343   /* input data for specific node */
344   tr = get_msgtraffic_entry(&msg->originator);
345   tr->current.data[type]++;
346   tr->current.data[DTR_MESSAGES]++;
347   tr->current.data[DTR_MSG_TRAFFIC] += msg->size;
348
349   OLSR_DEBUG(LOG_PLUGINS, "Added message type %d to statistics of %s: %d\n",
350       type, olsr_ip_to_string(&buf, &tr->ip), tr->current.data[type]);
351
352   /* input data for total traffic handling */
353   tr = get_msgtraffic_entry(&total_ip_addr);
354   tr->current.data[type]++;
355   tr->current.data[DTR_MESSAGES]++;
356   tr->current.data[DTR_MSG_TRAFFIC] += msg->size;
357 }
358
359 /* update traffic statistics */
360 static uint8_t *
361 olsr_packet_statistics(uint8_t *binary, struct interface *interface, union olsr_ip_addr *ip, int *length)
362 {
363   struct debug_pkttraffic *tr;
364   tr = get_pkttraffic_entry(ip, interface);
365   tr->current.data[DTR_PACK_TRAFFIC] += *length;
366   tr->current.data[DTR_PACKETS] ++;
367
368   tr = get_pkttraffic_entry(&total_ip_addr, NULL);
369   tr->current.data[DTR_PACK_TRAFFIC] += *length;
370   tr->current.data[DTR_PACKETS] ++;
371   return binary;
372 }
373
374 static const char *debuginfo_print_trafficip(struct ipaddr_str *buf, union olsr_ip_addr *ip) {
375   static const char *total = "Total";
376   if (olsr_ipcmp(ip, &total_ip_addr) == 0) {
377     return total;
378   }
379   return olsr_ip_to_string(buf, ip);
380 }
381
382 static bool debuginfo_print_msgstat(struct autobuf *buf, union olsr_ip_addr *ip, struct debug_msgtraffic_count *cnt) {
383   struct ipaddr_str strbuf;
384   return abuf_appendf(buf, "%-*s\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t\n",
385       olsr_cnf->ip_version == AF_INET ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN, debuginfo_print_trafficip(&strbuf, ip),
386       cnt->data[DTR_HELLO],
387       cnt->data[DTR_TC],
388       cnt->data[DTR_MID],
389       cnt->data[DTR_HNA],
390       cnt->data[DTR_OTHER],
391       cnt->data[DTR_MESSAGES],
392       cnt->data[DTR_MSG_TRAFFIC]) < 0;
393 }
394
395 static enum olsr_txtcommand_result
396 debuginfo_msgstat(struct comport_connection *con,
397     const char *cmd __attribute__ ((unused)), const char *param __attribute__ ((unused)))
398 {
399   struct debug_msgtraffic *tr, *iterator;
400
401   if (abuf_appendf(&con->out, "Slot size: %d seconds\tSlot count: %d\n", traffic_interval, traffic_slots) < 0) {
402     return ABUF_ERROR;
403   }
404   if (abuf_appendf(&con->out,
405       "Table: Statistics (without duplicates)\n%-*s\tHello\tTC\tMID\tHNA\tOther\tTotal\tBytes\n",
406       olsr_cnf->ip_version == AF_INET ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN, "IP"
407       ) < 0) {
408     return ABUF_ERROR;
409   }
410
411   if (param == NULL || strcasecmp(param, "node") == 0) {
412     OLSR_FOR_ALL_MSGTRAFFIC_ENTRIES(tr, iterator) {
413       if (debuginfo_print_msgstat(&con->out, &tr->ip, &tr->traffic[current_slot])) {
414         return ABUF_ERROR;
415       }
416     }
417   }
418   else {
419     uint32_t mult = 1, divisor = 1;
420     struct debug_msgtraffic_count cnt;
421     int i;
422
423     if (strcasecmp(param, "total") == 0) {
424       divisor = 1;
425     }
426     else if (strcasecmp(param, "average") == 0) {
427       divisor = traffic_slots;
428     }
429     else if (strcasecmp(param, "avgsec") == 0) {
430       divisor = traffic_slots * traffic_interval;
431       mult = 1;
432     }
433     else if (strcasecmp(param, "avgmin") == 0) {
434       divisor = traffic_slots * traffic_interval;
435       mult = 60;
436     }
437     else if (strcasecmp(param, "avghour") == 0) {
438       divisor = traffic_slots * traffic_interval;
439       mult = 3600;
440     }
441     else {
442       abuf_appendf(&con->out, "Error, unknown parameter %s for msgstat\n", param);
443       return CONTINUE;
444     }
445
446     OLSR_FOR_ALL_MSGTRAFFIC_ENTRIES(tr, iterator) {
447       for (i=0; i<DTR_MSG_COUNT; i++) {
448         cnt.data[i] = (tr->total.data[i] * mult) / divisor;
449       }
450       if (debuginfo_print_msgstat(&con->out, &tr->ip, &cnt)) {
451         return ABUF_ERROR;
452       }
453     }
454   }
455
456   return CONTINUE;
457 }
458
459 static bool debuginfo_print_pktstat(struct autobuf *buf, union olsr_ip_addr *ip, char *int_name, struct debug_pkttraffic_count *cnt) {
460   struct ipaddr_str strbuf;
461   return abuf_appendf(buf, "%-*s\t%s\t%d\t%d\n",
462       olsr_cnf->ip_version == AF_INET ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN, debuginfo_print_trafficip(&strbuf, ip),
463       int_name,
464       cnt->data[DTR_PACKETS],
465       cnt->data[DTR_PACK_TRAFFIC]) < 0;
466 }
467
468 static enum olsr_txtcommand_result
469 debuginfo_pktstat(struct comport_connection *con,
470     const char *cmd __attribute__ ((unused)), const char *param __attribute__ ((unused)))
471 {
472   struct debug_pkttraffic *tr, *iterator;
473
474   if (abuf_appendf(&con->out, "Slot size: %d seconds\tSlot count: %d\n", traffic_interval, traffic_slots) < 0) {
475     return ABUF_ERROR;
476   }
477   if (abuf_appendf(&con->out,
478       "Table: Statistics (without duplicates)\n%-*s\tInterf.\tPackets\tBytes\n",
479       olsr_cnf->ip_version == AF_INET ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN, "IP"
480       ) < 0) {
481     return ABUF_ERROR;
482   }
483
484   if (param == NULL || strcasecmp(param, "node") == 0) {
485     OLSR_FOR_ALL_PKTTRAFFIC_ENTRIES(tr, iterator) {
486       if (debuginfo_print_pktstat(&con->out, &tr->ip, tr->int_name, &tr->traffic[current_slot])) {
487         return ABUF_ERROR;
488       }
489     }
490   }
491   else {
492     uint32_t mult = 1, divisor = 1;
493     struct debug_pkttraffic_count cnt;
494     int i;
495
496     if (strcasecmp(param, "total") == 0) {
497       divisor = 1;
498     }
499     else if (strcasecmp(param, "average") == 0) {
500       divisor = traffic_slots;
501     }
502     else if (strcasecmp(param, "avgsec") == 0) {
503       divisor = traffic_slots * traffic_interval;
504       mult = 1;
505     }
506     else if (strcasecmp(param, "avgmin") == 0) {
507       divisor = traffic_slots * traffic_interval;
508       mult = 60;
509     }
510     else if (strcasecmp(param, "avghour") == 0) {
511       divisor = traffic_slots * traffic_interval;
512       mult = 3600;
513     }
514     else {
515       abuf_appendf(&con->out, "Error, unknown parameter %s for msgstat\n", param);
516       return CONTINUE;
517     }
518
519     OLSR_FOR_ALL_PKTTRAFFIC_ENTRIES(tr, iterator) {
520       for (i=0; i<DTR_PKT_COUNT; i++) {
521         cnt.data[i] = (tr->total.data[i] * mult) / divisor;
522       }
523       if (debuginfo_print_pktstat(&con->out, &tr->ip, tr->int_name, &cnt)) {
524         return ABUF_ERROR;
525       }
526     }
527   }
528
529   return CONTINUE;
530 }
531
532 static INLINE bool debuginfo_print_cookies_mem(struct autobuf *buf) {
533   struct olsr_memcookie_info *c, *iterator;
534
535   OLSR_FOR_ALL_COOKIES(c, iterator) {
536     if (abuf_appendf(buf, "%-25s (MEMORY) size: %lu usage: %u freelist: %u\n",
537         c->ci_name, (unsigned long)c->ci_size, c->ci_usage, c->ci_free_list_usage) < 0) {
538       return true;
539     }
540   }
541   return false;
542 }
543
544 static INLINE bool debuginfo_print_cookies_timer(struct autobuf *buf) {
545   struct olsr_timer_info *t, *iterator;
546
547   OLSR_FOR_ALL_TIMERS(t, iterator) {
548     if (abuf_appendf(buf, "%-25s (TIMER) usage: %u changes: %u\n",
549         t->name, t->usage, t->changes) < 0) {
550       return true;
551     }
552   }
553   return false;
554 }
555
556 static enum olsr_txtcommand_result
557 debuginfo_cookies(struct comport_connection *con,
558     const char *cmd __attribute__ ((unused)), const char *param __attribute__ ((unused)))
559 {
560   if (abuf_puts(&con->out, "Memory cookies:\n") < 0) {
561     return ABUF_ERROR;
562   }
563
564   if (debuginfo_print_cookies_mem(&con->out)) {
565     return ABUF_ERROR;
566   }
567
568   if (abuf_puts(&con->out, "\nTimer cookies:\n") < 0) {
569     return ABUF_ERROR;
570   }
571
572   if (debuginfo_print_cookies_timer(&con->out)) {
573     return ABUF_ERROR;
574   }
575   return CONTINUE;
576 }
577
578 /*
579  * Local Variables:
580  * mode: c
581  * style: linux
582  * c-basic-offset: 4
583  * indent-tabs-mode: nil
584  * End:
585  */