/*
* Copyright (c) 1998-2001
* University of Southern California/Information Sciences Institute.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* $Id: debug.c,v 1.1.1.1 2017/06/12 07:59:37 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.
*
*/
#define SYSLOG_NAMES
#include "defs.h"
#include <stdarg.h>
#include <stdio.h>
#define MAX_MSG_SIZE 64 /* Max for dump_frame() */
int log_nmsgs = 0;
int loglevel = LOG_NOTICE;
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(int proto, int type, int 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 Membership Report";
case IGMP_V2_MEMBERSHIP_REPORT: return "IGMP v2 Membership Report";
case IGMP_V3_MEMBERSHIP_REPORT: return "IGMP v3 Membership 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:
snprintf(unknown, sizeof(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:
snprintf(unknown, sizeof(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:
snprintf(unknown, sizeof (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:
snprintf(unknown, sizeof(unknown), "UNKNOWN PIM v2 message type =%3d ", type);
return unknown;
}
default:
snprintf(unknown, sizeof(unknown), "UNKNOWN proto =%3d ", proto);
return unknown;
}
}
/*
* Used for debugging particular type of messages.
*/
int debug_kind(int proto, int type, int 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_V3_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(int proto, int type, int 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;
}
return LOG_WARNING;
case IGMP_PIM:
/* PIM v1 */
switch (code) {
default:
return LOG_INFO;
}
return LOG_WARNING;
default:
return LOG_WARNING;
}
case IPPROTO_PIM:
/* PIM v2 */
switch (type) {
default:
return LOG_INFO;
}
return LOG_WARNING;
default:
return LOG_WARNING;
}
return LOG_WARNING;
}
/*
* Dump internal data structures to a file.
*/
void fdump(int i __attribute__((unused)))
{
FILE *fp;
fp = fopen(dumpfilename, "w");
if (fp) {
dump_vifs(fp);
dump_pim_mrt(fp);
fclose(fp);
}
}
/* TODO: dummy, to be used in the future. */
/*
* Dump local cache contents to a file.
*/
void cdump(int i __attribute__((unused)))
{
FILE *fp;
fp = fopen(cachefilename, "w");
if (fp) {
/* XXX: TODO: implement it:
dump_cache(fp);
*/
fclose(fp);
}
}
/*
1 2 3 4 5 6 7 8
012345678901234567890123456789012345678901234567890123456789012345678901234567890
Virtual Interface Table
Vif Local-Address Subnet Thresh Flags Neighbors
0 10.0.3.1 10.0.3/24 1 DR NO-NBR
1 172.16.12.254 172.16.12/24 1 DR PIM 172.16.12.2
172.16.12.3
2 192.168.122.147 register_vif0 1
*/
void dump_vifs(FILE *fp)
{
vifi_t vifi;
struct uvif *v;
pim_nbr_entry_t *n;
int width;
int i;
struct listaddr *group, *source;
fprintf(fp, "Virtual Interface Table ======================================================\n");
fprintf(fp, "Vif Local Address Subnet Thresh Flags Neighbors\n");
fprintf(fp, "--- --------------- ------------------ ------ --------- -----------------\n");
for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
int down = 0;
fprintf(fp, "%3u %-15s ", vifi, inet_fmt(v->uv_lcl_addr, s1, sizeof(s1)));
if (v->uv_flags & VIFF_REGISTER)
fprintf(fp, "%-18s ", v->uv_name);
else
fprintf(fp,"%-18.18s ", netname(v->uv_subnet, v->uv_subnetmask));
fprintf(fp, "%6u ", v->uv_threshold);
/* TODO: XXX: Print VIFF_TUNNEL? */
width = 0;
if (v->uv_flags & VIFF_DISABLED) {
fprintf(fp, " DISABLED");
down = 1;
}
if (v->uv_flags & VIFF_DOWN) {
fprintf(fp, " DOWN");
down = 1;
}
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, " NO-NBR");
width += 6;
}
n = v->uv_pim_neighbors;
if (!down && n) {
for (i = width; i <= 11; i++)
fprintf(fp, " ");
fprintf(fp, "%-15s\n", inet_fmt(n->address, s1, sizeof(s1)));
for (n = n->next; n; n = n->next)
fprintf(fp, "%61s%-15s\n", "", inet_fmt(n->address, s1, sizeof(s1)));
} else {
fprintf(fp, "\n");
}
}
fprintf(fp, "\n");
/* Dump groups and sources */
fprintf(fp, " %-3s %-15s %-20s", "Vif", "SSM Group", "Sources");
for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
for (group = v->uv_groups; group != NULL; group = group->al_next) {
if (IN_PIM_SSM_RANGE(group->al_addr)) {
fprintf(fp, "\n %3u %-15s ", vifi, inet_fmt(group->al_addr, s1, sizeof(s1)));
for (source = group->al_sources; source != NULL; source = source->al_next) {
fprintf(fp, "%s ", inet_fmt(source->al_addr, s1, sizeof(s1)));
}
}
}
}
fprintf(fp, "\n\n");
}
int loglvl(char *level)
{
int i;
for (i = 0; prioritynames[i].c_name; i++) {
if (string_match(prioritynames[i].c_name, level))
return prioritynames[i].c_val;
}
return atoi(level);
}
/*
* 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.
*/
void logit(int severity, int syserr, const char *format, ...)
{
va_list ap;
char msg[211];
struct timeval now;
struct tm *thyme;
time_t lt;
va_start(ap, format);
vsnprintf(msg, sizeof(msg), format, ap);
va_end(ap);
/*
* 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);
lt = now.tv_sec;
thyme = localtime(<);
if (!debug)
fprintf(stderr, "%s: ", __progname);
fprintf(stderr, "%02d:%02d:%02d.%03ld %s", thyme->tm_hour, thyme->tm_min,
thyme->tm_sec, (long int)(now.tv_usec / 1000), msg);
if (syserr) {
errno = syserr;
fprintf(stderr, ": %m");
}
fprintf(stderr, "\n");
}
/*
* Always log things that are worse than warnings, no matter what
* the log_nmsgs rate limiter says.
*
* Only count things at the defined loglevel or worse in the rate limiter
* and exclude debugging (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 <= loglevel) && (severity != LOG_DEBUG))
log_nmsgs++;
if (syserr) {
errno = syserr;
syslog(severity, "%s: %m", msg);
} else {
syslog(severity, "%s", msg);
}
}
#ifndef CONTINUE_ON_ERROR
if (severity <= LOG_ERR)
exit(-1); /* Exit status: 255 */
#endif /* CONTINUE_ON_ERROR */
}
/*
* Hex dump a control frame to the log, MAX 64 bytes length
*/
void dump_frame(char *desc, void *dump, size_t len)
{
unsigned int length, i = 0;
unsigned char *data = (unsigned char *)dump;
char buf[80] = "";
char tmp[10];
length = len;
if (length > MAX_MSG_SIZE)
length = MAX_MSG_SIZE;
if (desc)
logit(LOG_DEBUG, 0, "%s", desc);
while (i < length) {
if (!(i % 16))
snprintf(buf, sizeof(buf), "%03X: ", i);
snprintf(tmp, sizeof(tmp), "%02X ", data[i++]);
strlcat(buf, tmp, sizeof(buf));
if (i > 0 && !(i % 16))
logit(LOG_DEBUG, 0, "%s", buf);
else if (i > 0 && !(i % 8))
strlcat(buf, ":: ", sizeof(buf));
}
logit(LOG_DEBUG, 0, "%s", buf);
}
static void dump_route(FILE *fp, mrtentry_t *r)
{
vifi_t vifi;
char oifs[(sizeof(vifbitmap_t)<<3)+1];
char joined_oifs[(sizeof(vifbitmap_t)<<3)+1];
char pruned_oifs[(sizeof(vifbitmap_t)<<3)+1];
char leaves_oifs[(sizeof(vifbitmap_t)<<3)+1];
char asserted_oifs[(sizeof(vifbitmap_t)<<3)+1];
char incoming_iif[(sizeof(vifbitmap_t)<<3)+1];
for (vifi = 0; vifi < numvifs; vifi++) {
oifs[vifi] =
VIFM_ISSET(vifi, r->oifs) ? 'o' : '.';
joined_oifs[vifi] =
VIFM_ISSET(vifi, r->joined_oifs) ? 'j' : '.';
pruned_oifs[vifi] =
VIFM_ISSET(vifi, r->pruned_oifs) ? 'p' : '.';
leaves_oifs[vifi] =
VIFM_ISSET(vifi, r->leaves) ? 'l' : '.';
asserted_oifs[vifi] =
VIFM_ISSET(vifi, r->asserted_oifs) ? 'a' : '.';
incoming_iif[vifi] = '.';
}
oifs[vifi] = 0x0; /* End of string */
joined_oifs[vifi] = 0x0;
pruned_oifs[vifi] = 0x0;
leaves_oifs[vifi] = 0x0;
asserted_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, "Joined oifs: %-20s\n", joined_oifs);
fprintf(fp, "Pruned oifs: %-20s\n", pruned_oifs);
fprintf(fp, "Leaves oifs: %-20s\n", leaves_oifs);
fprintf(fp, "Asserted oifs: %-20s\n", asserted_oifs);
fprintf(fp, "Outgoing oifs: %-20s\n", oifs);
fprintf(fp, "Incoming : %-20s\n", incoming_iif);
fprintf(fp, "\nTIMERS: Entry JP RS Assert VIFS:");
for (vifi = 0; vifi < numvifs; vifi++)
fprintf(fp, " %d", vifi);
fprintf(fp, "\n %5d %4d %4d %6d ",
r->timer, r->jp_timer, r->rs_timer, r->assert_timer);
for (vifi = 0; vifi < numvifs; vifi++)
fprintf(fp, " %2d", r->vif_timers[vifi]);
fprintf(fp, "\n");
}
void dump_pim_mrt(FILE *fp)
{
grpentry_t *g;
mrtentry_t *r;
u_int number_of_cache_mirrors = 0;
u_int number_of_groups = 0;
cand_rp_t *rp;
kernel_cache_t *kc;
fprintf(fp, "Multicast Routing Table ======================================================\n");
/* TODO: remove the dummy 0.0.0.0 group (first in the chain) */
for (g = grplist->next; g; g = g->next) {
number_of_groups++;
r = g->grp_route;
if (r) {
if (r->flags & MRTF_KERNEL_CACHE) {
for (kc = r->kernel_cache; kc; kc = kc->next)
number_of_cache_mirrors++;
}
/* Print the (*,G) routing info */
fprintf(fp, "----------------------------------- (*,G) ------------------------------------\n");
fprintf(fp, "Source Group RP Address Flags\n");
fprintf(fp, "--------------- --------------- --------------- ---------------------------\n");
fprintf(fp, "%-15s ", "INADDR_ANY");
fprintf(fp, "%-15s ", inet_fmt(g->group, s1, sizeof(s1)));
fprintf(fp, "%-15s ", IN_PIM_SSM_RANGE(g->group) ? "SSM" :
(g->active_rp_grp ? inet_fmt(g->rpaddr, s2, sizeof(s2)) : "NULL"));
dump_route(fp, r);
}
/* Print all (S,G) routing info */
fprintf(fp, "----------------------------------- (S,G) ------------------------------------\n");
for (r = g->mrtlink; r; r = r->grpnext) {
if (r->flags & MRTF_KERNEL_CACHE)
number_of_cache_mirrors++;
/* Print the routing info */
fprintf(fp, "Source Group RP Address Flags\n");
fprintf(fp, "--------------- --------------- --------------- ---------------------------\n");
fprintf(fp, "%-15s ", inet_fmt(r->source->address, s1, sizeof(s1)));
fprintf(fp, "%-15s ", inet_fmt(g->group, s2, sizeof(s2)));
fprintf(fp, "%-15s ", IN_PIM_SSM_RANGE(g->group) ? "SSM" :
(g->active_rp_grp ? inet_fmt(g->rpaddr, s2, sizeof(s2)) : "NULL"));
dump_route(fp, r);
}
}/* for all groups */
/* Print the (*,*,R) routing entries */
fprintf(fp, "--------------------------------- (*,*,G) ------------------------------------\n");
for (rp = cand_rp_list; rp; rp = rp->next) {
r = rp->rpentry->mrtlink;
if (r) {
if (r->flags & MRTF_KERNEL_CACHE) {
for (kc = r->kernel_cache; kc; kc = kc->next)
number_of_cache_mirrors++;
}
/* Print the (*,*,RP) routing info */
fprintf(fp, "Source Group RP Address Flags\n");
fprintf(fp, "--------------- --------------- --------------- ---------------------------\n");
fprintf(fp, "%-15s ", inet_fmt(r->source->address, s1, sizeof(s1)));
fprintf(fp, "%-15s ", "INADDR_ANY");
fprintf(fp, "%-15s ", "");
dump_route(fp, r);
}
} /* For all (*,*,RP) */
fprintf(fp, "Number of Groups: %u\n", number_of_groups);
fprintf(fp, "Number of Cache MIRRORs: %u\n", number_of_cache_mirrors);
fprintf(fp, "------------------------------------------------------------------------------\n\n");
}
static void dump_rpgrp(FILE *fp, rp_grp_entry_t *rpgrp, int indent)
{
grp_mask_t *grp = rpgrp->group;
if (indent)
fprintf(fp, " ");
fprintf(fp, "%-18.18s %-8u %-8u\n",
netname(grp->group_addr, grp->group_mask),
rpgrp->priority, rpgrp->holdtime);
}
/*
* Dumps the local Cand-RP-set
*/
int dump_rp_set(FILE *fp)
{
cand_rp_t *rp;
rp_grp_entry_t *rpgrp;
fprintf(fp, "Candidate Rendezvous-Point Set ===============================================\n");
fprintf(fp, "RP address Incoming Group Prefix Priority Holdtime\n");
fprintf(fp, "--------------- -------- ------------------ -------- ---------------------\n");
for (rp = cand_rp_list; rp; rp = rp->next) {
fprintf(fp, "%-15s %-8d ",
inet_fmt(rp->rpentry->address, s1, sizeof(s1)),
rp->rpentry->incoming);
rpgrp = rp->rp_grp_next;
if (rpgrp) {
dump_rpgrp(fp, rpgrp, 0);
for (rpgrp = rpgrp->rp_grp_next; rpgrp; rpgrp = rpgrp->rp_grp_next)
dump_rpgrp(fp, rpgrp, 1);
}
}
fprintf(fp, "------------------------------------------------------------------------------\n");
fprintf(fp, "Current BSR address: %s\n\n", inet_fmt(curr_bsr_address, s1, sizeof(s1)));
return TRUE;
}
/**
* Local Variables:
* version-control: t
* indent-tabs-mode: t
* c-file-style: "ellemtel"
* c-basic-offset: 4
* End:
*/
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>