/*
* The mrouted program is covered by the license in the accompanying file
* named "LICENSE". Use of the mrouted program represents acceptance of
* the terms and conditions listed in that file.
*
* The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
* Leland Stanford Junior University.
*/
/*
* Written by Steve Deering, Stanford University, February 1989.
*
* (An earlier version of DVMRP was implemented by David Waitzman of
* BBN STC by extending Berkeley's routed program. Some of Waitzman's
* extensions have been incorporated into mrouted, but none of the
* original routed code has been adopted.)
*/
/*
* Allow cleanup if unexpected exit. Apparently some architectures
* have a kernel bug where closing the socket doesn't do an
* ip_mrouter_done(), so we attempt to do it on exit.
*/
atexit(cleanup);
if (debug)
fprintf(stderr, "pruning %s\n", pruning ? "on" : "off");
/*
* routine invoked every second. Its main goal is to cycle through
* the routing table and send partial updates to all neighbors at a
* rate that will cause the entire table to be sent in ROUTE_REPORT_INTERVAL
* seconds. Also, every TIMER_INTERVAL seconds it calls timer() to
* do all the other time-based processing.
*/
static void
fasttimer(int i)
{
static unsigned int tlast;
static unsigned int nsent;
unsigned int t = tlast + 1;
int n;
/*
* if we're in the last second, send everything that's left.
* otherwise send at least the fraction we should have sent by now.
*/
if (t >= ROUTE_REPORT_INTERVAL) {
int nleft = nroutes - nsent;
while (nleft > 0) {
if ((n = report_next_chunk()) <= 0)
break;
nleft -= n;
}
tlast = 0;
nsent = 0;
} else {
unsigned int ncum = nroutes * t / ROUTE_REPORT_INTERVAL;
while (nsent < ncum) {
if ((n = report_next_chunk()) <= 0)
break;
nsent += n;
}
tlast = t;
}
if ((t % TIMER_INTERVAL) == 0)
timer();
age_callout_queue();/* Advance the timer for the callout queue
for groups */
alarm(1);
}
/*
* 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.
*/
static u_long virtual_time = 0;
/*
* Timer routine. Performs periodic neighbor probing, route reporting, and
* group querying duties, and drives various timers in routing entries and
* virtual interface data structures.
*/
static void
timer(void)
{
age_routes(); /* Advance the timers in the route entries */
age_vifs(); /* Advance the timers for neighbors */
age_table_entry(); /* Advance the timers for the cache entries */
if (virtual_time % GROUP_QUERY_INTERVAL == 0) {
/*
* Time to query the local group memberships on all subnets
* for which this router is the elected querier.
*/
query_groups();
}
if (virtual_time % NEIGHBOR_PROBE_INTERVAL == 0) {
/*
* Time to send a probe on all vifs from which no neighbors have
* been heard. Also, check if any inoperative interfaces have now
* come up. (If they have, they will also be probed as part of
* their initialization.)
*/
probe_for_neighbors();
if (vifs_down)
check_vif_state();
}
delay_change_reports = FALSE;
if (routes_changed) {
/*
* Some routes have changed since the last timer interrupt, but
* have not been reported yet. Report the changed routes to all
* neighbors.
*/
report_to_all_neighbors(CHANGED_ROUTES);
}
#ifdef SNMP
sync_timer();
#endif
/*
* Advance virtual time
*/
virtual_time += TIMER_INTERVAL;
}
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);
}
/*
* 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;
static char fmt[211] = "warning - ";
char *msg;
char tbuf[20];
struct timeval now;
struct tm *thyme;
time_t t;