5c2dafc3814059f20ac0e928d98d5cf35746cec4
[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_NAME    "OLSRD debuginfo plugin"
66 #define PLUGIN_VERSION "0.1"
67 #define PLUGIN_AUTHOR   "Henning Rogge"
68 #define MOD_DESC PLUGIN_NAME " " PLUGIN_VERSION " by " PLUGIN_AUTHOR
69 #define PLUGIN_INTERFACE_VERSION 5
70
71 struct debuginfo_cmd {
72   const char *name;
73   olsr_txthandler handler;
74   struct olsr_txtcommand *cmd;
75 };
76
77 static void debuginfo_new(void) __attribute__ ((constructor));
78 static void debuginfo_delete(void) __attribute__ ((destructor));
79
80 static enum olsr_txtcommand_result debuginfo_msgstat(struct comport_connection *con,
81     const char *cmd, const char *param);
82 static enum olsr_txtcommand_result debuginfo_pktstat(struct comport_connection *con,
83     const char *cmd, const char *param);
84 static enum olsr_txtcommand_result debuginfo_cookies(struct comport_connection *con,
85     const char *cmd, const char *param);
86
87 static void update_statistics_ptr(void *);
88 static void olsr_msg_statistics(struct olsr_message *,
89     struct interface *, union olsr_ip_addr *, enum duplicate_status);
90 static uint8_t *olsr_packet_statistics(uint8_t *binary,
91     struct interface *interface, union olsr_ip_addr *ip, int *length);
92
93 static void update_statistics_ptr(void *data __attribute__ ((unused)));
94
95 /* plugin configuration */
96 static struct ip_acl allowed_nets;
97 static uint32_t traffic_interval, traffic_slots, current_slot;
98
99 /* plugin parameters */
100 static const struct olsrd_plugin_parameters plugin_parameters[] = {
101   {.name = IP_ACL_ACCEPT_PARAP,.set_plugin_parameter = &ip_acl_add_plugin_accept,.data = &allowed_nets},
102   {.name = IP_ACL_REJECT_PARAM,.set_plugin_parameter = &ip_acl_add_plugin_reject,.data = &allowed_nets},
103   {.name = IP_ACL_CHECKFIRST_PARAM,.set_plugin_parameter = &ip_acl_add_plugin_checkFirst,.data = &allowed_nets},
104   {.name = IP_ACL_DEFAULTPOLICY_PARAM,.set_plugin_parameter = &ip_acl_add_plugin_defaultPolicy,.data = &allowed_nets},
105   {.name = "stat_interval", .set_plugin_parameter = &set_plugin_int, .data = &traffic_interval},
106   {.name = "stat_slots", .set_plugin_parameter = &set_plugin_int, .data = &traffic_slots},
107 };
108
109 /* command callbacks and names */
110 static struct debuginfo_cmd commands[] = {
111     {"msgstat", &debuginfo_msgstat, NULL},
112     {"pktstat", &debuginfo_pktstat, NULL},
113     {"cookies", &debuginfo_cookies, NULL}
114 };
115
116 /* variables for statistics */
117 static struct avl_tree stat_msg_tree, stat_pkt_tree;
118
119 static struct debug_msgtraffic_count total_msg_traffic;
120 static struct debug_pkttraffic_count total_pkt_traffic;
121
122 static struct olsr_cookie_info *statistics_msg_mem = NULL;
123 static struct olsr_cookie_info *statistics_pkt_mem = NULL;
124
125 static struct olsr_timer_info *statistics_timer = NULL;
126
127 static union olsr_ip_addr total_ip_addr;
128
129 int
130 olsrd_plugin_interface_version(void)
131 {
132   return PLUGIN_INTERFACE_VERSION;
133 }
134
135 void
136 olsrd_get_plugin_parameters(const struct olsrd_plugin_parameters **params, int *size)
137 {
138   *params = plugin_parameters;
139   *size = ARRAYSIZE(plugin_parameters);
140 }
141
142
143 /**
144  *Constructor
145  */
146 static void
147 debuginfo_new(void)
148 {
149   /* Print plugin info to stdout */
150   OLSR_INFO(LOG_PLUGINS, "%s\n", MOD_DESC);
151
152   ip_acl_init(&allowed_nets);
153
154   traffic_interval = 5; /* seconds */
155   traffic_slots = 12;      /* number of 5000 second slots */
156   current_slot = 0;
157
158   memset(&total_ip_addr, 255, sizeof(total_ip_addr));
159
160   /* always allow localhost */
161   if (olsr_cnf->ip_version == AF_INET) {
162     union olsr_ip_addr ip;
163
164     ip.v4.s_addr = ntohl(INADDR_LOOPBACK);
165     ip_acl_add(&allowed_nets, &ip, 32, false);
166   } else {
167     ip_acl_add(&allowed_nets, (const union olsr_ip_addr *)&in6addr_loopback, 128, false);
168     ip_acl_add(&allowed_nets, (const union olsr_ip_addr *)&in6addr_v4mapped_loopback, 128, false);
169   }
170 }
171
172 /**
173  *Destructor
174  */
175 static void
176 debuginfo_delete(void)
177 {
178   size_t i;
179
180   for (i=0; i<ARRAYSIZE(commands); i++) {
181     olsr_com_remove_normal_txtcommand(commands[i].cmd);
182   }
183   olsr_parser_remove_function(&olsr_msg_statistics);
184   olsr_preprocessor_remove_function(&olsr_packet_statistics);
185   ip_acl_flush(&allowed_nets);
186 }
187
188 int
189 olsrd_plugin_init(void)
190 {
191   size_t i;
192
193   for (i=0; i<ARRAYSIZE(commands); i++) {
194     commands[i].cmd = olsr_com_add_normal_txtcommand(commands[i].name, commands[i].handler);
195     commands[i].cmd->acl = &allowed_nets;
196   }
197
198   statistics_timer = olsr_alloc_timerinfo("debuginfo timer", &update_statistics_ptr, true);
199   olsr_start_timer(traffic_interval * 1000, 0, NULL, statistics_timer);
200
201   statistics_msg_mem = olsr_create_memcookie("debuginfo msgstat",
202       sizeof(struct debug_msgtraffic) + sizeof(struct debug_msgtraffic_count) * traffic_slots);
203
204   statistics_pkt_mem = olsr_create_memcookie("debuginfo pktstat",
205       sizeof(struct debug_pkttraffic) + sizeof(struct debug_pkttraffic_count) * traffic_slots);
206
207   memset(&total_msg_traffic, 0, sizeof(total_msg_traffic));
208   memset(&total_pkt_traffic, 0, sizeof(total_pkt_traffic));
209   avl_init(&stat_msg_tree, avl_comp_default, false, NULL);
210   avl_init(&stat_pkt_tree, avl_comp_default, false, NULL);
211
212   olsr_parser_add_function(&olsr_msg_statistics, PROMISCUOUS);
213   olsr_preprocessor_add_function(&olsr_packet_statistics);
214   return 1;
215 }
216
217 static struct debug_msgtraffic *get_msgtraffic_entry(union olsr_ip_addr *ip) {
218   struct debug_msgtraffic *tr;
219   tr = (struct debug_msgtraffic *) avl_find(&stat_msg_tree, ip);
220   if (tr == NULL) {
221     tr = olsr_cookie_malloc(statistics_msg_mem);
222
223     memcpy(&tr->ip, ip, sizeof(union olsr_ip_addr));
224     tr->node.key = &tr->ip;
225
226     avl_insert(&stat_msg_tree, &tr->node);
227   }
228   return tr;
229 }
230
231 static struct debug_pkttraffic *get_pkttraffic_entry(union olsr_ip_addr *ip, struct interface *in) {
232   struct debug_pkttraffic *tr;
233   tr = (struct debug_pkttraffic *) avl_find(&stat_pkt_tree, ip);
234   if (tr == NULL) {
235     tr = olsr_cookie_malloc(statistics_pkt_mem);
236
237     memcpy(&tr->ip, ip, sizeof(union olsr_ip_addr));
238     tr->node.key = &tr->ip;
239
240     tr->int_name = strdup(in ? in->int_name : "---");
241
242     avl_insert(&stat_pkt_tree, &tr->node);
243   }
244   return tr;
245 }
246
247 static void
248 update_statistics_ptr(void *data __attribute__ ((unused)))
249 {
250   struct debug_msgtraffic *msg;
251   struct debug_pkttraffic *pkt;
252   struct list_iterator iterator;
253   uint32_t last_slot, i;
254
255   last_slot = current_slot;
256   current_slot++;
257   if (current_slot == traffic_slots) {
258     current_slot = 0;
259   }
260
261   /* move data from "current" template to slot array */
262   OLSR_FOR_ALL_MSGTRAFFIC_ENTRIES(msg, iterator) {
263     /* subtract old values from node count and total count */
264     for (i=0; i<DTR_MSG_COUNT; i++) {
265       msg->total.data[i] -= msg->traffic[current_slot].data[i];
266     }
267
268     /* copy new traffic into slot */
269     msg->traffic[current_slot] = msg->current;
270
271     /* add new values to node count and total count */
272     for (i=0; i<DTR_MSG_COUNT; i++) {
273       msg->total.data[i] += msg->current.data[i];
274     }
275
276     /* erase new traffic */
277     memset(&msg->current, 0, sizeof(msg->current));
278
279     if (msg->total.data[DTR_MESSAGES] == 0) {
280       /* no traffic left, cleanup ! */
281
282       avl_delete(&stat_msg_tree, &msg->node);
283       olsr_cookie_free(statistics_msg_mem, msg);
284     }
285   }
286
287   OLSR_FOR_ALL_PKTTRAFFIC_ENTRIES(pkt, iterator) {
288     /* subtract old values from node count and total count */
289     for (i=0; i<DTR_PKT_COUNT; i++) {
290       pkt->total.data[i] -= pkt->traffic[current_slot].data[i];
291     }
292
293     /* copy new traffic into slot */
294     pkt->traffic[current_slot] = pkt->current;
295
296     /* add new values to node count and total count */
297     for (i=0; i<DTR_PKT_COUNT; i++) {
298       pkt->total.data[i] += pkt->current.data[i];
299     }
300
301     /* erase new traffic */
302     memset(&pkt->current, 0, sizeof(pkt->current));
303
304     if (pkt->total.data[DTR_PACKETS] == 0) {
305       /* no traffic left, cleanup ! */
306
307       avl_delete(&stat_pkt_tree, &pkt->node);
308       free(pkt->int_name);
309       olsr_cookie_free(statistics_pkt_mem, pkt);
310     }
311   }
312 }
313
314 /* update message statistics */
315 static void
316 olsr_msg_statistics(struct olsr_message *msg,
317     struct interface *input_if __attribute__ ((unused)),
318     union olsr_ip_addr *from_addr __attribute__ ((unused)), enum duplicate_status status  __attribute__ ((unused)))
319 {
320   enum debug_msgtraffic_type type;
321   struct debug_msgtraffic *tr;
322 #if !defined REMOVE_LOG_DEBUG
323   struct ipaddr_str buf;
324 #endif
325
326   switch (msg->type) {
327   case HELLO_MESSAGE:
328     type = DTR_HELLO;
329     break;
330   case TC_MESSAGE:
331     type = DTR_TC;
332     break;
333   case MID_MESSAGE:
334     type = DTR_MID;
335     break;
336   case HNA_MESSAGE:
337     type = DTR_HNA;
338     break;
339   case LQ_HELLO_MESSAGE:
340     type = DTR_HELLO;
341     break;
342   case LQ_TC_MESSAGE:
343     type = DTR_TC;
344     break;
345   default:
346     type = DTR_OTHER;
347     break;
348   }
349
350   /* input data for specific node */
351   tr = get_msgtraffic_entry(&msg->originator);
352   tr->current.data[type]++;
353   tr->current.data[DTR_MESSAGES]++;
354   tr->current.data[DTR_MSG_TRAFFIC] += msg->size;
355
356   OLSR_DEBUG(LOG_PLUGINS, "Added message type %d to statistics of %s: %d\n",
357       type, olsr_ip_to_string(&buf, &tr->ip), tr->current.data[type]);
358
359   /* input data for total traffic handling */
360   tr = get_msgtraffic_entry(&total_ip_addr);
361   tr->current.data[type]++;
362   tr->current.data[DTR_MESSAGES]++;
363   tr->current.data[DTR_MSG_TRAFFIC] += msg->size;
364 }
365
366 /* update traffic statistics */
367 static uint8_t *
368 olsr_packet_statistics(uint8_t *binary, struct interface *interface, union olsr_ip_addr *ip, int *length)
369 {
370   struct debug_pkttraffic *tr;
371   tr = get_pkttraffic_entry(ip, interface);
372   tr->current.data[DTR_PACK_TRAFFIC] += *length;
373   tr->current.data[DTR_PACKETS] ++;
374
375   tr = get_pkttraffic_entry(&total_ip_addr, NULL);
376   tr->current.data[DTR_PACK_TRAFFIC] += *length;
377   tr->current.data[DTR_PACKETS] ++;
378   return binary;
379 }
380
381 static const char *debuginfo_print_trafficip(struct ipaddr_str *buf, union olsr_ip_addr *ip) {
382   static const char *total = "Total";
383   if (olsr_ipcmp(ip, &total_ip_addr) == 0) {
384     return total;
385   }
386   return olsr_ip_to_string(buf, ip);
387 }
388
389 static bool debuginfo_print_msgstat(struct autobuf *buf, union olsr_ip_addr *ip, struct debug_msgtraffic_count *cnt) {
390   struct ipaddr_str strbuf;
391   return abuf_appendf(buf, "%-*s\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t\n",
392       olsr_cnf->ip_version == AF_INET ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN, debuginfo_print_trafficip(&strbuf, ip),
393       cnt->data[DTR_HELLO],
394       cnt->data[DTR_TC],
395       cnt->data[DTR_MID],
396       cnt->data[DTR_HNA],
397       cnt->data[DTR_OTHER],
398       cnt->data[DTR_MESSAGES],
399       cnt->data[DTR_MSG_TRAFFIC]) < 0;
400 }
401
402 static enum olsr_txtcommand_result
403 debuginfo_msgstat(struct comport_connection *con,
404     const char *cmd __attribute__ ((unused)), const char *param __attribute__ ((unused)))
405 {
406   struct debug_msgtraffic *tr;
407   struct list_iterator iterator;
408
409   if (abuf_appendf(&con->out, "Slot size: %d seconds\tSlot count: %d\n", traffic_interval, traffic_slots) < 0) {
410     return ABUF_ERROR;
411   }
412   if (abuf_appendf(&con->out,
413       "Table: Statistics (without duplicates)\n%-*s\tHello\tTC\tMID\tHNA\tOther\tTotal\tBytes\n",
414       olsr_cnf->ip_version == AF_INET ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN, "IP"
415       ) < 0) {
416     return ABUF_ERROR;
417   }
418
419   if (param == NULL || strcasecmp(param, "node") == 0) {
420     OLSR_FOR_ALL_MSGTRAFFIC_ENTRIES(tr, iterator) {
421       if (debuginfo_print_msgstat(&con->out, &tr->ip, &tr->traffic[current_slot])) {
422         return ABUF_ERROR;
423       }
424     }
425   }
426   else {
427     uint32_t mult = 1, divisor = 1;
428     struct debug_msgtraffic_count cnt;
429     int i;
430
431     if (strcasecmp(param, "total") == 0) {
432       divisor = 1;
433     }
434     else if (strcasecmp(param, "average") == 0) {
435       divisor = traffic_slots;
436     }
437     else if (strcasecmp(param, "avgsec") == 0) {
438       divisor = traffic_slots * traffic_interval;
439       mult = 1;
440     }
441     else if (strcasecmp(param, "avgmin") == 0) {
442       divisor = traffic_slots * traffic_interval;
443       mult = 60;
444     }
445     else if (strcasecmp(param, "avghour") == 0) {
446       divisor = traffic_slots * traffic_interval;
447       mult = 3600;
448     }
449     else {
450       abuf_appendf(&con->out, "Error, unknown parameter %s for msgstat\n", param);
451       return CONTINUE;
452     }
453
454     OLSR_FOR_ALL_MSGTRAFFIC_ENTRIES(tr, iterator) {
455       for (i=0; i<DTR_MSG_COUNT; i++) {
456         cnt.data[i] = (tr->total.data[i] * mult) / divisor;
457       }
458       if (debuginfo_print_msgstat(&con->out, &tr->ip, &cnt)) {
459         return ABUF_ERROR;
460       }
461     }
462   }
463
464   return CONTINUE;
465 }
466
467 static bool debuginfo_print_pktstat(struct autobuf *buf, union olsr_ip_addr *ip, char *int_name, struct debug_pkttraffic_count *cnt) {
468   struct ipaddr_str strbuf;
469   return abuf_appendf(buf, "%-*s\t%s\t%d\t%d\n",
470       olsr_cnf->ip_version == AF_INET ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN, debuginfo_print_trafficip(&strbuf, ip),
471       int_name,
472       cnt->data[DTR_PACKETS],
473       cnt->data[DTR_PACK_TRAFFIC]) < 0;
474 }
475
476 static enum olsr_txtcommand_result
477 debuginfo_pktstat(struct comport_connection *con,
478     const char *cmd __attribute__ ((unused)), const char *param __attribute__ ((unused)))
479 {
480   struct debug_pkttraffic *tr;
481   struct list_iterator iterator;
482
483   if (abuf_appendf(&con->out, "Slot size: %d seconds\tSlot count: %d\n", traffic_interval, traffic_slots) < 0) {
484     return ABUF_ERROR;
485   }
486   if (abuf_appendf(&con->out,
487       "Table: Statistics (without duplicates)\n%-*s\tInterf.\tPackets\tBytes\n",
488       olsr_cnf->ip_version == AF_INET ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN, "IP"
489       ) < 0) {
490     return ABUF_ERROR;
491   }
492
493   if (param == NULL || strcasecmp(param, "node") == 0) {
494     OLSR_FOR_ALL_PKTTRAFFIC_ENTRIES(tr, iterator) {
495       if (debuginfo_print_pktstat(&con->out, &tr->ip, tr->int_name, &tr->traffic[current_slot])) {
496         return ABUF_ERROR;
497       }
498     }
499   }
500   else {
501     uint32_t mult = 1, divisor = 1;
502     struct debug_pkttraffic_count cnt;
503     int i;
504
505     if (strcasecmp(param, "total") == 0) {
506       divisor = 1;
507     }
508     else if (strcasecmp(param, "average") == 0) {
509       divisor = traffic_slots;
510     }
511     else if (strcasecmp(param, "avgsec") == 0) {
512       divisor = traffic_slots * traffic_interval;
513       mult = 1;
514     }
515     else if (strcasecmp(param, "avgmin") == 0) {
516       divisor = traffic_slots * traffic_interval;
517       mult = 60;
518     }
519     else if (strcasecmp(param, "avghour") == 0) {
520       divisor = traffic_slots * traffic_interval;
521       mult = 3600;
522     }
523     else {
524       abuf_appendf(&con->out, "Error, unknown parameter %s for msgstat\n", param);
525       return CONTINUE;
526     }
527
528     OLSR_FOR_ALL_PKTTRAFFIC_ENTRIES(tr, iterator) {
529       for (i=0; i<DTR_PKT_COUNT; i++) {
530         cnt.data[i] = (tr->total.data[i] * mult) / divisor;
531       }
532       if (debuginfo_print_pktstat(&con->out, &tr->ip, tr->int_name, &cnt)) {
533         return ABUF_ERROR;
534       }
535     }
536   }
537
538   return CONTINUE;
539 }
540
541 static INLINE bool debuginfo_print_cookies_mem(struct autobuf *buf) {
542   struct olsr_cookie_info *c;
543   struct list_iterator iterator;
544
545   OLSR_FOR_ALL_COOKIES(c, iterator) {
546     if (abuf_appendf(buf, "%-25s (MEMORY) size: %lu usage: %u freelist: %u\n",
547         c->ci_name, (unsigned long)c->ci_size, c->ci_usage, c->ci_free_list_usage) < 0) {
548       return true;
549     }
550   }
551   return false;
552 }
553
554 static INLINE bool debuginfo_print_cookies_timer(struct autobuf *buf) {
555   struct olsr_timer_info *t;
556   struct list_iterator iterator;
557
558   OLSR_FOR_ALL_TIMERS(t, iterator) {
559     if (abuf_appendf(buf, "%-25s (TIMER) usage: %u changes: %u\n",
560         t->name, t->usage, t->changes) < 0) {
561       return true;
562     }
563   }
564   return false;
565 }
566
567 static enum olsr_txtcommand_result
568 debuginfo_cookies(struct comport_connection *con,
569     const char *cmd __attribute__ ((unused)), const char *param __attribute__ ((unused)))
570 {
571   if (abuf_puts(&con->out, "Memory cookies:\n") < 0) {
572     return ABUF_ERROR;
573   }
574
575   if (debuginfo_print_cookies_mem(&con->out)) {
576     return ABUF_ERROR;
577   }
578
579   if (abuf_puts(&con->out, "\nTimer cookies:\n") < 0) {
580     return ABUF_ERROR;
581   }
582
583   if (debuginfo_print_cookies_timer(&con->out)) {
584     return ABUF_ERROR;
585   }
586   return CONTINUE;
587 }
588
589 /*
590  * Local Variables:
591  * mode: c
592  * style: linux
593  * c-basic-offset: 4
594  * indent-tabs-mode: nil
595  * End:
596  */