ptopgen.in 11.5 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 4

#
# EMULAB-COPYRIGHT
5
# Copyright (c) 2000-2003 University of Utah and the Flux Group.
Leigh B. Stoller's avatar
Leigh B. Stoller committed
6 7 8
# All rights reserved.
#

9 10
use English;
use Getopt::Std;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
11

12 13
sub usage()
{
14 15 16 17 18 19
    print("Usage: ptopgen [-v] [-s switch] [-p pid [-e eid]] [-m factor]\n" .
	  "       -p include nodes the project has permission to use\n".
	  "       -e include given experiment's resources\n" .
	  "          in the ptopfile (as if they were free)\n" .
	  "       -v Include stuff for topologies with virtual nodes\n".
	  "       -m Override multiplex_factor\n");
20 21
    exit(-1);
}
22
my $optlist = "s:e:m:vp:";
23
my $mfactor;
24
my $virtstuff = 0;
25

26 27 28 29
#
# Turn off line buffering on output
#
$| = 1;
30 31 32 33 34 35 36 37 38 39 40 41

# Settings - Change these to your particular network.

#
# Also bogus. The interfaces table does not hold entries for the switch
# side of each link. It will have to at some point, when we have something
# other than 100Mbs ports (say, gbit ports).
#
# Speed in in Kbs!
#
my $default_switchport_speed    = 100000;

42 43
######################################################################

44
my $TBROOT = "@prefix@";
45
use lib '@prefix@/lib';
46
require exitonwarn;
47
use libdb;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
48

49 50
my $TRACK_INTERSWITCH_BANDWIDTH = "@TRACK_INTERSWITCH_BANDWIDTH@";

51 52 53
my %switches	  = ();
my %used_switches = ();
my %permissions   = ();
54

55 56 57
my $DEADPID = NODEDEAD_PID();
my $DEADEID = NODEDEAD_EID();

58
my $pid;
59
my $exempt_eid;
60
my $switchtouse;
61

62 63 64 65 66 67 68 69 70 71 72 73 74 75
#
# Parse command arguments. Once we return from getopts, all that should be
# left are the required arguments.
#
%options = ();
if (! getopts($optlist, \%options)) {
    usage();
}
if (@ARGV) {
    usage();
}
if (defined($options{"s"})) {
    $switchtouse = $options{"s"};
}
76 77 78
if (defined($options{"m"})) {
    $mfactor = $options{"m"};
}
79 80 81
if (defined($options{"v"})) {
    $virtstuff = 1;
}
82 83 84
if (defined($options{"p"})) {
    $pid = $options{"p"};
}
85
if (defined($options{"e"})) {
86 87 88
    $exempt_eid = $options{"e"};
    usage()
	if (!defined($pid));
89 90
}

91
# Read class/type maps
92 93 94 95
my $result =
    DBQueryFatal("select class,type,delay_capacity,virtnode_capacity ".
		 "from node_types");
while (($class,$type,$delaycapacity,$vcap) = $result->fetchrow_array) {
96
    $classes{$type} = $class;
97
    $nodetypes{$type} = $delaycapacity;
98
    $virtcapacity{$type} = $vcap;
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136

    # Default is permission to use all types,classes. 
    $permissions{$class} = 1;
    $permissions{$type}  = 1;
}

#
# Read the features table for each type.
# 
$result = DBQueryFatal("select type, feature, weight from node_type_features");
while (my ($type, $feature, $weight) = $result->fetchrow()) {
    if (! defined($features{$type})) {
	$features{$type} = "$feature:$weight";
	next;
    }
    $features{$type} .= " $feature:$weight";
}

#
# Read the permission table if given a pid. If there is an entry in
# the table for a type/class, then permission is granted only if there
# is a record with the pid. If not, remove the permission granted above.
# 
if (defined($pid)) {
    $result =
	DBQueryFatal("select type from nodetypeXpid_permissions");
    
    while (my ($type) = $result->fetchrow_array) {
	$permissions{$type} = 0;
    }
    
    $result =
	DBQueryFatal("select type from nodetypeXpid_permissions ".
		     "where pid='$pid'");
    
    while (my ($type) = $result->fetchrow_array) {
	$permissions{$type} = 1;
    }
137 138 139 140 141
}

# switches can't delay
$nodetypes{"switch"} = 0;

142
# Print switches
143
if (defined($switchtouse)) {
144
    print "node $switchtouse switch:1 *lan:*\n";
145 146 147 148 149 150 151
    $switches{$switchtouse} = 1;
}
else {
    $result =
	DBQueryFatal("select node_id from nodes where role = \"testswitch\"");

    while (($switch) = $result->fetchrow_array) {
152
	print "node $switch switch:1 *lan:*\n";
153 154
	$switches{$switch} = 1;
    }
155
}
156

Leigh B. Stoller's avatar
Leigh B. Stoller committed
157
# Find available nodes
158 159 160 161 162 163
#
# VIRTNODES HACK: If the node is a virtual node, then in addition to
# to being free, the underlying physnode has to either be free, or
# not in the hwdown group. Either way, the the underlying physnode has
# to be "up", as determined by the autostatus stuff; this will prevent us
# from allocating a dead virtual node to an experiment. 
164 165
# This is especially hacky. We need another mechanism for this. We only
# add virtnodes when assign says we need them. This reduces the problem
166 167
# size for assign! Also note that local virtnodes never go into the
# ptop file. 
168
#
169 170 171 172
my $virtnode_condition = "";

if ($virtstuff) {
    $virtnode_condition = " or ".
173 174
	"       (a.role='virtnode' and t.isremotenode=1 and ".
	"        ns.status='up' and ".
175 176 177
	"        (m.node_id is null or ".
	"         m.pid!='$DEADPID' or m.eid!='$DEADEID')) ";
}
178 179 180 181 182 183 184 185

# the ordinary free condition for a node
my $free_condition = "(b.node_id is null)";

# if the user has specified an exempt pid/eid, 
# then view any node which is reserved to that experiment as available.
if (defined($exempt_eid)) {
    $free_condition = "($free_condition or ".
186
	"(b.pid='$pid' and b.eid='$exempt_eid'))"; 
187
}
Chad Barb's avatar
Chad Barb committed
188

189
$result =
190
    DBQueryFatal("select a.node_id,a.type,t.class from nodes as a ".
191 192
		 "left join reserved as b on a.node_id=b.node_id ".
		 "left join reserved as m on a.phys_nodeid=m.node_id ".
193 194
		 "left join node_status as ns on a.phys_nodeid=ns.node_id ".
		 "left join node_types as t on t.type=a.type ".
195 196
		 "where $free_condition and ".
		 "      (a.role='testnode' $virtnode_condition)");
Leigh B. Stoller's avatar
Leigh B. Stoller committed
197

198 199 200 201 202 203 204 205 206 207
#
# Scan the results, checking permissions and adding to the list
# You get to use a node type if no pid was specified (that is, you get
# to use all nodes), or if there is no entry as all in 

while (($node,$type,$class) = $result->fetchrow_array) {
    $nodes{$node} = $type
	if (!defined($pid) ||
	    ($permissions{$type} && $permissions{$class}));
}
Leigh B. Stoller's avatar
Leigh B. Stoller committed
208

209
$sharklinks = "";
Shashi Guruprasad's avatar
Shashi Guruprasad committed
210 211 212 213

# XXX NSE hack


Leigh B. Stoller's avatar
Leigh B. Stoller committed
214
foreach $node (keys(%nodes)) {
215 216 217 218 219 220 221 222
    my $type = $nodes{$node};
    
    $text = "node $node $type:1 $classes{$type}:1";
    $delay_capacity = $nodetypes{$type};
    $virtnode_capacity = $virtcapacity{$type};
    
    if ($delay_capacity > 0) {
	$text .= " delay:$delay_capacity";
223
	    
224 225 226 227 228 229 230 231 232 233
	#################################################################
	### NSE Node hack. Instead of adding sim nodes into the
	### database schema, I'm just adding it here for now
	### untill we can figure out how to add sim nodes into the
	### nodes table.  One assumption is that if we the node
	### type can support delay nodes, then it is a local node
	### and therefore we can support sim nodes
	#################################################################
	$text .= " sim:100000";
    }
234

235 236 237 238 239 240 241 242 243 244 245 246 247 248
    if ($virtstuff && $virtnode_capacity > 0) {
	#
	# Ditto for jailed nodes
	#
	if (defined($mfactor)) {
	    $text .= " pcvm:$mfactor";
	}
	else {
	    $text .= " pcvm:$virtnode_capacity";
	}
	$text .= " *lan:*";
	# Add features
	if (defined($features{$type})) {
	    $text .= " - $features{$type}";
249
	} else {
250 251 252 253 254 255 256 257 258
	    $text .= " -";
	}
	# Add trivial bw spec.
	$text .= " - trivial_bw:400000";
    } else {
	if (defined($features{$type})) {
	    $text .= " - $features{$type}";
	} else {
	    $text .= " -";
Leigh B. Stoller's avatar
Leigh B. Stoller committed
259 260
	}
    }
261
    print "$text\n";
Leigh B. Stoller's avatar
Leigh B. Stoller committed
262 263
}

264
# Read interfaces
265
$result = DBQueryFatal("SELECT node_id,card,port,iface,interface_type" .
266
		     " from interfaces");
267
while (($node,$card,$port,$iface,$type) = $result->fetchrow_array) {
268
    $interfacemap{"$node:$card:$port"} = $iface;
Chad Barb's avatar
 
Chad Barb committed
269
    if ((defined $type) && ($type ne "")) {
270 271 272 273 274
	$interfacetypes{"$node:$card:$port"} = $type;
    }
}

# Read interface types
275 276
$result = DBQueryFatal("SELECT type,max_speed from interface_types");
while (($type,$speed) = $result->fetchrow_array) {
277 278 279
    $interfacespeeds{$type} = $speed;
}

280 281 282 283 284 285 286 287 288 289 290 291 292 293 294
# Read interface switches
$result = DBQueryFatal("SELECT node_id1, iface, node_id2 FROM wires AS w " .
	"LEFT JOIN interfaces as i ON w.node_id1=i.node_id AND w.card1=i.card");
while (($node,$iface,$switch) = $result->fetchrow_array) {
    if ($node && $iface) {
	$interfaceswitches{"$node:$iface"} = $switch;
    }
}

# Read interface cards and ports
$result = DBQueryFatal("SELECT node_id, iface, card, port FROM interfaces");
while (($node,$iface,$card,$port) = $result->fetchrow_array) {
    $interfacecardports{"$node:$iface"} = [$card,$port];
}

295
$result = DBQueryFatal("SELECT node_id1,card1,port1,node_id2,card2,port2" .
296
 		    " from wires where type=\"Node\" or type=\"Trunk\"");
297
while (($node1,$card1,$port1,$node2,$card2,$port2) = 
298
       $result->fetchrow_array) {
299
    if ((defined($nodes{$node1}) || defined($switches{$node1})) && 
300
	(defined($nodes{$node2}) || defined($switches{$node2}))) {
301 302 303 304 305 306 307 308 309
	$iface1 = get_iface($node1,$card1,$port1);
	$iface2 = get_iface($node2,$card2,$port2);
	$iface1bw = get_ifacebw($node1,$card1,$port1);
	$iface2bw = get_ifacebw($node2,$card2,$port2);
	if ($iface1bw < $iface2bw) {
	    $bw = $iface1bw;
	} else {
	    $bw = $iface2bw;
	}
310
	if (defined($switches{$node2})) {
311 312
	    $used_switches{$node2} = 1;
	}
313 314 315 316 317 318 319 320 321 322 323 324 325 326
	if (defined($switches{$node1})) {
	    $used_switches{$node1} = 1;
	}
	if (defined($switches{$node1}) && defined($switches{$node2})) {
	    # interswitch link
	    if (defined($interconnects{"$node1:$node2"})) {
		$interconnects{"$node1:$node2"} += $bw;
	    } else {
		$interconnects{"$node1:$node2"} = $bw;
	    }
	} else {
	    # !!! - Here we use our knowledge that in the wires table links
	    # to the switch always come as node2.
	    print "link link-$node1:$iface1-$node2:$iface2 $node1:$node1/$iface1" .
327
		" $node2:$iface2 $bw 0 0 1\n";
328 329
	}
    } 
330
}
331 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 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380

#
# If we're supposed to track interswitch bandwidth, subtract out the amount
# that's already in use
#
if ($TRACK_INTERSWITCH_BANDWIDTH) {
    #
    # Get a list of all VLANs
    #
    my $result = DBQueryFatal("SELECT virtual, members FROM vlans");
    while (my ($virtual, $members) = $result->fetchrow()) {
	#
	# Split apart the space-separated list of members
	#
	my @members = split /\s+/, $members;
	my %switches = ();
	foreach my $member (@members) {
	    my ($node,$iface) = split /:/, $member;
	    my $switch = get_ifaceswitch($node,$iface);
	    my ($card, $port) = get_ifacecardport($node,$iface);
	    my $bw = get_ifacebw($node,$card,$port);
	    $switches{$switch} += $bw;
	}

	#
	# Check to see if more than one switch was found among the member
	# list, and if so, go through all the pairs
	#
	my @switches = keys %switches;
	if (@switches > 1) {
	    for (my $i = 0; $i < (@switches -1); $i++) {
		my $switch1 = $switches[$i];
		my $switch2 = $switches[$i+1];
		my $bw = $switches{$switch1};
		if ($switches{$switch2} < $bw) {
			$bw = $switches{$switch2};
		}
		#
		# The trunk link could be listed in either order
		#
		if ($interconnects{"$switch1:$switch2"}) {
		    $interconnects{"$switch1:$switch2"} -= $bw;
		} elsif ($interconnects{"$switch2:$switch1"}) {
		    $interconnects{"$switch2:$switch1"} -= $bw;
		}
	    }
	}
    }
}

381 382
foreach $interconnect (keys(%interconnects)) {
    ($src,$dst) = split(":",$interconnect);
383
    print "link link-$interconnect $src $dst $interconnects{$interconnect} 0 0 1\n";
384
}
385 386 387

print $sharklinks;

388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408
# Print out links
sub get_iface {
    ($node,$card,$port) = @_;
    if (defined($interfacemap{"$node:$card:$port"})) {
	return $interfacemap{"$node:$card:$port"};
    } else {
	# shark hack
	if ($node =~ /^sh/) {
	    return "eth0";
	} else {
	    return "(null)";
	}
	# end shark hack 
    }
};

# Find the bandwidth for an interface
sub get_ifacebw {
    ($node,$card,$port) = @_;
    if (defined($interfacetypes{"$node:$card:$port"})) {
	return $interfacespeeds{$interfacetypes{"$node:$card:$port"}};
409 410 411
    }
    else {
	return $default_switchport_speed;
412 413
    }
}
414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431

sub get_ifaceswitch {
    ($node,$iface) = @_;
    if (defined($interfaceswitches{"$node:$iface"})) {
	return $interfaceswitches{"$node:$iface"};
    } else {
	return undef;
    }
}

sub get_ifacecardport {
    ($node,$iface) = @_;
    if (defined($interfacecardports{"$node:$iface"})) {
	return @{$interfacecardports{"$node:$iface"}};
    } else {
	return ();
    }
}