Commit 7d524fde authored by Leigh B. Stoller's avatar Leigh B. Stoller

Add variable netmask support to the parser. You can now do this in

your NS file:

	tb-set-netmask $lan0  "255.255.240.0"
	tb-set-netmask $link0 "255.255.255.248"
	tb-set-netmask $link1 "255.255.255.240"

Yep, more rope for the user to hang herself with. Notes:

* You are restricted to 255.255.XXX.XXX. I did not see a reason to
  allow the user that much rope.

* get_subnet can handle 10 or 192.168 addresses so that other sites
  can continue to operate without changing to 10 addresses, although
  they will still be able to change the netmask.

* I've changed the handling for widearea networks to use 192.168, but
  I force the netmask to 255.255.255.248 so that we are not restricted
  to just 255 networks (not that it really matters). To avoid possible
  confusion, the user is not allowed to choose their own IPs for
  widearea networks, and I actually set them to 1.1.x.x, and then
  patch it up later. This is to avoid conflict with existing
  experiments where people may have used tb-set-ip in their NS files.

* There are tmcd and staticroutes and image changes that are required
  to make this all work right!
parent 92a82e86
......@@ -128,6 +128,9 @@ Link instproc init {s nodes bw d type} {
$self set src_node $src
$self set dst_node $dst
# The default netmask, which the user may change (at his own peril).
$self set netmask "255.255.255.0"
var_import GLOBALS::new_counter
set q1 q[incr new_counter]
......@@ -179,7 +182,9 @@ LanLink instproc init {s nodes bw d type} {
break
}
}
# The default netmask, which the user may change (at his own peril).
$self set netmask "255.255.255.0"
# Make sure BW is reasonable.
# XXX: Should come from DB instead of hardwired max.
......@@ -247,9 +252,11 @@ LanLink instproc fill_ips {} {
$self instvar nodelist
$self instvar sim
$self instvar widearea
$self instvar netmask
set isremote 0
set netmaskint [inet_atohl $netmask]
# Determined a subnet (if possible) and any used IP addresses in it.
# Determine a subnet (if possible) and any used IP addresses in it.
# ips is a set which contains all used IP addresses in this LanLink.
set subnet {}
foreach nodeport $nodelist {
......@@ -261,8 +268,10 @@ LanLink instproc fill_ips {} {
if {$isremote} {
perror "Not allowed to specify IP subnet of a remote link!"
}
set subnet [join [lrange [split $ip .] 0 2] .]
set ipint [inet_atohl $ip]
set subnet [inet_hltoa [expr $ipint & $netmaskint]]
set ips($ip) 1
$sim use_subnet $subnet $netmask
}
}
if {$isremote && [$self info class] != "Link"} {
......@@ -271,26 +280,37 @@ LanLink instproc fill_ips {} {
}
set widearea $isremote
# See parse-ns if you change this!
if {$isremote && ($netmask != "255.255.255.248")} {
puts "Ignoring netmask for remote link; forcing 255.255.255.248"
set netmask "255.255.255.248"
set netmaskint [inet_atohl $netmask]
}
# If we couldn't find a subnet we ask the Simulator for one.
if {$subnet == {}} {
if {$isremote} {
set subnet [$sim get_subnet_remote]
} else {
set subnet [$sim get_subnet]
set subnet [$sim get_subnet $netmask]
}
}
# Now we assign IP addresses to any node:port's without them.
set ip_counter 2
set subnetint [inet_atohl $subnet]
foreach nodeport $nodelist {
set node [lindex $nodeport 0]
set port [lindex $nodeport 1]
if {[$node ip $port] == {}} {
set ip {}
for {set i $ip_counter} {$i < 255} {incr i} {
if {! [info exists ips($subnet.$i)]} {
set ip $subnet.$i
set ips($subnet.$i) 1
set max [expr ~ $netmaskint]
for {set i $ip_counter} {$i < $max} {incr i} {
set nextip [inet_hltoa [expr $subnetint | $i]]
if {! [info exists ips($nextip)]} {
set ip $nextip
set ips($ip) 1
set ip_counter [expr $i + 1]
break
}
......@@ -317,6 +337,15 @@ LanLink instproc get_subnet {} {
return [$node ip $port]
}
#
# Return the subnet of a lan. Actually, just return one of the IPs.
#
LanLink instproc get_netmask {} {
$self instvar netmask
return $netmask
}
#
# Set the routing cost for all interfaces on this LAN
#
......@@ -404,6 +433,7 @@ Link instproc updatedb {DB} {
$self instvar nobwshaping
$self instvar useveth
$self instvar sim
$self instvar netmask
foreach nodeport $nodelist {
set node [lindex $nodeport 0]
......@@ -448,9 +478,9 @@ Link instproc updatedb {DB} {
set nodeportraw [join $nodeport ":"]
set fields [list "vname" "member" "delay" "rdelay" "bandwidth" "rbandwidth" "lossrate" "rlossrate" "cost" "widearea" "emulated" "uselinkdelay" "nobwshaping" "usevethiface" "q_limit" "q_maxthresh" "q_minthresh" "q_weight" "q_linterm" "q_qinbytes" "q_bytes" "q_meanpsize" "q_wait" "q_setbit" "q_droptail" "q_red" "q_gentle" "trivial_ok"]
set fields [list "vname" "member" "mask" "delay" "rdelay" "bandwidth" "rbandwidth" "lossrate" "rlossrate" "cost" "widearea" "emulated" "uselinkdelay" "nobwshaping" "usevethiface" "q_limit" "q_maxthresh" "q_minthresh" "q_weight" "q_linterm" "q_qinbytes" "q_bytes" "q_meanpsize" "q_wait" "q_setbit" "q_droptail" "q_red" "q_gentle" "trivial_ok"]
set values [list $self $nodeportraw $delay($nodeport) $rdelay($nodeport) $bandwidth($nodeport) $rbandwidth($nodeport) $loss($nodeport) $rloss($nodeport) $cost($nodeport) $widearea $emulated $uselinkdelay $nobwshaping $useveth $limit_ $maxthresh_ $thresh_ $q_weight_ $linterm_ ${queue-in-bytes_} $bytes_ $mean_pktsize_ $wait_ $setbit_ $droptail_ $red_ $gentle_ $trivial_ok]
set values [list $self $nodeportraw $netmask $delay($nodeport) $rdelay($nodeport) $bandwidth($nodeport) $rbandwidth($nodeport) $loss($nodeport) $rloss($nodeport) $cost($nodeport) $widearea $emulated $uselinkdelay $nobwshaping $useveth $limit_ $maxthresh_ $thresh_ $q_weight_ $linterm_ ${queue-in-bytes_} $bytes_ $mean_pktsize_ $wait_ $setbit_ $droptail_ $red_ $gentle_ $trivial_ok]
$sim spitxml_data "virt_lans" $fields $values
}
......@@ -475,6 +505,7 @@ Lan instproc updatedb {DB} {
$self instvar nobwshaping
$self instvar useveth
$self instvar sim
$self instvar netmask
foreach nodeport $nodelist {
set node [lindex $nodeport 0]
......@@ -516,11 +547,29 @@ Lan instproc updatedb {DB} {
set nodeportraw [join $nodeport ":"]
set fields [list "vname" "member" "delay" "rdelay" "bandwidth" "rbandwidth" "lossrate" "rlossrate" "cost" "widearea" "emulated" "uselinkdelay" "nobwshaping" "usevethiface" "q_limit" "q_maxthresh" "q_minthresh" "q_weight" "q_linterm" "q_qinbytes" "q_bytes" "q_meanpsize" "q_wait" "q_setbit" "q_droptail" "q_red" "q_gentle" "trivial_ok"]
set fields [list "vname" "member" "mask" "delay" "rdelay" "bandwidth" "rbandwidth" "lossrate" "rlossrate" "cost" "widearea" "emulated" "uselinkdelay" "nobwshaping" "usevethiface" "q_limit" "q_maxthresh" "q_minthresh" "q_weight" "q_linterm" "q_qinbytes" "q_bytes" "q_meanpsize" "q_wait" "q_setbit" "q_droptail" "q_red" "q_gentle" "trivial_ok"]
set values [list $self $nodeportraw $delay($nodeport) $rdelay($nodeport) $bandwidth($nodeport) $rbandwidth($nodeport) $loss($nodeport) $rloss($nodeport) $cost($nodeport) $widearea $emulated $uselinkdelay $nobwshaping $useveth $limit_ $maxthresh_ $thresh_ $q_weight_ $linterm_ ${queue-in-bytes_} $bytes_ $mean_pktsize_ $wait_ $setbit_ $droptail_ $red_ $gentle_ $trivial_ok]
set values [list $self $nodeportraw $netmask $delay($nodeport) $rdelay($nodeport) $bandwidth($nodeport) $rbandwidth($nodeport) $loss($nodeport) $rloss($nodeport) $cost($nodeport) $widearea $emulated $uselinkdelay $nobwshaping $useveth $limit_ $maxthresh_ $thresh_ $q_weight_ $linterm_ ${queue-in-bytes_} $bytes_ $mean_pktsize_ $wait_ $setbit_ $droptail_ $red_ $gentle_ $trivial_ok]
$sim spitxml_data "virt_lans" $fields $values
}
}
#
# Convert IP/Mask to an integer (host order)
#
proc inet_atohl {ip} {
if {[scan $ip "%d.%d.%d.%d" a b c d] != 4} {
perror "\[inet_atohl] Invalid ip $ip; cannot be converted!"
return 0
}
return [expr ($a << 24) | ($b << 16) | ($c << 8) | $d]
}
proc inet_hltoa {ip} {
set a [expr ($ip >> 24) & 0xff]
set b [expr ($ip >> 16) & 0xff]
set c [expr ($ip >> 8) & 0xff]
set d [expr ($ip >> 0) & 0xff]
return "$a.$b.$c.$d"
}
......@@ -234,9 +234,7 @@ Node instproc ip {port args} {
return [lindex $iplist $port]
} else {
set ip [lindex $args 0]
set subnet [join [lrange [split $ip .] 0 2] .]
set iplist [lreplace $iplist $port $port $ip]
$sim use_subnet $subnet
}
}
......@@ -350,21 +348,26 @@ Node instproc add_routes_to_DB {DB} {
if {[llength [$dst set portlist]] != 1} {
perror "\[add-route] $dst must have only one link."
}
set link [lindex [$dst set portlist] 0]
set mask [$link get_netmask]
set dstip [$dst ip 0]
set type "host"
}
"SimplexLink" {
set link [$dst set mylink]
set src [$link set src_node]
set link [$dst set mylink]
set mask [$link get_netmask]
set src [$link set src_node]
set dstip [$src ip [$src find_port $link]]
set type "net"
}
"Link" {
set dstip [$dst get_subnet]
set mask [$dst get_netmask]
set type "net"
}
"Lan" {
set dstip [$dst get_subnet]
set mask [$dst get_netmask]
set type "net"
}
unknown {
......@@ -372,7 +375,7 @@ Node instproc add_routes_to_DB {DB} {
return
}
}
$sim spitxml_data "virt_routes" [list "vname" "dst" "nexthop" "dst_type" ] [list $self $dstip $hopip $type ]
$sim spitxml_data "virt_routes" [list "vname" "dst" "nexthop" "dst_type" "dst_mask"] [list $self $dstip $hopip $type $mask]
}
}
......
......@@ -8,6 +8,7 @@
use English;
use Getopt::Std;
use Socket;
#
# Parse an ns file. Since the parser runs arbitrary NS file for the user,
......@@ -247,9 +248,10 @@ if ($?) {
#
# Now we have to fix up one minor thing; widearea tunnel IPs. These have
# to be unique, but without the DB to ask, there is no easy way to arrange
# that.
#
# that.
my %subnetmap = ();
my $WANETMASK = "255.255.255.248";
my $query_result =
DBQueryFatal("select vname,ips from virt_nodes ".
......@@ -262,20 +264,29 @@ while (my ($vname,$ips) = $query_result->fetchrow_array()) {
my ($port,$ip) = split(":", $ipinfo);
my ($a,$b,$c,$d) = ($ip =~ /(\d+).(\d+).(\d+).(\d+)/);
if ($a eq "10") {
if (! defined($subnetmap{"$a.$b.$c"})) {
if ($a eq "1" && $b eq "1") {
my $net = inet_ntoa(inet_aton($WANETMASK) & inet_aton($ip));
if (! defined($subnetmap{$net})) {
DBQueryFatal("insert into ipsubnets ".
"values ('$pid','$eid', NULL)");
my ($id) =
DBQueryFatal("select LAST_INSERT_ID() ".
"from ipsubnets")->fetchrow_array();
my $bb = ($id & 0xff00) >> 8;
my $cc = ($id & 0xff);
$subnetmap{"$a.$b.$c"} = "$a.$bb.$cc";
# We are going to shift the bits up so they do not conflict
# with the lower part.
if ($id >= 8192) {
die("No more widearea subnets left!\n");
}
$id = $id << 3;
my $cc = ($id & 0xff00) >> 8;
my $dd = ($id & 0xf8);
$subnetmap{$net} = inet_aton("192.168.$cc.$dd");
}
my $newsubnet = $subnetmap{"$a.$b.$c"};
push(@newiplist, "$port:${newsubnet}.$d");
my $newsubnet = inet_ntoa($subnetmap{$net} | inet_aton("$d"));
push(@newiplist, "$port:${newsubnet}");
}
else {
push(@newiplist, $ipinfo);
......@@ -300,13 +311,15 @@ if (keys(%subnetmap)) {
my ($a,$b,$c,$d) = ($ip =~ /(\d+).(\d+).(\d+).(\d+)/);
my $newip = $ip;
my $newdstip = $dstip;
my $net = inet_ntoa(inet_aton($WANETMASK) & inet_aton($ip));
if (defined($subnetmap{"$a.$b.$c"})) {
$newip = $subnetmap{"$a.$b.$c"} . ".$d";
if (defined($subnetmap{$net})) {
$newip = inet_ntoa($subnetmap{$net} | inet_aton("$d"));
}
($a,$b,$c,$d) = ($dstip =~ /(\d+).(\d+).(\d+).(\d+)/);
if (defined($subnetmap{"$a.$b.$c"})) {
$newdstip = $subnetmap{"$a.$b.$c"} . ".$d";
$net = inet_ntoa(inet_aton($WANETMASK) & inet_aton($dstip));
if (defined($subnetmap{$net})) {
$newdstip = inet_ntoa($subnetmap{$net} | inet_aton("$d"));
}
if ($ip ne $newip || $dstip ne $newdstip) {
DBQueryFatal("update virt_trafgens set ".
......
......@@ -28,8 +28,7 @@ Simulator instproc init {args} {
# A counter for internal ids
$self set id_counter 0
# A counter for subnets. This is the lowest unused subnet
# suffix.
# Counters for subnets.
$self set subnet_counter 1
$self set wa_subnet_counter 1
......@@ -774,15 +773,72 @@ Simulator instproc lanlink {lan node} {
# get_subnet
# This is called by lanlinks. When called get_subnet will find an available
# IP subnet, mark it as used, and return it to the caller.
Simulator instproc get_subnet {} {
Simulator instproc get_subnet {netmask} {
$self instvar subnet_base
$self instvar subnets
$self instvar subnet_counter
for {set i $subnet_counter} {$i < 255} {incr i} {
if {! [info exists subnets($subnet_base.$i)]} {
set subnet_counter $i
return $subnet_base.$i
set netmaskint [inet_atohl $netmask]
set A $subnet_base
set C [expr ($netmaskint >> 8) & 0xff]
set D [expr $netmaskint & 0xff]
set minB 1
set maxB 254
set minC 0
set maxC 1
set incC 1
set minD 0
set maxD 1
set incD 1
# allow for 10. or 192.168. I know, could be more general.
if {[expr [llength [split $subnet_base .]]] == 2} {
# 192.168.
set A [expr [lindex [split $subnet_base .] 0]]
set minB [expr [lindex [split $subnet_base .] 1]]
set maxB [expr $minB + 1]
}
if {$C != 0} {
set minC [expr 256 - $C]
set maxC 255
set incC $minC
}
if {$D != 0} {
set minD [expr 256 - $D]
set maxD 255
set incD $minD
}
# We never let the user change the second octet. See tb-set-netmask.
for {set i $minB} {$i < $maxB} {incr i} {
for {set j $minC} {$j < $maxC} {set j [expr $j + $incC]} {
for {set k $minD} {$k < $maxD} {set k [expr $k + $incD]} {
set subnet "$A.$i.$j.$k"
set subnetint [inet_atohl $subnet]
# No such subnet exists?
if {! [info exists subnets($subnetint)]} {
set okay 1
#
# See if this subnet violates any existing subnet masks
# Is this overly restrictive? Totally wrong?
#
foreach osubnetint [concat [array names subnets]] {
set onetmaskint $subnets($osubnetint)
if {[expr $subnetint & $onetmaskint] == $osubnetint ||
[expr $osubnetint & $netmaskint] == $subnetint} {
set okay 0
break
}
}
if {$okay} {
$self use_subnet $subnet $netmask
return $subnet
}
}
}
}
}
perror "Ran out of subnets."
......@@ -794,19 +850,25 @@ Simulator instproc get_subnet {} {
Simulator instproc get_subnet_remote {} {
$self instvar wa_subnet_counter
if {$wa_subnet_counter > 255} {
perror "Ran out of widearea subnets."
return 0
}
set subnet $wa_subnet_counter
incr wa_subnet_counter
set b [expr [expr $subnet & 0xff00] >> 8]
set c [expr $subnet & 0xff]
return 10.$b.$c
return "1.1.$subnet.0"
}
# use_subnet
# This is called by the ip method of nodes. It marks the passed subnet
# as used and thus should never be returned by get_subnet.
Simulator instproc use_subnet {subnet} {
Simulator instproc use_subnet {subnet netmask} {
$self instvar subnets
set subnets($subnet) {}
set subnetint [inet_atohl $subnet]
set netmaskint [inet_atohl $netmask]
set subnets($subnetint) $netmaskint
}
# add_program
......
......@@ -124,6 +124,31 @@ proc tb-set-ip-link {src link ip} {
::TBCOMPAT::set-ip $src $link $ip
}
#
# Set the netmask. To make it easier to compute subnets later, do
# allow the user to alter the netmask beyond the bottom 3 octets.
# This restricts the user to a lan of 4095 nodes, but that seems okay
# for now.
#
proc tb-set-netmask {lanlink netmask} {
var_import ::TBCOMPAT::IP
if {[$lanlink info class] != "Link" && [$lanlink info class] != "Lan"} {
perror "\[tb-set-netmask] $lanlink is not a link or a lan."
return
}
if {[regexp $IP $netmask] == 0} {
perror "\[tb-set-netmask] - $netmask is not a valid IP mask"
return
}
set netmaskint [inet_atohl $netmask]
if {[expr ($netmaskint & 0xFFFFF000)] != 0xFFFFF000} {
perror "\[tb-set-netmask] - $netmask is too big"
return
}
$lanlink set netmask $netmask
}
# Node state routines.
proc tb-set-hardware {node type args} {
var_import ::TBCOMPAT::hwtypes
......
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