assign_wrapper.in 106 KB
Newer Older
Leigh B. Stoller's avatar
Leigh B. Stoller committed
1
#!/usr/bin/perl -w
Leigh B. Stoller's avatar
Leigh B. Stoller committed
2
3
#
# EMULAB-COPYRIGHT
Leigh B. Stoller's avatar
Leigh B. Stoller committed
4
# Copyright (c) 2000-2003 University of Utah and the Flux Group.
Leigh B. Stoller's avatar
Leigh B. Stoller committed
5
6
# All rights reserved.
#
7
8
use English;
use Getopt::Std;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
9

10
#
Leigh B. Stoller's avatar
Leigh B. Stoller committed
11
12
13
14
15
16
# This function as the main assign loop.  It converts the virtual
# topology into a top input including LAN and delay translation.  It
# then snapshots the current testbed physical state and runs assign,
# looping a couple times if assign fails.  When assign successfully
# completes it will interpret the results.  Attempt to match any
# existing portmap entries and then update the delays and vlans table.
Chad Barb's avatar
Chad Barb committed
17
#
18
19
20
21
22
# XXX: Update does not work with widearea nodes.
#      Internally created nodes (jailhost,delay,sim) are not treated
#        consistently. Needs more thought.
#
# Return codes:
Chad Barb's avatar
Chad Barb committed
23
24
25
#
# 0  - success
# 1+ - error (Add other values:)
26
# 2  - max_concurrent violation
Chad Barb's avatar
Chad Barb committed
27
28
29
30
31
32
33
# 4  - bandwidth violation
# 8  - linkusers violation
# 16 - desires violation
# 32 - unassigned
# 64 - Set to indicate 'recoverability'
#      (E.g., no db or physical state was modified
#       by the time the error occurred.)
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# -1 - An uncontrolled error (someone called die()). No recovery is possible
#      so the caller has to check for this explicitly.
#
sub usage ()
{
    print STDERR "Usage: $0 [-v] [-u | -n] pid eid\n";
    print STDERR " -v   - enables verbose output\n";
    print STDERR " -u   - enables update functionality\n";
    print STDERR " -t   - Create the TOP file and then exit\n";
    print STDERR " -n   - Run assign, but do not reserve/modify resources.\n";
    exit(-1);
}
my $optlist  = "vutn";
my $verbose  = 0;
my $updating = 0;
my $toponly  = 0;
my $impotent = 0;

#
# Configure variables
#
my $TBROOT	  = "@prefix@";
my $DELAYCAPACITY = @DELAYCAPACITY@;
$ENV{'PATH'} = "/usr/bin:$TBROOT/libexec:$TBROOT/sbin:$TBROOT/bin";

#
# Turn off line buffering on output
#
$| = 1;

#
# Testbed Support libraries
#
use lib "@prefix@/lib";
use libdb;
use libtestbed;
require exitonwarn;

Chad Barb's avatar
Chad Barb committed
72
#
73
74
75
76
77
# assign_wrapper Settings
#
# Maximum delay in ms above which a delay node is needed.
# (Note that the DB represents delays as floating point numbers)
my $delaythresh = 2;
Chad Barb's avatar
Chad Barb committed
78

79
80
# Maximum number of times we run assign.
my $maxrun = 20;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
81

82
83
84
# Use the switch to delay when possible. Currentlythis only works for 10mbit
# links (actually, its turned off cause it does not work; auto handshake).
my $delaywithswitch = 0;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
85

86
87
88
89
90
91
92
93
94
95
96
#
# Some handy constants. Speed in Mbits/sec and Kbits/sec units.
#
# Its probably a good idea to leave portbw (current_speed) in Mbs, since
# those numbers are used at the switch and the interfaces, which really
# only think in Mbps.
#
my $S10Mbs  = 10;
my $S100Mbs = 100;
my $S10Kbs  = 10000;
my $S100Kbs = 100000;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
97

98
#
99
100
# Parse command arguments. Once we return from getopts, all that should be
# left are the required arguments.
101
#
102
103
104
%options = ();
if (! getopts($optlist, \%options)) {
    usage();
105
}
106
107
if (@ARGV != 2) {
    usage();
Chad Barb's avatar
Chad Barb committed
108
}
109
if (defined($options{"v"})) {
Chad Barb's avatar
   
Chad Barb committed
110
111
    $verbose = 1;
}
112
if (defined($options{"u"})) {
Chad Barb's avatar
   
Chad Barb committed
113
    $updating = 1;
114
}
115
116
117
118
119
if (defined($options{"t"})) {
    $toponly = 1;
}
if (defined($options{"n"})) {
    $impotent = 1;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
120
}
121
122
123
124
my $pid = $ARGV[0];
my $eid = $ARGV[1];
my $ptopfile = "$pid-$eid-$$.ptop";
my $topfile  = "$eid.top";
125

126
127
128
sub fatal ($$)
{
    my($exitcode, $message) = @_;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
129

130
131
132
133
    $message =~ s/\n$//;
    print STDERR "$message\n";
    exit($exitcode);
}
Leigh B. Stoller's avatar
Leigh B. Stoller committed
134

135
136
sub printdb ($)
{
Leigh B. Stoller's avatar
Leigh B. Stoller committed
137
138
139
    if ($verbose) {
	print $_[0];
    }
140
}
Leigh B. Stoller's avatar
Leigh B. Stoller committed
141

142
print "assign_wrapper improved started\n";
143
144
TBDebugTimeStamp("assign_wrapper started");

Leigh B. Stoller's avatar
Leigh B. Stoller committed
145
#
146
# The main data structures:
Leigh B. Stoller's avatar
Leigh B. Stoller committed
147
#
148
149
150
151
152
# virt_nodes: The virtual nodes, indexed by vname. Each entry is a
# hash reference, initially of just the DB info, but possibly
# augmented as we proceed through assign.  Do not confuse these
# virtual nodes with the other virtual nodes! These are the ones from
# the actual topology, the virt_nodes table in the DB.
Leigh B. Stoller's avatar
Leigh B. Stoller committed
153
#
154
155
my %virt_nodes = ();

Leigh B. Stoller's avatar
Leigh B. Stoller committed
156
#
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
# virt_lans: The equivalent of virt_nodes; the virt_lans table in the DB.
# Since there are multiple rows per lan (one for each node), this is a
# multilevel structure. The first slot is another hash, one for each node.
# The rest of the slots store other random things associated with the lan.
# So, looks something like:
#
#   %virt_lans = (link0 => {members    => member0 => { db row ref },
#                                         member1 => { db row ref }}
#                           mustdelay    => 0,
#                           emulated     => 0,
#                           uselinkdelay => 0,
#                           nobwshaping  => 0,
#                           useveth      => 0,
#                           trivok       => 0
#                          }
#                 link1 => ...
#                )
#
my %virt_lans = ();

#
# virt_vtypes: The virt_vtypes table in the DB, indexed by the vtype
# name (user chosen name).
#
my %virt_vtypes = ();

#
# node_types: The node_types table from the DB, indexed by the type name.
#
my %node_types = ();

Leigh B. Stoller's avatar
Leigh B. Stoller committed
188
# 
189
190
191
192
# interface_types: We need this to find out the bandwidths of the devices
# we actually have on the testbed. Index by interface type name.
#
my %interface_types = ();
Leigh B. Stoller's avatar
Leigh B. Stoller committed
193

194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
#
# phys_nodes: The equiv of virt_nodes above, except that these are pulled
# from the DB once the physical resources have been allocated. Indexed
# by physname, but there is a pointer from the virt_nodes table entry
# to the the corresponding physnode entry. 
# 
my %phys_nodes = ();

#
# More physical side data structures.
# v2pmap is indexed by virtual and contains the physical node.
my %v2pmap = ();
# p2vmap is indexed by physical and contains one or more virtual nodes.
my %p2vmap = ();
# plinks is indexed by virtual name and contains
#  (pnodeportA,pnodeportB) .  If one is a delay node it is always
#  the second.
my %plinks = ();
# virtnodes is the list of subnodes on physnodes.
my %virtnodes = ();
my %v2vmap = ();

#
# Support for experiment modify. We create v2p and v2v mappings of the
# current topology so we can figure out how its changed after assign
# runs. These correspond to v2pmap and v2vmap mentioned above.
# 
my %reserved_v2pmap  = ();
my %reserved_v2vmap  = ();
223

Leigh B. Stoller's avatar
Leigh B. Stoller committed
224
#
225
226
227
228
229
230
231
232
233
234
235
236
237
# Experiment wide options. See below. They come from the experiments table.
# Defining these will override experiment table setting. 
#
# Set this when forcing linkdelays instead of delay nodes. Set in the NS
# file with a tb-compat directive. The force directive says to set up a
# link delay, even when no delay would otherwise be inserted.
# usewatunnels is also set in the NS, and can be used to turn them off. 
# The multiplex_factor is to override node_types table for virtnode.
my $uselinkdelays;
my $forcelinkdelays;
my $usewatunnels;
my $multiplex_factor;

238
239
240
241
# For admission control. Not well defined yet.
my $cpu_usage;
my $mem_usage;

242
######################################################################
Leigh B. Stoller's avatar
Leigh B. Stoller committed
243

244
245
246
247
248
# ips is indexed by node:port and contains the IP address for the port.
my %ips	      = ();

# memberof is indexed by node:port and holds the lan it is a member of.
my %memberof = ();
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264

# delaylinks stores the actual link delay info, converted from the
# virt delay params above. It is indexed by link name and contains
# [delay,bw,loss] for each direction. 
my %delaylinks = ();

# delaynodes stores the names of delaynodes that we create on the
# fly using delayid. This is useful for doing isdelay? tests.
my %delaynodes = ();
my $delayid    = 0;

# nodedelays and linkdelays are the final (!) representation. Indexed by
# integer id, they store the physical node info and the delay info. 
my %nodedelays = ();
my %linkdelays = ();

265
266
267
268
# Virtual nodes that the user has requested be "fixed" to a specific
# physical node.
my %fixed_nodes     = ();

269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
# portbw is indexed by virtual nodeport and contains the bandwidth of
# that port. Note that port bandwidth in the interfaces table is left
# in Mbps units for now. Thats inconsistent, I know. For LANs with
# other bandwidths the port speed will be 100 and a delay node will be
# inserted.
my %portbw = ();

# lannodes is indexed by physical name and is the set of fake lan nodes.
# lan nodes are named lan/<virtual lan>. We need to know these so that
# when they come back from assign, we can ignore them.
my %lannodes = ();

# Node estimates and counts. Avoid running assign if there is no way to
# satisfy the estimates for physical nodes.
my $minimum_nodes;
my $maximum_nodes;
my $remotecount  = 0;
my $virtcount    = 0;
287
my $plabcount    = 0;
288
my $needwanassign= 0;
289

290
291
292
293
294
295
296
297
298
299
300
301
#
# This is for stats gathering. It might duplicate other stuff, but
# thats okay.
#
my %expt_stats = (# pnodes include jailnodes and delaynodes.
		  # We let the wrapper determine pnodes once the
		  # experiment is fully swapped in so that the record
		  # is not "committed" until successful swapin.
		  jailnodes   => 0,
		  vnodes      => 0,
                  # vnodes include wanodes.
		  wanodes     => 0,
302
303
		  # wanodes includes plabnodes.
		  plabnodes   => 0,
304
305
306
307
308
309
310
311
312
313
314
315
316
		  simnodes    => 0,
		  delaynodes  => 0,
		  linkdelays  => 0,
		  links       => 0,
		  walinks     => 0,
		  lans        => 0,
		  shapedlinks => 0,
		  shapedlans  => 0,
		  minlinks    => 100000,
		  # includes emulated links. Maybe thats wrong.
		  maxlinks    => 0,
);

317
318
# XXX NSE hack: List of simulated nodes. All these will go
# into one pc850. Needs to change in distributed nse.
Shashi Guruprasad's avatar
Shashi Guruprasad committed
319
320
my @simnodelist;
my %simnode_iplist = ();
321
322
my %iptonodemap    = ();
my $nsenode_id     = 0;
323
324
# lans that have simulated nodes
my %simnodelans    = ();
Shashi Guruprasad's avatar
Shashi Guruprasad committed
325

326
# Counters for generating IDs.
327
my $virtnode_id  = 0;
328
my $veth_id      = 0;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
329

330
331
######################################################################
# Step 1 - Setup virtual topology
332
#
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
# Here we need to read the virtual topology in from the virt_nodes
# and virt_lans table.  We then need to add delay and lan nodes as
# necessary.
#
# Conversion details:
#   Let L be a LAN with N members.
#   If N == 2 
#      Let N1 be node 1
#      Let N2 be node 2
#      If L is delayed
#         Generate delay node D
#         Link N1 to D
#         Link N2 to D
#      Else
#         Link N1 to N2
#   Else
#      Generate lan node A
#      If L is delayed
#        Foreach node N in L
#           Generate delay node DN
#           Link A to DN
#           Link N to DN
#      Else
#        Foreach node N in L
#           Link N to A
#
# Delay node names:
#  delay nodes are named tbdelayXX N > 2
#   and tbsdelayXX for N == 2.
#
########################################################################
Chad Barb's avatar
   
Chad Barb committed
364

365
366
printdb "Generating TOP file.\n";
TBDebugTimeStamp("TOP started");
367

368
369
370
371
372
#
# Load phys info. Interface types, node types, etc. Its any physical stuff
# we need.
#
LoadPhysInfo();
373

374
375
376
377
#
# Load the Experiment info and virt topology.
#
LoadExperiment();
378

379
380
381
382
383
384
#
# If updating, load current experiment resources. We have to be careful
# of how this is merged in with the (new) desired topology. See below.
#
LoadCurrent()
    if ($updating);
Chad Barb's avatar
   
Chad Barb committed
385

386
387
388
389
#
# Check Max Concurrent for OSID violations.
#
CheckMaxConcurrent();
390

391
392
393
394
#
# Create the TOP file.
#
CreateTopFile();
395

396
397
398
399
400
401
TBDebugTimeStamp("TOP finished");

# Stop here ...
if ($toponly) {
    print "Stopping after creating the TOP file, as directed.\n";
    exit(0);
Leigh B. Stoller's avatar
Leigh B. Stoller committed
402
}
403

404
405
406
407
408
409
410
411
412
######################################################################
# Step 2 - Assign Loop
# 
# Here we loop up to maxrun times.  In each loop we snapshot the
# current testbed state into a ptop file.  We then run assign.  If
# assign succeeds we attempt to reserve the resources.  If that works
# we're done with step 2 otherwise we loop again.
#
#######################################################################
Leigh B. Stoller's avatar
Leigh B. Stoller committed
413

414

415

416
417
418
419
TBDebugTimeStamp("assign_loop started");
$currentrun = 1;
while (1) {
    print "Assign Run $currentrun\n";
420

421
422
423
424
425
    # Violation counts
    $unassigned = -1;
    $linkusers = -1;
    $bandwidth = -1;
    $desires = -1;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
426
427
428
429

    # Clear v2pmap, p2vmap, and plinks
    undef %v2pmap;
    undef %p2vmap;
430
    undef %v2vmap;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
431
    undef %plinks;
432
433
    undef %toreserve;
    undef %virtnodes;
434
    my %subnodes = ();
Shashi Guruprasad's avatar
Shashi Guruprasad committed
435
    
436
    TBDebugTimeStamp("ptopgen started");
Leigh B. Stoller's avatar
Leigh B. Stoller committed
437
    # Snapshot
Chad Barb's avatar
   
Chad Barb committed
438
439
440
441
    #
    # if updating (-u), include any resources that may already be
    # allocated to experiment in the PTOP results.
    #
442
443
    my $ptopargs = "-p $pid ";
    $ptopargs   .= "-e $eid "
444
445
446
	if ($updating);
    $ptopargs   .= "-m $multiplex_factor "
	if (defined($multiplex_factor));
447
448
    $ptopargs   .= "-v "
	if ($virtcount);
449
450
    $ptopargs   .= "-r "
	if ($remotecount);
451
    system("ptopgen $ptopargs > $ptopfile");
Chad Barb's avatar
   
Chad Barb committed
452

453
    TBDebugTimeStamp("ptopgen finished");
Leigh B. Stoller's avatar
Leigh B. Stoller committed
454
455

    # Get number of nodes
456
457
    my $numnodes_result = 
	DBQueryFatal("select a.node_id,a.type from" .
Leigh B. Stoller's avatar
Leigh B. Stoller committed
458
459
460
		     " nodes as a left join reserved as b" .
		     " on a.node_id=b.node_id" .
		     " where b.node_id is null" .
461
		     " and a.role='testnode' and a.type!='dnard'");
462
    $numnodes = $numnodes_result->numrows;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
463
464
    
    if ($numnodes < $minimum_nodes) {
465
466
	fatal(65, "*** $0:\n".
	          "    Insufficient nodes available.\n");
Leigh B. Stoller's avatar
Leigh B. Stoller committed
467
468
    }

469
    TBDebugTimeStamp("assign started");
Leigh B. Stoller's avatar
Leigh B. Stoller committed
470
471
    # Run assign
    $fail = 0;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
472
    my $cmdargs = "$ptopfile $topfile";
473
    $cmdargs = "-Pop $cmdargs"
474
	if ($virtcount);
475
    print "assign $cmdargs\n";
476
477
478
    if (system("assign $cmdargs > assign.log") < 0) {
	fatal(65, "*** $0:\n".
	          "    Could not start assign!");
Chad Barb's avatar
Chad Barb committed
479
480
    }
    
Leigh B. Stoller's avatar
Leigh B. Stoller committed
481
482
    $violations = 0;
    $score = -1;
Chad Barb's avatar
Chad Barb committed
483
    $assignexitcode = $? >> 8;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
484

485
486
487
    open(ASSIGNFP, "assign.log") or
	fatal(65, "*** $0:\n".
	          "    Could not open assign logfile!");
Chad Barb's avatar
Chad Barb committed
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503

    if ($assignexitcode == 0)
    {
	# read output
	# Header
	printdb "Reading assign results.\n";
	while (<ASSIGNFP>) {
	    chop;
	    /No physical nodes of type (.+)$/ && do {
		$score=-2;
		print $_ . "\n";
	    };
	    /^With ([0-9]+) violations$/ && do {
		$violations = $1;
		last;
	    };
504
505
506
507
	    /^[ \t]+BEST SCORE: [ \t]+([0-9]+(\.[0-9]+)?)/ && do {
		$score=$1;
		print $_ . "\n";
	    };
Chad Barb's avatar
Chad Barb committed
508
509
510
511
512
513
	}
	if ($score == -2) {
	    # Type error
	    fatal(65, "Giving up.\n" );
	}
	printdb "Found score $score, violations $violations.\n";
514
    }
Leigh B. Stoller's avatar
Leigh B. Stoller committed
515

516
    # We do not bother reading anything else if violations occured.
Leigh B. Stoller's avatar
Leigh B. Stoller committed
517
518
519
520
521
522
523
524
    if (($violations == 0) && ($score != -1)) {
	# read nodes section
	while (<ASSIGNFP> !~ /^Nodes:/) {}
	printdb "Nodes:\n";
	while (<ASSIGNFP>) {
	    chop;
	    /^End Nodes$/ && last;
	    @info = split;
525
526
527
528
529
530
	    ($virtual,$physical) = @info[0,1];

	    # We don't care about LAN nodes anymore.
	    if (defined($lannodes{$virtual})) {
		next;
	    }
Chad Barb's avatar
   
Chad Barb committed
531

532
	    if (physnodeallocated($physical)) {
Chad Barb's avatar
   
Chad Barb committed
533
534
535
536
537
		#
		# Mark node as being reused.
		#
		# Look at virtual node being mapped to node;
		# if it wasn't in the previous map, mark node for reboot.
538
		#
539
		if (physnodereuse($physical) eq "reboot") {
540
541
		    # No changes once it goes into reboot.
		    ;
Chad Barb's avatar
   
Chad Barb committed
542
		}
543
		elsif (virtnodeisvirt($virtual)) {
544
545
546
547
548
		    #
		    # A new virt virtual node on an existing physical node
		    # does not force the physnode to be rebooted; we can
		    # set up a new virtnode on it without a reboot. If its
		    # an existing virtual on the same physnode, then mark
549
		    # both as reused; no need to reboot either. If the 
550
551
552
553
554
555
556
		    # virtnode has moved here from someplace else, no
		    # reboot of the physnode either, but obviously the
		    # vnode will be released and a new one allocated.  What
		    # we cannot determine is if its just a renamed node
		    # (which would require a reboot of the the virtual
		    # node). 
		    # 
557
558
		    if (!exists($reserved_v2pmap{$virtual})) {
			physnodesetreuse($physical, "reused");
559
		    }
560
561
		    elsif ($reserved_v2pmap{$virtual} eq $physical) {
			my $reserved = $reserved_v2vmap{$virtual};
562

563
564
			physnodesetreuse($reserved, "reused");
			physnodesetreuse($physical, "reused");
565
566
		    }
		    else {
567
			physnodesetreuse($physical, "reused");
568
569
570
571
572
573
574
575
576
577
578
579
		    }
		}
		else {
		    #
		    # If a new virtual node mapped to this physnode (maybe
		    # even the luser changed the name of the node), or if an
		    # existing virtual node moved to this physnode, must
		    # reboot the physnode. Else, the physnode is being
		    # reused as is, and no need to mess with it. If the
		    # user requested reboot, that will be handled outside
		    # of this script.
		    #
580
581
582
		    if (!exists($reserved_v2pmap{$virtual}) ||
			$reserved_v2pmap{$virtual} ne $physical) {
			physnodesetreuse($physical, "reboot");
583
584
		    }
		    else {
585
			physnodesetreuse($physical, "reused");
586
587
588
589
		    }
		}
	    }
	    else {
Chad Barb's avatar
   
Chad Barb committed
590
		#
591
592
593
		# This is a new node; we'll have to reserve it. Note that
		# we do not reserve a widearea physnode when a virtual node
		# is mapped to it; they are special.
Chad Barb's avatar
   
Chad Barb committed
594
		#
595
596
		$toreserve{$physical} = 1
		    if (!virtnodeisremote($virtual));
Chad Barb's avatar
   
Chad Barb committed
597
	    }
598
	    
599
	    if (virtnodeisvirt($virtual)) {
600
601
602
603
604
605
606
607
608
		#
		# If mapping a virtual node, then record that, since we need
		# to allocate the virtnodes on that physnode, later.
		#
		if (!defined($virtnodes{$physical})) {
		    $virtnodes{$physical} = [];
		}
		push(@{$virtnodes{$physical}}, $virtual);
	    }
609
610
611
612
613
614
615
	    elsif (virtnodeissubnode($virtual)) {
		#
		# Need to allocate the parent to. Should be optional?
		# Save away and deal with once we have all the results.
		#
		$subnodes{$virtual} = $physical;
	    }
616
	    
Leigh B. Stoller's avatar
Leigh B. Stoller committed
617
	    $v2pmap{$virtual} = $physical;
Shashi Guruprasad's avatar
Shashi Guruprasad committed
618
	    if( ! defined($p2vmap{$physical}) ) {
619
		$p2vmap{$physical} = [];
Shashi Guruprasad's avatar
Shashi Guruprasad committed
620
621
	    }
	    push(@{$p2vmap{$physical}}, $virtual);
Leigh B. Stoller's avatar
Leigh B. Stoller committed
622
623
624
	    printdb "  $virtual $physical\n";
	}

625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
	#
	# Process the subnodes. We have to allocate the parent at the same
	# time, lest it get sucked away for some other purpose by another
	# experiment. We might want to push this off into nalloc, but not
	# sure yet.
	#
	for my $virtual (keys(%subnodes)) {
	    my $physical = $subnodes{$virtual};
	    my $parent;

	    TBPhysNodeID($physical, \$parent);

	    printdb "  Subnode: $virtual $physical $parent\n";

	    #
	    # See if we already have it. Swapmod, retry, or perhaps
	    # the parent could be named separately? Or maybe there are
	    # several subnodes on the physnode?
	    #
	    next
		if (exists($p2vmap{$parent}));

	    # Make up a name and add to the list.
	    my $newvname = newvname($parent, "phost");

	    $v2pmap{$newvname} = $parent;
	    $p2vmap{$parent} = [ $newvname ];
	    $toreserve{$parent} = 1;
	    printdb "  Adding subnode host: $newvname $parent\n";
	}

Leigh B. Stoller's avatar
Leigh B. Stoller committed
656
657
658
	# read Edges
	# By convention, in plinks, the delay node is always the second
	# entry.
Chad Barb's avatar
Chad Barb committed
659
	while (<ASSIGNFP> !~ /^Edges:/) { }
Leigh B. Stoller's avatar
Leigh B. Stoller committed
660
	printdb "Edges:\n";
Shashi Guruprasad's avatar
Shashi Guruprasad committed
661
662
	EDGEWHILE: while (<ASSIGNFP>) {
	    /^End Edges$/ && last EDGEWHILE;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
663
664
665
666
667
668
669
670
671
	    @info = split;
	    $line = $_;
	    $_ = $info[1]; # type
	  SWITCH1: {
	      /^intraswitch$/ && do {
		  ($vlink,$rawA,$rawB) = @info[0,3,5];
		  last SWITCH1;
	      };
	      /^interswitch$/ && do {
672
673
		  ($vlink,$rawA,$rawB) = @info[0,3,$#info];
		  last SWITCH1;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
674
675
	      };
	      /^direct$/ && do {
676
		  ($vlink,$rawA,$rawB) = @info[0,3,5];
677
		  last SWITCH1;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
678
	      };
Shashi Guruprasad's avatar
Shashi Guruprasad committed
679
680
681
682
683
684
	      /^trivial$/ && do {
		  # we don't have plinks for trivial links
		  $vlink = $info[0];
		  $plinks{$vlink} = [];
		  next EDGEWHILE;
	      };
Leigh B. Stoller's avatar
Leigh B. Stoller committed
685
686
	      print "Found garbage: $line\n";
	  }
687
688
689
690
	    $nodeportA = &getnodeport($rawA);
	    $nodeportB = &getnodeport($rawB);
	    $nodeportA =~ s/\//:/;
	    $nodeportB =~ s/\//:/;
691
	    $plinks{$vlink} = [$nodeportA,$nodeportB];
Leigh B. Stoller's avatar
Leigh B. Stoller committed
692
693
694
695
	    printdb "  $vlink " . join(" ",@{$plinks{$vlink}}) . "\n";
	}
    } else {
	# spit out up to nodes
Chad Barb's avatar
Chad Barb committed
696
	print "ASSIGN FAILED: \n";       
Leigh B. Stoller's avatar
Leigh B. Stoller committed
697
	while (<ASSIGNFP>) {
698
	    if (/link_users:\s*(\d+)$/) {
Leigh B. Stoller's avatar
Leigh B. Stoller committed
699
		$linkusers = $1;
700
	    } elsif (/bandwidth:\s*(\d+)$/) {
Leigh B. Stoller's avatar
Leigh B. Stoller committed
701
		$bandwidth = $1;
702
	    } elsif (/unassigned:\s*(\d+)$/) {
703
		$unassigned = $1;
704
	    } elsif (/desires:\s*(\d+)$/) {
Leigh B. Stoller's avatar
Leigh B. Stoller committed
705
706
707
708
709
710
711
712
713
		$desires = $1;
	    }
	    if (/^Nodes:/) {last;}
	    print "$_";
	}
	$fail = 1;
    }
    while (<ASSIGNFP>) { } # Read anything left in the pipe before closing
    close(ASSIGNFP);
714
    TBDebugTimeStamp("assign finished");
Leigh B. Stoller's avatar
Leigh B. Stoller committed
715
716

    # Reserve resources
717
    if (!$fail) {
718
719
720
721
	if ($impotent) {
	    print "Skipping physical reservation, as directed.\n";
	    last;
	}
Chad Barb's avatar
Chad Barb committed
722
723
	TBDebugTimeStamp("reserving started");

724
	if (system("nalloc $pid $eid " . join(" ", keys(%toreserve)))) {
Leigh B. Stoller's avatar
Leigh B. Stoller committed
725
	    print "Failed to reserve nodes. Trying again.\n";
726
727
	}
	else {
Leigh B. Stoller's avatar
Leigh B. Stoller committed
728
	    print "Successfully reserved physical nodes\n";
Chad Barb's avatar
   
Chad Barb committed
729
730
731
732
733
734

	    foreach $node (keys(%toreserve)) {
		# in future, this will be a fully enforced state machine.
		TBSetNodeAllocState( $node, TBDB_ALLOCSTATE_RES_INIT_DIRTY() );
	    }

735
	    TBDebugTimeStamp("reserving finished");
Chad Barb's avatar
   
Chad Barb committed
736

737
738
739
740
741
742
	    #
	    # Release phys and virt nodes no longer needed. They are marked
	    # for teardown. They need to be freed by SOMEONE, currently the
	    # wrapper (tbswap), since this only happens when in update mode
	    # (swapmod).
	    #
743
744
745
746
	    foreach my $pnode (keys(%phys_nodes)) {
		my $reuse = physnodereuse($pnode);
		
		if ($reuse eq "unused") {
Chad Barb's avatar
   
Chad Barb committed
747
748
749
		    #
		    # Node was used in previous incarnation, but not any more.
		    #
750
		    TBSetNodeAllocState($pnode,
751
752
753
					TBDB_ALLOCSTATE_RES_TEARDOWN());
		    
		}
754
		elsif ($reuse eq "reboot") {
Chad Barb's avatar
   
Chad Barb committed
755
756
757
758
		    #
		    # Node is being reused, but for a different purpose, so
		    # it should be rebooted.
		    #
759
		    TBSetNodeAllocState($pnode,
760
					TBDB_ALLOCSTATE_RES_INIT_DIRTY());
Chad Barb's avatar
   
Chad Barb committed
761
762
		}
	    }
Leigh B. Stoller's avatar
Leigh B. Stoller committed
763
764
765
766
767
	    last;
	}
    }

    # Check for exit
Chad Barb's avatar
Chad Barb committed
768
769
    if ($assignexitcode == 2 || $currentrun >= $maxrun) {
	$exitcode = 65;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
770
771
	if ($bandwidth > 0) {
	    $exitcode += 4;
Chad Barb's avatar
Chad Barb committed
772
	}
Leigh B. Stoller's avatar
Leigh B. Stoller committed
773
774
775
776
777
778
	if ($linkusers > 0) {
	    $exitcode += 8;
	}
	if ($desires > 0) {
	    $exitcode += 16;
	}
779
780
781
	if ($unassigned > 0) {
	    $exitcode += 32;
	}
Chad Barb's avatar
Chad Barb committed
782
783
784
785
786
787
788
789

	if ($assignexitcode == 2) {
	    fatal($exitcode, "*** $0:\n".
		     "    Unretriable error. Giving up.\n");
	} else {
	    fatal($exitcode, "*** $0:\n".
		     "    Reached run limit. Giving up.\n");
	}
Leigh B. Stoller's avatar
Leigh B. Stoller committed
790
    }
Chad Barb's avatar
Chad Barb committed
791
792
793
    print "Waiting 5 seconds and trying again...\n";
    sleep(5);

Leigh B. Stoller's avatar
Leigh B. Stoller committed
794
795
    $currentrun++;
}
796
797
TBDebugTimeStamp("assign_loop finished");

798
799
800
801
802
803
804
805
806
807
###########################################################################
# Step 2A
#
# We run the wanassigner to allocate remote nodes. We do this after cause
# it takes so long. We run it just once.
#
# wanassign does its own nalloc.
#
###########################################################################

808
#
809
# VIRTNODES HACK: Allocate the remote virtual nodes.
810
#
811
if ($needwanassign) {
812
    my $success  = 0;
813
    my $wanargs  = ($impotent ? "-n" : "");
814

815
816
817
818
819
820
821
822
823
824
825
    print "Running 'wanassign -d $wanargs $pid $eid'\n";
    open(WANFP,"wanassign -d $wanargs $pid $eid 2>&1 | tee wanassign.log |") or
	fatal(65, "*** $0:\n".
	          "    Failed to start wanassign: $!\n");

    printdb "Reading wanassign results.\n";
    while (<WANFP>) {
	chop;
	if ($_ =~ /(\S+) mapsto (\S+)/) {
	    $v2vmap{$1} = $2;
	    printdb "  $1 $2\n";
826
	}
827
828
829
830
831
832
833
834
	if ($_ =~ /^Success/) {
	    $success = 1;
	}
	# Skip other output. Usually its debugging output.
    }
    close(WANFP) or
	fatal(65, "*** $0:\n".
	          "    wanassign: " . $? ? "exited with status: $?.\n" :
835
836
		                         "error closing pipe: $!\n");

837
838
839
840
841
842
843
    if (!$success) {
	fatal(65,"*** $0:\n".
	         "    wanassign could not find a solution!\n");
    }
    foreach my $virtual (keys(%v2vmap)) {
	my $physical = $v2vmap{$virtual};
	my $phys_nodeid;
844

845
	TBPhysNodeID($physical, \$phys_nodeid);
846
	    
847
848
849
850
851
	$v2pmap{$virtual} = $phys_nodeid;
	if ( !defined($p2vmap{$phys_nodeid})) {
	    $p2vmap{$phys_nodeid} = [];
	}
	push(@{$p2vmap{$phys_nodeid}}, $virtual);
852

853
854
	# Virtual nodes are always clean. Also prevents errors elsewhere.
	if (!$impotent) {
855
	    TBSetNodeAllocState($physical, TBDB_ALLOCSTATE_RES_INIT_CLEAN());
856
	}
857
    }
858
    TBDebugTimeStamp("wanassign finished");
859
860
}

Chad Barb's avatar
Chad Barb committed
861
862
#
# Recoverability ends.
863
# All fatal() calls from this point do not have the recoverable '64' bit set.
Chad Barb's avatar
Chad Barb committed
864
865
#

Leigh B. Stoller's avatar
Leigh B. Stoller committed
866
#
867
868
869
# VIRTNODES HACK: Local virtnodes have to be mapped now. This is a little
# hokey in that the virtnodes just need to be allocated from the pool that
# is on the real node. We know they are free, but we should go through
870
# nalloc anyway. If anything fails, no point in retry.
Leigh B. Stoller's avatar
Leigh B. Stoller committed
871
#
872
873
foreach my $pnode (keys(%virtnodes)) {
    my @vlist = @{$virtnodes{$pnode}};
874
    my $numvs = @vlist;
875
    my @plist = ();
876
877
    my @oplist = ();
    my @ovlist = ();
Leigh B. Stoller's avatar
Leigh B. Stoller committed
878
879

    #
880
881
882
    # If updating, need to watch for nodes that are already reserved.
    # We save that info in oplist/ovlist, and build a new vlist for
    # avail, of just the nodes we need in this run. 
883
    #
884
885
886
887
888
    if ($updating) {
	my @newvlist = ();
	my @delvlist = ();
	
	foreach my $vnode (@vlist) {
889
	    if (!defined($reserved_v2vmap{$vnode})) {
890
891
892
893
		# A new vnode on pnode to allocate.
		push(@newvlist, $vnode);
		next;
	    }
894
	    if ($reserved_v2pmap{$vnode} ne $pnode) {
895
		# A vnode moved. Its new to this pnode.
896
		print "$vnode has moved from $reserved_v2pmap{$vnode} ".
897
898
899
900
901
		    "to $pnode!\n";
		
		push(@newvlist, $vnode);
		next;
	    }
Leigh B. Stoller's avatar
Leigh B. Stoller committed
902

903
	    # Push already allocated p/v onto lists for later.
904
	    push(@oplist, $reserved_v2vmap{$vnode});
905
906
907
908
909
	    push(@ovlist, $vnode);
	}
	# These are the new nodes we need to allocate
	@vlist = @newvlist;
	$numvs = scalar(@vlist);
Leigh B. Stoller's avatar
Leigh B. Stoller committed
910

911
912
913
914
	if (@oplist) {
	    print "Reusing vnodes @oplist\n"; 
	}
    }
Leigh B. Stoller's avatar
Leigh B. Stoller committed
915

916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
    #
    # Still need to allocate some virtnodes?
    #
    if ($numvs) {
	#
	# Run avail to get the list of virtnodes on the phys node. We
	# already know there are enough, since assign knows that.
	#
	print "Asking avail for $numvs vnodes on $pnode\n";
    
	open(AVAIL,"$TBROOT/sbin/avail virtonly=$pnode rand limit=$numvs |")
	    or fatal(1, "*** $0:\n".
		        "    avail failed\n");

	while (<AVAIL>) {
	    next
		if (! /^\|/);
	    next
		if (/node_id/);

	    if ($_ =~ /^\|([-a-zA-Z0-9]+)\s*\|(\w+)\s*\|(\w+)\s*\|$/) {
		push(@plist, $1);
	    }
	    else {
		fatal(1, "*** $0:\n".
		      "    Bad line from avail: $_\n");
	    }
Leigh B. Stoller's avatar
Leigh B. Stoller committed
943
	}
944
945
946
947
	close(AVAIL);

	# Sanity check.
	if (scalar(@vlist) != scalar(@plist)) {
Leigh B. Stoller's avatar
Leigh B. Stoller committed
948
	    fatal(1, "*** $0:\n".
949
		     "    Could not map some virtual nodes on $pnode\n");
Leigh B. Stoller's avatar
Leigh B. Stoller committed
950
	}
Leigh B. Stoller's avatar
Leigh B. Stoller committed
951

952
953
954
955
	#
	# Try to allocate. Note, if this fails we are done for. Okay for now
	# since it is never the case that it should fail!
	#
956
957
958
959
960
961
962
963
964
965
	if ($impotent) {
	    print "Selected ($pnode) @plist\n";
	    print "Skipping physical reservation, as directed.\n";
	}
	else {
	    print "Reserving ($pnode) @plist ...\n";
	    if (system("nalloc $pid $eid @plist")) {
		fatal(1, "*** $0:\n".
		         "    Failed to reserve @plist (on $pnode)\n");
	    }
966
	}
Leigh B. Stoller's avatar
Leigh B. Stoller committed
967
968
    }

969
970
971
972
973
974
975
    if ($updating) {
	#
	# Append the lists we created above, so that we get all of them
	# in the loop below.
	#
	@plist = (@plist, @oplist);
	@vlist = (@vlist, @ovlist);
Leigh B. Stoller's avatar
Leigh B. Stoller committed
976
    }
977
    
978
979
980
    while (@plist) {
	my $physical = pop(@plist);
	my $virtual  = pop(@vlist);
Leigh B. Stoller's avatar
Leigh B. Stoller committed
981

982
983
	$v2vmap{$virtual}  = $physical;
	printdb "  Mapping $virtual to $physical on $pnode\n";
Leigh B. Stoller's avatar
Leigh B. Stoller committed
984

985
986
987
988
989
	#
	# New virtual nodes are always clean. Old ones stay in whatever
	# state they were in so that os_setup/vnode_setup know they
	# need to reboot them.
	#
990
991
992
993
994
995
996
997
998
999
	if (!$impotent) {
	    if (!defined($reserved_v2vmap{$virtual})) {
		TBSetNodeAllocState($physical,
				    TBDB_ALLOCSTATE_RES_INIT_CLEAN());
	    }
	    elsif ($reserved_v2vmap{$virtual} ne $physical) {
		# Node has moved! Nuts!
		TBSetNodeAllocState($physical,
				    TBDB_ALLOCSTATE_RES_INIT_DIRTY());
	    }
1000
	}
1001
1002
    }
}
1003

1004
# Set port range (see below for how we deal with update).
Leigh B. Stoller's avatar
Leigh B. Stoller committed
1005
TBExptSetPortRange();
1006

1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
# Load the current physical resources. This avoids lots of repeated
# queries to the DB.
LoadPhysResources();

#
# For update, wipe old interfaces in DB (normally done by nfree.)
# These will get rebuilt soon. 
#
if ($updating && !$impotent) {
    foreach my $pnode (keys(%phys_nodes)) {
	#
	# Do not need to do this for phys nodes that are to be
	# released, or for virtnodes since they do not have interfaces
	# associated with them directly. This is probably a bad assumption
	# though, and perhaps this entire function should be moved to the
	# library. 
	#
	next
	    if (physnodeisvirtnode($pnode) ||
		physnodereuse($pnode) eq "unused");

1028
	DBQueryFatal("update interfaces set IP='',IPaliases=NULL,mask=NULL " .
1029
1030
		     "where node_id='$pnode' and ".
		     "  role='" . TBDB_IFACEROLE_EXPERIMENT() . "'");
1031
1032
1033
1034
1035
1036

	# Clean the veth_interfaces table for this node too.
	DBQueryFatal("delete from veth_interfaces where node_id='$pnode'");
    }
}

Leigh B. Stoller's avatar
Leigh B. Stoller committed
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
######################################################################
# Step 3 - Convert to vlans, delays, and portmap
# 
# Here we convert the plinks into vlans, delays, and portmap.  We
# convert them first into internal datastructure.  After Step 4
# when we do some port swapping we'll upload the modified versions
# of these structures into the database.
#
# delays is indexed by an internal ID and contains:
#  [pnode, int0, int1, vname, delay, bandwidth, lossrate]
# portmap is indexed by <virtual node>:<virtual port> and contains
#  the physical port.
#
# vlan ids
#  vlan ids are increasing integers in the case of node<->delay connections.
#  In the case of actual LANs either of real node or of delay nodes
#  they are indexed by virtual lan name.
# delay ids
#  delay ids are increasing integers.  We could have used a list of
# delays just as well.  Having it as an array may prove useful for
# future changes however.
######################################################################

$delayid = 0;

printdb "Interpreting results.\n";
1063
TBDebugTimeStamp("interpreting started");
Leigh B. Stoller's avatar
Leigh B. Stoller committed
1064
foreach $plink (keys(%plinks)) {
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
    # trivial links do not have physical links, so no delay nodes. But,
    # we *do* use trivial links for intranode links, and thus there could
    # be link delays (ie: two jailed nodes on a link/lan assigned to the
    # same phys node).
    my $trivial = 0;

    if (scalar(@{$plinks{$plink}})) {
	($nodeportA,$nodeportB) = @{$plinks{$plink}};
	($nodeA,$portA) = split(":", $nodeportA);
	($nodeB,$portB) = split(":", $nodeportB);
	printdb "plink $plink - $nodeportA $nodeportB\n";
    }
    else {
	$trivial = 1;
	printdb "plink $plink - trivial\n";
Shashi Guruprasad's avatar
Shashi Guruprasad committed
1080
    }
1081

1082
    if (($lan,$virtA,$virtC) =
1083
	   ($plink =~ m|^linksdelaysrc/(.+)/(.+),(.+)$|)) {
1084
1085
1086
1087
	# trivial links do not have physical links, so no delay nodes.
	if ($trivial) {
	    next;
	}
Leigh B. Stoller's avatar
Leigh B. Stoller committed
1088
1089
1090
	# Node has a single entry in lan.
	# Node is nodeportA
	# Delay node is nodeportB
1091
	# Other end of delay node will be given by corresponding plink
1092
1093
	#   linksdelaydst/lan/virtC,virtA where nodeportA will be the other 
	#   node in the virtual LAN and nodeportB will be the other end of the
Leigh B. Stoller's avatar
Leigh B. Stoller committed
1094
	#   delay node.
1095
1096
	($nodeportC,$nodeportD) =
	    @{$plinks{"linksdelaydst/$lan/$virtC,$virtA"}};
Leigh B. Stoller's avatar
Leigh B. Stoller committed
1097
1098
1099
1100
1101
1102
1103
	($nodeC,$portC) = split(":",$nodeportC);
	($nodeD,$portD) = split(":",$nodeportD);
	printdb "LINK delay: other end = $nodeportC $nodeportD\n";

	# assert nodeB == nodeD

	printdb "  VLANS:\n";
1104
1105
	AddVlan("link", "$lan" . "-delaysrc", $nodeportA, $nodeportB);
	AddVlan("link", "$lan" . "-delaydst", $nodeportC, $nodeportD);
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
	
	my ($member0,$delay,$bandwidth,$lossrate,
	    $member1,$rdelay,$rbandwidth,$rlossrate) = @{$delaylinks{$plink}};
	
	$nodedelays{$delayid++} = [$nodeB,$portB,$portD,$lan,
			       $member0,$delay,$bandwidth,$lossrate,
			       $member1,$rdelay,$rbandwidth,$rlossrate];
	printdb "  Delay: \[$nodeB,$portB,$portD,$lan," .
	    "$delay,$bandwidth,$lossrate,$rdelay,$rbandwidth," .
	    "$rlossrate,$nodeportA,$nodeportC\]\n";

	#
	# Setup portmap using virt members in plink name.
	#
	$portmap{$virtA} = $portA;
	$portmap{$virtC} = $portC;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
1122
	printdb "  Portmap:\n";
1123
1124
1125
1126
	printdb "    $virtA = $portA\n";
	printdb "    $virtC = $portC\n";
    }
    elsif (($lan,$virtA) = ($plink =~ m|^linkdelaysrc/([^/]+)/(.+)$|)) {
1127
1128
1129
1130
	# trivial links do not have physical links, so no delay nodes.
	if ($trivial) {
	    next;
	}
Leigh B. Stoller's avatar
Leigh B. Stoller committed
1131
1132
	# Node may have multiple entries in lan.
	# Delay node is nodeB and portB.
1133
	# Other end of delay node will be given by corresponding plink
Leigh B. Stoller's avatar
Leigh B. Stoller committed
1134
1135
	#  linkdelaydst/lan/node where nodeportA will the LAN node and
	#  nodeportB will be the other end of the delay node.
1136
1137
	
	($nodeportC,$nodeportD) = @{$plinks{"linkdelaydst/$lan/$virtA"}};
Leigh B. Stoller's avatar
Leigh B. Stoller committed
1138
1139
1140
	($nodeC,$portC) = split(":",$nodeportC);
	($nodeD,$portD) = split(":",$nodeportD);
	printdb "LAN delay src: other end = $nodeportC $nodeportD\n";
1141

Leigh B. Stoller's avatar
Leigh B. Stoller committed
1142
	printdb "  VLANS:\n";
1143
	AddVlan("link", $lan . "-delay" . $nodeA, $nodeportA, $nodeportB);
1144
	AddVlan("lan",  $lan, $nodeportD);
Leigh B. Stoller's avatar
Leigh B. Stoller committed
1145
	
1146
1147
1148
1149
1150
1151
1152
	my ($member0,$delay,$bandwidth,$loss,
	    $member1,$rdelay,$rbandwidth,$rloss) = @{$delaylinks{$plink}};
	
	$nodedelays{$delayid++} = [$nodeB,$portB,$portD,$lan,
				   $member0,$delay,$bandwidth,$loss,
				   $member1,$rdelay,$rbandwidth,$rloss];
	printdb "  Delays: \[$nodeB,$portB,$portD,$lan," .
Christopher Alfeld's avatar
Christopher Alfeld committed
1153
	    "$delay,$bandwidth,$loss,$rdelay,$rbandwidth,$rloss," .
1154
	    "$nodeportA,$nodeportC\]\n";
Shashi Guruprasad's avatar
Shashi Guruprasad committed
1155

1156
	$portmap{$virtA} = $portA;
Shashi Guruprasad's avatar
Shashi Guruprasad committed
1157
	printdb "  Portmap:\n";
1158
1159
1160
1161
1162
1163
1164
1165
	printdb "    $virtA = $portA\n";
    }
    elsif (($lan,$virtA,$virtB) = ($plink =~ m|^linksimple/(.+)/(.+),(.+)$|)) {
	#
	# nodeportA and nodeportB are the only two nodes in the LAN.
	# If the link is delayed, its with endpoint delays, not a delay node.
	#
	printdb "  Link:";
1166
1167
1168
1169
1170
1171
1172
1173

	#
	# trivial links do not have physical links, but could be using
	# virtual interfaces on the same node. 
	#
	if (! $trivial) {
	    AddVlan("link", $lan, $nodeportA, $nodeportB);

1174
	    if (virtlanuseveth($lan)) {
1175
1176
1177
		#
		# Create some new veth devices.
		# 
1178
1179
		$portA = NewVethIface($lan, $virtA, $nodeA, $portA);
		$portB = NewVethIface($lan, $virtB, $nodeB, $portB);
1180
1181
1182
1183
1184
1185
1186
	    }
	}
	else {
	    # No phys mapping. We create a veth, but there is no phys mapping
	    # for the port.
	    $nodeA = $v2pmap{(split(":", $virtA))[0]};
	    $nodeB = $v2pmap{(split(":", $virtB))[0]};
1187
1188
	    $portA = NewVethIface($lan, $virtA, $nodeA);
	    $portB = NewVethIface($lan, $virtB, $nodeB);
1189
1190
1191
1192
1193
1194
1195
1196
1197
	}
	#
	# Setup portmap using virt members in plink name.
	#
	$portmap{$virtA} = $portA;
	$portmap{$virtB} = $portB;
	printdb "  Portmap:\n";
	printdb "    $virtA = $portA\n";
	printdb "    $virtB = $portB\n";
Leigh B. Stoller's avatar
Leigh B. Stoller committed
1198
	
1199
1200
1201
1202
	if ($delaylinks{$plink}) {
	    my ($member0,$delay,$bandwidth,$loss,
		$member1,$rdelay,$rbandwidth,$rloss) =
		    @{$delaylinks{$plink}};
Shashi Guruprasad's avatar
Shashi Guruprasad committed
1203

1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
	    #
	    # Two entries, one for each side of the duplex link.
	    #
	    $linkdelays{$delayid++} = [$nodeA,$portA,$lan,$member0,
				       $delay,$bandwidth,$loss,
				       undef,undef,undef,0];
	    
	    $linkdelays{$delayid++} = [$nodeB,$portB,$lan,$member1,
				       $rdelay,$rbandwidth,$rloss,
				       undef,undef,undef,0];
	    
	    printdb "  LinkDelay: \[$nodeA,$portA,$nodeB,$portB," .
		"$lan,$delay,$bandwidth,$loss,$rdelay,$rbandwidth,$rloss\]\n";
Shashi Guruprasad's avatar
Shashi Guruprasad committed
1217
	}
1218
1219
    }
    elsif (($lan,$virtA) = ($plink =~ m|^linklan/([^/]+)/(.+)$|)) {
Leigh B. Stoller's avatar
Leigh B. Stoller committed
1220
1221
1222
1223
	# node may be the LAN multiple times.
	# nodeportA is the node.
	# nodeportB is the LAN
	# No delays
1224
	printdb "  LAN:";
1225
1226
1227
1228
1229
1230
1231
1232

	#
	# trivial links do not have physical links, but could be using
	# virtual interfaces on the same node. 
	#
	if (! $trivial) {
	    AddVlan("lan", $lan, $nodeportA);

1233
	    if (virtlanuseveth($lan)) {
1234
		#
1235
		# Create new veth device.
1236
		# 
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
		$portA = NewVethIface($lan, $virtA, $nodeA, $portA);

		#
		# If the "lannode" is placed on a node, and that node is
		# different than the current node, we have to connect the
		# two in the vlan. Typically, the lannode is placed on a
		# switch, and this is not an issue. Rob understands this!
		#
		if ($nodeportA ne $nodeportB) {
		    AddVlan("lan", $lan, $nodeportB);
		    AddVethPatch($lan, $nodeportB);
		}
1249
1250
1251
1252
1253
	    }
	}
	else {
	    # No phys mapping. We create a veth, but there is no phys port.
	    $nodeA = $v2pmap{(split(":", $virtA))[0]};
1254
	    $portA = NewVethIface($lan, $virtA, $nodeA);
1255
1256
1257
1258
	}
	$portmap{$virtA} = $portA;
	printdb "  Portmap:\n";
	printdb "    $virtA = $portA\n";
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
	
	if ($delaylinks{$plink}) {
	    my ($member0,$delay,$bandwidth,$loss,
		$member1,$rdelay,$rbandwidth,$rloss) =
		    @{$delaylinks{$plink}};

	    #
	    # One entry, comprising each side of the link to lan.
	    #
	    $linkdelays{$delayid++} = [$nodeA,$portA,$lan,$member0,
				       $delay,$bandwidth,$loss,
				       $rdelay,$rbandwidth,$rloss,1];
	    
	    printdb "  LinkDelay: \[$nodeA,$portA," .
		"$lan,$delay,$bandwidth,$loss,$rdelay,$rbandwidth,$rloss\]\n";
Leigh B. Stoller's avatar
Leigh B. Stoller committed
1274
	}
1275
1276
1277
1278
1279
1280
1281
    }
    elsif ($plink =~ m|^linkdelaydst/([^/]+)/(.+)$| ||
	   $plink =~ m|^linksdelaydst/(.+)/(.+),(.+)$|) {
	next;
    }
    else {
	warn("Bad plink: $plink\n");
Leigh B. Stoller's avatar
Leigh B. Stoller committed
1282
1283
    }
}
1284
TBDebugTimeStamp("interpreting finished");
Leigh B. Stoller's avatar
Leigh B. Stoller committed
1285

1286
1287
1288
1289
# Stop here ...
exit(0)
    if ($impotent);

Leigh B. Stoller's avatar
Leigh B. Stoller committed