Commit 1ad5c4a6 authored by Jonathon Duerig's avatar Jonathon Duerig
Browse files

Merge branch 'master' of git-public.flux.utah.edu:/flux/git/emulab-devel

parents 1351043d 2136aec5
......@@ -3198,5 +3198,76 @@ sub SetRole($$)
return $self->GetLan()->SetRole($role);
}
############################################################################
#
# Another convenience package, for external references.
#
package ExternalNetwork;
use libdb;
use libtestbed;
use English;
use Lan;
use overload ('""' => 'Stringify');
#
# Lookup by either the node or the network name.
#
sub Lookup($$)
{
my ($class, $arg) = @_;
# Always sanity check before hitting the DB.
return undef
if (! ($arg =~ /^[-\w]*$/));
my $query_result =
DBQueryWarn("select * from external_networks ".
"where node_id='$arg' or network_id='$arg'");
return undef
if (!$query_result || !$query_result->numrows);
# This would be unusual;
if ($query_result->numrows > 1) {
print STDERR "*** Multiple rows in external_networks for $arg\n";
return undef;
}
my $self = {};
$self->{'DBROW'} = $query_result->fetchrow_hashref();
bless($self, $class);
return $self;
}
# accessors
sub field($$) { return ((! ref($_[0])) ? -1 : $_[0]->{'DBROW'}->{$_[1]}); }
sub node_id($) { return field($_[0], 'node_id'); }
sub node_type($) { return field($_[0], 'node_type'); }
sub network_id($) { return field($_[0], 'network_id'); }
sub min_vlan($) { return field($_[0], 'min_vlan'); }
sub max_vlan($) { return field($_[0], 'max_vlan'); }
#
# Stringify for output.
#
sub Stringify($)
{
my ($self) = @_;
my $node_id = $self->node_id();
my $network_id = $self->network_id();
return "[External Network: $network_id,$node_id]";
}
#
# Given a vlan tag, is it okay (in the range).
#
sub VlanTagOkay($$)
{
my ($self, $tag) = @_;
return ($tag >= $self->min_vlan() && $tag < $self->max_vlan() ? 1 : 0);
}
# _Always_ make sure that this 1 is at the end of the file...
1;
......@@ -1693,7 +1693,8 @@ PlayFrisbee(void)
p->msg.join2.chunksize = MAXCHUNKSIZE;
p->msg.join2.blocksize = MAXBLOCKSIZE;
p->msg.join2.bytecount =
p->msg.join.blockcount * MAXBLOCKSIZE;
(uint64_t)p->msg.join.blockcount *
MAXBLOCKSIZE;
}
CLEVENT(1, EV_CLIJOINREP,
CHUNKSIZE, BLOCKSIZE,
......
......@@ -290,7 +290,7 @@ typedef struct {
int32_t blockcount;
int32_t chunksize;
int32_t blocksize;
int64_t bytecount;
uint64_t bytecount;
} join2;
/*
......
......@@ -1053,6 +1053,7 @@ sub GetTicketAuxAux($$$$$$$$$)
"n:interface_ref",
$linkref)->get_nodelist();
my %managers = ();
my %hops = ();
my $ifacenum = 1;
my $vindex = 0;
my $trivial_ok = 1;
......@@ -1065,7 +1066,7 @@ sub GetTicketAuxAux($$$$$$$$$)
#
# Look for managers list; optional for now. If not specified then
# we assume the link is for thie CM.
# we assume the link is for this CM.
#
if (GeniXML::FindNodes("n:component_manager", $linkref)) {
%managers = map { GetLinkManager($_) => $_ }
......@@ -1080,6 +1081,16 @@ sub GetTicketAuxAux($$$$$$$$$)
if (!exists($managers{$ENV{'MYURN'}}));
}
#
# Look for hops list; optional.
#
if (GeniXML::FindNodes("n:component_hop", $linkref)) {
%hops = map { GeniXML::GetNodeId($_) => $_ }
GeniXML::FindNodes("n:component_hop",
$linkref)->get_nodelist();
}
#
# Ick. Before we create the virt_lan_lans entry, we have to check
# inside to see if one of the interfaces is connected to a lan
......@@ -1150,34 +1161,85 @@ sub GetTicketAuxAux($$$$$$$$$)
if (!exists($namemap{$node_nickname}) &&
exists($external_nodemap{$node_nickname})) {
#
# I have completely punted on how we represent external
# links in the DB so that we know what to put into the
# virtual topology. For now, just hardwire the one test
# case.
# Find the hop that says how we get to the edge. For
# now I assume a single hop is all we ever have.
#
my $noderef = $external_nodemap{$node_nickname};
my $other_cm = GeniXML::GetManagerId($noderef);
if (! ($other_cm eq "urn:publicid:IDN+" .
"myelab.testbed.emulab.net+authority+cm" ||
$other_cm eq "urn:publicid:IDN+" .
"emulab.net+authority+cm")) {
my $hopref;
my $hop_urn;
foreach my $urn (keys(%hops)) {
my ($auth,undef,undef) = GeniHRN::Parse($urn);
if (defined($auth) and $auth eq $OURDOMAIN) {
$hopref = $hops{$urn};
$hop_urn= $urn;
last;
}
}
if (!defined($hopref)) {
$response =
GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"$lanname: links to external node");
"$lanname: no local component_hop");
goto bad;
}
my (undef,undef,$hop_id) = GeniHRN::Parse($hop_urn);
print "$hop_id\n";
#
# An artifact of the way we convert physical links
# into urns is that we now have to undo that to
# figure out what node and interface. At the moment
# it looks like "link-ion:eth2-procurve-pgeni-wash:(null)"
#
my ($link,$iface,undef) = split(":", $hop_id);
if (! (defined($link) && defined($iface))) {
$response =
GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"$lanname: bad component_hop");
goto bad;
}
# and strip off the link- stuff.
my ($network_id) = ($link =~ /^link-(.*)$/);
# ditto for the iface cruft.
my ($iface_id) = ($iface =~ /^(eth\d*)/);
if (! ($network_id =~ /^[-\w]*$/ &&
$iface_id =~ /^[-\w]*$/)) {
$response =
GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"$lanname: bad network or iface");
goto bad;
}
#
# Look in the external networks table to get the hop
# details.
#
my $network = ExternalNetwork->Lookup($network_id);
if (!defined($network)) {
$response =
GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"$lanname: unknown component_hop");
goto bad;
}
my $network_node = Node->Lookup($network->node_id());
if (!defined($network_node)) {
$response =
GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"$lanname: unknown component_hop node");
goto bad;
}
#
# Stick in a reference to the fake bbg node that
# corresponds to where the link comes in.
# Stick in a reference to the fake node.
#
my $virtnode =
$virtexperiment->NewTableRow("virt_nodes",
{"vname" => $node_nickname,
"type" => "bbgenivm",
"osname" => 'BBGENIVM-FAKE',
"ips" => '', # deprecated
"cmd_line"=> '', # bogus
"fixed" => "bbg1"});
{"vname" => $node_nickname,
"type" => $network->node_type(),
"osname" => '',
"ips" => '', # deprecated
"cmd_line"=> '', # bogus
"fixed" => $network_node->node_id()});
if (!defined($virtnode)) {
print STDERR "Error creating bbg node\n";
$response = GeniResponse->Create(GENIRESPONSE_ERROR);
......@@ -1188,9 +1250,8 @@ sub GetTicketAuxAux($$$$$$$$$)
{"vname" => $node_nickname,
"desire" => "pcshared",
"weight" => 0.95});
$virtexperiment->multiplex_factor(1);
$virtexperiment->encap_style("vlan");
$iface_name = "";
$iface_name = $iface_id;
$iface_vport = 0;
goto stitch;
}
......
......@@ -314,6 +314,8 @@ sub CreateSliver($)
my $impotent = $argref->{'impotent'} || 0;
require Node;
require Experiment;
require libtestbed;
require libaudit;
# For now, I am not worrying about the slice_urn argument.
if (! (defined($credentials) &&
......@@ -426,26 +428,31 @@ sub CreateSliver($)
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"Internal Error");
}
#
# At this point we want to return and let the startsliver proceed
# in the background
#
my $mypid = fork();
if ($mypid) {
# Let the child get going.
sleep(1);
return GeniResponse->Create(GENIRESPONSE_SUCCESS,
[$sliver_credential, $sliver_manifest]);
}
# This switches the file that we are writing to.
libaudit::AuditFork();
# Make sure that the next phase sees all changes.
Experiment->FlushAll();
Node->FlushAll();
if ($aggregate->Start($API_VERSION, 0) != 0) {
$slice->UnLock();
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"Could not start sliver");
print STDERR "Could not start sliver\n";
return -1;
}
# GeniCM::UpdateManifest($slice);
$sliver_manifest = $aggregate->GetManifest(1);
if (!defined($sliver_manifest)) {
print STDERR "CreateSliver: Could not get manifest for $aggregate\n";
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"Internal Error");
}
$slice->UnLock();
return GeniResponse->Create(GENIRESPONSE_SUCCESS,
[$sliver_credential, $sliver_manifest]);
return 0;
}
#
......@@ -1547,6 +1554,7 @@ sub ReserveVlanTags($)
my $taglist = $argref->{'taglist'};
my $response;
my $actualtag;
my ($myauth,undef,undef) = GeniHRN::Parse($ENV{'MYURN'});
# List of vlans to delete after getting the tags.
my @delete = ();
my %linkmap = ();
......@@ -1682,6 +1690,52 @@ sub ReserveVlanTags($)
"Could not find link in rspec");
goto done;
}
#
# Go through the component hops and find the one that refers to us.
# This is our external network point.
#
my $hopref;
foreach my $ref (GeniXML::FindNodes("n:component_hop",
$linkref)->get_nodelist()) {
my $component_urn = GeniXML::GetNodeId($ref);
my ($auth,undef,undef) = GeniHRN::Parse($component_urn);
if (defined($auth) and $auth eq $myauth) {
$hopref = $ref;
last;
}
}
if (!defined($hopref)) {
$response = GeniResponse->Create(GENIRESPONSE_BADARGS, undef,
"Could not find hop in link");
goto done;
}
my $hop_urn = GeniXML::GetNodeId($hopref);
my (undef,undef,$hop_id) = GeniHRN::Parse($hop_urn);
#
# An artifact of the way we convert physical links
# into urns is that we now have to undo that to
# figure out what node and interface. At the moment
# it looks like "link-ion:eth2-procurve-pgeni-wash:(null)"
#
my ($link,$iface,undef) = split(":", $hop_id);
if (! (defined($link) && defined($iface))) {
$response =
GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"badly specified component_hop");
goto done;
}
# and strip off the link- stuff.
my ($network_id) = ($link =~ /^link-(.*)$/);
my $network = ExternalNetwork->Lookup($network_id);
if (!defined($network)) {
$response = GeniResponse->Create(GENIRESPONSE_BADARGS, undef,
"$hop_urn is not an external network");
goto done;
}
my $vlan = VLan->Lookup($slice_experiment, $linkname);
if (!defined($vlan)) {
#
......@@ -1714,6 +1768,29 @@ sub ReserveVlanTags($)
$actualtag = $tag;
}
else {
#
# Check to see what tags are valid for us.
#
my @tags = ();
foreach my $tag (@{ $taglist }) {
push(@tags, $tag)
if ($network->VlanTagOkay($tag));
}
if (!@tags) {
#
# Return a list of okay tags.
#
my @okaytags = ();
for (my $i = $network->min_vlan();
$i < $network->max_vlan(); $i++) {
push(@okaytags, $i);
}
$response = GeniResponse->Create(GENIRESPONSE_SEARCHFAILED,
\@okaytags,
"Could not find a suitable tag");
goto done;
}
#
# This is a debugging hack; Inside an elabinelab, it might be
# an other local elabinelab or the outer boss. In this case,
......@@ -1722,7 +1799,6 @@ sub ReserveVlanTags($)
# In this case, we can just stipulate that one of the tags is good.
#
if ($ELABINELAB) {
my ($myauth,undef,undef) = GeniHRN::Parse($ENV{'MYURN'});
my ($hisauth,undef,undef) = GeniHRN::Parse($slice_urn);
my @tmp = split('\.', $OURDOMAIN);
......@@ -1732,7 +1808,7 @@ sub ReserveVlanTags($)
if ($myauth =~ /$dom$/ && $hisauth =~ /$dom$/) {
print STDERR "ElabInElab clause is true: $myauth $hisauth\n";
my $tag = pop(@{ $taglist });
my $tag = pop(@tags);
if ($vlan->ReserveVlanTag($tag)) {
$actualtag = $tag;
goto gottag;
......@@ -1751,7 +1827,7 @@ sub ReserveVlanTags($)
#
my $vlanid = $vlan->lanid();
my $tag = undef;
my @tmp = @{ $taglist };
my @tmp = @tags;
while (@tmp) {
$tag = pop(@tmp);
if ($vlan->ReserveVlanTag($tag, 1)) {
......
#!/usr/bin/perl -w
#
# GENIPUBLIC-COPYRIGHT
# Copyright (c) 2008-2010 University of Utah and the Flux Group.
# Copyright (c) 2008-2011 University of Utah and the Flux Group.
# All rights reserved.
#
use strict;
......@@ -180,10 +180,13 @@ sub ExpireTickets()
sub ExpireSlices()
{
my $query_result =
GeniDB::DBQueryWarn("select idx from geni_slices ".
"where UNIX_TIMESTAMP(now()) > ".
" UNIX_TIMESTAMP(expires) and ".
" shutdown is null");
GeniDB::DBQueryWarn("select idx from geni_slices where ".
" (UNIX_TIMESTAMP(now()) > ".
" UNIX_TIMESTAMP(expires) or ".
" (isplaceholder=1 and ".
" (UNIX_TIMESTAMP(now()) - ".
" UNIX_TIMESTAMP(created)) > 3600)) ".
" and shutdown is null");
while (my ($idx) = $query_result->fetchrow_array()) {
my $slice = GeniSlice->Lookup($idx);
......@@ -211,7 +214,7 @@ sub ExpireSlices()
# See if we have any local nodes. No point in using the idle
# check if there are no nodes.
#
if ($idlecheck) {
if ($idlecheck && !$slice->isplaceholder()) {
my @localnodes = ();
$experiment->LocalNodeListNames(\@localnodes);
if (@localnodes) {
......@@ -233,7 +236,12 @@ sub ExpireSlices()
print STDERR "$slice ($experiment) is idle; releasing.\n";
}
else {
print STDERR "$slice ($experiment) has expired; releasing.\n";
if ($slice->isplaceholder()) {
print STDERR "Releasing placeholder $slice $experiment.\n";
}
else {
print STDERR "Expiring $slice $experiment.\n";
}
}
cleanup:
if (GeniCM::CleanupDeadSlice($slice) != 0) {
......
......@@ -19,7 +19,8 @@ sub usage()
exit(1);
}
my $optlist = "";
my $basetag = 750;
my $mintag = 750;
my $maxtag = 1000;
my $other_manager;
#
# Configure variables
......@@ -38,8 +39,8 @@ delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
# Protos
sub fatal($);
sub ReserveLocalTags();
sub ReserveRemoteTags($@);
sub ReserveLocalTags(@);
sub ReserveRemoteTags($$@);
#
# Turn off line buffering on output
......@@ -162,9 +163,10 @@ if (!defined($vlan)) {
fatal("Could not create vlan for $linkname");
}
my $lanid = $vlan->lanid();
my @othertags = ();
while (my @tags = ReserveLocalTags()) {
my $tag = ReserveRemoteTags($other_manager, @tags);
while (my @tags = ReserveLocalTags(@othertags)) {
my $tag = ReserveRemoteTags($other_manager, \@othertags, @tags);
if ($tag) {
print STDERR "Agreeded on tag $tag. Releasing the rest.\n";
foreach my $t (@tags) {
......@@ -175,14 +177,13 @@ while (my @tags = ReserveLocalTags()) {
}
# Clear all the tags so we can try again.
$vlan->ClearReservedVlanTag();
last;
}
$vlan->Destroy();
exit(0);
sub ReserveRemoteTags($@)
sub ReserveRemoteTags($$@)
{
my ($authority, @tags) = @_;
my ($authority, $othertags, @tags) = @_;
my $method_args = {};
$method_args->{'credentials'} = [$credential->asString()];
......@@ -191,6 +192,7 @@ sub ReserveRemoteTags($@)
$method_args->{'rspec'} = $rspecstr;
$method_args->{'linkname'} = $linkname;
$method_args->{'taglist'} = \@tags;
@$othertags = ();
my $response =
Genixmlrpc::CallMethod($authority->url(),
......@@ -207,6 +209,16 @@ sub ReserveRemoteTags($@)
}
if ($response->code == GENIRESPONSE_SEARCHFAILED) {
print STDERR "*** Target CM did not like any of the tags we sent\n";
if (defined($response->value()) && ref($response->value()) eq "ARRAY"){
my @otags = @{ $response->value() };
print STDERR "*** But they said they like these tags: @otags\n";
foreach my $t (@otags) {
if (! ($t =~ /^\d*$/)) {
fatal("Bad tag return from target CM: $t");
}
}
@$othertags = @otags;
}
return undef;
}
my $tempstr = $response->value();
......@@ -228,38 +240,62 @@ sub ReserveRemoteTags($@)
#
# Reserve a set of local tags and return a list.
#
sub ReserveLocalTags()
sub ReserveLocalTags(@)
{
my @tags = ();
my @try = ();
for (my $i = 0; $i < 100; $i++) {
# Try for 10.
last
if (scalar(@tags) >= 10);
my $tag = $basetag++;
my @otags = @_;
my @tags = ();
my @try = ();
my $gototags = scalar(@otags);
if (VLan->VlanTagAvailable($tag)) {
push(@try, $tag);
if (scalar(@try) > 5) {
# Need more then one tag to activate "block" mode.
print STDERR "Trying to allocate vlan tags: @try\n";
system("$SNMPIT -A $pid $eid $lanid," . join(",", @try));
if ($?) {
fatal("Could not reserve vlan tags\n");
}
# See what tags we actually got.
foreach my $t (@try) {
push(@tags, $t)
if ($vlan->HasVlanTagReserved($t));
}
@try = ();
#
# The goal is reserve 10 tags before we call the target CM, but
# we will take what we can get.
#
while (scalar(@tags) < 10) {
if ($gototags) {
while (@otags) {
my $t = pop(@otags);
push(@try, $t)
if (VLan->VlanTagAvailable($t));
# But do not let the other CM make us reserve too many at once
last
if (scalar(@try) > 10);
}
}
else {
while ($mintag < $maxtag) {
my $t = $mintag++;
push(@try, $t)
if (VLan->VlanTagAvailable($t));
# But not more then 10 at a time.
last
if (scalar(@try) > 10);
}
}
# Nothing is available to reserve.
last
if (!@try);
#
# Do this in "blockmode" so that snmpit does not throw an error
# if one of the tags is not available.
#
print STDERR "Trying to allocate vlan tags: @try\n";
system("$SNMPIT --blockmode -A $pid $eid $lanid," . join(",", @try));
if ($?) {
fatal("Could not reserve vlan tags\n");
}
# See what tags we actually got.
foreach my $t (@try) {
push(@tags, $t)
if ($vlan->HasVlanTagReserved($t));