diff options
author | cvs2svn <cvs2svn@FreeBSD.org> | 1995-06-13 18:05:18 +0000 |
---|---|---|
committer | cvs2svn <cvs2svn@FreeBSD.org> | 1995-06-13 18:05:18 +0000 |
commit | bf0d1f50c5f34c3dfa7c01eb7208f8c1748a13d9 (patch) | |
tree | 989d74468ea768bfc8cc4b6fc42fcd3d9053c6f7 /usr.sbin | |
parent | 21876867d877dec1bf967dcd74dcfdd83a3ab69e (diff) | |
download | FreeBSD-src-bf0d1f50c5f34c3dfa7c01eb7208f8c1748a13d9.zip FreeBSD-src-bf0d1f50c5f34c3dfa7c01eb7208f8c1748a13d9.tar.gz |
This commit was manufactured by cvs2svn to create branch 'XEROX'.
Diffstat (limited to 'usr.sbin')
-rw-r--r-- | usr.sbin/mrouted/cfparse.y | 511 | ||||
-rw-r--r-- | usr.sbin/mrouted/map-mbone.8 | 97 | ||||
-rw-r--r-- | usr.sbin/mrouted/mrinfo.8 | 92 | ||||
-rw-r--r-- | usr.sbin/mrouted/mtrace.8 | 499 | ||||
-rw-r--r-- | usr.sbin/mrouted/pathnames.h | 25 | ||||
-rw-r--r-- | usr.sbin/mrouted/rsrr.c | 498 | ||||
-rw-r--r-- | usr.sbin/mrouted/rsrr.h | 138 | ||||
-rw-r--r-- | usr.sbin/mrouted/rsrr_var.h | 41 |
8 files changed, 1901 insertions, 0 deletions
diff --git a/usr.sbin/mrouted/cfparse.y b/usr.sbin/mrouted/cfparse.y new file mode 100644 index 0000000..5c1402f --- /dev/null +++ b/usr.sbin/mrouted/cfparse.y @@ -0,0 +1,511 @@ +%{ +/* + * Configuration file parser for mrouted. + * + * Written by Bill Fenner, NRL, 1994 + * + * $Id: cfparse.y,v 3.5 1995/05/09 01:00:39 fenner Exp $ + */ +#include <stdio.h> +#include <varargs.h> +#include "defs.h" + +static FILE *f; + +extern int udp_socket; +char *configfilename = _PATH_MROUTED_CONF; + +extern int cache_lifetime; +extern int max_prune_lifetime; + +static int lineno; +static struct ifreq ifbuf[32]; +static struct ifconf ifc; + +static struct uvif *v; + +static int order; + +struct addrmask { + u_int32 addr; + int mask; +}; + +struct boundnam { + char *name; + struct addrmask bound; +}; + +#define MAXBOUNDS 20 + +struct boundnam boundlist[MAXBOUNDS]; /* Max. of 20 named boundaries */ +int numbounds = 0; /* Number of named boundaries */ + +%} + +%union +{ + int num; + char *ptr; + struct addrmask addrmask; + u_int32 addr; +}; + +%token CACHE_LIFETIME PRUNING +%token PHYINT TUNNEL NAME +%token DISABLE METRIC THRESHOLD RATE_LIMIT SRCRT BOUNDARY NETMASK ALTNET +%token <num> BOOLEAN +%token <num> NUMBER +%token <ptr> STRING +%token <addrmask> ADDRMASK +%token <addr> ADDR + +%type <addr> interface +%type <addrmask> bound boundary addrmask + +%start conf + +%% + +conf : stmts + ; + +stmts : /* Empty */ + | stmts stmt + ; + +stmt : error + | PHYINT interface { + + vifi_t vifi; + + if (order) + fatal("phyints must appear before tunnels"); + + for (vifi = 0, v = uvifs; + vifi < numvifs; + ++vifi, ++v) + if (!(v->uv_flags & VIFF_TUNNEL) && + $2 == v->uv_lcl_addr) + break; + + if (vifi == numvifs) + fatal("%s is not a configured interface", + inet_fmt($2,s1)); + + /*log(LOG_INFO, 0, "phyint: %x\n", v);*/ + } + ifmods + | TUNNEL interface ADDR { + + struct ifreq *ifr; + struct ifreq ffr; + vifi_t vifi; + + order++; + + ifr = ifconfaddr(&ifc, $2); + if (ifr == 0) + fatal("Tunnel local address %s is not mine", + inet_fmt($2, s1)); + + strncpy(ffr.ifr_name, ifr->ifr_name, IFNAMSIZ); + if (ioctl(udp_socket, SIOCGIFFLAGS, (char *)&ffr)<0) + fatal("ioctl SIOCGIFFLAGS on %s",ffr.ifr_name); + if (ffr.ifr_flags & IFF_LOOPBACK) + fatal("Tunnel local address %s is a loopback interface", + inet_fmt($2, s1)); + + if (ifconfaddr(&ifc, $3) != 0) + fatal("Tunnel remote address %s is one of mine", + inet_fmt($3, s1)); + + for (vifi = 0, v = uvifs; + vifi < numvifs; + ++vifi, ++v) + if (v->uv_flags & VIFF_TUNNEL) { + if ($3 == v->uv_rmt_addr) + fatal("Duplicate tunnel to %s", + inet_fmt($3, s1)); + } else if (!(v->uv_flags & VIFF_DISABLED)) { + if (($3 & v->uv_subnetmask) == v->uv_subnet) + fatal("Unnecessary tunnel to %s", + inet_fmt($3,s1)); + } + + if (numvifs == MAXVIFS) + fatal("too many vifs"); + + v = &uvifs[numvifs]; + v->uv_flags = VIFF_TUNNEL; + v->uv_metric = DEFAULT_METRIC; + v->uv_rate_limit= DEFAULT_TUN_RATE_LIMIT; + v->uv_threshold = DEFAULT_THRESHOLD; + v->uv_lcl_addr = $2; + v->uv_rmt_addr = $3; + v->uv_subnet = 0; + v->uv_subnetmask= 0; + v->uv_subnetbcast= 0; + strncpy(v->uv_name, ffr.ifr_name, IFNAMSIZ); + v->uv_groups = NULL; + v->uv_neighbors = NULL; + v->uv_acl = NULL; + v->uv_addrs = NULL; + + if (!(ffr.ifr_flags & IFF_UP)) { + v->uv_flags |= VIFF_DOWN; + vifs_down = TRUE; + } + /*log(LOG_INFO, 0, "tunnel: %x\n", v);*/ + } + tunnelmods + { + log(LOG_INFO, 0, + "installing tunnel from %s to %s as vif #%u - rate=%d", + inet_fmt($2, s1), inet_fmt($3, s2), + numvifs, v->uv_rate_limit); + + ++numvifs; + } + | PRUNING BOOLEAN { pruning = $2; } + | CACHE_LIFETIME NUMBER { cache_lifetime = $2; + max_prune_lifetime = cache_lifetime * 2; + } + | NAME STRING boundary { if (numbounds >= MAXBOUNDS) { + fatal("Too many named boundaries (max %d)", MAXBOUNDS); + } + + boundlist[numbounds].name = malloc(strlen($2) + 1); + strcpy(boundlist[numbounds].name, $2); + boundlist[numbounds++].bound = $3; + } + ; + +tunnelmods : /* empty */ + | tunnelmods /*{ log(LOG_INFO, 0, "tunnelmod: %x", v); }*/ tunnelmod + ; + +tunnelmod : mod + | SRCRT { fatal("Source-route tunnels not supported"); } + ; + +ifmods : /* empty */ + | ifmods /*{ log(LOG_INFO, 0, "ifmod: %x", v); }*/ ifmod + ; + +ifmod : mod + | DISABLE { v->uv_flags |= VIFF_DISABLED; } + | NETMASK ADDR { v->uv_subnetmask = $2; } + | ALTNET addrmask { + + struct phaddr *ph; + + ph = (struct phaddr *)malloc(sizeof(struct phaddr)); + if (ph == NULL) + fatal("out of memory"); + if ($2.mask) { + VAL_TO_MASK(ph->pa_mask, $2.mask); + } else + ph->pa_mask = v->uv_subnetmask; + ph->pa_addr = $2.addr & ph->pa_mask; + if ($2.addr & ~ph->pa_mask) + warn("Extra addr %s/%d has host bits set", + inet_fmt($2.addr,s1), $2.mask); + ph->pa_next = v->uv_addrs; + v->uv_addrs = ph; + + } + ; + +mod : THRESHOLD NUMBER { if ($2 < 1 || $2 > 255) + fatal("Invalid threshold %d",$2); + v->uv_threshold = $2; + } + | THRESHOLD { + + warn("Expected number after threshold keyword"); + + } + | METRIC NUMBER { if ($2 < 1 || $2 > UNREACHABLE) + fatal("Invalid metric %d",$2); + v->uv_metric = $2; + } + | METRIC { + + warn("Expected number after metric keyword"); + + } + | RATE_LIMIT NUMBER { if ($2 > MAX_RATE_LIMIT) + fatal("Invalid rate_limit %d",$2); + v->uv_rate_limit = $2; + } + | RATE_LIMIT { + + warn("Expected number after rate_limit keyword"); + + } + | BOUNDARY bound { + + struct vif_acl *v_acl; + + v_acl = (struct vif_acl *)malloc(sizeof(struct vif_acl)); + if (v_acl == NULL) + fatal("out of memory"); + VAL_TO_MASK(v_acl->acl_mask, $2.mask); + v_acl->acl_addr = $2.addr & v_acl->acl_mask; + if ($2.addr & ~v_acl->acl_mask) + warn("Boundary spec %s/%d has host bits set", + inet_fmt($2.addr,s1),$2.mask); + v_acl->acl_next = v->uv_acl; + v->uv_acl = v_acl; + + } + | BOUNDARY { + + warn("Expected boundary spec after boundary keyword"); + + } + ; + +interface : ADDR { $$ = $1; } + | STRING { + $$ = valid_if($1); + if ($$ == 0) + fatal("Invalid interface name %s",$1); + } + ; + +bound : boundary { $$ = $1; } + | STRING { int i; + + for (i=0; i < numbounds; i++) { + if (!strcmp(boundlist[i].name, $1)) { + $$ = boundlist[i].bound; + break; + } + } + if (i == numbounds) { + fatal("Invalid boundary name %s",$1); + } + } + ; + +boundary : ADDRMASK { + + if ((ntohl($1.addr) & 0xff000000) != 0xef000000) { + fatal("Boundaries must be 239.x.x.x, not %s/%d", + inet_fmt($1.addr, s1), $1.mask); + } + $$ = $1; + + } + ; + +addrmask : ADDRMASK { $$ = $1; } + | ADDR { $$.addr = $1; $$.mask = 0; } + ; +%% +/*VARARGS1*/ +static void fatal(fmt, va_alist) +char *fmt; +va_dcl +{ + va_list ap; + char buf[200]; + + va_start(ap); + vsprintf(buf, fmt, ap); + va_end(ap); + + log(LOG_ERR,0,"%s: %s near line %d", configfilename, buf, lineno); +} + +/*VARARGS1*/ +static void warn(fmt, va_alist) +char *fmt; +va_dcl +{ + va_list ap; + char buf[200]; + + va_start(ap); + vsprintf(buf, fmt, ap); + va_end(ap); + + log(LOG_WARNING,0,"%s: %s near line %d", configfilename, buf, lineno); +} + +void yyerror(s) +char *s; +{ + log(LOG_ERR, 0, "%s: %s near line %d", configfilename, s, lineno); +} + +char *next_word() +{ + static char buf[1024]; + static char *p=NULL; + extern FILE *f; + char *q; + + while (1) { + if (!p || !*p) { + lineno++; + if (fgets(buf, sizeof(buf), f) == NULL) + return NULL; + p = buf; + } + while (*p && (*p == ' ' || *p == '\t')) /* skip whitespace */ + p++; + if (*p == '#') { + p = NULL; /* skip comments */ + continue; + } + q = p; + while (*p && *p != ' ' && *p != '\t' && *p != '\n') + p++; /* find next whitespace */ + *p++ = '\0'; /* null-terminate string */ + + if (!*q) { + p = NULL; + continue; /* if 0-length string, read another line */ + } + + return q; + } +} + +int yylex() +{ + int n; + u_int32 addr; + char *q; + + if ((q = next_word()) == NULL) { + return 0; + } + + if (!strcmp(q,"cache_lifetime")) + return CACHE_LIFETIME; + if (!strcmp(q,"pruning")) + return PRUNING; + if (!strcmp(q,"phyint")) + return PHYINT; + if (!strcmp(q,"tunnel")) + return TUNNEL; + if (!strcmp(q,"disable")) + return DISABLE; + if (!strcmp(q,"metric")) + return METRIC; + if (!strcmp(q,"threshold")) + return THRESHOLD; + if (!strcmp(q,"rate_limit")) + return RATE_LIMIT; + if (!strcmp(q,"srcrt") || !strcmp(q,"sourceroute")) + return SRCRT; + if (!strcmp(q,"boundary")) + return BOUNDARY; + if (!strcmp(q,"netmask")) + return NETMASK; + if (!strcmp(q,"name")) + return NAME; + if (!strcmp(q,"altnet")) + return ALTNET; + if (!strcmp(q,"on") || !strcmp(q,"yes")) { + yylval.num = 1; + return BOOLEAN; + } + if (!strcmp(q,"off") || !strcmp(q,"no")) { + yylval.num = 0; + return BOOLEAN; + } + if (sscanf(q,"%[.0-9]/%d%c",s1,&n,s2) == 2) { + if ((addr = inet_parse(s1)) != 0xffffffff) { + yylval.addrmask.mask = n; + yylval.addrmask.addr = addr; + return ADDRMASK; + } + /* fall through to returning STRING */ + } + if (sscanf(q,"%[.0-9]%c",s1,s2) == 1) { + if ((addr = inet_parse(s1)) != 0xffffffff && + inet_valid_host(addr)) { + yylval.addr = addr; + return ADDR; + } + } + if (sscanf(q,"0x%8x%c",&n,s1) == 1) { + yylval.addr = n; + return ADDR; + } + if (sscanf(q,"%d%c",&n,s1) == 1) { + yylval.num = n; + return NUMBER; + } + yylval.ptr = q; + return STRING; +} + +void config_vifs_from_file() +{ + extern FILE *f; + + order = 0; + numbounds = 0; + lineno = 0; + + if ((f = fopen(configfilename, "r")) == NULL) { + if (errno != ENOENT) + log(LOG_ERR, errno, "can't open %s", configfilename); + return; + } + + ifc.ifc_buf = (char *)ifbuf; + ifc.ifc_len = sizeof(ifbuf); + if (ioctl(udp_socket, SIOCGIFCONF, (char *)&ifc) < 0) + log(LOG_ERR, errno, "ioctl SIOCGIFCONF"); + + yyparse(); + + close(f); +} + +static u_int32 +valid_if(s) +char *s; +{ + register vifi_t vifi; + register struct uvif *v; + + for (vifi=0, v=uvifs; vifi<numvifs; vifi++, v++) + if (!strcmp(v->uv_name, s)) + return v->uv_lcl_addr; + + return 0; +} + +static struct ifreq * +ifconfaddr(ifcp, a) + struct ifconf *ifcp; + u_int32 a; +{ + int n; + struct ifreq *ifrp = (struct ifreq *)ifcp->ifc_buf; + struct ifreq *ifend = (struct ifreq *)((char *)ifrp + ifcp->ifc_len); + + while (ifrp < ifend) { + if (ifrp->ifr_addr.sa_family == AF_INET && + ((struct sockaddr_in *)&ifrp->ifr_addr)->sin_addr.s_addr == a) + return (ifrp); +#if (defined(BSD) && (BSD >= 199006)) + n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name); + if (n < sizeof(*ifrp)) + ++ifrp; + else + ifrp = (struct ifreq *)((char *)ifrp + n); +#else + ++ifrp; +#endif + } + return (0); +} diff --git a/usr.sbin/mrouted/map-mbone.8 b/usr.sbin/mrouted/map-mbone.8 new file mode 100644 index 0000000..41eb808 --- /dev/null +++ b/usr.sbin/mrouted/map-mbone.8 @@ -0,0 +1,97 @@ +.Dd March 31, 1995 +.Dt MAP-MBONE 8 +.Os FreeBSD 2.0 +.Sh NAME +.Nm map-mbone +.Nd multicast connection mapper +.Sh SYNOPSIS +.Nm map-mbone +.Op Fl d Ar debuglevel +.Op Fl f +.Op Fl g +.Op Fl n +.Op Fl r Ar retries +.Op Fl t Ar timeout +.Op Ar router +.Sh DESCRIPTION +.Nm map-mbone +attempts to display all multicast routers that are reachable from the multicast +router +.Ar router . +If not specified on the command line, the default +.Ar router +is the local host. +.Nm +traverses neighboring multicast routers by sending the +.Dv ASK_NEIGHBORS +.Tn IGMP +message to each router. If this multicast router responds, the version +number and a list of their neighboring multicast router addresses is +part of that response. If the responding router has recent multicast +version number, then +.Nm +requests additional information such as metrics, thresholds, and flags from the +multicast router. For each new occurrence of neighboring multicast router in +the reply and provided the flooding option has been selected, then +.Nm +asks each of this multicast router for a list of neighbors. This search +for unique routers will continue until no new neighboring multicast routers +are reported. +.Pp +The options supported by +.Nm +are as follows: +.Bl -tag -width XXXdebuglevel +.It Fl d Ar debuglevel +This sets the debug level to +.Ar debuglevel . +When the debug level is greater than the default value of 0, +additional debugging messages are printed. Regardless of the debug +level, an error condition, will always write an error message and will +cause +.I map-mbone +to terminate. +Non-zero debug levels have the following effects: +.Bl -tag -width "level 3" +.It level 1 +packet warnings are printed to stderr. +.It level 2 +all level 1 messages plus notifications down networks are printed to stderr. +.It level 3 +all level 2 messages plus notifications of all packet +timeouts are printed to stderr. +.El +.It Fl f +This option enables flooding. Flooding allows +.Nm +to perform recursive search +of neighboring multicast routers and is enabled by default when an +initial +.Ar router +is not specified. +.It Fl g +This option enables graphing in GraphEd format. +.It Fl n +This option disables the DNS lookup for the multicast routers' names. +.It Fl r Ar retries +This options sets the neighbor query retry limit to +.Ar retries . +The default is one retry. +.It Fl t Ar timeout +This option sets the number of seconds to wait for a neighbor query +reply before retrying. The default timeout is two seconds. +.Sh RESTRICTIONS +.Nm +must be run as `root'. +.Sh SEE ALSO +.Xr mrinfo 8 , +.Xr mrouted 8 , +.Xr mtrace 8 +.Sh AUTHOR +Pavel Curtis +.Sh HISTORY +A +.Nm +command first appeared in +.Tn FreeBSD +2.0. diff --git a/usr.sbin/mrouted/mrinfo.8 b/usr.sbin/mrouted/mrinfo.8 new file mode 100644 index 0000000..b1e7880 --- /dev/null +++ b/usr.sbin/mrouted/mrinfo.8 @@ -0,0 +1,92 @@ +.Dd March 31, 1995 +.Dt MRINFO 8 +.Sh NAME +.Nm mrinfo +.Nd displays configuration info from a multicast router +.Sh SYNOPSIS +.Nm mrinfo +.Op Fl d Ar debuglevel +.Op Fl r Ar retries +.Op Fl t Ar timeout +.Ar router +.Sh DESCRIPTION +The +.Nm mrinfo +program attempts to display the configuration information from the +multicast router +.Ar router . +.Pp +.Nm +uses the +.Dv ASK_NEIGHBORS +.Tn IGMP +message to the specified multicast router. If this multicast router +responds, the version number and a list of their neighboring multicast +router addresses is part of that response. If the responding router +has a recent multicast version number, then +.Nm mrinfo +requests additional information such as metrics, thresholds, and flags +from the multicast router. Once the specified multicast router +responds, the configuration is displayed to the standard output. +.Pp +The +.Nm +program accepts the following options: +.Bl -tag -width XXXdebuglevel +.It Fl d Ar debuglevel +This option sets the debug level to +.Ar debuglevel . +When the debug level is greater than the default value of 0, addition +debugging messages are printed. Regardless of the debug level, an +error condition, will always write an error message and will cause +.Nm +to terminate. +Non-zero debug levels have the following effects: +.Bl -tag -width "level 3" +.It level 1 +packet warnings are printed to stderr. +.It level 2 +all level 1 messages plus notifications down networks are printed to stderr. +.It level 3 +all level 2 messages plus notifications of all packet +timeouts are printed to stderr. +.El +.It Fl r Ar retries +This option sets the neighbor query retry limit to +.Ar retries . +The default is three retries. +.It Fl t Ar timeout +This sets the number of seconds to wait for a neighbor query +reply. The default timeout is four seconds. +.El +.Sh SAMPLE OUTPUT +.Bd -literal +# mrinfo mbone.phony.dom.net +127.148.176.10 (mbone.phony.dom.net) [version 3.3]: + 127.148.176.10 -> 0.0.0.0 (?) [1/1/querier] + 127.148.176.10 -> 127.0.8.4 (mbone2.phony.dom.net) [1/45/tunnel] + 127.148.176.10 -> 105.1.41.9 (momoney.com) [1/32/tunnel/down] + 127.148.176.10 -> 143.192.152.119 (mbone.dipu.edu) [1/32/tunnel] +.Ed +.Pp +For each neighbor of the queried multicast router, the IP of the +queried router is displayed, followed by the IP and name of the +neighbor. In square brackets the metric (cost of connection) and the +threshold (minimum TTL to forward) are displayed. If the queried multicast +router has a newer version number, the type (tunnel, srcrt) and status +(disabled, down) of the connection are also displayed. +.Sh RESTRICTIONS +.Nm +must be run as `root'. +.Sh SEE ALSO +.Xr map-mbone 8 , +.Xr mrouted 8 , +.Xr mtrace 8 +.Sh AUTHOR +Pavel Curtis +.Sh HISTORY +An +.Nm +command first appeared in +.Tn FreeBSD +2.0. diff --git a/usr.sbin/mrouted/mtrace.8 b/usr.sbin/mrouted/mtrace.8 new file mode 100644 index 0000000..bfc6dd5 --- /dev/null +++ b/usr.sbin/mrouted/mtrace.8 @@ -0,0 +1,499 @@ +.\" Copyright (c) 1995 by the University of Southern California +.\" All rights reserved. +.\" +.\" Permission to use, copy, modify, and distribute this software and its +.\" documentation in source and binary forms for non-commercial purposes +.\" and without fee is hereby granted, provided that the above copyright +.\" notice appear in all copies and that both the copyright notice and +.\" this permission notice appear in supporting documentation, and that +.\" any documentation, advertising materials, and other materials related +.\" to such distribution and use acknowledge that the software was +.\" developed by the University of Southern California, Information +.\" Sciences Institute. The name of the University may not be used to +.\" endorse or promote products derived from this software without +.\" specific prior written permission. +.\" +.\" THE UNIVERSITY OF SOUTHERN CALIFORNIA makes no representations about +.\" the suitability of this software for any purpose. THIS SOFTWARE IS +.\" PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, +.\" INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.\" Other copyrights might apply to parts of this software and are so +.\" noted when applicable. +.\" +.\" This manual page (but not the software) was derived from the +.\" manual page for the traceroute program which bears the following +.\" copyright notice: +.\" +.\" Copyright (c) 1988 The Regents of the University of California. +.\" All rights reserved. +.\" +.\" $Id: mtrace.8,v 3.5 1995/05/09 01:23:58 fenner Exp $ +.\" +.TH MTRACE 8 "May 8, 1995" +.UC 6 +.SH NAME +mtrace \- print multicast path from a source to a receiver +.SH SYNOPSIS +.B mtrace +[ +.B \-g +.I gateway +] [ +.B \-i +.I if_addr +] [ +.B \-l +] [ +.B \-M +] [ +.B \-m +.I max_hops +] [ +.B \-n +] [ +.B \-p +] [ +.B \-q +.I nqueries +] [ +.B \-r +.I resp_dest +] [ +.B \-s +.I src_addr +] [ +.B \-t +.I ttl +] [ +.B \-w +.I waittime +] +.I source +[ +.I receiver +] [ +.I group +] +.SH DESCRIPTION +Assessing problems in the distribution of IP multicast traffic +can be difficult. +.B mtrace +utilizes a tracing feature implemented in multicast routers +.RB ( mrouted +version 3.3 and later) that is +accessed via an extension to the IGMP protocol. A trace query is +passed hop-by-hop along the reverse path from the +.I receiver +to the +.IR source , +collecting hop addresses, packet counts, and routing error conditions +along the path, and then the response is returned to the requestor. +.PP +The only required parameter is the +.I source +host name or address. The default +.I receiver +is the host running mtrace, and the default +.I group +is "MBone Audio" (224.2.0.1), which is sufficient if packet loss +statistics for a particular multicast group are not needed. These two +optional parameters may be specified to test the path to some other +receiver in a particular group, subject to some constraints as +detailed below. The two parameters can be distinguished because the +.I receiver +is a unicast address and the +.I group +is a multicast address. +.SH OPTIONS +.TP 8 8 +.BI \-g\ gwy +Send the trace query via unicast directly to the multicast router +.I gwy +rather than multicasting the query. +This must be the last-hop router on the path from the intended +.I source +to the +.IR receiver . +.RS 8 +.TP 12 12 +.I CAUTION!! +Version 3.3 of +.B mrouted +will crash if a trace query is received via a +unicast packet and +.B mrouted +has no route for the +.I source +address. Therefore, do not use the +.B \-g +option unless the target +.B mrouted +has been verified to be newer than 3.3. +.RE +.TP 8 8 +.BI \-i\ addr +Use +.I addr +as the local interface address (on a multi-homed host) for sending the +trace query and as the default for the +.I receiver +and the response destination. +.TP 8 8 +.B \-l +Loop indefinitely printing packet rate and loss statistics for the +multicast path every 10 seconds. +.TP 8 8 +.B \-M +Always send the response using multicast rather than attempting +unicast first. +.TP 8 8 +.BI \-m\ n +Set to +.I n +the maximum number of hops that will be traced from the +.I receiver +back toward the +.IR source . +The default is 32 hops (infinity for the DVMRP routing protocol). +.TP 8 8 +.B \-n +Print hop addresses numerically rather than symbolically and numerically +(saves a nameserver address-to-name lookup for each router found on the +path). +.TP 8 8 +.BI \-q\ n +Set the maximum number of query attempts for any hop to +.IR n . +The default is 3. +.TP 8 8 +.B \-p +Listen passively for multicast responses from traces initiated by +others (not implemented yet). +.TP 8 8 +.BI \-r\ host +Send the trace response to +.I host +rather than to the host on which +.B mtrace +is being run, or to a multicast address other than the one registered +for this purpose (224.0.1.32). +.TP 8 8 +.B \-s +Print a short form output including only the multicast path and not +the packet rate and loss statistics. +.TP 8 8 +.BI \-t\ ttl +Set the +.I ttl +(time-to-live, or number of hops) for multicast trace queries and +responses. The default is 64, except for local queries to the "all +routers" multicast group which use ttl 1. +.TP 8 8 +.BI \-w\ n +Set the time to wait for a trace response to +.I n +seconds (default 3 seconds). +.SH USAGE +.SS How It Works +The technique used by the +.B traceroute +tool to trace unicast network paths will not work for IP multicast +because ICMP responses are specifically forbidden for multicast traffic. +Instead, a tracing feature has been built into the multicast routers. +This technique has the advantage that additional information about +packet rates and losses can be accumulated while the number of packets +sent is minimized. +.PP +Since multicast uses +reverse path forwarding, the trace is run backwards from the +.I receiver +to the +.IR source . +A trace query packet is sent to the last +hop multicast router (the leaf router for the desired +.I receiver +address). The last hop router builds a trace response packet, fills in +a report for its hop, and forwards the trace packet using unicast to +the router it believes is the previous hop for packets originating +from the specified +.IR source . +Each router along the path adds its report and forwards the packet. +When the trace response packet reaches the first hop router (the router +that is directly connected to the source's net), that router sends the +completed response to the response destination address specified in +the trace query. +.PP +If some multicast router along the path does not implement the +multicast traceroute feature or if there is some outage, then no +response will be returned. To solve this problem, the trace query +includes a maximum hop count field to limit the number of hops traced +before the response is returned. That allows a partial path to be +traced. +.PP +The reports inserted by each router contain not only the address of +the hop, but also the ttl required to forward and some flags to indicate +routing errors, plus counts of the total number of packets on the +incoming and outgoing interfaces and those forwarded for the specified +.IR group . +Taking differences in these counts for two traces separated in time +and comparing the output packet counts from one hop with the input +packet counts of the next hop allows the calculation of packet rate +and packet loss statistics for each hop to isolate congestion +problems. +.SS Finding the Last-Hop Router +The trace query must be sent to the multicast router which is the +last hop on the path from the +.I source +to the +.IR receiver . +If the receiver is on the local subnet (as determined using the subnet +mask), then the default method is to multicast the trace query to +all-routers.mcast.net (224.0.0.2) with a ttl of 1. Otherwise, the +trace query is multicast to the +.I group +address since the last hop router will be a member of that group if +the receiver is. Therefore it is necessary to specify a group that +the intended receiver has joined. This multicast is sent with a +default ttl of 64, which may not be sufficient for all cases (changed +with the +.B \-t +option). +If the last hop router is known, it may also be addressed directly +using the +.B \-g +option). Alternatively, if it is desired to trace a group that the +receiver has not joined, but it is known that the last-hop router is a +member of another group, the +.B \-g +option may also be used to specify a different multicast address for the +trace query. +.PP +When tracing from a multihomed host or router, the default receiver +address may not be the desired interface for the path from the source. +In that case, the desired interface should be specified explicitly as +the +.IR receiver . +.SS Directing the Response +By default, +.B mtrace +first attempts to trace the full reverse path, unless the number of +hops to trace is explicitly set with the +.B \-m +option. If there is no response within a 3 second timeout interval +(changed with the +.B \-w +option), a "*" is printed and the probing switches to hop-by-hop mode. +Trace queries are issued starting with a maximum hop count of one and +increasing by one until the full path is traced or no response is +received. At each hop, multiple probes are sent (default is three, +changed with +.B \-q +option). The first half of the attempts (default is one) are made with +the unicast address of the host running +.B mtrace +as the destination for the response. Since the unicast route may be +blocked, the remainder of attempts request that the response be +multicast to mtrace.mcast.net (224.0.1.32) with the ttl set to 32 more +than what's needed to pass the thresholds seen so far along the path +to the receiver. For the last quarter of the attempts (default is +one), the ttl is increased by another 32 each time up to a maximum of +192. Alternatively, the ttl may be set explicity with the +.B \-t +option and/or the initial unicast attempts can be forced to use +multicast instead with the +.B \-M +option. For each attempt, if no response is received within the +timeout, a "*" is printed. After the specified number of attempts +have failed, +.B mtrace +will try to query the next hop router with a DVMRP_ASK_NEIGHBORS2 +request (as used by the +.B mrinfo +program) to see what kind of router it is. +.SH EXAMPLES +The output of +.B mtrace +is in two sections. The first section is a short listing of the hops +in the order they are queried, that is, in the reverse of the order +from the +.I source +to the +.IR receiver . +For each hop, a line is printed showing the hop number (counted +negatively to indicate that this is the reverse path); the multicast +routing protocol (DVMRP, MOSPF, PIM, etc.); the threshold required to +forward data (to the previous hop in the listing as indicated by the +up-arrow character); and the cumulative delay for the query to reach +that hop (valid only if the clocks are synchronized). This first +section ends with a line showing the round-trip time which measures +the interval from when the query is issued until the response is +received, both derived from the local system clock. A sample use and +output might be: +.PP +.nf +.ft C +oak.isi.edu 80# mtrace -l caraway.lcs.mit.edu 224.2.0.3 +Mtrace from 18.26.0.170 to 128.9.160.100 via group 224.2.0.3 +Querying full reverse path... + 0 oak.isi.edu (128.9.160.100) + -1 cub.isi.edu (128.9.160.153) DVMRP thresh^ 1 3 ms + -2 la.dart.net (140.173.128.1) DVMRP thresh^ 1 14 ms + -3 dc.dart.net (140.173.64.1) DVMRP thresh^ 1 50 ms + -4 bbn.dart.net (140.173.32.1) DVMRP thresh^ 1 63 ms + -5 mit.dart.net (140.173.48.2) DVMRP thresh^ 1 71 ms + -6 caraway.lcs.mit.edu (18.26.0.170) +Round trip time 124 ms +.fi +.PP +The second section provides a pictorial view of the path in the +forward direction with data flow indicated by arrows pointing downward +and the query path indicated by arrows pointing upward. For each hop, +both the entry and exit addresses of the router are shown if +different, along with the initial ttl required on the packet in order +to be forwarded at this hop and the propagation delay across the hop +assuming that the routers at both ends have synchronized clocks. The +right half of this section is composed of several columns of +statistics in two groups. Within each group, the columns are the +number of packets lost, the number of packets sent, the percentage +lost, and the average packet rate at each hop. These statistics are +calculated from differences between traces and from hop to hop as +explained above. The first group shows the statistics for all traffic +flowing out the interface at one hop and in the interface at the next +hop. The second group shows the statistics only for traffic forwarded +from the specified +.I source +to the specified +.IR group . +.PP +These statistics are shown on one or two lines for each hop. Without +any options, this second section of the output is printed only once, +approximately 10 seconds after the initial trace. One line is shown +for each hop showing the statistics over that 10-second period. If +the +.B \-l +option is given, the second section is repeated every 10 seconds and +two lines are shown for each hop. The first line shows the statistics +for the last 10 seconds, and the second line shows the cumulative +statistics over the period since the initial trace, which is 101 +seconds in the example below. The second section of the output is +omitted if the +.B \-s +option is set. +.ie t \{\ +.ft C +. ie \w'i'<>\w'm' \{\" looks like this is not proper Courier font +(If this example is not properly columned with a fixed-width font, get +.B groff +and try again.) +. \} +.\} +.PP +.ft C +.nf +Waiting to accumulate statistics... Results after 101 seconds: + + Source Response Dest Packet Statistics For Only For Traffic +18.26.0.170 128.9.160.100 All Multicast Traffic From 18.26.0.170 + | __/ rtt 125 ms Lost/Sent = Pct Rate To 224.2.0.3 + v / hop 65 ms --------------------- ------------------ +18.26.0.144 +140.173.48.2 mit.dart.net + | ^ ttl 1 0/6 = --% 0 pps 0/2 = --% 0 pps + v | hop 8 ms 1/52 = 2% 0 pps 0/18 = 0% 0 pps +140.173.48.1 +140.173.32.1 bbn.dart.net + | ^ ttl 2 0/6 = --% 0 pps 0/2 = --% 0 pps + v | hop 12 ms 1/52 = 2% 0 pps 0/18 = 0% 0 pps +140.173.32.2 +140.173.64.1 dc.dart.net + | ^ ttl 3 0/271 = 0% 27 pps 0/2 = --% 0 pps + v | hop 34 ms -1/2652 = 0% 26 pps 0/18 = 0% 0 pps +140.173.64.2 +140.173.128.1 la.dart.net + | ^ ttl 4 -2/831 = 0% 83 pps 0/2 = --% 0 pps + v | hop 11 ms -3/8072 = 0% 79 pps 0/18 = 0% 0 pps +140.173.128.2 +128.9.160.153 cub.isi.edu + | \\__ ttl 5 833 83 pps 2 0 pps + v \\ hop -8 ms 8075 79 pps 18 0 pps +128.9.160.100 128.9.160.100 + Receiver Query Source +.fi +.PP +Because the packet counts may be changing as the trace query is +propagating, there may be small errors (off by 1 or 2) in these +statistics. However, those errors should not accumulate, so the +cumulative statistics line should increase in accuracy as a new trace +is run every 10 seconds. There are two sources of larger errors, both +of which show up as negative losses: +.LP +.RS +.PD 0 +.TP 3 +\(bu +If the input to a node is from a multi-access network with more than +one other node attached, then the input count will be (close to) the +sum of the output counts from all the attached nodes, but the output +count from the previous hop on the traced path will be only part of +that. Hence the output count minus the input count will be negative. +.TP 3 +\(bu +In release 3.3 of the DVMRP multicast forwarding software for SunOS +and other systems, a multicast packet generated on a router will be +counted as having come in an interface even though it did not. This +creates the negative loss that can be seen in the example above. +.PD +.RE +.LP +Note that these negative losses may mask positive losses. +.PP +In the example, there is also one negative hop time. This simply +indicates a lack of synchronization between the system clocks across +that hop. This example also illustrates how the percentage loss is +shown as two dashes when the number of packets sent is less than 10 +because the percentage would not be statistically valid. +.PP +A second example shows a trace to a receiver that is not local; the +query is sent to the last-hop router with the +.B \-g +option. In this example, the trace of the full reverse path resulted +in no response because there was a node running an old version of +.B mrouted +that did not implement the multicast traceroute function, so +.B mtrace +switched to hop-by-hop mode. The \*(lqRoute pruned\*(rq error code +indicates that traffic for group 224.2.143.24 would not be forwarded. +.PP +.nf +.ft C +oak.isi.edu 108# mtrace -g 140.173.48.2 204.62.246.73 \\ + butter.lcs.mit.edu 224.2.143.24 +Mtrace from 204.62.246.73 to 18.26.0.151 via group 224.2.143.24 +Querying full reverse path... * switching to hop-by-hop: + 0 butter.lcs.mit.edu (18.26.0.151) + -1 jam.lcs.mit.edu (18.26.0.144) DVMRP thresh^ 1 33 ms Route pruned + -2 bbn.dart.net (140.173.48.1) DVMRP thresh^ 1 36 ms + -3 dc.dart.net (140.173.32.2) DVMRP thresh^ 1 44 ms + -4 darpa.dart.net (140.173.240.2) DVMRP thresh^ 16 47 ms + -5 * * * noc.hpc.org (192.187.8.2) [mrouted 2.2] didn't respond +Round trip time 95 ms +.fi +.SH AUTHOR +Implemented by Steve Casner based on an initial prototype written by +Ajit Thyagarajan. The multicast traceroute mechanism was designed by +Van Jacobson with help from Steve Casner, Steve Deering, Dino +Farinacci, and Deb Agrawal; it was implemented in +.B mrouted +by Ajit Thyagarajan and Bill Fenner. The option syntax and the output +format of +.B mtrace +are modeled after the unicast +.B traceroute +program written by Van Jacobson. +.SH SEE ALSO +.BR mrouted (8) , +.BR mrinfo (8) , +.BR map-mbone (8) , +.BR traceroute (8) diff --git a/usr.sbin/mrouted/pathnames.h b/usr.sbin/mrouted/pathnames.h new file mode 100644 index 0000000..2022314 --- /dev/null +++ b/usr.sbin/mrouted/pathnames.h @@ -0,0 +1,25 @@ +/* + * The mrouted program is covered by the license in the accompanying file + * named "LICENSE". Use of the mrouted program represents acceptance of + * the terms and conditions listed in that file. + * + * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of + * Leland Stanford Junior University. + * + * + * $Id: pathnames.h,v 3.5 1995/05/09 01:00:39 fenner Exp $ + */ + +#define _PATH_MROUTED_CONF "/etc/mrouted.conf" + +#if (defined(BSD) && (BSD >= 199103)) +#define _PATH_MROUTED_PID "/var/run/mrouted.pid" +#define _PATH_MROUTED_GENID "/var/run/mrouted.genid" +#define _PATH_MROUTED_DUMP "/var/tmp/mrouted.dump" +#define _PATH_MROUTED_CACHE "/var/tmp/mrouted.cache" +#else +#define _PATH_MROUTED_PID "/etc/mrouted.pid" +#define _PATH_MROUTED_GENID "/etc/mrouted.genid" +#define _PATH_MROUTED_DUMP "/usr/tmp/mrouted.dump" +#define _PATH_MROUTED_CACHE "/usr/tmp/mrouted.cache" +#endif diff --git a/usr.sbin/mrouted/rsrr.c b/usr.sbin/mrouted/rsrr.c new file mode 100644 index 0000000..34eedab --- /dev/null +++ b/usr.sbin/mrouted/rsrr.c @@ -0,0 +1,498 @@ +/* + * Copyright (c) 1993 by the University of Southern California + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation in source and binary forms for non-commercial purposes + * and without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both the copyright notice and + * this permission notice appear in supporting documentation. and that + * any documentation, advertising materials, and other materials related + * to such distribution and use acknowledge that the software was + * developed by the University of Southern California, Information + * Sciences Institute. The name of the University may not be used to + * endorse or promote products derived from this software without + * specific prior written permission. + * + * THE UNIVERSITY OF SOUTHERN CALIFORNIA makes no representations about + * the suitability of this software for any purpose. THIS SOFTWARE IS + * PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Other copyrights might apply to parts of this software and are so + * noted when applicable. + */ + +/* RSRR code written by Daniel Zappala, USC Information Sciences Institute, + * April 1995. + */ + +/* May 1995 -- Added support for Route Change Notification */ + +#ifdef RSRR + +#include "defs.h" + +/* Taken from prune.c */ +/* + * checks for scoped multicast addresses + */ +#define GET_SCOPE(gt) { \ + register int _i; \ + if (((gt)->gt_mcastgrp & 0xff000000) == 0xef000000) \ + for (_i = 0; _i < numvifs; _i++) \ + if (scoped_addr(_i, (gt)->gt_mcastgrp)) \ + VIFM_SET(_i, (gt)->gt_scope); \ + } + +/* + * Exported variables. + */ +int rsrr_socket; /* interface to reservation protocol */ + +/* + * Global RSRR variables. + */ +char rsrr_recv_buf[RSRR_MAX_LEN]; /* RSRR receive buffer */ +char rsrr_send_buf[RSRR_MAX_LEN]; /* RSRR send buffer */ + +struct sockaddr_un client_addr; +int client_length = sizeof(client_addr); + + +/* + * Procedure definitions needed internally. + */ +void rsrr_accept(); +void rsrr_accept_iq(); +int rsrr_accept_rq(); +int rsrr_send(); +void rsrr_cache(); + +/* Initialize RSRR socket */ +void +rsrr_init() +{ + int servlen; + struct sockaddr_un serv_addr; + + if ((rsrr_socket = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) + log(LOG_ERR, errno, "Can't create RSRR socket"); + + unlink(RSRR_SERV_PATH); + bzero((char *) &serv_addr, sizeof(serv_addr)); + serv_addr.sun_family = AF_UNIX; + strcpy(serv_addr.sun_path, RSRR_SERV_PATH); + servlen = sizeof(serv_addr.sun_family) + strlen(serv_addr.sun_path); + + if (bind(rsrr_socket, (struct sockaddr *) &serv_addr, servlen) < 0) + log(LOG_ERR, errno, "Can't bind RSRR socket"); + + if (register_input_handler(rsrr_socket,rsrr_read) < 0) + log(LOG_WARNING, 0, "Couldn't register RSRR as an input handler"); +} + +/* Read a message from the RSRR socket */ +void +rsrr_read() +{ + register int rsrr_recvlen; + register int omask; + + bzero((char *) &client_addr, sizeof(client_addr)); + rsrr_recvlen = recvfrom(rsrr_socket, rsrr_recv_buf, sizeof(rsrr_recv_buf), + 0, (struct sockaddr *)&client_addr,&client_length); + if (rsrr_recvlen < 0) { + if (errno != EINTR) + log(LOG_ERR, errno, "RSRR recvfrom"); + return; + } + /* Use of omask taken from main() */ + omask = sigblock(sigmask(SIGALRM)); + rsrr_accept(rsrr_recvlen); + (void)sigsetmask(omask); +} + +/* Accept a message from the reservation protocol and take + * appropriate action. + */ +void +rsrr_accept(recvlen) + int recvlen; +{ + struct rsrr_header *rsrr; + struct rsrr_rq *route_query; + + if (recvlen < RSRR_HEADER_LEN) { + log(LOG_WARNING, 0, + "Received RSRR packet of %d bytes, which is less than min size", + recvlen); + return; + } + + rsrr = (struct rsrr_header *) rsrr_recv_buf; + + if (rsrr->version > RSRR_MAX_VERSION) { + log(LOG_WARNING, 0, + "Received RSRR packet version %d, which I don't understand", + rsrr->version); + return; + } + + switch (rsrr->version) { + case 1: + switch (rsrr->type) { + case RSRR_INITIAL_QUERY: + /* Send Initial Reply to client */ + log(LOG_INFO, 0, "Received Initial Query\n"); + rsrr_accept_iq(); + break; + case RSRR_ROUTE_QUERY: + /* Check size */ + if (recvlen < RSRR_RQ_LEN) { + log(LOG_WARNING, 0, + "Received Route Query of %d bytes, which is too small", + recvlen); + break; + } + /* Get the query */ + route_query = (struct rsrr_rq *) (rsrr_recv_buf + RSRR_HEADER_LEN); + log(LOG_INFO, 0, + "Received Route Query for src %s grp %s notification %d", + inet_fmt(route_query->source_addr.s_addr, s1), + inet_fmt(route_query->dest_addr.s_addr,s2), + BIT_TST(rsrr->flags,RSRR_NOTIFICATION_BIT)); + /* Send Route Reply to client */ + rsrr_accept_rq(route_query,rsrr->flags,NULL); + break; + default: + log(LOG_WARNING, 0, + "Received RSRR packet type %d, which I don't handle", + rsrr->type); + break; + } + break; + + default: + log(LOG_WARNING, 0, + "Received RSRR packet version %d, which I don't understand", + rsrr->version); + break; + } +} + +/* Send an Initial Reply to the reservation protocol. */ +void +rsrr_accept_iq() +{ + struct rsrr_header *rsrr; + struct rsrr_vif *vif_list; + struct uvif *v; + int vifi, sendlen; + + /* Check for space. There should be room for plenty of vifs, + * but we should check anyway. + */ + if (numvifs > RSRR_MAX_VIFS) { + log(LOG_WARNING, 0, + "Can't send RSRR Route Reply because %d is too many vifs %d", + numvifs); + return; + } + + /* Set up message */ + rsrr = (struct rsrr_header *) rsrr_send_buf; + rsrr->version = 1; + rsrr->type = RSRR_INITIAL_REPLY; + rsrr->flags = 0; + rsrr->num = numvifs; + + vif_list = (struct rsrr_vif *) (rsrr_send_buf + RSRR_HEADER_LEN); + + /* Include the vif list. */ + for (vifi=0, v = uvifs; vifi < numvifs; vifi++, v++) { + vif_list[vifi].id = vifi; + vif_list[vifi].status = 0; + if (v->uv_flags & VIFF_DISABLED) + BIT_SET(vif_list[vifi].status,RSRR_DISABLED_BIT); + vif_list[vifi].threshold = v->uv_threshold; + vif_list[vifi].local_addr.s_addr = v->uv_lcl_addr; + } + + /* Get the size. */ + sendlen = RSRR_HEADER_LEN + numvifs*RSRR_VIF_LEN; + + /* Send it. */ + log(LOG_INFO, 0, "Send RSRR Initial Reply"); + rsrr_send(sendlen); +} + +/* Send a Route Reply to the reservation protocol. The Route Query + * contains the query to which we are responding. The flags contain + * the incoming flags from the query or, for route change + * notification, the flags that should be set for the reply. The + * kernel table entry contains the routing info to use for a route + * change notification. + */ +int +rsrr_accept_rq(route_query,flags,gt_notify) + struct rsrr_rq *route_query; + int flags; + struct gtable *gt_notify; +{ + struct rsrr_header *rsrr; + struct rsrr_rr *route_reply; + struct gtable *gt,local_g; + struct rtentry *r; + int sendlen,i; + u_long mcastgrp; + + /* Set up message */ + rsrr = (struct rsrr_header *) rsrr_send_buf; + rsrr->version = 1; + rsrr->type = RSRR_ROUTE_REPLY; + rsrr->flags = 0; + rsrr->num = 0; + + route_reply = (struct rsrr_rr *) (rsrr_send_buf + RSRR_HEADER_LEN); + route_reply->dest_addr.s_addr = route_query->dest_addr.s_addr; + route_reply->source_addr.s_addr = route_query->source_addr.s_addr; + route_reply->query_id = route_query->query_id; + + /* Blank routing entry for error. */ + route_reply->in_vif = 0; + route_reply->reserved = 0; + route_reply->out_vif_bm = 0; + + /* Get the size. */ + sendlen = RSRR_RR_LEN; + + /* If kernel table entry is defined, then we are sending a Route Reply + * due to a Route Change Notification event. Use the kernel table entry + * to supply the routing info. + */ + if (gt_notify) { + /* Set flags */ + rsrr->flags = flags; + /* Include the routing entry. */ + route_reply->in_vif = gt_notify->gt_route->rt_parent; + route_reply->out_vif_bm = gt_notify->gt_grpmems; + + } else if (find_src_grp(route_query->source_addr.s_addr, 0, + route_query->dest_addr.s_addr)) { + + /* Found kernel entry. Code taken from add_table_entry() */ + gt = gtp ? gtp->gt_gnext : kernel_table; + + /* Include the routing entry. */ + route_reply->in_vif = gt->gt_route->rt_parent; + route_reply->out_vif_bm = gt->gt_grpmems; + + /* Cache reply if using route change notification. */ + if BIT_TST(flags,RSRR_NOTIFICATION_BIT) { + rsrr_cache(gt,route_query); + BIT_SET(rsrr->flags,RSRR_NOTIFICATION_BIT); + } + + } else { + /* No kernel entry; use routing table. */ + r = determine_route(route_query->source_addr.s_addr); + + if (r != NULL) { + /* We need to mimic what will happen if a data packet + * is forwarded by multicast routing -- the kernel will + * make an upcall and mrouted will install a route in the kernel. + * Our outgoing vif bitmap should reflect what that table + * will look like. Grab code from add_table_entry(). + * This is gross, but it's probably better to be accurate. + */ + + gt = &local_g; + mcastgrp = route_query->dest_addr.s_addr; + + gt->gt_mcastgrp = mcastgrp; + gt->gt_grpmems = 0; + gt->gt_scope = 0; + gt->gt_route = r; + + /* obtain the multicast group membership list */ + for (i = 0; i < numvifs; i++) { + if (VIFM_ISSET(i, r->rt_children) && + !(VIFM_ISSET(i, r->rt_leaves))) + VIFM_SET(i, gt->gt_grpmems); + + if (VIFM_ISSET(i, r->rt_leaves) && grplst_mem(i, mcastgrp)) + VIFM_SET(i, gt->gt_grpmems); + } + + GET_SCOPE(gt); + gt->gt_grpmems &= ~gt->gt_scope; + + /* Include the routing entry. */ + route_reply->in_vif = gt->gt_route->rt_parent; + route_reply->out_vif_bm = gt->gt_grpmems; + + } else { + /* Set error bit. */ + BIT_SET(rsrr->flags,RSRR_ERROR_BIT); + } + } + + if (gt_notify) + log(LOG_INFO, 0, "Route Change: Send RSRR Route Reply"); + + else + log(LOG_INFO, 0, "Send RSRR Route Reply"); + + log(LOG_INFO, 0, "for src %s dst %s in vif %d out vif %d\n", + inet_fmt(route_reply->source_addr.s_addr,s1), + inet_fmt(route_reply->dest_addr.s_addr,s2), + route_reply->in_vif,route_reply->out_vif_bm); + + /* Send it. */ + return rsrr_send(sendlen); +} + +/* Send an RSRR message. */ +int +rsrr_send(sendlen) + int sendlen; +{ + int error; + + /* Send it. */ + error = sendto(rsrr_socket, rsrr_send_buf, sendlen, 0, + (struct sockaddr *)&client_addr, client_length); + + /* Check for errors. */ + if (error < 0) { + log(LOG_WARNING, errno, "Failed send on RSRR socket"); + return error; + } + if (error != sendlen) { + log(LOG_WARNING, 0, + "Sent only %d out of %d bytes on RSRR socket\n", error, sendlen); + return error; + } +} + +/* Cache a message being sent to a client. Currently only used for + * caching Route Reply messages for route change notification. + */ +void +rsrr_cache(gt,route_query) + struct gtable *gt; + struct rsrr_rq *route_query; +{ + struct rsrr_cache *rc,*rc_prev; + struct rsrr_header *rsrr; + + rsrr = (struct rsrr_header *) rsrr_send_buf; + + rc = gt->gt_rsrr_cache; + while (rc) { + if ((rc->route_query.source_addr.s_addr == + route_query->source_addr.s_addr) && + (rc->route_query.dest_addr.s_addr == + route_query->dest_addr.s_addr) && + (!strcmp(rc->client_addr.sun_path,client_addr.sun_path))) { + /* Cache entry already exists. + * Check if route notification bit has been cleared. + */ + if (!BIT_TST(rsrr->flags,RSRR_NOTIFICATION_BIT)) { + /* Delete cache entry. */ + if (rc == gt->gt_rsrr_cache) + /* Deleting first entry. */ + gt->gt_rsrr_cache = rc->next; + else + rc_prev->next = rc->next; + free(rc); + } else { + /* Update */ + rc->route_query.query_id = route_query->query_id; + printf("Update cached query id %d from client %s\n", + rc->route_query.query_id,rc->client_addr.sun_path); + } + return; + } + rc_prev = rc; + rc = rc->next; + } + + /* Cache entry doesn't already exist. Create one and insert at + * front of list. + */ + rc = (struct rsrr_cache *) malloc(sizeof(struct rsrr_cache)); + if (rc == NULL) + log(LOG_ERR, 0, "ran out of memory"); + rc->route_query.source_addr.s_addr = route_query->source_addr.s_addr; + rc->route_query.dest_addr.s_addr = route_query->dest_addr.s_addr; + rc->route_query.query_id = route_query->query_id; + strcpy(rc->client_addr.sun_path, client_addr.sun_path); + rc->client_length = client_length; + rc->next = gt->gt_rsrr_cache; + gt->gt_rsrr_cache = rc; + printf("Cached query id %d from client %s\n", + rc->route_query.query_id,rc->client_addr.sun_path); +} + +/* Send all the messages in the cache. Currently this is used to send + * all the cached Route Reply messages for route change notification. + */ +void +rsrr_cache_send(gt,notify) + struct gtable *gt; + int notify; +{ + struct rsrr_cache *rc,*rc_next,*rc_prev; + int flags = 0; + + rc = gt->gt_rsrr_cache; + while (rc) { + rc_next = rc->next; + + if (notify) + BIT_SET(flags,RSRR_NOTIFICATION_BIT); + + if (rsrr_accept_rq(&rc->route_query,flags,gt) < 0) { + printf("Deleting cached query id %d from client %s\n", + rc->route_query.query_id,rc->client_addr.sun_path); + /* Delete cache entry. */ + if (rc == gt->gt_rsrr_cache) + /* Deleting first entry. */ + gt->gt_rsrr_cache = rc_next; + else + rc_prev->next = rc_next; + free(rc); + } else { + rc_prev = rc; + } + rc = rc_next; + } +} + +/* Clean the cache by deleting all entries. */ +void +rsrr_cache_clean(gt) + struct gtable *gt; +{ + struct rsrr_cache *rc,*rc_next; + + printf("cleaning cache for group %s\n",inet_fmt(gt->gt_mcastgrp, s1)); + rc = gt->gt_rsrr_cache; + while (rc) { + rc_next = rc->next; + free(rc); + rc = rc_next; + } + gt->gt_rsrr_cache = NULL; +} + +void +rsrr_clean() +{ + unlink(RSRR_SERV_PATH); +} + +#endif /* RSRR */ diff --git a/usr.sbin/mrouted/rsrr.h b/usr.sbin/mrouted/rsrr.h new file mode 100644 index 0000000..4099dcd --- /dev/null +++ b/usr.sbin/mrouted/rsrr.h @@ -0,0 +1,138 @@ +/* + * Copyright (c) 1993 by the University of Southern California + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation in source and binary forms for non-commercial purposes + * and without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both the copyright notice and + * this permission notice appear in supporting documentation. and that + * any documentation, advertising materials, and other materials related + * to such distribution and use acknowledge that the software was + * developed by the University of Southern California, Information + * Sciences Institute. The name of the University may not be used to + * endorse or promote products derived from this software without + * specific prior written permission. + * + * THE UNIVERSITY OF SOUTHERN CALIFORNIA makes no representations about + * the suitability of this software for any purpose. THIS SOFTWARE IS + * PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Other copyrights might apply to parts of this software and are so + * noted when applicable. + */ + +#define RSRR_SERV_PATH "/tmp/.rsrr_svr" +/* Note this needs to be 14 chars for 4.3 BSD compatibility */ +#define RSRR_CLI_PATH "/tmp/.rsrr_cli" + +#define RSRR_MAX_LEN 2048 +#define RSRR_HEADER_LEN (sizeof(struct rsrr_header)) +#define RSRR_RQ_LEN (RSRR_HEADER_LEN + sizeof(struct rsrr_rq)) +#define RSRR_RR_LEN (RSRR_HEADER_LEN + sizeof(struct rsrr_rr)) +#define RSRR_VIF_LEN (sizeof(struct rsrr_vif)) + +/* Current maximum number of vifs. */ +#define RSRR_MAX_VIFS 32 + +/* Maximum acceptable version */ +#define RSRR_MAX_VERSION 1 + +/* RSRR message types */ +#define RSRR_ALL_TYPES 0 +#define RSRR_INITIAL_QUERY 1 +#define RSRR_INITIAL_REPLY 2 +#define RSRR_ROUTE_QUERY 3 +#define RSRR_ROUTE_REPLY 4 + +/* RSRR Initial Reply (Vif) Status bits. + * Each definition represents the position of the bit from right to left. + * + * Right-most bit is the disabled bit, set if the vif is administratively + * disabled. + */ +#define RSRR_DISABLED_BIT 0 +/* All other bits are zeroes */ + +/* RSRR Route Query/Reply flag bits. + * Each definition represents the position of the bit from right to left. + * + * Right-most bit is the Route Change Notification bit, set if the + * reservation protocol wishes to receive notification of + * a route change for the source-destination pair listed in the query. + * Notification is in the form of an unsolicitied Route Reply. + */ +#define RSRR_NOTIFICATION_BIT 0 +/* Next bit indicates an error returning the Route Reply. */ +#define RSRR_ERROR_BIT 1 +/* All other bits are zeroes */ + +/* Definition of an RSRR message header. + * An Initial Query uses only the header, and an Initial Reply uses + * the header and a list of vifs. + */ +struct rsrr_header { + u_char version; /* RSRR Version, currently 1 */ + u_char type; /* type of message, as defined above */ + u_char flags; /* flags; defined by type */ + u_char num; /* number; defined by type */ +}; + +/* Definition of a vif as seen by the reservation protocol. + * + * Routing gives the reservation protocol a list of vifs in the + * Initial Reply. + * + * We explicitly list the ID because we can't assume that all routing + * protocols will use the same numbering scheme. + * + * The status is a bitmask of status flags, as defined above. It is the + * responsibility of the reservation protocol to perform any status checks + * if it uses the MULTICAST_VIF socket option. + * + * The threshold indicates the ttl an outgoing packet needs in order to + * be forwarded. The reservation protocol must perform this check itself if + * it uses the MULTICAST_VIF socket option. + * + * The local address is the address of the physical interface over which + * packets are sent. + */ +struct rsrr_vif { + u_char id; /* vif id */ + u_char threshold; /* vif threshold ttl */ + u_short status; /* vif status bitmask */ + struct in_addr local_addr; /* vif local address */ +}; + +/* Definition of an RSRR Route Query. + * + * The query asks routing for the forwarding entry for a particular + * source and destination. The query ID uniquely identifies the query + * for the reservation protocol. Thus, the combination of the client's + * address and the query ID forms a unique identifier for routing. + * Flags are defined above. + */ +struct rsrr_rq { + struct in_addr dest_addr; /* destination */ + struct in_addr source_addr; /* source */ + u_long query_id; /* query ID */ +}; + +/* Definition of an RSRR Route Reply. + * + * Routing uses the reply to give the reservation protocol the + * forwarding entry for a source-destination pair. Routing copies the + * query ID from the query and fills in the incoming vif and a bitmask + * of the outgoing vifs. + * Flags are defined above. + */ +struct rsrr_rr { + struct in_addr dest_addr; /* destination */ + struct in_addr source_addr; /* source */ + u_long query_id; /* query ID */ + u_short in_vif; /* incoming vif */ + u_short reserved; /* reserved */ + u_long out_vif_bm; /* outgoing vif bitmask */ +}; diff --git a/usr.sbin/mrouted/rsrr_var.h b/usr.sbin/mrouted/rsrr_var.h new file mode 100644 index 0000000..9b1c09c --- /dev/null +++ b/usr.sbin/mrouted/rsrr_var.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 1993 by the University of Southern California + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation in source and binary forms for non-commercial purposes + * and without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both the copyright notice and + * this permission notice appear in supporting documentation. and that + * any documentation, advertising materials, and other materials related + * to such distribution and use acknowledge that the software was + * developed by the University of Southern California, Information + * Sciences Institute. The name of the University may not be used to + * endorse or promote products derived from this software without + * specific prior written permission. + * + * THE UNIVERSITY OF SOUTHERN CALIFORNIA makes no representations about + * the suitability of this software for any purpose. THIS SOFTWARE IS + * PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Other copyrights might apply to parts of this software and are so + * noted when applicable. + */ + +/* RSRR things that are only needed by mrouted. */ + +/* Cache of Route Query messages, distinguished by source, + * destination, and client addresses. Cache is flushed by RSRR client + * -- it sends notification when an unwanted Route Reply is received. + * Since this only happens during route changes, it is more likely + * that the cache will be flushed when the kernel table entry is + * deleted. */ +struct rsrr_cache { + struct rsrr_rq route_query; /* Cached Route Query */ + struct sockaddr_un client_addr; /* Client address */ + int client_length; /* Length of client */ + struct rsrr_cache *next; /* next cache item */ +}; + |