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