This is a 'for reference' import of mrouted release 3.8.

I'm using these to try to resync our tree with the vendor branch..
This commit is contained in:
Peter Wemm 1996-01-06 21:04:38 +00:00
parent 29a6d69cc3
commit 73950bd7a6
23 changed files with 1444 additions and 612 deletions

View File

@ -7,7 +7,7 @@
* Leland Stanford Junior University.
*
*
* $Id: callout.c,v 3.6 1995/06/25 18:47:29 fenner Exp $
* $Id: callout.c,v 3.8 1995/11/29 22:36:57 fenner Rel $
*/
#include "defs.h"
@ -16,7 +16,7 @@
static int id = 0;
static struct timeout_q *Q = 0; /* pointer to the beginning of timeout queue */
static int in_callout= 0;
static int in_callout = 0;
struct timeout_q {
struct timeout_q *next; /* next event */
@ -53,12 +53,15 @@ age_callout_queue()
in_callout = 1;
ptr = Q;
while (ptr){
if (!ptr->time ) {
while (ptr) {
if (!ptr->time) {
/* timeout has happened */
Q = Q->next;
in_callout = 0;
if (ptr->func)
ptr->func(ptr->data);
Q = Q->next;
in_callout = 1;
free(ptr);
ptr = Q;
@ -206,3 +209,18 @@ print_Q()
log(LOG_DEBUG,0,"(%d,%d) ", ptr->id, ptr->time);
}
#endif /* IGMP_DEBUG */
int
secs_remaining( timer_id)
int timer_id;
{
struct timeout_q *ptr;
int left=0;
for (ptr = Q; ptr && ptr->id != timer_id; ptr = ptr->next)
left += ptr->time;
if (!ptr) /* not found */
return 0;
return left + ptr->time;
}

View File

@ -4,7 +4,7 @@
*
* Written by Bill Fenner, NRL, 1994
*
* $Id: cfparse.y,v 3.6 1995/06/25 18:49:46 fenner Exp $
* $Id: cfparse.y,v 3.8 1995/11/29 22:36:57 fenner Rel $
*/
#include <stdio.h>
#ifdef __STDC__
@ -13,6 +13,7 @@
#include <varargs.h>
#endif
#include "defs.h"
#include <netdb.h>
/*
* Local function declarations
@ -69,14 +70,16 @@ int numbounds = 0; /* Number of named boundaries */
%token CACHE_LIFETIME PRUNING
%token PHYINT TUNNEL NAME
%token DISABLE METRIC THRESHOLD RATE_LIMIT SRCRT BOUNDARY NETMASK ALTNET
%token DISABLE IGMPV1 SRCRT
%token METRIC THRESHOLD RATE_LIMIT BOUNDARY NETMASK ALTNET
%token SYSNAM SYSCONTACT SYSVERSION SYSLOCATION
%token <num> BOOLEAN
%token <num> NUMBER
%token <ptr> STRING
%token <addrmask> ADDRMASK
%token <addr> ADDR
%type <addr> interface
%type <addr> interface addrname
%type <addrmask> bound boundary addrmask
%start conf
@ -109,10 +112,9 @@ stmt : error
fatal("%s is not a configured interface",
inet_fmt($2,s1));
/*log(LOG_INFO, 0, "phyint: %x\n", v);*/
}
ifmods
| TUNNEL interface ADDR {
| TUNNEL interface addrname {
struct ifreq *ifr;
struct ifreq ffr;
@ -172,7 +174,6 @@ stmt : error
v->uv_flags |= VIFF_DOWN;
vifs_down = TRUE;
}
/*log(LOG_INFO, 0, "tunnel: %x\n", v);*/
}
tunnelmods
{
@ -195,10 +196,30 @@ stmt : error
strcpy(boundlist[numbounds].name, $2);
boundlist[numbounds++].bound = $3;
}
| SYSNAM STRING {
#ifdef SNMP
set_sysName($2);
#endif /* SNMP */
}
| SYSCONTACT STRING {
#ifdef SNMP
set_sysContact($2);
#endif /* SNMP */
}
| SYSVERSION STRING {
#ifdef SNMP
set_sysVersion($2);
#endif /* SNMP */
}
| SYSLOCATION STRING {
#ifdef SNMP
set_sysLocation($2);
#endif /* SNMP */
}
;
tunnelmods : /* empty */
| tunnelmods /*{ log(LOG_INFO, 0, "tunnelmod: %x", v); }*/ tunnelmod
| tunnelmods tunnelmod
;
tunnelmod : mod
@ -206,12 +227,13 @@ tunnelmod : mod
;
ifmods : /* empty */
| ifmods /*{ log(LOG_INFO, 0, "ifmod: %x", v); }*/ ifmod
| ifmods ifmod
;
ifmod : mod
| DISABLE { v->uv_flags |= VIFF_DISABLED; }
| NETMASK ADDR {
| IGMPV1 { v->uv_flags |= VIFF_IGMPV1; }
| NETMASK addrname {
u_int32 subnet, mask;
mask = $2;
@ -222,6 +244,11 @@ ifmod : mod
v->uv_subnetmask = mask;
v->uv_subnetbcast = subnet | ~mask;
}
| NETMASK {
warn("Expected address after netmask keyword, ignored");
}
| ALTNET addrmask {
struct phaddr *ph;
@ -241,6 +268,11 @@ ifmod : mod
ph->pa_next = v->uv_addrs;
v->uv_addrs = ph;
}
| ALTNET {
warn("Expected address after altnet keyword, ignored");
}
;
@ -250,7 +282,7 @@ mod : THRESHOLD NUMBER { if ($2 < 1 || $2 > 255)
}
| THRESHOLD {
warn("Expected number after threshold keyword");
warn("Expected number after threshold keyword, ignored");
}
| METRIC NUMBER { if ($2 < 1 || $2 > UNREACHABLE)
@ -259,7 +291,7 @@ mod : THRESHOLD NUMBER { if ($2 < 1 || $2 > 255)
}
| METRIC {
warn("Expected number after metric keyword");
warn("Expected number after metric keyword, ignored");
}
| RATE_LIMIT NUMBER { if ($2 > MAX_RATE_LIMIT)
@ -268,7 +300,7 @@ mod : THRESHOLD NUMBER { if ($2 < 1 || $2 > 255)
}
| RATE_LIMIT {
warn("Expected number after rate_limit keyword");
warn("Expected number after rate_limit keyword, ignored");
}
| BOUNDARY bound {
@ -289,7 +321,7 @@ mod : THRESHOLD NUMBER { if ($2 < 1 || $2 > 255)
}
| BOUNDARY {
warn("Expected boundary spec after boundary keyword");
warn("Expected boundary spec after boundary keyword, ignored");
}
;
@ -302,6 +334,20 @@ interface : ADDR { $$ = $1; }
}
;
addrname : ADDR { $$ = $1; }
| STRING { struct hostent *hp;
if ((hp = gethostbyname($1)) == NULL)
fatal("No such host %s", $1);
if (hp->h_addr_list[1])
fatal("Hostname %s does not %s",
$1, "map to a unique address");
bcopy(hp->h_addr_list[0], &$$,
hp->h_length);
}
bound : boundary { $$ = $1; }
| STRING { int i;
@ -413,6 +459,15 @@ next_word()
continue;
}
q = p;
#ifdef SNMP
if (*p == '"') {
p++;
while (*p && *p != '"' && *p != '\n')
p++; /* find next whitespace */
if (*p == '"')
p++;
} else
#endif
while (*p && *p != ' ' && *p != '\t' && *p != '\n')
p++; /* find next whitespace */
*p++ = '\0'; /* null-terminate string */
@ -459,10 +514,12 @@ yylex()
return BOUNDARY;
if (!strcmp(q,"netmask"))
return NETMASK;
if (!strcmp(q,"name"))
return NAME;
if (!strcmp(q,"igmpv1"))
return IGMPV1;
if (!strcmp(q,"altnet"))
return ALTNET;
if (!strcmp(q,"name"))
return NAME;
if (!strcmp(q,"on") || !strcmp(q,"yes")) {
yylval.num = 1;
return BOOLEAN;
@ -494,6 +551,22 @@ yylex()
yylval.num = n;
return NUMBER;
}
#ifdef SNMP
if (!strcmp(q,"sysName"))
return SYSNAM;
if (!strcmp(q,"sysContact"))
return SYSCONTACT;
if (!strcmp(q,"sysVersion"))
return SYSVERSION;
if (!strcmp(q,"sysLocation"))
return SYSLOCATION;
if (*q=='"') {
if (q[ strlen(q)-1 ]=='"')
q[ strlen(q)-1 ]='\0'; /* trash trailing quote */
yylval.ptr = q+1;
return STRING;
}
#endif
yylval.ptr = q;
return STRING;
}

View File

@ -7,7 +7,7 @@
* Leland Stanford Junior University.
*
*
* $Id: config.c,v 3.6 1995/06/25 18:50:37 fenner Exp $
* $Id: config.c,v 3.8 1995/11/29 22:36:57 fenner Rel $
*/

View File

@ -7,7 +7,7 @@
* Leland Stanford Junior University.
*
*
* $Id: defs.h,v 3.6.1.1 1995/06/26 00:18:18 fenner Exp $
* $Id: defs.h,v 3.8 1995/11/29 22:36:34 fenner Rel $
*/
@ -23,6 +23,9 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#ifdef SYSV
#include <sys/sockio.h>
#endif
#include <sys/time.h>
#include <net/if.h>
#include <netinet/in.h>
@ -46,7 +49,7 @@ typedef u_int u_int32;
#endif
typedef void (*cfunc_t) __P((void *));
typedef void (*ihfunc_t) __P((fd_set *));
typedef void (*ihfunc_t) __P((int, fd_set *));
#include "dvmrp.h"
#include "vif.h"
@ -68,13 +71,17 @@ typedef void (*ihfunc_t) __P((fd_set *));
#define TIMER_INTERVAL ROUTE_MAX_REPORT_DELAY
#define VENDOR_CODE 1 /* Get a new vendor code if you make significant
* changes to mrouted. */
#define PROTOCOL_VERSION 3 /* increment when packet format/content changes */
#define MROUTED_VERSION 6 /* increment on local changes or bug fixes, */
#define MROUTED_VERSION 8 /* increment on local changes or bug fixes, */
/* reset to 0 whever PROTOCOL_VERSION increments */
#define MROUTED_LEVEL ( (MROUTED_VERSION << 8) | PROTOCOL_VERSION | \
((NF_PRUNE | NF_GENID | NF_MTRACE) << 16))
#define MROUTED_LEVEL ((MROUTED_VERSION << 8) | PROTOCOL_VERSION | \
((NF_PRUNE | NF_GENID | NF_MTRACE) << 16) | \
(VENDOR_CODE << 24))
/* for IGMP 'group' field of DVMRP messages */
#define LEAF_FLAGS (( vifs_with_neighbors == 1 ) ? 0x010000 : 0)
@ -98,10 +105,17 @@ typedef void (*ihfunc_t) __P((fd_set *));
#define BIT_TST(X,n) ((X) & 1 << (n))
#endif /* RSRR */
#ifdef SYSV
#define bcopy(a, b, c) memcpy(b, a, c)
#define bzero(s, n) memset((s), 0, (n))
#define setlinebuf(s) setvbuf(s, NULL, _IOLBF, 0)
#define signal(s,f) sigset(s,f)
#endif
/*
* External declarations for global variables and functions.
*/
#define RECV_BUF_SIZE MAX_IP_PACKET_LEN
#define RECV_BUF_SIZE 8192
extern char *recv_buf;
extern char *send_buf;
extern int igmp_socket;
@ -139,6 +153,17 @@ extern int sys_nerr;
extern char * sys_errlist[];
#endif
#ifdef OLD_KERNEL
#define MRT_INIT DVMRP_INIT
#define MRT_DONE DVMRP_DONE
#define MRT_ADD_VIF DVMRP_ADD_VIF
#define MRT_DEL_VIF DVMRP_DEL_VIF
#define MRT_ADD_MFC DVMRP_ADD_MFC
#define MRT_DEL_MFC DVMRP_DEL_MFC
#define IGMP_PIM 0x14
#endif
/* main.c */
extern void log __P((int, int, char *, ...));
extern int register_input_handler __P((int fd, ihfunc_t func));
@ -161,7 +186,7 @@ extern void timer_clearTimer __P((int timer_id));
extern void init_routes __P((void));
extern void start_route_updates __P((void));
extern void update_route __P((u_int32 origin, u_int32 mask,
int metric, u_int32 src,
u_int metric, u_int32 src,
vifi_t vifi));
extern void age_routes __P((void));
extern void expire_all_routes __P((void));
@ -285,7 +310,7 @@ extern int find_src_grp __P((u_int32 src, u_int32 mask,
/* rsrr.c */
extern void rsrr_init __P((void));
extern void rsrr_read __P((fd_set *rfd));
extern void rsrr_read __P((int f, fd_set *rfd));
extern void rsrr_clean __P((void));
extern void rsrr_cache_send __P((struct gtable *gt, int notify));
extern void rsrr_cache_clean __P((struct gtable *gt));

View File

@ -7,7 +7,7 @@
* Leland Stanford Junior University.
*
*
* $Id: dvmrp.h,v 3.6 1995/06/25 18:52:10 fenner Exp $
* $Id: dvmrp.h,v 3.8 1995/11/29 22:36:57 fenner Rel $
*/
/*
@ -96,6 +96,8 @@
#define DVMRP_PRUNE 7 /* prune message */
#define DVMRP_GRAFT 8 /* graft message */
#define DVMRP_GRAFT_ACK 9 /* graft acknowledgement */
#define DVMRP_INFO_REQUEST 10 /* information request */
#define DVMRP_INFO_REPLY 11 /* information reply */
/*
* 'flags' byte values in DVMRP_NEIGHBORS2 reply.
@ -108,6 +110,12 @@
#define DVMRP_NF_QUERIER 0x40 /* I am the subnet's querier */
#define DVMRP_NF_LEAF 0x80 /* Neighbor reports that it is a leaf */
/*
* Request/reply types for info queries/replies
*/
#define DVMRP_INFO_VERSION 1 /* version string */
#define DVMRP_INFO_NEIGHBORS 2 /* neighbors2 data */
/*
* Limit on length of route data
*/
@ -122,8 +130,14 @@
*/
/* address for multicast DVMRP msgs */
#define INADDR_DVMRP_GROUP (u_int32)0xe0000004 /* 224.0.0.4 */
/*
* The IGMPv2 <netinet/in.h> defines INADDR_ALLRTRS_GROUP, but earlier
* ones don't, so we define it conditionally here.
*/
#ifndef INADDR_ALLRTRS_GROUP
/* address for multicast mtrace msg */
#define INADDR_ALLRTRS_GROUP (u_int32)0xe0000002 /* 224.0.0.2 */
#endif
#define ROUTE_MAX_REPORT_DELAY 5 /* max delay for reporting changes */
/* (This is the timer interrupt */
@ -144,8 +158,7 @@
#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. */
* the timer in mrouted doesn't allow us to make it any shorter. */
#define UNREACHABLE 32 /* "infinity" metric, must be <= 64 */
#define DEFAULT_METRIC 1 /* default subnet/tunnel metric */

View File

@ -7,7 +7,7 @@
* Leland Stanford Junior University.
*
*
* $Id: igmp.c,v 3.6 1995/06/25 18:52:55 fenner Exp $
* $Id: igmp.c,v 3.8 1995/11/29 22:36:57 fenner Rel $
*/
@ -94,6 +94,8 @@ packet_kind(type, code)
case DVMRP_PRUNE: return "prune message ";
case DVMRP_GRAFT: return "graft message ";
case DVMRP_GRAFT_ACK: return "graft message ack ";
case DVMRP_INFO_REQUEST: return "info request ";
case DVMRP_INFO_REPLY: return "info reply ";
default: return "unknown DVMRP msg ";
}
case IGMP_PIM:
@ -154,8 +156,8 @@ accept_igmp(recvlen)
ipdatalen = ip->ip_len;
if (iphdrlen + ipdatalen != recvlen) {
log(LOG_WARNING, 0,
"received packet shorter (%u bytes) than hdr+data length (%u+%u)",
recvlen, iphdrlen, ipdatalen);
"received packet from %s shorter (%u bytes) than hdr+data length (%u+%u)",
inet_fmt(src, s1), recvlen, iphdrlen, ipdatalen);
return;
}
@ -232,6 +234,15 @@ accept_igmp(recvlen)
accept_g_ack(src, dst, (char *)(igmp+1), igmpdatalen);
return;
case DVMRP_INFO_REQUEST:
accept_info_request(src, dst, (char *)(igmp+1),
igmpdatalen);
return;
case DVMRP_INFO_REPLY:
accept_info_reply(src, dst, (char *)(igmp+1), igmpdatalen);
return;
default:
log(LOG_INFO, 0,
"ignoring unknown DVMRP message code %u from %s to %s",
@ -296,9 +307,10 @@ send_igmp(src, dst, type, code, group, datalen)
u_int32 group;
int datalen;
{
static struct sockaddr_in sdst;
struct sockaddr_in sdst;
struct ip *ip;
struct igmp *igmp;
int setloop;
ip = (struct ip *)send_buf;
ip->ip_src.s_addr = src;
@ -313,8 +325,13 @@ send_igmp(src, dst, type, code, group, datalen)
igmp->igmp_cksum = inet_cksum((u_short *)igmp,
IGMP_MINLEN + datalen);
if (IN_MULTICAST(ntohl(dst))) k_set_if(src);
if (dst == allhosts_group) k_set_loop(TRUE);
if (IN_MULTICAST(ntohl(dst))) {
k_set_if(src);
if (type != IGMP_DVMRP) {
setloop = 1;
k_set_loop(TRUE);
}
}
bzero(&sdst, sizeof(sdst));
sdst.sin_family = AF_INET;
@ -332,7 +349,8 @@ send_igmp(src, dst, type, code, group, datalen)
inet_fmt(dst, s1), inet_fmt(src, s2));
}
if (dst == allhosts_group) k_set_loop(FALSE);
if (setloop)
k_set_loop(FALSE);
log(LOG_DEBUG, 0, "SENT %s from %-15s to %s",
packet_kind(type, code), inet_fmt(src, s1), inet_fmt(dst, s2));

View File

@ -7,7 +7,7 @@
* Leland Stanford Junior University.
*
*
* $Id: inet.c,v 3.6 1995/06/25 18:54:45 fenner Exp $
* $Id: inet.c,v 3.8 1995/11/29 22:36:57 fenner Rel $
*/
@ -41,6 +41,22 @@ inet_valid_host(naddr)
(addr & 0xff000000) == 0));
}
/*
* Verify that a given netmask is plausible;
* make sure that it is a series of 1's followed by
* a series of 0's with no discontiguous 1's.
*/
int
inet_valid_mask(mask)
u_int32 mask;
{
if (~(((mask & -mask) - 1) | mask) != 0) {
/* Mask is not contiguous */
return (FALSE);
}
return (TRUE);
}
/*
* Verify that a given subnet number and mask pair are credible.
@ -62,21 +78,26 @@ inet_valid_subnet(nsubnet, nmask)
if ((subnet & mask) != subnet) return (FALSE);
if (subnet == 0 && mask == 0)
return (TRUE);
if (subnet == 0)
return (mask == 0);
if (IN_CLASSA(subnet)) {
if (mask < 0xff000000 ||
(subnet & 0xff000000) == 0x7f000000) return (FALSE);
(subnet & 0xff000000) == 0x7f000000 ||
(subnet & 0xff000000) == 0x00000000) return (FALSE);
}
else if (IN_CLASSD(subnet) || IN_BADCLASS(subnet)) {
/* Above Class C address space */
return (FALSE);
}
else if (subnet & ~mask) {
if (subnet & ~mask) {
/* Host bits are set in the subnet */
return (FALSE);
}
if (!inet_valid_mask(mask)) {
/* Netmask is not contiguous */
return (FALSE);
}
return (TRUE);
}

View File

@ -7,7 +7,7 @@
* Leland Stanford Junior University.
*
*
* $Id: kern.c,v 3.6 1995/06/25 18:57:38 fenner Exp $
* $Id: kern.c,v 3.8 1995/11/29 22:36:57 fenner Rel $
*/
@ -162,8 +162,11 @@ void k_add_rg(origin, g)
struct gtable *g;
{
struct mfcctl mc;
int i;
vifi_t i;
#ifdef DEBUG_MFC
md_log(MD_ADD, origin, g->gt_mcastgrp);
#endif
/* copy table values so that setsockopt can process it */
mc.mfcc_origin.s_addr = origin;
#ifdef OLD_KERNEL
@ -176,8 +179,12 @@ void k_add_rg(origin, g)
/* write to kernel space */
if (setsockopt(igmp_socket, IPPROTO_IP, MRT_ADD_MFC,
(char *)&mc, sizeof(mc)) < 0)
(char *)&mc, sizeof(mc)) < 0) {
#ifdef DEBUG_MFC
md_log(MD_ADD_FAIL, origin, g->gt_mcastgrp);
#endif
log(LOG_WARNING, errno, "setsockopt MRT_ADD_MFC");
}
}
@ -191,6 +198,9 @@ int k_del_rg(origin, g)
struct mfcctl mc;
int retval;
#ifdef DEBUG_MFC
md_log(MD_DEL, origin, g->gt_mcastgrp);
#endif
/* copy table values so that setsockopt can process it */
mc.mfcc_origin.s_addr = origin;
#ifdef OLD_KERNEL
@ -200,8 +210,12 @@ int k_del_rg(origin, g)
/* write to kernel space */
if ((retval = setsockopt(igmp_socket, IPPROTO_IP, MRT_DEL_MFC,
(char *)&mc, sizeof(mc))) < 0)
(char *)&mc, sizeof(mc))) < 0) {
#ifdef DEBUG_MFC
md_log(MD_DEL_FAIL, origin, g->gt_mcastgrp);
#endif
log(LOG_WARNING, errno, "setsockopt MRT_DEL_MFC");
}
return retval;
}
@ -211,6 +225,9 @@ int k_del_rg(origin, g)
*/
int k_get_version()
{
#ifdef OLD_KERNEL
return -1;
#else
int vers;
int len = sizeof(vers);
@ -220,4 +237,5 @@ int k_get_version()
"getsockopt MRT_VERSION: perhaps your kernel is too old");
return vers;
#endif
}

View File

@ -7,7 +7,7 @@
* Leland Stanford Junior University.
*
*
* $Id: main.c,v 3.6 1995/06/25 18:58:06 fenner Exp $
* $Id: main.c,v 3.8 1995/11/29 22:36:34 fenner Rel $
*/
/*
@ -32,7 +32,13 @@
#include "snmp.h"
#endif
#ifndef lint
static char rcsid[] =
"@(#) $Id: main.c,v 3.8 1995/11/29 22:36:34 fenner Rel $";
#endif
extern char *configfilename;
char versionstring[100];
static char pidfilename[] = _PATH_MROUTED_PID;
static char dumpfilename[] = _PATH_MROUTED_DUMP;
@ -45,7 +51,11 @@ int max_prune_lifetime = DEFAULT_CACHE_LIFETIME * 2;
int debug = 0;
u_char pruning = 1; /* Enable pruning by default */
#ifdef SNMP
#define NHANDLERS 34
#else
#define NHANDLERS 2
#endif
static struct ihandler {
int fd; /* File descriptor */
@ -64,6 +74,7 @@ static void cdump __P((int));
static void restart __P((int));
static void timer __P((void));
static void cleanup __P((void));
static void resetlogging __P((void *));
/* To shut up gcc -Wstrict-prototypes */
int main __P((int argc, char **argv));
@ -97,22 +108,12 @@ main(argc, argv)
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);
struct timeval timeout, *tvp = &timeout;
struct timeval sched, *svp = &sched, now, *nvp = &now;
int index, block;
#endif
#ifdef SYSV
setvbuf(stderr, NULL, _IOLBF, 0);
#else
setlinebuf(stderr);
#endif
if (geteuid() != 0) {
fprintf(stderr, "must be root\n");
@ -135,6 +136,14 @@ main(argc, argv)
goto usage;
} else if (strcmp(*argv, "-p") == 0) {
pruning = 0;
#ifdef SNMP
} else if (strcmp(*argv, "-P") == 0) {
if (argc > 1 && isdigit(*(argv + 1)[0])) {
argv++, argc--;
dest_port = atoi(*argv);
} else
dest_port = DEFAULT_PORT;
#endif
} else
goto usage;
argv++, argc--;
@ -159,6 +168,9 @@ usage: fprintf(stderr,
(void)open("/", 0);
(void)dup2(0, 1);
(void)dup2(0, 2);
#ifdef SYSV
(void)setpgrp();
#else
#ifdef TIOCNOTTY
t = open("/dev/tty", 2);
if (t >= 0) {
@ -168,6 +180,7 @@ usage: fprintf(stderr,
#else
if (setsid() < 0)
perror("setsid");
#endif
#endif
}
else
@ -179,9 +192,11 @@ usage: fprintf(stderr,
#else
(void)openlog("mrouted", LOG_PID);
#endif
log(LOG_NOTICE, 0, "mrouted version %d.%d",
sprintf(versionstring, "mrouted version %d.%d",
PROTOCOL_VERSION, MROUTED_VERSION);
log(LOG_NOTICE, 0, "%s", versionstring);
#ifdef SYSV
srand48(time(NULL));
#else
@ -209,12 +224,9 @@ usage: fprintf(stderr,
}
callout_init();
#ifdef SNMP
snmp_init();
#endif
init_igmp();
init_routes();
init_ktable();
k_init_dvmrp(); /* enable DVMRP routing in kernel */
#ifndef OLD_KERNEL
@ -229,15 +241,29 @@ usage: fprintf(stderr,
PROTOCOL_VERSION, MROUTED_VERSION);
#endif
init_routes();
init_ktable();
#ifdef SNMP
if (i = snmp_init())
return i;
gettimeofday(nvp, 0);
if (nvp->tv_usec < 500000L){
svp->tv_usec = nvp->tv_usec + 500000L;
svp->tv_sec = nvp->tv_sec;
} else {
svp->tv_usec = nvp->tv_usec - 500000L;
svp->tv_sec = nvp->tv_sec + 1;
}
#endif /* SNMP */
init_vifs();
#ifdef RSRR
rsrr_init();
#endif /* RSRR */
#if defined(__STDC__) || defined(__GNUC__)
/* Allow cleanup if unexpected exit. Apparently some architectures
/*
* 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.
*/
@ -253,8 +279,6 @@ usage: fprintf(stderr,
(void) fclose(fp);
}
if (debug >= 2) dump(0);
(void)signal(SIGALRM, fasttimer);
(void)signal(SIGHUP, restart);
@ -274,6 +298,17 @@ usage: fprintf(stderr,
nfds = ihandlers[i].fd + 1;
}
/*
* Install the vifs in the kernel as late as possible in the
* initialization sequence.
*/
init_installvifs();
if (debug >= 2) dump(0);
/* Start up the log rate-limiter */
resetlogging(NULL);
(void)alarm(1); /* schedule first timer interrupt */
/*
@ -281,23 +316,38 @@ usage: fprintf(stderr,
*/
dummy = 0;
for(;;) {
#ifdef SYSV
sigset_t block, oblock;
#endif
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) {
gettimeofday(nvp, 0);
if (nvp->tv_sec > svp->tv_sec
|| (nvp->tv_sec == svp->tv_sec && nvp->tv_usec > svp->tv_usec)){
alarmTimer(nvp);
eventTimer(nvp);
if (nvp->tv_usec < 500000L){
svp->tv_usec = nvp->tv_usec + 500000L;
svp->tv_sec = nvp->tv_sec;
} else {
svp->tv_usec = nvp->tv_usec - 500000L;
svp->tv_sec = nvp->tv_sec + 1;
}
}
tvp = &timeout;
tvp->tv_sec = 0;
tvp->tv_usec = 500000L;
block = 0;
snmp_select_info(&nfds, &rfds, tvp, &block);
if (block == 1)
tvp = NULL; /* block without timeout */
if ((n = select(nfds, &rfds, NULL, NULL, tvp)) < 0)
#else
if ((n = select(nfds, &rfds, NULL, NULL, NULL)) < 0) {
if ((n = select(nfds, &rfds, NULL, NULL, NULL)) < 0)
#endif
{
if (errno != EINTR) /* SIGALRM is expected */
log(LOG_WARNING, errno, "select failed");
continue;
@ -310,25 +360,31 @@ usage: fprintf(stderr,
if (errno != EINTR) log(LOG_ERR, errno, "recvfrom");
continue;
}
#ifdef SYSV
(void)sigemptyset(&block);
(void)sigaddset(&block, SIGALRM);
if (sigprocmask(SIG_BLOCK, &block, &oblock) < 0)
log(LOG_ERR, errno, "sigprocmask");
#else
omask = sigblock(sigmask(SIGALRM));
#endif
accept_igmp(recvlen);
#ifdef SYSV
(void)sigprocmask(SIG_SETMASK, &oblock, (sigset_t *)NULL);
#else
(void)sigsetmask(omask);
#endif
}
for (i = 0; i < nhandlers; i++) {
if (FD_ISSET(ihandlers[i].fd, &rfds)) {
(*ihandlers[i].func)(&rfds);
(*ihandlers[i].func)(ihandlers[i].fd, &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();
}
snmp_read(&rfds);
snmp_timeout(); /* poll */
#endif
}
}
@ -444,13 +500,7 @@ timer()
}
#ifdef SNMP
if (smux_fd == NOTOK && !dont_bother_anymore
&& virtual_time % SNMPD_RETRY_INTERVAL == 0) {
/*
* Time to check for snmpd running.
*/
try_smux_init();
}
sync_timer();
#endif
/*
@ -467,8 +517,7 @@ static void
done(i)
int i;
{
log(LOG_NOTICE, 0, "mrouted version %d.%d exiting",
PROTOCOL_VERSION, MROUTED_VERSION);
log(LOG_NOTICE, 0, "%s exiting", versionstring);
cleanup();
_exit(1);
}
@ -545,14 +594,23 @@ restart(i)
int i;
{
register int omask;
#ifdef SYSV
sigset_t block, oblock;
#endif
log(LOG_NOTICE, 0, "mrouted version %d.%d restart",
PROTOCOL_VERSION, MROUTED_VERSION);
log(LOG_NOTICE, 0, "%s restart", versionstring);
/*
* reset all the entries
*/
#ifdef SYSV
(void)sigemptyset(&block);
(void)sigaddset(&block, SIGALRM);
if (sigprocmask(SIG_BLOCK, &block, &oblock) < 0)
log(LOG_ERR, errno, "sigprocmask");
#else
omask = sigblock(sigmask(SIGALRM));
#endif
free_all_prunes();
free_all_routes();
stop_all_vifs();
@ -567,14 +625,41 @@ restart(i)
pruning = 1;
init_igmp();
k_init_dvmrp(); /* enable DVMRP routing in kernel */
init_routes();
init_ktable();
init_vifs();
k_init_dvmrp(); /* enable DVMRP routing in kernel */
init_installvifs();
#ifdef SYSV
(void)sigprocmask(SIG_SETMASK, &oblock, (sigset_t *)NULL);
#else
(void)sigsetmask(omask);
#endif
}
#define LOG_MAX_MSGS 20 /* if > 20/minute then shut up for a while */
#define LOG_SHUT_UP 600 /* shut up for 10 minutes */
static int log_nmsgs = 0;
static void
resetlogging(arg)
void *arg;
{
int nxttime = 60;
void *narg = NULL;
if (arg == NULL && log_nmsgs > LOG_MAX_MSGS) {
nxttime = LOG_SHUT_UP;
narg = (void *)&log_nmsgs; /* just need some valid void * */
syslog(LOG_WARNING, "logging too fast, shutting up for %d minutes",
LOG_SHUT_UP / 60);
} else {
log_nmsgs = 0;
}
timer_setTimer(nxttime, resetlogging, narg);
}
/*
* Log errors and other messages to the system log daemon and to stderr,
@ -633,12 +718,40 @@ log(severity, syserr, format, va_alist)
}
if (severity <= LOG_NOTICE) {
if (syserr != 0) {
errno = syserr;
syslog(severity, "%s: %m", msg);
} else
syslog(severity, "%s", msg);
if (log_nmsgs++ < LOG_MAX_MSGS) {
if (syserr != 0) {
errno = syserr;
syslog(severity, "%s: %m", msg);
} else
syslog(severity, "%s", msg);
}
if (severity <= LOG_ERR) exit(-1);
}
}
#ifdef DEBUG_MFC
void
md_log(what, origin, mcastgrp)
int what;
u_int32 origin, mcastgrp;
{
static FILE *f = NULL;
struct timeval tv;
u_int32 buf[4];
if (!f) {
if ((f = fopen("/tmp/mrouted.clog", "w")) == NULL) {
log(LOG_ERR, errno, "open /tmp/mrouted.clog");
}
}
gettimeofday(&tv, NULL);
buf[0] = tv.tv_sec;
buf[1] = what;
buf[2] = origin;
buf[3] = mcastgrp;
fwrite(buf, sizeof(u_int32), 4, f);
}
#endif

View File

@ -1,7 +1,7 @@
/* Mapper for connections between MRouteD multicast routers.
* Written by Pavel Curtis <Pavel@PARC.Xerox.Com>
*
* $Id: mapper.c,v 3.6 1995/06/25 18:59:02 fenner Exp $
* $Id: mapper.c,v 3.8 1995/11/29 22:36:57 fenner Rel $
*/
/*
@ -302,7 +302,7 @@ void accept_neighbors(src, dst, p, datalen, level)
/* if node is running a recent mrouted, ask for additional info */
if (level != 0) {
node->version = level;
node->tries = 0;
node->tries = 1;
ask2(src);
return;
}
@ -374,7 +374,7 @@ void accept_neighbors(src, dst, p, datalen, level)
for (nb_n = old_neighbors; nb_n; nb_n = nb_n->next)
if (nb_i->addr == nb_n->addr) {
if (nb_i->metric != nb_n->metric
|| nb_i->threshold != nb_i->threshold)
|| nb_i->threshold != nb_n->threshold)
log(LOG_WARNING, 0,
"inconsistent %s for neighbor %s of %s",
"metric/threshold",
@ -451,6 +451,8 @@ void accept_neighbors2(src, dst, p, datalen, level)
int datalen;
{
Node *node = find_node(src, &routers);
u_int broken_cisco = ((level & 0xffff) == 0x020a); /* 10.2 */
/* well, only possibly_broken_cisco, but that's too long to type. */
if (node->tries == 0) /* Never heard of 'em; must have hit them at */
node->tries = 1; /* least once, though...*/
@ -478,6 +480,11 @@ void accept_neighbors2(src, dst, p, datalen, level)
ncount = *p++;
datalen -= 4 + 4;
if (broken_cisco && ncount == 0) /* dumb Ciscos */
ncount = 1;
if (broken_cisco && ncount > 15) /* dumb Ciscos */
ncount = ncount & 0xf;
/* Fix up any alias information */
ifc_node = find_node(ifc_addr, &routers);
if (ifc_node->tries == 0) { /* new node */
@ -837,11 +844,7 @@ int main(argc, argv)
{
int flood = FALSE, graph = FALSE;
#ifdef SYSV
setvbuf(stderr, NULL, _IOLBF, 0);
#else
setlinebuf(stderr);
#endif
if (geteuid() != 0) {
fprintf(stderr, "must be root\n");
@ -1017,3 +1020,15 @@ void accept_membership_query(src, dst, group, tmo)
int tmo;
{
}
void accept_info_request(src, dst, p, datalen)
u_int32 src, dst;
u_char *p;
int datalen;
{
}
void accept_info_reply(src, dst, p, datalen)
u_int32 src, dst;
u_char *p;
int datalen;
{
}

View File

@ -61,7 +61,7 @@
#ifndef lint
static char rcsid[] =
"@(#) $Id: mrinfo.c,v 3.6 1995/06/25 19:05:34 fenner Exp $";
"@(#) $Id: mrinfo.c,v 3.8 1995/11/29 22:36:34 fenner Rel $";
/* original rcsid:
"@(#) Header: mrinfo.c,v 1.6 93/04/08 15:14:16 van Exp (LBL)";
*/
@ -237,8 +237,13 @@ accept_neighbors2(src, dst, p, datalen, level)
u_int broken_cisco = ((level & 0xffff) == 0x020a); /* 10.2 */
/* well, only possibly_broken_cisco, but that's too long to type. */
printf("%s (%s) [version %d.%d]:\n", inet_fmt(src, s1), inet_name(src),
printf("%s (%s) [version %d.%d", inet_fmt(src, s1), inet_name(src),
level & 0xff, (level >> 8) & 0xff);
if ((level >> 16) & NF_LEAF) { printf (",leaf"); }
if ((level >> 16) & NF_PRUNE) { printf (",prune"); }
if ((level >> 16) & NF_GENID) { printf (",genid"); }
if ((level >> 16) & NF_MTRACE) { printf (",mtrace"); }
printf ("]:\n");
while (p < ep) {
register u_char metric;
@ -307,23 +312,6 @@ get_number(var, deflt, pargv, pargc)
}
}
u_int32
host_addr(name)
char *name;
{
struct hostent *e;
u_int32 addr;
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);
}
return(addr);
}
void
usage()
{
@ -337,9 +325,13 @@ main(argc, argv)
int argc;
char *argv[];
{
int tries = 0;
int trynew = 1;
int tries;
int trynew;
struct timeval et;
struct hostent *hp;
struct hostent bogus;
char *host;
int curaddr;
setlinebuf(stderr);
@ -373,11 +365,21 @@ main(argc, argv)
if (argc > 1)
usage();
if (argc == 1)
target_addr = host_addr(argv[0]);
host = argv[0];
else
target_addr = host_addr("127.0.0.1");
host = "127.0.0.1";
if (target_addr == 0) {
if ((target_addr = inet_addr(host)) != -1) {
hp = &bogus;
hp->h_length = sizeof(target_addr);
hp->h_addr_list = (char **)malloc(2 * sizeof(char *));
hp->h_addr_list[0] = malloc(hp->h_length);
memcpy(hp->h_addr_list[0], &target_addr, hp->h_length);
hp->h_addr_list[1] = 0;
} else
hp = gethostbyname(host);
if (hp == NULL) {
fprintf(stderr, "mrinfo: %s: no such host\n", argv[0]);
exit(1);
}
@ -386,7 +388,10 @@ main(argc, argv)
init_igmp();
{ /* Find a good local address for us. */
/* Check all addresses; mrouters often have unreachable interfaces */
for (curaddr = 0; hp->h_addr_list[curaddr] != NULL; curaddr++) {
memcpy(&target_addr, hp->h_addr_list[curaddr], hp->h_length);
{ /* Find a good local address for us. */
int udp;
struct sockaddr_in addr;
int addrlen = sizeof(addr);
@ -406,20 +411,22 @@ main(argc, argv)
}
close(udp);
our_addr = addr.sin_addr.s_addr;
}
}
/*
* New strategy: send 'ask2' for two timeouts, then fall back
* to 'ask', since it's not very likely that we are going to
* find someone who only responds to 'ask' these days
*/
ask2(target_addr);
tries = 0;
trynew = 1;
/*
* New strategy: send 'ask2' for two timeouts, then fall back
* to 'ask', since it's not very likely that we are going to
* find someone who only responds to 'ask' these days
*/
ask2(target_addr);
gettimeofday(&et, 0);
et.tv_sec += timeout;
gettimeofday(&et, 0);
et.tv_sec += timeout;
/* Main receive loop */
for (;;) {
/* Main receive loop */
for (;;) {
fd_set fds;
struct timeval tv, now;
int count, recvlen, dummy = 0;
@ -451,7 +458,7 @@ main(argc, argv)
} else if (count == 0) {
log(LOG_DEBUG, 0, "Timed out receiving neighbor lists");
if (++tries > retries)
exit(1);
break;
/* If we've tried ASK_NEIGHBORS2 twice with
* no response, fall back to ASK_NEIGHBORS
*/
@ -461,6 +468,8 @@ main(argc, argv)
ask(target_addr);
else
ask2(target_addr);
gettimeofday(&et, 0);
et.tv_sec += timeout;
continue;
}
recvlen = recvfrom(igmp_socket, recv_buf, RECV_BUF_SIZE,
@ -485,19 +494,19 @@ main(argc, argv)
iphdrlen = ip->ip_hl << 2;
ipdatalen = ip->ip_len;
if (iphdrlen + ipdatalen != recvlen) {
log(LOG_WARNING, 0,
"packet shorter (%u bytes) than hdr+data length (%u+%u)",
recvlen, iphdrlen, ipdatalen);
continue;
log(LOG_WARNING, 0,
"packet shorter (%u bytes) than hdr+data length (%u+%u)",
recvlen, iphdrlen, ipdatalen);
continue;
}
igmp = (struct igmp *) (recv_buf + iphdrlen);
group = igmp->igmp_group.s_addr;
igmpdatalen = ipdatalen - IGMP_MINLEN;
if (igmpdatalen < 0) {
log(LOG_WARNING, 0,
"IP data field too short (%u bytes) for IGMP, from %s",
ipdatalen, inet_fmt(src, s1));
continue;
log(LOG_WARNING, 0,
"IP data field too short (%u bytes) for IGMP, from %s",
ipdatalen, inet_fmt(src, s1));
continue;
}
if (igmp->igmp_type != IGMP_DVMRP)
continue;
@ -538,7 +547,9 @@ main(argc, argv)
igmpdatalen, ntohl(group));
exit(0);
}
}
}
exit(1);
}
/* dummies */
@ -608,3 +619,15 @@ void accept_membership_query(src, dst, group, tmo)
int tmo;
{
}
void accept_info_request(src, dst, p, datalen)
u_int32 src, dst;
u_char *p;
int datalen;
{
}
void accept_info_reply(src, dst, p, datalen)
u_int32 src, dst;
u_char *p;
int datalen;
{
}

View File

@ -1,5 +1,5 @@
'\"COPYRIGHT 1989 by The Board of Trustees of Leland Stanford Junior University.
'\"$Id: mrouted.8,v 3.6 1995/06/25 19:10:58 fenner Exp $
'\"$Id: mrouted.8,v 3.8 1995/11/29 22:37:21 fenner Rel $
.TH MROUTED 8
.UC 5
.SH NAME
@ -140,7 +140,7 @@ options may be specified as many times as necessary.
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
The local IP address <local-addr> may be replaced by the
interface name (e.g le0).
If a phyint is attached to multiple IP subnets, describe each additional subnet
with the altnet keyword.
@ -148,7 +148,12 @@ Phyint commands must precede tunnel commands.
.PP
The tunnel command can be used to establish a tunnel link between local
IP address <local-addr> and remote IP address <remote-addr>, and to associate
a non-default metric or threshold with that tunnel. The tunnel must be set
a non-default metric or threshold with that tunnel.
The local IP address <local-addr> may be replaced by the
interface name (e.g. le0). The remote IP address <remote-addr> may
be replaced by a host name, if and only if the host name has a single
IP address associated with it.
The tunnel must be set
up in the mrouted.conf files of both routers before it can be used.
'\"For backwards compatibility with older
'\".IR mrouted s,

View File

@ -1,4 +1,4 @@
# $Id: mrouted.conf,v 3.6 1995/06/25 19:11:55 fenner Exp $
# $Id: mrouted.conf,v 3.8 1995/11/29 22:40:47 fenner Rel $
#
# This is the configuration file for "mrouted", an IP multicast router.
# mrouted looks for it in "/etc/mrouted.conf".
@ -35,3 +35,9 @@ tunnel 128.4.0.77 128.4.0.8 metric 1 threshold 64 rate_limit 500 # <-- REPLACE
#
# You might want to specify a boundary on your tunnel to the outside world,
# as above.
#
# NOTE: ONLY uncomment the following if you are running mrouted.snmp!
#sysName "mymrouter"
#sysContact "Me <me@me.com> +x.yyy.zzz-zzzz"
#sysVersion "MyOS 4.1.3 and mrouted"
#sysLocation "The MBONE"

View File

@ -29,7 +29,7 @@
.\" Copyright (c) 1988 The Regents of the University of California.
.\" All rights reserved.
.\"
.\" $Id: mtrace.8,v 3.6 1995/06/25 19:14:07 fenner Exp $
.\" $Id: mtrace.8,v 3.8 1995/11/29 22:37:21 fenner Rel $
.\"
.TH MTRACE 8 "May 8, 1995"
.UC 6
@ -63,9 +63,14 @@ mtrace \- print multicast path from a source to a receiver
] [
.B \-s
] [
.B \-S
.I stat_int
] [
.B \-t
.I ttl
] [
.B \-v
] [
.B \-w
.I waittime
]
@ -105,6 +110,9 @@ detailed below. The two parameters can be distinguished because the
is a unicast address and the
.I group
is a multicast address.
.PP
NOTE: For Solaris 2.4/2.5, if the multicast interface is not the default
interface, the -i option must be used to set the local address.
.SH OPTIONS
.TP 8 8
.BI \-g\ gwy
@ -118,7 +126,7 @@ to the
.RS 8
.TP 12 12
.I CAUTION!!
Version 3.3 of
Versions 3.3 and 3.5 of
.B mrouted
will crash if a trace query is received via a
unicast packet and
@ -129,7 +137,7 @@ address. Therefore, do not use the
.B \-g
option unless the target
.B mrouted
has been verified to be newer than 3.3.
has been verified to be 3.4 or newer than 3.5.
.RE
.TP 8 8
.BI \-i\ addr
@ -142,7 +150,9 @@ and the response destination.
.TP 8 8
.B \-l
Loop indefinitely printing packet rate and loss statistics for the
multicast path every 10 seconds.
multicast path every 10 seconds (see
.B \-S
.IR stat_int ).
.TP 8 8
.B \-M
Always send the response using multicast rather than attempting
@ -169,7 +179,7 @@ The default is 3.
.TP 8 8
.B \-p
Listen passively for multicast responses from traces initiated by
others (not implemented yet).
others. This works best when run on a multicast router.
.TP 8 8
.BI \-r\ host
Send the trace response to
@ -183,6 +193,11 @@ for this purpose (224.0.1.32).
Print a short form output including only the multicast path and not
the packet rate and loss statistics.
.TP 8 8
.BI \-S\ n
Change the interval between statistics gathering traces to
.I n
seconds (default 10 seconds).
.TP 8 8
.BI \-t\ ttl
Set the
.I ttl
@ -190,6 +205,9 @@ Set the
responses. The default is 64, except for local queries to the "all
routers" multicast group which use ttl 1.
.TP 8 8
.B \-v
Verbose mode; show hop times on the initial trace and statistics display.
.TP 8 8
.BI \-w\ n
Set the time to wait for a trace response to
.I n

View File

@ -46,16 +46,19 @@
* In particular, parts of the prototype version of this program may
* have been derived from mrouted programs sources covered by the
* license in the accompanying file named "LICENSE".
*
* $Id: mtrace.c,v 3.6 1995/06/25 19:17:14 fenner Exp $
*/
#ifndef lint
static char rcsid[] =
"@(#) $Id: mtrace.c,v 3.8 1995/11/29 22:36:34 fenner Rel $";
#endif
#include <netdb.h>
#include <sys/time.h>
#include <sys/filio.h>
#include <memory.h>
#include <string.h>
#include <ctype.h>
#include <sys/ioctl.h>
#include "defs.h"
#include <arpa/inet.h>
#ifdef __STDC__
@ -63,6 +66,9 @@
#else
#include <varargs.h>
#endif
#ifdef SUNOS5
#include <sys/systeminfo.h>
#endif
#define DEFAULT_TIMEOUT 3 /* How long to wait before retrying requests */
#define DEFAULT_RETRIES 3 /* How many times to try */
@ -91,6 +97,8 @@ struct resp_buf {
#define ndata u.d
char names[MAXHOPS][40];
int reset[MAXHOPS]; /* To get around 3.4 bug, ... */
int swaps[MAXHOPS]; /* To get around 3.6 bug, ... */
int timeout = DEFAULT_TIMEOUT;
int nqueries = DEFAULT_RETRIES;
@ -98,6 +106,8 @@ int numeric = FALSE;
int debug = 0;
int passive = FALSE;
int multicast = FALSE;
int statint = 10;
int verbose = 0;
u_int32 defgrp; /* Default group if not specified */
u_int32 query_cast; /* All routers multicast addr */
@ -140,12 +150,14 @@ u_long fixtime __P((u_long time));
int send_recv __P((u_int32 dst, int type, int code,
int tries, struct resp_buf *save));
char * print_host __P((u_int32 addr));
char * print_host2 __P((u_int32 addr1, u_int32 addr2));
void print_trace __P((int index, struct resp_buf *buf));
int what_kind __P((struct resp_buf *buf));
int what_kind __P((struct resp_buf *buf, char *why));
char * scale __P((int *hop));
void stat_line __P((struct tr_resp *r, struct tr_resp *s,
int have_next));
int have_next, int *res));
void fixup_stats __P((struct resp_buf *base,
struct resp_buf *prev,
struct resp_buf *new));
int print_stats __P((struct resp_buf *base,
struct resp_buf *prev,
@ -313,9 +325,9 @@ int
get_ttl(buf)
struct resp_buf *buf;
{
register rno;
register struct tr_resp *b;
register ttl;
int rno;
struct tr_resp *b;
u_int ttl;
if (buf && (rno = buf->len) > 0) {
b = buf->resps + rno - 1;
@ -361,6 +373,17 @@ fixtime(time)
return (time);
}
/*
* Swap bytes for poor little-endian machines that don't byte-swap
*/
u_long
byteswap(v)
u_long v;
{
return ((v << 24) | ((v & 0xff00) << 8) |
((v >> 8) & 0xff00) | (v >> 24));
}
int
send_recv(dst, type, code, tries, save)
u_int32 dst;
@ -504,11 +527,11 @@ send_recv(dst, type, code, tries, save)
* addresses in the response.
*/
if (ip->ip_src.s_addr != dst) {
register u_int32 *p = (u_int32 *)(igmp + 1);
register u_int32 *ep = p + (len >> 2);
u_int32 *p = (u_int32 *)(igmp + 1);
u_int32 *ep = p + (len >> 2);
while (p < ep) {
register u_int32 laddr = *p++;
register int n = ntohl(*p++) & 0xFF;
u_int32 laddr = *p++;
int n = ntohl(*p++) & 0xFF;
if (laddr == dst) {
ep = p + 1; /* ensure p < ep after loop */
break;
@ -586,19 +609,155 @@ send_recv(dst, type, code, tries, save)
return (0);
}
/*
* Most of this code is duplicated elsewhere. I'm not sure if
* the duplication is absolutely required or not.
*
* Ideally, this would keep track of ongoing statistics
* collection and print out statistics. (& keep track
* of h-b-h traces and only print the longest) For now,
* it just snoops on what traces it can.
*/
void
passive_mode()
{
struct timeval tr;
struct ip *ip;
struct igmp *igmp;
struct tr_resp *r;
int ipdatalen, iphdrlen, igmpdatalen;
int len, recvlen, dummy = 0;
u_int32 smask;
init_igmp();
if (raddr) {
if (IN_MULTICAST(ntohl(raddr))) k_join(raddr, INADDR_ANY);
} else k_join(htonl(0xE0000120), INADDR_ANY);
while (1) {
recvlen = recvfrom(igmp_socket, recv_buf, RECV_BUF_SIZE,
0, (struct sockaddr *)0, &dummy);
gettimeofday(&tr,0);
if (recvlen <= 0) {
if (recvlen && errno != EINTR) perror("recvfrom");
continue;
}
if (recvlen < sizeof(struct ip)) {
fprintf(stderr,
"packet too short (%u bytes) for IP header", recvlen);
continue;
}
ip = (struct ip *) recv_buf;
if (ip->ip_p == 0) /* ignore cache creation requests */
continue;
iphdrlen = ip->ip_hl << 2;
ipdatalen = ip->ip_len;
if (iphdrlen + ipdatalen != recvlen) {
fprintf(stderr,
"packet shorter (%u bytes) than hdr+data len (%u+%u)\n",
recvlen, iphdrlen, ipdatalen);
continue;
}
igmp = (struct igmp *) (recv_buf + iphdrlen);
igmpdatalen = ipdatalen - IGMP_MINLEN;
if (igmpdatalen < 0) {
fprintf(stderr,
"IP data field too short (%u bytes) for IGMP from %s\n",
ipdatalen, inet_fmt(ip->ip_src.s_addr, s1));
continue;
}
switch (igmp->igmp_type) {
case IGMP_MTRACE: /* For backward compatibility with 3.3 */
case IGMP_MTRACE_RESP:
if (igmpdatalen < QLEN) continue;
if ((igmpdatalen - QLEN)%RLEN) {
printf("packet with incorrect datalen\n");
continue;
}
len = (igmpdatalen - QLEN)/RLEN;
break;
default:
continue;
}
base.qtime = ((tr.tv_sec + JAN_1970) << 16) +
(tr.tv_usec << 10) / 15625;
base.rtime = ((tr.tv_sec + JAN_1970) << 16) +
(tr.tv_usec << 10) / 15625;
base.len = len;
bcopy((char *)igmp, (char *)&base.igmp, ipdatalen);
/*
* If the user specified which traces to monitor,
* only accept traces that correspond to the
* request
*/
if ((qsrc != 0 && qsrc != base.qhdr.tr_src) ||
(qdst != 0 && qdst != base.qhdr.tr_dst) ||
(qgrp != 0 && qgrp != igmp->igmp_group.s_addr))
continue;
printf("Mtrace from %s to %s via group %s (mxhop=%d)\n",
inet_fmt(base.qhdr.tr_dst, s1), inet_fmt(base.qhdr.tr_src, s2),
inet_fmt(igmp->igmp_group.s_addr, s3), igmp->igmp_code);
if (len == 0)
continue;
printf(" 0 ");
print_host(base.qhdr.tr_dst);
printf("\n");
print_trace(1, &base);
r = base.resps + base.len - 1;
VAL_TO_MASK(smask, r->tr_smask);
if ((r->tr_inaddr & smask) == (base.qhdr.tr_src & smask)) {
printf("%3d ", -(base.len+1));
print_host(base.qhdr.tr_src);
printf("\n");
} else if (r->tr_rmtaddr != 0) {
printf("%3d ", -(base.len+1));
what_kind(&base, r->tr_rflags == TR_OLD_ROUTER ?
"doesn't support mtrace"
: "is the next hop");
}
printf("\n");
}
}
char *
print_host(addr)
u_int32 addr;
{
return print_host2(addr, 0);
}
/*
* On some routers, one interface has a name and the other doesn't.
* We always print the address of the outgoing interface, but can
* sometimes get the name from the incoming interface. This might be
* confusing but should be slightly more helpful than just a "?".
*/
char *
print_host2(addr1, addr2)
u_int32 addr1, addr2;
{
char *name;
if (numeric) {
printf("%s", inet_fmt(addr, s1));
printf("%s", inet_fmt(addr1, s1));
return ("");
}
name = inet_name(addr);
printf("%s (%s)", name, inet_fmt(addr, s1));
name = inet_name(addr1);
if (*name == '?' && *(name + 1) == '\0' && addr2 != 0)
name = inet_name(addr2);
printf("%s (%s)", name, inet_fmt(addr1, s1));
return (name);
}
@ -613,16 +772,22 @@ print_trace(index, buf)
struct tr_resp *r;
char *name;
int i;
int hop;
char *ms;
i = abs(index);
r = buf->resps + i - 1;
for (; i <= buf->len; ++i, ++r) {
if (index > 0) printf("%3d ", -i);
name = print_host(r->tr_outaddr);
printf(" %s thresh^ %d %d ms %s\n", proto_type(r->tr_rproto),
r->tr_fttl, t_diff(fixtime(ntohl(r->tr_qarr)), buf->qtime),
flag_type(r->tr_rflags));
name = print_host2(r->tr_outaddr, r->tr_inaddr);
printf(" %s thresh^ %d", proto_type(r->tr_rproto), r->tr_fttl);
if (verbose) {
hop = t_diff(fixtime(ntohl(r->tr_qarr)), buf->qtime);
ms = scale(&hop);
printf(" %d%s", hop, ms);
}
printf(" %s\n", flag_type(r->tr_rflags));
memcpy(names[i-1], name, sizeof(names[0]) - 1);
names[i-1][sizeof(names[0])-1] = '\0';
}
@ -632,8 +797,9 @@ print_trace(index, buf)
* See what kind of router is the next hop
*/
int
what_kind(buf)
what_kind(buf, why)
struct resp_buf *buf;
char *why;
{
u_int32 smask;
int retval;
@ -666,13 +832,14 @@ what_kind(buf)
case 10:
type = "cisco ";
}
printf(" [%s%d.%d] didn't respond\n",
type, version & 0xFF, (version >> 8) & 0xFF);
printf(" [%s%d.%d] %s\n",
type, version & 0xFF, (version >> 8) & 0xFF,
why);
VAL_TO_MASK(smask, r->tr_smask);
while (p < ep) {
register u_int32 laddr = *p++;
register int flags = (ntohl(*p) & 0xFF00) >> 8;
register int n = ntohl(*p++) & 0xFF;
u_int32 laddr = *p++;
int flags = (ntohl(*p) & 0xFF00) >> 8;
int n = ntohl(*p++) & 0xFF;
if (!(flags & (DVMRP_NF_DOWN | DVMRP_NF_DISABLED)) &&
(laddr & smask) == (qsrc & smask)) {
printf("%3d ", -(hops+2));
@ -684,7 +851,7 @@ what_kind(buf)
}
return retval;
}
printf(" didn't respond\n");
printf(" %s\n", why);
return 0;
}
@ -708,30 +875,37 @@ scale(hop)
#define OUTS 2
#define BOTH 3
void
stat_line(r, s, have_next)
stat_line(r, s, have_next, rst)
struct tr_resp *r, *s;
int have_next;
int *rst;
{
register timediff = (fixtime(ntohl(s->tr_qarr)) -
int timediff = (fixtime(ntohl(s->tr_qarr)) -
fixtime(ntohl(r->tr_qarr))) >> 16;
register v_lost, v_pct;
register g_lost, g_pct;
register v_out = ntohl(s->tr_vifout) - ntohl(r->tr_vifout);
register g_out = ntohl(s->tr_pktcnt) - ntohl(r->tr_pktcnt);
register v_pps, g_pps;
int v_lost, v_pct;
int g_lost, g_pct;
int v_out = ntohl(s->tr_vifout) - ntohl(r->tr_vifout);
int g_out = ntohl(s->tr_pktcnt) - ntohl(r->tr_pktcnt);
int v_pps, g_pps;
char v_str[8], g_str[8];
register have = NEITHER;
int have = NEITHER;
int res = *rst;
if (timediff == 0) timediff = 1;
v_pps = v_out / timediff;
g_pps = g_out / timediff;
if (v_out || s->tr_vifout != 0xFFFFFFFF) have |= OUTS;
if (v_out && (s->tr_vifout != 0xFFFFFFFF && s->tr_vifout != 0) ||
(r->tr_vifout != 0xFFFFFFFF && r->tr_vifout != 0))
have |= OUTS;
if (have_next) {
--r, --s;
if (s->tr_vifin != 0xFFFFFFFF || r->tr_vifin != 0xFFFFFFFF)
--r, --s, --rst;
if ((s->tr_vifin != 0xFFFFFFFF && s->tr_vifin != 0) ||
(r->tr_vifin != 0xFFFFFFFF && r->tr_vifin != 0))
have |= INS;
if (*rst)
res = 1;
}
switch (have) {
@ -750,61 +924,129 @@ stat_line(r, s, have_next)
sprintf(g_str, "%3d", g_pct);
else memcpy(g_str, " --", 4);
printf("%6d/%-5d=%s%%%4d pps%6d/%-5d=%s%%%4d pps\n",
v_lost, v_out, v_str, v_pps, g_lost, g_out, g_str, g_pps);
if (debug > 2) {
printf("\t\t\t\tv_in: %ld ", ntohl(s->tr_vifin));
printf("v_out: %ld ", ntohl(s->tr_vifout));
printf("pkts: %ld\n", ntohl(s->tr_pktcnt));
printf("\t\t\t\tv_in: %ld ", ntohl(r->tr_vifin));
printf("v_out: %ld ", ntohl(r->tr_vifout));
printf("pkts: %ld\n", ntohl(r->tr_pktcnt));
printf("\t\t\t\tv_in: %ld ",ntohl(s->tr_vifin)-ntohl(r->tr_vifin));
printf("v_out: %ld ", ntohl(s->tr_vifout) - ntohl(r->tr_vifout));
printf("pkts: %ld ", ntohl(s->tr_pktcnt) - ntohl(r->tr_pktcnt));
printf("time: %d\n", timediff);
}
printf("%6d/%-5d=%s%%%4d pps",
v_lost, v_out, v_str, v_pps);
if (res)
printf("\n");
else
printf("%6d/%-5d=%s%%%4d pps\n",
g_lost, g_out, g_str, g_pps);
break;
case INS:
v_out = (ntohl(s->tr_vifin) - ntohl(r->tr_vifin));
g_out = (ntohl(s->tr_pktcnt) - ntohl(r->tr_pktcnt));
v_out = ntohl(s->tr_vifin) - ntohl(r->tr_vifin);
v_pps = v_out / timediff;
g_pps = g_out / timediff;
/* Fall through */
case OUTS:
printf(" %-5d %4d pps %-5d %4d pps\n",
v_out, v_pps, g_out, g_pps);
printf(" %-5d %4d pps",
v_out, v_pps);
if (res)
printf("\n");
else
printf(" %-5d %4d pps\n",
g_out, g_pps);
break;
case NEITHER:
printf("\n");
break;
}
if (debug > 2) {
printf("\t\t\t\tv_in: %ld ", ntohl(s->tr_vifin));
printf("v_out: %ld ", ntohl(s->tr_vifout));
printf("pkts: %ld\n", ntohl(s->tr_pktcnt));
printf("\t\t\t\tv_in: %ld ", ntohl(r->tr_vifin));
printf("v_out: %ld ", ntohl(r->tr_vifout));
printf("pkts: %ld\n", ntohl(r->tr_pktcnt));
printf("\t\t\t\tv_in: %ld ",ntohl(s->tr_vifin)-ntohl(r->tr_vifin));
printf("v_out: %ld ", ntohl(s->tr_vifout) - ntohl(r->tr_vifout));
printf("pkts: %ld ", ntohl(s->tr_pktcnt) - ntohl(r->tr_pktcnt));
printf("time: %d\n", timediff);
printf("\t\t\t\tres: %d\n", res);
}
}
/*
* A fixup to check if any pktcnt has been reset.
* A fixup to check if any pktcnt has been reset, and to fix the
* byteorder bugs in mrouted 3.6 on little-endian machines.
*/
void
fixup_stats(base, new)
struct resp_buf *base, *new;
fixup_stats(base, prev, new)
struct resp_buf *base, *prev, *new;
{
register rno = base->len;
register struct tr_resp *b = base->resps + rno;
register struct tr_resp *n = new->resps + rno;
int rno = base->len;
struct tr_resp *b = base->resps + rno;
struct tr_resp *p = prev->resps + rno;
struct tr_resp *n = new->resps + rno;
int *r = reset + rno;
int *s = swaps + rno;
int res;
while (--rno >= 0)
if (ntohl((--n)->tr_pktcnt) < ntohl((--b)->tr_pktcnt)) break;
/* Check for byte-swappers */
while (--rno >= 0) {
--n; --p; --b; --s;
if (*s || abs(ntohl(n->tr_vifout) - ntohl(p->tr_vifout)) > 100000) {
/* This host sends byteswapped reports; swap 'em */
if (!*s) {
*s = 1;
b->tr_qarr = byteswap(b->tr_qarr);
b->tr_vifin = byteswap(b->tr_vifin);
b->tr_vifout = byteswap(b->tr_vifout);
b->tr_pktcnt = byteswap(b->tr_pktcnt);
}
n->tr_qarr = byteswap(n->tr_qarr);
n->tr_vifin = byteswap(n->tr_vifin);
n->tr_vifout = byteswap(n->tr_vifout);
n->tr_pktcnt = byteswap(n->tr_pktcnt);
}
}
rno = base->len;
b = base->resps + rno;
p = prev->resps + rno;
n = new->resps + rno;
while (--rno >= 0) {
--n; --p; --b; --r;
res = ((ntohl(n->tr_pktcnt) < ntohl(b->tr_pktcnt)) ||
(ntohl(n->tr_pktcnt) < ntohl(p->tr_pktcnt)));
if (debug > 2)
printf("\t\tr=%d, res=%d\n", *r, res);
if (*r) {
if (res || *r > 1) {
/*
* This router appears to be a 3.4 with that nasty ol'
* neighbor version bug, which causes it to constantly
* reset. Just nuke the statistics for this node, and
* don't even bother giving it the benefit of the
* doubt from now on.
*/
p->tr_pktcnt = b->tr_pktcnt = n->tr_pktcnt;
*r++;
} else {
/*
* This is simply the situation that the original
* fixup_stats was meant to deal with -- that a
* 3.3 or 3.4 router deleted a cache entry while
* traffic was still active.
*/
*r = 0;
break;
}
} else
*r = res;
}
if (rno < 0) return;
rno = base->len;
b = base->resps + rno;
n = new->resps + rno;
p = prev->resps + rno;
while (--rno >= 0) (--b)->tr_pktcnt = (--n)->tr_pktcnt;
while (--rno >= 0) (--b)->tr_pktcnt = (--p)->tr_pktcnt;
}
/*
@ -815,15 +1057,17 @@ print_stats(base, prev, new)
struct resp_buf *base, *prev, *new;
{
int rtt, hop;
register char *ms;
register u_int32 smask;
register rno = base->len - 1;
register struct tr_resp *b = base->resps + rno;
register struct tr_resp *p = prev->resps + rno;
register struct tr_resp *n = new->resps + rno;
register u_long resptime = new->rtime;
register u_long qarrtime = fixtime(ntohl(n->tr_qarr));
register ttl = n->tr_fttl;
char *ms;
u_int32 smask;
int rno = base->len - 1;
struct tr_resp *b = base->resps + rno;
struct tr_resp *p = prev->resps + rno;
struct tr_resp *n = new->resps + rno;
int *r = reset + rno;
u_long resptime = new->rtime;
u_long qarrtime = fixtime(ntohl(n->tr_qarr));
u_int ttl = n->tr_fttl;
int first = (base == prev);
VAL_TO_MASK(smask, b->tr_smask);
printf(" Source Response Dest");
@ -833,12 +1077,14 @@ print_stats(base, prev, new)
inet_fmt(base->qhdr.tr_raddr, s2), inet_fmt(qsrc, s1));
rtt = t_diff(resptime, new->qtime);
ms = scale(&rtt);
printf(" | __/ rtt%5d%s Lost/Sent = Pct Rate To %s\n",
rtt, ms, inet_fmt(qgrp, s2));
hop = t_diff(resptime, qarrtime);
ms = scale(&hop);
printf(" v / hop%5d%s", hop, ms);
printf(" --------------------- --------------------\n");
printf(" %c __/ rtt%5d%s Lost/Sent = Pct Rate To %s\n",
first ? 'v' : '|', rtt, ms, inet_fmt(qgrp, s2));
if (!first) {
hop = t_diff(resptime, qarrtime);
ms = scale(&hop);
printf(" v / hop%5d%s", hop, ms);
printf(" --------------------- --------------------\n");
}
if (debug > 2) {
printf("\t\t\t\tv_in: %ld ", ntohl(n->tr_vifin));
printf("v_out: %ld ", ntohl(n->tr_vifout));
@ -849,6 +1095,7 @@ print_stats(base, prev, new)
printf("\t\t\t\tv_in: %ld ", ntohl(n->tr_vifin) - ntohl(b->tr_vifin));
printf("v_out: %ld ", ntohl(n->tr_vifout) - ntohl(b->tr_vifout));
printf("pkts: %ld\n", ntohl(n->tr_pktcnt) - ntohl(b->tr_pktcnt));
printf("\t\t\t\treset: %d\n", *r);
}
while (TRUE) {
@ -862,28 +1109,30 @@ print_stats(base, prev, new)
if (rno-- < 1) break;
printf(" | ^ ttl%5d ", ttl);
if (prev == new) printf("\n");
else stat_line(p, n, TRUE);
resptime = qarrtime;
qarrtime = fixtime(ntohl((n-1)->tr_qarr));
hop = t_diff(resptime, qarrtime);
ms = scale(&hop);
printf(" v | hop%5d%s", hop, ms);
stat_line(b, n, TRUE);
printf(" %c ^ ttl%5d ", first ? 'v' : '|', ttl);
stat_line(p, n, TRUE, r);
if (!first) {
resptime = qarrtime;
qarrtime = fixtime(ntohl((n-1)->tr_qarr));
hop = t_diff(resptime, qarrtime);
ms = scale(&hop);
printf(" v | hop%5d%s", hop, ms);
stat_line(b, n, TRUE, r);
}
--b, --p, --n;
--b, --p, --n, --r;
if (ttl < n->tr_fttl) ttl = n->tr_fttl;
else ++ttl;
}
printf(" | \\__ ttl%5d ", ttl);
if (prev == new) printf("\n");
else stat_line(p, n, FALSE);
hop = t_diff(qarrtime, new->qtime);
ms = scale(&hop);
printf(" v \\ hop%5d%s", hop, ms);
stat_line(b, n, FALSE);
printf(" %c \\__ ttl%5d ", first ? 'v' : '|', ttl);
stat_line(p, n, FALSE, r);
if (!first) {
hop = t_diff(qarrtime, new->qtime);
ms = scale(&hop);
printf(" v \\ hop%5d%s", hop, ms);
stat_line(b, n, FALSE, r);
}
printf("%-15s %s\n", inet_fmt(qdst, s1), inet_fmt(lcl_addr, s2));
printf(" Receiver Query Source\n\n");
return 0;
@ -923,11 +1172,11 @@ char *argv[];
if (argc == 0) goto usage;
while (argc > 0 && *argv[0] == '-') {
register char *p = *argv++; argc--;
char *p = *argv++; argc--;
p++;
do {
register char c = *p++;
register char *arg = (char *) 0;
char c = *p++;
char *arg = (char *) 0;
if (isdigit(*p)) {
arg = p;
p = "";
@ -954,6 +1203,9 @@ char *argv[];
case 'p': /* Passive listen for traces */
passive = TRUE;
break;
case 'v': /* Verbosity */
verbose = TRUE;
break;
case 's': /* Short form, don't wait for stats */
numstats = 0;
break;
@ -1009,6 +1261,14 @@ char *argv[];
break;
} else
goto usage;
case 'S': /* Stat accumulation interval */
if (arg && isdigit(*arg)) {
statint = atoi(arg);
if (statint < 1) statint = 1;
if (arg == argv[0]) argv++, argc--;
break;
} else
goto usage;
default:
goto usage;
}
@ -1032,10 +1292,15 @@ char *argv[];
}
}
if (passive) {
passive_mode();
return(0);
}
if (argc > 0 || qsrc == 0) {
usage: printf("\
Usage: mtrace [-Mlnps] [-w wait] [-m max_hops] [-q nqueries] [-g gateway]\n\
[-t ttl] [-r resp_dest] [-i if_addr] source [receiver] [group]\n");
[-S statint] [-t ttl] [-r resp_dest] [-i if_addr] source [receiver] [group]\n");
exit(1);
}
@ -1067,6 +1332,36 @@ Usage: mtrace [-Mlnps] [-w wait] [-m max_hops] [-q nqueries] [-g gateway]\n\
exit(-1);
}
#ifdef SUNOS5
/*
* SunOS 5.X prior to SunOS 2.6, getsockname returns 0 for udp socket.
* This call to sysinfo will return the hostname.
* If the default multicast interfface (set with the route
* for 224.0.0.0) is not the same as the hostname,
* mtrace -i [if_addr] will have to be used.
*/
if (addr.sin_addr.s_addr == 0) {
char myhostname[MAXHOSTNAMELEN];
struct hostent *hp;
int error;
error = sysinfo(SI_HOSTNAME, myhostname, sizeof(myhostname));
if (error == -1) {
perror("Getting my hostname");
exit(-1);
}
hp = gethostbyname(myhostname);
if (hp == NULL || hp->h_addrtype != AF_INET ||
hp->h_length != sizeof(addr.sin_addr)) {
perror("Finding IP address for my hostname");
exit(-1);
}
memcpy((char *)&addr.sin_addr.s_addr, hp->h_addr, hp->h_length);
}
#endif
/*
* Default destination for path to be queried is the local host.
*/
@ -1136,7 +1431,7 @@ Usage: mtrace [-Mlnps] [-w wait] [-m max_hops] [-q nqueries] [-g gateway]\n\
}
/*
* Try a query at the requested number of hops or MAXOPS if unspecified.
* Try a query at the requested number of hops or MAXHOPS if unspecified.
*/
if (qno == 0) {
hops = MAXHOPS;
@ -1148,7 +1443,7 @@ Usage: mtrace [-Mlnps] [-w wait] [-m max_hops] [-q nqueries] [-g gateway]\n\
tries = nqueries;
printf("Querying reverse path, maximum %d hops... ", qno);
fflush(stdout);
}
}
base.rtime = 0;
base.len = 0;
@ -1167,9 +1462,12 @@ Usage: mtrace [-Mlnps] [-w wait] [-m max_hops] [-q nqueries] [-g gateway]\n\
printf("\n");
print_trace(1, &base);
r = base.resps + base.len - 1;
if (r->tr_rflags == TR_OLD_ROUTER) {
if (r->tr_rflags == TR_OLD_ROUTER || r->tr_rflags == TR_NO_SPACE ||
qno != 0) {
printf("%3d ", -(base.len+1));
what_kind(&base);
what_kind(&base, r->tr_rflags == TR_OLD_ROUTER ?
"doesn't support mtrace"
: "is the next hop");
} else {
VAL_TO_MASK(smask, r->tr_smask);
if ((r->tr_inaddr & smask) == (qsrc & smask)) {
@ -1204,7 +1502,7 @@ Usage: mtrace [-Mlnps] [-w wait] [-m max_hops] [-q nqueries] [-g gateway]\n\
if (recvlen == 0) {
if (hops == 1) break;
if (hops == nexthop) {
if (what_kind(&base)) {
if (what_kind(&base, "didn't respond")) {
/* the ask_neighbors determined that the
* not-responding router is the first-hop. */
break;
@ -1227,36 +1525,62 @@ Usage: mtrace [-Mlnps] [-w wait] [-m max_hops] [-q nqueries] [-g gateway]\n\
print_trace(nexthop, &base);
}
} else {
if (base.len == hops - 1) {
if (base.len < hops) {
/*
* A shorter trace than requested means a fatal error
* occurred along the path, or that the route changed
* to a shorter one.
*
* If the trace is longer than the last one we received,
* then we are resuming from a skipped router (but there
* is still probably a problem).
*
* If the trace is shorter than the last one we
* received, then the route must have changed (and
* there is still probably a problem).
*/
if (nexthop <= base.len) {
printf("\nResuming...\n");
print_trace(nexthop, &base);
} else if (nexthop > base.len + 1) {
hops = base.len;
printf("\nRoute must have changed...\n");
print_trace(1, &base);
}
} else {
/*
* The last hop address is not the same as it was;
* the route probably changed underneath us.
*/
hops = base.len;
printf("\nRoute must have changed...\n");
print_trace(1, &base);
}
if (r->tr_rflags == TR_OLD_ROUTER) {
what_kind(&base);
break;
}
if (r->tr_rflags == TR_NO_SPACE) {
printf("No space left in trace packet for more hops\n");
break; /* XXX could do segmented trace */
}
}
lastout = r->tr_outaddr;
nexthop = hops + 1;
VAL_TO_MASK(smask, r->tr_smask);
if ((r->tr_inaddr & smask) == (qsrc & smask)) {
printf("%3d ", -nexthop);
print_host(qsrc);
printf("\n");
if (base.len < hops ||
r->tr_rmtaddr == 0 ||
(r->tr_rflags & 0x80)) {
VAL_TO_MASK(smask, r->tr_smask);
if (r->tr_rmtaddr) {
if (hops != nexthop) {
printf("\n%3d ", -(base.len+1));
}
what_kind(&base, r->tr_rflags == TR_OLD_ROUTER ?
"doesn't support mtrace" :
"would be the next hop");
/* XXX could do segmented trace if TR_NO_SPACE */
} else if (r->tr_rflags == TR_NO_ERR &&
(r->tr_inaddr & smask) == (qsrc & smask)) {
printf("%3d ", -(hops + 1));
print_host(qsrc);
printf("\n");
}
break;
}
if (r->tr_rmtaddr == 0 || (r->tr_rflags & 0x80)) break;
nexthop = hops + 1;
}
}
@ -1284,8 +1608,9 @@ or multicast at ttl %d doesn't reach its last-hop router for that source\n",
raddr = base.qhdr.tr_raddr;
rttl = base.qhdr.tr_rttl;
gettimeofday(&tv, 0);
waittime = 10 - (((tv.tv_sec + JAN_1970) & 0xFFFF) - (base.qtime >> 16));
prev = new = &incr[numstats&1];
waittime = statint - (((tv.tv_sec + JAN_1970) & 0xFFFF) - (base.qtime >> 16));
prev = &base;
new = &incr[numstats&1];
while (numstats--) {
if (waittime < 1) printf("\n");
@ -1304,14 +1629,23 @@ or multicast at ttl %d doesn't reach its last-hop router for that source\n",
if (rno != new->len) {
printf("Trace length doesn't match:\n");
/*
* XXX Should this trace result be printed, or is that
* too verbose? Perhaps it should just say restarting.
* But if the path is changing quickly, this may be the
* only snapshot of the current path. But, if the path
* is changing that quickly, does the current path really
* matter?
*/
print_trace(1, new);
printf("Restarting.\n\n");
numstats++;
goto restart;
}
printf("Results after %d seconds:\n\n",
(int)((new->qtime - base.qtime) >> 16));
fixup_stats(&base, new);
fixup_stats(&base, prev, new);
if (print_stats(&base, prev, new)) {
printf("Route changed:\n");
print_trace(1, new);
@ -1320,7 +1654,7 @@ or multicast at ttl %d doesn't reach its last-hop router for that source\n",
}
prev = new;
new = &incr[numstats&1];
waittime = 10;
waittime = statint;
}
/*
@ -1461,3 +1795,15 @@ void accept_neighbors2(src, dst, p, datalen, level)
int datalen;
{
}
void accept_info_request(src, dst, p, datalen)
u_int32 src, dst;
u_char *p;
int datalen;
{
}
void accept_info_reply(src, dst, p, datalen)
u_int32 src, dst;
u_char *p;
int datalen;
{
}

View File

@ -7,7 +7,7 @@
* Leland Stanford Junior University.
*
*
* $Id: pathnames.h,v 3.6 1995/06/25 19:17:45 fenner Exp $
* $Id: pathnames.h,v 3.8 1995/11/29 22:36:57 fenner Rel $
*/
#define _PATH_MROUTED_CONF "/etc/mrouted.conf"

View File

@ -7,7 +7,7 @@
* Leland Stanford Junior University.
*
*
* $Id: prune.c,v 3.6 1995/06/25 19:18:43 fenner Exp $
* $Id: prune.c,v 3.8 1995/11/29 22:36:34 fenner Rel $
*/
@ -55,6 +55,7 @@ static void prun_add_ttls __P((struct gtable *gt));
static int pruning_neighbor __P((vifi_t vifi, u_int32 addr));
static int can_mtrace __P((vifi_t vifi, u_int32 addr));
static struct ptable * find_prune_entry __P((u_int32 vr, struct ptable *pt));
static void expire_prune __P((vifi_t vifi, struct gtable *gt));
static void send_prune __P((struct gtable *gt));
static void send_graft __P((struct gtable *gt));
static void send_graft_ack __P((u_int32 src, u_int32 dst,
@ -84,7 +85,7 @@ prun_add_ttls(gt)
* checks for scoped multicast addresses
*/
#define GET_SCOPE(gt) { \
register int _i; \
register vifi_t _i; \
if ((ntohl((gt)->gt_mcastgrp) & 0xff000000) == 0xef000000) \
for (_i = 0; _i < numvifs; _i++) \
if (scoped_addr(_i, (gt)->gt_mcastgrp)) \
@ -633,7 +634,11 @@ add_table_entry(origin, mcastgrp)
struct rtentry *r;
struct gtable *gt,**gtnp,*prev_gt;
struct stable *st,**stnp;
int i;
vifi_t i;
#ifdef DEBUG_MFC
md_log(MD_MISS, origin, mcastgrp);
#endif
r = determine_route(origin);
prev_gt = NULL;
@ -727,7 +732,7 @@ add_table_entry(origin, mcastgrp)
gt->gt_gnext->gt_gprev = gt;
}
} else {
gt->gt_gnext = gt->gt_prev = NULL;
gt->gt_gnext = gt->gt_gprev = NULL;
}
}
@ -748,8 +753,14 @@ add_table_entry(origin, mcastgrp)
st->st_next = *stnp;
*stnp = st;
} else {
#ifdef DEBUG_MFC
md_log(MD_DUPE, origin, mcastgrp);
#endif
log(LOG_WARNING, 0, "kernel entry already exists for (%s %s)",
inet_fmt(origin, s1), inet_fmt(mcastgrp, s2));
/* XXX Doing this should cause no harm, and may ensure
* kernel<>mrouted synchronization */
k_add_rg(origin, gt);
return;
}
@ -780,60 +791,31 @@ reset_neighbor_state(vifi, addr)
{
struct rtentry *r;
struct gtable *g;
struct ptable *pt, *prev_pt;
struct stable *st, *prev_st;
struct ptable *pt, **ptnp;
struct stable *st;
for (g = kernel_table; g; g = g->gt_gnext) {
r = g->gt_route;
/*
* If neighbor was the parent, remove the prune sent state
* Don't send any grafts upstream.
* and all of the source cache info so that prunes get
* regenerated.
*/
if (vifi == r->rt_parent) {
if (addr == r->rt_gateway) {
log(LOG_DEBUG, 0, "reset_neighbor_state del prunes (%s %s)",
log(LOG_DEBUG, 0, "reset_neighbor_state parent reset (%s %s)",
inet_fmts(r->rt_origin, r->rt_originmask, s1),
inet_fmt(g->gt_mcastgrp, s2));
pt = g->gt_pruntbl;
while (pt) {
/*
* Expire prune, send again on this vif.
*/
VIFM_SET(pt->pt_vifi, g->gt_grpmems);
prev_pt = pt;
pt = prev_pt->pt_next;
free(prev_pt);
}
g->gt_pruntbl = NULL;
st = g->gt_srctbl;
while (st) {
log(LOG_DEBUG, 0, "reset_neighbor_state del sg (%s %s)",
inet_fmt(st->st_origin, s1),
inet_fmt(g->gt_mcastgrp, s2));
if (k_del_rg(st->st_origin, g) < 0) {
log(LOG_WARNING, errno,
"reset_neighbor_state trying to delete (%s %s)",
inet_fmt(st->st_origin, s1),
inet_fmt(g->gt_mcastgrp, s2));
}
kroutes--;
prev_st = st;
st = prev_st->st_next;
free(prev_st);
}
g->gt_srctbl = NULL;
/*
* Keep the group entries themselves around since the
* state will likely just come right back, and if not,
* the group entries will time out with no kernel entries
* and no prune state.
*/
g->gt_prsent_timer = 0;
g->gt_grftsnt = 0;
while (st = g->gt_srctbl) {
g->gt_srctbl = st->st_next;
k_del_rg(st->st_origin, g);
kroutes--;
free(st);
}
}
} else {
/*
@ -848,13 +830,13 @@ reset_neighbor_state(vifi, addr)
/*
* Remove any prunes that this router has sent us.
*/
prev_pt = (struct ptable *)&g->gt_pruntbl;
for (pt = g->gt_pruntbl; pt; pt = pt->pt_next) {
ptnp = &g->gt_pruntbl;
while ((pt = *ptnp) != NULL) {
if (pt->pt_vifi == vifi && pt->pt_router == addr) {
prev_pt->pt_next = pt->pt_next;
*ptnp = pt->pt_next;
free(pt);
} else
prev_pt = pt;
ptnp = &pt->pt_next;
}
/*
@ -924,9 +906,9 @@ del_table_entry(r, mcastgrp, del_flag)
pt = g->gt_pruntbl;
while (pt) {
prev_pt = pt->pt_next;
free(pt);
pt = prev_pt;
prev_pt = pt;
pt = pt->pt_next;
free(prev_pt);
}
g->gt_pruntbl = NULL;
@ -937,14 +919,14 @@ del_table_entry(r, mcastgrp, del_flag)
else
kernel_table = g->gt_gnext;
prev_g = g->gt_next;
#ifdef RSRR
/* Send route change notification to reservation protocol. */
rsrr_cache_send(g,0);
rsrr_cache_clean(g);
#endif /* RSRR */
free(g);
g = prev_g;
prev_g = g;
g = g->gt_next;
free(prev_g);
}
r->rt_groups = NULL;
}
@ -968,17 +950,17 @@ del_table_entry(r, mcastgrp, del_flag)
inet_fmt(g->gt_mcastgrp, s2));
}
kroutes--;
prev_st = st->st_next;
free(st);
st = prev_st;
prev_st = st;
st = st->st_next;
free(prev_st);
}
g->gt_srctbl = NULL;
pt = g->gt_pruntbl;
while (pt) {
prev_pt = pt->pt_next;
free(pt);
pt = prev_pt;
prev_pt = pt;
pt = pt->pt_next;
free(prev_pt);
}
g->gt_pruntbl = NULL;
@ -1018,7 +1000,7 @@ update_table_entry(r)
{
struct gtable *g;
struct ptable *pt, *prev_pt;
int i;
vifi_t i;
for (g = r->rt_groups; g; g = g->gt_next) {
pt = g->gt_pruntbl;
@ -1282,7 +1264,7 @@ accept_prune(src, dst, p, datalen)
g->gt_timer = CACHE_LIFETIME(cache_lifetime);
if (g->gt_timer < prun_tmr)
g->gt_timer = prun_tmr;
/*
* check if any more packets need to be sent on the
* vif which sent this message
@ -1580,21 +1562,21 @@ free_all_prunes()
while (g) {
s = g->gt_srctbl;
while (s) {
prev_s = s->st_next;
free(s);
s = prev_s;
prev_s = s;
s = s->st_next;
free(prev_s);
}
p = g->gt_pruntbl;
while (p) {
prev_p = p->pt_next;
free(p);
p = prev_p;
prev_p = p;
p = p->pt_next;
free(prev_p);
}
prev_g = g->gt_next;
free(g);
g = prev_g;
prev_g = g;
g = g->gt_next;
free(prev_g);
}
r->rt_groups = NULL;
}
@ -1605,9 +1587,9 @@ free_all_prunes()
if (g->gt_srctbl)
free(g->gt_srctbl);
prev_g = g->gt_next;
free(g);
g = prev_g;
prev_g = g;
g = g->gt_next;
free(prev_g);
}
kernel_no_route = NULL;
}
@ -1742,34 +1724,8 @@ age_table_entry()
inet_fmt(gt->gt_mcastgrp, s2),
inet_fmt(pt->pt_router, s3),
pt->pt_vifi);
/*
* No need to send a graft, any prunes that we sent
* will expire before any prunes that we have received.
*/
if (gt->gt_prsent_timer > 0) {
log(LOG_DEBUG, 0, "prune expired with %d left on %s",
gt->gt_prsent_timer, "prsent_timer");
gt->gt_prsent_timer = 0;
}
/* modify the kernel entry to forward packets */
if (!VIFM_ISSET(pt->pt_vifi, gt->gt_grpmems)) {
VIFM_SET(pt->pt_vifi, gt->gt_grpmems);
log(LOG_DEBUG, 0, "forw again (%s %s) gm:%x vif:%d",
inet_fmts(r->rt_origin, r->rt_originmask, s1),
inet_fmt(gt->gt_mcastgrp, s2), gt->gt_grpmems,
pt->pt_vifi);
prun_add_ttls(gt);
update_kernel(gt);
#ifdef RSRR
/* Send route change notification to reservation
* protocol.
*/
rsrr_cache_send(gt,1);
#endif /* RSRR */
}
expire_prune(pt->pt_vifi, gt);
/* remove the router's prune entry and await new one */
*ptnp = pt->pt_next;
@ -1780,94 +1736,65 @@ age_table_entry()
}
/*
* If the cache entry has expired, check for downstream prunes.
*
* If there are downstream prunes, refresh the cache entry's timer.
* Otherwise, check for traffic. If no traffic, delete this
* entry.
* If the cache entry has expired, delete source table entries for
* silent sources. If there are no source entries left, and there
* are no downstream prunes, then the entry is deleted.
* Otherwise, the cache entry's timer is refreshed.
*/
if (gt->gt_timer <= 0) {
if (gt->gt_pruntbl) {
if (gt->gt_prsent_timer == -1)
gt->gt_prsent_timer = 0;
gt->gt_timer = CACHE_LIFETIME(cache_lifetime);
gtnptr = &gt->gt_gnext;
continue;
/* Check for traffic before deleting source entries */
sg_req.grp.s_addr = gt->gt_mcastgrp;
stnp = &gt->gt_srctbl;
while ((st = *stnp) != NULL) {
sg_req.src.s_addr = st->st_origin;
if (ioctl(udp_socket, SIOCGETSGCNT, (char *)&sg_req) < 0) {
log(LOG_WARNING, errno, "%s (%s %s)",
"age_table_entry: SIOCGETSGCNT failing for",
inet_fmt(st->st_origin, s1),
inet_fmt(gt->gt_mcastgrp, s2));
/* Make sure it gets deleted below */
sg_req.pktcnt = st->st_pktcnt;
}
if (sg_req.pktcnt == st->st_pktcnt) {
*stnp = st->st_next;
log(LOG_DEBUG, 0, "age_table_entry deleting (%s %s)",
inet_fmt(st->st_origin, s1),
inet_fmt(gt->gt_mcastgrp, s2));
if (k_del_rg(st->st_origin, gt) < 0) {
log(LOG_WARNING, errno,
"age_table_entry trying to delete (%s %s)",
inet_fmt(st->st_origin, s1),
inet_fmt(gt->gt_mcastgrp, s2));
}
kroutes--;
free(st);
} else {
st->st_pktcnt = sg_req.pktcnt;
stnp = &st->st_next;
}
}
/*
* If this entry was pruned, but all downstream prunes
* have expired, then it is safe to simply delete it.
* Otherwise, check for traffic before deleting.
* Retain the group entry if we have downstream prunes or if
* there is at least one source in the list that still has
* traffic, or if our upstream prune timer is running.
*/
if (gt->gt_prsent_timer == 0) {
sg_req.grp.s_addr = gt->gt_mcastgrp;
stnp = &gt->gt_srctbl;
while ((st = *stnp) != NULL) {
sg_req.src.s_addr = st->st_origin;
if (ioctl(udp_socket, SIOCGETSGCNT, (char *)&sg_req)
< 0) {
log(LOG_WARNING, errno, "%s (%s %s)",
"age_table_entry: SIOCGETSGCNT failing for",
inet_fmt(st->st_origin, s1),
inet_fmt(gt->gt_mcastgrp, s2));
/* Make sure it gets deleted below */
sg_req.pktcnt = st->st_pktcnt;
}
if (sg_req.pktcnt == st->st_pktcnt) {
*stnp = st->st_next;
log(LOG_DEBUG, 0,
"age_table_entry deleting (%s %s)",
inet_fmt(st->st_origin, s1),
inet_fmt(gt->gt_mcastgrp, s2));
if (k_del_rg(st->st_origin, gt) < 0) {
log(LOG_WARNING, errno,
"age_table_entry trying to delete (%s %s)",
inet_fmt(st->st_origin, s1),
inet_fmt(gt->gt_mcastgrp, s2));
}
kroutes--;
free(st);
} else {
stnp = &st->st_next;
}
}
if (gt->gt_srctbl) {
/* At least one source in the list still has traffic */
gt->gt_timer = CACHE_LIFETIME(cache_lifetime);
gtnptr = &gt->gt_gnext;
continue;
}
if (gt->gt_pruntbl != NULL || gt->gt_srctbl != NULL ||
gt->gt_prsent_timer > 0) {
gt->gt_timer = CACHE_LIFETIME(cache_lifetime);
if (gt->gt_prsent_timer == -1)
if (gt->gt_grpmems == 0)
send_prune(gt);
else
gt->gt_prsent_timer = 0;
gtnptr = &gt->gt_gnext;
continue;
}
log(LOG_DEBUG, 0, "timeout cache entry (%s, %s)",
inet_fmts(r->rt_origin, r->rt_originmask, s1),
inet_fmt(gt->gt_mcastgrp, s2));
/* free all the source entries */
while ((st = gt->gt_srctbl) != NULL) {
log(LOG_DEBUG, 0,
"age_table_entry (P) deleting (%s %s)",
inet_fmt(st->st_origin, s1),
inet_fmt(gt->gt_mcastgrp, s2));
if (k_del_rg(st->st_origin, gt) < 0) {
log(LOG_WARNING, errno,
"age_table_entry (P) trying to delete (%s %s)",
inet_fmt(st->st_origin, s1),
inet_fmt(gt->gt_mcastgrp, s2));
}
kroutes--;
gt->gt_srctbl = st->st_next;
free(st);
}
/* free all the prune list entries */
while ((pt = gt->gt_pruntbl) != NULL) {
gt->gt_pruntbl = pt->pt_next;
free(pt);
}
if (gt->gt_prev)
gt->gt_prev->gt_next = gt->gt_next;
else
@ -1893,7 +1820,10 @@ age_table_entry()
free((char *)gt);
} else {
if (gt->gt_prsent_timer == -1)
gt->gt_prsent_timer = 0;
if (gt->gt_grpmems == 0)
send_prune(gt);
else
gt->gt_prsent_timer = 0;
gtnptr = &gt->gt_gnext;
}
}
@ -1928,6 +1858,44 @@ age_table_entry()
}
}
/*
* Modify the kernel to forward packets when one or multiple prunes that
* were received on the vif given by vifi, for the group given by gt,
* have expired.
*/
static void
expire_prune(vifi, gt)
vifi_t vifi;
struct gtable *gt;
{
/*
* No need to send a graft, any prunes that we sent
* will expire before any prunes that we have received.
*/
if (gt->gt_prsent_timer > 0) {
log(LOG_DEBUG, 0, "prune expired with %d left on %s",
gt->gt_prsent_timer, "prsent_timer");
gt->gt_prsent_timer = 0;
}
/* modify the kernel entry to forward packets */
if (!VIFM_ISSET(vifi, gt->gt_grpmems)) {
struct rtentry *rt = gt->gt_route;
VIFM_SET(vifi, gt->gt_grpmems);
log(LOG_DEBUG, 0, "forw again (%s %s) gm:%x vif:%d",
inet_fmts(rt->rt_origin, rt->rt_originmask, s1),
inet_fmt(gt->gt_mcastgrp, s2), gt->gt_grpmems, vifi);
prun_add_ttls(gt);
update_kernel(gt);
#ifdef RSRR
/* Send route change notification to reservation protocol. */
rsrr_cache_send(gt,1);
#endif /* RSRR */
}
}
static char *
scaletime(t)
u_long t;
@ -1978,7 +1946,7 @@ dump_cache(fp2)
register struct gtable *gt;
register struct stable *st;
register struct ptable *pt;
register int i;
register vifi_t i;
register time_t thyme = time(0);
fprintf(fp2,
@ -2091,21 +2059,6 @@ accept_mtrace(src, dst, group, data, no, datalen)
qry = (struct tr_query *)data;
if (oqid == qry->tr_qid) {
/*
* If the multicast router is a member of the group being
* queried, and the query is multicasted, then the router can
* recieve multiple copies of the same query. If we have already
* replied to this traceroute, just ignore it this time.
*
* This is not a total solution, but since if this fails you
* only get N copies, N <= the number of interfaces on the router,
* it is not fatal.
*/
log(LOG_DEBUG, 0, "ignoring duplicate traceroute packet");
return;
}
/*
* if it is a packet with all reports filled, drop it
*/
@ -2136,6 +2089,21 @@ accept_mtrace(src, dst, group, data, no, datalen)
* and if so, whether I should start response back
*/
if (type == QUERY) {
if (oqid == qry->tr_qid) {
/*
* If the multicast router is a member of the group being
* queried, and the query is multicasted, then the router can
* recieve multiple copies of the same query. If we have already
* replied to this traceroute, just ignore it this time.
*
* This is not a total solution, but since if this fails you
* only get N copies, N <= the number of interfaces on the router,
* it is not fatal.
*/
log(LOG_DEBUG, 0, "ignoring duplicate traceroute packet");
return;
}
if (rt == NULL) {
log(LOG_DEBUG, 0, "Mcast traceroute: no route entry %s",
inet_fmt(qry->tr_src, s1));
@ -2201,7 +2169,7 @@ accept_mtrace(src, dst, group, data, no, datalen)
bzero(resp, sizeof(struct tr_resp));
datalen += RLEN;
resp->tr_qarr = ((tp.tv_sec + JAN_1970) << 16) +
resp->tr_qarr = htonl((tp.tv_sec + JAN_1970) << 16) +
((tp.tv_usec >> 4) & 0xffff);
resp->tr_rproto = PROTO_DVMRP;
@ -2219,7 +2187,7 @@ accept_mtrace(src, dst, group, data, no, datalen)
*/
v_req.vifi = vifi;
if (ioctl(udp_socket, SIOCGETVIFCNT, (char *)&v_req) >= 0)
resp->tr_vifout = v_req.ocount;
resp->tr_vifout = htonl(v_req.ocount);
/*
* fill in scoping & pruning information
@ -2236,7 +2204,7 @@ accept_mtrace(src, dst, group, data, no, datalen)
sg_req.src.s_addr = qry->tr_src;
sg_req.grp.s_addr = group;
if (ioctl(udp_socket, SIOCGETSGCNT, (char *)&sg_req) >= 0)
resp->tr_pktcnt = sg_req.pktcnt;
resp->tr_pktcnt = htonl(sg_req.pktcnt);
if (VIFM_ISSET(vifi, gt->gt_scope))
resp->tr_rflags = TR_SCOPED;
@ -2267,7 +2235,7 @@ accept_mtrace(src, dst, group, data, no, datalen)
/* get # of packets in on interface */
v_req.vifi = rt->rt_parent;
if (ioctl(udp_socket, SIOCGETVIFCNT, (char *)&v_req) >= 0)
resp->tr_vifin = v_req.icount;
resp->tr_vifin = htonl(v_req.icount);
MASK_TO_VAL(rt->rt_originmask, resp->tr_smask);
src = uvifs[rt->rt_parent].uv_lcl_addr;

View File

@ -7,7 +7,7 @@
* Leland Stanford Junior University.
*
*
* $Id: prune.h,v 3.6 1995/06/25 19:19:04 fenner Exp $
* $Id: prune.h,v 3.8 1995/11/29 22:36:57 fenner Rel $
*/
/*

View File

@ -7,7 +7,7 @@
* Leland Stanford Junior University.
*
*
* $Id: route.c,v 3.6 1995/06/25 19:20:19 fenner Exp $
* $Id: route.c,v 3.8 1995/11/29 22:36:57 fenner Rel $
*/
@ -353,12 +353,12 @@ discard_route(prev_r)
void
update_route(origin, mask, metric, src, vifi)
u_int32 origin, mask;
int metric;
u_int metric;
u_int32 src;
vifi_t vifi;
{
register struct rtentry *r;
int adj_metric;
u_int adj_metric;
/*
* Compute an adjusted metric, taking into account the cost of the
@ -462,7 +462,8 @@ update_route(origin, mask, metric, src, vifi)
(r->rt_gateway != 0 &&
(adj_metric < r->rt_metric ||
(adj_metric == r->rt_metric &&
r->rt_timer >= ROUTE_SWITCH_TIME)))) {
(ntohl(src) < ntohl(r->rt_gateway) ||
r->rt_timer >= ROUTE_SWITCH_TIME))))) {
/*
* The report is for an origin we consider reachable; the report
* comes either from one of our own interfaces or from a gateway
@ -473,10 +474,15 @@ update_route(origin, mask, metric, src, vifi)
* what our routing entry says, update the entry to use the new
* gateway and metric. We also switch gateways if the reported
* metric is the same as the one in the route entry and the gateway
* associated with the route entry has not been heard from recently.
* associated with the route entry has not been heard from recently,
* or if the metric is the same but the reporting gateway has a lower
* IP address than the gateway associated with the route entry.
* Did you get all that?
*/
if (r->rt_parent != vifi || adj_metric < r->rt_metric) {
/*
* XXX Why do we do this if we are just changing the metric?
*/
r->rt_parent = vifi;
if (init_children_and_leaves(r, vifi)) {
update_table_entry(r);
@ -785,6 +791,12 @@ accept_report(src, dst, p, datalen, level)
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;
if (!inet_valid_mask(ntohl(mask))) {
log(LOG_WARNING, 0,
"%s reports bogus netmask 0x%08x (%s)",
inet_fmt(src, s1), ntohl(mask), inet_fmt(mask, s2));
return;
}
datalen -= 3;
do { /* Loop through (origin, metric) pairs */
@ -805,6 +817,7 @@ accept_report(src, dst, p, datalen, level)
++nrt;
} while (!(metric & 0x80));
}
qsort((char*)rt, nrt, sizeof(rt[0]), compare_rts);
start_route_updates();
/*
@ -815,9 +828,16 @@ accept_report(src, dst, p, datalen, level)
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)
for (i = 0; i < nrt; ++i) {
if (i != 0 && rt[i].origin == rt[i-1].origin &&
rt[i].mask == rt[i-1].mask) {
log(LOG_WARNING, 0, "%s reports duplicate route for %s",
inet_fmt(src, s1), inet_fmts(rt[i].origin, rt[i].mask, s2));
continue;
}
update_route(rt[i].origin, rt[i].mask, rt[i].metric,
src, vifi);
}
if (routes_changed && !delay_change_reports)
report_to_all_neighbors(CHANGED_ROUTES);
@ -1098,7 +1118,7 @@ dump_routes(fp)
FILE *fp;
{
register struct rtentry *r;
register int i;
register vifi_t i;
fprintf(fp,

View File

@ -7,7 +7,7 @@
* Leland Stanford Junior University.
*
*
* $Id: route.h,v 3.6 1995/06/25 19:21:05 fenner Exp $
* $Id: route.h,v 3.8 1995/11/29 22:36:57 fenner Rel $
*/
/*

View File

@ -107,7 +107,8 @@ rsrr_init()
/* Read a message from the RSRR socket */
void
rsrr_read(rfd)
rsrr_read(f, rfd)
int f;
fd_set *rfd;
{
register int rsrr_recvlen;

View File

@ -7,14 +7,13 @@
* Leland Stanford Junior University.
*
*
* $Id: vif.c,v 3.6 1995/06/25 19:53:01 fenner Exp $
* $Id: vif.c,v 3.8 1995/11/29 22:36:57 fenner Rel $
*/
#include "defs.h"
#include <fcntl.h>
/*
* Exported variables.
*/
@ -34,24 +33,27 @@ typedef struct {
int q_time;
} cbk_t;
static cbk_t *cbk;
/*
* Forward declarations.
*/
static void start_vif __P((vifi_t vifi));
static void start_vif2 __P((vifi_t vifi));
static void stop_vif __P((vifi_t vifi));
static void age_old_hosts __P((void));
static void send_probe_on_vif __P((struct uvif *v));
static void DelVif __P((cbk_t *cbk));
static int info_version __P((char *p));
static void DelVif __P((void *arg));
static int SetTimer __P((int vifi, struct listaddr *g));
static int DeleteTimer __P((int id));
static void SendQuery __P((cbk_t *cbk));
static void SendQuery __P((void *arg));
static int SetQueryTimer __P((struct listaddr *g, vifi_t vifi, int to_expire,
int q_time));
/*
* Initialize the virtual interfaces.
* Initialize the virtual interfaces, but do not install
* them in the kernel. Start routing on all vifs that are
* not down or disabled.
*/
void
init_vifs()
@ -101,10 +103,35 @@ init_vifs()
log(LOG_WARNING, 0,
"no enabled interfaces, forwarding via tunnels only");
/*
* Start routing on all virtual interfaces that are not down or
* administratively disabled.
*/
log(LOG_INFO, 0, "Installing vifs in mrouted...");
for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
if (!(v->uv_flags & VIFF_DISABLED)) {
if (!(v->uv_flags & VIFF_DOWN)) {
if (v->uv_flags & VIFF_TUNNEL)
log(LOG_INFO, 0, "vif #%d, tunnel %s -> %s", vifi,
inet_fmt(v->uv_lcl_addr, s1),
inet_fmt(v->uv_rmt_addr, s2));
else
log(LOG_INFO, 0, "vif #%d, phyint %s", vifi,
inet_fmt(v->uv_lcl_addr, s1));
start_vif2(vifi);
} else log(LOG_INFO, 0,
"%s is not yet up; vif #%u not in service",
v->uv_name, vifi);
}
}
}
/*
* Start routing on all virtual interfaces that are not down or
* administratively disabled.
*/
void
init_installvifs()
{
vifi_t vifi;
struct uvif *v;
log(LOG_INFO, 0, "Installing vifs in kernel...");
for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
if (!(v->uv_flags & VIFF_DISABLED)) {
@ -116,7 +143,7 @@ init_vifs()
else
log(LOG_INFO, 0, "vif #%d, phyint %s", vifi,
inet_fmt(v->uv_lcl_addr, s1));
start_vif(vifi);
k_add_vif(vifi, &uvifs[vifi]);
} else log(LOG_INFO, 0,
"%s is not yet up; vif #%u not in service",
v->uv_name, vifi);
@ -124,7 +151,6 @@ init_vifs()
}
}
/*
* See if any interfaces have changed from up state to down, or vice versa,
* including any non-multicast-capable interfaces that are in use as local
@ -211,11 +237,27 @@ send_probe_on_vif(v)
}
/*
* Start routing on the specified virtual interface.
* Add a vifi to the kernel and start routing on it.
*/
static void
start_vif(vifi)
vifi_t vifi;
{
/*
* Install the interface in the kernel's vif structure.
*/
k_add_vif(vifi, &uvifs[vifi]);
start_vif2(vifi);
}
/*
* Add a vifi to all the user-level data structures but don't add
* it to the kernel yet.
*/
static void
start_vif2(vifi)
vifi_t vifi;
{
struct uvif *v;
u_int32 src;
@ -224,11 +266,6 @@ start_vif(vifi)
v = &uvifs[vifi];
src = v->uv_lcl_addr;
/*
* Install the interface in the kernel's vif structure.
*/
k_add_vif(vifi, &uvifs[vifi]);
/*
* Update the existing route entries to take into account the new vif.
*/
@ -269,7 +306,8 @@ start_vif(vifi)
*/
v->uv_flags |= VIFF_QUERIER;
send_igmp(src, allhosts_group, IGMP_HOST_MEMBERSHIP_QUERY,
IGMP_MAX_HOST_REPORT_DELAY * IGMP_TIMER_SCALE, 0, 0);
(v->uv_flags & VIFF_IGMPV1) ? 0 :
IGMP_MAX_HOST_REPORT_DELAY * IGMP_TIMER_SCALE, 0, 0);
age_old_hosts();
}
@ -428,16 +466,15 @@ age_old_hosts()
register vifi_t vifi;
register struct uvif *v;
register struct listaddr *g;
for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
/* -*- increment the time since an old report was heard */
for (g = v->uv_groups; g != NULL; g = g->al_next) {
g->al_last ++;
if (g->al_last >= OLD_AGE_THRESHOLD){
g->al_old = 0;
g->al_last = OLD_AGE_THRESHOLD;
}
}
}
/*
* Decrement the old-hosts-present timer for each
* active group on each vif.
*/
for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++)
for (g = v->uv_groups; g != NULL; g = g->al_next)
if (g->al_old)
g->al_old--;
}
@ -454,6 +491,7 @@ query_groups()
if (v->uv_flags & VIFF_QUERIER) {
send_igmp(v->uv_lcl_addr, allhosts_group,
IGMP_HOST_MEMBERSHIP_QUERY,
(v->uv_flags & VIFF_IGMPV1) ? 0 :
IGMP_MAX_HOST_REPORT_DELAY * IGMP_TIMER_SCALE, 0, 0);
}
}
@ -481,16 +519,19 @@ accept_membership_query(src, dst, group, tmo)
v = &uvifs[vifi];
/* If we consider ourselves the querier for this vif, but hear a
/*
* If we consider ourselves the querier for this vif, but hear a
* query from a router with a lower IP address, yield to them.
*
* This is done here as well as in the neighbor discovery in case
* there is a querier that doesn't speak DVMRP.
*
* XXX If this neighbor doesn't speak DVMRP, then we need to create
* some neighbor state for him so that we can time him out!
*/
if ((v->uv_flags & VIFF_QUERIER) &&
(ntohl(src) < ntohl(v->uv_lcl_addr))) {
v->uv_flags &= ~VIFF_QUERIER;
v->uv_flags &= ~VIFF_QUERIER;
}
}
@ -522,17 +563,14 @@ accept_group_report(src, dst, group, r_type)
*/
for (g = v->uv_groups; g != NULL; g = g->al_next) {
if (group == g->al_addr) {
if (r_type == IGMP_HOST_NEW_MEMBERSHIP_REPORT) {
g->al_last = OLD_AGE_THRESHOLD;
g->al_old = 0;
}
else {
g->al_last = 0;
g->al_old = 1;
}
if (r_type == IGMP_HOST_MEMBERSHIP_REPORT)
g->al_old = OLD_AGE_THRESHOLD;
#ifdef SNMP
g->al_genid = src;
#endif /* SNMP */
/** delete old timer set a timer for expiration **/
g->al_timer= GROUP_EXPIRE_TIME;
/** delete old timers, set a timer for expiration **/
g->al_timer = GROUP_EXPIRE_TIME;
if (g->al_query)
g->al_query = DeleteTimer(g->al_query);
if (g->al_timerid)
@ -551,14 +589,13 @@ accept_group_report(src, dst, group, r_type)
log(LOG_ERR, 0, "ran out of memory"); /* fatal */
g->al_addr = group;
if (r_type == IGMP_HOST_NEW_MEMBERSHIP_REPORT) {
g->al_last = OLD_AGE_THRESHOLD;
if (r_type == IGMP_HOST_NEW_MEMBERSHIP_REPORT)
g->al_old = 0;
}
else {
g->al_last = 0;
g->al_old = 1;
}
else
g->al_old = OLD_AGE_THRESHOLD;
#ifdef SNMP
g->al_genid = src;
#endif
/** set a timer for expiration **/
g->al_query = 0;
@ -596,7 +633,7 @@ accept_leave_message(src, dst, group)
v = &uvifs[vifi];
if (!(v->uv_flags & VIFF_QUERIER))
if (!(v->uv_flags & VIFF_QUERIER) || (v->uv_flags & VIFF_IGMPV1))
return;
/*
@ -857,6 +894,68 @@ accept_neighbor_request2(src, dst)
datalen);
}
void
accept_info_request(src, dst, p, datalen)
u_int32 src, dst;
u_char *p;
int datalen;
{
u_char *q;
int len;
int outlen = 0;
q = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
/* To be general, this must deal properly with breaking up over-sized
* packets. That implies passing a length to each function, and
* allowing each function to request to be called again. Right now,
* we're only implementing the one thing we are positive will fit into
* a single packet, so we wimp out.
*/
while (datalen > 0) {
len = 0;
switch (*p) {
case DVMRP_INFO_VERSION:
len = info_version(q);
break;
case DVMRP_INFO_NEIGHBORS:
default:
log(LOG_INFO, 0, "ignoring unknown info type %d", *p);
break;
}
*(q+1) = len++;
outlen += len * 4;
q += len * 4;
len = (*(p+1) + 1) * 4;
p += len;
datalen -= len;
}
if (outlen != 0)
send_igmp(INADDR_ANY, src, IGMP_DVMRP, DVMRP_INFO_REPLY,
htonl(MROUTED_LEVEL), outlen);
}
/*
* Information response -- return version string
*/
static int
info_version(p)
char *p;
{
int len;
extern char versionstring[];
*p++ = DVMRP_INFO_VERSION;
p++; /* skip over length */
*p++ = 0; /* zero out */
*p++ = 0; /* reserved fields */
strcpy(p, versionstring); /* XXX strncpy!!! */
len = strlen(versionstring);
return ((len + 3) / 4);
}
/*
* Process an incoming neighbor-list message.
@ -885,6 +984,19 @@ accept_neighbors2(src, dst, p, datalen, level)
inet_fmt(src, s1), inet_fmt(dst, s2));
}
/*
* Process an incoming info reply message.
*/
void
accept_info_reply(src, dst, p, datalen)
u_int32 src, dst;
u_char *p;
int datalen;
{
log(LOG_INFO, 0, "ignoring spurious DVMRP info reply from %s to %s",
inet_fmt(src, s1), inet_fmt(dst, s2));
}
/*
* Update the neighbor entry for neighbor 'addr' on vif 'vifi'.
@ -1215,6 +1327,7 @@ dump_vifs(fp)
if (v->uv_flags & VIFF_QUERIER) fprintf(fp, " querier");
if (v->uv_flags & VIFF_SRCRT) fprintf(fp, " src-rt");
if (v->uv_flags & VIFF_LEAF) fprintf(fp, " leaf");
if (v->uv_flags & VIFF_IGMPV1) fprintf(fp, " IGMPv1");
fprintf(fp, "\n");
if (v->uv_addrs != NULL) {
@ -1272,80 +1385,98 @@ dump_vifs(fp)
fprintf(fp, "\n");
}
/**** the timeout routines ********/
/*
* Time out record of a group membership on a vif
*/
static void
DelVif(cbk)
cbk_t *cbk;
DelVif(arg)
void *arg;
{
/* -*- make the list consistent */
register vifi_t vifi = cbk->vifi;
register struct uvif *v;
register struct listaddr *a, *prev_a, *g = cbk->g;
cbk_t *cbk = (cbk_t *)arg;
vifi_t vifi = cbk->vifi;
struct uvif *v = &uvifs[vifi];
struct listaddr *a, **anp, *g = cbk->g;
v = &uvifs[vifi];
/*
* Group has expired
* delete all kernel cache entries with this group
*/
if (g->al_query)
DeleteTimer(g->al_query);
for (prev_a = (struct listaddr *)&(v->uv_groups),
a = v->uv_groups;
a != NULL;
prev_a = a, a = a->al_next) {
delete_lclgrp(vifi, g->al_addr);
if (a != g) continue;
anp = &(v->uv_groups);
while ((a = *anp) != NULL) {
if (a == g) {
*anp = a->al_next;
free((char *)a);
} else {
anp = &a->al_next;
}
}
/*
* Group has expired
* delete all kernel cache entries with this group
*/
if (g->al_query) DeleteTimer(g->al_query);
delete_lclgrp(vifi, a->al_addr);
prev_a->al_next = a->al_next;
free((char *)a);
a = prev_a;
}
free(cbk);
free(cbk);
}
/*
* Set a timer to delete the record of a group membership on a vif.
*/
static int
SetTimer(vifi, g)
vifi_t vifi; struct listaddr *g;
vifi_t vifi;
struct listaddr *g;
{
cbk = (cbk_t *) malloc(sizeof(cbk_t));
cbk->g = g;
cbk->vifi = vifi;
return timer_setTimer(g->al_timer, (cfunc_t)DelVif, (void *)cbk);
cbk_t *cbk;
cbk = (cbk_t *) malloc(sizeof(cbk_t));
cbk->g = g;
cbk->vifi = vifi;
return timer_setTimer(g->al_timer, (cfunc_t)DelVif, (void *)cbk);
}
/*
* Delete a timer that was set above.
*/
static int
DeleteTimer(id)
int id;
int id;
{
timer_clearTimer(id);
return 0;
timer_clearTimer(id);
return 0;
}
/*
* Send a group-specific query.
*/
static void
SendQuery(cbk)
cbk_t *cbk;
SendQuery(arg)
void *arg;
{
register struct uvif *v = &uvifs[cbk->vifi];
cbk_t *cbk = (cbk_t *)arg;
register struct uvif *v = &uvifs[cbk->vifi];
send_igmp(v->uv_lcl_addr, cbk->g->al_addr,
IGMP_HOST_MEMBERSHIP_QUERY,
cbk->q_time, 0, 0);
cbk->g->al_query = 0;
free(cbk);
send_igmp(v->uv_lcl_addr, cbk->g->al_addr,
IGMP_HOST_MEMBERSHIP_QUERY,
cbk->q_time, cbk->g->al_addr, 0);
cbk->g->al_query = 0;
free(cbk);
}
/*
* Set a timer to send a group-specific query.
*/
static int
SetQueryTimer(g , vifi, to_expire, q_time)
struct listaddr *g; vifi_t vifi;
int to_expire, q_time;
SetQueryTimer(g, vifi, to_expire, q_time)
struct listaddr *g;
vifi_t vifi;
int to_expire, q_time;
{
cbk = (cbk_t *) malloc(sizeof(cbk_t));
cbk->g = g;
cbk->q_time = q_time; cbk-> vifi = vifi;
return timer_setTimer(to_expire, (cfunc_t)SendQuery, (void *)cbk);
cbk_t *cbk;
cbk = (cbk_t *) malloc(sizeof(cbk_t));
cbk->g = g;
cbk->q_time = q_time;
cbk->vifi = vifi;
return timer_setTimer(to_expire, (cfunc_t)SendQuery, (void *)cbk);
}

View File

@ -7,7 +7,7 @@
* Leland Stanford Junior University.
*
*
* $Id: vif.h,v 3.6 1995/06/25 19:53:22 fenner Exp $
* $Id: vif.h,v 3.8 1995/11/29 22:36:57 fenner Rel $
*/
/*
@ -41,6 +41,7 @@ struct uvif {
#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 */
#define VIFF_IGMPV1 0x2000 /* Act as an IGMPv1 Router */
struct phaddr {
struct phaddr *pa_next;
@ -65,8 +66,7 @@ struct listaddr {
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_short al_old; /* time since heard old report */
u_char al_flags; /* flags related to this neighbor */
};