node.tcl 16.4 KB
Newer Older
1
# -*- tcl -*-
Leigh B. Stoller's avatar
Leigh B. Stoller committed
2 3
#
# EMULAB-COPYRIGHT
4
# Copyright (c) 2000-2006 University of Utah and the Flux Group.
Leigh B. Stoller's avatar
Leigh B. Stoller committed
5 6 7
# All rights reserved.
#

Leigh B. Stoller's avatar
Leigh B. Stoller committed
8 9 10 11 12 13 14 15 16 17 18 19
######################################################################
# 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
20

Leigh B. Stoller's avatar
Leigh B. Stoller committed
21
Class Node -superclass NSObject
Mac Newbold's avatar
Mac Newbold committed
22

Leigh B. Stoller's avatar
Leigh B. Stoller committed
23 24
Node instproc init {s} {
    $self set sim $s
Mac Newbold's avatar
Mac Newbold committed
25

Leigh B. Stoller's avatar
Leigh B. Stoller committed
26 27 28 29 30
    # 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 {}

31 32 33 34 35 36 37
    # 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 B. Stoller's avatar
Leigh B. Stoller committed
38 39 40 41
    # iplist, like portlist, is supported by portnumber.  An entry of
    # {} indicates an unassigned IP address for that port.
    $self set iplist {}

Leigh B. Stoller's avatar
Leigh B. Stoller committed
42 43 44 45
    # A route list. 
    $self instvar routelist
    array set routelist {}

Leigh B. Stoller's avatar
Leigh B. Stoller committed
46
    # The type of the node.
47
    $self set type "pc" 
Leigh B. Stoller's avatar
Leigh B. Stoller committed
48

49 50 51
    # Is remote flag. Used when we do IP assignment later.
    $self set isremote 0

52 53 54
    # Sorta ditto for virt.
    $self set isvirt 0

55 56 57
    # If hosting a virtual node (or nodes).
    $self set virthost 0

Leigh B. Stoller's avatar
Leigh B. Stoller committed
58
    # Sorta ditto for subnode stuff.
59 60 61
    $self set issubnode    0
    $self set subnodehost  0
    $self set subnodechild ""
Leigh B. Stoller's avatar
Leigh B. Stoller committed
62

Leigh B. Stoller's avatar
Leigh B. Stoller committed
63 64 65 66 67
    # 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 ""

68 69 70 71
    # Start with an empty set of desires
    $self instvar desirelist
    array set desirelist {}

Leigh B. Stoller's avatar
Leigh B. Stoller committed
72 73 74 75 76
    # These are just various strings that we pass through to the DB.
    $self set cmdline ""
    $self set rpms ""
    $self set startup ""
    $self set tarfiles ""
77
    $self set failureaction "fatal"
78
    $self set inner_elab_role ""
79
    $self set plab_role "none"
80
    $self set fixed ""
81 82
    $self set nseconfig ""

Timothy Stack's avatar
 
Timothy Stack committed
83 84
    $self set topo ""

Timothy Stack's avatar
 
Timothy Stack committed
85 86
    $self set X_ ""
    $self set Y_ ""
Timothy Stack's avatar
 
Timothy Stack committed
87 88
    $self set Z_ 0.0
    $self set orientation_ 0.0
Timothy Stack's avatar
 
Timothy Stack committed
89

Timothy Stack's avatar
 
Timothy Stack committed
90 91 92 93 94
    set cname "${self}-console"
    Console $cname $s $self
    $s add_console $cname
    $self set console_ $cname

95
    if { ${::GLOBALS::simulated} == 1 } {
96 97 98 99
	$self set simulated 1
    } else {
	$self set simulated 0
    }
100
    $self set nsenode_vportlist {}
101 102 103

    # This is a mote thing.
    $self set numeric_id {}
Leigh B. Stoller's avatar
Leigh B. Stoller committed
104 105 106 107 108
}

# The following procs support renaming (see README)
Node instproc rename {old new} {
    $self instvar portlist
Timothy Stack's avatar
 
Timothy Stack committed
109 110
    $self instvar console_

Leigh B. Stoller's avatar
Leigh B. Stoller committed
111 112
    foreach object $portlist {
	$object rename_node $old $new
Mac Newbold's avatar
Mac Newbold committed
113
    }
Leigh B. Stoller's avatar
Leigh B. Stoller committed
114
    [$self set sim] rename_node $old $new
Timothy Stack's avatar
 
Timothy Stack committed
115 116 117 118
    $console_ set node $new
    $console_ rename "${old}-console" "${new}-console"
    uplevel "#0" rename "${old}-console" "${new}-console"
    set console_ ${new}-console
Leigh B. Stoller's avatar
Leigh B. Stoller committed
119 120 121 122 123 124 125 126 127
}

Node instproc rename_lanlink {old new} {
    $self instvar portlist
    set newportlist {}
    foreach node $portlist {
	if {$node == $old} {
	    lappend newportlist $new
	} else {
128
	    lappend newportlist $node
Leigh B. Stoller's avatar
Leigh B. Stoller committed
129
	}
Mac Newbold's avatar
Mac Newbold committed
130
    }
Leigh B. Stoller's avatar
Leigh B. Stoller committed
131
    set portlist $newportlist
Mac Newbold's avatar
Mac Newbold committed
132 133
}

Leigh B. Stoller's avatar
Leigh B. Stoller committed
134 135 136 137 138 139 140 141 142 143 144
# 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 iplist
    $self instvar tarfiles
145
    $self instvar failureaction
146
    $self instvar inner_elab_role
147
    $self instvar plab_role
148
    $self instvar routertype
149
    $self instvar fixed
150
    $self instvar agentlist
Leigh B. Stoller's avatar
Leigh B. Stoller committed
151 152
    $self instvar routelist
    $self instvar sim
153 154
    $self instvar isvirt
    $self instvar virthost
Leigh B. Stoller's avatar
Leigh B. Stoller committed
155
    $self instvar issubnode
156
    $self instvar desirelist
157 158
    $self instvar nseconfig
    $self instvar simulated
Timothy Stack's avatar
 
Timothy Stack committed
159 160 161 162
    $self instvar topo
    $self instvar X_
    $self instvar Y_
    $self instvar orientation_
163
    $self instvar numeric_id
164
    var_import ::TBCOMPAT::default_osids
165 166
    var_import ::GLOBALS::use_physnaming
    var_import ::TBCOMPAT::physnodes
Timothy Stack's avatar
 
Timothy Stack committed
167
    var_import ::TBCOMPAT::objtypes
Leigh B. Stoller's avatar
Leigh B. Stoller committed
168 169
    var_import ::GLOBALS::pid
    var_import ::GLOBALS::eid
170
    var_import ::GLOBALS::default_ip_routing_type
171
    var_import ::GLOBALS::enforce_user_restrictions
172
    var_import ::TBCOMPAT::hwtype_class
173
    
Leigh B. Stoller's avatar
Leigh B. Stoller committed
174 175 176
    # 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 == {}} {
177 178 179 180
	if {$virthost == 0} {
	    if {[info exists default_osids($type)]} {
		set osid $default_osids($type)
	    }
181
	}
182 183
    } else {
	# Do not allow user to set os for virt nodes at this time.
184
	if {$enforce_user_restrictions && $isvirt} {
185 186 187 188
	    perror "You may not specify an OS for virtual nodes ($self)!"
	    return
	}
	# Do not allow user to set os for host running virt nodes.
189
	if {$enforce_user_restrictions && $virthost} {
190 191 192
	    perror "You may not specify an OS for hosting virtnodes ($self)!"
	    return
	}
Leigh B. Stoller's avatar
Leigh B. Stoller committed
193 194
    }

Leigh B. Stoller's avatar
Leigh B. Stoller committed
195 196 197 198 199
    #
    # If a subnode, then it must be fixed to a pnode, or we have to
    # create one on the fly and set the type properly. 
    # 
    if {$issubnode && $fixed == ""} {
200 201 202 203 204 205
        # XXX - hack for motes, to make Jay happy
        set hosttype "pc"
        if {$type == "mica2" || $type == "mica"} {
            set hosttype "mote-host"
        }
	$sim spitxml_data "virt_nodes" [list "vname" "type" "ips" "osname" "cmd_line" "rpms" "startupcmd" "tarfiles" "fixed" ] [list "host-$self" "$hosttype" "" "" "" "" "" "" "" ]
206
	$sim spitxml_data "virt_node_desires" [list "vname" "desire" "weight"] [list "host-$self" "hosts-$type" 1.0]
207
	set fixed "host-$self"
Leigh B. Stoller's avatar
Leigh B. Stoller committed
208 209
    }

210 211 212 213 214 215 216
    # Implicitly fix node if not already fixed.
    if { $issubnode == 0 && $use_physnaming == 1 && $fixed == "" } {
	if {[info exists physnodes($self)]} {
		set fixed $self
	}
    }

Leigh B. Stoller's avatar
Leigh B. Stoller committed
217 218 219 220
    # We need to generate the IP column from our iplist.
    set ipraw {}
    set i 0
    foreach ip $iplist {
221 222 223 224
	if { $ip == {} } {
	    # Give a dummy IP address if none has been set
	    set ip "0.0.0.0"
	}
Leigh B. Stoller's avatar
Leigh B. Stoller committed
225 226 227
	lappend ipraw $i:$ip
	incr i
    }
Mac Newbold's avatar
Mac Newbold committed
228

229 230
    foreach agent $agentlist {
	$agent updatedb $DB
231

232 233 234
	if {[$agent set application] != {}} {
	    $sim agentinit [$agent set application]
	}
235

236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254
	# The following is for NSE traffic generation
	# Simulated nodes in make-simulated should not be doing this
	if { $simulated != 1 } { 
	    append nseconfig [$agent get_nseconfig]
	}
    }

     if {$nseconfig != {}} {

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

        # update the per-node nseconfigs table in the DB
	$sim spitxml_data "nseconfigs" [list "vname" "nseconfig"] [list "$self" "$nsecfg_script"]
255
    }
256

Leigh B. Stoller's avatar
Leigh B. Stoller committed
257 258
    $self add_routes_to_DB $DB

Leigh B. Stoller's avatar
Leigh B. Stoller committed
259
    # Update the DB
260 261
    set fields [list "vname" "type" "ips" "osname" "cmd_line" "rpms" "startupcmd" "tarfiles" "failureaction" "routertype" "fixed" ]
    set values [list $self $type $ipraw $osid $cmdline $rpms $startup $tarfiles $failureaction $default_ip_routing_type $fixed ]
262

263 264 265 266 267
    if { $inner_elab_role != "" } {
	lappend fields "inner_elab_role"
	lappend values $inner_elab_role
    }

268 269 270 271 272
    if { $plab_role != "none" } {
	lappend fields "plab_role"
	lappend values $plab_role
    }

273 274 275 276 277
    if { $numeric_id != {} } {
	lappend fields "numeric_id"
	lappend values $numeric_id
    }

278
    $sim spitxml_data "virt_nodes" $fields $values
Timothy Stack's avatar
 
Timothy Stack committed
279

280
    if {$topo != "" && ($type == "robot" || $hwtype_class($type) == "robot")} {
Timothy Stack's avatar
 
Timothy Stack committed
281 282 283 284 285
	if {$X_ == "" || $Y_ == ""} {
	    perror "node \"$self\" has no initial position"
	    return
	}

Timothy Stack's avatar
 
Timothy Stack committed
286
	if {! [$topo checkdest $self $X_ $Y_ -showerror 1]} {
Timothy Stack's avatar
 
Timothy Stack committed
287 288 289 290 291
	    return
	}

	$sim spitxml_data "virt_node_startloc" \
		[list "vname" "building" "floor" "loc_x" "loc_y" "orientation"] \
Timothy Stack's avatar
 
Timothy Stack committed
292
		[list $self [$topo set area_name] "" $X_ $Y_ $orientation_]
Timothy Stack's avatar
 
Timothy Stack committed
293
    }
294
    
295 296 297 298 299
    # Put in the desires, too
    foreach desire [lsort [array names desirelist]] {
	set weight $desirelist($desire)
	$sim spitxml_data "virt_node_desires" [list "vname" "desire" "weight"] [list $self $desire $weight]
    }
Timothy Stack's avatar
 
Timothy Stack committed
300 301

    $sim spitxml_data "virt_agents" [list "vnode" "vname" "objecttype"] [list $self $self $objtypes(NODE)]
Mac Newbold's avatar
Mac Newbold committed
302
}
303

Leigh B. Stoller's avatar
Leigh B. Stoller committed
304 305 306 307 308 309
# 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
310
    $self instvar simulated
311 312 313 314

    # Check if we're making too many lanlinks to this node
    # XXX Could come from db from node_types if necessary
    # For now, no more than 4 links or interfaces per node
315 316
    # XXX Ignore if the lanlink is simulated i.e. one that
    # has all simulated nodes in it. 
317 318 319 320 321
#    set maxlanlinks 4
#    if { [$lanlink set simulated] != 1 && $maxlanlinks == [llength $portlist] } {
#	# adding this one would put us over
#	perror "Too many links/LANs to node $self! Maximum is $maxlanlinks."
#    }
322

Leigh B. Stoller's avatar
Leigh B. Stoller committed
323 324 325 326
    lappend portlist $lanlink
    lappend iplist ""
    return [expr [llength $portlist] - 1]
}
327

328 329 330 331 332 333 334 335 336 337 338
#
# 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} {
339
	    return $ll
340 341
	}
    }
342
    return {}
343 344
}

Leigh B. Stoller's avatar
Leigh B. Stoller committed
345 346 347 348 349 350 351 352 353 354 355 356 357
# 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 iplist [lreplace $iplist $port $port $ip]
    }    
358 359
}

Leigh B. Stoller's avatar
Leigh B. Stoller committed
360 361 362 363 364 365
# 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]
}
366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383

# 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
}
Leigh B. Stoller's avatar
Leigh B. Stoller committed
384 385 386 387 388 389 390 391 392 393 394 395 396 397

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

398
#
399
# Set the type/isremote/isvirt for a node. Called from tb_compat.
400
#
Leigh B. Stoller's avatar
Leigh B. Stoller committed
401
Node instproc set_hwtype {hwtype isrem isv issub} {
402 403
    $self instvar type
    $self instvar isremote
404
    $self instvar isvirt
Leigh B. Stoller's avatar
Leigh B. Stoller committed
405
    $self instvar issubnode
406 407 408

    set type $hwtype
    set isremote $isrem
409
    set isvirt $isv
Leigh B. Stoller's avatar
Leigh B. Stoller committed
410
    set issubnode $issub
411 412
}

413
#
Leigh B. Stoller's avatar
Leigh B. Stoller committed
414
# Fix a node. Watch for fixing a node to another node.
415 416
#
Node instproc set_fixed {pnode} {
417 418 419 420
    var_import ::TBCOMPAT::location_info
    var_import ::TBCOMPAT::physnodes
    $self instvar type
    $self instvar topo
421
    $self instvar fixed
Leigh B. Stoller's avatar
Leigh B. Stoller committed
422
    $self instvar issubnode
423 424 425

    if { [Node info instances $pnode] != {} } {
        # $pnode is an object instance of class Node
Leigh B. Stoller's avatar
Leigh B. Stoller committed
426 427
	if {$issubnode} {
	    $pnode set subnodehost 1
428
	    $pnode set subnodechild $self
Leigh B. Stoller's avatar
Leigh B. Stoller committed
429 430 431 432
	} else {
	    perror "\[set-fixed] Improper fix-node $self to $pnode!"
	    return
	}
433
    }
434
    set fixed $pnode
435 436 437 438 439 440 441 442 443 444 445 446 447 448

    if {[info exists physnodes($pnode)]} {
	set type $physnodes($pnode)
	
	if {$topo != ""} {
	    set building [$topo set area_name]
	    if {$building != {} && 
	    [info exists location_info($fixed,$building,x)]} {
		$self set X_ $location_info($fixed,$building,x)
		$self set Y_ $location_info($fixed,$building,y)
		$self set Z_ $location_info($fixed,$building,z)
	    }
	}
    }
449 450
}

Leigh B. Stoller's avatar
Leigh B. Stoller committed
451 452 453 454 455 456 457 458 459 460 461
#
# 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)
462
	set port -1
Leigh B. Stoller's avatar
Leigh B. Stoller committed
463 464

	#
465
	# Convert hop to IP address. Need to find the link between the
466
	# this node and the hop. This is easy if its a link. If its
467 468 469 470
	# a lan, then its ugly.
	#
	set hoplink [$sim find_link $self $hop]
	if {$hoplink == {}} {
471 472 473
	    set hoplan [$self find_commonlan $hop]
	    set port [$hop find_port $hoplan]
	    set srcip [$self ip [$self find_port $hoplan]]
474 475
	} else {
	    set port [$hop find_port $hoplink]
476
	    set srcip [$self ip [$self find_port $hoplink]]
477 478 479 480 481 482 483 484 485
	}
	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.
Leigh B. Stoller's avatar
Leigh B. Stoller committed
486 487 488 489 490 491
	#
	switch -- [$dst info class] {
	    "Node" {
		if {[llength [$dst set portlist]] != 1} {
		    perror "\[add-route] $dst must have only one link."
		}
492 493
		set link  [lindex [$dst set portlist] 0]
		set mask  [$link get_netmask]
Leigh B. Stoller's avatar
Leigh B. Stoller committed
494 495 496 497
		set dstip [$dst ip 0]
		set type  "host"
	    }
	    "SimplexLink" {
498 499 500
		set link  [$dst set mylink]
		set mask  [$link get_netmask]
		set src   [$link set src_node]
Leigh B. Stoller's avatar
Leigh B. Stoller committed
501 502 503 504 505
		set dstip [$src ip [$src find_port $link]]
		set type  "net"
	    }
	    "Link" {
		set dstip [$dst get_subnet]
506
		set mask  [$dst get_netmask]
Leigh B. Stoller's avatar
Leigh B. Stoller committed
507 508
		set type  "net"
	    }
509 510
	    "Lan" {
		set dstip [$dst get_subnet]
511
		set mask  [$dst get_netmask]
512 513
		set type  "net"
	    }
Leigh B. Stoller's avatar
Leigh B. Stoller committed
514 515 516 517 518
	    unknown {
		perror "\[add-route] Bad argument. Must be a node or a link."
		return
	    }
	}
519
	$sim spitxml_data "virt_routes" [list "vname" "src" "dst" "nexthop" "dst_type" "dst_mask"] [list $self $srcip $dstip $hopip $type $mask]
Leigh B. Stoller's avatar
Leigh B. Stoller committed
520 521
    }
}
Leigh B. Stoller's avatar
Leigh B. Stoller committed
522 523 524 525 526 527

#
# Create a program object to run on the node when the experiment starts.
#
Node instproc start-command {command} {
    $self instvar sim
528
    set newname "${self}_startcmd"
Leigh B. Stoller's avatar
Leigh B. Stoller committed
529

530
    set newprog [uplevel 2 "set $newname [new Program $sim]"]
Leigh B. Stoller's avatar
Leigh B. Stoller committed
531 532 533 534 535 536 537 538
    $newprog set node $self
    $newprog set command $command

    # Starts at time 0
    $sim at 0  "$newprog start"

    return $newprog
}
539 540 541 542 543 544 545 546 547 548 549 550 551

#
# Add a desire to the node, with the given weight
# Fails if the desire already exists, but maybe it could just update the
# weight?
#
Node instproc add-desire {desire weight} {
    $self instvar desirelist
    if {[info exists desirelist($desire)]} {
	perror "\[add-desire] Desire $desire on $self already exists!"
    }
    set desirelist($desire) $weight
}
Timothy Stack's avatar
 
Timothy Stack committed
552 553 554

Node instproc program-agent {args} {
    
Timothy Stack's avatar
 
Timothy Stack committed
555 556 557
    ::GLOBALS::named-args $args { 
	-command {} -dir {} -timeout {} -expected-exit-code {}
    }
Timothy Stack's avatar
 
Timothy Stack committed
558 559 560 561 562

    set curprog [new Program [$self set sim]]
    $curprog set node $self
    $curprog set command $(-command)
    $curprog set dir $(-dir)
Timothy Stack's avatar
 
Timothy Stack committed
563
    $curprog set expected-exit-code $(-expected-exit-code)
Timothy Stack's avatar
 
Timothy Stack committed
564
    if {$(-timeout) != {}} {
Timothy Stack's avatar
 
Timothy Stack committed
565
	set to [::GLOBALS::reltime-to-secs $(-timeout)]
Timothy Stack's avatar
 
Timothy Stack committed
566 567 568 569 570 571 572 573 574 575 576 577
	if {$to == -1} {
	    perror "-timeout value is not a relative time: $(-timeout)"
	    return
	} else {
	    $curprog set timeout $to
	}
    }

    return $curprog
}

Node instproc topography {topo} {
578
    var_import ::TBCOMPAT::location_info
Timothy Stack's avatar
 
Timothy Stack committed
579
    $self instvar sim
580
    $self instvar fixed
Timothy Stack's avatar
 
Timothy Stack committed
581

Timothy Stack's avatar
 
Timothy Stack committed
582 583 584 585 586 587 588 589 590 591 592 593 594
    if {$topo == ""} {
	$self set topo ""
	return
    } elseif {$topo != "" && ! [$topo info class Topography]} {
	perror "\[topography] $topo is not a Topography."
	return
    } elseif {! [$topo initialized]} {
	perror "\[topography] $topo is not initialized."
	return
    }

    $self set topo $topo

Timothy Stack's avatar
 
Timothy Stack committed
595 596 597
    $topo set sim $sim; # Need to link the topography to the simulator here.
    $sim add_topography $topo

598 599 600 601 602 603 604 605 606
    if {$fixed != ""} {
	set building [$topo set area_name]
	if {$building != {} && 
	    [info exists location_info($fixed,$building,x)]} {
	    $self set X_ $location_info($fixed,$building,x)
	    $self set Y_ $location_info($fixed,$building,y)
	    $self set Z_ $location_info($fixed,$building,z)
	}
    } elseif {[$self set type] == "pc"} {
Timothy Stack's avatar
 
Timothy Stack committed
607 608 609
	$self set type "robot"
    }
}
Timothy Stack's avatar
 
Timothy Stack committed
610 611 612 613 614 615

Node instproc console {} {
    $self instvar console_
    
    return $console_
}
616 617 618 619 620 621 622 623 624

#
# Set numeric ID (a mote thing)
#
Node instproc set_numeric_id {myid} {
    $self instvar numeric_id

    set numeric_id $myid
}