File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / pimd / debug.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Jun 12 07:59:37 2017 UTC (6 years, 11 months ago) by misho
Branches: pimd, MAIN
CVS tags: v2_3_2, HEAD
pimd 2.3.2

    1: /*
    2:  * Copyright (c) 1998-2001
    3:  * University of Southern California/Information Sciences Institute.
    4:  * All rights reserved.
    5:  *
    6:  * Redistribution and use in source and binary forms, with or without
    7:  * modification, are permitted provided that the following conditions
    8:  * are met:
    9:  * 1. Redistributions of source code must retain the above copyright
   10:  *    notice, this list of conditions and the following disclaimer.
   11:  * 2. Redistributions in binary form must reproduce the above copyright
   12:  *    notice, this list of conditions and the following disclaimer in the
   13:  *    documentation and/or other materials provided with the distribution.
   14:  * 3. Neither the name of the project nor the names of its contributors
   15:  *    may be used to endorse or promote products derived from this software
   16:  *    without specific prior written permission.
   17:  *
   18:  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
   19:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   20:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   21:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
   22:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   23:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   24:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   25:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   26:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   27:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   28:  * SUCH DAMAGE.
   29:  */
   30: /*
   31:  *  $Id: debug.c,v 1.1.1.1 2017/06/12 07:59:37 misho Exp $
   32:  */
   33: /*
   34:  * Part of this program has been derived from mrouted.
   35:  * The mrouted program is covered by the license in the accompanying file
   36:  * named "LICENSE.mrouted".
   37:  *
   38:  * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
   39:  * Leland Stanford Junior University.
   40:  *
   41:  */
   42: 
   43: #define SYSLOG_NAMES
   44: #include "defs.h"
   45: 
   46: #include <stdarg.h>
   47: #include <stdio.h>
   48: 
   49: #define MAX_MSG_SIZE 64                  /* Max for dump_frame() */
   50: 
   51: int log_nmsgs = 0;
   52: int loglevel = LOG_NOTICE;
   53: unsigned long debug = 0x00000000;        /* If (long) is smaller than
   54: 					  * 4 bytes, then we are in
   55: 					  * trouble.
   56: 					  */
   57: static char dumpfilename[] = _PATH_PIMD_DUMP;
   58: static char cachefilename[] = _PATH_PIMD_CACHE; /* TODO: notused */
   59: 
   60: 
   61: char *packet_kind(int proto, int type, int code)
   62: {
   63:     static char unknown[60];
   64: 
   65:     switch (proto) {
   66: 	case IPPROTO_IGMP:
   67: 	    switch (type) {
   68: 		case IGMP_MEMBERSHIP_QUERY:     return "IGMP Membership Query    ";
   69: 		case IGMP_V1_MEMBERSHIP_REPORT: return "IGMP v1 Membership Report";
   70: 		case IGMP_V2_MEMBERSHIP_REPORT: return "IGMP v2 Membership Report";
   71: 		case IGMP_V3_MEMBERSHIP_REPORT: return "IGMP v3 Membership Report";
   72: 		case IGMP_V2_LEAVE_GROUP:       return "IGMP Leave message       ";
   73: 		case IGMP_DVMRP:
   74: 		    switch (code) {
   75: 			case DVMRP_PROBE:          return "DVMRP Neighbor Probe     ";
   76: 			case DVMRP_REPORT:         return "DVMRP Route Report       ";
   77: 			case DVMRP_ASK_NEIGHBORS:  return "DVMRP Neighbor Request   ";
   78: 			case DVMRP_NEIGHBORS:      return "DVMRP Neighbor List      ";
   79: 			case DVMRP_ASK_NEIGHBORS2: return "DVMRP Neighbor request 2 ";
   80: 			case DVMRP_NEIGHBORS2:     return "DVMRP Neighbor list 2    ";
   81: 			case DVMRP_PRUNE:          return "DVMRP Prune message      ";
   82: 			case DVMRP_GRAFT:          return "DVMRP Graft message      ";
   83: 			case DVMRP_GRAFT_ACK:      return "DVMRP Graft message ack  ";
   84: 			case DVMRP_INFO_REQUEST:   return "DVMRP Info Request       ";
   85: 			case DVMRP_INFO_REPLY:     return "DVMRP Info Reply         ";
   86: 			default:
   87: 			    snprintf(unknown, sizeof(unknown), "UNKNOWN DVMRP message code = %3d ", code);
   88: 			    return unknown;
   89: 		    }
   90: 
   91: 		case IGMP_PIM:
   92: 		    /* The old style (PIM v1) encapsulation of PIM messages
   93: 		     * inside IGMP messages.
   94: 		     */
   95: 		    /* PIM v1 is not implemented but we just inform that a message
   96: 		     *	has arrived.
   97: 		     */
   98: 		    switch (code) {
   99: 			case PIM_V1_QUERY:         return "PIM v1 Router-Query      ";
  100: 			case PIM_V1_REGISTER:      return "PIM v1 Register          ";
  101: 			case PIM_V1_REGISTER_STOP: return "PIM v1 Register-Stop     ";
  102: 			case PIM_V1_JOIN_PRUNE:    return "PIM v1 Join/Prune        ";
  103: 			case PIM_V1_RP_REACHABILITY:
  104: 			    return "PIM v1 RP-Reachability   ";
  105: 
  106: 			case PIM_V1_ASSERT:        return "PIM v1 Assert            ";
  107: 			case PIM_V1_GRAFT:         return "PIM v1 Graft             ";
  108: 			case PIM_V1_GRAFT_ACK:     return "PIM v1 Graft_Ack         ";
  109: 			default:
  110: 			    snprintf(unknown, sizeof(unknown), "UNKNOWN PIM v1 message type =%3d ", code);
  111: 			    return unknown;
  112: 		    }
  113: 
  114: 		case IGMP_MTRACE:              return "IGMP trace query         ";
  115: 		case IGMP_MTRACE_RESP:         return "IGMP trace reply         ";
  116: 		default:
  117: 		    snprintf(unknown, sizeof (unknown), "UNKNOWN IGMP message: type = 0x%02x, code = 0x%02x ", type, code);
  118: 		    return unknown;
  119: 	    }
  120: 
  121: 	case IPPROTO_PIM:    /* PIM v2 */
  122: 	    switch (type) {
  123: 		case PIM_V2_HELLO:             return "PIM v2 Hello             ";
  124: 		case PIM_V2_REGISTER:          return "PIM v2 Register          ";
  125: 		case PIM_V2_REGISTER_STOP:     return "PIM v2 Register_Stop     ";
  126: 		case PIM_V2_JOIN_PRUNE:        return "PIM v2 Join/Prune        ";
  127: 		case PIM_V2_BOOTSTRAP:         return "PIM v2 Bootstrap         ";
  128: 		case PIM_V2_ASSERT:            return "PIM v2 Assert            ";
  129: 		case PIM_V2_GRAFT:             return "PIM-DM v2 Graft          ";
  130: 		case PIM_V2_GRAFT_ACK:         return "PIM-DM v2 Graft_Ack      ";
  131: 		case PIM_V2_CAND_RP_ADV:       return "PIM v2 Cand. RP Adv.     ";
  132: 		default:
  133: 		    snprintf(unknown, sizeof(unknown), "UNKNOWN PIM v2 message type =%3d ", type);
  134: 		    return unknown;
  135: 	    }
  136: 
  137: 	default:
  138: 	    snprintf(unknown, sizeof(unknown), "UNKNOWN proto =%3d               ", proto);
  139: 	    return unknown;
  140:     }
  141: }
  142: 
  143: 
  144: /*
  145:  * Used for debugging particular type of messages.
  146:  */
  147: int debug_kind(int proto, int type, int code)
  148: {
  149:     switch (proto) {
  150: 	case IPPROTO_IGMP:
  151: 	    switch (type) {
  152: 		case IGMP_MEMBERSHIP_QUERY:        return DEBUG_IGMP;
  153: 		case IGMP_V1_MEMBERSHIP_REPORT:    return DEBUG_IGMP;
  154: 		case IGMP_V2_MEMBERSHIP_REPORT:    return DEBUG_IGMP;
  155: 		case IGMP_V3_MEMBERSHIP_REPORT:    return DEBUG_IGMP;
  156: 		case IGMP_V2_LEAVE_GROUP:          return DEBUG_IGMP;
  157: 		case IGMP_DVMRP:
  158: 		    switch (code) {
  159: 			case DVMRP_PROBE:              return DEBUG_DVMRP_PEER;
  160: 			case DVMRP_REPORT:             return DEBUG_DVMRP_ROUTE;
  161: 			case DVMRP_ASK_NEIGHBORS:      return 0;
  162: 			case DVMRP_NEIGHBORS:          return 0;
  163: 			case DVMRP_ASK_NEIGHBORS2:     return 0;
  164: 			case DVMRP_NEIGHBORS2:         return 0;
  165: 			case DVMRP_PRUNE:              return DEBUG_DVMRP_PRUNE;
  166: 			case DVMRP_GRAFT:              return DEBUG_DVMRP_PRUNE;
  167: 			case DVMRP_GRAFT_ACK:          return DEBUG_DVMRP_PRUNE;
  168: 			case DVMRP_INFO_REQUEST:       return 0;
  169: 			case DVMRP_INFO_REPLY:         return 0;
  170: 			default:                       return 0;
  171: 		    }
  172: 
  173: 		case IGMP_PIM:
  174: 		    /* PIM v1 is not implemented */
  175: 		    switch (code) {
  176: 			case PIM_V1_QUERY:             return DEBUG_PIM;
  177: 			case PIM_V1_REGISTER:          return DEBUG_PIM;
  178: 			case PIM_V1_REGISTER_STOP:     return DEBUG_PIM;
  179: 			case PIM_V1_JOIN_PRUNE:        return DEBUG_PIM;
  180: 			case PIM_V1_RP_REACHABILITY:   return DEBUG_PIM;
  181: 			case PIM_V1_ASSERT:            return DEBUG_PIM;
  182: 			case PIM_V1_GRAFT:             return DEBUG_PIM;
  183: 			case PIM_V1_GRAFT_ACK:         return DEBUG_PIM;
  184: 			default:                       return DEBUG_PIM;
  185: 		    }
  186: 
  187: 		case IGMP_MTRACE:                  return DEBUG_TRACE;
  188: 		case IGMP_MTRACE_RESP:             return DEBUG_TRACE;
  189: 		default:                           return DEBUG_IGMP;
  190: 	    }
  191: 
  192: 	case IPPROTO_PIM:       /* PIM v2 */
  193: 	    /* TODO: modify? */
  194: 	    switch (type) {
  195: 		case PIM_V2_HELLO:             return DEBUG_PIM;
  196: 		case PIM_V2_REGISTER:          return DEBUG_PIM_REGISTER;
  197: 		case PIM_V2_REGISTER_STOP:     return DEBUG_PIM_REGISTER;
  198: 		case PIM_V2_JOIN_PRUNE:        return DEBUG_PIM;
  199: 		case PIM_V2_BOOTSTRAP:         return DEBUG_PIM_BOOTSTRAP;
  200: 		case PIM_V2_ASSERT:            return DEBUG_PIM;
  201: 		case PIM_V2_GRAFT:             return DEBUG_PIM;
  202: 		case PIM_V2_GRAFT_ACK:         return DEBUG_PIM;
  203: 		case PIM_V2_CAND_RP_ADV:       return DEBUG_PIM_CAND_RP;
  204: 		default:                       return DEBUG_PIM;
  205: 	    }
  206: 
  207: 	default:                               return 0;
  208:     }
  209: 
  210:     return 0;
  211: }
  212: 
  213: 
  214: /*
  215:  * Some messages are more important than others.  This routine
  216:  * determines the logging level at which to log a send error (often
  217:  * "No route to host").  This is important when there is asymmetric
  218:  * reachability and someone is trying to, i.e., mrinfo me periodically.
  219:  */
  220: int
  221: log_level(int proto, int type, int code)
  222: {
  223:     switch (proto) {
  224: 	case IPPROTO_IGMP:
  225: 	    switch (type) {
  226: 		case IGMP_MTRACE_RESP:
  227: 		    return LOG_INFO;
  228: 
  229: 		case IGMP_DVMRP:
  230: 		    switch (code) {
  231: 			case DVMRP_NEIGHBORS:
  232: 			case DVMRP_NEIGHBORS2:
  233: 			    return LOG_INFO;
  234: 		    }
  235: 		    return LOG_WARNING;
  236: 
  237: 		case IGMP_PIM:
  238: 		    /* PIM v1 */
  239: 		    switch (code) {
  240: 			default:
  241: 			    return LOG_INFO;
  242: 		    }
  243: 		    return LOG_WARNING;
  244: 
  245: 		default:
  246: 		    return LOG_WARNING;
  247: 	    }
  248: 
  249: 	case IPPROTO_PIM:
  250: 	    /* PIM v2 */
  251: 	    switch (type) {
  252: 		default:
  253: 		    return LOG_INFO;
  254: 	    }
  255: 	    return LOG_WARNING;
  256: 
  257: 	default:
  258: 	    return LOG_WARNING;
  259:     }
  260:     return LOG_WARNING;
  261: }
  262: 
  263: 
  264: /*
  265:  * Dump internal data structures to a file.
  266:  */
  267: void fdump(int i __attribute__((unused)))
  268: {
  269:     FILE *fp;
  270: 
  271:     fp = fopen(dumpfilename, "w");
  272:     if (fp) {
  273: 	dump_vifs(fp);
  274: 	dump_pim_mrt(fp);
  275: 	fclose(fp);
  276:     }
  277: }
  278: 
  279: /* TODO: dummy, to be used in the future. */
  280: /*
  281:  * Dump local cache contents to a file.
  282:  */
  283: void cdump(int i __attribute__((unused)))
  284: {
  285:     FILE *fp;
  286: 
  287:     fp = fopen(cachefilename, "w");
  288:     if (fp) {
  289: 	/* XXX: TODO: implement it:
  290: 	   dump_cache(fp);
  291: 	*/
  292: 	fclose(fp);
  293:     }
  294: }
  295: 
  296: /*
  297:   1         2         3         4         5         6         7         8
  298:   012345678901234567890123456789012345678901234567890123456789012345678901234567890
  299:   Virtual Interface Table
  300:   Vif  Local-Address    Subnet                Thresh  Flags          Neighbors
  301:   0  10.0.3.1         10.0.3/24             1       DR NO-NBR
  302:   1  172.16.12.254    172.16.12/24          1       DR PIM         172.16.12.2
  303:   172.16.12.3
  304:   2  192.168.122.147  register_vif0         1
  305: */
  306: void dump_vifs(FILE *fp)
  307: {
  308:     vifi_t vifi;
  309:     struct uvif *v;
  310:     pim_nbr_entry_t *n;
  311:     int width;
  312:     int i;
  313:     struct listaddr *group, *source;
  314: 
  315:     fprintf(fp, "Virtual Interface Table ======================================================\n");
  316:     fprintf(fp, "Vif  Local Address    Subnet              Thresh  Flags      Neighbors\n");
  317:     fprintf(fp, "---  ---------------  ------------------  ------  ---------  -----------------\n");
  318: 
  319:     for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
  320: 	int down = 0;
  321: 
  322: 	fprintf(fp, "%3u  %-15s  ", vifi, inet_fmt(v->uv_lcl_addr, s1, sizeof(s1)));
  323: 
  324: 	if (v->uv_flags & VIFF_REGISTER)
  325: 	    fprintf(fp, "%-18s  ", v->uv_name);
  326: 	else
  327: 	    fprintf(fp,"%-18.18s  ", netname(v->uv_subnet, v->uv_subnetmask));
  328: 
  329: 	fprintf(fp, "%6u ", v->uv_threshold);
  330: 
  331: 	/* TODO: XXX: Print VIFF_TUNNEL? */
  332: 	width = 0;
  333: 	if (v->uv_flags & VIFF_DISABLED) {
  334: 	    fprintf(fp, " DISABLED");
  335: 	    down = 1;
  336: 	}
  337: 	if (v->uv_flags & VIFF_DOWN) {
  338: 	    fprintf(fp, " DOWN");
  339: 	    down = 1;
  340: 	}
  341: 
  342: 	if (v->uv_flags & VIFF_DR) {
  343: 	    fprintf(fp, " DR");
  344: 	    width += 3;
  345: 	}
  346: 	if (v->uv_flags & VIFF_PIM_NBR) {
  347: 	    fprintf(fp, " PIM");
  348: 	    width += 4;
  349: 	}
  350: 	if (v->uv_flags & VIFF_DVMRP_NBR) {
  351: 	    fprintf(fp, " DVMRP");
  352: 	    width += 6;
  353: 	}
  354: 	if (v->uv_flags & VIFF_NONBRS) {
  355: 	    fprintf(fp, " NO-NBR");
  356: 	    width += 6;
  357: 	}
  358: 
  359: 	n = v->uv_pim_neighbors;
  360: 	if (!down && n) {
  361: 	    for (i = width; i <= 11; i++)
  362: 		fprintf(fp, " ");
  363: 	    fprintf(fp, "%-15s\n", inet_fmt(n->address, s1, sizeof(s1)));
  364: 	    for (n = n->next; n; n = n->next)
  365: 		fprintf(fp, "%61s%-15s\n", "", inet_fmt(n->address, s1, sizeof(s1)));
  366: 	} else {
  367: 	    fprintf(fp, "\n");
  368: 	}
  369:     }
  370: 
  371:     fprintf(fp, "\n");
  372: 
  373:     /* Dump groups and sources */
  374:     fprintf(fp, " %-3s  %-15s  %-20s", "Vif", "SSM Group", "Sources");
  375:     for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
  376: 	for (group = v->uv_groups; group != NULL; group = group->al_next) {
  377: 	    if (IN_PIM_SSM_RANGE(group->al_addr)) {
  378: 		fprintf(fp, "\n %3u  %-15s ", vifi, inet_fmt(group->al_addr, s1, sizeof(s1)));
  379: 		for (source = group->al_sources; source != NULL; source = source->al_next) {
  380: 		    fprintf(fp, "%s ", inet_fmt(source->al_addr, s1, sizeof(s1)));
  381: 		}
  382: 	    }
  383: 	}
  384:     }
  385: 
  386:     fprintf(fp, "\n\n");
  387: }
  388: 
  389: int loglvl(char *level)
  390: {
  391:     int i;
  392: 
  393:     for (i = 0; prioritynames[i].c_name; i++) {
  394: 	if (string_match(prioritynames[i].c_name, level))
  395: 	    return prioritynames[i].c_val;
  396:     }
  397: 
  398:     return atoi(level);
  399: }
  400: 
  401: /*
  402:  * Log errors and other messages to the system log daemon and to stderr,
  403:  * according to the severity of the message and the current debug level.
  404:  * For errors of severity LOG_ERR or worse, terminate the program.
  405:  */
  406: void logit(int severity, int syserr, const char *format, ...)
  407: {
  408:     va_list ap;
  409:     char msg[211];
  410:     struct timeval now;
  411:     struct tm *thyme;
  412:     time_t lt;
  413: 
  414:     va_start(ap, format);
  415:     vsnprintf(msg, sizeof(msg), format, ap);
  416:     va_end(ap);
  417: 
  418:     /*
  419:      * Log to stderr if we haven't forked yet and it's a warning or
  420:      * worse, or if we're debugging.
  421:      */
  422:     if (haveterminal && (debug || severity <= LOG_WARNING)) {
  423: 	gettimeofday(&now, NULL);
  424: 	lt = now.tv_sec;
  425: 	thyme = localtime(&lt);
  426: 
  427: 	if (!debug)
  428: 	    fprintf(stderr, "%s: ", __progname);
  429: 
  430: 	fprintf(stderr, "%02d:%02d:%02d.%03ld %s", thyme->tm_hour, thyme->tm_min,
  431: 		thyme->tm_sec, (long int)(now.tv_usec / 1000), msg);
  432: 
  433: 	if (syserr) {
  434: 	    errno = syserr;
  435: 	    fprintf(stderr, ": %m");
  436: 	}
  437: 	fprintf(stderr, "\n");
  438:     }
  439: 
  440:     /*
  441:      * Always log things that are worse than warnings, no matter what
  442:      * the log_nmsgs rate limiter says.
  443:      *
  444:      * Only count things at the defined loglevel or worse in the rate limiter
  445:      * and exclude debugging (since if you put daemon.debug in syslog.conf
  446:      * you probably actually want to log the debugging messages so they
  447:      * shouldn't be rate-limited)
  448:      */
  449:     if ((severity < LOG_WARNING) || (log_nmsgs < LOG_MAX_MSGS)) {
  450: 	if ((severity <= loglevel) && (severity != LOG_DEBUG))
  451: 	    log_nmsgs++;
  452: 
  453: 	if (syserr) {
  454: 	    errno = syserr;
  455: 	    syslog(severity, "%s: %m", msg);
  456: 	} else {
  457: 	    syslog(severity, "%s", msg);
  458: 	}
  459:     }
  460: 
  461: #ifndef CONTINUE_ON_ERROR
  462:     if (severity <= LOG_ERR)
  463: 	exit(-1);		/* Exit status: 255 */
  464: #endif /* CONTINUE_ON_ERROR */
  465: }
  466: 
  467: 
  468: /*
  469:  * Hex dump a control frame to the log, MAX 64 bytes length
  470:  */
  471: void dump_frame(char *desc, void *dump, size_t len)
  472: {
  473:     unsigned int length, i = 0;
  474:     unsigned char *data = (unsigned char *)dump;
  475:     char buf[80] = "";
  476:     char tmp[10];
  477: 
  478:     length = len;
  479:     if (length > MAX_MSG_SIZE)
  480: 	length = MAX_MSG_SIZE;
  481: 
  482:     if (desc)
  483: 	logit(LOG_DEBUG, 0, "%s", desc);
  484: 
  485:     while (i < length) {
  486: 	if (!(i % 16))
  487: 	    snprintf(buf, sizeof(buf), "%03X: ", i);
  488: 
  489: 	snprintf(tmp, sizeof(tmp), "%02X ", data[i++]);
  490: 	strlcat(buf, tmp, sizeof(buf));
  491: 
  492: 	if (i > 0 && !(i % 16))
  493: 	    logit(LOG_DEBUG, 0, "%s", buf);
  494: 	else if (i > 0 && !(i % 8))
  495: 	    strlcat(buf, ":: ", sizeof(buf));
  496:     }
  497:     logit(LOG_DEBUG, 0, "%s", buf);
  498: }
  499: 
  500: 
  501: static void dump_route(FILE *fp, mrtentry_t *r)
  502: {
  503:     vifi_t vifi;
  504:     char oifs[(sizeof(vifbitmap_t)<<3)+1];
  505:     char joined_oifs[(sizeof(vifbitmap_t)<<3)+1];
  506:     char pruned_oifs[(sizeof(vifbitmap_t)<<3)+1];
  507:     char leaves_oifs[(sizeof(vifbitmap_t)<<3)+1];
  508:     char asserted_oifs[(sizeof(vifbitmap_t)<<3)+1];
  509:     char incoming_iif[(sizeof(vifbitmap_t)<<3)+1];
  510: 
  511:     for (vifi = 0; vifi < numvifs; vifi++) {
  512: 	oifs[vifi] =
  513: 	    VIFM_ISSET(vifi, r->oifs)	       ? 'o' : '.';
  514: 	joined_oifs[vifi] =
  515: 	    VIFM_ISSET(vifi, r->joined_oifs)   ? 'j' : '.';
  516: 	pruned_oifs[vifi] =
  517: 	    VIFM_ISSET(vifi, r->pruned_oifs)   ? 'p' : '.';
  518: 	leaves_oifs[vifi] =
  519: 	    VIFM_ISSET(vifi, r->leaves)	       ? 'l' : '.';
  520: 	asserted_oifs[vifi] =
  521: 	    VIFM_ISSET(vifi, r->asserted_oifs) ? 'a' : '.';
  522: 	incoming_iif[vifi] = '.';
  523:     }
  524:     oifs[vifi]		= 0x0;	/* End of string */
  525:     joined_oifs[vifi]	= 0x0;
  526:     pruned_oifs[vifi]	= 0x0;
  527:     leaves_oifs[vifi]	= 0x0;
  528:     asserted_oifs[vifi] = 0x0;
  529:     incoming_iif[vifi]	= 0x0;
  530:     incoming_iif[r->incoming] = 'I';
  531: 
  532:     /* TODO: don't need some of the flags */
  533:     if (r->flags & MRTF_SPT)	       fprintf(fp, " SPT");
  534:     if (r->flags & MRTF_WC)	       fprintf(fp, " WC");
  535:     if (r->flags & MRTF_RP)	       fprintf(fp, " RP");
  536:     if (r->flags & MRTF_REGISTER)      fprintf(fp, " REG");
  537:     if (r->flags & MRTF_IIF_REGISTER)  fprintf(fp, " IIF_REG");
  538:     if (r->flags & MRTF_NULL_OIF)      fprintf(fp, " NULL_OIF");
  539:     if (r->flags & MRTF_KERNEL_CACHE)  fprintf(fp, " CACHE");
  540:     if (r->flags & MRTF_ASSERTED)      fprintf(fp, " ASSERTED");
  541:     if (r->flags & MRTF_REG_SUPP)      fprintf(fp, " REG_SUPP");
  542:     if (r->flags & MRTF_SG)	       fprintf(fp, " SG");
  543:     if (r->flags & MRTF_PMBR)	       fprintf(fp, " PMBR");
  544:     fprintf(fp, "\n");
  545: 
  546:     fprintf(fp, "Joined   oifs: %-20s\n", joined_oifs);
  547:     fprintf(fp, "Pruned   oifs: %-20s\n", pruned_oifs);
  548:     fprintf(fp, "Leaves   oifs: %-20s\n", leaves_oifs);
  549:     fprintf(fp, "Asserted oifs: %-20s\n", asserted_oifs);
  550:     fprintf(fp, "Outgoing oifs: %-20s\n", oifs);
  551:     fprintf(fp, "Incoming     : %-20s\n", incoming_iif);
  552: 
  553:     fprintf(fp, "\nTIMERS:  Entry    JP    RS  Assert VIFS:");
  554:     for (vifi = 0; vifi < numvifs; vifi++)
  555: 	fprintf(fp, "  %d", vifi);
  556:     fprintf(fp, "\n         %5d  %4d  %4d  %6d      ",
  557: 	    r->timer, r->jp_timer, r->rs_timer, r->assert_timer);
  558:     for (vifi = 0; vifi < numvifs; vifi++)
  559: 	fprintf(fp, " %2d", r->vif_timers[vifi]);
  560:     fprintf(fp, "\n");
  561: }
  562: 
  563: void dump_pim_mrt(FILE *fp)
  564: {
  565:     grpentry_t *g;
  566:     mrtentry_t *r;
  567:     u_int number_of_cache_mirrors = 0;
  568:     u_int number_of_groups = 0;
  569:     cand_rp_t *rp;
  570:     kernel_cache_t *kc;
  571: 
  572:     fprintf(fp, "Multicast Routing Table ======================================================\n");
  573: 
  574:     /* TODO: remove the dummy 0.0.0.0 group (first in the chain) */
  575:     for (g = grplist->next; g; g = g->next) {
  576: 	number_of_groups++;
  577: 
  578: 	r = g->grp_route;
  579: 	if (r) {
  580: 	    if (r->flags & MRTF_KERNEL_CACHE) {
  581: 		for (kc = r->kernel_cache; kc; kc = kc->next)
  582: 		    number_of_cache_mirrors++;
  583: 	    }
  584: 
  585: 	    /* Print the (*,G) routing info */
  586: 	    fprintf(fp, "----------------------------------- (*,G) ------------------------------------\n");
  587: 	    fprintf(fp, "Source           Group            RP Address       Flags\n");
  588: 	    fprintf(fp, "---------------  ---------------  ---------------  ---------------------------\n");
  589: 	    fprintf(fp, "%-15s  ", "INADDR_ANY");
  590: 	    fprintf(fp, "%-15s  ", inet_fmt(g->group, s1, sizeof(s1)));
  591: 	    fprintf(fp, "%-15s ", IN_PIM_SSM_RANGE(g->group) ? "SSM" :
  592: 		    (g->active_rp_grp ? inet_fmt(g->rpaddr, s2, sizeof(s2)) : "NULL"));
  593: 
  594: 	    dump_route(fp, r);
  595: 	}
  596: 
  597: 	/* Print all (S,G) routing info */
  598: 	fprintf(fp, "----------------------------------- (S,G) ------------------------------------\n");
  599: 	for (r = g->mrtlink; r; r = r->grpnext) {
  600: 	    if (r->flags & MRTF_KERNEL_CACHE)
  601: 		number_of_cache_mirrors++;
  602: 
  603: 	    /* Print the routing info */
  604: 	    fprintf(fp, "Source           Group            RP Address       Flags\n");
  605: 	    fprintf(fp, "---------------  ---------------  ---------------  ---------------------------\n");
  606: 	    fprintf(fp, "%-15s  ", inet_fmt(r->source->address, s1, sizeof(s1)));
  607: 	    fprintf(fp, "%-15s  ", inet_fmt(g->group, s2, sizeof(s2)));
  608: 	    fprintf(fp, "%-15s ", IN_PIM_SSM_RANGE(g->group) ? "SSM" :
  609: 		    (g->active_rp_grp ? inet_fmt(g->rpaddr, s2, sizeof(s2)) : "NULL"));
  610: 
  611: 	    dump_route(fp, r);
  612: 	}
  613:     }/* for all groups */
  614: 
  615:     /* Print the (*,*,R) routing entries */
  616:     fprintf(fp, "--------------------------------- (*,*,G) ------------------------------------\n");
  617:     for (rp = cand_rp_list; rp; rp = rp->next) {
  618: 	r = rp->rpentry->mrtlink;
  619: 	if (r) {
  620: 	    if (r->flags & MRTF_KERNEL_CACHE) {
  621: 		for (kc = r->kernel_cache; kc; kc = kc->next)
  622: 		    number_of_cache_mirrors++;
  623: 	    }
  624: 
  625: 	    /* Print the (*,*,RP) routing info */
  626: 	    fprintf(fp, "Source           Group            RP Address       Flags\n");
  627: 	    fprintf(fp, "---------------  ---------------  ---------------  ---------------------------\n");
  628: 	    fprintf(fp, "%-15s  ", inet_fmt(r->source->address, s1, sizeof(s1)));
  629: 	    fprintf(fp, "%-15s  ", "INADDR_ANY");
  630: 	    fprintf(fp, "%-15s ", "");
  631: 
  632: 	    dump_route(fp, r);
  633: 	}
  634:     } /* For all (*,*,RP) */
  635: 
  636:     fprintf(fp, "Number of Groups: %u\n", number_of_groups);
  637:     fprintf(fp, "Number of Cache MIRRORs: %u\n", number_of_cache_mirrors);
  638:     fprintf(fp, "------------------------------------------------------------------------------\n\n");
  639: }
  640: 
  641: static void dump_rpgrp(FILE *fp, rp_grp_entry_t *rpgrp, int indent)
  642: {
  643:     grp_mask_t *grp = rpgrp->group;
  644: 
  645:     if (indent)
  646: 	fprintf(fp, "                           ");
  647: 
  648:     fprintf(fp, "%-18.18s  %-8u  %-8u\n",
  649: 	    netname(grp->group_addr, grp->group_mask),
  650: 	    rpgrp->priority, rpgrp->holdtime);
  651: }
  652: 
  653: /*
  654:  * Dumps the local Cand-RP-set
  655:  */
  656: int dump_rp_set(FILE *fp)
  657: {
  658:     cand_rp_t      *rp;
  659:     rp_grp_entry_t *rpgrp;
  660: 
  661:     fprintf(fp, "Candidate Rendezvous-Point Set ===============================================\n");
  662:     fprintf(fp, "RP address       Incoming  Group Prefix        Priority  Holdtime\n");
  663:     fprintf(fp, "---------------  --------  ------------------  --------  ---------------------\n");
  664:     for (rp = cand_rp_list; rp; rp = rp->next) {
  665: 	fprintf(fp, "%-15s  %-8d  ",
  666: 		inet_fmt(rp->rpentry->address, s1, sizeof(s1)),
  667: 		rp->rpentry->incoming);
  668: 
  669: 	rpgrp = rp->rp_grp_next;
  670: 	if (rpgrp) {
  671: 	    dump_rpgrp(fp, rpgrp, 0);
  672: 
  673: 	    for (rpgrp = rpgrp->rp_grp_next; rpgrp; rpgrp = rpgrp->rp_grp_next)
  674: 		dump_rpgrp(fp, rpgrp, 1);
  675: 	}
  676:     }
  677: 
  678:     fprintf(fp, "------------------------------------------------------------------------------\n");
  679:     fprintf(fp, "Current BSR address: %s\n\n", inet_fmt(curr_bsr_address, s1, sizeof(s1)));
  680: 
  681:     return TRUE;
  682: }
  683: 
  684: /**
  685:  * Local Variables:
  686:  *  version-control: t
  687:  *  indent-tabs-mode: t
  688:  *  c-file-style: "ellemtel"
  689:  *  c-basic-offset: 4
  690:  * End:
  691:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>