Update to the unreleased mrouted 3.8a . This includes a minor

endian-ness fix, Router Alert options on IGMP messages, and a
new keyword, "advert_metric", for fine-tuning tunnel metrics.

This also includes a new mtrace, which is also unreleased but
builds significantly on the experiences of users' troubles with
using and understanding mtrace in release 3.8 .

(unreleased does not, of course, mean untested!)

This is a candidate for both 2.2 and 2.1.6 .
This commit is contained in:
Bill Fenner 1996-11-11 03:50:15 +00:00
parent f29c770b37
commit f014b7e69b
16 changed files with 607 additions and 239 deletions

View File

@ -4,7 +4,7 @@
*
* Written by Bill Fenner, NRL, 1994
*
* $Id: cfparse.y,v 3.8 1995/11/29 22:36:57 fenner Rel $
* $Id: cfparse.y,v 3.8.1.2 1996/08/09 22:46:18 fenner Exp $
*/
#include <stdio.h>
#ifdef __STDC__
@ -71,7 +71,7 @@ int numbounds = 0; /* Number of named boundaries */
%token CACHE_LIFETIME PRUNING
%token PHYINT TUNNEL NAME
%token DISABLE IGMPV1 SRCRT
%token METRIC THRESHOLD RATE_LIMIT BOUNDARY NETMASK ALTNET
%token METRIC THRESHOLD RATE_LIMIT BOUNDARY NETMASK ALTNET ADVERT_METRIC
%token SYSNAM SYSCONTACT SYSVERSION SYSLOCATION
%token <num> BOOLEAN
%token <num> NUMBER
@ -157,6 +157,7 @@ stmt : error
v = &uvifs[numvifs];
v->uv_flags = VIFF_TUNNEL;
v->uv_metric = DEFAULT_METRIC;
v->uv_admetric = 0;
v->uv_rate_limit= DEFAULT_TUN_RATE_LIMIT;
v->uv_threshold = DEFAULT_THRESHOLD;
v->uv_lcl_addr = $2;
@ -293,6 +294,15 @@ mod : THRESHOLD NUMBER { if ($2 < 1 || $2 > 255)
warn("Expected number after metric keyword, ignored");
}
| ADVERT_METRIC NUMBER { if ($2 < 0 || $2 > UNREACHABLE - 1)
fatal("Invalid advert_metric %d", $2);
v->uv_admetric = $2;
}
| ADVERT_METRIC {
warn("Expected number after advert_metric keyword, ignored");
}
| RATE_LIMIT NUMBER { if ($2 > MAX_RATE_LIMIT)
fatal("Invalid rate_limit %d",$2);
@ -504,6 +514,8 @@ yylex()
return DISABLE;
if (!strcmp(q,"metric"))
return METRIC;
if (!strcmp(q,"advert_metric"))
return ADVERT_METRIC;
if (!strcmp(q,"threshold"))
return THRESHOLD;
if (!strcmp(q,"rate_limit"))
@ -528,8 +540,13 @@ yylex()
yylval.num = 0;
return BOOLEAN;
}
if (!strcmp(q,"default")) {
yylval.addrmask.mask = 0;
yylval.addrmask.addr = 0;
return ADDRMASK;
}
if (sscanf(q,"%[.0-9]/%d%c",s1,&n,s2) == 2) {
if ((addr = inet_parse(s1)) != 0xffffffff) {
if ((addr = inet_parse(s1,1)) != 0xffffffff) {
yylval.addrmask.mask = n;
yylval.addrmask.addr = addr;
return ADDRMASK;
@ -537,7 +554,7 @@ yylex()
/* fall through to returning STRING */
}
if (sscanf(q,"%[.0-9]%c",s1,s2) == 1) {
if ((addr = inet_parse(s1)) != 0xffffffff &&
if ((addr = inet_parse(s1,4)) != 0xffffffff &&
inet_valid_host(addr)) {
yylval.addr = addr;
return ADDR;

View File

@ -7,7 +7,7 @@
* Leland Stanford Junior University.
*
*
* $Id: config.c,v 3.8 1995/11/29 22:36:57 fenner Rel $
* $Id: config.c,v 3.8.1.1 1996/08/09 22:46:16 fenner Exp $
*/
@ -116,6 +116,7 @@ config_vifs_from_kernel()
v = &uvifs[numvifs];
v->uv_flags = 0;
v->uv_metric = DEFAULT_METRIC;
v->uv_admetric = 0;
v->uv_rate_limit = DEFAULT_PHY_RATE_LIMIT;
v->uv_threshold = DEFAULT_THRESHOLD;
v->uv_lcl_addr = addr;

View File

@ -7,7 +7,7 @@
* Leland Stanford Junior University.
*
*
* $Id: defs.h,v 3.8 1995/11/29 22:36:34 fenner Rel $
* $Id: defs.h,v 3.8.1.2 1996/09/05 19:00:20 fenner Exp $
*/
@ -160,10 +160,20 @@ extern char * sys_errlist[];
#define MRT_DEL_VIF DVMRP_DEL_VIF
#define MRT_ADD_MFC DVMRP_ADD_MFC
#define MRT_DEL_MFC DVMRP_DEL_MFC
#endif
#ifndef IGMP_PIM
#define IGMP_PIM 0x14
#endif
#ifndef IGMP_MEMBERSHIP_QUERY
#define IGMP_MEMBERSHIP_QUERY IGMP_HOST_MEMBERSHIP_QUERY
#define IGMP_V1_MEMBERSHIP_REPORT IGMP_HOST_MEMBERSHIP_REPORT
#define IGMP_V2_MEMBERSHIP_REPORT IGMP_HOST_NEW_MEMBERSHIP_REPORT
#define IGMP_V2_LEAVE_GROUP IGMP_HOST_LEAVE_MESSAGE
#endif
/* main.c */
extern void log __P((int, int, char *, ...));
extern int register_input_handler __P((int fd, ihfunc_t func));
@ -247,7 +257,7 @@ extern int inet_valid_host __P((u_int32 naddr));
extern int inet_valid_subnet __P((u_int32 nsubnet, u_int32 nmask));
extern char * inet_fmt __P((u_int32 addr, char *s));
extern char * inet_fmts __P((u_int32 addr, u_int32 mask, char *s));
extern u_int32 inet_parse __P((char *s));
extern u_int32 inet_parse __P((char *s, int n));
extern int inet_cksum __P((u_short *addr, u_int len));
/* prune.c */

View File

@ -7,7 +7,7 @@
* Leland Stanford Junior University.
*
*
* $Id: igmp.c,v 1.9 1996/01/06 21:09:44 peter Exp $
* $Id: igmp.c,v 3.8.1.1 1996/08/09 22:49:12 fenner Exp $
*/
@ -25,6 +25,23 @@ u_int32 allrtrs_group; /* All-Routers " in net order */
u_int32 dvmrp_group; /* DVMRP grp addr in net order */
u_int32 dvmrp_genid; /* IGMP generation id */
/*
* Private variables
*/
static char router_alert[4]; /* Router Alert IP Option */
#ifndef IPOPT_RA
#define IPOPT_RA 148
#endif
#ifdef SUNOS5
static char no_op[4]; /* Null IP Option */
static int ip_addlen = 0; /* Workaround for Option bug #2*/
#endif
#define SEND_RA(x) (((x) == IGMP_MEMBERSHIP_QUERY) || \
((x) == IGMP_V1_MEMBERSHIP_REPORT) || \
((x) == IGMP_V2_MEMBERSHIP_REPORT) || \
((x) == IGMP_V2_LEAVE_GROUP) || \
((x) == IGMP_MTRACE))
/*
* Local function definitions.
*/
@ -40,6 +57,9 @@ void
init_igmp()
{
struct ip *ip;
#ifdef SUNOS5
u_int32 localhost = htonl(0x7f000001);
#endif
recv_buf = malloc(RECV_BUF_SIZE);
send_buf = malloc(RECV_BUF_SIZE);
@ -63,6 +83,67 @@ init_igmp()
allhosts_group = htonl(INADDR_ALLHOSTS_GROUP);
dvmrp_group = htonl(INADDR_DVMRP_GROUP);
allrtrs_group = htonl(INADDR_ALLRTRS_GROUP);
router_alert[0] = IPOPT_RA; /* Router Alert */
router_alert[1] = 4; /* 4 bytes */
router_alert[2] = 0;
router_alert[3] = 0;
#ifdef SUNOS5
no_op[0] = IPOPT_NOP;
no_op[1] = IPOPT_NOP;
no_op[2] = IPOPT_NOP;
no_op[3] = IPOPT_NOP;
setsockopt(igmp_socket, IPPROTO_IP, IP_OPTIONS, no_op, sizeof(no_op));
/*
* Check if the kernel adds the options length to the packet
* length. Send myself an IGMP packet of type 0 (illegal),
* with 4 IPOPT_NOP options, my PID (for collision detection)
* and 4 bytes of zero (so that the checksum works whether
* the 4 bytes of zero get truncated or not).
*/
bzero(send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN, 8);
*(int *)(send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN) = getpid();
send_igmp(localhost, localhost, 0, 0, 0, 8);
while (1) {
int recvlen, dummy = 0;
recvlen = recvfrom(igmp_socket, recv_buf, RECV_BUF_SIZE,
0, NULL, &dummy);
/* 8 == 4 bytes of options and 4 bytes of PID */
if (recvlen >= MIN_IP_HEADER_LEN + IGMP_MINLEN + 8) {
struct ip *ip = (struct ip *)recv_buf;
struct igmp *igmp;
int *p;
if (ip->ip_hl != 6 ||
ip->ip_p != IPPROTO_IGMP ||
ip->ip_src.s_addr != localhost ||
ip->ip_dst.s_addr != localhost)
continue;
igmp = (struct igmp *)(recv_buf + (ip->ip_hl << 2));
if (igmp->igmp_group.s_addr != 0)
continue;
if (igmp->igmp_type != 0 || igmp->igmp_code != 0)
continue;
p = (int *)((char *)igmp + IGMP_MINLEN);
if (*p != getpid())
continue;
if (ip->ip_len == IGMP_MINLEN + 4)
ip_addlen = 4;
else if (ip->ip_len == IGMP_MINLEN + 8)
ip_addlen = 0;
else
log(LOG_ERR, 0, "while checking for Solaris bug: Sent %d bytes and got back %d!", IGMP_MINLEN + 8, ip->ip_len);
break;
}
}
#endif
}
#define PIM_QUERY 0
@ -80,8 +161,8 @@ packet_kind(type, code)
{
switch (type) {
case IGMP_HOST_MEMBERSHIP_QUERY: return "membership query ";
case IGMP_HOST_MEMBERSHIP_REPORT: return "membership report ";
case IGMP_HOST_NEW_MEMBERSHIP_REPORT: return "new member report ";
case IGMP_HOST_MEMBERSHIP_REPORT: return "V1 member report ";
case IGMP_HOST_NEW_MEMBERSHIP_REPORT: return "V2 member report ";
case IGMP_HOST_LEAVE_MESSAGE: return "leave message ";
case IGMP_DVMRP:
switch (code) {
@ -310,12 +391,19 @@ send_igmp(src, dst, type, code, group, datalen)
struct sockaddr_in sdst;
struct ip *ip;
struct igmp *igmp;
int setloop;
int setloop = 0;
static int raset = 0;
int sendra = 0;
int sendlen;
ip = (struct ip *)send_buf;
ip->ip_src.s_addr = src;
ip->ip_dst.s_addr = dst;
ip->ip_len = MIN_IP_HEADER_LEN + IGMP_MINLEN + datalen;
sendlen = ip->ip_len;
#ifdef SUNOS5
ip->ip_len += ip_addlen;
#endif
igmp = (struct igmp *)(send_buf + MIN_IP_HEADER_LEN);
igmp->igmp_type = type;
@ -331,6 +419,27 @@ send_igmp(src, dst, type, code, group, datalen)
setloop = 1;
k_set_loop(TRUE);
}
if (SEND_RA(type))
sendra = 1;
}
if (sendra && !raset) {
setsockopt(igmp_socket, IPPROTO_IP, IP_OPTIONS,
router_alert, sizeof(router_alert));
raset = 1;
} else if (!sendra && raset) {
#ifdef SUNOS5
/*
* SunOS5 < 5.6 cannot properly reset the IP_OPTIONS "socket"
* option. Instead, set up a string of 4 no-op's.
*/
setsockopt(igmp_socket, IPPROTO_IP, IP_OPTIONS,
no_op, sizeof(no_op));
#else
setsockopt(igmp_socket, IPPROTO_IP, IP_OPTIONS,
NULL, 0);
#endif
raset = 0;
}
bzero(&sdst, sizeof(sdst));
@ -339,7 +448,7 @@ send_igmp(src, dst, type, code, group, datalen)
sdst.sin_len = sizeof(sdst);
#endif
sdst.sin_addr.s_addr = dst;
if (sendto(igmp_socket, send_buf, ip->ip_len, 0,
if (sendto(igmp_socket, send_buf, sendlen, 0,
(struct sockaddr *)&sdst, sizeof(sdst)) < 0) {
if (errno == ENETDOWN)
check_vif_state();
@ -353,5 +462,6 @@ send_igmp(src, dst, type, code, group, datalen)
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));
packet_kind(type, code), src == INADDR_ANY ? "INADDR_ANY" :
inet_fmt(src, s1), inet_fmt(dst, s2));
}

View File

@ -7,7 +7,7 @@
* Leland Stanford Junior University.
*
*
* $Id: inet.c,v 3.8 1995/11/29 22:36:57 fenner Rel $
* $Id: inet.c,v 3.8.1.1 1995/12/01 22:20:26 fenner Exp $
*/
@ -155,15 +155,17 @@ inet_fmts(addr, mask, s)
* with "255.255.255.255".)
*/
u_int32
inet_parse(s)
inet_parse(s,n)
char *s;
int n;
{
u_int32 a = 0;
u_int a0, a1, a2, a3;
u_int a0 = 0, a1 = 0, a2 = 0, a3 = 0;
int i;
char c;
if (sscanf(s, "%u.%u.%u.%u%c", &a0, &a1, &a2, &a3, &c) != 4 ||
a0 > 255 || a1 > 255 || a2 > 255 || a3 > 255)
i = sscanf(s, "%u.%u.%u.%u%c", &a0, &a1, &a2, &a3, &c);
if (i < n || i > 4 || a0 > 255 || a1 > 255 || a2 > 255 || a3 > 255)
return (0xffffffff);
((u_char *)&a)[0] = a0;

View File

@ -7,7 +7,7 @@
* Leland Stanford Junior University.
*
*
* $Id: kern.c,v 3.8 1995/11/29 22:36:57 fenner Rel $
* $Id: kern.c,v 3.8.1.1 1995/12/07 18:17:58 fenner Exp $
*/
@ -150,7 +150,7 @@ void k_del_vif(vifi)
{
if (setsockopt(igmp_socket, IPPROTO_IP, MRT_DEL_VIF,
(char *)&vifi, sizeof(vifi)) < 0)
log(LOG_ERR, errno, "setsockopt MRT_DEL_VIF");
log(LOG_ERR, errno, "setsockopt MRT_DEL_VIF on vif %d", vifi);
}

View File

@ -7,7 +7,7 @@
* Leland Stanford Junior University.
*
*
* $Id: main.c,v 1.7 1996/01/06 21:09:51 peter Exp $
* $Id: main.c,v 3.8.1.3 1996/09/06 18:30:00 fenner Exp $
*/
/*
@ -34,7 +34,7 @@
#ifndef lint
static char rcsid[] =
"@(#) $Id: main.c,v 1.7 1996/01/06 21:09:51 peter Exp $";
"@(#) $Id: main.c,v 3.8.1.3 1996/09/06 18:30:00 fenner Exp $";
#endif
extern char *configfilename;
@ -192,7 +192,7 @@ usage: fprintf(stderr,
#else
(void)openlog("mrouted", LOG_PID);
#endif
sprintf(versionstring, "mrouted version %d.%d",
sprintf(versionstring, "mrouted version %d.%da",
PROTOCOL_VERSION, MROUTED_VERSION);
log(LOG_NOTICE, 0, "%s", versionstring);

View File

@ -66,7 +66,7 @@ reply. Default timeout is 4 seconds.
.PP
For each neighbor of the queried multicast router, the IP of the queried router
is displayed, followed by the IP and name of the neighbor. In square brackets
the metric (cost of connection), the threshold (multicast ttl) is displayed. If
the metric (cost of connection), the treashold (multicast ttl) is displayed. If
the queried multicast router has a newer version number, the type (tunnel,
srcrt) and status (disabled, down) of the connection is displayed.
.PP

View File

@ -1,5 +1,5 @@
'\"COPYRIGHT 1989 by The Board of Trustees of Leland Stanford Junior University.
'\"$Id: mrouted.8,v 3.8 1995/11/29 22:37:21 fenner Rel $
'\"$Id: mrouted.8,v 3.8.1.1 1996/11/10 22:16:52 fenner Exp $
.TH MROUTED 8
.UC 5
.SH NAME
@ -112,19 +112,17 @@ configuration commands may be placed in
There are four types of configuration commands:
.nf
phyint <local-addr> [disable] [metric <m>]
phyint <local-addr> [disable] [metric <m>] [advert_metric <m>]
[threshold <t>] [rate_limit <b>]
[boundary (<boundary-name>|<scoped-addr>/<mask-len>)]
[altnet <network>/<mask-len>]
tunnel <local-addr> <remote-addr> [metric <m>]
tunnel <local-addr> <remote-addr> [metric <m>] [advert_metric <m>]
[threshold <t>] [rate_limit <b>]
[boundary (<boundary-name>|<scoped-addr>/<mask-len>)]
cache_lifetime <ct>
pruning <off/on>
name <boundary-name> <scoped-addr>/<mask-len>
.fi
@ -155,23 +153,11 @@ 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,
'\"the srcrt keyword specifies
'\"encapsulation using IP source routing.
.PP
The cache_lifetime is a value that determines the amount of time that a
cached multicast route stays in kernel before timing out. The value of this
entry should lie between 300 (5 min) and 86400 (1 day). It defaults to 300.
.PP
The pruning <off/on> option is provided for
.IR mrouted
to act as a non-pruning router. It is also possible to start
.IR mrouted
in a non-pruning mode using the "-p" option on the command line. It is
expected that a router would be configured in this manner for test
purposes only. The default mode is pruning enabled.
.PP
You may assign names to boundaries to make configuration easier with
the name keyword. The boundary option on phyint or tunnel commands
can accept either a name or a boundary.
@ -183,6 +169,11 @@ because
.I mrouted
cannot route along paths with a sum of metrics greater
than 31.
.PP
The advert_metric is the "cost" associated with receiving a datagram
on the given interface or tunnel; it may be used to influence the choice
of routes. The advert_metric defaults to 0. Note that the effective
metric of a link is one end's metric plus the other end's advert_metric.
.LP
The threshold is the minimum IP time-to-live required for a multicast datagram
to be forwarded to the given interface or tunnel. It is used to control the

View File

@ -29,7 +29,7 @@
.\" Copyright (c) 1988 The Regents of the University of California.
.\" All rights reserved.
.\"
.\" $Id: mtrace.8,v 3.8 1995/11/29 22:37:21 fenner Rel $
.\" $Id: mtrace.8,v 3.8.1.1 1996/11/10 22:24:15 fenner Exp $
.\"
.TH MTRACE 8 "May 8, 1995"
.UC 6
@ -48,6 +48,8 @@ mtrace \- print multicast path from a source to a receiver
] [
.B \-M
] [
.B \-T
] [
.B \-m
.I max_hops
] [
@ -110,6 +112,13 @@ detailed below. The two parameters can be distinguished because the
is a unicast address and the
.I group
is a multicast address.
If the
.B \-g
flag is specified, the source address defaults to the host running
mtrace, and the receiver defaults to the router being addressed with
the
.B \-g
flag. In this case, there are no required parameters.
.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.
@ -202,11 +211,16 @@ seconds (default 10 seconds).
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
responses. The default is 127, except for local queries to the "all
routers" multicast group which use ttl 1.
.TP 8 8
.B \-T
"Tunnel statistics" mode; show loss rates for overall traffic.
These statistics can be extremely misleading.
.TP 8 8
.B \-v
Verbose mode; show hop times on the initial trace and statistics display.
Also show the route that was used to forward the initial trace.
.TP 8 8
.BI \-w\ n
Set the time to wait for a trace response to
@ -273,7 +287,7 @@ trace query is multicast to the
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
default ttl of 127, which may not be sufficient for all cases (changed
with the
.B \-t
option).
@ -316,7 +330,7 @@ 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
192. Alternatively, the ttl may be set explicitly with the
.B \-t
option and/or the initial unicast attempts can be forced to use
multicast instead with the
@ -346,7 +360,8 @@ 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
received, both derived from the local system clock, and the total
ttl required for a packet to travel along this path. A sample use and
output might be:
.PP
.nf
@ -361,18 +376,29 @@ Querying full reverse path...
-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
Round trip time 124 ms; total ttl of 6 required.
.fi
.PP
If a hop reports that it is using the default route to forward packets,
the word
.B [default]
is printed after that hop. If the
.B \-v
flag is supplied, the route being used to forward packets is printed
in the form
.B [18.26.0/24] .
.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
assuming that the routers at both ends have synchronized clocks.
The right half of this section is composed of two sets of statistics.
The first column contains the average packet rate for all traffic at
each hop.
The remaining 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
@ -383,6 +409,11 @@ from the specified
.I source
to the specified
.IR group .
The first group of statistics may be expanded to include loss rates
using the
.B \-T
option. However, these numbers can be extremely misleading and require
detailed knowledge of the routers involved to be interpreted properly.
.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,
@ -397,7 +428,7 @@ 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.
option is set or if no multicast group is specified.
.ie t \{\
.ft C
. ie \w'i'<>\w'm' \{\" looks like this is not proper Courier font
@ -411,30 +442,30 @@ and try again.)
.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 --------------------- ------------------
Source Response Dest Overall Packet Statistics For Traffic From
18.26.0.170 128.9.160.100 Packet 18.26.0.170 To 224.2.0.3
| __/ rtt 125 ms Rate Lost/Sent = Pct Rate
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
| ^ ttl 1 0 pps 0/2 = --% 0 pps
v | hop 8 ms 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
| ^ ttl 2 0 pps 0/2 = --% 0 pps
v | hop 12 ms 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
| ^ ttl 3 27 pps 0/2 = --% 0 pps
v | hop 34 ms 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
| ^ ttl 4 83 pps 0/2 = --% 0 pps
v | hop 11 ms 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
| \\__ ttl 5 83 pps ?/2 0 pps
v \\ hop -8 ms 79 pps ?/18 0 pps
128.9.160.100 128.9.160.100
Receiver Query Source
.fi

View File

@ -50,7 +50,7 @@
#ifndef lint
static char rcsid[] =
"@(#) $Id: mtrace.c,v 1.7 1996/01/06 21:10:05 peter Exp $";
"@(#) $Id: mtrace.c,v 3.8.1.12 1996/11/10 22:23:46 fenner Exp $";
#endif
#include <netdb.h>
@ -74,7 +74,7 @@ static char rcsid[] =
#define DEFAULT_RETRIES 3 /* How many times to try */
#define MAXHOPS UNREACHABLE /* Don't need more hops than max metric */
#define UNICAST_TTL 255 /* TTL for unicast response */
#define MULTICAST_TTL1 64 /* Default TTL for multicast query/response */
#define MULTICAST_TTL1 127 /* Default TTL for multicast query/response */
#define MULTICAST_TTL_INC 32 /* TTL increment for increase after timeout */
#define MULTICAST_TTL_MAX 192 /* Maximum TTL allowed (protect low-BW links */
@ -99,6 +99,7 @@ struct resp_buf {
char names[MAXHOPS][40];
int reset[MAXHOPS]; /* To get around 3.4 bug, ... */
int swaps[MAXHOPS]; /* To get around 3.6 bug, ... */
int bogustime[MAXHOPS]; /* To get around 3.5 bug, ... */
int timeout = DEFAULT_TIMEOUT;
int nqueries = DEFAULT_RETRIES;
@ -106,8 +107,11 @@ int numeric = FALSE;
int debug = 0;
int passive = FALSE;
int multicast = FALSE;
int unicast = FALSE;
int statint = 10;
int verbose = 0;
int verbose = FALSE;
int tunstats = FALSE;
int weak = FALSE;
u_int32 defgrp; /* Default group if not specified */
u_int32 query_cast; /* All routers multicast addr */
@ -132,11 +136,17 @@ u_int32 tdst = 0; /* Address where trace is sent (last-hop) */
vifi_t numvifs; /* to keep loader happy */
/* (see kern.c) */
#ifndef SYSV
extern long random();
#endif
extern int errno;
/*
* max macro, with weird case to avoid conflicts
*/
#define MaX(a,b) (a) > (b) ? (a) : (b)
char * inet_name __P((u_int32 addr));
u_int32 host_addr __P((char *name));
/* u_int is promoted u_char */
@ -211,7 +221,7 @@ host_addr(name)
if (e) memcpy((char *)&addr, e->h_addr_list[0], e->h_length);
else {
addr = inet_addr(buf);
if (addr == -1) {
if (addr == -1 || (IN_MULTICAST(addr) && dots)) {
addr = 0;
printf("Could not parse %s as host name or address\n", name);
}
@ -395,10 +405,12 @@ send_recv(dst, type, code, tries, save)
struct ip *ip;
struct igmp *igmp;
struct tr_query *query, *rquery;
int ipdatalen, iphdrlen, igmpdatalen;
struct tr_resp *r;
struct sockaddr_in recvaddr;
u_int32 local, group;
int ipdatalen, iphdrlen, igmpdatalen;
int datalen;
int count, recvlen, dummy = 0;
int count, recvlen, socklen = sizeof(recvaddr);
int len;
int i;
@ -482,7 +494,7 @@ send_recv(dst, type, code, tries, save)
gettimeofday(&tr, 0);
recvlen = recvfrom(igmp_socket, recv_buf, RECV_BUF_SIZE,
0, (struct sockaddr *)0, &dummy);
0, (struct sockaddr *)&recvaddr, &socklen);
if (recvlen <= 0) {
if (recvlen && errno != EINTR) perror("recvfrom");
@ -519,6 +531,8 @@ send_recv(dst, type, code, tries, save)
switch (igmp->igmp_type) {
case IGMP_DVMRP:
if (type != IGMP_DVMRP || code != DVMRP_ASK_NEIGHBORS2)
continue;
if (igmp->igmp_code != DVMRP_NEIGHBORS2) continue;
len = igmpdatalen;
/*
@ -544,6 +558,7 @@ send_recv(dst, type, code, tries, save)
case IGMP_MTRACE: /* For backward compatibility with 3.3 */
case IGMP_MTRACE_RESP:
if (type != IGMP_MTRACE) continue;
if (igmpdatalen <= QLEN) continue;
if ((igmpdatalen - QLEN)%RLEN) {
printf("packet with incorrect datalen\n");
@ -558,6 +573,7 @@ send_recv(dst, type, code, tries, save)
if (rquery->tr_src != qsrc) continue;
if (rquery->tr_dst != qdst) continue;
len = (igmpdatalen - QLEN)/RLEN;
r = (struct tr_resp *)(rquery+1) + len - 1;
/*
* Ignore trace queries passing through this node when
@ -566,7 +582,6 @@ send_recv(dst, type, code, tries, save)
* for backward compatibility with multicast release 3.3).
*/
if (igmp->igmp_type == IGMP_MTRACE) {
struct tr_resp *r = (struct tr_resp *)(rquery+1) + len - 1;
u_int32 smask;
VAL_TO_MASK(smask, r->tr_smask);
@ -574,6 +589,13 @@ send_recv(dst, type, code, tries, save)
&& r->tr_rmtaddr != 0 && !(r->tr_rflags & 0x80))
continue;
}
/*
* Some routers will return error messages without
* filling in their addresses. We fill in the address
* for them.
*/
if (r->tr_outaddr == 0)
r->tr_outaddr = recvaddr.sin_addr.s_addr;
/*
* A match, we'll keep this one.
@ -625,6 +647,10 @@ passive_mode()
struct ip *ip;
struct igmp *igmp;
struct tr_resp *r;
struct sockaddr_in recvaddr;
struct tm *now;
char timebuf[32];
int socklen;
int ipdatalen, iphdrlen, igmpdatalen;
int len, recvlen, dummy = 0;
u_int32 smask;
@ -634,8 +660,9 @@ passive_mode()
} else k_join(htonl(0xE0000120), INADDR_ANY);
while (1) {
socklen = sizeof(recvaddr);
recvlen = recvfrom(igmp_socket, recv_buf, RECV_BUF_SIZE,
0, (struct sockaddr *)0, &dummy);
0, (struct sockaddr *)&recvaddr, &socklen);
gettimeofday(&tr,0);
if (recvlen <= 0) {
@ -704,16 +731,41 @@ passive_mode()
(qgrp != 0 && qgrp != igmp->igmp_group.s_addr))
continue;
printf("Mtrace from %s to %s via group %s (mxhop=%d)\n",
now = localtime(&tr.tv_sec);
strftime(timebuf, sizeof(timebuf) - 1, "%b %e %k:%M:%S", now);
printf("Mtrace %s at %s",
len == 0 ? "query" :
igmp->igmp_type == IGMP_MTRACE_RESP ? "response" :
"in transit",
timebuf);
if (len == 0)
printf(" by %s", inet_fmt(recvaddr.sin_addr.s_addr, s1));
if (!IN_MULTICAST(base.qhdr.tr_raddr))
printf(", resp to %s", (len == 0 && recvaddr.sin_addr.s_addr == base.qhdr.tr_raddr) ? "same" : inet_fmt(base.qhdr.tr_raddr, s1));
else
printf(", respttl %d", base.qhdr.tr_rttl);
printf(", qid %06x\n", base.qhdr.tr_qid);
printf("packet from %s to %s\n",
inet_fmt(ip->ip_src.s_addr, s1),
inet_fmt(ip->ip_dst.s_addr, s2));
printf("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;
r = base.resps + base.len - 1;
/*
* Some routers will return error messages without
* filling in their addresses. We fill in the address
* for them.
*/
if (r->tr_outaddr == 0)
r->tr_outaddr = recvaddr.sin_addr.s_addr;
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));
@ -785,7 +837,20 @@ print_trace(index, buf)
ms = scale(&hop);
printf(" %d%s", hop, ms);
}
printf(" %s\n", flag_type(r->tr_rflags));
printf(" %s", flag_type(r->tr_rflags));
if (i > 1 && r->tr_outaddr != (r-1)->tr_rmtaddr) {
printf(" !RPF!");
print_host((r-1)->tr_rmtaddr);
}
if (r->tr_smask <= 1) /* Buggy MASK_TO_VAL() returns 1 for default */
printf(" [default]");
else if (verbose) {
u_int32 smask;
VAL_TO_MASK(smask, r->tr_smask);
printf(" [%s]", inet_fmts(buf->qhdr.tr_src & smask, smask, s1));
}
printf("\n");
memcpy(names[i-1], name, sizeof(names[0]) - 1);
names[i-1][sizeof(names[0])-1] = '\0';
}
@ -886,27 +951,33 @@ stat_line(r, s, have_next, rst)
int g_out = ntohl(s->tr_pktcnt) - ntohl(r->tr_pktcnt);
int v_pps, g_pps;
char v_str[8], g_str[8];
int have = NEITHER;
int res = *rst;
int vhave = NEITHER;
int ghave = NEITHER;
char whochar;
if (timediff == 0) timediff = 1;
v_pps = v_out / timediff;
g_pps = g_out / timediff;
if (v_out && (s->tr_vifout != 0xFFFFFFFF && s->tr_vifout != 0) ||
(r->tr_vifout != 0xFFFFFFFF && r->tr_vifout != 0))
have |= OUTS;
(r->tr_vifout != 0xFFFFFFFF && r->tr_vifout != 0)) {
vhave |= OUTS;
if (!*rst)
ghave |= OUTS;
}
if (have_next) {
--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;
(r->tr_vifin != 0xFFFFFFFF && r->tr_vifin != 0)) {
vhave |= INS;
if (!*rst)
ghave |= INS;
}
}
switch (have) {
whochar = have_next ? '^' : ' ';
switch (vhave) {
case BOTH:
v_lost = v_out - (ntohl(s->tr_vifin) - ntohl(r->tr_vifin));
if (v_out) v_pct = (v_lost * 100 + (v_out >> 1)) / v_out;
@ -915,6 +986,42 @@ stat_line(r, s, have_next, rst)
sprintf(v_str, "%3d", v_pct);
else memcpy(v_str, " --", 4);
if (tunstats)
printf("%6d/%-5d=%s%%", v_lost, v_out, v_str);
else
printf(" ");
printf("%4d pps", v_pps);
break;
case INS:
v_out = ntohl(s->tr_vifin) - ntohl(r->tr_vifin);
v_pps = v_out / timediff;
whochar = 'v';
/* Fall through */
case OUTS:
if (tunstats)
printf(" %c%-5d ", whochar, v_out);
else
printf(" %c", whochar);
printf("%4d pps", v_pps);
break;
case NEITHER:
if (vhave != NEITHER)
if (tunstats)
printf(" ");
else
printf(" ");
break;
}
whochar = have_next ? '^' : ' ';
switch (ghave) {
case BOTH:
g_lost = g_out - (ntohl(s->tr_pktcnt) - ntohl(r->tr_pktcnt));
if (g_out) g_pct = (g_lost * 100 + (g_out >> 1))/ g_out;
else g_pct = 0;
@ -922,35 +1029,35 @@ stat_line(r, s, have_next, rst)
sprintf(g_str, "%3d", g_pct);
else memcpy(g_str, " --", 4);
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);
if (!tunstats)
printf(" ");
printf("%6d/%-5d=%s%%%4d pps\n",
g_lost, g_out, g_str, g_pps);
break;
#if 0
case INS:
g_out = ntohl(s->tr_pktcnt) - ntohl(r->tr_pktcnt);
g_pps = g_out / timediff;
whochar = 'v';
/* Fall through */
#endif
case OUTS:
if (!tunstats)
printf(" ");
printf(" ?/%-5d %4d pps\n",
g_out, g_pps);
break;
case INS:
v_out = ntohl(s->tr_vifin) - ntohl(r->tr_vifin);
v_pps = v_out / timediff;
/* Fall through */
case OUTS:
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));
@ -962,7 +1069,6 @@ stat_line(r, s, have_next, rst)
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);
}
}
@ -980,11 +1086,12 @@ fixup_stats(base, prev, new)
struct tr_resp *n = new->resps + rno;
int *r = reset + rno;
int *s = swaps + rno;
int *t = bogustime + rno;
int res;
/* Check for byte-swappers */
while (--rno >= 0) {
--n; --p; --b; --s;
--n; --p; --b; --s; --t;
if (*s || abs(ntohl(n->tr_vifout) - ntohl(p->tr_vifout)) > 100000) {
/* This host sends byteswapped reports; swap 'em */
if (!*s) {
@ -1000,6 +1107,26 @@ fixup_stats(base, prev, new)
n->tr_vifout = byteswap(n->tr_vifout);
n->tr_pktcnt = byteswap(n->tr_pktcnt);
}
/*
* A missing parenthesis in mrouted 3.5-3.8's prune.c
* causes extremely bogus time diff's.
* One half of the time calculation was
* inside an htonl() and one half wasn't. Therefore, on
* a little-endian machine, both halves of the calculation
* would get added together in the little end. Thus, the
* low-order 2 bytes are either 0000 (no overflow) or
* 0100 (overflow from the addition).
*
* Odds are against these particular bit patterns
* happening in both prev and new for actual time values.
*/
if (*t || ((ntohl(n->tr_qarr) & 0xfeff) == 0x0000) &&
((ntohl(p->tr_qarr) & 0xfeff) == 0x0000)) {
*t = 1;
n->tr_qarr = new->rtime;
p->tr_qarr = prev->rtime;
b->tr_qarr = base->rtime;
}
}
rno = base->len;
@ -1064,24 +1191,39 @@ print_stats(base, prev, new)
int *r = reset + rno;
u_long resptime = new->rtime;
u_long qarrtime = fixtime(ntohl(n->tr_qarr));
u_int ttl = n->tr_fttl;
u_int ttl = n->tr_fttl + 1;
int first = (base == prev);
VAL_TO_MASK(smask, b->tr_smask);
printf(" Source Response Dest");
printf(" Packet Statistics For Only For Traffic\n");
printf("%-15s %-15s All Multicast Traffic From %s\n",
printf(" Source Response Dest ");
if (tunstats)
printf("Packet Statistics For Only For Traffic\n");
else
printf("Overall Packet Statistics For Traffic From\n");
(void)inet_fmt(qsrc, s1);
printf("%-15s %-15s ",
((b->tr_inaddr & smask) == (qsrc & smask)) ? s1 : " * * * ",
inet_fmt(base->qhdr.tr_raddr, s2), inet_fmt(qsrc, s1));
inet_fmt(base->qhdr.tr_raddr, s2));
if (tunstats)
printf("All Multicast Traffic From %s\n", s1);
else
printf("Packet %s To %s\n", s1, inet_fmt(qgrp, s2));
rtt = t_diff(resptime, new->qtime);
ms = scale(&rtt);
printf(" %c __/ rtt%5d%s Lost/Sent = Pct Rate To %s\n",
first ? 'v' : '|', rtt, ms, inet_fmt(qgrp, s2));
if (!first) {
printf(" %c __/ rtt%5d%s ",
(first && !verbose) ? 'v' : '|', rtt, ms);
if (tunstats)
printf("Lost/Sent = Pct Rate To %s\n",inet_fmt(qgrp, s2));
else
printf(" Rate Lost/Sent = Pct Rate\n");
if (!first || verbose) {
hop = t_diff(resptime, qarrtime);
ms = scale(&hop);
printf(" v / hop%5d%s", hop, ms);
printf(" --------------------- --------------------\n");
printf(" v / hop%5d%s ", hop, ms);
if (tunstats)
printf("--------------------- --------------------\n");
else
printf("------- ---------------------\n");
}
if (debug > 2) {
printf("\t\t\t\tv_in: %ld ", ntohl(n->tr_vifin));
@ -1097,39 +1239,46 @@ print_stats(base, prev, new)
}
while (TRUE) {
if ((n->tr_inaddr != b->tr_inaddr) || (n->tr_inaddr != b->tr_inaddr))
if ((n->tr_inaddr != b->tr_inaddr) || (n->tr_outaddr != b->tr_outaddr))
return 1; /* Route changed */
if ((n->tr_inaddr != n->tr_outaddr))
if ((n->tr_inaddr != n->tr_outaddr) && n->tr_inaddr)
printf("%-15s\n", inet_fmt(n->tr_inaddr, s1));
printf("%-15s %-14s %s\n", inet_fmt(n->tr_outaddr, s1), names[rno],
flag_type(n->tr_rflags));
printf("%-15s %-14s %s%s\n", inet_fmt(n->tr_outaddr, s1), names[rno],
flag_type(n->tr_rflags), *r ? " [reset counters]" : "");
if (rno-- < 1) break;
printf(" %c ^ ttl%5d ", first ? 'v' : '|', ttl);
printf(" %c ^ ttl%5d ", (first && !verbose) ? 'v' : '|',
ttl);
stat_line(p, n, TRUE, r);
if (!first) {
if (!first || verbose) {
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);
if (first)
printf("\n");
else
stat_line(b, n, TRUE, r);
}
--b, --p, --n, --r;
if (ttl < n->tr_fttl) ttl = n->tr_fttl;
else ++ttl;
ttl = MaX(ttl, n->tr_fttl + base->len - rno);
}
printf(" %c \\__ ttl%5d ", first ? 'v' : '|', ttl);
printf(" %c \\__ ttl%5d ", (first && !verbose) ? 'v' : '|',
ttl);
stat_line(p, n, FALSE, r);
if (!first) {
if (!first || verbose) {
hop = t_diff(qarrtime, new->qtime);
ms = scale(&hop);
printf(" v \\ hop%5d%s", hop, ms);
stat_line(b, n, FALSE, r);
if (first)
printf("\n");
else
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");
@ -1195,6 +1344,15 @@ char *argv[];
case 'M': /* Use multicast for reponse */
multicast = TRUE;
break;
case 'U': /* Use unicast for response */
unicast = TRUE;
break;
case 'T': /* Print confusing tunnel stats */
tunstats = TRUE;
break;
case 'W': /* Cisco's "weak" mtrace */
weak = TRUE;
break;
case 'l': /* Loop updating stats indefinitely */
numstats = 3153600;
break;
@ -1277,7 +1435,16 @@ char *argv[];
}
if (argc > 0 && (qsrc = host_addr(argv[0]))) { /* Source of path */
if (IN_MULTICAST(ntohl(qsrc))) goto usage;
if (IN_MULTICAST(ntohl(qsrc))) {
if (gwy) {
/* Should probably rewrite arg parsing at some point, as
* this makes "mtrace -g foo 224.1.2.3 224.2.3.4" valid!... */
qgrp = qsrc;
qsrc = 0;
} else {
goto usage;
}
}
argv++, argc--;
if (argc > 0 && (qdst = host_addr(argv[0]))) { /* Dest of path */
argv++, argc--;
@ -1298,7 +1465,7 @@ char *argv[];
return(0);
}
if (argc > 0 || qsrc == 0) {
if (argc > 0) {
usage: printf("\
Usage: mtrace [-Mlnps] [-w wait] [-m max_hops] [-q nqueries] [-g gateway]\n\
[-S statint] [-t ttl] [-r resp_dest] [-i if_addr] source [receiver] [group]\n");
@ -1312,7 +1479,16 @@ Usage: mtrace [-Mlnps] [-w wait] [-m max_hops] [-q nqueries] [-g gateway]\n\
defgrp = htonl(0xE0020001); /* MBone Audio (224.2.0.1) */
query_cast = htonl(0xE0000002); /* All routers multicast addr */
resp_cast = htonl(0xE0000120); /* Mtrace response multicast addr */
if (qgrp == 0) qgrp = defgrp;
if (qgrp == 0) {
if (!weak)
qgrp = defgrp;
/* Stats are useless without a group */
fprintf(stderr, "mtrace: WARNING: no multicast group specified, so no statistics printed\n");
numstats = 0;
} else {
if (weak)
fprintf(stderr, "mtrace: WARNING: group was specified so not performing \"weak\" mtrace\n");
}
/*
* Get default local address for multicasts to use in setting defaults.
@ -1321,7 +1497,7 @@ Usage: mtrace [-Mlnps] [-w wait] [-m max_hops] [-q nqueries] [-g gateway]\n\
#if (defined(BSD) && (BSD >= 199103))
addr.sin_len = sizeof(addr);
#endif
addr.sin_addr.s_addr = qgrp;
addr.sin_addr.s_addr = qgrp ? qgrp : query_cast;
addr.sin_port = htons(2000); /* Any port above 1024 will do */
if (((udp = socket(AF_INET, SOCK_DGRAM, 0)) < 0) ||
@ -1363,8 +1539,15 @@ Usage: mtrace [-Mlnps] [-w wait] [-m max_hops] [-q nqueries] [-g gateway]\n\
/*
* Default destination for path to be queried is the local host.
* When gateway specified, default destination is that gateway
* and default source is local host.
*/
if (qdst == 0) qdst = lcl_addr ? lcl_addr : addr.sin_addr.s_addr;
if (qdst == 0)
qdst = gwy ? gwy : (lcl_addr ? lcl_addr : addr.sin_addr.s_addr);
if (qsrc == 0 && gwy)
qsrc = lcl_addr ? lcl_addr : addr.sin_addr.s_addr;
if (qsrc == 0)
goto usage;
dst_netmask = get_netmask(udp, qdst);
close(udp);
if (lcl_addr == 0) lcl_addr = addr.sin_addr.s_addr;
@ -1382,15 +1565,25 @@ Usage: mtrace [-Mlnps] [-w wait] [-m max_hops] [-q nqueries] [-g gateway]\n\
/*
* Protect against unicast queries to mrouted versions that might crash.
* Also use the obsolete "can mtrace" neighbor bit to warn about
* older implementations.
*/
if (gwy && !IN_MULTICAST(ntohl(gwy)))
if (send_recv(gwy, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS2, 1, &incr[0])) {
int version = ntohl(incr[0].igmp.igmp_group.s_addr) & 0xFFFF;
if (version == 0x0303 || version == 0x0503) {
int flags = ntohl(incr[0].igmp.igmp_group.s_addr);
int version = flags & 0xFFFF;
int info = (flags & 0xFF0000) >> 16;
if (version == 0x0303 || version == 0x0503) {
printf("Don't use -g to address an mrouted 3.%d, it might crash\n",
(version >> 8) & 0xFF);
exit(0);
}
if ((info & 0x08) == 0) {
printf("mtrace: ");
print_host(gwy);
printf(" probably doesn't support mtrace, trying anyway...\n");
}
}
printf("Mtrace from %s to %s via group %s\n",
@ -1409,6 +1602,17 @@ Usage: mtrace [-Mlnps] [-w wait] [-m max_hops] [-q nqueries] [-g gateway]\n\
if (IN_MULTICAST(ntohl(raddr))) k_join(raddr, lcl_addr);
} else k_join(resp_cast, lcl_addr);
restart:
/*
* Zero out bug-avoidance counters
*/
memset(reset, 0, sizeof(reset));
memset(swaps, 0, sizeof(swaps));
memset(bogustime, 0, sizeof(bogustime));
memset(&base, 0, sizeof(base));
/*
* If the destination is on the local net, the last-hop router can
* be found by multicast to the all-routers multicast group.
@ -1416,12 +1620,14 @@ Usage: mtrace [-Mlnps] [-w wait] [-m max_hops] [-q nqueries] [-g gateway]\n\
* query since by definition the last-hop router will be a member.
* Set default TTLs for local remote multicasts.
*/
restart:
if (gwy == 0)
if ((qdst & dst_netmask) == (lcl_addr & dst_netmask)) tdst = query_cast;
else tdst = qgrp;
else tdst = gwy;
if (tdst == 0 && weak) {
fprintf(stderr, "mtrace: -W requires -g if destination is not local.\n");
exit(1);
}
if (IN_MULTICAST(ntohl(tdst))) {
k_set_loop(1); /* If I am running on a router, I need to hear this */
@ -1462,7 +1668,7 @@ Usage: mtrace [-Mlnps] [-w wait] [-m max_hops] [-q nqueries] [-g gateway]\n\
print_trace(1, &base);
r = base.resps + base.len - 1;
if (r->tr_rflags == TR_OLD_ROUTER || r->tr_rflags == TR_NO_SPACE ||
qno != 0) {
(qno != 0 && r->tr_rmtaddr != 0)) {
printf("%3d ", -(base.len+1));
what_kind(&base, r->tr_rflags == TR_OLD_ROUTER ?
"doesn't support mtrace"
@ -1598,7 +1804,18 @@ or multicast at ttl %d doesn't reach its last-hop router for that source\n",
exit(1);
}
printf("Round trip time %d ms\n\n", t_diff(base.rtime, base.qtime));
printf("Round trip time %d ms; ", t_diff(base.rtime, base.qtime));
{
struct tr_resp *n = base.resps + base.len - 1;
u_int ttl = n->tr_fttl + 1;
rno = base.len - 1;
while (--rno > 0) {
--n;
ttl = MaX(ttl, n->tr_fttl + base.len - rno);
}
printf("total ttl of %d required.\n\n",ttl);
}
/*
* Use the saved response which was the longest one received,
@ -1623,7 +1840,11 @@ or multicast at ttl %d doesn't reach its last-hop router for that source\n",
if (recvlen == 0) {
printf("Timed out.\n");
exit(1);
if (numstats) {
numstats++;
continue;
} else
exit(1);
}
if (rno != new->len) {
@ -1649,6 +1870,7 @@ or multicast at ttl %d doesn't reach its last-hop router for that source\n",
printf("Route changed:\n");
print_trace(1, new);
printf("Restarting.\n\n");
numstats++;
goto restart;
}
prev = new;

View File

@ -7,7 +7,7 @@
* Leland Stanford Junior University.
*
*
* $Id: prune.c,v 3.8 1995/11/29 22:36:34 fenner Rel $
* $Id: prune.c,v 3.8.1.4 1996/09/06 18:26:29 fenner Exp $
*/
@ -1234,17 +1234,11 @@ accept_prune(src, dst, p, datalen)
return;
}
if ((pt = find_prune_entry(src, g->gt_pruntbl)) != NULL) {
/*
* If it's about to expire, then it's only still around because
* of timer granularity, so don't warn about it.
*/
if (pt->pt_timer > 10) {
log(LOG_WARNING, 0, "%s %d from %s for (%s %s)/%d %s %d %s %x",
"duplicate prune received on vif",
vifi, inet_fmt(src, s1), inet_fmt(prun_src, s2),
inet_fmt(prun_grp, s3), prun_tmr,
"old timer:", pt->pt_timer, "cur gm:", g->gt_grpmems);
}
log(LOG_DEBUG, 0, "%s %d from %s for (%s %s)/%d %s %d %s %x",
"duplicate prune received on vif",
vifi, inet_fmt(src, s1), inet_fmt(prun_src, s2),
inet_fmt(prun_grp, s3), prun_tmr,
"old timer:", pt->pt_timer, "cur gm:", g->gt_grpmems);
pt->pt_timer = prun_tmr;
} else {
/* allocate space for the prune structure */
@ -1947,6 +1941,7 @@ dump_cache(fp2)
register struct stable *st;
register struct ptable *pt;
register vifi_t i;
char c;
register time_t thyme = time(0);
fprintf(fp2,
@ -1988,15 +1983,19 @@ dump_cache(fp2)
VIFM_ISSET(i, gt->gt_scope) ? 'b' : 'p');
}
fprintf(fp2, "\n");
if (gt->gt_pruntbl) {
fprintf(fp2, "<");
c = '(';
for (pt = gt->gt_pruntbl; pt; pt = pt->pt_next) {
fprintf(fp2, "%c%s:%d/%d", c, inet_fmt(pt->pt_router, s1),
pt->pt_vifi, pt->pt_timer);
c = ',';
}
fprintf(fp2, ")\n");
}
for (st = gt->gt_srctbl; st; st = st->st_next) {
fprintf(fp2, ">%s\n", inet_fmt(st->st_origin, s1));
}
#ifdef DEBUG_PRUNES
for (pt = gt->gt_pruntbl; pt; pt = pt->pt_next) {
fprintf(fp2, "<r:%s v:%d t:%d\n", inet_fmt(pt->pt_router, s1),
pt->pt_vifi, pt->pt_timer);
}
#endif
}
}
@ -2169,8 +2168,8 @@ accept_mtrace(src, dst, group, data, no, datalen)
bzero(resp, sizeof(struct tr_resp));
datalen += RLEN;
resp->tr_qarr = htonl((tp.tv_sec + JAN_1970) << 16) +
((tp.tv_usec >> 4) & 0xffff);
resp->tr_qarr = htonl(((tp.tv_sec + JAN_1970) << 16) +
((tp.tv_usec << 10) / 15625));
resp->tr_rproto = PROTO_DVMRP;
if (errcode != TR_NO_ERR) {

View File

@ -7,7 +7,7 @@
* Leland Stanford Junior University.
*
*
* $Id: route.c,v 3.8 1995/11/29 22:36:57 fenner Rel $
* $Id: route.c,v 3.8.1.1 1996/08/09 22:46:20 fenner Exp $
*/
@ -862,6 +862,8 @@ report(which_routes, vifi, dst)
u_int32 mask = 0;
u_int32 src;
u_int32 nflags;
int metric;
int admetric = uvifs[vifi].uv_admetric;
src = uvifs[vifi].uv_lcl_addr;
@ -918,9 +920,12 @@ report(which_routes, vifi, dst)
for (i = 0; i < width; ++i)
*p++ = ((char *)&(r->rt_origin))[i];
*p++ = (r->rt_parent == vifi && r->rt_metric != UNREACHABLE) ?
(char)(r->rt_metric + UNREACHABLE) : /* "poisoned reverse" */
(char)(r->rt_metric);
metric = r->rt_metric + admetric;
if (metric > UNREACHABLE)
metric = UNREACHABLE;
*p++ = (r->rt_parent == vifi && metric != UNREACHABLE) ?
(char)(metric + UNREACHABLE) : /* "poisoned reverse" */
(char)(metric);
datalen += width + 1;
}
@ -1001,6 +1006,8 @@ report_chunk(start_rt, vifi, dst)
u_int32 mask = 0;
u_int32 src;
u_int32 nflags;
int admetric = uvifs[vifi].uv_admetric;
int metric;
src = uvifs[vifi].uv_lcl_addr;
p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
@ -1042,9 +1049,12 @@ report_chunk(start_rt, vifi, dst)
for (i = 0; i < width; ++i)
*p++ = ((char *)&(r->rt_origin))[i];
*p++ = (r->rt_parent == vifi && r->rt_metric != UNREACHABLE) ?
(char)(r->rt_metric + UNREACHABLE) : /* "poisoned reverse" */
(char)(r->rt_metric);
metric = r->rt_metric + admetric;
if (metric > UNREACHABLE)
metric = UNREACHABLE;
*p++ = (r->rt_parent == vifi && metric != UNREACHABLE) ?
(char)(metric + UNREACHABLE) : /* "poisoned reverse" */
(char)(metric);
++nrt;
datalen += width + 1;
}

View File

@ -112,7 +112,11 @@ rsrr_read(f, rfd)
fd_set *rfd;
{
register int rsrr_recvlen;
#ifdef SYSV
sigset_t block, oblock;
#else
register int omask;
#endif
bzero((char *) &client_addr, sizeof(client_addr));
rsrr_recvlen = recvfrom(rsrr_socket, rsrr_recv_buf, sizeof(rsrr_recv_buf),
@ -122,10 +126,21 @@ rsrr_read(f, rfd)
log(LOG_ERR, errno, "RSRR recvfrom");
return;
}
#ifdef SYSV
(void)sigemptyset(&block);
(void)sigaddset(&block, SIGALRM);
if (sigprocmask(SIG_BLOCK, &block, &oblock) < 0)
log(LOG_ERR, errno, "sigprocmask");
#else
/* Use of omask taken from main() */
omask = sigblock(sigmask(SIGALRM));
#endif
rsrr_accept(rsrr_recvlen);
#ifdef SYSV
(void)sigprocmask(SIG_SETMASK, &oblock, (sigset_t *)NULL);
#else
(void)sigsetmask(omask);
#endif
}
/* Accept a message from the reservation protocol and take

View File

@ -7,7 +7,7 @@
* Leland Stanford Junior University.
*
*
* $Id: vif.c,v 3.8 1995/11/29 22:36:57 fenner Rel $
* $Id: vif.c,v 3.8.1.2 1996/08/09 22:42:13 fenner Exp $
*/
@ -163,8 +163,18 @@ check_vif_state()
register vifi_t vifi;
register struct uvif *v;
struct ifreq ifr;
static int checking_vifs = 0;
/*
* If we get an error while checking, (e.g. two interfaces go down
* at once, and we decide to send a prune out one of the failed ones)
* then don't go into an infinite loop!
*/
if (checking_vifs)
return;
vifs_down = FALSE;
checking_vifs = 1;
for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
if (v->uv_flags & VIFF_DISABLED) continue;
@ -176,25 +186,26 @@ check_vif_state()
if (v->uv_flags & VIFF_DOWN) {
if (ifr.ifr_flags & IFF_UP) {
v->uv_flags &= ~VIFF_DOWN;
start_vif(vifi);
log(LOG_INFO, 0,
log(LOG_NOTICE, 0,
"%s has come up; vif #%u now in service",
v->uv_name, vifi);
v->uv_flags &= ~VIFF_DOWN;
start_vif(vifi);
}
else vifs_down = TRUE;
}
else {
if (!(ifr.ifr_flags & IFF_UP)) {
stop_vif(vifi);
v->uv_flags |= VIFF_DOWN;
log(LOG_INFO, 0,
log(LOG_NOTICE, 0,
"%s has gone down; vif #%u taken out of service",
v->uv_name, vifi);
stop_vif(vifi);
v->uv_flags |= VIFF_DOWN;
vifs_down = TRUE;
}
}
}
checking_vifs = 0;
}
/*
@ -704,33 +715,7 @@ accept_neighbor_request(src, dst)
u_char *p, *ncount;
struct listaddr *la;
int datalen;
u_int32 temp_addr, us, them = src;
/* Determine which of our addresses to use as the source of our response
* to this query.
*/
if (IN_MULTICAST(ntohl(dst))) { /* query sent to a multicast group */
int udp; /* find best interface to reply on */
struct sockaddr_in addr;
int addrlen = sizeof(addr);
addr.sin_family = AF_INET;
#if (defined(BSD) && (BSD >= 199103))
addr.sin_len = sizeof addr;
#endif
addr.sin_addr.s_addr = dst;
addr.sin_port = htons(2000); /* any port over 1024 will do... */
if ((udp = socket(AF_INET, SOCK_DGRAM, 0)) < 0
|| connect(udp, (struct sockaddr *) &addr, sizeof(addr)) < 0
|| getsockname(udp, (struct sockaddr *) &addr, &addrlen) < 0) {
log(LOG_WARNING, errno, "Determining local address");
close(udp);
return;
}
close(udp);
us = addr.sin_addr.s_addr;
} else /* query sent to us alone */
us = dst;
u_int32 temp_addr, them = src;
#define PUT_ADDR(a) temp_addr = ntohl(a); \
*p++ = temp_addr >> 24; \
@ -751,7 +736,7 @@ accept_neighbor_request(src, dst)
/* Make sure that there's room for this neighbor... */
if (datalen + (ncount == 0 ? 4 + 3 + 4 : 4) > MAX_DVMRP_DATA_LEN) {
send_igmp(us, them, IGMP_DVMRP, DVMRP_NEIGHBORS,
send_igmp(INADDR_ANY, them, IGMP_DVMRP, DVMRP_NEIGHBORS,
htonl(MROUTED_LEVEL), datalen);
p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
datalen = 0;
@ -775,8 +760,8 @@ accept_neighbor_request(src, dst)
}
if (datalen != 0)
send_igmp(us, them, IGMP_DVMRP, DVMRP_NEIGHBORS, htonl(MROUTED_LEVEL),
datalen);
send_igmp(INADDR_ANY, them, IGMP_DVMRP, DVMRP_NEIGHBORS,
htonl(MROUTED_LEVEL), datalen);
}
/*
@ -791,33 +776,7 @@ accept_neighbor_request2(src, dst)
u_char *p, *ncount;
struct listaddr *la;
int datalen;
u_int32 us, them = src;
/* Determine which of our addresses to use as the source of our response
* to this query.
*/
if (IN_MULTICAST(ntohl(dst))) { /* query sent to a multicast group */
int udp; /* find best interface to reply on */
struct sockaddr_in addr;
int addrlen = sizeof(addr);
addr.sin_family = AF_INET;
#if (defined(BSD) && (BSD >= 199103))
addr.sin_len = sizeof addr;
#endif
addr.sin_addr.s_addr = dst;
addr.sin_port = htons(2000); /* any port over 1024 will do... */
if ((udp = socket(AF_INET, SOCK_DGRAM, 0)) < 0
|| connect(udp, (struct sockaddr *) &addr, sizeof(addr)) < 0
|| getsockname(udp, (struct sockaddr *) &addr, &addrlen) < 0) {
log(LOG_WARNING, errno, "Determining local address");
close(udp);
return;
}
close(udp);
us = addr.sin_addr.s_addr;
} else /* query sent to us alone */
us = dst;
u_int32 them = src;
p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
datalen = 0;
@ -847,7 +806,7 @@ accept_neighbor_request2(src, dst)
if (rflags & DVMRP_NF_TUNNEL)
rflags |= DVMRP_NF_DOWN;
if (datalen > MAX_DVMRP_DATA_LEN - 12) {
send_igmp(us, them, IGMP_DVMRP, DVMRP_NEIGHBORS2,
send_igmp(INADDR_ANY, them, IGMP_DVMRP, DVMRP_NEIGHBORS2,
htonl(MROUTED_LEVEL), datalen);
p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
datalen = 0;
@ -865,7 +824,7 @@ accept_neighbor_request2(src, dst)
for ( ; la; la = la->al_next) {
/* Make sure that there's room for this neighbor... */
if (datalen + (ncount == 0 ? 4+4+4 : 4) > MAX_DVMRP_DATA_LEN) {
send_igmp(us, them, IGMP_DVMRP, DVMRP_NEIGHBORS2,
send_igmp(INADDR_ANY, them, IGMP_DVMRP, DVMRP_NEIGHBORS2,
htonl(MROUTED_LEVEL), datalen);
p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
datalen = 0;
@ -890,8 +849,8 @@ accept_neighbor_request2(src, dst)
}
}
if (datalen != 0)
send_igmp(us, them, IGMP_DVMRP, DVMRP_NEIGHBORS2, htonl(MROUTED_LEVEL),
datalen);
send_igmp(INADDR_ANY, them, IGMP_DVMRP, DVMRP_NEIGHBORS2,
htonl(MROUTED_LEVEL), datalen);
}
void

View File

@ -7,7 +7,7 @@
* Leland Stanford Junior University.
*
*
* $Id: vif.h,v 3.8 1995/11/29 22:36:57 fenner Rel $
* $Id: vif.h,v 3.8.1.1 1996/08/09 22:46:19 fenner Exp $
*/
/*
@ -20,6 +20,7 @@
struct uvif {
u_short uv_flags; /* VIFF_ flags defined below */
u_char uv_metric; /* cost of this vif */
u_char uv_admetric; /* advertised cost of this vif */
u_int uv_rate_limit; /* rate limit on this vif */
u_char uv_threshold; /* min ttl required to forward on vif */
u_int32 uv_lcl_addr; /* local address of this vif */