From 73950bd7a6d01b29d656a59c00de1ff876c44de1 Mon Sep 17 00:00:00 2001 From: Peter Wemm Date: Sat, 6 Jan 1996 21:04:38 +0000 Subject: [PATCH] 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.. --- usr.sbin/mrouted/callout.c | 28 +- usr.sbin/mrouted/cfparse.y | 103 +++++- usr.sbin/mrouted/config.c | 2 +- usr.sbin/mrouted/defs.h | 41 ++- usr.sbin/mrouted/dvmrp.h | 19 +- usr.sbin/mrouted/igmp.c | 32 +- usr.sbin/mrouted/inet.c | 31 +- usr.sbin/mrouted/kern.c | 26 +- usr.sbin/mrouted/main.c | 239 ++++++++++---- usr.sbin/mrouted/mapper.c | 29 +- usr.sbin/mrouted/mrinfo.c | 113 ++++--- usr.sbin/mrouted/mrouted.8 | 11 +- usr.sbin/mrouted/mrouted.conf | 8 +- usr.sbin/mrouted/mtrace.8 | 28 +- usr.sbin/mrouted/mtrace.c | 600 +++++++++++++++++++++++++++------- usr.sbin/mrouted/pathnames.h | 2 +- usr.sbin/mrouted/prune.c | 364 ++++++++++----------- usr.sbin/mrouted/prune.h | 2 +- usr.sbin/mrouted/route.c | 34 +- usr.sbin/mrouted/route.h | 2 +- usr.sbin/mrouted/rsrr.c | 3 +- usr.sbin/mrouted/vif.c | 333 +++++++++++++------ usr.sbin/mrouted/vif.h | 6 +- 23 files changed, 1444 insertions(+), 612 deletions(-) diff --git a/usr.sbin/mrouted/callout.c b/usr.sbin/mrouted/callout.c index 29e44eccfbdc..358c7ae86a21 100644 --- a/usr.sbin/mrouted/callout.c +++ b/usr.sbin/mrouted/callout.c @@ -7,7 +7,7 @@ * Leland Stanford Junior University. * * - * $Id: callout.c,v 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; +} diff --git a/usr.sbin/mrouted/cfparse.y b/usr.sbin/mrouted/cfparse.y index c08938d4a47a..ab5b89f30ea8 100644 --- a/usr.sbin/mrouted/cfparse.y +++ b/usr.sbin/mrouted/cfparse.y @@ -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 #ifdef __STDC__ @@ -13,6 +13,7 @@ #include #endif #include "defs.h" +#include /* * 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 BOOLEAN %token NUMBER %token STRING %token ADDRMASK %token ADDR -%type interface +%type interface addrname %type 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; } diff --git a/usr.sbin/mrouted/config.c b/usr.sbin/mrouted/config.c index 56fdccb991e2..1147412b904e 100644 --- a/usr.sbin/mrouted/config.c +++ b/usr.sbin/mrouted/config.c @@ -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 $ */ diff --git a/usr.sbin/mrouted/defs.h b/usr.sbin/mrouted/defs.h index 5829314ce500..63aef773e77c 100644 --- a/usr.sbin/mrouted/defs.h +++ b/usr.sbin/mrouted/defs.h @@ -7,7 +7,7 @@ * Leland Stanford Junior University. * * - * $Id: defs.h,v 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 #include #include +#ifdef SYSV +#include +#endif #include #include #include @@ -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)); diff --git a/usr.sbin/mrouted/dvmrp.h b/usr.sbin/mrouted/dvmrp.h index 5553dc34910e..e471800588dc 100644 --- a/usr.sbin/mrouted/dvmrp.h +++ b/usr.sbin/mrouted/dvmrp.h @@ -7,7 +7,7 @@ * Leland Stanford Junior University. * * - * $Id: dvmrp.h,v 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 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 */ diff --git a/usr.sbin/mrouted/igmp.c b/usr.sbin/mrouted/igmp.c index 00eeff56500b..3c27e6d38d26 100644 --- a/usr.sbin/mrouted/igmp.c +++ b/usr.sbin/mrouted/igmp.c @@ -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)); diff --git a/usr.sbin/mrouted/inet.c b/usr.sbin/mrouted/inet.c index e8d5ab6f23f8..b60e3854da35 100644 --- a/usr.sbin/mrouted/inet.c +++ b/usr.sbin/mrouted/inet.c @@ -7,7 +7,7 @@ * Leland Stanford Junior University. * * - * $Id: inet.c,v 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); } diff --git a/usr.sbin/mrouted/kern.c b/usr.sbin/mrouted/kern.c index a4030c831bb2..2a64e5c13916 100644 --- a/usr.sbin/mrouted/kern.c +++ b/usr.sbin/mrouted/kern.c @@ -7,7 +7,7 @@ * Leland Stanford Junior University. * * - * $Id: kern.c,v 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 } diff --git a/usr.sbin/mrouted/main.c b/usr.sbin/mrouted/main.c index f66ce7193f2f..b5ef723bcb73 100644 --- a/usr.sbin/mrouted/main.c +++ b/usr.sbin/mrouted/main.c @@ -7,7 +7,7 @@ * Leland Stanford Junior University. * * - * $Id: main.c,v 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 diff --git a/usr.sbin/mrouted/mapper.c b/usr.sbin/mrouted/mapper.c index 8c1c5fd7e6ff..1eacd04bb61d 100644 --- a/usr.sbin/mrouted/mapper.c +++ b/usr.sbin/mrouted/mapper.c @@ -1,7 +1,7 @@ /* Mapper for connections between MRouteD multicast routers. * Written by Pavel Curtis * - * $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; +{ +} diff --git a/usr.sbin/mrouted/mrinfo.c b/usr.sbin/mrouted/mrinfo.c index f4ccc86eb6d8..7335aba95cf9 100644 --- a/usr.sbin/mrouted/mrinfo.c +++ b/usr.sbin/mrouted/mrinfo.c @@ -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; +{ +} diff --git a/usr.sbin/mrouted/mrouted.8 b/usr.sbin/mrouted/mrouted.8 index 7dae5e38b2c6..6c4c7bd98616 100644 --- a/usr.sbin/mrouted/mrouted.8 +++ b/usr.sbin/mrouted/mrouted.8 @@ -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 , or to associate a non-default metric or threshold with the specified physical interface. -The local IP address may be alternatively replaced by the +The local IP address 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 and remote IP address , 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 may be replaced by the +interface name (e.g. le0). The remote IP address 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, diff --git a/usr.sbin/mrouted/mrouted.conf b/usr.sbin/mrouted/mrouted.conf index 4962d68e71f8..eb3bad3f4995 100644 --- a/usr.sbin/mrouted/mrouted.conf +++ b/usr.sbin/mrouted/mrouted.conf @@ -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 +x.yyy.zzz-zzzz" +#sysVersion "MyOS 4.1.3 and mrouted" +#sysLocation "The MBONE" diff --git a/usr.sbin/mrouted/mtrace.8 b/usr.sbin/mrouted/mtrace.8 index c4ac21866af7..5c8e1fe13465 100644 --- a/usr.sbin/mrouted/mtrace.8 +++ b/usr.sbin/mrouted/mtrace.8 @@ -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 diff --git a/usr.sbin/mrouted/mtrace.c b/usr.sbin/mrouted/mtrace.c index 321b2693092d..389084ae2416 100644 --- a/usr.sbin/mrouted/mtrace.c +++ b/usr.sbin/mrouted/mtrace.c @@ -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 #include -#include #include #include #include +#include #include "defs.h" #include #ifdef __STDC__ @@ -63,6 +66,9 @@ #else #include #endif +#ifdef SUNOS5 +#include +#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; +{ +} diff --git a/usr.sbin/mrouted/pathnames.h b/usr.sbin/mrouted/pathnames.h index 22b0019f089d..b3e3c88f8988 100644 --- a/usr.sbin/mrouted/pathnames.h +++ b/usr.sbin/mrouted/pathnames.h @@ -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" diff --git a/usr.sbin/mrouted/prune.c b/usr.sbin/mrouted/prune.c index f30b056d1fb1..fe3cdd5b4e14 100644 --- a/usr.sbin/mrouted/prune.c +++ b/usr.sbin/mrouted/prune.c @@ -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_gnext; - continue; + /* Check for traffic before deleting source entries */ + sg_req.grp.s_addr = gt->gt_mcastgrp; + stnp = >->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_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_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_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_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; diff --git a/usr.sbin/mrouted/prune.h b/usr.sbin/mrouted/prune.h index eef9d2842331..57ae067ce74f 100644 --- a/usr.sbin/mrouted/prune.h +++ b/usr.sbin/mrouted/prune.h @@ -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 $ */ /* diff --git a/usr.sbin/mrouted/route.c b/usr.sbin/mrouted/route.c index 38b9002982f0..c2b6b9e8b932 100644 --- a/usr.sbin/mrouted/route.c +++ b/usr.sbin/mrouted/route.c @@ -7,7 +7,7 @@ * Leland Stanford Junior University. * * - * $Id: route.c,v 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, diff --git a/usr.sbin/mrouted/route.h b/usr.sbin/mrouted/route.h index c947dd2da62a..73159d50261e 100644 --- a/usr.sbin/mrouted/route.h +++ b/usr.sbin/mrouted/route.h @@ -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 $ */ /* diff --git a/usr.sbin/mrouted/rsrr.c b/usr.sbin/mrouted/rsrr.c index c7bbc892379f..ea9628f55aea 100644 --- a/usr.sbin/mrouted/rsrr.c +++ b/usr.sbin/mrouted/rsrr.c @@ -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; diff --git a/usr.sbin/mrouted/vif.c b/usr.sbin/mrouted/vif.c index 98915aa5ac9c..3716292d1cab 100644 --- a/usr.sbin/mrouted/vif.c +++ b/usr.sbin/mrouted/vif.c @@ -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 - /* * 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); } diff --git a/usr.sbin/mrouted/vif.h b/usr.sbin/mrouted/vif.h index 57c1c8f14526..94f5f7a9ee7b 100644 --- a/usr.sbin/mrouted/vif.h +++ b/usr.sbin/mrouted/vif.h @@ -7,7 +7,7 @@ * Leland Stanford Junior University. * * - * $Id: vif.h,v 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 */ };