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

    set curprog [new Program [$self set sim]]
    $curprog set node $self
    $curprog set command $(-command)
562
    $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
}