summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--usr.sbin/mrouted/Makefile.inc1
-rw-r--r--usr.sbin/mrouted/callout.c67
-rw-r--r--usr.sbin/mrouted/cfparse.y511
-rw-r--r--usr.sbin/mrouted/config.c670
-rw-r--r--usr.sbin/mrouted/defs.h102
-rw-r--r--usr.sbin/mrouted/dvmrp.h15
-rw-r--r--usr.sbin/mrouted/igmp.c80
-rw-r--r--usr.sbin/mrouted/inet.c64
-rw-r--r--usr.sbin/mrouted/kern.c90
-rw-r--r--usr.sbin/mrouted/main.c263
-rw-r--r--usr.sbin/mrouted/map-mbone.8156
-rw-r--r--usr.sbin/mrouted/mapper.c94
-rw-r--r--usr.sbin/mrouted/mrinfo.8153
-rw-r--r--usr.sbin/mrouted/mrinfo.c149
-rw-r--r--usr.sbin/mrouted/mrouted.8490
-rw-r--r--usr.sbin/mrouted/mrouted.conf33
-rw-r--r--usr.sbin/mrouted/mrouted/Makefile4
-rw-r--r--usr.sbin/mrouted/mtrace.8499
-rw-r--r--usr.sbin/mrouted/mtrace.c1457
-rw-r--r--usr.sbin/mrouted/pathnames.h25
-rw-r--r--usr.sbin/mrouted/prune.c2718
-rw-r--r--usr.sbin/mrouted/prune.h154
-rw-r--r--usr.sbin/mrouted/route.c356
-rw-r--r--usr.sbin/mrouted/route.h21
-rw-r--r--usr.sbin/mrouted/rsrr.c498
-rw-r--r--usr.sbin/mrouted/rsrr.h138
-rw-r--r--usr.sbin/mrouted/rsrr_var.h41
-rw-r--r--usr.sbin/mrouted/vif.c506
-rw-r--r--usr.sbin/mrouted/vif.h43
29 files changed, 6422 insertions, 2976 deletions
diff --git a/usr.sbin/mrouted/Makefile.inc b/usr.sbin/mrouted/Makefile.inc
index 8137233..dd437b1 100644
--- a/usr.sbin/mrouted/Makefile.inc
+++ b/usr.sbin/mrouted/Makefile.inc
@@ -1 +1,2 @@
.include "${.CURDIR}/../../Makefile.inc"
+CFLAGS+= -DRSRR
diff --git a/usr.sbin/mrouted/callout.c b/usr.sbin/mrouted/callout.c
index 04b1521..e2e81fb 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.3 1995/05/16 00:28:42 jkh Exp $
+ * $Id: callout.c,v 3.5 1995/05/09 01:00:39 fenner Exp $
*/
#include "defs.h"
@@ -22,13 +22,12 @@ typedef void (* cfunc_t)();
struct timeout_q {
struct timeout_q *next; /* next event */
- int id;
+ int id;
cfunc_t func ; /* function to call */
char *data; /* func's data */
int time; /* time offset to next event*/
};
-
static void print_Q();
void callout_init()
@@ -43,20 +42,20 @@ void callout_init()
void age_callout_queue()
{
struct timeout_q *ptr;
-
+
if (in_callout)
return;
in_callout = 1;
ptr = Q;
-
+
while (ptr){
if (!ptr->time ) {
/* timeout has happened */
if(ptr->func)
ptr->func(ptr->data);
Q = Q->next;
-
+
free(ptr);
ptr = Q;
}
@@ -73,7 +72,7 @@ void age_callout_queue()
}
-/*
+/*
* sets the timer
*/
int timer_setTimer(delay, action, data)
@@ -82,39 +81,39 @@ int timer_setTimer(delay, action, data)
char *data; /* what to call the timeout function with */
{
struct timeout_q *ptr, *node, *prev;
-
+
if (in_callout)
return -1;
in_callout = 1;
-
- /* create a node */
+
+ /* create a node */
node = (struct timeout_q *)malloc(sizeof(struct timeout_q));
- if ((int) node <= 0) {
+ if (node == 0) {
log(LOG_WARNING, 0, "Malloc Failed in timer_settimer\n");
in_callout = 0;
return -1;
}
- node->func = action;
+ node->func = action;
node->data = data;
- node->time = delay;
- node->next = 0;
+ node->time = delay;
+ node->next = 0;
node->id = ++id;
-
+
prev = ptr = Q;
-
+
/* insert node in the queue */
-
+
/* if the queue is empty, insert the node and return */
if (!Q)
Q = node;
else {
/* chase the pointer looking for the right place */
while (ptr){
-
+
if (delay < ptr->time){
/* right place */
-
+
node->next = ptr;
if (ptr == Q)
Q = node;
@@ -127,7 +126,7 @@ int timer_setTimer(delay, action, data)
}
else {
/* keep moving */
-
+
delay -= ptr->time; node->time = delay;
prev = ptr;
ptr = ptr->next;
@@ -142,39 +141,39 @@ 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;
in_callout = 1;
-
-
- if ( !id ) {in_callout = 0; return;}
-
+
+
+ if ( !timer_id ) {in_callout = 0; return;}
+
prev = ptr = Q;
-
+
/*
* find the right node, delete it. the subsequent node's time
* gets bumped up
*/
-
+
print_Q();
while (ptr){
- if (ptr->id == id){
+ if (ptr->id == timer_id){
/* got the right node */
-
+
/* unlink it from the queue */
if ( ptr == Q)
Q = Q->next;
else
prev->next = ptr->next;
-
+
/* increment next node if any */
if (ptr->next != 0)
(ptr->next)->time += ptr->time;
-
+
free(ptr->data);
free(ptr);
print_Q();
@@ -195,7 +194,7 @@ static void print_Q()
{
#ifdef IGMP_DEBUG
struct timeout_q *ptr;
-
+
for(ptr = Q; ptr; ptr = ptr->next)
log(LOG_DEBUG,0,"(%d,%d) ", ptr->id, ptr->time);
#endif IGMP_DEBUG
diff --git a/usr.sbin/mrouted/cfparse.y b/usr.sbin/mrouted/cfparse.y
new file mode 100644
index 0000000..5c1402f
--- /dev/null
+++ b/usr.sbin/mrouted/cfparse.y
@@ -0,0 +1,511 @@
+%{
+/*
+ * Configuration file parser for mrouted.
+ *
+ * Written by Bill Fenner, NRL, 1994
+ *
+ * $Id: cfparse.y,v 3.5 1995/05/09 01:00:39 fenner Exp $
+ */
+#include <stdio.h>
+#include <varargs.h>
+#include "defs.h"
+
+static FILE *f;
+
+extern int udp_socket;
+char *configfilename = _PATH_MROUTED_CONF;
+
+extern int cache_lifetime;
+extern int max_prune_lifetime;
+
+static int lineno;
+static struct ifreq ifbuf[32];
+static struct ifconf ifc;
+
+static struct uvif *v;
+
+static int order;
+
+struct addrmask {
+ u_int32 addr;
+ int mask;
+};
+
+struct boundnam {
+ char *name;
+ struct addrmask bound;
+};
+
+#define MAXBOUNDS 20
+
+struct boundnam boundlist[MAXBOUNDS]; /* Max. of 20 named boundaries */
+int numbounds = 0; /* Number of named boundaries */
+
+%}
+
+%union
+{
+ int num;
+ char *ptr;
+ struct addrmask addrmask;
+ u_int32 addr;
+};
+
+%token CACHE_LIFETIME PRUNING
+%token PHYINT TUNNEL NAME
+%token DISABLE METRIC THRESHOLD RATE_LIMIT SRCRT BOUNDARY NETMASK ALTNET
+%token <num> BOOLEAN
+%token <num> NUMBER
+%token <ptr> STRING
+%token <addrmask> ADDRMASK
+%token <addr> ADDR
+
+%type <addr> interface
+%type <addrmask> bound boundary addrmask
+
+%start conf
+
+%%
+
+conf : stmts
+ ;
+
+stmts : /* Empty */
+ | stmts stmt
+ ;
+
+stmt : error
+ | PHYINT interface {
+
+ vifi_t vifi;
+
+ if (order)
+ fatal("phyints must appear before tunnels");
+
+ for (vifi = 0, v = uvifs;
+ vifi < numvifs;
+ ++vifi, ++v)
+ if (!(v->uv_flags & VIFF_TUNNEL) &&
+ $2 == v->uv_lcl_addr)
+ break;
+
+ if (vifi == numvifs)
+ fatal("%s is not a configured interface",
+ inet_fmt($2,s1));
+
+ /*log(LOG_INFO, 0, "phyint: %x\n", v);*/
+ }
+ ifmods
+ | TUNNEL interface ADDR {
+
+ struct ifreq *ifr;
+ struct ifreq ffr;
+ vifi_t vifi;
+
+ order++;
+
+ ifr = ifconfaddr(&ifc, $2);
+ if (ifr == 0)
+ fatal("Tunnel local address %s is not mine",
+ inet_fmt($2, s1));
+
+ strncpy(ffr.ifr_name, ifr->ifr_name, IFNAMSIZ);
+ if (ioctl(udp_socket, SIOCGIFFLAGS, (char *)&ffr)<0)
+ fatal("ioctl SIOCGIFFLAGS on %s",ffr.ifr_name);
+ if (ffr.ifr_flags & IFF_LOOPBACK)
+ fatal("Tunnel local address %s is a loopback interface",
+ inet_fmt($2, s1));
+
+ if (ifconfaddr(&ifc, $3) != 0)
+ fatal("Tunnel remote address %s is one of mine",
+ inet_fmt($3, s1));
+
+ for (vifi = 0, v = uvifs;
+ vifi < numvifs;
+ ++vifi, ++v)
+ if (v->uv_flags & VIFF_TUNNEL) {
+ if ($3 == v->uv_rmt_addr)
+ fatal("Duplicate tunnel to %s",
+ inet_fmt($3, s1));
+ } else if (!(v->uv_flags & VIFF_DISABLED)) {
+ if (($3 & v->uv_subnetmask) == v->uv_subnet)
+ fatal("Unnecessary tunnel to %s",
+ inet_fmt($3,s1));
+ }
+
+ if (numvifs == MAXVIFS)
+ fatal("too many vifs");
+
+ v = &uvifs[numvifs];
+ v->uv_flags = VIFF_TUNNEL;
+ v->uv_metric = DEFAULT_METRIC;
+ v->uv_rate_limit= DEFAULT_TUN_RATE_LIMIT;
+ v->uv_threshold = DEFAULT_THRESHOLD;
+ v->uv_lcl_addr = $2;
+ v->uv_rmt_addr = $3;
+ 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;
+ v->uv_addrs = NULL;
+
+ if (!(ffr.ifr_flags & IFF_UP)) {
+ v->uv_flags |= VIFF_DOWN;
+ vifs_down = TRUE;
+ }
+ /*log(LOG_INFO, 0, "tunnel: %x\n", v);*/
+ }
+ tunnelmods
+ {
+ log(LOG_INFO, 0,
+ "installing tunnel from %s to %s as vif #%u - rate=%d",
+ inet_fmt($2, s1), inet_fmt($3, s2),
+ numvifs, v->uv_rate_limit);
+
+ ++numvifs;
+ }
+ | PRUNING BOOLEAN { pruning = $2; }
+ | CACHE_LIFETIME NUMBER { cache_lifetime = $2;
+ max_prune_lifetime = cache_lifetime * 2;
+ }
+ | NAME STRING boundary { if (numbounds >= MAXBOUNDS) {
+ fatal("Too many named boundaries (max %d)", MAXBOUNDS);
+ }
+
+ boundlist[numbounds].name = malloc(strlen($2) + 1);
+ strcpy(boundlist[numbounds].name, $2);
+ boundlist[numbounds++].bound = $3;
+ }
+ ;
+
+tunnelmods : /* empty */
+ | tunnelmods /*{ log(LOG_INFO, 0, "tunnelmod: %x", v); }*/ tunnelmod
+ ;
+
+tunnelmod : mod
+ | SRCRT { fatal("Source-route tunnels not supported"); }
+ ;
+
+ifmods : /* empty */
+ | ifmods /*{ log(LOG_INFO, 0, "ifmod: %x", v); }*/ ifmod
+ ;
+
+ifmod : mod
+ | DISABLE { v->uv_flags |= VIFF_DISABLED; }
+ | NETMASK ADDR { v->uv_subnetmask = $2; }
+ | ALTNET addrmask {
+
+ struct phaddr *ph;
+
+ ph = (struct phaddr *)malloc(sizeof(struct phaddr));
+ if (ph == NULL)
+ fatal("out of memory");
+ if ($2.mask) {
+ VAL_TO_MASK(ph->pa_mask, $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",
+ inet_fmt($2.addr,s1), $2.mask);
+ ph->pa_next = v->uv_addrs;
+ v->uv_addrs = ph;
+
+ }
+ ;
+
+mod : THRESHOLD NUMBER { if ($2 < 1 || $2 > 255)
+ fatal("Invalid threshold %d",$2);
+ v->uv_threshold = $2;
+ }
+ | THRESHOLD {
+
+ warn("Expected number after threshold keyword");
+
+ }
+ | METRIC NUMBER { if ($2 < 1 || $2 > UNREACHABLE)
+ fatal("Invalid metric %d",$2);
+ v->uv_metric = $2;
+ }
+ | METRIC {
+
+ warn("Expected number after metric keyword");
+
+ }
+ | RATE_LIMIT NUMBER { if ($2 > MAX_RATE_LIMIT)
+ fatal("Invalid rate_limit %d",$2);
+ v->uv_rate_limit = $2;
+ }
+ | RATE_LIMIT {
+
+ warn("Expected number after rate_limit keyword");
+
+ }
+ | BOUNDARY bound {
+
+ struct vif_acl *v_acl;
+
+ v_acl = (struct vif_acl *)malloc(sizeof(struct vif_acl));
+ if (v_acl == NULL)
+ fatal("out of memory");
+ VAL_TO_MASK(v_acl->acl_mask, $2.mask);
+ v_acl->acl_addr = $2.addr & v_acl->acl_mask;
+ if ($2.addr & ~v_acl->acl_mask)
+ warn("Boundary spec %s/%d has host bits set",
+ inet_fmt($2.addr,s1),$2.mask);
+ v_acl->acl_next = v->uv_acl;
+ v->uv_acl = v_acl;
+
+ }
+ | BOUNDARY {
+
+ warn("Expected boundary spec after boundary keyword");
+
+ }
+ ;
+
+interface : ADDR { $$ = $1; }
+ | STRING {
+ $$ = valid_if($1);
+ if ($$ == 0)
+ fatal("Invalid interface name %s",$1);
+ }
+ ;
+
+bound : boundary { $$ = $1; }
+ | STRING { int i;
+
+ for (i=0; i < numbounds; i++) {
+ if (!strcmp(boundlist[i].name, $1)) {
+ $$ = boundlist[i].bound;
+ break;
+ }
+ }
+ if (i == numbounds) {
+ fatal("Invalid boundary name %s",$1);
+ }
+ }
+ ;
+
+boundary : ADDRMASK {
+
+ if ((ntohl($1.addr) & 0xff000000) != 0xef000000) {
+ fatal("Boundaries must be 239.x.x.x, not %s/%d",
+ inet_fmt($1.addr, s1), $1.mask);
+ }
+ $$ = $1;
+
+ }
+ ;
+
+addrmask : ADDRMASK { $$ = $1; }
+ | ADDR { $$.addr = $1; $$.mask = 0; }
+ ;
+%%
+/*VARARGS1*/
+static void fatal(fmt, va_alist)
+char *fmt;
+va_dcl
+{
+ va_list ap;
+ char buf[200];
+
+ va_start(ap);
+ vsprintf(buf, fmt, ap);
+ va_end(ap);
+
+ log(LOG_ERR,0,"%s: %s near line %d", configfilename, buf, lineno);
+}
+
+/*VARARGS1*/
+static void warn(fmt, va_alist)
+char *fmt;
+va_dcl
+{
+ va_list ap;
+ char buf[200];
+
+ va_start(ap);
+ vsprintf(buf, fmt, ap);
+ va_end(ap);
+
+ log(LOG_WARNING,0,"%s: %s near line %d", configfilename, buf, lineno);
+}
+
+void yyerror(s)
+char *s;
+{
+ log(LOG_ERR, 0, "%s: %s near line %d", configfilename, s, lineno);
+}
+
+char *next_word()
+{
+ static char buf[1024];
+ static char *p=NULL;
+ extern FILE *f;
+ char *q;
+
+ while (1) {
+ if (!p || !*p) {
+ lineno++;
+ if (fgets(buf, sizeof(buf), f) == NULL)
+ return NULL;
+ p = buf;
+ }
+ while (*p && (*p == ' ' || *p == '\t')) /* skip whitespace */
+ p++;
+ if (*p == '#') {
+ p = NULL; /* skip comments */
+ continue;
+ }
+ q = p;
+ while (*p && *p != ' ' && *p != '\t' && *p != '\n')
+ p++; /* find next whitespace */
+ *p++ = '\0'; /* null-terminate string */
+
+ if (!*q) {
+ p = NULL;
+ continue; /* if 0-length string, read another line */
+ }
+
+ return q;
+ }
+}
+
+int yylex()
+{
+ int n;
+ u_int32 addr;
+ char *q;
+
+ if ((q = next_word()) == NULL) {
+ return 0;
+ }
+
+ if (!strcmp(q,"cache_lifetime"))
+ return CACHE_LIFETIME;
+ if (!strcmp(q,"pruning"))
+ return PRUNING;
+ if (!strcmp(q,"phyint"))
+ return PHYINT;
+ if (!strcmp(q,"tunnel"))
+ return TUNNEL;
+ if (!strcmp(q,"disable"))
+ return DISABLE;
+ if (!strcmp(q,"metric"))
+ return METRIC;
+ if (!strcmp(q,"threshold"))
+ return THRESHOLD;
+ if (!strcmp(q,"rate_limit"))
+ return RATE_LIMIT;
+ if (!strcmp(q,"srcrt") || !strcmp(q,"sourceroute"))
+ return SRCRT;
+ if (!strcmp(q,"boundary"))
+ return BOUNDARY;
+ if (!strcmp(q,"netmask"))
+ return NETMASK;
+ if (!strcmp(q,"name"))
+ return NAME;
+ if (!strcmp(q,"altnet"))
+ return ALTNET;
+ if (!strcmp(q,"on") || !strcmp(q,"yes")) {
+ yylval.num = 1;
+ return BOOLEAN;
+ }
+ if (!strcmp(q,"off") || !strcmp(q,"no")) {
+ yylval.num = 0;
+ return BOOLEAN;
+ }
+ if (sscanf(q,"%[.0-9]/%d%c",s1,&n,s2) == 2) {
+ if ((addr = inet_parse(s1)) != 0xffffffff) {
+ yylval.addrmask.mask = n;
+ yylval.addrmask.addr = addr;
+ return ADDRMASK;
+ }
+ /* fall through to returning STRING */
+ }
+ if (sscanf(q,"%[.0-9]%c",s1,s2) == 1) {
+ if ((addr = inet_parse(s1)) != 0xffffffff &&
+ inet_valid_host(addr)) {
+ yylval.addr = addr;
+ return ADDR;
+ }
+ }
+ if (sscanf(q,"0x%8x%c",&n,s1) == 1) {
+ yylval.addr = n;
+ return ADDR;
+ }
+ if (sscanf(q,"%d%c",&n,s1) == 1) {
+ yylval.num = n;
+ return NUMBER;
+ }
+ yylval.ptr = q;
+ return STRING;
+}
+
+void config_vifs_from_file()
+{
+ extern FILE *f;
+
+ order = 0;
+ numbounds = 0;
+ lineno = 0;
+
+ if ((f = fopen(configfilename, "r")) == 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");
+
+ yyparse();
+
+ close(f);
+}
+
+static u_int32
+valid_if(s)
+char *s;
+{
+ register vifi_t vifi;
+ register struct uvif *v;
+
+ for (vifi=0, v=uvifs; vifi<numvifs; vifi++, v++)
+ if (!strcmp(v->uv_name, s))
+ return v->uv_lcl_addr;
+
+ return 0;
+}
+
+static struct ifreq *
+ifconfaddr(ifcp, a)
+ struct ifconf *ifcp;
+ u_int32 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 (defined(BSD) && (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);
+}
diff --git a/usr.sbin/mrouted/config.c b/usr.sbin/mrouted/config.c
index 8f232ff..0113807 100644
--- a/usr.sbin/mrouted/config.c
+++ b/usr.sbin/mrouted/config.c
@@ -7,24 +7,13 @@
* Leland Stanford Junior University.
*
*
- * $Id: config.c,v 1.3 1995/04/10 18:42:10 wollman Exp $
+ * $Id: config.c,v 3.5 1995/05/09 01:00:39 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.
@@ -32,12 +21,12 @@ static char *next_word();
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 +51,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 +86,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 +115,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 +126,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 +144,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 ||
- (ntohl(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 ||
- (ntohl(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 ||
- (ntohl(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 c75dd8e..b239557 100644
--- a/usr.sbin/mrouted/defs.h
+++ b/usr.sbin/mrouted/defs.h
@@ -7,7 +7,7 @@
* Leland Stanford Junior University.
*
*
- * $Id: defs.h,v 1.2 1994/09/08 02:51:13 wollman Exp $
+ * $Id: defs.h,v 3.5 1995/05/09 01:00:39 fenner Exp $
*/
@@ -27,11 +27,22 @@
#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;
#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 +56,47 @@
#define PROTOCOL_VERSION 3 /* increment when packet format/content changes */
-#define MROUTED_VERSION 4 /* increment on local changes or bug fixes, */
+#define MROUTED_VERSION 5 /* 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 */
+#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,14 +111,16 @@ 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;
-#ifndef __FreeBSD__
extern char * sys_errlist[];
#endif
@@ -118,12 +153,16 @@ extern vifi_t find_vif();
extern void age_vifs();
extern void dump_vifs();
extern void stop_all_vifs();
+extern struct listaddr *neighbor_info();
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 accept_neighbor_request2();
+extern void accept_neighbors();
+extern void accept_neighbors2();
extern void config_vifs_from_kernel();
extern void config_vifs_from_file();
@@ -132,13 +171,12 @@ extern int inet_valid_host();
extern int inet_valid_subnet();
extern char * inet_fmt();
extern char * inet_fmts();
-extern u_long inet_parse();
+extern u_int32 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();
@@ -146,27 +184,59 @@ extern void update_lclgrp();
extern void delete_lclgrp();
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();
+#ifdef SNMP
+extern struct rtentry * snmp_find_route();
+extern struct gtable * find_grp();
+extern struct stable * find_grp_src();
+#endif
+
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 void accept_mtrace();
+extern void accept_leave_message();
+extern void accept_membership_query();
+#ifdef RSRR
+extern struct gtable *kernel_table;
+extern struct gtable *gtp;
+extern int find_src_grp();
+extern int grplst_mem();
+extern int scoped_addr();
+#endif /* RSRR */
+
+extern void k_set_rcvbuf();
+extern void k_hdr_include();
+extern void k_set_ttl();
+extern void k_set_loop();
+extern void k_set_if();
+extern void k_join();
+extern void k_leave();
+extern void k_init_dvmrp();
+extern void k_stop_dvmrp();
+extern void k_add_vif();
+extern void k_del_vif();
+extern void k_add_rg();
+extern int k_del_rg();
+extern int k_get_version();
extern char * malloc();
extern char * fgets();
extern FILE * fopen();
-#ifndef htonl
+#if !defined(htonl) && !defined(__osf__)
extern u_long htonl();
extern u_long ntohl();
#endif
+
+#ifdef RSRR
+extern void rsrr_init();
+extern void rsrr_read();
+#endif /* RSRR */
diff --git a/usr.sbin/mrouted/dvmrp.h b/usr.sbin/mrouted/dvmrp.h
index 5decfdb..4a0a163 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.5 1995/05/09 01:00:39 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 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 f814e67..5fe08e7 100644
--- a/usr.sbin/mrouted/igmp.c
+++ b/usr.sbin/mrouted/igmp.c
@@ -7,7 +7,7 @@
* Leland Stanford Junior University.
*
*
- * igmp.c,v 1.2 1994/09/08 02:51:15 wollman Exp
+ * $Id: igmp.c,v 3.5 1995/05/09 01:00:39 fenner Exp $
*/
@@ -17,12 +17,13 @@
/*
* 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 */
/*
* Open and initialize the igmp socket, and fill in the non-changing
@@ -32,7 +33,10 @@ void init_igmp()
{
struct ip *ip;
- if ((igmp_socket = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP)) < 0)
+ 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");
k_hdr_include(TRUE); /* include IP header when sending */
@@ -50,10 +54,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
@@ -69,8 +72,8 @@ static char *packet_kind(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 ";
@@ -79,12 +82,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 ";
@@ -109,7 +112,7 @@ static char *packet_kind(type, code)
void accept_igmp(recvlen)
int recvlen;
{
- register u_long src, dst, group;
+ register u_int32 src, dst, group;
struct ip *ip;
struct igmp *igmp;
int ipdatalen, iphdrlen, igmpdatalen;
@@ -124,9 +127,9 @@ void accept_igmp(recvlen)
src = ip->ip_src.s_addr;
dst = ip->ip_dst.s_addr;
- /*
+ /*
* this is most likely a message from the kernel indicating that
- * a new src grp pair message has arrived and so, it would be
+ * a new src grp pair message has arrived and so, it would be
* necessary to install a route into the kernel for this.
*/
if (ip->ip_p == 0) {
@@ -163,29 +166,30 @@ 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, ntohl(group));
+ (char *)(igmp+1), igmpdatalen, group);
return;
case DVMRP_REPORT:
accept_report(src, dst,
- (char *)(igmp+1), igmpdatalen, ntohl(group));
+ (char *)(igmp+1), igmpdatalen, group);
return;
case DVMRP_ASK_NEIGHBORS:
@@ -198,12 +202,12 @@ void accept_igmp(recvlen)
case DVMRP_NEIGHBORS:
accept_neighbors(src, dst, (char *)(igmp+1), igmpdatalen,
- group);
+ group);
return;
case DVMRP_NEIGHBORS2:
accept_neighbors2(src, dst, (char *)(igmp+1), igmpdatalen,
- group);
+ group);
return;
case DVMRP_PRUNE:
@@ -226,18 +230,20 @@ 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;
@@ -250,13 +256,14 @@ void accept_igmp(recvlen)
* 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, sizeof sdst};
+ static struct sockaddr_in sdst;
struct ip *ip;
struct igmp *igmp;
@@ -276,6 +283,11 @@ 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) {
diff --git a/usr.sbin/mrouted/inet.c b/usr.sbin/mrouted/inet.c
index 5d7442b..b888bec 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.5 1995/05/09 01:00:39 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];
/*
@@ -28,9 +29,9 @@ char s3[16]; /* or inet_fmts(). */
* {subnet,-1}.)
*/
int inet_valid_host(naddr)
- u_long naddr;
+ u_int32 naddr;
{
- register u_long addr;
+ register u_int32 addr;
addr = ntohl(naddr);
@@ -42,29 +43,38 @@ 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;
+ 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);
}
@@ -74,7 +84,7 @@ 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;
+ u_int32 addr;
char *s;
{
register u_char *a;
@@ -87,36 +97,42 @@ 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;
+ 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;
diff --git a/usr.sbin/mrouted/kern.c b/usr.sbin/mrouted/kern.c
index 8ef3571..9c308eb 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.2 1994/09/08 02:51:17 wollman Exp $
+ * $Id: kern.c,v 3.5 1995/05/09 01:00:39 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_long 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_long origin;
+ struct gtable *g;
{
struct mfcctl mc;
+ int retval, 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;
/* 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 d7292c7..efb3630 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.3 1995/03/31 21:16:43 wollman Exp $
+ * $Id: main.c,v 3.5 1995/05/09 01:00:39 fenner Exp $
*/
/*
@@ -21,13 +21,19 @@
#include "defs.h"
+#include <varargs.h>
+
+#ifdef SNMP
+#include <string.h>
+#include "snmp.h"
+#endif
extern char *configfilename;
-static char pidfilename[] = "/var/run/mrouted.pid";
-static char dumpfilename[] = "/var/tmp/mrouted.dump";
-static char cachefilename[] = "/var/tmp/mrouted.cache";
-static char genidfilename[] = "/var/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,19 +41,41 @@ 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 */
+ void (*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 cleanup();
+static void done();
static void dump();
static void fdump();
static void cdump();
static void restart();
-main(argc, argv)
+int
+register_input_handler(fd, func)
+ int fd;
+ void (*func)();
+{
+ if (nhandlers >= NHANDLERS)
+ return -1;
+
+ ihandlers[nhandlers].fd = fd;
+ ihandlers[nhandlers++].func = func;
+
+ return 0;
+}
+
+int main(argc, argv)
int argc;
char *argv[];
{
@@ -57,10 +85,27 @@ main(argc, argv)
FILE *fp;
extern uid_t geteuid();
struct timeval tv;
- struct timezone tzp;
u_long 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");
@@ -89,7 +134,7 @@ main(argc, argv)
}
if (argc > 0) {
-usage: fprintf(stderr,
+usage: fprintf(stderr,
"usage: mrouted [-p] [-c configfile] [-d [debug_level]]\n");
exit(1);
}
@@ -107,11 +152,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 +175,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
+ * Get generation id
*/
- gettimeofday(&tv, &tzp);
+ gettimeofday(&tv, 0);
dvmrp_genid = tv.tv_sec;
fp = fopen(genidfilename, "r");
@@ -148,16 +202,42 @@ 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();
+ if ((((vers >> 8) & 0xff) != PROTOCOL_VERSION) ||
+ ((vers & 0xff) != MROUTED_VERSION))
+ 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");
+ fp = fopen(pidfilename, "w");
if (fp != NULL) {
fprintf(fp, "%d\n", getpid());
(void) fclose(fp);
@@ -168,13 +248,22 @@ usage: fprintf(stderr,
(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,7 +271,30 @@ usage: fprintf(stderr,
*/
dummy = 0;
for(;;) {
- recvlen = recvfrom(igmp_socket, recv_buf, sizeof(recv_buf),
+ 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");
@@ -192,17 +304,35 @@ usage: fprintf(stderr,
accept_igmp(recvlen);
(void)sigsetmask(omask);
}
+
+ for (i = 0; i < nhandlers; i++) {
+ if (FD_ISSET(ihandlers[i].fd, &rfds)) {
+ (*ihandlers[i].func)(&rfds);
+ }
+ }
+
+#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()
{
static unsigned int tlast;
static unsigned int nsent;
@@ -235,7 +365,7 @@ static void fasttimer()
timer();
age_callout_queue();/* Advance the timer for the callout queue
- for groups */
+ for groups */
alarm(1);
}
@@ -264,7 +394,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 +432,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 +450,39 @@ 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()
+{
+ log(LOG_NOTICE, 0, "mrouted version %d.%d exiting",
+ PROTOCOL_VERSION, MROUTED_VERSION);
+ cleanup();
+ _exit(1);
+}
+
+static void
+cleanup()
{
- log(LOG_INFO, 0, "hup");
+ static in_cleanup = 0;
+
+ if (!in_cleanup) {
+ in_cleanup++;
+#ifdef RSRR
+ rsrr_clean();
+#endif /* RSRR */
expire_all_routes();
report_to_all_neighbors(ALL_ROUTES);
- exit(1);
+ k_stop_dvmrp();
+ }
}
/*
* Dump internal data structures to stderr.
*/
-static void dump()
+static void
+dump()
{
dump_vifs(stderr);
dump_routes(stderr);
@@ -333,7 +492,8 @@ static void dump()
/*
* Dump internal data structures to a file.
*/
-static void fdump()
+static void
+fdump()
{
FILE *fp;
@@ -349,13 +509,14 @@ static void fdump()
/*
* Dump local cache contents to a file.
*/
-static void cdump()
+static void
+cdump()
{
FILE *fp;
fp = fopen(cachefilename, "w");
if (fp != NULL) {
- dump_cache(fp);
+ dump_cache(fp);
(void) fclose(fp);
}
}
@@ -364,11 +525,13 @@ static void cdump()
/*
* Restart mrouted
*/
-static void restart()
+static void
+restart()
{
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 +541,8 @@ static void restart()
free_all_routes();
stop_all_vifs();
k_stop_dvmrp();
+ close(igmp_socket);
+ close(udp_socket);
/*
* start processing again
@@ -400,39 +565,49 @@ 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)
+/*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);
+ 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 41eb808..ba850d2 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 bd1dfaa..526ed9f 100644
--- a/usr.sbin/mrouted/mapper.c
+++ b/usr.sbin/mrouted/mapper.c
@@ -1,26 +1,27 @@
/* Mapper for connections between MRouteD multicast routers.
* Written by Pavel Curtis <Pavel@PARC.Xerox.Com>
*
- * $Id: mapper.c,v 1.2 1994/09/08 02:51:19 wollman Exp $
+ * $Id: mapper.c,v 3.5 1995/05/09 01:00:39 fenner Exp $
*/
/*
* Copyright (c) Xerox Corporation 1992. All rights reserved.
- *
+ *
* License is granted to copy, to use, and to make and to use derivative
* works for research and evaluation purposes, provided that Xerox is
* acknowledged in all documentation pertaining to any such copy or derivative
* work. Xerox grants no other licenses expressed or implied. The Xerox trade
* name should not be used in any advertising without its written permission.
- *
+ *
* XEROX CORPORATION MAKES NO REPRESENTATIONS CONCERNING EITHER THE
* MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF THIS SOFTWARE
* FOR ANY PARTICULAR PURPOSE. The software is provided "as is" without
* express or implied warranty of any kind.
- *
+ *
* 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"
@@ -33,7 +34,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 +43,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 +60,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;
@@ -69,7 +70,7 @@ vifi_t numvifs; /* to keep loader happy */
Node *find_node(addr, ptr)
- u_long addr;
+ u_int32 addr;
Node **ptr;
{
Node *n = *ptr;
@@ -92,7 +93,7 @@ Node *find_node(addr, ptr)
Interface *find_interface(addr, node)
- u_long addr;
+ u_int32 addr;
Node *node;
{
Interface *ifc;
@@ -112,7 +113,7 @@ Interface *find_interface(addr, node)
Neighbor *find_neighbor(addr, node)
- u_long addr;
+ u_int32 addr;
Node *node;
{
Interface *ifc;
@@ -168,14 +169,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);
@@ -186,7 +187,7 @@ void ask2(dst)
* Process an incoming group membership report.
*/
void accept_group_report(src, dst, group)
- u_long src, dst, group;
+ u_int32 src, dst, group;
{
log(LOG_INFO, 0, "ignoring IGMP group membership report from %s to %s",
inet_fmt(src, s1), inet_fmt(dst, s2));
@@ -197,7 +198,7 @@ void accept_group_report(src, dst, group)
* Process an incoming neighbor probe message.
*/
void accept_probe(src, dst)
- u_long src, dst;
+ u_int32 src, dst;
{
log(LOG_INFO, 0, "ignoring DVMRP probe from %s to %s",
inet_fmt(src, s1), inet_fmt(dst, s2));
@@ -208,7 +209,7 @@ void accept_probe(src, dst)
* Process an incoming route report message.
*/
void accept_report(src, dst, p, datalen)
- u_long src, dst;
+ u_int32 src, dst;
char *p;
int datalen;
{
@@ -221,7 +222,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 +231,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 +244,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,8 +255,8 @@ 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) {
@@ -281,7 +282,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;
@@ -354,13 +355,13 @@ void accept_neighbors(src, dst, p, datalen, level)
ifc_node->tries = -1;
ifc_node->u.alias = node;
}
-
+
ifc = find_interface(ifc_addr, node);
old_neighbors = ifc->neighbors;
-
+
/* Add the neighbors for this interface */
while (ncount--) {
- u_long neighbor;
+ u_int32 neighbor;
Neighbor *nb;
Node *n_node;
@@ -404,7 +405,7 @@ void accept_neighbors(src, dst, p, datalen, level)
}
void accept_neighbors2(src, dst, p, datalen)
- u_long src, dst;
+ u_int32 src, dst;
u_char *p;
int datalen;
{
@@ -416,7 +417,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 +429,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++;
@@ -490,13 +491,13 @@ void accept_neighbors2(src, dst, p, datalen)
ifc_node->tries = -1;
ifc_node->u.alias = node;
}
-
+
ifc = find_interface(ifc_addr, node);
old_neighbors = ifc->neighbors;
-
+
/* Add the neighbors for this interface */
while (ncount--) {
- u_long neighbor;
+ u_int32 neighbor;
Neighbor *nb;
Node *n_node;
@@ -506,7 +507,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,7 +572,7 @@ int retry_requests(node)
char *inet_name(addr)
- u_long addr;
+ u_int32 addr;
{
struct hostent *e;
@@ -586,7 +587,7 @@ void print_map(node)
{
if (node) {
char *name, *addr;
-
+
print_map(node->left);
addr = inet_fmt(node->addr, s1);
@@ -650,7 +651,7 @@ void print_map(node)
char *graph_name(addr, buf)
- u_long addr;
+ u_int32 addr;
char *buf;
{
char *name;
@@ -734,7 +735,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 +772,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,12 +790,12 @@ u_long host_addr(name)
}
-main(argc, argv)
+int main(argc, argv)
int argc;
char *argv[];
{
int flood = FALSE, graph = FALSE;
-
+
#ifdef SYSV
setvbuf(stderr, NULL, _IOLBF, 0);
#else
@@ -837,7 +838,7 @@ main(argc, argv)
}
if (argc > 1) {
- usage:
+ usage:
fprintf(stderr,
"Usage: map-mbone [-f] [-g] [-n] [-t timeout] %s\n\n",
"[-r retries] [-d [debug-level]] [router]");
@@ -862,7 +863,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
@@ -913,7 +916,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);
@@ -946,9 +949,12 @@ void accept_g_ack()
void add_table_entry()
{
}
-void leave_group_message()
+void accept_leave_message()
+{
+}
+void accept_mtrace()
{
}
-void mtrace()
+void accept_membership_query()
{
}
diff --git a/usr.sbin/mrouted/mrinfo.8 b/usr.sbin/mrouted/mrinfo.8
index b1e7880..1e7f9a9 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 d0d9e6b..8f137d0 100644
--- a/usr.sbin/mrouted/mrinfo.c
+++ b/usr.sbin/mrouted/mrinfo.c
@@ -44,24 +44,24 @@
* SUCH DAMAGE.
* ---------------------------------
* Copyright (c) Xerox Corporation 1992. All rights reserved.
- *
+ *
* License is granted to copy, to use, and to make and to use derivative works
* for research and evaluation purposes, provided that Xerox is acknowledged
* in all documentation pertaining to any such copy or derivative work. Xerox
* grants no other licenses expressed or implied. The Xerox trade name should
* not be used in any advertising without its written permission.
- *
+ *
* XEROX CORPORATION MAKES NO REPRESENTATIONS CONCERNING EITHER THE
* MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF THIS SOFTWARE FOR
* ANY PARTICULAR PURPOSE. The software is provided "as is" without express
* or implied warranty of any kind.
- *
+ *
* These notices must be retained in any copies of any part of this software.
*/
#ifndef lint
static char rcsid[] =
- "@(#) $Id: mrinfo.c,v 1.3 1995/05/16 00:28:46 jkh Exp $";
+ "@(#) $Id: mrinfo.c,v 3.5.1.1 1995/05/09 22:58:05 fenner Exp $";
/* original rcsid:
"@(#) Header: mrinfo.c,v 1.6 93/04/08 15:14:16 van Exp (LBL)";
*/
@@ -70,12 +70,14 @@ static char rcsid[] =
#include <netdb.h>
#include <sys/time.h>
#include "defs.h"
+#include <arpa/inet.h>
#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;
@@ -84,13 +86,20 @@ vifi_t numvifs; /* to keep loader happy */
char *
inet_name(addr)
- u_long addr;
+ u_int32 addr;
{
struct hostent *e;
+ struct in_addr in;
- e = gethostbyaddr((char *)&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,7 +107,7 @@ inet_name(addr)
* message and the current debug level. For errors of severity LOG_ERR or
* worse, terminate the program.
*/
-void
+void
log(severity, syserr, format, a, b, c, d, e)
int severity, syserr;
char *format;
@@ -137,17 +146,17 @@ log(severity, syserr, format, a, b, c, d, e)
/*
* Send a neighbors-list request.
*/
-void
+void
ask(dst)
- u_long dst;
+ u_int32 dst;
{
send_igmp(our_addr, dst, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS,
htonl(MROUTED_LEVEL), 0);
}
-void
+void
ask2(dst)
- u_long dst;
+ u_int32 dst;
{
send_igmp(our_addr, dst, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS2,
htonl(MROUTED_LEVEL), 0);
@@ -156,19 +165,19 @@ ask2(dst)
/*
* Process an incoming neighbor-list message.
*/
-void
+void
accept_neighbors(src, dst, p, datalen)
- u_long src, dst;
+ u_int32 src, dst;
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 +188,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));
@@ -189,30 +198,37 @@ accept_neighbors(src, dst, p, datalen)
}
}
-void
+void
accept_neighbors2(src, dst, p, datalen)
- u_long src, dst;
+ u_int32 src, dst;
u_char *p;
int datalen;
{
u_char *ep = p + datalen;
+ u_int broken_cisco = ((target_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);
+
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,18 +237,22 @@ 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");
}
}
}
-int
+int
get_number(var, deflt, pargv, pargc)
int *var, *pargc, deflt;
char ***pargv;
@@ -258,33 +278,40 @@ 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
+main(argc, argv)
int argc;
char *argv[];
{
setlinebuf(stderr);
if (geteuid() != 0) {
- fprintf(stderr, "must be root\n");
+ fprintf(stderr, "mrinfo: must be root\n");
exit(1);
}
argv++, argc--;
@@ -292,29 +319,35 @@ int 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,7 +359,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... */
@@ -347,7 +382,7 @@ usage: fprintf(stderr,
fd_set fds;
struct timeval tv;
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;
@@ -374,7 +409,7 @@ usage: fprintf(stderr,
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)
@@ -392,13 +427,6 @@ usage: fprintf(stderr,
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;
@@ -428,7 +456,7 @@ usage: fprintf(stderr,
inet_fmt(src, s1));
fprintf(stderr, " instead of %s\n",
inet_fmt(target_addr, s1));
- continue;
+ /*continue;*/
}
break;
default:
@@ -490,9 +518,12 @@ void add_table_entry()
void check_vif_state()
{
}
-void leave_group_message()
+void accept_leave_message()
+{
+}
+void accept_mtrace()
{
}
-void mtrace()
+void accept_membership_query()
{
}
diff --git a/usr.sbin/mrouted/mrouted.8 b/usr.sbin/mrouted/mrouted.8
index 11966c2..53dcec8 100644
--- a/usr.sbin/mrouted/mrouted.8
+++ b/usr.sbin/mrouted/mrouted.8
@@ -1,26 +1,30 @@
'\"COPYRIGHT 1989 by The Board of Trustees of Leland Stanford Junior University.
-.Dd March 25, 1995
-.Dt MROUTED 8
-.Os FreeBSD 2.0
-.Sh NAME
-.Nm mrouted
-.Nd IP multicast routing process
-.Sh SYNOPSIS
-.Nm mrouted
-.Op Fl p
-.Op Fl c Ar config
-.Op Fl d Ar debuglevel
-.Sh DESCRIPTION
-The
-.Nm
-program
+'\"$Id: mrouted.8,v 3.5 1995/05/09 01:00:39 fenner Exp $
+.TH MROUTED 8
+.UC 5
+.SH NAME
+mrouted \- IP multicast routing daemon
+.SH SYNOPSIS
+.B /etc/mrouted
+[
+.B \-p
+] [
+.B \-c
+.I config_file
+] [
+.B \-d
+[
+.I debug_level
+]]
+.SH DESCRIPTION
+.I Mrouted
is an implementation of the Distance-Vector Multicast Routing
Protocol (DVMRP), an earlier version of which is specified in RFC-1075.
It maintains topological knowledge via a distance-vector routing protocol
(like RIP, described in RFC-1058), upon which it implements a multicast
datagram forwarding algorithm called Reverse Path Multicasting.
-.Pp
-.Nm
+.PP
+.I Mrouted
forwards a multicast datagram along a shortest (reverse) path tree
rooted at the subnet on which the datagram originates. The multicast
delivery tree may be thought of as a broadcast delivery tree that has
@@ -29,221 +33,251 @@ that have members of the destination group. Hence, datagrams
are not forwarded along those branches which have no listeners of the
multicast group. The IP time-to-live of a multicast datagram can be
used to limit the range of multicast datagrams.
-.Pp
+.PP
In order to support multicasting among subnets that are separated by (unicast)
routers that do not support IP multicasting,
-.Nm
+.I mrouted
includes support for
-.Dq tunnels ,
-which are virtual point-to-point links between pairs of
-.Nm
-programs located anywhere in an internet. IP multicast packets are
-encapsulated for transmission through tunnels, so that they look like
-normal unicast datagrams to intervening routers and subnets. The
-encapsulation is added on entry to a tunnel, and stripped off on exit
-from a tunnel. By default, the packets are encapsulated using the
-IP-in-IP protocol (IP protocol number 4). Older versions of
-.Nm
-tunneled using IP source routing, which puts a heavy load on some
+"tunnels", which are virtual point-to-point links between pairs of
+.IR mrouted s
+located anywhere in an internet. IP multicast packets are encapsulated for
+transmission through tunnels, so that they look like normal unicast datagrams
+to intervening routers and subnets. The encapsulation
+is added on entry to a tunnel, and stripped off
+on exit from a tunnel.
+By default, the packets are encapsulated using the IP-in-IP protocol
+(IP protocol number 4).
+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.
-.Pp
+This version does not support IP source route tunnelling.
+.PP
The tunnelling mechanism allows
-.Nm
+.I mrouted
to establish a virtual internet, for
the purpose of multicasting only, which is independent of the physical
internet, and which may span multiple Autonomous Systems. This capability
is intended for experimental support of internet multicasting only, pending
widespread support for multicast routing by the regular (unicast) routers.
-.Nm
+.I Mrouted
suffers from the well-known scaling problems of any distance-vector
routing protocol, and does not (yet) support hierarchical multicast routing.
-.Pp
-.Nm
+.PP
+.I Mrouted
handles multicast routing only; there may or may not be unicast routing
software running on the same machine as
-.Nm mrouted .
+.IR mrouted .
With the use of tunnels, it
is not necessary for
-.Nm
+.I mrouted
to have access to more than one physical subnet
in order to perform multicast forwarding.
-.Pp
-If no
-.Fl d
-option is given, or if the debug level is specified as 0,
-.Nm
-detaches from its controlling terminal. Otherwise, it remains attached to the
-terminal and responsive to signals.
-.Pp
-The
-.Nm
-program accepts the following command-line options:
-.Bl -tag -width XXXdebuglevel
-.It Fl c Ar config
-This option specifies an alternate configuration file location as
-.Ar config .
-The default location is
-.Pa /etc/mrouted.conf .
-.It Fl d Ar debuglevel
-This option sets the debuging level to
-.Ar debuglevel .
-Regardless of the debug level,
-.Nm
+.br
+.ne 5
+.SH INVOCATION
+.PP
+If no "\-d" option is given, or if the debug level is specified as 0,
+.I mrouted
+detaches from the invoking terminal. Otherwise, it remains attached to the
+invoking terminal and responsive to signals from that terminal. If "\-d" is
+given with no argument, the debug level defaults to 2. Regardless of the
+debug level,
+.I mrouted
always writes warning and error messages to the system
log demon. Non-zero debug levels have the following effects:
-.Bl -tag -width "level 3"
-.It level 1
+.IP "level 1"
all syslog'ed messages are also printed to stderr.
-.It level 2
-all level 1 messages plus notifications of
-.Dq significant
+.IP "level 2"
+all level 1 messages plus notifications of "significant"
events are printed to stderr.
-.It level 3
+.IP "level 3"
all level 2 messages plus notifications of all packet
arrivals and departures are printed to stderr.
-.El
-.It Fl p
-This option disables pruning of uninterested links in the multicast
-distribution tree.
-.El
-.Sh CONFIGURATION
-.Nm
+.PP
+Upon startup, mrouted writes its pid to the file /etc/mrouted.pid .
+.SH CONFIGURATION
+.PP
+.I Mrouted
automatically configures itself to forward on all multicast-capable
-interfaces; i.e., interfaces that have the
-.Dv IFF_MULTICAST
-flag set (excluding the loopback), and it finds other
-.Nm
-programs directly reachable via those interfaces. To override the
-default configuration, or to add tunnel links to other
-.Nm
-programs, configuration commands may be placed in
-.Pa /etc/mrouted.conf
-(or an alternate location can be specified using the
-.Fl c
-option).
+interfaces, i.e., interfaces that have the IFF_MULTICAST flag set (excluding
+the loopback "interface"), and it finds other
+.IR mrouted s
+directly reachable
+via those interfaces. To override the default configuration, or to add
+tunnel links to other
+.IR mrouted s,
+configuration commands may be placed in
+/etc/mrouted.conf (or an alternative file, specified by the "\-c" option).
There are four types of configuration commands:
-.Bd -literal
+.nf
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>]
+ [boundary (<boundary-name>|<scoped-addr>/<mask-len>)]
cache_lifetime <ct>
pruning <off/on>
-.Ed
-.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.
-.Pp
+ name <boundary-name> <scoped-addr>/<mask-len>
+
+.fi
+.PP
+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
+.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
-.Nm
-programs, the srcrt keyword specifies
-encapsulation using IP source routing.
-.Pp
+'\"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
entry should lie between 300 (5 min) and 86400 (1 day). It defaults to 300.
-.Pp
+.PP
The pruning <off/on> option is provided for
-.Nm
+.IR mrouted
to act as a non-pruning router. It is also possible to start
-.Nm
-in a non-pruning mode using the
-.Fl p
-flag 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
-The metric is the
-.Dq cost
-associated with sending a datagram on the given
+.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,
because
-.Nm
+.I mrouted
cannot route along paths with a sum of metrics greater
than 31.
-.Pp
+.LP
The threshold is the minimum IP time-to-live required for a multicast datagram
to be forwarded to the given interface or tunnel. It is used to control the
scope of multicast datagrams. (The TTL of forwarded packets is only compared
to the threshold, it is not decremented by the threshold. Every multicast
router decrements the TTL by 1.) The default threshold is 1.
-.Pp
+.LP
In general, all
-.Nm mrouted
-programs connected to a particular subnet or tunnel should
+.IR mrouted s
+connected to a particular subnet or tunnel should
use the same metric and threshold for that subnet or tunnel.
-.Pp
+.PP
The rate_limit option allows the network administrator to specify a
certain bandwidth in Kbits/second which would be allocated to multicast
-traffic.
-.Pp
+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.
-.Pp
-The
-.Nm
-program
+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,
where a vif (virtual interface) is either a physical multicast-capable
interface or a tunnel. It will log a warning if all of its vifs are
tunnels; such an
-.Nm
+.I mrouted
configuration would be better replaced by more
direct tunnels (i.e., eliminate the middle man).
-.Sh SIGNALS
-The
-.Nm
-program responds to the following signals:
-.Bl -tag -width SIGTERMx
-.It Dv SIGHUP
+.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
+responds to the following signals:
+.IP HUP
restarts
-.Nm mrouted .
+.I mrouted .
The configuration file is reread every time this signal is evoked.
-.It Dv SIGINT
+.IP INT
terminates execution gracefully (i.e., by sending
good-bye messages to all neighboring routers).
-.It Dv SIGTERM
-same as
-.Dv SIGINT
-.It Dv SIGUSR1
-dumps the internal routing tables to
-.Pa /var/tmp/mrouted.dump .
-.It Dv SIGUSR2
-dumps the internal cache tables to
-.Pa /var/tmp/mrouted.cache .
-.It Dv SIGQUIT
+.IP TERM
+same as INT
+.IP USR1
+dumps the internal routing tables to /usr/tmp/mrouted.dump.
+.IP USR2
+dumps the internal cache tables to /usr/tmp/mrouted.cache.
+.IP QUIT
dumps the internal routing tables to stderr (only if
-.Nm
+.I mrouted
was invoked with a non-zero debug level).
-.El
-.Sh EXAMPLE
+.PP
+For convenience in sending signals,
+.I mrouted
+writes its pid to /etc/mrouted.pid upon startup.
+.bp
+.SH EXAMPLE
+.PP
The routing tables look like this:
-.Bd -literal
+.nf
Virtual Interface Table
Vif Local-Address Metric Thresh Flags
@@ -270,110 +304,96 @@ 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*
.
.
.
-.Ed
-.Pp
+.fi
In this example, there are four vifs connecting to two subnets and two
tunnels. The vif 3 tunnel is not in use (no peer address). The vif 0 and
vif 1 subnets have some groups present; tunnels never have any groups. This
instance of
-.Nm
+.I mrouted
is the one responsible for sending periodic group
membership queries on the vif 0 and vif 1 subnets, as indicated by the
-.Dq querier
-flags. The list of boundaries indicate the scoped addresses on that
-interface. A count of the number of incoming and outgoing packets is
-also 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 multicasts from that origin, and a list of
-outgoing vifs.
-.Dq Li \&*
-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 outgoing vif only if there are members of
-the destination group on that leaf.
-.Pp
-.Nm
+"querier" flags. The list of boundaries indicate the scoped addresses on that
+interface. A count of the no. of incoming and outgoing packets is also
+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 amount of time
+since we last recieved 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
+outgoing vif only if there are members of the destination group on that leaf.
+.bp
+.PP
+.I Mrouted
also maintains a copy of the kernel forwarding cache table. Entries
are created and deleted by
-.Nm mrouted .
-.Pp
+.I mrouted.
+.PP
The cache tables look like this:
-.Bd -literal
+.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
-.Ed
-.Pp
-Each entry is characterized by the origin subnet number and the
-destination multicast group. The
-.Dq 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
-.Dq Ivif
-field indicates the
+.fi
+Each entry is characterized by the origin subnet number and mask and the
+destination multicast group. The 'CTmr' field indicates the lifetime
+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
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
-.Dq Li \&P
-in the
-.Dq Psnt
-field. The
-.Dq 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
-.Dq Li \&p
-indicates that no datagrams are being forwarded along
+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
-.Dq Li \&b
-on an interface
-indicates that it is a boundary interface; i.e., traffic will not be
+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.
-.Sh FILES
-.Bl -tag -compact -width /var/tmp/mrouted.cache
-.It Pa /etc/mrouted.conf
-default configuration file
-.It Pa /var/tmp/mrouted.cache
-kernel forwarding cache dump file
-.It Pa /var/tmp/mrouted.dump
-routing table dump file
-.El
-.Sh SEE ALSO
-.Xr map-mbone 8 ,
-.Xr mrinfo 8 ,
-.Xr mtrace 8
-.Rs
-.%A "S. Deering"
-.%B "Proceedings of the ACM SIGCOMM '88 Conference"
-.%T "Multicast Routing in Internetworks and Extended LANs"
-.Re
-.Sh AUTHORS
-Steve Deering & Ajit Thyagarajan
-.Sh HISTORY
-The
-.Nm
-program first appeared in
-.Tn FreeBSD
-2.0.
+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, Bill Fenner
diff --git a/usr.sbin/mrouted/mrouted.conf b/usr.sbin/mrouted/mrouted.conf
index 5340bfc..993fd9e 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.5.1.1 1995/05/09 05:48:48 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/mrouted/Makefile b/usr.sbin/mrouted/mrouted/Makefile
index 12c4495..d4c216c 100644
--- a/usr.sbin/mrouted/mrouted/Makefile
+++ b/usr.sbin/mrouted/mrouted/Makefile
@@ -1,4 +1,4 @@
-# $Id$
+# $Id: Makefile,v 1.1 1994/09/08 02:51:35 wollman Exp $
PROG= mrouted
@@ -14,7 +14,7 @@ LDDESTDIR+= -L$S/common
DPADD+= $S/common/libmrouted.a
.endif
-SRCS= config.c main.c route.c vif.c prune.c callout.c
+SRCS= config.c cfparse.y main.c route.c vif.c prune.c callout.c rsrr.c
MAN8= ${.CURDIR}/../mrouted.8
.include <bsd.prog.mk>
diff --git a/usr.sbin/mrouted/mtrace.8 b/usr.sbin/mrouted/mtrace.8
new file mode 100644
index 0000000..bfc6dd5
--- /dev/null
+++ b/usr.sbin/mrouted/mtrace.8
@@ -0,0 +1,499 @@
+.\" 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.
+.\"
+.\" This manual page (but not the software) was derived from the
+.\" manual page for the traceroute program which bears the following
+.\" copyright notice:
+.\"
+.\" 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 $
+.\"
+.TH MTRACE 8 "May 8, 1995"
+.UC 6
+.SH NAME
+mtrace \- print multicast path from a source to a receiver
+.SH SYNOPSIS
+.B mtrace
+[
+.B \-g
+.I gateway
+] [
+.B \-i
+.I if_addr
+] [
+.B \-l
+] [
+.B \-M
+] [
+.B \-m
+.I max_hops
+] [
+.B \-n
+] [
+.B \-p
+] [
+.B \-q
+.I nqueries
+] [
+.B \-r
+.I resp_dest
+] [
+.B \-s
+.I src_addr
+] [
+.B \-t
+.I ttl
+] [
+.B \-w
+.I waittime
+]
+.I source
+[
+.I receiver
+] [
+.I group
+]
+.SH DESCRIPTION
+Assessing problems in the distribution of IP multicast traffic
+can be difficult.
+.B mtrace
+utilizes a tracing feature implemented in multicast routers
+.RB ( mrouted
+version 3.3 and later) that is
+accessed via an extension to the IGMP protocol. A trace query is
+passed hop-by-hop along the reverse path from the
+.I receiver
+to the
+.IR source ,
+collecting hop addresses, packet counts, and routing error conditions
+along the path, and then the response is returned to the requestor.
+.PP
+The only required parameter is the
+.I source
+host name or address. The default
+.I receiver
+is the host running mtrace, and the default
+.I group
+is "MBone Audio" (224.2.0.1), which is sufficient if packet loss
+statistics for a particular multicast group are not needed. These two
+optional parameters may be specified to test the path to some other
+receiver in a particular group, subject to some constraints as
+detailed below. The two parameters can be distinguished because the
+.I receiver
+is a unicast address and the
+.I group
+is a multicast address.
+.SH OPTIONS
+.TP 8 8
+.BI \-g\ gwy
+Send the trace query via unicast directly to the multicast router
+.I gwy
+rather than multicasting the query.
+This must be the last-hop router on the path from the intended
+.I source
+to the
+.IR receiver .
+.RS 8
+.TP 12 12
+.I CAUTION!!
+Version 3.3 of
+.B mrouted
+will crash if a trace query is received via a
+unicast packet and
+.B mrouted
+has no route for the
+.I source
+address. Therefore, do not use the
+.B \-g
+option unless the target
+.B mrouted
+has been verified to be newer than 3.3.
+.RE
+.TP 8 8
+.BI \-i\ addr
+Use
+.I addr
+as the local interface address (on a multi-homed host) for sending the
+trace query and as the default for the
+.I receiver
+and the response destination.
+.TP 8 8
+.B \-l
+Loop indefinitely printing packet rate and loss statistics for the
+multicast path every 10 seconds.
+.TP 8 8
+.B \-M
+Always send the response using multicast rather than attempting
+unicast first.
+.TP 8 8
+.BI \-m\ n
+Set to
+.I n
+the maximum number of hops that will be traced from the
+.I receiver
+back toward the
+.IR source .
+The default is 32 hops (infinity for the DVMRP routing protocol).
+.TP 8 8
+.B \-n
+Print hop addresses numerically rather than symbolically and numerically
+(saves a nameserver address-to-name lookup for each router found on the
+path).
+.TP 8 8
+.BI \-q\ n
+Set the maximum number of query attempts for any hop to
+.IR n .
+The default is 3.
+.TP 8 8
+.B \-p
+Listen passively for multicast responses from traces initiated by
+others (not implemented yet).
+.TP 8 8
+.BI \-r\ host
+Send the trace response to
+.I host
+rather than to the host on which
+.B mtrace
+is being run, or to a multicast address other than the one registered
+for this purpose (224.0.1.32).
+.TP 8 8
+.B \-s
+Print a short form output including only the multicast path and not
+the packet rate and loss statistics.
+.TP 8 8
+.BI \-t\ ttl
+Set the
+.I ttl
+(time-to-live, or number of hops) for multicast trace queries and
+responses. The default is 64, except for local queries to the "all
+routers" multicast group which use ttl 1.
+.TP 8 8
+.BI \-w\ n
+Set the time to wait for a trace response to
+.I n
+seconds (default 3 seconds).
+.SH USAGE
+.SS How It Works
+The technique used by the
+.B traceroute
+tool to trace unicast network paths will not work for IP multicast
+because ICMP responses are specifically forbidden for multicast traffic.
+Instead, a tracing feature has been built into the multicast routers.
+This technique has the advantage that additional information about
+packet rates and losses can be accumulated while the number of packets
+sent is minimized.
+.PP
+Since multicast uses
+reverse path forwarding, the trace is run backwards from the
+.I receiver
+to the
+.IR source .
+A trace query packet is sent to the last
+hop multicast router (the leaf router for the desired
+.I receiver
+address). The last hop router builds a trace response packet, fills in
+a report for its hop, and forwards the trace packet using unicast to
+the router it believes is the previous hop for packets originating
+from the specified
+.IR source .
+Each router along the path adds its report and forwards the packet.
+When the trace response packet reaches the first hop router (the router
+that is directly connected to the source's net), that router sends the
+completed response to the response destination address specified in
+the trace query.
+.PP
+If some multicast router along the path does not implement the
+multicast traceroute feature or if there is some outage, then no
+response will be returned. To solve this problem, the trace query
+includes a maximum hop count field to limit the number of hops traced
+before the response is returned. That allows a partial path to be
+traced.
+.PP
+The reports inserted by each router contain not only the address of
+the hop, but also the ttl required to forward and some flags to indicate
+routing errors, plus counts of the total number of packets on the
+incoming and outgoing interfaces and those forwarded for the specified
+.IR group .
+Taking differences in these counts for two traces separated in time
+and comparing the output packet counts from one hop with the input
+packet counts of the next hop allows the calculation of packet rate
+and packet loss statistics for each hop to isolate congestion
+problems.
+.SS Finding the Last-Hop Router
+The trace query must be sent to the multicast router which is the
+last hop on the path from the
+.I source
+to the
+.IR receiver .
+If the receiver is on the local subnet (as determined using the subnet
+mask), then the default method is to multicast the trace query to
+all-routers.mcast.net (224.0.0.2) with a ttl of 1. Otherwise, the
+trace query is multicast to the
+.I group
+address since the last hop router will be a member of that group if
+the receiver is. Therefore it is necessary to specify a group that
+the intended receiver has joined. This multicast is sent with a
+default ttl of 64, which may not be sufficient for all cases (changed
+with the
+.B \-t
+option).
+If the last hop router is known, it may also be addressed directly
+using the
+.B \-g
+option). Alternatively, if it is desired to trace a group that the
+receiver has not joined, but it is known that the last-hop router is a
+member of another group, the
+.B \-g
+option may also be used to specify a different multicast address for the
+trace query.
+.PP
+When tracing from a multihomed host or router, the default receiver
+address may not be the desired interface for the path from the source.
+In that case, the desired interface should be specified explicitly as
+the
+.IR receiver .
+.SS Directing the Response
+By default,
+.B mtrace
+first attempts to trace the full reverse path, unless the number of
+hops to trace is explicitly set with the
+.B \-m
+option. If there is no response within a 3 second timeout interval
+(changed with the
+.B \-w
+option), a "*" is printed and the probing switches to hop-by-hop mode.
+Trace queries are issued starting with a maximum hop count of one and
+increasing by one until the full path is traced or no response is
+received. At each hop, multiple probes are sent (default is three,
+changed with
+.B \-q
+option). The first half of the attempts (default is one) are made with
+the unicast address of the host running
+.B mtrace
+as the destination for the response. Since the unicast route may be
+blocked, the remainder of attempts request that the response be
+multicast to mtrace.mcast.net (224.0.1.32) with the ttl set to 32 more
+than what's needed to pass the thresholds seen so far along the path
+to the receiver. For the last quarter of the attempts (default is
+one), the ttl is increased by another 32 each time up to a maximum of
+192. Alternatively, the ttl may be set explicity with the
+.B \-t
+option and/or the initial unicast attempts can be forced to use
+multicast instead with the
+.B \-M
+option. For each attempt, if no response is received within the
+timeout, a "*" is printed. After the specified number of attempts
+have failed,
+.B mtrace
+will try to query the next hop router with a DVMRP_ASK_NEIGHBORS2
+request (as used by the
+.B mrinfo
+program) to see what kind of router it is.
+.SH EXAMPLES
+The output of
+.B mtrace
+is in two sections. The first section is a short listing of the hops
+in the order they are queried, that is, in the reverse of the order
+from the
+.I source
+to the
+.IR receiver .
+For each hop, a line is printed showing the hop number (counted
+negatively to indicate that this is the reverse path); the multicast
+routing protocol (DVMRP, MOSPF, PIM, etc.); the threshold required to
+forward data (to the previous hop in the listing as indicated by the
+up-arrow character); and the cumulative delay for the query to reach
+that hop (valid only if the clocks are synchronized). This first
+section ends with a line showing the round-trip time which measures
+the interval from when the query is issued until the response is
+received, both derived from the local system clock. A sample use and
+output might be:
+.PP
+.nf
+.ft C
+oak.isi.edu 80# mtrace -l caraway.lcs.mit.edu 224.2.0.3
+Mtrace from 18.26.0.170 to 128.9.160.100 via group 224.2.0.3
+Querying full reverse path...
+ 0 oak.isi.edu (128.9.160.100)
+ -1 cub.isi.edu (128.9.160.153) DVMRP thresh^ 1 3 ms
+ -2 la.dart.net (140.173.128.1) DVMRP thresh^ 1 14 ms
+ -3 dc.dart.net (140.173.64.1) DVMRP thresh^ 1 50 ms
+ -4 bbn.dart.net (140.173.32.1) DVMRP thresh^ 1 63 ms
+ -5 mit.dart.net (140.173.48.2) DVMRP thresh^ 1 71 ms
+ -6 caraway.lcs.mit.edu (18.26.0.170)
+Round trip time 124 ms
+.fi
+.PP
+The second section provides a pictorial view of the path in the
+forward direction with data flow indicated by arrows pointing downward
+and the query path indicated by arrows pointing upward. For each hop,
+both the entry and exit addresses of the router are shown if
+different, along with the initial ttl required on the packet in order
+to be forwarded at this hop and the propagation delay across the hop
+assuming that the routers at both ends have synchronized clocks. The
+right half of this section is composed of several columns of
+statistics in two groups. Within each group, the columns are the
+number of packets lost, the number of packets sent, the percentage
+lost, and the average packet rate at each hop. These statistics are
+calculated from differences between traces and from hop to hop as
+explained above. The first group shows the statistics for all traffic
+flowing out the interface at one hop and in the interface at the next
+hop. The second group shows the statistics only for traffic forwarded
+from the specified
+.I source
+to the specified
+.IR group .
+.PP
+These statistics are shown on one or two lines for each hop. Without
+any options, this second section of the output is printed only once,
+approximately 10 seconds after the initial trace. One line is shown
+for each hop showing the statistics over that 10-second period. If
+the
+.B \-l
+option is given, the second section is repeated every 10 seconds and
+two lines are shown for each hop. The first line shows the statistics
+for the last 10 seconds, and the second line shows the cumulative
+statistics over the period since the initial trace, which is 101
+seconds in the example below. The second section of the output is
+omitted if the
+.B \-s
+option is set.
+.ie t \{\
+.ft C
+. ie \w'i'<>\w'm' \{\" looks like this is not proper Courier font
+(If this example is not properly columned with a fixed-width font, get
+.B groff
+and try again.)
+. \}
+.\}
+.PP
+.ft C
+.nf
+Waiting to accumulate statistics... Results after 101 seconds:
+
+ Source Response Dest Packet Statistics For Only For Traffic
+18.26.0.170 128.9.160.100 All Multicast Traffic From 18.26.0.170
+ | __/ rtt 125 ms Lost/Sent = Pct Rate To 224.2.0.3
+ v / hop 65 ms --------------------- ------------------
+18.26.0.144
+140.173.48.2 mit.dart.net
+ | ^ ttl 1 0/6 = --% 0 pps 0/2 = --% 0 pps
+ v | hop 8 ms 1/52 = 2% 0 pps 0/18 = 0% 0 pps
+140.173.48.1
+140.173.32.1 bbn.dart.net
+ | ^ ttl 2 0/6 = --% 0 pps 0/2 = --% 0 pps
+ v | hop 12 ms 1/52 = 2% 0 pps 0/18 = 0% 0 pps
+140.173.32.2
+140.173.64.1 dc.dart.net
+ | ^ ttl 3 0/271 = 0% 27 pps 0/2 = --% 0 pps
+ v | hop 34 ms -1/2652 = 0% 26 pps 0/18 = 0% 0 pps
+140.173.64.2
+140.173.128.1 la.dart.net
+ | ^ ttl 4 -2/831 = 0% 83 pps 0/2 = --% 0 pps
+ v | hop 11 ms -3/8072 = 0% 79 pps 0/18 = 0% 0 pps
+140.173.128.2
+128.9.160.153 cub.isi.edu
+ | \\__ ttl 5 833 83 pps 2 0 pps
+ v \\ hop -8 ms 8075 79 pps 18 0 pps
+128.9.160.100 128.9.160.100
+ Receiver Query Source
+.fi
+.PP
+Because the packet counts may be changing as the trace query is
+propagating, there may be small errors (off by 1 or 2) in these
+statistics. However, those errors should not accumulate, so the
+cumulative statistics line should increase in accuracy as a new trace
+is run every 10 seconds. There are two sources of larger errors, both
+of which show up as negative losses:
+.LP
+.RS
+.PD 0
+.TP 3
+\(bu
+If the input to a node is from a multi-access network with more than
+one other node attached, then the input count will be (close to) the
+sum of the output counts from all the attached nodes, but the output
+count from the previous hop on the traced path will be only part of
+that. Hence the output count minus the input count will be negative.
+.TP 3
+\(bu
+In release 3.3 of the DVMRP multicast forwarding software for SunOS
+and other systems, a multicast packet generated on a router will be
+counted as having come in an interface even though it did not. This
+creates the negative loss that can be seen in the example above.
+.PD
+.RE
+.LP
+Note that these negative losses may mask positive losses.
+.PP
+In the example, there is also one negative hop time. This simply
+indicates a lack of synchronization between the system clocks across
+that hop. This example also illustrates how the percentage loss is
+shown as two dashes when the number of packets sent is less than 10
+because the percentage would not be statistically valid.
+.PP
+A second example shows a trace to a receiver that is not local; the
+query is sent to the last-hop router with the
+.B \-g
+option. In this example, the trace of the full reverse path resulted
+in no response because there was a node running an old version of
+.B mrouted
+that did not implement the multicast traceroute function, so
+.B mtrace
+switched to hop-by-hop mode. The \*(lqRoute pruned\*(rq error code
+indicates that traffic for group 224.2.143.24 would not be forwarded.
+.PP
+.nf
+.ft C
+oak.isi.edu 108# mtrace -g 140.173.48.2 204.62.246.73 \\
+ butter.lcs.mit.edu 224.2.143.24
+Mtrace from 204.62.246.73 to 18.26.0.151 via group 224.2.143.24
+Querying full reverse path... * switching to hop-by-hop:
+ 0 butter.lcs.mit.edu (18.26.0.151)
+ -1 jam.lcs.mit.edu (18.26.0.144) DVMRP thresh^ 1 33 ms Route pruned
+ -2 bbn.dart.net (140.173.48.1) DVMRP thresh^ 1 36 ms
+ -3 dc.dart.net (140.173.32.2) DVMRP thresh^ 1 44 ms
+ -4 darpa.dart.net (140.173.240.2) DVMRP thresh^ 16 47 ms
+ -5 * * * noc.hpc.org (192.187.8.2) [mrouted 2.2] didn't respond
+Round trip time 95 ms
+.fi
+.SH AUTHOR
+Implemented by Steve Casner based on an initial prototype written by
+Ajit Thyagarajan. The multicast traceroute mechanism was designed by
+Van Jacobson with help from Steve Casner, Steve Deering, Dino
+Farinacci, and Deb Agrawal; it was implemented in
+.B mrouted
+by Ajit Thyagarajan and Bill Fenner. The option syntax and the output
+format of
+.B mtrace
+are modeled after the unicast
+.B traceroute
+program written by Van Jacobson.
+.SH SEE ALSO
+.BR mrouted (8) ,
+.BR mrinfo (8) ,
+.BR map-mbone (8) ,
+.BR traceroute (8)
diff --git a/usr.sbin/mrouted/mtrace.c b/usr.sbin/mrouted/mtrace.c
index d3e7f5f..42a6084 100644
--- a/usr.sbin/mrouted/mtrace.c
+++ b/usr.sbin/mrouted/mtrace.c
@@ -1,82 +1,307 @@
+/*
+ * 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.5 1995/05/09 01:24:19 fenner Exp $
+ */
+
#include <netdb.h>
#include <sys/time.h>
+#include <sys/filio.h>
+#include <memory.h>
+#include <string.h>
#include "defs.h"
-
-#define DEFAULT_TIMEOUT 10 /* How long to wait before retrying requests */
-#define JAN_1970 2208988800 /* 1970 - 1900 in seconds */
-
-int timeout = DEFAULT_TIMEOUT;
+#include <arpa/inet.h>
+
+#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
+
+char names[MAXHOPS][40];
+
+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;
+u_int32 qgrp = 0;
+u_int32 qdst = 0;
+u_char qno = 0;
+u_int32 raddr = 0;
+int qttl = 0;
+u_char rttl = 0;
+u_int32 gwy = 0;
vifi_t numvifs; /* to keep loader happy */
- /* (see COPY_TABLES macro called in kern.c) */
+ /* (see kern.c) */
+extern void k_join();
+extern void k_leave();
+extern void k_set_ttl();
+extern void exit();
+#ifndef SYSV
+extern long random();
+#endif
+extern int errno;
char *
inet_name(addr)
- u_long addr;
+ u_int32 addr;
{
- struct hostent *e;
+ struct hostent *e;
- e = gethostbyaddr((char *)&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;
-
- if (e)
- memcpy(&addr, e->h_addr_list[0], e->h_length);
- else {
- addr = inet_addr(name);
- if (addr == -1)
- addr = 0;
+ struct hostent *e = gethostbyname(name);
+ u_int32 addr;
+ int i, dots = 3;
+ char buf[40];
+ char *ip = name;
+ char *op = buf;
+
+ if (e) memcpy((char *)&addr, e->h_addr_list[0], e->h_length);
+ else {
+ /*
+ * Undo BSD's favor -- take fewer than 4 octets as net/subnet address.
+ */
+ for (i = sizeof(buf) - 7; i > 0; --i) {
+ if (*ip == '.') --dots;
+ if (*ip == '\0') break;
+ *op++ = *ip++;
}
-
- return addr;
+ for (i = 0; i < dots; ++i) {
+ *op++ = '.';
+ *op++ = '0';
+ }
+ *op = '\0';
+ 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;
{
+ 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;
{
+ 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;
@@ -86,132 +311,682 @@ t_diff(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
+send_recv(dst, type, code, tries, save)
+ u_int32 dst;
+ int type, code, tries;
+ struct resp_buf *save;
+{
+ 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, j;
+
+ 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;
+
+ 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;
+ if (ip->ip_src.s_addr != dst) continue;
+ len = igmpdatalen;
+ 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
+ */
+void
+what_kind(buf)
+ struct resp_buf *buf;
+{
+ u_int32 smask;
+ int recvlen;
+ int hops = buf->len;
+ struct tr_resp *r = buf->resps + hops - 1;
+ u_int32 next = r->tr_rmtaddr;
+
+ recvlen = send_recv(next, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS2, 1, &incr[0]);
+ print_host(next);
+ if (recvlen) {
+ 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);
+ printf(" [%s%d.%d] didn't respond\n",
+ (version == 1) ? "proteon/mrouted " :
+ ((version & 0xff) == 2) ? "mrouted " :
+ ((version & 0xff) == 3) ? "mrouted " :
+ ((version & 0xff) == 4) ? "mrouted " :
+ ((version & 0xff) == 10) ? "cisco " : "",
+ version & 0xff, (version >> 8) & 0xff);
+ VAL_TO_MASK(smask, r->tr_smask);
+ while (p < ep) {
+ register u_int32 laddr = *p++;
+ register int n = ntohl(*p++) & 0xFF;
+ if ((laddr & smask) == (qsrc & smask)) {
+ printf("%3d ", -(hops+2));
+ print_host(qsrc);
+ printf("\n");
+ break;
+ }
+ p += n;
+ }
+ return;
+ }
+ printf(" didn't respond\n");
+}
+
+
+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);
+
+ 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 NEITHER:
+ printf("\n");
+ break;
+ }
+}
+
+/*
+ * 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)
+ */
+void
+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)) {
+ printf("Route changed, start again.\n");
+ exit(1);
+ }
+ 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");
+}
+
+
+/***************************************************************************
+ * main
+ ***************************************************************************/
+
+int
main(argc, argv)
int argc;
char *argv[];
{
- struct timeval tq;
- struct timezone tzp;
- u_long querytime, 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;
-
+ int recvlen;
+ struct timeval tv;
+ struct resp_buf *prev, *new;
struct tr_query *query;
-
- struct tr_rlist *tr_rlist = NULL;
-
- char *p;
- int datalen = 0;
-
- int i;
- int done = 0;
+ struct tr_resp *r;
+ u_int32 smask;
+ int rno;
+ int hops, tries;
+ int numstats = 1;
+ int waittime;
+ int seed;
if (geteuid() != 0) {
- fprintf(stderr, "must be root\n");
+ 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]);
+ 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 'g':
- if (argc > 1 && isdigit(*(argv + 1)[0])) {
- argv++, argc--;
- qgrp = host_addr(argv[0]);
+ case 'l': /* Loop updating stats indefinitely */
+ numstats = 3153600;
break;
- } else
- goto usage;
- case 'd':
- if (argc > 1 && isdigit(*(argv + 1)[0])) {
- argv++, argc--;
- qdst = host_addr(argv[0]);
+ case 'n': /* Don't reverse map host addresses */
+ numeric = TRUE;
break;
- } else
- goto usage;
- case 'x':
- if (argc > 1 && isdigit(*(argv + 1)[0])) {
- argv++, argc--;
- dst = host_addr(argv[0]);
+ case 'p': /* Passive listen for traces */
+ passive = TRUE;
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 '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 'n':
- if (argc > 1 && isdigit(*(argv + 1)[0])) {
- argv++, argc--;
- qno = atoi(argv[0]);
- break;
- } else
- goto usage;
- case 'l':
- if (argc > 1 && isdigit(*(argv + 1)[0])) {
- argv++, argc--;
- rttl = atoi(argv[0]);
- break;
- } else
- 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;
- addr.sin_len = sizeof addr;
+#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) ||
@@ -219,232 +994,272 @@ usage: printf("usage: mtrace -s <src> -g <grp> -d <dst> -n <# reports> \n");
perror("Determining local address");
exit(-1);
}
+
+ /*
+ * Default destination for path to be queried is the local host.
+ */
+ if (qdst == 0) qdst = lcl_addr ? lcl_addr : addr.sin_addr.s_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.
+ */
+ dst_netmask = get_netmask(udp, qdst);
close(udp);
- lcl_addr = addr.sin_addr.s_addr;
+ if (lcl_addr == 0) lcl_addr = addr.sin_addr.s_addr;
+ if (gwy == 0)
+ if ((qdst & dst_netmask) == (lcl_addr & dst_netmask)) gwy = query_cast;
+ else gwy = qgrp;
+
+ if (IN_MULTICAST(ntohl(gwy))) {
+ k_set_loop(1); /* If I am running on a router, I need to hear this */
+ if (gwy == query_cast) k_set_ttl(qttl ? qttl : 1);
+ else k_set_ttl(qttl ? qttl : MULTICAST_TTL1);
+ } else
+ if (send_recv(gwy, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS2, 1, &incr[0]))
+ if (ntohl(incr[0].igmp.igmp_group.s_addr) == 0x0303) {
+ printf("Don't use -g to address an mrouted 3.3, it might crash\n");
+ exit(0);
+ }
- /* Got the local address now */
- /* Now, make up the IGMP packet to send */
+ printf("Mtrace from %s to %s via group %s\n",
+ inet_fmt(qsrc, s1), inet_fmt(qdst, s2), inet_fmt(qgrp, s3));
- query = (struct tr_query *)(send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
+ if ((qdst & dst_netmask) == (qsrc & dst_netmask)) {
+ printf("Source & receiver are directly connected, no path to trace\n");
+ exit(0);
+ }
+ /*
+ * Make up the IGMP_MTRACE query packet to send (some parameters
+ * are set later), including initializing the seed for random
+ * query identifiers.
+ */
+ query = (struct tr_query *)(send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
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;
+ gettimeofday(&tv, 0);
+ seed = tv.tv_usec ^ lcl_addr;
+#ifdef SYSV
+ srand48(seed);
+#else
+ srandom(seed);
+#endif
/*
- * set timer to calculate delays & send query
+ * If the response is to be a multicast address, make sure we
+ * are listening on that multicast address.
*/
- gettimeofday(&tq, &tzp);
- querytime = ((tq.tv_sec + JAN_1970) << 16) + (tq.tv_usec << 10) / 15625;
+ if (raddr && IN_MULTICAST(ntohl(raddr))) k_join(raddr, lcl_addr);
+ else k_join(resp_cast, lcl_addr);
- send_igmp(lcl_addr, dst, IGMP_MTRACE, qno,
- qgrp, datalen);
+ /*
+ * 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(gwy, IGMP_MTRACE, hops, tries, &base);
/*
- * If the response is to be a multicast address, make sure we
- * are listening on that multicast address.
+ * 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 a timeout occurs.
*/
- 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, 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 (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));
+ fflush(stdout);
+ 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");
- gettimeofday(&tq, &tzp);
- resptime = ((tq.tv_sec + JAN_1970) << 16) + (tq.tv_usec << 10) / 15625;
-
- recvlen = recvfrom(igmp_socket, recv_buf, sizeof(recv_buf),
- 0, NULL, &dummy);
+ for (hops = 1; hops <= MAXHOPS; ++hops) {
+ printf("%3d ", -hops);
+ fflush(stdout);
- if (recvlen <= 0) {
- if (recvlen && errno != EINTR)
- perror("recvfrom");
- continue;
- }
-
- if (recvlen < sizeof(struct ip)) {
- log(LOG_WARNING, 0,
- "packet too short (%u bytes) for IP header",
- recvlen);
- continue;
- }
- 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;
- }
+ recvlen = send_recv(gwy, IGMP_MTRACE, hops, nqueries, &base);
- 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 (recvlen == 0) {
+ if (--hops == 0) break;
+ what_kind(&base);
+ break;
+ }
+ r = base.resps + base.len - 1;
+ if (base.len == hops) print_trace(-hops, &base);
+ else {
+ hops = base.len;
+ 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 further hops\n");
+ break; /* XXX could do segmented trace */
+ }
+ printf("Route must have changed...\n\n");
+ print_trace(1, &base);
+ }
+
+ VAL_TO_MASK(smask, r->tr_smask);
+ if ((r->tr_inaddr & smask) == (qsrc & smask)) {
+ printf("%3d ", -(hops+1));
+ print_host(qsrc);
+ printf("\n");
+ break;
+ }
+ if (r->tr_rmtaddr == 0 || (r->tr_rflags & 0x80)) break;
}
+ }
- if (igmp->igmp_type != IGMP_MTRACE &&
- igmp->igmp_type != IGMP_MTRACE_RESP)
- continue;
+ if (base.rtime == 0) {
+ printf("Timed out receiving responses\n");
+ if (IN_MULTICAST(ntohl(gwy)))
+ if (gwy == 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);
+ }
- if (igmpdatalen == QLEN)
- continue;
+ printf("Round trip time %d ms\n\n", t_diff(base.rtime, base.qtime));
- if ((igmpdatalen - QLEN)%RLEN) {
- printf("packet with incorrect datalen\n");
- continue;
+ /*
+ * 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);
}
+ rno = base.len;
+ recvlen = send_recv(gwy, IGMP_MTRACE, rno, nqueries, new);
- query = (struct tr_query *)(igmp + 1);
-
- /* 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;
-
- /*
- * print the responses out in reverse order (from src to dst)
- */
- printf("src: <%s> grp: <%s> dst: <%s> rtt: %d ms\n\n",
- inet_fmt(qsrc, s1), inet_fmt(qgrp, s2), inet_fmt(qdst, s3),
- t_diff(resptime, querytime));
-
- 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");
-
- 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, querytime));
- printf("hop: %d ms ", t_diff(resptime, r->tr_qarr));
- 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;
+ if (recvlen == 0) {
+ printf("Timed out.\n");
+ exit(1);
}
- printf(" | \n");
- printf(" %-15s \n", inet_fmt(qdst, s1));
- /*
- * if the response was multicast back, leave the group
- */
- if (IN_MULTICAST(ntohl(raddr)))
- k_leave(raddr, lcl_addr);
+ if (rno != new->len) {
+ printf("Trace length doesn't match.\n");
+ exit(1);
+ }
- /* If I don't expect any more replies, exit here */
- exit(0);
+ printf("Results after %d seconds:\n\n",
+ (new->qtime - base.qtime) >> 16);
+ fixup_stats(&base, new);
+ print_stats(&base, prev, new);
+ prev = new;
+ new = &incr[numstats&1];
+ waittime = 10;
}
+
+ /*
+ * If the response was multicast back, leave the group
+ */
+ if (raddr && IN_MULTICAST(ntohl(raddr))) k_leave(raddr, lcl_addr);
+ else k_leave(resp_cast, lcl_addr);
+
+ return (0);
}
-/* dummies */
-void log()
-{
-}
-void accept_probe()
-{
-}
-void accept_group_report()
-{
-}
-void accept_neighbors()
-{
-}
-void accept_neighbors2()
-{
-}
-void accept_neighbor_request2()
-{
-}
-void accept_report()
-{
-}
-void accept_neighbor_request()
-{
-}
-void accept_prune()
-{
-}
-void accept_graft()
-{
-}
-void accept_g_ack()
-{
-}
-void add_table_entry()
-{
-}
-void check_vif_state()
-{
-}
-void mtrace()
+
+void
+check_vif_state()
{
+ log(LOG_WARNING, errno, "sendto");
}
-void leave_group_message()
+
+/*
+ * 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.
+ */
+/*VARARGS3*/
+void
+log(severity, syserr, format, a, b, c, d, e)
+ int severity, syserr;
+ char *format;
+ int a, b, c, d, e;
{
+ char fmt[100];
+
+ 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);
+ fprintf(stderr, fmt, a, b, c, d, e);
+ 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 */
+
+/*VARARGS*/
+void accept_probe() {} /*VARARGS*/
+void accept_group_report() {} /*VARARGS*/
+void accept_neighbors() {} /*VARARGS*/
+void accept_neighbors2() {} /*VARARGS*/
+void accept_neighbor_request() {} /*VARARGS*/
+void accept_neighbor_request2() {} /*VARARGS*/
+void accept_report() {} /*VARARGS*/
+void accept_prune() {} /*VARARGS*/
+void accept_graft() {} /*VARARGS*/
+void accept_g_ack() {} /*VARARGS*/
+void add_table_entry() {} /*VARARGS*/
+void accept_mtrace() {} /*VARARGS*/
+void accept_leave_message() {} /*VARARGS*/
+void accept_membership_query() {} /*VARARGS*/
diff --git a/usr.sbin/mrouted/pathnames.h b/usr.sbin/mrouted/pathnames.h
new file mode 100644
index 0000000..2022314
--- /dev/null
+++ b/usr.sbin/mrouted/pathnames.h
@@ -0,0 +1,25 @@
+/*
+ * The mrouted program is covered by the license in the accompanying file
+ * named "LICENSE". Use of the mrouted program represents acceptance of
+ * the terms and conditions listed in that file.
+ *
+ * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
+ * Leland Stanford Junior University.
+ *
+ *
+ * $Id: pathnames.h,v 3.5 1995/05/09 01:00:39 fenner Exp $
+ */
+
+#define _PATH_MROUTED_CONF "/etc/mrouted.conf"
+
+#if (defined(BSD) && (BSD >= 199103))
+#define _PATH_MROUTED_PID "/var/run/mrouted.pid"
+#define _PATH_MROUTED_GENID "/var/run/mrouted.genid"
+#define _PATH_MROUTED_DUMP "/var/tmp/mrouted.dump"
+#define _PATH_MROUTED_CACHE "/var/tmp/mrouted.cache"
+#else
+#define _PATH_MROUTED_PID "/etc/mrouted.pid"
+#define _PATH_MROUTED_GENID "/etc/mrouted.genid"
+#define _PATH_MROUTED_DUMP "/usr/tmp/mrouted.dump"
+#define _PATH_MROUTED_CACHE "/usr/tmp/mrouted.cache"
+#endif
diff --git a/usr.sbin/mrouted/prune.c b/usr.sbin/mrouted/prune.c
index 3269288..96d282e 100644
--- a/usr.sbin/mrouted/prune.c
+++ b/usr.sbin/mrouted/prune.c
@@ -7,21 +7,24 @@
* Leland Stanford Junior University.
*
*
- * $Id: prune.c,v 1.4 1995/05/16 00:28:48 jkh Exp $
+ * $Id: prune.c,v 3.5 1995/05/09 01:00:39 fenner Exp $
*/
#include "defs.h"
-#define JAN_1970 2208988800 /* 1970 - 1900 in seconds */
-
extern int cache_lifetime;
extern int max_prune_lifetime;
+extern struct rtentry *routing_table;
/*
* 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) { \
@@ -37,247 +40,835 @@ extern int max_prune_lifetime;
default: y = 0; \
} \
}
-
-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
+****************************************************************************/
-/*
- * Initialize the kernel table structure
+/*
+ * Updates the ttl values for each vif.
*/
-void init_ktable()
+static void
+prun_add_ttls(gt)
+ struct gtable *gt;
{
- kernel_rtable = NULL;
- kroutes = 0;
+ 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;
+ }
}
/*
+ * checks for scoped multicast addresses
+ */
+#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;
+{
+ 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;
-
+
v = &uvifs[vifi];
-
+
for (g = v->uv_groups; g != NULL; g = g->al_next)
- if (mcastgrp == g->al_addr)
+ if (mcastgrp == g->al_addr)
return 1;
-
+
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;
- vifi_t vifi;
-
- 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] = 0;
+ 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;
}
/*
- * checks for scoped multicast addresses
+ * Check if the neighbor supports pruning
*/
-#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 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;
-int scoped_addr(vifi, addr)
+ /*
+ * 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_long addr;
+ u_int32 addr;
{
- struct vif_acl *acl;
+ struct listaddr *n = neighbor_info(vifi, addr);
+ int vers;
- for (acl = uvifs[vifi].uv_acl; acl; acl = acl->acl_next)
- if ((addr & acl->acl_mask) == acl->acl_addr)
- return 1;
+ if (n == NULL)
+ return 0;
- 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);
}
/*
- * Add a new table entry for (origin, mcastgrp)
+ * Returns the prune entry of the router, or NULL if none exists
*/
-void add_table_entry(origin, mcastgrp)
- u_long origin;
- u_long mcastgrp;
+static struct ptable *
+find_prune_entry(vr, pt)
+ u_int32 vr;
+ struct ptable *pt;
{
- struct rtentry *r;
- struct ktable *kt;
+ 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;
+
+ /* 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;
- 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));
+ /* 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);
+}
- r = determine_route(origin);
+/*
+ * Send an ack that a graft was received
+ */
+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;
+
+ 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 stable *st;
- /* 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 */
+ for (st = g->gt_srctbl; st; st = st->st_next)
+ k_add_rg(st->st_origin, g);
+}
- kroutes++;
+/****************************************************************************
+ 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;
+}
- /* add the new values in */
+/*
+ * 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_int32 origin;
+ u_int32 mcastgrp;
+{
+ struct rtentry *r;
+ struct gtable *gt,**gtnp,*prev_gt;
+ struct stable *st,**stnp;
+ int i;
+
+ r = determine_route(origin);
+ 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);
+ 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;
+ gt->gt_rsrr_cache = NULL;
+
+ if (r != NULL) {
/* 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, r->rt_children) &&
+ !(VIFM_ISSET(i, r->rt_leaves)))
+ VIFM_SET(i, gt->gt_grpmems);
- if (VIFM_ISSET(i, kt->kt_leaves) && grplst_mem(i, mcastgrp))
- VIFM_SET(i, kt->kt_grpmems);
+ if (VIFM_ISSET(i, r->rt_leaves) && grplst_mem(i, mcastgrp))
+ VIFM_SET(i, gt->gt_grpmems);
}
- GET_SCOPE(kt);
- if (VIFM_ISSET(kt->kt_parent, kt->kt_scope)) {
- kt->kt_grpmems = 0;
- kt->kt_scope = -1; /* make sure we don't forward */
+ 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;
}
- else
- kt->kt_grpmems &= ~kt->kt_scope;
}
- /* update the kernel_rtable pointer */
- kt->kt_next = kernel_rtable;
- kernel_rtable = kt;
+ stnp = &gt->gt_srctbl;
+ while ((st = *stnp) != NULL) {
+ if (ntohl(st->st_origin) >= ntohl(origin))
+ break;
+ stnp = &st->st_next;
+ }
- /* update ttls and add entry into kernel */
- prun_add_ttls(kt);
- k_add_rg(kt);
+ 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;
+ }
- log(LOG_DEBUG, 0, "add entry (%s %s) vif-list:%x",
- inet_fmt(kt->kt_origin, s1),
- inet_fmt(kt->kt_mcastgrp, s2),
- kt->kt_grpmems);
+ 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.
+ * mark this src-grp as a prune candidate.
*/
- 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;
-
- /* 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--;
- }
- }
+ struct rtentry *r;
+ struct gtable *g;
+ struct ptable *pt, *prev_pt;
+ struct stable *st, *prev_st;
+
+ 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;
- }
-
- 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);
+ /*
+ * 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;
+ }
- 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);
+ }
}
}
}
@@ -286,63 +877,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 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 %s",
- inet_fmt(kt->kt_origin, s1));
-
- 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 (%s, %s)",
- inet_fmt(kt->kt_origin, s1), inet_fmt(mcastgrp, s2));
-
- 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;
}
+ g->gt_srctbl = NULL;
- /* free the source mcastgrp entry */
- prev_kt->kt_next = kt->kt_next;
- free((char *)kt);
- kroutes--;
- break;
+ 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;
}
}
}
@@ -351,219 +998,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 |= 0x1;
- if (kt->kt_children != r->rt_children)
- changed |= 0x2;
- if (kt->kt_parent != r->rt_parent)
- changed |= 0x4;
-
- if (!changed)
- continue;
-
- log(LOG_DEBUG, 0, "updating entry: (%s %s) code:%x",
- inet_fmt(kt->kt_origin, s1),
- inet_fmt(kt->kt_mcastgrp, s2), changed);
-
- /* 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 = 0;
- kt->kt_scope = -1;
- }
- 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;
-
- log(LOG_DEBUG, 0, "group %s joined at vif %d",
+ struct rtentry *r;
+ struct gtable *g;
+
+ log(LOG_DEBUG, 0, "group %s joined on vif %d",
inet_fmt(mcastgrp, s1), vifi);
+
+ 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)) {
- 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 == 0)
+ 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 ktable *kt;
-
- log(LOG_DEBUG, 0, "group %s left at vif %d",
+ struct rtentry *r;
+ struct gtable *g;
+
+ log(LOG_DEBUG, 0, "group %s left on vif %d",
inet_fmt(mcastgrp, s1), vifi);
+
+ for (g = kernel_table; g; g = g->gt_gnext) {
+ if (ntohl(mcastgrp) < ntohl(g->gt_mcastgrp))
+ break;
- for (kt = kernel_rtable; kt; kt = kt->kt_next)
- if (kt->kt_mcastgrp == mcastgrp) {
- struct listaddr *vr;
+ if (g->gt_mcastgrp == mcastgrp) {
int stop_sending = 1;
- for (vr = uvifs[vifi].uv_neighbors; vr; vr = vr->al_next)
- if (no_entry_exists(vr->al_addr, kt)) {
- stop_sending = 0;
- break;
- }
+ r = g->gt_route;
+ /*
+ * If this is not a leaf, then we have router neighbors on this
+ * vif. Only turn off forwarding if they have all pruned.
+ */
+ 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;
+ }
+ }
if (stop_sending) {
- VIFM_CLR(vifi, kt->kt_grpmems);
- prun_add_ttls(kt);
- k_add_rg(kt);
+ 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);
+
+ prun_add_ttls(g);
+ update_kernel(g);
+#ifdef RSRR
+ /* Send route change notification to reservation protocol. */
+ rsrr_cache_send(g,1);
+#endif /* RSRR */
- /*
- * If there are no more members of this particular group,
- * send prune upstream
- */
- if (kt->kt_grpmems == NULL && kt->kt_gateway)
- send_prune(kt);
- }
+ /*
+ * 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);
}
+ }
}
-
-/*
- * 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;
-
- return 0;
-}
-
-/*
- * 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];
-#if BYTE_ORDER == BIG_ENDIAN
- for (i = 0; i < 4; i++)
-#endif
-#if BYTE_ORDER == LITTLE_ENDIAN
- for (i = 3; i >= 0; i--)
-#endif
- *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);*/
}
/*
@@ -576,766 +1168,1031 @@ 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;
+ int stop_sending;
+ struct rtentry *r;
+ struct gtable *g;
+ struct ptable *pt;
struct listaddr *vr;
-
+
/* Don't process any prunes if router is not pruning */
if (pruning == 0)
return;
-
+
if ((vifi = find_vif(src, dst)) == NO_VIF) {
log(LOG_INFO, 0,
"ignoring prune report from non-neighbor %s",
inet_fmt(src, s1));
return;
}
-
+
/* Check if enough data is present */
- if (datalen < 12) {
- log(LOG_WARNING, 0,
- "non-decipherable prune from %s",
- inet_fmt(src, s1));
- return;
- }
-
+ if (datalen < 12)
+ {
+ log(LOG_WARNING, 0,
+ "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++;
-#if BYTE_ORDER == BIG_ENDIAN
+ ((char *)&prun_grp)[i] = *p++;
for (i = 0; i< 4; i++)
-#endif
-#if BYTE_ORDER == LITTLE_ENDIAN
- for (i = 3; i >= 0; i--)
-#endif
((char *)&prun_tmr)[i] = *p++;
+
+ 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_grp, s3), prun_tmr);
- kt = find_src_grp(prun_src, prun_dst);
-
- if (kt == NULL)
- {
- log(LOG_WARNING, 0, "prune message received incorrectly");
+ /*
+ * Find the subnet for the prune
+ */
+ 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 (!VIFM_ISSET(vifi, kt->kt_children))
- {
- log(LOG_INFO, 0,
- "ignoring prune report from non-child %s", inet_fmt(src, s1));
+ 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 (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;
+ 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;
+
+ pt->pt_next = g->gt_pruntbl;
+ g->gt_pruntbl = pt;
}
- log(LOG_DEBUG, 0, "%s on vif %d prunes (%s %s) tmr %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;
-
- /*
- * check if any more packets need to be sent on the
- * vif which sent this message
- */
- 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;
+ /* 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 */
}
- 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);
+ /*
+ * 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;
}
}
/*
- * 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;
-}
-
-/*
- * 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;
-}
-
-/*
- * 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;
-}
-
-/*
* 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;
+ 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);
- 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);
/*
* 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 == 0)
+ 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
- *
- * if it does, then determine if a prune was sent
+ *
+ * if it does, then determine if a prune was sent
* upstream.
* if prune sent upstream, send graft upstream and send
* ack downstream.
- *
+ *
* 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 from non-neighbor %s",
inet_fmt(src, s1));
return;
}
-
+
if (datalen < 8) {
log(LOG_WARNING, 0,
"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));
-
- 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
+ inet_fmt(graft_src, s2), inet_fmt(graft_grp, s3));
+
+ /*
+ * 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);
-
- /* reset the prune sent timer */
- kt->kt_prsent_timer = 0;
- }
-}
-
-/*
- * 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, "sent graft ack (%s, %s) to %s",
- inet_fmt(kt->kt_origin, s1), inet_fmt(kt->kt_mcastgrp, s2),
- inet_fmt(dst, 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.
- */
-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;
+ 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;
+ }
+ }
- p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
- datalen = 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;
- 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 graft upwards */
+ send_graft(g);
- 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, "sent graft (%s, %s) to %s",
- inet_fmt(kt->kt_origin, s1), inet_fmt(kt->kt_mcastgrp, s2),
- inet_fmt(kt->kt_gateway, s3));
}
/*
- * find out which group is involved first of all
+ * find out which group is involved first of all
* then determine if a graft was sent.
* if no graft sent, ignore the message
- * if graft was sent and the ack is from the right
- * source, remove the graft timer so that we don't
+ * if graft was sent and the ack is from the right
+ * 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",
+ "ignoring graft ack from non-neighbor %s",
inet_fmt(src, s1));
return;
}
-
- if (datalen < 8) {
+
+ if (datalen < 0 || datalen > 8) {
log(LOG_WARNING, 0,
- "received non-decipherable graft ack report from %s",
+ "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++;
-
- log(LOG_DEBUG, 0, "%s on vif %d acks graft (%s %s)",
+ ((char *)&grft_grp)[i] = *p++;
+
+ 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);
-
- if (kt == NULL) {
- log(LOG_WARNING, 0, "received wrong graft ack from %s", inet_fmt(src, s1));
+ inet_fmt(grft_src, s2), inet_fmt(grft_grp, s3));
+
+ /*
+ * 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;
+ 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;
+ }
- while (kernel_rtable != NULL) {
- kt = kernel_rtable;
- kernel_rtable = kt->kt_next;
+ p = g->gt_pruntbl;
+ while (p) {
+ prev_p = p->pt_next;
+ free(p);
+ p = prev_p;
+ }
- while (kt->kt_rlist != NULL) {
- krl = kt->kt_rlist;
- kt->kt_rlist = krl->rl_next;
- free((char *)krl);
+ prev_g = g->gt_next;
+ free(g);
+ g = prev_g;
}
+ r->rt_groups = NULL;
+ }
+ kernel_table = NULL;
- free((char *)kt);
- kroutes--;
+ g = kernel_no_route;
+ while (g) {
+ if (g->gt_srctbl)
+ free(g->gt_srctbl);
+
+ 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;
-
- log(LOG_DEBUG, 0, "kr:%x pr:%x",
- kernel_rtable, (struct ktable *)&kernel_rtable);
+ 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, "ageing entries");
+
+ gtnptr = &kernel_table;
+ while ((gt = *gtnptr) != NULL) {
+ r = gt->gt_route;
- for (prev_kt = (struct ktable *)&kernel_rtable;
- kt = prev_kt->kt_next;
- prev_kt = kt) {
/* 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 (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 prune
- 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) {
-
- /* decrement prune timer received from downstream routers */
- if ((krl->rl_timer -= ROUTE_MAX_REPORT_DELAY) <= 0) {
- log(LOG_DEBUG, 0, "forw again (%s, %s) on vif %d",
- inet_fmt(kt->kt_origin, s1),
- inet_fmt(kt->kt_mcastgrp, s2),
- 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);
+
/*
- * forwarding now, so entry is not pruned anymore
- * reset the cache timer to a largish value also
+ * No need to send a graft, any prunes that we sent
+ * will expire before any prunes that we have received.
*/
- kt->kt_prsent_timer = 0;
+ 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;
+ }
/* modify the kernel entry to forward packets */
- 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);
+ 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 */
- kt->kt_prun_count--;
- prev_krl->rl_next = krl->rl_next;
- free((char *)krl);
- krl = prev_krl;
-
- if (krl == NULL)
- break;
+ *ptnp = pt->pt_next;
+ free(pt);
+ } else {
+ ptnp = &pt->pt_next;
}
}
- if (kt->kt_timer <= 0) {
/*
- * If there are prune entries still outstanding,
- * update the cache timer otherwise expire entry.
+ * 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 (kt->kt_rlist) {
- kt->kt_timer = CACHE_LIFETIME(cache_lifetime);
+ 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;
}
- else {
- log(LOG_DEBUG, 0, "aging entry (%s, %s)",
- inet_fmt(kt->kt_origin, s1),
- inet_fmt(kt->kt_mcastgrp, s2));
-
- 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);
+
+ /*
+ * 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 (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;
+ }
}
- free((char *)kt);
+ 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;
+ }
+ }
+
+ 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) {
+ 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));
+ }
kroutes--;
- kt = prev_kt;
+ gt->gt_srctbl = st->st_next;
+ free(st);
+ }
+
+ /* free all the prune list entries */
+ while (gt->gt_pruntbl) {
+ 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;
}
}
}
+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", 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");
+ " 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));
+ }
+ }
+
+ 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));
- for (kt = kernel_rtable, count = 0; kt != NULL; kt = kt->kt_next) {
+ fprintf(fp2, " %-4s", scaletime(gt->gt_timer));
- fprintf(fp2, " %-15s %-15s",
- inet_fmts(kt->kt_origin, kt->kt_originmask, s1),
- inet_fmt(kt->kt_mcastgrp, s2));
+ fprintf(fp2, " %-4s %-4s ", scaletime(thyme - gt->gt_ctime),
+ gt->gt_prsent_timer ? scaletime(gt->gt_prsent_timer) :
+ " -");
- 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;
- }
- else
- fprintf(fp2, " %5u %2u %3u %c ",
- kt->kt_timer, kt->kt_parent, kt->kt_prun_count,
- kt->kt_prsent_timer ? 'P' : ' ');
+ 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;
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, "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, "Traceroute response 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 tracer 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;
+ } else
+ oqid = qry->tr_qid;
+
/*
- * 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", rcount);
/* 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
+ * Query type packet - check if rte exists
* Check if the query destination is a vif connected to me.
* and if so, whether I should start response back
*/
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;
-
- if (vifi == numvifs) {
- printf("Destination %s not an interface\n",
+ vifi = find_vif(qry->tr_dst, 0);
+
+ 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");
-
+ }
+
+ log(LOG_DEBUG, 0, "Sending traceroute response");
+
/* copy the packet to the sending buffer */
p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
-
+
bcopy(data, p, 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 + JAN_1970) << 16) +
- ((tp.tv_usec << 10) / 15625);
+ 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;
@@ -1350,18 +2207,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 (!VIFM_ISSET(vifi, rt->rt_children))
+ resp->tr_rflags = TR_NO_FWD;
}
/*
@@ -1371,9 +2245,8 @@ void mtrace(src, dst, group, data, no, datalen)
src = dst; /* the dst address of resp. pkt */
resp->tr_inaddr = 0;
resp->tr_rflags = TR_NO_RTE;
- resp->tr_rmtaddr = 0;
- }
- 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)
@@ -1384,33 +2257,54 @@ 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 == NULL) || (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;
+ }
+
+ log(LOG_DEBUG, 0, "Sending %s to %s from %s",
+ resptype == IGMP_MTRACE_RESP ? "response" : "request on",
+ inet_fmt(dst, s1), inet_fmt(src, s2));
if (IN_MULTICAST(ntohl(dst))) {
k_set_ttl(qry->tr_rttl);
+ /* Let the kernel pick the source address, since we might have picked
+ * a disabled phyint to multicast on.
+ */
send_igmp(INADDR_ANY, dst,
- IGMP_MTRACE_RESP, no, group,
- datalen + RLEN);
+ resptype, no, group,
+ datalen);
k_set_ttl(1);
- }
- else
+ } else
send_igmp(src, dst,
- IGMP_MTRACE, no, group,
- datalen + RLEN);
+ resptype, no, group,
+ datalen);
return;
}
diff --git a/usr.sbin/mrouted/prune.h b/usr.sbin/mrouted/prune.h
index fd1fd23..dadba5d 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.2 1994/09/08 02:51:24 wollman Exp $
+ * $Id: prune.h,v 3.5 1995/05/09 01:00:39 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) { \
+ u_int32 _x = ntohl(x); \
(i) = 0; \
- while ((x) << (i)) \
+ while ((_x) << (i)) \
(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 70ee5a5..756623f 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.2 1994/09/08 02:51:25 wollman Exp $
+ * $Id: route.c,v 3.5 1995/05/09 01:00:39 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,17 +27,22 @@ 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 */
-
/*
* Initialize the routing table and associated variables.
*/
-void init_routes()
+void
+init_routes()
{
routing_table = NULL;
nroutes = 0;
@@ -47,7 +57,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 +102,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 +136,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 +171,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 +227,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 +243,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 +255,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 +266,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 +276,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_long)))) == NULL) {
log(LOG_ERR, 0, "ran out of memory"); /* fatal */
}
r->rt_origin = origin;
@@ -301,12 +294,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_dominants = (u_int32 *)(r + 1);
+ r->rt_subordinates = (u_int32 *)(r->rt_dominants + numvifs);
r->rt_leaf_timers = (u_long *)(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 +314,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,10 +337,11 @@ 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;
@@ -361,6 +366,10 @@ void update_route(origin, mask, metric, src, vifi)
* Look up the reported origin in the routing table.
*/
if (!find_route(origin, mask)) {
+ register struct rtentry *rp;
+ register struct gtable *gt;
+ register struct stable *st, **stnp;
+
/*
* Not found.
* Don't create a new entry if the report says it's unreachable,
@@ -377,38 +386,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 +568,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 +592,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 +617,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 +650,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 +666,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 +681,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;
@@ -699,48 +704,50 @@ void accept_probe(src, dst, 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)
+int
+compare_rts(r1, r2)
register struct newrt *r1;
register struct newrt *r2;
{
- register unsigned long m1 = ntohl(r1->mask);
- register unsigned long m2 = ntohl(r2->mask);
- register unsigned long o1, o2;
+ 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) {
@@ -763,20 +770,20 @@ void accept_report(src, dst, p, datalen, level)
if (datalen < 3) {
log(LOG_WARNING, 0,
- "received truncated route report from %s",
+ "received truncated route report from %s",
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 */
if (datalen < width + 1) {
log(LOG_WARNING, 0,
- "received truncated route report from %s",
+ "received truncated route report from %s",
inet_fmt(src, s1));
return;
}
@@ -787,14 +794,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,18 +821,20 @@ 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;
+ u_int32 mask;
+ u_int32 src;
+ u_int32 nflags;
src = uvifs[vifi].uv_lcl_addr;
@@ -825,7 +842,24 @@ void report(which_routes, vifi, dst)
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,7 +873,7 @@ 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;
@@ -869,7 +903,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 +912,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,10 +961,11 @@ 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)
+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;
@@ -937,15 +973,28 @@ int report_chunk(start_rt, vifi, dst)
register int nrt = 0;
int datalen;
int width;
- u_long mask;
- u_long src;
+ u_int32 mask;
+ 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,7 +1004,7 @@ 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) {
@@ -979,21 +1028,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 +1052,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 +1090,30 @@ 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;
+ register time_t thyme = time(0);
+
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,15 +1126,15 @@ 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;
for (rt = routing_table; rt != NULL; rt = rt->rt_next) {
- if (rt->rt_origin == (src & rt->rt_originmask))
+ if (rt->rt_origin == (src & rt->rt_originmask))
break;
}
return rt;
}
-
diff --git a/usr.sbin/mrouted/route.h b/usr.sbin/mrouted/route.h
index 2e7aa33..fd84572 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.5 1995/05/09 01:00:39 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_int32 *rt_dominants; /* per vif dominant gateways */
+ u_int32 *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 */
+ 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
new file mode 100644
index 0000000..34eedab
--- /dev/null
+++ b/usr.sbin/mrouted/rsrr.c
@@ -0,0 +1,498 @@
+/*
+ * Copyright (c) 1993 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.
+ */
+
+/* RSRR code written by Daniel Zappala, USC Information Sciences Institute,
+ * April 1995.
+ */
+
+/* May 1995 -- Added support for Route Change Notification */
+
+#ifdef RSRR
+
+#include "defs.h"
+
+/* Taken from prune.c */
+/*
+ * checks for scoped multicast addresses
+ */
+#define GET_SCOPE(gt) { \
+ register int _i; \
+ if (((gt)->gt_mcastgrp & 0xff000000) == 0xef000000) \
+ for (_i = 0; _i < numvifs; _i++) \
+ if (scoped_addr(_i, (gt)->gt_mcastgrp)) \
+ VIFM_SET(_i, (gt)->gt_scope); \
+ }
+
+/*
+ * Exported variables.
+ */
+int rsrr_socket; /* interface to reservation protocol */
+
+/*
+ * Global RSRR variables.
+ */
+char rsrr_recv_buf[RSRR_MAX_LEN]; /* RSRR receive buffer */
+char rsrr_send_buf[RSRR_MAX_LEN]; /* RSRR send buffer */
+
+struct sockaddr_un client_addr;
+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();
+
+/* Initialize RSRR socket */
+void
+rsrr_init()
+{
+ int servlen;
+ struct sockaddr_un serv_addr;
+
+ if ((rsrr_socket = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)
+ log(LOG_ERR, errno, "Can't create RSRR socket");
+
+ unlink(RSRR_SERV_PATH);
+ bzero((char *) &serv_addr, sizeof(serv_addr));
+ serv_addr.sun_family = AF_UNIX;
+ strcpy(serv_addr.sun_path, RSRR_SERV_PATH);
+ servlen = sizeof(serv_addr.sun_family) + strlen(serv_addr.sun_path);
+
+ if (bind(rsrr_socket, (struct sockaddr *) &serv_addr, servlen) < 0)
+ log(LOG_ERR, errno, "Can't bind RSRR socket");
+
+ if (register_input_handler(rsrr_socket,rsrr_read) < 0)
+ log(LOG_WARNING, 0, "Couldn't register RSRR as an input handler");
+}
+
+/* Read a message from the RSRR socket */
+void
+rsrr_read()
+{
+ 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);
+ if (rsrr_recvlen < 0) {
+ if (errno != EINTR)
+ log(LOG_ERR, errno, "RSRR recvfrom");
+ return;
+ }
+ /* Use of omask taken from main() */
+ omask = sigblock(sigmask(SIGALRM));
+ rsrr_accept(rsrr_recvlen);
+ (void)sigsetmask(omask);
+}
+
+/* Accept a message from the reservation protocol and take
+ * appropriate action.
+ */
+void
+rsrr_accept(recvlen)
+ int recvlen;
+{
+ struct rsrr_header *rsrr;
+ struct rsrr_rq *route_query;
+
+ if (recvlen < RSRR_HEADER_LEN) {
+ log(LOG_WARNING, 0,
+ "Received RSRR packet of %d bytes, which is less than min size",
+ recvlen);
+ return;
+ }
+
+ rsrr = (struct rsrr_header *) rsrr_recv_buf;
+
+ if (rsrr->version > RSRR_MAX_VERSION) {
+ log(LOG_WARNING, 0,
+ "Received RSRR packet version %d, which I don't understand",
+ rsrr->version);
+ return;
+ }
+
+ switch (rsrr->version) {
+ case 1:
+ switch (rsrr->type) {
+ case RSRR_INITIAL_QUERY:
+ /* Send Initial Reply to client */
+ log(LOG_INFO, 0, "Received Initial Query\n");
+ rsrr_accept_iq();
+ break;
+ case RSRR_ROUTE_QUERY:
+ /* Check size */
+ if (recvlen < RSRR_RQ_LEN) {
+ log(LOG_WARNING, 0,
+ "Received Route Query of %d bytes, which is too small",
+ recvlen);
+ break;
+ }
+ /* Get the query */
+ route_query = (struct rsrr_rq *) (rsrr_recv_buf + RSRR_HEADER_LEN);
+ log(LOG_INFO, 0,
+ "Received Route Query for src %s grp %s notification %d",
+ inet_fmt(route_query->source_addr.s_addr, s1),
+ inet_fmt(route_query->dest_addr.s_addr,s2),
+ BIT_TST(rsrr->flags,RSRR_NOTIFICATION_BIT));
+ /* Send Route Reply to client */
+ rsrr_accept_rq(route_query,rsrr->flags,NULL);
+ break;
+ default:
+ log(LOG_WARNING, 0,
+ "Received RSRR packet type %d, which I don't handle",
+ rsrr->type);
+ break;
+ }
+ break;
+
+ default:
+ log(LOG_WARNING, 0,
+ "Received RSRR packet version %d, which I don't understand",
+ rsrr->version);
+ break;
+ }
+}
+
+/* Send an Initial Reply to the reservation protocol. */
+void
+rsrr_accept_iq()
+{
+ struct rsrr_header *rsrr;
+ struct rsrr_vif *vif_list;
+ struct uvif *v;
+ int vifi, sendlen;
+
+ /* Check for space. There should be room for plenty of vifs,
+ * but we should check anyway.
+ */
+ if (numvifs > RSRR_MAX_VIFS) {
+ log(LOG_WARNING, 0,
+ "Can't send RSRR Route Reply because %d is too many vifs %d",
+ numvifs);
+ return;
+ }
+
+ /* Set up message */
+ rsrr = (struct rsrr_header *) rsrr_send_buf;
+ rsrr->version = 1;
+ rsrr->type = RSRR_INITIAL_REPLY;
+ rsrr->flags = 0;
+ rsrr->num = numvifs;
+
+ vif_list = (struct rsrr_vif *) (rsrr_send_buf + RSRR_HEADER_LEN);
+
+ /* Include the vif list. */
+ for (vifi=0, v = uvifs; vifi < numvifs; vifi++, v++) {
+ vif_list[vifi].id = vifi;
+ vif_list[vifi].status = 0;
+ if (v->uv_flags & VIFF_DISABLED)
+ BIT_SET(vif_list[vifi].status,RSRR_DISABLED_BIT);
+ vif_list[vifi].threshold = v->uv_threshold;
+ vif_list[vifi].local_addr.s_addr = v->uv_lcl_addr;
+ }
+
+ /* Get the size. */
+ sendlen = RSRR_HEADER_LEN + numvifs*RSRR_VIF_LEN;
+
+ /* Send it. */
+ log(LOG_INFO, 0, "Send RSRR Initial Reply");
+ rsrr_send(sendlen);
+}
+
+/* Send a Route Reply to the reservation protocol. The Route Query
+ * contains the query to which we are responding. The flags contain
+ * the incoming flags from the query or, for route change
+ * notification, the flags that should be set for the reply. The
+ * kernel table entry contains the routing info to use for a route
+ * change notification.
+ */
+int
+rsrr_accept_rq(route_query,flags,gt_notify)
+ struct rsrr_rq *route_query;
+ int flags;
+ struct gtable *gt_notify;
+{
+ struct rsrr_header *rsrr;
+ struct rsrr_rr *route_reply;
+ struct gtable *gt,local_g;
+ struct rtentry *r;
+ int sendlen,i;
+ u_long mcastgrp;
+
+ /* Set up message */
+ rsrr = (struct rsrr_header *) rsrr_send_buf;
+ rsrr->version = 1;
+ rsrr->type = RSRR_ROUTE_REPLY;
+ rsrr->flags = 0;
+ rsrr->num = 0;
+
+ route_reply = (struct rsrr_rr *) (rsrr_send_buf + RSRR_HEADER_LEN);
+ route_reply->dest_addr.s_addr = route_query->dest_addr.s_addr;
+ route_reply->source_addr.s_addr = route_query->source_addr.s_addr;
+ route_reply->query_id = route_query->query_id;
+
+ /* Blank routing entry for error. */
+ route_reply->in_vif = 0;
+ route_reply->reserved = 0;
+ route_reply->out_vif_bm = 0;
+
+ /* Get the size. */
+ sendlen = RSRR_RR_LEN;
+
+ /* If kernel table entry is defined, then we are sending a Route Reply
+ * due to a Route Change Notification event. Use the kernel table entry
+ * to supply the routing info.
+ */
+ if (gt_notify) {
+ /* Set flags */
+ rsrr->flags = flags;
+ /* Include the routing entry. */
+ route_reply->in_vif = gt_notify->gt_route->rt_parent;
+ route_reply->out_vif_bm = gt_notify->gt_grpmems;
+
+ } else if (find_src_grp(route_query->source_addr.s_addr, 0,
+ route_query->dest_addr.s_addr)) {
+
+ /* Found kernel entry. Code taken from add_table_entry() */
+ gt = gtp ? gtp->gt_gnext : kernel_table;
+
+ /* Include the routing entry. */
+ route_reply->in_vif = gt->gt_route->rt_parent;
+ route_reply->out_vif_bm = gt->gt_grpmems;
+
+ /* Cache reply if using route change notification. */
+ if BIT_TST(flags,RSRR_NOTIFICATION_BIT) {
+ rsrr_cache(gt,route_query);
+ BIT_SET(rsrr->flags,RSRR_NOTIFICATION_BIT);
+ }
+
+ } else {
+ /* No kernel entry; use routing table. */
+ r = determine_route(route_query->source_addr.s_addr);
+
+ if (r != NULL) {
+ /* We need to mimic what will happen if a data packet
+ * is forwarded by multicast routing -- the kernel will
+ * make an upcall and mrouted will install a route in the kernel.
+ * Our outgoing vif bitmap should reflect what that table
+ * will look like. Grab code from add_table_entry().
+ * This is gross, but it's probably better to be accurate.
+ */
+
+ gt = &local_g;
+ mcastgrp = route_query->dest_addr.s_addr;
+
+ gt->gt_mcastgrp = mcastgrp;
+ gt->gt_grpmems = 0;
+ gt->gt_scope = 0;
+ gt->gt_route = r;
+
+ /* 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);
+ gt->gt_grpmems &= ~gt->gt_scope;
+
+ /* Include the routing entry. */
+ route_reply->in_vif = gt->gt_route->rt_parent;
+ route_reply->out_vif_bm = gt->gt_grpmems;
+
+ } else {
+ /* Set error bit. */
+ BIT_SET(rsrr->flags,RSRR_ERROR_BIT);
+ }
+ }
+
+ if (gt_notify)
+ log(LOG_INFO, 0, "Route Change: Send RSRR Route Reply");
+
+ else
+ log(LOG_INFO, 0, "Send RSRR Route Reply");
+
+ log(LOG_INFO, 0, "for src %s dst %s in vif %d out vif %d\n",
+ inet_fmt(route_reply->source_addr.s_addr,s1),
+ inet_fmt(route_reply->dest_addr.s_addr,s2),
+ route_reply->in_vif,route_reply->out_vif_bm);
+
+ /* Send it. */
+ return rsrr_send(sendlen);
+}
+
+/* Send an RSRR message. */
+int
+rsrr_send(sendlen)
+ int sendlen;
+{
+ int error;
+
+ /* Send it. */
+ error = sendto(rsrr_socket, rsrr_send_buf, sendlen, 0,
+ (struct sockaddr *)&client_addr, client_length);
+
+ /* Check for errors. */
+ if (error < 0) {
+ log(LOG_WARNING, errno, "Failed send on RSRR socket");
+ return error;
+ }
+ if (error != sendlen) {
+ log(LOG_WARNING, 0,
+ "Sent only %d out of %d bytes on RSRR socket\n", error, sendlen);
+ return error;
+ }
+}
+
+/* Cache a message being sent to a client. Currently only used for
+ * caching Route Reply messages for route change notification.
+ */
+void
+rsrr_cache(gt,route_query)
+ struct gtable *gt;
+ struct rsrr_rq *route_query;
+{
+ struct rsrr_cache *rc,*rc_prev;
+ struct rsrr_header *rsrr;
+
+ rsrr = (struct rsrr_header *) rsrr_send_buf;
+
+ rc = gt->gt_rsrr_cache;
+ while (rc) {
+ if ((rc->route_query.source_addr.s_addr ==
+ route_query->source_addr.s_addr) &&
+ (rc->route_query.dest_addr.s_addr ==
+ route_query->dest_addr.s_addr) &&
+ (!strcmp(rc->client_addr.sun_path,client_addr.sun_path))) {
+ /* Cache entry already exists.
+ * Check if route notification bit has been cleared.
+ */
+ 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;
+ 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);
+ }
+ return;
+ }
+ rc_prev = rc;
+ rc = rc->next;
+ }
+
+ /* Cache entry doesn't already exist. Create one and insert at
+ * front of list.
+ */
+ rc = (struct rsrr_cache *) malloc(sizeof(struct rsrr_cache));
+ if (rc == NULL)
+ log(LOG_ERR, 0, "ran out of memory");
+ rc->route_query.source_addr.s_addr = route_query->source_addr.s_addr;
+ rc->route_query.dest_addr.s_addr = route_query->dest_addr.s_addr;
+ rc->route_query.query_id = route_query->query_id;
+ strcpy(rc->client_addr.sun_path, client_addr.sun_path);
+ 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",
+ rc->route_query.query_id,rc->client_addr.sun_path);
+}
+
+/* Send all the messages in the cache. Currently this is used to send
+ * all the cached Route Reply messages for route change notification.
+ */
+void
+rsrr_cache_send(gt,notify)
+ struct gtable *gt;
+ int notify;
+{
+ struct rsrr_cache *rc,*rc_next,*rc_prev;
+ int flags = 0;
+
+ rc = gt->gt_rsrr_cache;
+ while (rc) {
+ rc_next = rc->next;
+
+ if (notify)
+ BIT_SET(flags,RSRR_NOTIFICATION_BIT);
+
+ if (rsrr_accept_rq(&rc->route_query,flags,gt) < 0) {
+ printf("Deleting cached query id %d 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;
+ free(rc);
+ } else {
+ rc_prev = rc;
+ }
+ rc = rc_next;
+ }
+}
+
+/* Clean the cache by deleting all entries. */
+void
+rsrr_cache_clean(gt)
+ struct gtable *gt;
+{
+ struct rsrr_cache *rc,*rc_next;
+
+ printf("cleaning cache for group %s\n",inet_fmt(gt->gt_mcastgrp, s1));
+ rc = gt->gt_rsrr_cache;
+ while (rc) {
+ rc_next = rc->next;
+ free(rc);
+ rc = rc_next;
+ }
+ gt->gt_rsrr_cache = NULL;
+}
+
+void
+rsrr_clean()
+{
+ unlink(RSRR_SERV_PATH);
+}
+
+#endif /* RSRR */
diff --git a/usr.sbin/mrouted/rsrr.h b/usr.sbin/mrouted/rsrr.h
new file mode 100644
index 0000000..4099dcd
--- /dev/null
+++ b/usr.sbin/mrouted/rsrr.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 1993 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.
+ */
+
+#define RSRR_SERV_PATH "/tmp/.rsrr_svr"
+/* Note this needs to be 14 chars for 4.3 BSD compatibility */
+#define RSRR_CLI_PATH "/tmp/.rsrr_cli"
+
+#define RSRR_MAX_LEN 2048
+#define RSRR_HEADER_LEN (sizeof(struct rsrr_header))
+#define RSRR_RQ_LEN (RSRR_HEADER_LEN + sizeof(struct rsrr_rq))
+#define RSRR_RR_LEN (RSRR_HEADER_LEN + sizeof(struct rsrr_rr))
+#define RSRR_VIF_LEN (sizeof(struct rsrr_vif))
+
+/* Current maximum number of vifs. */
+#define RSRR_MAX_VIFS 32
+
+/* Maximum acceptable version */
+#define RSRR_MAX_VERSION 1
+
+/* RSRR message types */
+#define RSRR_ALL_TYPES 0
+#define RSRR_INITIAL_QUERY 1
+#define RSRR_INITIAL_REPLY 2
+#define RSRR_ROUTE_QUERY 3
+#define RSRR_ROUTE_REPLY 4
+
+/* 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
+ * disabled.
+ */
+#define RSRR_DISABLED_BIT 0
+/* All other bits are zeroes */
+
+/* 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
+ * reservation protocol wishes to receive notification of
+ * a route change for the source-destination pair listed in the query.
+ * Notification is in the form of an unsolicitied Route Reply.
+ */
+#define RSRR_NOTIFICATION_BIT 0
+/* Next bit indicates an error returning the Route Reply. */
+#define RSRR_ERROR_BIT 1
+/* All other bits are zeroes */
+
+/* Definition of an RSRR message header.
+ * An Initial Query uses only the header, and an Initial Reply uses
+ * the header and a list of vifs.
+ */
+struct rsrr_header {
+ u_char version; /* RSRR Version, currently 1 */
+ u_char type; /* type of message, as defined above */
+ u_char flags; /* flags; defined by type */
+ u_char num; /* number; defined by type */
+};
+
+/* Definition of a vif as seen by the reservation protocol.
+ *
+ * Routing gives the reservation protocol a list of vifs in the
+ * Initial Reply.
+ *
+ * We explicitly list the ID because we can't assume that all routing
+ * protocols will use the same numbering scheme.
+ *
+ * The status is a bitmask of status flags, as defined above. It is the
+ * responsibility of the reservation protocol to perform any status checks
+ * if it uses the MULTICAST_VIF socket option.
+ *
+ * The threshold indicates the ttl an outgoing packet needs in order to
+ * be forwarded. The reservation protocol must perform this check itself if
+ * it uses the MULTICAST_VIF socket option.
+ *
+ * The local address is the address of the physical interface over which
+ * packets are sent.
+ */
+struct rsrr_vif {
+ u_char id; /* vif id */
+ u_char threshold; /* vif threshold ttl */
+ u_short status; /* vif status bitmask */
+ struct in_addr local_addr; /* vif local address */
+};
+
+/* Definition of an RSRR Route Query.
+ *
+ * The query asks routing for the forwarding entry for a particular
+ * source and destination. The query ID uniquely identifies the query
+ * for the reservation protocol. Thus, the combination of the client's
+ * address and the query ID forms a unique identifier for routing.
+ * Flags are defined above.
+ */
+struct rsrr_rq {
+ struct in_addr dest_addr; /* destination */
+ struct in_addr source_addr; /* source */
+ u_long query_id; /* query ID */
+};
+
+/* Definition of an RSRR Route Reply.
+ *
+ * Routing uses the reply to give the reservation protocol the
+ * forwarding entry for a source-destination pair. Routing copies the
+ * query ID from the query and fills in the incoming vif and a bitmask
+ * of the outgoing vifs.
+ * Flags are defined above.
+ */
+struct rsrr_rr {
+ struct in_addr dest_addr; /* destination */
+ struct in_addr source_addr; /* source */
+ u_long query_id; /* query ID */
+ u_short in_vif; /* incoming vif */
+ u_short reserved; /* reserved */
+ u_long out_vif_bm; /* outgoing vif bitmask */
+};
diff --git a/usr.sbin/mrouted/rsrr_var.h b/usr.sbin/mrouted/rsrr_var.h
new file mode 100644
index 0000000..9b1c09c
--- /dev/null
+++ b/usr.sbin/mrouted/rsrr_var.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 1993 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.
+ */
+
+/* RSRR things that are only needed by mrouted. */
+
+/* Cache of Route Query messages, distinguished by source,
+ * destination, and client addresses. Cache is flushed by RSRR client
+ * -- it sends notification when an unwanted Route Reply is received.
+ * Since this only happens during route changes, it is more likely
+ * that the cache will be flushed when the kernel table entry is
+ * deleted. */
+struct rsrr_cache {
+ struct rsrr_rq route_query; /* Cached Route Query */
+ struct sockaddr_un client_addr; /* Client address */
+ int client_length; /* Length of client */
+ struct rsrr_cache *next; /* next cache item */
+};
+
diff --git a/usr.sbin/mrouted/vif.c b/usr.sbin/mrouted/vif.c
index 56aae3f..07878d8 100644
--- a/usr.sbin/mrouted/vif.c
+++ b/usr.sbin/mrouted/vif.c
@@ -7,7 +7,7 @@
* Leland Stanford Junior University.
*
*
- * $Id: vif.c,v 1.3 1995/05/16 00:28:50 jkh Exp $
+ * $Id: vif.c,v 3.5 1995/05/09 01:00:39 fenner Exp $
*/
@@ -24,6 +24,7 @@ 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 */
/*
* Forward declarations.
@@ -35,11 +36,13 @@ static void age_old_hosts();
/*
* 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_down = FALSE;
@@ -51,7 +54,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();
/*
@@ -78,11 +83,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);
}
@@ -96,7 +109,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;
@@ -135,28 +149,62 @@ void check_vif_state()
}
}
+/*
+ * Send a probe message on vif v
+ */
+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.
*/
- log(LOG_DEBUG, 0, "Installing vif %d in kernel\n", vifi);
k_add_vif(vifi, &uvifs[vifi]);
/*
@@ -175,11 +223,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_addr, p->pa_mask, 0, 0, vifi);
+ }
/*
* Until neighbors are discovered, assume responsibility for sending
@@ -187,46 +246,29 @@ static void start_vif(vifi)
* query.
*/
v->uv_flags |= VIFF_QUERIER;
- send_igmp(src, allhosts_group, IGMP_HOST_MEMBERSHIP_QUERY,
+ send_igmp(src, allhosts_group, IGMP_HOST_MEMBERSHIP_QUERY,
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];
@@ -237,12 +279,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_addr, p->pa_mask, UNREACHABLE, 0, vifi);
+ }
/*
* Discard all group addresses. (No need to tell kernel;
@@ -270,6 +321,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;
@@ -281,7 +335,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;
@@ -313,12 +368,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))) {
@@ -330,14 +387,19 @@ vifi_t find_vif(src, dst)
if ((src & v->uv_subnetmask) == v->uv_subnet &&
src != v->uv_subnetbcast)
return(vifi);
+ for (p=v->uv_addrs; p; p=p->pa_next) {
+ if ((src & p->pa_mask) == p->pa_addr &&
+ src != p->pa_addr)
+ return(vifi);
+ }
}
}
}
return (NO_VIF);
}
-
-static void age_old_hosts()
+static void
+age_old_hosts()
{
register vifi_t vifi;
register struct uvif *v;
@@ -358,7 +420,8 @@ static void 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;
@@ -366,19 +429,54 @@ void query_groups()
for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
if (v->uv_flags & VIFF_QUERIER) {
send_igmp(v->uv_lcl_addr, allhosts_group,
- IGMP_HOST_MEMBERSHIP_QUERY,
+ IGMP_HOST_MEMBERSHIP_QUERY,
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;
@@ -415,7 +513,7 @@ void accept_group_report(src, dst, group, r_type)
g->al_query = DeleteTimer(g->al_query);
if (g->al_timerid)
g->al_timerid = DeleteTimer(g->al_timerid);
- g->al_timerid = SetTimer(vifi, g);
+ g->al_timerid = SetTimer(vifi, g);
break;
}
}
@@ -441,6 +539,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;
@@ -448,15 +547,16 @@ void accept_group_report(src, dst, group, r_type)
update_lclgrp(vifi, group);
}
- /*
+ /*
* Check if a graft is necessary for this group
*/
chkgrp_graft(vifi, group);
}
-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;
@@ -465,40 +565,47 @@ 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,
- GROUP_EXPIRE_TIME / 30 * IGMP_TIMER_SCALE,
+ IGMP_HOST_MEMBERSHIP_QUERY,
+ LEAVE_EXPIRE_TIME / 3 * IGMP_TIMER_SCALE,
g->al_addr, 0);
- g->al_query = SetQueryTimer(g, vifi, g->al_timer / 3 ,
- GROUP_EXPIRE_TIME / 30 * IGMP_TIMER_SCALE);
- g->al_timerid = SetTimer(vifi, g);
+ g->al_query = SetQueryTimer(g, vifi, g->al_timer / 3,
+ LEAVE_EXPIRE_TIME / 3 * IGMP_TIMER_SCALE);
+ g->al_timerid = SetTimer(vifi, g);
break;
}
}
@@ -510,40 +617,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);
}
}
}
@@ -552,15 +634,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.
@@ -571,7 +654,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,13 +669,13 @@ void accept_neighbor_request(src, dst)
close(udp);
us = addr.sin_addr.s_addr;
} else /* query sent to us alone */
- us = 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;
@@ -636,15 +721,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 us, them = src;
+ u_int32 us, them = src;
/* Determine which of our addresses to use as the source of our response
* to this query.
@@ -655,7 +741,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
@@ -668,7 +756,7 @@ void accept_neighbor_request2(src, dst)
close(udp);
us = addr.sin_addr.s_addr;
} else /* query sent to us alone */
- us = dst;
+ us = dst;
p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
datalen = 0;
@@ -686,6 +774,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) {
@@ -747,8 +837,9 @@ 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;
+void
+accept_neighbors(src, dst, p, datalen, level)
+ u_int32 src, dst, level;
char *p;
int datalen;
{
@@ -760,8 +851,9 @@ 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;
+void
+accept_neighbors2(src, dst, p, datalen, level)
+ u_int32 src, dst, level;
char *p;
int datalen;
{
@@ -775,21 +867,24 @@ 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 = 0;
- u_long router;
+ u_int32 genid = 0;
+ u_int32 router;
int he_hears_me = TRUE;
+ int nflags;
v = &uvifs[vifi];
+ nflags = (level >> 16) & 0xff;
/*
* Confirm that 'addr' is a valid neighbor address on vif 'vifi'.
@@ -822,39 +917,40 @@ int update_neighbor(vifi, addr, msgtype, p, datalen, level)
(v->uv_flags & VIFF_TUNNEL) ? addr : dvmrp_group);
/*
- * Check if the router gen-ids are the same.
+ * Check if the router gen-ids are the same (only if vers > 3.2)
* Need to reset the prune state of the router if not.
*/
if (msgtype == DVMRP_PROBE) {
- /* if mrouted level > 3.2, analyze further */
- if ((level&0xff) > 3 ||
- (((level&0xff) == 3) && (((level>>8)&0xff) > 2))) {
+ /* 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",
- inet_fmt(addr, s1));
- return FALSE;
+ "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;
-
- /*
+
+ /*
* 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));
+ "received truncated probe message from %s (len %d)",
+ inet_fmt(addr, s1), datalen);
return (FALSE);
}
for (i = 0; i < 4; i++)
@@ -867,7 +963,6 @@ int update_neighbor(vifi, addr, msgtype, p, datalen, level)
}
}
}
-
/*
* Look for addr in list of neighbors; if found, reset its timer.
*/
@@ -875,8 +970,10 @@ int update_neighbor(vifi, addr, msgtype, p, datalen, level)
if (addr == n->al_addr) {
n->al_timer = 0;
- /* If probe message and version no >= 3.3 check genid */
- if (msgtype == DVMRP_PROBE &&
+ /*
+ * 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;
@@ -884,46 +981,66 @@ int update_neighbor(vifi, addr, msgtype, p, datalen, level)
if (he_hears_me == FALSE)
v->uv_flags |= VIFF_ONEWAY;
- if ((n->al_genid != 0) && (n->al_genid != genid)) {
+ if (n->al_genid == 0)
+ n->al_genid = genid;
+ else if (n->al_genid != genid) {
log(LOG_DEBUG, 0,
- "old:%d new:%dreset neighbor %s",
- n->al_genid, genid, inet_fmt(addr, s1));
+ "reset neighbor %s on vif %d [old genid:%x, new:%x]",
+ inet_fmt(addr, s1), vifi, n->al_genid, genid);
- reset_neighbor_state(vifi, addr);
n->al_genid = genid;
n->al_pv = level & 0xff;
n->al_mv = (level >> 8) & 0xff;
+ n->al_flags = 0; /*XXX*/
+ reset_neighbor_state(vifi, addr);
- /*
- * need to do a full route report here
+ /*
+ * need to do a full route report here
* it gets done by accept_probe()
*/
return (TRUE);
}
+
+ /*XXX nflags shouldn't be dealt with in 2 places in the same
+ *XXX routine...*/
+ if (n->al_flags != nflags) {
+ n->al_flags = nflags;
+ if (nflags & NF_LEAF) {
+ if (!v->uv_leaf_timer)
+ v->uv_leaf_timer = LEAF_CONFIRMATION_TIME;
+ } else {
+ v->uv_flags &= ~VIFF_LEAF;
+ v->uv_leaf_timer = 0;
+ }
+ /* Neighbor flags changed, do a full report */
+ return TRUE;
+ }
}
/*
* update the neighbors version and protocol number
- * if changed => router went down and came up,
+ * if changed => router went down and came up,
* so take action immediately.
*/
if ((n->al_pv != (level & 0xff)) ||
- ((n->al_mv != (level >> 8)) & 0xff)) {
+ (n->al_mv != ((level >> 8) & 0xff))) {
+
log(LOG_DEBUG, 0,
"resetting 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, n->al_mv, level&0xff, (level >> 8) & 0xff);
+
n->al_pv = level & 0xff;
n->al_mv = (level >> 8) & 0xff;
reset_neighbor_state(vifi, addr);
}
+
/* recurring probe - so no need to do a route report */
if (msgtype == DVMRP_PROBE)
- return (FALSE);
+ return (FALSE);
else
- return (TRUE);
+ return (TRUE);
}
}
@@ -932,6 +1049,10 @@ int update_neighbor(vifi, addr, msgtype, p, datalen, level)
* IP address than me, yield querier duties to it.
*/
if (n == NULL) {
+ 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 */
@@ -944,8 +1065,13 @@ int update_neighbor(vifi, addr, msgtype, p, datalen, level)
else
n->al_genid = 0;
+ time(&n->al_ctime);
n->al_timer = 0;
n->al_next = v->uv_neighbors;
+
+ if (v->uv_neighbors == NULL)
+ vifs_with_neighbors++;
+
v->uv_neighbors = n;
if (!(v->uv_flags & VIFF_TUNNEL) &&
@@ -953,6 +1079,18 @@ int update_neighbor(vifi, addr, msgtype, p, datalen, level)
v->uv_flags &= ~VIFF_QUERIER;
}
+ n->al_flags = nflags;
+ if (!(n->al_flags & NF_LEAF)) {
+ v->uv_flags &= ~VIFF_LEAF;
+ v->uv_leaf_timer = 0;
+ } else {
+ /*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;
+ }
+
return (TRUE);
}
@@ -961,14 +1099,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;
@@ -991,12 +1133,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;
}
}
}
@@ -1004,27 +1153,64 @@ 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;
+}
+
+/*
+ * Return the neighbor's version number
+ * returns (protocol_version << 8 + mrouted_version) of neighbor
+ */
+int
+nbr_vers(vifi, addr)
+ vifi_t vifi;
+ u_int32 addr;
+{
+ struct listaddr *u = neighbor_info(vifi, addr);
+
+ return u ? NBR_VERS(u) : 0;
+}
/*
* 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),
@@ -1043,15 +1229,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_addr, v->uv_addrs->pa_mask, s1));
+ for (p = v->uv_addrs->pa_next; p; p = p->pa_next) {
+ fprintf(fp, " %s\n",
+ inet_fmts(p->pa_addr, p->pa_mask, 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);
}
}
@@ -1066,10 +1264,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));
}
}
@@ -1100,6 +1298,7 @@ typedef struct {
static cbk_t *cbk;
+void
DelVif(cbk)
cbk_t *cbk;
{
@@ -1133,6 +1332,7 @@ cbk_t *cbk;
}
+int
SetTimer( vifi, g)
vifi_t vifi; struct listaddr *g;
{
@@ -1142,6 +1342,7 @@ SetTimer( vifi, g)
return timer_setTimer(g->al_timer,DelVif,cbk);
}
+int
DeleteTimer( id)
int id;
{
@@ -1149,6 +1350,7 @@ int id;
return 0;
}
+void
SendQuery(cbk)
cbk_t *cbk;
{
@@ -1160,6 +1362,7 @@ cbk_t *cbk;
free(cbk);
}
+int
SetQueryTimer(g , vifi, to_expire, q_time)
struct listaddr *g; vifi_t vifi;
int to_expire, q_time;
@@ -1169,4 +1372,3 @@ SetQueryTimer(g , vifi, to_expire, q_time)
cbk->q_time = q_time; cbk-> vifi = vifi;
return timer_setTimer(to_expire,SendQuery,cbk);
}
-
diff --git a/usr.sbin/mrouted/vif.h b/usr.sbin/mrouted/vif.h
index 3cfa2e5..53c309e 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.5 1995/05/09 01:00:39 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,38 @@ 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_long pa_addr;
+ u_long pa_mask;
+};
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 */
OpenPOWER on IntegriCloud