aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Wemm <peter@FreeBSD.org>1996-01-06 21:00:43 +0000
committerPeter Wemm <peter@FreeBSD.org>1996-01-06 21:00:43 +0000
commit29a6d69cc3ace06013586242876d971734f09820 (patch)
tree15ba303fa7e144622226413c26079a978d1e6ae2
parented30da51aa6c648930983a5e2dc31760eda8e16a (diff)
downloadsrc-29a6d69cc3ace06013586242876d971734f09820.tar.gz
src-29a6d69cc3ace06013586242876d971734f09820.zip
This is a 'for reference' import of mrouted release 3.6. It's purevendor/mrouted/3.6
conflict markers, but it actually changes nothing. We've been running this code with small changes for some time, this may be useful for checking what those changes. It was unfortunate this module got so far away from the vendor branch (whitespace changes didn't help)
Notes
Notes: svn path=/cvs2svn/branches/XEROX/; revision=13278 svn path=/cvs2svn/tags/release_3_6/; revision=13279; tag=vendor/mrouted/3.6
-rw-r--r--usr.sbin/mrouted/callout.c59
-rw-r--r--usr.sbin/mrouted/cfparse.y81
-rw-r--r--usr.sbin/mrouted/config.c673
-rw-r--r--usr.sbin/mrouted/defs.h294
-rw-r--r--usr.sbin/mrouted/dvmrp.h17
-rw-r--r--usr.sbin/mrouted/igmp.c126
-rw-r--r--usr.sbin/mrouted/inet.c84
-rw-r--r--usr.sbin/mrouted/kern.c90
-rw-r--r--usr.sbin/mrouted/main.c319
-rw-r--r--usr.sbin/mrouted/map-mbone.8156
-rw-r--r--usr.sbin/mrouted/mapper.c168
-rw-r--r--usr.sbin/mrouted/mrinfo.8153
-rw-r--r--usr.sbin/mrouted/mrinfo.c282
-rw-r--r--usr.sbin/mrouted/mrouted.8154
-rw-r--r--usr.sbin/mrouted/mrouted.conf33
-rw-r--r--usr.sbin/mrouted/mtrace.83
-rw-r--r--usr.sbin/mrouted/mtrace.c1620
-rw-r--r--usr.sbin/mrouted/pathnames.h2
-rw-r--r--usr.sbin/mrouted/prune.c2687
-rw-r--r--usr.sbin/mrouted/prune.h158
-rw-r--r--usr.sbin/mrouted/route.c384
-rw-r--r--usr.sbin/mrouted/route.h25
-rw-r--r--usr.sbin/mrouted/rsrr.c88
-rw-r--r--usr.sbin/mrouted/rsrr.h4
-rw-r--r--usr.sbin/mrouted/vif.c681
-rw-r--r--usr.sbin/mrouted/vif.h44
26 files changed, 5400 insertions, 2985 deletions
diff --git a/usr.sbin/mrouted/callout.c b/usr.sbin/mrouted/callout.c
index 0538a3f5acd2..29e44eccfbdc 100644
--- a/usr.sbin/mrouted/callout.c
+++ b/usr.sbin/mrouted/callout.c
@@ -7,7 +7,7 @@
* Leland Stanford Junior University.
*
*
- * $Id: callout.c,v 1.1 1994/08/24 23:52:49 thyagara Exp $
+ * $Id: callout.c,v 3.6 1995/06/25 18:47:29 fenner Exp $
*/
#include "defs.h"
@@ -18,17 +18,21 @@ static struct timeout_q *Q = 0; /* pointer to the beginning of timeout queue */
static int in_callout= 0;
-typedef void (* cfunc_t)();
-
struct timeout_q {
struct timeout_q *next; /* next event */
int id;
- cfunc_t func ; /* function to call */
+ cfunc_t func; /* function to call */
char *data; /* func's data */
int time; /* time offset to next event*/
};
+#ifdef IGMP_DEBUG
+static void print_Q __P((void));
+#else
+#define print_Q()
+#endif
+void
callout_init()
{
Q = (struct timeout_q *) 0;
@@ -38,6 +42,7 @@ callout_init()
/*
* signal handler for SIGALARM that is called once every second
*/
+void
age_callout_queue()
{
struct timeout_q *ptr;
@@ -51,7 +56,7 @@ age_callout_queue()
while (ptr){
if (!ptr->time ) {
/* timeout has happened */
- if(ptr->func)
+ if (ptr->func)
ptr->func(ptr->data);
Q = Q->next;
@@ -62,7 +67,7 @@ age_callout_queue()
ptr->time --;
#ifdef IGMP_DEBUG
log(LOG_DEBUG,0,"[callout, age_callout_queue] -- time (%d)", ptr->time);
-#endif IGMP_DEBUG
+#endif /* IGMP_DEBUG */
in_callout = 0; return;
}
}
@@ -74,7 +79,8 @@ age_callout_queue()
/*
* sets the timer
*/
-int timer_setTimer(delay, action, data)
+int
+timer_setTimer(delay, action, data)
int delay; /* number of units for timeout */
cfunc_t action; /* function to be called on timeout */
char *data; /* what to call the timeout function with */
@@ -82,13 +88,13 @@ int timer_setTimer(delay, action, data)
struct timeout_q *ptr, *node, *prev;
if (in_callout)
- return;
+ return -1;
in_callout = 1;
/* create a node */
- node = (struct timeout_q *)malloc(sizeof(struct timeout_q));
- if ((int) node <= 0) {
+ node = (struct timeout_q *)malloc(sizeof(struct timeout_q));
+ if (node == 0) {
log(LOG_WARNING, 0, "Malloc Failed in timer_settimer\n");
in_callout = 0;
return -1;
@@ -108,9 +114,9 @@ int timer_setTimer(delay, action, data)
Q = node;
else {
/* chase the pointer looking for the right place */
- while (ptr){
+ while (ptr) {
- if (delay < ptr->time){
+ if (delay < ptr->time) {
/* right place */
node->next = ptr;
@@ -122,8 +128,7 @@ int timer_setTimer(delay, action, data)
print_Q();
in_callout = 0;
return node->id;
- }
- else {
+ } else {
/* keep moving */
delay -= ptr->time; node->time = delay;
@@ -140,17 +145,19 @@ int timer_setTimer(delay, action, data)
/* clears the associated timer */
-void timer_clearTimer( id)
- int id;
+void
+timer_clearTimer(timer_id)
+ int timer_id;
{
struct timeout_q *ptr, *prev;
- if (in_callout) return;
+ if (in_callout)
+ return;
+ if (!timer_id)
+ return;
+
in_callout = 1;
-
- if ( !id ) {in_callout = 0; return;}
-
prev = ptr = Q;
/*
@@ -159,12 +166,12 @@ void timer_clearTimer( id)
*/
print_Q();
- while (ptr){
- if (ptr->id == id){
+ while (ptr) {
+ if (ptr->id == timer_id) {
/* got the right node */
/* unlink it from the queue */
- if ( ptr == Q)
+ if (ptr == Q)
Q = Q->next;
else
prev->next = ptr->next;
@@ -186,16 +193,16 @@ void timer_clearTimer( id)
in_callout = 0;
}
+#ifdef IGMP_DEBUG
/*
* debugging utility
*/
+static void
print_Q()
{
struct timeout_q *ptr;
-#ifdef IGMP_DEBUG
for(ptr = Q; ptr; ptr = ptr->next)
log(LOG_DEBUG,0,"(%d,%d) ", ptr->id, ptr->time);
-#endif IGMP_DEBUG
}
-
+#endif /* IGMP_DEBUG */
diff --git a/usr.sbin/mrouted/cfparse.y b/usr.sbin/mrouted/cfparse.y
index 5c1402f41bdc..c08938d4a47a 100644
--- a/usr.sbin/mrouted/cfparse.y
+++ b/usr.sbin/mrouted/cfparse.y
@@ -4,12 +4,28 @@
*
* Written by Bill Fenner, NRL, 1994
*
- * $Id: cfparse.y,v 3.5 1995/05/09 01:00:39 fenner Exp $
+ * $Id: cfparse.y,v 3.6 1995/06/25 18:49:46 fenner Exp $
*/
#include <stdio.h>
+#ifdef __STDC__
+#include <stdarg.h>
+#else
#include <varargs.h>
+#endif
#include "defs.h"
+/*
+ * Local function declarations
+ */
+static void fatal __P((char *fmt, ...));
+static void warn __P((char *fmt, ...));
+static void yyerror __P((char *s));
+static char * next_word __P((void));
+static int yylex __P((void));
+static u_int32 valid_if __P((char *s));
+static struct ifreq * ifconfaddr __P((struct ifconf *ifcp, u_int32 a));
+int yyparse __P((void));
+
static FILE *f;
extern int udp_socket;
@@ -195,7 +211,17 @@ ifmods : /* empty */
ifmod : mod
| DISABLE { v->uv_flags |= VIFF_DISABLED; }
- | NETMASK ADDR { v->uv_subnetmask = $2; }
+ | NETMASK ADDR {
+ u_int32 subnet, mask;
+
+ mask = $2;
+ subnet = v->uv_lcl_addr & mask;
+ if (!inet_valid_subnet(subnet, mask))
+ fatal("Invalid netmask");
+ v->uv_subnet = subnet;
+ v->uv_subnetmask = mask;
+ v->uv_subnetbcast = subnet | ~mask;
+ }
| ALTNET addrmask {
struct phaddr *ph;
@@ -204,12 +230,13 @@ ifmod : mod
if (ph == NULL)
fatal("out of memory");
if ($2.mask) {
- VAL_TO_MASK(ph->pa_mask, $2.mask);
+ VAL_TO_MASK(ph->pa_subnetmask, $2.mask);
} else
- ph->pa_mask = v->uv_subnetmask;
- ph->pa_addr = $2.addr & ph->pa_mask;
- if ($2.addr & ~ph->pa_mask)
- warn("Extra addr %s/%d has host bits set",
+ ph->pa_subnetmask = v->uv_subnetmask;
+ ph->pa_subnet = $2.addr & ph->pa_subnetmask;
+ ph->pa_subnetbcast = ph->pa_subnet | ~ph->pa_subnetmask;
+ if ($2.addr & ~ph->pa_subnetmask)
+ warn("Extra subnet %s/%d has host bits set",
inet_fmt($2.addr,s1), $2.mask);
ph->pa_next = v->uv_addrs;
v->uv_addrs = ph;
@@ -305,8 +332,18 @@ addrmask : ADDRMASK { $$ = $1; }
| ADDR { $$.addr = $1; $$.mask = 0; }
;
%%
+#ifdef __STDC__
+static void
+fatal(char *fmt, ...)
+{
+ va_list ap;
+ char buf[200];
+
+ va_start(ap, fmt);
+#else
/*VARARGS1*/
-static void fatal(fmt, va_alist)
+static void
+fatal(fmt, va_alist)
char *fmt;
va_dcl
{
@@ -314,14 +351,25 @@ va_dcl
char buf[200];
va_start(ap);
+#endif
vsprintf(buf, fmt, ap);
va_end(ap);
log(LOG_ERR,0,"%s: %s near line %d", configfilename, buf, lineno);
}
+#ifdef __STDC__
+static void
+warn(char *fmt, ...)
+{
+ va_list ap;
+ char buf[200];
+
+ va_start(ap, fmt);
+#else
/*VARARGS1*/
-static void warn(fmt, va_alist)
+static void
+warn(fmt, va_alist)
char *fmt;
va_dcl
{
@@ -329,19 +377,22 @@ va_dcl
char buf[200];
va_start(ap);
+#endif
vsprintf(buf, fmt, ap);
va_end(ap);
log(LOG_WARNING,0,"%s: %s near line %d", configfilename, buf, lineno);
}
-void yyerror(s)
+static void
+yyerror(s)
char *s;
{
log(LOG_ERR, 0, "%s: %s near line %d", configfilename, s, lineno);
}
-char *next_word()
+static char *
+next_word()
{
static char buf[1024];
static char *p=NULL;
@@ -375,7 +426,8 @@ char *next_word()
}
}
-int yylex()
+static int
+yylex()
{
int n;
u_int32 addr;
@@ -446,7 +498,8 @@ int yylex()
return STRING;
}
-void config_vifs_from_file()
+void
+config_vifs_from_file()
{
extern FILE *f;
@@ -467,7 +520,7 @@ void config_vifs_from_file()
yyparse();
- close(f);
+ fclose(f);
}
static u_int32
diff --git a/usr.sbin/mrouted/config.c b/usr.sbin/mrouted/config.c
index c7aa7b003bdf..56fdccb991e2 100644
--- a/usr.sbin/mrouted/config.c
+++ b/usr.sbin/mrouted/config.c
@@ -7,37 +7,27 @@
* Leland Stanford Junior University.
*
*
- * $Id: config.c,v 1.6 1994/08/24 23:52:54 thyagara Exp $
+ * $Id: config.c,v 3.6 1995/06/25 18:50:37 fenner Exp $
*/
#include "defs.h"
-char *configfilename = "/etc/mrouted.conf";
-
-extern int cache_lifetime;
-extern int max_prune_lifetime;
-
-/*
- * Forward declarations.
- */
-static char *next_word();
-
-
/*
* Query the kernel to find network interfaces that are multicast-capable
* and install them in the uvifs array.
*/
-void config_vifs_from_kernel()
+void
+config_vifs_from_kernel()
{
struct ifreq ifbuf[32];
- struct ifreq *ifrp, *ifend, *mp;
+ struct ifreq *ifrp, *ifend;
struct ifconf ifc;
register struct uvif *v;
register vifi_t vifi;
- int i, n;
- u_long addr, mask, subnet;
+ int n;
+ u_int32 addr, mask, subnet;
short flags;
ifc.ifc_buf = (char *)ifbuf;
@@ -62,10 +52,11 @@ void config_vifs_from_kernel()
/*
* Ignore any interface for an address family other than IP.
*/
- addr = ((struct sockaddr_in *)&ifrp->ifr_addr)->sin_addr.s_addr;
if (ifrp->ifr_addr.sa_family != AF_INET)
continue;
+ addr = ((struct sockaddr_in *)&ifrp->ifr_addr)->sin_addr.s_addr;
+
/*
* Need a template to preserve address info that is
* used below to locate the next entry. (Otherwise,
@@ -96,8 +87,8 @@ void config_vifs_from_kernel()
addr == subnet ||
addr == (subnet | ~mask)) {
log(LOG_WARNING, 0,
- "ignoring %s, has invalid address (%s) and/or mask (%08x)",
- ifr.ifr_name, inet_fmt(addr, s1), ntohl(mask));
+ "ignoring %s, has invalid address (%s) and/or mask (%s)",
+ ifr.ifr_name, inet_fmt(addr, s1), inet_fmt(mask, s2));
continue;
}
@@ -125,7 +116,7 @@ void config_vifs_from_kernel()
v = &uvifs[numvifs];
v->uv_flags = 0;
v->uv_metric = DEFAULT_METRIC;
- v->uv_rate_limit = DEFAULT_RATE_LIMIT;
+ v->uv_rate_limit = DEFAULT_PHY_RATE_LIMIT;
v->uv_threshold = DEFAULT_THRESHOLD;
v->uv_lcl_addr = addr;
v->uv_rmt_addr = 0;
@@ -136,6 +127,7 @@ void config_vifs_from_kernel()
v->uv_groups = NULL;
v->uv_neighbors = NULL;
v->uv_acl = NULL;
+ v->uv_addrs = NULL;
log(LOG_INFO,0,"installing %s (%s on subnet %s) as vif #%u - rate=%d",
v->uv_name, inet_fmt(addr, s1), inet_fmts(subnet, mask, s2),
@@ -153,644 +145,3 @@ void config_vifs_from_kernel()
}
}
}
-
-static struct ifreq *
-ifconfaddr(ifcp, a)
- struct ifconf *ifcp;
- u_long a;
-{
- int n;
- struct ifreq *ifrp = (struct ifreq *)ifcp->ifc_buf;
- struct ifreq *ifend = (struct ifreq *)((char *)ifrp + ifcp->ifc_len);
-
- while (ifrp < ifend) {
- if (ifrp->ifr_addr.sa_family == AF_INET &&
- ((struct sockaddr_in *)&ifrp->ifr_addr)->sin_addr.s_addr == a)
- return (ifrp);
-#if BSD >= 199006
- n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name);
- if (n < sizeof(*ifrp))
- ++ifrp;
- else
- ifrp = (struct ifreq *)((char *)ifrp + n);
-#else
- ++ifrp;
-#endif
- }
- return (0);
-}
-
-/*
- * Checks if the string constitutes a valid interface name
- */
-static u_long valid_if(w)
-char *w;
-{
- register vifi_t vifi;
- register struct uvif *v;
-
- for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++)
- if (EQUAL(v->uv_name, w))
- return v->uv_lcl_addr;
-
- return NULL;
-}
-
-/*
- * Read the config file to learn about tunnel vifs and
- * non-default phyint parameters.
- */
-void config_vifs_from_file()
-{
- FILE *f;
- char linebuf[100];
- char *w, *s, c;
- u_long lcl_addr, rmt_addr;
- struct ifconf ifc;
- struct ifreq *ifr;
- struct ifreq ffr;
- int i;
- u_int n;
- struct ifreq ifbuf[32];
- vifi_t vifi;
- struct uvif *v;
- u_char order = 0;
- vifi_t prev_vif = NO_VIF;
-
- f = fopen(configfilename, "r");
- if (f == NULL) {
- if (errno != ENOENT)
- log(LOG_ERR, errno, "can't open %s", configfilename);
- return;
- }
-
- ifc.ifc_buf = (char *)ifbuf;
- ifc.ifc_len = sizeof(ifbuf);
- if (ioctl(udp_socket, SIOCGIFCONF, (char *)&ifc) < 0)
- log(LOG_ERR, errno, "ioctl SIOCGIFCONF");
-
- while (fgets(linebuf, sizeof(linebuf), f) != NULL) {
-
- s = linebuf;
- if (EQUAL((w = next_word(&s)), "")) {
- /*
- * blank or comment line; ignore
- */
- }
-
- /* Set the cache_lifetime for kernel entries */
- else if (EQUAL(w, "cache_lifetime")) {
- if (EQUAL((w = next_word(&s)), "")) {
- log(LOG_ERR, 0,
- "missing cache_lifetime value in %s",
- configfilename);
- continue;
- }
- if(sscanf(w, "%u%c", &n, &c) != 1 ||
- n < 300 || n > 86400 ) {
- log(LOG_ERR, 0,
- "invalid cache_lifetime '%s' (300<n>86400) in %s",
- w, configfilename);
- break;
- }
- prev_vif = NO_VIF;
- cache_lifetime = n;
- max_prune_lifetime = cache_lifetime * 2;
- }
-
- /* Check if pruning is to be turned off */
- else if (EQUAL(w, "pruning")) {
- if (!EQUAL((w = next_word(&s)), "off") &&
- !EQUAL(w, "on")) {
- log(LOG_ERR, 0,
- "invalid word '%s' in %s",
- w, configfilename);
- continue;
- }
- if (EQUAL(w, "off"))
- pruning = 0;
-
- prev_vif = NO_VIF;
- }
-
- /* Check for boundary statements (as continuation of a prev. line) */
- else if (EQUAL(w, "boundary") && prev_vif != NO_VIF) {
- register struct vif_acl *v_acl;
- register u_long baddr;
-
- v = &uvifs[prev_vif];
-
- if (EQUAL((w = next_word(&s)), "")) {
- log(LOG_ERR, 0,
- "missing group address for boundary %s in %s",
- inet_fmt(lcl_addr, s1), configfilename);
- w = "garbage";
- break;
- }
-
- if ((sscanf(w, "%[0-9.]/%d", s1, &n) != 2) ||
- n < 0 || n> 32) {
- log(LOG_ERR, 0,
- "incorrect boundary format %s in %s",
- w, configfilename);
- w = "garbage";
- break;
- }
-
- if ((baddr = inet_parse(s1)) == 0xffffffff ||
- (baddr & 0xff000000) != 0xef000000) {
- log(LOG_ERR, 0,
- "incorrect boundary address %s in %s",
- s1, configfilename);
- continue;
- }
-
- v_acl = (struct vif_acl *)malloc(sizeof(struct vif_acl));
- if (v_acl == NULL)
- log(LOG_ERR, 0,
- "out of memory");
- VAL_TO_MASK(v_acl->acl_mask, n);
- v_acl->acl_addr = baddr & v_acl->acl_mask;
-
- /*
- * link into data structure
- */
- v_acl->acl_next = v->uv_acl;
- v->uv_acl = v_acl;
- }
-
- else if (EQUAL(w, "phyint")) {
- /*
- * phyint <local-addr> [disable] [metric <m>] [threshold <t>]
- * [rate_limit <b>]
- */
-
- /*
- * Check if phyint was the first line - scream if not
- */
- if (order) {
- log(LOG_ERR, 0,
- "phyint stmnts should occur before tunnel stmnts in %s",
- configfilename);
- continue;
- }
-
- /*
- * Parse the local address.
- */
- if (EQUAL((w = next_word(&s)), "")) {
- log(LOG_ERR, 0,
- "missing phyint address in %s",
- configfilename);
- continue;
- }
-
- if (isalpha(*w) && !(lcl_addr = valid_if(w))) {
- log(LOG_ERR, 0,
- "invalid phyint name '%s' in %s",
- w, configfilename);
- continue;
- }
-
- if (isdigit(*w)) {
- if ((lcl_addr = inet_parse(w)) == 0xffffffff ||
- !inet_valid_host(lcl_addr)) {
- log(LOG_ERR, 0,
- "invalid phyint address '%s' in %s",
- w, configfilename);
- continue;
- }
- }
-
- /*
- * Look up the vif with the specified local address.
- */
- for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
- if (!(v->uv_flags & VIFF_TUNNEL) &&
- lcl_addr == v->uv_lcl_addr) {
- break;
- }
- }
-
- if (vifi == numvifs) {
- log(LOG_ERR, 0,
- "phyint %s in %s is not a configured interface",
- inet_fmt(lcl_addr, s1), configfilename);
- continue;
- }
-
- /*
- * Look for "disable", "metric", "threshold", "rate_limit"
- * and "boundary" options.
- */
- prev_vif = vifi;
-
- while (!EQUAL((w = next_word(&s)), "")) {
- if (EQUAL(w, "disable")) {
- v->uv_flags |= VIFF_DISABLED;
- }
- else if (EQUAL(w, "metric")) {
- if(EQUAL((w = next_word(&s)), "")) {
- log(LOG_ERR, 0,
- "missing metric for phyint %s in %s",
- inet_fmt(lcl_addr, s1), configfilename);
- w = "garbage";
- break;
- }
- if(sscanf(w, "%u%c", &n, &c) != 1 ||
- n < 1 || n >= UNREACHABLE ) {
- log(LOG_ERR, 0,
- "invalid metric '%s' for phyint %s in %s",
- w, inet_fmt(lcl_addr, s1), configfilename);
- break;
- }
- v->uv_metric = n;
- }
- else if (EQUAL(w, "threshold")) {
- if(EQUAL((w = next_word(&s)), "")) {
- log(LOG_ERR, 0,
- "missing threshold for phyint %s in %s",
- inet_fmt(lcl_addr, s1), configfilename);
- w = "garbage";
- break;
- }
- if(sscanf(w, "%u%c", &n, &c) != 1 ||
- n < 1 || n > 255 ) {
- log(LOG_ERR, 0,
- "invalid threshold '%s' for phyint %s in %s",
- w, inet_fmt(lcl_addr, s1), configfilename);
- break;
- }
- v->uv_threshold = n;
- }
- else if (EQUAL(w, "rate_limit")) {
- if (EQUAL((w = next_word(&s)), "")) {
- log(LOG_ERR, 0,
- "missing rate_limit for phyint %s in %s",
- inet_fmt(rmt_addr, s1), configfilename);
- w = "garbage";
- break;
- }
- if(sscanf(w, "%u%c", &n, &c) != 1 ||
- n < 0 || n > MAX_RATE_LIMIT ) {
- log(LOG_ERR, 0,
- "invalid rate limit '%s' for phyint %s in %s",
- w, inet_fmt(lcl_addr, s1), configfilename);
- break;
- }
- v->uv_rate_limit = n;
- }
- else if (EQUAL(w, "boundary")) {
- register struct vif_acl *v_acl;
- register u_long baddr;
-
- if (EQUAL((w = next_word(&s)), "")) {
- log(LOG_ERR, 0,
- "missing group address for boundary %s in %s",
- inet_fmt(lcl_addr, s1), configfilename);
- w = "garbage";
- break;
- }
-
- if ((sscanf(w, "%[0-9.]/%d", s1, &n) != 2) ||
- n < 0 || n> 32) {
- log(LOG_ERR, 0,
- "incorrect boundary format %s in %s",
- w, configfilename);
- w = "garbage";
- break;
- }
-
- if ((baddr = inet_parse(s1)) == 0xffffffff ||
- (baddr & 0xef000000) != 0xef000000) {
- log(LOG_ERR, 0,
- "incorrect boundary address %s in %s",
- s1, configfilename);
- continue;
- }
-
- v_acl = (struct vif_acl *)malloc(sizeof(struct vif_acl));
- if (v_acl == NULL)
- log(LOG_ERR, 0,
- "out of memory");
- VAL_TO_MASK(v_acl->acl_mask, n);
- v_acl->acl_addr = baddr & v_acl->acl_mask;
-
- /*
- * link into data structure
- */
- v_acl->acl_next = v->uv_acl;
- v->uv_acl = v_acl;
- }
- else {
- log(LOG_ERR, 0,
- "invalid keyword (%s) in %s",
- w, configfilename);
- break;
- }
- }
- if (!EQUAL(w, "")) continue;
- }
-
- else if (EQUAL(w, "tunnel")) {
- /*
- * tunnel <local-addr> <remote-addr> [srcrt] [metric <m>]
- * [threshold <t>] [rate_limit <b>]
- */
-
- order++;
-
- /*
- * Parse the local address.
- */
- if (EQUAL((w = next_word(&s)), "")) {
- log(LOG_ERR, 0,
- "missing tunnel local address in %s",
- configfilename);
- continue;
- }
- if ((lcl_addr = inet_parse(w)) == 0xffffffff ||
- !inet_valid_host(lcl_addr)) {
- log(LOG_ERR, 0,
- "invalid tunnel local address '%s' in %s",
- w, configfilename);
- continue;
- }
-
- /*
- * Make sure the local address is one of ours.
- */
- ifr = ifconfaddr(&ifc, lcl_addr);
- if (ifr == 0) {
- log(LOG_ERR, 0,
- "tunnel local address %s in %s is not one of ours",
- inet_fmt(lcl_addr, s1), configfilename);
- continue;
- }
-
- /*
- * Make sure the local address doesn't name a loopback interface..
- */
- strncpy(ffr.ifr_name, ifr->ifr_name, IFNAMSIZ);
- if (ioctl(udp_socket, SIOCGIFFLAGS, (char *)&ffr) < 0) {
- log(LOG_ERR, errno,
- "ioctl SIOCGIFFLAGS for %s", ffr.ifr_name);
- }
- if (ffr.ifr_flags & IFF_LOOPBACK) {
- log(LOG_ERR, 0,
- "tunnel local address %s in %s is a loopback interface",
- inet_fmt(lcl_addr, s1), configfilename);
- continue;
- }
-
- /*
- * Parse the remote address.
- */
- if (EQUAL((w = next_word(&s)), "")) {
- log(LOG_ERR, 0,
- "missing tunnel remote address in %s",
- configfilename);
- continue;
- }
- if ((rmt_addr = inet_parse(w)) == 0xffffffff ||
- !inet_valid_host(rmt_addr)) {
- log(LOG_ERR, 0,
- "invalid tunnel remote address %s in %s",
- w, configfilename);
- continue;
- }
-
- /*
- * Make sure the remote address is not one of ours.
- */
- if (ifconfaddr(&ifc, rmt_addr) != 0) {
- log(LOG_ERR, 0,
- "tunnel remote address %s in %s is one of ours",
- inet_fmt(rmt_addr, s1), configfilename);
- continue;
- }
-
- /*
- * Make sure the remote address has not been used for another
- * tunnel and does not belong to a subnet to which we have direct
- * access on an enabled phyint.
- */
- for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
- if (v->uv_flags & VIFF_TUNNEL) {
- if (rmt_addr == v->uv_rmt_addr) {
- log(LOG_ERR, 0,
- "duplicate tunnel remote address %s in %s",
- inet_fmt(rmt_addr, s1), configfilename);
- break;
- }
- }
- else if (!(v->uv_flags & VIFF_DISABLED)) {
- if ((rmt_addr & v->uv_subnetmask) == v->uv_subnet) {
- log(LOG_ERR, 0,
- "unnecessary tunnel remote address %s in %s",
- inet_fmt(rmt_addr, s1), configfilename);
- break;
- }
- }
- }
- if (vifi != numvifs) continue;
-
- /*
- * OK, let's initialize a uvif structure for the tunnel.
- */
- if (numvifs == MAXVIFS) {
- log(LOG_ERR, 0, "too many vifs, ignoring tunnel to %s",
- inet_fmt(rmt_addr, s1));
- continue;
- }
- v = &uvifs[numvifs];
- v->uv_flags = VIFF_TUNNEL;
- v->uv_metric = DEFAULT_METRIC;
- v->uv_rate_limit = DEFAULT_RATE_LIMIT;
- v->uv_threshold = DEFAULT_THRESHOLD;
- v->uv_lcl_addr = lcl_addr;
- v->uv_rmt_addr = rmt_addr;
- v->uv_subnet = 0;
- v->uv_subnetmask = 0;
- v->uv_subnetbcast = 0;
- strncpy(v->uv_name, ffr.ifr_name, IFNAMSIZ);
- v->uv_groups = NULL;
- v->uv_neighbors = NULL;
- v->uv_acl = NULL;
-
- /*
- * set variable to define which interface
- */
- prev_vif = numvifs;
-
- /*
- * Look for "metric", "threshold", "srcrt", "rate_limit"
- * and "boundary" options.
- */
- while (!EQUAL((w = next_word(&s)), "")) {
- if (EQUAL(w, "metric")) {
- if(EQUAL((w = next_word(&s)), "")) {
- log(LOG_ERR, 0,
- "missing metric for tunnel to %s in %s",
- inet_fmt(rmt_addr, s1), configfilename);
- w = "garbage";
- break;
- }
- if(sscanf(w, "%u%c", &n, &c) != 1 ||
- n < 1 || n >= UNREACHABLE ) {
- log(LOG_ERR, 0,
- "invalid metric '%s' for tunnel to %s in %s",
- w, inet_fmt(rmt_addr, s1), configfilename);
- break;
- }
- v->uv_metric = n;
- }
- else if (EQUAL(w, "threshold")) {
- if(EQUAL((w = next_word(&s)), "")) {
- log(LOG_ERR, 0,
- "missing threshold for tunnel to %s in %s",
- inet_fmt(rmt_addr, s1), configfilename);
- w = "garbage";
- break;
- }
- if(sscanf(w, "%u%c", &n, &c) != 1 ||
- n < 1 || n > 255 ) {
- log(LOG_ERR, 0,
- "invalid threshold '%s' for tunnel to %s in %s",
- w, inet_fmt(rmt_addr, s1), configfilename);
- break;
- }
- v->uv_threshold = n;
- }
- else if (EQUAL(w, "srcrt") || EQUAL(w, "sourceroute")) {
- v->uv_flags |= VIFF_SRCRT;
- }
- else if (EQUAL(w, "rate_limit")) {
- if (EQUAL((w = next_word(&s)), "")) {
- log(LOG_ERR, 0,
- "missing rate_limit for tunnel to %s in %s",
- inet_fmt(rmt_addr, s1), configfilename);
- w = "garbage";
- break;
- }
- if(sscanf(w, "%u%c", &n, &c) != 1 ||
- n < 0 || n > MAX_RATE_LIMIT ) {
- log(LOG_ERR, 0,
- "invalid rate_limit '%s' for tunnel to %s in %s",
- w, inet_fmt(rmt_addr, s1), configfilename);
- break;
- }
- v->uv_rate_limit = n;
- }
- else if (EQUAL(w, "boundary")) {
- register struct vif_acl *v_acl;
- register u_long baddr;
-
- if (EQUAL((w = next_word(&s)), "")) {
- log(LOG_ERR, 0,
- "missing group address for tunnel to %s in %s",
- inet_fmt(rmt_addr, s1), configfilename);
- w = "garbage";
- break;
- }
-
- if ((sscanf(w, "%[0-9.]/%d", s1, &n) != 2) ||
- n < 0 || n> 32) {
- log(LOG_ERR, 0,
- "incorrect format '%s' for tunnel to %s in %s",
- w, inet_fmt(rmt_addr, s1), configfilename);
- break;
- }
-
- if ((baddr = inet_parse(s1)) == 0xffffffff ||
- (baddr & 0xef000000) != 0xef000000) {
- log(LOG_ERR, 0,
- "incorrect address %s for tunnel to %s in %s",
- s1, inet_fmt(rmt_addr, s1), configfilename);
- continue;
- }
-
- v_acl = (struct vif_acl *)malloc(sizeof(struct vif_acl));
- if (v_acl == NULL)
- log(LOG_ERR, 0,
- "out of memory");
- VAL_TO_MASK(v_acl->acl_mask, n);
- v_acl->acl_addr = baddr & v_acl->acl_mask;
-
- /*
- * link into data structure
- */
- v_acl->acl_next = v->uv_acl;
- v->uv_acl = v_acl;
- }
- else {
- log(LOG_ERR, 0,
- "invalid keyword (%s) in %s",
- w, configfilename);
- break;
- }
- }
- if (!EQUAL(w, "")) continue;
-
- log(LOG_INFO, 0,
- "installing %stunnel from %s to %s as vif #%u - rate=%d",
- v->uv_flags & VIFF_SRCRT? "srcrt " : "",
- inet_fmt(lcl_addr, s1), inet_fmt(rmt_addr, s2),
- numvifs, v->uv_rate_limit);
-
- ++numvifs;
-
- if (!(ffr.ifr_flags & IFF_UP)) {
- v->uv_flags |= VIFF_DOWN;
- vifs_down = TRUE;
- }
- }
-
- else {
- log(LOG_ERR, 0,
- "unknown command '%s' in %s", w, configfilename);
- }
- }
-
- close(f);
-}
-
-
-/*
- * Return a pointer to the next "word" in the string to which '*s' points,
- * lower-cased and null terminated, and advance '*s' to point beyond the word.
- * Words are separated by blanks and/or tabs, and the input string is
- * considered to terminate at a newline, '#' (comment), or null character.
- * If no words remain, a pointer to a null string ("") is returned.
- * Warning: This function clobbers the input string.
- */
-static char *next_word(s)
- char **s;
-{
- char *w;
-
- w = *s;
- while (*w == ' ' || *w == '\t')
- ++w;
-
- *s = w;
- for(;;) {
- switch (**s) {
-
- case ' ' :
- case '\t' : **s = '\0';
- ++*s;
- return (w);
-
- case '\n' :
- case '#' : **s = '\0';
- return (w);
-
- case '\0' : return (w);
-
- default : if (isascii(**s) && isupper(**s))
- **s = tolower(**s);
- ++*s;
- }
- }
-}
diff --git a/usr.sbin/mrouted/defs.h b/usr.sbin/mrouted/defs.h
index 8239f7ca961e..5829314ce500 100644
--- a/usr.sbin/mrouted/defs.h
+++ b/usr.sbin/mrouted/defs.h
@@ -7,15 +7,18 @@
* Leland Stanford Junior University.
*
*
- * $Id: defs.h,v 1.8 1994/08/24 23:53:23 thyagara Exp $
+ * $Id: defs.h,v 3.6.1.1 1995/06/26 00:18:18 fenner Exp $
*/
#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
#include <ctype.h>
#include <errno.h>
#include <syslog.h>
#include <signal.h>
+#include <string.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/socket.h>
@@ -27,11 +30,33 @@
#include <netinet/ip.h>
#include <netinet/igmp.h>
#include <netinet/ip_mroute.h>
+#ifdef RSRR
+#include <sys/un.h>
+#endif /* RSRR */
+
+/*XXX*/
+typedef u_int u_int32;
+
+#ifndef __P
+#ifdef __STDC__
+#define __P(x) x
+#else
+#define __P(x) ()
+#endif
+#endif
+
+typedef void (*cfunc_t) __P((void *));
+typedef void (*ihfunc_t) __P((fd_set *));
#include "dvmrp.h"
#include "vif.h"
#include "route.h"
#include "prune.h"
+#include "pathnames.h"
+#ifdef RSRR
+#include "rsrr.h"
+#include "rsrr_var.h"
+#endif /* RSRR */
/*
* Miscellaneous constants and macros.
@@ -45,25 +70,48 @@
#define PROTOCOL_VERSION 3 /* increment when packet format/content changes */
-#define MROUTED_VERSION 3 /* increment on local changes or bug fixes, */
+#define MROUTED_VERSION 6 /* increment on local changes or bug fixes, */
/* reset to 0 whever PROTOCOL_VERSION increments */
-#define MROUTED_LEVEL ( (MROUTED_VERSION << 8) | PROTOCOL_VERSION )
+#define MROUTED_LEVEL ( (MROUTED_VERSION << 8) | PROTOCOL_VERSION | \
+ ((NF_PRUNE | NF_GENID | NF_MTRACE) << 16))
/* for IGMP 'group' field of DVMRP messages */
+#define LEAF_FLAGS (( vifs_with_neighbors == 1 ) ? 0x010000 : 0)
+ /* more for IGMP 'group' field of DVMRP messages */
#define DEL_RTE_GROUP 0
#define DEL_ALL_ROUTES 1
/* for Deleting kernel table entries */
+/* obnoxious gcc gives an extraneous warning about this constant... */
+#if defined(__STDC__) || defined(__GNUC__)
+#define JAN_1970 2208988800UL /* 1970 - 1900 in seconds */
+#else
+#define JAN_1970 2208988800L /* 1970 - 1900 in seconds */
+#define const /**/
+#endif
+
+#ifdef RSRR
+#define BIT_ZERO(X) ((X) = 0)
+#define BIT_SET(X,n) ((X) |= 1 << (n))
+#define BIT_CLR(X,n) ((X) &= ~(1 << (n)))
+#define BIT_TST(X,n) ((X) & 1 << (n))
+#endif /* RSRR */
+
/*
* External declarations for global variables and functions.
*/
-extern char recv_buf[MAX_IP_PACKET_LEN];
-extern char send_buf[MAX_IP_PACKET_LEN];
+#define RECV_BUF_SIZE MAX_IP_PACKET_LEN
+extern char *recv_buf;
+extern char *send_buf;
extern int igmp_socket;
-extern u_long allhosts_group;
-extern u_long dvmrp_group;
-extern u_long dvmrp_genid;
+#ifdef RSRR
+extern int rsrr_socket;
+#endif /* RSRR */
+extern u_int32 allhosts_group;
+extern u_int32 allrtrs_group;
+extern u_int32 dvmrp_group;
+extern u_int32 dvmrp_genid;
#define DEFAULT_DEBUG 2 /* default if "-d" given without value */
@@ -78,93 +126,167 @@ extern struct uvif uvifs[MAXVIFS];
extern vifi_t numvifs;
extern int vifs_down;
extern int udp_socket;
+extern int vifs_with_neighbors;
extern char s1[];
extern char s2[];
extern char s3[];
+extern char s4[];
+#if !(defined(BSD) && (BSD >= 199103))
extern int errno;
extern int sys_nerr;
extern char * sys_errlist[];
+#endif
+
+/* main.c */
+extern void log __P((int, int, char *, ...));
+extern int register_input_handler __P((int fd, ihfunc_t func));
-extern void log();
-
-extern void init_igmp();
-extern void accept_igmp();
-extern void send_igmp();
-
-extern void init_routes();
-extern void start_route_updates();
-extern void update_route();
-extern void age_routes();
-extern void expire_all_routes();
-extern void free_all_routes();
-
-extern void accept_probe();
-extern void accept_report();
-extern void report();
-extern void report_to_all_neighbors();
-extern int report_next_chunk();
-extern void add_vif_to_routes();
-extern void delete_vif_from_routes();
-extern void delete_neighbor_from_routes();
-extern void dump_routes();
-
-extern void init_vifs();
-extern void check_vif_state();
-extern vifi_t find_vif();
-extern void age_vifs();
-extern void dump_vifs();
-extern void stop_all_vifs();
-
-extern void accept_group_report();
-extern void query_groups();
-extern void probe_for_neighbors();
-extern int update_neighbor();
-extern void accept_neighbor_request();
-
-extern void config_vifs_from_kernel();
-extern void config_vifs_from_file();
-
-extern int inet_valid_host();
-extern int inet_valid_subnet();
-extern char * inet_fmt();
-extern char * inet_fmts();
-extern u_long inet_parse();
-extern int inet_cksum();
-
-extern struct rtentry * determine_route();
-
-extern void init_ktable();
-extern int grplst_mem();
-extern void add_table_entry();
-extern void del_table_entry();
-extern void update_table_entry();
-extern void update_lclgrp();
-extern void delete_lclgrp();
+/* igmp.c */
+extern void init_igmp __P((void));
+extern void accept_igmp __P((int recvlen));
+extern void send_igmp __P((u_int32 src, u_int32 dst, int type,
+ int code, u_int32 group,
+ int datalen));
+/* callout.c */
+extern void callout_init __P((void));
+extern void age_callout_queue __P((void));
+extern int timer_setTimer __P((int delay, cfunc_t action,
+ char *data));
+extern void timer_clearTimer __P((int timer_id));
+
+/* route.c */
+extern void init_routes __P((void));
+extern void start_route_updates __P((void));
+extern void update_route __P((u_int32 origin, u_int32 mask,
+ int metric, u_int32 src,
+ vifi_t vifi));
+extern void age_routes __P((void));
+extern void expire_all_routes __P((void));
+extern void free_all_routes __P((void));
+extern void accept_probe __P((u_int32 src, u_int32 dst,
+ char *p, int datalen,
+ u_int32 level));
+extern void accept_report __P((u_int32 src, u_int32 dst,
+ char *p, int datalen,
+ u_int32 level));
+extern struct rtentry * determine_route __P((u_int32 src));
+extern void report __P((int which_routes, vifi_t vifi,
+ u_int32 dst));
+extern void report_to_all_neighbors __P((int which_routes));
+extern int report_next_chunk __P((void));
+extern void add_vif_to_routes __P((vifi_t vifi));
+extern void delete_vif_from_routes __P((vifi_t vifi));
+extern void delete_neighbor_from_routes __P((u_int32 addr,
+ vifi_t vifi));
+extern void dump_routes __P((FILE *fp));
+extern void start_route_updates __P((void));
+
+/* vif.c */
+extern void init_vifs __P((void));
+extern void check_vif_state __P((void));
+extern vifi_t find_vif __P((u_int32 src, u_int32 dst));
+extern void age_vifs __P((void));
+extern void dump_vifs __P((FILE *fp));
+extern void stop_all_vifs __P((void));
+extern struct listaddr *neighbor_info __P((vifi_t vifi, u_int32 addr));
+extern void accept_group_report __P((u_int32 src, u_int32 dst,
+ u_int32 group, int r_type));
+extern void query_groups __P((void));
+extern void probe_for_neighbors __P((void));
+extern int update_neighbor __P((vifi_t vifi, u_int32 addr,
+ int msgtype, char *p, int datalen,
+ u_int32 level));
+extern void accept_neighbor_request __P((u_int32 src, u_int32 dst));
+extern void accept_neighbor_request2 __P((u_int32 src,
+ u_int32 dst));
+extern void accept_neighbors __P((u_int32 src, u_int32 dst,
+ u_char *p, int datalen, u_int32 level));
+extern void accept_neighbors2 __P((u_int32 src, u_int32 dst,
+ u_char *p, int datalen, u_int32 level));
+extern void accept_leave_message __P((u_int32 src, u_int32 dst,
+ u_int32 group));
+extern void accept_membership_query __P((u_int32 src, u_int32 dst,
+ u_int32 group, int tmo));
+
+/* config.c */
+extern void config_vifs_from_kernel __P((void));
+
+/* cfparse.y */
+extern void config_vifs_from_file __P((void));
+
+/* inet.c */
+extern int inet_valid_host __P((u_int32 naddr));
+extern int inet_valid_subnet __P((u_int32 nsubnet, u_int32 nmask));
+extern char * inet_fmt __P((u_int32 addr, char *s));
+extern char * inet_fmts __P((u_int32 addr, u_int32 mask, char *s));
+extern u_int32 inet_parse __P((char *s));
+extern int inet_cksum __P((u_short *addr, u_int len));
+
+/* prune.c */
extern unsigned kroutes;
-extern void send_prune();
-extern void accept_prune();
-extern int no_entry_exists();
-extern struct ktable * find_src_grp();
-extern int rtr_cnt();
-extern void free_all_prunes();
-extern void age_table_entry();
-extern void dump_cache();
-
-extern void chkgrp_graft();
-extern void accept_graft();
-extern void send_graft_ack();
-extern void send_graft();
-extern void accept_g_ack();
-extern void mtrace();
-
-extern char * malloc();
-extern char * fgets();
-extern FILE * fopen();
-
-#ifndef htonl
-extern u_long htonl();
-extern u_long ntohl();
+extern void add_table_entry __P((u_int32 origin, u_int32 mcastgrp));
+extern void del_table_entry __P((struct rtentry *r,
+ u_int32 mcastgrp, u_int del_flag));
+extern void update_table_entry __P((struct rtentry *r));
+extern void init_ktable __P((void));
+extern void accept_prune __P((u_int32 src, u_int32 dst, char *p,
+ int datalen));
+extern void steal_sources __P((struct rtentry *rt));
+extern void reset_neighbor_state __P((vifi_t vifi, u_int32 addr));
+extern int grplst_mem __P((vifi_t vifi, u_int32 mcastgrp));
+extern int scoped_addr __P((vifi_t vifi, u_int32 addr));
+extern void free_all_prunes __P((void));
+extern void age_table_entry __P((void));
+extern void dump_cache __P((FILE *fp2));
+extern void update_lclgrp __P((vifi_t vifi, u_int32 mcastgrp));
+extern void delete_lclgrp __P((vifi_t vifi, u_int32 mcastgrp));
+extern void chkgrp_graft __P((vifi_t vifi, u_int32 mcastgrp));
+extern void accept_graft __P((u_int32 src, u_int32 dst, char *p,
+ int datalen));
+extern void accept_g_ack __P((u_int32 src, u_int32 dst, char *p,
+ int datalen));
+/* u_int is promoted u_char */
+extern void accept_mtrace __P((u_int32 src, u_int32 dst,
+ u_int32 group, char *data, u_int no,
+ int datalen));
+
+/* kern.c */
+extern void k_set_rcvbuf __P((int bufsize));
+extern void k_hdr_include __P((int bool));
+extern void k_set_ttl __P((int t));
+extern void k_set_loop __P((int l));
+extern void k_set_if __P((u_int32 ifa));
+extern void k_join __P((u_int32 grp, u_int32 ifa));
+extern void k_leave __P((u_int32 grp, u_int32 ifa));
+extern void k_init_dvmrp __P((void));
+extern void k_stop_dvmrp __P((void));
+extern void k_add_vif __P((vifi_t vifi, struct uvif *v));
+extern void k_del_vif __P((vifi_t vifi));
+extern void k_add_rg __P((u_int32 origin, struct gtable *g));
+extern int k_del_rg __P((u_int32 origin, struct gtable *g));
+extern int k_get_version __P((void));
+
+#ifdef SNMP
+/* prune.c */
+extern struct rtentry * snmp_find_route __P(());
+extern struct gtable * find_grp __P(());
+extern struct stable * find_grp_src __P(());
#endif
+
+#ifdef RSRR
+/* prune.c */
+extern struct gtable *kernel_table;
+extern struct gtable *gtp;
+extern int find_src_grp __P((u_int32 src, u_int32 mask,
+ u_int32 grp));
+
+/* rsrr.c */
+extern void rsrr_init __P((void));
+extern void rsrr_read __P((fd_set *rfd));
+extern void rsrr_clean __P((void));
+extern void rsrr_cache_send __P((struct gtable *gt, int notify));
+extern void rsrr_cache_clean __P((struct gtable *gt));
+#endif /* RSRR */
diff --git a/usr.sbin/mrouted/dvmrp.h b/usr.sbin/mrouted/dvmrp.h
index 5decfdba5683..5553dc34910e 100644
--- a/usr.sbin/mrouted/dvmrp.h
+++ b/usr.sbin/mrouted/dvmrp.h
@@ -7,7 +7,7 @@
* Leland Stanford Junior University.
*
*
- * $Id: dvmrp.h,v 1.6 1994/08/24 23:53:30 thyagara Exp $
+ * $Id: dvmrp.h,v 3.6 1995/06/25 18:52:10 fenner Exp $
*/
/*
@@ -102,9 +102,11 @@
*/
#define DVMRP_NF_TUNNEL 0x01 /* neighbors reached via tunnel */
#define DVMRP_NF_SRCRT 0x02 /* tunnel uses IP source routing */
+#define DVMRP_NF_PIM 0x04 /* neighbor is a PIM neighbor */
#define DVMRP_NF_DOWN 0x10 /* kernel state of interface */
#define DVMRP_NF_DISABLED 0x20 /* administratively disabled */
#define DVMRP_NF_QUERIER 0x40 /* I am the subnet's querier */
+#define DVMRP_NF_LEAF 0x80 /* Neighbor reports that it is a leaf */
/*
* Limit on length of route data
@@ -119,7 +121,9 @@
* Various protocol constants (all times in seconds)
*/
/* address for multicast DVMRP msgs */
-#define INADDR_DVMRP_GROUP (u_long)0xe0000004 /* 224.0.0.4 */
+#define INADDR_DVMRP_GROUP (u_int32)0xe0000004 /* 224.0.0.4 */
+ /* address for multicast mtrace msg */
+#define INADDR_ALLRTRS_GROUP (u_int32)0xe0000002 /* 224.0.0.2 */
#define ROUTE_MAX_REPORT_DELAY 5 /* max delay for reporting changes */
/* (This is the timer interrupt */
@@ -138,13 +142,18 @@
#define GROUP_QUERY_INTERVAL 125 /* periodic group query interval */
#define GROUP_EXPIRE_TIME 270 /* time to consider group gone */
+#define LEAVE_EXPIRE_TIME 3 /* " " after receiving a leave */
+/* Note: LEAVE_EXPIRE_TIME should ideally be shorter, but the resolution of
+ * the timer in mrouted doesn't allow us to follow the spec and make it any
+ * shorter. */
#define UNREACHABLE 32 /* "infinity" metric, must be <= 64 */
#define DEFAULT_METRIC 1 /* default subnet/tunnel metric */
#define DEFAULT_THRESHOLD 1 /* default subnet/tunnel threshold */
-#define MAX_RATE_LIMIT 100000 /* max rate limit */
-#define DEFAULT_RATE_LIMIT 0 /* default rate limit */
+#define MAX_RATE_LIMIT 100000 /* max rate limit */
+#define DEFAULT_PHY_RATE_LIMIT 0 /* default phyint rate limit */
+#define DEFAULT_TUN_RATE_LIMIT 500 /* default tunnel rate limit */
#define DEFAULT_CACHE_LIFETIME 300 /* kernel route entry discard time */
#define GRAFT_TIMEOUT_VAL 5 /* retransmission time for grafts */
diff --git a/usr.sbin/mrouted/igmp.c b/usr.sbin/mrouted/igmp.c
index f44e2f1616f2..00eeff56500b 100644
--- a/usr.sbin/mrouted/igmp.c
+++ b/usr.sbin/mrouted/igmp.c
@@ -7,7 +7,7 @@
* Leland Stanford Junior University.
*
*
- * $Id: igmp.c,v 1.8 1994/08/24 23:53:32 thyagara Exp $
+ * $Id: igmp.c,v 3.6 1995/06/25 18:52:55 fenner Exp $
*/
@@ -17,21 +17,33 @@
/*
* Exported variables.
*/
-char recv_buf[MAX_IP_PACKET_LEN]; /* input packet buffer */
-char send_buf[MAX_IP_PACKET_LEN]; /* output packet buffer */
+char *recv_buf; /* input packet buffer */
+char *send_buf; /* output packet buffer */
int igmp_socket; /* socket for all network I/O */
-u_long allhosts_group; /* allhosts addr in net order */
-u_long dvmrp_group; /* DVMRP grp addr in net order */
-u_long dvmrp_genid; /* IGMP generation id */
+u_int32 allhosts_group; /* All hosts addr in net order */
+u_int32 allrtrs_group; /* All-Routers " in net order */
+u_int32 dvmrp_group; /* DVMRP grp addr in net order */
+u_int32 dvmrp_genid; /* IGMP generation id */
+
+/*
+ * Local function definitions.
+ */
+/* u_char promoted to u_int */
+static char * packet_kind __P((u_int type, u_int code));
+static int igmp_log_level __P((u_int type, u_int code));
/*
* Open and initialize the igmp socket, and fill in the non-changing
* IP header fields in the output packet buffer.
*/
-void init_igmp()
+void
+init_igmp()
{
struct ip *ip;
+ recv_buf = malloc(RECV_BUF_SIZE);
+ send_buf = malloc(RECV_BUF_SIZE);
+
if ((igmp_socket = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP)) < 0)
log(LOG_ERR, errno, "IGMP socket");
@@ -41,6 +53,8 @@ void init_igmp()
k_set_loop(FALSE); /* disable multicast loopback */
ip = (struct ip *)send_buf;
+ ip->ip_hl = sizeof(struct ip) >> 2;
+ ip->ip_v = IPVERSION;
ip->ip_tos = 0;
ip->ip_off = 0;
ip->ip_p = IPPROTO_IGMP;
@@ -48,10 +62,9 @@ void init_igmp()
allhosts_group = htonl(INADDR_ALLHOSTS_GROUP);
dvmrp_group = htonl(INADDR_DVMRP_GROUP);
+ allrtrs_group = htonl(INADDR_ALLRTRS_GROUP);
}
-/* %%% hack for PIM %%% */
-#define IGMP_PIM 0x14
#define PIM_QUERY 0
#define PIM_REGISTER 1
#define PIM_REGISTER_STOP 2
@@ -61,14 +74,15 @@ void init_igmp()
#define PIM_GRAFT 6
#define PIM_GRAFT_ACK 7
-static char *packet_kind(type, code)
- u_char type, code;
+static char *
+packet_kind(type, code)
+ u_int type, code;
{
switch (type) {
case IGMP_HOST_MEMBERSHIP_QUERY: return "membership query ";
case IGMP_HOST_MEMBERSHIP_REPORT: return "membership report ";
- case IGMP_HOST_NEW_MEMBERSHIP_REPORT: return "new membership report ";
- case IGMP_HOST_LEAVE_MESSAGE: return "leave message";
+ case IGMP_HOST_NEW_MEMBERSHIP_REPORT: return "new member report ";
+ case IGMP_HOST_LEAVE_MESSAGE: return "leave message ";
case IGMP_DVMRP:
switch (code) {
case DVMRP_PROBE: return "neighbor probe ";
@@ -77,12 +91,12 @@ static char *packet_kind(type, code)
case DVMRP_NEIGHBORS: return "neighbor list ";
case DVMRP_ASK_NEIGHBORS2: return "neighbor request 2";
case DVMRP_NEIGHBORS2: return "neighbor list 2 ";
- case DVMRP_PRUNE: return "prune message ";
- case DVMRP_GRAFT: return "graft message ";
+ case DVMRP_PRUNE: return "prune message ";
+ case DVMRP_GRAFT: return "graft message ";
case DVMRP_GRAFT_ACK: return "graft message ack ";
default: return "unknown DVMRP msg ";
}
- case IGMP_PIM: /* %%% hack for PIM %%% */
+ case IGMP_PIM:
switch (code) {
case PIM_QUERY: return "PIM Router-Query ";
case PIM_REGISTER: return "PIM Register ";
@@ -104,11 +118,11 @@ static char *packet_kind(type, code)
* Process a newly received IGMP packet that is sitting in the input
* packet buffer.
*/
-void accept_igmp(recvlen)
+void
+accept_igmp(recvlen)
int recvlen;
{
- register vifi_t vifi;
- register u_long src, dst, group;
+ register u_int32 src, dst, group;
struct ip *ip;
struct igmp *igmp;
int ipdatalen, iphdrlen, igmpdatalen;
@@ -129,7 +143,7 @@ void accept_igmp(recvlen)
* necessary to install a route into the kernel for this.
*/
if (ip->ip_p == 0) {
- if (src == NULL || dst == NULL)
+ if (src == 0 || dst == 0)
log(LOG_WARNING, 0, "kernel request not accurate");
else
add_table_entry(src, dst);
@@ -162,21 +176,22 @@ void accept_igmp(recvlen)
switch (igmp->igmp_type) {
case IGMP_HOST_MEMBERSHIP_QUERY:
- /* we have to do the determination of the querrier router here */
+ accept_membership_query(src, dst, group, igmp->igmp_code);
return;
case IGMP_HOST_MEMBERSHIP_REPORT:
case IGMP_HOST_NEW_MEMBERSHIP_REPORT:
- accept_group_report(src, dst, group,igmp->igmp_type);
+ accept_group_report(src, dst, group, igmp->igmp_type);
return;
case IGMP_HOST_LEAVE_MESSAGE:
- leave_group_message(src, dst, group);
+ accept_leave_message(src, dst, group);
return;
case IGMP_DVMRP:
- switch (igmp->igmp_code) {
+ group = ntohl(group);
+ switch (igmp->igmp_code) {
case DVMRP_PROBE:
accept_probe(src, dst,
(char *)(igmp+1), igmpdatalen, group);
@@ -196,13 +211,13 @@ void accept_igmp(recvlen)
return;
case DVMRP_NEIGHBORS:
- accept_neighbors(src, dst, (char *)(igmp+1), igmpdatalen,
- group);
+ accept_neighbors(src, dst, (u_char *)(igmp+1), igmpdatalen,
+ group);
return;
case DVMRP_NEIGHBORS2:
- accept_neighbors2(src, dst, (char *)(igmp+1), igmpdatalen,
- group);
+ accept_neighbors2(src, dst, (u_char *)(igmp+1), igmpdatalen,
+ group);
return;
case DVMRP_PRUNE:
@@ -225,37 +240,63 @@ void accept_igmp(recvlen)
return;
}
-
- case IGMP_PIM: /* %%% hack for PIM %%% */
+ case IGMP_PIM:
return;
+ case IGMP_MTRACE_RESP:
+ return;
+
case IGMP_MTRACE:
- mtrace(src, dst, group, (char *)(igmp+1),
+ accept_mtrace(src, dst, group, (char *)(igmp+1),
igmp->igmp_code, igmpdatalen);
return;
default:
log(LOG_INFO, 0,
- "ignoring unknown IGMP message type %u from %s to %s",
+ "ignoring unknown IGMP message type %x from %s to %s",
igmp->igmp_type, inet_fmt(src, s1),
inet_fmt(dst, s2));
return;
}
}
+/*
+ * Some IGMP 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.
+ */
+static int
+igmp_log_level(type, code)
+ u_int type, code;
+{
+ 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;
+}
/*
* Construct an IGMP message in the output packet buffer. The caller may
* have already placed data in that buffer, of length 'datalen'. Then send
* the message from the interface with IP address 'src' to destination 'dst'.
*/
-void send_igmp(src, dst, type, code, group, datalen)
- u_long src, dst;
+void
+send_igmp(src, dst, type, code, group, datalen)
+ u_int32 src, dst;
int type, code;
- u_long group;
+ u_int32 group;
int datalen;
{
- static struct sockaddr_in sdst = {AF_INET};
+ static struct sockaddr_in sdst;
struct ip *ip;
struct igmp *igmp;
@@ -275,11 +316,20 @@ void send_igmp(src, dst, type, code, group, datalen)
if (IN_MULTICAST(ntohl(dst))) k_set_if(src);
if (dst == allhosts_group) k_set_loop(TRUE);
+ bzero(&sdst, sizeof(sdst));
+ sdst.sin_family = AF_INET;
+#if (defined(BSD) && (BSD >= 199103))
+ sdst.sin_len = sizeof(sdst);
+#endif
sdst.sin_addr.s_addr = dst;
if (sendto(igmp_socket, send_buf, ip->ip_len, 0,
(struct sockaddr *)&sdst, sizeof(sdst)) < 0) {
- if (errno == ENETDOWN) check_vif_state();
- else log(LOG_WARNING, errno, "sendto on %s", inet_fmt(src, s1));
+ if (errno == ENETDOWN)
+ check_vif_state();
+ else
+ log(igmp_log_level(type, code), errno,
+ "sendto to %s on %s",
+ inet_fmt(dst, s1), inet_fmt(src, s2));
}
if (dst == allhosts_group) k_set_loop(FALSE);
diff --git a/usr.sbin/mrouted/inet.c b/usr.sbin/mrouted/inet.c
index 5d7442ba1af0..e8d5ab6f23f8 100644
--- a/usr.sbin/mrouted/inet.c
+++ b/usr.sbin/mrouted/inet.c
@@ -7,7 +7,7 @@
* Leland Stanford Junior University.
*
*
- * $Id: inet.c,v 1.4 1993/05/30 01:36:38 deering Exp $
+ * $Id: inet.c,v 3.6 1995/06/25 18:54:45 fenner Exp $
*/
@@ -17,9 +17,10 @@
/*
* Exported variables.
*/
-char s1[16]; /* buffers to hold the string representations */
-char s2[16]; /* of IP addresses, to be passed to inet_fmt() */
-char s3[16]; /* or inet_fmts(). */
+char s1[19]; /* buffers to hold the string representations */
+char s2[19]; /* of IP addresses, to be passed to inet_fmt() */
+char s3[19]; /* or inet_fmts(). */
+char s4[19];
/*
@@ -27,10 +28,11 @@ char s3[16]; /* or inet_fmts(). */
* (Without a mask, cannot detect addresses of the form {subnet,0} or
* {subnet,-1}.)
*/
-int inet_valid_host(naddr)
- u_long naddr;
+int
+inet_valid_host(naddr)
+ u_int32 naddr;
{
- register u_long addr;
+ register u_int32 addr;
addr = ntohl(naddr);
@@ -42,29 +44,39 @@ int inet_valid_host(naddr)
/*
* Verify that a given subnet number and mask pair are credible.
+ *
+ * With CIDR, almost any subnet and mask are credible. mrouted still
+ * can't handle aggregated class A's, so we still check that, but
+ * otherwise the only requirements are that the subnet address is
+ * within the [ABC] range and that the host bits of the subnet
+ * are all 0.
*/
-int inet_valid_subnet(nsubnet, nmask)
- u_long nsubnet, nmask;
+int
+inet_valid_subnet(nsubnet, nmask)
+ u_int32 nsubnet, nmask;
{
- register u_long subnet, mask;
+ register u_int32 subnet, mask;
subnet = ntohl(nsubnet);
mask = ntohl(nmask);
if ((subnet & mask) != subnet) return (FALSE);
+ if (subnet == 0 && mask == 0)
+ return (TRUE);
+
if (IN_CLASSA(subnet)) {
if (mask < 0xff000000 ||
- (subnet & 0xff000000) == 0 ||
(subnet & 0xff000000) == 0x7f000000) return (FALSE);
}
- else if (IN_CLASSB(subnet)) {
- if (mask < 0xffff0000) return (FALSE);
+ else if (IN_CLASSD(subnet) || IN_BADCLASS(subnet)) {
+ /* Above Class C address space */
+ return (FALSE);
}
- else if (IN_CLASSC(subnet)) {
- if (mask < 0xffffff00) return (FALSE);
+ else if (subnet & ~mask) {
+ /* Host bits are set in the subnet */
+ return (FALSE);
}
- else return (FALSE);
return (TRUE);
}
@@ -73,8 +85,9 @@ int inet_valid_subnet(nsubnet, nmask)
/*
* Convert an IP address in u_long (network) format into a printable string.
*/
-char *inet_fmt(addr, s)
- u_long addr;
+char *
+inet_fmt(addr, s)
+ u_int32 addr;
char *s;
{
register u_char *a;
@@ -87,36 +100,44 @@ char *inet_fmt(addr, s)
/*
* Convert an IP subnet number in u_long (network) format into a printable
- * string.
+ * string including the netmask as a number of bits.
*/
-char *inet_fmts(addr, mask, s)
- u_long addr, mask;
+char *
+inet_fmts(addr, mask, s)
+ u_int32 addr, mask;
char *s;
{
register u_char *a, *m;
+ int bits;
+ if ((addr == 0) && (mask == 0)) {
+ sprintf(s, "default");
+ return (s);
+ }
a = (u_char *)&addr;
m = (u_char *)&mask;
+ bits = 33 - ffs(ntohl(mask));
- if (m[3] != 0) sprintf(s, "%u.%u.%u.%u", a[0], a[1], a[2], a[3]);
- else if (m[2] != 0) sprintf(s, "%u.%u.%u", a[0], a[1], a[2]);
- else if (m[1] != 0) sprintf(s, "%u.%u", a[0], a[1]);
- else sprintf(s, "%u", a[0]);
+ if (m[3] != 0) sprintf(s, "%u.%u.%u.%u/%d", a[0], a[1], a[2], a[3],
+ bits);
+ else if (m[2] != 0) sprintf(s, "%u.%u.%u/%d", a[0], a[1], a[2], bits);
+ else if (m[1] != 0) sprintf(s, "%u.%u/%d", a[0], a[1], bits);
+ else sprintf(s, "%u/%d", a[0], bits);
return (s);
}
-
/*
* Convert the printable string representation of an IP address into the
* u_long (network) format. Return 0xffffffff on error. (To detect the
* legal address with that value, you must explicitly compare the string
* with "255.255.255.255".)
*/
-u_long inet_parse(s)
+u_int32
+inet_parse(s)
char *s;
{
- u_long a;
+ u_int32 a = 0;
u_int a0, a1, a2, a3;
char c;
@@ -151,7 +172,8 @@ u_long inet_parse(s)
* Checksum routine for Internet Protocol family headers (C Version)
*
*/
-int inet_cksum(addr, len)
+int
+inet_cksum(addr, len)
u_short *addr;
u_int len;
{
@@ -166,13 +188,13 @@ int inet_cksum(addr, len)
* back all the carry bits from the top 16 bits into the lower
* 16 bits.
*/
- while( nleft > 1 ) {
+ while (nleft > 1) {
sum += *w++;
nleft -= 2;
}
/* mop up an odd byte, if necessary */
- if( nleft == 1 ) {
+ if (nleft == 1) {
*(u_char *) (&answer) = *(u_char *)w ;
sum += answer;
}
diff --git a/usr.sbin/mrouted/kern.c b/usr.sbin/mrouted/kern.c
index a44a15f9812b..a4030c831bb2 100644
--- a/usr.sbin/mrouted/kern.c
+++ b/usr.sbin/mrouted/kern.c
@@ -7,7 +7,7 @@
* Leland Stanford Junior University.
*
*
- * $Id: kern.c,v 1.6 1994/08/24 23:53:37 thyagara Exp $
+ * $Id: kern.c,v 3.6 1995/06/25 18:57:38 fenner Exp $
*/
@@ -59,7 +59,7 @@ void k_set_loop(l)
void k_set_if(ifa)
- u_long ifa;
+ u_int32 ifa;
{
struct in_addr adr;
@@ -72,8 +72,8 @@ void k_set_if(ifa)
void k_join(grp, ifa)
- u_long grp;
- u_long ifa;
+ u_int32 grp;
+ u_int32 ifa;
{
struct ip_mreq mreq;
@@ -88,8 +88,8 @@ void k_join(grp, ifa)
void k_leave(grp, ifa)
- u_long grp;
- u_long ifa;
+ u_int32 grp;
+ u_int32 ifa;
{
struct ip_mreq mreq;
@@ -105,17 +105,24 @@ void k_leave(grp, ifa)
void k_init_dvmrp()
{
- if (setsockopt(igmp_socket, IPPROTO_IP, DVMRP_INIT,
+#ifdef OLD_KERNEL
+ if (setsockopt(igmp_socket, IPPROTO_IP, MRT_INIT,
(char *)NULL, 0) < 0)
- log(LOG_ERR, errno, "can't enable DVMRP routing in kernel");
+#else
+ int v=1;
+
+ if (setsockopt(igmp_socket, IPPROTO_IP, MRT_INIT,
+ (char *)&v, sizeof(int)) < 0)
+#endif
+ log(LOG_ERR, errno, "can't enable Multicast routing in kernel");
}
void k_stop_dvmrp()
{
- if (setsockopt(igmp_socket, IPPROTO_IP, DVMRP_DONE,
+ if (setsockopt(igmp_socket, IPPROTO_IP, MRT_DONE,
(char *)NULL, 0) < 0)
- log(LOG_WARNING, errno, "can't disable DVMRP routing in kernel");
+ log(LOG_WARNING, errno, "can't disable Multicast routing in kernel");
}
@@ -132,52 +139,85 @@ void k_add_vif(vifi, v)
vc.vifc_lcl_addr.s_addr = v->uv_lcl_addr;
vc.vifc_rmt_addr.s_addr = v->uv_rmt_addr;
- if (setsockopt(igmp_socket, IPPROTO_IP, DVMRP_ADD_VIF,
+ if (setsockopt(igmp_socket, IPPROTO_IP, MRT_ADD_VIF,
(char *)&vc, sizeof(vc)) < 0)
- log(LOG_ERR, errno, "setsockopt DVMRP_ADD_VIF");
+ log(LOG_ERR, errno, "setsockopt MRT_ADD_VIF");
}
void k_del_vif(vifi)
vifi_t vifi;
{
- if (setsockopt(igmp_socket, IPPROTO_IP, DVMRP_DEL_VIF,
+ if (setsockopt(igmp_socket, IPPROTO_IP, MRT_DEL_VIF,
(char *)&vifi, sizeof(vifi)) < 0)
- log(LOG_ERR, errno, "setsockopt DVMRP_DEL_VIF");
+ log(LOG_ERR, errno, "setsockopt MRT_DEL_VIF");
}
/*
* Adds a (source, mcastgrp) entry to the kernel
*/
-void k_add_rg(kt)
- struct ktable *kt;
+void k_add_rg(origin, g)
+ u_int32 origin;
+ struct gtable *g;
{
struct mfcctl mc;
+ int i;
/* copy table values so that setsockopt can process it */
- COPY_TABLES(kt, mc);
+ mc.mfcc_origin.s_addr = origin;
+#ifdef OLD_KERNEL
+ mc.mfcc_originmask.s_addr = 0xffffffff;
+#endif
+ mc.mfcc_mcastgrp.s_addr = g->gt_mcastgrp;
+ mc.mfcc_parent = g->gt_route ? g->gt_route->rt_parent : NO_VIF;
+ for (i = 0; i < numvifs; i++)
+ mc.mfcc_ttls[i] = g->gt_ttls[i];
/* write to kernel space */
- if (setsockopt(igmp_socket, IPPROTO_IP, DVMRP_ADD_MFC,
+ if (setsockopt(igmp_socket, IPPROTO_IP, MRT_ADD_MFC,
(char *)&mc, sizeof(mc)) < 0)
- log(LOG_WARNING, errno, "setsockopt DVMRP_ADD_MFC");
+ log(LOG_WARNING, errno, "setsockopt MRT_ADD_MFC");
}
/*
* Deletes a (source, mcastgrp) entry from the kernel
*/
-void k_del_rg(kt)
- struct ktable *kt;
+int k_del_rg(origin, g)
+ u_int32 origin;
+ struct gtable *g;
{
struct mfcctl mc;
+ int retval;
/* copy table values so that setsockopt can process it */
- COPY_TABLES(kt, mc);
+ mc.mfcc_origin.s_addr = origin;
+#ifdef OLD_KERNEL
+ mc.mfcc_originmask.s_addr = 0xffffffff;
+#endif
+ mc.mfcc_mcastgrp.s_addr = g->gt_mcastgrp;
/* write to kernel space */
- if (setsockopt(igmp_socket, IPPROTO_IP, DVMRP_DEL_MFC,
- (char *)&mc, sizeof(mc)) < 0)
- log(LOG_WARNING, errno, "setsockopt DVMRP_DEL_MFC");
+ if ((retval = setsockopt(igmp_socket, IPPROTO_IP, MRT_DEL_MFC,
+ (char *)&mc, sizeof(mc))) < 0)
+ log(LOG_WARNING, errno, "setsockopt MRT_DEL_MFC");
+
+ return retval;
}
+
+/*
+ * Get the kernel's idea of what version of mrouted needs to run with it.
+ */
+int k_get_version()
+{
+ int vers;
+ int len = sizeof(vers);
+
+ if (getsockopt(igmp_socket, IPPROTO_IP, MRT_VERSION,
+ (char *)&vers, &len) < 0)
+ log(LOG_ERR, errno,
+ "getsockopt MRT_VERSION: perhaps your kernel is too old");
+
+ return vers;
+}
diff --git a/usr.sbin/mrouted/main.c b/usr.sbin/mrouted/main.c
index 22a021429d94..f66ce7193f2f 100644
--- a/usr.sbin/mrouted/main.c
+++ b/usr.sbin/mrouted/main.c
@@ -7,7 +7,7 @@
* Leland Stanford Junior University.
*
*
- * $Id: main.c,v 1.8 1994/08/24 23:53:42 thyagara Exp $
+ * $Id: main.c,v 3.6 1995/06/25 18:58:06 fenner Exp $
*/
/*
@@ -21,13 +21,23 @@
#include "defs.h"
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+#include <fcntl.h>
+
+#ifdef SNMP
+#include "snmp.h"
+#endif
extern char *configfilename;
-static char pidfilename[] = "/etc/mrouted.pid";
-static char dumpfilename[] = "/usr/tmp/mrouted.dump";
-static char cachefilename[] = "/usr/tmp/mrouted.cache";
-static char genidfilename[] = "/usr/tmp/mrouted.genid";
+static char pidfilename[] = _PATH_MROUTED_PID;
+static char dumpfilename[] = _PATH_MROUTED_DUMP;
+static char cachefilename[] = _PATH_MROUTED_CACHE;
+static char genidfilename[] = _PATH_MROUTED_GENID;
int cache_lifetime = DEFAULT_CACHE_LIFETIME;
int max_prune_lifetime = DEFAULT_CACHE_LIFETIME * 2;
@@ -35,18 +45,44 @@ int max_prune_lifetime = DEFAULT_CACHE_LIFETIME * 2;
int debug = 0;
u_char pruning = 1; /* Enable pruning by default */
+#define NHANDLERS 2
+
+static struct ihandler {
+ int fd; /* File descriptor */
+ ihfunc_t func; /* Function to call with &fd_set */
+} ihandlers[NHANDLERS];
+static int nhandlers = 0;
/*
* Forward declarations.
*/
-static void fasttimer();
-static void timer();
-static void hup();
-static void dump();
-static void fdump();
-static void cdump();
-static void restart();
+static void fasttimer __P((int));
+static void done __P((int));
+static void dump __P((int));
+static void fdump __P((int));
+static void cdump __P((int));
+static void restart __P((int));
+static void timer __P((void));
+static void cleanup __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[];
@@ -55,12 +91,28 @@ main(argc, argv)
register int omask;
int dummy;
FILE *fp;
- extern uid_t geteuid();
struct timeval tv;
- struct timezone tzp;
- u_long prev_genid;
+ u_int32 prev_genid;
+ int vers;
+ fd_set rfds, readers;
+ int nfds, n, i;
+#ifdef SNMP
+ char *myname;
+ fd_set wfds;
+
+
+ if (myname = strrchr(argv[0], '/'))
+ myname++;
+ if (myname == NULL || *myname == 0)
+ myname = argv[0];
+ isodetailor (myname, 0);
+#endif
+#ifdef SYSV
+ setvbuf(stderr, NULL, _IOLBF, 0);
+#else
setlinebuf(stderr);
+#endif
if (geteuid() != 0) {
fprintf(stderr, "must be root\n");
@@ -107,11 +159,16 @@ usage: fprintf(stderr,
(void)open("/", 0);
(void)dup2(0, 1);
(void)dup2(0, 2);
+#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
}
else
fprintf(stderr, "debug level %u\n", debug);
@@ -125,12 +182,16 @@ usage: fprintf(stderr,
log(LOG_NOTICE, 0, "mrouted version %d.%d",
PROTOCOL_VERSION, MROUTED_VERSION);
+#ifdef SYSV
+ srand48(time(NULL));
+#else
srandom(gethostid());
+#endif
/*
* Get generation id
*/
- gettimeofday(&tv, &tzp);
+ gettimeofday(&tv, 0);
dvmrp_genid = tv.tv_sec;
fp = fopen(genidfilename, "r");
@@ -148,33 +209,71 @@ usage: fprintf(stderr,
}
callout_init();
+
+#ifdef SNMP
+ snmp_init();
+#endif
+
init_igmp();
k_init_dvmrp(); /* enable DVMRP routing in kernel */
+
+#ifndef OLD_KERNEL
+ vers = k_get_version();
+ /*XXX
+ * This function must change whenever the kernel version changes
+ */
+ if ((((vers >> 8) & 0xff) != 3) ||
+ ((vers & 0xff) != 5))
+ log(LOG_ERR, 0, "kernel (v%d.%d)/mrouted (v%d.%d) version mismatch",
+ (vers >> 8) & 0xff, vers & 0xff,
+ PROTOCOL_VERSION, MROUTED_VERSION);
+#endif
+
init_routes();
init_ktable();
init_vifs();
+#ifdef RSRR
+ rsrr_init();
+#endif /* RSRR */
+
+#if defined(__STDC__) || defined(__GNUC__)
+ /* 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);
+#endif
if (debug)
fprintf(stderr, "pruning %s\n", pruning ? "on" : "off");
fp = fopen(pidfilename, "w");
if (fp != NULL) {
- fprintf(fp, "%d\n", getpid());
+ fprintf(fp, "%d\n", (int)getpid());
(void) fclose(fp);
}
- if (debug >= 2) dump();
+ if (debug >= 2) dump(0);
(void)signal(SIGALRM, fasttimer);
(void)signal(SIGHUP, restart);
- (void)signal(SIGTERM, hup);
- (void)signal(SIGINT, hup);
+ (void)signal(SIGTERM, done);
+ (void)signal(SIGINT, done);
(void)signal(SIGUSR1, fdump);
(void)signal(SIGUSR2, cdump);
if (debug != 0)
(void)signal(SIGQUIT, dump);
+ FD_ZERO(&readers);
+ FD_SET(igmp_socket, &readers);
+ nfds = igmp_socket + 1;
+ for (i = 0; i < nhandlers; i++) {
+ FD_SET(ihandlers[i].fd, &readers);
+ if (ihandlers[i].fd >= nfds)
+ nfds = ihandlers[i].fd + 1;
+ }
+
(void)alarm(1); /* schedule first timer interrupt */
/*
@@ -182,27 +281,69 @@ usage: fprintf(stderr,
*/
dummy = 0;
for(;;) {
- recvlen = recvfrom(igmp_socket, recv_buf, sizeof(recv_buf),
- 0, NULL, &dummy);
- if (recvlen < 0) {
- if (errno != EINTR) log(LOG_ERR, errno, "recvfrom");
- continue;
+ bcopy((char *)&readers, (char *)&rfds, sizeof(rfds));
+#ifdef SNMP
+ FD_ZERO(&wfds);
+
+ if (smux_fd != NOTOK) {
+ if (rock_and_roll)
+ FD_SET(smux_fd, &rfds);
+ else
+ FD_SET(smux_fd, &wfds);
+ if (smux_fd >= nfds)
+ nfds = smux_fd + 1;
+ }
+
+ if ((n = xselect(nfds, &rfds, &wfds, NULLFD, NOTOK))==NOTOK) {
+#else
+ if ((n = select(nfds, &rfds, NULL, NULL, NULL)) < 0) {
+#endif
+ if (errno != EINTR) /* SIGALRM is expected */
+ log(LOG_WARNING, errno, "select failed");
+ continue;
+ }
+
+ if (FD_ISSET(igmp_socket, &rfds)) {
+ recvlen = recvfrom(igmp_socket, recv_buf, RECV_BUF_SIZE,
+ 0, NULL, &dummy);
+ if (recvlen < 0) {
+ if (errno != EINTR) log(LOG_ERR, errno, "recvfrom");
+ continue;
+ }
+ omask = sigblock(sigmask(SIGALRM));
+ accept_igmp(recvlen);
+ (void)sigsetmask(omask);
+ }
+
+ for (i = 0; i < nhandlers; i++) {
+ if (FD_ISSET(ihandlers[i].fd, &rfds)) {
+ (*ihandlers[i].func)(&rfds);
+ }
}
- omask = sigblock(sigmask(SIGALRM));
- accept_igmp(recvlen);
- (void)sigsetmask(omask);
+
+#ifdef SNMP
+ if (smux_fd != NOTOK) {
+ if (rock_and_roll) {
+ if (FD_ISSET(smux_fd, &rfds))
+ doit_smux();
+ } else if (FD_ISSET(smux_fd, &wfds))
+ start_smux();
+ }
+#endif
}
}
/*
- * routine invoked every second. It's main goal is to cycle through
+ * 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()
+static void
+fasttimer(i)
+ int i;
{
static unsigned int tlast;
static unsigned int nsent;
@@ -264,7 +405,8 @@ static u_long virtual_time = 0;
* group querying duties, and drives various timers in routing entries and
* virtual interface data structures.
*/
-static void timer()
+static void
+timer()
{
age_routes(); /* Advance the timers in the route entries */
age_vifs(); /* Advance the timers for neighbors */
@@ -301,6 +443,16 @@ static void timer()
report_to_all_neighbors(CHANGED_ROUTES);
}
+#ifdef SNMP
+ if (smux_fd == NOTOK && !dont_bother_anymore
+ && virtual_time % SNMPD_RETRY_INTERVAL == 0) {
+ /*
+ * Time to check for snmpd running.
+ */
+ try_smux_init();
+ }
+#endif
+
/*
* Advance virtual time
*/
@@ -309,21 +461,41 @@ static void timer()
/*
- * On hangup signal, let everyone know we're going away.
+ * On termination, let everyone know we're going away.
*/
-static void hup()
+static void
+done(i)
+ int i;
{
- log(LOG_INFO, 0, "hup");
- expire_all_routes();
- report_to_all_neighbors(ALL_ROUTES);
- exit(1);
+ log(LOG_NOTICE, 0, "mrouted version %d.%d exiting",
+ PROTOCOL_VERSION, MROUTED_VERSION);
+ cleanup();
+ _exit(1);
+}
+
+static void
+cleanup()
+{
+ static in_cleanup = 0;
+
+ if (!in_cleanup) {
+ in_cleanup++;
+#ifdef RSRR
+ rsrr_clean();
+#endif /* RSRR */
+ expire_all_routes();
+ report_to_all_neighbors(ALL_ROUTES);
+ k_stop_dvmrp();
+ }
}
/*
* Dump internal data structures to stderr.
*/
-static void dump()
+static void
+dump(i)
+ int i;
{
dump_vifs(stderr);
dump_routes(stderr);
@@ -333,7 +505,9 @@ static void dump()
/*
* Dump internal data structures to a file.
*/
-static void fdump()
+static void
+fdump(i)
+ int i;
{
FILE *fp;
@@ -349,7 +523,9 @@ static void fdump()
/*
* Dump local cache contents to a file.
*/
-static void cdump()
+static void
+cdump(i)
+ int i;
{
FILE *fp;
@@ -364,11 +540,14 @@ static void cdump()
/*
* Restart mrouted
*/
-static void restart()
+static void
+restart(i)
+ int i;
{
register int omask;
- log(LOG_INFO, 0, "restart");
+ log(LOG_NOTICE, 0, "mrouted version %d.%d restart",
+ PROTOCOL_VERSION, MROUTED_VERSION);
/*
* reset all the entries
@@ -378,6 +557,8 @@ static void restart()
free_all_routes();
stop_all_vifs();
k_stop_dvmrp();
+ close(igmp_socket);
+ close(udp_socket);
/*
* start processing again
@@ -400,39 +581,63 @@ static void restart()
* according to the severity of the message and the current debug level.
* For errors of severity LOG_ERR or worse, terminate the program.
*/
-void log(severity, syserr, format, a, b, c, d, e)
+#ifdef __STDC__
+void
+log(int severity, int syserr, char *format, ...)
+{
+ va_list ap;
+ static char fmt[211] = "warning - ";
+ char *msg;
+ char tbuf[20];
+ struct timeval now;
+ struct tm *thyme;
+
+ va_start(ap, format);
+#else
+/*VARARGS3*/
+void
+log(severity, syserr, format, va_alist)
int severity, syserr;
char *format;
- int a, b, c, d, e;
+ va_dcl
{
- char fmt[100];
+ va_list ap;
+ static char fmt[211] = "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];
switch (debug) {
case 0: break;
case 1: if (severity > LOG_NOTICE) break;
case 2: if (severity > LOG_INFO ) break;
default:
- fmt[0] = '\0';
- if (severity == LOG_WARNING) strcat(fmt, "warning - ");
- strncat(fmt, format, 80);
- fprintf(stderr, fmt, a, b, c, d, e);
+ gettimeofday(&now,NULL);
+ thyme = localtime(&now.tv_sec);
+ strftime(tbuf, sizeof(tbuf), "%X.%%03d ", thyme);
+ fprintf(stderr, tbuf, now.tv_usec / 1000);
+ fprintf(stderr, "%s", msg);
if (syserr == 0)
fprintf(stderr, "\n");
- else if(syserr < sys_nerr)
+ else if (syserr < sys_nerr)
fprintf(stderr, ": %s\n", sys_errlist[syserr]);
else
fprintf(stderr, ": errno %d\n", syserr);
}
if (severity <= LOG_NOTICE) {
- fmt[0] = '\0';
- if (severity == LOG_WARNING) strcat(fmt, "warning - ");
- strncat(fmt, format, 80);
if (syserr != 0) {
- strcat(fmt, ": %m");
- errno = syserr;
- }
- syslog(severity, fmt, a, b, c, d, e);
+ errno = syserr;
+ syslog(severity, "%s: %m", msg);
+ } else
+ syslog(severity, "%s", msg);
if (severity <= LOG_ERR) exit(-1);
}
diff --git a/usr.sbin/mrouted/map-mbone.8 b/usr.sbin/mrouted/map-mbone.8
index 41eb8088206c..ba850d234395 100644
--- a/usr.sbin/mrouted/map-mbone.8
+++ b/usr.sbin/mrouted/map-mbone.8
@@ -1,97 +1,89 @@
-.Dd March 31, 1995
-.Dt MAP-MBONE 8
-.Os FreeBSD 2.0
-.Sh NAME
-.Nm map-mbone
-.Nd multicast connection mapper
-.Sh SYNOPSIS
-.Nm map-mbone
-.Op Fl d Ar debuglevel
-.Op Fl f
-.Op Fl g
-.Op Fl n
-.Op Fl r Ar retries
-.Op Fl t Ar timeout
-.Op Ar router
-.Sh DESCRIPTION
-.Nm map-mbone
+.TH MAP-MBONE 8
+.UC 5
+.SH NAME
+map-mbone \- Multicast connection mapper
+.SH SYNOPSIS
+.B /usr/sbin/map-mbone
+[
+.B \-d
+.I debug_level
+] [
+.B \-f
+] [
+.B \-g
+] [
+.B \-n
+] [
+.B \-r
+.I retry_count
+] [
+.B \-t
+.I timeout_count
+] [
+.B starting_router
+]
+.SH DESCRIPTION
+.I map-mbone
attempts to display all multicast routers that are reachable from the multicast
-router
-.Ar router .
-If not specified on the command line, the default
-.Ar router
-is the local host.
-.Nm
-traverses neighboring multicast routers by sending the
-.Dv ASK_NEIGHBORS
-.Tn IGMP
-message to each router. If this multicast router responds, the version
-number and a list of their neighboring multicast router addresses is
-part of that response. If the responding router has recent multicast
-version number, then
-.Nm
+.I starting_router.
+If not specified on the command line, the default multicast
+.I starting_router
+is the localhost.
+.PP
+.I map-mbone
+traverses neighboring multicast routers by sending the ASK_NEIGHBORS IGMP
+message to the multicast starting_router. If this multicast router responds,
+the version number and a list of their neighboring multicast router addresses is
+part of that response. If the responding router has recent multicast version
+number, then
+.I map-mbone
requests additional information such as metrics, thresholds, and flags from the
multicast router. For each new occurrence of neighboring multicast router in
the reply and provided the flooding option has been selected, then
-.Nm
+.I map-mbone
asks each of this multicast router for a list of neighbors. This search
for unique routers will continue until no new neighboring multicast routers
are reported.
-.Pp
-The options supported by
-.Nm
-are as follows:
-.Bl -tag -width XXXdebuglevel
-.It Fl d Ar debuglevel
-This sets the debug level to
-.Ar debuglevel .
-When the debug level is greater than the default value of 0,
-additional debugging messages are printed. Regardless of the debug
-level, an error condition, will always write an error message and will
-cause
+.br
+.ne 5
+.SH INVOCATION
+.PP
+"\-d" option sets the debug level. When the debug level is greater than the
+default value of 0, addition debugging messages are printed. Regardless of
+the debug level, an error condition, will always write an error message and will
+cause
.I map-mbone
to terminate.
Non-zero debug levels have the following effects:
-.Bl -tag -width "level 3"
-.It level 1
+.IP "level 1"
packet warnings are printed to stderr.
-.It level 2
+.IP "level 2"
all level 1 messages plus notifications down networks are printed to stderr.
-.It level 3
+.IP "level 3"
all level 2 messages plus notifications of all packet
timeouts are printed to stderr.
-.El
-.It Fl f
-This option enables flooding. Flooding allows
-.Nm
-to perform recursive search
-of neighboring multicast routers and is enabled by default when an
-initial
-.Ar router
-is not specified.
-.It Fl g
-This option enables graphing in GraphEd format.
-.It Fl n
-This option disables the DNS lookup for the multicast routers' names.
-.It Fl r Ar retries
-This options sets the neighbor query retry limit to
-.Ar retries .
-The default is one retry.
-.It Fl t Ar timeout
-This option sets the number of seconds to wait for a neighbor query
-reply before retrying. The default timeout is two seconds.
-.Sh RESTRICTIONS
-.Nm
-must be run as `root'.
-.Sh SEE ALSO
-.Xr mrinfo 8 ,
-.Xr mrouted 8 ,
-.Xr mtrace 8
-.Sh AUTHOR
+.PP
+"\-f" option sets flooding option. Flooding allows the recursive search
+of neighboring multicast routers and is enable by default when starting_router
+is not used.
+.PP
+"\-g" option sets graphing in GraphEd format.
+.PP
+"\-n" option disables the DNS lookup for the multicast routers names.
+.PP
+"\-r retry_count" sets the neighbor query retry limit. Default is 1 retry.
+.PP
+"\-t timeout_count" sets the number of seconds to wait for a neighbor query
+reply before retrying. Default timeout is 2 seconds.
+.PP
+.SH IMPORTANT NOTE
+.I map-mbone
+must be run as root.
+.PP
+.SH SEE ALSO
+.BR mrouted (8) ,
+.BR mrinfo (8) ,
+.BR mtrace (8)
+.PP
+.SH AUTHOR
Pavel Curtis
-.Sh HISTORY
-A
-.Nm
-command first appeared in
-.Tn FreeBSD
-2.0.
diff --git a/usr.sbin/mrouted/mapper.c b/usr.sbin/mrouted/mapper.c
index 64a05b5f8d24..8c1c5fd7e6ff 100644
--- a/usr.sbin/mrouted/mapper.c
+++ b/usr.sbin/mrouted/mapper.c
@@ -1,7 +1,7 @@
/* Mapper for connections between MRouteD multicast routers.
* Written by Pavel Curtis <Pavel@PARC.Xerox.Com>
*
- * $Id: mapper.c,v 1.8 1994/08/24 23:53:54 thyagara Exp $
+ * $Id: mapper.c,v 3.6 1995/06/25 18:59:02 fenner Exp $
*/
/*
@@ -21,9 +21,16 @@
* These notices must be retained in any copies of any part of this software.
*/
+#include <string.h>
#include <netdb.h>
#include <sys/time.h>
#include "defs.h"
+#include <arpa/inet.h>
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
#define DEFAULT_TIMEOUT 2 /* How long to wait before retrying requests */
#define DEFAULT_RETRIES 1 /* How many times to ask each router */
@@ -33,7 +40,7 @@
typedef struct neighbor {
struct neighbor *next;
- u_long addr; /* IP address in NET order */
+ u_int32 addr; /* IP address in NET order */
u_char metric; /* TTL cost of forwarding */
u_char threshold; /* TTL threshold to forward */
u_short flags; /* flags on connection */
@@ -42,13 +49,13 @@ typedef struct neighbor {
typedef struct interface {
struct interface *next;
- u_long addr; /* IP address of the interface in NET order */
+ u_int32 addr; /* IP address of the interface in NET order */
Neighbor *neighbors; /* List of neighbors' IP addresses */
} Interface;
typedef struct node {
- u_long addr; /* IP address of this entry in NET order */
- u_long version; /* which mrouted version is running */
+ u_int32 addr; /* IP address of this entry in NET order */
+ u_int32 version; /* which mrouted version is running */
int tries; /* How many requests sent? -1 for aliases */
union {
struct node *alias; /* If alias, to what? */
@@ -59,7 +66,7 @@ typedef struct node {
Node *routers = 0;
-u_long our_addr, target_addr = 0; /* in NET order */
+u_int32 our_addr, target_addr = 0; /* in NET order */
int debug = 0;
int retries = DEFAULT_RETRIES;
int timeout = DEFAULT_TIMEOUT;
@@ -67,9 +74,26 @@ int show_names = TRUE;
vifi_t numvifs; /* to keep loader happy */
/* (see COPY_TABLES macro called in kern.c) */
+Node * find_node __P((u_int32 addr, Node **ptr));
+Interface * find_interface __P((u_int32 addr, Node *node));
+Neighbor * find_neighbor __P((u_int32 addr, Node *node));
+int main __P((int argc, char *argv[]));
+void ask __P((u_int32 dst));
+void ask2 __P((u_int32 dst));
+int retry_requests __P((Node *node));
+char * inet_name __P((u_int32 addr));
+void print_map __P((Node *node));
+char * graph_name __P((u_int32 addr, char *buf));
+void graph_edges __P((Node *node));
+void elide_aliases __P((Node *node));
+void graph_map __P((void));
+int get_number __P((int *var, int deflt, char ***pargv,
+ int *pargc));
+u_int32 host_addr __P((char *name));
+
Node *find_node(addr, ptr)
- u_long addr;
+ u_int32 addr;
Node **ptr;
{
Node *n = *ptr;
@@ -92,7 +116,7 @@ Node *find_node(addr, ptr)
Interface *find_interface(addr, node)
- u_long addr;
+ u_int32 addr;
Node *node;
{
Interface *ifc;
@@ -112,7 +136,7 @@ Interface *find_interface(addr, node)
Neighbor *find_neighbor(addr, node)
- u_long addr;
+ u_int32 addr;
Node *node;
{
Interface *ifc;
@@ -134,12 +158,27 @@ Neighbor *find_neighbor(addr, node)
* message and the current debug level. For errors of severity LOG_ERR or
* worse, terminate the program.
*/
-void log(severity, syserr, format, a, b, c, d, e)
- int severity, syserr;
- char *format;
- int a, b, c, d, e;
+#ifdef __STDC__
+void
+log(int severity, int syserr, char *format, ...)
{
- char fmt[100];
+ va_list ap;
+ char fmt[100];
+
+ va_start(ap, format);
+#else
+/*VARARGS3*/
+void
+log(severity, syserr, format, va_alist)
+ int severity, syserr;
+ char *format;
+ va_dcl
+{
+ va_list ap;
+ char fmt[100];
+
+ va_start(ap);
+#endif
switch (debug) {
case 0: if (severity > LOG_WARNING) return;
@@ -150,7 +189,7 @@ void log(severity, syserr, format, a, b, c, d, e)
if (severity == LOG_WARNING)
strcat(fmt, "warning - ");
strncat(fmt, format, 80);
- fprintf(stderr, fmt, a, b, c, d, e);
+ vfprintf(stderr, fmt, ap);
if (syserr == 0)
fprintf(stderr, "\n");
else if (syserr < sys_nerr)
@@ -168,14 +207,14 @@ void log(severity, syserr, format, a, b, c, d, e)
* Send a neighbors-list request.
*/
void ask(dst)
- u_long dst;
+ u_int32 dst;
{
send_igmp(our_addr, dst, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS,
htonl(MROUTED_LEVEL), 0);
}
void ask2(dst)
- u_long dst;
+ u_int32 dst;
{
send_igmp(our_addr, dst, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS2,
htonl(MROUTED_LEVEL), 0);
@@ -185,8 +224,9 @@ void ask2(dst)
/*
* Process an incoming group membership report.
*/
-void accept_group_report(src, dst, group)
- u_long src, dst, group;
+void accept_group_report(src, dst, group, r_type)
+ u_int32 src, dst, group;
+ int r_type;
{
log(LOG_INFO, 0, "ignoring IGMP group membership report from %s to %s",
inet_fmt(src, s1), inet_fmt(dst, s2));
@@ -196,8 +236,10 @@ void accept_group_report(src, dst, group)
/*
* Process an incoming neighbor probe message.
*/
-void accept_probe(src, dst)
- u_long src, dst;
+void accept_probe(src, dst, p, datalen, level)
+ u_int32 src, dst, level;
+ char *p;
+ int datalen;
{
log(LOG_INFO, 0, "ignoring DVMRP probe from %s to %s",
inet_fmt(src, s1), inet_fmt(dst, s2));
@@ -207,8 +249,8 @@ void accept_probe(src, dst)
/*
* Process an incoming route report message.
*/
-void accept_report(src, dst, p, datalen)
- u_long src, dst;
+void accept_report(src, dst, p, datalen, level)
+ u_int32 src, dst, level;
char *p;
int datalen;
{
@@ -221,7 +263,7 @@ void accept_report(src, dst, p, datalen)
* Process an incoming neighbor-list request message.
*/
void accept_neighbor_request(src, dst)
- u_long src, dst;
+ u_int32 src, dst;
{
if (src != our_addr)
log(LOG_INFO, 0,
@@ -230,7 +272,7 @@ void accept_neighbor_request(src, dst)
}
void accept_neighbor_request2(src, dst)
- u_long src, dst;
+ u_int32 src, dst;
{
if (src != our_addr)
log(LOG_INFO, 0,
@@ -243,7 +285,7 @@ void accept_neighbor_request2(src, dst)
* Process an incoming neighbor-list message.
*/
void accept_neighbors(src, dst, p, datalen, level)
- u_long src, dst, level;
+ u_int32 src, dst, level;
u_char *p;
int datalen;
{
@@ -254,12 +296,12 @@ void accept_neighbors(src, dst, p, datalen, level)
else if (node->tries == -1) /* follow alias link */
node = node->u.alias;
-#define GET_ADDR(a) (a = ((u_long)*p++ << 24), a += ((u_long)*p++ << 16),\
- a += ((u_long)*p++ << 8), a += *p++)
+#define GET_ADDR(a) (a = ((u_int32)*p++ << 24), a += ((u_int32)*p++ << 16),\
+ a += ((u_int32)*p++ << 8), a += *p++)
/* if node is running a recent mrouted, ask for additional info */
if (level != 0) {
- node->version = ntohl(level);
+ node->version = level;
node->tries = 0;
ask2(src);
return;
@@ -281,7 +323,7 @@ void accept_neighbors(src, dst, p, datalen, level)
}
while (datalen > 0) { /* loop through interfaces */
- u_long ifc_addr;
+ u_int32 ifc_addr;
u_char metric, threshold, ncount;
Node *ifc_node;
Interface *ifc;
@@ -360,7 +402,7 @@ void accept_neighbors(src, dst, p, datalen, level)
/* Add the neighbors for this interface */
while (ncount--) {
- u_long neighbor;
+ u_int32 neighbor;
Neighbor *nb;
Node *n_node;
@@ -403,8 +445,8 @@ void accept_neighbors(src, dst, p, datalen, level)
}
}
-void accept_neighbors2(src, dst, p, datalen)
- u_long src, dst;
+void accept_neighbors2(src, dst, p, datalen, level)
+ u_int32 src, dst, level;
u_char *p;
int datalen;
{
@@ -416,7 +458,7 @@ void accept_neighbors2(src, dst, p, datalen)
node = node->u.alias;
while (datalen > 0) { /* loop through interfaces */
- u_long ifc_addr;
+ u_int32 ifc_addr;
u_char metric, threshold, ncount, flags;
Node *ifc_node;
Interface *ifc;
@@ -428,7 +470,7 @@ void accept_neighbors2(src, dst, p, datalen)
return;
}
- ifc_addr = *(u_long*)p;
+ ifc_addr = *(u_int32*)p;
p += 4;
metric = *p++;
threshold = *p++;
@@ -495,8 +537,8 @@ void accept_neighbors2(src, dst, p, datalen)
old_neighbors = ifc->neighbors;
/* Add the neighbors for this interface */
- while (ncount--) {
- u_long neighbor;
+ while (ncount-- && datalen > 0) {
+ u_int32 neighbor;
Neighbor *nb;
Node *n_node;
@@ -506,7 +548,7 @@ void accept_neighbors2(src, dst, p, datalen)
return;
}
- neighbor = *(u_long*)p;
+ neighbor = *(u_int32*)p;
p += 4;
datalen -= 4;
if (neighbor == 0)
@@ -571,11 +613,11 @@ int retry_requests(node)
char *inet_name(addr)
- u_long addr;
+ u_int32 addr;
{
struct hostent *e;
- e = gethostbyaddr(&addr, sizeof(addr), AF_INET);
+ e = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET);
return e ? e->h_name : 0;
}
@@ -650,7 +692,7 @@ void print_map(node)
char *graph_name(addr, buf)
- u_long addr;
+ u_int32 addr;
char *buf;
{
char *name;
@@ -734,7 +776,7 @@ void elide_aliases(node)
void graph_map()
{
- u_long now = time(0);
+ time_t now = time(0);
char *nowstr = ctime(&now);
nowstr[24] = '\0'; /* Kill the newline at the end */
@@ -771,7 +813,7 @@ int get_number(var, deflt, pargv, pargc)
}
-u_long host_addr(name)
+u_int32 host_addr(name)
char *name;
{
struct hostent *e = gethostbyname(name);
@@ -789,7 +831,7 @@ u_long host_addr(name)
}
-main(argc, argv)
+int main(argc, argv)
int argc;
char *argv[];
{
@@ -862,6 +904,9 @@ main(argc, argv)
int addrlen = sizeof(addr);
addr.sin_family = AF_INET;
+#if (defined(BSD) && (BSD >= 199103))
+ addr.sin_len = sizeof addr;
+#endif
addr.sin_addr.s_addr = dvmrp_group;
addr.sin_port = htons(2000); /* any port over 1024 will do... */
if ((udp = socket(AF_INET, SOCK_DGRAM, 0)) < 0
@@ -912,7 +957,7 @@ main(argc, argv)
break;
}
- recvlen = recvfrom(igmp_socket, recv_buf, sizeof(recv_buf),
+ recvlen = recvfrom(igmp_socket, recv_buf, RECV_BUF_SIZE,
0, NULL, &dummy);
if (recvlen >= 0)
accept_igmp(recvlen);
@@ -933,21 +978,42 @@ main(argc, argv)
exit(0);
}
-void accept_prune()
+/* dummies */
+void accept_prune(src, dst, p, datalen)
+ u_int32 src, dst;
+ char *p;
+ int datalen;
+{
+}
+void accept_graft(src, dst, p, datalen)
+ u_int32 src, dst;
+ char *p;
+ int datalen;
{
}
-void accept_graft()
+void accept_g_ack(src, dst, p, datalen)
+ u_int32 src, dst;
+ char *p;
+ int datalen;
{
}
-void accept_g_ack()
+void add_table_entry(origin, mcastgrp)
+ u_int32 origin, mcastgrp;
{
}
-void add_table_entry()
+void accept_leave_message(src, dst, group)
+ u_int32 src, dst, group;
{
}
-void leave_group_message()
+void accept_mtrace(src, dst, group, data, no, datalen)
+ u_int32 src, dst, group;
+ char *data;
+ u_int no;
+ int datalen;
{
}
-void mtrace()
+void accept_membership_query(src, dst, group, tmo)
+ u_int32 src, dst, group;
+ int tmo;
{
}
diff --git a/usr.sbin/mrouted/mrinfo.8 b/usr.sbin/mrouted/mrinfo.8
index b1e7880bf8ae..1e7f9a91159a 100644
--- a/usr.sbin/mrouted/mrinfo.8
+++ b/usr.sbin/mrouted/mrinfo.8
@@ -1,92 +1,83 @@
-.Dd March 31, 1995
-.Dt MRINFO 8
-.Sh NAME
-.Nm mrinfo
-.Nd displays configuration info from a multicast router
-.Sh SYNOPSIS
-.Nm mrinfo
-.Op Fl d Ar debuglevel
-.Op Fl r Ar retries
-.Op Fl t Ar timeout
-.Ar router
-.Sh DESCRIPTION
-The
-.Nm mrinfo
-program attempts to display the configuration information from the
-multicast router
-.Ar router .
-.Pp
-.Nm
-uses the
-.Dv ASK_NEIGHBORS
-.Tn IGMP
-message to the specified multicast router. If this multicast router
-responds, the version number and a list of their neighboring multicast
-router addresses is part of that response. If the responding router
-has a recent multicast version number, then
-.Nm mrinfo
-requests additional information such as metrics, thresholds, and flags
-from the multicast router. Once the specified multicast router
-responds, the configuration is displayed to the standard output.
-.Pp
-The
-.Nm
-program accepts the following options:
-.Bl -tag -width XXXdebuglevel
-.It Fl d Ar debuglevel
-This option sets the debug level to
-.Ar debuglevel .
-When the debug level is greater than the default value of 0, addition
-debugging messages are printed. Regardless of the debug level, an
-error condition, will always write an error message and will cause
-.Nm
+.TH MRINFO 8
+.UC 5
+.SH NAME
+mrinfo \- Displays configuration info from a multicast router
+.SH SYNOPSIS
+.B /usr/sbin/mrinfo
+[
+.B \-d
+.I debug_level
+] [
+.B \-r
+.I retry_count
+] [
+.B \-t
+.I timeout_count
+]
+.B multicast_router
+
+.SH DESCRIPTION
+.I mrinfo
+attempts to display the configuration information from the multicast router
+.I multicast_router.
+.PP
+.I mrinfo
+uses the ASK_NEIGHBORS IGMP message to the specified multicast router. If this
+multicast router responds, the version number and a list of their neighboring
+multicast router addresses is part of that response. If the responding router
+has a recent multicast version number, then
+.I mrinfo
+requests additional information such as metrics, thresholds, and flags from the
+multicast router. Once the specified multicast router responds, the
+configuration is displayed to the standard output.
+.br
+.ne 5
+.SH INVOCATION
+.PP
+"\-d" option sets the debug level. When the debug level is greater than the
+default value of 0, addition debugging messages are printed. Regardless of
+the debug level, an error condition, will always write an error message and will
+cause
+.I mrinfo
to terminate.
Non-zero debug levels have the following effects:
-.Bl -tag -width "level 3"
-.It level 1
+.IP "level 1"
packet warnings are printed to stderr.
-.It level 2
+.IP "level 2"
all level 1 messages plus notifications down networks are printed to stderr.
-.It level 3
+.IP "level 3"
all level 2 messages plus notifications of all packet
timeouts are printed to stderr.
-.El
-.It Fl r Ar retries
-This option sets the neighbor query retry limit to
-.Ar retries .
-The default is three retries.
-.It Fl t Ar timeout
-This sets the number of seconds to wait for a neighbor query
-reply. The default timeout is four seconds.
-.El
-.Sh SAMPLE OUTPUT
-.Bd -literal
-# mrinfo mbone.phony.dom.net
+.PP
+"\-r retry_count" sets the neighbor query retry limit. Default is 3 retry.
+.PP
+"\-t timeout_count" sets the number of seconds to wait for a neighbor query
+reply. Default timeout is 4 seconds.
+.PP
+.SH SAMPLE OUTPUT
+.nf
+.I mrinfo mbone.phony.dom.net
127.148.176.10 (mbone.phony.dom.net) [version 3.3]:
127.148.176.10 -> 0.0.0.0 (?) [1/1/querier]
127.148.176.10 -> 127.0.8.4 (mbone2.phony.dom.net) [1/45/tunnel]
127.148.176.10 -> 105.1.41.9 (momoney.com) [1/32/tunnel/down]
127.148.176.10 -> 143.192.152.119 (mbone.dipu.edu) [1/32/tunnel]
-.Ed
-.Pp
-For each neighbor of the queried multicast router, the IP of the
-queried router is displayed, followed by the IP and name of the
-neighbor. In square brackets the metric (cost of connection) and the
-threshold (minimum TTL to forward) are displayed. If the queried multicast
-router has a newer version number, the type (tunnel, srcrt) and status
-(disabled, down) of the connection are also displayed.
-.Sh RESTRICTIONS
-.Nm
-must be run as `root'.
-.Sh SEE ALSO
-.Xr map-mbone 8 ,
-.Xr mrouted 8 ,
-.Xr mtrace 8
-.Sh AUTHOR
-Pavel Curtis
-.Sh HISTORY
-An
-.Nm
-command first appeared in
-.Tn FreeBSD
-2.0.
+.fi
+.PP
+For each neighbor of the queried multicast router, the IP of the queried router
+is displayed, followed by the IP and name of the neighbor. In square brackets
+the metric (cost of connection), the treashold (multicast ttl) is displayed. If
+the queried multicast router has a newer version number, the type (tunnel,
+srcrt) and status (disabled, down) of the connection is displayed.
+.PP
+.SH IMPORTANT NOTE
+.I mrinfo
+must be run as root.
+.PP
+.SH SEE ALSO
+.BR mrouted (8) ,
+.BR map-mbone (8) ,
+.BR mtrace (8)
+.PP
+.SH AUTHOR
+Van Jacobson
diff --git a/usr.sbin/mrouted/mrinfo.c b/usr.sbin/mrouted/mrinfo.c
index d774cdfa5eaa..f4ccc86eb6d8 100644
--- a/usr.sbin/mrouted/mrinfo.c
+++ b/usr.sbin/mrouted/mrinfo.c
@@ -61,7 +61,7 @@
#ifndef lint
static char rcsid[] =
- "@(#) $Id: mrinfo.c,v 1.7 1994/08/24 23:54:04 thyagara Exp $";
+ "@(#) $Id: mrinfo.c,v 3.6 1995/06/25 19:05:34 fenner Exp $";
/* original rcsid:
"@(#) Header: mrinfo.c,v 1.6 93/04/08 15:14:16 van Exp (LBL)";
*/
@@ -70,27 +70,53 @@ static char rcsid[] =
#include <netdb.h>
#include <sys/time.h>
#include "defs.h"
+#include <arpa/inet.h>
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
#define DEFAULT_TIMEOUT 4 /* How long to wait before retrying requests */
#define DEFAULT_RETRIES 3 /* How many times to ask each router */
-u_long our_addr, target_addr = 0; /* in NET order */
+u_int32 our_addr, target_addr = 0; /* in NET order */
int debug = 0;
+int nflag = 0;
int retries = DEFAULT_RETRIES;
int timeout = DEFAULT_TIMEOUT;
-int target_level;
+int target_level = 0;
vifi_t numvifs; /* to keep loader happy */
/* (see COPY_TABLES macro called in kern.c) */
+char * inet_name __P((u_int32 addr));
+void ask __P((u_int32 dst));
+void ask2 __P((u_int32 dst));
+int get_number __P((int *var, int deflt, char ***pargv,
+ int *pargc));
+u_int32 host_addr __P((char *name));
+void usage __P((void));
+
+/* to shut up -Wstrict-prototypes */
+int main __P((int argc, char *argv[]));
+
+
char *
inet_name(addr)
- u_long addr;
+ u_int32 addr;
{
struct hostent *e;
+ struct in_addr in;
- e = gethostbyaddr(&addr, sizeof(addr), AF_INET);
+ if (addr == 0)
+ return "local";
- return e ? e->h_name : "?";
+ if (nflag ||
+ (e = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET)) == NULL) {
+ in.s_addr = addr;
+ return (inet_ntoa(in));
+ }
+ return (e->h_name);
}
/*
@@ -98,14 +124,26 @@ inet_name(addr)
* 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;
+ char fmt[100];
+
+ va_start(ap, format);
+#else
void
-log(severity, syserr, format, a, b, c, d, e)
+log(severity, syserr, format, va_alist)
int severity, syserr;
char *format;
- int a, b, c, d, e;
+ va_dcl
{
+ va_list ap;
char fmt[100];
+ va_start(ap);
+#endif
switch (debug) {
case 0:
if (severity > LOG_WARNING)
@@ -121,7 +159,7 @@ log(severity, syserr, format, a, b, c, d, e)
if (severity == LOG_WARNING)
strcat(fmt, "warning - ");
strncat(fmt, format, 80);
- fprintf(stderr, fmt, a, b, c, d, e);
+ vfprintf(stderr, fmt, ap);
if (syserr == 0)
fprintf(stderr, "\n");
else if (syserr < sys_nerr)
@@ -139,7 +177,7 @@ log(severity, syserr, format, a, b, c, d, e)
*/
void
ask(dst)
- u_long dst;
+ u_int32 dst;
{
send_igmp(our_addr, dst, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS,
htonl(MROUTED_LEVEL), 0);
@@ -147,7 +185,7 @@ ask(dst)
void
ask2(dst)
- u_long dst;
+ u_int32 dst;
{
send_igmp(our_addr, dst, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS2,
htonl(MROUTED_LEVEL), 0);
@@ -157,18 +195,18 @@ ask2(dst)
* Process an incoming neighbor-list message.
*/
void
-accept_neighbors(src, dst, p, datalen)
- u_long src, dst;
- u_char *p;
+accept_neighbors(src, dst, p, datalen, level)
+ u_int32 src, dst, level;
+ u_char *p;
int datalen;
{
u_char *ep = p + datalen;
-#define GET_ADDR(a) (a = ((u_long)*p++ << 24), a += ((u_long)*p++ << 16),\
- a += ((u_long)*p++ << 8), a += *p++)
+#define GET_ADDR(a) (a = ((u_int32)*p++ << 24), a += ((u_int32)*p++ << 16),\
+ a += ((u_int32)*p++ << 8), a += *p++)
printf("%s (%s):\n", inet_fmt(src, s1), inet_name(src));
while (p < ep) {
- register u_long laddr;
+ register u_int32 laddr;
register u_char metric;
register u_char thresh;
register int ncount;
@@ -179,7 +217,7 @@ accept_neighbors(src, dst, p, datalen)
thresh = *p++;
ncount = *p++;
while (--ncount >= 0) {
- register u_long neighbor;
+ register u_int32 neighbor;
GET_ADDR(neighbor);
neighbor = htonl(neighbor);
printf(" %s -> ", inet_fmt(laddr, s1));
@@ -190,29 +228,36 @@ accept_neighbors(src, dst, p, datalen)
}
void
-accept_neighbors2(src, dst, p, datalen)
- u_long src, dst;
- u_char *p;
+accept_neighbors2(src, dst, p, datalen, level)
+ u_int32 src, dst, level;
+ u_char *p;
int datalen;
{
u_char *ep = p + datalen;
+ u_int broken_cisco = ((level & 0xffff) == 0x020a); /* 10.2 */
+ /* well, only possibly_broken_cisco, but that's too long to type. */
printf("%s (%s) [version %d.%d]:\n", inet_fmt(src, s1), inet_name(src),
- target_level & 0xff, (target_level >> 8) & 0xff);
+ level & 0xff, (level >> 8) & 0xff);
+
while (p < ep) {
register u_char metric;
register u_char thresh;
register u_char flags;
register int ncount;
- register u_long laddr = *(u_long*)p;
+ register u_int32 laddr = *(u_int32*)p;
p += 4;
metric = *p++;
thresh = *p++;
flags = *p++;
ncount = *p++;
- while (--ncount >= 0) {
- register u_long neighbor = *(u_long*)p;
+ if (broken_cisco && ncount == 0) /* dumb Ciscos */
+ ncount = 1;
+ if (broken_cisco && ncount > 15) /* dumb Ciscos */
+ ncount = ncount & 0xf;
+ while (--ncount >= 0 && p < ep) {
+ register u_int32 neighbor = *(u_int32*)p;
p += 4;
printf(" %s -> ", inet_fmt(laddr, s1));
printf("%s (%s) [%d/%d", inet_fmt(neighbor, s1),
@@ -221,12 +266,16 @@ accept_neighbors2(src, dst, p, datalen)
printf("/tunnel");
if (flags & DVMRP_NF_SRCRT)
printf("/srcrt");
+ if (flags & DVMRP_NF_PIM)
+ printf("/pim");
if (flags & DVMRP_NF_QUERIER)
printf("/querier");
if (flags & DVMRP_NF_DISABLED)
printf("/disabled");
if (flags & DVMRP_NF_DOWN)
printf("/down");
+ if (flags & DVMRP_NF_LEAF)
+ printf("/leaf");
printf("]\n");
}
}
@@ -258,33 +307,44 @@ get_number(var, deflt, pargv, pargc)
}
}
-u_long
+u_int32
host_addr(name)
char *name;
{
- struct hostent *e = gethostbyname(name);
- int addr;
+ struct hostent *e;
+ u_int32 addr;
- if (e)
+ addr = inet_addr(name);
+ if ((int)addr == -1) {
+ e = gethostbyname(name);
+ if (e == NULL || e->h_length != sizeof(addr))
+ return (0);
memcpy(&addr, e->h_addr_list[0], e->h_length);
- else {
- addr = inet_addr(name);
- if (addr == -1)
- addr = 0;
}
-
- return addr;
+ return(addr);
}
+void
+usage()
+{
+ fprintf(stderr,
+ "Usage: mrinfo [-n] [-t timeout] [-r retries] [router]\n");
+ exit(1);
+}
+int
main(argc, argv)
int argc;
char *argv[];
{
+ int tries = 0;
+ int trynew = 1;
+ struct timeval et;
+
setlinebuf(stderr);
if (geteuid() != 0) {
- fprintf(stderr, "must be root\n");
+ fprintf(stderr, "mrinfo: must be root\n");
exit(1);
}
argv++, argc--;
@@ -292,29 +352,35 @@ main(argc, argv)
switch (argv[0][1]) {
case 'd':
if (!get_number(&debug, DEFAULT_DEBUG, &argv, &argc))
- goto usage;
+ usage();
+ break;
+ case 'n':
+ ++nflag;
break;
case 'r':
if (!get_number(&retries, -1, &argv, &argc))
- goto usage;
+ usage();
break;
case 't':
if (!get_number(&timeout, -1, &argv, &argc))
- goto usage;
+ usage();
break;
default:
- goto usage;
+ usage();
}
argv++, argc--;
}
-
- if (argc > 1 || (argc == 1 && !(target_addr = host_addr(argv[0])))) {
-usage: fprintf(stderr,
- "Usage: mrinfo [-t timeout] [-r retries] router\n");
+ if (argc > 1)
+ usage();
+ if (argc == 1)
+ target_addr = host_addr(argv[0]);
+ else
+ target_addr = host_addr("127.0.0.1");
+
+ if (target_addr == 0) {
+ fprintf(stderr, "mrinfo: %s: no such host\n", argv[0]);
exit(1);
}
- if (target_addr == 0)
- goto usage;
if (debug)
fprintf(stderr, "Debug level %u\n", debug);
@@ -326,6 +392,9 @@ usage: fprintf(stderr,
int addrlen = sizeof(addr);
addr.sin_family = AF_INET;
+#if (defined(BSD) && (BSD >= 199103))
+ addr.sin_len = sizeof addr;
+#endif
addr.sin_addr.s_addr = target_addr;
addr.sin_port = htons(2000); /* any port over 1024 will
* do... */
@@ -339,14 +408,22 @@ usage: fprintf(stderr,
our_addr = addr.sin_addr.s_addr;
}
- ask(target_addr);
+ /*
+ * New strategy: send 'ask2' for two timeouts, then fall back
+ * to 'ask', since it's not very likely that we are going to
+ * find someone who only responds to 'ask' these days
+ */
+ ask2(target_addr);
+
+ gettimeofday(&et, 0);
+ et.tv_sec += timeout;
/* Main receive loop */
for (;;) {
fd_set fds;
- struct timeval tv;
+ struct timeval tv, now;
int count, recvlen, dummy = 0;
- register u_long src, dst, group;
+ register u_int32 src, dst, group;
struct ip *ip;
struct igmp *igmp;
int ipdatalen, iphdrlen, igmpdatalen;
@@ -354,8 +431,16 @@ usage: fprintf(stderr,
FD_ZERO(&fds);
FD_SET(igmp_socket, &fds);
- tv.tv_sec = timeout;
- tv.tv_usec = 0;
+ gettimeofday(&now, 0);
+ tv.tv_sec = et.tv_sec - now.tv_sec;
+ tv.tv_usec = et.tv_usec - now.tv_usec;
+
+ if (tv.tv_usec < 0) {
+ tv.tv_usec += 1000000L;
+ --tv.tv_sec;
+ }
+ if (tv.tv_sec < 0)
+ tv.tv_sec = tv.tv_usec = 0;
count = select(igmp_socket + 1, &fds, 0, 0, &tv);
@@ -365,15 +450,20 @@ usage: fprintf(stderr,
continue;
} else if (count == 0) {
log(LOG_DEBUG, 0, "Timed out receiving neighbor lists");
- if (--retries < 0)
+ if (++tries > retries)
exit(1);
- if (target_level == 0)
+ /* If we've tried ASK_NEIGHBORS2 twice with
+ * no response, fall back to ASK_NEIGHBORS
+ */
+ if (tries == 2 && target_level == 0)
+ trynew = 0;
+ if (target_level == 0 && trynew == 0)
ask(target_addr);
else
ask2(target_addr);
continue;
}
- recvlen = recvfrom(igmp_socket, recv_buf, sizeof(recv_buf),
+ recvlen = recvfrom(igmp_socket, recv_buf, RECV_BUF_SIZE,
0, NULL, &dummy);
if (recvlen <= 0) {
if (recvlen && errno != EINTR)
@@ -388,14 +478,9 @@ usage: fprintf(stderr,
continue;
}
ip = (struct ip *) recv_buf;
+ if (ip->ip_p == 0)
+ continue; /* Request to install cache entry */
src = ip->ip_src.s_addr;
- if (src != target_addr) {
- fprintf(stderr, "mrinfo: got reply from %s",
- inet_fmt(src, s1));
- fprintf(stderr, " instead of %s\n",
- inet_fmt(target_addr, s1));
- continue;
- }
dst = ip->ip_dst.s_addr;
iphdrlen = ip->ip_hl << 2;
ipdatalen = ip->ip_len;
@@ -418,6 +503,21 @@ usage: fprintf(stderr,
continue;
switch (igmp->igmp_code) {
+ case DVMRP_NEIGHBORS:
+ case DVMRP_NEIGHBORS2:
+ if (src != target_addr) {
+ fprintf(stderr, "mrinfo: got reply from %s",
+ inet_fmt(src, s1));
+ fprintf(stderr, " instead of %s\n",
+ inet_fmt(target_addr, s1));
+ /*continue;*/
+ }
+ break;
+ default:
+ continue; /* ignore all other DVMRP messages */
+ }
+
+ switch (igmp->igmp_code) {
case DVMRP_NEIGHBORS:
if (group) {
@@ -427,54 +527,84 @@ usage: fprintf(stderr,
ask2(target_addr);
}
} else {
- accept_neighbors(src, dst, (char *)(igmp + 1),
- igmpdatalen);
+ accept_neighbors(src, dst, (u_char *)(igmp + 1),
+ igmpdatalen, ntohl(group));
exit(0);
}
break;
case DVMRP_NEIGHBORS2:
- accept_neighbors2(src, dst, (char *)(igmp + 1),
- igmpdatalen);
+ accept_neighbors2(src, dst, (u_char *)(igmp + 1),
+ igmpdatalen, ntohl(group));
exit(0);
}
}
}
/* dummies */
-void accept_probe()
+void accept_probe(src, dst, p, datalen, level)
+ u_int32 src, dst, level;
+ char *p;
+ int datalen;
{
}
-void accept_group_report()
+void accept_group_report(src, dst, group, r_type)
+ u_int32 src, dst, group;
+ int r_type;
{
}
-void accept_neighbor_request2()
+void accept_neighbor_request2(src, dst)
+ u_int32 src, dst;
{
}
-void accept_report()
+void accept_report(src, dst, p, datalen, level)
+ u_int32 src, dst, level;
+ char *p;
+ int datalen;
{
}
-void accept_neighbor_request()
+void accept_neighbor_request(src, dst)
+ u_int32 src, dst;
{
}
-void accept_prune()
+void accept_prune(src, dst, p, datalen)
+ u_int32 src, dst;
+ char *p;
+ int datalen;
{
}
-void accept_graft()
+void accept_graft(src, dst, p, datalen)
+ u_int32 src, dst;
+ char *p;
+ int datalen;
{
}
-void accept_g_ack()
+void accept_g_ack(src, dst, p, datalen)
+ u_int32 src, dst;
+ char *p;
+ int datalen;
{
}
-void add_table_entry()
+void add_table_entry(origin, mcastgrp)
+ u_int32 origin, mcastgrp;
{
}
void check_vif_state()
{
}
-void leave_group_message()
+void accept_leave_message(src, dst, group)
+ u_int32 src, dst, group;
+{
+}
+void accept_mtrace(src, dst, group, data, no, datalen)
+ u_int32 src, dst, group;
+ char *data;
+ u_int no;
+ int datalen;
{
}
-void mtrace()
+void accept_membership_query(src, dst, group, tmo)
+ u_int32 src, dst, group;
+ int tmo;
{
}
diff --git a/usr.sbin/mrouted/mrouted.8 b/usr.sbin/mrouted/mrouted.8
index 5b9ee969a4d7..7dae5e38b2c6 100644
--- a/usr.sbin/mrouted/mrouted.8
+++ b/usr.sbin/mrouted/mrouted.8
@@ -1,4 +1,5 @@
'\"COPYRIGHT 1989 by The Board of Trustees of Leland Stanford Junior University.
+'\"$Id: mrouted.8,v 3.6 1995/06/25 19:10:58 fenner Exp $
.TH MROUTED 8
.UC 5
.SH NAME
@@ -50,8 +51,7 @@ Older versions of
.I mrouted
tunnel using IP source routing, which puts a heavy load on some
types of routers.
-This version supports IP source route tunnelling only for backwards
-compatibility.
+This version does not support IP source route tunnelling.
.PP
The tunnelling mechanism allows
.I mrouted
@@ -94,6 +94,8 @@ events are printed to stderr.
.IP "level 3"
all level 2 messages plus notifications of all packet
arrivals and departures are printed to stderr.
+.PP
+Upon startup, mrouted writes its pid to the file /etc/mrouted.pid .
.SH CONFIGURATION
.PP
.I Mrouted
@@ -112,38 +114,46 @@ There are four types of configuration commands:
phyint <local-addr> [disable] [metric <m>]
[threshold <t>] [rate_limit <b>]
- [boundary <scoped-addr>/<mask-len>]
+ [boundary (<boundary-name>|<scoped-addr>/<mask-len>)]
+ [altnet <network>/<mask-len>]
tunnel <local-addr> <remote-addr> [metric <m>]
- [threshold <t>] [srcrt] [rate_limit <b>]
- [boundary <scoped-addr>/<mask-len>]
+ [threshold <t>] [rate_limit <b>]
+ [boundary (<boundary-name>|<scoped-addr>/<mask-len>)]
cache_lifetime <ct>
pruning <off/on>
+ name <boundary-name> <scoped-addr>/<mask-len>
+
.fi
.PP
-One note about the configuration commands - all the phyint and tunnel
-command options must be on a single line except for the boundary option
-which may begin on a separate line. A single phyint or tunnel command may
-have multiple boundary options.
+The file format is free-form; whitespace (including newlines) is not
+significant.
+The
+.I boundary
+and
+.I altnet
+options may be specified as many times as necessary.
.PP
The phyint command can be used to disable multicast routing on the physical
interface identified by local IP address <local-addr>, or to associate a
non-default metric or threshold with the specified physical interface.
The local IP address <local-addr> may be alternatively replaced by the
-interface name (e.g le0) for the phyint command only.
+interface name (e.g le0).
+If a phyint is attached to multiple IP subnets, describe each additional subnet
+with the altnet keyword.
Phyint commands must precede tunnel commands.
.PP
The tunnel command can be used to establish a tunnel link between local
IP address <local-addr> and remote IP address <remote-addr>, and to associate
a non-default metric or threshold with that tunnel. The tunnel must be set
up in the mrouted.conf files of both routers before it can be used.
-For backwards compatibility with older
-.IR mrouted s,
-the srcrt keyword specifies
-encapsulation using IP source routing.
+'\"For backwards compatibility with older
+'\".IR mrouted s,
+'\"the srcrt keyword specifies
+'\"encapsulation using IP source routing.
.PP
The cache_lifetime is a value that determines the amount of time that a
cached multicast route stays in kernel before timing out. The value of this
@@ -152,11 +162,15 @@ entry should lie between 300 (5 min) and 86400 (1 day). It defaults to 300.
The pruning <off/on> option is provided for
.IR mrouted
to act as a non-pruning router. It is also possible to start
-.Ir mrouted
+.IR mrouted
in a non-pruning mode using the "-p" option on the command line. It is
expected that a router would be configured in this manner for test
purposes only. The default mode is pruning enabled.
.PP
+You may assign names to boundaries to make configuration easier with
+the name keyword. The boundary option on phyint or tunnel commands
+can accept either a name or a boundary.
+.PP
The metric is the "cost" associated with sending a datagram on the given
interface or tunnel; it may be used to influence the choice of routes.
The metric defaults to 1. Metrics should be kept as small as possible,
@@ -178,12 +192,14 @@ use the same metric and threshold for that subnet or tunnel.
.PP
The rate_limit option allows the network administrator to specify a
certain bandwidth in Kbits/second which would be allocated to multicast
-traffic.
+traffic. It defaults to 500Kbps on tunnels, and 0 (unlimited) on physical
+interfaces.
.PP
The boundary option allows an interface
to be configured as an administrative boundary for the specified
scoped address. Packets belonging to this address will not
-be forwarded on a scoped interface.
+be forwarded on a scoped interface. The boundary option accepts either
+a name or a boundary spec.
.PP
.I Mrouted
will not initiate execution if it has fewer than two enabled vifs,
@@ -193,6 +209,45 @@ tunnels; such an
.I mrouted
configuration would be better replaced by more
direct tunnels (i.e., eliminate the middle man).
+.SH "EXAMPLE CONFIGURATION"
+.PP
+This is an example configuration for a mythical multicast router at a big
+school.
+.sp
+.nf
+#
+# mrouted.conf example
+#
+# Name our boundaries to make it easier
+name LOCAL 239.255.0.0/16
+name EE 239.254.0.0/16
+#
+# le1 is our gateway to compsci, don't forward our
+# local groups to them
+phyint le1 boundary EE
+#
+# le2 is our interface on the classroom net, it has four
+# different length subnets on it.
+# note that you can use either an ip address or an
+# interface name
+phyint 172.16.12.38 boundary EE altnet 172.16.15.0/26
+ altnet 172.16.15.128/26 altnet 172.16.48.0/24
+#
+# atm0 is our ATM interface, which doesn't properly
+# support multicasting.
+phyint atm0 disable
+#
+# This is an internal tunnel to another EE subnet
+# Remove the default tunnel rate limit, since this
+# tunnel is over ethernets
+tunnel 192.168.5.4 192.168.55.101 metric 1 threshold 1
+ rate_limit 0
+#
+# This is our tunnel to the outside world.
+# Careful with those boundaries, Eugene.
+tunnel 192.168.5.4 10.11.12.13 metric 1 threshold 32
+ boundary LOCAL boundary EE
+.fi
.SH SIGNALS
.PP
.I Mrouted
@@ -214,6 +269,10 @@ dumps the internal cache tables to /usr/tmp/mrouted.cache.
dumps the internal routing tables to stderr (only if
.I mrouted
was invoked with a non-zero debug level).
+.PP
+For convenience in sending signals,
+.I mrouted
+writes its pid to /etc/mrouted.pid upon startup.
.bp
.SH EXAMPLE
.PP
@@ -245,10 +304,10 @@ Virtual Interface Table
3 36.2.0.8 tunnel: 36.6.8.23 3 16
Multicast Routing Table (1136 entries)
- Origin-Subnet From-Gateway Metric In-Vif Out-Vifs
- 36.2 1 0 1* 2 3*
- 36.8 36.8.0.77 4 2 0* 1* 3*
- 36.11 1 1 0* 2 3*
+ Origin-Subnet From-Gateway Metric Tmr In-Vif Out-Vifs
+ 36.2 1 45 0 1* 2 3*
+ 36.8 36.8.0.77 4 15 2 0* 1* 3*
+ 36.11 1 20 1 0* 2 3*
.
.
.
@@ -267,7 +326,8 @@ shown at each interface.
.PP
Associated with each subnet from which a multicast datagram can originate
is the address of the previous hop router (unless the subnet is directly-
-connected), the metric of the path back to the origin, the incoming vif for
+connected), the metric of the path back to the origin, the amount of time
+since we last received an update for this subnet, the incoming vif for
multicasts from that origin, and a list of outgoing vifs. "*" means that
the outgoing vif is connected to a leaf of the broadcast tree rooted at the
origin, and a multicast datagram from that origin will be forwarded on that
@@ -282,38 +342,58 @@ are created and deleted by
The cache tables look like this:
.nf
-Multicast Routing Cache Table (325 entries)
- Origin-Subnet Mcast-group CTmr IVif Prcv# Psnt Forwvifs
- 134.207.7 224.2.140.239 300 1 0 0 2
- 138.15.103 224.2.203.214 295 1 2 P 0p 2p
- 128.237.0 224.2.253.119 290 1 1 0 2p
- 129.215.200 224.2.207.48 40 1 1 0p 2
- 36.77.14 239.0.1.234 345 2b
+Multicast Routing Cache Table (147 entries)
+ Origin Mcast-group CTmr Age Ptmr IVif Forwvifs
+ 13.2.116/22 224.2.127.255 3m 2m - 0 1
+>13.2.116.19
+>13.2.116.196
+ 138.96.48/21 224.2.127.255 5m 2m - 0 1
+>138.96.48.108
+ 128.9.160/20 224.2.127.255 3m 2m - 0 1
+>128.9.160.45
+ 198.106.194/24 224.2.135.190 9m 28s 9m 0P
+>198.106.194.22
.fi
-Each entry is characterized by the origin subnet number and the
+Each entry is characterized by the origin subnet number and mask and the
destination multicast group. The 'CTmr' field indicates the lifetime
-(in seconds) of the entry. The entry is deleted from the cache table
-when the timer decrements to zero. The Ivif field indicates the
+of the entry. The entry is deleted from the cache table
+when the timer decrements to zero. The 'Age' field is the time since
+this cache entry was originally created. Since cache entries get refreshed
+if traffic is flowing, routing entries can grow very old.
+The 'Ptmr' field is simply a dash if no prune was sent upstream, or the
+amount of time until the upstream prune will time out.
+The 'Ivif' field indicates the
incoming vif for multicast packets from that origin. Each router also
-maintains a record of the number of prunes received from neighbouring
+maintains a record of the number of prunes received from neighboring
routers for a particular source and group. If there are no members of
a multicast group on any downward link of the multicast tree for a
subnet, a prune message is sent to the upstream router. They are
-indicated by a "P" in the Psnt field. The Forwvifs field shows the
+indicated by a "P" after the vif number. The Forwvifs field shows the
interfaces along which datagrams belonging to the source-group are
forwarded. A "p" indicates that no datagrams are being forwarded along
that interface. An unlisted interface is a leaf subnet with are no
members of the particular group on that subnet. A "b" on an interface
indicates that it is a boundary interface, i.e. traffic will not be
forwarded on the scoped address on that interface.
-
-
+An additional line with a ">" as the first character is printed for
+each source on the subnet. Note that there can be many sources in
+one subnet.
.SH FILES
/etc/mrouted.conf
+.br
+/etc/mrouted.pid
+.br
+/usr/tmp/mrouted.dump
+.br
+/usr/tmp/mrouted.cache
.SH SEE ALSO
+.BR mrinfo (8) ,
+.BR mtrace (8) ,
+.BR map-mbone (8)
+.sp
DVMRP is described, along with other multicast routing algorithms, in the
paper "Multicast Routing in Internetworks and Extended LANs" by S. Deering,
in the Proceedings of the ACM SIGCOMM '88 Conference.
.SH AUTHORS
-Steve Deering & Ajit Thyagarajan
+Steve Deering, Ajit Thyagarajan, Bill Fenner
diff --git a/usr.sbin/mrouted/mrouted.conf b/usr.sbin/mrouted/mrouted.conf
index 5340bfcd0a6d..4962d68e71f8 100644
--- a/usr.sbin/mrouted/mrouted.conf
+++ b/usr.sbin/mrouted/mrouted.conf
@@ -1,26 +1,37 @@
-# $Id: mrouted.conf,v 1.5 1994/08/24 23:54:21 thyagara Exp $
+# $Id: mrouted.conf,v 3.6 1995/06/25 19:11:55 fenner Exp $
#
# This is the configuration file for "mrouted", an IP multicast router.
# mrouted looks for it in "/etc/mrouted.conf".
#
# Command formats:
#
-# cache_lifetime 3600
+# name <boundname> <scoped-addr>/<mask-len>
+# cache_lifetime 3600 # seconds
# pruning on
#
# phyint <local-addr> [disable] [metric <m>] [threshold <t>] [rate_limit <b>]
-# [boundary <scoped-addr>/<mask-len>]
+# [boundary (<boundname>|<scoped-addr>/<mask-len>)]
+# [altnet (<subnet>/<mask-len>|<subnet>)]
# tunnel <local-addr> <remote-addr> [srcrt] [metric <m>]
# [threshold <t>] [rate_limit <b>]
-# [boundary <scoped-addr>/<mask-len>]
+# [boundary (<boundname>|<scoped-addr>/<mask-len>)]
#
# NOTE: any phyint commands MUST precede any tunnel commands
-# NOTE: boundary commands may appear on a separate line
-# (OTHER keywords must be on the same line as phyint or tunnel)
# NOTE: the mask-len is the no. of leading 1's in the mask
+# NOTE: rate_limit is in kilobits, and defaults to 500 for tunnels
#
-
-phyint 128.4.2.2 metric 1 threshold 16 boundary 239.2.0.0/16
- boundary 239.5.8.0/24
-tunnel 128.4.0.77 128.4.0.8 metric 3 rate_limit 500 # <-- EXAMPLE
- boundary 239.2.3.3/16 # 239.2.x.x is scoped
+# Example of named bounary:
+#name LOCAL 239.255.0.0/16
+#name EE 239.254.0.0/16 # i.e. the EE dept wants local groups
+#
+# Example of use of named boundary
+#phyint le1 boundary EE # le1 is our interface to comp sci,
+# # keep them away from our local groups
+#
+#
+# Template tunnel for mcast_install
+tunnel 128.4.0.77 128.4.0.8 metric 1 threshold 64 rate_limit 500 # <-- REPLACE
+# boundary LOCAL
+#
+# You might want to specify a boundary on your tunnel to the outside world,
+# as above.
diff --git a/usr.sbin/mrouted/mtrace.8 b/usr.sbin/mrouted/mtrace.8
index bfc6dd54135c..c4ac21866af7 100644
--- a/usr.sbin/mrouted/mtrace.8
+++ b/usr.sbin/mrouted/mtrace.8
@@ -29,7 +29,7 @@
.\" Copyright (c) 1988 The Regents of the University of California.
.\" All rights reserved.
.\"
-.\" $Id: mtrace.8,v 3.5 1995/05/09 01:23:58 fenner Exp $
+.\" $Id: mtrace.8,v 3.6 1995/06/25 19:14:07 fenner Exp $
.\"
.TH MTRACE 8 "May 8, 1995"
.UC 6
@@ -62,7 +62,6 @@ mtrace \- print multicast path from a source to a receiver
.I resp_dest
] [
.B \-s
-.I src_addr
] [
.B \-t
.I ttl
diff --git a/usr.sbin/mrouted/mtrace.c b/usr.sbin/mrouted/mtrace.c
index 9bee6b248e52..321b2693092d 100644
--- a/usr.sbin/mrouted/mtrace.c
+++ b/usr.sbin/mrouted/mtrace.c
@@ -1,226 +1,1064 @@
+/*
+ * mtrace.c
+ *
+ * This tool traces the branch of a multicast tree from a source to a
+ * receiver for a particular multicast group and gives statistics
+ * about packet rate and loss for each hop along the path. It can
+ * usually be invoked just as
+ *
+ * mtrace source
+ *
+ * to trace the route from that source to the local host for a default
+ * group when only the route is desired and not group-specific packet
+ * counts. See the usage line for more complex forms.
+ *
+ *
+ * Released 4 Apr 1995. This program was adapted by Steve Casner
+ * (USC/ISI) from a prototype written by Ajit Thyagarajan (UDel and
+ * Xerox PARC). It attempts to parallel in command syntax and output
+ * format the unicast traceroute program written by Van Jacobson (LBL)
+ * for the parts where that makes sense.
+ *
+ * Copyright (c) 1995 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 non-commercial 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, Information
+ * Sciences Institute. The name of the University may not be used to
+ * endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THE UNIVERSITY OF SOUTHERN CALIFORNIA makes no 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.
+ *
+ * Other copyrights might apply to parts of this software and are so
+ * noted when applicable.
+ *
+ * In particular, parts of the prototype version of this program may
+ * have been derived from mrouted programs sources covered by the
+ * license in the accompanying file named "LICENSE".
+ *
+ * $Id: mtrace.c,v 3.6 1995/06/25 19:17:14 fenner Exp $
+ */
+
#include <netdb.h>
#include <sys/time.h>
+#include <sys/filio.h>
+#include <memory.h>
+#include <string.h>
+#include <ctype.h>
#include "defs.h"
+#include <arpa/inet.h>
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+#define DEFAULT_TIMEOUT 3 /* How long to wait before retrying requests */
+#define DEFAULT_RETRIES 3 /* How many times to try */
+#define MAXHOPS UNREACHABLE /* Don't need more hops than max metric */
+#define UNICAST_TTL 255 /* TTL for unicast response */
+#define MULTICAST_TTL1 64 /* Default TTL for multicast query/response */
+#define MULTICAST_TTL_INC 32 /* TTL increment for increase after timeout */
+#define MULTICAST_TTL_MAX 192 /* Maximum TTL allowed (protect low-BW links */
+
+struct resp_buf {
+ u_long qtime; /* Time query was issued */
+ u_long rtime; /* Time response was received */
+ int len; /* Number of reports or length of data */
+ struct igmp igmp; /* IGMP header */
+ union {
+ struct {
+ struct tr_query q; /* Query/response header */
+ struct tr_resp r[MAXHOPS]; /* Per-hop reports */
+ } t;
+ char d[MAX_DVMRP_DATA_LEN]; /* Neighbor data */
+ } u;
+} base, incr[2];
+
+#define qhdr u.t.q
+#define resps u.t.r
+#define ndata u.d
-#define DEFAULT_TIMEOUT 10 /* How long to wait before retrying requests */
+char names[MAXHOPS][40];
-int timeout = DEFAULT_TIMEOUT;
+int timeout = DEFAULT_TIMEOUT;
+int nqueries = DEFAULT_RETRIES;
+int numeric = FALSE;
+int debug = 0;
+int passive = FALSE;
+int multicast = FALSE;
+
+u_int32 defgrp; /* Default group if not specified */
+u_int32 query_cast; /* All routers multicast addr */
+u_int32 resp_cast; /* Mtrace response multicast addr */
+
+u_int32 lcl_addr = 0; /* This host address, in NET order */
+u_int32 dst_netmask; /* netmask to go with qdst */
+
+/*
+ * Query/response parameters, all initialized to zero and set later
+ * to default values or from options.
+ */
+u_int32 qsrc = 0; /* Source address in the query */
+u_int32 qgrp = 0; /* Group address in the query */
+u_int32 qdst = 0; /* Destination (receiver) address in query */
+u_char qno = 0; /* Max number of hops to query */
+u_int32 raddr = 0; /* Address where response should be sent */
+int qttl = 0; /* TTL for the query packet */
+u_char rttl = 0; /* TTL for the response packet */
+u_int32 gwy = 0; /* User-supplied last-hop router address */
+u_int32 tdst = 0; /* Address where trace is sent (last-hop) */
vifi_t numvifs; /* to keep loader happy */
- /* (see COPY_TABLES macro called in kern.c) */
+ /* (see kern.c) */
+#ifndef SYSV
+extern long random();
+#endif
+extern int errno;
+
+char * inet_name __P((u_int32 addr));
+u_int32 host_addr __P((char *name));
+/* u_int is promoted u_char */
+char * proto_type __P((u_int type));
+char * flag_type __P((u_int type));
+
+u_int32 get_netmask __P((int s, u_int32 dst));
+int get_ttl __P((struct resp_buf *buf));
+int t_diff __P((u_long a, u_long b));
+u_long fixtime __P((u_long time));
+int send_recv __P((u_int32 dst, int type, int code,
+ int tries, struct resp_buf *save));
+char * print_host __P((u_int32 addr));
+void print_trace __P((int index, struct resp_buf *buf));
+int what_kind __P((struct resp_buf *buf));
+char * scale __P((int *hop));
+void stat_line __P((struct tr_resp *r, struct tr_resp *s,
+ int have_next));
+void fixup_stats __P((struct resp_buf *base,
+ struct resp_buf *new));
+int print_stats __P((struct resp_buf *base,
+ struct resp_buf *prev,
+ struct resp_buf *new));
+void check_vif_state __P((void));
+
+int main __P((int argc, char *argv[]));
+
char *
inet_name(addr)
- u_long addr;
+ u_int32 addr;
{
- struct hostent *e;
+ struct hostent *e;
- e = gethostbyaddr(&addr, sizeof(addr), AF_INET);
+ e = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET);
- return e ? e->h_name : "?";
+ return e ? e->h_name : "?";
}
-u_long
+
+u_int32
host_addr(name)
- char *name;
+ char *name;
{
- struct hostent *e = gethostbyname(name);
- int addr;
+ struct hostent *e = (struct hostent *)0;
+ u_int32 addr;
+ int i, dots = 3;
+ char buf[40];
+ char *ip = name;
+ char *op = buf;
- if (e)
- memcpy(&addr, e->h_addr_list[0], e->h_length);
- else {
- addr = inet_addr(name);
- if (addr == -1)
- addr = 0;
- }
+ /*
+ * Undo BSD's favor -- take fewer than 4 octets as net/subnet address
+ * if the name is all numeric.
+ */
+ for (i = sizeof(buf) - 7; i > 0; --i) {
+ if (*ip == '.') --dots;
+ else if (*ip == '\0') break;
+ else if (!isdigit(*ip)) dots = 0; /* Not numeric, don't add zeroes */
+ *op++ = *ip++;
+ }
+ for (i = 0; i < dots; ++i) {
+ *op++ = '.';
+ *op++ = '0';
+ }
+ *op = '\0';
- return addr;
+ if (dots <= 0) e = gethostbyname(name);
+ if (e) memcpy((char *)&addr, e->h_addr_list[0], e->h_length);
+ else {
+ addr = inet_addr(buf);
+ if (addr == -1) {
+ addr = 0;
+ printf("Could not parse %s as host name or address\n", name);
+ }
+ }
+ return addr;
}
+
+
char *
proto_type(type)
- u_char type;
+ u_int type;
{
+ static char buf[80];
+
switch (type) {
case PROTO_DVMRP:
- return ("PROTO_DVMRP");
+ return ("DVMRP");
case PROTO_MOSPF:
- return ("PROTO_MOSPF");
+ return ("MOSPF");
case PROTO_PIM:
- return ("PROTO_PIM");
+ return ("PIM");
case PROTO_CBT:
- return ("PROTO_CBT");
+ return ("CBT");
default:
- return ("PROTO_UNKNOWN");
+ (void) sprintf(buf, "Unknown protocol code %d", type);
+ return (buf);
}
}
+
char *
flag_type(type)
- u_char type;
+ u_int type;
{
+ static char buf[80];
+
switch (type) {
case TR_NO_ERR:
- return ("NO_ERR");
+ return ("");
case TR_WRONG_IF:
- return ("WRONG_IF");
+ return ("Wrong interface");
case TR_PRUNED:
- return ("PRUNED");
+ return ("Prune sent upstream");
+ case TR_OPRUNED:
+ return ("Output pruned");
case TR_SCOPED:
- return ("SCOPED");
+ return ("Hit scope boundary");
case TR_NO_RTE:
- return ("NO_RTE");
+ return ("No route");
+ case TR_OLD_ROUTER:
+ return ("Next router no mtrace");
+ case TR_NO_FWD:
+ return ("Not forwarding");
+ case TR_NO_SPACE:
+ return ("No space in packet");
default:
- return ("INVALID ERR");
+ (void) sprintf(buf, "Unknown error code %d", type);
+ return (buf);
}
}
+/*
+ * If destination is on a local net, get the netmask, else set the
+ * netmask to all ones. There are two side effects: if the local
+ * address was not explicitly set, and if the destination is on a
+ * local net, use that one; in either case, verify that the local
+ * address is valid.
+ */
+
+u_int32
+get_netmask(s, dst)
+ int s;
+ u_int32 dst;
+{
+ unsigned int i;
+ char ifbuf[5000];
+ struct ifconf ifc;
+ struct ifreq *ifr;
+ u_int32 if_addr, if_mask;
+ u_int32 retval = 0xFFFFFFFF;
+ int found = FALSE;
+
+ ifc.ifc_buf = ifbuf;
+ ifc.ifc_len = sizeof(ifbuf);
+ if (ioctl(s, SIOCGIFCONF, (char *) &ifc) < 0) {
+ perror("ioctl (SIOCGIFCONF)");
+ return (retval);
+ }
+ i = ifc.ifc_len / sizeof(struct ifreq);
+ ifr = ifc.ifc_req;
+ for (; i > 0; i--, ifr++) {
+ if_addr = ((struct sockaddr_in *)&(ifr->ifr_addr))->sin_addr.s_addr;
+ if (ioctl(s, SIOCGIFNETMASK, (char *)ifr) >= 0) {
+ if_mask = ((struct sockaddr_in *)&(ifr->ifr_addr))->sin_addr.s_addr;
+ if ((dst & if_mask) == (if_addr & if_mask)) {
+ retval = if_mask;
+ if (lcl_addr == 0) lcl_addr = if_addr;
+ }
+ }
+ if (lcl_addr == if_addr) found = TRUE;
+ }
+ if (!found && lcl_addr != 0) {
+ printf("Interface address is not valid\n");
+ exit(1);
+ }
+ return (retval);
+}
+
+
+int
+get_ttl(buf)
+ struct resp_buf *buf;
+{
+ register rno;
+ register struct tr_resp *b;
+ register ttl;
+
+ if (buf && (rno = buf->len) > 0) {
+ b = buf->resps + rno - 1;
+ ttl = b->tr_fttl;
+
+ while (--rno > 0) {
+ --b;
+ if (ttl < b->tr_fttl) ttl = b->tr_fttl;
+ else ++ttl;
+ }
+ ttl += MULTICAST_TTL_INC;
+ if (ttl < MULTICAST_TTL1) ttl = MULTICAST_TTL1;
+ if (ttl > MULTICAST_TTL_MAX) ttl = MULTICAST_TTL_MAX;
+ return (ttl);
+ } else return(MULTICAST_TTL1);
+}
+
+/*
+ * Calculate the difference between two 32-bit NTP timestamps and return
+ * the result in milliseconds.
+ */
+int
+t_diff(a, b)
+ u_long a, b;
+{
+ int d = a - b;
+
+ return ((d * 125) >> 13);
+}
+
+/*
+ * Fixup for incorrect time format in 3.3 mrouted.
+ * This is possible because (JAN_1970 mod 64K) is quite close to 32K,
+ * so correct and incorrect times will be far apart.
+ */
+u_long
+fixtime(time)
+ u_long time;
+{
+ if (abs((int)(time-base.qtime)) > 0x3FFFFFFF)
+ time = ((time & 0xFFFF0000) + (JAN_1970 << 16)) +
+ ((time & 0xFFFF) << 14) / 15625;
+ return (time);
+}
+
int
-t_diff(a_sec, a_usec, b_sec, b_usec)
- u_long a_sec, a_usec, b_sec, b_usec;
+send_recv(dst, type, code, tries, save)
+ u_int32 dst;
+ int type, code, tries;
+ struct resp_buf *save;
{
- int d = a_sec - b_sec;
- int ms = a_usec - b_usec;
+ fd_set fds;
+ struct timeval tq, tr, tv;
+ struct ip *ip;
+ struct igmp *igmp;
+ struct tr_query *query, *rquery;
+ int ipdatalen, iphdrlen, igmpdatalen;
+ u_int32 local, group;
+ int datalen;
+ int count, recvlen, dummy = 0;
+ int len;
+ int i;
- if ((d < 0) ||
- ((d == 0) && (ms < 0))) {
- d = b_sec - a_sec;
- ms = b_usec - a_usec;
+ if (type == IGMP_MTRACE) {
+ group = qgrp;
+ datalen = sizeof(struct tr_query);
+ } else {
+ group = htonl(MROUTED_LEVEL);
+ datalen = 0;
}
+ if (IN_MULTICAST(ntohl(dst))) local = lcl_addr;
+ else local = INADDR_ANY;
+
+ /*
+ * If the reply address was not explictly specified, start off
+ * with the unicast address of this host. Then, if there is no
+ * response after trying half the tries with unicast, switch to
+ * the standard multicast reply address. If the TTL was also not
+ * specified, set a multicast TTL and if needed increase it for the
+ * last quarter of the tries.
+ */
+ query = (struct tr_query *)(send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
+ query->tr_raddr = raddr ? raddr : multicast ? resp_cast : lcl_addr;
+ query->tr_rttl = rttl ? rttl :
+ IN_MULTICAST(ntohl(query->tr_raddr)) ? get_ttl(save) : UNICAST_TTL;
+ query->tr_src = qsrc;
+ query->tr_dst = qdst;
+
+ for (i = tries ; i > 0; --i) {
+ if (tries == nqueries && raddr == 0) {
+ if (i == ((nqueries + 1) >> 1)) {
+ query->tr_raddr = resp_cast;
+ if (rttl == 0) query->tr_rttl = get_ttl(save);
+ }
+ if (i <= ((nqueries + 3) >> 2) && rttl == 0) {
+ query->tr_rttl += MULTICAST_TTL_INC;
+ if (query->tr_rttl > MULTICAST_TTL_MAX)
+ query->tr_rttl = MULTICAST_TTL_MAX;
+ }
+ }
+
+ /*
+ * Change the qid for each request sent to avoid being confused
+ * by duplicate responses
+ */
+#ifdef SYSV
+ query->tr_qid = ((u_int32)lrand48() >> 8);
+#else
+ query->tr_qid = ((u_int32)random() >> 8);
+#endif
+
+ /*
+ * Set timer to calculate delays, then send query
+ */
+ gettimeofday(&tq, 0);
+ send_igmp(local, dst, type, code, group, datalen);
+
+ /*
+ * Wait for response, discarding false alarms
+ */
+ while (TRUE) {
+ FD_ZERO(&fds);
+ FD_SET(igmp_socket, &fds);
+ gettimeofday(&tv, 0);
+ tv.tv_sec = tq.tv_sec + timeout - tv.tv_sec;
+ tv.tv_usec = tq.tv_usec - tv.tv_usec;
+ if (tv.tv_usec < 0) tv.tv_usec += 1000000L, --tv.tv_sec;
+ if (tv.tv_sec < 0) tv.tv_sec = tv.tv_usec = 0;
+
+ count = select(igmp_socket + 1, &fds, (fd_set *)0, (fd_set *)0,
+ &tv);
+
+ if (count < 0) {
+ if (errno != EINTR) perror("select");
+ continue;
+ } else if (count == 0) {
+ printf("* ");
+ fflush(stdout);
+ break;
+ }
+
+ gettimeofday(&tr, 0);
+ recvlen = recvfrom(igmp_socket, recv_buf, RECV_BUF_SIZE,
+ 0, (struct sockaddr *)0, &dummy);
+
+ if (recvlen <= 0) {
+ if (recvlen && errno != EINTR) perror("recvfrom");
+ continue;
+ }
+
+ if (recvlen < sizeof(struct ip)) {
+ fprintf(stderr,
+ "packet too short (%u bytes) for IP header", recvlen);
+ continue;
+ }
+ ip = (struct ip *) recv_buf;
+ if (ip->ip_p == 0) /* ignore cache creation requests */
+ continue;
+
+ iphdrlen = ip->ip_hl << 2;
+ ipdatalen = ip->ip_len;
+ if (iphdrlen + ipdatalen != recvlen) {
+ fprintf(stderr,
+ "packet shorter (%u bytes) than hdr+data len (%u+%u)\n",
+ recvlen, iphdrlen, ipdatalen);
+ continue;
+ }
+
+ igmp = (struct igmp *) (recv_buf + iphdrlen);
+ igmpdatalen = ipdatalen - IGMP_MINLEN;
+ if (igmpdatalen < 0) {
+ fprintf(stderr,
+ "IP data field too short (%u bytes) for IGMP from %s\n",
+ ipdatalen, inet_fmt(ip->ip_src.s_addr, s1));
+ continue;
+ }
+
+ switch (igmp->igmp_type) {
+
+ case IGMP_DVMRP:
+ if (igmp->igmp_code != DVMRP_NEIGHBORS2) continue;
+ len = igmpdatalen;
+ /*
+ * Accept DVMRP_NEIGHBORS2 response if it comes from the
+ * address queried or if that address is one of the local
+ * addresses in the response.
+ */
+ if (ip->ip_src.s_addr != dst) {
+ register u_int32 *p = (u_int32 *)(igmp + 1);
+ register u_int32 *ep = p + (len >> 2);
+ while (p < ep) {
+ register u_int32 laddr = *p++;
+ register int n = ntohl(*p++) & 0xFF;
+ if (laddr == dst) {
+ ep = p + 1; /* ensure p < ep after loop */
+ break;
+ }
+ p += n;
+ }
+ if (p >= ep) continue;
+ }
+ break;
+
+ case IGMP_MTRACE: /* For backward compatibility with 3.3 */
+ case IGMP_MTRACE_RESP:
+ if (igmpdatalen <= QLEN) continue;
+ if ((igmpdatalen - QLEN)%RLEN) {
+ printf("packet with incorrect datalen\n");
+ continue;
+ }
+
+ /*
+ * Ignore responses that don't match query.
+ */
+ rquery = (struct tr_query *)(igmp + 1);
+ if (rquery->tr_qid != query->tr_qid) continue;
+ if (rquery->tr_src != qsrc) continue;
+ if (rquery->tr_dst != qdst) continue;
+ len = (igmpdatalen - QLEN)/RLEN;
+
+ /*
+ * Ignore trace queries passing through this node when
+ * mtrace is run on an mrouter that is in the path
+ * (needed only because IGMP_MTRACE is accepted above
+ * for backward compatibility with multicast release 3.3).
+ */
+ if (igmp->igmp_type == IGMP_MTRACE) {
+ struct tr_resp *r = (struct tr_resp *)(rquery+1) + len - 1;
+ u_int32 smask;
+
+ VAL_TO_MASK(smask, r->tr_smask);
+ if (len < code && (r->tr_inaddr & smask) != (qsrc & smask)
+ && r->tr_rmtaddr != 0 && !(r->tr_rflags & 0x80))
+ continue;
+ }
+
+ /*
+ * A match, we'll keep this one.
+ */
+ if (len > code) {
+ fprintf(stderr,
+ "Num hops received (%d) exceeds request (%d)\n",
+ len, code);
+ }
+ rquery->tr_raddr = query->tr_raddr; /* Insure these are */
+ rquery->tr_rttl = query->tr_rttl; /* as we sent them */
+ break;
+
+ default:
+ continue;
+ }
+
+ /*
+ * Most of the sanity checking done at this point.
+ * Return this packet we have been waiting for.
+ */
+ if (save) {
+ save->qtime = ((tq.tv_sec + JAN_1970) << 16) +
+ (tq.tv_usec << 10) / 15625;
+ save->rtime = ((tr.tv_sec + JAN_1970) << 16) +
+ (tr.tv_usec << 10) / 15625;
+ save->len = len;
+ bcopy((char *)igmp, (char *)&save->igmp, ipdatalen);
+ }
+ return (recvlen);
+ }
+ }
+ return (0);
+}
+
+
+char *
+print_host(addr)
+ u_int32 addr;
+{
+ char *name;
+
+ if (numeric) {
+ printf("%s", inet_fmt(addr, s1));
+ return ("");
+ }
+ name = inet_name(addr);
+ printf("%s (%s)", name, inet_fmt(addr, s1));
+ return (name);
+}
+
+/*
+ * Print responses as received (reverse path from dst to src)
+ */
+void
+print_trace(index, buf)
+ int index;
+ struct resp_buf *buf;
+{
+ struct tr_resp *r;
+ char *name;
+ int i;
+
+ i = abs(index);
+ r = buf->resps + i - 1;
+
+ for (; i <= buf->len; ++i, ++r) {
+ if (index > 0) printf("%3d ", -i);
+ name = print_host(r->tr_outaddr);
+ printf(" %s thresh^ %d %d ms %s\n", proto_type(r->tr_rproto),
+ r->tr_fttl, t_diff(fixtime(ntohl(r->tr_qarr)), buf->qtime),
+ flag_type(r->tr_rflags));
+ memcpy(names[i-1], name, sizeof(names[0]) - 1);
+ names[i-1][sizeof(names[0])-1] = '\0';
+ }
+}
+
+/*
+ * See what kind of router is the next hop
+ */
+int
+what_kind(buf)
+ struct resp_buf *buf;
+{
+ u_int32 smask;
+ int retval;
+ int hops = buf->len;
+ struct tr_resp *r = buf->resps + hops - 1;
+ u_int32 next = r->tr_rmtaddr;
+
+ retval = send_recv(next, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS2, 1, &incr[0]);
+ print_host(next);
+ if (retval) {
+ u_int32 version = ntohl(incr[0].igmp.igmp_group.s_addr);
+ u_int32 *p = (u_int32 *)incr[0].ndata;
+ u_int32 *ep = p + (incr[0].len >> 2);
+ char *type = "";
+ retval = 0;
+ switch (version & 0xFF) {
+ case 1:
+ type = "proteon/mrouted ";
+ retval = 1;
+ break;
+
+ case 2:
+ case 3:
+ if (((version >> 8) & 0xFF) < 3) retval = 1;
+ /* Fall through */
+ case 4:
+ type = "mrouted ";
+ break;
+
+ case 10:
+ type = "cisco ";
+ }
+ printf(" [%s%d.%d] didn't respond\n",
+ type, version & 0xFF, (version >> 8) & 0xFF);
+ VAL_TO_MASK(smask, r->tr_smask);
+ while (p < ep) {
+ register u_int32 laddr = *p++;
+ register int flags = (ntohl(*p) & 0xFF00) >> 8;
+ register int n = ntohl(*p++) & 0xFF;
+ if (!(flags & (DVMRP_NF_DOWN | DVMRP_NF_DISABLED)) &&
+ (laddr & smask) == (qsrc & smask)) {
+ printf("%3d ", -(hops+2));
+ print_host(qsrc);
+ printf("\n");
+ return 1;
+ }
+ p += n;
+ }
+ return retval;
+ }
+ printf(" didn't respond\n");
+ return 0;
+}
+
+
+char *
+scale(hop)
+ int *hop;
+{
+ if (*hop > -1000 && *hop < 10000) return (" ms");
+ *hop /= 1000;
+ if (*hop > -1000 && *hop < 10000) return (" s ");
+ return ("s ");
+}
+
+/*
+ * Calculate and print one line of packet loss and packet rate statistics.
+ * Checks for count of all ones from mrouted 2.3 that doesn't have counters.
+ */
+#define NEITHER 0
+#define INS 1
+#define OUTS 2
+#define BOTH 3
+void
+stat_line(r, s, have_next)
+ struct tr_resp *r, *s;
+ int have_next;
+{
+ register timediff = (fixtime(ntohl(s->tr_qarr)) -
+ fixtime(ntohl(r->tr_qarr))) >> 16;
+ register v_lost, v_pct;
+ register g_lost, g_pct;
+ register v_out = ntohl(s->tr_vifout) - ntohl(r->tr_vifout);
+ register g_out = ntohl(s->tr_pktcnt) - ntohl(r->tr_pktcnt);
+ register v_pps, g_pps;
+ char v_str[8], g_str[8];
+ register have = NEITHER;
+
+ if (timediff == 0) timediff = 1;
+ v_pps = v_out / timediff;
+ g_pps = g_out / timediff;
+
+ if (v_out || s->tr_vifout != 0xFFFFFFFF) have |= OUTS;
+
+ if (have_next) {
+ --r, --s;
+ if (s->tr_vifin != 0xFFFFFFFF || r->tr_vifin != 0xFFFFFFFF)
+ have |= INS;
+ }
+
+ switch (have) {
+ case BOTH:
+ v_lost = v_out - (ntohl(s->tr_vifin) - ntohl(r->tr_vifin));
+ if (v_out) v_pct = (v_lost * 100 + (v_out >> 1)) / v_out;
+ else v_pct = 0;
+ if (-100 < v_pct && v_pct < 101 && v_out > 10)
+ sprintf(v_str, "%3d", v_pct);
+ else memcpy(v_str, " --", 4);
- switch (d) {
- case 0:
+ g_lost = g_out - (ntohl(s->tr_pktcnt) - ntohl(r->tr_pktcnt));
+ if (g_out) g_pct = (g_lost * 100 + (g_out >> 1))/ g_out;
+ else g_pct = 0;
+ if (-100 < g_pct && g_pct < 101 && g_out > 10)
+ sprintf(g_str, "%3d", g_pct);
+ else memcpy(g_str, " --", 4);
+
+ printf("%6d/%-5d=%s%%%4d pps%6d/%-5d=%s%%%4d pps\n",
+ v_lost, v_out, v_str, v_pps, g_lost, g_out, g_str, g_pps);
+ if (debug > 2) {
+ printf("\t\t\t\tv_in: %ld ", ntohl(s->tr_vifin));
+ printf("v_out: %ld ", ntohl(s->tr_vifout));
+ printf("pkts: %ld\n", ntohl(s->tr_pktcnt));
+ printf("\t\t\t\tv_in: %ld ", ntohl(r->tr_vifin));
+ printf("v_out: %ld ", ntohl(r->tr_vifout));
+ printf("pkts: %ld\n", ntohl(r->tr_pktcnt));
+ printf("\t\t\t\tv_in: %ld ",ntohl(s->tr_vifin)-ntohl(r->tr_vifin));
+ printf("v_out: %ld ", ntohl(s->tr_vifout) - ntohl(r->tr_vifout));
+ printf("pkts: %ld ", ntohl(s->tr_pktcnt) - ntohl(r->tr_pktcnt));
+ printf("time: %d\n", timediff);
+ }
+ break;
+
+ case INS:
+ v_out = (ntohl(s->tr_vifin) - ntohl(r->tr_vifin));
+ g_out = (ntohl(s->tr_pktcnt) - ntohl(r->tr_pktcnt));
+ v_pps = v_out / timediff;
+ g_pps = g_out / timediff;
+ /* Fall through */
+
+ case OUTS:
+ printf(" %-5d %4d pps %-5d %4d pps\n",
+ v_out, v_pps, g_out, g_pps);
break;
- case 2:
- ms += 1000000;
- case 1:
- ms += 1000000;
+
+ case NEITHER:
+ printf("\n");
break;
- default:
- ms += (1000000) * d;
}
- return (ms/1000);
}
+/*
+ * A fixup to check if any pktcnt has been reset.
+ */
+void
+fixup_stats(base, new)
+ struct resp_buf *base, *new;
+{
+ register rno = base->len;
+ register struct tr_resp *b = base->resps + rno;
+ register struct tr_resp *n = new->resps + rno;
+
+ while (--rno >= 0)
+ if (ntohl((--n)->tr_pktcnt) < ntohl((--b)->tr_pktcnt)) break;
+
+ if (rno < 0) return;
+
+ rno = base->len;
+ b = base->resps + rno;
+ n = new->resps + rno;
+
+ while (--rno >= 0) (--b)->tr_pktcnt = (--n)->tr_pktcnt;
+}
+
+/*
+ * Print responses with statistics for forward path (from src to dst)
+ */
+int
+print_stats(base, prev, new)
+ struct resp_buf *base, *prev, *new;
+{
+ int rtt, hop;
+ register char *ms;
+ register u_int32 smask;
+ register rno = base->len - 1;
+ register struct tr_resp *b = base->resps + rno;
+ register struct tr_resp *p = prev->resps + rno;
+ register struct tr_resp *n = new->resps + rno;
+ register u_long resptime = new->rtime;
+ register u_long qarrtime = fixtime(ntohl(n->tr_qarr));
+ register ttl = n->tr_fttl;
+
+ VAL_TO_MASK(smask, b->tr_smask);
+ printf(" Source Response Dest");
+ printf(" Packet Statistics For Only For Traffic\n");
+ printf("%-15s %-15s All Multicast Traffic From %s\n",
+ ((b->tr_inaddr & smask) == (qsrc & smask)) ? s1 : " * * * ",
+ inet_fmt(base->qhdr.tr_raddr, s2), inet_fmt(qsrc, s1));
+ rtt = t_diff(resptime, new->qtime);
+ ms = scale(&rtt);
+ printf(" | __/ rtt%5d%s Lost/Sent = Pct Rate To %s\n",
+ rtt, ms, inet_fmt(qgrp, s2));
+ hop = t_diff(resptime, qarrtime);
+ ms = scale(&hop);
+ printf(" v / hop%5d%s", hop, ms);
+ printf(" --------------------- --------------------\n");
+ if (debug > 2) {
+ printf("\t\t\t\tv_in: %ld ", ntohl(n->tr_vifin));
+ printf("v_out: %ld ", ntohl(n->tr_vifout));
+ printf("pkts: %ld\n", ntohl(n->tr_pktcnt));
+ printf("\t\t\t\tv_in: %ld ", ntohl(b->tr_vifin));
+ printf("v_out: %ld ", ntohl(b->tr_vifout));
+ printf("pkts: %ld\n", ntohl(b->tr_pktcnt));
+ printf("\t\t\t\tv_in: %ld ", ntohl(n->tr_vifin) - ntohl(b->tr_vifin));
+ printf("v_out: %ld ", ntohl(n->tr_vifout) - ntohl(b->tr_vifout));
+ printf("pkts: %ld\n", ntohl(n->tr_pktcnt) - ntohl(b->tr_pktcnt));
+ }
+
+ while (TRUE) {
+ if ((n->tr_inaddr != b->tr_inaddr) || (n->tr_inaddr != b->tr_inaddr))
+ return 1; /* Route changed */
+
+ if ((n->tr_inaddr != n->tr_outaddr))
+ printf("%-15s\n", inet_fmt(n->tr_inaddr, s1));
+ printf("%-15s %-14s %s\n", inet_fmt(n->tr_outaddr, s1), names[rno],
+ flag_type(n->tr_rflags));
+
+ if (rno-- < 1) break;
+
+ printf(" | ^ ttl%5d ", ttl);
+ if (prev == new) printf("\n");
+ else stat_line(p, n, TRUE);
+ resptime = qarrtime;
+ qarrtime = fixtime(ntohl((n-1)->tr_qarr));
+ hop = t_diff(resptime, qarrtime);
+ ms = scale(&hop);
+ printf(" v | hop%5d%s", hop, ms);
+ stat_line(b, n, TRUE);
+
+ --b, --p, --n;
+ if (ttl < n->tr_fttl) ttl = n->tr_fttl;
+ else ++ttl;
+ }
+
+ printf(" | \\__ ttl%5d ", ttl);
+ if (prev == new) printf("\n");
+ else stat_line(p, n, FALSE);
+ hop = t_diff(qarrtime, new->qtime);
+ ms = scale(&hop);
+ printf(" v \\ hop%5d%s", hop, ms);
+ stat_line(b, n, FALSE);
+ printf("%-15s %s\n", inet_fmt(qdst, s1), inet_fmt(lcl_addr, s2));
+ printf(" Receiver Query Source\n\n");
+ return 0;
+}
+
+
+/***************************************************************************
+ * main
+ ***************************************************************************/
+
+int
main(argc, argv)
int argc;
char *argv[];
{
- struct timeval tq;
- struct timezone tzp;
- u_long resptime;
-
int udp;
struct sockaddr_in addr;
int addrlen = sizeof(addr);
- u_long lcl_addr = 0; /* in NET order */
-
- u_long qid = ((u_long)random() >> 8);
- u_long qsrc = NULL;
- u_long qgrp = NULL;
- u_long qdst = NULL;
- u_char qno = 0;
- u_long raddr = NULL;
- u_char qttl = 1;
- u_char rttl = 1;
- u_long dst = NULL;
-
- struct tr_query *query;
+ int recvlen;
+ struct timeval tv;
+ struct resp_buf *prev, *new;
+ struct tr_resp *r;
+ u_int32 smask;
+ int rno;
+ int hops, nexthop, tries;
+ u_int32 lastout = 0;
+ int numstats = 1;
+ int waittime;
+ int seed;
- struct tr_rlist *tr_rlist = NULL;
-
- char *p;
- int datalen = 0;
-
- int i;
- int done = 0;
+ if (geteuid() != 0) {
+ fprintf(stderr, "mtrace: must be root\n");
+ exit(1);
+ }
argv++, argc--;
+ if (argc == 0) goto usage;
while (argc > 0 && *argv[0] == '-') {
- switch (argv[0][1]) {
- case 's':
- if (argc > 1 && isdigit(*(argv + 1)[0])) {
- argv++, argc--;
- qsrc = host_addr(argv[0]);
- break;
- } else
- goto usage;
- case 'g':
- if (argc > 1 && isdigit(*(argv + 1)[0])) {
- argv++, argc--;
- qgrp = host_addr(argv[0]);
- break;
- } else
- goto usage;
- case 'd':
- if (argc > 1 && isdigit(*(argv + 1)[0])) {
- argv++, argc--;
- qdst = host_addr(argv[0]);
+ register char *p = *argv++; argc--;
+ p++;
+ do {
+ register char c = *p++;
+ register char *arg = (char *) 0;
+ if (isdigit(*p)) {
+ arg = p;
+ p = "";
+ } else if (argc > 0) arg = argv[0];
+ switch (c) {
+ case 'd': /* Unlisted debug print option */
+ if (arg && isdigit(*arg)) {
+ debug = atoi(arg);
+ if (debug < 0) debug = 0;
+ if (debug > 3) debug = 3;
+ if (arg == argv[0]) argv++, argc--;
+ break;
+ } else
+ goto usage;
+ case 'M': /* Use multicast for reponse */
+ multicast = TRUE;
break;
- } else
- goto usage;
- case 'x':
- if (argc > 1 && isdigit(*(argv + 1)[0])) {
- argv++, argc--;
- dst = host_addr(argv[0]);
+ case 'l': /* Loop updating stats indefinitely */
+ numstats = 3153600;
break;
- } else
- goto usage;
- case 't':
- if (argc > 1 && isdigit(*(argv + 1)[0])) {
- argv++, argc--;
- qttl = atoi(argv[0]);
- if (qttl < 1)
- qttl = 1;
+ case 'n': /* Don't reverse map host addresses */
+ numeric = TRUE;
break;
- } else
- goto usage;
- case 'n':
- if (argc > 1 && isdigit(*(argv + 1)[0])) {
- argv++, argc--;
- qno = atoi(argv[0]);
+ case 'p': /* Passive listen for traces */
+ passive = TRUE;
break;
- } else
- goto usage;
- case 'l':
- if (argc > 1 && isdigit(*(argv + 1)[0])) {
- argv++, argc--;
- rttl = atoi(argv[0]);
+ case 's': /* Short form, don't wait for stats */
+ numstats = 0;
break;
- } else
+ case 'w': /* Time to wait for packet arrival */
+ if (arg && isdigit(*arg)) {
+ timeout = atoi(arg);
+ if (timeout < 1) timeout = 1;
+ if (arg == argv[0]) argv++, argc--;
+ break;
+ } else
+ goto usage;
+ case 'm': /* Max number of hops to trace */
+ if (arg && isdigit(*arg)) {
+ qno = atoi(arg);
+ if (qno > MAXHOPS) qno = MAXHOPS;
+ else if (qno < 1) qno = 0;
+ if (arg == argv[0]) argv++, argc--;
+ break;
+ } else
+ goto usage;
+ case 'q': /* Number of query retries */
+ if (arg && isdigit(*arg)) {
+ nqueries = atoi(arg);
+ if (nqueries < 1) nqueries = 1;
+ if (arg == argv[0]) argv++, argc--;
+ break;
+ } else
+ goto usage;
+ case 'g': /* Last-hop gateway (dest of query) */
+ if (arg && (gwy = host_addr(arg))) {
+ if (arg == argv[0]) argv++, argc--;
+ break;
+ } else
+ goto usage;
+ case 't': /* TTL for query packet */
+ if (arg && isdigit(*arg)) {
+ qttl = atoi(arg);
+ if (qttl < 1) qttl = 1;
+ rttl = qttl;
+ if (arg == argv[0]) argv++, argc--;
+ break;
+ } else
+ goto usage;
+ case 'r': /* Dest for response packet */
+ if (arg && (raddr = host_addr(arg))) {
+ if (arg == argv[0]) argv++, argc--;
+ break;
+ } else
+ goto usage;
+ case 'i': /* Local interface address */
+ if (arg && (lcl_addr = host_addr(arg))) {
+ if (arg == argv[0]) argv++, argc--;
+ break;
+ } else
+ goto usage;
+ default:
goto usage;
- case 'r':
- if (argc > 1 && isdigit(*(argv + 1)[0])) {
+ }
+ } while (*p);
+ }
+
+ if (argc > 0 && (qsrc = host_addr(argv[0]))) { /* Source of path */
+ if (IN_MULTICAST(ntohl(qsrc))) goto usage;
+ argv++, argc--;
+ if (argc > 0 && (qdst = host_addr(argv[0]))) { /* Dest of path */
+ argv++, argc--;
+ if (argc > 0 && (qgrp = host_addr(argv[0]))) { /* Path via group */
argv++, argc--;
- raddr = host_addr(argv[0]);
- break;
- } else
- goto usage;
- default:
- goto usage;
+ }
+ if (IN_MULTICAST(ntohl(qdst))) {
+ u_int32 temp = qdst;
+ qdst = qgrp;
+ qgrp = temp;
+ if (IN_MULTICAST(ntohl(qdst))) goto usage;
+ } else if (qgrp && !IN_MULTICAST(ntohl(qgrp))) goto usage;
}
- argv++, argc--;
}
- if (argc > 0) {
-usage: printf("usage: mtrace -s <src> -g <grp> -d <dst> -n <# reports> \n");
- printf(" -t <ttl> [-x <qdst>] [-r <rdst>] [-l <rttl>]\n");
+ if (argc > 0 || qsrc == 0) {
+usage: printf("\
+Usage: mtrace [-Mlnps] [-w wait] [-m max_hops] [-q nqueries] [-g gateway]\n\
+ [-t ttl] [-r resp_dest] [-i if_addr] source [receiver] [group]\n");
exit(1);
}
- printf("Mtrace src %s grp %s dst %s #%d\n", inet_fmt(qsrc, s1),
- inet_fmt(qgrp, s2), inet_fmt(qdst, s3), qno);
- printf(" resp ttl %d resp addr %s\n", rttl, inet_fmt(raddr, s1));
-
init_igmp();
- /* Obtain the local address from which to send out packets */
+ /*
+ * Set useful defaults for as many parameters as possible.
+ */
+
+ defgrp = htonl(0xE0020001); /* MBone Audio (224.2.0.1) */
+ query_cast = htonl(0xE0000002); /* All routers multicast addr */
+ resp_cast = htonl(0xE0000120); /* Mtrace response multicast addr */
+ if (qgrp == 0) qgrp = defgrp;
+ /*
+ * Get default local address for multicasts to use in setting defaults.
+ */
addr.sin_family = AF_INET;
+#if (defined(BSD) && (BSD >= 199103))
+ addr.sin_len = sizeof(addr);
+#endif
addr.sin_addr.s_addr = qgrp;
- addr.sin_port = htons(2000);
+ addr.sin_port = htons(2000); /* Any port above 1024 will do */
if (((udp = socket(AF_INET, SOCK_DGRAM, 0)) < 0) ||
(connect(udp, (struct sockaddr *) &addr, sizeof(addr)) < 0) ||
@@ -228,232 +1066,398 @@ usage: printf("usage: mtrace -s <src> -g <grp> -d <dst> -n <# reports> \n");
perror("Determining local address");
exit(-1);
}
- close(udp);
- lcl_addr = addr.sin_addr.s_addr;
- /* Got the local address now */
- /* Now, make up the IGMP packet to send */
+ /*
+ * Default destination for path to be queried is the local host.
+ */
+ if (qdst == 0) qdst = lcl_addr ? lcl_addr : addr.sin_addr.s_addr;
+ dst_netmask = get_netmask(udp, qdst);
+ close(udp);
+ if (lcl_addr == 0) lcl_addr = addr.sin_addr.s_addr;
- query = (struct tr_query *)(send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
+ /*
+ * Initialize the seed for random query identifiers.
+ */
+ gettimeofday(&tv, 0);
+ seed = tv.tv_usec ^ lcl_addr;
+#ifdef SYSV
+ srand48(seed);
+#else
+ srandom(seed);
+#endif
- query->tr_src = qsrc;
- query->tr_dst = qdst;
- query->tr_qid = qid;
- if (raddr)
- query->tr_raddr = raddr;
- else
- query->tr_raddr = lcl_addr;
- query->tr_rttl = rttl;
-
- datalen += sizeof(struct tr_query);
-
- if (IN_MULTICAST(ntohl(qgrp)))
- k_set_ttl(qttl);
- else
- k_set_ttl(1);
-
- if (dst == NULL)
- dst = qgrp;
-
/*
- * set timer to calculate delays & send query
+ * Protect against unicast queries to mrouted versions that might crash.
*/
- gettimeofday(&tq, &tzp);
+ if (gwy && !IN_MULTICAST(ntohl(gwy)))
+ if (send_recv(gwy, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS2, 1, &incr[0])) {
+ int version = ntohl(incr[0].igmp.igmp_group.s_addr) & 0xFFFF;
+ if (version == 0x0303 || version == 0x0503) {
+ printf("Don't use -g to address an mrouted 3.%d, it might crash\n",
+ (version >> 8) & 0xFF);
+ exit(0);
+ }
+ }
- send_igmp(lcl_addr, dst, IGMP_MTRACE, qno,
- qgrp, datalen);
+ printf("Mtrace from %s to %s via group %s\n",
+ inet_fmt(qsrc, s1), inet_fmt(qdst, s2), inet_fmt(qgrp, s3));
+
+ if ((qdst & dst_netmask) == (qsrc & dst_netmask)) {
+ printf("Source & receiver are directly connected, no path to trace\n");
+ exit(0);
+ }
/*
* If the response is to be a multicast address, make sure we
* are listening on that multicast address.
*/
- if (IN_MULTICAST(ntohl(raddr)))
- k_join(raddr, lcl_addr);
-
- /* Wait for our reply now */
- while (!done) {
- fd_set fds;
- struct timeval tv;
- struct timezone tzp;
-
- int count, recvlen, dummy = 0;
- register u_long src, dst, group, smask;
- struct ip *ip;
- struct igmp *igmp;
- struct tr_resp *resp;
- int ipdatalen, iphdrlen, igmpdatalen;
- int rno;
-
- FD_ZERO(&fds);
- FD_SET(igmp_socket, &fds);
-
- /* need to input timeout as optional argument */
- tv.tv_sec = timeout;
- tv.tv_usec = 0;
-
- count = select(igmp_socket + 1, &fds, 0, 0, &tv);
-
- if (count < 0) {
- if (errno != EINTR)
- perror("select");
- continue;
- } else if (count == 0) {
- printf("Timed out receiving responses\n");
- exit(1);
+ if (raddr) {
+ if (IN_MULTICAST(ntohl(raddr))) k_join(raddr, lcl_addr);
+ } else k_join(resp_cast, lcl_addr);
+
+ /*
+ * If the destination is on the local net, the last-hop router can
+ * be found by multicast to the all-routers multicast group.
+ * Otherwise, use the group address that is the subject of the
+ * query since by definition the last-hop router will be a member.
+ * Set default TTLs for local remote multicasts.
+ */
+ restart:
+
+ if (gwy == 0)
+ if ((qdst & dst_netmask) == (lcl_addr & dst_netmask)) tdst = query_cast;
+ else tdst = qgrp;
+ else tdst = gwy;
+
+ if (IN_MULTICAST(ntohl(tdst))) {
+ k_set_loop(1); /* If I am running on a router, I need to hear this */
+ if (tdst == query_cast) k_set_ttl(qttl ? qttl : 1);
+ else k_set_ttl(qttl ? qttl : MULTICAST_TTL1);
+ }
+
+ /*
+ * Try a query at the requested number of hops or MAXOPS if unspecified.
+ */
+ if (qno == 0) {
+ hops = MAXHOPS;
+ tries = 1;
+ printf("Querying full reverse path... ");
+ fflush(stdout);
+ } else {
+ hops = qno;
+ tries = nqueries;
+ printf("Querying reverse path, maximum %d hops... ", qno);
+ fflush(stdout);
+ }
+ base.rtime = 0;
+ base.len = 0;
+
+ recvlen = send_recv(tdst, IGMP_MTRACE, hops, tries, &base);
+
+ /*
+ * If the initial query was successful, print it. Otherwise, if
+ * the query max hop count is the default of zero, loop starting
+ * from one until there is no response for four hops. The extra
+ * hops allow getting past an mtrace-capable mrouter that can't
+ * send multicast packets because all phyints are disabled.
+ */
+ if (recvlen) {
+ printf("\n 0 ");
+ print_host(qdst);
+ printf("\n");
+ print_trace(1, &base);
+ r = base.resps + base.len - 1;
+ if (r->tr_rflags == TR_OLD_ROUTER) {
+ printf("%3d ", -(base.len+1));
+ what_kind(&base);
+ } else {
+ VAL_TO_MASK(smask, r->tr_smask);
+ if ((r->tr_inaddr & smask) == (qsrc & smask)) {
+ printf("%3d ", -(base.len+1));
+ print_host(qsrc);
+ printf("\n");
+ }
}
+ } else if (qno == 0) {
+ printf("switching to hop-by-hop:\n 0 ");
+ print_host(qdst);
+ printf("\n");
+
+ for (hops = 1, nexthop = 1; hops <= MAXHOPS; ++hops) {
+ printf("%3d ", -hops);
+ fflush(stdout);
- recvlen = recvfrom(igmp_socket, recv_buf, sizeof(recv_buf),
- 0, NULL, &dummy);
+ /*
+ * After a successful first hop, try switching to the unicast
+ * address of the last-hop router instead of multicasting the
+ * trace query. This should be safe for mrouted versions 3.3
+ * and 3.5 because there is a long route timeout with metric
+ * infinity before a route disappears. Switching to unicast
+ * reduces the amount of multicast traffic and avoids a bug
+ * with duplicate suppression in mrouted 3.5.
+ */
+ if (hops == 2 && gwy == 0 &&
+ (recvlen = send_recv(lastout, IGMP_MTRACE, hops, 1, &base)))
+ tdst = lastout;
+ else recvlen = send_recv(tdst, IGMP_MTRACE, hops, nqueries, &base);
- if (recvlen <= 0) {
- if (recvlen && errno != EINTR)
- perror("recvfrom");
- continue;
+ if (recvlen == 0) {
+ if (hops == 1) break;
+ if (hops == nexthop) {
+ if (what_kind(&base)) {
+ /* the ask_neighbors determined that the
+ * not-responding router is the first-hop. */
+ break;
+ }
+ } else if (hops < nexthop + 3) {
+ printf("\n");
+ } else {
+ printf("...giving up\n");
+ break;
+ }
+ continue;
+ }
+ r = base.resps + base.len - 1;
+ if (base.len == hops &&
+ (hops == 1 || (base.resps+nexthop-2)->tr_outaddr == lastout)) {
+ if (hops == nexthop) {
+ print_trace(-hops, &base);
+ } else {
+ printf("\nResuming...\n");
+ print_trace(nexthop, &base);
+ }
+ } else {
+ if (base.len == hops - 1) {
+ if (nexthop <= base.len) {
+ printf("\nResuming...\n");
+ print_trace(nexthop, &base);
+ }
+ } else {
+ hops = base.len;
+ printf("\nRoute must have changed...\n");
+ print_trace(1, &base);
+ }
+ if (r->tr_rflags == TR_OLD_ROUTER) {
+ what_kind(&base);
+ break;
+ }
+ if (r->tr_rflags == TR_NO_SPACE) {
+ printf("No space left in trace packet for more hops\n");
+ break; /* XXX could do segmented trace */
+ }
+ }
+ lastout = r->tr_outaddr;
+ nexthop = hops + 1;
+
+ VAL_TO_MASK(smask, r->tr_smask);
+ if ((r->tr_inaddr & smask) == (qsrc & smask)) {
+ printf("%3d ", -nexthop);
+ print_host(qsrc);
+ printf("\n");
+ break;
+ }
+ if (r->tr_rmtaddr == 0 || (r->tr_rflags & 0x80)) break;
}
-
- if (recvlen < sizeof(struct ip)) {
- log(LOG_WARNING, 0,
- "packet too short (%u bytes) for IP header",
- recvlen);
- continue;
+ }
+
+ if (base.rtime == 0) {
+ printf("Timed out receiving responses\n");
+ if (IN_MULTICAST(ntohl(tdst)))
+ if (tdst == query_cast)
+ printf("Perhaps no local router has a route for source %s\n",
+ inet_fmt(qsrc, s1));
+ else
+ printf("Perhaps receiver %s is not a member of group %s,\n\
+or no router local to it has a route for source %s,\n\
+or multicast at ttl %d doesn't reach its last-hop router for that source\n",
+ inet_fmt(qdst, s2), inet_fmt(qgrp, s3), inet_fmt(qsrc, s1),
+ qttl ? qttl : MULTICAST_TTL1);
+ exit(1);
+ }
+
+ printf("Round trip time %d ms\n\n", t_diff(base.rtime, base.qtime));
+
+ /*
+ * Use the saved response which was the longest one received,
+ * and make additional probes after delay to measure loss.
+ */
+ raddr = base.qhdr.tr_raddr;
+ rttl = base.qhdr.tr_rttl;
+ gettimeofday(&tv, 0);
+ waittime = 10 - (((tv.tv_sec + JAN_1970) & 0xFFFF) - (base.qtime >> 16));
+ prev = new = &incr[numstats&1];
+
+ while (numstats--) {
+ if (waittime < 1) printf("\n");
+ else {
+ printf("Waiting to accumulate statistics... ");
+ fflush(stdout);
+ sleep((unsigned)waittime);
}
- ip = (struct ip *) recv_buf;
-
- iphdrlen = ip->ip_hl << 2;
- ipdatalen = ip->ip_len;
- if (iphdrlen + ipdatalen != recvlen) {
- printf("packet shorter (%u bytes) than hdr+data length (%u+%u)\n",
- recvlen, iphdrlen, ipdatalen);
- continue;
+ rno = base.len;
+ recvlen = send_recv(tdst, IGMP_MTRACE, rno, nqueries, new);
+
+ if (recvlen == 0) {
+ printf("Timed out.\n");
+ exit(1);
}
- igmp = (struct igmp *) (recv_buf + iphdrlen);
- group = igmp->igmp_group.s_addr;
- igmpdatalen = ipdatalen - IGMP_MINLEN;
- if (igmpdatalen < 0) {
- printf("IP data field too short (%u bytes) for IGMP, from %s\n",
- ipdatalen, inet_fmt(src, s1));
- continue;
+ if (rno != new->len) {
+ printf("Trace length doesn't match:\n");
+ print_trace(1, new);
+ printf("Restarting.\n\n");
+ goto restart;
}
- if (igmp->igmp_type != IGMP_MTRACE &&
- igmp->igmp_type != IGMP_MTRACE_RESP)
- continue;
+ printf("Results after %d seconds:\n\n",
+ (int)((new->qtime - base.qtime) >> 16));
+ fixup_stats(&base, new);
+ if (print_stats(&base, prev, new)) {
+ printf("Route changed:\n");
+ print_trace(1, new);
+ printf("Restarting.\n\n");
+ goto restart;
+ }
+ prev = new;
+ new = &incr[numstats&1];
+ waittime = 10;
+ }
- if (igmpdatalen == QLEN)
- continue;
+ /*
+ * If the response was multicast back, leave the group
+ */
+ if (raddr) {
+ if (IN_MULTICAST(ntohl(raddr))) k_leave(raddr, lcl_addr);
+ } else k_leave(resp_cast, lcl_addr);
- if ((igmpdatalen - QLEN)%RLEN) {
- printf("packet with incorrect datalen\n");
- continue;
- }
+ return (0);
+}
- query = (struct tr_query *)(igmp + 1);
+void
+check_vif_state()
+{
+ log(LOG_WARNING, errno, "sendto");
+}
- /* If this is query with a different id, ignore! */
- if (query->tr_qid != qid)
- continue;
-
- /*
- * Most of the sanity checking done at this point.
- * This is the packet we have been waiting for all this time
- */
- resp = (struct tr_resp *)(query + 1);
-
- rno = (igmpdatalen - QLEN)/RLEN;
+/*
+ * Log errors and other messages 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;
+ char fmt[100];
- /*
- * print the responses out in reverse order (from src to dst)
- */
- printf("src: <%s> grp: <%s> dst: <%s>\n\n", inet_fmt(qsrc, s1),
- inet_fmt(qgrp, s2), inet_fmt(qdst, s3));
-
- VAL_TO_MASK(smask, (resp+rno-1)->tr_smask);
-
- if (((resp+rno-1)->tr_inaddr & smask) == (qsrc & smask))
- printf(" %-15s \n", inet_fmt(qsrc, s1));
- else
- printf(" * * *\n");
-
- resptime = 0;
- while (rno--) {
- struct tr_resp *r = resp + rno;
-
- printf(" | \n");
- printf(" %-15s ", inet_fmt(r->tr_inaddr, s1));
- printf("ttl %d ", r->tr_fttl);
- printf("cum: %d ms ",
- t_diff(r->tr_qarr >> 16, (r->tr_qarr & 0xffff) << 4,
- tq.tv_sec & 0xffff, tq.tv_usec));
- printf("hop: %d ms ",
- t_diff(resptime >> 16, (resptime & 0xffff) << 4,
- r->tr_qarr >> 16, (r->tr_qarr & 0xffff) << 4));
- printf("%s ", proto_type(r->tr_rproto));
- printf("%s\n", flag_type(r->tr_rflags));
-
- printf(" %-15s ", inet_fmt(r->tr_outaddr, s1));
- printf("v_in: %ld ", r->tr_vifin);
- printf("v_out: %ld ", r->tr_vifout);
- printf("pkts: %ld\n", r->tr_pktcnt);
-
- resptime = r->tr_qarr;
- }
- printf(" | \n");
- printf(" %-15s \n", inet_fmt(qdst, s1));
+ va_start(ap, format);
+#else
+/*VARARGS3*/
+void
+log(severity, syserr, format, va_alist)
+ int severity, syserr;
+ char *format;
+ va_dcl
+{
+ va_list ap;
+ char fmt[100];
- /*
- * if the response was multicast back, leave the group
- */
- if (IN_MULTICAST(ntohl(raddr)))
- k_leave(raddr, lcl_addr);
+ va_start(ap);
+#endif
- /* If I don't expect any more replies, exit here */
- exit(0);
+ switch (debug) {
+ case 0: if (severity > LOG_WARNING) return;
+ case 1: if (severity > LOG_NOTICE) return;
+ case 2: if (severity > LOG_INFO ) return;
+ default:
+ fmt[0] = '\0';
+ if (severity == LOG_WARNING) strcat(fmt, "warning - ");
+ strncat(fmt, format, 80);
+ vfprintf(stderr, fmt, ap);
+ 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);
}
+ if (severity <= LOG_ERR) exit(-1);
}
+
/* dummies */
-void log()
-{
-}
-void accept_probe()
+void accept_probe(src, dst, p, datalen, level)
+ u_int32 src, dst, level;
+ char *p;
+ int datalen;
{
}
-void accept_group_report()
+void accept_group_report(src, dst, group, r_type)
+ u_int32 src, dst, group;
+ int r_type;
{
}
-void accept_neighbors()
+void accept_neighbor_request2(src, dst)
+ u_int32 src, dst;
{
}
-void accept_neighbors2()
+void accept_report(src, dst, p, datalen, level)
+ u_int32 src, dst, level;
+ char *p;
+ int datalen;
{
}
-void accept_neighbor_request2()
+void accept_neighbor_request(src, dst)
+ u_int32 src, dst;
{
}
-void accept_report()
+void accept_prune(src, dst, p, datalen)
+ u_int32 src, dst;
+ char *p;
+ int datalen;
{
}
-void accept_neighbor_request()
+void accept_graft(src, dst, p, datalen)
+ u_int32 src, dst;
+ char *p;
+ int datalen;
{
}
-void accept_prune()
+void accept_g_ack(src, dst, p, datalen)
+ u_int32 src, dst;
+ char *p;
+ int datalen;
{
}
-void accept_graft()
+void add_table_entry(origin, mcastgrp)
+ u_int32 origin, mcastgrp;
{
}
-void accept_g_ack()
+void accept_leave_message(src, dst, group)
+ u_int32 src, dst, group;
{
}
-void add_table_entry()
+void accept_mtrace(src, dst, group, data, no, datalen)
+ u_int32 src, dst, group;
+ char *data;
+ u_int no;
+ int datalen;
{
}
-void check_vif_state()
+void accept_membership_query(src, dst, group, tmo)
+ u_int32 src, dst, group;
+ int tmo;
{
}
-void mtrace()
+void accept_neighbors(src, dst, p, datalen, level)
+ u_int32 src, dst, level;
+ u_char *p;
+ int datalen;
{
}
-void leave_group_message()
+void accept_neighbors2(src, dst, p, datalen, level)
+ u_int32 src, dst, level;
+ u_char *p;
+ int datalen;
{
}
diff --git a/usr.sbin/mrouted/pathnames.h b/usr.sbin/mrouted/pathnames.h
index 20223144c779..22b0019f089d 100644
--- a/usr.sbin/mrouted/pathnames.h
+++ b/usr.sbin/mrouted/pathnames.h
@@ -7,7 +7,7 @@
* Leland Stanford Junior University.
*
*
- * $Id: pathnames.h,v 3.5 1995/05/09 01:00:39 fenner Exp $
+ * $Id: pathnames.h,v 3.6 1995/06/25 19:17:45 fenner Exp $
*/
#define _PATH_MROUTED_CONF "/etc/mrouted.conf"
diff --git a/usr.sbin/mrouted/prune.c b/usr.sbin/mrouted/prune.c
index 04387a1cfe71..f30b056d1fb1 100644
--- a/usr.sbin/mrouted/prune.c
+++ b/usr.sbin/mrouted/prune.c
@@ -7,7 +7,7 @@
* Leland Stanford Junior University.
*
*
- * $Id: prune.c,v 1.4 1994/08/24 23:54:33 thyagara Exp $
+ * $Id: prune.c,v 3.6 1995/06/25 19:18:43 fenner Exp $
*/
@@ -15,11 +15,18 @@
extern int cache_lifetime;
extern int max_prune_lifetime;
+extern struct rtentry *routing_table;
+
+extern int phys_vif;
/*
* dither cache lifetime to obtain a value between x and 2*x
*/
+#ifdef SYSV
+#define CACHE_LIFETIME(x) ((x) + (lrand48() % (x)))
+#else
#define CACHE_LIFETIME(x) ((x) + (random() % (x)))
+#endif
#define CHK_GS(x, y) { \
switch(x) { \
@@ -36,25 +43,75 @@ extern int max_prune_lifetime;
} \
}
-static struct ktable *kernel_rtable; /* ptr to list of kernel rt entries */
+struct gtable *kernel_table; /* ptr to list of kernel grp entries*/
+static struct gtable *kernel_no_route; /* list of grp entries w/o routes */
+struct gtable *gtp; /* pointer for kernel rt entries */
unsigned int kroutes; /* current number of cache entries */
+/****************************************************************************
+ Functions that are local to prune.c
+****************************************************************************/
+static void prun_add_ttls __P((struct gtable *gt));
+static int pruning_neighbor __P((vifi_t vifi, u_int32 addr));
+static int can_mtrace __P((vifi_t vifi, u_int32 addr));
+static struct ptable * find_prune_entry __P((u_int32 vr, struct ptable *pt));
+static void send_prune __P((struct gtable *gt));
+static void send_graft __P((struct gtable *gt));
+static void send_graft_ack __P((u_int32 src, u_int32 dst,
+ u_int32 origin, u_int32 grp));
+static void update_kernel __P((struct gtable *g));
+static char * scaletime __P((u_long t));
+
+/*
+ * Updates the ttl values for each vif.
+ */
+static void
+prun_add_ttls(gt)
+ struct gtable *gt;
+{
+ struct uvif *v;
+ vifi_t vifi;
+
+ for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
+ if (VIFM_ISSET(vifi, gt->gt_grpmems))
+ gt->gt_ttls[vifi] = v->uv_threshold;
+ else
+ gt->gt_ttls[vifi] = 0;
+ }
+}
/*
- * Initialize the kernel table structure
+ * checks for scoped multicast addresses
*/
-void init_ktable()
+#define GET_SCOPE(gt) { \
+ register int _i; \
+ if ((ntohl((gt)->gt_mcastgrp) & 0xff000000) == 0xef000000) \
+ for (_i = 0; _i < numvifs; _i++) \
+ if (scoped_addr(_i, (gt)->gt_mcastgrp)) \
+ VIFM_SET(_i, (gt)->gt_scope); \
+ }
+
+int
+scoped_addr(vifi, addr)
+ vifi_t vifi;
+ u_int32 addr;
{
- kernel_rtable = NULL;
- kroutes = 0;
+ struct vif_acl *acl;
+
+ for (acl = uvifs[vifi].uv_acl; acl; acl = acl->acl_next)
+ if ((addr & acl->acl_mask) == acl->acl_addr)
+ return 1;
+
+ return 0;
}
/*
* Determine if mcastgrp has a listener on vifi
*/
-int grplst_mem(vifi, mcastgrp)
+int
+grplst_mem(vifi, mcastgrp)
vifi_t vifi;
- u_long mcastgrp;
+ u_int32 mcastgrp;
{
register struct listaddr *g;
register struct uvif *v;
@@ -68,210 +125,764 @@ int grplst_mem(vifi, mcastgrp)
return 0;
}
-/*
- * Updates the ttl values for each vif.
+/*
+ * Finds the group entry with the specified source and netmask.
+ * If netmask is 0, it uses the route's netmask.
+ *
+ * Returns TRUE if found a match, and the global variable gtp is left
+ * pointing to entry before the found entry.
+ * Returns FALSE if no exact match found, gtp is left pointing to before
+ * the entry in question belongs, or is NULL if the it belongs at the
+ * head of the list.
*/
-void prun_add_ttls(kt)
- struct ktable *kt;
+int
+find_src_grp(src, mask, grp)
+ u_int32 src;
+ u_int32 mask;
+ u_int32 grp;
{
- struct uvif *v;
+ struct gtable *gt;
+
+ gtp = NULL;
+ gt = kernel_table;
+ while (gt != NULL) {
+ if (grp == gt->gt_mcastgrp &&
+ (mask ? (gt->gt_route->rt_origin == src &&
+ gt->gt_route->rt_originmask == mask) :
+ ((src & gt->gt_route->rt_originmask) ==
+ gt->gt_route->rt_origin)))
+ return TRUE;
+ if (ntohl(grp) > ntohl(gt->gt_mcastgrp) ||
+ (grp == gt->gt_mcastgrp &&
+ (ntohl(mask) < ntohl(gt->gt_route->rt_originmask) ||
+ (mask == gt->gt_route->rt_originmask &&
+ (ntohl(src) > ntohl(gt->gt_route->rt_origin)))))) {
+ gtp = gt;
+ gt = gt->gt_gnext;
+ }
+ else break;
+ }
+ return FALSE;
+}
+
+/*
+ * Check if the neighbor supports pruning
+ */
+static int
+pruning_neighbor(vifi, addr)
vifi_t vifi;
+ u_int32 addr;
+{
+ struct listaddr *n = neighbor_info(vifi, addr);
+ int vers;
+
+ if (n == NULL)
+ return 0;
+
+ if (n->al_flags & NF_PRUNE)
+ return 1;
+
+ /*
+ * Versions from 3.0 to 3.4 relied on the version number to identify
+ * that they could handle pruning.
+ */
+ vers = NBR_VERS(n);
+ return (vers >= 0x0300 && vers <= 0x0304);
+}
+
+/*
+ * Can the neighbor in question handle multicast traceroute?
+ */
+static int
+can_mtrace(vifi, addr)
+ vifi_t vifi;
+ u_int32 addr;
+{
+ struct listaddr *n = neighbor_info(vifi, addr);
+ int vers;
+
+ if (n == NULL)
+ return 0;
+
+ if (n->al_flags & NF_MTRACE)
+ return 1;
+
+ /*
+ * Versions 3.3 and 3.4 relied on the version number to identify
+ * that they could handle traceroute.
+ */
+ vers = NBR_VERS(n);
+ return (vers >= 0x0303 && vers <= 0x0304);
+}
+
+/*
+ * Returns the prune entry of the router, or NULL if none exists
+ */
+static struct ptable *
+find_prune_entry(vr, pt)
+ u_int32 vr;
+ struct ptable *pt;
+{
+ while (pt) {
+ if (pt->pt_router == vr)
+ return pt;
+ pt = pt->pt_next;
+ }
+
+ return NULL;
+}
+
+/*
+ * Send a prune message to the dominant router for
+ * this source.
+ *
+ * Record an entry that a prune was sent for this group
+ */
+static void
+send_prune(gt)
+ struct gtable *gt;
+{
+ struct ptable *pt;
+ char *p;
+ int i;
+ int datalen;
+ u_int32 src;
+ u_int32 dst;
+ u_int32 tmp;
- for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
- if (VIFM_ISSET(vifi, kt->kt_grpmems))
- kt->kt_ttls[vifi] = v->uv_threshold;
- else
- kt->kt_ttls[vifi] = NULL;
+ /* Don't process any prunes if router is not pruning */
+ if (pruning == 0)
+ return;
+
+ /* Can't process a prune if we don't have an associated route */
+ if (gt->gt_route == NULL)
+ return;
+
+ /* Don't send a prune to a non-pruning router */
+ if (!pruning_neighbor(gt->gt_route->rt_parent, gt->gt_route->rt_gateway))
+ return;
+
+ /*
+ * sends a prune message to the router upstream.
+ */
+ src = uvifs[gt->gt_route->rt_parent].uv_lcl_addr;
+ dst = gt->gt_route->rt_gateway;
+
+ p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
+ datalen = 0;
+
+ /*
+ * determine prune lifetime
+ */
+ gt->gt_prsent_timer = gt->gt_timer;
+ for (pt = gt->gt_pruntbl; pt; pt = pt->pt_next)
+ if (pt->pt_timer < gt->gt_prsent_timer)
+ gt->gt_prsent_timer = pt->pt_timer;
+
+ /*
+ * If we have a graft pending, cancel graft retransmission
+ */
+ gt->gt_grftsnt = 0;
+
+ for (i = 0; i < 4; i++)
+ *p++ = ((char *)&(gt->gt_route->rt_origin))[i];
+ for (i = 0; i < 4; i++)
+ *p++ = ((char *)&(gt->gt_mcastgrp))[i];
+ tmp = htonl(gt->gt_prsent_timer);
+ for (i = 0; i < 4; i++)
+ *p++ = ((char *)&(tmp))[i];
+ datalen += 12;
+
+ send_igmp(src, dst, IGMP_DVMRP, DVMRP_PRUNE,
+ htonl(MROUTED_LEVEL), datalen);
+
+ log(LOG_DEBUG, 0, "sent prune for (%s %s)/%d on vif %d to %s",
+ inet_fmts(gt->gt_route->rt_origin, gt->gt_route->rt_originmask, s1),
+ inet_fmt(gt->gt_mcastgrp, s2),
+ gt->gt_prsent_timer, gt->gt_route->rt_parent,
+ inet_fmt(gt->gt_route->rt_gateway, s3));
+}
+
+/*
+ * a prune was sent upstream
+ * so, a graft has to be sent to annul the prune
+ * set up a graft timer so that if an ack is not
+ * heard within that time, another graft request
+ * is sent out.
+ */
+static void
+send_graft(gt)
+ struct gtable *gt;
+{
+ register char *p;
+ register int i;
+ int datalen;
+ u_int32 src;
+ u_int32 dst;
+
+ /* Can't send a graft without an associated route */
+ if (gt->gt_route == NULL)
+ return;
+
+ src = uvifs[gt->gt_route->rt_parent].uv_lcl_addr;
+ dst = gt->gt_route->rt_gateway;
+
+ p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
+ datalen = 0;
+
+ for (i = 0; i < 4; i++)
+ *p++ = ((char *)&(gt->gt_route->rt_origin))[i];
+ for (i = 0; i < 4; i++)
+ *p++ = ((char *)&(gt->gt_mcastgrp))[i];
+ datalen += 8;
+
+ if (datalen != 0) {
+ send_igmp(src, dst, IGMP_DVMRP, DVMRP_GRAFT,
+ htonl(MROUTED_LEVEL), datalen);
}
+ log(LOG_DEBUG, 0, "sent graft for (%s %s) to %s on vif %d",
+ inet_fmts(gt->gt_route->rt_origin, gt->gt_route->rt_originmask, s1),
+ inet_fmt(gt->gt_mcastgrp, s2),
+ inet_fmt(gt->gt_route->rt_gateway, s3), gt->gt_route->rt_parent);
}
/*
- * checks for scoped multicast addresses
+ * Send an ack that a graft was received
*/
-#define GET_SCOPE(kt) { \
- register int _i; \
- if (((kt)->kt_mcastgrp & 0xff000000) == 0xef000000) \
- for (_i = 0; _i < numvifs; _i++) \
- if (scoped_addr(_i, (kt)->kt_mcastgrp)) \
- VIFM_SET(_i, (kt)->kt_scope); \
- }
+static void
+send_graft_ack(src, dst, origin, grp)
+ u_int32 src;
+ u_int32 dst;
+ u_int32 origin;
+ u_int32 grp;
+{
+ register char *p;
+ register int i;
+ int datalen;
-int scoped_addr(vifi, addr)
- vifi_t vifi;
- u_long addr;
+ p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
+ datalen = 0;
+
+ for (i = 0; i < 4; i++)
+ *p++ = ((char *)&(origin))[i];
+ for (i = 0; i < 4; i++)
+ *p++ = ((char *)&(grp))[i];
+ datalen += 8;
+
+ send_igmp(src, dst, IGMP_DVMRP, DVMRP_GRAFT_ACK,
+ htonl(MROUTED_LEVEL), datalen);
+
+ log(LOG_DEBUG, 0, "sent graft ack for (%s, %s) to %s",
+ inet_fmt(origin, s1), inet_fmt(grp, s2), inet_fmt(dst, s3));
+}
+
+/*
+ * Update the kernel cache with all the routes hanging off the group entry
+ */
+static void
+update_kernel(g)
+ struct gtable *g;
{
- struct vif_acl *acl;
+ struct stable *st;
- for (acl = uvifs[vifi].uv_acl; acl; acl = acl->acl_next)
- if ((addr & acl->acl_mask) == acl->acl_addr)
- return 1;
+ for (st = g->gt_srctbl; st; st = st->st_next)
+ k_add_rg(st->st_origin, g);
+}
- return 0;
+/****************************************************************************
+ Functions that are used externally
+****************************************************************************/
+
+#ifdef SNMP
+#include <sys/types.h>
+#include "snmp.h"
+
+/*
+ * Find a specific group entry in the group table
+ */
+struct gtable *
+find_grp(grp)
+ u_long grp;
+{
+ struct gtable *gt;
+
+ for (gt = kernel_table; gt; gt = gt->gt_gnext) {
+ if (ntohl(grp) < ntohl(gt->gt_mcastgrp))
+ break;
+ if (gt->gt_mcastgrp == grp)
+ return gt;
+ }
+ return NULL;
+}
+
+/*
+ * Given a group entry and source, find the corresponding source table
+ * entry
+ */
+struct stable *
+find_grp_src(gt, src)
+ struct gtable *gt;
+ u_long src;
+{
+ struct stable *st;
+ u_long grp = gt->gt_mcastgrp;
+ struct gtable *gtcurr;
+
+ for (gtcurr = gt; gtcurr->gt_mcastgrp == grp; gtcurr = gtcurr->gt_gnext) {
+ for (st = gtcurr->gt_srctbl; st; st = st->st_next)
+ if (st->st_origin == src)
+ return st;
+ }
+ return NULL;
+}
+
+/*
+ * Find next entry > specification
+ */
+int
+next_grp_src_mask(gtpp, stpp, grp, src, mask)
+ struct gtable **gtpp; /* ordered by group */
+ struct stable **stpp; /* ordered by source */
+ u_long grp;
+ u_long src;
+ u_long mask;
+{
+ struct gtable *gt, *gbest = NULL;
+ struct stable *st, *sbest = NULL;
+
+ /* Find first group entry >= grp spec */
+ (*gtpp) = kernel_table;
+ while ((*gtpp) && ntohl((*gtpp)->gt_mcastgrp) < ntohl(grp))
+ (*gtpp)=(*gtpp)->gt_gnext;
+ if (!(*gtpp))
+ return 0; /* no more groups */
+
+ for (gt = kernel_table; gt; gt=gt->gt_gnext) {
+ /* Since grps are ordered, we can stop when group changes from gbest */
+ if (gbest && gbest->gt_mcastgrp != gt->gt_mcastgrp)
+ break;
+ for (st = gt->gt_srctbl; st; st=st->st_next) {
+
+ /* Among those entries > spec, find "lowest" one */
+ if (((ntohl(gt->gt_mcastgrp)> ntohl(grp))
+ || (ntohl(gt->gt_mcastgrp)==ntohl(grp)
+ && ntohl(st->st_origin)> ntohl(src))
+ || (ntohl(gt->gt_mcastgrp)==ntohl(grp)
+ && ntohl(st->st_origin)==src && 0xFFFFFFFF>ntohl(mask)))
+ && (!gbest
+ || (ntohl(gt->gt_mcastgrp)< ntohl(gbest->gt_mcastgrp))
+ || (ntohl(gt->gt_mcastgrp)==ntohl(gbest->gt_mcastgrp)
+ && ntohl(st->st_origin)< ntohl(sbest->st_origin)))) {
+ gbest = gt;
+ sbest = st;
+ }
+ }
+ }
+ (*gtpp) = gbest;
+ (*stpp) = sbest;
+ return (*gtpp)!=0;
+}
+
+/*
+ * Ensure that sg contains current information for the given group,source.
+ * This is fetched from the kernel as a unit so that counts for the entry
+ * are consistent, i.e. packet and byte counts for the same entry are
+ * read at the same time.
+ */
+void
+refresh_sg(sg, gt, st)
+ struct sioc_sg_req *sg;
+ struct gtable *gt;
+ struct stable *st;
+{
+ static int lastq = -1;
+
+ if (quantum != lastq || sg->src.s_addr!=st->st_origin
+ || sg->grp.s_addr!=gt->gt_mcastgrp) {
+ lastq = quantum;
+ sg->src.s_addr = st->st_origin;
+ sg->grp.s_addr = gt->gt_mcastgrp;
+ ioctl(udp_socket, SIOCGETSGCNT, (char *)sg);
+ }
+}
+
+/*
+ * Return pointer to a specific route entry. This must be a separate
+ * function from find_route() which modifies rtp.
+ */
+struct rtentry *
+snmp_find_route(src, mask)
+ register u_long src, mask;
+{
+ register struct rtentry *rt;
+
+ for (rt = routing_table; rt; rt = rt->rt_next) {
+ if (src == rt->rt_origin && mask == rt->rt_originmask)
+ return rt;
+ }
+ return NULL;
+}
+
+/*
+ * Find next route entry > specification
+ */
+int
+next_route(rtpp, src, mask)
+ struct rtentry **rtpp;
+ u_long src;
+ u_long mask;
+{
+ struct rtentry *rt, *rbest = NULL;
+
+ /* Among all entries > spec, find "lowest" one in order */
+ for (rt = routing_table; rt; rt=rt->rt_next) {
+ if ((ntohl(rt->rt_origin) > ntohl(src)
+ || (ntohl(rt->rt_origin) == ntohl(src)
+ && ntohl(rt->rt_originmask) > ntohl(mask)))
+ && (!rbest || (ntohl(rt->rt_origin) < ntohl(rbest->rt_origin))
+ || (ntohl(rt->rt_origin) == ntohl(rbest->rt_origin)
+ && ntohl(rt->rt_originmask) < ntohl(rbest->rt_originmask))))
+ rbest = rt;
+ }
+ (*rtpp) = rbest;
+ return (*rtpp)!=0;
+}
+
+/*
+ * Given a routing table entry, and a vifi, find the next vifi/entry
+ */
+int
+next_route_child(rtpp, src, mask, vifi)
+ struct rtentry **rtpp;
+ u_long src;
+ u_long mask;
+ vifi_t *vifi; /* vif at which to start looking */
+{
+ struct rtentry *rt;
+
+ /* Get (S,M) entry */
+ if (!((*rtpp) = snmp_find_route(src,mask)))
+ if (!next_route(rtpp, src, mask))
+ return 0;
+
+ /* Continue until we get one with a valid next vif */
+ do {
+ for (; (*rtpp)->rt_children && *vifi<numvifs; (*vifi)++)
+ if (VIFM_ISSET(*vifi, (*rtpp)->rt_children))
+ return 1;
+ *vifi = 0;
+ } while( next_route(rtpp, (*rtpp)->rt_origin, (*rtpp)->rt_originmask) );
+
+ return 0;
+}
+
+/*
+ * Given a routing table entry, and a vifi, find the next entry
+ * equal to or greater than those
+ */
+int
+next_child(gtpp, stpp, grp, src, mask, vifi)
+ struct gtable **gtpp;
+ struct stable **stpp;
+ u_long grp;
+ u_long src;
+ u_long mask;
+ vifi_t *vifi; /* vif at which to start looking */
+{
+ struct stable *st;
+
+ /* Get (G,S,M) entry */
+ if (mask!=0xFFFFFFFF
+ || !((*gtpp) = find_grp(grp))
+ || !((*stpp) = find_grp_src((*gtpp),src)))
+ if (!next_grp_src_mask(gtpp, stpp, grp, src, mask))
+ return 0;
+
+ /* Continue until we get one with a valid next vif */
+ do {
+ for (; (*gtpp)->gt_route->rt_children && *vifi<numvifs; (*vifi)++)
+ if (VIFM_ISSET(*vifi, (*gtpp)->gt_route->rt_children))
+ return 1;
+ *vifi = 0;
+ } while (next_grp_src_mask(gtpp, stpp, (*gtpp)->gt_mcastgrp,
+ (*stpp)->st_origin, 0xFFFFFFFF) );
+
+ return 0;
+}
+#endif /* SNMP */
+
+/*
+ * Initialize the kernel table structure
+ */
+void
+init_ktable()
+{
+ kernel_table = NULL;
+ kernel_no_route = NULL;
+ kroutes = 0;
}
/*
* Add a new table entry for (origin, mcastgrp)
*/
-void add_table_entry(origin, mcastgrp)
- u_long origin;
- u_long mcastgrp;
+void
+add_table_entry(origin, mcastgrp)
+ u_int32 origin;
+ u_int32 mcastgrp;
{
struct rtentry *r;
- struct ktable *kt;
+ struct gtable *gt,**gtnp,*prev_gt;
+ struct stable *st,**stnp;
int i;
- if ((kt = find_src_grp(origin, mcastgrp)) != NULL) {
- log(LOG_DEBUG, 0, "kernel entry exists for (%s %s)",
- inet_fmt(origin, s1), inet_fmt(mcastgrp, s2));
- return;
- }
-
r = determine_route(origin);
-
- /* allocate space for the new entry */
- kt = (struct ktable *)malloc(sizeof(struct ktable));
- if (kt == NULL)
- log(LOG_ERR, 0, "ran out of memory"); /* fatal */
-
- kroutes++;
-
- /* add the new values in */
+ prev_gt = NULL;
if (r == NULL) {
- kt->kt_origin = origin;
- kt->kt_mcastgrp = mcastgrp;
- kt->kt_originmask = 0xffffffff;
- kt->kt_parent = NO_VIF;
- kt->kt_gateway = 0;
- kt->kt_children = 0;
- kt->kt_leaves = 0;
- kt->kt_timer = CACHE_LIFETIME(cache_lifetime);
- kt->kt_grpmems = 0;
- kt->kt_rlist = NULL;
- kt->kt_prsent_timer = 0;
- kt->kt_grftsnt = 0;
- kt->kt_prun_count = 0;
- kt->kt_scope = 0;
+ /*
+ * Look for it on the no_route table; if it is found then
+ * it will be detected as a duplicate below.
+ */
+ for (gt = kernel_no_route; gt; gt = gt->gt_next)
+ if (mcastgrp == gt->gt_mcastgrp &&
+ gt->gt_srctbl && gt->gt_srctbl->st_origin == origin)
+ break;
+ gtnp = &kernel_no_route;
+ } else {
+ gtnp = &r->rt_groups;
+ while ((gt = *gtnp) != NULL) {
+ if (gt->gt_mcastgrp >= mcastgrp)
+ break;
+ gtnp = &gt->gt_next;
+ prev_gt = gt;
+ }
}
- else {
- kt->kt_origin = r->rt_origin;
- kt->kt_mcastgrp = mcastgrp;
- kt->kt_originmask = r->rt_originmask;
- kt->kt_parent = r->rt_parent;
- kt->kt_gateway = r->rt_gateway;
- kt->kt_timer = CACHE_LIFETIME(cache_lifetime);
- kt->kt_grpmems = 0;
- kt->kt_rlist = NULL;
- kt->kt_prsent_timer = 0;
- kt->kt_grftsnt = 0;
- kt->kt_prun_count = 0;
- kt->kt_scope = 0;
-
- VIFM_COPY(r->rt_children, kt->kt_children);
- VIFM_COPY(r->rt_leaves, kt->kt_leaves);
- /* obtain the multicast group membership list */
- for (i = 0; i < numvifs; i++) {
- if (VIFM_ISSET(i, kt->kt_children) &&
- !(VIFM_ISSET(i, kt->kt_leaves)))
- VIFM_SET(i, kt->kt_grpmems);
-
- if (VIFM_ISSET(i, kt->kt_leaves) && grplst_mem(i, mcastgrp))
- VIFM_SET(i, kt->kt_grpmems);
+ if (gt == NULL || gt->gt_mcastgrp != mcastgrp) {
+ gt = (struct gtable *)malloc(sizeof(struct gtable));
+ if (gt == NULL)
+ log(LOG_ERR, 0, "ran out of memory");
+
+ gt->gt_mcastgrp = mcastgrp;
+ gt->gt_timer = CACHE_LIFETIME(cache_lifetime);
+ time(&gt->gt_ctime);
+ gt->gt_grpmems = 0;
+ gt->gt_scope = 0;
+ gt->gt_prsent_timer = 0;
+ gt->gt_grftsnt = 0;
+ gt->gt_srctbl = NULL;
+ gt->gt_pruntbl = NULL;
+ gt->gt_route = r;
+#ifdef RSRR
+ gt->gt_rsrr_cache = NULL;
+#endif
+
+ if (r != NULL) {
+ /* obtain the multicast group membership list */
+ for (i = 0; i < numvifs; i++) {
+ if (VIFM_ISSET(i, r->rt_children) &&
+ !(VIFM_ISSET(i, r->rt_leaves)))
+ VIFM_SET(i, gt->gt_grpmems);
+
+ if (VIFM_ISSET(i, r->rt_leaves) && grplst_mem(i, mcastgrp))
+ VIFM_SET(i, gt->gt_grpmems);
+ }
+ GET_SCOPE(gt);
+ if (VIFM_ISSET(r->rt_parent, gt->gt_scope))
+ gt->gt_scope = -1;
+ gt->gt_grpmems &= ~gt->gt_scope;
+ } else {
+ gt->gt_scope = -1;
+ gt->gt_grpmems = 0;
+ }
+
+ /* update ttls */
+ prun_add_ttls(gt);
+
+ gt->gt_next = *gtnp;
+ *gtnp = gt;
+ if (gt->gt_next)
+ gt->gt_next->gt_prev = gt;
+ gt->gt_prev = prev_gt;
+
+ if (r) {
+ if (find_src_grp(r->rt_origin, r->rt_originmask, gt->gt_mcastgrp)) {
+ struct gtable *g;
+
+ g = gtp ? gtp->gt_gnext : kernel_table;
+ log(LOG_WARNING, 0, "Entry for (%s %s) (rt:%x) exists (rt:%x)",
+ inet_fmts(r->rt_origin, r->rt_originmask, s1),
+ inet_fmt(g->gt_mcastgrp, s2),
+ r, g->gt_route);
+ } else {
+ if (gtp) {
+ gt->gt_gnext = gtp->gt_gnext;
+ gt->gt_gprev = gtp;
+ gtp->gt_gnext = gt;
+ } else {
+ gt->gt_gnext = kernel_table;
+ gt->gt_gprev = NULL;
+ kernel_table = gt;
+ }
+ if (gt->gt_gnext)
+ gt->gt_gnext->gt_gprev = gt;
+ }
+ } else {
+ gt->gt_gnext = gt->gt_prev = NULL;
}
- GET_SCOPE(kt);
- if (VIFM_ISSET(kt->kt_parent, kt->kt_scope))
- kt->kt_grpmems = NULL;
- else
- kt->kt_grpmems &= ~kt->kt_scope;
}
-
- /* update the kernel_rtable pointer */
- kt->kt_next = kernel_rtable;
- kernel_rtable = kt;
-
- /* update ttls and add entry into kernel */
- prun_add_ttls(kt);
- k_add_rg(kt);
-
- log(LOG_DEBUG, 0, "add entry s:%x g:%x gm:%x",
- kt->kt_origin, kt->kt_mcastgrp, kt->kt_grpmems);
+
+ stnp = &gt->gt_srctbl;
+ while ((st = *stnp) != NULL) {
+ if (ntohl(st->st_origin) >= ntohl(origin))
+ break;
+ stnp = &st->st_next;
+ }
+
+ if (st == NULL || st->st_origin != origin) {
+ st = (struct stable *)malloc(sizeof(struct stable));
+ if (st == NULL)
+ log(LOG_ERR, 0, "ran out of memory");
+
+ st->st_origin = origin;
+ st->st_pktcnt = 0;
+ st->st_next = *stnp;
+ *stnp = st;
+ } else {
+ log(LOG_WARNING, 0, "kernel entry already exists for (%s %s)",
+ inet_fmt(origin, s1), inet_fmt(mcastgrp, s2));
+ return;
+ }
+
+ kroutes++;
+ k_add_rg(origin, gt);
+
+ log(LOG_DEBUG, 0, "add cache entry (%s %s) gm:%x, parent-vif:%d",
+ inet_fmt(origin, s1),
+ inet_fmt(mcastgrp, s2),
+ gt->gt_grpmems, r ? r->rt_parent : -1);
/* If there are no leaf vifs
* which have this group, then
* mark this src-grp as a prune candidate.
- * One thing to do is to check if parent vif is the source
- * and not send a prune to that.
*/
- if (!kt->kt_grpmems && kt->kt_gateway)
- send_prune(kt);
+ if (!gt->gt_prsent_timer && !gt->gt_grpmems && r && r->rt_gateway)
+ send_prune(gt);
}
/*
* An mrouter has gone down and come up on an interface
* Forward on that interface immediately
*/
-void reset_neighbor_state(vifi, addr)
+void
+reset_neighbor_state(vifi, addr)
vifi_t vifi;
- u_long addr;
+ u_int32 addr;
{
- struct ktable *prev_kt, *kt;
- struct prunlst *prev_krl, *krl;
+ struct rtentry *r;
+ struct gtable *g;
+ struct ptable *pt, *prev_pt;
+ struct stable *st, *prev_st;
- /* Check each src-grp entry to see if it was pruned on that interface
- If so, forward on that interface */
- for (prev_kt = (struct ktable *)&kernel_rtable,
- kt = kernel_rtable; kt;
- prev_kt = kt, kt = kt->kt_next) {
- for (prev_krl = (struct prunlst *)&kt->kt_rlist,
- krl = prev_krl->rl_next;
- krl;
- prev_krl = krl, krl = krl->rl_next) {
- if (krl->rl_router == addr) {
- prev_krl->rl_next = krl->rl_next;
- free(krl);
- krl = prev_krl;
- kt->kt_prun_count--;
- }
- }
+ for (g = kernel_table; g; g = g->gt_gnext) {
+ r = g->gt_route;
/*
* If neighbor was the parent, remove the prune sent state
* Don't send any grafts upstream.
*/
- if (vifi == kt->kt_parent) {
- k_del_rg(kt);
- prev_kt->kt_next = kt->kt_next;
- while (krl = kt->kt_rlist) {
- kt->kt_rlist = krl->rl_next;
- free((char *)krl);
+ if (vifi == r->rt_parent) {
+ if (addr == r->rt_gateway) {
+ log(LOG_DEBUG, 0, "reset_neighbor_state del prunes (%s %s)",
+ inet_fmts(r->rt_origin, r->rt_originmask, s1),
+ inet_fmt(g->gt_mcastgrp, s2));
+
+ pt = g->gt_pruntbl;
+ while (pt) {
+ /*
+ * Expire prune, send again on this vif.
+ */
+ VIFM_SET(pt->pt_vifi, g->gt_grpmems);
+ prev_pt = pt;
+ pt = prev_pt->pt_next;
+ free(prev_pt);
+ }
+ g->gt_pruntbl = NULL;
+
+ st = g->gt_srctbl;
+ while (st) {
+ log(LOG_DEBUG, 0, "reset_neighbor_state del sg (%s %s)",
+ inet_fmt(st->st_origin, s1),
+ inet_fmt(g->gt_mcastgrp, s2));
+
+ if (k_del_rg(st->st_origin, g) < 0) {
+ log(LOG_WARNING, errno,
+ "reset_neighbor_state trying to delete (%s %s)",
+ inet_fmt(st->st_origin, s1),
+ inet_fmt(g->gt_mcastgrp, s2));
+ }
+ kroutes--;
+ prev_st = st;
+ st = prev_st->st_next;
+ free(prev_st);
+ }
+ g->gt_srctbl = NULL;
+ /*
+ * Keep the group entries themselves around since the
+ * state will likely just come right back, and if not,
+ * the group entries will time out with no kernel entries
+ * and no prune state.
+ */
+ g->gt_prsent_timer = 0;
+ g->gt_grftsnt = 0;
+ }
+ } else {
+ /*
+ * Neighbor was not the parent, send grafts to join the groups
+ */
+ if (g->gt_prsent_timer) {
+ g->gt_grftsnt = 1;
+ send_graft(g);
+ g->gt_prsent_timer = 0;
}
- free((char *)kt);
- kt = prev_kt;
- kroutes--;
- continue;
- }
- /*
- * Neighbor was not the parent, send grafts to join the groups
- */
- if (kt->kt_prsent_timer) {
- kt->kt_grftsnt = 1;
- send_graft(kt);
- kt->kt_prsent_timer = 0;
- }
+ /*
+ * Remove any prunes that this router has sent us.
+ */
+ prev_pt = (struct ptable *)&g->gt_pruntbl;
+ for (pt = g->gt_pruntbl; pt; pt = pt->pt_next) {
+ if (pt->pt_vifi == vifi && pt->pt_router == addr) {
+ prev_pt->pt_next = pt->pt_next;
+ free(pt);
+ } else
+ prev_pt = pt;
+ }
- if (!VIFM_ISSET(vifi, kt->kt_grpmems)) {
- if (VIFM_ISSET(vifi, kt->kt_children) &&
- !(VIFM_ISSET(vifi, kt->kt_leaves)))
- VIFM_SET(vifi, kt->kt_grpmems);
-
- if (VIFM_ISSET(vifi, kt->kt_leaves) &&
- grplst_mem(vifi, kt->kt_mcastgrp))
- VIFM_SET(vifi, kt->kt_grpmems);
-
- kt->kt_grpmems &= ~kt->kt_scope;
- prun_add_ttls(kt);
- k_add_rg(kt);
+ /*
+ * And see if we want to forward again.
+ */
+ if (!VIFM_ISSET(vifi, g->gt_grpmems)) {
+ if (VIFM_ISSET(vifi, r->rt_children) &&
+ !(VIFM_ISSET(vifi, r->rt_leaves)))
+ VIFM_SET(vifi, g->gt_grpmems);
+
+ if (VIFM_ISSET(vifi, r->rt_leaves) &&
+ grplst_mem(vifi, g->gt_mcastgrp))
+ VIFM_SET(vifi, g->gt_grpmems);
+
+ g->gt_grpmems &= ~g->gt_scope;
+ prun_add_ttls(g);
+
+ /* Update kernel state */
+ update_kernel(g);
+#ifdef RSRR
+ /* Send route change notification to reservation protocol. */
+ rsrr_cache_send(g,1);
+#endif /* RSRR */
+
+ log(LOG_DEBUG, 0, "reset member state (%s %s) gm:%x",
+ inet_fmts(r->rt_origin, r->rt_originmask, s1),
+ inet_fmt(g->gt_mcastgrp, s2), g->gt_grpmems);
+ }
}
}
}
@@ -280,64 +891,119 @@ void reset_neighbor_state(vifi, addr)
* Delete table entry from the kernel
* del_flag determines how many entries to delete
*/
-void del_table_entry(r, mcastgrp, del_flag)
+void
+del_table_entry(r, mcastgrp, del_flag)
struct rtentry *r;
- u_long mcastgrp;
+ u_int32 mcastgrp;
u_int del_flag;
{
- struct mfcctl mc;
- struct ktable *kt, *prev_kt;
- struct prunlst *krl;
+ struct gtable *g, *prev_g;
+ struct stable *st, *prev_st;
+ struct ptable *pt, *prev_pt;
if (del_flag == DEL_ALL_ROUTES) {
- for (prev_kt = (struct ktable *)&kernel_rtable;
- kt = prev_kt->kt_next;
- prev_kt = kt) {
- if ((kt->kt_origin & r->rt_originmask) == r->rt_origin) {
- log(LOG_DEBUG, 0, "delete all rtes %x grp %x",
- kt->kt_origin, mcastgrp);
-
- k_del_rg(kt);
-
- /* free prun list entries */
- while (kt->kt_rlist) {
- krl = kt->kt_rlist;
- kt->kt_rlist = krl->rl_next;
- free((char *)krl);
+ g = r->rt_groups;
+ while (g) {
+ log(LOG_DEBUG, 0, "del_table_entry deleting (%s %s)",
+ inet_fmts(r->rt_origin, r->rt_originmask, s1),
+ inet_fmt(g->gt_mcastgrp, s2));
+ st = g->gt_srctbl;
+ while (st) {
+ if (k_del_rg(st->st_origin, g) < 0) {
+ log(LOG_WARNING, errno,
+ "del_table_entry trying to delete (%s, %s)",
+ inet_fmt(st->st_origin, s1),
+ inet_fmt(g->gt_mcastgrp, s2));
}
-
- /* free the source mcastgrp entry */
- prev_kt->kt_next = kt->kt_next;
- free((char *)kt);
kroutes--;
- kt = prev_kt;
+ prev_st = st;
+ st = st->st_next;
+ free(prev_st);
}
+ g->gt_srctbl = NULL;
+
+ pt = g->gt_pruntbl;
+ while (pt) {
+ prev_pt = pt->pt_next;
+ free(pt);
+ pt = prev_pt;
+ }
+ g->gt_pruntbl = NULL;
+
+ if (g->gt_gnext)
+ g->gt_gnext->gt_gprev = g->gt_gprev;
+ if (g->gt_gprev)
+ g->gt_gprev->gt_gnext = g->gt_gnext;
+ else
+ kernel_table = g->gt_gnext;
+
+ prev_g = g->gt_next;
+#ifdef RSRR
+ /* Send route change notification to reservation protocol. */
+ rsrr_cache_send(g,0);
+ rsrr_cache_clean(g);
+#endif /* RSRR */
+ free(g);
+ g = prev_g;
}
+ r->rt_groups = NULL;
}
+ /*
+ * Dummy routine - someday this may be needed, so it is just there
+ */
if (del_flag == DEL_RTE_GROUP) {
- for (prev_kt = (struct ktable *)&kernel_rtable;
- (prev_kt) && (kt = prev_kt->kt_next);
- prev_kt = kt) {
- if ((kt->kt_origin & r->rt_originmask) == r->rt_origin &&
- kt->kt_mcastgrp == mcastgrp) {
- log(LOG_DEBUG, 0, "delete src %x grp %x",
- kt->kt_origin, mcastgrp);
-
- k_del_rg(kt);
-
- /* free prun list entries */
- while (kt->kt_rlist) {
- krl = kt->kt_rlist;
- kt->kt_rlist = krl->rl_next;
- free((char *)krl);
+ prev_g = (struct gtable *)&r->rt_groups;
+ for (g = r->rt_groups; g; g = g->gt_next) {
+ if (g->gt_mcastgrp == mcastgrp) {
+ log(LOG_DEBUG, 0, "del_table_entry deleting (%s %s)",
+ inet_fmts(r->rt_origin, r->rt_originmask, s1),
+ inet_fmt(g->gt_mcastgrp, s2));
+ st = g->gt_srctbl;
+ while (st) {
+ if (k_del_rg(st->st_origin, g) < 0) {
+ log(LOG_WARNING, errno,
+ "del_table_entry trying to delete (%s, %s)",
+ inet_fmt(st->st_origin, s1),
+ inet_fmt(g->gt_mcastgrp, s2));
+ }
+ kroutes--;
+ prev_st = st->st_next;
+ free(st);
+ st = prev_st;
}
-
- /* free the source mcastgrp entry */
- prev_kt->kt_next = kt->kt_next;
- free((char *)kt);
- kroutes--;
- break;
+ g->gt_srctbl = NULL;
+
+ pt = g->gt_pruntbl;
+ while (pt) {
+ prev_pt = pt->pt_next;
+ free(pt);
+ pt = prev_pt;
+ }
+ g->gt_pruntbl = NULL;
+
+ if (g->gt_gnext)
+ g->gt_gnext->gt_gprev = g->gt_gprev;
+ if (g->gt_gprev)
+ g->gt_gprev->gt_gnext = g->gt_gnext;
+ else
+ kernel_table = g->gt_gnext;
+
+ if (prev_g != (struct gtable *)&r->rt_groups)
+ g->gt_next->gt_prev = prev_g;
+ else
+ g->gt_next->gt_prev = NULL;
+ prev_g->gt_next = g->gt_next;
+
+#ifdef RSRR
+ /* Send route change notification to reservation protocol. */
+ rsrr_cache_send(g,0);
+ rsrr_cache_clean(g);
+#endif /* RSRR */
+ free(g);
+ g = prev_g;
+ } else {
+ prev_g = g;
}
}
}
@@ -346,199 +1012,164 @@ void del_table_entry(r, mcastgrp, del_flag)
/*
* update kernel table entry when a route entry changes
*/
-void update_table_entry(r)
+void
+update_table_entry(r)
struct rtentry *r;
{
- struct ktable *kt;
- struct prunlst *krl;
+ struct gtable *g;
+ struct ptable *pt, *prev_pt;
int i;
- int changed;
-
- for (kt = kernel_rtable; kt; kt = kt->kt_next)
- if ((kt->kt_origin & r->rt_originmask)== r->rt_origin) {
- changed = 0;
-
- if (kt->kt_leaves != r->rt_leaves)
- changed++;
- if (kt->kt_children != r->rt_children)
- changed++;
- if (kt->kt_parent != r->rt_parent)
- changed++;
-
- if (!changed)
- continue;
-
- log(LOG_DEBUG, 0, "update entry: s %-15s g %-15s",
- inet_fmt(kt->kt_origin, s1), inet_fmt(kt->kt_mcastgrp, s2));
-
- /* free prun list entries */
- while (kt->kt_rlist) {
- krl = kt->kt_rlist;
- kt->kt_rlist = krl->rl_next;
- free((char *)krl);
- }
-
- kt->kt_parent = r->rt_parent;
- kt->kt_gateway = r->rt_gateway;
- kt->kt_grpmems = 0;
- kt->kt_prun_count = 0;
- VIFM_COPY(r->rt_children, kt->kt_children);
- VIFM_COPY(r->rt_leaves, kt->kt_leaves);
-
- /* obtain the multicast group membership list */
- for (i = 0; i < numvifs; i++) {
- if (VIFM_ISSET(i, kt->kt_children) &&
- !(VIFM_ISSET(i, kt->kt_leaves)))
- VIFM_SET(i, kt->kt_grpmems);
-
- if (VIFM_ISSET(i, kt->kt_leaves) && grplst_mem(i, kt->kt_mcastgrp))
- VIFM_SET(i, kt->kt_grpmems);
- }
- if (VIFM_ISSET(kt->kt_parent, kt->kt_scope))
- kt->kt_grpmems = NULL;
- else
- kt->kt_grpmems &= ~kt->kt_scope;
-
- if (kt->kt_grpmems && kt->kt_prsent_timer) {
- kt->kt_grftsnt = 1;
- send_graft(kt);
- kt->kt_prsent_timer = 0;
- }
-
- /* update ttls and add entry into kernel */
- prun_add_ttls(kt);
- k_add_rg(kt);
-
- if (!kt->kt_grpmems && kt->kt_gateway) {
- kt->kt_timer = CACHE_LIFETIME(cache_lifetime);
- send_prune(kt);
- }
+
+ for (g = r->rt_groups; g; g = g->gt_next) {
+ pt = g->gt_pruntbl;
+ while (pt) {
+ prev_pt = pt->pt_next;
+ free(pt);
+ pt = prev_pt;
}
-}
+ g->gt_pruntbl = NULL;
+ g->gt_grpmems = 0;
+ /* obtain the multicast group membership list */
+ for (i = 0; i < numvifs; i++) {
+ if (VIFM_ISSET(i, r->rt_children) &&
+ !(VIFM_ISSET(i, r->rt_leaves)))
+ VIFM_SET(i, g->gt_grpmems);
+
+ if (VIFM_ISSET(i, r->rt_leaves) && grplst_mem(i, g->gt_mcastgrp))
+ VIFM_SET(i, g->gt_grpmems);
+ }
+ if (VIFM_ISSET(r->rt_parent, g->gt_scope))
+ g->gt_scope = -1;
+ g->gt_grpmems &= ~g->gt_scope;
+
+ log(LOG_DEBUG, 0, "updating cache entries (%s %s) gm:%x",
+ inet_fmts(r->rt_origin, r->rt_originmask, s1),
+ inet_fmt(g->gt_mcastgrp, s2),
+ g->gt_grpmems);
+
+ if (g->gt_grpmems && g->gt_prsent_timer) {
+ g->gt_grftsnt = 1;
+ send_graft(g);
+ g->gt_prsent_timer = 0;
+ }
+
+ /* update ttls and add entry into kernel */
+ prun_add_ttls(g);
+ update_kernel(g);
+#ifdef RSRR
+ /* Send route change notification to reservation protocol. */
+ rsrr_cache_send(g,1);
+#endif /* RSRR */
+
+ /* Check if we want to prune this group */
+ if (!g->gt_prsent_timer && g->gt_grpmems == 0 && r->rt_gateway) {
+ g->gt_timer = CACHE_LIFETIME(cache_lifetime);
+ send_prune(g);
+ }
+ }
+}
/*
* set the forwarding flag for all mcastgrps on this vifi
*/
-void update_lclgrp(vifi, mcastgrp)
+void
+update_lclgrp(vifi, mcastgrp)
vifi_t vifi;
- u_long mcastgrp;
+ u_int32 mcastgrp;
{
- struct ktable *kt;
+ struct rtentry *r;
+ struct gtable *g;
- log(LOG_DEBUG, 0, "group %x joined at vif %d", mcastgrp, vifi);
+ log(LOG_DEBUG, 0, "group %s joined on vif %d",
+ inet_fmt(mcastgrp, s1), vifi);
- for (kt = kernel_rtable; kt; kt = kt->kt_next)
- if (kt->kt_mcastgrp == mcastgrp && VIFM_ISSET(vifi, kt->kt_children)) {
- VIFM_SET(vifi, kt->kt_grpmems);
- kt->kt_grpmems &= ~kt->kt_scope;
- if (kt->kt_grpmems == NULL)
+ for (g = kernel_table; g; g = g->gt_gnext) {
+ if (ntohl(mcastgrp) < ntohl(g->gt_mcastgrp))
+ break;
+
+ r = g->gt_route;
+ if (g->gt_mcastgrp == mcastgrp &&
+ VIFM_ISSET(vifi, r->rt_children)) {
+
+ VIFM_SET(vifi, g->gt_grpmems);
+ g->gt_grpmems &= ~g->gt_scope;
+ if (g->gt_grpmems == 0)
continue;
- prun_add_ttls(kt);
- k_add_rg(kt);
- }
+
+ prun_add_ttls(g);
+ log(LOG_DEBUG, 0, "update lclgrp (%s %s) gm:%x",
+ inet_fmts(r->rt_origin, r->rt_originmask, s1),
+ inet_fmt(g->gt_mcastgrp, s2), g->gt_grpmems);
+
+ update_kernel(g);
+#ifdef RSRR
+ /* Send route change notification to reservation protocol. */
+ rsrr_cache_send(g,1);
+#endif /* RSRR */
+ }
+ }
}
/*
* reset forwarding flag for all mcastgrps on this vifi
*/
-void delete_lclgrp(vifi, mcastgrp)
+void
+delete_lclgrp(vifi, mcastgrp)
vifi_t vifi;
- u_long mcastgrp;
+ u_int32 mcastgrp;
{
+ struct rtentry *r;
+ struct gtable *g;
- struct ktable *kt;
-
- log(LOG_DEBUG, 0, "group %x left at vif %d", mcastgrp, vifi);
+ log(LOG_DEBUG, 0, "group %s left on vif %d",
+ inet_fmt(mcastgrp, s1), vifi);
- for (kt = kernel_rtable; kt; kt = kt->kt_next)
- if (kt->kt_mcastgrp == mcastgrp) {
- VIFM_CLR(vifi, kt->kt_grpmems);
- prun_add_ttls(kt);
- k_add_rg(kt);
-
+ for (g = kernel_table; g; g = g->gt_gnext) {
+ if (ntohl(mcastgrp) < ntohl(g->gt_mcastgrp))
+ break;
+
+ if (g->gt_mcastgrp == mcastgrp) {
+ int stop_sending = 1;
+
+ r = g->gt_route;
/*
- * If there are no more members of this particular group,
- * send prune upstream
+ * If this is not a leaf, then we have router neighbors on this
+ * vif. Only turn off forwarding if they have all pruned.
*/
- if (kt->kt_grpmems == NULL && kt->kt_gateway)
- send_prune(kt);
- }
-}
+ if (!VIFM_ISSET(vifi, r->rt_leaves)) {
+ struct listaddr *vr;
+
+ for (vr = uvifs[vifi].uv_neighbors; vr; vr = vr->al_next)
+ if (find_prune_entry(vr->al_addr, g->gt_pruntbl) == NULL) {
+ stop_sending = 0;
+ break;
+ }
+ }
-/*
- * Check if the neighbor supports pruning
- */
-int pruning_neighbor(vifi, addr)
- vifi_t vifi;
- u_long addr;
-{
- struct listaddr *u;
-
- for (u = uvifs[vifi].uv_neighbors; u; u = u->al_next)
- if ((u->al_addr == addr) && (u->al_pv > 2))
- return 1;
+ if (stop_sending) {
+ VIFM_CLR(vifi, g->gt_grpmems);
+ log(LOG_DEBUG, 0, "delete lclgrp (%s %s) gm:%x",
+ inet_fmts(r->rt_origin, r->rt_originmask, s1),
+ inet_fmt(g->gt_mcastgrp, s2), g->gt_grpmems);
- return 0;
-}
+ prun_add_ttls(g);
+ update_kernel(g);
+#ifdef RSRR
+ /* Send route change notification to reservation protocol. */
+ rsrr_cache_send(g,1);
+#endif /* RSRR */
-/*
- * Send a prune message to the upstream router
- * given by the kt->kt_gateway argument. The origin and
- * multicast group can be determined from the kt
- * structure.
- *
- * Also, record an entry that a prune was sent for this group
- */
-void send_prune(kt)
- struct ktable *kt;
-{
- struct prunlst *krl;
- char *p;
- int i;
- int datalen;
- u_long src;
- u_long dst;
-
- /* Don't process any prunes if router is not pruning */
- if (pruning == 0)
- return;
-
- /* Don't send a prune to a non-pruning router */
- if (!pruning_neighbor(kt->kt_parent, kt->kt_gateway))
- return;
-
- /*
- * sends a prune message to the router upstream.
- */
- src = uvifs[kt->kt_parent].uv_lcl_addr;
- dst = kt->kt_gateway;
-
- p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
- datalen = 0;
-
- /*
- * determine prune lifetime
- */
- kt->kt_prsent_timer = kt->kt_timer;
- for (krl = kt->kt_rlist; krl; krl = krl->rl_next)
- if (krl->rl_timer < kt->kt_prsent_timer)
- kt->kt_prsent_timer = krl->rl_timer;
-
- for (i = 0; i < 4; i++)
- *p++ = ((char *)&(kt->kt_origin))[i];
- for (i = 0; i < 4; i++)
- *p++ = ((char *)&(kt->kt_mcastgrp))[i];
- for (i = 0; i < 4; i++)
- *p++ = ((char *)&(kt->kt_prsent_timer))[i];
- datalen += 12;
-
- send_igmp(src, dst, IGMP_DVMRP, DVMRP_PRUNE,
- htonl(MROUTED_LEVEL), datalen);
-
- /* log(LOG_DEBUG, 0, "send prune for src:%x, grp:%x up to %x",
- kt->kt_origin, kt->kt_mcastgrp, kt->kt_gateway);*/
+ /*
+ * If there are no more members of this particular group,
+ * send prune upstream
+ */
+ if (!g->gt_prsent_timer && g->gt_grpmems == 0 && r->rt_gateway)
+ send_prune(g);
+ }
+ }
+ }
}
/*
@@ -551,21 +1182,22 @@ void send_prune(kt)
*
* Determines if a corresponding prune message has to be generated
*/
-void accept_prune(src, dst, p, datalen)
- u_long src;
- u_long dst;
+void
+accept_prune(src, dst, p, datalen)
+ u_int32 src;
+ u_int32 dst;
char *p;
int datalen;
{
- u_long prun_src;
- u_long prun_dst;
- u_long prun_tmr;
+ u_int32 prun_src;
+ u_int32 prun_grp;
+ u_int32 prun_tmr;
vifi_t vifi;
int i;
int stop_sending;
- struct ktable *kt;
- struct prunlst *pr_recv;
- struct prunlst *krl;
+ struct rtentry *r;
+ struct gtable *g;
+ struct ptable *pt;
struct listaddr *vr;
/* Don't process any prunes if router is not pruning */
@@ -574,193 +1206,182 @@ void accept_prune(src, dst, p, datalen)
if ((vifi = find_vif(src, dst)) == NO_VIF) {
log(LOG_INFO, 0,
- "ignoring prune report from non-neighbor %s", inet_fmt(src, s1));
+ "ignoring prune report from non-neighbor %s",
+ inet_fmt(src, s1));
return;
}
- if (datalen < 0 || datalen > 12)
+ /* Check if enough data is present */
+ if (datalen < 12)
{
log(LOG_WARNING, 0,
- "received non-decipherable prune report from %s", inet_fmt(src, s1));
+ "non-decipherable prune from %s",
+ inet_fmt(src, s1));
return;
}
for (i = 0; i< 4; i++)
((char *)&prun_src)[i] = *p++;
for (i = 0; i< 4; i++)
- ((char *)&prun_dst)[i] = *p++;
+ ((char *)&prun_grp)[i] = *p++;
for (i = 0; i< 4; i++)
((char *)&prun_tmr)[i] = *p++;
+ prun_tmr = ntohl(prun_tmr);
- kt = find_src_grp(prun_src, prun_dst);
-
- if (kt == NULL)
- {
- log(LOG_WARNING, 0, "prune message received incorrectly");
- return;
- }
-
- if (!VIFM_ISSET(vifi, kt->kt_children))
- {
- log(LOG_INFO, 0,
- "ignoring prune report from non-child %s", inet_fmt(src, s1));
- return;
- }
- if (VIFM_ISSET(vifi, kt->kt_scope)) {
- log(LOG_INFO, 0,
- "ignoring prune report from %s on scoped vif %d",
- inet_fmt(src, s1), vifi);
- return;
- }
- /* check if prune has been received from this source */
- if (!no_entry_exists(src, kt))
- {
- log(LOG_INFO, 0, "duplicate prune from %s", inet_fmt(src, s1));
- return;
- }
-
- log(LOG_DEBUG, 0, "%s on vif %d prunes (%s %s) tmr %d",
+ log(LOG_DEBUG, 0, "%s on vif %d prunes (%s %s)/%d",
inet_fmt(src, s1), vifi,
- inet_fmt(prun_src, s2), inet_fmt(prun_dst, s3), prun_tmr);
-
- /* allocate space for the prune structure */
- pr_recv = (struct prunlst *)(malloc(sizeof(struct prunlst)));
-
- if (pr_recv == NULL)
- log(LOG_ERR, 0, "pr_recv: ran out of memory");
-
- pr_recv->rl_vifi = vifi;
- pr_recv->rl_router = src;
- pr_recv->rl_timer = prun_tmr;
-
- /*
- * add this prune message to the list of prunes received
- * for this src group pair
- */
- pr_recv->rl_next = kt->kt_rlist;
- kt->kt_rlist = pr_recv;
-
- kt->kt_prun_count++;
- kt->kt_timer = CACHE_LIFETIME(cache_lifetime);
- if (kt->kt_timer < prun_tmr)
- kt->kt_timer = prun_tmr;
-
+ inet_fmt(prun_src, s2), inet_fmt(prun_grp, s3), prun_tmr);
+
/*
- * check if any more packets need to be sent on the
- * vif which sent this message
+ * Find the subnet for the prune
*/
- for (vr = uvifs[vifi].uv_neighbors, stop_sending = 1;
- vr; vr = vr->al_next)
- if (no_entry_exists(vr->al_addr, kt)) {
- stop_sending = 0;
- break;
+ if (find_src_grp(prun_src, 0, prun_grp)) {
+ g = gtp ? gtp->gt_gnext : kernel_table;
+ r = g->gt_route;
+
+ if (!VIFM_ISSET(vifi, r->rt_children)) {
+ log(LOG_WARNING, 0, "prune received from non-child %s for (%s %s)",
+ inet_fmt(src, s1), inet_fmt(prun_src, s2),
+ inet_fmt(prun_grp, s3));
+ return;
}
-
- if (stop_sending && !grplst_mem(vifi, prun_dst)) {
- VIFM_CLR(vifi, kt->kt_grpmems);
- prun_add_ttls(kt);
- k_add_rg(kt);
- }
-
- /*
- * check if all the child routers have expressed no interest
- * in this group and if this group does not exist in the
- * interface
- * Send a prune message then upstream
- */
- if(kt->kt_grpmems == NULL && kt->kt_gateway) {
- log(LOG_DEBUG, 0, "snt prun up %d %d", kt->kt_prun_count, rtr_cnt(kt));
- send_prune(kt);
- }
-}
+ if (VIFM_ISSET(vifi, g->gt_scope)) {
+ log(LOG_WARNING, 0, "prune received from %s on scoped grp (%s %s)",
+ inet_fmt(src, s1), inet_fmt(prun_src, s2),
+ inet_fmt(prun_grp, s3));
+ return;
+ }
+ if ((pt = find_prune_entry(src, g->gt_pruntbl)) != NULL) {
+ /*
+ * If it's about to expire, then it's only still around because
+ * of timer granularity, so don't warn about it.
+ */
+ if (pt->pt_timer > 10) {
+ log(LOG_WARNING, 0, "%s %d from %s for (%s %s)/%d %s %d %s %x",
+ "duplicate prune received on vif",
+ vifi, inet_fmt(src, s1), inet_fmt(prun_src, s2),
+ inet_fmt(prun_grp, s3), prun_tmr,
+ "old timer:", pt->pt_timer, "cur gm:", g->gt_grpmems);
+ }
+ pt->pt_timer = prun_tmr;
+ } else {
+ /* allocate space for the prune structure */
+ pt = (struct ptable *)(malloc(sizeof(struct ptable)));
+ if (pt == NULL)
+ log(LOG_ERR, 0, "pt: ran out of memory");
+
+ pt->pt_vifi = vifi;
+ pt->pt_router = src;
+ pt->pt_timer = prun_tmr;
-/*
- * Returns 1 if router vr is not present in the prunlist of kt
- */
-int no_entry_exists(vr, kt)
- u_long vr;
- struct ktable *kt;
-{
- struct prunlst *krl;
-
- for (krl = kt->kt_rlist; krl; krl = krl->rl_next)
- if (krl->rl_router == vr)
- return 0;
-
- return 1;
-}
+ pt->pt_next = g->gt_pruntbl;
+ g->gt_pruntbl = pt;
+ }
-/*
- * Finds the entry for the source group pair in the table
- */
-struct ktable *find_src_grp(src, grp)
- u_long src;
- u_long grp;
-{
- struct ktable *kt;
-
- for (kt = kernel_rtable; kt; kt = kt->kt_next)
- if ((kt->kt_origin == (src & kt->kt_originmask)) &&
- (kt->kt_mcastgrp == grp))
- return kt;
-
- return NULL;
-}
+ /* Refresh the group's lifetime */
+ g->gt_timer = CACHE_LIFETIME(cache_lifetime);
+ if (g->gt_timer < prun_tmr)
+ g->gt_timer = prun_tmr;
+
+ /*
+ * check if any more packets need to be sent on the
+ * vif which sent this message
+ */
+ stop_sending = 1;
+ for (vr = uvifs[vifi].uv_neighbors; vr; vr = vr->al_next)
+ if (find_prune_entry(vr->al_addr, g->gt_pruntbl) == NULL) {
+ stop_sending = 0;
+ break;
+ }
+
+ if (stop_sending && !grplst_mem(vifi, prun_grp)) {
+ VIFM_CLR(vifi, g->gt_grpmems);
+ log(LOG_DEBUG, 0, "prune (%s %s), stop sending on vif %d, gm:%x",
+ inet_fmts(r->rt_origin, r->rt_originmask, s1),
+ inet_fmt(g->gt_mcastgrp, s2), vifi, g->gt_grpmems);
+
+ prun_add_ttls(g);
+ update_kernel(g);
+#ifdef RSRR
+ /* Send route change notification to reservation protocol. */
+ rsrr_cache_send(g,1);
+#endif /* RSRR */
+ }
-/*
- * scans through the neighbor list of this router and then
- * determines the total no. of child routers present
- */
-int rtr_cnt(kt)
- struct ktable *kt;
-{
- int ri;
- int rcount = 0;
- struct listaddr *u;
-
- for (ri = 0; ri < numvifs; ri++)
- if (VIFM_ISSET(ri, kt->kt_children))
- for(u = uvifs[ri].uv_neighbors; u; u = u->al_next)
- rcount++;
-
- return rcount;
+ /*
+ * check if all the child routers have expressed no interest
+ * in this group and if this group does not exist in the
+ * interface
+ * Send a prune message then upstream
+ */
+ if (!g->gt_prsent_timer && g->gt_grpmems == 0 && r->rt_gateway) {
+ send_prune(g);
+ }
+ } else {
+ /*
+ * There is no kernel entry for this group. Therefore, we can
+ * simply ignore the prune, as we are not forwarding this traffic
+ * downstream.
+ */
+ log(LOG_DEBUG, 0, "%s (%s %s)/%d from %s",
+ "prune message received with no kernel entry for",
+ inet_fmt(prun_src, s1), inet_fmt(prun_grp, s2),
+ prun_tmr, inet_fmt(src, s3));
+ return;
+ }
}
/*
* Checks if this mcastgrp is present in the kernel table
* If so and if a prune was sent, it sends a graft upwards
*/
-void chkgrp_graft(vifi, mcastgrp)
+void
+chkgrp_graft(vifi, mcastgrp)
vifi_t vifi;
- u_long mcastgrp;
+ u_int32 mcastgrp;
{
- struct ktable *kt;
-
- for (kt = kernel_rtable; kt; kt = kt->kt_next)
- if (kt->kt_mcastgrp == mcastgrp && VIFM_ISSET(vifi, kt->kt_children))
- if (kt->kt_prsent_timer) {
- VIFM_SET(vifi, kt->kt_grpmems);
+ struct rtentry *r;
+ struct gtable *g;
+
+ for (g = kernel_table; g; g = g->gt_gnext) {
+ if (ntohl(mcastgrp) < ntohl(g->gt_mcastgrp))
+ break;
+
+ r = g->gt_route;
+ if (g->gt_mcastgrp == mcastgrp && VIFM_ISSET(vifi, r->rt_children))
+ if (g->gt_prsent_timer) {
+ VIFM_SET(vifi, g->gt_grpmems);
+
/*
* If the vif that was joined was a scoped vif,
* ignore it ; don't graft back
*/
- kt->kt_grpmems &= ~kt->kt_scope;
- if (kt->kt_grpmems == NULL)
+ g->gt_grpmems &= ~g->gt_scope;
+ if (g->gt_grpmems == 0)
continue;
/* set the flag for graft retransmission */
- kt->kt_grftsnt = 1;
-
+ g->gt_grftsnt = 1;
+
/* send graft upwards */
- send_graft(kt);
-
+ send_graft(g);
+
/* reset the prune timer and update cache timer*/
- kt->kt_prsent_timer = 0;
- kt->kt_timer = max_prune_lifetime;
-
- prun_add_ttls(kt);
- k_add_rg(kt);
+ g->gt_prsent_timer = 0;
+ g->gt_timer = max_prune_lifetime;
+
+ log(LOG_DEBUG, 0, "chkgrp graft (%s %s) gm:%x",
+ inet_fmts(r->rt_origin, r->rt_originmask, s1),
+ inet_fmt(g->gt_mcastgrp, s2), g->gt_grpmems);
+
+ prun_add_ttls(g);
+ update_kernel(g);
+#ifdef RSRR
+ /* Send route change notification to reservation protocol. */
+ rsrr_cache_send(g,1);
+#endif /* RSRR */
}
+ }
}
/* determine the multicast group and src
@@ -773,159 +1394,111 @@ void chkgrp_graft(vifi, mcastgrp)
* if no prune sent upstream, change the forwarding bit
* for this interface and send ack downstream.
*
- * if no entry exists for this group just ignore the message
- * [this may not be the right thing to do. but lets see what
- * happens for the time being and then we might decide to do
- * a modification to the code depending on the type of behaviour
- * that we see in this]
+ * if no entry exists for this group send ack downstream.
*/
-void accept_graft(src, dst, p, datalen)
- u_long src;
- u_long dst;
+void
+accept_graft(src, dst, p, datalen)
+ u_int32 src;
+ u_int32 dst;
char *p;
int datalen;
{
vifi_t vifi;
- u_long prun_src;
- u_long prun_dst;
- struct ktable *kt;
+ u_int32 graft_src;
+ u_int32 graft_grp;
int i;
- struct prunlst *krl;
- struct prunlst *prev_krl;
+ struct rtentry *r;
+ struct gtable *g;
+ struct ptable *pt, **ptnp;
if ((vifi = find_vif(src, dst)) == NO_VIF) {
log(LOG_INFO, 0,
- "ignoring graft report from non-neighbor %s", inet_fmt(src, s1));
+ "ignoring graft from non-neighbor %s",
+ inet_fmt(src, s1));
return;
}
- if (datalen < 0 || datalen > 8) {
+ if (datalen < 8) {
log(LOG_WARNING, 0,
- "received non-decipherable graft report from %s", inet_fmt(src, s1));
+ "received non-decipherable graft from %s",
+ inet_fmt(src, s1));
return;
}
for (i = 0; i< 4; i++)
- ((char *)&prun_src)[i] = *p++;
+ ((char *)&graft_src)[i] = *p++;
for (i = 0; i< 4; i++)
- ((char *)&prun_dst)[i] = *p++;
+ ((char *)&graft_grp)[i] = *p++;
log(LOG_DEBUG, 0, "%s on vif %d grafts (%s %s)",
inet_fmt(src, s1), vifi,
- inet_fmt(prun_src, s2), inet_fmt(prun_dst, s3));
+ inet_fmt(graft_src, s2), inet_fmt(graft_grp, s3));
- kt = find_src_grp(prun_src, prun_dst);
- if (kt == NULL) {
- log(LOG_DEBUG, 0, "incorrect graft received from %s", inet_fmt(src, s1));
- return;
- }
-
- if (VIFM_ISSET(vifi, kt->kt_scope)) {
- log(LOG_INFO, 0,
- "incorrect graft received from %s on scoped vif %d",
- inet_fmt(src, s1), vifi);
- return;
- }
- /* remove prune entry from the list
- * allow forwarding on that vif, make change in the kernel
+ /*
+ * Find the subnet for the graft
*/
- for (prev_krl = (struct prunlst *)&kt->kt_rlist;
- krl = prev_krl->rl_next;
- prev_krl = krl)
- if ((krl->rl_vifi) == vifi && (krl->rl_router == src)) {
- prev_krl->rl_next = krl->rl_next;
- free((char *)krl);
- krl = prev_krl;
-
- kt->kt_prun_count--;
- VIFM_SET(vifi, kt->kt_grpmems);
- prun_add_ttls(kt);
- k_add_rg(kt);
- break;
+ if (find_src_grp(graft_src, 0, graft_grp)) {
+ g = gtp ? gtp->gt_gnext : kernel_table;
+ r = g->gt_route;
+
+ if (VIFM_ISSET(vifi, g->gt_scope)) {
+ log(LOG_WARNING, 0, "graft received from %s on scoped grp (%s %s)",
+ inet_fmt(src, s1), inet_fmt(graft_src, s2),
+ inet_fmt(graft_grp, s3));
+ return;
}
-
- /* send ack downstream */
- send_graft_ack(kt, src);
- kt->kt_timer = max_prune_lifetime;
-
- if (kt->kt_prsent_timer) {
- /* set the flag for graft retransmission */
- kt->kt_grftsnt = 1;
- /* send graft upwards */
- send_graft(kt);
+ ptnp = &g->gt_pruntbl;
+ while ((pt = *ptnp) != NULL) {
+ if ((pt->pt_vifi == vifi) && (pt->pt_router == src)) {
+ *ptnp = pt->pt_next;
+ free(pt);
+
+ VIFM_SET(vifi, g->gt_grpmems);
+ log(LOG_DEBUG, 0, "accept graft (%s %s) gm:%x",
+ inet_fmts(r->rt_origin, r->rt_originmask, s1),
+ inet_fmt(g->gt_mcastgrp, s2), g->gt_grpmems);
+
+ prun_add_ttls(g);
+ update_kernel(g);
+#ifdef RSRR
+ /* Send route change notification to reservation protocol. */
+ rsrr_cache_send(g,1);
+#endif /* RSRR */
+ break;
+ } else {
+ ptnp = &pt->pt_next;
+ }
+ }
- /* reset the prune sent timer */
- kt->kt_prsent_timer = 0;
- }
-}
+ /* send ack downstream */
+ send_graft_ack(dst, src, graft_src, graft_grp);
+ g->gt_timer = max_prune_lifetime;
+
+ if (g->gt_prsent_timer) {
+ /* set the flag for graft retransmission */
+ g->gt_grftsnt = 1;
-/*
- * Send an ack that a graft was received
- */
-void send_graft_ack(kt, to)
- struct ktable *kt;
- u_long to;
-{
- register char *p;
- register int i;
- int datalen;
- u_long src;
- u_long dst;
-
- src = uvifs[kt->kt_parent].uv_lcl_addr;
- dst = to;
-
- p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
- datalen = 0;
-
- for (i = 0; i < 4; i++)
- *p++ = ((char *)&(kt->kt_origin))[i];
- for (i = 0; i < 4; i++)
- *p++ = ((char *)&(kt->kt_mcastgrp))[i];
- datalen += 8;
-
- send_igmp(src, dst, IGMP_DVMRP, DVMRP_GRAFT_ACK,
- htonl(MROUTED_LEVEL), datalen);
-
- log(LOG_DEBUG, 0, "send graft ack for src:%x, grp:%x to %x",
- kt->kt_origin, kt->kt_mcastgrp, dst);
-}
+ /* send graft upwards */
+ send_graft(g);
-/*
- * a prune was sent upstream
- * so, a graft has to be sent to annul the prune
- * set up a graft timer so that if an ack is not
- * heard within that time, another graft request
- * is sent out.
- */
-void send_graft(kt)
- struct ktable *kt;
-{
- register char *p;
- register int i;
- int datalen;
- u_long src;
- u_long dst;
-
- src = uvifs[kt->kt_parent].uv_lcl_addr;
- dst = kt->kt_gateway;
-
- p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
- datalen = 0;
-
- for (i = 0; i < 4; i++)
- *p++ = ((char *)&(kt->kt_origin))[i];
- for (i = 0; i < 4; i++)
- *p++ = ((char *)&(kt->kt_mcastgrp))[i];
- datalen += 8;
-
- if (datalen != 0) {
- send_igmp(src, dst, IGMP_DVMRP, DVMRP_GRAFT,
- htonl(MROUTED_LEVEL), datalen);
+ /* reset the prune sent timer */
+ g->gt_prsent_timer = 0;
+ }
+ } else {
+ /*
+ * We have no state for the source and group in question.
+ * We can simply acknowledge the graft, since we know
+ * that we have no prune state, and grafts are requests
+ * to remove prune state.
+ */
+ send_graft_ack(dst, src, graft_src, graft_grp);
+ log(LOG_DEBUG, 0, "%s (%s %s) from %s",
+ "graft received with no kernel entry for",
+ inet_fmt(graft_src, s1), inet_fmt(graft_grp, s2),
+ inet_fmt(src, s3));
+ return;
}
- log(LOG_DEBUG, 0, "send graft for src:%x, grp:%x up to %x",
- kt->kt_origin, kt->kt_mcastgrp, kt->kt_gateway);
}
/*
@@ -936,301 +1509,626 @@ void send_graft(kt)
* source, remove the graft timer so that we don't
* have send a graft again
*/
-void accept_g_ack(src, dst, p, datalen)
- u_long src;
- u_long dst;
+void
+accept_g_ack(src, dst, p, datalen)
+ u_int32 src;
+ u_int32 dst;
char *p;
int datalen;
{
+ struct gtable *g;
vifi_t vifi;
- u_long grft_src;
- u_long grft_dst;
- struct ktable *kt;
+ u_int32 grft_src;
+ u_int32 grft_grp;
int i;
if ((vifi = find_vif(src, dst)) == NO_VIF) {
log(LOG_INFO, 0,
- "ignoring graft ack report from non-neighbor %s", inet_fmt(src, s1));
+ "ignoring graft ack from non-neighbor %s",
+ inet_fmt(src, s1));
return;
}
if (datalen < 0 || datalen > 8) {
log(LOG_WARNING, 0,
- "received non-decipherable graft ack report from %s", inet_fmt(src, s1));
+ "received non-decipherable graft ack from %s",
+ inet_fmt(src, s1));
return;
}
for (i = 0; i< 4; i++)
((char *)&grft_src)[i] = *p++;
for (i = 0; i< 4; i++)
- ((char *)&grft_dst)[i] = *p++;
+ ((char *)&grft_grp)[i] = *p++;
- log(LOG_DEBUG, 0, "%s on vif %d acks graft (%s %s)",
+ log(LOG_DEBUG, 0, "%s on vif %d acks graft (%s, %s)",
inet_fmt(src, s1), vifi,
- inet_fmt(grft_src, s2), inet_fmt(grft_dst, s3));
-
- kt = find_src_grp(grft_src, grft_dst);
+ inet_fmt(grft_src, s2), inet_fmt(grft_grp, s3));
- if (kt == NULL) {
- log(LOG_WARNING, 0, "received wrong graft ack from %s", inet_fmt(src, s1));
+ /*
+ * Find the subnet for the graft ack
+ */
+ if (find_src_grp(grft_src, 0, grft_grp)) {
+ g = gtp ? gtp->gt_gnext : kernel_table;
+ g->gt_grftsnt = 0;
+ } else {
+ log(LOG_WARNING, 0, "%s (%s, %s) from %s",
+ "rcvd graft ack with no kernel entry for",
+ inet_fmt(grft_src, s1), inet_fmt(grft_grp, s2),
+ inet_fmt(src, s3));
return;
}
-
- if (kt->kt_grftsnt)
- kt->kt_grftsnt = 0;
}
/*
- * free all prune entries
+ * free all prune entries and kernel routes
+ * normally, this should inform the kernel that all of its routes
+ * are going away, but this is only called by restart(), which is
+ * about to call MRT_DONE which does that anyway.
*/
-void free_all_prunes()
+void
+free_all_prunes()
{
- register struct ktable *kt;
- register struct prunlst *krl;
-
- while (kernel_rtable != NULL) {
- kt = kernel_rtable;
- kernel_rtable = kt->kt_next;
-
- while (kt->kt_rlist != NULL) {
- krl = kt->kt_rlist;
- kt->kt_rlist = krl->rl_next;
- free((char *)krl);
+ register struct rtentry *r;
+ register struct gtable *g, *prev_g;
+ register struct stable *s, *prev_s;
+ register struct ptable *p, *prev_p;
+
+ for (r = routing_table; r; r = r->rt_next) {
+ g = r->rt_groups;
+ while (g) {
+ s = g->gt_srctbl;
+ while (s) {
+ prev_s = s->st_next;
+ free(s);
+ s = prev_s;
+ }
+
+ p = g->gt_pruntbl;
+ while (p) {
+ prev_p = p->pt_next;
+ free(p);
+ p = prev_p;
+ }
+
+ prev_g = g->gt_next;
+ free(g);
+ g = prev_g;
}
+ r->rt_groups = NULL;
+ }
+ kernel_table = NULL;
+
+ g = kernel_no_route;
+ while (g) {
+ if (g->gt_srctbl)
+ free(g->gt_srctbl);
- free((char *)kt);
- kroutes--;
+ prev_g = g->gt_next;
+ free(g);
+ g = prev_g;
}
+ kernel_no_route = NULL;
}
+/*
+ * When a new route is created, search
+ * a) The less-specific part of the routing table
+ * b) The route-less kernel table
+ * for sources that the new route might want to handle.
+ *
+ * "Inheriting" these sources might be cleanest, but simply deleting
+ * them is easier, and letting the kernel re-request them.
+ */
+void
+steal_sources(rt)
+ struct rtentry *rt;
+{
+ register struct rtentry *rp;
+ register struct gtable *gt, **gtnp;
+ register struct stable *st, **stnp;
+
+ for (rp = rt->rt_next; rp; rp = rp->rt_next) {
+ if ((rt->rt_origin & rp->rt_originmask) == rp->rt_origin) {
+ log(LOG_DEBUG, 0, "Route for %s stealing sources from %s",
+ inet_fmts(rt->rt_origin, rt->rt_originmask, s1),
+ inet_fmts(rp->rt_origin, rp->rt_originmask, s2));
+ for (gt = rp->rt_groups; gt; gt = gt->gt_next) {
+ stnp = &gt->gt_srctbl;
+ while ((st = *stnp) != NULL) {
+ if ((st->st_origin & rt->rt_originmask) == rt->rt_origin) {
+ log(LOG_DEBUG, 0, "%s stealing (%s %s) from %s",
+ inet_fmts(rt->rt_origin, rt->rt_originmask, s1),
+ inet_fmt(st->st_origin, s3),
+ inet_fmt(gt->gt_mcastgrp, s4),
+ inet_fmts(rp->rt_origin, rp->rt_originmask, s2));
+ if (k_del_rg(st->st_origin, gt) < 0) {
+ log(LOG_WARNING, errno, "%s (%s, %s)",
+ "steal_sources trying to delete",
+ inet_fmt(st->st_origin, s1),
+ inet_fmt(gt->gt_mcastgrp, s2));
+ }
+ *stnp = st->st_next;
+ kroutes--;
+ free(st);
+ } else {
+ stnp = &st->st_next;
+ }
+ }
+ }
+ }
+ }
+
+ gtnp = &kernel_no_route;
+ while ((gt = *gtnp) != NULL) {
+ if (gt->gt_srctbl && ((gt->gt_srctbl->st_origin & rt->rt_originmask)
+ == rt->rt_origin)) {
+ log(LOG_DEBUG, 0, "%s stealing (%s %s) from %s",
+ inet_fmts(rt->rt_origin, rt->rt_originmask, s1),
+ inet_fmt(gt->gt_srctbl->st_origin, s3),
+ inet_fmt(gt->gt_mcastgrp, s4),
+ "no_route table");
+ if (k_del_rg(gt->gt_srctbl->st_origin, gt) < 0) {
+ log(LOG_WARNING, errno, "%s (%s %s)",
+ "steal_sources trying to delete",
+ inet_fmt(gt->gt_srctbl->st_origin, s1),
+ inet_fmt(gt->gt_mcastgrp, s2));
+ }
+ kroutes--;
+ free(gt->gt_srctbl);
+ *gtnp = gt->gt_next;
+ if (gt->gt_next)
+ gt->gt_next->gt_prev = gt->gt_prev;
+ free(gt);
+ } else {
+ gtnp = &gt->gt_next;
+ }
+ }
+}
/*
* Advance the timers on all the cache entries.
* If there are any entries whose timers have expired,
* remove these entries from the kernel cache.
*/
-void age_table_entry()
+void
+age_table_entry()
{
- struct ktable *kt;
- struct ktable *prev_kt;
- struct prunlst *krl;
- struct prunlst *prev_krl;
+ struct rtentry *r;
+ struct gtable *gt, **gtnptr;
+ struct stable *st, **stnp;
+ struct ptable *pt, **ptnp;
+ struct sioc_sg_req sg_req;
- log(LOG_DEBUG, 0, "kr:%x pr:%x",
- kernel_rtable, (struct ktable *)&kernel_rtable);
+ log(LOG_DEBUG, 0, "ageing entries");
- for (prev_kt = (struct ktable *)&kernel_rtable;
- kt = prev_kt->kt_next;
- prev_kt = kt) {
+ gtnptr = &kernel_table;
+ while ((gt = *gtnptr) != NULL) {
+ r = gt->gt_route;
+
/* advance the timer for the kernel entry */
- kt->kt_timer -= ROUTE_MAX_REPORT_DELAY;
+ gt->gt_timer -= ROUTE_MAX_REPORT_DELAY;
/* decrement prune timer if need be */
- if (kt->kt_prsent_timer)
- kt->kt_prsent_timer -= ROUTE_MAX_REPORT_DELAY;
+ if (gt->gt_prsent_timer > 0) {
+ gt->gt_prsent_timer -= ROUTE_MAX_REPORT_DELAY;
+ if (gt->gt_prsent_timer <= 0) {
+ log(LOG_DEBUG, 0, "upstream prune tmo (%s %s)",
+ inet_fmts(r->rt_origin, r->rt_originmask, s1),
+ inet_fmt(gt->gt_mcastgrp, s2));
+ gt->gt_prsent_timer = -1;
+ }
+ }
/* retransmit graft if graft sent flag is still set */
- if (kt->kt_grftsnt) {
+ if (gt->gt_grftsnt) {
register int y;
- CHK_GS(kt->kt_grftsnt++, y);
+ CHK_GS(gt->gt_grftsnt++, y);
if (y)
- send_graft(kt);
+ send_graft(gt);
}
- /* delete the entry only if there are no subordinate
- routers
-
- Now, if there are subordinate routers, then, what we
- have to do is to decrement each and every router's
- time entry too and decide if we want to forward on
- that link basically
- */
- for (prev_krl = (struct prunlst *)&kt->kt_rlist,
- krl = prev_krl->rl_next;
- krl;
- prev_krl = krl, krl = krl->rl_next) {
- if ((krl->rl_timer -= ROUTE_MAX_REPORT_DELAY) <= 0) {
- log(LOG_DEBUG, 0, "forw again s %x g%x on vif %d",
- kt->kt_origin, kt->kt_mcastgrp, krl->rl_vifi);
+ /*
+ * Age prunes
+ *
+ * If a prune expires, forward again on that vif.
+ */
+ ptnp = &gt->gt_pruntbl;
+ while ((pt = *ptnp) != NULL) {
+ if ((pt->pt_timer -= ROUTE_MAX_REPORT_DELAY) <= 0) {
+ log(LOG_DEBUG, 0, "expire prune (%s %s) from %s on vif %d",
+ inet_fmts(r->rt_origin, r->rt_originmask, s1),
+ inet_fmt(gt->gt_mcastgrp, s2),
+ inet_fmt(pt->pt_router, s3),
+ pt->pt_vifi);
- if (!VIFM_ISSET(krl->rl_vifi, kt->kt_grpmems)) {
- VIFM_SET(krl->rl_vifi, kt->kt_grpmems);
- prun_add_ttls(kt);
- k_add_rg(kt);
+ /*
+ * No need to send a graft, any prunes that we sent
+ * will expire before any prunes that we have received.
+ */
+ if (gt->gt_prsent_timer > 0) {
+ log(LOG_DEBUG, 0, "prune expired with %d left on %s",
+ gt->gt_prsent_timer, "prsent_timer");
+ gt->gt_prsent_timer = 0;
}
-
- kt->kt_prun_count--;
- prev_krl->rl_next = krl->rl_next;
- free((char *)krl);
- krl = prev_krl;
-
- if (krl == NULL)
- break;
+
+ /* modify the kernel entry to forward packets */
+ if (!VIFM_ISSET(pt->pt_vifi, gt->gt_grpmems)) {
+ VIFM_SET(pt->pt_vifi, gt->gt_grpmems);
+ log(LOG_DEBUG, 0, "forw again (%s %s) gm:%x vif:%d",
+ inet_fmts(r->rt_origin, r->rt_originmask, s1),
+ inet_fmt(gt->gt_mcastgrp, s2), gt->gt_grpmems,
+ pt->pt_vifi);
+
+ prun_add_ttls(gt);
+ update_kernel(gt);
+#ifdef RSRR
+ /* Send route change notification to reservation
+ * protocol.
+ */
+ rsrr_cache_send(gt,1);
+#endif /* RSRR */
+ }
+
+ /* remove the router's prune entry and await new one */
+ *ptnp = pt->pt_next;
+ free(pt);
+ } else {
+ ptnp = &pt->pt_next;
}
}
- if (kt->kt_timer <= 0) {
+ /*
+ * If the cache entry has expired, check for downstream prunes.
+ *
+ * If there are downstream prunes, refresh the cache entry's timer.
+ * Otherwise, check for traffic. If no traffic, delete this
+ * entry.
+ */
+ if (gt->gt_timer <= 0) {
+ if (gt->gt_pruntbl) {
+ if (gt->gt_prsent_timer == -1)
+ gt->gt_prsent_timer = 0;
+ gt->gt_timer = CACHE_LIFETIME(cache_lifetime);
+ gtnptr = &gt->gt_gnext;
+ continue;
+ }
+
/*
- * If there are prune entries still outstanding,
- * update the cache timer otherwise expire entry.
+ * If this entry was pruned, but all downstream prunes
+ * have expired, then it is safe to simply delete it.
+ * Otherwise, check for traffic before deleting.
*/
- if (kt->kt_rlist) {
- kt->kt_timer = CACHE_LIFETIME(cache_lifetime);
+ if (gt->gt_prsent_timer == 0) {
+ sg_req.grp.s_addr = gt->gt_mcastgrp;
+ stnp = &gt->gt_srctbl;
+ while ((st = *stnp) != NULL) {
+ sg_req.src.s_addr = st->st_origin;
+ if (ioctl(udp_socket, SIOCGETSGCNT, (char *)&sg_req)
+ < 0) {
+ log(LOG_WARNING, errno, "%s (%s %s)",
+ "age_table_entry: SIOCGETSGCNT failing for",
+ inet_fmt(st->st_origin, s1),
+ inet_fmt(gt->gt_mcastgrp, s2));
+ /* Make sure it gets deleted below */
+ sg_req.pktcnt = st->st_pktcnt;
+ }
+ if (sg_req.pktcnt == st->st_pktcnt) {
+ *stnp = st->st_next;
+ log(LOG_DEBUG, 0,
+ "age_table_entry deleting (%s %s)",
+ inet_fmt(st->st_origin, s1),
+ inet_fmt(gt->gt_mcastgrp, s2));
+ if (k_del_rg(st->st_origin, gt) < 0) {
+ log(LOG_WARNING, errno,
+ "age_table_entry trying to delete (%s %s)",
+ inet_fmt(st->st_origin, s1),
+ inet_fmt(gt->gt_mcastgrp, s2));
+ }
+ kroutes--;
+ free(st);
+ } else {
+ stnp = &st->st_next;
+ }
+ }
+
+ if (gt->gt_srctbl) {
+ /* At least one source in the list still has traffic */
+ gt->gt_timer = CACHE_LIFETIME(cache_lifetime);
+ gtnptr = &gt->gt_gnext;
+ continue;
+ }
}
- else {
- log(LOG_DEBUG, 0, "age route s %x g %x",
- kt->kt_origin, kt->kt_mcastgrp);
-
- k_del_rg(kt);
- prev_kt->kt_next = kt->kt_next;
-
- /* free all the prune list entries */
- krl = kt->kt_rlist;
- while(krl) {
- prev_krl = krl;
- krl = krl->rl_next;
- free((char *)prev_krl);
+
+ log(LOG_DEBUG, 0, "timeout cache entry (%s, %s)",
+ inet_fmts(r->rt_origin, r->rt_originmask, s1),
+ inet_fmt(gt->gt_mcastgrp, s2));
+
+ /* free all the source entries */
+ while ((st = gt->gt_srctbl) != NULL) {
+ log(LOG_DEBUG, 0,
+ "age_table_entry (P) deleting (%s %s)",
+ inet_fmt(st->st_origin, s1),
+ inet_fmt(gt->gt_mcastgrp, s2));
+ if (k_del_rg(st->st_origin, gt) < 0) {
+ log(LOG_WARNING, errno,
+ "age_table_entry (P) trying to delete (%s %s)",
+ inet_fmt(st->st_origin, s1),
+ inet_fmt(gt->gt_mcastgrp, s2));
}
-
- free((char *)kt);
kroutes--;
- kt = prev_kt;
+ gt->gt_srctbl = st->st_next;
+ free(st);
}
+
+ /* free all the prune list entries */
+ while ((pt = gt->gt_pruntbl) != NULL) {
+ gt->gt_pruntbl = pt->pt_next;
+ free(pt);
+ }
+
+ if (gt->gt_prev)
+ gt->gt_prev->gt_next = gt->gt_next;
+ else
+ gt->gt_route->rt_groups = gt->gt_next;
+ if (gt->gt_next)
+ gt->gt_next->gt_prev = gt->gt_prev;
+
+ if (gt->gt_gprev) {
+ gt->gt_gprev->gt_gnext = gt->gt_gnext;
+ gtnptr = &gt->gt_gprev->gt_gnext;
+ } else {
+ kernel_table = gt->gt_gnext;
+ gtnptr = &kernel_table;
+ }
+ if (gt->gt_gnext)
+ gt->gt_gnext->gt_gprev = gt->gt_gprev;
+
+#ifdef RSRR
+ /* Send route change notification to reservation protocol. */
+ rsrr_cache_send(gt,0);
+ rsrr_cache_clean(gt);
+#endif /* RSRR */
+ free((char *)gt);
+ } else {
+ if (gt->gt_prsent_timer == -1)
+ gt->gt_prsent_timer = 0;
+ gtnptr = &gt->gt_gnext;
}
}
+
+ /*
+ * When traversing the no_route table, the decision is much easier.
+ * Just delete it if it has timed out.
+ */
+ gtnptr = &kernel_no_route;
+ while ((gt = *gtnptr) != NULL) {
+ /* advance the timer for the kernel entry */
+ gt->gt_timer -= ROUTE_MAX_REPORT_DELAY;
+
+ if (gt->gt_timer < 0) {
+ if (gt->gt_srctbl) {
+ if (k_del_rg(gt->gt_srctbl->st_origin, gt) < 0) {
+ log(LOG_WARNING, errno, "%s (%s %s)",
+ "age_table_entry trying to delete no-route",
+ inet_fmt(gt->gt_srctbl->st_origin, s1),
+ inet_fmt(gt->gt_mcastgrp, s2));
+ }
+ free(gt->gt_srctbl);
+ }
+ *gtnptr = gt->gt_next;
+ if (gt->gt_next)
+ gt->gt_next->gt_prev = gt->gt_prev;
+
+ free((char *)gt);
+ } else {
+ gtnptr = &gt->gt_next;
+ }
+ }
+}
+
+static char *
+scaletime(t)
+ u_long t;
+{
+ static char buf1[5];
+ static char buf2[5];
+ static char *buf=buf1;
+ char s;
+ char *p;
+
+ p = buf;
+ if (buf == buf1)
+ buf = buf2;
+ else
+ buf = buf1;
+
+ if (t < 120) {
+ s = 's';
+ } else if (t < 3600) {
+ t /= 60;
+ s = 'm';
+ } else if (t < 86400) {
+ t /= 3600;
+ s = 'h';
+ } else if (t < 864000) {
+ t /= 86400;
+ s = 'd';
+ } else {
+ t /= 604800;
+ s = 'w';
+ }
+ if (t > 999)
+ return "*** ";
+
+ sprintf(p,"%3d%c", (int)t, s);
+
+ return p;
}
/*
- * Print the contents of the routing table on file 'fp'.
+ * Print the contents of the cache table on file 'fp2'.
*/
-void dump_cache(fp2)
+void
+dump_cache(fp2)
FILE *fp2;
{
- register struct ktable *kt;
- register struct prunlst *krl;
+ register struct rtentry *r;
+ register struct gtable *gt;
+ register struct stable *st;
+ register struct ptable *pt;
register int i;
- register int count;
+ register time_t thyme = time(0);
fprintf(fp2,
"Multicast Routing Cache Table (%d entries)\n%s", kroutes,
- " Origin-Subnet Mcast-group CTmr IVif Prcv# Psnt Forwvifs\n");
-
- for (kt = kernel_rtable, count = 0; kt != NULL; kt = kt->kt_next) {
-
- fprintf(fp2, " %-15s %-15s",
- inet_fmts(kt->kt_origin, kt->kt_originmask, s1),
- inet_fmt(kt->kt_mcastgrp, s2));
-
- if (VIFM_ISSET(kt->kt_parent, kt->kt_scope)) {
- fprintf(fp2, " %5u %2ub %3u %c ",
- kt->kt_timer, kt->kt_parent, kt->kt_prun_count,
- kt->kt_prsent_timer ? 'P' : ' ');
- fprintf(fp2, "\n");
- continue;
+ " Origin Mcast-group CTmr Age Ptmr IVif Forwvifs\n");
+
+ for (gt = kernel_no_route; gt; gt = gt->gt_next) {
+ if (gt->gt_srctbl) {
+ fprintf(fp2, " %-18s %-15s %-4s %-4s - -1\n",
+ inet_fmts(gt->gt_srctbl->st_origin, 0xffffffff, s1),
+ inet_fmt(gt->gt_mcastgrp, s2), scaletime(gt->gt_timer),
+ scaletime(thyme - gt->gt_ctime));
+ fprintf(fp2, ">%s\n", inet_fmt(gt->gt_srctbl->st_origin, s1));
}
- else
- fprintf(fp2, " %5u %2u %3u %c ",
- kt->kt_timer, kt->kt_parent, kt->kt_prun_count,
- kt->kt_prsent_timer ? 'P' : ' ');
+ }
+
+ for (gt = kernel_table; gt; gt = gt->gt_gnext) {
+ r = gt->gt_route;
+ fprintf(fp2, " %-18s %-15s",
+ inet_fmts(r->rt_origin, r->rt_originmask, s1),
+ inet_fmt(gt->gt_mcastgrp, s2));
+
+ fprintf(fp2, " %-4s", scaletime(gt->gt_timer));
+
+ fprintf(fp2, " %-4s %-4s ", scaletime(thyme - gt->gt_ctime),
+ gt->gt_prsent_timer ? scaletime(gt->gt_prsent_timer) :
+ " -");
+
+ fprintf(fp2, "%2u%c%c ", r->rt_parent,
+ gt->gt_prsent_timer ? 'P' : ' ',
+ VIFM_ISSET(r->rt_parent, gt->gt_scope) ? 'B' : ' ');
for (i = 0; i < numvifs; ++i) {
- if (VIFM_ISSET(i, kt->kt_grpmems))
+ if (VIFM_ISSET(i, gt->gt_grpmems))
fprintf(fp2, " %u ", i);
- else if (VIFM_ISSET(i, kt->kt_children) &&
- !VIFM_ISSET(i, kt->kt_leaves) &&
- VIFM_ISSET(i, kt->kt_scope))
- fprintf(fp2, " %u%c", i, 'b');
- else if (VIFM_ISSET(i, kt->kt_children) &&
- !VIFM_ISSET(i, kt->kt_leaves))
- fprintf(fp2, " %u%c", i, 'p');
+ else if (VIFM_ISSET(i, r->rt_children) &&
+ !VIFM_ISSET(i, r->rt_leaves))
+ fprintf(fp2, " %u%c", i,
+ VIFM_ISSET(i, gt->gt_scope) ? 'b' : 'p');
}
fprintf(fp2, "\n");
- count++;
+ for (st = gt->gt_srctbl; st; st = st->st_next) {
+ fprintf(fp2, ">%s\n", inet_fmt(st->st_origin, s1));
+ }
+#ifdef DEBUG_PRUNES
+ for (pt = gt->gt_pruntbl; pt; pt = pt->pt_next) {
+ fprintf(fp2, "<r:%s v:%d t:%d\n", inet_fmt(pt->pt_router, s1),
+ pt->pt_vifi, pt->pt_timer);
+ }
+#endif
}
}
-
-/*
- * Checks if there are any routers that can understand traceroute
- * downstream
- */
-int can_forward(vifi)
- vifi_t vifi;
-{
- struct listaddr *u;
-
- for (u = uvifs[vifi].uv_neighbors; u; u = u->al_next)
- if (((u->al_pv > 2) && (u->al_mv > 2)) ||
- (u->al_pv > 3))
- return 1;
-
- return 0;
-}
-
/*
* Traceroute function which returns traceroute replies to the requesting
* router. Also forwards the request to downstream routers.
*/
-void mtrace(src, dst, group, data, no, datalen)
- u_long src;
- u_long dst;
- u_long group;
+void
+accept_mtrace(src, dst, group, data, no, datalen)
+ u_int32 src;
+ u_int32 dst;
+ u_int32 group;
char *data;
- u_char no;
+ u_int no; /* promoted u_char */
int datalen;
{
u_char type;
struct rtentry *rt;
+ struct gtable *gt;
struct tr_query *qry;
struct tr_resp *resp;
- struct uvif *v;
int vifi;
char *p;
- struct ktable *kt;
int rcount;
-
+ int errcode = TR_NO_ERR;
+ int resptype;
struct timeval tp;
- struct timezone tzp;
struct sioc_vif_req v_req;
struct sioc_sg_req sg_req;
+ /* Remember qid across invocations */
+ static u_int32 oqid = 0;
+
/* timestamp the request/response */
- gettimeofday(&tp, &tzp);
+ gettimeofday(&tp, 0);
/*
* Check if it is a query or a response
*/
if (datalen == QLEN) {
type = QUERY;
- printf("Traceroute query rcvd\n");
+ log(LOG_DEBUG, 0, "Initial traceroute query rcvd from %s to %s",
+ inet_fmt(src, s1), inet_fmt(dst, s2));
}
- else if ((datalen - QLEN)%RLEN == 0) {
+ else if ((datalen - QLEN) % RLEN == 0) {
type = RESP;
- printf("Traceroute response rcvd\n");
+ log(LOG_DEBUG, 0, "In-transit traceroute query rcvd from %s to %s",
+ inet_fmt(src, s1), inet_fmt(dst, s2));
+ if (IN_MULTICAST(ntohl(dst))) {
+ log(LOG_DEBUG, 0, "Dropping multicast response");
+ return;
+ }
}
else {
- printf("Non decipherable trace request %s", inet_fmt(src, s1));
+ log(LOG_WARNING, 0, "%s from %s to %s",
+ "Non decipherable traceroute request recieved",
+ inet_fmt(src, s1), inet_fmt(dst, s2));
return;
}
qry = (struct tr_query *)data;
+ if (oqid == qry->tr_qid) {
+ /*
+ * If the multicast router is a member of the group being
+ * queried, and the query is multicasted, then the router can
+ * recieve multiple copies of the same query. If we have already
+ * replied to this traceroute, just ignore it this time.
+ *
+ * This is not a total solution, but since if this fails you
+ * only get N copies, N <= the number of interfaces on the router,
+ * it is not fatal.
+ */
+ log(LOG_DEBUG, 0, "ignoring duplicate traceroute packet");
+ return;
+ }
+
/*
- * if it is a multicast packet with all reports filled, drop it
+ * if it is a packet with all reports filled, drop it
*/
if ((rcount = (datalen - QLEN)/RLEN) == no) {
- printf("multicast packet with reports filled in\n");
+ log(LOG_DEBUG, 0, "packet with all reports filled in");
return;
}
- printf("s: %s g: %s d: %s ", inet_fmt(qry->tr_src, s1),
- inet_fmt(group, s2), inet_fmt(qry->tr_dst, s3));
- printf("rttl: %d rd: %s\n", qry->tr_rttl, inet_fmt(qry->tr_raddr, s1));
- printf("rcount:%d\n", rcount);
+ log(LOG_DEBUG, 0, "s: %s g: %s d: %s ", inet_fmt(qry->tr_src, s1),
+ inet_fmt(group, s2), inet_fmt(qry->tr_dst, s3));
+ log(LOG_DEBUG, 0, "rttl: %d rd: %s", qry->tr_rttl,
+ inet_fmt(qry->tr_raddr, s1));
+ log(LOG_DEBUG, 0, "rcount:%d, qid:%06x", rcount, qry->tr_qid);
/* determine the routing table entry for this traceroute */
rt = determine_route(qry->tr_src);
+ if (rt) {
+ log(LOG_DEBUG, 0, "rt parent vif: %d rtr: %s metric: %d",
+ rt->rt_parent, inet_fmt(rt->rt_gateway, s1), rt->rt_metric);
+ log(LOG_DEBUG, 0, "rt origin %s",
+ inet_fmts(rt->rt_origin, rt->rt_originmask, s1));
+ } else
+ log(LOG_DEBUG, 0, "...no route");
/*
* Query type packet - check if rte exists
@@ -1239,38 +2137,44 @@ void mtrace(src, dst, group, data, no, datalen)
*/
if (type == QUERY) {
if (rt == NULL) {
- printf("Mcast traceroute: no route entry %s\n",
+ log(LOG_DEBUG, 0, "Mcast traceroute: no route entry %s",
inet_fmt(qry->tr_src, s1));
if (IN_MULTICAST(ntohl(dst)))
return;
}
- for (v = uvifs, vifi = 0; vifi < numvifs; ++vifi, ++v)
- if (!(v->uv_flags & VIFF_TUNNEL) &&
- ((qry->tr_dst & v->uv_subnetmask) == v->uv_subnet))
- break;
+ vifi = find_vif(qry->tr_dst, 0);
- if (vifi == numvifs) {
- printf("Destination %s not an interface\n",
+ if (vifi == NO_VIF) {
+ /* The traceroute destination is not on one of my subnet vifs. */
+ log(LOG_DEBUG, 0, "Destination %s not an interface",
inet_fmt(qry->tr_dst, s1));
- return;
- }
- if (rt != NULL && !VIFM_ISSET(vifi, rt->rt_children)) {
- printf("Destination %s not on forwarding tree for src %s\n",
+ if (IN_MULTICAST(ntohl(dst)))
+ return;
+ errcode = TR_WRONG_IF;
+ } else if (rt != NULL && !VIFM_ISSET(vifi, rt->rt_children)) {
+ log(LOG_DEBUG, 0, "Destination %s not on forwarding tree for src %s",
inet_fmt(qry->tr_dst, s1), inet_fmt(qry->tr_src, s2));
- return;
+ if (IN_MULTICAST(ntohl(dst)))
+ return;
+ errcode = TR_WRONG_IF;
}
}
else {
/*
* determine which interface the packet came in on
+ * RESP packets travel hop-by-hop so this either traversed
+ * a tunnel or came from a directly attached mrouter.
*/
if ((vifi = find_vif(src, dst)) == NO_VIF) {
- printf("Wrong interface for packet\n");
- return;
+ log(LOG_DEBUG, 0, "Wrong interface for packet");
+ errcode = TR_WRONG_IF;
}
}
- printf("Sending traceroute response\n");
+ /* Now that we've decided to send a response, save the qid */
+ oqid = qry->tr_qid;
+
+ log(LOG_DEBUG, 0, "Sending traceroute response");
/* copy the packet to the sending buffer */
p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
@@ -1280,16 +2184,32 @@ void mtrace(src, dst, group, data, no, datalen)
p += datalen;
/*
+ * If there is no room to insert our reply, coopt the previous hop
+ * error indication to relay this fact.
+ */
+ if (p + sizeof(struct tr_resp) > send_buf + RECV_BUF_SIZE) {
+ resp = (struct tr_resp *)p - 1;
+ resp->tr_rflags = TR_NO_SPACE;
+ rt = NULL;
+ goto sendit;
+ }
+
+ /*
* fill in initial response fields
*/
resp = (struct tr_resp *)p;
- resp->tr_qarr = ((tp.tv_sec & 0xffff) << 16) +
+ bzero(resp, sizeof(struct tr_resp));
+ datalen += RLEN;
+
+ resp->tr_qarr = ((tp.tv_sec + JAN_1970) << 16) +
((tp.tv_usec >> 4) & 0xffff);
- resp->tr_vifin = 0; /* default values */
- resp->tr_pktcnt = 0; /* default values */
resp->tr_rproto = PROTO_DVMRP;
- resp->tr_smask = 0;
+ if (errcode != TR_NO_ERR) {
+ resp->tr_rflags = errcode;
+ rt = NULL; /* hack to enforce send straight to requestor */
+ goto sendit;
+ }
resp->tr_outaddr = uvifs[vifi].uv_lcl_addr;
resp->tr_fttl = uvifs[vifi].uv_threshold;
resp->tr_rflags = TR_NO_ERR;
@@ -1304,18 +2224,35 @@ void mtrace(src, dst, group, data, no, datalen)
/*
* fill in scoping & pruning information
*/
- kt = find_src_grp(qry->tr_src, group);
+ if (rt)
+ for (gt = rt->rt_groups; gt; gt = gt->gt_next) {
+ if (gt->gt_mcastgrp >= group)
+ break;
+ }
+ else
+ gt = NULL;
- if (kt != NULL) {
+ if (gt && gt->gt_mcastgrp == group) {
sg_req.src.s_addr = qry->tr_src;
sg_req.grp.s_addr = group;
if (ioctl(udp_socket, SIOCGETSGCNT, (char *)&sg_req) >= 0)
- resp->tr_pktcnt = sg_req.count;
+ resp->tr_pktcnt = sg_req.pktcnt;
- if (VIFM_ISSET(vifi, kt->kt_scope))
+ if (VIFM_ISSET(vifi, gt->gt_scope))
resp->tr_rflags = TR_SCOPED;
- else if (kt->kt_prsent_timer)
+ else if (gt->gt_prsent_timer)
resp->tr_rflags = TR_PRUNED;
+ else if (!VIFM_ISSET(vifi, gt->gt_grpmems))
+ if (VIFM_ISSET(vifi, rt->rt_children) &&
+ !VIFM_ISSET(vifi, rt->rt_leaves))
+ resp->tr_rflags = TR_OPRUNED;
+ else
+ resp->tr_rflags = TR_NO_FWD;
+ } else {
+ if (scoped_addr(vifi, group))
+ resp->tr_rflags = TR_SCOPED;
+ else if (rt && !VIFM_ISSET(vifi, rt->rt_children))
+ resp->tr_rflags = TR_NO_FWD;
}
/*
@@ -1323,11 +2260,10 @@ void mtrace(src, dst, group, data, no, datalen)
*/
if (rt == NULL) {
src = dst; /* the dst address of resp. pkt */
- resp->tr_inaddr = NULL;
+ resp->tr_inaddr = 0;
resp->tr_rflags = TR_NO_RTE;
- resp->tr_rmtaddr = NULL;
- }
- else {
+ resp->tr_rmtaddr = 0;
+ } else {
/* get # of packets in on interface */
v_req.vifi = rt->rt_parent;
if (ioctl(udp_socket, SIOCGETVIFCNT, (char *)&v_req) >= 0)
@@ -1338,33 +2274,62 @@ void mtrace(src, dst, group, data, no, datalen)
resp->tr_inaddr = src;
resp->tr_rmtaddr = rt->rt_gateway;
if (!VIFM_ISSET(vifi, rt->rt_children)) {
- printf("Destination %s not on forwarding tree for src %s\n",
+ log(LOG_DEBUG, 0, "Destination %s not on forwarding tree for src %s",
inet_fmt(qry->tr_dst, s1), inet_fmt(qry->tr_src, s2));
resp->tr_rflags = TR_WRONG_IF;
}
+ if (rt->rt_metric >= UNREACHABLE) {
+ resp->tr_rflags = TR_NO_RTE;
+ /* Hack to send reply directly */
+ rt = NULL;
+ }
}
+sendit:
/*
* if metric is 1 or no. of reports is 1, send response to requestor
- * else send to upstream router.
+ * else send to upstream router. If the upstream router can't handle
+ * mtrace, set an error code and send to requestor anyway.
*/
- printf("rcount:%d, no:%d\n", rcount, no);
+ log(LOG_DEBUG, 0, "rcount:%d, no:%d", rcount, no);
- if ((rcount + 1 == no) || (rt->rt_metric == 1))
+ if ((rcount + 1 == no) || (rt == NULL) || (rt->rt_metric == 1)) {
+ resptype = IGMP_MTRACE_RESP;
dst = qry->tr_raddr;
- else
- dst = rt->rt_gateway;
+ } else
+ if (!can_mtrace(rt->rt_parent, rt->rt_gateway)) {
+ dst = qry->tr_raddr;
+ resp->tr_rflags = TR_OLD_ROUTER;
+ resptype = IGMP_MTRACE_RESP;
+ } else {
+ dst = rt->rt_gateway;
+ resptype = IGMP_MTRACE;
+ }
if (IN_MULTICAST(ntohl(dst))) {
- k_set_ttl(qry->tr_rttl);
+ /*
+ * Send the reply on a known multicast capable vif.
+ * If we don't have one, we can't source any multicasts anyway.
+ */
+ if (phys_vif != -1) {
+ log(LOG_DEBUG, 0, "Sending reply to %s from %s",
+ inet_fmt(dst, s1), inet_fmt(uvifs[phys_vif].uv_lcl_addr, s2));
+ k_set_ttl(qry->tr_rttl);
+ send_igmp(uvifs[phys_vif].uv_lcl_addr, dst,
+ resptype, no, group,
+ datalen);
+ k_set_ttl(1);
+ } else
+ log(LOG_INFO, 0, "No enabled phyints -- %s",
+ "dropping traceroute reply");
+ } else {
+ log(LOG_DEBUG, 0, "Sending %s to %s from %s",
+ resptype == IGMP_MTRACE_RESP ? "reply" : "request on",
+ inet_fmt(dst, s1), inet_fmt(src, s2));
+
send_igmp(src, dst,
- IGMP_MTRACE_RESP, no, group,
- datalen + RLEN);
- k_set_ttl(1);
+ resptype, no, group,
+ datalen);
}
- else
- send_igmp(src, dst,
- IGMP_MTRACE, no, group,
- datalen + RLEN);
return;
}
diff --git a/usr.sbin/mrouted/prune.h b/usr.sbin/mrouted/prune.h
index 3cce25e38eba..eef9d2842331 100644
--- a/usr.sbin/mrouted/prune.h
+++ b/usr.sbin/mrouted/prune.h
@@ -7,91 +7,104 @@
* Leland Stanford Junior University.
*
*
- * $Id: prune.h,v 1.3 1994/08/24 23:54:40 thyagara Exp $
+ * $Id: prune.h,v 3.6 1995/06/25 19:19:04 fenner Exp $
*/
-/*
- * Macro for copying the user-level cache table to the kernel
- * level table variable passed on by the setsock option
+/*
+ * Group table
+ *
+ * Each group entry is a member of two doubly-linked lists:
+ *
+ * a) A list hanging off of the routing table entry for this source (rt_groups)
+ * sorted by group address under the routing entry (gt_next, gt_prev)
+ * b) An independent list pointed to by kernel_table, which is a list of
+ * active source,group's (gt_gnext, gt_gprev).
+ *
*/
-
-#define COPY_TABLES(from, to) { \
- register u_int _i; \
- (to).mfcc_origin.s_addr = (from)->kt_origin; \
- (to).mfcc_mcastgrp.s_addr = (from)->kt_mcastgrp; \
- (to).mfcc_originmask.s_addr = (from)->kt_originmask; \
- (to).mfcc_parent = (from)->kt_parent; \
- for (_i = 0; _i < numvifs; _i++) \
- (to).mfcc_ttls[_i] = (from)->kt_ttls[_i]; \
+struct gtable {
+ struct gtable *gt_next; /* pointer to the next entry */
+ struct gtable *gt_prev; /* back pointer for linked list */
+ struct gtable *gt_gnext; /* fwd pointer for group list */
+ struct gtable *gt_gprev; /* rev pointer for group list */
+ u_int32 gt_mcastgrp; /* multicast group associated */
+ vifbitmap_t gt_scope; /* scoped interfaces */
+ u_char gt_ttls[MAXVIFS]; /* ttl vector for forwarding */
+ vifbitmap_t gt_grpmems; /* forw. vifs for src, grp */
+ int gt_prsent_timer; /* prune timer for this group */
+ int gt_timer; /* timer for this group entry */
+ time_t gt_ctime; /* time of entry creation */
+ u_char gt_grftsnt; /* graft sent/retransmit timer */
+ struct stable *gt_srctbl; /* source table */
+ struct ptable *gt_pruntbl; /* prune table */
+ struct rtentry *gt_route; /* parent route */
+#ifdef RSRR
+ struct rsrr_cache *gt_rsrr_cache; /* RSRR cache */
+#endif /* RSRR */
};
-
/*
- * User level Kernel Cache Table structure
- *
- * A copy of the kernel table is kept at the user level. Modifications are
- * made to this table and then passed on to the kernel. A timeout value is
- * an extra field in the user level table.
+ * Source table
*
+ * When source-based prunes exist, there will be a struct ptable here as well.
*/
-struct ktable
+struct stable
{
- struct ktable *kt_next; /* pointer to the next entry */
- u_long kt_origin; /* subnet origin of multicasts */
- u_long kt_mcastgrp; /* multicast group associated */
- u_long kt_originmask; /* subnet mask for origin */
- vifi_t kt_parent; /* incoming vif */
- u_long kt_gateway; /* upstream router */
- vifbitmap_t kt_children; /* outgoing children vifs */
- vifbitmap_t kt_leaves; /* subset of outgoing children vifs */
- vifbitmap_t kt_scope; /* scoped interfaces */
- u_char kt_ttls[MAXVIFS]; /* ttl vector for forwarding */
- vifbitmap_t kt_grpmems; /* forw. vifs for src, grp */
- int kt_timer; /* for timing out entry in cache */
- struct prunlst *kt_rlist; /* router list nghboring this rter */
- u_short kt_prun_count; /* count of total no. of prunes */
- int kt_prsent_timer; /* prune lifetime timer */
- u_int kt_grftsnt; /* graft sent upstream */
+ struct stable *st_next; /* pointer to the next entry */
+ u_int32 st_origin; /* host origin of multicasts */
+ u_long st_pktcnt; /* packet count for src-grp entry */
};
/*
- * structure to store incoming prunes
+ * structure to store incoming prunes. Can hang off of either group or source.
*/
-struct prunlst
+struct ptable
{
- struct prunlst *rl_next;
- u_long rl_router;
- u_long rl_router_subnet;
- vifi_t rl_vifi;
- int rl_timer;
+ struct ptable *pt_next; /* pointer to the next entry */
+ u_int32 pt_router; /* router that sent this prune */
+ vifi_t pt_vifi; /* vif prune received on */
+ int pt_timer; /* timer for prune */
};
+/*
+ * The packet format for a traceroute request.
+ */
struct tr_query {
- u_long tr_src; /* traceroute source */
- u_long tr_dst; /* traceroute destination */
- u_long tr_raddr; /* traceroute response address */
+ u_int32 tr_src; /* traceroute source */
+ u_int32 tr_dst; /* traceroute destination */
+ u_int32 tr_raddr; /* traceroute response address */
+#if defined(BYTE_ORDER) && (BYTE_ORDER == LITTLE_ENDIAN)
+ struct {
+ u_int qid : 24; /* traceroute query id */
+ u_int ttl : 8; /* traceroute response ttl */
+ } q;
+#else
struct {
u_int ttl : 8; /* traceroute response ttl */
u_int qid : 24; /* traceroute query id */
} q;
-} tr_query;
+#endif /* BYTE_ORDER */
+};
#define tr_rttl q.ttl
#define tr_qid q.qid
+/*
+ * Traceroute response format. A traceroute response has a tr_query at the
+ * beginning, followed by one tr_resp for each hop taken.
+ */
struct tr_resp {
- u_long tr_qarr; /* query arrival time */
- u_long tr_inaddr; /* incoming interface address */
- u_long tr_outaddr; /* outgoing interface address */
- u_long tr_rmtaddr; /* parent address in source tree */
- u_long tr_vifin; /* input packet count on interface */
- u_long tr_vifout; /* output packet count on interface */
- u_long tr_pktcnt; /* total incoming packets for src-grp */
+ u_int32 tr_qarr; /* query arrival time */
+ u_int32 tr_inaddr; /* incoming interface address */
+ u_int32 tr_outaddr; /* outgoing interface address */
+ u_int32 tr_rmtaddr; /* parent address in source tree */
+ u_int32 tr_vifin; /* input packet count on interface */
+ u_int32 tr_vifout; /* output packet count on interface */
+ u_int32 tr_pktcnt; /* total incoming packets for src-grp */
u_char tr_rproto; /* routing protocol deployed on router */
u_char tr_fttl; /* ttl required to forward on outvif */
u_char tr_smask; /* subnet mask for src addr */
u_char tr_rflags; /* forwarding error codes */
-} tr_resp;
+};
/* defs within mtrace */
#define QUERY 1
@@ -100,24 +113,31 @@ struct tr_resp {
#define RLEN sizeof(struct tr_resp)
/* fields for tr_rflags (forwarding error codes) */
-#define TR_NO_ERR 0x0
-#define TR_WRONG_IF 0x1
-#define TR_PRUNED 0x2
-#define TR_SCOPED 0x4
-#define TR_NO_RTE 0x5
+#define TR_NO_ERR 0
+#define TR_WRONG_IF 1
+#define TR_PRUNED 2
+#define TR_OPRUNED 3
+#define TR_SCOPED 4
+#define TR_NO_RTE 5
+#define TR_NO_FWD 7
+#define TR_NO_SPACE 0x81
+#define TR_OLD_ROUTER 0x82
/* fields for tr_rproto (routing protocol) */
-#define PROTO_DVMRP 0x1
-#define PROTO_MOSPF 0x2
-#define PROTO_PIM 0x3
-#define PROTO_CBT 0x4
+#define PROTO_DVMRP 1
+#define PROTO_MOSPF 2
+#define PROTO_PIM 3
+#define PROTO_CBT 4
#define MASK_TO_VAL(x, i) { \
- (i) = 0; \
- while ((x) << (i)) \
+ u_int32 _x = ntohl(x); \
+ (i) = 1; \
+ while ((_x) <<= 1) \
(i)++; \
- }
+ };
#define VAL_TO_MASK(x, i) { \
- x = ~((1 << (32 - (i))) - 1); \
- }
+ x = htonl(~((1 << (32 - (i))) - 1)); \
+ };
+
+#define NBR_VERS(n) (((n)->al_pv << 8) + (n)->al_mv)
diff --git a/usr.sbin/mrouted/route.c b/usr.sbin/mrouted/route.c
index 2debcc7ad0b6..38b9002982f0 100644
--- a/usr.sbin/mrouted/route.c
+++ b/usr.sbin/mrouted/route.c
@@ -7,7 +7,7 @@
* Leland Stanford Junior University.
*
*
- * $Id: route.c,v 1.8 1994/08/24 23:54:42 thyagara Exp $
+ * $Id: route.c,v 3.6 1995/06/25 19:20:19 fenner Exp $
*/
@@ -15,6 +15,11 @@
/*
+ * This define statement saves a lot of space later
+ */
+#define RT_ADDR (struct rtentry *)&routing_table
+
+/*
* Exported variables.
*/
int routes_changed; /* 1=>some routes have changed */
@@ -22,19 +27,37 @@ int delay_change_reports; /* 1=>postpone change reports */
/*
+ * The routing table is shared with prune.c , so must not be static.
+ */
+struct rtentry *routing_table; /* pointer to list of route entries */
+
+/*
* Private variables.
*/
-static struct rtentry *routing_table; /* pointer to list of route entries */
static struct rtentry *rtp; /* pointer to a route entry */
+static struct rtentry *rt_end; /* pointer to last route entry */
unsigned int nroutes; /* current number of route entries */
+/*
+ * Private functions.
+ */
+static int init_children_and_leaves __P((struct rtentry *r,
+ vifi_t parent));
+static int find_route __P((u_int32 origin, u_int32 mask));
+static void create_route __P((u_int32 origin, u_int32 mask));
+static void discard_route __P((struct rtentry *prev_r));
+static int compare_rts __P((const void *rt1, const void *rt2));
+static int report_chunk __P((struct rtentry *start_rt, vifi_t vifi,
+ u_int32 dst));
/*
* Initialize the routing table and associated variables.
*/
-void init_routes()
+void
+init_routes()
{
routing_table = NULL;
+ rt_end = RT_ADDR;
nroutes = 0;
routes_changed = FALSE;
delay_change_reports = FALSE;
@@ -47,7 +70,8 @@ void init_routes()
* Return TRUE if this changes the value of either the children or
* leaf bitmaps for 'r'.
*/
-static int init_children_and_leaves(r, parent)
+static int
+init_children_and_leaves(r, parent)
register struct rtentry *r;
register vifi_t parent;
{
@@ -91,7 +115,8 @@ static int init_children_and_leaves(r, parent)
* A new vif has come up -- update the children and leaf bitmaps in all route
* entries to take that into account.
*/
-void add_vif_to_routes(vifi)
+void
+add_vif_to_routes(vifi)
register vifi_t vifi;
{
register struct rtentry *r;
@@ -124,7 +149,8 @@ void add_vif_to_routes(vifi)
* and update the children bitmaps in all other route entries to take into
* account the failed vif.
*/
-void delete_vif_from_routes(vifi)
+void
+delete_vif_from_routes(vifi)
register vifi_t vifi;
{
register struct rtentry *r;
@@ -158,8 +184,9 @@ void delete_vif_from_routes(vifi)
* considered a dominant or subordinate router in any route entries,
* take appropriate action.
*/
-void delete_neighbor_from_routes(addr, vifi)
- register u_long addr;
+void
+delete_neighbor_from_routes(addr, vifi)
+ register u_int32 addr;
register vifi_t vifi;
{
register struct rtentry *r;
@@ -213,9 +240,10 @@ void delete_neighbor_from_routes(addr, vifi)
* a single message be in the same order as the route entries in the routing
* table.
*/
-void start_route_updates()
+void
+start_route_updates()
{
- rtp = (struct rtentry *)&routing_table;
+ rtp = RT_ADDR;
}
@@ -228,8 +256,9 @@ void start_route_updates()
* This code is optimized for the normal case in which the first entry to
* be examined is the matching entry.
*/
-static int find_route(origin, mask)
- register u_long origin, mask;
+static int
+find_route(origin, mask)
+ register u_int32 origin, mask;
{
register struct rtentry *r;
@@ -239,9 +268,9 @@ static int find_route(origin, mask)
rtp = r;
return (TRUE);
}
- if (ntohl(mask) > ntohl(r->rt_originmask) ||
+ if (ntohl(mask) < ntohl(r->rt_originmask) ||
(mask == r->rt_originmask &&
- ntohl(origin) > ntohl(r->rt_origin))) {
+ ntohl(origin) < ntohl(r->rt_origin))) {
rtp = r;
r = r->rt_next;
}
@@ -250,31 +279,6 @@ static int find_route(origin, mask)
return (FALSE);
}
-
-/*
- * Search the entire routing table, looking for an entry which conflicts
- * with the given origin and mask, for example, an entry which has the same
- * origin under a different mask. If a conflicting entry is found, return
- * a pointer to the entry preceding it (to facilitate deletion); if no
- * conflict is found, return NULL.
- */
-static struct rtentry *find_conflicting_route(origin, mask)
- register u_long origin, mask;
-{
- register struct rtentry *r, *prev_r;
-
- for (prev_r = (struct rtentry *)&routing_table, r = routing_table;
- r != NULL;
- prev_r = r, r = r->rt_next ) {
- if ((origin & r->rt_originmask) == r->rt_origin ||
- (r->rt_origin & mask) == origin) {
- return (prev_r);
- }
- }
- return (NULL);
-}
-
-
/*
* Create a new routing table entry for the specified origin and link it into
* the routing table. The shared variable 'rtp' is assumed to point to the
@@ -285,13 +289,15 @@ static struct rtentry *find_conflicting_route(origin, mask)
* in the new route entry; the caller is responsible for filling in the the
* rest.
*/
-static void create_route(origin, mask)
- u_long origin, mask;
+static void
+create_route(origin, mask)
+ u_int32 origin, mask;
{
register struct rtentry *r;
- if ((r = (struct rtentry *) malloc(sizeof(struct rtentry)
- + (3 * numvifs * sizeof(u_long)))) == NULL) {
+ if ((r = (struct rtentry *) malloc(sizeof(struct rtentry) +
+ (2 * numvifs * sizeof(u_int32)) +
+ (numvifs * sizeof(u_int)))) == NULL) {
log(LOG_ERR, 0, "ran out of memory"); /* fatal */
}
r->rt_origin = origin;
@@ -301,12 +307,18 @@ static void create_route(origin, mask)
else if (((char *)&mask)[1] != 0) r->rt_originwidth = 2;
else r->rt_originwidth = 1;
r->rt_flags = 0;
- r->rt_dominants = (u_long *)(r + 1);
- r->rt_subordinates = (u_long *)(r->rt_dominants + numvifs);
- r->rt_leaf_timers = (u_long *)(r->rt_subordinates + numvifs);
+ r->rt_dominants = (u_int32 *)(r + 1);
+ r->rt_subordinates = (u_int32 *)(r->rt_dominants + numvifs);
+ r->rt_leaf_timers = (u_int *)(r->rt_subordinates + numvifs);
+ r->rt_groups = NULL;
r->rt_next = rtp->rt_next;
rtp->rt_next = r;
+ r->rt_prev = rtp;
+ if (r->rt_next != NULL)
+ (r->rt_next)->rt_prev = r;
+ else
+ rt_end = r;
rtp = r;
++nroutes;
}
@@ -315,13 +327,18 @@ static void create_route(origin, mask)
/*
* Discard the routing table entry following the one to which 'prev_r' points.
*/
-static void discard_route(prev_r)
+static void
+discard_route(prev_r)
register struct rtentry *prev_r;
{
register struct rtentry *r;
r = prev_r->rt_next;
prev_r->rt_next = r->rt_next;
+ if (prev_r->rt_next != NULL)
+ (prev_r->rt_next)->rt_prev = prev_r;
+ else
+ rt_end = prev_r;
free((char *)r);
--nroutes;
}
@@ -333,14 +350,14 @@ static void discard_route(prev_r)
* address of a neighboring router from which the report arrived, or zero
* to indicate a change of status of one of our own interfaces.
*/
-void update_route(origin, mask, metric, src, vifi)
- u_long origin, mask;
+void
+update_route(origin, mask, metric, src, vifi)
+ u_int32 origin, mask;
int metric;
- u_long src;
+ u_int32 src;
vifi_t vifi;
{
register struct rtentry *r;
- struct rtentry *prev_r;
int adj_metric;
/*
@@ -377,38 +394,18 @@ void update_route(origin, mask, metric, src, vifi)
}
/*
- * If the new origin and mask are inconsistent with an entry
- * already in the routing table, either ignore this update
- * (if it came from another router), or delete the conflicting
- * entry (if the update is for a directly-connected subnet).
- */
- if ((prev_r = find_conflicting_route(origin, mask)) != NULL ) {
- if (src != 0) {
- log(LOG_INFO, 0,
- "%s reports a conflicting origin (%s) and mask (%08x)",
- inet_fmt(src, s1), inet_fmt(origin, s2), ntohl(mask));
- return;
- }
- else {
- r = prev_r->rt_next;
- log(LOG_INFO, 0,
- "deleting route with conflicting origin (%s), mask (%08x)",
- inet_fmt(r->rt_origin, s1), ntohl(r->rt_originmask));
-
- if (r->rt_metric != UNREACHABLE) {
- del_table_entry(r, 0, DEL_ALL_ROUTES);
- }
- discard_route(prev_r);
- if (rtp == r) rtp = prev_r;
- }
- }
-
- /*
* OK, create the new routing entry. 'rtp' will be left pointing
* to the new entry.
*/
create_route(origin, mask);
+ /*
+ * Now "steal away" any sources that belong under this route
+ * by deleting any cache entries they might have created
+ * and allowing the kernel to re-request them.
+ */
+ steal_sources(rtp);
+
rtp->rt_metric = UNREACHABLE; /* temporary; updated below */
}
@@ -579,13 +576,14 @@ void update_route(origin, mask, metric, src, vifi)
/*
* On every timer interrupt, advance the timer in each routing entry.
*/
-void age_routes()
+void
+age_routes()
{
register struct rtentry *r;
register struct rtentry *prev_r;
register vifi_t vifi;
- for (prev_r = (struct rtentry *)&routing_table, r = routing_table;
+ for (prev_r = RT_ADDR, r = routing_table;
r != NULL;
prev_r = r, r = r->rt_next) {
@@ -602,8 +600,19 @@ void age_routes()
* Unlike other timers, leaf timers decrement.
*/
if ((r->rt_leaf_timers[vifi] -= TIMER_INTERVAL) == 0){
- VIFM_SET(vifi, r->rt_leaves);
- update_table_entry(r);
+#ifdef NOTYET
+ /* If the vif is a physical leaf but has neighbors,
+ * it is not a tree leaf. If I am a leaf, then no
+ * interface with neighbors is a tree leaf. */
+ if (!(((uvifs[vifi].uv_flags & VIFF_LEAF) ||
+ (vifs_with_neighbors == 1)) &&
+ (uvifs[vifi].uv_neighbors != NULL))) {
+#endif
+ VIFM_SET(vifi, r->rt_leaves);
+ update_table_entry(r);
+#ifdef NOTYET
+ }
+#endif
}
else {
r->rt_flags |= RTF_LEAF_TIMING;
@@ -616,6 +625,7 @@ void age_routes()
/*
* Time to garbage-collect the route entry.
*/
+ del_table_entry(r, 0, DEL_ALL_ROUTES);
discard_route(prev_r);
r = prev_r;
}
@@ -648,7 +658,8 @@ void age_routes()
* on the kernel to do its own cleanup -- no point in making all those
* expensive kernel calls now.
*/
-void expire_all_routes()
+void
+expire_all_routes()
{
register struct rtentry *r;
@@ -663,11 +674,12 @@ void expire_all_routes()
/*
* Delete all the routes in the routing table.
*/
-void free_all_routes()
+void
+free_all_routes()
{
register struct rtentry *r;
- r = (struct rtentry *)&routing_table;
+ r = RT_ADDR;
while (r->rt_next)
discard_route(r);
@@ -677,12 +689,13 @@ void free_all_routes()
/*
* Process an incoming neighbor probe message.
*/
-void accept_probe(src, dst, p, datalen, level)
- u_long src;
- u_long dst;
+void
+accept_probe(src, dst, p, datalen, level)
+ u_int32 src;
+ u_int32 dst;
char *p;
int datalen;
- u_long level;
+ u_int32 level;
{
vifi_t vifi;
@@ -692,55 +705,56 @@ void accept_probe(src, dst, p, datalen, level)
return;
}
- if (!update_neighbor(vifi, src, DVMRP_PROBE, p, datalen, level))
- return;
-
- report(ALL_ROUTES, vifi, src);
+ update_neighbor(vifi, src, DVMRP_PROBE, p, datalen, level);
}
struct newrt {
- u_long mask;
- u_long origin;
+ u_int32 mask;
+ u_int32 origin;
int metric;
int pad;
};
-int compare_rts(r1, r2)
- register struct newrt *r1;
- register struct newrt *r2;
+static int
+compare_rts(rt1, rt2)
+ const void *rt1;
+ const void *rt2;
{
- register unsigned long m1 = ntohl(r1->mask);
- register unsigned long m2 = ntohl(r2->mask);
- register unsigned long o1, o2;
+ register struct newrt *r1 = (struct newrt *)rt1;
+ register struct newrt *r2 = (struct newrt *)rt2;
+ register u_int32 m1 = ntohl(r1->mask);
+ register u_int32 m2 = ntohl(r2->mask);
+ register u_int32 o1, o2;
if (m1 > m2)
- return (1);
- if (m1 < m2)
return (-1);
+ if (m1 < m2)
+ return (1);
/* masks are equal */
o1 = ntohl(r1->origin);
o2 = ntohl(r2->origin);
if (o1 > o2)
- return (1);
- if (o1 < o2)
return (-1);
+ if (o1 < o2)
+ return (1);
return (0);
}
/*
* Process an incoming route report message.
*/
-void accept_report(src, dst, p, datalen, level)
- u_long src, dst, level;
+void
+accept_report(src, dst, p, datalen, level)
+ u_int32 src, dst, level;
register char *p;
register int datalen;
{
vifi_t vifi;
register int width, i, nrt = 0;
int metric;
- u_long mask;
- u_long origin;
+ u_int32 mask;
+ u_int32 origin;
struct newrt rt[4096];
if ((vifi = find_vif(src, dst)) == NO_VIF) {
@@ -767,10 +781,10 @@ void accept_report(src, dst, p, datalen, level)
inet_fmt(src, s1));
return;
}
- ((char *)&mask)[0] = 0xff; width = 1;
- if ((((char *)&mask)[1] = *p++) != 0) width = 2;
- if ((((char *)&mask)[2] = *p++) != 0) width = 3;
- if ((((char *)&mask)[3] = *p++) != 0) width = 4;
+ ((u_char *)&mask)[0] = 0xff; width = 1;
+ if ((((u_char *)&mask)[1] = *p++) != 0) width = 2;
+ if ((((u_char *)&mask)[2] = *p++) != 0) width = 3;
+ if ((((u_char *)&mask)[3] = *p++) != 0) width = 4;
datalen -= 3;
do { /* Loop through (origin, metric) pairs */
@@ -787,14 +801,22 @@ void accept_report(src, dst, p, datalen, level)
datalen -= width + 1;
rt[nrt].mask = mask;
rt[nrt].origin = origin;
- rt[nrt].metric = metric;
+ rt[nrt].metric = (metric & 0x7f);
++nrt;
} while (!(metric & 0x80));
}
qsort((char*)rt, nrt, sizeof(rt[0]), compare_rts);
start_route_updates();
+ /*
+ * If the last entry is default, change mask from 0xff000000 to 0
+ */
+ if (rt[nrt-1].origin == 0)
+ rt[nrt-1].mask = 0;
+
+ log(LOG_DEBUG, 0, "Updating %d routes from %s to %s", nrt,
+ inet_fmt(src, s1), inet_fmt(dst, s2));
for (i = 0; i < nrt; ++i)
- update_route(rt[i].origin, rt[i].mask, (rt[i].metric & 0x7f),
+ update_route(rt[i].origin, rt[i].mask, rt[i].metric,
src, vifi);
if (routes_changed && !delay_change_reports)
@@ -806,26 +828,43 @@ void accept_report(src, dst, p, datalen, level)
* Send a route report message to destination 'dst', via virtual interface
* 'vifi'. 'which_routes' specifies ALL_ROUTES or CHANGED_ROUTES.
*/
-void report(which_routes, vifi, dst)
+void
+report(which_routes, vifi, dst)
int which_routes;
vifi_t vifi;
- u_long dst;
+ u_int32 dst;
{
register struct rtentry *r;
register char *p;
register int i;
- int datalen;
- int width;
- u_long mask;
- u_long src;
+ int datalen = 0;
+ int width = 0;
+ u_int32 mask = 0;
+ u_int32 src;
+ u_int32 nflags;
src = uvifs[vifi].uv_lcl_addr;
p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
- datalen = 0;
- mask = 0;
- for (r = routing_table; r != NULL; r = r->rt_next) {
+#ifdef NOTYET
+ /* If I'm not a leaf, but the neighbor is a leaf, only advertise default */
+ if ((vifs_with_neighbors != 1) && (uvifs[vifi].uv_flags & VIFF_LEAF)) {
+ *p++ = 0; /* 0xff000000 mask */
+ *p++ = 0;
+ *p++ = 0;
+ *p++ = 0; /* class A net 0.0.0.0 == default */
+ *p++ = 0x81; /*XXX metric 1, is this safe? */
+ datalen += 5;
+ send_igmp(src, dst, IGMP_DVMRP, DVMRP_REPORT,
+ htonl(MROUTED_LEVEL), datalen);
+ return;
+ }
+#endif
+
+ nflags = (uvifs[vifi].uv_flags & VIFF_LEAF) ? 0 : LEAF_FLAGS;
+
+ for (r = rt_end; r != RT_ADDR; r = r->rt_prev) {
if (which_routes == CHANGED_ROUTES && !(r->rt_flags & RTF_CHANGED))
continue;
@@ -839,14 +878,14 @@ void report(which_routes, vifi, dst)
(r->rt_originwidth + 4)) > MAX_DVMRP_DATA_LEN) {
*(p-1) |= 0x80;
send_igmp(src, dst, IGMP_DVMRP, DVMRP_REPORT,
- htonl(MROUTED_LEVEL), datalen);
+ htonl(MROUTED_LEVEL | nflags), datalen);
p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
datalen = 0;
mask = 0;
}
- if(r->rt_originmask != mask) {
+ if (r->rt_originmask != mask || datalen == 0) {
mask = r->rt_originmask;
width = r->rt_originwidth;
if (datalen != 0) *(p-1) |= 0x80;
@@ -869,7 +908,7 @@ void report(which_routes, vifi, dst)
if (datalen != 0) {
*(p-1) |= 0x80;
send_igmp(src, dst, IGMP_DVMRP, DVMRP_REPORT,
- htonl(MROUTED_LEVEL), datalen);
+ htonl(MROUTED_LEVEL | nflags), datalen);
}
}
@@ -878,7 +917,8 @@ void report(which_routes, vifi, dst)
* Send a route report message to all neighboring routers.
* 'which_routes' specifies ALL_ROUTES or CHANGED_ROUTES.
*/
-void report_to_all_neighbors(which_routes)
+void
+report_to_all_neighbors(which_routes)
int which_routes;
{
register vifi_t vifi;
@@ -926,26 +966,38 @@ void report_to_all_neighbors(which_routes)
* Send a route report message to destination 'dst', via virtual interface
* 'vifi'. 'which_routes' specifies ALL_ROUTES or CHANGED_ROUTES.
*/
-int report_chunk(start_rt, vifi, dst)
+static int
+report_chunk(start_rt, vifi, dst)
register struct rtentry *start_rt;
vifi_t vifi;
- u_long dst;
+ u_int32 dst;
{
register struct rtentry *r;
register char *p;
register int i;
register int nrt = 0;
- int datalen;
- int width;
- u_long mask;
- u_long src;
+ int datalen = 0;
+ int width = 0;
+ u_int32 mask = 0;
+ u_int32 src;
+ u_int32 nflags;
src = uvifs[vifi].uv_lcl_addr;
p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
- datalen = 0;
- mask = 0;
- for (r = start_rt; r != NULL; r = r->rt_next) {
+ nflags = (uvifs[vifi].uv_flags & VIFF_LEAF) ? 0 : LEAF_FLAGS;
+
+ for (r = start_rt; r != RT_ADDR; r = r->rt_prev) {
+
+#ifdef NOTYET
+ /* Don't send poisoned routes back to parents if I am a leaf */
+ if ((vifs_with_neighbors == 1) && (r->rt_parent == vifi)
+ && (r->rt_metric > 1)) {
+ ++nrt;
+ continue;
+ }
+#endif
+
/*
* If there is no room for this route in the current message,
* send it & return how many routes we sent.
@@ -955,10 +1007,10 @@ int report_chunk(start_rt, vifi, dst)
(r->rt_originwidth + 4)) > MAX_DVMRP_DATA_LEN) {
*(p-1) |= 0x80;
send_igmp(src, dst, IGMP_DVMRP, DVMRP_REPORT,
- htonl(MROUTED_LEVEL), datalen);
+ htonl(MROUTED_LEVEL | nflags), datalen);
return (nrt);
}
- if(r->rt_originmask != mask) {
+ if (r->rt_originmask != mask || datalen == 0) {
mask = r->rt_originmask;
width = r->rt_originwidth;
if (datalen != 0) *(p-1) |= 0x80;
@@ -979,21 +1031,22 @@ int report_chunk(start_rt, vifi, dst)
if (datalen != 0) {
*(p-1) |= 0x80;
send_igmp(src, dst, IGMP_DVMRP, DVMRP_REPORT,
- htonl(MROUTED_LEVEL), datalen);
+ htonl(MROUTED_LEVEL | nflags), datalen);
}
return (nrt);
}
/*
* send the next chunk of our routing table to all neighbors.
+ * return the length of the smallest chunk we sent out.
*/
-int report_next_chunk()
+int
+report_next_chunk()
{
register vifi_t vifi;
register struct uvif *v;
- register struct rtentry *r;
register struct rtentry *sr;
- register int i, n = 0;
+ register int i, n = 0, min = 20000;
static int start_rt;
if (nroutes <= 0)
@@ -1002,24 +1055,36 @@ int report_next_chunk()
/*
* find this round's starting route.
*/
- for (sr = routing_table, i = start_rt; --i >= 0; ) {
- sr = sr->rt_next;
- if (sr == NULL)
- sr = routing_table;
+ for (sr = rt_end, i = start_rt; --i >= 0; ) {
+ sr = sr->rt_prev;
+ if (sr == RT_ADDR)
+ sr = rt_end;
}
+
/*
* send one chunk of routes starting at this round's start to
* all our neighbors.
*/
for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
- if (v->uv_neighbors != NULL) {
+ if ((v->uv_neighbors != NULL)
+#ifdef NOTYET
+ && !(v->uv_flags & VIFF_LEAF)
+#endif
+ ) {
n = report_chunk(sr, vifi,
(v->uv_flags & VIFF_TUNNEL) ? v->uv_rmt_addr
: dvmrp_group);
+ if (n < min)
+ min = n;
}
}
- if (debug)
- printf("update %d starting at %d of %d\n", n, start_rt, nroutes);
+ if (min == 20000)
+ min = 0; /* Neighborless router didn't send any routes */
+
+ n = min;
+ log(LOG_INFO, 0, "update %d starting at %d of %d",
+ n, (nroutes - start_rt), nroutes);
+
start_rt = (start_rt + n) % nroutes;
return (n);
}
@@ -1028,28 +1093,29 @@ int report_next_chunk()
/*
* Print the contents of the routing table on file 'fp'.
*/
-void dump_routes(fp)
+void
+dump_routes(fp)
FILE *fp;
{
register struct rtentry *r;
register int i;
+
fprintf(fp,
- "Multicast Routing Table (%u %s)\n%s",
+ "Multicast Routing Table (%u %s)\n%s\n",
nroutes, (nroutes == 1) ? "entry" : "entries",
- " Origin-Subnet From-Gateway Metric In-Vif Out-Vifs\n");
+ " Origin-Subnet From-Gateway Metric Tmr In-Vif Out-Vifs");
for (r = routing_table; r != NULL; r = r->rt_next) {
- fprintf(fp, " %-15s %-15s ",
+ fprintf(fp, " %-18s %-15s ",
inet_fmts(r->rt_origin, r->rt_originmask, s1),
(r->rt_gateway == 0) ? "" : inet_fmt(r->rt_gateway, s2));
fprintf(fp, (r->rt_metric == UNREACHABLE) ? " NR " : "%4u ",
r->rt_metric);
- fprintf(fp, "%7u ",
- r->rt_parent);
+ fprintf(fp, " %3u %3u ", r->rt_timer, r->rt_parent);
for (i = 0; i < numvifs; ++i) {
if (VIFM_ISSET(i, r->rt_children)) {
@@ -1062,8 +1128,9 @@ void dump_routes(fp)
fprintf(fp, "\n");
}
-struct rtentry *determine_route(src)
- u_long src;
+struct rtentry *
+determine_route(src)
+ u_int32 src;
{
struct rtentry *rt;
@@ -1073,4 +1140,3 @@ struct rtentry *determine_route(src)
}
return rt;
}
-
diff --git a/usr.sbin/mrouted/route.h b/usr.sbin/mrouted/route.h
index 2e7aa3303bbc..c947dd2da62a 100644
--- a/usr.sbin/mrouted/route.h
+++ b/usr.sbin/mrouted/route.h
@@ -7,16 +7,16 @@
* Leland Stanford Junior University.
*
*
- * $Id: route.h,v 1.3 1993/05/30 01:36:38 deering Exp $
+ * $Id: route.h,v 3.6 1995/06/25 19:21:05 fenner Exp $
*/
/*
* Routing Table Entry, one per subnet from which a multicast could originate.
* (Note: all addresses, subnet numbers and masks are kept in NETWORK order.)
*
- * The Routing Table is stored as a singly-linked list of these structures,
- * ordered by increasing value of rt_originmask and, secondarily, by
- * increasing value of rt_origin within each rt_originmask value.
+ * The Routing Table is stored as a doubly-linked list of these structures,
+ * ordered by decreasing value of rt_originmask and, secondarily, by
+ * decreasing value of rt_origin within each rt_originmask value.
* This data structure is efficient for generating route reports, whether
* full or partial, for processing received full reports, for clearing the
* CHANGED flags, and for periodically advancing the timers in all routes.
@@ -27,24 +27,25 @@
*/
struct rtentry {
struct rtentry *rt_next; /* link to next entry MUST BE FIRST */
- u_long rt_origin; /* subnet origin of multicasts */
- u_long rt_originmask; /* subnet mask for origin */
+ u_int32 rt_origin; /* subnet origin of multicasts */
+ u_int32 rt_originmask; /* subnet mask for origin */
short rt_originwidth; /* # bytes of origin subnet number */
u_char rt_metric; /* cost of route back to origin */
u_char rt_flags; /* RTF_ flags defined below */
- u_long rt_gateway; /* first-hop gateway back to origin */
+ u_int32 rt_gateway; /* first-hop gateway back to origin */
vifi_t rt_parent; /* incoming vif (ie towards origin) */
vifbitmap_t rt_children; /* outgoing children vifs */
vifbitmap_t rt_leaves; /* subset of outgoing children vifs */
- u_long *rt_dominants; /* per vif dominant gateways */
- u_long *rt_subordinates; /* per vif subordinate gateways */
- u_long *rt_leaf_timers; /* per vif leaf confirmation timers */
- u_long rt_timer; /* for timing out the route entry */
+ u_int32 *rt_dominants; /* per vif dominant gateways */
+ u_int32 *rt_subordinates; /* per vif subordinate gateways */
+ u_int *rt_leaf_timers; /* per vif leaf confirmation timers */
+ u_int rt_timer; /* for timing out the route entry */
+ struct rtentry *rt_prev; /* link to previous entry */
+ struct gtable *rt_groups; /* link to active groups */
};
#define RTF_CHANGED 0x01 /* route changed but not reported */
#define RTF_LEAF_TIMING 0x02 /* some leaf timers are running */
-
#define ALL_ROUTES 0 /* possible arguments to report() */
#define CHANGED_ROUTES 1 /* and report_to_all_neighbors() */
diff --git a/usr.sbin/mrouted/rsrr.c b/usr.sbin/mrouted/rsrr.c
index 34eedabbe8aa..c7bbc892379f 100644
--- a/usr.sbin/mrouted/rsrr.c
+++ b/usr.sbin/mrouted/rsrr.c
@@ -33,6 +33,10 @@
#ifdef RSRR
#include "defs.h"
+#include <sys/param.h>
+#if (defined(BSD) && (BSD >= 199103))
+#include <stddef.h>
+#endif
/* Taken from prune.c */
/*
@@ -64,11 +68,13 @@ int client_length = sizeof(client_addr);
/*
* Procedure definitions needed internally.
*/
-void rsrr_accept();
-void rsrr_accept_iq();
-int rsrr_accept_rq();
-int rsrr_send();
-void rsrr_cache();
+static void rsrr_accept __P((int recvlen));
+static void rsrr_accept_iq __P((void));
+static int rsrr_accept_rq __P((struct rsrr_rq *route_query, int flags,
+ struct gtable *gt_notify));
+static int rsrr_send __P((int sendlen));
+static void rsrr_cache __P((struct gtable *gt,
+ struct rsrr_rq *route_query));
/* Initialize RSRR socket */
void
@@ -84,7 +90,13 @@ rsrr_init()
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sun_family = AF_UNIX;
strcpy(serv_addr.sun_path, RSRR_SERV_PATH);
+#if (defined(BSD) && (BSD >= 199103))
+ servlen = offsetof(struct sockaddr_un, sun_path) +
+ strlen(serv_addr.sun_path);
+ serv_addr.sun_len = servlen;
+#else
servlen = sizeof(serv_addr.sun_family) + strlen(serv_addr.sun_path);
+#endif
if (bind(rsrr_socket, (struct sockaddr *) &serv_addr, servlen) < 0)
log(LOG_ERR, errno, "Can't bind RSRR socket");
@@ -95,14 +107,15 @@ rsrr_init()
/* Read a message from the RSRR socket */
void
-rsrr_read()
+rsrr_read(rfd)
+ fd_set *rfd;
{
register int rsrr_recvlen;
register int omask;
bzero((char *) &client_addr, sizeof(client_addr));
rsrr_recvlen = recvfrom(rsrr_socket, rsrr_recv_buf, sizeof(rsrr_recv_buf),
- 0, (struct sockaddr *)&client_addr,&client_length);
+ 0, (struct sockaddr *)&client_addr, &client_length);
if (rsrr_recvlen < 0) {
if (errno != EINTR)
log(LOG_ERR, errno, "RSRR recvfrom");
@@ -117,7 +130,7 @@ rsrr_read()
/* Accept a message from the reservation protocol and take
* appropriate action.
*/
-void
+static void
rsrr_accept(recvlen)
int recvlen;
{
@@ -183,7 +196,7 @@ rsrr_accept(recvlen)
}
/* Send an Initial Reply to the reservation protocol. */
-void
+static void
rsrr_accept_iq()
{
struct rsrr_header *rsrr;
@@ -235,7 +248,7 @@ rsrr_accept_iq()
* kernel table entry contains the routing info to use for a route
* change notification.
*/
-int
+static int
rsrr_accept_rq(route_query,flags,gt_notify)
struct rsrr_rq *route_query;
int flags;
@@ -355,7 +368,7 @@ rsrr_accept_rq(route_query,flags,gt_notify)
}
/* Send an RSRR message. */
-int
+static int
rsrr_send(sendlen)
int sendlen;
{
@@ -368,30 +381,28 @@ rsrr_send(sendlen)
/* Check for errors. */
if (error < 0) {
log(LOG_WARNING, errno, "Failed send on RSRR socket");
- return error;
- }
- if (error != sendlen) {
+ } else if (error != sendlen) {
log(LOG_WARNING, 0,
"Sent only %d out of %d bytes on RSRR socket\n", error, sendlen);
- return error;
}
+ return error;
}
/* Cache a message being sent to a client. Currently only used for
* caching Route Reply messages for route change notification.
*/
-void
+static void
rsrr_cache(gt,route_query)
struct gtable *gt;
struct rsrr_rq *route_query;
{
- struct rsrr_cache *rc,*rc_prev;
+ struct rsrr_cache *rc, **rcnp;
struct rsrr_header *rsrr;
rsrr = (struct rsrr_header *) rsrr_send_buf;
- rc = gt->gt_rsrr_cache;
- while (rc) {
+ rcnp = &gt->gt_rsrr_cache;
+ while ((rc = *rcnp) != NULL) {
if ((rc->route_query.source_addr.s_addr ==
route_query->source_addr.s_addr) &&
(rc->route_query.dest_addr.s_addr ==
@@ -402,22 +413,18 @@ rsrr_cache(gt,route_query)
*/
if (!BIT_TST(rsrr->flags,RSRR_NOTIFICATION_BIT)) {
/* Delete cache entry. */
- if (rc == gt->gt_rsrr_cache)
- /* Deleting first entry. */
- gt->gt_rsrr_cache = rc->next;
- else
- rc_prev->next = rc->next;
+ *rcnp = rc->next;
free(rc);
} else {
/* Update */
rc->route_query.query_id = route_query->query_id;
- printf("Update cached query id %d from client %s\n",
- rc->route_query.query_id,rc->client_addr.sun_path);
+ log(LOG_DEBUG, 0,
+ "Update cached query id %ld from client %s\n",
+ rc->route_query.query_id, rc->client_addr.sun_path);
}
return;
}
- rc_prev = rc;
- rc = rc->next;
+ rcnp = &rc->next;
}
/* Cache entry doesn't already exist. Create one and insert at
@@ -433,7 +440,7 @@ rsrr_cache(gt,route_query)
rc->client_length = client_length;
rc->next = gt->gt_rsrr_cache;
gt->gt_rsrr_cache = rc;
- printf("Cached query id %d from client %s\n",
+ log(LOG_DEBUG, 0, "Cached query id %ld from client %s\n",
rc->route_query.query_id,rc->client_addr.sun_path);
}
@@ -445,30 +452,23 @@ rsrr_cache_send(gt,notify)
struct gtable *gt;
int notify;
{
- struct rsrr_cache *rc,*rc_next,*rc_prev;
+ struct rsrr_cache *rc, **rcnp;
int flags = 0;
- rc = gt->gt_rsrr_cache;
- while (rc) {
- rc_next = rc->next;
-
- if (notify)
- BIT_SET(flags,RSRR_NOTIFICATION_BIT);
+ if (notify)
+ BIT_SET(flags,RSRR_NOTIFICATION_BIT);
+ rcnp = &gt->gt_rsrr_cache;
+ while ((rc = *rcnp) != NULL) {
if (rsrr_accept_rq(&rc->route_query,flags,gt) < 0) {
- printf("Deleting cached query id %d from client %s\n",
+ log(LOG_DEBUG, 0, "Deleting cached query id %ld from client %s\n",
rc->route_query.query_id,rc->client_addr.sun_path);
/* Delete cache entry. */
- if (rc == gt->gt_rsrr_cache)
- /* Deleting first entry. */
- gt->gt_rsrr_cache = rc_next;
- else
- rc_prev->next = rc_next;
+ *rcnp = rc->next;
free(rc);
} else {
- rc_prev = rc;
+ rcnp = &rc->next;
}
- rc = rc_next;
}
}
diff --git a/usr.sbin/mrouted/rsrr.h b/usr.sbin/mrouted/rsrr.h
index 4099dcd8e438..8bc8c9176535 100644
--- a/usr.sbin/mrouted/rsrr.h
+++ b/usr.sbin/mrouted/rsrr.h
@@ -47,7 +47,7 @@
#define RSRR_ROUTE_QUERY 3
#define RSRR_ROUTE_REPLY 4
-/* RSRR Initial Reply (Vif) Status bits.
+/* RSRR Initial Reply (Vif) Status bits
* Each definition represents the position of the bit from right to left.
*
* Right-most bit is the disabled bit, set if the vif is administratively
@@ -56,7 +56,7 @@
#define RSRR_DISABLED_BIT 0
/* All other bits are zeroes */
-/* RSRR Route Query/Reply flag bits.
+/* RSRR Route Query/Reply flag bits
* Each definition represents the position of the bit from right to left.
*
* Right-most bit is the Route Change Notification bit, set if the
diff --git a/usr.sbin/mrouted/vif.c b/usr.sbin/mrouted/vif.c
index bf7b8673159c..98915aa5ac9c 100644
--- a/usr.sbin/mrouted/vif.c
+++ b/usr.sbin/mrouted/vif.c
@@ -7,40 +7,62 @@
* Leland Stanford Junior University.
*
*
- * $Id: vif.c,v 1.8 1994/08/24 23:54:45 thyagara Exp $
+ * $Id: vif.c,v 3.6 1995/06/25 19:53:01 fenner Exp $
*/
#include "defs.h"
+#include <fcntl.h>
/*
* Exported variables.
*/
-struct uvif uvifs[MAXVIFS]; /* array of virtual interfaces */
-vifi_t numvifs; /* number of vifs in use */
-int vifs_down; /* 1=>some interfaces are down */
+struct uvif uvifs[MAXVIFS]; /* array of virtual interfaces */
+vifi_t numvifs; /* number of vifs in use */
+int vifs_down; /* 1=>some interfaces are down */
+int phys_vif; /* An enabled vif */
int udp_socket; /* Since the honkin' kernel doesn't support */
/* ioctls on raw IP sockets, we need a UDP */
/* socket as well as our IGMP (raw) socket. */
/* How dumb. */
+int vifs_with_neighbors; /* == 1 if I am a leaf */
+typedef struct {
+ vifi_t vifi;
+ struct listaddr *g;
+ int q_time;
+} cbk_t;
+
+static cbk_t *cbk;
/*
* Forward declarations.
*/
-static void start_vif();
-static void stop_vif();
+static void start_vif __P((vifi_t vifi));
+static void stop_vif __P((vifi_t vifi));
+static void age_old_hosts __P((void));
+static void send_probe_on_vif __P((struct uvif *v));
+static void DelVif __P((cbk_t *cbk));
+static int SetTimer __P((int vifi, struct listaddr *g));
+static int DeleteTimer __P((int id));
+static void SendQuery __P((cbk_t *cbk));
+static int SetQueryTimer __P((struct listaddr *g, vifi_t vifi, int to_expire,
+ int q_time));
+
/*
* Initialize the virtual interfaces.
*/
-void init_vifs()
+void
+init_vifs()
{
vifi_t vifi;
struct uvif *v;
int enabled_vifs, enabled_phyints;
+ extern char *configfilename;
numvifs = 0;
+ vifs_with_neighbors = 0;
vifs_down = FALSE;
/*
@@ -50,7 +72,9 @@ void init_vifs()
*/
if ((udp_socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
log(LOG_ERR, errno, "UDP socket");
+ log(LOG_INFO,0,"Getting vifs from kernel interfaces");
config_vifs_from_kernel();
+ log(LOG_INFO,0,"Getting vifs from %s",configfilename);
config_vifs_from_file();
/*
@@ -58,11 +82,15 @@ void init_vifs()
*/
enabled_vifs = 0;
enabled_phyints = 0;
+ phys_vif = -1;
for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
if (!(v->uv_flags & VIFF_DISABLED)) {
++enabled_vifs;
- if (!(v->uv_flags & VIFF_TUNNEL))
+ if (!(v->uv_flags & VIFF_TUNNEL)) {
+ if (phys_vif == -1)
+ phys_vif = vifi;
++enabled_phyints;
+ }
}
}
if (enabled_vifs < 2)
@@ -77,11 +105,19 @@ void init_vifs()
* Start routing on all virtual interfaces that are not down or
* administratively disabled.
*/
+ log(LOG_INFO, 0, "Installing vifs in kernel...");
for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
if (!(v->uv_flags & VIFF_DISABLED)) {
- if (!(v->uv_flags & VIFF_DOWN))
+ if (!(v->uv_flags & VIFF_DOWN)) {
+ if (v->uv_flags & VIFF_TUNNEL)
+ log(LOG_INFO, 0, "vif #%d, tunnel %s -> %s", vifi,
+ inet_fmt(v->uv_lcl_addr, s1),
+ inet_fmt(v->uv_rmt_addr, s2));
+ else
+ log(LOG_INFO, 0, "vif #%d, phyint %s", vifi,
+ inet_fmt(v->uv_lcl_addr, s1));
start_vif(vifi);
- else log(LOG_INFO, 0,
+ } else log(LOG_INFO, 0,
"%s is not yet up; vif #%u not in service",
v->uv_name, vifi);
}
@@ -95,7 +131,8 @@ void init_vifs()
* tunnel end-points. Ignore interfaces that have been administratively
* disabled.
*/
-void check_vif_state()
+void
+check_vif_state()
{
register vifi_t vifi;
register struct uvif *v;
@@ -134,23 +171,58 @@ void check_vif_state()
}
}
+/*
+ * Send a probe message on vif v
+ */
+static void
+send_probe_on_vif(v)
+ register struct uvif *v;
+{
+ register char *p;
+ register int datalen = 0;
+ struct listaddr *nbr;
+ int i;
+
+ p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
+
+ for (i = 0; i < 4; i++)
+ *p++ = ((char *)&(dvmrp_genid))[i];
+ datalen += 4;
+
+ /*
+ * add the neighbor list on the interface to the message
+ */
+ nbr = v->uv_neighbors;
+
+ while (nbr) {
+ for (i = 0; i < 4; i++)
+ *p++ = ((char *)&nbr->al_addr)[i];
+ datalen +=4;
+ nbr = nbr->al_next;
+ }
+
+ send_igmp(v->uv_lcl_addr,
+ (v->uv_flags & VIFF_TUNNEL) ? v->uv_rmt_addr
+ : dvmrp_group,
+ IGMP_DVMRP, DVMRP_PROBE,
+ htonl(MROUTED_LEVEL |
+ ((v->uv_flags & VIFF_LEAF) ? 0 : LEAF_FLAGS)),
+ datalen);
+}
/*
* Start routing on the specified virtual interface.
*/
-static void start_vif(vifi)
+static void
+start_vif(vifi)
vifi_t vifi;
{
struct uvif *v;
- u_long src, dst;
- int i;
- char *p;
- int datalen;
- struct listaddr *nbr;
+ u_int32 src;
+ struct phaddr *p;
v = &uvifs[vifi];
src = v->uv_lcl_addr;
- dst = (v->uv_flags & VIFF_TUNNEL) ? v->uv_rmt_addr : dvmrp_group;
/*
* Install the interface in the kernel's vif structure.
@@ -173,11 +245,22 @@ static void start_vif(vifi)
k_join(dvmrp_group, src);
/*
+ * Join the ALL-ROUTERS multicast group on the interface.
+ * This allows mtrace requests to loop back if they are run
+ * on the multicast router.
+ */
+ k_join(allrtrs_group, src);
+
+ /*
* Install an entry in the routing table for the subnet to which
* the interface is connected.
*/
start_route_updates();
update_route(v->uv_subnet, v->uv_subnetmask, 0, 0, vifi);
+ for (p = v->uv_addrs; p; p = p->pa_next) {
+ start_route_updates();
+ update_route(p->pa_subnet, p->pa_subnetmask, 0, 0, vifi);
+ }
/*
* Until neighbors are discovered, assume responsibility for sending
@@ -186,45 +269,28 @@ static void start_vif(vifi)
*/
v->uv_flags |= VIFF_QUERIER;
send_igmp(src, allhosts_group, IGMP_HOST_MEMBERSHIP_QUERY,
- GROUP_EXPIRE_TIME * 10 / ROUTE_MAX_REPORT_DELAY, 0, 0);
+ IGMP_MAX_HOST_REPORT_DELAY * IGMP_TIMER_SCALE, 0, 0);
age_old_hosts();
}
- /*
- * Send a probe via the new vif to look for neighbors.
- */
- p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
- datalen = 0;
-
- for (i = 0; i < 4; i++)
- *p++ = ((char *)&(dvmrp_genid))[i];
- datalen += 4;
+ v->uv_leaf_timer = LEAF_CONFIRMATION_TIME;
/*
- * add the neighbor list on the interface to the message
+ * Send a probe via the new vif to look for neighbors.
*/
- nbr = v->uv_neighbors;
-
- while (nbr) {
- for (i = 0; i < 4; i++)
- *p++ = ((char *)&nbr->al_addr)[i];
- datalen +=4;
- nbr = nbr->al_next;
- }
-
- send_igmp(src, dst, IGMP_DVMRP, DVMRP_PROBE,
- htonl(MROUTED_LEVEL), datalen);
+ send_probe_on_vif(v);
}
-
/*
* Stop routing on the specified virtual interface.
*/
-static void stop_vif(vifi)
+static void
+stop_vif(vifi)
vifi_t vifi;
{
struct uvif *v;
struct listaddr *a;
+ struct phaddr *p;
v = &uvifs[vifi];
@@ -235,12 +301,21 @@ static void stop_vif(vifi)
k_leave(dvmrp_group, v->uv_lcl_addr);
/*
+ * Depart from the ALL-ROUTERS multicast group on the interface.
+ */
+ k_leave(allrtrs_group, v->uv_lcl_addr);
+
+ /*
* Update the entry in the routing table for the subnet to which
* the interface is connected, to take into account the interface
* failure.
*/
start_route_updates();
update_route(v->uv_subnet, v->uv_subnetmask, UNREACHABLE, 0, vifi);
+ for (p = v->uv_addrs; p; p = p->pa_next) {
+ start_route_updates();
+ update_route(p->pa_subnet, p->pa_subnetmask, UNREACHABLE, 0, vifi);
+ }
/*
* Discard all group addresses. (No need to tell kernel;
@@ -268,6 +343,9 @@ static void stop_vif(vifi)
/*
* Discard all neighbor addresses.
*/
+ if (v->uv_neighbors)
+ vifs_with_neighbors--;
+
while (v->uv_neighbors != NULL) {
a = v->uv_neighbors;
v->uv_neighbors = a->al_next;
@@ -279,7 +357,8 @@ static void stop_vif(vifi)
/*
* stop routing on all vifs
*/
-void stop_all_vifs()
+void
+stop_all_vifs()
{
vifi_t vifi;
struct uvif *v;
@@ -311,12 +390,14 @@ void stop_all_vifs()
* Find the virtual interface from which an incoming packet arrived,
* based on the packet's source and destination IP addresses.
*/
-vifi_t find_vif(src, dst)
- register u_long src;
- register u_long dst;
+vifi_t
+find_vif(src, dst)
+ register u_int32 src;
+ register u_int32 dst;
{
register vifi_t vifi;
register struct uvif *v;
+ register struct phaddr *p;
for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
if (!(v->uv_flags & (VIFF_DOWN|VIFF_DISABLED))) {
@@ -326,15 +407,22 @@ vifi_t find_vif(src, dst)
}
else {
if ((src & v->uv_subnetmask) == v->uv_subnet &&
- src != v->uv_subnetbcast)
+ ((v->uv_subnetmask == 0xffffffff) ||
+ (src != v->uv_subnetbcast)))
return(vifi);
+ for (p=v->uv_addrs; p; p=p->pa_next) {
+ if ((src & p->pa_subnetmask) == p->pa_subnet &&
+ ((p->pa_subnetmask == 0xffffffff) ||
+ (src != p->pa_subnetbcast)))
+ return(vifi);
+ }
}
}
}
return (NO_VIF);
}
-
+static void
age_old_hosts()
{
register vifi_t vifi;
@@ -356,7 +444,8 @@ age_old_hosts()
/*
* Send group membership queries to all subnets for which I am querier.
*/
-void query_groups()
+void
+query_groups()
{
register vifi_t vifi;
register struct uvif *v;
@@ -365,18 +454,53 @@ void query_groups()
if (v->uv_flags & VIFF_QUERIER) {
send_igmp(v->uv_lcl_addr, allhosts_group,
IGMP_HOST_MEMBERSHIP_QUERY,
- GROUP_EXPIRE_TIME * 10 / ROUTE_MAX_REPORT_DELAY, 0, 0);
+ IGMP_MAX_HOST_REPORT_DELAY * IGMP_TIMER_SCALE, 0, 0);
}
}
age_old_hosts();
}
+/*
+ * Process an incoming host membership query
+ */
+void
+accept_membership_query(src, dst, group, tmo)
+ u_int32 src, dst, group;
+ int tmo;
+{
+ register vifi_t vifi;
+ register struct uvif *v;
+
+ if ((vifi = find_vif(src, dst)) == NO_VIF ||
+ (uvifs[vifi].uv_flags & VIFF_TUNNEL)) {
+ log(LOG_INFO, 0,
+ "ignoring group membership query from non-adjacent host %s",
+ inet_fmt(src, s1));
+ return;
+ }
+
+ v = &uvifs[vifi];
+
+ /* If we consider ourselves the querier for this vif, but hear a
+ * query from a router with a lower IP address, yield to them.
+ *
+ * This is done here as well as in the neighbor discovery in case
+ * there is a querier that doesn't speak DVMRP.
+ */
+ if ((v->uv_flags & VIFF_QUERIER) &&
+ (ntohl(src) < ntohl(v->uv_lcl_addr))) {
+
+ v->uv_flags &= ~VIFF_QUERIER;
+
+ }
+}
/*
* Process an incoming group membership report.
*/
-void accept_group_report(src, dst, group, r_type)
- u_long src, dst, group;
+void
+accept_group_report(src, dst, group, r_type)
+ u_int32 src, dst, group;
int r_type;
{
register vifi_t vifi;
@@ -427,7 +551,7 @@ void accept_group_report(src, dst, group, r_type)
log(LOG_ERR, 0, "ran out of memory"); /* fatal */
g->al_addr = group;
- if (r_type == IGMP_HOST_NEW_MEMBERSHIP_REPORT){
+ if (r_type == IGMP_HOST_NEW_MEMBERSHIP_REPORT) {
g->al_last = OLD_AGE_THRESHOLD;
g->al_old = 0;
}
@@ -439,6 +563,7 @@ void accept_group_report(src, dst, group, r_type)
/** set a timer for expiration **/
g->al_query = 0;
g->al_timer = GROUP_EXPIRE_TIME;
+ time(&g->al_ctime);
g->al_timerid = SetTimer(vifi, g);
g->al_next = v->uv_groups;
v->uv_groups = g;
@@ -453,8 +578,9 @@ void accept_group_report(src, dst, group, r_type)
}
-void leave_group_message( src, dst, group)
- u_long src, dst, group;
+void
+accept_leave_message(src, dst, group)
+ u_int32 src, dst, group;
{
register vifi_t vifi;
register struct uvif *v;
@@ -463,39 +589,46 @@ void leave_group_message( src, dst, group)
if ((vifi = find_vif(src, dst)) == NO_VIF ||
(uvifs[vifi].uv_flags & VIFF_TUNNEL)) {
log(LOG_INFO, 0,
- "ignoring group membership report from non-adjacent host %s",
+ "ignoring group leave report from non-adjacent host %s",
inet_fmt(src, s1));
return;
}
v = &uvifs[vifi];
+ if (!(v->uv_flags & VIFF_QUERIER))
+ return;
+
/*
- * Look for the group in our group list; if found, reset its timer.
+ * Look for the group in our group list in order to set up a short-timeout
+ * query.
*/
for (g = v->uv_groups; g != NULL; g = g->al_next) {
if (group == g->al_addr) {
log(LOG_DEBUG, 0,
- "[vif.c, _leave_group_message] %d %d \n",
+ "[vif.c, _accept_leave_message] %d %d \n",
g->al_old, g->al_query);
+ /* Ignore the leave message if there are old hosts present */
if (g->al_old)
return;
+ /* still waiting for a reply to a query, ignore the leave */
+ if (g->al_query)
+ return;
+
/** delete old timer set a timer for expiration **/
if (g->al_timerid)
g->al_timerid = DeleteTimer(g->al_timerid);
- if (g->al_query)
- return;
/** send a group specific querry **/
- g->al_timer = GROUP_EXPIRE_TIME / 10;
+ g->al_timer = LEAVE_EXPIRE_TIME;
send_igmp(v->uv_lcl_addr, g->al_addr,
IGMP_HOST_MEMBERSHIP_QUERY,
- IGMP_MAX_HOST_REPORT_DELAY * 10 / (2*TIMER_INTERVAL),
- 0, 0);
- g->al_query = SetQueryTimer(g, vifi, g->al_timer / 3 ,
- IGMP_MAX_HOST_REPORT_DELAY / 2);
+ LEAVE_EXPIRE_TIME / 3 * IGMP_TIMER_SCALE,
+ g->al_addr, 0);
+ g->al_query = SetQueryTimer(g, vifi, g->al_timer / 3,
+ LEAVE_EXPIRE_TIME / 3 * IGMP_TIMER_SCALE);
g->al_timerid = SetTimer(vifi, g);
break;
}
@@ -508,40 +641,15 @@ void leave_group_message( src, dst, group)
* Useful to determine one-way interfaces.
* Detect neighbor loss faster.
*/
-void probe_for_neighbors()
+void
+probe_for_neighbors()
{
register vifi_t vifi;
register struct uvif *v;
- int i;
- register char *p;
- register int datalen = 0;
- struct listaddr *nbr;
for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
if (!(v->uv_flags & (VIFF_DOWN|VIFF_DISABLED))) {
-
- p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
-
- for (i = 0; i < 4; i++)
- *p++ = ((char *)&(dvmrp_genid))[i];
- datalen += 4;
-
- /*
- * add the neighbor list on the interface to the message
- */
- nbr = v->uv_neighbors;
-
- while (nbr) {
- for (i = 0; i < 4; i++)
- *p++ = ((char *)&nbr->al_addr)[i];
- datalen +=4;
- nbr = nbr->al_next;
- }
-
- send_igmp(v->uv_lcl_addr,
- (v->uv_flags & VIFF_TUNNEL) ? v->uv_rmt_addr
- : dvmrp_group,
- IGMP_DVMRP, DVMRP_PROBE, htonl(MROUTED_LEVEL), datalen);
+ send_probe_on_vif(v);
}
}
}
@@ -550,15 +658,16 @@ void probe_for_neighbors()
/*
* Send a list of all of our neighbors to the requestor, `src'.
*/
-void accept_neighbor_request(src, dst)
- u_long src, dst;
+void
+accept_neighbor_request(src, dst)
+ u_int32 src, dst;
{
vifi_t vifi;
struct uvif *v;
u_char *p, *ncount;
struct listaddr *la;
int datalen;
- u_long temp_addr, us, them = src;
+ u_int32 temp_addr, us, them = src;
/* Determine which of our addresses to use as the source of our response
* to this query.
@@ -569,6 +678,9 @@ void accept_neighbor_request(src, dst)
int addrlen = sizeof(addr);
addr.sin_family = AF_INET;
+#if (defined(BSD) && (BSD >= 199103))
+ addr.sin_len = sizeof addr;
+#endif
addr.sin_addr.s_addr = dst;
addr.sin_port = htons(2000); /* any port over 1024 will do... */
if ((udp = socket(AF_INET, SOCK_DGRAM, 0)) < 0
@@ -584,10 +696,10 @@ void accept_neighbor_request(src, dst)
us = dst;
#define PUT_ADDR(a) temp_addr = ntohl(a); \
- *p++ = temp_addr >> 24; \
- *p++ = (temp_addr >> 16) & 0xFF; \
- *p++ = (temp_addr >> 8) & 0xFF; \
- *p++ = temp_addr & 0xFF;
+ *p++ = temp_addr >> 24; \
+ *p++ = (temp_addr >> 16) & 0xFF; \
+ *p++ = (temp_addr >> 8) & 0xFF; \
+ *p++ = temp_addr & 0xFF;
p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
datalen = 0;
@@ -633,15 +745,16 @@ void accept_neighbor_request(src, dst)
/*
* Send a list of all of our neighbors to the requestor, `src'.
*/
-void accept_neighbor_request2(src, dst)
- u_long src, dst;
+void
+accept_neighbor_request2(src, dst)
+ u_int32 src, dst;
{
vifi_t vifi;
struct uvif *v;
u_char *p, *ncount;
struct listaddr *la;
int datalen;
- u_long temp_addr, us, them = src;
+ u_int32 us, them = src;
/* Determine which of our addresses to use as the source of our response
* to this query.
@@ -652,6 +765,9 @@ void accept_neighbor_request2(src, dst)
int addrlen = sizeof(addr);
addr.sin_family = AF_INET;
+#if (defined(BSD) && (BSD >= 199103))
+ addr.sin_len = sizeof addr;
+#endif
addr.sin_addr.s_addr = dst;
addr.sin_port = htons(2000); /* any port over 1024 will do... */
if ((udp = socket(AF_INET, SOCK_DGRAM, 0)) < 0
@@ -682,6 +798,8 @@ void accept_neighbor_request2(src, dst)
rflags |= DVMRP_NF_DISABLED;
if (vflags & VIFF_QUERIER)
rflags |= DVMRP_NF_QUERIER;
+ if (vflags & VIFF_LEAF)
+ rflags |= DVMRP_NF_LEAF;
ncount = 0;
la = v->uv_neighbors;
if (la == NULL) {
@@ -743,9 +861,10 @@ void accept_neighbor_request2(src, dst)
/*
* Process an incoming neighbor-list message.
*/
-void accept_neighbors(src, dst, p, datalen, level)
- u_long src, dst, level;
- char *p;
+void
+accept_neighbors(src, dst, p, datalen, level)
+ u_int32 src, dst, level;
+ u_char *p;
int datalen;
{
log(LOG_INFO, 0, "ignoring spurious DVMRP neighbor list from %s to %s",
@@ -756,9 +875,10 @@ void accept_neighbors(src, dst, p, datalen, level)
/*
* Process an incoming neighbor-list message.
*/
-void accept_neighbors2(src, dst, p, datalen, level)
- u_long src, dst, level;
- char *p;
+void
+accept_neighbors2(src, dst, p, datalen, level)
+ u_int32 src, dst, level;
+ u_char *p;
int datalen;
{
log(LOG_INFO, 0, "ignoring spurious DVMRP neighbor list2 from %s to %s",
@@ -771,21 +891,25 @@ void accept_neighbors2(src, dst, p, datalen, level)
* 'msgtype' is the type of DVMRP message received from the neighbor.
* Return TRUE if 'addr' is a valid neighbor, FALSE otherwise.
*/
-int update_neighbor(vifi, addr, msgtype, p, datalen, level)
+int
+update_neighbor(vifi, addr, msgtype, p, datalen, level)
vifi_t vifi;
- u_long addr;
+ u_int32 addr;
int msgtype;
char *p;
int datalen;
- u_long level;
+ u_int32 level;
{
register struct uvif *v;
register struct listaddr *n;
- u_long genid;
- u_long router;
- int he_hears_me = TRUE;
+ u_int32 genid = 0;
+ u_int32 router;
+ u_int32 send_tables = 0;
+ int do_reset = FALSE;
+ int nflags;
v = &uvifs[vifi];
+ nflags = (level >> 16) & 0xff;
/*
* Confirm that 'addr' is a valid neighbor address on vif 'vifi'.
@@ -808,94 +932,46 @@ int update_neighbor(vifi, addr, msgtype, p, datalen, level)
}
/*
- * If we have received a route report from a neighbor, and we believed
- * that we had no neighbors on this vif, send a full route report to
- * all neighbors on the vif.
- */
-
- if (msgtype == DVMRP_REPORT && v->uv_neighbors == NULL)
- report(ALL_ROUTES, vifi,
- (v->uv_flags & VIFF_TUNNEL) ? addr : dvmrp_group);
-
- /*
- * Check if the router gen-ids are the same.
- * Need to reset the prune state of the router if not.
- */
- if (msgtype == DVMRP_PROBE) {
- int i;
-
- if (datalen < 4) {
- log(LOG_WARNING, 0,
- "received truncated probe message from %s",
- inet_fmt(addr, s1));
- return;
- }
-
- for (i = 0; i < 4; i++)
- ((char *)&genid)[i] = *p++;
- datalen -=4;
-
- /*
- * loop through router list and check for one-way ifs.
- */
-
- he_hears_me = FALSE;
-
- while (datalen > 0) {
- if (datalen < 4) {
- log(LOG_WARNING, 0,
- "received truncated probe message from %s",
- inet_fmt(addr, s1));
- return;
- }
- for (i = 0; i < 4; i++)
- ((char *)&router)[i] = *p++;
- datalen -= 4;
- if (router == v->uv_lcl_addr) {
- he_hears_me = TRUE;
- break;
- }
- }
- }
- /*
- * Look for addr in list of neighbors; if found, reset its timer.
+ * Look for addr in list of neighbors.
*/
for (n = v->uv_neighbors; n != NULL; n = n->al_next) {
if (addr == n->al_addr) {
- n->al_timer = 0;
-
- /* If probe message and version no >= 3.3 check genid */
- if (msgtype == DVMRP_PROBE &&
- ((n->al_pv >= 3 && n->al_mv > 2) || n->al_pv > 3)) {
- if (he_hears_me == TRUE && v->uv_flags & VIFF_ONEWAY)
- v->uv_flags &= ~VIFF_ONEWAY;
-
- if (he_hears_me == FALSE)
- v->uv_flags |= VIFF_ONEWAY;
-
- if ((n->al_genid != 0) && (n->al_genid != genid)) {
- log(LOG_DEBUG, 0,
- "old:%d new:%dreset neighbor %s",
- n->al_genid, genid, inet_fmt(addr, s1));
-
- reset_neighbor_state(vifi, addr);
- n->al_genid = genid;
- /* need to do a full route report here */
- break;
- }
-
- /* recurring probe - so no need to do a route report */
- return FALSE;
- }
break;
}
}
/*
- * If not found, add it to the list. If the neighbor has a lower
- * IP address than me, yield querier duties to it.
+ * Found it. Reset its timer, and check for a version change
*/
- if (n == NULL) {
+ if (n) {
+ n->al_timer = 0;
+
+ /*
+ * update the neighbors version and protocol number
+ * if changed => router went down and came up,
+ * so take action immediately.
+ */
+ if ((n->al_pv != (level & 0xff)) ||
+ (n->al_mv != ((level >> 8) & 0xff))) {
+
+ do_reset = TRUE;
+ log(LOG_DEBUG, 0,
+ "version change neighbor %s [old:%d.%d, new:%d.%d]",
+ inet_fmt(addr, s1),
+ n->al_pv, n->al_mv, level&0xff, (level >> 8) & 0xff);
+
+ n->al_pv = level & 0xff;
+ n->al_mv = (level >> 8) & 0xff;
+ }
+ } else {
+ /*
+ * If not found, add it to the list. If the neighbor has a lower
+ * IP address than me, yield querier duties to it.
+ */
+ log(LOG_DEBUG, 0, "New neighbor %s on vif %d v%d.%d nf 0x%02x",
+ inet_fmt(addr, s1), vifi, level & 0xff, (level >> 8) & 0xff,
+ (level >> 16) & 0xff);
+
n = (struct listaddr *)malloc(sizeof(struct listaddr));
if (n == NULL)
log(LOG_ERR, 0, "ran out of memory"); /* fatal */
@@ -903,13 +979,24 @@ int update_neighbor(vifi, addr, msgtype, p, datalen, level)
n->al_addr = addr;
n->al_pv = level & 0xff;
n->al_mv = (level >> 8) & 0xff;
- if (msgtype == DVMRP_PROBE)
- n->al_genid = genid;
- else
- n->al_genid = 0;
+ n->al_genid = 0;
+ time(&n->al_ctime);
n->al_timer = 0;
n->al_next = v->uv_neighbors;
+
+ /*
+ * If we thought that we had no neighbors on this vif, send a route
+ * report to the vif. If this is just a new neighbor on the same
+ * vif, send the route report just to the new neighbor.
+ */
+ if (v->uv_neighbors == NULL) {
+ send_tables = (v->uv_flags & VIFF_TUNNEL) ? addr : dvmrp_group;
+ vifs_with_neighbors++;
+ } else {
+ send_tables = addr;
+ }
+
v->uv_neighbors = n;
if (!(v->uv_flags & VIFF_TUNNEL) &&
@@ -917,6 +1004,92 @@ int update_neighbor(vifi, addr, msgtype, p, datalen, level)
v->uv_flags &= ~VIFF_QUERIER;
}
+ /*
+ * Check if the router gen-ids are the same.
+ * Need to reset the prune state of the router if not.
+ * Also check for one-way interfaces by seeing if we are in our
+ * neighbor's list of known routers.
+ */
+ if (msgtype == DVMRP_PROBE) {
+
+ /* Check genid neighbor flag. Also check version number; 3.3 and
+ * 3.4 didn't set this flag. */
+ if ((((level >> 16) & 0xff) & NF_GENID) ||
+ (((level & 0xff) == 3) && (((level >> 8) & 0xff) > 2))) {
+
+ int i;
+
+ if (datalen < 4) {
+ log(LOG_WARNING, 0,
+ "received truncated probe message from %s (len %d)",
+ inet_fmt(addr, s1), datalen);
+ return (FALSE);
+ }
+
+ for (i = 0; i < 4; i++)
+ ((char *)&genid)[i] = *p++;
+ datalen -= 4;
+
+ if (n->al_genid == 0)
+ n->al_genid = genid;
+ else if (n->al_genid != genid) {
+ log(LOG_DEBUG, 0,
+ "new genid neigbor %s on vif %d [old:%x, new:%x]",
+ inet_fmt(addr, s1), vifi, n->al_genid, genid);
+
+ n->al_genid = genid;
+ do_reset = TRUE;
+ }
+
+ /*
+ * loop through router list and check for one-way ifs.
+ */
+
+ v->uv_flags |= VIFF_ONEWAY;
+
+ while (datalen > 0) {
+ if (datalen < 4) {
+ log(LOG_WARNING, 0,
+ "received truncated probe message from %s (len %d)",
+ inet_fmt(addr, s1), datalen);
+ return (FALSE);
+ }
+ for (i = 0; i < 4; i++)
+ ((char *)&router)[i] = *p++;
+ datalen -= 4;
+ if (router == v->uv_lcl_addr) {
+ v->uv_flags &= ~VIFF_ONEWAY;
+ break;
+ }
+ }
+ }
+ }
+ if (n->al_flags != nflags) {
+ n->al_flags = nflags;
+
+ if (n->al_flags & NF_LEAF) {
+ /*XXX If we have non-leaf neighbors then we know we shouldn't
+ * mark this vif as a leaf. For now we just count on other
+ * probes and/or reports resetting the timer. */
+ if (!v->uv_leaf_timer)
+ v->uv_leaf_timer = LEAF_CONFIRMATION_TIME;
+ } else {
+ /* If we get a leaf to non-leaf transition, we *must* update
+ * the routing table. */
+ if (v->uv_flags & VIFF_LEAF && send_tables == 0)
+ send_tables = addr;
+ v->uv_flags &= ~VIFF_LEAF;
+ v->uv_leaf_timer = 0;
+ }
+ }
+ if (do_reset) {
+ reset_neighbor_state(vifi, addr);
+ if (!send_tables)
+ send_tables = addr;
+ }
+ if (send_tables)
+ report(ALL_ROUTES, vifi, send_tables);
+
return (TRUE);
}
@@ -925,14 +1098,18 @@ int update_neighbor(vifi, addr, msgtype, p, datalen, level)
* On every timer interrupt, advance the timer in each neighbor and
* group entry on every vif.
*/
-void age_vifs()
+void
+age_vifs()
{
register vifi_t vifi;
register struct uvif *v;
register struct listaddr *a, *prev_a, *n;
- register u_long addr;
+ register u_int32 addr;
for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v ) {
+ if (v->uv_leaf_timer && (v->uv_leaf_timer -= TIMER_INTERVAL == 0)) {
+ v->uv_flags |= VIFF_LEAF;
+ }
for (prev_a = (struct listaddr *)&(v->uv_neighbors),
a = v->uv_neighbors;
@@ -955,12 +1132,19 @@ void age_vifs()
delete_neighbor_from_routes(addr, vifi);
+ if (v->uv_neighbors == NULL)
+ vifs_with_neighbors--;
+
+ v->uv_leaf_timer = LEAF_CONFIRMATION_TIME;
+
if (!(v->uv_flags & VIFF_TUNNEL)) {
v->uv_flags |= VIFF_QUERIER;
for (n = v->uv_neighbors; n != NULL; n = n->al_next) {
if (ntohl(n->al_addr) < ntohl(v->uv_lcl_addr)) {
v->uv_flags &= ~VIFF_QUERIER;
- break;
+ }
+ if (!(n->al_flags & NF_LEAF)) {
+ v->uv_leaf_timer = 0;
}
}
}
@@ -968,27 +1152,50 @@ void age_vifs()
}
}
+/*
+ * Returns the neighbor info struct for a given neighbor
+ */
+struct listaddr *
+neighbor_info(vifi, addr)
+ vifi_t vifi;
+ u_int32 addr;
+{
+ struct listaddr *u;
+
+ for (u = uvifs[vifi].uv_neighbors; u; u = u->al_next)
+ if (u->al_addr == addr)
+ return u;
+
+ return NULL;
+}
/*
* Print the contents of the uvifs array on file 'fp'.
*/
-void dump_vifs(fp)
+void
+dump_vifs(fp)
FILE *fp;
{
register vifi_t vifi;
register struct uvif *v;
register struct listaddr *a;
+ register struct phaddr *p;
struct sioc_vif_req v_req;
+ fprintf(fp, "vifs_with_neighbors = %d\n", vifs_with_neighbors);
+
+ if (vifs_with_neighbors == 1)
+ fprintf(fp,"[This host is a leaf]\n\n");
+
fprintf(fp,
"\nVirtual Interface Table\n%s",
- "Vif Name Local-Address ");
+ "Vif Name Local-Address ");
fprintf(fp,
"M Thr Rate Flags\n");
for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
- fprintf(fp, "%2u %6s %-15s %6s: %-15s %2u %3u %5u ",
+ fprintf(fp, "%2u %6s %-15s %6s: %-18s %2u %3u %5u ",
vifi,
v->uv_name,
inet_fmt(v->uv_lcl_addr, s1),
@@ -1007,15 +1214,27 @@ void dump_vifs(fp)
if (v->uv_flags & VIFF_DISABLED) fprintf(fp, " disabled");
if (v->uv_flags & VIFF_QUERIER) fprintf(fp, " querier");
if (v->uv_flags & VIFF_SRCRT) fprintf(fp, " src-rt");
+ if (v->uv_flags & VIFF_LEAF) fprintf(fp, " leaf");
fprintf(fp, "\n");
+ if (v->uv_addrs != NULL) {
+ fprintf(fp, " alternate subnets: %s\n",
+ inet_fmts(v->uv_addrs->pa_subnet, v->uv_addrs->pa_subnetmask, s1));
+ for (p = v->uv_addrs->pa_next; p; p = p->pa_next) {
+ fprintf(fp, " %s\n",
+ inet_fmts(p->pa_subnet, p->pa_subnetmask, s1));
+ }
+ }
+
if (v->uv_neighbors != NULL) {
- fprintf(fp, " peers: %s (%d.%d)\n",
+ fprintf(fp, " peers: %s (%d.%d) (0x%x)\n",
inet_fmt(v->uv_neighbors->al_addr, s1),
- v->uv_neighbors->al_pv, v->uv_neighbors->al_mv);
+ v->uv_neighbors->al_pv, v->uv_neighbors->al_mv,
+ v->uv_neighbors->al_flags);
for (a = v->uv_neighbors->al_next; a != NULL; a = a->al_next) {
- fprintf(fp, " %s (%d.%d)\n",
- inet_fmt(a->al_addr, s1), a->al_pv, a->al_mv);
+ fprintf(fp, " %s (%d.%d) (0x%x)\n",
+ inet_fmt(a->al_addr, s1), a->al_pv, a->al_mv,
+ a->al_flags);
}
}
@@ -1030,10 +1249,10 @@ void dump_vifs(fp)
if (v->uv_acl != NULL) {
struct vif_acl *acl;
- fprintf(fp, " boundaries: %-15s\n",
+ fprintf(fp, " boundaries: %-18s\n",
inet_fmts(v->uv_acl->acl_addr, v->uv_acl->acl_mask, s1));
for (acl = v->uv_acl->acl_next; acl != NULL; acl = acl->acl_next) {
- fprintf(fp, " : %-15s\n",
+ fprintf(fp, " : %-18s\n",
inet_fmts(acl->acl_addr, acl->acl_mask, s1));
}
}
@@ -1043,9 +1262,9 @@ void dump_vifs(fp)
"SIOCGETVIFCNT fails");
}
else {
- fprintf(fp, " pkts in : %d\n",
+ fprintf(fp, " pkts in : %ld\n",
v_req.icount);
- fprintf(fp, " pkts out: %d\n",
+ fprintf(fp, " pkts out: %ld\n",
v_req.ocount);
}
fprintf(fp, "\n");
@@ -1056,14 +1275,7 @@ void dump_vifs(fp)
/**** the timeout routines ********/
-typedef struct {
- vifi_t vifi;
- struct listaddr *g;
- int q_time;
-} cbk_t;
-
-static cbk_t *cbk;
-
+static void
DelVif(cbk)
cbk_t *cbk;
{
@@ -1085,7 +1297,7 @@ cbk_t *cbk;
* Group has expired
* delete all kernel cache entries with this group
*/
- if( g->al_query) DeleteTimer(g->al_query);
+ if (g->al_query) DeleteTimer(g->al_query);
delete_lclgrp(vifi, a->al_addr);
prev_a->al_next = a->al_next;
@@ -1096,34 +1308,38 @@ cbk_t *cbk;
free(cbk);
}
-
-SetTimer( vifi, g)
+static int
+SetTimer(vifi, g)
vifi_t vifi; struct listaddr *g;
{
cbk = (cbk_t *) malloc(sizeof(cbk_t));
cbk->g = g;
cbk->vifi = vifi;
- return timer_setTimer(g->al_timer,DelVif,cbk);
+ return timer_setTimer(g->al_timer, (cfunc_t)DelVif, (void *)cbk);
}
-DeleteTimer( id)
+static int
+DeleteTimer(id)
int id;
{
timer_clearTimer(id);
return 0;
}
+static void
SendQuery(cbk)
cbk_t *cbk;
{
- register struct uvif *v = &uvifs[cbk->vifi];
- send_igmp(v->uv_lcl_addr, cbk->g->al_addr,
- IGMP_HOST_MEMBERSHIP_QUERY,
- cbk->q_time * 10 / TIMER_INTERVAL, 0, 0);
- cbk->g->al_query = 0;
- free(cbk);
+ register struct uvif *v = &uvifs[cbk->vifi];
+
+ send_igmp(v->uv_lcl_addr, cbk->g->al_addr,
+ IGMP_HOST_MEMBERSHIP_QUERY,
+ cbk->q_time, 0, 0);
+ cbk->g->al_query = 0;
+ free(cbk);
}
+static int
SetQueryTimer(g , vifi, to_expire, q_time)
struct listaddr *g; vifi_t vifi;
int to_expire, q_time;
@@ -1131,6 +1347,5 @@ SetQueryTimer(g , vifi, to_expire, q_time)
cbk = (cbk_t *) malloc(sizeof(cbk_t));
cbk->g = g;
cbk->q_time = q_time; cbk-> vifi = vifi;
- return timer_setTimer(to_expire,SendQuery,cbk);
+ return timer_setTimer(to_expire, (cfunc_t)SendQuery, (void *)cbk);
}
-
diff --git a/usr.sbin/mrouted/vif.h b/usr.sbin/mrouted/vif.h
index 3cfa2e596f04..57c1c8f14526 100644
--- a/usr.sbin/mrouted/vif.h
+++ b/usr.sbin/mrouted/vif.h
@@ -7,7 +7,7 @@
* Leland Stanford Junior University.
*
*
- * $Id: vif.h,v 1.6 1994/08/24 23:54:47 thyagara Exp $
+ * $Id: vif.h,v 3.6 1995/06/25 19:53:22 fenner Exp $
*/
/*
@@ -22,15 +22,17 @@ struct uvif {
u_char uv_metric; /* cost of this vif */
u_int uv_rate_limit; /* rate limit on this vif */
u_char uv_threshold; /* min ttl required to forward on vif */
- u_long uv_lcl_addr; /* local address of this vif */
- u_long uv_rmt_addr; /* remote end-point addr (tunnels only) */
- u_long uv_subnet; /* subnet number (phyints only) */
- u_long uv_subnetmask; /* subnet mask (phyints only) */
- u_long uv_subnetbcast;/* subnet broadcast addr (phyints only) */
+ u_int32 uv_lcl_addr; /* local address of this vif */
+ u_int32 uv_rmt_addr; /* remote end-point addr (tunnels only) */
+ u_int32 uv_subnet; /* subnet number (phyints only) */
+ u_int32 uv_subnetmask; /* subnet mask (phyints only) */
+ u_int32 uv_subnetbcast;/* subnet broadcast addr (phyints only) */
char uv_name[IFNAMSIZ]; /* interface name */
struct listaddr *uv_groups; /* list of local groups (phyints only) */
struct listaddr *uv_neighbors; /* list of neighboring routers */
struct vif_acl *uv_acl; /* access control list of groups */
+ int uv_leaf_timer; /* time until this vif is considrd leaf */
+ struct phaddr *uv_addrs; /* Additional subnets on this vif */
};
#define VIFF_KERNEL_FLAGS (VIFF_TUNNEL|VIFF_SRCRT)
@@ -38,25 +40,39 @@ struct uvif {
#define VIFF_DISABLED 0x0200 /* administratively disabled */
#define VIFF_QUERIER 0x0400 /* I am the subnet's querier */
#define VIFF_ONEWAY 0x0800 /* Maybe one way interface */
+#define VIFF_LEAF 0x1000 /* all neighbors are leaves */
+
+struct phaddr {
+ struct phaddr *pa_next;
+ u_int32 pa_subnet; /* extra subnet */
+ u_int32 pa_subnetmask; /* netmask of extra subnet */
+ u_int32 pa_subnetbcast; /* broadcast of extra subnet */
+};
struct vif_acl {
struct vif_acl *acl_next; /* next acl member */
- u_long acl_addr; /* Group address */
- u_long acl_mask; /* Group addr. mask */
+ u_int32 acl_addr; /* Group address */
+ u_int32 acl_mask; /* Group addr. mask */
};
struct listaddr {
struct listaddr *al_next; /* link to next addr, MUST BE FIRST */
- u_long al_addr; /* local group or neighbor address */
+ u_int32 al_addr; /* local group or neighbor address */
u_long al_timer; /* for timing out group or neighbor */
- u_long al_genid; /* generation id for neighbor */
+ time_t al_ctime; /* neighbor creation time */
+ u_int32 al_genid; /* generation id for neighbor */
u_char al_pv; /* router protocol version */
u_char al_mv; /* router mrouted version */
- u_long al_timerid; /* returned by set timer */
- u_long al_query; /* second query in case of leave*/
- u_short al_old; /* if old memberships are present */
- u_short al_last; /* # of query's since last old rep */
+ u_long al_timerid; /* returned by set timer */
+ u_long al_query; /* second query in case of leave */
+ u_short al_old; /* if old memberships are present */
+ u_short al_last; /* # of query's since last old rep */
+ u_char al_flags; /* flags related to this neighbor */
};
+#define NF_LEAF 0x01 /* This neighbor is a leaf */
+#define NF_PRUNE 0x02 /* This neighbor understands prunes */
+#define NF_GENID 0x04 /* I supply genid & rtrlist in probe*/
+#define NF_MTRACE 0x08 /* I can understand mtrace requests */
#define NO_VIF ((vifi_t)MAXVIFS) /* An invalid vif index */