This is a 'for reference' import of mrouted release 3.6. It's pure

conflict markers, but it actually changes nothing.

We've been running this code with small changes for some time, this may
be useful for checking what those changes.  It was unfortunate this
module got so far away from the vendor branch (whitespace changes didn't
help)
This commit is contained in:
Peter Wemm 1996-01-06 21:00:43 +00:00
parent ed30da51aa
commit 29a6d69cc3
26 changed files with 5446 additions and 3031 deletions

View File

@ -7,7 +7,7 @@
* Leland Stanford Junior University.
*
*
* $Id: callout.c,v 1.1 1994/08/24 23:52:49 thyagara Exp $
* $Id: callout.c,v 3.6 1995/06/25 18:47:29 fenner Exp $
*/
#include "defs.h"
@ -18,17 +18,21 @@ static struct timeout_q *Q = 0; /* pointer to the beginning of timeout queue */
static int in_callout= 0;
typedef void (* cfunc_t)();
struct timeout_q {
struct timeout_q *next; /* next event */
int id;
cfunc_t func ; /* function to call */
cfunc_t func; /* function to call */
char *data; /* func's data */
int time; /* time offset to next event*/
};
#ifdef IGMP_DEBUG
static void print_Q __P((void));
#else
#define print_Q()
#endif
void
callout_init()
{
Q = (struct timeout_q *) 0;
@ -38,6 +42,7 @@ callout_init()
/*
* signal handler for SIGALARM that is called once every second
*/
void
age_callout_queue()
{
struct timeout_q *ptr;
@ -51,7 +56,7 @@ age_callout_queue()
while (ptr){
if (!ptr->time ) {
/* timeout has happened */
if(ptr->func)
if (ptr->func)
ptr->func(ptr->data);
Q = Q->next;
@ -62,7 +67,7 @@ age_callout_queue()
ptr->time --;
#ifdef IGMP_DEBUG
log(LOG_DEBUG,0,"[callout, age_callout_queue] -- time (%d)", ptr->time);
#endif IGMP_DEBUG
#endif /* IGMP_DEBUG */
in_callout = 0; return;
}
}
@ -74,7 +79,8 @@ age_callout_queue()
/*
* sets the timer
*/
int timer_setTimer(delay, action, data)
int
timer_setTimer(delay, action, data)
int delay; /* number of units for timeout */
cfunc_t action; /* function to be called on timeout */
char *data; /* what to call the timeout function with */
@ -82,13 +88,13 @@ int timer_setTimer(delay, action, data)
struct timeout_q *ptr, *node, *prev;
if (in_callout)
return;
return -1;
in_callout = 1;
/* create a node */
node = (struct timeout_q *)malloc(sizeof(struct timeout_q));
if ((int) node <= 0) {
node = (struct timeout_q *)malloc(sizeof(struct timeout_q));
if (node == 0) {
log(LOG_WARNING, 0, "Malloc Failed in timer_settimer\n");
in_callout = 0;
return -1;
@ -108,9 +114,9 @@ int timer_setTimer(delay, action, data)
Q = node;
else {
/* chase the pointer looking for the right place */
while (ptr){
while (ptr) {
if (delay < ptr->time){
if (delay < ptr->time) {
/* right place */
node->next = ptr;
@ -122,8 +128,7 @@ int timer_setTimer(delay, action, data)
print_Q();
in_callout = 0;
return node->id;
}
else {
} else {
/* keep moving */
delay -= ptr->time; node->time = delay;
@ -140,17 +145,19 @@ int timer_setTimer(delay, action, data)
/* clears the associated timer */
void timer_clearTimer( id)
int id;
void
timer_clearTimer(timer_id)
int timer_id;
{
struct timeout_q *ptr, *prev;
if (in_callout) return;
if (in_callout)
return;
if (!timer_id)
return;
in_callout = 1;
if ( !id ) {in_callout = 0; return;}
prev = ptr = Q;
/*
@ -159,12 +166,12 @@ void timer_clearTimer( id)
*/
print_Q();
while (ptr){
if (ptr->id == id){
while (ptr) {
if (ptr->id == timer_id) {
/* got the right node */
/* unlink it from the queue */
if ( ptr == Q)
if (ptr == Q)
Q = Q->next;
else
prev->next = ptr->next;
@ -186,16 +193,16 @@ void timer_clearTimer( id)
in_callout = 0;
}
#ifdef IGMP_DEBUG
/*
* debugging utility
*/
static void
print_Q()
{
struct timeout_q *ptr;
#ifdef IGMP_DEBUG
for(ptr = Q; ptr; ptr = ptr->next)
log(LOG_DEBUG,0,"(%d,%d) ", ptr->id, ptr->time);
#endif IGMP_DEBUG
}
#endif /* IGMP_DEBUG */

View File

@ -4,12 +4,28 @@
*
* Written by Bill Fenner, NRL, 1994
*
* $Id: cfparse.y,v 3.5 1995/05/09 01:00:39 fenner Exp $
* $Id: cfparse.y,v 3.6 1995/06/25 18:49:46 fenner Exp $
*/
#include <stdio.h>
#ifdef __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
#include "defs.h"
/*
* Local function declarations
*/
static void fatal __P((char *fmt, ...));
static void warn __P((char *fmt, ...));
static void yyerror __P((char *s));
static char * next_word __P((void));
static int yylex __P((void));
static u_int32 valid_if __P((char *s));
static struct ifreq * ifconfaddr __P((struct ifconf *ifcp, u_int32 a));
int yyparse __P((void));
static FILE *f;
extern int udp_socket;
@ -195,7 +211,17 @@ ifmods : /* empty */
ifmod : mod
| DISABLE { v->uv_flags |= VIFF_DISABLED; }
| NETMASK ADDR { v->uv_subnetmask = $2; }
| NETMASK ADDR {
u_int32 subnet, mask;
mask = $2;
subnet = v->uv_lcl_addr & mask;
if (!inet_valid_subnet(subnet, mask))
fatal("Invalid netmask");
v->uv_subnet = subnet;
v->uv_subnetmask = mask;
v->uv_subnetbcast = subnet | ~mask;
}
| ALTNET addrmask {
struct phaddr *ph;
@ -204,12 +230,13 @@ ifmod : mod
if (ph == NULL)
fatal("out of memory");
if ($2.mask) {
VAL_TO_MASK(ph->pa_mask, $2.mask);
VAL_TO_MASK(ph->pa_subnetmask, $2.mask);
} else
ph->pa_mask = v->uv_subnetmask;
ph->pa_addr = $2.addr & ph->pa_mask;
if ($2.addr & ~ph->pa_mask)
warn("Extra addr %s/%d has host bits set",
ph->pa_subnetmask = v->uv_subnetmask;
ph->pa_subnet = $2.addr & ph->pa_subnetmask;
ph->pa_subnetbcast = ph->pa_subnet | ~ph->pa_subnetmask;
if ($2.addr & ~ph->pa_subnetmask)
warn("Extra subnet %s/%d has host bits set",
inet_fmt($2.addr,s1), $2.mask);
ph->pa_next = v->uv_addrs;
v->uv_addrs = ph;
@ -305,8 +332,18 @@ addrmask : ADDRMASK { $$ = $1; }
| ADDR { $$.addr = $1; $$.mask = 0; }
;
%%
#ifdef __STDC__
static void
fatal(char *fmt, ...)
{
va_list ap;
char buf[200];
va_start(ap, fmt);
#else
/*VARARGS1*/
static void fatal(fmt, va_alist)
static void
fatal(fmt, va_alist)
char *fmt;
va_dcl
{
@ -314,14 +351,25 @@ va_dcl
char buf[200];
va_start(ap);
#endif
vsprintf(buf, fmt, ap);
va_end(ap);
log(LOG_ERR,0,"%s: %s near line %d", configfilename, buf, lineno);
}
#ifdef __STDC__
static void
warn(char *fmt, ...)
{
va_list ap;
char buf[200];
va_start(ap, fmt);
#else
/*VARARGS1*/
static void warn(fmt, va_alist)
static void
warn(fmt, va_alist)
char *fmt;
va_dcl
{
@ -329,19 +377,22 @@ va_dcl
char buf[200];
va_start(ap);
#endif
vsprintf(buf, fmt, ap);
va_end(ap);
log(LOG_WARNING,0,"%s: %s near line %d", configfilename, buf, lineno);
}
void yyerror(s)
static void
yyerror(s)
char *s;
{
log(LOG_ERR, 0, "%s: %s near line %d", configfilename, s, lineno);
}
char *next_word()
static char *
next_word()
{
static char buf[1024];
static char *p=NULL;
@ -375,7 +426,8 @@ char *next_word()
}
}
int yylex()
static int
yylex()
{
int n;
u_int32 addr;
@ -446,7 +498,8 @@ int yylex()
return STRING;
}
void config_vifs_from_file()
void
config_vifs_from_file()
{
extern FILE *f;
@ -467,7 +520,7 @@ void config_vifs_from_file()
yyparse();
close(f);
fclose(f);
}
static u_int32

View File

@ -7,37 +7,27 @@
* Leland Stanford Junior University.
*
*
* $Id: config.c,v 1.6 1994/08/24 23:52:54 thyagara Exp $
* $Id: config.c,v 3.6 1995/06/25 18:50:37 fenner Exp $
*/
#include "defs.h"
char *configfilename = "/etc/mrouted.conf";
extern int cache_lifetime;
extern int max_prune_lifetime;
/*
* Forward declarations.
*/
static char *next_word();
/*
* Query the kernel to find network interfaces that are multicast-capable
* and install them in the uvifs array.
*/
void config_vifs_from_kernel()
void
config_vifs_from_kernel()
{
struct ifreq ifbuf[32];
struct ifreq *ifrp, *ifend, *mp;
struct ifreq *ifrp, *ifend;
struct ifconf ifc;
register struct uvif *v;
register vifi_t vifi;
int i, n;
u_long addr, mask, subnet;
int n;
u_int32 addr, mask, subnet;
short flags;
ifc.ifc_buf = (char *)ifbuf;
@ -62,10 +52,11 @@ void config_vifs_from_kernel()
/*
* Ignore any interface for an address family other than IP.
*/
addr = ((struct sockaddr_in *)&ifrp->ifr_addr)->sin_addr.s_addr;
if (ifrp->ifr_addr.sa_family != AF_INET)
continue;
addr = ((struct sockaddr_in *)&ifrp->ifr_addr)->sin_addr.s_addr;
/*
* Need a template to preserve address info that is
* used below to locate the next entry. (Otherwise,
@ -96,8 +87,8 @@ void config_vifs_from_kernel()
addr == subnet ||
addr == (subnet | ~mask)) {
log(LOG_WARNING, 0,
"ignoring %s, has invalid address (%s) and/or mask (%08x)",
ifr.ifr_name, inet_fmt(addr, s1), ntohl(mask));
"ignoring %s, has invalid address (%s) and/or mask (%s)",
ifr.ifr_name, inet_fmt(addr, s1), inet_fmt(mask, s2));
continue;
}
@ -125,7 +116,7 @@ void config_vifs_from_kernel()
v = &uvifs[numvifs];
v->uv_flags = 0;
v->uv_metric = DEFAULT_METRIC;
v->uv_rate_limit = DEFAULT_RATE_LIMIT;
v->uv_rate_limit = DEFAULT_PHY_RATE_LIMIT;
v->uv_threshold = DEFAULT_THRESHOLD;
v->uv_lcl_addr = addr;
v->uv_rmt_addr = 0;
@ -136,6 +127,7 @@ void config_vifs_from_kernel()
v->uv_groups = NULL;
v->uv_neighbors = NULL;
v->uv_acl = NULL;
v->uv_addrs = NULL;
log(LOG_INFO,0,"installing %s (%s on subnet %s) as vif #%u - rate=%d",
v->uv_name, inet_fmt(addr, s1), inet_fmts(subnet, mask, s2),
@ -153,644 +145,3 @@ void config_vifs_from_kernel()
}
}
}
static struct ifreq *
ifconfaddr(ifcp, a)
struct ifconf *ifcp;
u_long a;
{
int n;
struct ifreq *ifrp = (struct ifreq *)ifcp->ifc_buf;
struct ifreq *ifend = (struct ifreq *)((char *)ifrp + ifcp->ifc_len);
while (ifrp < ifend) {
if (ifrp->ifr_addr.sa_family == AF_INET &&
((struct sockaddr_in *)&ifrp->ifr_addr)->sin_addr.s_addr == a)
return (ifrp);
#if BSD >= 199006
n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name);
if (n < sizeof(*ifrp))
++ifrp;
else
ifrp = (struct ifreq *)((char *)ifrp + n);
#else
++ifrp;
#endif
}
return (0);
}
/*
* Checks if the string constitutes a valid interface name
*/
static u_long valid_if(w)
char *w;
{
register vifi_t vifi;
register struct uvif *v;
for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++)
if (EQUAL(v->uv_name, w))
return v->uv_lcl_addr;
return NULL;
}
/*
* Read the config file to learn about tunnel vifs and
* non-default phyint parameters.
*/
void config_vifs_from_file()
{
FILE *f;
char linebuf[100];
char *w, *s, c;
u_long lcl_addr, rmt_addr;
struct ifconf ifc;
struct ifreq *ifr;
struct ifreq ffr;
int i;
u_int n;
struct ifreq ifbuf[32];
vifi_t vifi;
struct uvif *v;
u_char order = 0;
vifi_t prev_vif = NO_VIF;
f = fopen(configfilename, "r");
if (f == NULL) {
if (errno != ENOENT)
log(LOG_ERR, errno, "can't open %s", configfilename);
return;
}
ifc.ifc_buf = (char *)ifbuf;
ifc.ifc_len = sizeof(ifbuf);
if (ioctl(udp_socket, SIOCGIFCONF, (char *)&ifc) < 0)
log(LOG_ERR, errno, "ioctl SIOCGIFCONF");
while (fgets(linebuf, sizeof(linebuf), f) != NULL) {
s = linebuf;
if (EQUAL((w = next_word(&s)), "")) {
/*
* blank or comment line; ignore
*/
}
/* Set the cache_lifetime for kernel entries */
else if (EQUAL(w, "cache_lifetime")) {
if (EQUAL((w = next_word(&s)), "")) {
log(LOG_ERR, 0,
"missing cache_lifetime value in %s",
configfilename);
continue;
}
if(sscanf(w, "%u%c", &n, &c) != 1 ||
n < 300 || n > 86400 ) {
log(LOG_ERR, 0,
"invalid cache_lifetime '%s' (300<n>86400) in %s",
w, configfilename);
break;
}
prev_vif = NO_VIF;
cache_lifetime = n;
max_prune_lifetime = cache_lifetime * 2;
}
/* Check if pruning is to be turned off */
else if (EQUAL(w, "pruning")) {
if (!EQUAL((w = next_word(&s)), "off") &&
!EQUAL(w, "on")) {
log(LOG_ERR, 0,
"invalid word '%s' in %s",
w, configfilename);
continue;
}
if (EQUAL(w, "off"))
pruning = 0;
prev_vif = NO_VIF;
}
/* Check for boundary statements (as continuation of a prev. line) */
else if (EQUAL(w, "boundary") && prev_vif != NO_VIF) {
register struct vif_acl *v_acl;
register u_long baddr;
v = &uvifs[prev_vif];
if (EQUAL((w = next_word(&s)), "")) {
log(LOG_ERR, 0,
"missing group address for boundary %s in %s",
inet_fmt(lcl_addr, s1), configfilename);
w = "garbage";
break;
}
if ((sscanf(w, "%[0-9.]/%d", s1, &n) != 2) ||
n < 0 || n> 32) {
log(LOG_ERR, 0,
"incorrect boundary format %s in %s",
w, configfilename);
w = "garbage";
break;
}
if ((baddr = inet_parse(s1)) == 0xffffffff ||
(baddr & 0xff000000) != 0xef000000) {
log(LOG_ERR, 0,
"incorrect boundary address %s in %s",
s1, configfilename);
continue;
}
v_acl = (struct vif_acl *)malloc(sizeof(struct vif_acl));
if (v_acl == NULL)
log(LOG_ERR, 0,
"out of memory");
VAL_TO_MASK(v_acl->acl_mask, n);
v_acl->acl_addr = baddr & v_acl->acl_mask;
/*
* link into data structure
*/
v_acl->acl_next = v->uv_acl;
v->uv_acl = v_acl;
}
else if (EQUAL(w, "phyint")) {
/*
* phyint <local-addr> [disable] [metric <m>] [threshold <t>]
* [rate_limit <b>]
*/
/*
* Check if phyint was the first line - scream if not
*/
if (order) {
log(LOG_ERR, 0,
"phyint stmnts should occur before tunnel stmnts in %s",
configfilename);
continue;
}
/*
* Parse the local address.
*/
if (EQUAL((w = next_word(&s)), "")) {
log(LOG_ERR, 0,
"missing phyint address in %s",
configfilename);
continue;
}
if (isalpha(*w) && !(lcl_addr = valid_if(w))) {
log(LOG_ERR, 0,
"invalid phyint name '%s' in %s",
w, configfilename);
continue;
}
if (isdigit(*w)) {
if ((lcl_addr = inet_parse(w)) == 0xffffffff ||
!inet_valid_host(lcl_addr)) {
log(LOG_ERR, 0,
"invalid phyint address '%s' in %s",
w, configfilename);
continue;
}
}
/*
* Look up the vif with the specified local address.
*/
for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
if (!(v->uv_flags & VIFF_TUNNEL) &&
lcl_addr == v->uv_lcl_addr) {
break;
}
}
if (vifi == numvifs) {
log(LOG_ERR, 0,
"phyint %s in %s is not a configured interface",
inet_fmt(lcl_addr, s1), configfilename);
continue;
}
/*
* Look for "disable", "metric", "threshold", "rate_limit"
* and "boundary" options.
*/
prev_vif = vifi;
while (!EQUAL((w = next_word(&s)), "")) {
if (EQUAL(w, "disable")) {
v->uv_flags |= VIFF_DISABLED;
}
else if (EQUAL(w, "metric")) {
if(EQUAL((w = next_word(&s)), "")) {
log(LOG_ERR, 0,
"missing metric for phyint %s in %s",
inet_fmt(lcl_addr, s1), configfilename);
w = "garbage";
break;
}
if(sscanf(w, "%u%c", &n, &c) != 1 ||
n < 1 || n >= UNREACHABLE ) {
log(LOG_ERR, 0,
"invalid metric '%s' for phyint %s in %s",
w, inet_fmt(lcl_addr, s1), configfilename);
break;
}
v->uv_metric = n;
}
else if (EQUAL(w, "threshold")) {
if(EQUAL((w = next_word(&s)), "")) {
log(LOG_ERR, 0,
"missing threshold for phyint %s in %s",
inet_fmt(lcl_addr, s1), configfilename);
w = "garbage";
break;
}
if(sscanf(w, "%u%c", &n, &c) != 1 ||
n < 1 || n > 255 ) {
log(LOG_ERR, 0,
"invalid threshold '%s' for phyint %s in %s",
w, inet_fmt(lcl_addr, s1), configfilename);
break;
}
v->uv_threshold = n;
}
else if (EQUAL(w, "rate_limit")) {
if (EQUAL((w = next_word(&s)), "")) {
log(LOG_ERR, 0,
"missing rate_limit for phyint %s in %s",
inet_fmt(rmt_addr, s1), configfilename);
w = "garbage";
break;
}
if(sscanf(w, "%u%c", &n, &c) != 1 ||
n < 0 || n > MAX_RATE_LIMIT ) {
log(LOG_ERR, 0,
"invalid rate limit '%s' for phyint %s in %s",
w, inet_fmt(lcl_addr, s1), configfilename);
break;
}
v->uv_rate_limit = n;
}
else if (EQUAL(w, "boundary")) {
register struct vif_acl *v_acl;
register u_long baddr;
if (EQUAL((w = next_word(&s)), "")) {
log(LOG_ERR, 0,
"missing group address for boundary %s in %s",
inet_fmt(lcl_addr, s1), configfilename);
w = "garbage";
break;
}
if ((sscanf(w, "%[0-9.]/%d", s1, &n) != 2) ||
n < 0 || n> 32) {
log(LOG_ERR, 0,
"incorrect boundary format %s in %s",
w, configfilename);
w = "garbage";
break;
}
if ((baddr = inet_parse(s1)) == 0xffffffff ||
(baddr & 0xef000000) != 0xef000000) {
log(LOG_ERR, 0,
"incorrect boundary address %s in %s",
s1, configfilename);
continue;
}
v_acl = (struct vif_acl *)malloc(sizeof(struct vif_acl));
if (v_acl == NULL)
log(LOG_ERR, 0,
"out of memory");
VAL_TO_MASK(v_acl->acl_mask, n);
v_acl->acl_addr = baddr & v_acl->acl_mask;
/*
* link into data structure
*/
v_acl->acl_next = v->uv_acl;
v->uv_acl = v_acl;
}
else {
log(LOG_ERR, 0,
"invalid keyword (%s) in %s",
w, configfilename);
break;
}
}
if (!EQUAL(w, "")) continue;
}
else if (EQUAL(w, "tunnel")) {
/*
* tunnel <local-addr> <remote-addr> [srcrt] [metric <m>]
* [threshold <t>] [rate_limit <b>]
*/
order++;
/*
* Parse the local address.
*/
if (EQUAL((w = next_word(&s)), "")) {
log(LOG_ERR, 0,
"missing tunnel local address in %s",
configfilename);
continue;
}
if ((lcl_addr = inet_parse(w)) == 0xffffffff ||
!inet_valid_host(lcl_addr)) {
log(LOG_ERR, 0,
"invalid tunnel local address '%s' in %s",
w, configfilename);
continue;
}
/*
* Make sure the local address is one of ours.
*/
ifr = ifconfaddr(&ifc, lcl_addr);
if (ifr == 0) {
log(LOG_ERR, 0,
"tunnel local address %s in %s is not one of ours",
inet_fmt(lcl_addr, s1), configfilename);
continue;
}
/*
* Make sure the local address doesn't name a loopback interface..
*/
strncpy(ffr.ifr_name, ifr->ifr_name, IFNAMSIZ);
if (ioctl(udp_socket, SIOCGIFFLAGS, (char *)&ffr) < 0) {
log(LOG_ERR, errno,
"ioctl SIOCGIFFLAGS for %s", ffr.ifr_name);
}
if (ffr.ifr_flags & IFF_LOOPBACK) {
log(LOG_ERR, 0,
"tunnel local address %s in %s is a loopback interface",
inet_fmt(lcl_addr, s1), configfilename);
continue;
}
/*
* Parse the remote address.
*/
if (EQUAL((w = next_word(&s)), "")) {
log(LOG_ERR, 0,
"missing tunnel remote address in %s",
configfilename);
continue;
}
if ((rmt_addr = inet_parse(w)) == 0xffffffff ||
!inet_valid_host(rmt_addr)) {
log(LOG_ERR, 0,
"invalid tunnel remote address %s in %s",
w, configfilename);
continue;
}
/*
* Make sure the remote address is not one of ours.
*/
if (ifconfaddr(&ifc, rmt_addr) != 0) {
log(LOG_ERR, 0,
"tunnel remote address %s in %s is one of ours",
inet_fmt(rmt_addr, s1), configfilename);
continue;
}
/*
* Make sure the remote address has not been used for another
* tunnel and does not belong to a subnet to which we have direct
* access on an enabled phyint.
*/
for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
if (v->uv_flags & VIFF_TUNNEL) {
if (rmt_addr == v->uv_rmt_addr) {
log(LOG_ERR, 0,
"duplicate tunnel remote address %s in %s",
inet_fmt(rmt_addr, s1), configfilename);
break;
}
}
else if (!(v->uv_flags & VIFF_DISABLED)) {
if ((rmt_addr & v->uv_subnetmask) == v->uv_subnet) {
log(LOG_ERR, 0,
"unnecessary tunnel remote address %s in %s",
inet_fmt(rmt_addr, s1), configfilename);
break;
}
}
}
if (vifi != numvifs) continue;
/*
* OK, let's initialize a uvif structure for the tunnel.
*/
if (numvifs == MAXVIFS) {
log(LOG_ERR, 0, "too many vifs, ignoring tunnel to %s",
inet_fmt(rmt_addr, s1));
continue;
}
v = &uvifs[numvifs];
v->uv_flags = VIFF_TUNNEL;
v->uv_metric = DEFAULT_METRIC;
v->uv_rate_limit = DEFAULT_RATE_LIMIT;
v->uv_threshold = DEFAULT_THRESHOLD;
v->uv_lcl_addr = lcl_addr;
v->uv_rmt_addr = rmt_addr;
v->uv_subnet = 0;
v->uv_subnetmask = 0;
v->uv_subnetbcast = 0;
strncpy(v->uv_name, ffr.ifr_name, IFNAMSIZ);
v->uv_groups = NULL;
v->uv_neighbors = NULL;
v->uv_acl = NULL;
/*
* set variable to define which interface
*/
prev_vif = numvifs;
/*
* Look for "metric", "threshold", "srcrt", "rate_limit"
* and "boundary" options.
*/
while (!EQUAL((w = next_word(&s)), "")) {
if (EQUAL(w, "metric")) {
if(EQUAL((w = next_word(&s)), "")) {
log(LOG_ERR, 0,
"missing metric for tunnel to %s in %s",
inet_fmt(rmt_addr, s1), configfilename);
w = "garbage";
break;
}
if(sscanf(w, "%u%c", &n, &c) != 1 ||
n < 1 || n >= UNREACHABLE ) {
log(LOG_ERR, 0,
"invalid metric '%s' for tunnel to %s in %s",
w, inet_fmt(rmt_addr, s1), configfilename);
break;
}
v->uv_metric = n;
}
else if (EQUAL(w, "threshold")) {
if(EQUAL((w = next_word(&s)), "")) {
log(LOG_ERR, 0,
"missing threshold for tunnel to %s in %s",
inet_fmt(rmt_addr, s1), configfilename);
w = "garbage";
break;
}
if(sscanf(w, "%u%c", &n, &c) != 1 ||
n < 1 || n > 255 ) {
log(LOG_ERR, 0,
"invalid threshold '%s' for tunnel to %s in %s",
w, inet_fmt(rmt_addr, s1), configfilename);
break;
}
v->uv_threshold = n;
}
else if (EQUAL(w, "srcrt") || EQUAL(w, "sourceroute")) {
v->uv_flags |= VIFF_SRCRT;
}
else if (EQUAL(w, "rate_limit")) {
if (EQUAL((w = next_word(&s)), "")) {
log(LOG_ERR, 0,
"missing rate_limit for tunnel to %s in %s",
inet_fmt(rmt_addr, s1), configfilename);
w = "garbage";
break;
}
if(sscanf(w, "%u%c", &n, &c) != 1 ||
n < 0 || n > MAX_RATE_LIMIT ) {
log(LOG_ERR, 0,
"invalid rate_limit '%s' for tunnel to %s in %s",
w, inet_fmt(rmt_addr, s1), configfilename);
break;
}
v->uv_rate_limit = n;
}
else if (EQUAL(w, "boundary")) {
register struct vif_acl *v_acl;
register u_long baddr;
if (EQUAL((w = next_word(&s)), "")) {
log(LOG_ERR, 0,
"missing group address for tunnel to %s in %s",
inet_fmt(rmt_addr, s1), configfilename);
w = "garbage";
break;
}
if ((sscanf(w, "%[0-9.]/%d", s1, &n) != 2) ||
n < 0 || n> 32) {
log(LOG_ERR, 0,
"incorrect format '%s' for tunnel to %s in %s",
w, inet_fmt(rmt_addr, s1), configfilename);
break;
}
if ((baddr = inet_parse(s1)) == 0xffffffff ||
(baddr & 0xef000000) != 0xef000000) {
log(LOG_ERR, 0,
"incorrect address %s for tunnel to %s in %s",
s1, inet_fmt(rmt_addr, s1), configfilename);
continue;
}
v_acl = (struct vif_acl *)malloc(sizeof(struct vif_acl));
if (v_acl == NULL)
log(LOG_ERR, 0,
"out of memory");
VAL_TO_MASK(v_acl->acl_mask, n);
v_acl->acl_addr = baddr & v_acl->acl_mask;
/*
* link into data structure
*/
v_acl->acl_next = v->uv_acl;
v->uv_acl = v_acl;
}
else {
log(LOG_ERR, 0,
"invalid keyword (%s) in %s",
w, configfilename);
break;
}
}
if (!EQUAL(w, "")) continue;
log(LOG_INFO, 0,
"installing %stunnel from %s to %s as vif #%u - rate=%d",
v->uv_flags & VIFF_SRCRT? "srcrt " : "",
inet_fmt(lcl_addr, s1), inet_fmt(rmt_addr, s2),
numvifs, v->uv_rate_limit);
++numvifs;
if (!(ffr.ifr_flags & IFF_UP)) {
v->uv_flags |= VIFF_DOWN;
vifs_down = TRUE;
}
}
else {
log(LOG_ERR, 0,
"unknown command '%s' in %s", w, configfilename);
}
}
close(f);
}
/*
* Return a pointer to the next "word" in the string to which '*s' points,
* lower-cased and null terminated, and advance '*s' to point beyond the word.
* Words are separated by blanks and/or tabs, and the input string is
* considered to terminate at a newline, '#' (comment), or null character.
* If no words remain, a pointer to a null string ("") is returned.
* Warning: This function clobbers the input string.
*/
static char *next_word(s)
char **s;
{
char *w;
w = *s;
while (*w == ' ' || *w == '\t')
++w;
*s = w;
for(;;) {
switch (**s) {
case ' ' :
case '\t' : **s = '\0';
++*s;
return (w);
case '\n' :
case '#' : **s = '\0';
return (w);
case '\0' : return (w);
default : if (isascii(**s) && isupper(**s))
**s = tolower(**s);
++*s;
}
}
}

View File

@ -7,15 +7,18 @@
* Leland Stanford Junior University.
*
*
* $Id: defs.h,v 1.8 1994/08/24 23:53:23 thyagara Exp $
* $Id: defs.h,v 3.6.1.1 1995/06/26 00:18:18 fenner Exp $
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>
#include <errno.h>
#include <syslog.h>
#include <signal.h>
#include <string.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/socket.h>
@ -27,11 +30,33 @@
#include <netinet/ip.h>
#include <netinet/igmp.h>
#include <netinet/ip_mroute.h>
#ifdef RSRR
#include <sys/un.h>
#endif /* RSRR */
/*XXX*/
typedef u_int u_int32;
#ifndef __P
#ifdef __STDC__
#define __P(x) x
#else
#define __P(x) ()
#endif
#endif
typedef void (*cfunc_t) __P((void *));
typedef void (*ihfunc_t) __P((fd_set *));
#include "dvmrp.h"
#include "vif.h"
#include "route.h"
#include "prune.h"
#include "pathnames.h"
#ifdef RSRR
#include "rsrr.h"
#include "rsrr_var.h"
#endif /* RSRR */
/*
* Miscellaneous constants and macros.
@ -45,25 +70,48 @@
#define PROTOCOL_VERSION 3 /* increment when packet format/content changes */
#define MROUTED_VERSION 3 /* increment on local changes or bug fixes, */
#define MROUTED_VERSION 6 /* increment on local changes or bug fixes, */
/* reset to 0 whever PROTOCOL_VERSION increments */
#define MROUTED_LEVEL ( (MROUTED_VERSION << 8) | PROTOCOL_VERSION )
#define MROUTED_LEVEL ( (MROUTED_VERSION << 8) | PROTOCOL_VERSION | \
((NF_PRUNE | NF_GENID | NF_MTRACE) << 16))
/* for IGMP 'group' field of DVMRP messages */
#define LEAF_FLAGS (( vifs_with_neighbors == 1 ) ? 0x010000 : 0)
/* more for IGMP 'group' field of DVMRP messages */
#define DEL_RTE_GROUP 0
#define DEL_ALL_ROUTES 1
/* for Deleting kernel table entries */
/* obnoxious gcc gives an extraneous warning about this constant... */
#if defined(__STDC__) || defined(__GNUC__)
#define JAN_1970 2208988800UL /* 1970 - 1900 in seconds */
#else
#define JAN_1970 2208988800L /* 1970 - 1900 in seconds */
#define const /**/
#endif
#ifdef RSRR
#define BIT_ZERO(X) ((X) = 0)
#define BIT_SET(X,n) ((X) |= 1 << (n))
#define BIT_CLR(X,n) ((X) &= ~(1 << (n)))
#define BIT_TST(X,n) ((X) & 1 << (n))
#endif /* RSRR */
/*
* External declarations for global variables and functions.
*/
extern char recv_buf[MAX_IP_PACKET_LEN];
extern char send_buf[MAX_IP_PACKET_LEN];
#define RECV_BUF_SIZE MAX_IP_PACKET_LEN
extern char *recv_buf;
extern char *send_buf;
extern int igmp_socket;
extern u_long allhosts_group;
extern u_long dvmrp_group;
extern u_long dvmrp_genid;
#ifdef RSRR
extern int rsrr_socket;
#endif /* RSRR */
extern u_int32 allhosts_group;
extern u_int32 allrtrs_group;
extern u_int32 dvmrp_group;
extern u_int32 dvmrp_genid;
#define DEFAULT_DEBUG 2 /* default if "-d" given without value */
@ -78,93 +126,167 @@ extern struct uvif uvifs[MAXVIFS];
extern vifi_t numvifs;
extern int vifs_down;
extern int udp_socket;
extern int vifs_with_neighbors;
extern char s1[];
extern char s2[];
extern char s3[];
extern char s4[];
#if !(defined(BSD) && (BSD >= 199103))
extern int errno;
extern int sys_nerr;
extern char * sys_errlist[];
extern void log();
extern void init_igmp();
extern void accept_igmp();
extern void send_igmp();
extern void init_routes();
extern void start_route_updates();
extern void update_route();
extern void age_routes();
extern void expire_all_routes();
extern void free_all_routes();
extern void accept_probe();
extern void accept_report();
extern void report();
extern void report_to_all_neighbors();
extern int report_next_chunk();
extern void add_vif_to_routes();
extern void delete_vif_from_routes();
extern void delete_neighbor_from_routes();
extern void dump_routes();
extern void init_vifs();
extern void check_vif_state();
extern vifi_t find_vif();
extern void age_vifs();
extern void dump_vifs();
extern void stop_all_vifs();
extern void accept_group_report();
extern void query_groups();
extern void probe_for_neighbors();
extern int update_neighbor();
extern void accept_neighbor_request();
extern void config_vifs_from_kernel();
extern void config_vifs_from_file();
extern int inet_valid_host();
extern int inet_valid_subnet();
extern char * inet_fmt();
extern char * inet_fmts();
extern u_long inet_parse();
extern int inet_cksum();
extern struct rtentry * determine_route();
extern void init_ktable();
extern int grplst_mem();
extern void add_table_entry();
extern void del_table_entry();
extern void update_table_entry();
extern void update_lclgrp();
extern void delete_lclgrp();
extern unsigned kroutes;
extern void send_prune();
extern void accept_prune();
extern int no_entry_exists();
extern struct ktable * find_src_grp();
extern int rtr_cnt();
extern void free_all_prunes();
extern void age_table_entry();
extern void dump_cache();
extern void chkgrp_graft();
extern void accept_graft();
extern void send_graft_ack();
extern void send_graft();
extern void accept_g_ack();
extern void mtrace();
extern char * malloc();
extern char * fgets();
extern FILE * fopen();
#ifndef htonl
extern u_long htonl();
extern u_long ntohl();
#endif
/* main.c */
extern void log __P((int, int, char *, ...));
extern int register_input_handler __P((int fd, ihfunc_t func));
/* igmp.c */
extern void init_igmp __P((void));
extern void accept_igmp __P((int recvlen));
extern void send_igmp __P((u_int32 src, u_int32 dst, int type,
int code, u_int32 group,
int datalen));
/* callout.c */
extern void callout_init __P((void));
extern void age_callout_queue __P((void));
extern int timer_setTimer __P((int delay, cfunc_t action,
char *data));
extern void timer_clearTimer __P((int timer_id));
/* route.c */
extern void init_routes __P((void));
extern void start_route_updates __P((void));
extern void update_route __P((u_int32 origin, u_int32 mask,
int metric, u_int32 src,
vifi_t vifi));
extern void age_routes __P((void));
extern void expire_all_routes __P((void));
extern void free_all_routes __P((void));
extern void accept_probe __P((u_int32 src, u_int32 dst,
char *p, int datalen,
u_int32 level));
extern void accept_report __P((u_int32 src, u_int32 dst,
char *p, int datalen,
u_int32 level));
extern struct rtentry * determine_route __P((u_int32 src));
extern void report __P((int which_routes, vifi_t vifi,
u_int32 dst));
extern void report_to_all_neighbors __P((int which_routes));
extern int report_next_chunk __P((void));
extern void add_vif_to_routes __P((vifi_t vifi));
extern void delete_vif_from_routes __P((vifi_t vifi));
extern void delete_neighbor_from_routes __P((u_int32 addr,
vifi_t vifi));
extern void dump_routes __P((FILE *fp));
extern void start_route_updates __P((void));
/* vif.c */
extern void init_vifs __P((void));
extern void check_vif_state __P((void));
extern vifi_t find_vif __P((u_int32 src, u_int32 dst));
extern void age_vifs __P((void));
extern void dump_vifs __P((FILE *fp));
extern void stop_all_vifs __P((void));
extern struct listaddr *neighbor_info __P((vifi_t vifi, u_int32 addr));
extern void accept_group_report __P((u_int32 src, u_int32 dst,
u_int32 group, int r_type));
extern void query_groups __P((void));
extern void probe_for_neighbors __P((void));
extern int update_neighbor __P((vifi_t vifi, u_int32 addr,
int msgtype, char *p, int datalen,
u_int32 level));
extern void accept_neighbor_request __P((u_int32 src, u_int32 dst));
extern void accept_neighbor_request2 __P((u_int32 src,
u_int32 dst));
extern void accept_neighbors __P((u_int32 src, u_int32 dst,
u_char *p, int datalen, u_int32 level));
extern void accept_neighbors2 __P((u_int32 src, u_int32 dst,
u_char *p, int datalen, u_int32 level));
extern void accept_leave_message __P((u_int32 src, u_int32 dst,
u_int32 group));
extern void accept_membership_query __P((u_int32 src, u_int32 dst,
u_int32 group, int tmo));
/* config.c */
extern void config_vifs_from_kernel __P((void));
/* cfparse.y */
extern void config_vifs_from_file __P((void));
/* inet.c */
extern int inet_valid_host __P((u_int32 naddr));
extern int inet_valid_subnet __P((u_int32 nsubnet, u_int32 nmask));
extern char * inet_fmt __P((u_int32 addr, char *s));
extern char * inet_fmts __P((u_int32 addr, u_int32 mask, char *s));
extern u_int32 inet_parse __P((char *s));
extern int inet_cksum __P((u_short *addr, u_int len));
/* prune.c */
extern unsigned kroutes;
extern void add_table_entry __P((u_int32 origin, u_int32 mcastgrp));
extern void del_table_entry __P((struct rtentry *r,
u_int32 mcastgrp, u_int del_flag));
extern void update_table_entry __P((struct rtentry *r));
extern void init_ktable __P((void));
extern void accept_prune __P((u_int32 src, u_int32 dst, char *p,
int datalen));
extern void steal_sources __P((struct rtentry *rt));
extern void reset_neighbor_state __P((vifi_t vifi, u_int32 addr));
extern int grplst_mem __P((vifi_t vifi, u_int32 mcastgrp));
extern int scoped_addr __P((vifi_t vifi, u_int32 addr));
extern void free_all_prunes __P((void));
extern void age_table_entry __P((void));
extern void dump_cache __P((FILE *fp2));
extern void update_lclgrp __P((vifi_t vifi, u_int32 mcastgrp));
extern void delete_lclgrp __P((vifi_t vifi, u_int32 mcastgrp));
extern void chkgrp_graft __P((vifi_t vifi, u_int32 mcastgrp));
extern void accept_graft __P((u_int32 src, u_int32 dst, char *p,
int datalen));
extern void accept_g_ack __P((u_int32 src, u_int32 dst, char *p,
int datalen));
/* u_int is promoted u_char */
extern void accept_mtrace __P((u_int32 src, u_int32 dst,
u_int32 group, char *data, u_int no,
int datalen));
/* kern.c */
extern void k_set_rcvbuf __P((int bufsize));
extern void k_hdr_include __P((int bool));
extern void k_set_ttl __P((int t));
extern void k_set_loop __P((int l));
extern void k_set_if __P((u_int32 ifa));
extern void k_join __P((u_int32 grp, u_int32 ifa));
extern void k_leave __P((u_int32 grp, u_int32 ifa));
extern void k_init_dvmrp __P((void));
extern void k_stop_dvmrp __P((void));
extern void k_add_vif __P((vifi_t vifi, struct uvif *v));
extern void k_del_vif __P((vifi_t vifi));
extern void k_add_rg __P((u_int32 origin, struct gtable *g));
extern int k_del_rg __P((u_int32 origin, struct gtable *g));
extern int k_get_version __P((void));
#ifdef SNMP
/* prune.c */
extern struct rtentry * snmp_find_route __P(());
extern struct gtable * find_grp __P(());
extern struct stable * find_grp_src __P(());
#endif
#ifdef RSRR
/* prune.c */
extern struct gtable *kernel_table;
extern struct gtable *gtp;
extern int find_src_grp __P((u_int32 src, u_int32 mask,
u_int32 grp));
/* rsrr.c */
extern void rsrr_init __P((void));
extern void rsrr_read __P((fd_set *rfd));
extern void rsrr_clean __P((void));
extern void rsrr_cache_send __P((struct gtable *gt, int notify));
extern void rsrr_cache_clean __P((struct gtable *gt));
#endif /* RSRR */

View File

@ -7,7 +7,7 @@
* Leland Stanford Junior University.
*
*
* $Id: dvmrp.h,v 1.6 1994/08/24 23:53:30 thyagara Exp $
* $Id: dvmrp.h,v 3.6 1995/06/25 18:52:10 fenner Exp $
*/
/*
@ -102,9 +102,11 @@
*/
#define DVMRP_NF_TUNNEL 0x01 /* neighbors reached via tunnel */
#define DVMRP_NF_SRCRT 0x02 /* tunnel uses IP source routing */
#define DVMRP_NF_PIM 0x04 /* neighbor is a PIM neighbor */
#define DVMRP_NF_DOWN 0x10 /* kernel state of interface */
#define DVMRP_NF_DISABLED 0x20 /* administratively disabled */
#define DVMRP_NF_QUERIER 0x40 /* I am the subnet's querier */
#define DVMRP_NF_LEAF 0x80 /* Neighbor reports that it is a leaf */
/*
* Limit on length of route data
@ -119,7 +121,9 @@
* Various protocol constants (all times in seconds)
*/
/* address for multicast DVMRP msgs */
#define INADDR_DVMRP_GROUP (u_long)0xe0000004 /* 224.0.0.4 */
#define INADDR_DVMRP_GROUP (u_int32)0xe0000004 /* 224.0.0.4 */
/* address for multicast mtrace msg */
#define INADDR_ALLRTRS_GROUP (u_int32)0xe0000002 /* 224.0.0.2 */
#define ROUTE_MAX_REPORT_DELAY 5 /* max delay for reporting changes */
/* (This is the timer interrupt */
@ -138,13 +142,18 @@
#define GROUP_QUERY_INTERVAL 125 /* periodic group query interval */
#define GROUP_EXPIRE_TIME 270 /* time to consider group gone */
#define LEAVE_EXPIRE_TIME 3 /* " " after receiving a leave */
/* Note: LEAVE_EXPIRE_TIME should ideally be shorter, but the resolution of
* the timer in mrouted doesn't allow us to follow the spec and make it any
* shorter. */
#define UNREACHABLE 32 /* "infinity" metric, must be <= 64 */
#define DEFAULT_METRIC 1 /* default subnet/tunnel metric */
#define DEFAULT_THRESHOLD 1 /* default subnet/tunnel threshold */
#define MAX_RATE_LIMIT 100000 /* max rate limit */
#define DEFAULT_RATE_LIMIT 0 /* default rate limit */
#define MAX_RATE_LIMIT 100000 /* max rate limit */
#define DEFAULT_PHY_RATE_LIMIT 0 /* default phyint rate limit */
#define DEFAULT_TUN_RATE_LIMIT 500 /* default tunnel rate limit */
#define DEFAULT_CACHE_LIFETIME 300 /* kernel route entry discard time */
#define GRAFT_TIMEOUT_VAL 5 /* retransmission time for grafts */

View File

@ -7,7 +7,7 @@
* Leland Stanford Junior University.
*
*
* $Id: igmp.c,v 1.8 1994/08/24 23:53:32 thyagara Exp $
* $Id: igmp.c,v 3.6 1995/06/25 18:52:55 fenner Exp $
*/
@ -17,21 +17,33 @@
/*
* Exported variables.
*/
char recv_buf[MAX_IP_PACKET_LEN]; /* input packet buffer */
char send_buf[MAX_IP_PACKET_LEN]; /* output packet buffer */
char *recv_buf; /* input packet buffer */
char *send_buf; /* output packet buffer */
int igmp_socket; /* socket for all network I/O */
u_long allhosts_group; /* allhosts addr in net order */
u_long dvmrp_group; /* DVMRP grp addr in net order */
u_long dvmrp_genid; /* IGMP generation id */
u_int32 allhosts_group; /* All hosts addr in net order */
u_int32 allrtrs_group; /* All-Routers " in net order */
u_int32 dvmrp_group; /* DVMRP grp addr in net order */
u_int32 dvmrp_genid; /* IGMP generation id */
/*
* Local function definitions.
*/
/* u_char promoted to u_int */
static char * packet_kind __P((u_int type, u_int code));
static int igmp_log_level __P((u_int type, u_int code));
/*
* Open and initialize the igmp socket, and fill in the non-changing
* IP header fields in the output packet buffer.
*/
void init_igmp()
void
init_igmp()
{
struct ip *ip;
recv_buf = malloc(RECV_BUF_SIZE);
send_buf = malloc(RECV_BUF_SIZE);
if ((igmp_socket = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP)) < 0)
log(LOG_ERR, errno, "IGMP socket");
@ -41,6 +53,8 @@ void init_igmp()
k_set_loop(FALSE); /* disable multicast loopback */
ip = (struct ip *)send_buf;
ip->ip_hl = sizeof(struct ip) >> 2;
ip->ip_v = IPVERSION;
ip->ip_tos = 0;
ip->ip_off = 0;
ip->ip_p = IPPROTO_IGMP;
@ -48,10 +62,9 @@ void init_igmp()
allhosts_group = htonl(INADDR_ALLHOSTS_GROUP);
dvmrp_group = htonl(INADDR_DVMRP_GROUP);
allrtrs_group = htonl(INADDR_ALLRTRS_GROUP);
}
/* %%% hack for PIM %%% */
#define IGMP_PIM 0x14
#define PIM_QUERY 0
#define PIM_REGISTER 1
#define PIM_REGISTER_STOP 2
@ -61,14 +74,15 @@ void init_igmp()
#define PIM_GRAFT 6
#define PIM_GRAFT_ACK 7
static char *packet_kind(type, code)
u_char type, code;
static char *
packet_kind(type, code)
u_int type, code;
{
switch (type) {
case IGMP_HOST_MEMBERSHIP_QUERY: return "membership query ";
case IGMP_HOST_MEMBERSHIP_REPORT: return "membership report ";
case IGMP_HOST_NEW_MEMBERSHIP_REPORT: return "new membership report ";
case IGMP_HOST_LEAVE_MESSAGE: return "leave message";
case IGMP_HOST_NEW_MEMBERSHIP_REPORT: return "new member report ";
case IGMP_HOST_LEAVE_MESSAGE: return "leave message ";
case IGMP_DVMRP:
switch (code) {
case DVMRP_PROBE: return "neighbor probe ";
@ -77,12 +91,12 @@ static char *packet_kind(type, code)
case DVMRP_NEIGHBORS: return "neighbor list ";
case DVMRP_ASK_NEIGHBORS2: return "neighbor request 2";
case DVMRP_NEIGHBORS2: return "neighbor list 2 ";
case DVMRP_PRUNE: return "prune message ";
case DVMRP_GRAFT: return "graft message ";
case DVMRP_PRUNE: return "prune message ";
case DVMRP_GRAFT: return "graft message ";
case DVMRP_GRAFT_ACK: return "graft message ack ";
default: return "unknown DVMRP msg ";
}
case IGMP_PIM: /* %%% hack for PIM %%% */
case IGMP_PIM:
switch (code) {
case PIM_QUERY: return "PIM Router-Query ";
case PIM_REGISTER: return "PIM Register ";
@ -104,11 +118,11 @@ static char *packet_kind(type, code)
* Process a newly received IGMP packet that is sitting in the input
* packet buffer.
*/
void accept_igmp(recvlen)
void
accept_igmp(recvlen)
int recvlen;
{
register vifi_t vifi;
register u_long src, dst, group;
register u_int32 src, dst, group;
struct ip *ip;
struct igmp *igmp;
int ipdatalen, iphdrlen, igmpdatalen;
@ -129,7 +143,7 @@ void accept_igmp(recvlen)
* necessary to install a route into the kernel for this.
*/
if (ip->ip_p == 0) {
if (src == NULL || dst == NULL)
if (src == 0 || dst == 0)
log(LOG_WARNING, 0, "kernel request not accurate");
else
add_table_entry(src, dst);
@ -162,21 +176,22 @@ void accept_igmp(recvlen)
switch (igmp->igmp_type) {
case IGMP_HOST_MEMBERSHIP_QUERY:
/* we have to do the determination of the querrier router here */
accept_membership_query(src, dst, group, igmp->igmp_code);
return;
case IGMP_HOST_MEMBERSHIP_REPORT:
case IGMP_HOST_NEW_MEMBERSHIP_REPORT:
accept_group_report(src, dst, group,igmp->igmp_type);
accept_group_report(src, dst, group, igmp->igmp_type);
return;
case IGMP_HOST_LEAVE_MESSAGE:
leave_group_message(src, dst, group);
accept_leave_message(src, dst, group);
return;
case IGMP_DVMRP:
switch (igmp->igmp_code) {
group = ntohl(group);
switch (igmp->igmp_code) {
case DVMRP_PROBE:
accept_probe(src, dst,
(char *)(igmp+1), igmpdatalen, group);
@ -196,13 +211,13 @@ void accept_igmp(recvlen)
return;
case DVMRP_NEIGHBORS:
accept_neighbors(src, dst, (char *)(igmp+1), igmpdatalen,
group);
accept_neighbors(src, dst, (u_char *)(igmp+1), igmpdatalen,
group);
return;
case DVMRP_NEIGHBORS2:
accept_neighbors2(src, dst, (char *)(igmp+1), igmpdatalen,
group);
accept_neighbors2(src, dst, (u_char *)(igmp+1), igmpdatalen,
group);
return;
case DVMRP_PRUNE:
@ -225,37 +240,63 @@ void accept_igmp(recvlen)
return;
}
case IGMP_PIM: /* %%% hack for PIM %%% */
case IGMP_PIM:
return;
case IGMP_MTRACE_RESP:
return;
case IGMP_MTRACE:
mtrace(src, dst, group, (char *)(igmp+1),
accept_mtrace(src, dst, group, (char *)(igmp+1),
igmp->igmp_code, igmpdatalen);
return;
default:
log(LOG_INFO, 0,
"ignoring unknown IGMP message type %u from %s to %s",
"ignoring unknown IGMP message type %x from %s to %s",
igmp->igmp_type, inet_fmt(src, s1),
inet_fmt(dst, s2));
return;
}
}
/*
* Some IGMP messages are more important than others. This routine
* determines the logging level at which to log a send error (often
* "No route to host"). This is important when there is asymmetric
* reachability and someone is trying to, i.e., mrinfo me periodically.
*/
static int
igmp_log_level(type, code)
u_int type, code;
{
switch (type) {
case IGMP_MTRACE_RESP:
return LOG_INFO;
case IGMP_DVMRP:
switch (code) {
case DVMRP_NEIGHBORS:
case DVMRP_NEIGHBORS2:
return LOG_INFO;
}
}
return LOG_WARNING;
}
/*
* Construct an IGMP message in the output packet buffer. The caller may
* have already placed data in that buffer, of length 'datalen'. Then send
* the message from the interface with IP address 'src' to destination 'dst'.
*/
void send_igmp(src, dst, type, code, group, datalen)
u_long src, dst;
void
send_igmp(src, dst, type, code, group, datalen)
u_int32 src, dst;
int type, code;
u_long group;
u_int32 group;
int datalen;
{
static struct sockaddr_in sdst = {AF_INET};
static struct sockaddr_in sdst;
struct ip *ip;
struct igmp *igmp;
@ -275,11 +316,20 @@ void send_igmp(src, dst, type, code, group, datalen)
if (IN_MULTICAST(ntohl(dst))) k_set_if(src);
if (dst == allhosts_group) k_set_loop(TRUE);
bzero(&sdst, sizeof(sdst));
sdst.sin_family = AF_INET;
#if (defined(BSD) && (BSD >= 199103))
sdst.sin_len = sizeof(sdst);
#endif
sdst.sin_addr.s_addr = dst;
if (sendto(igmp_socket, send_buf, ip->ip_len, 0,
(struct sockaddr *)&sdst, sizeof(sdst)) < 0) {
if (errno == ENETDOWN) check_vif_state();
else log(LOG_WARNING, errno, "sendto on %s", inet_fmt(src, s1));
if (errno == ENETDOWN)
check_vif_state();
else
log(igmp_log_level(type, code), errno,
"sendto to %s on %s",
inet_fmt(dst, s1), inet_fmt(src, s2));
}
if (dst == allhosts_group) k_set_loop(FALSE);

View File

@ -7,7 +7,7 @@
* Leland Stanford Junior University.
*
*
* $Id: inet.c,v 1.4 1993/05/30 01:36:38 deering Exp $
* $Id: inet.c,v 3.6 1995/06/25 18:54:45 fenner Exp $
*/
@ -17,9 +17,10 @@
/*
* Exported variables.
*/
char s1[16]; /* buffers to hold the string representations */
char s2[16]; /* of IP addresses, to be passed to inet_fmt() */
char s3[16]; /* or inet_fmts(). */
char s1[19]; /* buffers to hold the string representations */
char s2[19]; /* of IP addresses, to be passed to inet_fmt() */
char s3[19]; /* or inet_fmts(). */
char s4[19];
/*
@ -27,10 +28,11 @@ char s3[16]; /* or inet_fmts(). */
* (Without a mask, cannot detect addresses of the form {subnet,0} or
* {subnet,-1}.)
*/
int inet_valid_host(naddr)
u_long naddr;
int
inet_valid_host(naddr)
u_int32 naddr;
{
register u_long addr;
register u_int32 addr;
addr = ntohl(naddr);
@ -42,29 +44,39 @@ int inet_valid_host(naddr)
/*
* Verify that a given subnet number and mask pair are credible.
*
* With CIDR, almost any subnet and mask are credible. mrouted still
* can't handle aggregated class A's, so we still check that, but
* otherwise the only requirements are that the subnet address is
* within the [ABC] range and that the host bits of the subnet
* are all 0.
*/
int inet_valid_subnet(nsubnet, nmask)
u_long nsubnet, nmask;
int
inet_valid_subnet(nsubnet, nmask)
u_int32 nsubnet, nmask;
{
register u_long subnet, mask;
register u_int32 subnet, mask;
subnet = ntohl(nsubnet);
mask = ntohl(nmask);
if ((subnet & mask) != subnet) return (FALSE);
if (subnet == 0 && mask == 0)
return (TRUE);
if (IN_CLASSA(subnet)) {
if (mask < 0xff000000 ||
(subnet & 0xff000000) == 0 ||
(subnet & 0xff000000) == 0x7f000000) return (FALSE);
}
else if (IN_CLASSB(subnet)) {
if (mask < 0xffff0000) return (FALSE);
else if (IN_CLASSD(subnet) || IN_BADCLASS(subnet)) {
/* Above Class C address space */
return (FALSE);
}
else if (IN_CLASSC(subnet)) {
if (mask < 0xffffff00) return (FALSE);
else if (subnet & ~mask) {
/* Host bits are set in the subnet */
return (FALSE);
}
else return (FALSE);
return (TRUE);
}
@ -73,8 +85,9 @@ int inet_valid_subnet(nsubnet, nmask)
/*
* Convert an IP address in u_long (network) format into a printable string.
*/
char *inet_fmt(addr, s)
u_long addr;
char *
inet_fmt(addr, s)
u_int32 addr;
char *s;
{
register u_char *a;
@ -87,36 +100,44 @@ char *inet_fmt(addr, s)
/*
* Convert an IP subnet number in u_long (network) format into a printable
* string.
* string including the netmask as a number of bits.
*/
char *inet_fmts(addr, mask, s)
u_long addr, mask;
char *
inet_fmts(addr, mask, s)
u_int32 addr, mask;
char *s;
{
register u_char *a, *m;
int bits;
if ((addr == 0) && (mask == 0)) {
sprintf(s, "default");
return (s);
}
a = (u_char *)&addr;
m = (u_char *)&mask;
bits = 33 - ffs(ntohl(mask));
if (m[3] != 0) sprintf(s, "%u.%u.%u.%u", a[0], a[1], a[2], a[3]);
else if (m[2] != 0) sprintf(s, "%u.%u.%u", a[0], a[1], a[2]);
else if (m[1] != 0) sprintf(s, "%u.%u", a[0], a[1]);
else sprintf(s, "%u", a[0]);
if (m[3] != 0) sprintf(s, "%u.%u.%u.%u/%d", a[0], a[1], a[2], a[3],
bits);
else if (m[2] != 0) sprintf(s, "%u.%u.%u/%d", a[0], a[1], a[2], bits);
else if (m[1] != 0) sprintf(s, "%u.%u/%d", a[0], a[1], bits);
else sprintf(s, "%u/%d", a[0], bits);
return (s);
}
/*
* Convert the printable string representation of an IP address into the
* u_long (network) format. Return 0xffffffff on error. (To detect the
* legal address with that value, you must explicitly compare the string
* with "255.255.255.255".)
*/
u_long inet_parse(s)
u_int32
inet_parse(s)
char *s;
{
u_long a;
u_int32 a = 0;
u_int a0, a1, a2, a3;
char c;
@ -151,7 +172,8 @@ u_long inet_parse(s)
* Checksum routine for Internet Protocol family headers (C Version)
*
*/
int inet_cksum(addr, len)
int
inet_cksum(addr, len)
u_short *addr;
u_int len;
{
@ -166,13 +188,13 @@ int inet_cksum(addr, len)
* back all the carry bits from the top 16 bits into the lower
* 16 bits.
*/
while( nleft > 1 ) {
while (nleft > 1) {
sum += *w++;
nleft -= 2;
}
/* mop up an odd byte, if necessary */
if( nleft == 1 ) {
if (nleft == 1) {
*(u_char *) (&answer) = *(u_char *)w ;
sum += answer;
}

View File

@ -7,7 +7,7 @@
* Leland Stanford Junior University.
*
*
* $Id: kern.c,v 1.6 1994/08/24 23:53:37 thyagara Exp $
* $Id: kern.c,v 3.6 1995/06/25 18:57:38 fenner Exp $
*/
@ -59,7 +59,7 @@ void k_set_loop(l)
void k_set_if(ifa)
u_long ifa;
u_int32 ifa;
{
struct in_addr adr;
@ -72,8 +72,8 @@ void k_set_if(ifa)
void k_join(grp, ifa)
u_long grp;
u_long ifa;
u_int32 grp;
u_int32 ifa;
{
struct ip_mreq mreq;
@ -88,8 +88,8 @@ void k_join(grp, ifa)
void k_leave(grp, ifa)
u_long grp;
u_long ifa;
u_int32 grp;
u_int32 ifa;
{
struct ip_mreq mreq;
@ -105,17 +105,24 @@ void k_leave(grp, ifa)
void k_init_dvmrp()
{
if (setsockopt(igmp_socket, IPPROTO_IP, DVMRP_INIT,
#ifdef OLD_KERNEL
if (setsockopt(igmp_socket, IPPROTO_IP, MRT_INIT,
(char *)NULL, 0) < 0)
log(LOG_ERR, errno, "can't enable DVMRP routing in kernel");
#else
int v=1;
if (setsockopt(igmp_socket, IPPROTO_IP, MRT_INIT,
(char *)&v, sizeof(int)) < 0)
#endif
log(LOG_ERR, errno, "can't enable Multicast routing in kernel");
}
void k_stop_dvmrp()
{
if (setsockopt(igmp_socket, IPPROTO_IP, DVMRP_DONE,
if (setsockopt(igmp_socket, IPPROTO_IP, MRT_DONE,
(char *)NULL, 0) < 0)
log(LOG_WARNING, errno, "can't disable DVMRP routing in kernel");
log(LOG_WARNING, errno, "can't disable Multicast routing in kernel");
}
@ -132,52 +139,85 @@ void k_add_vif(vifi, v)
vc.vifc_lcl_addr.s_addr = v->uv_lcl_addr;
vc.vifc_rmt_addr.s_addr = v->uv_rmt_addr;
if (setsockopt(igmp_socket, IPPROTO_IP, DVMRP_ADD_VIF,
if (setsockopt(igmp_socket, IPPROTO_IP, MRT_ADD_VIF,
(char *)&vc, sizeof(vc)) < 0)
log(LOG_ERR, errno, "setsockopt DVMRP_ADD_VIF");
log(LOG_ERR, errno, "setsockopt MRT_ADD_VIF");
}
void k_del_vif(vifi)
vifi_t vifi;
{
if (setsockopt(igmp_socket, IPPROTO_IP, DVMRP_DEL_VIF,
if (setsockopt(igmp_socket, IPPROTO_IP, MRT_DEL_VIF,
(char *)&vifi, sizeof(vifi)) < 0)
log(LOG_ERR, errno, "setsockopt DVMRP_DEL_VIF");
log(LOG_ERR, errno, "setsockopt MRT_DEL_VIF");
}
/*
* Adds a (source, mcastgrp) entry to the kernel
*/
void k_add_rg(kt)
struct ktable *kt;
void k_add_rg(origin, g)
u_int32 origin;
struct gtable *g;
{
struct mfcctl mc;
int i;
/* copy table values so that setsockopt can process it */
COPY_TABLES(kt, mc);
mc.mfcc_origin.s_addr = origin;
#ifdef OLD_KERNEL
mc.mfcc_originmask.s_addr = 0xffffffff;
#endif
mc.mfcc_mcastgrp.s_addr = g->gt_mcastgrp;
mc.mfcc_parent = g->gt_route ? g->gt_route->rt_parent : NO_VIF;
for (i = 0; i < numvifs; i++)
mc.mfcc_ttls[i] = g->gt_ttls[i];
/* write to kernel space */
if (setsockopt(igmp_socket, IPPROTO_IP, DVMRP_ADD_MFC,
if (setsockopt(igmp_socket, IPPROTO_IP, MRT_ADD_MFC,
(char *)&mc, sizeof(mc)) < 0)
log(LOG_WARNING, errno, "setsockopt DVMRP_ADD_MFC");
log(LOG_WARNING, errno, "setsockopt MRT_ADD_MFC");
}
/*
* Deletes a (source, mcastgrp) entry from the kernel
*/
void k_del_rg(kt)
struct ktable *kt;
int k_del_rg(origin, g)
u_int32 origin;
struct gtable *g;
{
struct mfcctl mc;
int retval;
/* copy table values so that setsockopt can process it */
COPY_TABLES(kt, mc);
mc.mfcc_origin.s_addr = origin;
#ifdef OLD_KERNEL
mc.mfcc_originmask.s_addr = 0xffffffff;
#endif
mc.mfcc_mcastgrp.s_addr = g->gt_mcastgrp;
/* write to kernel space */
if (setsockopt(igmp_socket, IPPROTO_IP, DVMRP_DEL_MFC,
(char *)&mc, sizeof(mc)) < 0)
log(LOG_WARNING, errno, "setsockopt DVMRP_DEL_MFC");
if ((retval = setsockopt(igmp_socket, IPPROTO_IP, MRT_DEL_MFC,
(char *)&mc, sizeof(mc))) < 0)
log(LOG_WARNING, errno, "setsockopt MRT_DEL_MFC");
return retval;
}
/*
* Get the kernel's idea of what version of mrouted needs to run with it.
*/
int k_get_version()
{
int vers;
int len = sizeof(vers);
if (getsockopt(igmp_socket, IPPROTO_IP, MRT_VERSION,
(char *)&vers, &len) < 0)
log(LOG_ERR, errno,
"getsockopt MRT_VERSION: perhaps your kernel is too old");
return vers;
}

View File

@ -7,7 +7,7 @@
* Leland Stanford Junior University.
*
*
* $Id: main.c,v 1.8 1994/08/24 23:53:42 thyagara Exp $
* $Id: main.c,v 3.6 1995/06/25 18:58:06 fenner Exp $
*/
/*
@ -21,13 +21,23 @@
#include "defs.h"
#ifdef __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
#include <fcntl.h>
#ifdef SNMP
#include "snmp.h"
#endif
extern char *configfilename;
static char pidfilename[] = "/etc/mrouted.pid";
static char dumpfilename[] = "/usr/tmp/mrouted.dump";
static char cachefilename[] = "/usr/tmp/mrouted.cache";
static char genidfilename[] = "/usr/tmp/mrouted.genid";
static char pidfilename[] = _PATH_MROUTED_PID;
static char dumpfilename[] = _PATH_MROUTED_DUMP;
static char cachefilename[] = _PATH_MROUTED_CACHE;
static char genidfilename[] = _PATH_MROUTED_GENID;
int cache_lifetime = DEFAULT_CACHE_LIFETIME;
int max_prune_lifetime = DEFAULT_CACHE_LIFETIME * 2;
@ -35,18 +45,44 @@ int max_prune_lifetime = DEFAULT_CACHE_LIFETIME * 2;
int debug = 0;
u_char pruning = 1; /* Enable pruning by default */
#define NHANDLERS 2
static struct ihandler {
int fd; /* File descriptor */
ihfunc_t func; /* Function to call with &fd_set */
} ihandlers[NHANDLERS];
static int nhandlers = 0;
/*
* Forward declarations.
*/
static void fasttimer();
static void timer();
static void hup();
static void dump();
static void fdump();
static void cdump();
static void restart();
static void fasttimer __P((int));
static void done __P((int));
static void dump __P((int));
static void fdump __P((int));
static void cdump __P((int));
static void restart __P((int));
static void timer __P((void));
static void cleanup __P((void));
/* To shut up gcc -Wstrict-prototypes */
int main __P((int argc, char **argv));
int
register_input_handler(fd, func)
int fd;
ihfunc_t func;
{
if (nhandlers >= NHANDLERS)
return -1;
ihandlers[nhandlers].fd = fd;
ihandlers[nhandlers++].func = func;
return 0;
}
int
main(argc, argv)
int argc;
char *argv[];
@ -55,12 +91,28 @@ main(argc, argv)
register int omask;
int dummy;
FILE *fp;
extern uid_t geteuid();
struct timeval tv;
struct timezone tzp;
u_long prev_genid;
u_int32 prev_genid;
int vers;
fd_set rfds, readers;
int nfds, n, i;
#ifdef SNMP
char *myname;
fd_set wfds;
if (myname = strrchr(argv[0], '/'))
myname++;
if (myname == NULL || *myname == 0)
myname = argv[0];
isodetailor (myname, 0);
#endif
#ifdef SYSV
setvbuf(stderr, NULL, _IOLBF, 0);
#else
setlinebuf(stderr);
#endif
if (geteuid() != 0) {
fprintf(stderr, "must be root\n");
@ -107,11 +159,16 @@ usage: fprintf(stderr,
(void)open("/", 0);
(void)dup2(0, 1);
(void)dup2(0, 2);
#ifdef TIOCNOTTY
t = open("/dev/tty", 2);
if (t >= 0) {
(void)ioctl(t, TIOCNOTTY, (char *)0);
(void)close(t);
}
#else
if (setsid() < 0)
perror("setsid");
#endif
}
else
fprintf(stderr, "debug level %u\n", debug);
@ -125,12 +182,16 @@ usage: fprintf(stderr,
log(LOG_NOTICE, 0, "mrouted version %d.%d",
PROTOCOL_VERSION, MROUTED_VERSION);
#ifdef SYSV
srand48(time(NULL));
#else
srandom(gethostid());
#endif
/*
* Get generation id
*/
gettimeofday(&tv, &tzp);
gettimeofday(&tv, 0);
dvmrp_genid = tv.tv_sec;
fp = fopen(genidfilename, "r");
@ -148,33 +209,71 @@ usage: fprintf(stderr,
}
callout_init();
#ifdef SNMP
snmp_init();
#endif
init_igmp();
k_init_dvmrp(); /* enable DVMRP routing in kernel */
#ifndef OLD_KERNEL
vers = k_get_version();
/*XXX
* This function must change whenever the kernel version changes
*/
if ((((vers >> 8) & 0xff) != 3) ||
((vers & 0xff) != 5))
log(LOG_ERR, 0, "kernel (v%d.%d)/mrouted (v%d.%d) version mismatch",
(vers >> 8) & 0xff, vers & 0xff,
PROTOCOL_VERSION, MROUTED_VERSION);
#endif
init_routes();
init_ktable();
init_vifs();
#ifdef RSRR
rsrr_init();
#endif /* RSRR */
#if defined(__STDC__) || defined(__GNUC__)
/* Allow cleanup if unexpected exit. Apparently some architectures
* have a kernel bug where closing the socket doesn't do an
* ip_mrouter_done(), so we attempt to do it on exit.
*/
atexit(cleanup);
#endif
if (debug)
fprintf(stderr, "pruning %s\n", pruning ? "on" : "off");
fp = fopen(pidfilename, "w");
if (fp != NULL) {
fprintf(fp, "%d\n", getpid());
fprintf(fp, "%d\n", (int)getpid());
(void) fclose(fp);
}
if (debug >= 2) dump();
if (debug >= 2) dump(0);
(void)signal(SIGALRM, fasttimer);
(void)signal(SIGHUP, restart);
(void)signal(SIGTERM, hup);
(void)signal(SIGINT, hup);
(void)signal(SIGTERM, done);
(void)signal(SIGINT, done);
(void)signal(SIGUSR1, fdump);
(void)signal(SIGUSR2, cdump);
if (debug != 0)
(void)signal(SIGQUIT, dump);
FD_ZERO(&readers);
FD_SET(igmp_socket, &readers);
nfds = igmp_socket + 1;
for (i = 0; i < nhandlers; i++) {
FD_SET(ihandlers[i].fd, &readers);
if (ihandlers[i].fd >= nfds)
nfds = ihandlers[i].fd + 1;
}
(void)alarm(1); /* schedule first timer interrupt */
/*
@ -182,27 +281,69 @@ usage: fprintf(stderr,
*/
dummy = 0;
for(;;) {
recvlen = recvfrom(igmp_socket, recv_buf, sizeof(recv_buf),
0, NULL, &dummy);
if (recvlen < 0) {
if (errno != EINTR) log(LOG_ERR, errno, "recvfrom");
continue;
bcopy((char *)&readers, (char *)&rfds, sizeof(rfds));
#ifdef SNMP
FD_ZERO(&wfds);
if (smux_fd != NOTOK) {
if (rock_and_roll)
FD_SET(smux_fd, &rfds);
else
FD_SET(smux_fd, &wfds);
if (smux_fd >= nfds)
nfds = smux_fd + 1;
}
if ((n = xselect(nfds, &rfds, &wfds, NULLFD, NOTOK))==NOTOK) {
#else
if ((n = select(nfds, &rfds, NULL, NULL, NULL)) < 0) {
#endif
if (errno != EINTR) /* SIGALRM is expected */
log(LOG_WARNING, errno, "select failed");
continue;
}
if (FD_ISSET(igmp_socket, &rfds)) {
recvlen = recvfrom(igmp_socket, recv_buf, RECV_BUF_SIZE,
0, NULL, &dummy);
if (recvlen < 0) {
if (errno != EINTR) log(LOG_ERR, errno, "recvfrom");
continue;
}
omask = sigblock(sigmask(SIGALRM));
accept_igmp(recvlen);
(void)sigsetmask(omask);
}
for (i = 0; i < nhandlers; i++) {
if (FD_ISSET(ihandlers[i].fd, &rfds)) {
(*ihandlers[i].func)(&rfds);
}
}
omask = sigblock(sigmask(SIGALRM));
accept_igmp(recvlen);
(void)sigsetmask(omask);
#ifdef SNMP
if (smux_fd != NOTOK) {
if (rock_and_roll) {
if (FD_ISSET(smux_fd, &rfds))
doit_smux();
} else if (FD_ISSET(smux_fd, &wfds))
start_smux();
}
#endif
}
}
/*
* routine invoked every second. It's main goal is to cycle through
* routine invoked every second. Its main goal is to cycle through
* the routing table and send partial updates to all neighbors at a
* rate that will cause the entire table to be sent in ROUTE_REPORT_INTERVAL
* seconds. Also, every TIMER_INTERVAL seconds it calls timer() to
* do all the other time-based processing.
*/
static void fasttimer()
static void
fasttimer(i)
int i;
{
static unsigned int tlast;
static unsigned int nsent;
@ -264,7 +405,8 @@ static u_long virtual_time = 0;
* group querying duties, and drives various timers in routing entries and
* virtual interface data structures.
*/
static void timer()
static void
timer()
{
age_routes(); /* Advance the timers in the route entries */
age_vifs(); /* Advance the timers for neighbors */
@ -301,6 +443,16 @@ static void timer()
report_to_all_neighbors(CHANGED_ROUTES);
}
#ifdef SNMP
if (smux_fd == NOTOK && !dont_bother_anymore
&& virtual_time % SNMPD_RETRY_INTERVAL == 0) {
/*
* Time to check for snmpd running.
*/
try_smux_init();
}
#endif
/*
* Advance virtual time
*/
@ -309,21 +461,41 @@ static void timer()
/*
* On hangup signal, let everyone know we're going away.
* On termination, let everyone know we're going away.
*/
static void hup()
static void
done(i)
int i;
{
log(LOG_INFO, 0, "hup");
expire_all_routes();
report_to_all_neighbors(ALL_ROUTES);
exit(1);
log(LOG_NOTICE, 0, "mrouted version %d.%d exiting",
PROTOCOL_VERSION, MROUTED_VERSION);
cleanup();
_exit(1);
}
static void
cleanup()
{
static in_cleanup = 0;
if (!in_cleanup) {
in_cleanup++;
#ifdef RSRR
rsrr_clean();
#endif /* RSRR */
expire_all_routes();
report_to_all_neighbors(ALL_ROUTES);
k_stop_dvmrp();
}
}
/*
* Dump internal data structures to stderr.
*/
static void dump()
static void
dump(i)
int i;
{
dump_vifs(stderr);
dump_routes(stderr);
@ -333,7 +505,9 @@ static void dump()
/*
* Dump internal data structures to a file.
*/
static void fdump()
static void
fdump(i)
int i;
{
FILE *fp;
@ -349,7 +523,9 @@ static void fdump()
/*
* Dump local cache contents to a file.
*/
static void cdump()
static void
cdump(i)
int i;
{
FILE *fp;
@ -364,11 +540,14 @@ static void cdump()
/*
* Restart mrouted
*/
static void restart()
static void
restart(i)
int i;
{
register int omask;
log(LOG_INFO, 0, "restart");
log(LOG_NOTICE, 0, "mrouted version %d.%d restart",
PROTOCOL_VERSION, MROUTED_VERSION);
/*
* reset all the entries
@ -378,6 +557,8 @@ static void restart()
free_all_routes();
stop_all_vifs();
k_stop_dvmrp();
close(igmp_socket);
close(udp_socket);
/*
* start processing again
@ -400,39 +581,63 @@ static void restart()
* according to the severity of the message and the current debug level.
* For errors of severity LOG_ERR or worse, terminate the program.
*/
void log(severity, syserr, format, a, b, c, d, e)
#ifdef __STDC__
void
log(int severity, int syserr, char *format, ...)
{
va_list ap;
static char fmt[211] = "warning - ";
char *msg;
char tbuf[20];
struct timeval now;
struct tm *thyme;
va_start(ap, format);
#else
/*VARARGS3*/
void
log(severity, syserr, format, va_alist)
int severity, syserr;
char *format;
int a, b, c, d, e;
va_dcl
{
char fmt[100];
va_list ap;
static char fmt[211] = "warning - ";
char *msg;
char tbuf[20];
struct timeval now;
struct tm *thyme;
va_start(ap);
#endif
vsprintf(&fmt[10], format, ap);
va_end(ap);
msg = (severity == LOG_WARNING) ? fmt : &fmt[10];
switch (debug) {
case 0: break;
case 1: if (severity > LOG_NOTICE) break;
case 2: if (severity > LOG_INFO ) break;
default:
fmt[0] = '\0';
if (severity == LOG_WARNING) strcat(fmt, "warning - ");
strncat(fmt, format, 80);
fprintf(stderr, fmt, a, b, c, d, e);
gettimeofday(&now,NULL);
thyme = localtime(&now.tv_sec);
strftime(tbuf, sizeof(tbuf), "%X.%%03d ", thyme);
fprintf(stderr, tbuf, now.tv_usec / 1000);
fprintf(stderr, "%s", msg);
if (syserr == 0)
fprintf(stderr, "\n");
else if(syserr < sys_nerr)
else if (syserr < sys_nerr)
fprintf(stderr, ": %s\n", sys_errlist[syserr]);
else
fprintf(stderr, ": errno %d\n", syserr);
}
if (severity <= LOG_NOTICE) {
fmt[0] = '\0';
if (severity == LOG_WARNING) strcat(fmt, "warning - ");
strncat(fmt, format, 80);
if (syserr != 0) {
strcat(fmt, ": %m");
errno = syserr;
}
syslog(severity, fmt, a, b, c, d, e);
errno = syserr;
syslog(severity, "%s: %m", msg);
} else
syslog(severity, "%s", msg);
if (severity <= LOG_ERR) exit(-1);
}

View File

@ -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.

View File

@ -1,7 +1,7 @@
/* Mapper for connections between MRouteD multicast routers.
* Written by Pavel Curtis <Pavel@PARC.Xerox.Com>
*
* $Id: mapper.c,v 1.8 1994/08/24 23:53:54 thyagara Exp $
* $Id: mapper.c,v 3.6 1995/06/25 18:59:02 fenner Exp $
*/
/*
@ -21,9 +21,16 @@
* These notices must be retained in any copies of any part of this software.
*/
#include <string.h>
#include <netdb.h>
#include <sys/time.h>
#include "defs.h"
#include <arpa/inet.h>
#ifdef __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
#define DEFAULT_TIMEOUT 2 /* How long to wait before retrying requests */
#define DEFAULT_RETRIES 1 /* How many times to ask each router */
@ -33,7 +40,7 @@
typedef struct neighbor {
struct neighbor *next;
u_long addr; /* IP address in NET order */
u_int32 addr; /* IP address in NET order */
u_char metric; /* TTL cost of forwarding */
u_char threshold; /* TTL threshold to forward */
u_short flags; /* flags on connection */
@ -42,13 +49,13 @@ typedef struct neighbor {
typedef struct interface {
struct interface *next;
u_long addr; /* IP address of the interface in NET order */
u_int32 addr; /* IP address of the interface in NET order */
Neighbor *neighbors; /* List of neighbors' IP addresses */
} Interface;
typedef struct node {
u_long addr; /* IP address of this entry in NET order */
u_long version; /* which mrouted version is running */
u_int32 addr; /* IP address of this entry in NET order */
u_int32 version; /* which mrouted version is running */
int tries; /* How many requests sent? -1 for aliases */
union {
struct node *alias; /* If alias, to what? */
@ -59,7 +66,7 @@ typedef struct node {
Node *routers = 0;
u_long our_addr, target_addr = 0; /* in NET order */
u_int32 our_addr, target_addr = 0; /* in NET order */
int debug = 0;
int retries = DEFAULT_RETRIES;
int timeout = DEFAULT_TIMEOUT;
@ -67,9 +74,26 @@ int show_names = TRUE;
vifi_t numvifs; /* to keep loader happy */
/* (see COPY_TABLES macro called in kern.c) */
Node * find_node __P((u_int32 addr, Node **ptr));
Interface * find_interface __P((u_int32 addr, Node *node));
Neighbor * find_neighbor __P((u_int32 addr, Node *node));
int main __P((int argc, char *argv[]));
void ask __P((u_int32 dst));
void ask2 __P((u_int32 dst));
int retry_requests __P((Node *node));
char * inet_name __P((u_int32 addr));
void print_map __P((Node *node));
char * graph_name __P((u_int32 addr, char *buf));
void graph_edges __P((Node *node));
void elide_aliases __P((Node *node));
void graph_map __P((void));
int get_number __P((int *var, int deflt, char ***pargv,
int *pargc));
u_int32 host_addr __P((char *name));
Node *find_node(addr, ptr)
u_long addr;
u_int32 addr;
Node **ptr;
{
Node *n = *ptr;
@ -92,7 +116,7 @@ Node *find_node(addr, ptr)
Interface *find_interface(addr, node)
u_long addr;
u_int32 addr;
Node *node;
{
Interface *ifc;
@ -112,7 +136,7 @@ Interface *find_interface(addr, node)
Neighbor *find_neighbor(addr, node)
u_long addr;
u_int32 addr;
Node *node;
{
Interface *ifc;
@ -134,12 +158,27 @@ Neighbor *find_neighbor(addr, node)
* message and the current debug level. For errors of severity LOG_ERR or
* worse, terminate the program.
*/
void log(severity, syserr, format, a, b, c, d, e)
int severity, syserr;
char *format;
int a, b, c, d, e;
#ifdef __STDC__
void
log(int severity, int syserr, char *format, ...)
{
char fmt[100];
va_list ap;
char fmt[100];
va_start(ap, format);
#else
/*VARARGS3*/
void
log(severity, syserr, format, va_alist)
int severity, syserr;
char *format;
va_dcl
{
va_list ap;
char fmt[100];
va_start(ap);
#endif
switch (debug) {
case 0: if (severity > LOG_WARNING) return;
@ -150,7 +189,7 @@ void log(severity, syserr, format, a, b, c, d, e)
if (severity == LOG_WARNING)
strcat(fmt, "warning - ");
strncat(fmt, format, 80);
fprintf(stderr, fmt, a, b, c, d, e);
vfprintf(stderr, fmt, ap);
if (syserr == 0)
fprintf(stderr, "\n");
else if (syserr < sys_nerr)
@ -168,14 +207,14 @@ void log(severity, syserr, format, a, b, c, d, e)
* Send a neighbors-list request.
*/
void ask(dst)
u_long dst;
u_int32 dst;
{
send_igmp(our_addr, dst, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS,
htonl(MROUTED_LEVEL), 0);
}
void ask2(dst)
u_long dst;
u_int32 dst;
{
send_igmp(our_addr, dst, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS2,
htonl(MROUTED_LEVEL), 0);
@ -185,8 +224,9 @@ void ask2(dst)
/*
* Process an incoming group membership report.
*/
void accept_group_report(src, dst, group)
u_long src, dst, group;
void accept_group_report(src, dst, group, r_type)
u_int32 src, dst, group;
int r_type;
{
log(LOG_INFO, 0, "ignoring IGMP group membership report from %s to %s",
inet_fmt(src, s1), inet_fmt(dst, s2));
@ -196,8 +236,10 @@ void accept_group_report(src, dst, group)
/*
* Process an incoming neighbor probe message.
*/
void accept_probe(src, dst)
u_long src, dst;
void accept_probe(src, dst, p, datalen, level)
u_int32 src, dst, level;
char *p;
int datalen;
{
log(LOG_INFO, 0, "ignoring DVMRP probe from %s to %s",
inet_fmt(src, s1), inet_fmt(dst, s2));
@ -207,8 +249,8 @@ void accept_probe(src, dst)
/*
* Process an incoming route report message.
*/
void accept_report(src, dst, p, datalen)
u_long src, dst;
void accept_report(src, dst, p, datalen, level)
u_int32 src, dst, level;
char *p;
int datalen;
{
@ -221,7 +263,7 @@ void accept_report(src, dst, p, datalen)
* Process an incoming neighbor-list request message.
*/
void accept_neighbor_request(src, dst)
u_long src, dst;
u_int32 src, dst;
{
if (src != our_addr)
log(LOG_INFO, 0,
@ -230,7 +272,7 @@ void accept_neighbor_request(src, dst)
}
void accept_neighbor_request2(src, dst)
u_long src, dst;
u_int32 src, dst;
{
if (src != our_addr)
log(LOG_INFO, 0,
@ -243,7 +285,7 @@ void accept_neighbor_request2(src, dst)
* Process an incoming neighbor-list message.
*/
void accept_neighbors(src, dst, p, datalen, level)
u_long src, dst, level;
u_int32 src, dst, level;
u_char *p;
int datalen;
{
@ -254,12 +296,12 @@ void accept_neighbors(src, dst, p, datalen, level)
else if (node->tries == -1) /* follow alias link */
node = node->u.alias;
#define GET_ADDR(a) (a = ((u_long)*p++ << 24), a += ((u_long)*p++ << 16),\
a += ((u_long)*p++ << 8), a += *p++)
#define GET_ADDR(a) (a = ((u_int32)*p++ << 24), a += ((u_int32)*p++ << 16),\
a += ((u_int32)*p++ << 8), a += *p++)
/* if node is running a recent mrouted, ask for additional info */
if (level != 0) {
node->version = ntohl(level);
node->version = level;
node->tries = 0;
ask2(src);
return;
@ -281,7 +323,7 @@ void accept_neighbors(src, dst, p, datalen, level)
}
while (datalen > 0) { /* loop through interfaces */
u_long ifc_addr;
u_int32 ifc_addr;
u_char metric, threshold, ncount;
Node *ifc_node;
Interface *ifc;
@ -360,7 +402,7 @@ void accept_neighbors(src, dst, p, datalen, level)
/* Add the neighbors for this interface */
while (ncount--) {
u_long neighbor;
u_int32 neighbor;
Neighbor *nb;
Node *n_node;
@ -403,8 +445,8 @@ void accept_neighbors(src, dst, p, datalen, level)
}
}
void accept_neighbors2(src, dst, p, datalen)
u_long src, dst;
void accept_neighbors2(src, dst, p, datalen, level)
u_int32 src, dst, level;
u_char *p;
int datalen;
{
@ -416,7 +458,7 @@ void accept_neighbors2(src, dst, p, datalen)
node = node->u.alias;
while (datalen > 0) { /* loop through interfaces */
u_long ifc_addr;
u_int32 ifc_addr;
u_char metric, threshold, ncount, flags;
Node *ifc_node;
Interface *ifc;
@ -428,7 +470,7 @@ void accept_neighbors2(src, dst, p, datalen)
return;
}
ifc_addr = *(u_long*)p;
ifc_addr = *(u_int32*)p;
p += 4;
metric = *p++;
threshold = *p++;
@ -495,8 +537,8 @@ void accept_neighbors2(src, dst, p, datalen)
old_neighbors = ifc->neighbors;
/* Add the neighbors for this interface */
while (ncount--) {
u_long neighbor;
while (ncount-- && datalen > 0) {
u_int32 neighbor;
Neighbor *nb;
Node *n_node;
@ -506,7 +548,7 @@ void accept_neighbors2(src, dst, p, datalen)
return;
}
neighbor = *(u_long*)p;
neighbor = *(u_int32*)p;
p += 4;
datalen -= 4;
if (neighbor == 0)
@ -571,11 +613,11 @@ int retry_requests(node)
char *inet_name(addr)
u_long addr;
u_int32 addr;
{
struct hostent *e;
e = gethostbyaddr(&addr, sizeof(addr), AF_INET);
e = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET);
return e ? e->h_name : 0;
}
@ -650,7 +692,7 @@ void print_map(node)
char *graph_name(addr, buf)
u_long addr;
u_int32 addr;
char *buf;
{
char *name;
@ -734,7 +776,7 @@ void elide_aliases(node)
void graph_map()
{
u_long now = time(0);
time_t now = time(0);
char *nowstr = ctime(&now);
nowstr[24] = '\0'; /* Kill the newline at the end */
@ -771,7 +813,7 @@ int get_number(var, deflt, pargv, pargc)
}
u_long host_addr(name)
u_int32 host_addr(name)
char *name;
{
struct hostent *e = gethostbyname(name);
@ -789,7 +831,7 @@ u_long host_addr(name)
}
main(argc, argv)
int main(argc, argv)
int argc;
char *argv[];
{
@ -862,6 +904,9 @@ main(argc, argv)
int addrlen = sizeof(addr);
addr.sin_family = AF_INET;
#if (defined(BSD) && (BSD >= 199103))
addr.sin_len = sizeof addr;
#endif
addr.sin_addr.s_addr = dvmrp_group;
addr.sin_port = htons(2000); /* any port over 1024 will do... */
if ((udp = socket(AF_INET, SOCK_DGRAM, 0)) < 0
@ -912,7 +957,7 @@ main(argc, argv)
break;
}
recvlen = recvfrom(igmp_socket, recv_buf, sizeof(recv_buf),
recvlen = recvfrom(igmp_socket, recv_buf, RECV_BUF_SIZE,
0, NULL, &dummy);
if (recvlen >= 0)
accept_igmp(recvlen);
@ -933,21 +978,42 @@ main(argc, argv)
exit(0);
}
void accept_prune()
/* dummies */
void accept_prune(src, dst, p, datalen)
u_int32 src, dst;
char *p;
int datalen;
{
}
void accept_graft()
void accept_graft(src, dst, p, datalen)
u_int32 src, dst;
char *p;
int datalen;
{
}
void accept_g_ack()
void accept_g_ack(src, dst, p, datalen)
u_int32 src, dst;
char *p;
int datalen;
{
}
void add_table_entry()
void add_table_entry(origin, mcastgrp)
u_int32 origin, mcastgrp;
{
}
void leave_group_message()
void accept_leave_message(src, dst, group)
u_int32 src, dst, group;
{
}
void mtrace()
void accept_mtrace(src, dst, group, data, no, datalen)
u_int32 src, dst, group;
char *data;
u_int no;
int datalen;
{
}
void accept_membership_query(src, dst, group, tmo)
u_int32 src, dst, group;
int tmo;
{
}

View File

@ -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

View File

@ -61,7 +61,7 @@
#ifndef lint
static char rcsid[] =
"@(#) $Id: mrinfo.c,v 1.7 1994/08/24 23:54:04 thyagara Exp $";
"@(#) $Id: mrinfo.c,v 3.6 1995/06/25 19:05:34 fenner Exp $";
/* original rcsid:
"@(#) Header: mrinfo.c,v 1.6 93/04/08 15:14:16 van Exp (LBL)";
*/
@ -70,27 +70,53 @@ static char rcsid[] =
#include <netdb.h>
#include <sys/time.h>
#include "defs.h"
#include <arpa/inet.h>
#ifdef __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
#define DEFAULT_TIMEOUT 4 /* How long to wait before retrying requests */
#define DEFAULT_RETRIES 3 /* How many times to ask each router */
u_long our_addr, target_addr = 0; /* in NET order */
u_int32 our_addr, target_addr = 0; /* in NET order */
int debug = 0;
int nflag = 0;
int retries = DEFAULT_RETRIES;
int timeout = DEFAULT_TIMEOUT;
int target_level;
int target_level = 0;
vifi_t numvifs; /* to keep loader happy */
/* (see COPY_TABLES macro called in kern.c) */
char * inet_name __P((u_int32 addr));
void ask __P((u_int32 dst));
void ask2 __P((u_int32 dst));
int get_number __P((int *var, int deflt, char ***pargv,
int *pargc));
u_int32 host_addr __P((char *name));
void usage __P((void));
/* to shut up -Wstrict-prototypes */
int main __P((int argc, char *argv[]));
char *
inet_name(addr)
u_long addr;
u_int32 addr;
{
struct hostent *e;
struct in_addr in;
e = gethostbyaddr(&addr, sizeof(addr), AF_INET);
if (addr == 0)
return "local";
return e ? e->h_name : "?";
if (nflag ||
(e = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET)) == NULL) {
in.s_addr = addr;
return (inet_ntoa(in));
}
return (e->h_name);
}
/*
@ -98,14 +124,26 @@ inet_name(addr)
* message and the current debug level. For errors of severity LOG_ERR or
* worse, terminate the program.
*/
void
log(severity, syserr, format, a, b, c, d, e)
int severity, syserr;
char *format;
int a, b, c, d, e;
#ifdef __STDC__
void
log(int severity, int syserr, char *format, ...)
{
va_list ap;
char fmt[100];
va_start(ap, format);
#else
void
log(severity, syserr, format, va_alist)
int severity, syserr;
char *format;
va_dcl
{
va_list ap;
char fmt[100];
va_start(ap);
#endif
switch (debug) {
case 0:
if (severity > LOG_WARNING)
@ -121,7 +159,7 @@ log(severity, syserr, format, a, b, c, d, e)
if (severity == LOG_WARNING)
strcat(fmt, "warning - ");
strncat(fmt, format, 80);
fprintf(stderr, fmt, a, b, c, d, e);
vfprintf(stderr, fmt, ap);
if (syserr == 0)
fprintf(stderr, "\n");
else if (syserr < sys_nerr)
@ -139,7 +177,7 @@ log(severity, syserr, format, a, b, c, d, e)
*/
void
ask(dst)
u_long dst;
u_int32 dst;
{
send_igmp(our_addr, dst, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS,
htonl(MROUTED_LEVEL), 0);
@ -147,7 +185,7 @@ ask(dst)
void
ask2(dst)
u_long dst;
u_int32 dst;
{
send_igmp(our_addr, dst, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS2,
htonl(MROUTED_LEVEL), 0);
@ -157,18 +195,18 @@ ask2(dst)
* Process an incoming neighbor-list message.
*/
void
accept_neighbors(src, dst, p, datalen)
u_long src, dst;
u_char *p;
accept_neighbors(src, dst, p, datalen, level)
u_int32 src, dst, level;
u_char *p;
int datalen;
{
u_char *ep = p + datalen;
#define GET_ADDR(a) (a = ((u_long)*p++ << 24), a += ((u_long)*p++ << 16),\
a += ((u_long)*p++ << 8), a += *p++)
#define GET_ADDR(a) (a = ((u_int32)*p++ << 24), a += ((u_int32)*p++ << 16),\
a += ((u_int32)*p++ << 8), a += *p++)
printf("%s (%s):\n", inet_fmt(src, s1), inet_name(src));
while (p < ep) {
register u_long laddr;
register u_int32 laddr;
register u_char metric;
register u_char thresh;
register int ncount;
@ -179,7 +217,7 @@ accept_neighbors(src, dst, p, datalen)
thresh = *p++;
ncount = *p++;
while (--ncount >= 0) {
register u_long neighbor;
register u_int32 neighbor;
GET_ADDR(neighbor);
neighbor = htonl(neighbor);
printf(" %s -> ", inet_fmt(laddr, s1));
@ -190,29 +228,36 @@ accept_neighbors(src, dst, p, datalen)
}
void
accept_neighbors2(src, dst, p, datalen)
u_long src, dst;
u_char *p;
accept_neighbors2(src, dst, p, datalen, level)
u_int32 src, dst, level;
u_char *p;
int datalen;
{
u_char *ep = p + datalen;
u_int broken_cisco = ((level & 0xffff) == 0x020a); /* 10.2 */
/* well, only possibly_broken_cisco, but that's too long to type. */
printf("%s (%s) [version %d.%d]:\n", inet_fmt(src, s1), inet_name(src),
target_level & 0xff, (target_level >> 8) & 0xff);
level & 0xff, (level >> 8) & 0xff);
while (p < ep) {
register u_char metric;
register u_char thresh;
register u_char flags;
register int ncount;
register u_long laddr = *(u_long*)p;
register u_int32 laddr = *(u_int32*)p;
p += 4;
metric = *p++;
thresh = *p++;
flags = *p++;
ncount = *p++;
while (--ncount >= 0) {
register u_long neighbor = *(u_long*)p;
if (broken_cisco && ncount == 0) /* dumb Ciscos */
ncount = 1;
if (broken_cisco && ncount > 15) /* dumb Ciscos */
ncount = ncount & 0xf;
while (--ncount >= 0 && p < ep) {
register u_int32 neighbor = *(u_int32*)p;
p += 4;
printf(" %s -> ", inet_fmt(laddr, s1));
printf("%s (%s) [%d/%d", inet_fmt(neighbor, s1),
@ -221,12 +266,16 @@ accept_neighbors2(src, dst, p, datalen)
printf("/tunnel");
if (flags & DVMRP_NF_SRCRT)
printf("/srcrt");
if (flags & DVMRP_NF_PIM)
printf("/pim");
if (flags & DVMRP_NF_QUERIER)
printf("/querier");
if (flags & DVMRP_NF_DISABLED)
printf("/disabled");
if (flags & DVMRP_NF_DOWN)
printf("/down");
if (flags & DVMRP_NF_LEAF)
printf("/leaf");
printf("]\n");
}
}
@ -258,33 +307,44 @@ get_number(var, deflt, pargv, pargc)
}
}
u_long
u_int32
host_addr(name)
char *name;
{
struct hostent *e = gethostbyname(name);
int addr;
struct hostent *e;
u_int32 addr;
if (e)
addr = inet_addr(name);
if ((int)addr == -1) {
e = gethostbyname(name);
if (e == NULL || e->h_length != sizeof(addr))
return (0);
memcpy(&addr, e->h_addr_list[0], e->h_length);
else {
addr = inet_addr(name);
if (addr == -1)
addr = 0;
}
return addr;
return(addr);
}
void
usage()
{
fprintf(stderr,
"Usage: mrinfo [-n] [-t timeout] [-r retries] [router]\n");
exit(1);
}
int
main(argc, argv)
int argc;
char *argv[];
{
int tries = 0;
int trynew = 1;
struct timeval et;
setlinebuf(stderr);
if (geteuid() != 0) {
fprintf(stderr, "must be root\n");
fprintf(stderr, "mrinfo: must be root\n");
exit(1);
}
argv++, argc--;
@ -292,29 +352,35 @@ main(argc, argv)
switch (argv[0][1]) {
case 'd':
if (!get_number(&debug, DEFAULT_DEBUG, &argv, &argc))
goto usage;
usage();
break;
case 'n':
++nflag;
break;
case 'r':
if (!get_number(&retries, -1, &argv, &argc))
goto usage;
usage();
break;
case 't':
if (!get_number(&timeout, -1, &argv, &argc))
goto usage;
usage();
break;
default:
goto usage;
usage();
}
argv++, argc--;
}
if (argc > 1)
usage();
if (argc == 1)
target_addr = host_addr(argv[0]);
else
target_addr = host_addr("127.0.0.1");
if (argc > 1 || (argc == 1 && !(target_addr = host_addr(argv[0])))) {
usage: fprintf(stderr,
"Usage: mrinfo [-t timeout] [-r retries] router\n");
if (target_addr == 0) {
fprintf(stderr, "mrinfo: %s: no such host\n", argv[0]);
exit(1);
}
if (target_addr == 0)
goto usage;
if (debug)
fprintf(stderr, "Debug level %u\n", debug);
@ -326,6 +392,9 @@ usage: fprintf(stderr,
int addrlen = sizeof(addr);
addr.sin_family = AF_INET;
#if (defined(BSD) && (BSD >= 199103))
addr.sin_len = sizeof addr;
#endif
addr.sin_addr.s_addr = target_addr;
addr.sin_port = htons(2000); /* any port over 1024 will
* do... */
@ -339,14 +408,22 @@ usage: fprintf(stderr,
our_addr = addr.sin_addr.s_addr;
}
ask(target_addr);
/*
* New strategy: send 'ask2' for two timeouts, then fall back
* to 'ask', since it's not very likely that we are going to
* find someone who only responds to 'ask' these days
*/
ask2(target_addr);
gettimeofday(&et, 0);
et.tv_sec += timeout;
/* Main receive loop */
for (;;) {
fd_set fds;
struct timeval tv;
struct timeval tv, now;
int count, recvlen, dummy = 0;
register u_long src, dst, group;
register u_int32 src, dst, group;
struct ip *ip;
struct igmp *igmp;
int ipdatalen, iphdrlen, igmpdatalen;
@ -354,8 +431,16 @@ usage: fprintf(stderr,
FD_ZERO(&fds);
FD_SET(igmp_socket, &fds);
tv.tv_sec = timeout;
tv.tv_usec = 0;
gettimeofday(&now, 0);
tv.tv_sec = et.tv_sec - now.tv_sec;
tv.tv_usec = et.tv_usec - now.tv_usec;
if (tv.tv_usec < 0) {
tv.tv_usec += 1000000L;
--tv.tv_sec;
}
if (tv.tv_sec < 0)
tv.tv_sec = tv.tv_usec = 0;
count = select(igmp_socket + 1, &fds, 0, 0, &tv);
@ -365,15 +450,20 @@ usage: fprintf(stderr,
continue;
} else if (count == 0) {
log(LOG_DEBUG, 0, "Timed out receiving neighbor lists");
if (--retries < 0)
if (++tries > retries)
exit(1);
if (target_level == 0)
/* If we've tried ASK_NEIGHBORS2 twice with
* no response, fall back to ASK_NEIGHBORS
*/
if (tries == 2 && target_level == 0)
trynew = 0;
if (target_level == 0 && trynew == 0)
ask(target_addr);
else
ask2(target_addr);
continue;
}
recvlen = recvfrom(igmp_socket, recv_buf, sizeof(recv_buf),
recvlen = recvfrom(igmp_socket, recv_buf, RECV_BUF_SIZE,
0, NULL, &dummy);
if (recvlen <= 0) {
if (recvlen && errno != EINTR)
@ -388,14 +478,9 @@ usage: fprintf(stderr,
continue;
}
ip = (struct ip *) recv_buf;
if (ip->ip_p == 0)
continue; /* Request to install cache entry */
src = ip->ip_src.s_addr;
if (src != target_addr) {
fprintf(stderr, "mrinfo: got reply from %s",
inet_fmt(src, s1));
fprintf(stderr, " instead of %s\n",
inet_fmt(target_addr, s1));
continue;
}
dst = ip->ip_dst.s_addr;
iphdrlen = ip->ip_hl << 2;
ipdatalen = ip->ip_len;
@ -417,6 +502,21 @@ usage: fprintf(stderr,
if (igmp->igmp_type != IGMP_DVMRP)
continue;
switch (igmp->igmp_code) {
case DVMRP_NEIGHBORS:
case DVMRP_NEIGHBORS2:
if (src != target_addr) {
fprintf(stderr, "mrinfo: got reply from %s",
inet_fmt(src, s1));
fprintf(stderr, " instead of %s\n",
inet_fmt(target_addr, s1));
/*continue;*/
}
break;
default:
continue; /* ignore all other DVMRP messages */
}
switch (igmp->igmp_code) {
case DVMRP_NEIGHBORS:
@ -427,54 +527,84 @@ usage: fprintf(stderr,
ask2(target_addr);
}
} else {
accept_neighbors(src, dst, (char *)(igmp + 1),
igmpdatalen);
accept_neighbors(src, dst, (u_char *)(igmp + 1),
igmpdatalen, ntohl(group));
exit(0);
}
break;
case DVMRP_NEIGHBORS2:
accept_neighbors2(src, dst, (char *)(igmp + 1),
igmpdatalen);
accept_neighbors2(src, dst, (u_char *)(igmp + 1),
igmpdatalen, ntohl(group));
exit(0);
}
}
}
/* dummies */
void accept_probe()
void accept_probe(src, dst, p, datalen, level)
u_int32 src, dst, level;
char *p;
int datalen;
{
}
void accept_group_report()
void accept_group_report(src, dst, group, r_type)
u_int32 src, dst, group;
int r_type;
{
}
void accept_neighbor_request2()
void accept_neighbor_request2(src, dst)
u_int32 src, dst;
{
}
void accept_report()
void accept_report(src, dst, p, datalen, level)
u_int32 src, dst, level;
char *p;
int datalen;
{
}
void accept_neighbor_request()
void accept_neighbor_request(src, dst)
u_int32 src, dst;
{
}
void accept_prune()
void accept_prune(src, dst, p, datalen)
u_int32 src, dst;
char *p;
int datalen;
{
}
void accept_graft()
void accept_graft(src, dst, p, datalen)
u_int32 src, dst;
char *p;
int datalen;
{
}
void accept_g_ack()
void accept_g_ack(src, dst, p, datalen)
u_int32 src, dst;
char *p;
int datalen;
{
}
void add_table_entry()
void add_table_entry(origin, mcastgrp)
u_int32 origin, mcastgrp;
{
}
void check_vif_state()
{
}
void leave_group_message()
void accept_leave_message(src, dst, group)
u_int32 src, dst, group;
{
}
void mtrace()
void accept_mtrace(src, dst, group, data, no, datalen)
u_int32 src, dst, group;
char *data;
u_int no;
int datalen;
{
}
void accept_membership_query(src, dst, group, tmo)
u_int32 src, dst, group;
int tmo;
{
}

View File

@ -1,4 +1,5 @@
'\"COPYRIGHT 1989 by The Board of Trustees of Leland Stanford Junior University.
'\"$Id: mrouted.8,v 3.6 1995/06/25 19:10:58 fenner Exp $
.TH MROUTED 8
.UC 5
.SH NAME
@ -50,8 +51,7 @@ Older versions of
.I mrouted
tunnel using IP source routing, which puts a heavy load on some
types of routers.
This version supports IP source route tunnelling only for backwards
compatibility.
This version does not support IP source route tunnelling.
.PP
The tunnelling mechanism allows
.I mrouted
@ -94,6 +94,8 @@ events are printed to stderr.
.IP "level 3"
all level 2 messages plus notifications of all packet
arrivals and departures are printed to stderr.
.PP
Upon startup, mrouted writes its pid to the file /etc/mrouted.pid .
.SH CONFIGURATION
.PP
.I Mrouted
@ -112,38 +114,46 @@ There are four types of configuration commands:
phyint <local-addr> [disable] [metric <m>]
[threshold <t>] [rate_limit <b>]
[boundary <scoped-addr>/<mask-len>]
[boundary (<boundary-name>|<scoped-addr>/<mask-len>)]
[altnet <network>/<mask-len>]
tunnel <local-addr> <remote-addr> [metric <m>]
[threshold <t>] [srcrt] [rate_limit <b>]
[boundary <scoped-addr>/<mask-len>]
[threshold <t>] [rate_limit <b>]
[boundary (<boundary-name>|<scoped-addr>/<mask-len>)]
cache_lifetime <ct>
pruning <off/on>
name <boundary-name> <scoped-addr>/<mask-len>
.fi
.PP
One note about the configuration commands - all the phyint and tunnel
command options must be on a single line except for the boundary option
which may begin on a separate line. A single phyint or tunnel command may
have multiple boundary options.
The file format is free-form; whitespace (including newlines) is not
significant.
The
.I boundary
and
.I altnet
options may be specified as many times as necessary.
.PP
The phyint command can be used to disable multicast routing on the physical
interface identified by local IP address <local-addr>, or to associate a
non-default metric or threshold with the specified physical interface.
The local IP address <local-addr> may be alternatively replaced by the
interface name (e.g le0) for the phyint command only.
interface name (e.g le0).
If a phyint is attached to multiple IP subnets, describe each additional subnet
with the altnet keyword.
Phyint commands must precede tunnel commands.
.PP
The tunnel command can be used to establish a tunnel link between local
IP address <local-addr> and remote IP address <remote-addr>, and to associate
a non-default metric or threshold with that tunnel. The tunnel must be set
up in the mrouted.conf files of both routers before it can be used.
For backwards compatibility with older
.IR mrouted s,
the srcrt keyword specifies
encapsulation using IP source routing.
'\"For backwards compatibility with older
'\".IR mrouted s,
'\"the srcrt keyword specifies
'\"encapsulation using IP source routing.
.PP
The cache_lifetime is a value that determines the amount of time that a
cached multicast route stays in kernel before timing out. The value of this
@ -152,11 +162,15 @@ entry should lie between 300 (5 min) and 86400 (1 day). It defaults to 300.
The pruning <off/on> option is provided for
.IR mrouted
to act as a non-pruning router. It is also possible to start
.Ir mrouted
.IR mrouted
in a non-pruning mode using the "-p" option on the command line. It is
expected that a router would be configured in this manner for test
purposes only. The default mode is pruning enabled.
.PP
You may assign names to boundaries to make configuration easier with
the name keyword. The boundary option on phyint or tunnel commands
can accept either a name or a boundary.
.PP
The metric is the "cost" associated with sending a datagram on the given
interface or tunnel; it may be used to influence the choice of routes.
The metric defaults to 1. Metrics should be kept as small as possible,
@ -178,12 +192,14 @@ use the same metric and threshold for that subnet or tunnel.
.PP
The rate_limit option allows the network administrator to specify a
certain bandwidth in Kbits/second which would be allocated to multicast
traffic.
traffic. It defaults to 500Kbps on tunnels, and 0 (unlimited) on physical
interfaces.
.PP
The boundary option allows an interface
to be configured as an administrative boundary for the specified
scoped address. Packets belonging to this address will not
be forwarded on a scoped interface.
be forwarded on a scoped interface. The boundary option accepts either
a name or a boundary spec.
.PP
.I Mrouted
will not initiate execution if it has fewer than two enabled vifs,
@ -193,6 +209,45 @@ tunnels; such an
.I mrouted
configuration would be better replaced by more
direct tunnels (i.e., eliminate the middle man).
.SH "EXAMPLE CONFIGURATION"
.PP
This is an example configuration for a mythical multicast router at a big
school.
.sp
.nf
#
# mrouted.conf example
#
# Name our boundaries to make it easier
name LOCAL 239.255.0.0/16
name EE 239.254.0.0/16
#
# le1 is our gateway to compsci, don't forward our
# local groups to them
phyint le1 boundary EE
#
# le2 is our interface on the classroom net, it has four
# different length subnets on it.
# note that you can use either an ip address or an
# interface name
phyint 172.16.12.38 boundary EE altnet 172.16.15.0/26
altnet 172.16.15.128/26 altnet 172.16.48.0/24
#
# atm0 is our ATM interface, which doesn't properly
# support multicasting.
phyint atm0 disable
#
# This is an internal tunnel to another EE subnet
# Remove the default tunnel rate limit, since this
# tunnel is over ethernets
tunnel 192.168.5.4 192.168.55.101 metric 1 threshold 1
rate_limit 0
#
# This is our tunnel to the outside world.
# Careful with those boundaries, Eugene.
tunnel 192.168.5.4 10.11.12.13 metric 1 threshold 32
boundary LOCAL boundary EE
.fi
.SH SIGNALS
.PP
.I Mrouted
@ -214,6 +269,10 @@ dumps the internal cache tables to /usr/tmp/mrouted.cache.
dumps the internal routing tables to stderr (only if
.I mrouted
was invoked with a non-zero debug level).
.PP
For convenience in sending signals,
.I mrouted
writes its pid to /etc/mrouted.pid upon startup.
.bp
.SH EXAMPLE
.PP
@ -245,10 +304,10 @@ Virtual Interface Table
3 36.2.0.8 tunnel: 36.6.8.23 3 16
Multicast Routing Table (1136 entries)
Origin-Subnet From-Gateway Metric In-Vif Out-Vifs
36.2 1 0 1* 2 3*
36.8 36.8.0.77 4 2 0* 1* 3*
36.11 1 1 0* 2 3*
Origin-Subnet From-Gateway Metric Tmr In-Vif Out-Vifs
36.2 1 45 0 1* 2 3*
36.8 36.8.0.77 4 15 2 0* 1* 3*
36.11 1 20 1 0* 2 3*
.
.
.
@ -267,7 +326,8 @@ shown at each interface.
.PP
Associated with each subnet from which a multicast datagram can originate
is the address of the previous hop router (unless the subnet is directly-
connected), the metric of the path back to the origin, the incoming vif for
connected), the metric of the path back to the origin, the amount of time
since we last received an update for this subnet, the incoming vif for
multicasts from that origin, and a list of outgoing vifs. "*" means that
the outgoing vif is connected to a leaf of the broadcast tree rooted at the
origin, and a multicast datagram from that origin will be forwarded on that
@ -282,38 +342,58 @@ are created and deleted by
The cache tables look like this:
.nf
Multicast Routing Cache Table (325 entries)
Origin-Subnet Mcast-group CTmr IVif Prcv# Psnt Forwvifs
134.207.7 224.2.140.239 300 1 0 0 2
138.15.103 224.2.203.214 295 1 2 P 0p 2p
128.237.0 224.2.253.119 290 1 1 0 2p
129.215.200 224.2.207.48 40 1 1 0p 2
36.77.14 239.0.1.234 345 2b
Multicast Routing Cache Table (147 entries)
Origin Mcast-group CTmr Age Ptmr IVif Forwvifs
13.2.116/22 224.2.127.255 3m 2m - 0 1
>13.2.116.19
>13.2.116.196
138.96.48/21 224.2.127.255 5m 2m - 0 1
>138.96.48.108
128.9.160/20 224.2.127.255 3m 2m - 0 1
>128.9.160.45
198.106.194/24 224.2.135.190 9m 28s 9m 0P
>198.106.194.22
.fi
Each entry is characterized by the origin subnet number and the
Each entry is characterized by the origin subnet number and mask and the
destination multicast group. The 'CTmr' field indicates the lifetime
(in seconds) of the entry. The entry is deleted from the cache table
when the timer decrements to zero. The Ivif field indicates the
of the entry. The entry is deleted from the cache table
when the timer decrements to zero. The 'Age' field is the time since
this cache entry was originally created. Since cache entries get refreshed
if traffic is flowing, routing entries can grow very old.
The 'Ptmr' field is simply a dash if no prune was sent upstream, or the
amount of time until the upstream prune will time out.
The 'Ivif' field indicates the
incoming vif for multicast packets from that origin. Each router also
maintains a record of the number of prunes received from neighbouring
maintains a record of the number of prunes received from neighboring
routers for a particular source and group. If there are no members of
a multicast group on any downward link of the multicast tree for a
subnet, a prune message is sent to the upstream router. They are
indicated by a "P" in the Psnt field. The Forwvifs field shows the
indicated by a "P" after the vif number. The Forwvifs field shows the
interfaces along which datagrams belonging to the source-group are
forwarded. A "p" indicates that no datagrams are being forwarded along
that interface. An unlisted interface is a leaf subnet with are no
members of the particular group on that subnet. A "b" on an interface
indicates that it is a boundary interface, i.e. traffic will not be
forwarded on the scoped address on that interface.
An additional line with a ">" as the first character is printed for
each source on the subnet. Note that there can be many sources in
one subnet.
.SH FILES
/etc/mrouted.conf
.br
/etc/mrouted.pid
.br
/usr/tmp/mrouted.dump
.br
/usr/tmp/mrouted.cache
.SH SEE ALSO
.BR mrinfo (8) ,
.BR mtrace (8) ,
.BR map-mbone (8)
.sp
DVMRP is described, along with other multicast routing algorithms, in the
paper "Multicast Routing in Internetworks and Extended LANs" by S. Deering,
in the Proceedings of the ACM SIGCOMM '88 Conference.
.SH AUTHORS
Steve Deering & Ajit Thyagarajan
Steve Deering, Ajit Thyagarajan, Bill Fenner

View File

@ -1,26 +1,37 @@
# $Id: mrouted.conf,v 1.5 1994/08/24 23:54:21 thyagara Exp $
# $Id: mrouted.conf,v 3.6 1995/06/25 19:11:55 fenner Exp $
#
# This is the configuration file for "mrouted", an IP multicast router.
# mrouted looks for it in "/etc/mrouted.conf".
#
# Command formats:
#
# cache_lifetime 3600
# name <boundname> <scoped-addr>/<mask-len>
# cache_lifetime 3600 # seconds
# pruning on
#
# phyint <local-addr> [disable] [metric <m>] [threshold <t>] [rate_limit <b>]
# [boundary <scoped-addr>/<mask-len>]
# [boundary (<boundname>|<scoped-addr>/<mask-len>)]
# [altnet (<subnet>/<mask-len>|<subnet>)]
# tunnel <local-addr> <remote-addr> [srcrt] [metric <m>]
# [threshold <t>] [rate_limit <b>]
# [boundary <scoped-addr>/<mask-len>]
# [boundary (<boundname>|<scoped-addr>/<mask-len>)]
#
# NOTE: any phyint commands MUST precede any tunnel commands
# NOTE: boundary commands may appear on a separate line
# (OTHER keywords must be on the same line as phyint or tunnel)
# NOTE: the mask-len is the no. of leading 1's in the mask
# NOTE: rate_limit is in kilobits, and defaults to 500 for tunnels
#
phyint 128.4.2.2 metric 1 threshold 16 boundary 239.2.0.0/16
boundary 239.5.8.0/24
tunnel 128.4.0.77 128.4.0.8 metric 3 rate_limit 500 # <-- EXAMPLE
boundary 239.2.3.3/16 # 239.2.x.x is scoped
# Example of named bounary:
#name LOCAL 239.255.0.0/16
#name EE 239.254.0.0/16 # i.e. the EE dept wants local groups
#
# Example of use of named boundary
#phyint le1 boundary EE # le1 is our interface to comp sci,
# # keep them away from our local groups
#
#
# Template tunnel for mcast_install
tunnel 128.4.0.77 128.4.0.8 metric 1 threshold 64 rate_limit 500 # <-- REPLACE
# boundary LOCAL
#
# You might want to specify a boundary on your tunnel to the outside world,
# as above.

View File

@ -29,7 +29,7 @@
.\" Copyright (c) 1988 The Regents of the University of California.
.\" All rights reserved.
.\"
.\" $Id: mtrace.8,v 3.5 1995/05/09 01:23:58 fenner Exp $
.\" $Id: mtrace.8,v 3.6 1995/06/25 19:14:07 fenner Exp $
.\"
.TH MTRACE 8 "May 8, 1995"
.UC 6
@ -62,7 +62,6 @@ mtrace \- print multicast path from a source to a receiver
.I resp_dest
] [
.B \-s
.I src_addr
] [
.B \-t
.I ttl

File diff suppressed because it is too large Load Diff

View File

@ -7,7 +7,7 @@
* Leland Stanford Junior University.
*
*
* $Id: pathnames.h,v 3.5 1995/05/09 01:00:39 fenner Exp $
* $Id: pathnames.h,v 3.6 1995/06/25 19:17:45 fenner Exp $
*/
#define _PATH_MROUTED_CONF "/etc/mrouted.conf"

File diff suppressed because it is too large Load Diff

View File

@ -7,91 +7,104 @@
* Leland Stanford Junior University.
*
*
* $Id: prune.h,v 1.3 1994/08/24 23:54:40 thyagara Exp $
* $Id: prune.h,v 3.6 1995/06/25 19:19:04 fenner Exp $
*/
/*
* Macro for copying the user-level cache table to the kernel
* level table variable passed on by the setsock option
*/
#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]; \
};
/*
* User level Kernel Cache Table structure
* Group table
*
* 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.
* 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).
*
*/
struct ktable
{
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 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 */
};
/*
* structure to store incoming prunes
* Source table
*
* When source-based prunes exist, there will be a struct ptable here as well.
*/
struct prunlst
struct stable
{
struct prunlst *rl_next;
u_long rl_router;
u_long rl_router_subnet;
vifi_t rl_vifi;
int rl_timer;
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. Can hang off of either group or source.
*/
struct ptable
{
struct ptable *pt_next; /* pointer to the next entry */
u_int32 pt_router; /* router that sent this prune */
vifi_t pt_vifi; /* vif prune received on */
int pt_timer; /* timer for prune */
};
/*
* The packet format for a traceroute request.
*/
struct tr_query {
u_long tr_src; /* traceroute source */
u_long tr_dst; /* traceroute destination */
u_long tr_raddr; /* traceroute response address */
u_int32 tr_src; /* traceroute source */
u_int32 tr_dst; /* traceroute destination */
u_int32 tr_raddr; /* traceroute response address */
#if defined(BYTE_ORDER) && (BYTE_ORDER == LITTLE_ENDIAN)
struct {
u_int qid : 24; /* traceroute query id */
u_int ttl : 8; /* traceroute response ttl */
} q;
#else
struct {
u_int ttl : 8; /* traceroute response ttl */
u_int qid : 24; /* traceroute query id */
} q;
} tr_query;
#endif /* BYTE_ORDER */
};
#define tr_rttl q.ttl
#define tr_qid q.qid
/*
* Traceroute response format. A traceroute response has a tr_query at the
* beginning, followed by one tr_resp for each hop taken.
*/
struct tr_resp {
u_long tr_qarr; /* query arrival time */
u_long tr_inaddr; /* incoming interface address */
u_long tr_outaddr; /* outgoing interface address */
u_long tr_rmtaddr; /* parent address in source tree */
u_long tr_vifin; /* input packet count on interface */
u_long tr_vifout; /* output packet count on interface */
u_long tr_pktcnt; /* total incoming packets for src-grp */
u_int32 tr_qarr; /* query arrival time */
u_int32 tr_inaddr; /* incoming interface address */
u_int32 tr_outaddr; /* outgoing interface address */
u_int32 tr_rmtaddr; /* parent address in source tree */
u_int32 tr_vifin; /* input packet count on interface */
u_int32 tr_vifout; /* output packet count on interface */
u_int32 tr_pktcnt; /* total incoming packets for src-grp */
u_char tr_rproto; /* routing protocol deployed on router */
u_char tr_fttl; /* ttl required to forward on outvif */
u_char tr_smask; /* subnet mask for src addr */
u_char tr_rflags; /* forwarding error codes */
} tr_resp;
};
/* defs within mtrace */
#define QUERY 1
@ -100,24 +113,31 @@ struct tr_resp {
#define RLEN sizeof(struct tr_resp)
/* fields for tr_rflags (forwarding error codes) */
#define TR_NO_ERR 0x0
#define TR_WRONG_IF 0x1
#define TR_PRUNED 0x2
#define TR_SCOPED 0x4
#define TR_NO_RTE 0x5
#define TR_NO_ERR 0
#define TR_WRONG_IF 1
#define TR_PRUNED 2
#define TR_OPRUNED 3
#define TR_SCOPED 4
#define TR_NO_RTE 5
#define TR_NO_FWD 7
#define TR_NO_SPACE 0x81
#define TR_OLD_ROUTER 0x82
/* fields for tr_rproto (routing protocol) */
#define PROTO_DVMRP 0x1
#define PROTO_MOSPF 0x2
#define PROTO_PIM 0x3
#define PROTO_CBT 0x4
#define PROTO_DVMRP 1
#define PROTO_MOSPF 2
#define PROTO_PIM 3
#define PROTO_CBT 4
#define MASK_TO_VAL(x, i) { \
(i) = 0; \
while ((x) << (i)) \
u_int32 _x = ntohl(x); \
(i) = 1; \
while ((_x) <<= 1) \
(i)++; \
}
};
#define VAL_TO_MASK(x, i) { \
x = ~((1 << (32 - (i))) - 1); \
}
x = htonl(~((1 << (32 - (i))) - 1)); \
};
#define NBR_VERS(n) (((n)->al_pv << 8) + (n)->al_mv)

View File

@ -7,13 +7,18 @@
* Leland Stanford Junior University.
*
*
* $Id: route.c,v 1.8 1994/08/24 23:54:42 thyagara Exp $
* $Id: route.c,v 3.6 1995/06/25 19:20:19 fenner Exp $
*/
#include "defs.h"
/*
* This define statement saves a lot of space later
*/
#define RT_ADDR (struct rtentry *)&routing_table
/*
* Exported variables.
*/
@ -21,20 +26,38 @@ int routes_changed; /* 1=>some routes have changed */
int delay_change_reports; /* 1=>postpone change reports */
/*
* The routing table is shared with prune.c , so must not be static.
*/
struct rtentry *routing_table; /* pointer to list of route entries */
/*
* Private variables.
*/
static struct rtentry *routing_table; /* pointer to list of route entries */
static struct rtentry *rtp; /* pointer to a route entry */
static struct rtentry *rt_end; /* pointer to last route entry */
unsigned int nroutes; /* current number of route entries */
/*
* Private functions.
*/
static int init_children_and_leaves __P((struct rtentry *r,
vifi_t parent));
static int find_route __P((u_int32 origin, u_int32 mask));
static void create_route __P((u_int32 origin, u_int32 mask));
static void discard_route __P((struct rtentry *prev_r));
static int compare_rts __P((const void *rt1, const void *rt2));
static int report_chunk __P((struct rtentry *start_rt, vifi_t vifi,
u_int32 dst));
/*
* Initialize the routing table and associated variables.
*/
void init_routes()
void
init_routes()
{
routing_table = NULL;
rt_end = RT_ADDR;
nroutes = 0;
routes_changed = FALSE;
delay_change_reports = FALSE;
@ -47,7 +70,8 @@ void init_routes()
* Return TRUE if this changes the value of either the children or
* leaf bitmaps for 'r'.
*/
static int init_children_and_leaves(r, parent)
static int
init_children_and_leaves(r, parent)
register struct rtentry *r;
register vifi_t parent;
{
@ -91,7 +115,8 @@ static int init_children_and_leaves(r, parent)
* A new vif has come up -- update the children and leaf bitmaps in all route
* entries to take that into account.
*/
void add_vif_to_routes(vifi)
void
add_vif_to_routes(vifi)
register vifi_t vifi;
{
register struct rtentry *r;
@ -124,7 +149,8 @@ void add_vif_to_routes(vifi)
* and update the children bitmaps in all other route entries to take into
* account the failed vif.
*/
void delete_vif_from_routes(vifi)
void
delete_vif_from_routes(vifi)
register vifi_t vifi;
{
register struct rtentry *r;
@ -158,8 +184,9 @@ void delete_vif_from_routes(vifi)
* considered a dominant or subordinate router in any route entries,
* take appropriate action.
*/
void delete_neighbor_from_routes(addr, vifi)
register u_long addr;
void
delete_neighbor_from_routes(addr, vifi)
register u_int32 addr;
register vifi_t vifi;
{
register struct rtentry *r;
@ -213,9 +240,10 @@ void delete_neighbor_from_routes(addr, vifi)
* a single message be in the same order as the route entries in the routing
* table.
*/
void start_route_updates()
void
start_route_updates()
{
rtp = (struct rtentry *)&routing_table;
rtp = RT_ADDR;
}
@ -228,8 +256,9 @@ void start_route_updates()
* This code is optimized for the normal case in which the first entry to
* be examined is the matching entry.
*/
static int find_route(origin, mask)
register u_long origin, mask;
static int
find_route(origin, mask)
register u_int32 origin, mask;
{
register struct rtentry *r;
@ -239,9 +268,9 @@ static int find_route(origin, mask)
rtp = r;
return (TRUE);
}
if (ntohl(mask) > ntohl(r->rt_originmask) ||
if (ntohl(mask) < ntohl(r->rt_originmask) ||
(mask == r->rt_originmask &&
ntohl(origin) > ntohl(r->rt_origin))) {
ntohl(origin) < ntohl(r->rt_origin))) {
rtp = r;
r = r->rt_next;
}
@ -250,31 +279,6 @@ static int find_route(origin, mask)
return (FALSE);
}
/*
* Search the entire routing table, looking for an entry which conflicts
* with the given origin and mask, for example, an entry which has the same
* origin under a different mask. If a conflicting entry is found, return
* a pointer to the entry preceding it (to facilitate deletion); if no
* conflict is found, return NULL.
*/
static struct rtentry *find_conflicting_route(origin, mask)
register u_long origin, mask;
{
register struct rtentry *r, *prev_r;
for (prev_r = (struct rtentry *)&routing_table, r = routing_table;
r != NULL;
prev_r = r, r = r->rt_next ) {
if ((origin & r->rt_originmask) == r->rt_origin ||
(r->rt_origin & mask) == origin) {
return (prev_r);
}
}
return (NULL);
}
/*
* Create a new routing table entry for the specified origin and link it into
* the routing table. The shared variable 'rtp' is assumed to point to the
@ -285,13 +289,15 @@ static struct rtentry *find_conflicting_route(origin, mask)
* in the new route entry; the caller is responsible for filling in the the
* rest.
*/
static void create_route(origin, mask)
u_long origin, mask;
static void
create_route(origin, mask)
u_int32 origin, mask;
{
register struct rtentry *r;
if ((r = (struct rtentry *) malloc(sizeof(struct rtentry)
+ (3 * numvifs * sizeof(u_long)))) == NULL) {
if ((r = (struct rtentry *) malloc(sizeof(struct rtentry) +
(2 * numvifs * sizeof(u_int32)) +
(numvifs * sizeof(u_int)))) == NULL) {
log(LOG_ERR, 0, "ran out of memory"); /* fatal */
}
r->rt_origin = origin;
@ -301,12 +307,18 @@ static void create_route(origin, mask)
else if (((char *)&mask)[1] != 0) r->rt_originwidth = 2;
else r->rt_originwidth = 1;
r->rt_flags = 0;
r->rt_dominants = (u_long *)(r + 1);
r->rt_subordinates = (u_long *)(r->rt_dominants + numvifs);
r->rt_leaf_timers = (u_long *)(r->rt_subordinates + numvifs);
r->rt_dominants = (u_int32 *)(r + 1);
r->rt_subordinates = (u_int32 *)(r->rt_dominants + numvifs);
r->rt_leaf_timers = (u_int *)(r->rt_subordinates + numvifs);
r->rt_groups = NULL;
r->rt_next = rtp->rt_next;
rtp->rt_next = r;
r->rt_prev = rtp;
if (r->rt_next != NULL)
(r->rt_next)->rt_prev = r;
else
rt_end = r;
rtp = r;
++nroutes;
}
@ -315,13 +327,18 @@ static void create_route(origin, mask)
/*
* Discard the routing table entry following the one to which 'prev_r' points.
*/
static void discard_route(prev_r)
static void
discard_route(prev_r)
register struct rtentry *prev_r;
{
register struct rtentry *r;
r = prev_r->rt_next;
prev_r->rt_next = r->rt_next;
if (prev_r->rt_next != NULL)
(prev_r->rt_next)->rt_prev = prev_r;
else
rt_end = prev_r;
free((char *)r);
--nroutes;
}
@ -333,14 +350,14 @@ static void discard_route(prev_r)
* address of a neighboring router from which the report arrived, or zero
* to indicate a change of status of one of our own interfaces.
*/
void update_route(origin, mask, metric, src, vifi)
u_long origin, mask;
void
update_route(origin, mask, metric, src, vifi)
u_int32 origin, mask;
int metric;
u_long src;
u_int32 src;
vifi_t vifi;
{
register struct rtentry *r;
struct rtentry *prev_r;
int adj_metric;
/*
@ -376,39 +393,19 @@ void update_route(origin, mask, metric, src, vifi)
return;
}
/*
* If the new origin and mask are inconsistent with an entry
* already in the routing table, either ignore this update
* (if it came from another router), or delete the conflicting
* entry (if the update is for a directly-connected subnet).
*/
if ((prev_r = find_conflicting_route(origin, mask)) != NULL ) {
if (src != 0) {
log(LOG_INFO, 0,
"%s reports a conflicting origin (%s) and mask (%08x)",
inet_fmt(src, s1), inet_fmt(origin, s2), ntohl(mask));
return;
}
else {
r = prev_r->rt_next;
log(LOG_INFO, 0,
"deleting route with conflicting origin (%s), mask (%08x)",
inet_fmt(r->rt_origin, s1), ntohl(r->rt_originmask));
if (r->rt_metric != UNREACHABLE) {
del_table_entry(r, 0, DEL_ALL_ROUTES);
}
discard_route(prev_r);
if (rtp == r) rtp = prev_r;
}
}
/*
* OK, create the new routing entry. 'rtp' will be left pointing
* to the new entry.
*/
create_route(origin, mask);
/*
* Now "steal away" any sources that belong under this route
* by deleting any cache entries they might have created
* and allowing the kernel to re-request them.
*/
steal_sources(rtp);
rtp->rt_metric = UNREACHABLE; /* temporary; updated below */
}
@ -579,13 +576,14 @@ void update_route(origin, mask, metric, src, vifi)
/*
* On every timer interrupt, advance the timer in each routing entry.
*/
void age_routes()
void
age_routes()
{
register struct rtentry *r;
register struct rtentry *prev_r;
register vifi_t vifi;
for (prev_r = (struct rtentry *)&routing_table, r = routing_table;
for (prev_r = RT_ADDR, r = routing_table;
r != NULL;
prev_r = r, r = r->rt_next) {
@ -602,8 +600,19 @@ void age_routes()
* Unlike other timers, leaf timers decrement.
*/
if ((r->rt_leaf_timers[vifi] -= TIMER_INTERVAL) == 0){
VIFM_SET(vifi, r->rt_leaves);
update_table_entry(r);
#ifdef NOTYET
/* If the vif is a physical leaf but has neighbors,
* it is not a tree leaf. If I am a leaf, then no
* interface with neighbors is a tree leaf. */
if (!(((uvifs[vifi].uv_flags & VIFF_LEAF) ||
(vifs_with_neighbors == 1)) &&
(uvifs[vifi].uv_neighbors != NULL))) {
#endif
VIFM_SET(vifi, r->rt_leaves);
update_table_entry(r);
#ifdef NOTYET
}
#endif
}
else {
r->rt_flags |= RTF_LEAF_TIMING;
@ -616,6 +625,7 @@ void age_routes()
/*
* Time to garbage-collect the route entry.
*/
del_table_entry(r, 0, DEL_ALL_ROUTES);
discard_route(prev_r);
r = prev_r;
}
@ -648,7 +658,8 @@ void age_routes()
* on the kernel to do its own cleanup -- no point in making all those
* expensive kernel calls now.
*/
void expire_all_routes()
void
expire_all_routes()
{
register struct rtentry *r;
@ -663,11 +674,12 @@ void expire_all_routes()
/*
* Delete all the routes in the routing table.
*/
void free_all_routes()
void
free_all_routes()
{
register struct rtentry *r;
r = (struct rtentry *)&routing_table;
r = RT_ADDR;
while (r->rt_next)
discard_route(r);
@ -677,12 +689,13 @@ void free_all_routes()
/*
* Process an incoming neighbor probe message.
*/
void accept_probe(src, dst, p, datalen, level)
u_long src;
u_long dst;
void
accept_probe(src, dst, p, datalen, level)
u_int32 src;
u_int32 dst;
char *p;
int datalen;
u_long level;
u_int32 level;
{
vifi_t vifi;
@ -692,55 +705,56 @@ void accept_probe(src, dst, p, datalen, level)
return;
}
if (!update_neighbor(vifi, src, DVMRP_PROBE, p, datalen, level))
return;
report(ALL_ROUTES, vifi, src);
update_neighbor(vifi, src, DVMRP_PROBE, p, datalen, level);
}
struct newrt {
u_long mask;
u_long origin;
u_int32 mask;
u_int32 origin;
int metric;
int pad;
};
int compare_rts(r1, r2)
register struct newrt *r1;
register struct newrt *r2;
static int
compare_rts(rt1, rt2)
const void *rt1;
const void *rt2;
{
register unsigned long m1 = ntohl(r1->mask);
register unsigned long m2 = ntohl(r2->mask);
register unsigned long o1, o2;
register struct newrt *r1 = (struct newrt *)rt1;
register struct newrt *r2 = (struct newrt *)rt2;
register u_int32 m1 = ntohl(r1->mask);
register u_int32 m2 = ntohl(r2->mask);
register u_int32 o1, o2;
if (m1 > m2)
return (1);
if (m1 < m2)
return (-1);
if (m1 < m2)
return (1);
/* masks are equal */
o1 = ntohl(r1->origin);
o2 = ntohl(r2->origin);
if (o1 > o2)
return (1);
if (o1 < o2)
return (-1);
if (o1 < o2)
return (1);
return (0);
}
/*
* Process an incoming route report message.
*/
void accept_report(src, dst, p, datalen, level)
u_long src, dst, level;
void
accept_report(src, dst, p, datalen, level)
u_int32 src, dst, level;
register char *p;
register int datalen;
{
vifi_t vifi;
register int width, i, nrt = 0;
int metric;
u_long mask;
u_long origin;
u_int32 mask;
u_int32 origin;
struct newrt rt[4096];
if ((vifi = find_vif(src, dst)) == NO_VIF) {
@ -767,10 +781,10 @@ void accept_report(src, dst, p, datalen, level)
inet_fmt(src, s1));
return;
}
((char *)&mask)[0] = 0xff; width = 1;
if ((((char *)&mask)[1] = *p++) != 0) width = 2;
if ((((char *)&mask)[2] = *p++) != 0) width = 3;
if ((((char *)&mask)[3] = *p++) != 0) width = 4;
((u_char *)&mask)[0] = 0xff; width = 1;
if ((((u_char *)&mask)[1] = *p++) != 0) width = 2;
if ((((u_char *)&mask)[2] = *p++) != 0) width = 3;
if ((((u_char *)&mask)[3] = *p++) != 0) width = 4;
datalen -= 3;
do { /* Loop through (origin, metric) pairs */
@ -787,14 +801,22 @@ void accept_report(src, dst, p, datalen, level)
datalen -= width + 1;
rt[nrt].mask = mask;
rt[nrt].origin = origin;
rt[nrt].metric = metric;
rt[nrt].metric = (metric & 0x7f);
++nrt;
} while (!(metric & 0x80));
}
qsort((char*)rt, nrt, sizeof(rt[0]), compare_rts);
start_route_updates();
/*
* If the last entry is default, change mask from 0xff000000 to 0
*/
if (rt[nrt-1].origin == 0)
rt[nrt-1].mask = 0;
log(LOG_DEBUG, 0, "Updating %d routes from %s to %s", nrt,
inet_fmt(src, s1), inet_fmt(dst, s2));
for (i = 0; i < nrt; ++i)
update_route(rt[i].origin, rt[i].mask, (rt[i].metric & 0x7f),
update_route(rt[i].origin, rt[i].mask, rt[i].metric,
src, vifi);
if (routes_changed && !delay_change_reports)
@ -806,26 +828,43 @@ void accept_report(src, dst, p, datalen, level)
* Send a route report message to destination 'dst', via virtual interface
* 'vifi'. 'which_routes' specifies ALL_ROUTES or CHANGED_ROUTES.
*/
void report(which_routes, vifi, dst)
void
report(which_routes, vifi, dst)
int which_routes;
vifi_t vifi;
u_long dst;
u_int32 dst;
{
register struct rtentry *r;
register char *p;
register int i;
int datalen;
int width;
u_long mask;
u_long src;
int datalen = 0;
int width = 0;
u_int32 mask = 0;
u_int32 src;
u_int32 nflags;
src = uvifs[vifi].uv_lcl_addr;
p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
datalen = 0;
mask = 0;
for (r = routing_table; r != NULL; r = r->rt_next) {
#ifdef NOTYET
/* If I'm not a leaf, but the neighbor is a leaf, only advertise default */
if ((vifs_with_neighbors != 1) && (uvifs[vifi].uv_flags & VIFF_LEAF)) {
*p++ = 0; /* 0xff000000 mask */
*p++ = 0;
*p++ = 0;
*p++ = 0; /* class A net 0.0.0.0 == default */
*p++ = 0x81; /*XXX metric 1, is this safe? */
datalen += 5;
send_igmp(src, dst, IGMP_DVMRP, DVMRP_REPORT,
htonl(MROUTED_LEVEL), datalen);
return;
}
#endif
nflags = (uvifs[vifi].uv_flags & VIFF_LEAF) ? 0 : LEAF_FLAGS;
for (r = rt_end; r != RT_ADDR; r = r->rt_prev) {
if (which_routes == CHANGED_ROUTES && !(r->rt_flags & RTF_CHANGED))
continue;
@ -839,14 +878,14 @@ void report(which_routes, vifi, dst)
(r->rt_originwidth + 4)) > MAX_DVMRP_DATA_LEN) {
*(p-1) |= 0x80;
send_igmp(src, dst, IGMP_DVMRP, DVMRP_REPORT,
htonl(MROUTED_LEVEL), datalen);
htonl(MROUTED_LEVEL | nflags), datalen);
p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
datalen = 0;
mask = 0;
}
if(r->rt_originmask != mask) {
if (r->rt_originmask != mask || datalen == 0) {
mask = r->rt_originmask;
width = r->rt_originwidth;
if (datalen != 0) *(p-1) |= 0x80;
@ -869,7 +908,7 @@ void report(which_routes, vifi, dst)
if (datalen != 0) {
*(p-1) |= 0x80;
send_igmp(src, dst, IGMP_DVMRP, DVMRP_REPORT,
htonl(MROUTED_LEVEL), datalen);
htonl(MROUTED_LEVEL | nflags), datalen);
}
}
@ -878,7 +917,8 @@ void report(which_routes, vifi, dst)
* Send a route report message to all neighboring routers.
* 'which_routes' specifies ALL_ROUTES or CHANGED_ROUTES.
*/
void report_to_all_neighbors(which_routes)
void
report_to_all_neighbors(which_routes)
int which_routes;
{
register vifi_t vifi;
@ -926,26 +966,38 @@ void report_to_all_neighbors(which_routes)
* Send a route report message to destination 'dst', via virtual interface
* 'vifi'. 'which_routes' specifies ALL_ROUTES or CHANGED_ROUTES.
*/
int report_chunk(start_rt, vifi, dst)
static int
report_chunk(start_rt, vifi, dst)
register struct rtentry *start_rt;
vifi_t vifi;
u_long dst;
u_int32 dst;
{
register struct rtentry *r;
register char *p;
register int i;
register int nrt = 0;
int datalen;
int width;
u_long mask;
u_long src;
int datalen = 0;
int width = 0;
u_int32 mask = 0;
u_int32 src;
u_int32 nflags;
src = uvifs[vifi].uv_lcl_addr;
p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
datalen = 0;
mask = 0;
for (r = start_rt; r != NULL; r = r->rt_next) {
nflags = (uvifs[vifi].uv_flags & VIFF_LEAF) ? 0 : LEAF_FLAGS;
for (r = start_rt; r != RT_ADDR; r = r->rt_prev) {
#ifdef NOTYET
/* Don't send poisoned routes back to parents if I am a leaf */
if ((vifs_with_neighbors == 1) && (r->rt_parent == vifi)
&& (r->rt_metric > 1)) {
++nrt;
continue;
}
#endif
/*
* If there is no room for this route in the current message,
* send it & return how many routes we sent.
@ -955,10 +1007,10 @@ int report_chunk(start_rt, vifi, dst)
(r->rt_originwidth + 4)) > MAX_DVMRP_DATA_LEN) {
*(p-1) |= 0x80;
send_igmp(src, dst, IGMP_DVMRP, DVMRP_REPORT,
htonl(MROUTED_LEVEL), datalen);
htonl(MROUTED_LEVEL | nflags), datalen);
return (nrt);
}
if(r->rt_originmask != mask) {
if (r->rt_originmask != mask || datalen == 0) {
mask = r->rt_originmask;
width = r->rt_originwidth;
if (datalen != 0) *(p-1) |= 0x80;
@ -979,21 +1031,22 @@ int report_chunk(start_rt, vifi, dst)
if (datalen != 0) {
*(p-1) |= 0x80;
send_igmp(src, dst, IGMP_DVMRP, DVMRP_REPORT,
htonl(MROUTED_LEVEL), datalen);
htonl(MROUTED_LEVEL | nflags), datalen);
}
return (nrt);
}
/*
* send the next chunk of our routing table to all neighbors.
* return the length of the smallest chunk we sent out.
*/
int report_next_chunk()
int
report_next_chunk()
{
register vifi_t vifi;
register struct uvif *v;
register struct rtentry *r;
register struct rtentry *sr;
register int i, n = 0;
register int i, n = 0, min = 20000;
static int start_rt;
if (nroutes <= 0)
@ -1002,24 +1055,36 @@ int report_next_chunk()
/*
* find this round's starting route.
*/
for (sr = routing_table, i = start_rt; --i >= 0; ) {
sr = sr->rt_next;
if (sr == NULL)
sr = routing_table;
for (sr = rt_end, i = start_rt; --i >= 0; ) {
sr = sr->rt_prev;
if (sr == RT_ADDR)
sr = rt_end;
}
/*
* send one chunk of routes starting at this round's start to
* all our neighbors.
*/
for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
if (v->uv_neighbors != NULL) {
if ((v->uv_neighbors != NULL)
#ifdef NOTYET
&& !(v->uv_flags & VIFF_LEAF)
#endif
) {
n = report_chunk(sr, vifi,
(v->uv_flags & VIFF_TUNNEL) ? v->uv_rmt_addr
: dvmrp_group);
if (n < min)
min = n;
}
}
if (debug)
printf("update %d starting at %d of %d\n", n, start_rt, nroutes);
if (min == 20000)
min = 0; /* Neighborless router didn't send any routes */
n = min;
log(LOG_INFO, 0, "update %d starting at %d of %d",
n, (nroutes - start_rt), nroutes);
start_rt = (start_rt + n) % nroutes;
return (n);
}
@ -1028,28 +1093,29 @@ int report_next_chunk()
/*
* Print the contents of the routing table on file 'fp'.
*/
void dump_routes(fp)
void
dump_routes(fp)
FILE *fp;
{
register struct rtentry *r;
register int i;
fprintf(fp,
"Multicast Routing Table (%u %s)\n%s",
"Multicast Routing Table (%u %s)\n%s\n",
nroutes, (nroutes == 1) ? "entry" : "entries",
" Origin-Subnet From-Gateway Metric In-Vif Out-Vifs\n");
" Origin-Subnet From-Gateway Metric Tmr In-Vif Out-Vifs");
for (r = routing_table; r != NULL; r = r->rt_next) {
fprintf(fp, " %-15s %-15s ",
fprintf(fp, " %-18s %-15s ",
inet_fmts(r->rt_origin, r->rt_originmask, s1),
(r->rt_gateway == 0) ? "" : inet_fmt(r->rt_gateway, s2));
fprintf(fp, (r->rt_metric == UNREACHABLE) ? " NR " : "%4u ",
r->rt_metric);
fprintf(fp, "%7u ",
r->rt_parent);
fprintf(fp, " %3u %3u ", r->rt_timer, r->rt_parent);
for (i = 0; i < numvifs; ++i) {
if (VIFM_ISSET(i, r->rt_children)) {
@ -1062,8 +1128,9 @@ void dump_routes(fp)
fprintf(fp, "\n");
}
struct rtentry *determine_route(src)
u_long src;
struct rtentry *
determine_route(src)
u_int32 src;
{
struct rtentry *rt;
@ -1073,4 +1140,3 @@ struct rtentry *determine_route(src)
}
return rt;
}

View File

@ -7,16 +7,16 @@
* Leland Stanford Junior University.
*
*
* $Id: route.h,v 1.3 1993/05/30 01:36:38 deering Exp $
* $Id: route.h,v 3.6 1995/06/25 19:21:05 fenner Exp $
*/
/*
* Routing Table Entry, one per subnet from which a multicast could originate.
* (Note: all addresses, subnet numbers and masks are kept in NETWORK order.)
*
* The Routing Table is stored as a singly-linked list of these structures,
* ordered by increasing value of rt_originmask and, secondarily, by
* increasing value of rt_origin within each rt_originmask value.
* The Routing Table is stored as a doubly-linked list of these structures,
* ordered by decreasing value of rt_originmask and, secondarily, by
* decreasing value of rt_origin within each rt_originmask value.
* This data structure is efficient for generating route reports, whether
* full or partial, for processing received full reports, for clearing the
* CHANGED flags, and for periodically advancing the timers in all routes.
@ -27,24 +27,25 @@
*/
struct rtentry {
struct rtentry *rt_next; /* link to next entry MUST BE FIRST */
u_long rt_origin; /* subnet origin of multicasts */
u_long rt_originmask; /* subnet mask for origin */
u_int32 rt_origin; /* subnet origin of multicasts */
u_int32 rt_originmask; /* subnet mask for origin */
short rt_originwidth; /* # bytes of origin subnet number */
u_char rt_metric; /* cost of route back to origin */
u_char rt_flags; /* RTF_ flags defined below */
u_long rt_gateway; /* first-hop gateway back to origin */
u_int32 rt_gateway; /* first-hop gateway back to origin */
vifi_t rt_parent; /* incoming vif (ie towards origin) */
vifbitmap_t rt_children; /* outgoing children vifs */
vifbitmap_t rt_leaves; /* subset of outgoing children vifs */
u_long *rt_dominants; /* per vif dominant gateways */
u_long *rt_subordinates; /* per vif subordinate gateways */
u_long *rt_leaf_timers; /* per vif leaf confirmation timers */
u_long rt_timer; /* for timing out the route entry */
u_int32 *rt_dominants; /* per vif dominant gateways */
u_int32 *rt_subordinates; /* per vif subordinate gateways */
u_int *rt_leaf_timers; /* per vif leaf confirmation timers */
u_int rt_timer; /* for timing out the route entry */
struct rtentry *rt_prev; /* link to previous entry */
struct gtable *rt_groups; /* link to active groups */
};
#define RTF_CHANGED 0x01 /* route changed but not reported */
#define RTF_LEAF_TIMING 0x02 /* some leaf timers are running */
#define ALL_ROUTES 0 /* possible arguments to report() */
#define CHANGED_ROUTES 1 /* and report_to_all_neighbors() */

View File

@ -33,6 +33,10 @@
#ifdef RSRR
#include "defs.h"
#include <sys/param.h>
#if (defined(BSD) && (BSD >= 199103))
#include <stddef.h>
#endif
/* Taken from prune.c */
/*
@ -64,11 +68,13 @@ int client_length = sizeof(client_addr);
/*
* Procedure definitions needed internally.
*/
void rsrr_accept();
void rsrr_accept_iq();
int rsrr_accept_rq();
int rsrr_send();
void rsrr_cache();
static void rsrr_accept __P((int recvlen));
static void rsrr_accept_iq __P((void));
static int rsrr_accept_rq __P((struct rsrr_rq *route_query, int flags,
struct gtable *gt_notify));
static int rsrr_send __P((int sendlen));
static void rsrr_cache __P((struct gtable *gt,
struct rsrr_rq *route_query));
/* Initialize RSRR socket */
void
@ -84,7 +90,13 @@ rsrr_init()
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sun_family = AF_UNIX;
strcpy(serv_addr.sun_path, RSRR_SERV_PATH);
#if (defined(BSD) && (BSD >= 199103))
servlen = offsetof(struct sockaddr_un, sun_path) +
strlen(serv_addr.sun_path);
serv_addr.sun_len = servlen;
#else
servlen = sizeof(serv_addr.sun_family) + strlen(serv_addr.sun_path);
#endif
if (bind(rsrr_socket, (struct sockaddr *) &serv_addr, servlen) < 0)
log(LOG_ERR, errno, "Can't bind RSRR socket");
@ -95,14 +107,15 @@ rsrr_init()
/* Read a message from the RSRR socket */
void
rsrr_read()
rsrr_read(rfd)
fd_set *rfd;
{
register int rsrr_recvlen;
register int omask;
bzero((char *) &client_addr, sizeof(client_addr));
rsrr_recvlen = recvfrom(rsrr_socket, rsrr_recv_buf, sizeof(rsrr_recv_buf),
0, (struct sockaddr *)&client_addr,&client_length);
0, (struct sockaddr *)&client_addr, &client_length);
if (rsrr_recvlen < 0) {
if (errno != EINTR)
log(LOG_ERR, errno, "RSRR recvfrom");
@ -117,7 +130,7 @@ rsrr_read()
/* Accept a message from the reservation protocol and take
* appropriate action.
*/
void
static void
rsrr_accept(recvlen)
int recvlen;
{
@ -183,7 +196,7 @@ rsrr_accept(recvlen)
}
/* Send an Initial Reply to the reservation protocol. */
void
static void
rsrr_accept_iq()
{
struct rsrr_header *rsrr;
@ -235,7 +248,7 @@ rsrr_accept_iq()
* kernel table entry contains the routing info to use for a route
* change notification.
*/
int
static int
rsrr_accept_rq(route_query,flags,gt_notify)
struct rsrr_rq *route_query;
int flags;
@ -355,7 +368,7 @@ rsrr_accept_rq(route_query,flags,gt_notify)
}
/* Send an RSRR message. */
int
static int
rsrr_send(sendlen)
int sendlen;
{
@ -368,30 +381,28 @@ rsrr_send(sendlen)
/* Check for errors. */
if (error < 0) {
log(LOG_WARNING, errno, "Failed send on RSRR socket");
return error;
}
if (error != sendlen) {
} else if (error != sendlen) {
log(LOG_WARNING, 0,
"Sent only %d out of %d bytes on RSRR socket\n", error, sendlen);
return error;
}
return error;
}
/* Cache a message being sent to a client. Currently only used for
* caching Route Reply messages for route change notification.
*/
void
static void
rsrr_cache(gt,route_query)
struct gtable *gt;
struct rsrr_rq *route_query;
{
struct rsrr_cache *rc,*rc_prev;
struct rsrr_cache *rc, **rcnp;
struct rsrr_header *rsrr;
rsrr = (struct rsrr_header *) rsrr_send_buf;
rc = gt->gt_rsrr_cache;
while (rc) {
rcnp = &gt->gt_rsrr_cache;
while ((rc = *rcnp) != NULL) {
if ((rc->route_query.source_addr.s_addr ==
route_query->source_addr.s_addr) &&
(rc->route_query.dest_addr.s_addr ==
@ -402,22 +413,18 @@ rsrr_cache(gt,route_query)
*/
if (!BIT_TST(rsrr->flags,RSRR_NOTIFICATION_BIT)) {
/* Delete cache entry. */
if (rc == gt->gt_rsrr_cache)
/* Deleting first entry. */
gt->gt_rsrr_cache = rc->next;
else
rc_prev->next = rc->next;
*rcnp = rc->next;
free(rc);
} else {
/* Update */
rc->route_query.query_id = route_query->query_id;
printf("Update cached query id %d from client %s\n",
rc->route_query.query_id,rc->client_addr.sun_path);
log(LOG_DEBUG, 0,
"Update cached query id %ld from client %s\n",
rc->route_query.query_id, rc->client_addr.sun_path);
}
return;
}
rc_prev = rc;
rc = rc->next;
rcnp = &rc->next;
}
/* Cache entry doesn't already exist. Create one and insert at
@ -433,7 +440,7 @@ rsrr_cache(gt,route_query)
rc->client_length = client_length;
rc->next = gt->gt_rsrr_cache;
gt->gt_rsrr_cache = rc;
printf("Cached query id %d from client %s\n",
log(LOG_DEBUG, 0, "Cached query id %ld from client %s\n",
rc->route_query.query_id,rc->client_addr.sun_path);
}
@ -445,30 +452,23 @@ rsrr_cache_send(gt,notify)
struct gtable *gt;
int notify;
{
struct rsrr_cache *rc,*rc_next,*rc_prev;
struct rsrr_cache *rc, **rcnp;
int flags = 0;
rc = gt->gt_rsrr_cache;
while (rc) {
rc_next = rc->next;
if (notify)
BIT_SET(flags,RSRR_NOTIFICATION_BIT);
if (notify)
BIT_SET(flags,RSRR_NOTIFICATION_BIT);
rcnp = &gt->gt_rsrr_cache;
while ((rc = *rcnp) != NULL) {
if (rsrr_accept_rq(&rc->route_query,flags,gt) < 0) {
printf("Deleting cached query id %d from client %s\n",
log(LOG_DEBUG, 0, "Deleting cached query id %ld from client %s\n",
rc->route_query.query_id,rc->client_addr.sun_path);
/* Delete cache entry. */
if (rc == gt->gt_rsrr_cache)
/* Deleting first entry. */
gt->gt_rsrr_cache = rc_next;
else
rc_prev->next = rc_next;
*rcnp = rc->next;
free(rc);
} else {
rc_prev = rc;
rcnp = &rc->next;
}
rc = rc_next;
}
}

View File

@ -47,7 +47,7 @@
#define RSRR_ROUTE_QUERY 3
#define RSRR_ROUTE_REPLY 4
/* RSRR Initial Reply (Vif) Status bits.
/* RSRR Initial Reply (Vif) Status bits
* Each definition represents the position of the bit from right to left.
*
* Right-most bit is the disabled bit, set if the vif is administratively
@ -56,7 +56,7 @@
#define RSRR_DISABLED_BIT 0
/* All other bits are zeroes */
/* RSRR Route Query/Reply flag bits.
/* RSRR Route Query/Reply flag bits
* Each definition represents the position of the bit from right to left.
*
* Right-most bit is the Route Change Notification bit, set if the

File diff suppressed because it is too large Load Diff

View File

@ -7,7 +7,7 @@
* Leland Stanford Junior University.
*
*
* $Id: vif.h,v 1.6 1994/08/24 23:54:47 thyagara Exp $
* $Id: vif.h,v 3.6 1995/06/25 19:53:22 fenner Exp $
*/
/*
@ -22,15 +22,17 @@ struct uvif {
u_char uv_metric; /* cost of this vif */
u_int uv_rate_limit; /* rate limit on this vif */
u_char uv_threshold; /* min ttl required to forward on vif */
u_long uv_lcl_addr; /* local address of this vif */
u_long uv_rmt_addr; /* remote end-point addr (tunnels only) */
u_long uv_subnet; /* subnet number (phyints only) */
u_long uv_subnetmask; /* subnet mask (phyints only) */
u_long uv_subnetbcast;/* subnet broadcast addr (phyints only) */
u_int32 uv_lcl_addr; /* local address of this vif */
u_int32 uv_rmt_addr; /* remote end-point addr (tunnels only) */
u_int32 uv_subnet; /* subnet number (phyints only) */
u_int32 uv_subnetmask; /* subnet mask (phyints only) */
u_int32 uv_subnetbcast;/* subnet broadcast addr (phyints only) */
char uv_name[IFNAMSIZ]; /* interface name */
struct listaddr *uv_groups; /* list of local groups (phyints only) */
struct listaddr *uv_neighbors; /* list of neighboring routers */
struct vif_acl *uv_acl; /* access control list of groups */
int uv_leaf_timer; /* time until this vif is considrd leaf */
struct phaddr *uv_addrs; /* Additional subnets on this vif */
};
#define VIFF_KERNEL_FLAGS (VIFF_TUNNEL|VIFF_SRCRT)
@ -38,25 +40,39 @@ struct uvif {
#define VIFF_DISABLED 0x0200 /* administratively disabled */
#define VIFF_QUERIER 0x0400 /* I am the subnet's querier */
#define VIFF_ONEWAY 0x0800 /* Maybe one way interface */
#define VIFF_LEAF 0x1000 /* all neighbors are leaves */
struct phaddr {
struct phaddr *pa_next;
u_int32 pa_subnet; /* extra subnet */
u_int32 pa_subnetmask; /* netmask of extra subnet */
u_int32 pa_subnetbcast; /* broadcast of extra subnet */
};
struct vif_acl {
struct vif_acl *acl_next; /* next acl member */
u_long acl_addr; /* Group address */
u_long acl_mask; /* Group addr. mask */
u_int32 acl_addr; /* Group address */
u_int32 acl_mask; /* Group addr. mask */
};
struct listaddr {
struct listaddr *al_next; /* link to next addr, MUST BE FIRST */
u_long al_addr; /* local group or neighbor address */
u_int32 al_addr; /* local group or neighbor address */
u_long al_timer; /* for timing out group or neighbor */
u_long al_genid; /* generation id for neighbor */
time_t al_ctime; /* neighbor creation time */
u_int32 al_genid; /* generation id for neighbor */
u_char al_pv; /* router protocol version */
u_char al_mv; /* router mrouted version */
u_long al_timerid; /* returned by set timer */
u_long al_query; /* second query in case of leave*/
u_short al_old; /* if old memberships are present */
u_short al_last; /* # of query's since last old rep */
u_long al_timerid; /* returned by set timer */
u_long al_query; /* second query in case of leave */
u_short al_old; /* if old memberships are present */
u_short al_last; /* # of query's since last old rep */
u_char al_flags; /* flags related to this neighbor */
};
#define NF_LEAF 0x01 /* This neighbor is a leaf */
#define NF_PRUNE 0x02 /* This neighbor understands prunes */
#define NF_GENID 0x04 /* I supply genid & rtrlist in probe*/
#define NF_MTRACE 0x08 /* I can understand mtrace requests */
#define NO_VIF ((vifi_t)MAXVIFS) /* An invalid vif index */