1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-12-04 09:09:56 +00:00

This is mrouted version 3.5, with the route-change notification hook from

mrouted-3.5n.  This is being splatted onto the head rather than properly
imported thanks to the ``delete trailing whitespace'' screw.  This code is
now actively working in an operational environment (the DARTNET) so I
have some confidence that the basic functionality actually works.

Obtained from: Bill Fenner, PARC, and ISI
This commit is contained in:
Garrett Wollman 1995-06-13 18:05:16 +00:00
parent 1c5de19afb
commit 2897e6fd5f
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=9210
29 changed files with 6453 additions and 3007 deletions

View File

@ -1 +1,2 @@
.include "${.CURDIR}/../../Makefile.inc"
CFLAGS+= -DRSRR

View File

@ -7,7 +7,7 @@
* Leland Stanford Junior University.
*
*
* $Id: callout.c,v 1.3 1995/05/16 00:28:42 jkh Exp $
* $Id: callout.c,v 3.5 1995/05/09 01:00:39 fenner Exp $
*/
#include "defs.h"
@ -22,13 +22,12 @@ typedef void (* cfunc_t)();
struct timeout_q {
struct timeout_q *next; /* next event */
int id;
int id;
cfunc_t func ; /* function to call */
char *data; /* func's data */
int time; /* time offset to next event*/
};
static void print_Q();
void callout_init()
@ -43,20 +42,20 @@ void callout_init()
void age_callout_queue()
{
struct timeout_q *ptr;
if (in_callout)
return;
in_callout = 1;
ptr = Q;
while (ptr){
if (!ptr->time ) {
/* timeout has happened */
if(ptr->func)
ptr->func(ptr->data);
Q = Q->next;
free(ptr);
ptr = Q;
}
@ -73,7 +72,7 @@ void age_callout_queue()
}
/*
/*
* sets the timer
*/
int timer_setTimer(delay, action, data)
@ -82,39 +81,39 @@ int timer_setTimer(delay, action, data)
char *data; /* what to call the timeout function with */
{
struct timeout_q *ptr, *node, *prev;
if (in_callout)
return -1;
in_callout = 1;
/* create a node */
/* create a node */
node = (struct timeout_q *)malloc(sizeof(struct timeout_q));
if ((int) node <= 0) {
if (node == 0) {
log(LOG_WARNING, 0, "Malloc Failed in timer_settimer\n");
in_callout = 0;
return -1;
}
node->func = action;
node->func = action;
node->data = data;
node->time = delay;
node->next = 0;
node->time = delay;
node->next = 0;
node->id = ++id;
prev = ptr = Q;
/* insert node in the queue */
/* if the queue is empty, insert the node and return */
if (!Q)
Q = node;
else {
/* chase the pointer looking for the right place */
while (ptr){
if (delay < ptr->time){
/* right place */
node->next = ptr;
if (ptr == Q)
Q = node;
@ -127,7 +126,7 @@ int timer_setTimer(delay, action, data)
}
else {
/* keep moving */
delay -= ptr->time; node->time = delay;
prev = ptr;
ptr = ptr->next;
@ -142,39 +141,39 @@ int timer_setTimer(delay, action, data)
/* clears the associated timer */
void timer_clearTimer( id)
int id;
void timer_clearTimer( timer_id)
int timer_id;
{
struct timeout_q *ptr, *prev;
if (in_callout) return;
in_callout = 1;
if ( !id ) {in_callout = 0; return;}
if ( !timer_id ) {in_callout = 0; return;}
prev = ptr = Q;
/*
* find the right node, delete it. the subsequent node's time
* gets bumped up
*/
print_Q();
while (ptr){
if (ptr->id == id){
if (ptr->id == timer_id){
/* got the right node */
/* unlink it from the queue */
if ( ptr == Q)
Q = Q->next;
else
prev->next = ptr->next;
/* increment next node if any */
if (ptr->next != 0)
(ptr->next)->time += ptr->time;
free(ptr->data);
free(ptr);
print_Q();
@ -195,7 +194,7 @@ static void print_Q()
{
#ifdef IGMP_DEBUG
struct timeout_q *ptr;
for(ptr = Q; ptr; ptr = ptr->next)
log(LOG_DEBUG,0,"(%d,%d) ", ptr->id, ptr->time);
#endif IGMP_DEBUG

511
usr.sbin/mrouted/cfparse.y Normal file
View File

@ -0,0 +1,511 @@
%{
/*
* Configuration file parser for mrouted.
*
* Written by Bill Fenner, NRL, 1994
*
* $Id: cfparse.y,v 3.5 1995/05/09 01:00:39 fenner Exp $
*/
#include <stdio.h>
#include <varargs.h>
#include "defs.h"
static FILE *f;
extern int udp_socket;
char *configfilename = _PATH_MROUTED_CONF;
extern int cache_lifetime;
extern int max_prune_lifetime;
static int lineno;
static struct ifreq ifbuf[32];
static struct ifconf ifc;
static struct uvif *v;
static int order;
struct addrmask {
u_int32 addr;
int mask;
};
struct boundnam {
char *name;
struct addrmask bound;
};
#define MAXBOUNDS 20
struct boundnam boundlist[MAXBOUNDS]; /* Max. of 20 named boundaries */
int numbounds = 0; /* Number of named boundaries */
%}
%union
{
int num;
char *ptr;
struct addrmask addrmask;
u_int32 addr;
};
%token CACHE_LIFETIME PRUNING
%token PHYINT TUNNEL NAME
%token DISABLE METRIC THRESHOLD RATE_LIMIT SRCRT BOUNDARY NETMASK ALTNET
%token <num> BOOLEAN
%token <num> NUMBER
%token <ptr> STRING
%token <addrmask> ADDRMASK
%token <addr> ADDR
%type <addr> interface
%type <addrmask> bound boundary addrmask
%start conf
%%
conf : stmts
;
stmts : /* Empty */
| stmts stmt
;
stmt : error
| PHYINT interface {
vifi_t vifi;
if (order)
fatal("phyints must appear before tunnels");
for (vifi = 0, v = uvifs;
vifi < numvifs;
++vifi, ++v)
if (!(v->uv_flags & VIFF_TUNNEL) &&
$2 == v->uv_lcl_addr)
break;
if (vifi == numvifs)
fatal("%s is not a configured interface",
inet_fmt($2,s1));
/*log(LOG_INFO, 0, "phyint: %x\n", v);*/
}
ifmods
| TUNNEL interface ADDR {
struct ifreq *ifr;
struct ifreq ffr;
vifi_t vifi;
order++;
ifr = ifconfaddr(&ifc, $2);
if (ifr == 0)
fatal("Tunnel local address %s is not mine",
inet_fmt($2, s1));
strncpy(ffr.ifr_name, ifr->ifr_name, IFNAMSIZ);
if (ioctl(udp_socket, SIOCGIFFLAGS, (char *)&ffr)<0)
fatal("ioctl SIOCGIFFLAGS on %s",ffr.ifr_name);
if (ffr.ifr_flags & IFF_LOOPBACK)
fatal("Tunnel local address %s is a loopback interface",
inet_fmt($2, s1));
if (ifconfaddr(&ifc, $3) != 0)
fatal("Tunnel remote address %s is one of mine",
inet_fmt($3, s1));
for (vifi = 0, v = uvifs;
vifi < numvifs;
++vifi, ++v)
if (v->uv_flags & VIFF_TUNNEL) {
if ($3 == v->uv_rmt_addr)
fatal("Duplicate tunnel to %s",
inet_fmt($3, s1));
} else if (!(v->uv_flags & VIFF_DISABLED)) {
if (($3 & v->uv_subnetmask) == v->uv_subnet)
fatal("Unnecessary tunnel to %s",
inet_fmt($3,s1));
}
if (numvifs == MAXVIFS)
fatal("too many vifs");
v = &uvifs[numvifs];
v->uv_flags = VIFF_TUNNEL;
v->uv_metric = DEFAULT_METRIC;
v->uv_rate_limit= DEFAULT_TUN_RATE_LIMIT;
v->uv_threshold = DEFAULT_THRESHOLD;
v->uv_lcl_addr = $2;
v->uv_rmt_addr = $3;
v->uv_subnet = 0;
v->uv_subnetmask= 0;
v->uv_subnetbcast= 0;
strncpy(v->uv_name, ffr.ifr_name, IFNAMSIZ);
v->uv_groups = NULL;
v->uv_neighbors = NULL;
v->uv_acl = NULL;
v->uv_addrs = NULL;
if (!(ffr.ifr_flags & IFF_UP)) {
v->uv_flags |= VIFF_DOWN;
vifs_down = TRUE;
}
/*log(LOG_INFO, 0, "tunnel: %x\n", v);*/
}
tunnelmods
{
log(LOG_INFO, 0,
"installing tunnel from %s to %s as vif #%u - rate=%d",
inet_fmt($2, s1), inet_fmt($3, s2),
numvifs, v->uv_rate_limit);
++numvifs;
}
| PRUNING BOOLEAN { pruning = $2; }
| CACHE_LIFETIME NUMBER { cache_lifetime = $2;
max_prune_lifetime = cache_lifetime * 2;
}
| NAME STRING boundary { if (numbounds >= MAXBOUNDS) {
fatal("Too many named boundaries (max %d)", MAXBOUNDS);
}
boundlist[numbounds].name = malloc(strlen($2) + 1);
strcpy(boundlist[numbounds].name, $2);
boundlist[numbounds++].bound = $3;
}
;
tunnelmods : /* empty */
| tunnelmods /*{ log(LOG_INFO, 0, "tunnelmod: %x", v); }*/ tunnelmod
;
tunnelmod : mod
| SRCRT { fatal("Source-route tunnels not supported"); }
;
ifmods : /* empty */
| ifmods /*{ log(LOG_INFO, 0, "ifmod: %x", v); }*/ ifmod
;
ifmod : mod
| DISABLE { v->uv_flags |= VIFF_DISABLED; }
| NETMASK ADDR { v->uv_subnetmask = $2; }
| ALTNET addrmask {
struct phaddr *ph;
ph = (struct phaddr *)malloc(sizeof(struct phaddr));
if (ph == NULL)
fatal("out of memory");
if ($2.mask) {
VAL_TO_MASK(ph->pa_mask, $2.mask);
} else
ph->pa_mask = v->uv_subnetmask;
ph->pa_addr = $2.addr & ph->pa_mask;
if ($2.addr & ~ph->pa_mask)
warn("Extra addr %s/%d has host bits set",
inet_fmt($2.addr,s1), $2.mask);
ph->pa_next = v->uv_addrs;
v->uv_addrs = ph;
}
;
mod : THRESHOLD NUMBER { if ($2 < 1 || $2 > 255)
fatal("Invalid threshold %d",$2);
v->uv_threshold = $2;
}
| THRESHOLD {
warn("Expected number after threshold keyword");
}
| METRIC NUMBER { if ($2 < 1 || $2 > UNREACHABLE)
fatal("Invalid metric %d",$2);
v->uv_metric = $2;
}
| METRIC {
warn("Expected number after metric keyword");
}
| RATE_LIMIT NUMBER { if ($2 > MAX_RATE_LIMIT)
fatal("Invalid rate_limit %d",$2);
v->uv_rate_limit = $2;
}
| RATE_LIMIT {
warn("Expected number after rate_limit keyword");
}
| BOUNDARY bound {
struct vif_acl *v_acl;
v_acl = (struct vif_acl *)malloc(sizeof(struct vif_acl));
if (v_acl == NULL)
fatal("out of memory");
VAL_TO_MASK(v_acl->acl_mask, $2.mask);
v_acl->acl_addr = $2.addr & v_acl->acl_mask;
if ($2.addr & ~v_acl->acl_mask)
warn("Boundary spec %s/%d has host bits set",
inet_fmt($2.addr,s1),$2.mask);
v_acl->acl_next = v->uv_acl;
v->uv_acl = v_acl;
}
| BOUNDARY {
warn("Expected boundary spec after boundary keyword");
}
;
interface : ADDR { $$ = $1; }
| STRING {
$$ = valid_if($1);
if ($$ == 0)
fatal("Invalid interface name %s",$1);
}
;
bound : boundary { $$ = $1; }
| STRING { int i;
for (i=0; i < numbounds; i++) {
if (!strcmp(boundlist[i].name, $1)) {
$$ = boundlist[i].bound;
break;
}
}
if (i == numbounds) {
fatal("Invalid boundary name %s",$1);
}
}
;
boundary : ADDRMASK {
if ((ntohl($1.addr) & 0xff000000) != 0xef000000) {
fatal("Boundaries must be 239.x.x.x, not %s/%d",
inet_fmt($1.addr, s1), $1.mask);
}
$$ = $1;
}
;
addrmask : ADDRMASK { $$ = $1; }
| ADDR { $$.addr = $1; $$.mask = 0; }
;
%%
/*VARARGS1*/
static void fatal(fmt, va_alist)
char *fmt;
va_dcl
{
va_list ap;
char buf[200];
va_start(ap);
vsprintf(buf, fmt, ap);
va_end(ap);
log(LOG_ERR,0,"%s: %s near line %d", configfilename, buf, lineno);
}
/*VARARGS1*/
static void warn(fmt, va_alist)
char *fmt;
va_dcl
{
va_list ap;
char buf[200];
va_start(ap);
vsprintf(buf, fmt, ap);
va_end(ap);
log(LOG_WARNING,0,"%s: %s near line %d", configfilename, buf, lineno);
}
void yyerror(s)
char *s;
{
log(LOG_ERR, 0, "%s: %s near line %d", configfilename, s, lineno);
}
char *next_word()
{
static char buf[1024];
static char *p=NULL;
extern FILE *f;
char *q;
while (1) {
if (!p || !*p) {
lineno++;
if (fgets(buf, sizeof(buf), f) == NULL)
return NULL;
p = buf;
}
while (*p && (*p == ' ' || *p == '\t')) /* skip whitespace */
p++;
if (*p == '#') {
p = NULL; /* skip comments */
continue;
}
q = p;
while (*p && *p != ' ' && *p != '\t' && *p != '\n')
p++; /* find next whitespace */
*p++ = '\0'; /* null-terminate string */
if (!*q) {
p = NULL;
continue; /* if 0-length string, read another line */
}
return q;
}
}
int yylex()
{
int n;
u_int32 addr;
char *q;
if ((q = next_word()) == NULL) {
return 0;
}
if (!strcmp(q,"cache_lifetime"))
return CACHE_LIFETIME;
if (!strcmp(q,"pruning"))
return PRUNING;
if (!strcmp(q,"phyint"))
return PHYINT;
if (!strcmp(q,"tunnel"))
return TUNNEL;
if (!strcmp(q,"disable"))
return DISABLE;
if (!strcmp(q,"metric"))
return METRIC;
if (!strcmp(q,"threshold"))
return THRESHOLD;
if (!strcmp(q,"rate_limit"))
return RATE_LIMIT;
if (!strcmp(q,"srcrt") || !strcmp(q,"sourceroute"))
return SRCRT;
if (!strcmp(q,"boundary"))
return BOUNDARY;
if (!strcmp(q,"netmask"))
return NETMASK;
if (!strcmp(q,"name"))
return NAME;
if (!strcmp(q,"altnet"))
return ALTNET;
if (!strcmp(q,"on") || !strcmp(q,"yes")) {
yylval.num = 1;
return BOOLEAN;
}
if (!strcmp(q,"off") || !strcmp(q,"no")) {
yylval.num = 0;
return BOOLEAN;
}
if (sscanf(q,"%[.0-9]/%d%c",s1,&n,s2) == 2) {
if ((addr = inet_parse(s1)) != 0xffffffff) {
yylval.addrmask.mask = n;
yylval.addrmask.addr = addr;
return ADDRMASK;
}
/* fall through to returning STRING */
}
if (sscanf(q,"%[.0-9]%c",s1,s2) == 1) {
if ((addr = inet_parse(s1)) != 0xffffffff &&
inet_valid_host(addr)) {
yylval.addr = addr;
return ADDR;
}
}
if (sscanf(q,"0x%8x%c",&n,s1) == 1) {
yylval.addr = n;
return ADDR;
}
if (sscanf(q,"%d%c",&n,s1) == 1) {
yylval.num = n;
return NUMBER;
}
yylval.ptr = q;
return STRING;
}
void config_vifs_from_file()
{
extern FILE *f;
order = 0;
numbounds = 0;
lineno = 0;
if ((f = fopen(configfilename, "r")) == NULL) {
if (errno != ENOENT)
log(LOG_ERR, errno, "can't open %s", configfilename);
return;
}
ifc.ifc_buf = (char *)ifbuf;
ifc.ifc_len = sizeof(ifbuf);
if (ioctl(udp_socket, SIOCGIFCONF, (char *)&ifc) < 0)
log(LOG_ERR, errno, "ioctl SIOCGIFCONF");
yyparse();
close(f);
}
static u_int32
valid_if(s)
char *s;
{
register vifi_t vifi;
register struct uvif *v;
for (vifi=0, v=uvifs; vifi<numvifs; vifi++, v++)
if (!strcmp(v->uv_name, s))
return v->uv_lcl_addr;
return 0;
}
static struct ifreq *
ifconfaddr(ifcp, a)
struct ifconf *ifcp;
u_int32 a;
{
int n;
struct ifreq *ifrp = (struct ifreq *)ifcp->ifc_buf;
struct ifreq *ifend = (struct ifreq *)((char *)ifrp + ifcp->ifc_len);
while (ifrp < ifend) {
if (ifrp->ifr_addr.sa_family == AF_INET &&
((struct sockaddr_in *)&ifrp->ifr_addr)->sin_addr.s_addr == a)
return (ifrp);
#if (defined(BSD) && (BSD >= 199006))
n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name);
if (n < sizeof(*ifrp))
++ifrp;
else
ifrp = (struct ifreq *)((char *)ifrp + n);
#else
++ifrp;
#endif
}
return (0);
}

View File

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

View File

@ -7,7 +7,7 @@
* Leland Stanford Junior University.
*
*
* $Id: defs.h,v 1.2 1994/09/08 02:51:13 wollman Exp $
* $Id: defs.h,v 3.5 1995/05/09 01:00:39 fenner Exp $
*/
@ -27,11 +27,22 @@
#include <netinet/ip.h>
#include <netinet/igmp.h>
#include <netinet/ip_mroute.h>
#ifdef RSRR
#include <sys/un.h>
#endif /* RSRR */
/*XXX*/
typedef u_int u_int32;
#include "dvmrp.h"
#include "vif.h"
#include "route.h"
#include "prune.h"
#include "pathnames.h"
#ifdef RSRR
#include "rsrr.h"
#include "rsrr_var.h"
#endif /* RSRR */
/*
* Miscellaneous constants and macros.
@ -45,25 +56,47 @@
#define PROTOCOL_VERSION 3 /* increment when packet format/content changes */
#define MROUTED_VERSION 4 /* increment on local changes or bug fixes, */
#define MROUTED_VERSION 5 /* increment on local changes or bug fixes, */
/* reset to 0 whever PROTOCOL_VERSION increments */
#define MROUTED_LEVEL ( (MROUTED_VERSION << 8) | PROTOCOL_VERSION )
#define MROUTED_LEVEL ( (MROUTED_VERSION << 8) | PROTOCOL_VERSION | \
((NF_PRUNE | NF_GENID | NF_MTRACE) << 16))
/* for IGMP 'group' field of DVMRP messages */
#define LEAF_FLAGS (( vifs_with_neighbors == 1 ) ? 0x010000 : 0)
/* more for IGMP 'group' field of DVMRP messages */
#define DEL_RTE_GROUP 0
#define DEL_ALL_ROUTES 1
/* for Deleting kernel table entries */
/* obnoxious gcc gives an extraneous warning about this constant... */
#if defined(__STDC__) || defined(__GNUC__)
#define JAN_1970 2208988800UL /* 1970 - 1900 in seconds */
#else
#define JAN_1970 2208988800L /* 1970 - 1900 in seconds */
#endif
#ifdef RSRR
#define BIT_ZERO(X) ((X) = 0)
#define BIT_SET(X,n) ((X) |= 1 << (n))
#define BIT_CLR(X,n) ((X) &= ~(1 << (n)))
#define BIT_TST(X,n) ((X) & 1 << (n))
#endif /* RSRR */
/*
* External declarations for global variables and functions.
*/
extern char recv_buf[MAX_IP_PACKET_LEN];
extern char send_buf[MAX_IP_PACKET_LEN];
#define RECV_BUF_SIZE MAX_IP_PACKET_LEN
extern char *recv_buf;
extern char *send_buf;
extern int igmp_socket;
extern u_long allhosts_group;
extern u_long dvmrp_group;
extern u_long dvmrp_genid;
#ifdef RSRR
extern int rsrr_socket;
#endif /* RSRR */
extern u_int32 allhosts_group;
extern u_int32 allrtrs_group;
extern u_int32 dvmrp_group;
extern u_int32 dvmrp_genid;
#define DEFAULT_DEBUG 2 /* default if "-d" given without value */
@ -78,14 +111,16 @@ extern struct uvif uvifs[MAXVIFS];
extern vifi_t numvifs;
extern int vifs_down;
extern int udp_socket;
extern int vifs_with_neighbors;
extern char s1[];
extern char s2[];
extern char s3[];
extern char s4[];
#if !(defined(BSD) && (BSD >= 199103))
extern int errno;
extern int sys_nerr;
#ifndef __FreeBSD__
extern char * sys_errlist[];
#endif
@ -118,12 +153,16 @@ extern vifi_t find_vif();
extern void age_vifs();
extern void dump_vifs();
extern void stop_all_vifs();
extern struct listaddr *neighbor_info();
extern void accept_group_report();
extern void query_groups();
extern void probe_for_neighbors();
extern int update_neighbor();
extern void accept_neighbor_request();
extern void accept_neighbor_request2();
extern void accept_neighbors();
extern void accept_neighbors2();
extern void config_vifs_from_kernel();
extern void config_vifs_from_file();
@ -132,13 +171,12 @@ extern int inet_valid_host();
extern int inet_valid_subnet();
extern char * inet_fmt();
extern char * inet_fmts();
extern u_long inet_parse();
extern u_int32 inet_parse();
extern int inet_cksum();
extern struct rtentry * determine_route();
extern void init_ktable();
extern int grplst_mem();
extern void add_table_entry();
extern void del_table_entry();
extern void update_table_entry();
@ -146,27 +184,59 @@ extern void update_lclgrp();
extern void delete_lclgrp();
extern unsigned kroutes;
extern void send_prune();
extern void accept_prune();
extern int no_entry_exists();
extern struct ktable * find_src_grp();
extern int rtr_cnt();
extern void free_all_prunes();
extern void age_table_entry();
extern void dump_cache();
#ifdef SNMP
extern struct rtentry * snmp_find_route();
extern struct gtable * find_grp();
extern struct stable * find_grp_src();
#endif
extern void chkgrp_graft();
extern void accept_graft();
extern void send_graft_ack();
extern void send_graft();
extern void accept_g_ack();
extern void mtrace();
extern void accept_mtrace();
extern void accept_leave_message();
extern void accept_membership_query();
#ifdef RSRR
extern struct gtable *kernel_table;
extern struct gtable *gtp;
extern int find_src_grp();
extern int grplst_mem();
extern int scoped_addr();
#endif /* RSRR */
extern void k_set_rcvbuf();
extern void k_hdr_include();
extern void k_set_ttl();
extern void k_set_loop();
extern void k_set_if();
extern void k_join();
extern void k_leave();
extern void k_init_dvmrp();
extern void k_stop_dvmrp();
extern void k_add_vif();
extern void k_del_vif();
extern void k_add_rg();
extern int k_del_rg();
extern int k_get_version();
extern char * malloc();
extern char * fgets();
extern FILE * fopen();
#ifndef htonl
#if !defined(htonl) && !defined(__osf__)
extern u_long htonl();
extern u_long ntohl();
#endif
#ifdef RSRR
extern void rsrr_init();
extern void rsrr_read();
#endif /* RSRR */

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

View File

@ -7,7 +7,7 @@
* Leland Stanford Junior University.
*
*
* igmp.c,v 1.2 1994/09/08 02:51:15 wollman Exp
* $Id: igmp.c,v 3.5 1995/05/09 01:00:39 fenner Exp $
*/
@ -17,12 +17,13 @@
/*
* Exported variables.
*/
char recv_buf[MAX_IP_PACKET_LEN]; /* input packet buffer */
char send_buf[MAX_IP_PACKET_LEN]; /* output packet buffer */
char *recv_buf; /* input packet buffer */
char *send_buf; /* output packet buffer */
int igmp_socket; /* socket for all network I/O */
u_long allhosts_group; /* allhosts addr in net order */
u_long dvmrp_group; /* DVMRP grp addr in net order */
u_long dvmrp_genid; /* IGMP generation id */
u_int32 allhosts_group; /* All hosts addr in net order */
u_int32 allrtrs_group; /* All-Routers " in net order */
u_int32 dvmrp_group; /* DVMRP grp addr in net order */
u_int32 dvmrp_genid; /* IGMP generation id */
/*
* Open and initialize the igmp socket, and fill in the non-changing
@ -32,7 +33,10 @@ void init_igmp()
{
struct ip *ip;
if ((igmp_socket = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP)) < 0)
recv_buf = malloc(RECV_BUF_SIZE);
send_buf = malloc(RECV_BUF_SIZE);
if ((igmp_socket = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP)) < 0)
log(LOG_ERR, errno, "IGMP socket");
k_hdr_include(TRUE); /* include IP header when sending */
@ -50,10 +54,9 @@ void init_igmp()
allhosts_group = htonl(INADDR_ALLHOSTS_GROUP);
dvmrp_group = htonl(INADDR_DVMRP_GROUP);
allrtrs_group = htonl(INADDR_ALLRTRS_GROUP);
}
/* %%% hack for PIM %%% */
#define IGMP_PIM 0x14
#define PIM_QUERY 0
#define PIM_REGISTER 1
#define PIM_REGISTER_STOP 2
@ -69,8 +72,8 @@ static char *packet_kind(type, code)
switch (type) {
case IGMP_HOST_MEMBERSHIP_QUERY: return "membership query ";
case IGMP_HOST_MEMBERSHIP_REPORT: return "membership report ";
case IGMP_HOST_NEW_MEMBERSHIP_REPORT: return "new membership report ";
case IGMP_HOST_LEAVE_MESSAGE: return "leave message";
case IGMP_HOST_NEW_MEMBERSHIP_REPORT: return "new member report ";
case IGMP_HOST_LEAVE_MESSAGE: return "leave message ";
case IGMP_DVMRP:
switch (code) {
case DVMRP_PROBE: return "neighbor probe ";
@ -79,12 +82,12 @@ static char *packet_kind(type, code)
case DVMRP_NEIGHBORS: return "neighbor list ";
case DVMRP_ASK_NEIGHBORS2: return "neighbor request 2";
case DVMRP_NEIGHBORS2: return "neighbor list 2 ";
case DVMRP_PRUNE: return "prune message ";
case DVMRP_GRAFT: return "graft message ";
case DVMRP_PRUNE: return "prune message ";
case DVMRP_GRAFT: return "graft message ";
case DVMRP_GRAFT_ACK: return "graft message ack ";
default: return "unknown DVMRP msg ";
}
case IGMP_PIM: /* %%% hack for PIM %%% */
case IGMP_PIM:
switch (code) {
case PIM_QUERY: return "PIM Router-Query ";
case PIM_REGISTER: return "PIM Register ";
@ -109,7 +112,7 @@ static char *packet_kind(type, code)
void accept_igmp(recvlen)
int recvlen;
{
register u_long src, dst, group;
register u_int32 src, dst, group;
struct ip *ip;
struct igmp *igmp;
int ipdatalen, iphdrlen, igmpdatalen;
@ -124,9 +127,9 @@ void accept_igmp(recvlen)
src = ip->ip_src.s_addr;
dst = ip->ip_dst.s_addr;
/*
/*
* this is most likely a message from the kernel indicating that
* a new src grp pair message has arrived and so, it would be
* a new src grp pair message has arrived and so, it would be
* necessary to install a route into the kernel for this.
*/
if (ip->ip_p == 0) {
@ -163,29 +166,30 @@ void accept_igmp(recvlen)
switch (igmp->igmp_type) {
case IGMP_HOST_MEMBERSHIP_QUERY:
/* we have to do the determination of the querrier router here */
accept_membership_query(src, dst, group, igmp->igmp_code);
return;
case IGMP_HOST_MEMBERSHIP_REPORT:
case IGMP_HOST_NEW_MEMBERSHIP_REPORT:
accept_group_report(src, dst, group,igmp->igmp_type);
accept_group_report(src, dst, group, igmp->igmp_type);
return;
case IGMP_HOST_LEAVE_MESSAGE:
leave_group_message(src, dst, group);
accept_leave_message(src, dst, group);
return;
case IGMP_DVMRP:
switch (igmp->igmp_code) {
group = ntohl(group);
switch (igmp->igmp_code) {
case DVMRP_PROBE:
accept_probe(src, dst,
(char *)(igmp+1), igmpdatalen, ntohl(group));
(char *)(igmp+1), igmpdatalen, group);
return;
case DVMRP_REPORT:
accept_report(src, dst,
(char *)(igmp+1), igmpdatalen, ntohl(group));
(char *)(igmp+1), igmpdatalen, group);
return;
case DVMRP_ASK_NEIGHBORS:
@ -198,12 +202,12 @@ void accept_igmp(recvlen)
case DVMRP_NEIGHBORS:
accept_neighbors(src, dst, (char *)(igmp+1), igmpdatalen,
group);
group);
return;
case DVMRP_NEIGHBORS2:
accept_neighbors2(src, dst, (char *)(igmp+1), igmpdatalen,
group);
group);
return;
case DVMRP_PRUNE:
@ -226,18 +230,20 @@ void accept_igmp(recvlen)
return;
}
case IGMP_PIM: /* %%% hack for PIM %%% */
case IGMP_PIM:
return;
case IGMP_MTRACE_RESP:
return;
case IGMP_MTRACE:
mtrace(src, dst, group, (char *)(igmp+1),
accept_mtrace(src, dst, group, (char *)(igmp+1),
igmp->igmp_code, igmpdatalen);
return;
default:
log(LOG_INFO, 0,
"ignoring unknown IGMP message type %u from %s to %s",
"ignoring unknown IGMP message type %x from %s to %s",
igmp->igmp_type, inet_fmt(src, s1),
inet_fmt(dst, s2));
return;
@ -250,13 +256,14 @@ void accept_igmp(recvlen)
* have already placed data in that buffer, of length 'datalen'. Then send
* the message from the interface with IP address 'src' to destination 'dst'.
*/
void send_igmp(src, dst, type, code, group, datalen)
u_long src, dst;
void
send_igmp(src, dst, type, code, group, datalen)
u_int32 src, dst;
int type, code;
u_long group;
u_int32 group;
int datalen;
{
static struct sockaddr_in sdst = {AF_INET, sizeof sdst};
static struct sockaddr_in sdst;
struct ip *ip;
struct igmp *igmp;
@ -276,6 +283,11 @@ void send_igmp(src, dst, type, code, group, datalen)
if (IN_MULTICAST(ntohl(dst))) k_set_if(src);
if (dst == allhosts_group) k_set_loop(TRUE);
bzero(&sdst, sizeof(sdst));
sdst.sin_family = AF_INET;
#if (defined(BSD) && (BSD >= 199103))
sdst.sin_len = sizeof(sdst);
#endif
sdst.sin_addr.s_addr = dst;
if (sendto(igmp_socket, send_buf, ip->ip_len, 0,
(struct sockaddr *)&sdst, sizeof(sdst)) < 0) {

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.5 1995/05/09 01:00:39 fenner Exp $
*/
@ -17,9 +17,10 @@
/*
* Exported variables.
*/
char s1[16]; /* buffers to hold the string representations */
char s2[16]; /* of IP addresses, to be passed to inet_fmt() */
char s3[16]; /* or inet_fmts(). */
char s1[19]; /* buffers to hold the string representations */
char s2[19]; /* of IP addresses, to be passed to inet_fmt() */
char s3[19]; /* or inet_fmts(). */
char s4[19];
/*
@ -28,9 +29,9 @@ char s3[16]; /* or inet_fmts(). */
* {subnet,-1}.)
*/
int inet_valid_host(naddr)
u_long naddr;
u_int32 naddr;
{
register u_long addr;
register u_int32 addr;
addr = ntohl(naddr);
@ -42,29 +43,38 @@ int inet_valid_host(naddr)
/*
* Verify that a given subnet number and mask pair are credible.
*
* With CIDR, almost any subnet and mask are credible. mrouted still
* can't handle aggregated class A's, so we still check that, but
* otherwise the only requirements are that the subnet address is
* within the [ABC] range and that the host bits of the subnet
* are all 0.
*/
int inet_valid_subnet(nsubnet, nmask)
u_long nsubnet, nmask;
u_int32 nsubnet, nmask;
{
register u_long subnet, mask;
register u_int32 subnet, mask;
subnet = ntohl(nsubnet);
mask = ntohl(nmask);
if ((subnet & mask) != subnet) return (FALSE);
if (subnet == 0 && mask == 0)
return (TRUE);
if (IN_CLASSA(subnet)) {
if (mask < 0xff000000 ||
(subnet & 0xff000000) == 0 ||
(subnet & 0xff000000) == 0x7f000000) return (FALSE);
}
else if (IN_CLASSB(subnet)) {
if (mask < 0xffff0000) return (FALSE);
else if (IN_CLASSD(subnet) || IN_BADCLASS(subnet)) {
/* Above Class C address space */
return (FALSE);
}
else if (IN_CLASSC(subnet)) {
if (mask < 0xffffff00) return (FALSE);
else if (subnet & ~mask) {
/* Host bits are set in the subnet */
return (FALSE);
}
else return (FALSE);
return (TRUE);
}
@ -74,7 +84,7 @@ int inet_valid_subnet(nsubnet, nmask)
* Convert an IP address in u_long (network) format into a printable string.
*/
char *inet_fmt(addr, s)
u_long addr;
u_int32 addr;
char *s;
{
register u_char *a;
@ -87,36 +97,42 @@ char *inet_fmt(addr, s)
/*
* Convert an IP subnet number in u_long (network) format into a printable
* string.
* string including the netmask as a number of bits.
*/
char *inet_fmts(addr, mask, s)
u_long addr, mask;
u_int32 addr, mask;
char *s;
{
register u_char *a, *m;
int bits;
if ((addr == 0) && (mask == 0)) {
sprintf(s, "default");
return (s);
}
a = (u_char *)&addr;
m = (u_char *)&mask;
bits = 33 - ffs(ntohl(mask));
if (m[3] != 0) sprintf(s, "%u.%u.%u.%u", a[0], a[1], a[2], a[3]);
else if (m[2] != 0) sprintf(s, "%u.%u.%u", a[0], a[1], a[2]);
else if (m[1] != 0) sprintf(s, "%u.%u", a[0], a[1]);
else sprintf(s, "%u", a[0]);
if (m[3] != 0) sprintf(s, "%u.%u.%u.%u/%d", a[0], a[1], a[2], a[3],
bits);
else if (m[2] != 0) sprintf(s, "%u.%u.%u/%d", a[0], a[1], a[2], bits);
else if (m[1] != 0) sprintf(s, "%u.%u/%d", a[0], a[1], bits);
else sprintf(s, "%u/%d", a[0], bits);
return (s);
}
/*
* Convert the printable string representation of an IP address into the
* u_long (network) format. Return 0xffffffff on error. (To detect the
* legal address with that value, you must explicitly compare the string
* with "255.255.255.255".)
*/
u_long inet_parse(s)
u_int32 inet_parse(s)
char *s;
{
u_long a;
u_int32 a = 0;
u_int a0, a1, a2, a3;
char c;

View File

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

View File

@ -7,7 +7,7 @@
* Leland Stanford Junior University.
*
*
* $Id: main.c,v 1.3 1995/03/31 21:16:43 wollman Exp $
* $Id: main.c,v 3.5 1995/05/09 01:00:39 fenner Exp $
*/
/*
@ -21,13 +21,19 @@
#include "defs.h"
#include <varargs.h>
#ifdef SNMP
#include <string.h>
#include "snmp.h"
#endif
extern char *configfilename;
static char pidfilename[] = "/var/run/mrouted.pid";
static char dumpfilename[] = "/var/tmp/mrouted.dump";
static char cachefilename[] = "/var/tmp/mrouted.cache";
static char genidfilename[] = "/var/tmp/mrouted.genid";
static char pidfilename[] = _PATH_MROUTED_PID;
static char dumpfilename[] = _PATH_MROUTED_DUMP;
static char cachefilename[] = _PATH_MROUTED_CACHE;
static char genidfilename[] = _PATH_MROUTED_GENID;
int cache_lifetime = DEFAULT_CACHE_LIFETIME;
int max_prune_lifetime = DEFAULT_CACHE_LIFETIME * 2;
@ -35,19 +41,41 @@ int max_prune_lifetime = DEFAULT_CACHE_LIFETIME * 2;
int debug = 0;
u_char pruning = 1; /* Enable pruning by default */
#define NHANDLERS 2
static struct ihandler {
int fd; /* File descriptor */
void (*func)(); /* Function to call with &fd_set */
} ihandlers[NHANDLERS];
static int nhandlers = 0;
/*
* Forward declarations.
*/
static void fasttimer();
static void timer();
static void hup();
static void cleanup();
static void done();
static void dump();
static void fdump();
static void cdump();
static void restart();
main(argc, argv)
int
register_input_handler(fd, func)
int fd;
void (*func)();
{
if (nhandlers >= NHANDLERS)
return -1;
ihandlers[nhandlers].fd = fd;
ihandlers[nhandlers++].func = func;
return 0;
}
int main(argc, argv)
int argc;
char *argv[];
{
@ -57,10 +85,27 @@ main(argc, argv)
FILE *fp;
extern uid_t geteuid();
struct timeval tv;
struct timezone tzp;
u_long prev_genid;
int vers;
fd_set rfds, readers;
int nfds, n, i;
#ifdef SNMP
char *myname;
fd_set wfds;
if (myname = strrchr(argv[0], '/'))
myname++;
if (myname == NULL || *myname == 0)
myname = argv[0];
isodetailor (myname, 0);
#endif
#ifdef SYSV
setvbuf(stderr, NULL, _IOLBF, 0);
#else
setlinebuf(stderr);
#endif
if (geteuid() != 0) {
fprintf(stderr, "must be root\n");
@ -89,7 +134,7 @@ main(argc, argv)
}
if (argc > 0) {
usage: fprintf(stderr,
usage: fprintf(stderr,
"usage: mrouted [-p] [-c configfile] [-d [debug_level]]\n");
exit(1);
}
@ -107,11 +152,16 @@ usage: fprintf(stderr,
(void)open("/", 0);
(void)dup2(0, 1);
(void)dup2(0, 2);
#ifdef TIOCNOTTY
t = open("/dev/tty", 2);
if (t >= 0) {
(void)ioctl(t, TIOCNOTTY, (char *)0);
(void)close(t);
}
#else
if (setsid() < 0)
perror("setsid");
#endif
}
else
fprintf(stderr, "debug level %u\n", debug);
@ -125,12 +175,16 @@ usage: fprintf(stderr,
log(LOG_NOTICE, 0, "mrouted version %d.%d",
PROTOCOL_VERSION, MROUTED_VERSION);
#ifdef SYSV
srand48(time(NULL));
#else
srandom(gethostid());
#endif
/*
* Get generation id
* Get generation id
*/
gettimeofday(&tv, &tzp);
gettimeofday(&tv, 0);
dvmrp_genid = tv.tv_sec;
fp = fopen(genidfilename, "r");
@ -148,16 +202,42 @@ usage: fprintf(stderr,
}
callout_init();
#ifdef SNMP
snmp_init();
#endif
init_igmp();
k_init_dvmrp(); /* enable DVMRP routing in kernel */
#ifndef OLD_KERNEL
vers = k_get_version();
if ((((vers >> 8) & 0xff) != PROTOCOL_VERSION) ||
((vers & 0xff) != MROUTED_VERSION))
log(LOG_ERR, 0, "kernel (v%d.%d)/mrouted (v%d.%d) version mismatch",
(vers >> 8) & 0xff, vers & 0xff,
PROTOCOL_VERSION, MROUTED_VERSION);
#endif
init_routes();
init_ktable();
init_vifs();
#ifdef RSRR
rsrr_init();
#endif /* RSRR */
#if defined(__STDC__) || defined(__GNUC__)
/* Allow cleanup if unexpected exit. Apparently some architectures
* have a kernel bug where closing the socket doesn't do an
* ip_mrouter_done(), so we attempt to do it on exit.
*/
atexit(cleanup);
#endif
if (debug)
fprintf(stderr, "pruning %s\n", pruning ? "on" : "off");
fp = fopen(pidfilename, "w");
fp = fopen(pidfilename, "w");
if (fp != NULL) {
fprintf(fp, "%d\n", getpid());
(void) fclose(fp);
@ -168,13 +248,22 @@ usage: fprintf(stderr,
(void)signal(SIGALRM, fasttimer);
(void)signal(SIGHUP, restart);
(void)signal(SIGTERM, hup);
(void)signal(SIGINT, hup);
(void)signal(SIGTERM, done);
(void)signal(SIGINT, done);
(void)signal(SIGUSR1, fdump);
(void)signal(SIGUSR2, cdump);
if (debug != 0)
(void)signal(SIGQUIT, dump);
FD_ZERO(&readers);
FD_SET(igmp_socket, &readers);
nfds = igmp_socket + 1;
for (i = 0; i < nhandlers; i++) {
FD_SET(ihandlers[i].fd, &readers);
if (ihandlers[i].fd >= nfds)
nfds = ihandlers[i].fd + 1;
}
(void)alarm(1); /* schedule first timer interrupt */
/*
@ -182,7 +271,30 @@ usage: fprintf(stderr,
*/
dummy = 0;
for(;;) {
recvlen = recvfrom(igmp_socket, recv_buf, sizeof(recv_buf),
bcopy((char *)&readers, (char *)&rfds, sizeof(rfds));
#ifdef SNMP
FD_ZERO(&wfds);
if (smux_fd != NOTOK) {
if (rock_and_roll)
FD_SET(smux_fd, &rfds);
else
FD_SET(smux_fd, &wfds);
if (smux_fd >= nfds)
nfds = smux_fd + 1;
}
if ((n = xselect(nfds, &rfds, &wfds, NULLFD, NOTOK))==NOTOK) {
#else
if ((n = select(nfds, &rfds, NULL, NULL, NULL)) < 0) {
#endif
if (errno != EINTR) /* SIGALRM is expected */
log(LOG_WARNING, errno, "select failed");
continue;
}
if (FD_ISSET(igmp_socket, &rfds)) {
recvlen = recvfrom(igmp_socket, recv_buf, RECV_BUF_SIZE,
0, NULL, &dummy);
if (recvlen < 0) {
if (errno != EINTR) log(LOG_ERR, errno, "recvfrom");
@ -192,17 +304,35 @@ usage: fprintf(stderr,
accept_igmp(recvlen);
(void)sigsetmask(omask);
}
for (i = 0; i < nhandlers; i++) {
if (FD_ISSET(ihandlers[i].fd, &rfds)) {
(*ihandlers[i].func)(&rfds);
}
}
#ifdef SNMP
if (smux_fd != NOTOK) {
if (rock_and_roll) {
if (FD_ISSET(smux_fd, &rfds))
doit_smux();
} else if (FD_ISSET(smux_fd, &wfds))
start_smux();
}
#endif
}
}
/*
* routine invoked every second. It's main goal is to cycle through
* routine invoked every second. Its main goal is to cycle through
* the routing table and send partial updates to all neighbors at a
* rate that will cause the entire table to be sent in ROUTE_REPORT_INTERVAL
* seconds. Also, every TIMER_INTERVAL seconds it calls timer() to
* do all the other time-based processing.
*/
static void fasttimer()
static void
fasttimer()
{
static unsigned int tlast;
static unsigned int nsent;
@ -235,7 +365,7 @@ static void fasttimer()
timer();
age_callout_queue();/* Advance the timer for the callout queue
for groups */
for groups */
alarm(1);
}
@ -264,7 +394,8 @@ static u_long virtual_time = 0;
* group querying duties, and drives various timers in routing entries and
* virtual interface data structures.
*/
static void timer()
static void
timer()
{
age_routes(); /* Advance the timers in the route entries */
age_vifs(); /* Advance the timers for neighbors */
@ -301,6 +432,16 @@ static void timer()
report_to_all_neighbors(CHANGED_ROUTES);
}
#ifdef SNMP
if (smux_fd == NOTOK && !dont_bother_anymore
&& virtual_time % SNMPD_RETRY_INTERVAL == 0) {
/*
* Time to check for snmpd running.
*/
try_smux_init();
}
#endif
/*
* Advance virtual time
*/
@ -309,21 +450,39 @@ static void timer()
/*
* On hangup signal, let everyone know we're going away.
* On termination, let everyone know we're going away.
*/
static void hup()
static void
done()
{
log(LOG_INFO, 0, "hup");
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);
exit(1);
k_stop_dvmrp();
}
}
/*
* Dump internal data structures to stderr.
*/
static void dump()
static void
dump()
{
dump_vifs(stderr);
dump_routes(stderr);
@ -333,7 +492,8 @@ static void dump()
/*
* Dump internal data structures to a file.
*/
static void fdump()
static void
fdump()
{
FILE *fp;
@ -349,13 +509,14 @@ static void fdump()
/*
* Dump local cache contents to a file.
*/
static void cdump()
static void
cdump()
{
FILE *fp;
fp = fopen(cachefilename, "w");
if (fp != NULL) {
dump_cache(fp);
dump_cache(fp);
(void) fclose(fp);
}
}
@ -364,11 +525,13 @@ static void cdump()
/*
* Restart mrouted
*/
static void restart()
static void
restart()
{
register int omask;
log(LOG_INFO, 0, "restart");
log(LOG_NOTICE, 0, "mrouted version %d.%d restart",
PROTOCOL_VERSION, MROUTED_VERSION);
/*
* reset all the entries
@ -378,6 +541,8 @@ static void restart()
free_all_routes();
stop_all_vifs();
k_stop_dvmrp();
close(igmp_socket);
close(udp_socket);
/*
* start processing again
@ -400,39 +565,49 @@ static void restart()
* according to the severity of the message and the current debug level.
* For errors of severity LOG_ERR or worse, terminate the program.
*/
void log(severity, syserr, format, a, b, c, d, e)
/*VARARGS3*/
void
log(severity, syserr, format, va_alist)
int severity, syserr;
char *format;
int a, b, c, d, e;
va_dcl
{
char fmt[100];
va_list ap;
static char fmt[211] = "warning - ";
char *msg;
char tbuf[20];
struct timeval now;
struct tm *thyme;
va_start(ap);
vsprintf(&fmt[10], format, ap);
va_end(ap);
msg = (severity == LOG_WARNING) ? fmt : &fmt[10];
switch (debug) {
case 0: break;
case 1: if (severity > LOG_NOTICE) break;
case 2: if (severity > LOG_INFO ) break;
default:
fmt[0] = '\0';
if (severity == LOG_WARNING) strcat(fmt, "warning - ");
strncat(fmt, format, 80);
fprintf(stderr, fmt, a, b, c, d, e);
gettimeofday(&now,NULL);
thyme = localtime(&now.tv_sec);
strftime(tbuf, sizeof(tbuf), "%X.%%03d ", thyme);
fprintf(stderr, tbuf, now.tv_usec / 1000);
fprintf(stderr, "%s", msg);
if (syserr == 0)
fprintf(stderr, "\n");
else if(syserr < sys_nerr)
else if (syserr < sys_nerr)
fprintf(stderr, ": %s\n", sys_errlist[syserr]);
else
fprintf(stderr, ": errno %d\n", syserr);
}
if (severity <= LOG_NOTICE) {
fmt[0] = '\0';
if (severity == LOG_WARNING) strcat(fmt, "warning - ");
strncat(fmt, format, 80);
if (syserr != 0) {
strcat(fmt, ": %m");
errno = syserr;
}
syslog(severity, fmt, a, b, c, d, e);
errno = syserr;
syslog(severity, "%s: %m", msg);
} else
syslog(severity, "%s", msg);
if (severity <= LOG_ERR) exit(-1);
}

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,26 +1,27 @@
/* Mapper for connections between MRouteD multicast routers.
* Written by Pavel Curtis <Pavel@PARC.Xerox.Com>
*
* $Id: mapper.c,v 1.2 1994/09/08 02:51:19 wollman Exp $
* $Id: mapper.c,v 3.5 1995/05/09 01:00:39 fenner Exp $
*/
/*
* Copyright (c) Xerox Corporation 1992. All rights reserved.
*
*
* License is granted to copy, to use, and to make and to use derivative
* works for research and evaluation purposes, provided that Xerox is
* acknowledged in all documentation pertaining to any such copy or derivative
* work. Xerox grants no other licenses expressed or implied. The Xerox trade
* name should not be used in any advertising without its written permission.
*
*
* XEROX CORPORATION MAKES NO REPRESENTATIONS CONCERNING EITHER THE
* MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF THIS SOFTWARE
* FOR ANY PARTICULAR PURPOSE. The software is provided "as is" without
* express or implied warranty of any kind.
*
*
* These notices must be retained in any copies of any part of this software.
*/
#include <string.h>
#include <netdb.h>
#include <sys/time.h>
#include "defs.h"
@ -33,7 +34,7 @@
typedef struct neighbor {
struct neighbor *next;
u_long addr; /* IP address in NET order */
u_int32 addr; /* IP address in NET order */
u_char metric; /* TTL cost of forwarding */
u_char threshold; /* TTL threshold to forward */
u_short flags; /* flags on connection */
@ -42,13 +43,13 @@ typedef struct neighbor {
typedef struct interface {
struct interface *next;
u_long addr; /* IP address of the interface in NET order */
u_int32 addr; /* IP address of the interface in NET order */
Neighbor *neighbors; /* List of neighbors' IP addresses */
} Interface;
typedef struct node {
u_long addr; /* IP address of this entry in NET order */
u_long version; /* which mrouted version is running */
u_int32 addr; /* IP address of this entry in NET order */
u_int32 version; /* which mrouted version is running */
int tries; /* How many requests sent? -1 for aliases */
union {
struct node *alias; /* If alias, to what? */
@ -59,7 +60,7 @@ typedef struct node {
Node *routers = 0;
u_long our_addr, target_addr = 0; /* in NET order */
u_int32 our_addr, target_addr = 0; /* in NET order */
int debug = 0;
int retries = DEFAULT_RETRIES;
int timeout = DEFAULT_TIMEOUT;
@ -69,7 +70,7 @@ vifi_t numvifs; /* to keep loader happy */
Node *find_node(addr, ptr)
u_long addr;
u_int32 addr;
Node **ptr;
{
Node *n = *ptr;
@ -92,7 +93,7 @@ Node *find_node(addr, ptr)
Interface *find_interface(addr, node)
u_long addr;
u_int32 addr;
Node *node;
{
Interface *ifc;
@ -112,7 +113,7 @@ Interface *find_interface(addr, node)
Neighbor *find_neighbor(addr, node)
u_long addr;
u_int32 addr;
Node *node;
{
Interface *ifc;
@ -168,14 +169,14 @@ void log(severity, syserr, format, a, b, c, d, e)
* Send a neighbors-list request.
*/
void ask(dst)
u_long dst;
u_int32 dst;
{
send_igmp(our_addr, dst, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS,
htonl(MROUTED_LEVEL), 0);
}
void ask2(dst)
u_long dst;
u_int32 dst;
{
send_igmp(our_addr, dst, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS2,
htonl(MROUTED_LEVEL), 0);
@ -186,7 +187,7 @@ void ask2(dst)
* Process an incoming group membership report.
*/
void accept_group_report(src, dst, group)
u_long src, dst, group;
u_int32 src, dst, group;
{
log(LOG_INFO, 0, "ignoring IGMP group membership report from %s to %s",
inet_fmt(src, s1), inet_fmt(dst, s2));
@ -197,7 +198,7 @@ void accept_group_report(src, dst, group)
* Process an incoming neighbor probe message.
*/
void accept_probe(src, dst)
u_long src, dst;
u_int32 src, dst;
{
log(LOG_INFO, 0, "ignoring DVMRP probe from %s to %s",
inet_fmt(src, s1), inet_fmt(dst, s2));
@ -208,7 +209,7 @@ void accept_probe(src, dst)
* Process an incoming route report message.
*/
void accept_report(src, dst, p, datalen)
u_long src, dst;
u_int32 src, dst;
char *p;
int datalen;
{
@ -221,7 +222,7 @@ void accept_report(src, dst, p, datalen)
* Process an incoming neighbor-list request message.
*/
void accept_neighbor_request(src, dst)
u_long src, dst;
u_int32 src, dst;
{
if (src != our_addr)
log(LOG_INFO, 0,
@ -230,7 +231,7 @@ void accept_neighbor_request(src, dst)
}
void accept_neighbor_request2(src, dst)
u_long src, dst;
u_int32 src, dst;
{
if (src != our_addr)
log(LOG_INFO, 0,
@ -243,7 +244,7 @@ void accept_neighbor_request2(src, dst)
* Process an incoming neighbor-list message.
*/
void accept_neighbors(src, dst, p, datalen, level)
u_long src, dst, level;
u_int32 src, dst, level;
u_char *p;
int datalen;
{
@ -254,8 +255,8 @@ void accept_neighbors(src, dst, p, datalen, level)
else if (node->tries == -1) /* follow alias link */
node = node->u.alias;
#define GET_ADDR(a) (a = ((u_long)*p++ << 24), a += ((u_long)*p++ << 16),\
a += ((u_long)*p++ << 8), a += *p++)
#define GET_ADDR(a) (a = ((u_int32)*p++ << 24), a += ((u_int32)*p++ << 16),\
a += ((u_int32)*p++ << 8), a += *p++)
/* if node is running a recent mrouted, ask for additional info */
if (level != 0) {
@ -281,7 +282,7 @@ void accept_neighbors(src, dst, p, datalen, level)
}
while (datalen > 0) { /* loop through interfaces */
u_long ifc_addr;
u_int32 ifc_addr;
u_char metric, threshold, ncount;
Node *ifc_node;
Interface *ifc;
@ -354,13 +355,13 @@ void accept_neighbors(src, dst, p, datalen, level)
ifc_node->tries = -1;
ifc_node->u.alias = node;
}
ifc = find_interface(ifc_addr, node);
old_neighbors = ifc->neighbors;
/* Add the neighbors for this interface */
while (ncount--) {
u_long neighbor;
u_int32 neighbor;
Neighbor *nb;
Node *n_node;
@ -404,7 +405,7 @@ void accept_neighbors(src, dst, p, datalen, level)
}
void accept_neighbors2(src, dst, p, datalen)
u_long src, dst;
u_int32 src, dst;
u_char *p;
int datalen;
{
@ -416,7 +417,7 @@ void accept_neighbors2(src, dst, p, datalen)
node = node->u.alias;
while (datalen > 0) { /* loop through interfaces */
u_long ifc_addr;
u_int32 ifc_addr;
u_char metric, threshold, ncount, flags;
Node *ifc_node;
Interface *ifc;
@ -428,7 +429,7 @@ void accept_neighbors2(src, dst, p, datalen)
return;
}
ifc_addr = *(u_long*)p;
ifc_addr = *(u_int32*)p;
p += 4;
metric = *p++;
threshold = *p++;
@ -490,13 +491,13 @@ void accept_neighbors2(src, dst, p, datalen)
ifc_node->tries = -1;
ifc_node->u.alias = node;
}
ifc = find_interface(ifc_addr, node);
old_neighbors = ifc->neighbors;
/* Add the neighbors for this interface */
while (ncount--) {
u_long neighbor;
u_int32 neighbor;
Neighbor *nb;
Node *n_node;
@ -506,7 +507,7 @@ void accept_neighbors2(src, dst, p, datalen)
return;
}
neighbor = *(u_long*)p;
neighbor = *(u_int32*)p;
p += 4;
datalen -= 4;
if (neighbor == 0)
@ -571,7 +572,7 @@ int retry_requests(node)
char *inet_name(addr)
u_long addr;
u_int32 addr;
{
struct hostent *e;
@ -586,7 +587,7 @@ void print_map(node)
{
if (node) {
char *name, *addr;
print_map(node->left);
addr = inet_fmt(node->addr, s1);
@ -650,7 +651,7 @@ void print_map(node)
char *graph_name(addr, buf)
u_long addr;
u_int32 addr;
char *buf;
{
char *name;
@ -734,7 +735,7 @@ void elide_aliases(node)
void graph_map()
{
u_long now = time(0);
time_t now = time(0);
char *nowstr = ctime(&now);
nowstr[24] = '\0'; /* Kill the newline at the end */
@ -771,7 +772,7 @@ int get_number(var, deflt, pargv, pargc)
}
u_long host_addr(name)
u_int32 host_addr(name)
char *name;
{
struct hostent *e = gethostbyname(name);
@ -789,12 +790,12 @@ u_long host_addr(name)
}
main(argc, argv)
int main(argc, argv)
int argc;
char *argv[];
{
int flood = FALSE, graph = FALSE;
#ifdef SYSV
setvbuf(stderr, NULL, _IOLBF, 0);
#else
@ -837,7 +838,7 @@ main(argc, argv)
}
if (argc > 1) {
usage:
usage:
fprintf(stderr,
"Usage: map-mbone [-f] [-g] [-n] [-t timeout] %s\n\n",
"[-r retries] [-d [debug-level]] [router]");
@ -862,7 +863,9 @@ main(argc, argv)
int addrlen = sizeof(addr);
addr.sin_family = AF_INET;
#if (defined(BSD) && (BSD >= 199103))
addr.sin_len = sizeof addr;
#endif
addr.sin_addr.s_addr = dvmrp_group;
addr.sin_port = htons(2000); /* any port over 1024 will do... */
if ((udp = socket(AF_INET, SOCK_DGRAM, 0)) < 0
@ -913,7 +916,7 @@ main(argc, argv)
break;
}
recvlen = recvfrom(igmp_socket, recv_buf, sizeof(recv_buf),
recvlen = recvfrom(igmp_socket, recv_buf, RECV_BUF_SIZE,
0, NULL, &dummy);
if (recvlen >= 0)
accept_igmp(recvlen);
@ -946,9 +949,12 @@ void accept_g_ack()
void add_table_entry()
{
}
void leave_group_message()
void accept_leave_message()
{
}
void mtrace()
void accept_mtrace()
{
}
void accept_membership_query()
{
}

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

@ -44,24 +44,24 @@
* SUCH DAMAGE.
* ---------------------------------
* Copyright (c) Xerox Corporation 1992. All rights reserved.
*
*
* License is granted to copy, to use, and to make and to use derivative works
* for research and evaluation purposes, provided that Xerox is acknowledged
* in all documentation pertaining to any such copy or derivative work. Xerox
* grants no other licenses expressed or implied. The Xerox trade name should
* not be used in any advertising without its written permission.
*
*
* XEROX CORPORATION MAKES NO REPRESENTATIONS CONCERNING EITHER THE
* MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF THIS SOFTWARE FOR
* ANY PARTICULAR PURPOSE. The software is provided "as is" without express
* or implied warranty of any kind.
*
*
* These notices must be retained in any copies of any part of this software.
*/
#ifndef lint
static char rcsid[] =
"@(#) $Id: mrinfo.c,v 1.3 1995/05/16 00:28:46 jkh Exp $";
"@(#) $Id: mrinfo.c,v 3.5.1.1 1995/05/09 22:58:05 fenner Exp $";
/* original rcsid:
"@(#) Header: mrinfo.c,v 1.6 93/04/08 15:14:16 van Exp (LBL)";
*/
@ -70,12 +70,14 @@ static char rcsid[] =
#include <netdb.h>
#include <sys/time.h>
#include "defs.h"
#include <arpa/inet.h>
#define DEFAULT_TIMEOUT 4 /* How long to wait before retrying requests */
#define DEFAULT_RETRIES 3 /* How many times to ask each router */
u_long our_addr, target_addr = 0; /* in NET order */
u_int32 our_addr, target_addr = 0; /* in NET order */
int debug = 0;
int nflag = 0;
int retries = DEFAULT_RETRIES;
int timeout = DEFAULT_TIMEOUT;
int target_level;
@ -84,13 +86,20 @@ vifi_t numvifs; /* to keep loader happy */
char *
inet_name(addr)
u_long addr;
u_int32 addr;
{
struct hostent *e;
struct in_addr in;
e = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET);
if (addr == 0)
return "local";
return e ? e->h_name : "?";
if (nflag ||
(e = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET)) == NULL) {
in.s_addr = addr;
return (inet_ntoa(in));
}
return (e->h_name);
}
/*
@ -98,7 +107,7 @@ inet_name(addr)
* message and the current debug level. For errors of severity LOG_ERR or
* worse, terminate the program.
*/
void
void
log(severity, syserr, format, a, b, c, d, e)
int severity, syserr;
char *format;
@ -137,17 +146,17 @@ log(severity, syserr, format, a, b, c, d, e)
/*
* Send a neighbors-list request.
*/
void
void
ask(dst)
u_long dst;
u_int32 dst;
{
send_igmp(our_addr, dst, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS,
htonl(MROUTED_LEVEL), 0);
}
void
void
ask2(dst)
u_long dst;
u_int32 dst;
{
send_igmp(our_addr, dst, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS2,
htonl(MROUTED_LEVEL), 0);
@ -156,19 +165,19 @@ ask2(dst)
/*
* Process an incoming neighbor-list message.
*/
void
void
accept_neighbors(src, dst, p, datalen)
u_long src, dst;
u_int32 src, dst;
u_char *p;
int datalen;
{
u_char *ep = p + datalen;
#define GET_ADDR(a) (a = ((u_long)*p++ << 24), a += ((u_long)*p++ << 16),\
a += ((u_long)*p++ << 8), a += *p++)
#define GET_ADDR(a) (a = ((u_int32)*p++ << 24), a += ((u_int32)*p++ << 16),\
a += ((u_int32)*p++ << 8), a += *p++)
printf("%s (%s):\n", inet_fmt(src, s1), inet_name(src));
while (p < ep) {
register u_long laddr;
register u_int32 laddr;
register u_char metric;
register u_char thresh;
register int ncount;
@ -179,7 +188,7 @@ accept_neighbors(src, dst, p, datalen)
thresh = *p++;
ncount = *p++;
while (--ncount >= 0) {
register u_long neighbor;
register u_int32 neighbor;
GET_ADDR(neighbor);
neighbor = htonl(neighbor);
printf(" %s -> ", inet_fmt(laddr, s1));
@ -189,30 +198,37 @@ accept_neighbors(src, dst, p, datalen)
}
}
void
void
accept_neighbors2(src, dst, p, datalen)
u_long src, dst;
u_int32 src, dst;
u_char *p;
int datalen;
{
u_char *ep = p + datalen;
u_int broken_cisco = ((target_level & 0xffff) == 0x020a); /* 10.2 */
/* well, only possibly_broken_cisco, but that's too long to type. */
printf("%s (%s) [version %d.%d]:\n", inet_fmt(src, s1), inet_name(src),
target_level & 0xff, (target_level >> 8) & 0xff);
while (p < ep) {
register u_char metric;
register u_char thresh;
register u_char flags;
register int ncount;
register u_long laddr = *(u_long*)p;
register u_int32 laddr = *(u_int32*)p;
p += 4;
metric = *p++;
thresh = *p++;
flags = *p++;
ncount = *p++;
while (--ncount >= 0) {
register u_long neighbor = *(u_long*)p;
if (broken_cisco && ncount == 0) /* dumb Ciscos */
ncount = 1;
if (broken_cisco && ncount > 15) /* dumb Ciscos */
ncount = ncount & 0xf;
while (--ncount >= 0 && p < ep) {
register u_int32 neighbor = *(u_int32*)p;
p += 4;
printf(" %s -> ", inet_fmt(laddr, s1));
printf("%s (%s) [%d/%d", inet_fmt(neighbor, s1),
@ -221,18 +237,22 @@ accept_neighbors2(src, dst, p, datalen)
printf("/tunnel");
if (flags & DVMRP_NF_SRCRT)
printf("/srcrt");
if (flags & DVMRP_NF_PIM)
printf("/pim");
if (flags & DVMRP_NF_QUERIER)
printf("/querier");
if (flags & DVMRP_NF_DISABLED)
printf("/disabled");
if (flags & DVMRP_NF_DOWN)
printf("/down");
if (flags & DVMRP_NF_LEAF)
printf("/leaf");
printf("]\n");
}
}
}
int
int
get_number(var, deflt, pargv, pargc)
int *var, *pargc, deflt;
char ***pargv;
@ -258,33 +278,40 @@ get_number(var, deflt, pargv, pargc)
}
}
u_long
u_int32
host_addr(name)
char *name;
{
struct hostent *e = gethostbyname(name);
int addr;
struct hostent *e;
u_int32 addr;
if (e)
addr = inet_addr(name);
if ((int)addr == -1) {
e = gethostbyname(name);
if (e == NULL || e->h_length != sizeof(addr))
return (0);
memcpy(&addr, e->h_addr_list[0], e->h_length);
else {
addr = inet_addr(name);
if (addr == -1)
addr = 0;
}
return addr;
return(addr);
}
void
usage()
{
fprintf(stderr,
"Usage: mrinfo [-n] [-t timeout] [-r retries] [router]\n");
exit(1);
}
int main(argc, argv)
int
main(argc, argv)
int argc;
char *argv[];
{
setlinebuf(stderr);
if (geteuid() != 0) {
fprintf(stderr, "must be root\n");
fprintf(stderr, "mrinfo: must be root\n");
exit(1);
}
argv++, argc--;
@ -292,29 +319,35 @@ int main(argc, argv)
switch (argv[0][1]) {
case 'd':
if (!get_number(&debug, DEFAULT_DEBUG, &argv, &argc))
goto usage;
usage();
break;
case 'n':
++nflag;
break;
case 'r':
if (!get_number(&retries, -1, &argv, &argc))
goto usage;
usage();
break;
case 't':
if (!get_number(&timeout, -1, &argv, &argc))
goto usage;
usage();
break;
default:
goto usage;
usage();
}
argv++, argc--;
}
if (argc > 1)
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,7 +359,9 @@ usage: fprintf(stderr,
int addrlen = sizeof(addr);
addr.sin_family = AF_INET;
#if (defined(BSD) && (BSD >= 199103))
addr.sin_len = sizeof addr;
#endif
addr.sin_addr.s_addr = target_addr;
addr.sin_port = htons(2000); /* any port over 1024 will
* do... */
@ -347,7 +382,7 @@ usage: fprintf(stderr,
fd_set fds;
struct timeval tv;
int count, recvlen, dummy = 0;
register u_long src, dst, group;
register u_int32 src, dst, group;
struct ip *ip;
struct igmp *igmp;
int ipdatalen, iphdrlen, igmpdatalen;
@ -374,7 +409,7 @@ usage: fprintf(stderr,
ask2(target_addr);
continue;
}
recvlen = recvfrom(igmp_socket, recv_buf, sizeof(recv_buf),
recvlen = recvfrom(igmp_socket, recv_buf, RECV_BUF_SIZE,
0, NULL, &dummy);
if (recvlen <= 0) {
if (recvlen && errno != EINTR)
@ -392,13 +427,6 @@ usage: fprintf(stderr,
if (ip->ip_p == 0)
continue; /* Request to install cache entry */
src = ip->ip_src.s_addr;
if (src != target_addr) {
fprintf(stderr, "mrinfo: got reply from %s",
inet_fmt(src, s1));
fprintf(stderr, " instead of %s\n",
inet_fmt(target_addr, s1));
continue;
}
dst = ip->ip_dst.s_addr;
iphdrlen = ip->ip_hl << 2;
ipdatalen = ip->ip_len;
@ -428,7 +456,7 @@ usage: fprintf(stderr,
inet_fmt(src, s1));
fprintf(stderr, " instead of %s\n",
inet_fmt(target_addr, s1));
continue;
/*continue;*/
}
break;
default:
@ -490,9 +518,12 @@ void add_table_entry()
void check_vif_state()
{
}
void leave_group_message()
void accept_leave_message()
{
}
void mtrace()
void accept_mtrace()
{
}
void accept_membership_query()
{
}

View File

@ -1,26 +1,30 @@
'\"COPYRIGHT 1989 by The Board of Trustees of Leland Stanford Junior University.
.Dd March 25, 1995
.Dt MROUTED 8
.Os FreeBSD 2.0
.Sh NAME
.Nm mrouted
.Nd IP multicast routing process
.Sh SYNOPSIS
.Nm mrouted
.Op Fl p
.Op Fl c Ar config
.Op Fl d Ar debuglevel
.Sh DESCRIPTION
The
.Nm
program
'\"$Id: mrouted.8,v 3.5 1995/05/09 01:00:39 fenner Exp $
.TH MROUTED 8
.UC 5
.SH NAME
mrouted \- IP multicast routing daemon
.SH SYNOPSIS
.B /etc/mrouted
[
.B \-p
] [
.B \-c
.I config_file
] [
.B \-d
[
.I debug_level
]]
.SH DESCRIPTION
.I Mrouted
is an implementation of the Distance-Vector Multicast Routing
Protocol (DVMRP), an earlier version of which is specified in RFC-1075.
It maintains topological knowledge via a distance-vector routing protocol
(like RIP, described in RFC-1058), upon which it implements a multicast
datagram forwarding algorithm called Reverse Path Multicasting.
.Pp
.Nm
.PP
.I Mrouted
forwards a multicast datagram along a shortest (reverse) path tree
rooted at the subnet on which the datagram originates. The multicast
delivery tree may be thought of as a broadcast delivery tree that has
@ -29,221 +33,251 @@ that have members of the destination group. Hence, datagrams
are not forwarded along those branches which have no listeners of the
multicast group. The IP time-to-live of a multicast datagram can be
used to limit the range of multicast datagrams.
.Pp
.PP
In order to support multicasting among subnets that are separated by (unicast)
routers that do not support IP multicasting,
.Nm
.I mrouted
includes support for
.Dq tunnels ,
which are virtual point-to-point links between pairs of
.Nm
programs located anywhere in an internet. IP multicast packets are
encapsulated for transmission through tunnels, so that they look like
normal unicast datagrams to intervening routers and subnets. The
encapsulation is added on entry to a tunnel, and stripped off on exit
from a tunnel. By default, the packets are encapsulated using the
IP-in-IP protocol (IP protocol number 4). Older versions of
.Nm
tunneled using IP source routing, which puts a heavy load on some
"tunnels", which are virtual point-to-point links between pairs of
.IR mrouted s
located anywhere in an internet. IP multicast packets are encapsulated for
transmission through tunnels, so that they look like normal unicast datagrams
to intervening routers and subnets. The encapsulation
is added on entry to a tunnel, and stripped off
on exit from a tunnel.
By default, the packets are encapsulated using the IP-in-IP protocol
(IP protocol number 4).
Older versions of
.I mrouted
tunnel using IP source routing, which puts a heavy load on some
types of routers.
This version supports IP source route tunnelling only for backwards
compatibility.
.Pp
This version does not support IP source route tunnelling.
.PP
The tunnelling mechanism allows
.Nm
.I mrouted
to establish a virtual internet, for
the purpose of multicasting only, which is independent of the physical
internet, and which may span multiple Autonomous Systems. This capability
is intended for experimental support of internet multicasting only, pending
widespread support for multicast routing by the regular (unicast) routers.
.Nm
.I Mrouted
suffers from the well-known scaling problems of any distance-vector
routing protocol, and does not (yet) support hierarchical multicast routing.
.Pp
.Nm
.PP
.I Mrouted
handles multicast routing only; there may or may not be unicast routing
software running on the same machine as
.Nm mrouted .
.IR mrouted .
With the use of tunnels, it
is not necessary for
.Nm
.I mrouted
to have access to more than one physical subnet
in order to perform multicast forwarding.
.Pp
If no
.Fl d
option is given, or if the debug level is specified as 0,
.Nm
detaches from its controlling terminal. Otherwise, it remains attached to the
terminal and responsive to signals.
.Pp
The
.Nm
program accepts the following command-line options:
.Bl -tag -width XXXdebuglevel
.It Fl c Ar config
This option specifies an alternate configuration file location as
.Ar config .
The default location is
.Pa /etc/mrouted.conf .
.It Fl d Ar debuglevel
This option sets the debuging level to
.Ar debuglevel .
Regardless of the debug level,
.Nm
.br
.ne 5
.SH INVOCATION
.PP
If no "\-d" option is given, or if the debug level is specified as 0,
.I mrouted
detaches from the invoking terminal. Otherwise, it remains attached to the
invoking terminal and responsive to signals from that terminal. If "\-d" is
given with no argument, the debug level defaults to 2. Regardless of the
debug level,
.I mrouted
always writes warning and error messages to the system
log demon. Non-zero debug levels have the following effects:
.Bl -tag -width "level 3"
.It level 1
.IP "level 1"
all syslog'ed messages are also printed to stderr.
.It level 2
all level 1 messages plus notifications of
.Dq significant
.IP "level 2"
all level 1 messages plus notifications of "significant"
events are printed to stderr.
.It level 3
.IP "level 3"
all level 2 messages plus notifications of all packet
arrivals and departures are printed to stderr.
.El
.It Fl p
This option disables pruning of uninterested links in the multicast
distribution tree.
.El
.Sh CONFIGURATION
.Nm
.PP
Upon startup, mrouted writes its pid to the file /etc/mrouted.pid .
.SH CONFIGURATION
.PP
.I Mrouted
automatically configures itself to forward on all multicast-capable
interfaces; i.e., interfaces that have the
.Dv IFF_MULTICAST
flag set (excluding the loopback), and it finds other
.Nm
programs directly reachable via those interfaces. To override the
default configuration, or to add tunnel links to other
.Nm
programs, configuration commands may be placed in
.Pa /etc/mrouted.conf
(or an alternate location can be specified using the
.Fl c
option).
interfaces, i.e., interfaces that have the IFF_MULTICAST flag set (excluding
the loopback "interface"), and it finds other
.IR mrouted s
directly reachable
via those interfaces. To override the default configuration, or to add
tunnel links to other
.IR mrouted s,
configuration commands may be placed in
/etc/mrouted.conf (or an alternative file, specified by the "\-c" option).
There are four types of configuration commands:
.Bd -literal
.nf
phyint <local-addr> [disable] [metric <m>]
[threshold <t>] [rate_limit <b>]
[boundary <scoped-addr>/<mask-len>]
[boundary (<boundary-name>|<scoped-addr>/<mask-len>)]
[altnet <network>/<mask-len>]
tunnel <local-addr> <remote-addr> [metric <m>]
[threshold <t>] [srcrt] [rate_limit <b>]
[boundary <scoped-addr>/<mask-len>]
[boundary (<boundary-name>|<scoped-addr>/<mask-len>)]
cache_lifetime <ct>
pruning <off/on>
.Ed
.Pp
One note about the configuration commands--all the phyint and tunnel
command options must be on a single line except for the boundary option
which may begin on a separate line. A single phyint or tunnel command may
have multiple boundary options.
.Pp
name <boundary-name> <scoped-addr>/<mask-len>
.fi
.PP
The file format is free-form; whitespace (including newlines) is not
significant.
The
.I boundary
and
.I altnet
options may be specified as many times as necessary.
.PP
The phyint command can be used to disable multicast routing on the physical
interface identified by local IP address <local-addr>, or to associate a
non-default metric or threshold with the specified physical interface.
The local IP address <local-addr> may be alternatively replaced by the
interface name (e.g., le0) for the phyint command only.
interface name (e.g le0).
If a phyint is attached to multiple IP subnets, describe each additional subnet
with the altnet keyword.
Phyint commands must precede tunnel commands.
.Pp
.PP
The tunnel command can be used to establish a tunnel link between local
IP address <local-addr> and remote IP address <remote-addr>, and to associate
a non-default metric or threshold with that tunnel. The tunnel must be set
up in the mrouted.conf files of both routers before it can be used.
For backwards compatibility with older
.Nm
programs, the srcrt keyword specifies
encapsulation using IP source routing.
.Pp
'\"For backwards compatibility with older
'\".IR mrouted s,
'\"the srcrt keyword specifies
'\"encapsulation using IP source routing.
.PP
The cache_lifetime is a value that determines the amount of time that a
cached multicast route stays in kernel before timing out. The value of this
entry should lie between 300 (5 min) and 86400 (1 day). It defaults to 300.
.Pp
.PP
The pruning <off/on> option is provided for
.Nm
.IR mrouted
to act as a non-pruning router. It is also possible to start
.Nm
in a non-pruning mode using the
.Fl p
flag on the command line. It is expected that a router would be
configured in this manner for test purposes only. The default mode is
pruning enabled.
.Pp
The metric is the
.Dq cost
associated with sending a datagram on the given
.IR mrouted
in a non-pruning mode using the "-p" option on the command line. It is
expected that a router would be configured in this manner for test
purposes only. The default mode is pruning enabled.
.PP
You may assign names to boundaries to make configuration easier with
the name keyword. The boundary option on phyint or tunnel commands
can accept either a name or a boundary.
.PP
The metric is the "cost" associated with sending a datagram on the given
interface or tunnel; it may be used to influence the choice of routes.
The metric defaults to 1. Metrics should be kept as small as possible,
because
.Nm
.I mrouted
cannot route along paths with a sum of metrics greater
than 31.
.Pp
.LP
The threshold is the minimum IP time-to-live required for a multicast datagram
to be forwarded to the given interface or tunnel. It is used to control the
scope of multicast datagrams. (The TTL of forwarded packets is only compared
to the threshold, it is not decremented by the threshold. Every multicast
router decrements the TTL by 1.) The default threshold is 1.
.Pp
.LP
In general, all
.Nm mrouted
programs connected to a particular subnet or tunnel should
.IR mrouted s
connected to a particular subnet or tunnel should
use the same metric and threshold for that subnet or tunnel.
.Pp
.PP
The rate_limit option allows the network administrator to specify a
certain bandwidth in Kbits/second which would be allocated to multicast
traffic.
.Pp
traffic. It defaults to 500Kbps on tunnels, and 0 (unlimited) on physical
interfaces.
.PP
The boundary option allows an interface
to be configured as an administrative boundary for the specified
scoped address. Packets belonging to this address will not
be forwarded on a scoped interface.
.Pp
The
.Nm
program
be forwarded on a scoped interface. The boundary option accepts either
a name or a boundary spec.
.PP
.I Mrouted
will not initiate execution if it has fewer than two enabled vifs,
where a vif (virtual interface) is either a physical multicast-capable
interface or a tunnel. It will log a warning if all of its vifs are
tunnels; such an
.Nm
.I mrouted
configuration would be better replaced by more
direct tunnels (i.e., eliminate the middle man).
.Sh SIGNALS
The
.Nm
program responds to the following signals:
.Bl -tag -width SIGTERMx
.It Dv SIGHUP
.SH "EXAMPLE CONFIGURATION"
.PP
This is an example configuration for a mythical multicast router at a big
school.
.sp
.nf
#
# mrouted.conf example
#
# Name our boundaries to make it easier
name LOCAL 239.255.0.0/16
name EE 239.254.0.0/16
#
# le1 is our gateway to compsci, don't forward our
# local groups to them
phyint le1 boundary EE
#
# le2 is our interface on the classroom net, it has four
# different length subnets on it.
# note that you can use either an ip address or an
# interface name
phyint 172.16.12.38 boundary EE altnet 172.16.15.0/26
altnet 172.16.15.128/26 altnet 172.16.48.0/24
#
# atm0 is our ATM interface, which doesn't properly
# support multicasting.
phyint atm0 disable
#
# This is an internal tunnel to another EE subnet
# Remove the default tunnel rate limit, since this
# tunnel is over ethernets
tunnel 192.168.5.4 192.168.55.101 metric 1 threshold 1
rate_limit 0
#
# This is our tunnel to the outside world.
# Careful with those boundaries, Eugene.
tunnel 192.168.5.4 10.11.12.13 metric 1 threshold 32
boundary LOCAL boundary EE
.fi
.SH SIGNALS
.PP
.I Mrouted
responds to the following signals:
.IP HUP
restarts
.Nm mrouted .
.I mrouted .
The configuration file is reread every time this signal is evoked.
.It Dv SIGINT
.IP INT
terminates execution gracefully (i.e., by sending
good-bye messages to all neighboring routers).
.It Dv SIGTERM
same as
.Dv SIGINT
.It Dv SIGUSR1
dumps the internal routing tables to
.Pa /var/tmp/mrouted.dump .
.It Dv SIGUSR2
dumps the internal cache tables to
.Pa /var/tmp/mrouted.cache .
.It Dv SIGQUIT
.IP TERM
same as INT
.IP USR1
dumps the internal routing tables to /usr/tmp/mrouted.dump.
.IP USR2
dumps the internal cache tables to /usr/tmp/mrouted.cache.
.IP QUIT
dumps the internal routing tables to stderr (only if
.Nm
.I mrouted
was invoked with a non-zero debug level).
.El
.Sh EXAMPLE
.PP
For convenience in sending signals,
.I mrouted
writes its pid to /etc/mrouted.pid upon startup.
.bp
.SH EXAMPLE
.PP
The routing tables look like this:
.Bd -literal
.nf
Virtual Interface Table
Vif Local-Address Metric Thresh Flags
@ -270,110 +304,96 @@ Virtual Interface Table
3 36.2.0.8 tunnel: 36.6.8.23 3 16
Multicast Routing Table (1136 entries)
Origin-Subnet From-Gateway Metric In-Vif Out-Vifs
36.2 1 0 1* 2 3*
36.8 36.8.0.77 4 2 0* 1* 3*
36.11 1 1 0* 2 3*
Origin-Subnet From-Gateway Metric Tmr In-Vif Out-Vifs
36.2 1 45 0 1* 2 3*
36.8 36.8.0.77 4 15 2 0* 1* 3*
36.11 1 20 1 0* 2 3*
.
.
.
.Ed
.Pp
.fi
In this example, there are four vifs connecting to two subnets and two
tunnels. The vif 3 tunnel is not in use (no peer address). The vif 0 and
vif 1 subnets have some groups present; tunnels never have any groups. This
instance of
.Nm
.I mrouted
is the one responsible for sending periodic group
membership queries on the vif 0 and vif 1 subnets, as indicated by the
.Dq querier
flags. The list of boundaries indicate the scoped addresses on that
interface. A count of the number of incoming and outgoing packets is
also shown at each interface.
.Pp
Associated with each subnet from which a multicast datagram can
originate is the address of the previous hop router (unless the subnet
is directly connected), the metric of the path back to the origin,
the incoming vif for multicasts from that origin, and a list of
outgoing vifs.
.Dq Li \&*
means that the outgoing vif is connected to a leaf of the broadcast
tree rooted at the origin, and a multicast datagram from that origin
will be forwarded on that outgoing vif only if there are members of
the destination group on that leaf.
.Pp
.Nm
"querier" flags. The list of boundaries indicate the scoped addresses on that
interface. A count of the no. of incoming and outgoing packets is also
shown at each interface.
.PP
Associated with each subnet from which a multicast datagram can originate
is the address of the previous hop router (unless the subnet is directly-
connected), the metric of the path back to the origin, the amount of time
since we last recieved an update for this subnet, the incoming vif for
multicasts from that origin, and a list of outgoing vifs. "*" means that
the outgoing vif is connected to a leaf of the broadcast tree rooted at the
origin, and a multicast datagram from that origin will be forwarded on that
outgoing vif only if there are members of the destination group on that leaf.
.bp
.PP
.I Mrouted
also maintains a copy of the kernel forwarding cache table. Entries
are created and deleted by
.Nm mrouted .
.Pp
.I mrouted.
.PP
The cache tables look like this:
.Bd -literal
.nf
Multicast Routing Cache Table (325 entries)
Origin-Subnet Mcast-group CTmr IVif Prcv# Psnt Forwvifs
134.207.7 224.2.140.239 300 1 0 0 2
138.15.103 224.2.203.214 295 1 2 P 0p 2p
128.237.0 224.2.253.119 290 1 1 0 2p
129.215.200 224.2.207.48 40 1 1 0p 2
36.77.14 239.0.1.234 345 2b
Multicast Routing Cache Table (147 entries)
Origin Mcast-group CTmr Age Ptmr IVif Forwvifs
13.2.116/22 224.2.127.255 3m 2m - 0 1
>13.2.116.19
>13.2.116.196
138.96.48/21 224.2.127.255 5m 2m - 0 1
>138.96.48.108
128.9.160/20 224.2.127.255 3m 2m - 0 1
>128.9.160.45
198.106.194/24 224.2.135.190 9m 28s 9m 0P
>198.106.194.22
.Ed
.Pp
Each entry is characterized by the origin subnet number and the
destination multicast group. The
.Dq CTmr
field indicates the lifetime
(in seconds) of the entry. The entry is deleted from the cache table
when the timer decrements to zero. The
.Dq Ivif
field indicates the
.fi
Each entry is characterized by the origin subnet number and mask and the
destination multicast group. The 'CTmr' field indicates the lifetime
of the entry. The entry is deleted from the cache table
when the timer decrements to zero. The 'Age' field is the time since
this cache entry was originally created. Since cache entries get refreshed
if traffic is flowing, routing entries can grow very old.
The 'Ptmr' field is simply a dash if no prune was sent upstream, or the
amount of time until the upstream prune will time out.
The 'Ivif' field indicates the
incoming vif for multicast packets from that origin. Each router also
maintains a record of the number of prunes received from neighbouring
routers for a particular source and group. If there are no members of
a multicast group on any downward link of the multicast tree for a
subnet, a prune message is sent to the upstream router. They are
indicated by a
.Dq Li \&P
in the
.Dq Psnt
field. The
.Dq Forwvifs
field shows the
indicated by a "P" after the vif number. The Forwvifs field shows the
interfaces along which datagrams belonging to the source-group are
forwarded. A
.Dq Li \&p
indicates that no datagrams are being forwarded along
forwarded. A "p" indicates that no datagrams are being forwarded along
that interface. An unlisted interface is a leaf subnet with are no
members of the particular group on that subnet. A
.Dq Li \&b
on an interface
indicates that it is a boundary interface; i.e., traffic will not be
members of the particular group on that subnet. A "b" on an interface
indicates that it is a boundary interface, i.e. traffic will not be
forwarded on the scoped address on that interface.
.Sh FILES
.Bl -tag -compact -width /var/tmp/mrouted.cache
.It Pa /etc/mrouted.conf
default configuration file
.It Pa /var/tmp/mrouted.cache
kernel forwarding cache dump file
.It Pa /var/tmp/mrouted.dump
routing table dump file
.El
.Sh SEE ALSO
.Xr map-mbone 8 ,
.Xr mrinfo 8 ,
.Xr mtrace 8
.Rs
.%A "S. Deering"
.%B "Proceedings of the ACM SIGCOMM '88 Conference"
.%T "Multicast Routing in Internetworks and Extended LANs"
.Re
.Sh AUTHORS
Steve Deering & Ajit Thyagarajan
.Sh HISTORY
The
.Nm
program first appeared in
.Tn FreeBSD
2.0.
An additional line with a ">" as the first character is printed for
each source on the subnet. Note that there can be many sources in
one subnet.
.SH FILES
/etc/mrouted.conf
.br
/etc/mrouted.pid
.br
/usr/tmp/mrouted.dump
.br
/usr/tmp/mrouted.cache
.SH SEE ALSO
.BR mrinfo (8) ,
.BR mtrace (8) ,
.BR map-mbone (8)
.sp
DVMRP is described, along with other multicast routing algorithms, in the
paper "Multicast Routing in Internetworks and Extended LANs" by S. Deering,
in the Proceedings of the ACM SIGCOMM '88 Conference.
.SH AUTHORS
Steve Deering, Ajit Thyagarajan, Bill Fenner

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

View File

@ -1,4 +1,4 @@
# $Id$
# $Id: Makefile,v 1.1 1994/09/08 02:51:35 wollman Exp $
PROG= mrouted
@ -14,7 +14,7 @@ LDDESTDIR+= -L$S/common
DPADD+= $S/common/libmrouted.a
.endif
SRCS= config.c main.c route.c vif.c prune.c callout.c
SRCS= config.c cfparse.y main.c route.c vif.c prune.c callout.c rsrr.c
MAN8= ${.CURDIR}/../mrouted.8
.include <bsd.prog.mk>

499
usr.sbin/mrouted/mtrace.8 Normal file
View File

@ -0,0 +1,499 @@
.\" Copyright (c) 1995 by the University of Southern California
.\" All rights reserved.
.\"
.\" Permission to use, copy, modify, and distribute this software and its
.\" documentation in source and binary forms for non-commercial purposes
.\" and without fee is hereby granted, provided that the above copyright
.\" notice appear in all copies and that both the copyright notice and
.\" this permission notice appear in supporting documentation, and that
.\" any documentation, advertising materials, and other materials related
.\" to such distribution and use acknowledge that the software was
.\" developed by the University of Southern California, Information
.\" Sciences Institute. The name of the University may not be used to
.\" endorse or promote products derived from this software without
.\" specific prior written permission.
.\"
.\" THE UNIVERSITY OF SOUTHERN CALIFORNIA makes no representations about
.\" the suitability of this software for any purpose. THIS SOFTWARE IS
.\" PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
.\" INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
.\"
.\" Other copyrights might apply to parts of this software and are so
.\" noted when applicable.
.\"
.\" This manual page (but not the software) was derived from the
.\" manual page for the traceroute program which bears the following
.\" copyright notice:
.\"
.\" Copyright (c) 1988 The Regents of the University of California.
.\" All rights reserved.
.\"
.\" $Id: mtrace.8,v 3.5 1995/05/09 01:23:58 fenner Exp $
.\"
.TH MTRACE 8 "May 8, 1995"
.UC 6
.SH NAME
mtrace \- print multicast path from a source to a receiver
.SH SYNOPSIS
.B mtrace
[
.B \-g
.I gateway
] [
.B \-i
.I if_addr
] [
.B \-l
] [
.B \-M
] [
.B \-m
.I max_hops
] [
.B \-n
] [
.B \-p
] [
.B \-q
.I nqueries
] [
.B \-r
.I resp_dest
] [
.B \-s
.I src_addr
] [
.B \-t
.I ttl
] [
.B \-w
.I waittime
]
.I source
[
.I receiver
] [
.I group
]
.SH DESCRIPTION
Assessing problems in the distribution of IP multicast traffic
can be difficult.
.B mtrace
utilizes a tracing feature implemented in multicast routers
.RB ( mrouted
version 3.3 and later) that is
accessed via an extension to the IGMP protocol. A trace query is
passed hop-by-hop along the reverse path from the
.I receiver
to the
.IR source ,
collecting hop addresses, packet counts, and routing error conditions
along the path, and then the response is returned to the requestor.
.PP
The only required parameter is the
.I source
host name or address. The default
.I receiver
is the host running mtrace, and the default
.I group
is "MBone Audio" (224.2.0.1), which is sufficient if packet loss
statistics for a particular multicast group are not needed. These two
optional parameters may be specified to test the path to some other
receiver in a particular group, subject to some constraints as
detailed below. The two parameters can be distinguished because the
.I receiver
is a unicast address and the
.I group
is a multicast address.
.SH OPTIONS
.TP 8 8
.BI \-g\ gwy
Send the trace query via unicast directly to the multicast router
.I gwy
rather than multicasting the query.
This must be the last-hop router on the path from the intended
.I source
to the
.IR receiver .
.RS 8
.TP 12 12
.I CAUTION!!
Version 3.3 of
.B mrouted
will crash if a trace query is received via a
unicast packet and
.B mrouted
has no route for the
.I source
address. Therefore, do not use the
.B \-g
option unless the target
.B mrouted
has been verified to be newer than 3.3.
.RE
.TP 8 8
.BI \-i\ addr
Use
.I addr
as the local interface address (on a multi-homed host) for sending the
trace query and as the default for the
.I receiver
and the response destination.
.TP 8 8
.B \-l
Loop indefinitely printing packet rate and loss statistics for the
multicast path every 10 seconds.
.TP 8 8
.B \-M
Always send the response using multicast rather than attempting
unicast first.
.TP 8 8
.BI \-m\ n
Set to
.I n
the maximum number of hops that will be traced from the
.I receiver
back toward the
.IR source .
The default is 32 hops (infinity for the DVMRP routing protocol).
.TP 8 8
.B \-n
Print hop addresses numerically rather than symbolically and numerically
(saves a nameserver address-to-name lookup for each router found on the
path).
.TP 8 8
.BI \-q\ n
Set the maximum number of query attempts for any hop to
.IR n .
The default is 3.
.TP 8 8
.B \-p
Listen passively for multicast responses from traces initiated by
others (not implemented yet).
.TP 8 8
.BI \-r\ host
Send the trace response to
.I host
rather than to the host on which
.B mtrace
is being run, or to a multicast address other than the one registered
for this purpose (224.0.1.32).
.TP 8 8
.B \-s
Print a short form output including only the multicast path and not
the packet rate and loss statistics.
.TP 8 8
.BI \-t\ ttl
Set the
.I ttl
(time-to-live, or number of hops) for multicast trace queries and
responses. The default is 64, except for local queries to the "all
routers" multicast group which use ttl 1.
.TP 8 8
.BI \-w\ n
Set the time to wait for a trace response to
.I n
seconds (default 3 seconds).
.SH USAGE
.SS How It Works
The technique used by the
.B traceroute
tool to trace unicast network paths will not work for IP multicast
because ICMP responses are specifically forbidden for multicast traffic.
Instead, a tracing feature has been built into the multicast routers.
This technique has the advantage that additional information about
packet rates and losses can be accumulated while the number of packets
sent is minimized.
.PP
Since multicast uses
reverse path forwarding, the trace is run backwards from the
.I receiver
to the
.IR source .
A trace query packet is sent to the last
hop multicast router (the leaf router for the desired
.I receiver
address). The last hop router builds a trace response packet, fills in
a report for its hop, and forwards the trace packet using unicast to
the router it believes is the previous hop for packets originating
from the specified
.IR source .
Each router along the path adds its report and forwards the packet.
When the trace response packet reaches the first hop router (the router
that is directly connected to the source's net), that router sends the
completed response to the response destination address specified in
the trace query.
.PP
If some multicast router along the path does not implement the
multicast traceroute feature or if there is some outage, then no
response will be returned. To solve this problem, the trace query
includes a maximum hop count field to limit the number of hops traced
before the response is returned. That allows a partial path to be
traced.
.PP
The reports inserted by each router contain not only the address of
the hop, but also the ttl required to forward and some flags to indicate
routing errors, plus counts of the total number of packets on the
incoming and outgoing interfaces and those forwarded for the specified
.IR group .
Taking differences in these counts for two traces separated in time
and comparing the output packet counts from one hop with the input
packet counts of the next hop allows the calculation of packet rate
and packet loss statistics for each hop to isolate congestion
problems.
.SS Finding the Last-Hop Router
The trace query must be sent to the multicast router which is the
last hop on the path from the
.I source
to the
.IR receiver .
If the receiver is on the local subnet (as determined using the subnet
mask), then the default method is to multicast the trace query to
all-routers.mcast.net (224.0.0.2) with a ttl of 1. Otherwise, the
trace query is multicast to the
.I group
address since the last hop router will be a member of that group if
the receiver is. Therefore it is necessary to specify a group that
the intended receiver has joined. This multicast is sent with a
default ttl of 64, which may not be sufficient for all cases (changed
with the
.B \-t
option).
If the last hop router is known, it may also be addressed directly
using the
.B \-g
option). Alternatively, if it is desired to trace a group that the
receiver has not joined, but it is known that the last-hop router is a
member of another group, the
.B \-g
option may also be used to specify a different multicast address for the
trace query.
.PP
When tracing from a multihomed host or router, the default receiver
address may not be the desired interface for the path from the source.
In that case, the desired interface should be specified explicitly as
the
.IR receiver .
.SS Directing the Response
By default,
.B mtrace
first attempts to trace the full reverse path, unless the number of
hops to trace is explicitly set with the
.B \-m
option. If there is no response within a 3 second timeout interval
(changed with the
.B \-w
option), a "*" is printed and the probing switches to hop-by-hop mode.
Trace queries are issued starting with a maximum hop count of one and
increasing by one until the full path is traced or no response is
received. At each hop, multiple probes are sent (default is three,
changed with
.B \-q
option). The first half of the attempts (default is one) are made with
the unicast address of the host running
.B mtrace
as the destination for the response. Since the unicast route may be
blocked, the remainder of attempts request that the response be
multicast to mtrace.mcast.net (224.0.1.32) with the ttl set to 32 more
than what's needed to pass the thresholds seen so far along the path
to the receiver. For the last quarter of the attempts (default is
one), the ttl is increased by another 32 each time up to a maximum of
192. Alternatively, the ttl may be set explicity with the
.B \-t
option and/or the initial unicast attempts can be forced to use
multicast instead with the
.B \-M
option. For each attempt, if no response is received within the
timeout, a "*" is printed. After the specified number of attempts
have failed,
.B mtrace
will try to query the next hop router with a DVMRP_ASK_NEIGHBORS2
request (as used by the
.B mrinfo
program) to see what kind of router it is.
.SH EXAMPLES
The output of
.B mtrace
is in two sections. The first section is a short listing of the hops
in the order they are queried, that is, in the reverse of the order
from the
.I source
to the
.IR receiver .
For each hop, a line is printed showing the hop number (counted
negatively to indicate that this is the reverse path); the multicast
routing protocol (DVMRP, MOSPF, PIM, etc.); the threshold required to
forward data (to the previous hop in the listing as indicated by the
up-arrow character); and the cumulative delay for the query to reach
that hop (valid only if the clocks are synchronized). This first
section ends with a line showing the round-trip time which measures
the interval from when the query is issued until the response is
received, both derived from the local system clock. A sample use and
output might be:
.PP
.nf
.ft C
oak.isi.edu 80# mtrace -l caraway.lcs.mit.edu 224.2.0.3
Mtrace from 18.26.0.170 to 128.9.160.100 via group 224.2.0.3
Querying full reverse path...
0 oak.isi.edu (128.9.160.100)
-1 cub.isi.edu (128.9.160.153) DVMRP thresh^ 1 3 ms
-2 la.dart.net (140.173.128.1) DVMRP thresh^ 1 14 ms
-3 dc.dart.net (140.173.64.1) DVMRP thresh^ 1 50 ms
-4 bbn.dart.net (140.173.32.1) DVMRP thresh^ 1 63 ms
-5 mit.dart.net (140.173.48.2) DVMRP thresh^ 1 71 ms
-6 caraway.lcs.mit.edu (18.26.0.170)
Round trip time 124 ms
.fi
.PP
The second section provides a pictorial view of the path in the
forward direction with data flow indicated by arrows pointing downward
and the query path indicated by arrows pointing upward. For each hop,
both the entry and exit addresses of the router are shown if
different, along with the initial ttl required on the packet in order
to be forwarded at this hop and the propagation delay across the hop
assuming that the routers at both ends have synchronized clocks. The
right half of this section is composed of several columns of
statistics in two groups. Within each group, the columns are the
number of packets lost, the number of packets sent, the percentage
lost, and the average packet rate at each hop. These statistics are
calculated from differences between traces and from hop to hop as
explained above. The first group shows the statistics for all traffic
flowing out the interface at one hop and in the interface at the next
hop. The second group shows the statistics only for traffic forwarded
from the specified
.I source
to the specified
.IR group .
.PP
These statistics are shown on one or two lines for each hop. Without
any options, this second section of the output is printed only once,
approximately 10 seconds after the initial trace. One line is shown
for each hop showing the statistics over that 10-second period. If
the
.B \-l
option is given, the second section is repeated every 10 seconds and
two lines are shown for each hop. The first line shows the statistics
for the last 10 seconds, and the second line shows the cumulative
statistics over the period since the initial trace, which is 101
seconds in the example below. The second section of the output is
omitted if the
.B \-s
option is set.
.ie t \{\
.ft C
. ie \w'i'<>\w'm' \{\" looks like this is not proper Courier font
(If this example is not properly columned with a fixed-width font, get
.B groff
and try again.)
. \}
.\}
.PP
.ft C
.nf
Waiting to accumulate statistics... Results after 101 seconds:
Source Response Dest Packet Statistics For Only For Traffic
18.26.0.170 128.9.160.100 All Multicast Traffic From 18.26.0.170
| __/ rtt 125 ms Lost/Sent = Pct Rate To 224.2.0.3
v / hop 65 ms --------------------- ------------------
18.26.0.144
140.173.48.2 mit.dart.net
| ^ ttl 1 0/6 = --% 0 pps 0/2 = --% 0 pps
v | hop 8 ms 1/52 = 2% 0 pps 0/18 = 0% 0 pps
140.173.48.1
140.173.32.1 bbn.dart.net
| ^ ttl 2 0/6 = --% 0 pps 0/2 = --% 0 pps
v | hop 12 ms 1/52 = 2% 0 pps 0/18 = 0% 0 pps
140.173.32.2
140.173.64.1 dc.dart.net
| ^ ttl 3 0/271 = 0% 27 pps 0/2 = --% 0 pps
v | hop 34 ms -1/2652 = 0% 26 pps 0/18 = 0% 0 pps
140.173.64.2
140.173.128.1 la.dart.net
| ^ ttl 4 -2/831 = 0% 83 pps 0/2 = --% 0 pps
v | hop 11 ms -3/8072 = 0% 79 pps 0/18 = 0% 0 pps
140.173.128.2
128.9.160.153 cub.isi.edu
| \\__ ttl 5 833 83 pps 2 0 pps
v \\ hop -8 ms 8075 79 pps 18 0 pps
128.9.160.100 128.9.160.100
Receiver Query Source
.fi
.PP
Because the packet counts may be changing as the trace query is
propagating, there may be small errors (off by 1 or 2) in these
statistics. However, those errors should not accumulate, so the
cumulative statistics line should increase in accuracy as a new trace
is run every 10 seconds. There are two sources of larger errors, both
of which show up as negative losses:
.LP
.RS
.PD 0
.TP 3
\(bu
If the input to a node is from a multi-access network with more than
one other node attached, then the input count will be (close to) the
sum of the output counts from all the attached nodes, but the output
count from the previous hop on the traced path will be only part of
that. Hence the output count minus the input count will be negative.
.TP 3
\(bu
In release 3.3 of the DVMRP multicast forwarding software for SunOS
and other systems, a multicast packet generated on a router will be
counted as having come in an interface even though it did not. This
creates the negative loss that can be seen in the example above.
.PD
.RE
.LP
Note that these negative losses may mask positive losses.
.PP
In the example, there is also one negative hop time. This simply
indicates a lack of synchronization between the system clocks across
that hop. This example also illustrates how the percentage loss is
shown as two dashes when the number of packets sent is less than 10
because the percentage would not be statistically valid.
.PP
A second example shows a trace to a receiver that is not local; the
query is sent to the last-hop router with the
.B \-g
option. In this example, the trace of the full reverse path resulted
in no response because there was a node running an old version of
.B mrouted
that did not implement the multicast traceroute function, so
.B mtrace
switched to hop-by-hop mode. The \*(lqRoute pruned\*(rq error code
indicates that traffic for group 224.2.143.24 would not be forwarded.
.PP
.nf
.ft C
oak.isi.edu 108# mtrace -g 140.173.48.2 204.62.246.73 \\
butter.lcs.mit.edu 224.2.143.24
Mtrace from 204.62.246.73 to 18.26.0.151 via group 224.2.143.24
Querying full reverse path... * switching to hop-by-hop:
0 butter.lcs.mit.edu (18.26.0.151)
-1 jam.lcs.mit.edu (18.26.0.144) DVMRP thresh^ 1 33 ms Route pruned
-2 bbn.dart.net (140.173.48.1) DVMRP thresh^ 1 36 ms
-3 dc.dart.net (140.173.32.2) DVMRP thresh^ 1 44 ms
-4 darpa.dart.net (140.173.240.2) DVMRP thresh^ 16 47 ms
-5 * * * noc.hpc.org (192.187.8.2) [mrouted 2.2] didn't respond
Round trip time 95 ms
.fi
.SH AUTHOR
Implemented by Steve Casner based on an initial prototype written by
Ajit Thyagarajan. The multicast traceroute mechanism was designed by
Van Jacobson with help from Steve Casner, Steve Deering, Dino
Farinacci, and Deb Agrawal; it was implemented in
.B mrouted
by Ajit Thyagarajan and Bill Fenner. The option syntax and the output
format of
.B mtrace
are modeled after the unicast
.B traceroute
program written by Van Jacobson.
.SH SEE ALSO
.BR mrouted (8) ,
.BR mrinfo (8) ,
.BR map-mbone (8) ,
.BR traceroute (8)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,25 @@
/*
* The mrouted program is covered by the license in the accompanying file
* named "LICENSE". Use of the mrouted program represents acceptance of
* the terms and conditions listed in that file.
*
* The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
* Leland Stanford Junior University.
*
*
* $Id: pathnames.h,v 3.5 1995/05/09 01:00:39 fenner Exp $
*/
#define _PATH_MROUTED_CONF "/etc/mrouted.conf"
#if (defined(BSD) && (BSD >= 199103))
#define _PATH_MROUTED_PID "/var/run/mrouted.pid"
#define _PATH_MROUTED_GENID "/var/run/mrouted.genid"
#define _PATH_MROUTED_DUMP "/var/tmp/mrouted.dump"
#define _PATH_MROUTED_CACHE "/var/tmp/mrouted.cache"
#else
#define _PATH_MROUTED_PID "/etc/mrouted.pid"
#define _PATH_MROUTED_GENID "/etc/mrouted.genid"
#define _PATH_MROUTED_DUMP "/usr/tmp/mrouted.dump"
#define _PATH_MROUTED_CACHE "/usr/tmp/mrouted.cache"
#endif

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.2 1994/09/08 02:51:24 wollman Exp $
* $Id: prune.h,v 3.5 1995/05/09 01:00:39 fenner Exp $
*/
/*
* Macro for copying the user-level cache table to the kernel
* level table variable passed on by the setsock option
*/
#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) { \
u_int32 _x = ntohl(x); \
(i) = 0; \
while ((x) << (i)) \
while ((_x) << (i)) \
(i)++; \
}
};
#define VAL_TO_MASK(x, i) { \
x = ~((1 << (32 - (i))) - 1); \
}
x = htonl(~((1 << (32 - (i))) - 1)); \
};
#define NBR_VERS(n) (((n)->al_pv << 8) + (n)->al_mv)

View File

@ -7,13 +7,18 @@
* Leland Stanford Junior University.
*
*
* $Id: route.c,v 1.2 1994/09/08 02:51:25 wollman Exp $
* $Id: route.c,v 3.5 1995/05/09 01:00:39 fenner Exp $
*/
#include "defs.h"
/*
* This define statement saves a lot of space later
*/
#define RT_ADDR (struct rtentry *)&routing_table
/*
* Exported variables.
*/
@ -21,18 +26,23 @@ 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 */
/*
* Initialize the routing table and associated variables.
*/
void init_routes()
void
init_routes()
{
routing_table = NULL;
nroutes = 0;
@ -47,7 +57,8 @@ void init_routes()
* Return TRUE if this changes the value of either the children or
* leaf bitmaps for 'r'.
*/
static int init_children_and_leaves(r, parent)
static int
init_children_and_leaves(r, parent)
register struct rtentry *r;
register vifi_t parent;
{
@ -91,7 +102,8 @@ static int init_children_and_leaves(r, parent)
* A new vif has come up -- update the children and leaf bitmaps in all route
* entries to take that into account.
*/
void add_vif_to_routes(vifi)
void
add_vif_to_routes(vifi)
register vifi_t vifi;
{
register struct rtentry *r;
@ -124,7 +136,8 @@ void add_vif_to_routes(vifi)
* and update the children bitmaps in all other route entries to take into
* account the failed vif.
*/
void delete_vif_from_routes(vifi)
void
delete_vif_from_routes(vifi)
register vifi_t vifi;
{
register struct rtentry *r;
@ -158,8 +171,9 @@ void delete_vif_from_routes(vifi)
* considered a dominant or subordinate router in any route entries,
* take appropriate action.
*/
void delete_neighbor_from_routes(addr, vifi)
register u_long addr;
void
delete_neighbor_from_routes(addr, vifi)
register u_int32 addr;
register vifi_t vifi;
{
register struct rtentry *r;
@ -213,9 +227,10 @@ void delete_neighbor_from_routes(addr, vifi)
* a single message be in the same order as the route entries in the routing
* table.
*/
void start_route_updates()
void
start_route_updates()
{
rtp = (struct rtentry *)&routing_table;
rtp = RT_ADDR;
}
@ -228,8 +243,9 @@ void start_route_updates()
* This code is optimized for the normal case in which the first entry to
* be examined is the matching entry.
*/
static int find_route(origin, mask)
register u_long origin, mask;
static int
find_route(origin, mask)
register u_int32 origin, mask;
{
register struct rtentry *r;
@ -239,9 +255,9 @@ static int find_route(origin, mask)
rtp = r;
return (TRUE);
}
if (ntohl(mask) > ntohl(r->rt_originmask) ||
if (ntohl(mask) < ntohl(r->rt_originmask) ||
(mask == r->rt_originmask &&
ntohl(origin) > ntohl(r->rt_origin))) {
ntohl(origin) < ntohl(r->rt_origin))) {
rtp = r;
r = r->rt_next;
}
@ -250,31 +266,6 @@ static int find_route(origin, mask)
return (FALSE);
}
/*
* Search the entire routing table, looking for an entry which conflicts
* with the given origin and mask, for example, an entry which has the same
* origin under a different mask. If a conflicting entry is found, return
* a pointer to the entry preceding it (to facilitate deletion); if no
* conflict is found, return NULL.
*/
static struct rtentry *find_conflicting_route(origin, mask)
register u_long origin, mask;
{
register struct rtentry *r, *prev_r;
for (prev_r = (struct rtentry *)&routing_table, r = routing_table;
r != NULL;
prev_r = r, r = r->rt_next ) {
if ((origin & r->rt_originmask) == r->rt_origin ||
(r->rt_origin & mask) == origin) {
return (prev_r);
}
}
return (NULL);
}
/*
* Create a new routing table entry for the specified origin and link it into
* the routing table. The shared variable 'rtp' is assumed to point to the
@ -285,13 +276,15 @@ static struct rtentry *find_conflicting_route(origin, mask)
* in the new route entry; the caller is responsible for filling in the the
* rest.
*/
static void create_route(origin, mask)
u_long origin, mask;
static void
create_route(origin, mask)
u_int32 origin, mask;
{
register struct rtentry *r;
if ((r = (struct rtentry *) malloc(sizeof(struct rtentry)
+ (3 * numvifs * sizeof(u_long)))) == NULL) {
if ((r = (struct rtentry *) malloc(sizeof(struct rtentry) +
(2 * numvifs * sizeof(u_int32)) +
(numvifs * sizeof(u_long)))) == NULL) {
log(LOG_ERR, 0, "ran out of memory"); /* fatal */
}
r->rt_origin = origin;
@ -301,12 +294,18 @@ static void create_route(origin, mask)
else if (((char *)&mask)[1] != 0) r->rt_originwidth = 2;
else r->rt_originwidth = 1;
r->rt_flags = 0;
r->rt_dominants = (u_long *)(r + 1);
r->rt_subordinates = (u_long *)(r->rt_dominants + numvifs);
r->rt_dominants = (u_int32 *)(r + 1);
r->rt_subordinates = (u_int32 *)(r->rt_dominants + numvifs);
r->rt_leaf_timers = (u_long *)(r->rt_subordinates + numvifs);
r->rt_groups = NULL;
r->rt_next = rtp->rt_next;
rtp->rt_next = r;
r->rt_prev = rtp;
if (r->rt_next != NULL)
(r->rt_next)->rt_prev = r;
else
rt_end = r;
rtp = r;
++nroutes;
}
@ -315,13 +314,18 @@ static void create_route(origin, mask)
/*
* Discard the routing table entry following the one to which 'prev_r' points.
*/
static void discard_route(prev_r)
static void
discard_route(prev_r)
register struct rtentry *prev_r;
{
register struct rtentry *r;
r = prev_r->rt_next;
prev_r->rt_next = r->rt_next;
if (prev_r->rt_next != NULL)
(prev_r->rt_next)->rt_prev = prev_r;
else
rt_end = prev_r;
free((char *)r);
--nroutes;
}
@ -333,10 +337,11 @@ static void discard_route(prev_r)
* address of a neighboring router from which the report arrived, or zero
* to indicate a change of status of one of our own interfaces.
*/
void update_route(origin, mask, metric, src, vifi)
u_long origin, mask;
void
update_route(origin, mask, metric, src, vifi)
u_int32 origin, mask;
int metric;
u_long src;
u_int32 src;
vifi_t vifi;
{
register struct rtentry *r;
@ -361,6 +366,10 @@ void update_route(origin, mask, metric, src, vifi)
* Look up the reported origin in the routing table.
*/
if (!find_route(origin, mask)) {
register struct rtentry *rp;
register struct gtable *gt;
register struct stable *st, **stnp;
/*
* Not found.
* Don't create a new entry if the report says it's unreachable,
@ -376,39 +385,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 +568,14 @@ void update_route(origin, mask, metric, src, vifi)
/*
* On every timer interrupt, advance the timer in each routing entry.
*/
void age_routes()
void
age_routes()
{
register struct rtentry *r;
register struct rtentry *prev_r;
register vifi_t vifi;
for (prev_r = (struct rtentry *)&routing_table, r = routing_table;
for (prev_r = RT_ADDR, r = routing_table;
r != NULL;
prev_r = r, r = r->rt_next) {
@ -602,8 +592,19 @@ void age_routes()
* Unlike other timers, leaf timers decrement.
*/
if ((r->rt_leaf_timers[vifi] -= TIMER_INTERVAL) == 0){
VIFM_SET(vifi, r->rt_leaves);
update_table_entry(r);
#ifdef NOTYET
/* If the vif is a physical leaf but has neighbors,
* it is not a tree leaf. If I am a leaf, then no
* interface with neighbors is a tree leaf. */
if (!(((uvifs[vifi].uv_flags & VIFF_LEAF) ||
(vifs_with_neighbors == 1)) &&
(uvifs[vifi].uv_neighbors != NULL))) {
#endif
VIFM_SET(vifi, r->rt_leaves);
update_table_entry(r);
#ifdef NOTYET
}
#endif
}
else {
r->rt_flags |= RTF_LEAF_TIMING;
@ -616,6 +617,7 @@ void age_routes()
/*
* Time to garbage-collect the route entry.
*/
del_table_entry(r, 0, DEL_ALL_ROUTES);
discard_route(prev_r);
r = prev_r;
}
@ -648,7 +650,8 @@ void age_routes()
* on the kernel to do its own cleanup -- no point in making all those
* expensive kernel calls now.
*/
void expire_all_routes()
void
expire_all_routes()
{
register struct rtentry *r;
@ -663,11 +666,12 @@ void expire_all_routes()
/*
* Delete all the routes in the routing table.
*/
void free_all_routes()
void
free_all_routes()
{
register struct rtentry *r;
r = (struct rtentry *)&routing_table;
r = RT_ADDR;
while (r->rt_next)
discard_route(r);
@ -677,12 +681,13 @@ void free_all_routes()
/*
* Process an incoming neighbor probe message.
*/
void accept_probe(src, dst, p, datalen, level)
u_long src;
u_long dst;
void
accept_probe(src, dst, p, datalen, level)
u_int32 src;
u_int32 dst;
char *p;
int datalen;
u_long level;
u_int32 level;
{
vifi_t vifi;
@ -699,48 +704,50 @@ void accept_probe(src, dst, p, datalen, level)
}
struct newrt {
u_long mask;
u_long origin;
u_int32 mask;
u_int32 origin;
int metric;
int pad;
};
};
int compare_rts(r1, r2)
int
compare_rts(r1, r2)
register struct newrt *r1;
register struct newrt *r2;
{
register unsigned long m1 = ntohl(r1->mask);
register unsigned long m2 = ntohl(r2->mask);
register unsigned long o1, o2;
register u_int32 m1 = ntohl(r1->mask);
register u_int32 m2 = ntohl(r2->mask);
register u_int32 o1, o2;
if (m1 > m2)
return (1);
if (m1 < m2)
return (-1);
if (m1 < m2)
return (1);
/* masks are equal */
o1 = ntohl(r1->origin);
o2 = ntohl(r2->origin);
if (o1 > o2)
return (1);
if (o1 < o2)
return (-1);
if (o1 < o2)
return (1);
return (0);
}
/*
* Process an incoming route report message.
*/
void accept_report(src, dst, p, datalen, level)
u_long src, dst, level;
void
accept_report(src, dst, p, datalen, level)
u_int32 src, dst, level;
register char *p;
register int datalen;
{
vifi_t vifi;
register int width, i, nrt = 0;
int metric;
u_long mask;
u_long origin;
u_int32 mask;
u_int32 origin;
struct newrt rt[4096];
if ((vifi = find_vif(src, dst)) == NO_VIF) {
@ -763,20 +770,20 @@ void accept_report(src, dst, p, datalen, level)
if (datalen < 3) {
log(LOG_WARNING, 0,
"received truncated route report from %s",
"received truncated route report from %s",
inet_fmt(src, s1));
return;
}
((char *)&mask)[0] = 0xff; width = 1;
if ((((char *)&mask)[1] = *p++) != 0) width = 2;
if ((((char *)&mask)[2] = *p++) != 0) width = 3;
if ((((char *)&mask)[3] = *p++) != 0) width = 4;
((u_char *)&mask)[0] = 0xff; width = 1;
if ((((u_char *)&mask)[1] = *p++) != 0) width = 2;
if ((((u_char *)&mask)[2] = *p++) != 0) width = 3;
if ((((u_char *)&mask)[3] = *p++) != 0) width = 4;
datalen -= 3;
do { /* Loop through (origin, metric) pairs */
if (datalen < width + 1) {
log(LOG_WARNING, 0,
"received truncated route report from %s",
"received truncated route report from %s",
inet_fmt(src, s1));
return;
}
@ -787,14 +794,22 @@ void accept_report(src, dst, p, datalen, level)
datalen -= width + 1;
rt[nrt].mask = mask;
rt[nrt].origin = origin;
rt[nrt].metric = metric;
rt[nrt].metric = (metric & 0x7f);
++nrt;
} while (!(metric & 0x80));
}
qsort((char*)rt, nrt, sizeof(rt[0]), compare_rts);
start_route_updates();
/*
* If the last entry is default, change mask from 0xff000000 to 0
*/
if (rt[nrt-1].origin == 0)
rt[nrt-1].mask = 0;
log(LOG_DEBUG, 0, "Updating %d routes from %s to %s", nrt,
inet_fmt(src, s1), inet_fmt(dst, s2));
for (i = 0; i < nrt; ++i)
update_route(rt[i].origin, rt[i].mask, (rt[i].metric & 0x7f),
update_route(rt[i].origin, rt[i].mask, rt[i].metric,
src, vifi);
if (routes_changed && !delay_change_reports)
@ -806,18 +821,20 @@ void accept_report(src, dst, p, datalen, level)
* Send a route report message to destination 'dst', via virtual interface
* 'vifi'. 'which_routes' specifies ALL_ROUTES or CHANGED_ROUTES.
*/
void report(which_routes, vifi, dst)
void
report(which_routes, vifi, dst)
int which_routes;
vifi_t vifi;
u_long dst;
u_int32 dst;
{
register struct rtentry *r;
register char *p;
register int i;
int datalen;
int width;
u_long mask;
u_long src;
u_int32 mask;
u_int32 src;
u_int32 nflags;
src = uvifs[vifi].uv_lcl_addr;
@ -825,7 +842,24 @@ void report(which_routes, vifi, dst)
datalen = 0;
mask = 0;
for (r = routing_table; r != NULL; r = r->rt_next) {
#ifdef NOTYET
/* If I'm not a leaf, but the neighbor is a leaf, only advertise default */
if ((vifs_with_neighbors != 1) && (uvifs[vifi].uv_flags & VIFF_LEAF)) {
*p++ = 0; /* 0xff000000 mask */
*p++ = 0;
*p++ = 0;
*p++ = 0; /* class A net 0.0.0.0 == default */
*p++ = 0x81; /*XXX metric 1, is this safe? */
datalen += 5;
send_igmp(src, dst, IGMP_DVMRP, DVMRP_REPORT,
htonl(MROUTED_LEVEL), datalen);
return;
}
#endif
nflags = (uvifs[vifi].uv_flags & VIFF_LEAF) ? 0 : LEAF_FLAGS;
for (r = rt_end; r != RT_ADDR; r = r->rt_prev) {
if (which_routes == CHANGED_ROUTES && !(r->rt_flags & RTF_CHANGED))
continue;
@ -839,7 +873,7 @@ void report(which_routes, vifi, dst)
(r->rt_originwidth + 4)) > MAX_DVMRP_DATA_LEN) {
*(p-1) |= 0x80;
send_igmp(src, dst, IGMP_DVMRP, DVMRP_REPORT,
htonl(MROUTED_LEVEL), datalen);
htonl(MROUTED_LEVEL | nflags), datalen);
p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
datalen = 0;
@ -869,7 +903,7 @@ void report(which_routes, vifi, dst)
if (datalen != 0) {
*(p-1) |= 0x80;
send_igmp(src, dst, IGMP_DVMRP, DVMRP_REPORT,
htonl(MROUTED_LEVEL), datalen);
htonl(MROUTED_LEVEL | nflags), datalen);
}
}
@ -878,7 +912,8 @@ void report(which_routes, vifi, dst)
* Send a route report message to all neighboring routers.
* 'which_routes' specifies ALL_ROUTES or CHANGED_ROUTES.
*/
void report_to_all_neighbors(which_routes)
void
report_to_all_neighbors(which_routes)
int which_routes;
{
register vifi_t vifi;
@ -926,10 +961,11 @@ void report_to_all_neighbors(which_routes)
* Send a route report message to destination 'dst', via virtual interface
* 'vifi'. 'which_routes' specifies ALL_ROUTES or CHANGED_ROUTES.
*/
int report_chunk(start_rt, vifi, dst)
int
report_chunk(start_rt, vifi, dst)
register struct rtentry *start_rt;
vifi_t vifi;
u_long dst;
u_int32 dst;
{
register struct rtentry *r;
register char *p;
@ -937,15 +973,28 @@ int report_chunk(start_rt, vifi, dst)
register int nrt = 0;
int datalen;
int width;
u_long mask;
u_long src;
u_int32 mask;
u_int32 src;
u_int32 nflags;
src = uvifs[vifi].uv_lcl_addr;
p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
datalen = 0;
mask = 0;
for (r = start_rt; r != NULL; r = r->rt_next) {
nflags = (uvifs[vifi].uv_flags & VIFF_LEAF) ? 0 : LEAF_FLAGS;
for (r = start_rt; r != RT_ADDR; r = r->rt_prev) {
#ifdef NOTYET
/* Don't send poisoned routes back to parents if I am a leaf */
if ((vifs_with_neighbors == 1) && (r->rt_parent == vifi)
&& (r->rt_metric > 1)) {
++nrt;
continue;
}
#endif
/*
* If there is no room for this route in the current message,
* send it & return how many routes we sent.
@ -955,7 +1004,7 @@ int report_chunk(start_rt, vifi, dst)
(r->rt_originwidth + 4)) > MAX_DVMRP_DATA_LEN) {
*(p-1) |= 0x80;
send_igmp(src, dst, IGMP_DVMRP, DVMRP_REPORT,
htonl(MROUTED_LEVEL), datalen);
htonl(MROUTED_LEVEL | nflags), datalen);
return (nrt);
}
if(r->rt_originmask != mask) {
@ -979,21 +1028,22 @@ int report_chunk(start_rt, vifi, dst)
if (datalen != 0) {
*(p-1) |= 0x80;
send_igmp(src, dst, IGMP_DVMRP, DVMRP_REPORT,
htonl(MROUTED_LEVEL), datalen);
htonl(MROUTED_LEVEL | nflags), datalen);
}
return (nrt);
}
/*
* send the next chunk of our routing table to all neighbors.
* return the length of the smallest chunk we sent out.
*/
int report_next_chunk()
int
report_next_chunk()
{
register vifi_t vifi;
register struct uvif *v;
register struct rtentry *r;
register struct rtentry *sr;
register int i, n = 0;
register int i, n = 0, min = 20000;
static int start_rt;
if (nroutes <= 0)
@ -1002,24 +1052,36 @@ int report_next_chunk()
/*
* find this round's starting route.
*/
for (sr = routing_table, i = start_rt; --i >= 0; ) {
sr = sr->rt_next;
if (sr == NULL)
sr = routing_table;
for (sr = rt_end, i = start_rt; --i >= 0; ) {
sr = sr->rt_prev;
if (sr == RT_ADDR)
sr = rt_end;
}
/*
* send one chunk of routes starting at this round's start to
* all our neighbors.
*/
for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
if (v->uv_neighbors != NULL) {
if ((v->uv_neighbors != NULL)
#ifdef NOTYET
&& !(v->uv_flags & VIFF_LEAF)
#endif
) {
n = report_chunk(sr, vifi,
(v->uv_flags & VIFF_TUNNEL) ? v->uv_rmt_addr
: dvmrp_group);
if (n < min)
min = n;
}
}
if (debug)
printf("update %d starting at %d of %d\n", n, start_rt, nroutes);
if (min == 20000)
min = 0; /* Neighborless router didn't send any routes */
n = min;
log(LOG_INFO, 0, "update %d starting at %d of %d",
n, (nroutes - start_rt), nroutes);
start_rt = (start_rt + n) % nroutes;
return (n);
}
@ -1028,28 +1090,30 @@ int report_next_chunk()
/*
* Print the contents of the routing table on file 'fp'.
*/
void dump_routes(fp)
void
dump_routes(fp)
FILE *fp;
{
register struct rtentry *r;
register int i;
register time_t thyme = time(0);
fprintf(fp,
"Multicast Routing Table (%u %s)\n%s",
"Multicast Routing Table (%u %s)\n%s\n",
nroutes, (nroutes == 1) ? "entry" : "entries",
" Origin-Subnet From-Gateway Metric In-Vif Out-Vifs\n");
" Origin-Subnet From-Gateway Metric Tmr In-Vif Out-Vifs");
for (r = routing_table; r != NULL; r = r->rt_next) {
fprintf(fp, " %-15s %-15s ",
fprintf(fp, " %-18s %-15s ",
inet_fmts(r->rt_origin, r->rt_originmask, s1),
(r->rt_gateway == 0) ? "" : inet_fmt(r->rt_gateway, s2));
fprintf(fp, (r->rt_metric == UNREACHABLE) ? " NR " : "%4u ",
r->rt_metric);
fprintf(fp, "%7u ",
r->rt_parent);
fprintf(fp, " %3u %3u ", r->rt_timer, r->rt_parent);
for (i = 0; i < numvifs; ++i) {
if (VIFM_ISSET(i, r->rt_children)) {
@ -1062,15 +1126,15 @@ void dump_routes(fp)
fprintf(fp, "\n");
}
struct rtentry *determine_route(src)
u_long src;
struct rtentry *
determine_route(src)
u_int32 src;
{
struct rtentry *rt;
for (rt = routing_table; rt != NULL; rt = rt->rt_next) {
if (rt->rt_origin == (src & rt->rt_originmask))
if (rt->rt_origin == (src & rt->rt_originmask))
break;
}
return rt;
}

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

498
usr.sbin/mrouted/rsrr.c Normal file
View File

@ -0,0 +1,498 @@
/*
* Copyright (c) 1993 by the University of Southern California
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software and its
* documentation in source and binary forms for non-commercial purposes
* and without fee is hereby granted, provided that the above copyright
* notice appear in all copies and that both the copyright notice and
* this permission notice appear in supporting documentation. and that
* any documentation, advertising materials, and other materials related
* to such distribution and use acknowledge that the software was
* developed by the University of Southern California, Information
* Sciences Institute. The name of the University may not be used to
* endorse or promote products derived from this software without
* specific prior written permission.
*
* THE UNIVERSITY OF SOUTHERN CALIFORNIA makes no representations about
* the suitability of this software for any purpose. THIS SOFTWARE IS
* PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* Other copyrights might apply to parts of this software and are so
* noted when applicable.
*/
/* RSRR code written by Daniel Zappala, USC Information Sciences Institute,
* April 1995.
*/
/* May 1995 -- Added support for Route Change Notification */
#ifdef RSRR
#include "defs.h"
/* Taken from prune.c */
/*
* checks for scoped multicast addresses
*/
#define GET_SCOPE(gt) { \
register int _i; \
if (((gt)->gt_mcastgrp & 0xff000000) == 0xef000000) \
for (_i = 0; _i < numvifs; _i++) \
if (scoped_addr(_i, (gt)->gt_mcastgrp)) \
VIFM_SET(_i, (gt)->gt_scope); \
}
/*
* Exported variables.
*/
int rsrr_socket; /* interface to reservation protocol */
/*
* Global RSRR variables.
*/
char rsrr_recv_buf[RSRR_MAX_LEN]; /* RSRR receive buffer */
char rsrr_send_buf[RSRR_MAX_LEN]; /* RSRR send buffer */
struct sockaddr_un client_addr;
int client_length = sizeof(client_addr);
/*
* Procedure definitions needed internally.
*/
void rsrr_accept();
void rsrr_accept_iq();
int rsrr_accept_rq();
int rsrr_send();
void rsrr_cache();
/* Initialize RSRR socket */
void
rsrr_init()
{
int servlen;
struct sockaddr_un serv_addr;
if ((rsrr_socket = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)
log(LOG_ERR, errno, "Can't create RSRR socket");
unlink(RSRR_SERV_PATH);
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sun_family = AF_UNIX;
strcpy(serv_addr.sun_path, RSRR_SERV_PATH);
servlen = sizeof(serv_addr.sun_family) + strlen(serv_addr.sun_path);
if (bind(rsrr_socket, (struct sockaddr *) &serv_addr, servlen) < 0)
log(LOG_ERR, errno, "Can't bind RSRR socket");
if (register_input_handler(rsrr_socket,rsrr_read) < 0)
log(LOG_WARNING, 0, "Couldn't register RSRR as an input handler");
}
/* Read a message from the RSRR socket */
void
rsrr_read()
{
register int rsrr_recvlen;
register int omask;
bzero((char *) &client_addr, sizeof(client_addr));
rsrr_recvlen = recvfrom(rsrr_socket, rsrr_recv_buf, sizeof(rsrr_recv_buf),
0, (struct sockaddr *)&client_addr,&client_length);
if (rsrr_recvlen < 0) {
if (errno != EINTR)
log(LOG_ERR, errno, "RSRR recvfrom");
return;
}
/* Use of omask taken from main() */
omask = sigblock(sigmask(SIGALRM));
rsrr_accept(rsrr_recvlen);
(void)sigsetmask(omask);
}
/* Accept a message from the reservation protocol and take
* appropriate action.
*/
void
rsrr_accept(recvlen)
int recvlen;
{
struct rsrr_header *rsrr;
struct rsrr_rq *route_query;
if (recvlen < RSRR_HEADER_LEN) {
log(LOG_WARNING, 0,
"Received RSRR packet of %d bytes, which is less than min size",
recvlen);
return;
}
rsrr = (struct rsrr_header *) rsrr_recv_buf;
if (rsrr->version > RSRR_MAX_VERSION) {
log(LOG_WARNING, 0,
"Received RSRR packet version %d, which I don't understand",
rsrr->version);
return;
}
switch (rsrr->version) {
case 1:
switch (rsrr->type) {
case RSRR_INITIAL_QUERY:
/* Send Initial Reply to client */
log(LOG_INFO, 0, "Received Initial Query\n");
rsrr_accept_iq();
break;
case RSRR_ROUTE_QUERY:
/* Check size */
if (recvlen < RSRR_RQ_LEN) {
log(LOG_WARNING, 0,
"Received Route Query of %d bytes, which is too small",
recvlen);
break;
}
/* Get the query */
route_query = (struct rsrr_rq *) (rsrr_recv_buf + RSRR_HEADER_LEN);
log(LOG_INFO, 0,
"Received Route Query for src %s grp %s notification %d",
inet_fmt(route_query->source_addr.s_addr, s1),
inet_fmt(route_query->dest_addr.s_addr,s2),
BIT_TST(rsrr->flags,RSRR_NOTIFICATION_BIT));
/* Send Route Reply to client */
rsrr_accept_rq(route_query,rsrr->flags,NULL);
break;
default:
log(LOG_WARNING, 0,
"Received RSRR packet type %d, which I don't handle",
rsrr->type);
break;
}
break;
default:
log(LOG_WARNING, 0,
"Received RSRR packet version %d, which I don't understand",
rsrr->version);
break;
}
}
/* Send an Initial Reply to the reservation protocol. */
void
rsrr_accept_iq()
{
struct rsrr_header *rsrr;
struct rsrr_vif *vif_list;
struct uvif *v;
int vifi, sendlen;
/* Check for space. There should be room for plenty of vifs,
* but we should check anyway.
*/
if (numvifs > RSRR_MAX_VIFS) {
log(LOG_WARNING, 0,
"Can't send RSRR Route Reply because %d is too many vifs %d",
numvifs);
return;
}
/* Set up message */
rsrr = (struct rsrr_header *) rsrr_send_buf;
rsrr->version = 1;
rsrr->type = RSRR_INITIAL_REPLY;
rsrr->flags = 0;
rsrr->num = numvifs;
vif_list = (struct rsrr_vif *) (rsrr_send_buf + RSRR_HEADER_LEN);
/* Include the vif list. */
for (vifi=0, v = uvifs; vifi < numvifs; vifi++, v++) {
vif_list[vifi].id = vifi;
vif_list[vifi].status = 0;
if (v->uv_flags & VIFF_DISABLED)
BIT_SET(vif_list[vifi].status,RSRR_DISABLED_BIT);
vif_list[vifi].threshold = v->uv_threshold;
vif_list[vifi].local_addr.s_addr = v->uv_lcl_addr;
}
/* Get the size. */
sendlen = RSRR_HEADER_LEN + numvifs*RSRR_VIF_LEN;
/* Send it. */
log(LOG_INFO, 0, "Send RSRR Initial Reply");
rsrr_send(sendlen);
}
/* Send a Route Reply to the reservation protocol. The Route Query
* contains the query to which we are responding. The flags contain
* the incoming flags from the query or, for route change
* notification, the flags that should be set for the reply. The
* kernel table entry contains the routing info to use for a route
* change notification.
*/
int
rsrr_accept_rq(route_query,flags,gt_notify)
struct rsrr_rq *route_query;
int flags;
struct gtable *gt_notify;
{
struct rsrr_header *rsrr;
struct rsrr_rr *route_reply;
struct gtable *gt,local_g;
struct rtentry *r;
int sendlen,i;
u_long mcastgrp;
/* Set up message */
rsrr = (struct rsrr_header *) rsrr_send_buf;
rsrr->version = 1;
rsrr->type = RSRR_ROUTE_REPLY;
rsrr->flags = 0;
rsrr->num = 0;
route_reply = (struct rsrr_rr *) (rsrr_send_buf + RSRR_HEADER_LEN);
route_reply->dest_addr.s_addr = route_query->dest_addr.s_addr;
route_reply->source_addr.s_addr = route_query->source_addr.s_addr;
route_reply->query_id = route_query->query_id;
/* Blank routing entry for error. */
route_reply->in_vif = 0;
route_reply->reserved = 0;
route_reply->out_vif_bm = 0;
/* Get the size. */
sendlen = RSRR_RR_LEN;
/* If kernel table entry is defined, then we are sending a Route Reply
* due to a Route Change Notification event. Use the kernel table entry
* to supply the routing info.
*/
if (gt_notify) {
/* Set flags */
rsrr->flags = flags;
/* Include the routing entry. */
route_reply->in_vif = gt_notify->gt_route->rt_parent;
route_reply->out_vif_bm = gt_notify->gt_grpmems;
} else if (find_src_grp(route_query->source_addr.s_addr, 0,
route_query->dest_addr.s_addr)) {
/* Found kernel entry. Code taken from add_table_entry() */
gt = gtp ? gtp->gt_gnext : kernel_table;
/* Include the routing entry. */
route_reply->in_vif = gt->gt_route->rt_parent;
route_reply->out_vif_bm = gt->gt_grpmems;
/* Cache reply if using route change notification. */
if BIT_TST(flags,RSRR_NOTIFICATION_BIT) {
rsrr_cache(gt,route_query);
BIT_SET(rsrr->flags,RSRR_NOTIFICATION_BIT);
}
} else {
/* No kernel entry; use routing table. */
r = determine_route(route_query->source_addr.s_addr);
if (r != NULL) {
/* We need to mimic what will happen if a data packet
* is forwarded by multicast routing -- the kernel will
* make an upcall and mrouted will install a route in the kernel.
* Our outgoing vif bitmap should reflect what that table
* will look like. Grab code from add_table_entry().
* This is gross, but it's probably better to be accurate.
*/
gt = &local_g;
mcastgrp = route_query->dest_addr.s_addr;
gt->gt_mcastgrp = mcastgrp;
gt->gt_grpmems = 0;
gt->gt_scope = 0;
gt->gt_route = r;
/* obtain the multicast group membership list */
for (i = 0; i < numvifs; i++) {
if (VIFM_ISSET(i, r->rt_children) &&
!(VIFM_ISSET(i, r->rt_leaves)))
VIFM_SET(i, gt->gt_grpmems);
if (VIFM_ISSET(i, r->rt_leaves) && grplst_mem(i, mcastgrp))
VIFM_SET(i, gt->gt_grpmems);
}
GET_SCOPE(gt);
gt->gt_grpmems &= ~gt->gt_scope;
/* Include the routing entry. */
route_reply->in_vif = gt->gt_route->rt_parent;
route_reply->out_vif_bm = gt->gt_grpmems;
} else {
/* Set error bit. */
BIT_SET(rsrr->flags,RSRR_ERROR_BIT);
}
}
if (gt_notify)
log(LOG_INFO, 0, "Route Change: Send RSRR Route Reply");
else
log(LOG_INFO, 0, "Send RSRR Route Reply");
log(LOG_INFO, 0, "for src %s dst %s in vif %d out vif %d\n",
inet_fmt(route_reply->source_addr.s_addr,s1),
inet_fmt(route_reply->dest_addr.s_addr,s2),
route_reply->in_vif,route_reply->out_vif_bm);
/* Send it. */
return rsrr_send(sendlen);
}
/* Send an RSRR message. */
int
rsrr_send(sendlen)
int sendlen;
{
int error;
/* Send it. */
error = sendto(rsrr_socket, rsrr_send_buf, sendlen, 0,
(struct sockaddr *)&client_addr, client_length);
/* Check for errors. */
if (error < 0) {
log(LOG_WARNING, errno, "Failed send on RSRR socket");
return error;
}
if (error != sendlen) {
log(LOG_WARNING, 0,
"Sent only %d out of %d bytes on RSRR socket\n", error, sendlen);
return error;
}
}
/* Cache a message being sent to a client. Currently only used for
* caching Route Reply messages for route change notification.
*/
void
rsrr_cache(gt,route_query)
struct gtable *gt;
struct rsrr_rq *route_query;
{
struct rsrr_cache *rc,*rc_prev;
struct rsrr_header *rsrr;
rsrr = (struct rsrr_header *) rsrr_send_buf;
rc = gt->gt_rsrr_cache;
while (rc) {
if ((rc->route_query.source_addr.s_addr ==
route_query->source_addr.s_addr) &&
(rc->route_query.dest_addr.s_addr ==
route_query->dest_addr.s_addr) &&
(!strcmp(rc->client_addr.sun_path,client_addr.sun_path))) {
/* Cache entry already exists.
* Check if route notification bit has been cleared.
*/
if (!BIT_TST(rsrr->flags,RSRR_NOTIFICATION_BIT)) {
/* Delete cache entry. */
if (rc == gt->gt_rsrr_cache)
/* Deleting first entry. */
gt->gt_rsrr_cache = rc->next;
else
rc_prev->next = rc->next;
free(rc);
} else {
/* Update */
rc->route_query.query_id = route_query->query_id;
printf("Update cached query id %d from client %s\n",
rc->route_query.query_id,rc->client_addr.sun_path);
}
return;
}
rc_prev = rc;
rc = rc->next;
}
/* Cache entry doesn't already exist. Create one and insert at
* front of list.
*/
rc = (struct rsrr_cache *) malloc(sizeof(struct rsrr_cache));
if (rc == NULL)
log(LOG_ERR, 0, "ran out of memory");
rc->route_query.source_addr.s_addr = route_query->source_addr.s_addr;
rc->route_query.dest_addr.s_addr = route_query->dest_addr.s_addr;
rc->route_query.query_id = route_query->query_id;
strcpy(rc->client_addr.sun_path, client_addr.sun_path);
rc->client_length = client_length;
rc->next = gt->gt_rsrr_cache;
gt->gt_rsrr_cache = rc;
printf("Cached query id %d from client %s\n",
rc->route_query.query_id,rc->client_addr.sun_path);
}
/* Send all the messages in the cache. Currently this is used to send
* all the cached Route Reply messages for route change notification.
*/
void
rsrr_cache_send(gt,notify)
struct gtable *gt;
int notify;
{
struct rsrr_cache *rc,*rc_next,*rc_prev;
int flags = 0;
rc = gt->gt_rsrr_cache;
while (rc) {
rc_next = rc->next;
if (notify)
BIT_SET(flags,RSRR_NOTIFICATION_BIT);
if (rsrr_accept_rq(&rc->route_query,flags,gt) < 0) {
printf("Deleting cached query id %d from client %s\n",
rc->route_query.query_id,rc->client_addr.sun_path);
/* Delete cache entry. */
if (rc == gt->gt_rsrr_cache)
/* Deleting first entry. */
gt->gt_rsrr_cache = rc_next;
else
rc_prev->next = rc_next;
free(rc);
} else {
rc_prev = rc;
}
rc = rc_next;
}
}
/* Clean the cache by deleting all entries. */
void
rsrr_cache_clean(gt)
struct gtable *gt;
{
struct rsrr_cache *rc,*rc_next;
printf("cleaning cache for group %s\n",inet_fmt(gt->gt_mcastgrp, s1));
rc = gt->gt_rsrr_cache;
while (rc) {
rc_next = rc->next;
free(rc);
rc = rc_next;
}
gt->gt_rsrr_cache = NULL;
}
void
rsrr_clean()
{
unlink(RSRR_SERV_PATH);
}
#endif /* RSRR */

138
usr.sbin/mrouted/rsrr.h Normal file
View File

@ -0,0 +1,138 @@
/*
* Copyright (c) 1993 by the University of Southern California
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software and its
* documentation in source and binary forms for non-commercial purposes
* and without fee is hereby granted, provided that the above copyright
* notice appear in all copies and that both the copyright notice and
* this permission notice appear in supporting documentation. and that
* any documentation, advertising materials, and other materials related
* to such distribution and use acknowledge that the software was
* developed by the University of Southern California, Information
* Sciences Institute. The name of the University may not be used to
* endorse or promote products derived from this software without
* specific prior written permission.
*
* THE UNIVERSITY OF SOUTHERN CALIFORNIA makes no representations about
* the suitability of this software for any purpose. THIS SOFTWARE IS
* PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* Other copyrights might apply to parts of this software and are so
* noted when applicable.
*/
#define RSRR_SERV_PATH "/tmp/.rsrr_svr"
/* Note this needs to be 14 chars for 4.3 BSD compatibility */
#define RSRR_CLI_PATH "/tmp/.rsrr_cli"
#define RSRR_MAX_LEN 2048
#define RSRR_HEADER_LEN (sizeof(struct rsrr_header))
#define RSRR_RQ_LEN (RSRR_HEADER_LEN + sizeof(struct rsrr_rq))
#define RSRR_RR_LEN (RSRR_HEADER_LEN + sizeof(struct rsrr_rr))
#define RSRR_VIF_LEN (sizeof(struct rsrr_vif))
/* Current maximum number of vifs. */
#define RSRR_MAX_VIFS 32
/* Maximum acceptable version */
#define RSRR_MAX_VERSION 1
/* RSRR message types */
#define RSRR_ALL_TYPES 0
#define RSRR_INITIAL_QUERY 1
#define RSRR_INITIAL_REPLY 2
#define RSRR_ROUTE_QUERY 3
#define RSRR_ROUTE_REPLY 4
/* RSRR Initial Reply (Vif) Status bits.
* Each definition represents the position of the bit from right to left.
*
* Right-most bit is the disabled bit, set if the vif is administratively
* disabled.
*/
#define RSRR_DISABLED_BIT 0
/* All other bits are zeroes */
/* RSRR Route Query/Reply flag bits.
* Each definition represents the position of the bit from right to left.
*
* Right-most bit is the Route Change Notification bit, set if the
* reservation protocol wishes to receive notification of
* a route change for the source-destination pair listed in the query.
* Notification is in the form of an unsolicitied Route Reply.
*/
#define RSRR_NOTIFICATION_BIT 0
/* Next bit indicates an error returning the Route Reply. */
#define RSRR_ERROR_BIT 1
/* All other bits are zeroes */
/* Definition of an RSRR message header.
* An Initial Query uses only the header, and an Initial Reply uses
* the header and a list of vifs.
*/
struct rsrr_header {
u_char version; /* RSRR Version, currently 1 */
u_char type; /* type of message, as defined above */
u_char flags; /* flags; defined by type */
u_char num; /* number; defined by type */
};
/* Definition of a vif as seen by the reservation protocol.
*
* Routing gives the reservation protocol a list of vifs in the
* Initial Reply.
*
* We explicitly list the ID because we can't assume that all routing
* protocols will use the same numbering scheme.
*
* The status is a bitmask of status flags, as defined above. It is the
* responsibility of the reservation protocol to perform any status checks
* if it uses the MULTICAST_VIF socket option.
*
* The threshold indicates the ttl an outgoing packet needs in order to
* be forwarded. The reservation protocol must perform this check itself if
* it uses the MULTICAST_VIF socket option.
*
* The local address is the address of the physical interface over which
* packets are sent.
*/
struct rsrr_vif {
u_char id; /* vif id */
u_char threshold; /* vif threshold ttl */
u_short status; /* vif status bitmask */
struct in_addr local_addr; /* vif local address */
};
/* Definition of an RSRR Route Query.
*
* The query asks routing for the forwarding entry for a particular
* source and destination. The query ID uniquely identifies the query
* for the reservation protocol. Thus, the combination of the client's
* address and the query ID forms a unique identifier for routing.
* Flags are defined above.
*/
struct rsrr_rq {
struct in_addr dest_addr; /* destination */
struct in_addr source_addr; /* source */
u_long query_id; /* query ID */
};
/* Definition of an RSRR Route Reply.
*
* Routing uses the reply to give the reservation protocol the
* forwarding entry for a source-destination pair. Routing copies the
* query ID from the query and fills in the incoming vif and a bitmask
* of the outgoing vifs.
* Flags are defined above.
*/
struct rsrr_rr {
struct in_addr dest_addr; /* destination */
struct in_addr source_addr; /* source */
u_long query_id; /* query ID */
u_short in_vif; /* incoming vif */
u_short reserved; /* reserved */
u_long out_vif_bm; /* outgoing vif bitmask */
};

View File

@ -0,0 +1,41 @@
/*
* Copyright (c) 1993 by the University of Southern California
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software and its
* documentation in source and binary forms for non-commercial purposes
* and without fee is hereby granted, provided that the above copyright
* notice appear in all copies and that both the copyright notice and
* this permission notice appear in supporting documentation. and that
* any documentation, advertising materials, and other materials related
* to such distribution and use acknowledge that the software was
* developed by the University of Southern California, Information
* Sciences Institute. The name of the University may not be used to
* endorse or promote products derived from this software without
* specific prior written permission.
*
* THE UNIVERSITY OF SOUTHERN CALIFORNIA makes no representations about
* the suitability of this software for any purpose. THIS SOFTWARE IS
* PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* Other copyrights might apply to parts of this software and are so
* noted when applicable.
*/
/* RSRR things that are only needed by mrouted. */
/* Cache of Route Query messages, distinguished by source,
* destination, and client addresses. Cache is flushed by RSRR client
* -- it sends notification when an unwanted Route Reply is received.
* Since this only happens during route changes, it is more likely
* that the cache will be flushed when the kernel table entry is
* deleted. */
struct rsrr_cache {
struct rsrr_rq route_query; /* Cached Route Query */
struct sockaddr_un client_addr; /* Client address */
int client_length; /* Length of client */
struct rsrr_cache *next; /* next cache item */
};

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