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:
parent
1c5de19afb
commit
2897e6fd5f
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=9210
@ -1 +1,2 @@
|
||||
.include "${.CURDIR}/../../Makefile.inc"
|
||||
CFLAGS+= -DRSRR
|
||||
|
@ -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
511
usr.sbin/mrouted/cfparse.y
Normal 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);
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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()
|
||||
{
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
{
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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
499
usr.sbin/mrouted/mtrace.8
Normal 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
25
usr.sbin/mrouted/pathnames.h
Normal file
25
usr.sbin/mrouted/pathnames.h
Normal 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
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
498
usr.sbin/mrouted/rsrr.c
Normal 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
138
usr.sbin/mrouted/rsrr.h
Normal 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 */
|
||||
};
|
41
usr.sbin/mrouted/rsrr_var.h
Normal file
41
usr.sbin/mrouted/rsrr_var.h
Normal 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
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user