File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / pimdd / debug.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Jun 12 07:58:55 2017 UTC (6 years, 11 months ago) by misho
Branches: pimdd, MAIN
CVS tags: v0_2_1p0, v0_2_1, HEAD
pimdd-dense 0.2.1.0_2

/*
 *  Copyright (c) 1998 by the University of Southern California.
 *  All rights reserved.
 *
 *  Permission to use, copy, modify, and distribute this software and
 *  its documentation in source and binary forms for lawful
 *  purposes and without fee is hereby granted, provided
 *  that the above copyright notice appear in all copies and that both
 *  the copyright notice and this permission notice appear in supporting
 *  documentation, and that any documentation, advertising materials,
 *  and other materials related to such distribution and use acknowledge
 *  that the software was developed by the University of Southern
 *  California and/or Information Sciences Institute.
 *  The name of the University of Southern California may not
 *  be used to endorse or promote products derived from this software
 *  without specific prior written permission.
 *
 *  THE UNIVERSITY OF SOUTHERN CALIFORNIA DOES NOT MAKE ANY REPRESENTATIONS
 *  ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE.  THIS SOFTWARE IS
 *  PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
 *  INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND 
 *  NON-INFRINGEMENT.
 *
 *  IN NO EVENT SHALL USC, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
 *  SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
 *  TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
 *  THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 *  Other copyrights might apply to parts of this software and are so
 *  noted when applicable.
 */
/*
 *  Questions concerning this software should be directed to 
 *  Pavlin Ivanov Radoslavov (pavlin@catarina.usc.edu)
 *
 *  $Id: debug.c,v 1.1.1.1 2017/06/12 07:58:55 misho Exp $
 */
/*
 * Part of this program has been derived from mrouted.
 * The mrouted program is covered by the license in the accompanying file
 * named "LICENSE.mrouted".
 *
 * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
 * Leland Stanford Junior University.
 *
 */

#include "defs.h"


#ifdef __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif

extern int haveterminal;
extern char *progname;

int log_nmsgs = 0;
unsigned long debug = 0x00000000;        /* If (long) is smaller than
					  * 4 bytes, then we are in
					  * trouble.
					  */
static char dumpfilename[] = _PATH_PIMD_DUMP;
static char cachefilename[] = _PATH_PIMD_CACHE; /* TODO: notused */


char *
packet_kind(proto, type, code)
    u_int proto, type, code;
{
    static char unknown[60];

    switch (proto) {
    case IPPROTO_IGMP:
	switch (type) {
	case IGMP_MEMBERSHIP_QUERY:    return "IGMP Membership Query    ";
	case IGMP_V1_MEMBERSHIP_REPORT:return "IGMP v1 Member Report    ";
	case IGMP_V2_MEMBERSHIP_REPORT:return "IGMP v2 Member Report    ";
	case IGMP_V2_LEAVE_GROUP:      return "IGMP Leave message       ";
	case IGMP_DVMRP:
	    switch (code) {
	    case DVMRP_PROBE:          return "DVMRP Neighbor Probe     ";
	    case DVMRP_REPORT:         return "DVMRP Route Report       ";
	    case DVMRP_ASK_NEIGHBORS:  return "DVMRP Neighbor Request   ";
	    case DVMRP_NEIGHBORS:      return "DVMRP Neighbor List      ";
	    case DVMRP_ASK_NEIGHBORS2: return "DVMRP Neighbor request 2 ";
	    case DVMRP_NEIGHBORS2:     return "DVMRP Neighbor list 2    ";
	    case DVMRP_PRUNE:          return "DVMRP Prune message      ";
	    case DVMRP_GRAFT:          return "DVMRP Graft message      ";
	    case DVMRP_GRAFT_ACK:      return "DVMRP Graft message ack  ";
	    case DVMRP_INFO_REQUEST:   return "DVMRP Info Request       ";
	    case DVMRP_INFO_REPLY:     return "DVMRP Info Reply         ";
	    default:
		sprintf(unknown,   "UNKNOWN DVMRP message code = %3d ", code);
		return unknown;
	    }
	case IGMP_PIM:
	    /* The old style (PIM v1) encapsulation of PIM messages
	     * inside IGMP messages.
	     */
	    /* PIM v1 is not implemented but we just inform that a message
	     *	has arrived.
	     */
	    switch (code) {
	    case PIM_V1_QUERY:	       return "PIM v1 Router-Query      ";
	    case PIM_V1_REGISTER:      return "PIM v1 Register          ";
	    case PIM_V1_REGISTER_STOP: return "PIM v1 Register-Stop     ";
	    case PIM_V1_JOIN_PRUNE:    return "PIM v1 Join/Prune        ";
	    case PIM_V1_RP_REACHABILITY:
		                       return "PIM v1 RP-Reachability   ";
	    case PIM_V1_ASSERT:        return "PIM v1 Assert            ";
	    case PIM_V1_GRAFT:         return "PIM v1 Graft             ";
	    case PIM_V1_GRAFT_ACK:     return "PIM v1 Graft_Ack         ";
	    default:
		sprintf(unknown,   "UNKNOWN PIM v1 message type =%3d ", code);
		return unknown;
	    }
	case IGMP_MTRACE:              return "IGMP trace query         ";
	case IGMP_MTRACE_RESP:         return "IGMP trace reply         ";
	default:
	    sprintf(unknown,
		    "UNKNOWN IGMP message: type = 0x%02x, code = 0x%02x ",
		    type, code);
	    return unknown;
	}
    case IPPROTO_PIM:    /* PIM v2 */
	switch (type) {
	case PIM_V2_HELLO:	       return "PIM v2 Hello             ";
	case PIM_V2_REGISTER:          return "PIM v2 Register          ";
	case PIM_V2_REGISTER_STOP:     return "PIM v2 Register_Stop     ";
	case PIM_V2_JOIN_PRUNE:        return "PIM v2 Join/Prune        ";
	case PIM_V2_BOOTSTRAP:         return "PIM v2 Bootstrap         ";
	case PIM_V2_ASSERT:            return "PIM v2 Assert            ";
	case PIM_V2_GRAFT:             return "PIM-DM v2 Graft          ";
	case PIM_V2_GRAFT_ACK:         return "PIM-DM v2 Graft_Ack      ";
	case PIM_V2_CAND_RP_ADV:       return "PIM v2 Cand. RP Adv.     ";
	default:
	    sprintf(unknown,      "UNKNOWN PIM v2 message type =%3d ", type);
	    return unknown;
	}
    default:
	sprintf(unknown,          "UNKNOWN proto =%3d               ", proto);
	return unknown;
    }
}


/*
 * Used for debugging particular type of messages.
 */
int
debug_kind(proto, type, code)
    u_int proto, type, code;
{
    switch (proto) {
    case IPPROTO_IGMP:
	switch (type) {
	case IGMP_MEMBERSHIP_QUERY:        return DEBUG_IGMP;
	case IGMP_V1_MEMBERSHIP_REPORT:    return DEBUG_IGMP;
	case IGMP_V2_MEMBERSHIP_REPORT:    return DEBUG_IGMP;
	case IGMP_V2_LEAVE_GROUP:          return DEBUG_IGMP;
	case IGMP_DVMRP:
	    switch (code) {
	    case DVMRP_PROBE:              return DEBUG_DVMRP_PEER;
	    case DVMRP_REPORT:             return DEBUG_DVMRP_ROUTE;
	    case DVMRP_ASK_NEIGHBORS:      return 0;
	    case DVMRP_NEIGHBORS:          return 0;
	    case DVMRP_ASK_NEIGHBORS2:     return 0;
	    case DVMRP_NEIGHBORS2:         return 0;
	    case DVMRP_PRUNE:              return DEBUG_DVMRP_PRUNE;
	    case DVMRP_GRAFT:              return DEBUG_DVMRP_PRUNE;
	    case DVMRP_GRAFT_ACK:          return DEBUG_DVMRP_PRUNE;
	    case DVMRP_INFO_REQUEST:       return 0;
	    case DVMRP_INFO_REPLY:         return 0;
	    default:                       return 0;
	    }
	case IGMP_PIM:
	    /* PIM v1 is not implemented */
	    switch (code) {
	    case PIM_V1_QUERY:             return DEBUG_PIM;
	    case PIM_V1_REGISTER:          return DEBUG_PIM;
	    case PIM_V1_REGISTER_STOP:     return DEBUG_PIM;
	    case PIM_V1_JOIN_PRUNE:        return DEBUG_PIM;
	    case PIM_V1_RP_REACHABILITY:   return DEBUG_PIM;
	    case PIM_V1_ASSERT:            return DEBUG_PIM;
	    case PIM_V1_GRAFT:             return DEBUG_PIM;
	    case PIM_V1_GRAFT_ACK:         return DEBUG_PIM;
	    default:                       return DEBUG_PIM;
	    }
	case IGMP_MTRACE:                  return DEBUG_TRACE;
	case IGMP_MTRACE_RESP:             return DEBUG_TRACE;
	default:                           return DEBUG_IGMP;
	}
    case IPPROTO_PIM: 	/* PIM v2 */
	/* TODO: modify? */
	switch (type) {
	case PIM_V2_HELLO:             return DEBUG_PIM;
	case PIM_V2_REGISTER:          return DEBUG_PIM_REGISTER;
	case PIM_V2_REGISTER_STOP:     return DEBUG_PIM_REGISTER;
	case PIM_V2_JOIN_PRUNE:        return DEBUG_PIM;
	case PIM_V2_BOOTSTRAP:         return DEBUG_PIM_BOOTSTRAP;
	case PIM_V2_ASSERT:            return DEBUG_PIM;
	case PIM_V2_GRAFT:             return DEBUG_PIM;
	case PIM_V2_GRAFT_ACK:         return DEBUG_PIM;
	case PIM_V2_CAND_RP_ADV:       return DEBUG_PIM_CAND_RP;
	default:                       return DEBUG_PIM;
	}
    default:                               return 0;
    }
    return 0;
}


/*
 * Some messages are more important than others.  This routine
 * determines the logging level at which to log a send error (often
 * "No route to host").  This is important when there is asymmetric
 * reachability and someone is trying to, i.e., mrinfo me periodically.
 */
int
log_level(proto, type, code)
    u_int proto, type, code;
{
    switch (proto) {
    case IPPROTO_IGMP:
	switch (type) {
	case IGMP_MTRACE_RESP:
	    return LOG_INFO;
	    
	case IGMP_DVMRP:
	    switch (code) {
	    case DVMRP_NEIGHBORS:
	    case DVMRP_NEIGHBORS2:
		return LOG_INFO;
	    }
	case IGMP_PIM:
	    /* PIM v1 */
	    switch (code) {
	    default:
		return LOG_INFO;
	    }
	default:
	    return LOG_WARNING;
	}
	
    case IPPROTO_PIM:
	/* PIM v2 */
	switch (type) {
	default:
	    return LOG_INFO;
	}
    default:
	return LOG_WARNING;
    }
    return LOG_WARNING;
}


/*
 * Dump internal data structures to stderr.
 */
/* TODO: currently not used
void 
dump(int i)
{
    dump_vifs(stderr);
    dump_pim_mrt(stderr);
}	
*/

/*
 * Dump internal data structures to a file.
 */
void 
fdump(i)
    int i;
{
    FILE *fp;
    fp = fopen(dumpfilename, "w");
    if (fp != NULL) {
	dump_vifs(fp);
	dump_pim_mrt(fp);
	(void) fclose(fp);
    }
}

/* TODO: dummy, to be used in the future. */
/*
 * Dump local cache contents to a file.
 */
void
cdump(i)
    int i;
{
    FILE *fp;
    
    fp = fopen(cachefilename, "w");
    if (fp != NULL) {
      /* TODO: implement it:
	 dump_cache(fp); 
	 */
	(void) fclose(fp);
    }
}

void
dump_vifs(fp)
    FILE *fp;
{	
    vifi_t vifi;
    register struct uvif *v;
    pim_nbr_entry_t *n;
    int width;
    int i;
    
    fprintf(fp, "\nVirtual Interface Table\n %-4s %-17s %-16s %-8s %-14s %s",
	    "Vif", "Local-Address", "Subnet", "Thresh", "Flags",
	    "Neighbors\n");
    
    for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
	fprintf(fp, "  %-3u %-17s ", vifi, inet_fmt(v->uv_lcl_addr, s1));
	if (v->uv_flags & VIFF_REGISTER)
	    fprintf(fp, "%-16s ", v->uv_name);
	else
	    fprintf(fp,"%-16.16s ", netname(v->uv_subnet, v->uv_subnetmask));
	fprintf(fp, "%-5u   ", v->uv_threshold);
	width = 0;
	if (v->uv_flags & VIFF_DISABLED)
	    fprintf(fp, " DISABLED");
	if (v->uv_flags & VIFF_DOWN)
	    fprintf(fp, " DOWN");
	if (v->uv_flags & VIFF_DR) {
	    fprintf(fp, " DR");
	    width += 3;
	}
	if (v->uv_flags & VIFF_PIM_NBR) {
	    fprintf(fp, " PIM");
	    width += 4;
	}
	if (v->uv_flags & VIFF_DVMRP_NBR) {
	    fprintf(fp, " DVMRP");
	    width += 6;
	}
	if (v->uv_flags & VIFF_NONBRS) {
	    fprintf(fp, " %-12s", "NO-NBR");
	    width += 6;
	}

	if ((n = v->uv_pim_neighbors) != NULL) {
	    /* Print the first neighbor on the same line */
	    for (i = width; i <= 15; i++)
		fprintf(fp, " ");
	    fprintf(fp, "%-12s\n", inet_fmt(n->address, s1));
	    for (n = n->next; n != NULL; n = n->next)
		fprintf(fp, "%64s %-15s\n", "", inet_fmt(n->address, s1));
	    
	}
	else
	    fprintf(fp, "\n");
    }  
    fprintf(fp, "\n");
}


/*
 * Log errors and other messages to the system log daemon and to stderr,
 * according to the severity of the message and the current debug level.
 * For errors of severity LOG_ERR or worse, terminate the program.
 */
#ifdef __STDC__
void
log(int severity, int syserr, char *format, ...)
{
    va_list ap;
    static char fmt[211] = "warning - ";
    char *msg;
    struct timeval now;
    struct tm *thyme;
    
    va_start(ap, format);
#else
/*VARARGS3*/
void
log(severity, syserr, format, va_alist)
    int severity, syserr;
    char *format;
    va_dcl
{
    va_list ap;
    static char fmt[311] = "warning - ";
    char *msg;
    char tbuf[20];
    struct timeval now;
    struct tm *thyme;
    
    va_start(ap);
#endif
    vsprintf(&fmt[10], format, ap);
    va_end(ap);
    msg = (severity == LOG_WARNING) ? fmt : &fmt[10];
    
    /*
     * Log to stderr if we haven't forked yet and it's a warning or worse,
     * or if we're debugging.
     */
    if (haveterminal && (debug || severity <= LOG_WARNING)) {
	gettimeofday(&now,NULL);
	thyme = localtime(&now.tv_sec);
	if (!debug)
	    fprintf(stderr, "%s: ", progname);
	fprintf(stderr, "%02d:%02d:%02d.%03ld %s", thyme->tm_hour,
		thyme->tm_min, thyme->tm_sec, now.tv_usec / 1000, msg);
	if (syserr == 0)
	    fprintf(stderr, "\n");
	else if (syserr < sys_nerr)
	    fprintf(stderr, ": %s\n", sys_errlist[syserr]);
	else
	    fprintf(stderr, ": errno %d\n", syserr);
    }
    
    /*
     * Always log things that are worse than warnings, no matter what
     * the log_nmsgs rate limiter says.
     * Only count things worse than debugging in the rate limiter
     * (since if you put daemon.debug in syslog.conf you probably
     * actually want to log the debugging messages so they shouldn't
     * be rate-limited)
     */
    if ((severity < LOG_WARNING) || (log_nmsgs < LOG_MAX_MSGS)) {
	if (severity < LOG_DEBUG)
	    log_nmsgs++;
	if (syserr != 0) {
	    errno = syserr;
	    syslog(severity, "%s: %m", msg);
	} else
	    syslog(severity, "%s", msg);
    }
    
    if (severity <= LOG_ERR) exit(-1);
}

/* TODO: format the output for better readability */
void 
dump_pim_mrt(fp)
    FILE *fp;
{
    grpentry_t *g;
    register mrtentry_t *r;
    register vifi_t vifi;
    u_int number_of_groups = 0;
    char oifs[(sizeof(vifbitmap_t)<<3)+1];
    char pruned_oifs[(sizeof(vifbitmap_t)<<3)+1];
    char leaves_oifs[(sizeof(vifbitmap_t)<<3)+1];
    char incoming_iif[(sizeof(vifbitmap_t)<<3)+1];
    
    fprintf(fp, "Multicast Routing Table\n%s", 
	    " Source          Group           Flags\n");

    /* TODO: remove the dummy 0.0.0.0 group (first in the chain) */
    for (g = grplist->next; g != (grpentry_t *)NULL; g = g->next) {
	number_of_groups++;
	/* Print all (S,G) routing info */
	for (r = g->mrtlink; r != (mrtentry_t *)NULL; r = r->grpnext) {
	    fprintf(fp, "---------------------------(S,G)----------------------------\n");
	    /* Print the routing info */
	    fprintf(fp, " %-15s", inet_fmt(r->source->address, s1));
	    fprintf(fp, " %-15s", inet_fmt(g->group, s2));

	    for (vifi = 0; vifi < numvifs; vifi++) {
		oifs[vifi] =
		    VIFM_ISSET(vifi, r->oifs)          ? 'o' : '.';
		pruned_oifs[vifi] =
		    VIFM_ISSET(vifi, r->pruned_oifs)   ? 'p' : '.';
		leaves_oifs[vifi] =
		    VIFM_ISSET(vifi, r->leaves)        ? 'l' : '.';
		incoming_iif[vifi] = '.';
	    }
	    oifs[vifi]          = 0x0;  /* End of string */
	    pruned_oifs[vifi]   = 0x0;
	    leaves_oifs[vifi]   = 0x0;
	    incoming_iif[vifi]  = 0x0;
	    incoming_iif[r->incoming] = 'I';

	    /* TODO: don't need some of the flags */
	    if (r->flags & MRTF_SPT)           fprintf(fp, " SPT");
	    if (r->flags & MRTF_WC)            fprintf(fp, " WC");
	    if (r->flags & MRTF_RP)            fprintf(fp, " RP");
	    if (r->flags & MRTF_REGISTER)      fprintf(fp, " REG");
	    if (r->flags & MRTF_IIF_REGISTER)  fprintf(fp, " IIF_REG");
	    if (r->flags & MRTF_NULL_OIF)      fprintf(fp, " NULL_OIF");
	    if (r->flags & MRTF_KERNEL_CACHE)  fprintf(fp, " CACHE");
	    if (r->flags & MRTF_ASSERTED)      fprintf(fp, " ASSERTED");
	    if (r->flags & MRTF_REG_SUPP)      fprintf(fp, " REG_SUPP");
	    if (r->flags & MRTF_SG)            fprintf(fp, " SG");
	    if (r->flags & MRTF_PMBR)          fprintf(fp, " PMBR");
	    fprintf(fp, "\n");
	    
	    fprintf(fp, "Pruned   oifs: %-20s\n", pruned_oifs);
	    fprintf(fp, "Leaves   oifs: %-20s\n", leaves_oifs);
	    fprintf(fp, "Outgoing oifs: %-20s\n", oifs);
	    fprintf(fp, "Incoming     : %-20s\n", incoming_iif);

	    fprintf(fp, "Upstream nbr: %s\n", 
		    r->upstream ? inet_fmt(r->upstream->address, s1) : "NONE");
	    fprintf(fp, "\nTIMERS:  Entry   Prune VIFS:");
	    for (vifi = 0; vifi < numvifs; vifi++)
		fprintf(fp, "  %2d", vifi);
	    fprintf(fp, "\n           %3d              ",
		    r->timer);
	    for (vifi = 0; vifi < numvifs; vifi++)
		fprintf(fp, " %3d", r->prune_timers[vifi]);
	    fprintf(fp, "\n");
	}
    }/* for all groups */

    fprintf(fp, "Number of Groups: %u\n", number_of_groups);
}


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