Commit c6911250 authored by David Anderson's avatar David Anderson
Browse files

Checkpoint commit. I've added the static-linked program "ltevent" to send

and wait for linktest events, and integrated it into the perl scripts.

At this point I'm working on small potatoes such as the rc.setup script
to invoke linktest daemon and nailing down where to put platform-specific
stuff such as the ns-linktest build and the customized tb-compat.

Also am testing linktest in cases where I've deliberately inserted an error
to make sure it catches it.
parent eae5072e
...@@ -11,6 +11,7 @@ SUBDIR = event/linktest ...@@ -11,6 +11,7 @@ SUBDIR = event/linktest
LIBTBDIR = $(OBJDIR)/lib/libtb LIBTBDIR = $(OBJDIR)/lib/libtb
LIBEVENTDIR = ../lib LIBEVENTDIR = ../lib
DAEMON = linktest DAEMON = linktest
LTEVENT = ltevent
SCRIPT = linktest.pl SCRIPT = linktest.pl
SCRIPT_RUN = run_linktest.pl SCRIPT_RUN = run_linktest.pl
...@@ -18,7 +19,7 @@ SYSTEM := $(shell uname -s) ...@@ -18,7 +19,7 @@ SYSTEM := $(shell uname -s)
include $(OBJDIR)/Makeconf include $(OBJDIR)/Makeconf
all: $(DAEMON) $(SCRIPT) $(SCRIPT_RUN) all: $(DAEMON) $(LTEVENT) $(SCRIPT) $(SCRIPT_RUN)
include $(TESTBED_SRCDIR)/GNUmakerules include $(TESTBED_SRCDIR)/GNUmakerules
...@@ -42,6 +43,7 @@ endif ...@@ -42,6 +43,7 @@ endif
LIBTB_OBJS = $(LIBTBDIR)/log.o $(LIBTBDIR)/tbdefs.o LIBTB_OBJS = $(LIBTBDIR)/log.o $(LIBTBDIR)/tbdefs.o
DAEMON_OBJS = linktest.o DAEMON_OBJS = linktest.o
LTEVENT_OBJS = ltevent.o
# Rules to make sure that some libraries we need from other directories get # Rules to make sure that some libraries we need from other directories get
# built first # built first
...@@ -56,13 +58,21 @@ $(DAEMON): $(DAEMON_OBJS) $(LIBTB_OBJS) ...@@ -56,13 +58,21 @@ $(DAEMON): $(DAEMON_OBJS) $(LIBTB_OBJS)
-mkdir $(LOCAL_BINDIR) -mkdir $(LOCAL_BINDIR)
$(CC) $(LDFLAGS) $(DAEMON_OBJS) $(LIBTB_OBJS) $(LIBS) -o $(LOCAL_BINDIR)/$@ $(CC) $(LDFLAGS) $(DAEMON_OBJS) $(LIBTB_OBJS) $(LIBS) -o $(LOCAL_BINDIR)/$@
$(LTEVENT): $(LTEVENT_OBJS) $(LIBTB_OBJS)
-mkdir $(LOCAL_BINDIR)
$(CC) $(LDFLAGS) $(LTEVENT_OBJS) $(LIBTB_OBJS) $(LIBS) -o $(LOCAL_BINDIR)/$@
$(DAEMON_OBJS): linktest.h ../lib/libevent.a ../lib/event.h $(DAEMON_OBJS): linktest.h ../lib/libevent.a ../lib/event.h
$(LTEVENT_OBJS): ../lib/libevent.a ../lib/event.h
install: install:
client-install: client-install:
$(INSTALL_PROGRAM) $(LOCAL_BINDIR)/$(DAEMON) \ $(INSTALL_PROGRAM) $(LOCAL_BINDIR)/$(DAEMON) \
$(DESTDIR)$(CLIENT_BINDIR)/$(DAEMON) $(DESTDIR)$(CLIENT_BINDIR)/$(DAEMON)
$(INSTALL_PROGRAM) $(LOCAL_BINDIR)/$(LTEVENT) \
$(DESTDIR)$(CLIENT_BINDIR)/$(LTEVENT)
$(INSTALL_PROGRAM) $(SCRIPT) \ $(INSTALL_PROGRAM) $(SCRIPT) \
$(DESTDIR)$(CLIENT_BINDIR)/$(SCRIPT) $(DESTDIR)$(CLIENT_BINDIR)/$(SCRIPT)
$(INSTALL_PROGRAM) $(SCRIPT_RUN) \ $(INSTALL_PROGRAM) $(SCRIPT_RUN) \
...@@ -71,3 +81,6 @@ client-install: ...@@ -71,3 +81,6 @@ client-install:
clean: clean:
/bin/rm -f *.o $(TESTS) /bin/rm -f *.o $(TESTS)
/bin/rm -f $(LOCAL_BINDIR)/$(DAEMON) /bin/rm -f $(LOCAL_BINDIR)/$(DAEMON)
/bin/rm -f $(LOCAL_BINDIR)/$(LTEVENT)
/bin/rm -f $(SCRIPT)
/bin/rm -f $(SCRIPT_RUN)
...@@ -73,8 +73,6 @@ main(int argc, char **argv) { ...@@ -73,8 +73,6 @@ main(int argc, char **argv) {
if (!pideid) if (!pideid)
usage(progname); usage(progname);
info("starting up\n");
loginit(0, logfile); loginit(0, logfile);
...@@ -106,20 +104,15 @@ main(int argc, char **argv) { ...@@ -106,20 +104,15 @@ main(int argc, char **argv) {
*/ */
tuple->expt = pideid; tuple->expt = pideid;
tuple->objtype = TBDB_OBJECTTYPE_LINKTEST; tuple->objtype = TBDB_OBJECTTYPE_LINKTEST;
tuple->objname = "linktest";
tuple->eventtype = ADDRESSTUPLE_ANY; tuple->eventtype = ADDRESSTUPLE_ANY;
/* /*
* Register with the event system. * Register with the event system.
*/ */
info("event_register...\n");
handle = event_register(server, 0); handle = event_register(server, 0);
if (handle == NULL) { if (handle == NULL) {
fatal("could not register with event system"); fatal("could not register with event system");
} }
info("registered with event system\n");
/* /*
* Subscribe to the event we specified above. * Subscribe to the event we specified above.
...@@ -127,15 +120,12 @@ main(int argc, char **argv) { ...@@ -127,15 +120,12 @@ main(int argc, char **argv) {
if (! event_subscribe(handle, callback, tuple, NULL)) { if (! event_subscribe(handle, callback, tuple, NULL)) {
fatal("could not subscribe to event"); fatal("could not subscribe to event");
} }
info("subscribed to event\n");
/* /*
* Begin the event loop, waiting to receive event notifications: * Begin the event loop, waiting to receive event notifications:
*/ */
info("starting main event loop\n");
event_main(handle); event_main(handle);
info("end main event loop\n");
/* /*
* Unregister with the event system: * Unregister with the event system:
...@@ -159,9 +149,6 @@ callback(event_handle_t handle, event_notification_t notification, void *data) ...@@ -159,9 +149,6 @@ callback(event_handle_t handle, event_notification_t notification, void *data)
gettimeofday(&now, NULL); gettimeofday(&now, NULL);
info("got a callback\n");
if (! event_notification_get_objname(handle, notification, if (! event_notification_get_objname(handle, notification,
objname, sizeof(objname))) { objname, sizeof(objname))) {
error("Could not get objname from notification!\n"); error("Could not get objname from notification!\n");
...@@ -177,39 +164,27 @@ callback(event_handle_t handle, event_notification_t notification, void *data) ...@@ -177,39 +164,27 @@ callback(event_handle_t handle, event_notification_t notification, void *data)
event_notification_get_arguments(handle, event_notification_get_arguments(handle,
notification, args, sizeof(args)); notification, args, sizeof(args));
info("Event: %lu:%d %s %s %s\n", now.tv_sec, now.tv_usec, /* info("Event: %lu:%d %s %s %s\n", now.tv_sec, now.tv_usec,
objname, event, args); objname, event, args);*/
/* /*
* Dispatch the event. * Dispatch the event.
*/ */
if (strcmp(event, TBDB_EVENTTYPE_START) == 0) if (strcmp(event, TBDB_EVENTTYPE_START) == 0) {
start_linktest(args, sizeof(args)); start_linktest(args, sizeof(args));
else {
error("Invalid event: %s\n", event);
return;
} }
} }
/* start one linktest at a time. /* convert arguments from the event into a form for Linktest.
*/ */
/* todo, move this to proper place */
#define MAX_ARGS 10
static void static void
start_linktest(char *args, int buflen) { start_linktest(char *args, int buflen) {
static int running = 0; /* is linktest currently running? */
pid_t lt_pid; pid_t lt_pid;
int status; int status;
char *word; char *word;
char *argv[MAX_ARGS]; char *argv[MAX_ARGS];
int i=1; int i=1;
if(running) return;
running = 1;
info("raw args: %s\n",args);
word = strtok(args," \t"); word = strtok(args," \t");
do { do {
argv[i++] = word; argv[i++] = word;
...@@ -217,16 +192,13 @@ start_linktest(char *args, int buflen) { ...@@ -217,16 +192,13 @@ start_linktest(char *args, int buflen) {
&& (i<MAX_ARGS)); && (i<MAX_ARGS));
argv[i] = NULL; argv[i] = NULL;
argv[0] = LINKTEST_SCRIPT; argv[0] = LINKTEST_SCRIPT;
info("starting linktest.\n"); /* info("starting linktest.\n");*/
lt_pid = fork(); lt_pid = fork();
if(!lt_pid) { if(!lt_pid) {
execv( LINKTEST_SCRIPT,argv); execv( LINKTEST_SCRIPT,argv);
} }
waitpid(lt_pid, &status, 0); waitpid(lt_pid, &status, 0);
running = 0; /* info("linktest completed.\n");*/
info("linktest completed.\n");
} }
...@@ -2,4 +2,8 @@ ...@@ -2,4 +2,8 @@
#define __LINKTEST_H_ #define __LINKTEST_H_
#define LINKTEST_SCRIPT "@CLIENT_BINDIR@" "/linktest.pl" #define LINKTEST_SCRIPT "@CLIENT_BINDIR@" "/linktest.pl"
/* max args to Linktest */
#define MAX_ARGS 10
#endif #endif
...@@ -3,11 +3,10 @@ ...@@ -3,11 +3,10 @@
# Linktest test script. # Linktest test script.
# #
# @author: davidand # @author: davidand
#
#
use strict; use strict;
use Class::Struct; use Class::Struct;
use constant STATIC => "Static";
use lib '@prefix@/lib';
use event;
# path to linktest special ns # path to linktest special ns
use constant LINKTEST_NSPATH => "@LINKTEST_NSPATH@"; use constant LINKTEST_NSPATH => "@LINKTEST_NSPATH@";
...@@ -26,18 +25,21 @@ use constant SEND_RATE => 400; # rude sends 1 more than specified here. ...@@ -26,18 +25,21 @@ use constant SEND_RATE => 400; # rude sends 1 more than specified here.
use constant SEND_COUNT => 401; use constant SEND_COUNT => 401;
# pathrate test limits -- see &valid_bw comment. # pathrate test limits -- see &valid_bw comment.
use constant HI_BW => 85000000; use constant PATHRATE_HI_BW => 80000000;
use constant LO_BW => 1000000; use constant PATHRATE_LO_BW => 1000000;
use constant HI_LOSS => 0; use constant PATHRATE_HI_LOSS => 0;
# supported OS's as returned by uname. # misc text contstants
use constant BSD => "FreeBSD"; use constant BSD => "FreeBSD";
use constant LINUX => "Linux"; use constant LINUX => "Linux";
use constant RTPROTO_STATIC => "Static";
use constant EVENT_STOP => "STOP";
use constant EVENT_SERVER => "boss";
# tolerance levelS # tolerance levelS
use constant LAT_TOL => 0.71; # units of ms use constant LAT_TOL => 0.71; # units of ms. Highest diff in finalpaper.
use constant BW_TOL => 3; # units of mb use constant BW_TOL => 2.13; # units of mb. The 99% quantile from finalpaper
use constant LOSS_TOL => 3; # number of standard deviations of binomial rv use constant LOSS_TOL => 3; # number of sd's. The 99% percentile of normal
# test levels # test levels
use constant PARSE_ONLY => 0; # parse and exit use constant PARSE_ONLY => 0; # parse and exit
...@@ -57,6 +59,8 @@ use constant SUFFIX_ERROR => ".error"; ...@@ -57,6 +59,8 @@ use constant SUFFIX_ERROR => ".error";
use constant SUFFIX_FATAL => ".fatal"; use constant SUFFIX_FATAL => ".fatal";
use constant SUFFIX_TOPO => ".topology"; use constant SUFFIX_TOPO => ".topology";
############################################################################## ##############################################################################
# Globals # Globals
############################################################################## ##############################################################################
...@@ -70,10 +74,10 @@ my $exp_id; # experiment id ...@@ -70,10 +74,10 @@ my $exp_id; # experiment id
my $proj_id; # project id my $proj_id; # project id
my $gid; # group id my $gid; # group id
my $platform; # name of platform my $platform; # name of platform
my $testlevel=99; # which tests to run (default, all) my $stopat=99; # which tests to run (default, all)
my $crude_pid; # pid of a crude process to harvest rude streams my $crude_pid; # pid of a crude process to harvest rude streams
my $pathrate_snd_pid; # pid of a pathrate_snd process to harvest rcv streams my $pathrate_snd_pid; # pid of a pathrate_snd process to harvest rcv streams
my $verbosity = 0; # enable debug statements my $debug_mode = 0; # enable debug statements
my $cumulative = 1; # cumulative tests (default,all) my $cumulative = 1; # cumulative tests (default,all)
my $barr_count; # used by synserv host, nubmer of hosts -1 my $barr_count; # used by synserv host, nubmer of hosts -1
my $server = "boss"; # event server. default to boss. my $server = "boss"; # event server. default to boss.
...@@ -106,43 +110,43 @@ my $run_in_path = "/users/davidand/testbed/event/linktest"; ...@@ -106,43 +110,43 @@ my $run_in_path = "/users/davidand/testbed/event/linktest";
############################################################################## ##############################################################################
# Main control # Main control
############################################################################## ##############################################################################
&proc_cmd; &proc_cmd;
&init; &init;
if($testlevel == PARSE_ONLY) { if($stopat == PARSE_ONLY) {
&debug_top; &debug_top;
} }
if(($cumulative && $testlevel >= ONEHOP_LEVEL) if(($cumulative && $stopat >= ONEHOP_LEVEL)
|| (!$cumulative && $testlevel == ONEHOP_LEVEL)) { || (!$cumulative && $stopat == ONEHOP_LEVEL)) {
&debug("\nTesting Single Hop Connectivity and Latency...\n\n"); &debug("\nTesting Single Hop Connectivity and Latency...\n\n");
&ping_latency_test; &ping_latency_test;
} }
if((($cumulative && $testlevel >= NHOP_LEVEL) if((($cumulative && $stopat >= NHOP_LEVEL)
|| (!$cumulative && $testlevel == NHOP_LEVEL)) || (!$cumulative && $stopat == NHOP_LEVEL))
&& defined($rtproto) && $rtproto eq STATIC) { && defined($rtproto) && $rtproto eq RTPROTO_STATIC) {
&debug("\nTesting Static Routing...\n\n"); &debug("\nTesting Static Routing...\n\n");
&static_rt_test; # nodes not covered by 1hop test &static_rt_test; # nodes not covered by 1hop test
} }
if (($cumulative && $testlevel >=LOSS_LEVEL) if (($cumulative && $stopat >=LOSS_LEVEL)
|| (!$cumulative && $testlevel ==LOSS_LEVEL)) { || (!$cumulative && $stopat ==LOSS_LEVEL)) {
&debug("\nTesting Loss...\n\n"); &debug("\nTesting Loss...\n\n");
&stream_test; &stream_test;
} }
if(($cumulative && $testlevel >=BW_LEVEL) if(($cumulative && $stopat >=BW_LEVEL)
|| (!$cumulative && $testlevel == BW_LEVEL)) { || (!$cumulative && $stopat == BW_LEVEL)) {
&debug("\nTesting Bandwidth...\n\n"); &debug("\nTesting Bandwidth...\n\n");
&bw_test; &bw_test;
} }
&send_done; &send_done;
&debug("Done\n");
############################################################################## ##############################################################################
# Test procedures # Test procedures
############################################################################## ##############################################################################
...@@ -289,7 +293,7 @@ sub stream_test { ...@@ -289,7 +293,7 @@ sub stream_test {
if(defined($edge) && defined($other_edge)) { if(defined($edge) && defined($other_edge)) {
if($hostname eq $edge->src) { if($hostname eq $edge->src) {
# TODO: parameterize this call # TODO: parameterize this call
open FCFG,">" . RUDE_CFG || &fatal ("Could not open " . RUDE_CFG); open FCFG,">" . RUDE_CFG || die &fatal ("Could not open " . RUDE_CFG);
print FCFG "START NOW\n"; print FCFG "START NOW\n";
print FCFG "0000 $stream_id ON 3001 " . $edge->dst . ":10001 CONSTANT " . SEND_RATE . " 20\n"; print FCFG "0000 $stream_id ON 3001 " . $edge->dst . ":10001 CONSTANT " . SEND_RATE . " 20\n";
print FCFG "1000 $stream_id OFF\n"; print FCFG "1000 $stream_id OFF\n";
...@@ -298,7 +302,7 @@ sub stream_test { ...@@ -298,7 +302,7 @@ sub stream_test {
system "rude -s" . RUDE_CFG . " 1>/dev/null 2>/dev/null"; system "rude -s" . RUDE_CFG . " 1>/dev/null 2>/dev/null";
$analyze{$stream_id} = $other_edge; $analyze{$stream_id} = $other_edge;
} elsif ($hostname eq $other_edge->src) { } elsif ($hostname eq $other_edge->src) {
open FCFG,">" . RUDE_CFG || &fatal ("Could not open " . RUDE_CFG); open FCFG,">" . RUDE_CFG || die &fatal ("Could not open " . RUDE_CFG);
print FCFG "START NOW\n"; print FCFG "START NOW\n";
print FCFG "0000 $stream_id ON 3001 " . $other_edge->dst . ":10001 CONSTANT " . SEND_RATE . " 20\n"; print FCFG "0000 $stream_id ON 3001 " . $other_edge->dst . ":10001 CONSTANT " . SEND_RATE . " 20\n";
print FCFG "1000 $stream_id OFF\n"; print FCFG "1000 $stream_id OFF\n";
...@@ -318,7 +322,7 @@ sub stream_test { ...@@ -318,7 +322,7 @@ sub stream_test {
# now, analyze the data that this node RECEIVED, which will be the # now, analyze the data that this node RECEIVED, which will be the
# data that the other node sent. # data that the other node sent.
system "crude -d " . CRUDE_DAT . " > " . CRUDE_DEC; system "crude -d " . CRUDE_DAT . " > " . CRUDE_DEC;
open CLOG, "" . CRUDE_DEC || &fatal ("Could not open " . CRUDE_DEC); open CLOG, "" . CRUDE_DEC || die &fatal ("Could not open " . CRUDE_DEC);
while(<CLOG>) { while(<CLOG>) {
if(/ID=(\d+) /) { if(/ID=(\d+) /) {
$recv_cnt{$1}++; $recv_cnt{$1}++;
...@@ -374,7 +378,7 @@ sub bw_test { ...@@ -374,7 +378,7 @@ sub bw_test {
# blitz old data # blitz old data
if (-e PATHRATE_DAT) { if (-e PATHRATE_DAT) {
unlink PATHRATE_DAT || &fatal ("Could not delete " . PATHRATE_DAT); unlink PATHRATE_DAT || die &fatal ("Could not delete " . PATHRATE_DAT);
} }
...@@ -401,7 +405,7 @@ sub bw_test { ...@@ -401,7 +405,7 @@ sub bw_test {
# read the log file. # read the log file.
if(@analyze_list) { if(@analyze_list) {
open PLOG, "".PATHRATE_DAT || &fatal ("Could not open " . PATHRATE_DAT); open PLOG, "".PATHRATE_DAT || die &fatal ("Could not open " . PATHRATE_DAT);
while(<PLOG>) { while(<PLOG>) {
my $edge = shift(@analyze_list); my $edge = shift(@analyze_list);
my $sender = $edge->src; my $sender = $edge->src;
...@@ -428,7 +432,7 @@ sub bw_test { ...@@ -428,7 +432,7 @@ sub bw_test {
} }
} else { } else {
&fatal("Error while parsing " . PATHRATE_DAT); die &fatal("Error while parsing " . PATHRATE_DAT);
} }
} }
} }
...@@ -450,9 +454,9 @@ sub bw_test { ...@@ -450,9 +454,9 @@ sub bw_test {
# successful measurement, since it's rather lengthy to run (16s average). # successful measurement, since it's rather lengthy to run (16s average).
sub valid_bw { sub valid_bw {
my $edge = shift @_; my $edge = shift @_;
if($edge->bw >= LO_BW if($edge->bw >= PATHRATE_LO_BW
&& $edge->bw <= HI_BW && $edge->bw <= PATHRATE_HI_BW
&& $edge->loss <= HI_LOSS && $edge->loss <= PATHRATE_HI_LOSS
) { ) {
return 1; return 1;
} else { } else {
...@@ -467,7 +471,7 @@ sub valid_bw { ...@@ -467,7 +471,7 @@ sub valid_bw {
sub get_topo { sub get_topo {
my $ns_outfile = shift(@_); my $ns_outfile = shift(@_);
open NSOUT,$ns_outfile || &fatal("Could not open $ns_outfile"); open NSOUT,$ns_outfile || die &fatal("Could not open $ns_outfile");
while(<NSOUT>) { while(<NSOUT>) {
chomp; chomp;
...@@ -488,7 +492,7 @@ sub get_topo { ...@@ -488,7 +492,7 @@ sub get_topo {
# currently recognize only Static routing # currently recognize only Static routing
} elsif (/^r Static/i) { } elsif (/^r Static/i) {
$rtproto = STATIC; $rtproto = RTPROTO_STATIC;
} }
} }
close NSOUT; close NSOUT;
...@@ -525,10 +529,10 @@ sub error { ...@@ -525,10 +529,10 @@ sub error {
$output .= " Error: $msg\n\n"; $output .= " Error: $msg\n\n";
my $fname = $linktest_path . "/" . $hostname . SUFFIX_ERROR; my $fname = $linktest_path . "/" . $hostname . SUFFIX_ERROR;
open ERRF,">>$fname" || &fatal("Could not open $fname"); open ERRF,">>$fname" || die &fatal("Could not open $fname");
print ERRF $output; print ERRF $output;
close ERRF; close ERRF;
if($verbosity) { if($debug_mode) {
print STDERR $output; print STDERR $output;
} }
} }
...@@ -545,7 +549,7 @@ sub fatal { ...@@ -545,7 +549,7 @@ sub fatal {
print ERRF $output; print ERRF $output;
close ERRF; close ERRF;
} }
die $output; return $output;
} }
...@@ -555,7 +559,7 @@ sub barrier { ...@@ -555,7 +559,7 @@ sub barrier {
if($hostname eq $synserv) { if($hostname eq $synserv) {
# note, the synserver should know what the node count is # note, the synserver should know what the node count is
# since it parsed the NS file. # since it parsed the NS file.
&fatal("barrcount not defined!") unless defined($barr_count); die &fatal("barrcount not defined!") unless defined($barr_count);
$cmd = "emulab-sync -i $barr_count"; $cmd = "emulab-sync -i $barr_count";
} else { } else {
$cmd = "emulab-sync"; $cmd = "emulab-sync";
...@@ -566,7 +570,7 @@ sub barrier { ...@@ -566,7 +570,7 @@ sub barrier {
} }
sub debug { sub debug {
return unless $verbosity; return unless $debug_mode;
print "@_"; print "@_";
} }
...@@ -582,11 +586,11 @@ sub init { ...@@ -582,11 +586,11 @@ sub init {
} elsif ($platform eq LINUX) { } elsif ($platform eq LINUX) {
$ns_cmd = LINKTEST_NSPATH ."/linux/ns"; $ns_cmd = LINKTEST_NSPATH ."/linux/ns";
} else { } else {
&fatal("Platform $platform is not currently supported."); die &fatal("Platform $platform is not currently supported.");
} }
# if this is a dry run, get out here. # if this is a dry run, get out here.