Commit d881770b authored by Leigh B. Stoller's avatar Leigh B. Stoller

Add static routing support:

	# Turn on manual routing.
	$ns rtproto Manual

	# Set manual routes
	$nodeA add-route $nodeC $nodeB
	$nodeC add-route $nodeA $nodeB

results in this information being returned from the tmcd routing
command:

	ROUTERTYPE=manual
	ROUTE DEST=192.168.2.3 DESTTYPE=host DESTMASK=255.255.255.0 \
		NEXTHOP=192.168.3.2 COST=0

The reason for DESTTYPE and DESTMASK is so that we can also support
routing to links and lans, since doing it on a per host basis if not
only hugely tedious, but plain impossible if the destination node has
multiple links; the add-route syntax takes a node, but we need the IP
of the relevant link in order to run the route add commands on the
nodes. So, I've "extended" the syntax of add-route so that you can
give it a Link or a Lan as the dest:

	$nodeA add-route $link0 $nodeB
	$nodeA add-route [$ns link $nodeB $nodeC] $nodeB

In this case, the DESTTYPE=net, and the netmask is no longer ignored;
it is used in the route add command. Currently, the mask is hardwired
in the DB to 255.255.255.0, but by providing it in the tmcd command,
we change it later if needed.

I did not implement add-route-to-adj-node since that is not really
useful in our context, and we definitely do not want the user to
change the default routes on his nodes. But, its easy to add if we
need to.

The client side stuff is not done yet.
parent 3fc9e424
......@@ -212,6 +212,19 @@ LanLink instproc fill_ips {} {
}
}
#
# Return the subnet of a lan. Actually, just return one of the IPs.
#
LanLink instproc get_subnet {} {
$self instvar nodelist
set nodeport [lindex $nodelist 0]
set node [lindex $nodeport 0]
set port [lindex $nodeport 1]
return [$node ip $port]
}
Link instproc rename {old new} {
$self next $old $new
......
......@@ -32,6 +32,10 @@ Node instproc init {s} {
# {} indicates an unassigned IP address for that port.
$self set iplist {}
# A route list.
$self instvar routelist
array set routelist {}
# The type of the node.
$self set type "pc"
......@@ -88,6 +92,8 @@ Node instproc updatedb {DB} {
$self instvar routertype
$self instvar fixed
$self instvar agentlist
$self instvar routelist
$self instvar sim
var_import ::GLOBALS::pid
var_import ::GLOBALS::eid
var_import ::GLOBALS::default_ip_routing_type
......@@ -119,6 +125,8 @@ Node instproc updatedb {DB} {
sql exec $DB "insert into nseconfigs (pid,eid,vname,nseconfig) values ('$pid','$eid','$self','$nseconfig')";
}
$self add_routes_to_DB $DB
# Update the DB
sql exec $DB "insert into virt_nodes (pid,eid,vname,type,ips,osname,cmd_line,rpms,deltas,startupcmd,tarfiles,failureaction,routertype,fixed) values (\"$pid\",\"$eid\",\"$self\",\"$type\",\"$ipraw\",\"$osid\",\"$cmdline\",\"$rpms\",\"$deltas\",\"$startup\",\"$tarfiles\",\"$failureaction\",\"$default_ip_routing_type\",\"$fixed\")";
}
......@@ -175,3 +183,62 @@ Node instproc next_portnumber {} {
set next_port [incr next_portnumber_]
return $next_port
}
#
# Add a route.
# The nexthop to <dst> from this node is <target>.
#
Node instproc add-route {dst nexthop} {
$self instvar routelist
if {[info exists routelist($dst)]} {
perror "\[add-route] route from $self to $dst already exists!"
}
set routelist($dst) $nexthop
}
#
# Update DB with routes
#
Node instproc add_routes_to_DB {DB} {
var_import ::GLOBALS::pid
var_import ::GLOBALS::eid
$self instvar routelist
$self instvar sim
foreach dst [lsort [array names routelist]] {
set hop $routelist($dst)
#
# Convert hop IP address.
#
set hopip [$hop ip [$hop find_port [$sim find_link $self $hop]]]
switch -- [$dst info class] {
"Node" {
if {[llength [$dst set portlist]] != 1} {
perror "\[add-route] $dst must have only one link."
}
set dstip [$dst ip 0]
set type "host"
}
"SimplexLink" {
set link [$dst set mylink]
set src [$link set src_node]
set dstip [$src ip [$src find_port $link]]
set type "net"
}
"Link" {
set dstip [$dst get_subnet]
set type "net"
}
unknown {
perror "\[add-route] Bad argument. Must be a node or a link."
return
}
}
puts stderr "'$pid','$eid','$self','$dstip','$hopip','$type'"
sql exec $DB "insert into virt_routes (pid,eid,vname,dst,nexthop,dst_type) values ('$pid','$eid','$self','$dstip','$hopip','$type')";
}
}
......@@ -511,6 +511,8 @@ Simulator instproc rtproto {type args} {
if {($type == "Session") || ($type == "ospf")} {
set default_ip_routing_type "ospf"
} elseif {($type == "Manual")} {
set default_ip_routing_type "manual"
} else {
punsup "rtproto: unsupported routing protocol ignored: $type"
return
......@@ -584,8 +586,6 @@ Simulator instproc link {src dst} {
set name sl[incr new_counter]
return [SimplexLink $name $reallink $dir]
return $reallink
}
# get_subnet
......@@ -619,4 +619,3 @@ Simulator instproc add_program {prog} {
$self instvar prog_list
set prog_list($prog) {}
}
......@@ -85,6 +85,8 @@ DBQueryWarn("DELETE from virt_trafgens where pid='$pid' and eid='$eid'") or
$errors++;
DBQueryWarn("DELETE from virt_agents where pid='$pid' and eid='$eid'") or
$errors++;
DBQueryWarn("DELETE from virt_routes where pid='$pid' and eid='$eid'") or
$errors++;
DBQueryWarn("DELETE from nseconfigs where pid='$pid' and eid='$eid'") or
$errors++;
DBQueryWarn("DELETE from eventlist where pid='$pid' and eid='$eid'") or
......
......@@ -8,6 +8,14 @@ use English;
# is to interpret the NS file and create the appropriate entries in
# virt_nodes and virt_lans. After this script ends successfully the
# NS file is no longer necessary.
#
sub usage()
{
print STDERR "Usage: $0 [-force] pid eid nsfile\n";
exit(-1);
}
my $force = 0;
my $state;
#
# Configure variables
......@@ -30,32 +38,36 @@ use libtestbed;
#
$| = 1;
if ($#ARGV != 2) {
print STDERR "Syntax: $0 pid eid ns_file\n";
exit(1);
#
# Check for -force, and ignore experiment state.
#
if ($ARGV[0] eq "-force") {
$force = 1;
shift;
}
if (@ARGV != 3) {
usage();
}
my ($pid,$eid,$nsfile) = @ARGV;
if (! -r $nsfile) {
print STDERR "*** NS File '$nsfile' does not exist!\n";
exit(1);
die("*** $0:\n".
" NS File '$nsfile' does not exist!\n");
}
my $state;
print "Beginning pre run for $pid/$eid. " . TBTimeStamp() . "\n";
if (! ($state = ExpState($pid, $eid))) {
print STDERR "*** No such experiment $pid/$eid\n";
exit(1);
die("*** $0:\n".
" No such experiment $pid/$eid\n");
}
if ($state ne EXPTSTATE_NEW) {
print STDERR "*** Experiment is not in the proper state: $state\n";
exit(1);
if (!$force && $state ne EXPTSTATE_NEW) {
die("*** $0:\n".
" Experiment is not in the proper state: $state\n");
}
if (! SetExpState($pid, $eid, EXPTSTATE_PRERUN)) {
print STDERR "*** Failed to set intermediate experiment state.\n";
exit(1);
die("*** $0:\n".
" Failed to set intermediate experiment state.\n");
}
#
......@@ -67,6 +79,7 @@ sub cleanup {
DBQueryWarn("DELETE from virt_lans where pid='$pid' and eid='$eid'");
DBQueryWarn("DELETE from virt_trafgens where pid='$pid' and eid='$eid'");
DBQueryWarn("DELETE from virt_agents where pid='$pid' and eid='$eid'");
DBQueryWarn("DELETE from virt_routes where pid='$pid' and eid='$eid'");
DBQueryWarn("DELETE from nseconfigs where pid='$pid' and eid='$eid'");
DBQueryWarn("DELETE from eventlist where pid='$pid' and eid='$eid'");
SetExpState($pid, $eid, EXPTSTATE_NEW);
......@@ -76,16 +89,16 @@ sub cleanup {
# and tb-* handling.
print "Running parser ... " . TBTimeStamp() . "\n";
if (system("parse-ns $pid $eid $nsfile")) {
print STDERR "*** Parsing failed.\n";
cleanup();
exit(1);
die("*** $0:\n".
" Parsing failed!\n");
}
print "Parser done! Marking as prerunned. " . TBTimeStamp() . "\n";
print "Parser done! " . TBTimeStamp() . "\n";
if (!SetExpState($pid, $eid, EXPTSTATE_SWAPPED)) {
print STDERR "*** Failed to set experiment state!\n";
cleanup();
exit(1);
die("*** $0:\n".
" Failed to set experiment state!\n");
}
print "Pre run finished. " . TBTimeStamp() . "\n";
......
......@@ -7,13 +7,14 @@
#
sub usage {
print "Usage: $0 [-h] [-n] [-l] [-m] [-e] [-d] [-v] pid eid\n";
print "Usage: $0 [-h] [-n] [-l] [-m] [-e] [-d] [-r] [-v] pid eid\n";
print "-h Shows this message\n";
print "-n Show node info\n";
print "-m Show node mapping\n";
print "-l Show link info\n";
print "-d Show traffic shapping info\n";
print "-e Show event listing\n";
print "-r Show routes\n";
print "-b Show most things\n";
print "-v Show everything!\n";
return 1;
......@@ -23,6 +24,7 @@ my $TBROOT = "@prefix@";
my $DOMAIN = "@OURDOMAIN@";
use lib '@prefix@/lib';
use libtestbed;
use libdb;
require exitonwarn;
use Getopt::Std;
......@@ -42,6 +44,7 @@ my $showmap = 0;
my $showlinks = 0;
my $showdelays = 0;
my $showevents = 0;
my $showroutes = 0;
my %v2pmap;
my %p2type;
my %p2osid;
......@@ -58,6 +61,7 @@ if ($opt{v}) {
$showdelays = 1;
$showlinks = 1;
$showevents = 1;
$showroutes = 1;
}
if ($opt{b}) {
$shownodes = 1;
......@@ -65,6 +69,7 @@ if ($opt{b}) {
$showdelays = 1;
$showlinks = 1;
$showevents = 1;
$showroutes = 1;
}
if ($opt{n}) {
$shownodes = 1;
......@@ -81,6 +86,9 @@ if ($opt{l}) {
if ($opt{e}) {
$showevents = 1;
}
if ($opt{r}) {
$showroutes = 1;
}
if (@ARGV != 2) {
exit &usage;
}
......@@ -255,6 +263,35 @@ if ($showdelays &&
}
}
#
# Print route list.
#
if ($showroutes) {
my $result =
DBQueryFatal("select vname,dst,dst_type,dst_mask,nexthop,cost ".
" from virt_routes where ".
"pid='$pid' and eid='$eid' order by vname");
if ($result->numrows) {
print "Route List:\n";
printf "%-15s %-15s %-15s %-15s %-8s \n",
"Node", "Dest", "Type/Mask", "Nexthop", "Cost";
print "--------------- --------------- --------------- ".
"--------------- --------\n";
while (($vname,$dst,$dst_type,$dst_mask,$nexthop,$cost) =
$result->fetchrow_array()) {
if ($dst_type eq "host") {
$dst_mask = "host";
}
printf "%-15s %-15s %-15s %-15s %-10s \n",
$vname, $dst, $dst_mask, $nexthop, $cost;
}
print "\n";
}
}
#
# Print event list or summary
#
......
......@@ -7,11 +7,34 @@ set node3 [$ns node]
set node4 [$ns node]
set node5 [$ns node]
$ns duplex-link $node0 $node1 100Mb .1ms DropTail
$ns duplex-link $node0 $node2 100Mb .1ms DropTail
$ns duplex-link $node0 $node3 10Mb 100ms DropTail
$ns duplex-link $node3 $node4 100Mb .1ms DropTail
$ns duplex-link $node3 $node5 100Mb .1ms DropTail
set link0 [$ns duplex-link $node0 $node1 100Mb .1ms DropTail]
set link1 [$ns duplex-link $node0 $node2 100Mb .1ms DropTail]
set link2 [$ns duplex-link $node0 $node3 10Mb 100ms DropTail]
set link3 [$ns duplex-link $node3 $node4 100Mb .1ms DropTail]
set link4 [$ns duplex-link $node3 $node5 100Mb .1ms DropTail]
$ns run
# Turn on manual routing.
$ns rtproto Manual
# Set manual routes
$node0 add-route $node4 $node3
$node0 add-route $node5 $node3
$node1 add-route $node2 $node0
$node1 add-route $link2 $node0
$node1 add-route $node4 $node0
$node1 add-route $node5 $node0
$node2 add-route $node1 $node0
$node2 add-route [$ns link $node3 $node0] $node0
$node2 add-route $node4 $node0
$node3 add-route $node1 $node0
$node3 add-route $node2 $node0
$node4 add-route $link2 $node3
$node4 add-route $node1 $node3
$node4 add-route $node2 $node3
$node4 add-route $node5 $node3
$node5 add-route [$ns link $node0 $node3] $node3
$node5 add-route $node1 $node3
$node5 add-route $node2 $node3
$node5 add-route $node4 $node3
$ns run
......@@ -1978,6 +1978,7 @@ COMMAND_PROTOTYPE(dorouting)
char eid[64];
char gid[64];
char buf[MYBUFSIZE];
int nrows;
/*
* Now check reserved table
......@@ -2019,6 +2020,39 @@ COMMAND_PROTOTYPE(dorouting)
client_writeback(sock, buf, strlen(buf), tcp);
info("ROUTES: %s", buf);
/*
* Get the routing type from the nodes table.
*/
res = mydb_query("select dst,dst_type,dst_mask,nexthop,cost "
"from virt_routes as vi "
"left join reserved as r on r.vname=vi.vname "
"where r.node_id='%s' and "
" vi.pid='%s' and vi.eid='%s'",
5, nodeid, pid, eid);
if (!res) {
error("ROUTES: %s: DB Error getting manual routes!\n", nodeid);
return 1;
}
if ((nrows = (int)mysql_num_rows(res)) == 0) {
mysql_free_result(res);
return 0;
}
while (nrows) {
row = mysql_fetch_row(res);
sprintf(buf, "ROUTE DEST=%s DESTTYPE=%s DESTMASK=%s "
"NEXTHOP=%s COST=%s\n",
row[0], row[1], row[2], row[3], row[4]);
client_writeback(sock, buf, strlen(buf), tcp);
nrows--;
info("ROUTES: %s", buf);
}
mysql_free_result(res);
return 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