node.tcl 8.3 KB
Newer Older
Leigh Stoller's avatar
Leigh Stoller committed
1 2 3 4 5 6 7 8 9 10 11 12
######################################################################
# node.tcl
#
# This defines the Node class.  Instances of this class are created by
# the 'node' method of Simulator.  A Node is connected to a number of
# LanLinks.  Each such connection is associated with a virtual port,
# an integer.  Each virtual port also has an IP address.  Virtual
# ports start at 0 and go up continuously.  Besides the port
# information each node also has a variety of strings.  These strings
# are set by tb-* commands and dumped to the DB but are otherwise
# uninterpreted.
######################################################################
Mac Newbold's avatar
Mac Newbold committed
13

Leigh Stoller's avatar
Leigh Stoller committed
14
Class Node -superclass NSObject
Mac Newbold's avatar
Mac Newbold committed
15

Leigh Stoller's avatar
Leigh Stoller committed
16 17
Node instproc init {s} {
    $self set sim $s
Mac Newbold's avatar
Mac Newbold committed
18

Leigh Stoller's avatar
Leigh Stoller committed
19 20 21 22 23
    # portlist is a list of connections for the node.  It is sorted
    # by portnumber.  I.e. the ith element of portlist is the connection
    # on port i.
    $self set portlist {}

24 25 26 27 28 29 30
    # A list of agents attached to this node.
    $self set agentlist {}

    # A counter for udp/tcp portnumbers. Assign them in an increasing
    # fashion as agents are assigned to the node.
    $self set next_portnumber_ 5000

Leigh Stoller's avatar
Leigh Stoller committed
31 32 33 34
    # iplist, like portlist, is supported by portnumber.  An entry of
    # {} indicates an unassigned IP address for that port.
    $self set iplist {}

35 36 37 38
    # A route list. 
    $self instvar routelist
    array set routelist {}

Leigh Stoller's avatar
Leigh Stoller committed
39
    # The type of the node.
40
    $self set type "pc" 
Leigh Stoller's avatar
Leigh Stoller committed
41

42 43 44
    # Is remote flag. Used when we do IP assignment later.
    $self set isremote 0

Leigh Stoller's avatar
Leigh Stoller committed
45 46 47 48 49 50 51 52 53 54 55
    # If osid remains blank when updatedb is called it is changed
    # to the default OS based on it's type (taken from node_types
    # table).
    $self set osid ""

    # These are just various strings that we pass through to the DB.
    $self set cmdline ""
    $self set rpms ""
    $self set startup ""
    $self set deltas ""
    $self set tarfiles ""
56
    $self set failureaction "fatal"
57
    $self set fixed ""
58 59 60 61 62 63 64 65 66 67 68
    $self set nseconfig ""

    var_import ::GLOBALS::simulated
    var_import ::GLOBALS::curnsenode
    if { $simulated == 1 } {
	$self set simulated 1
	$self set nsenode $curnsenode
    } else {
	$self set simulated 0
	$self set nsenode ""
    }
69
    $self set nsenode_vportlist {}
Leigh Stoller's avatar
Leigh Stoller committed
70 71 72 73 74 75 76
}

# The following procs support renaming (see README)
Node instproc rename {old new} {
    $self instvar portlist
    foreach object $portlist {
	$object rename_node $old $new
Mac Newbold's avatar
Mac Newbold committed
77
    }
Leigh Stoller's avatar
Leigh Stoller committed
78 79 80 81 82 83 84 85 86 87
    [$self set sim] rename_node $old $new
}

Node instproc rename_lanlink {old new} {
    $self instvar portlist
    set newportlist {}
    foreach node $portlist {
	if {$node == $old} {
	    lappend newportlist $new
	} else {
88
	    lappend newportlist $node
Leigh Stoller's avatar
Leigh Stoller committed
89
	}
Mac Newbold's avatar
Mac Newbold committed
90
    }
Leigh Stoller's avatar
Leigh Stoller committed
91
    set portlist $newportlist
Mac Newbold's avatar
Mac Newbold committed
92 93
}

Leigh Stoller's avatar
Leigh Stoller committed
94 95 96 97 98 99 100 101 102 103 104 105
# updatedb DB
# This adds a row to the virt_nodes table corresponding to this node.
Node instproc updatedb {DB} {
    $self instvar portlist
    $self instvar type
    $self instvar osid
    $self instvar cmdline
    $self instvar rpms
    $self instvar startup
    $self instvar deltas
    $self instvar iplist
    $self instvar tarfiles
106
    $self instvar failureaction
107
    $self instvar routertype
108
    $self instvar fixed
109
    $self instvar agentlist
110 111
    $self instvar routelist
    $self instvar sim
112 113
    $self instvar simulated
    $self instvar nseconfig
Leigh Stoller's avatar
Leigh Stoller committed
114 115
    var_import ::GLOBALS::pid
    var_import ::GLOBALS::eid
116
    var_import ::GLOBALS::default_ip_routing_type
Mac Newbold's avatar
Mac Newbold committed
117

118 119 120 121 122
    # currently we don't want to update the DB for simulated nodes
    if { $simulated == 1 } {
	return
    }

Leigh Stoller's avatar
Leigh Stoller committed
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
    # If we haven't specified a osid so far then we should fill it
    # with the id from the node_types table now.
    if {$osid == {}} {
	sql query $DB "select osid from node_types where type = \"$type\""
	set osid [sql fetchrow $DB]
	sql endquery $DB
    }

    # We need to generate the IP column from our iplist.
    set ipraw {}
    set i 0
    foreach ip $iplist {
	lappend ipraw $i:$ip
	incr i
    }
Mac Newbold's avatar
Mac Newbold committed
138

139 140
    foreach agent $agentlist {
	$agent updatedb $DB
141 142

        append nseconfig [$agent get_nseconfig]
143
    }
Leigh Stoller's avatar
Leigh Stoller committed
144
    if {$nseconfig != {}} {
145 146 147 148 149 150 151

	set nsecfg_script ""
	set simu [lindex [Simulator info instances] 0]
	append nsecfg_script "set $simu \[new Simulator]\n"
	append nsecfg_script "\$$simu use-scheduler RealTime\n\n"
	append nsecfg_script $nseconfig

152
        # update the per-node nseconfigs table in the DB
153
        sql exec $DB "insert into nseconfigs (pid,eid,vname,nseconfig) values ('$pid','$eid','$self','$nsecfg_script')";
154
    }
155

156 157
    $self add_routes_to_DB $DB

Leigh Stoller's avatar
Leigh Stoller committed
158
    # Update the DB
159
    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\")";
Mac Newbold's avatar
Mac Newbold committed
160
}
161

Leigh Stoller's avatar
Leigh Stoller committed
162 163 164 165 166 167 168 169 170 171
# add_lanlink lanlink
# This creates a new virtual port and connects the specified LanLink to it.
# The port number is returned.
Node instproc add_lanlink {lanlink} {
    $self instvar portlist
    $self instvar iplist
    lappend portlist $lanlink
    lappend iplist ""
    return [expr [llength $portlist] - 1]
}
172

173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
#
# Find the lan that both nodes are attached to. Very bad. If more than
# comman lan, returns the first.
#
Node instproc find_commonlan {node} {
    $self instvar portlist
    set match -1

    foreach ll $portlist {
	set match [$node find_port $ll]
	if {$match != -1} {
	    break
	}
    }
    return $match
}

Leigh Stoller's avatar
Leigh Stoller committed
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
# ip port
# ip port ip
# In the first form this returns the IP address associated with the port.
# In the second from this sets the IP address of a port.
Node instproc ip {port args} {
    $self instvar iplist
    $self instvar sim
    if {$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
    }    
205 206
}

Leigh Stoller's avatar
Leigh Stoller committed
207 208 209 210 211 212
# find_port lanlink
# This takes a lanlink and returns the port it is connected to or 
# -1 if there is no connection.
Node instproc find_port {lanlink} {
    return [lsearch [$self set portlist] $lanlink]
}
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230

# Attach an agent to a node. This mainly a bookkeeping device so
# that the we can update the DB at the end.
Node instproc attach-agent {agent} {
    $self instvar agentlist

    lappend agentlist $agent
    $agent set_node $self
}

#
# Return and bump next agent portnumber,
Node instproc next_portnumber {} {
    $self instvar next_portnumber_
    
    set next_port [incr next_portnumber_]
    return $next_port
}
231 232 233 234 235 236 237 238 239 240 241 242 243 244

#
# 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
}

245 246 247 248 249 250 251 252 253 254 255
#
# Set the type/isremote for a node. Called from tb_compat.
#
Node instproc set_hwtype {hwtype isrem} {
    $self instvar type
    $self instvar isremote

    set type $hwtype
    set isremote $isrem
}

256 257 258 259 260 261 262 263 264 265 266
#
# 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)
267
	set port -1
268 269

	#
270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287
	# Convert hop to IP address. Need to find the link between the
	# the this node and the hop. This is easy if its a link. If its
	# a lan, then its ugly.
	#
	set hoplink [$sim find_link $self $hop]
	if {$hoplink == {}} {
	    set port [$self find_commonlan $hop]
	} else {
	    set port [$hop find_port $hoplink]
	}
	if {$port == -1} {
	    perror "\[add-route] Cannot find a link from $self to $hop!"
	    return
	}
	set hopip [$hop ip $port]
	
	#
	# Convert dst to IP address.
288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306
	#
	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"
	    }
307 308 309 310
	    "Lan" {
		set dstip [$dst get_subnet]
		set type  "net"
	    }
311 312 313 314 315 316 317 318 319
	    unknown {
		perror "\[add-route] Bad argument. Must be a node or a link."
		return
	    }
	}
	
	sql exec $DB "insert into virt_routes (pid,eid,vname,dst,nexthop,dst_type) values ('$pid','$eid','$self','$dstip','$hopip','$type')";
    }
}