Commit fe13d60f authored by Leigh Stoller's avatar Leigh Stoller

A bunch of backend delay node changes. Change the delays DB table to

hold separate values for each of the two pipes. This allows us to
treat the links asymmetrically with respect to the delay node
configuration. Changes to tmcd to return the expanded info, and rework
(completely) delay_config to allow user to change the duplex
characteristics (just like before), or just simplex characteristics by
specifying the pipe number. By convention (I invented) pipe 0 is
traffic coming in on iface0. Of course, none of the front end stuff
has been changed, so the changing a single pipe does not cause
anything in virt_lans to be changed, so those changes will be lost at
swapout. Also get rid of all the ssh'ed pipe config stuff in
delay_config. Instead, add a client side script called update_delays
to /etc/testbed on the experiment nodes. After updating the delays
table, just ssh over and run that script, which calls the existing
code. Less distribution of knowledge.
parent f532b039
......@@ -750,11 +750,15 @@ foreach $vlan (keys(%vlans)) {
foreach $delay (keys(%delays)) {
($pnode,$int0,$int1,$vname,$delay,$bandwidth,$lossrate) =
@{$delays{$delay}};
my $pipe0 = 100 + (10 * $delay);
my $pipe1 = $pipe0 + 10;
DBQueryFatal("insert into delays" .
" (pid,eid,node_id,iface0,iface1" .
",delay,bandwidth,lossrate,vname)" .
" values (\"$pid\",\"$eid\",\"$pnode\",\"$int0\",\"$int1\"".
",$delay,$bandwidth,$lossrate,\"$vname\")");
" (pid,eid,node_id,vname,iface0,iface1" .
",pipe0,delay0,bandwidth0,lossrate0" .
",pipe1,delay1,bandwidth1,lossrate1)" .
" values ('$pid','$eid','$pnode','$vname','$int0','$int1'".
",$pipe0,$delay,$bandwidth,$lossrate".
",$pipe1,$delay,$bandwidth,$lossrate)");
}
DBQueryFatal("delete from portmap where pid=\"$pid\" and eid=\"$eid\"");
foreach $vnodeport (keys(%portmap)) {
......
......@@ -10,7 +10,7 @@ use Exporter;
qw ( $CP $EGREP $MOUNT $UMOUNT $TMPASSWD
os_cleanup_node os_ifconfig_line os_etchosts_line
os_setup os_groupadd os_useradd os_userdel os_usermod
os_rpminstall_line
os_rpminstall_line update_delays
);
# Must come after package declaration!
......@@ -189,6 +189,15 @@ sub os_setup()
print STDOUT "Checking Testbed delay configuration ... \n";
dodelays();
}
#
# Special update.
#
sub update_delays()
{
dodelays();
system($TMDELAY);
}
sub dodelays ()
{
......@@ -210,13 +219,13 @@ sub dodelays ()
print DEL "#!/bin/sh\n";
print DEL "sysctl -w net.link.ether.bridge=0\n";
print DEL "sysctl -w net.link.ether.bridge_ipfw=0\n";
print DEL "sysctl -w net.link.ether.bridge_cfg=${CTLIFACE}:6,";
print DEL "sysctl -w net.link.ether.bridge_cfg=";
foreach $delay (@delays) {
$delay =~ /DELAY INT0=([\d\w]+) INT1=([\d\w]+) DELAY/;
$delay =~ /DELAY INT0=([\d\w]+) INT1=([\d\w]+) /;
my $iface1 = libsetup::findiface($1);
my $iface2 = libsetup::findiface($2);
print DEL "$iface1:$count,$iface2:$count,";
$count++;
}
......@@ -226,29 +235,26 @@ sub dodelays ()
print DEL "ipfw -f flush\n";
$count = 69;
$pipe = 100;
foreach $delay (@delays) {
$delay =~
/DELAY INT0=([\d\w]+) INT1=([\d\w]+) DELAY=(\d+) BW=([\d\.]+) PLR=([\d\.]+)/;
$pat = q(DELAY INT0=([\d\w]+) INT1=([\d\w]+) );
$pat .= q(PIPE0=(\d+) DELAY0=(\d+) BW0=([\d\.]+) PLR0=([\d\.]+) );
$pat .= q(PIPE1=(\d+) DELAY1=(\d+) BW1=([\d\.]+) PLR1=([\d\.]+));
$delay =~ /$pat/;
#
# tmcd returns the INTs as MAC addrs.
#
my $iface1 = libsetup::findiface($1);
my $iface2 = libsetup::findiface($2);
$p1 = $pipe += 10;
$p2 = $pipe += 10;
$delay = $3;
$bandw = $4;
$plr = $5;
#
# We want to know what the minimum delay is so we can boot the
# the correct kernel.
#
if ($delay < $mindelay) {
$mindelay = $delay;
}
$p1 = $3;
$delay1 = $4;
$bandw1 = $5;
$plr1 = $6;
$p2 = $7;
$delay2 = $8;
$bandw2 = $9;
$plr2 = $10;
print DEL "ifconfig $iface1 media 100baseTX mediaopt full-duplex";
print DEL "\n";
......@@ -256,13 +262,15 @@ sub dodelays ()
print DEL "\n";
print DEL "ipfw add pipe $p1 ip from any to any in recv $iface1\n";
print DEL "ipfw add pipe $p2 ip from any to any in recv $iface2\n";
print DEL "ipfw pipe $p1 config delay ${delay}ms ";
print DEL "bw ${bandw}Mbit/s plr $plr\n";
print DEL "ipfw pipe $p2 config delay ${delay}ms ";
print DEL "bw ${bandw}Mbit/s plr $plr\n";
print STDOUT " $iface1/$iface2 pipe $p1/$p2 config delay ";
print STDOUT "${delay}ms bw ${bandw}Mbit/s plr $plr\n";
print DEL "ipfw pipe $p1 config delay ${delay1}ms ";
print DEL "bw ${bandw1}Mbit/s plr $plr1\n";
print DEL "ipfw pipe $p2 config delay ${delay2}ms ";
print DEL "bw ${bandw2}Mbit/s plr $plr2\n";
print STDOUT " $iface1/$iface2 pipe $p1 config delay ";
print STDOUT "${delay1}ms bw ${bandw1}Mbit/s plr $plr1\n";
print STDOUT " $iface1/$iface2 pipe $p2 config delay ";
print STDOUT "${delay2}ms bw ${bandw2}Mbit/s plr $plr2\n";
$count++;
}
......
#!/usr/bin/perl -wT
use English;
#
# Untaint path
#
$ENV{'PATH'} = '/bin:/sbin:/usr/bin:/usr/local/bin:/etc/testbed';
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
#
# Load the OS independent support library. It will load the OS dependent
# library and initialize itself.
#
use lib "/etc/testbed";
use libsetup;
#
# Update the delays configuration. This routine will also run the
# the commands to make the changes.
#
liblocsetup::update_delays();
exit 0;
......@@ -893,14 +893,16 @@ dodelay(int sock, struct in_addr ipaddr, char *rdata, int tcp)
* join is to get the type out so that we can pass it back. Of
* course, this assumes that the type is the BSD name, not linux.
*/
res = mydb_query("select i.MAC,j.MAC,delay,bandwidth,lossrate "
" from delays "
res = mydb_query("select i.MAC,j.MAC, "
"pipe0,delay0,bandwidth0,lossrate0, "
"pipe1,delay1,bandwidth1,lossrate1 "
" from delays as d "
"left join interfaces as i on "
" i.node_id=delays.node_id and i.iface=iface0 "
" i.node_id=d.node_id and i.iface=iface0 "
"left join interfaces as j on "
" j.node_id=delays.node_id and j.iface=iface1 "
" where delays.node_id='%s'",
5, nodeid);
" j.node_id=d.node_id and j.iface=iface1 "
" where d.node_id='%s'",
10, nodeid);
if (!res) {
syslog(LOG_ERR, "DELAY: %s: DB Error getting delays!",
nodeid);
......@@ -925,9 +927,12 @@ dodelay(int sock, struct in_addr ipaddr, char *rdata, int tcp)
return 1;
}
sprintf(buf,
"DELAY INT0=%s INT1=%s DELAY=%s BW=%s PLR=%s\n",
row[0], row[1], row[2], row[3], row[4]);
sprintf(buf, "DELAY INT0=%s INT1=%s "
"PIPE0=%s DELAY0=%s BW0=%s PLR0=%s "
"PIPE1=%s DELAY1=%s BW1=%s PLR1=%s\n",
row[0], row[1],
row[2], row[3], row[4], row[5],
row[6], row[7], row[8], row[9]);
client_writeback(sock, buf, strlen(buf), tcp);
nrows--;
......@@ -945,7 +950,7 @@ static int
dohosts(int sock, struct in_addr ipaddr, char *rdata, int tcp)
{
char *tmp, *buf, *vname_list;
char *tmp, buf[MYBUFSIZE], *vname_list;
char pid[64], eid[64];
char gid[64];
char nickname[128]; /* XXX: Shouldn't be statically sized, potential buffer
......
#!/usr/bin/perl -w
use English;
use Getopt::Std;
my $TB = "@prefix@";
my $debug=0;
#
# Change delay params for a link.
#
sub usage()
{
print STDERR
"Usage: delay_config [-d delay] [-b bw] [-l plr] [-p 0|1] ",
"<pid> <eid> <link>\n",
" pid = Project ID\n",
" eid = Experiment ID\n",
" link = link name from ns file, ie. 'link1' in\n",
" 'set link1 [\$ns duplex-link \$A \$B 100Mb 0ms DropTail]'\n",
" -d = one-way link delay in milliseconds greater than 1\n",
" -b = <NNN> N=bandwidth (1-100 Mbs)\n",
" -l = packet loss rate (0 <= plr < 1)\n",
" -p = Select one of the pipes. 0 - packets received on iface0\n";
exit(-1);
}
my $optlist = "gd:b:l:p:";
#
# Configure variables
#
my $TB = "@prefix@";
my $TBOPS = "@TBOPSEMAIL@";
my $debug = 0;
#
# Testbed Support libraries
#
use lib "@prefix@/lib";
use libdb;
use libtestbed;
if ( @ARGV < 4 ) {
print STDERR
"Usage: delay_config <pid> <eid> <link> [<delay>] [<bw>] [<plr>]\n",
" pid = Project ID\n",
" eid = Experiment ID\n",
" link = link name from ns file, ie. 'link1' in\n",
" 'set link1 [\$ns duplex-link \$A \$B 100Mb 0ms DropTail]'\n",
"delay = one-way link delay in milliseconds\n",
" bw = bw<NNN><U>, N=bandwidth (1-100), U=units (M=Mbps, k=kbps)\n",
" plr = packet loss rate (0 <= plr < 1)\n";
exit(0); # so plasticwrap doesn't think ssh failed.
#
# Turn off line buffering on output
#
$| = 1;
#
# Untaint the path
#
$ENV{'PATH'} = "/bin:/sbin:/usr/bin:/usr/sbin";
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
#
# Parse command arguments. Once we return from getopts, all that should be
# left are the required arguments.
#
%options = ();
if (! getopts($optlist, \%options)) {
usage();
}
if (@ARGV != 3) {
usage();
}
if (defined($options{"g"})) {
$debug = 1;
}
my $pid = $ARGV[0];
my $eid = $ARGV[1];
my $link = $ARGV[2];
my $pipe;
if (defined($options{"p"})) {
$pipe = $options{"p"};
@_ = @ARGV;
my $pid = shift || "";
my $eid = shift || "";
my $link = shift || "";
my $sth =
DBQueryFatal("select node_id,iface0,iface1,delay,bandwidth,lossrate from ".
"delays where pid='$pid' and eid='$eid' and vname='$link'");
my @row= $sth->fetchrow_array();
if (!@row) { die("Link $link in proj. $pid, expt. $eid, not found.\n"); }
my $node = $row[0];
$row[1] =~ /^[a-zA-Z]*(\d*)$/;
my $card0 = $1;
my $pipe1= $card0*10 + 110;
$row[2] =~ /^[a-zA-Z]*(\d*)$/;
my $card1 = $1;
my $pipe2= $card1*10 + 110;
my $delay= $row[3];
my $bw= $row[4];
my $unit= "M";
my $plr= $row[5];
if ($debug) {
print "Found row in delays table: ", join (", ",@row),"\n";
print "Found $node($pipe1,$pipe2), delay $delay, bw $bw$unit, plr $plr\n";
if ($pipe != 0 && $pipe != 1) {
usage();
}
}
my $n;
while (defined ($n = shift)) {
if ($n =~ /bw(\d+)(\w)/) {
$bw = $1;
$unit = $2;
if (($bw > 100) || ($bw < 1) || !($unit =~ /^M|k$/)) {
die ("Illegal Bandwidth spec '$n'\n");
}
print "Setting Bandwidth $bw ${unit}bit/s.\n";
} elsif ( !($n =~ /^[0-9.]*$/) ) {
die ("Illegal parameter '$n'\n");
} elsif ($n >= 1 ) {
if ($n % 10 != 0) {
print "(Delay of $n may be rounded according to kernel settings)\n";
}
$delay = $n;
print "Setting Delay $delay ms.\n";
} elsif (($n >= 0) && ($n < 1)) {
$plr = $n;
print "Setting Packet Loss Rate ".($plr*100)."%.\n";
} else {
die ("Illegal parameter '$n'\n");
}
#
# Verify user and get his DB uid.
#
if (! UNIX2DBUID($UID, \$dbuid)) {
die("*** $0:\n".
" You do not exist in the Emulab Database.\n");
}
applyChanges() && updatedb();
#
# Permission check.
#
if ($UID && !TBAdmin($UID) &&
! TBExptAccessCheck($dbuid, $pid, $eid, TB_EXPT_MODIFY)) {
die("*** $0:\n".
" You do not have permission to modify the delay parameters!\n");
}
exit(0);
#
# Get current delay configuration.
#
my $query_result =
DBQueryFatal("select * from delays ".
"where pid='$pid' and eid='$eid' and vname='$link'");
if (! $query_result->numrows) {
die("*** $0:\n".
" No such delay link $link in $pid/$eid!\n");
}
my %row = $query_result->fetchhash();
my $node = $row{'node_id'};
my $iface0 = $row{'iface0'};
my $iface1 = $row{'iface1'};
my %bw;
my %delay;
my %plr;
$delay[0] = $row{'delay0'};
$bw[0] = $row{'bandwidth0'};
$plr[0] = $row{'lossrate0'};
$delay[1] = $row{'delay1'};
$bw[1] = $row{'bandwidth1'};
$plr[1] = $row{'lossrate1'};
sub applyChanges {
my $config = " config delay ${delay}ms bw ${bw}${unit}bit/s plr $plr";
my $cmd = "ssh -f -n $node ".
"'sudo /sbin/ipfw pipe $pipe1 $config ; ".
" sudo /sbin/ipfw pipe $pipe2 $config'";
if ($debug) { print "$cmd\n"; }
system($cmd) && die("Command '$cmd' failed: $!\n");
#
# Parse options, which modify the above configuration.
#
my $newdelay;
my $newbw;
my $newplr;
if (defined($options{"d"})) {
$newdelay = $options{"d"};
if (! ($newdelay =~ /^[0-9]*$/)) {
die("Illegal delay spec: $newdelay\n");
}
return 1;
if ($newdelay < 1) {
usage();
}
if ($debug) {
print "Setting delay to $newdelay milliseconds.\n";
}
}
sub updatedb {
# for now, we assume that the db holds Mbps for bw, and assume that
# this is what they set for the bw on the cmd line
if (! DBQuery("update delays set delay=$delay,bandwidth=$bw,lossrate=$plr ".
"where pid='$pid' and eid='$eid' and vname='$link'")) {
DBWarn("Couldn't update database!");
}
if (! DBQuery("update virt_lans set delay=$delay,bandwidth=$bw,".
"lossrate=$plr where pid='$pid' and eid='$eid' and ".
"vname='$link'")) {
DBWarn("Couldn't update database!");
}
if (defined($options{"l"})) {
$newplr = $options{"l"};
if (! ($newplr =~ /^[0-9\.]*$/)) {
die("Illegal plr spec: $newplr.\n");
}
if ($newplr < 0 || $newplr > 1) {
usage();
}
if ($debug) {
print "Setting plr to $newplr.\n";
}
}
if (defined($options{"b"})) {
$newbw = $options{"b"};
if (! ($newbw =~ /^[0-9]*$/)) {
die("Illegal bw spec: $newbw.\n");
}
if ($newbw > 100 || $newbw < 1) {
usage();
}
if ($debug) {
print "Setting bandwidth to $newbw Mbs.\n";
}
}
if (defined($pipe)) {
if (defined($newbw)) {
$bw[$pipe] = $newbw;
}
if (defined($newplr)) {
$plr[$pipe] = $newplr;
}
if (defined($newdelay)) {
$delay[$pipe] = $newdelay;
}
}
else {
my @joinlist;
my $joinstr = "";
if (defined($newbw)) {
$bw[0] = $newbw;
$bw[1] = $newbw;
push(@joinlist, "bandwidth=$newbw");
}
if (defined($newplr)) {
$plr[0] = $newplr;
$plr[1] = $newplr;
push(@joinlist, "lossrate=$newplr");
}
if (defined($newdelay)) {
$delay[0] = $newdelay;
$delay[1] = $newdelay;
push(@joinlist, "delay=$newdelay");
}
if (@joinlist) {
$joinstr = join(',', @joinlist);
}
#
# This happens only when no pipe is specified, since we do not
# support changing the pipes at that level yet.
#
DBQueryWarn("update virt_lans set $joinstr ".
"where pid='$pid' and eid='$eid' and vname='$link'");
}
#
# Update the delays table.
#
DBQueryWarn("update delays set ".
"delay0=$delay[0],bandwidth0=$bw[0],lossrate0=$plr[0], ".
"delay1=$delay[1],bandwidth1=$bw[1],lossrate1=$plr[1] ".
"where pid='$pid' and eid='$eid' and vname='$link'");
#
# Now ssh over to the node and have it update its delay params.
#
system("ssh -f -n $node 'sudo /etc/testbed/update_delays'") &&
die("*** $0:\n".
" Failed to update delays on $node!\n");
exit(0);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment