2 * Copyright (c) 1998 by the University of Southern California.
5 * Permission to use, copy, modify, and distribute this software and
6 * its documentation in source and binary forms for lawful
7 * purposes and without fee is hereby granted, provided
8 * that the above copyright notice appear in all copies and that both
9 * the copyright notice and this permission notice appear in supporting
10 * documentation, and that any documentation, advertising materials,
11 * and other materials related to such distribution and use acknowledge
12 * that the software was developed by the University of Southern
13 * California and/or Information Sciences Institute.
14 * The name of the University of Southern California may not
15 * be used to endorse or promote products derived from this software
16 * without specific prior written permission.
18 * THE UNIVERSITY OF SOUTHERN CALIFORNIA DOES NOT MAKE ANY REPRESENTATIONS
19 * ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. THIS SOFTWARE IS
20 * PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
21 * INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
22 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
25 * IN NO EVENT SHALL USC, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
26 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
27 * TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
28 * THE USE OR PERFORMANCE OF THIS SOFTWARE.
30 * Other copyrights might apply to parts of this software and are so
31 * noted when applicable.
34 * Questions concerning this software should be directed to
35 * Pavlin Ivanov Radoslavov (pavlin@catarina.usc.edu)
37 * $Id: debug.c,v 1.10 2000/10/05 22:27:07 itojun Exp $
40 * Part of this program has been derived from mrouted.
41 * The mrouted program is covered by the license in the accompanying file
42 * named "LICENSE.mrouted".
44 * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
45 * Leland Stanford Junior University.
59 extern int haveterminal;
60 extern char *progname;
63 unsigned long debug = 0x00000000; /* If (long) is smaller than
64 * 4 bytes, then we are in
67 static char dumpfilename[] = _PATH_PIM6D_DUMP;
68 static char cachefilename[] = _PATH_PIM6D_CACHE; /* TODO: notused */
70 static char *sec2str __P((time_t));
76 static char result[256];
77 int days, hours, mins, secs;
81 days = total / 3600 / 24;
82 hours = (total / 3600) % 24;
83 mins = (total / 60) % 60;
88 p += sprintf(p, "%dd", days);
90 if (!first || hours) {
92 p += sprintf(p, "%dh", hours);
96 p += sprintf(p, "%dm", mins);
98 sprintf(p, "%ds", secs);
104 packet_kind(proto, type, code)
105 u_int proto, type, code;
107 static char unknown[60];
112 case MLD6_LISTENER_QUERY: return "Multicast Listener Query ";
113 case MLD6_LISTENER_REPORT: return "Multicast Listener Report ";
114 case MLD6_LISTENER_DONE: return "Multicast Listener Done ";
117 "UNKNOWN ICMPv6 message: type = 0x%02x, code = 0x%02x ",
122 case IPPROTO_PIM: /* PIM v2 */
124 case PIM_V2_HELLO: return "PIM v2 Hello ";
125 case PIM_V2_REGISTER: return "PIM v2 Register ";
126 case PIM_V2_REGISTER_STOP: return "PIM v2 Register_Stop ";
127 case PIM_V2_JOIN_PRUNE: return "PIM v2 Join/Prune ";
128 case PIM_V2_BOOTSTRAP: return "PIM v2 Bootstrap ";
129 case PIM_V2_ASSERT: return "PIM v2 Assert ";
130 case PIM_V2_GRAFT: return "PIM-DM v2 Graft ";
131 case PIM_V2_GRAFT_ACK: return "PIM-DM v2 Graft_Ack ";
132 case PIM_V2_CAND_RP_ADV: return "PIM v2 Cand. RP Adv. ";
134 sprintf(unknown, "UNKNOWN PIM v2 message type =%3d ", type);
138 sprintf(unknown, "UNKNOWN proto =%3d ", proto);
145 * Used for debugging particular type of messages.
148 debug_kind(proto, type, code)
149 u_int proto, type, code;
154 case MLD6_LISTENER_QUERY: return DEBUG_MLD;
155 case MLD6_LISTENER_REPORT: return DEBUG_MLD;
156 case MLD6_LISTENER_DONE: return DEBUG_MLD;
157 default: return DEBUG_MLD;
159 case IPPROTO_PIM: /* PIM v2 */
162 case PIM_V2_HELLO: return DEBUG_PIM;
163 case PIM_V2_REGISTER: return DEBUG_PIM_REGISTER;
164 case PIM_V2_REGISTER_STOP: return DEBUG_PIM_REGISTER;
165 case PIM_V2_JOIN_PRUNE: return DEBUG_PIM;
166 case PIM_V2_BOOTSTRAP: return DEBUG_PIM_BOOTSTRAP;
167 case PIM_V2_ASSERT: return DEBUG_PIM;
168 case PIM_V2_GRAFT: return DEBUG_PIM;
169 case PIM_V2_GRAFT_ACK: return DEBUG_PIM;
170 case PIM_V2_CAND_RP_ADV: return DEBUG_PIM_CAND_RP;
171 default: return DEBUG_PIM;
180 * Some messages are more important than others. This routine
181 * determines the logging level at which to log a send error (often
182 * "No route to host"). This is important when there is asymmetric
183 * reachability and someone is trying to, i.e., mrinfo me periodically.
186 log_level(proto, type, code)
187 u_int proto, type, code;
210 * Dump internal data structures to stderr.
212 /* TODO: currently not used
217 dump_pim_mrt(stderr);
222 * Dump internal data structures to a file.
229 fp = fopen(dumpfilename, "w");
232 dump_mldqueriers(fp);
239 /* TODO: dummy, to be used in the future. */
241 * Dump local cache contents to a file.
249 fp = fopen(cachefilename, "w");
251 /* TODO: implement it:
263 register struct uvif *v;
269 fprintf(fp, "\nMulticast Interface Table\n %-4s %-6s %-50s %-14s %s",
270 "Mif", " PhyIF", "Local-Address/Prefixlen", "Flags",
273 for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
275 for (pa = v->uv_addrs; pa; pa = pa->pa_next) {
277 fprintf(fp, " %3s %6s %-50s\n", "", "",
278 net6name(&pa->pa_addr.sin6_addr,
279 &pa->pa_subnetmask));
284 fprintf(fp, " %-3u %6s %-50s", vifi, v->uv_name,
285 net6name(&pa->pa_addr.sin6_addr,
286 &pa->pa_subnetmask));
289 if (v->uv_flags & MIFF_REGISTER)
290 fprintf(fp, "%-16s ", v->uv_name);
292 fprintf(fp,"%-16.16s ",
293 net6name(&v->uv_prefix.sin6_addr,
297 if (v->uv_flags & VIFF_DISABLED)
298 fprintf(fp, " DISABLED");
299 if (v->uv_flags & VIFF_NOLISTENER)
300 fprintf(fp, " NOLISTENER");
301 if (v->uv_flags & VIFF_DOWN)
302 fprintf(fp, " DOWN");
303 if (v->uv_flags & VIFF_DR) {
307 if (v->uv_flags & VIFF_PIM_NBR) {
311 #if 0 /* impossible */
312 if (v->uv_flags & VIFF_DVMRP_NBR) {
313 fprintf(fp, " DVMRP");
317 if (v->uv_flags & VIFF_NONBRS) {
318 fprintf(fp, " %-12s", "NO-NBR");
321 if (v->uv_flags & VIFF_QUERIER)
324 if ((n = v->uv_pim_neighbors) != NULL) {
325 /* Print the first neighbor on the same line */
326 for (i = width; i <= 15; i++)
328 fprintf(fp, "%-12s\n",
329 inet6_fmt(&n->address.sin6_addr));
330 for (n = n->next; n != NULL; n = n->next)
331 fprintf(fp, "%64s %-15s\n", "",
332 inet6_fmt(&n->address.sin6_addr));
344 * Log errors and other messages to the system log daemon and to stderr,
345 * according to the severity of the message and the current debug level.
346 * For errors of severity LOG_ERR or worse, terminate the program.
350 log(int severity, int syserr, char *format, ...)
353 static char fmt[211] = "warning - ";
358 va_start(ap, format);
362 log(severity, syserr, format, va_alist)
363 int severity, syserr;
368 static char fmt[311] = "warning - ";
376 vsprintf(&fmt[10], format, ap);
378 msg = (severity == LOG_WARNING) ? fmt : &fmt[10];
381 * Log to stderr if we haven't forked yet and it's a warning or worse,
382 * or if we're debugging.
384 if (haveterminal && (debug || severity <= LOG_WARNING)) {
386 gettimeofday(&now,NULL);
387 sectime = (time_t) now.tv_sec;
388 thyme = localtime(§ime);
390 fprintf(stderr, "%s: ", progname);
391 fprintf(stderr, "%02d:%02d:%02d.%03ld %s", thyme->tm_hour,
392 thyme->tm_min, thyme->tm_sec, (long int)now.tv_usec / 1000,
395 fprintf(stderr, "\n");
396 else if (syserr < sys_nerr)
397 fprintf(stderr, ": %s\n", sys_errlist[syserr]);
399 fprintf(stderr, ": errno %d\n", syserr);
403 * Always log things that are worse than warnings, no matter what
404 * the log_nmsgs rate limiter says.
405 * Only count things worse than debugging in the rate limiter
406 * (since if you put daemon.debug in syslog.conf you probably
407 * actually want to log the debugging messages so they shouldn't
410 if ((severity < LOG_WARNING) || (log_nmsgs < LOG_MAX_MSGS)) {
411 if (severity < LOG_DEBUG)
415 syslog(severity, "%s: %m", msg);
417 syslog(severity, "%s", msg);
420 if (severity <= LOG_ERR) exit(-1);
431 fprintf(fp, "MLD Querier List\n");
432 fprintf(fp, " %-3s %6s %-40s %-5s %15s\n",
433 "Mif", "PhyIF", "Address", "Timer", "Last");
436 for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
438 fprintf(fp, " %-3u %6s", vifi,
439 (v->uv_flags & MIFF_REGISTER) ? "regist":
442 fprintf(fp, " %-40s %5lu %15s\n",
443 inet6_fmt(&v->uv_querier->al_addr.sin6_addr),
444 (u_long)v->uv_querier->al_timer,
445 sec2str(now - v->uv_querier->al_ctime));
452 /* TODO: format the output for better readability */
458 register mrtentry_t *r;
459 register vifi_t vifi;
460 u_int number_of_groups = 0;
461 char oifs[(sizeof(if_set)<<3)+1];
462 char pruned_oifs[(sizeof(if_set)<<3)+1];
463 char asserted_oifs[(sizeof(if_set)<<3)+1];
464 char leaves_oifs[(sizeof(if_set)<<3)+1];
465 char filter_oifs[(sizeof(if_set)<<3)+1];
466 char incoming_iif[(sizeof(if_set)<<3)+1];
468 fprintf(fp, "Multicast Routing Table\n%s",
469 " Source Group Flags\n");
471 /* TODO: remove the dummy 0:: group (first in the chain) */
472 for (g = grplist->next; g != (grpentry_t *)NULL; g = g->next) {
474 /* Print all (S,G) routing info */
475 for (r = g->mrtlink; r != (mrtentry_t *)NULL; r = r->grpnext) {
476 fprintf(fp, "---------------------------(S,G)----------------------------\n");
477 /* Print the routing info */
478 fprintf(fp, " %-15s", inet6_fmt(&r->source->address.sin6_addr));
479 fprintf(fp, " %-15s", inet6_fmt(&g->group.sin6_addr));
481 for (vifi = 0; vifi < numvifs; vifi++) {
483 IF_ISSET(vifi, &r->oifs) ? 'o' : '.';
485 IF_ISSET(vifi, &r->pruned_oifs) ? 'p' : '.';
486 asserted_oifs[vifi] =
487 IF_ISSET(vifi, &r->pruned_oifs) ? 'a' : '.';
489 IF_ISSET(vifi, &r->filter_oifs) ? 'f' : '.';
491 IF_ISSET(vifi, &r->leaves) ? 'l' : '.';
492 incoming_iif[vifi] = '.';
494 oifs[vifi] = 0x0; /* End of string */
495 pruned_oifs[vifi] = 0x0;
496 leaves_oifs[vifi] = 0x0;
497 filter_oifs[vifi] = 0x0;
498 incoming_iif[vifi] = 0x0;
499 incoming_iif[r->incoming] = 'I';
501 /* TODO: don't need some of the flags */
502 if (r->flags & MRTF_SPT) fprintf(fp, " SPT");
503 if (r->flags & MRTF_WC) fprintf(fp, " WC");
504 if (r->flags & MRTF_RP) fprintf(fp, " RP");
505 if (r->flags & MRTF_REGISTER) fprintf(fp, " REG");
506 if (r->flags & MRTF_IIF_REGISTER) fprintf(fp, " IIF_REG");
507 if (r->flags & MRTF_NULL_OIF) fprintf(fp, " NULL_OIF");
508 if (r->flags & MRTF_KERNEL_CACHE) fprintf(fp, " CACHE");
509 if (r->flags & MRTF_ASSERTED) fprintf(fp, " ASSERTED");
510 if (r->flags & MRTF_REG_SUPP) fprintf(fp, " REG_SUPP");
511 if (r->flags & MRTF_SG) fprintf(fp, " SG");
512 if (r->flags & MRTF_PMBR) fprintf(fp, " PMBR");
515 fprintf(fp, "Pruned oifs: %-20s\n", pruned_oifs);
516 fprintf(fp, "Asserted oifs: %-20s\n", pruned_oifs);
517 fprintf(fp, "Filtered oifs: %-20s\n", filter_oifs);
518 fprintf(fp, "Leaves oifs: %-20s\n", leaves_oifs);
519 fprintf(fp, "Outgoing oifs: %-20s\n", oifs);
520 fprintf(fp, "Incoming : %-20s\n", incoming_iif);
522 fprintf(fp, "Upstream nbr: %s\n",
523 r->upstream ? inet6_fmt(&r->upstream->address.sin6_addr) : "NONE");
524 fprintf(fp, "\nTIMERS: Entry Prune VIFS:");
525 for (vifi = 0; vifi < numvifs; vifi++)
526 fprintf(fp, " %2d", vifi);
527 fprintf(fp, "\n %3d ",
529 for (vifi = 0; vifi < numvifs; vifi++)
530 fprintf(fp, " %3d", r->prune_timers[vifi]);
533 }/* for all groups */
535 fprintf(fp, "Number of Groups: %u\n", number_of_groups);
546 fprintf(fp, "\nList of local listener information per interface\n");
547 for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
550 for (g = v->uv_groups; g != NULL; g = g->al_next) {
552 fprintf(fp, " Mif %d(%s)\n", vifi, v->uv_name);
555 fprintf(fp, " %s", inet6_fmt(&g->al_addr.sin6_addr));
557 fprintf(fp, " timeout: %d",
558 timer_leftTimer(g->al_timerid));
560 fprintf(fp, " querytimer: %d",
561 timer_leftTimer(g->al_timerid));