0fea3d5165
kernel IPv6 multicast routing support. pim6 dense mode daemon pim6 sparse mode daemon netstat support of IPv6 multicast routing statistics Merging to the current and testing with other existing multicast routers is done by Tatsuya Jinmei <jinmei@kame.net>, who writes and maintainances the base code in KAME distribution. Make world check and kernel build check was also successful.
720 lines
19 KiB
C
720 lines
19 KiB
C
/*
|
|
* Copyright (c) 1998 by the University of Oregon.
|
|
* 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 Oregon.
|
|
* The name of the University of Oregon may not be used to endorse or
|
|
* promote products derived from this software without specific prior
|
|
* written permission.
|
|
*
|
|
* THE UNIVERSITY OF OREGON 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 UO, 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
|
|
* Kurt Windisch (kurtw@antc.uoregon.edu)
|
|
*
|
|
* $Id: main.c,v 1.2 1999/08/13 09:20:13 jinmei Exp $
|
|
*/
|
|
/*
|
|
* Part of this program has been derived from PIM sparse-mode pimd.
|
|
* The pimd program is covered by the license in the accompanying file
|
|
* named "LICENSE.pimd".
|
|
*
|
|
* The pimd program is COPYRIGHT 1998 by University of Southern California.
|
|
*
|
|
* 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.
|
|
*
|
|
* $FreeBSD$
|
|
*/
|
|
|
|
#include "defs.h"
|
|
|
|
#ifdef SNMP
|
|
#include "snmp.h"
|
|
#endif
|
|
|
|
char configfilename[256] = _PATH_PIM6D_CONF;
|
|
char versionstring[100];
|
|
|
|
static char pidfilename[] = _PATH_PIM6D_PID;
|
|
/* TODO: not used
|
|
static char genidfilename[] = _PATH_PIM6D_GENID;
|
|
*/
|
|
|
|
int haveterminal = 1;
|
|
char *progname;
|
|
|
|
static int sighandled = 0;
|
|
#define GOT_SIGINT 0x01
|
|
#define GOT_SIGHUP 0x02
|
|
#define GOT_SIGUSR1 0x04
|
|
#define GOT_SIGUSR2 0x08
|
|
#define GOT_SIGALRM 0x10
|
|
|
|
|
|
#ifdef SNMP
|
|
#define NHANDLERS 34
|
|
#else
|
|
#define NHANDLERS 3
|
|
#endif
|
|
|
|
static struct ihandler {
|
|
int fd; /* File descriptor */
|
|
ihfunc_t func; /* Function to call with &fd_set */
|
|
} ihandlers[NHANDLERS];
|
|
static int nhandlers = 0;
|
|
|
|
static struct debugname {
|
|
char *name;
|
|
int level;
|
|
int nchars;
|
|
} debugnames[] = {
|
|
#if 0
|
|
{ "dvmrp_detail", DEBUG_DVMRP_DETAIL, 5 },
|
|
{ "dvmrp_prunes", DEBUG_DVMRP_PRUNE, 8 },
|
|
{ "dvmrp_pruning", DEBUG_DVMRP_PRUNE, 8 },
|
|
{ "dvmrp_mrt", DEBUG_DVMRP_ROUTE, 7 },
|
|
{ "dvmrp_routes", DEBUG_DVMRP_ROUTE, 7 },
|
|
{ "dvmrp_routing", DEBUG_DVMRP_ROUTE, 7 },
|
|
{ "dvmrp_neighbors", DEBUG_DVMRP_PEER, 7 },
|
|
{ "dvmrp_peers", DEBUG_DVMRP_PEER, 8 },
|
|
{ "dvmrp_hello", DEBUG_DVMRP_PEER, 7 },
|
|
{ "dvmrp_timers", DEBUG_DVMRP_TIMER, 7 },
|
|
{ "dvmrp", DEBUG_DVMRP, 1 },
|
|
{ "igmp_proto", DEBUG_IGMP_PROTO, 6 },
|
|
{ "igmp_timers", DEBUG_IGMP_TIMER, 6 },
|
|
{ "igmp_members", DEBUG_IGMP_MEMBER, 6 },
|
|
{ "groups", DEBUG_MEMBER, 1 },
|
|
{ "membership", DEBUG_MEMBER, 2 },
|
|
{ "igmp", DEBUG_IGMP, 1 },
|
|
#endif
|
|
{ "trace", DEBUG_TRACE, 2 },
|
|
{ "mtrace", DEBUG_TRACE, 2 },
|
|
{ "traceroute", DEBUG_TRACE, 2 },
|
|
{ "timeout", DEBUG_TIMEOUT, 2 },
|
|
{ "callout", DEBUG_TIMEOUT, 3 },
|
|
{ "pkt", DEBUG_PKT, 2 },
|
|
{ "packets", DEBUG_PKT, 2 },
|
|
{ "interfaces", DEBUG_IF, 2 },
|
|
{ "vif", DEBUG_IF, 1 },
|
|
{ "kernel", DEBUG_KERN, 2 },
|
|
{ "cache", DEBUG_MFC, 1 },
|
|
{ "mfc", DEBUG_MFC, 2 },
|
|
{ "k_cache", DEBUG_MFC, 2 },
|
|
{ "k_mfc", DEBUG_MFC, 2 },
|
|
{ "rsrr", DEBUG_RSRR, 2 },
|
|
{ "pim_detail", DEBUG_PIM_DETAIL, 5 },
|
|
{ "pim_hello", DEBUG_PIM_HELLO, 5 },
|
|
{ "pim_neighbors", DEBUG_PIM_HELLO, 5 },
|
|
{ "pim_register", DEBUG_PIM_REGISTER, 5 },
|
|
{ "registers", DEBUG_PIM_REGISTER, 2 },
|
|
{ "pim_join_prune", DEBUG_PIM_JOIN_PRUNE, 5 },
|
|
{ "pim_j_p", DEBUG_PIM_JOIN_PRUNE, 5 },
|
|
{ "pim_jp", DEBUG_PIM_JOIN_PRUNE, 5 },
|
|
{ "pim_graft", DEBUG_PIM_GRAFT, 5 },
|
|
{ "pim_bootstrap", DEBUG_PIM_BOOTSTRAP, 5 },
|
|
{ "pim_bsr", DEBUG_PIM_BOOTSTRAP, 5 },
|
|
{ "bsr", DEBUG_PIM_BOOTSTRAP, 1 },
|
|
{ "bootstrap", DEBUG_PIM_BOOTSTRAP, 1 },
|
|
{ "pim_asserts", DEBUG_PIM_ASSERT, 5 },
|
|
{ "pim_cand_rp", DEBUG_PIM_CAND_RP, 5 },
|
|
{ "pim_c_rp", DEBUG_PIM_CAND_RP, 5 },
|
|
{ "pim_rp", DEBUG_PIM_CAND_RP, 6 },
|
|
{ "rp", DEBUG_PIM_CAND_RP, 2 },
|
|
{ "pim_routes", DEBUG_PIM_MRT, 6 },
|
|
{ "pim_routing", DEBUG_PIM_MRT, 6 },
|
|
{ "pim_mrt", DEBUG_PIM_MRT, 5 },
|
|
{ "pim_timers", DEBUG_PIM_TIMER, 5 },
|
|
{ "pim_rpf", DEBUG_PIM_RPF, 6 },
|
|
{ "rpf", DEBUG_RPF, 3 },
|
|
{ "pim", DEBUG_PIM, 1 },
|
|
{ "routes", DEBUG_MRT, 1 },
|
|
{ "routing", DEBUG_MRT, 1 },
|
|
{ "mrt", DEBUG_MRT, 1 },
|
|
{ "routers", DEBUG_NEIGHBORS, 6 },
|
|
{ "mrouters", DEBUG_NEIGHBORS, 7 },
|
|
{ "neighbors", DEBUG_NEIGHBORS, 1 },
|
|
{ "timers", DEBUG_TIMER, 1 },
|
|
{ "asserts", DEBUG_ASSERT, 1 },
|
|
{ "all", DEBUG_ALL, 2 },
|
|
{ "3", 0xffffffff, 1 } /* compat. */
|
|
};
|
|
|
|
/*
|
|
* Forward declarations.
|
|
*/
|
|
static void handler __P((int));
|
|
static void timer __P((void *));
|
|
static void cleanup __P((void));
|
|
static void restart __P((int));
|
|
static void cleanup __P((void));
|
|
static void resetlogging __P((void *));
|
|
|
|
|
|
/* To shut up gcc -Wstrict-prototypes */
|
|
int main __P((int argc, char **argv));
|
|
|
|
int
|
|
register_input_handler(fd, func)
|
|
int fd;
|
|
ihfunc_t func;
|
|
{
|
|
if (nhandlers >= NHANDLERS)
|
|
return -1;
|
|
|
|
ihandlers[nhandlers].fd = fd;
|
|
ihandlers[nhandlers++].func = func;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
main(argc, argv)
|
|
int argc;
|
|
char *argv[];
|
|
{
|
|
int dummy, dummysigalrm;
|
|
FILE *fp;
|
|
struct timeval tv, difftime, curtime, lasttime, *timeout;
|
|
fd_set rfds, readers;
|
|
int nfds, n, i, secs;
|
|
extern char todaysversion[];
|
|
struct sigaction sa;
|
|
struct debugname *d;
|
|
char c;
|
|
int tmpd;
|
|
|
|
|
|
setlinebuf(stderr);
|
|
|
|
if (geteuid() != 0) {
|
|
fprintf(stderr, "pim6dd: must be root\n");
|
|
exit(1);
|
|
}
|
|
|
|
progname = strrchr(argv[0], '/');
|
|
if (progname)
|
|
progname++;
|
|
else
|
|
progname = argv[0];
|
|
|
|
argv++;
|
|
argc--;
|
|
while (argc > 0 && *argv[0] == '-') {
|
|
if (strcmp(*argv, "-d") == 0) {
|
|
if (argc > 1 && *(argv + 1)[0] != '-') {
|
|
char *p,*q;
|
|
int i, len;
|
|
struct debugname *d;
|
|
|
|
argv++;
|
|
argc--;
|
|
debug = 0;
|
|
p = *argv; q = NULL;
|
|
while (p) {
|
|
q = strchr(p, ',');
|
|
if (q)
|
|
*q++ = '\0';
|
|
len = strlen(p);
|
|
for (i = 0, d = debugnames;
|
|
i < sizeof(debugnames) / sizeof(debugnames[0]);
|
|
i++, d++)
|
|
if (len >= d->nchars && strncmp(d->name, p, len) == 0)
|
|
break;
|
|
if (i == sizeof(debugnames) / sizeof(debugnames[0])) {
|
|
int j = 0xffffffff;
|
|
int k = 0;
|
|
fprintf(stderr, "Valid debug levels: ");
|
|
for (i = 0, d = debugnames;
|
|
i < sizeof(debugnames) / sizeof(debugnames[0]);
|
|
i++, d++) {
|
|
if ((j & d->level) == d->level) {
|
|
if (k++)
|
|
putc(',', stderr);
|
|
fputs(d->name, stderr);
|
|
j &= ~d->level;
|
|
}
|
|
}
|
|
putc('\n', stderr);
|
|
goto usage;
|
|
}
|
|
debug |= d->level;
|
|
p = q;
|
|
}
|
|
}
|
|
else
|
|
debug = DEBUG_DEFAULT;
|
|
}
|
|
else if (strcmp(*argv, "-c") == 0) {
|
|
if (argc > 1) {
|
|
argv++; argc--;
|
|
strcpy(configfilename, *argv);
|
|
}
|
|
else
|
|
goto usage;
|
|
/* TODO: not implemented */
|
|
#ifdef SNMP
|
|
}
|
|
else if (strcmp(*argv, "-P") == 0) {
|
|
if (argc > 1 && isdigit(*(argv + 1)[0])) {
|
|
argv++, argc--;
|
|
dest_port = atoi(*argv);
|
|
}
|
|
else
|
|
dest_port = DEFAULT_PORT;
|
|
#endif
|
|
}
|
|
else
|
|
goto usage;
|
|
argv++; argc--;
|
|
}
|
|
|
|
if (argc > 0) {
|
|
usage:
|
|
tmpd = 0xffffffff;
|
|
fprintf(stderr, "usage: pim6dd [-c configfile] [-d [debug_level][,debug_level]]\n");
|
|
|
|
fprintf(stderr, "debug levels: ");
|
|
c = '(';
|
|
for (d = debugnames; d < debugnames +
|
|
sizeof(debugnames) / sizeof(debugnames[0]); d++) {
|
|
if ((tmpd & d->level) == d->level) {
|
|
tmpd &= ~d->level;
|
|
fprintf(stderr, "%c%s", c, d->name);
|
|
c = ',';
|
|
}
|
|
}
|
|
fprintf(stderr, ")\n");
|
|
exit(1);
|
|
}
|
|
|
|
if (debug != 0) {
|
|
tmpd = debug;
|
|
fprintf(stderr, "debug level 0x%lx ", debug);
|
|
c = '(';
|
|
for (d = debugnames; d < debugnames +
|
|
sizeof(debugnames) / sizeof(debugnames[0]); d++) {
|
|
if ((tmpd & d->level) == d->level) {
|
|
tmpd &= ~d->level;
|
|
fprintf(stderr, "%c%s", c, d->name);
|
|
c = ',';
|
|
}
|
|
}
|
|
fprintf(stderr, ")\n");
|
|
}
|
|
|
|
#ifdef LOG_DAEMON
|
|
(void)openlog("pim6dd", LOG_PID, LOG_DAEMON);
|
|
(void)setlogmask(LOG_UPTO(LOG_NOTICE));
|
|
#else
|
|
(void)openlog("pim6dd", LOG_PID);
|
|
#endif /* LOG_DAEMON */
|
|
sprintf(versionstring, "pim6dd version %s", todaysversion);
|
|
|
|
log(LOG_DEBUG, 0, "%s starting", versionstring);
|
|
|
|
/* TODO: XXX: use a combination of time and hostid to initialize the random
|
|
* generator.
|
|
*/
|
|
#ifdef SYSV
|
|
srand48(time(NULL));
|
|
#else
|
|
{
|
|
struct timeval tm;
|
|
gettimeofday(&tm, NULL);
|
|
srandom(tm.tv_usec + gethostid());
|
|
}
|
|
#endif
|
|
|
|
callout_init();
|
|
|
|
/* Start up the log rate-limiter */
|
|
resetlogging(NULL);
|
|
|
|
init_mld6();
|
|
#if 0
|
|
k_stop_pim(mld6_socket);
|
|
exit(0); /* XXX */
|
|
#endif
|
|
init_pim6();
|
|
|
|
init_pim6_mrt();
|
|
init_timers();
|
|
|
|
/* TODO: check the kernel DVMRP/MROUTED/PIM support version */
|
|
|
|
#ifdef SNMP
|
|
if (i = snmp_init())
|
|
return i;
|
|
#endif /* SNMP */
|
|
init_vifs();
|
|
|
|
#ifdef RSRR
|
|
rsrr_init();
|
|
#endif /* RSRR */
|
|
|
|
sa.sa_handler = handler;
|
|
sa.sa_flags = 0; /* Interrupt system calls */
|
|
sigemptyset(&sa.sa_mask);
|
|
sigaction(SIGALRM, &sa, NULL);
|
|
sigaction(SIGHUP, &sa, NULL);
|
|
sigaction(SIGTERM, &sa, NULL);
|
|
sigaction(SIGINT, &sa, NULL);
|
|
sigaction(SIGUSR1, &sa, NULL);
|
|
sigaction(SIGUSR2, &sa, NULL);
|
|
|
|
FD_ZERO(&readers);
|
|
FD_SET(mld6_socket, &readers);
|
|
nfds = mld6_socket + 1;
|
|
for (i = 0; i < nhandlers; i++) {
|
|
FD_SET(ihandlers[i].fd, &readers);
|
|
if (ihandlers[i].fd >= nfds)
|
|
nfds = ihandlers[i].fd + 1;
|
|
}
|
|
|
|
IF_DEBUG(DEBUG_IF)
|
|
dump_vifs(stderr);
|
|
IF_DEBUG(DEBUG_PIM_MRT)
|
|
dump_pim_mrt(stderr);
|
|
|
|
/* schedule first timer interrupt */
|
|
timer_setTimer(TIMER_INTERVAL, timer, NULL);
|
|
|
|
if (debug == 0) {
|
|
/* Detach from the terminal */
|
|
#ifdef TIOCNOTTY
|
|
int t;
|
|
#endif /* TIOCNOTTY */
|
|
|
|
haveterminal = 0;
|
|
if (fork())
|
|
exit(0);
|
|
(void)close(0);
|
|
(void)close(1);
|
|
(void)close(2);
|
|
(void)open("/", 0);
|
|
(void)dup2(0, 1);
|
|
(void)dup2(0, 2);
|
|
#if defined(SYSV) || defined(linux)
|
|
(void)setpgrp();
|
|
#else
|
|
#ifdef TIOCNOTTY
|
|
t = open("/dev/tty", 2);
|
|
if (t >= 0) {
|
|
(void)ioctl(t, TIOCNOTTY, (char *)0);
|
|
(void)close(t);
|
|
}
|
|
#else
|
|
if (setsid() < 0)
|
|
perror("setsid");
|
|
#endif /* TIOCNOTTY */
|
|
#endif /* SYSV */
|
|
} /* End of child process code */
|
|
|
|
#ifdef HAVE_ROUTING_SOCKETS
|
|
init_routesock();
|
|
#endif /* HAVE_ROUTING_SOCKETS */
|
|
|
|
fp = fopen(pidfilename, "w");
|
|
if (fp != NULL) {
|
|
fprintf(fp, "%d\n", (int)getpid());
|
|
(void) fclose(fp);
|
|
}
|
|
|
|
/*
|
|
* Main receive loop.
|
|
*/
|
|
dummy = 0;
|
|
dummysigalrm = SIGALRM;
|
|
difftime.tv_usec = 0;
|
|
gettimeofday(&curtime, NULL);
|
|
lasttime = curtime;
|
|
for(;;) {
|
|
bcopy((char *)&readers, (char *)&rfds, sizeof(rfds));
|
|
secs = timer_nextTimer();
|
|
if (secs == -1)
|
|
timeout = NULL;
|
|
else {
|
|
timeout = &tv;
|
|
timeout->tv_sec = secs;
|
|
timeout->tv_usec = 0;
|
|
}
|
|
|
|
if (sighandled) {
|
|
if (sighandled & GOT_SIGINT) {
|
|
sighandled &= ~GOT_SIGINT;
|
|
break;
|
|
}
|
|
if (sighandled & GOT_SIGHUP) {
|
|
sighandled &= ~GOT_SIGHUP;
|
|
restart(SIGHUP);
|
|
}
|
|
if (sighandled & GOT_SIGUSR1) {
|
|
sighandled &= ~GOT_SIGUSR1;
|
|
fdump(SIGUSR1);
|
|
}
|
|
if (sighandled & GOT_SIGUSR2) {
|
|
sighandled &= ~GOT_SIGUSR2;
|
|
cdump(SIGUSR2);
|
|
}
|
|
if (sighandled & GOT_SIGALRM) {
|
|
sighandled &= ~GOT_SIGALRM;
|
|
timer(&dummysigalrm);
|
|
}
|
|
}
|
|
if ((n = select(nfds, &rfds, NULL, NULL, timeout)) < 0) {
|
|
if (errno != EINTR) /* SIGALRM is expected */
|
|
log(LOG_WARNING, errno, "select failed");
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
* Handle timeout queue.
|
|
*
|
|
* If select + packet processing took more than 1 second,
|
|
* or if there is a timeout pending, age the timeout queue.
|
|
*
|
|
* If not, collect usec in difftime to make sure that the
|
|
* time doesn't drift too badly.
|
|
*
|
|
* If the timeout handlers took more than 1 second,
|
|
* age the timeout queue again. XXX This introduces the
|
|
* potential for infinite loops!
|
|
*/
|
|
do {
|
|
/*
|
|
* If the select timed out, then there's no other
|
|
* activity to account for and we don't need to
|
|
* call gettimeofday.
|
|
*/
|
|
if (n == 0) {
|
|
curtime.tv_sec = lasttime.tv_sec + secs;
|
|
curtime.tv_usec = lasttime.tv_usec;
|
|
n = -1; /* don't do this next time through the loop */
|
|
} else
|
|
gettimeofday(&curtime, NULL);
|
|
difftime.tv_sec = curtime.tv_sec - lasttime.tv_sec;
|
|
difftime.tv_usec += curtime.tv_usec - lasttime.tv_usec;
|
|
#ifdef TIMERDEBUG
|
|
IF_DEBUG(DEBUG_TIMEOUT)
|
|
log(LOG_DEBUG, 0, "TIMEOUT: secs %d, diff secs %d, diff usecs %d", secs, difftime.tv_sec, difftime.tv_usec );
|
|
#endif
|
|
while (difftime.tv_usec > 1000000) {
|
|
difftime.tv_sec++;
|
|
difftime.tv_usec -= 1000000;
|
|
}
|
|
if (difftime.tv_usec < 0) {
|
|
difftime.tv_sec--;
|
|
difftime.tv_usec += 1000000;
|
|
}
|
|
lasttime = curtime;
|
|
if (secs == 0 || difftime.tv_sec > 0) {
|
|
#ifdef TIMERDEBUG
|
|
IF_DEBUG(DEBUG_TIMEOUT)
|
|
log(LOG_DEBUG, 0, "\taging callouts: secs %d, diff secs %d, diff usecs %d", secs, difftime.tv_sec, difftime.tv_usec );
|
|
#endif
|
|
age_callout_queue(difftime.tv_sec);
|
|
}
|
|
secs = -1;
|
|
} while (difftime.tv_sec > 0);
|
|
|
|
/* Handle sockets */
|
|
if (n > 0) {
|
|
/* TODO: shall check first mld6_socket for better performance? */
|
|
for (i = 0; i < nhandlers; i++) {
|
|
if (FD_ISSET(ihandlers[i].fd, &rfds)) {
|
|
(*ihandlers[i].func)(ihandlers[i].fd, &rfds);
|
|
}
|
|
}
|
|
}
|
|
|
|
} /* Main loop */
|
|
|
|
log(LOG_NOTICE, 0, "%s exiting", versionstring);
|
|
cleanup();
|
|
exit(0);
|
|
}
|
|
|
|
/*
|
|
* The 'virtual_time' variable is initialized to a value that will cause the
|
|
* first invocation of timer() to send a probe or route report to all vifs
|
|
* and send group membership queries to all subnets for which this router is
|
|
* querier. This first invocation occurs approximately TIMER_INTERVAL seconds
|
|
* after the router starts up. Note that probes for neighbors and queries
|
|
* for group memberships are also sent at start-up time, as part of initial-
|
|
* ization. This repetition after a short interval is desirable for quickly
|
|
* building up topology and membership information in the presence of possible
|
|
* packet loss.
|
|
*
|
|
* 'virtual_time' advances at a rate that is only a crude approximation of
|
|
* real time, because it does not take into account any time spent processing,
|
|
* and because the timer intervals are sometimes shrunk by a random amount to
|
|
* avoid unwanted synchronization with other routers.
|
|
*/
|
|
|
|
u_long virtual_time = 0;
|
|
|
|
/*
|
|
* Timer routine. Performs all perodic functions:
|
|
* aging interfaces, quering neighbors and members, etc... The granularity
|
|
* is equal to TIMER_INTERVAL.
|
|
*/
|
|
static void
|
|
timer(i)
|
|
void *i;
|
|
{
|
|
age_vifs(); /* Timeout neighbors and groups */
|
|
age_routes(); /* Timeout routing entries */
|
|
|
|
virtual_time += TIMER_INTERVAL;
|
|
timer_setTimer(TIMER_INTERVAL, timer, NULL);
|
|
}
|
|
|
|
/*
|
|
* Performs all necessary functions to quit gracefully
|
|
*/
|
|
/* TODO: implement all necessary stuff */
|
|
static void
|
|
cleanup()
|
|
{
|
|
|
|
#ifdef RSRR
|
|
rsrr_clean();
|
|
#endif /* RSRR */
|
|
|
|
k_stop_pim(mld6_socket);
|
|
|
|
/* TODO: XXX (not in the spec)
|
|
*/
|
|
}
|
|
|
|
|
|
/*
|
|
* Signal handler. Take note of the fact that the signal arrived
|
|
* so that the main loop can take care of it.
|
|
*/
|
|
static void
|
|
handler(sig)
|
|
int sig;
|
|
{
|
|
switch (sig) {
|
|
case SIGALRM:
|
|
sighandled |= GOT_SIGALRM;
|
|
case SIGINT:
|
|
case SIGTERM:
|
|
sighandled |= GOT_SIGINT;
|
|
break;
|
|
|
|
case SIGHUP:
|
|
sighandled |= GOT_SIGHUP;
|
|
break;
|
|
|
|
case SIGUSR1:
|
|
sighandled |= GOT_SIGUSR1;
|
|
break;
|
|
|
|
case SIGUSR2:
|
|
sighandled |= GOT_SIGUSR2;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/* TODO: not verified */
|
|
/* PIMDM TODO */
|
|
/*
|
|
* Restart the daemon
|
|
*/
|
|
static void
|
|
restart(i)
|
|
int i;
|
|
{
|
|
#ifdef SNMP
|
|
int s;
|
|
#endif /* SNMP */
|
|
|
|
log(LOG_NOTICE, 0, "% restart", versionstring);
|
|
|
|
/*
|
|
* reset all the entries
|
|
*/
|
|
/*
|
|
* TODO: delete?
|
|
* free_all_routes();
|
|
*/
|
|
free_all_callouts();
|
|
stop_all_vifs();
|
|
nhandlers=0;
|
|
k_stop_pim(mld6_socket);
|
|
close(mld6_socket);
|
|
close(pim6_socket);
|
|
close(udp_socket);
|
|
|
|
/*
|
|
* start processing again
|
|
*/
|
|
init_mld6();
|
|
init_pim6();
|
|
#ifdef HAVE_ROUTING_SOCKETS
|
|
init_routesock();
|
|
#endif /* HAVE_ROUTING_SOCKETS */
|
|
init_pim6_mrt();
|
|
#ifdef SNMP
|
|
if ( s = snmp_init())
|
|
exit(s);
|
|
#endif /* SNMP */
|
|
init_vifs();
|
|
|
|
#ifdef RSRR
|
|
rsrr_init();
|
|
#endif /* RSRR */
|
|
|
|
/* schedule timer interrupts */
|
|
timer_setTimer(TIMER_INTERVAL, timer, NULL);
|
|
}
|
|
|
|
|
|
static void
|
|
resetlogging(arg)
|
|
void *arg;
|
|
{
|
|
int nxttime = 60;
|
|
void *narg = NULL;
|
|
|
|
if (arg == NULL && log_nmsgs > LOG_MAX_MSGS) {
|
|
nxttime = LOG_SHUT_UP;
|
|
narg = (void *)&log_nmsgs; /* just need some valid void * */
|
|
syslog(LOG_WARNING, "logging too fast, shutting up for %d minutes",
|
|
LOG_SHUT_UP / 60);
|
|
} else {
|
|
log_nmsgs = 0;
|
|
}
|
|
|
|
timer_setTimer(nxttime, resetlogging, narg);
|
|
}
|