Commit 2be10d86 authored by Leigh B Stoller's avatar Leigh B Stoller
Browse files

Merge branch 'mymaster'

parents 64702af5 2b095d85
......@@ -3540,6 +3540,31 @@ sub ClearReservedVlanTags($)
return 0;
}
#
# This is slightly different then above. Rather then releasing all
# reserved tags, we release only the tags that are "dangling"; these
# are tags in the reserved_vlantags table, but without a corresonding
# entry in the lans table. Used from the Protogeni code, when
# releasing a ticket (which reserved some tags that will not be used).
#
sub ClearUnusedReservedVlanTags($)
{
my ($self) = @_;
# Must be a real reference.
return -1
if (! ref($self));
my $idx = $self->idx();
return -1
if (! DBQueryWarn("delete r from reserved_vlantags as r ".
"left join lans as l on l.lanid=r.lanid ".
"where l.lanid is null and r.exptidx='$idx'"));
return 0;
}
#
# Does experiment have any program agents.
#
......
......@@ -263,7 +263,7 @@ SELFLOADER_DATA="__DATA__"
#
# Virtual node network configuration (if you don't want virtual nodes,
# just leave this as is)
# just leave this as is).
#
# Needs at least a /16 network. For a /16 the layout of an IP is:
# X.Y.<pnode>.<vnode>
......@@ -274,6 +274,8 @@ SELFLOADER_DATA="__DATA__"
# the default 172.16/12, then you can have up to 16 * 254 physical hosts.
# If you want more than 254 vnodes per pnode, you are screwed.
#
# ********* DO NOT CHANGE THESE UNLESS YOU ASK UTAH FIRST! *********
#
VIRTNODE_NETWORK=172.16.0.0
VIRTNODE_NETMASK=255.240.0.0
# XXX compat
......
......@@ -1473,6 +1473,7 @@ sub GetTicketAuxAux($$$$$$$$$)
#
my $linknum = 1;
my %linkexistsmap = ();
my %vlan_reservations = ();
foreach my $linkref (GeniXML::FindNodes("n:link",
$rspec)->get_nodelist()) {
......@@ -1482,7 +1483,6 @@ sub GetTicketAuxAux($$$$$$$$$)
"n:interface_ref",
$linkref)->get_nodelist();
my %managers = ();
my %hops = ();
my $ifacenum = 1;
my $vindex = 0;
my $trivial_ok = 1;
......@@ -1521,14 +1521,26 @@ sub GetTicketAuxAux($$$$$$$$$)
}
#
# Look for hops list; optional.
# Look for a vlan tag reservation request.
#
if (GeniXML::FindNodes("n:component_hop", $linkref)) {
%hops = map { GeniXML::GetNodeId($_) => $_ }
GeniXML::FindNodes("n:component_hop",
$linkref)->get_nodelist();
if (my $vlan_tag = GeniXML::GetText("vlantag", $linkref)) {
if (! ($vlan_tag =~ /^\d*/)) {
$response =
GeniResponse->Create(GENIRESPONSE_BADARGS, undef,
"Bad vlan tag for $lanname");
goto bad;
}
my $result =
ReserveLocalVlanTag($slice_experiment, $lanname, $vlan_tag);
if (GeniResponse::IsResponse($result)) {
$response = $result;
goto bad;
}
# Record newly reserved tags for rollback.
if (ref($result)) {
$vlan_reservations{$lanname} = $result;
}
}
#
# Ick. Before we create the virt_lan_lans entry, we have to check
......@@ -1722,6 +1734,25 @@ sub GetTicketAuxAux($$$$$$$$$)
# Stash for later. We need to allocate a vlan tag, and
# this stores the min/max vlan numbers we have to use.
$stitching_paths{$lanname}->{'network'} = $network;
$stitching_paths{$lanname}->{'edgeurn'} = $edgeurn;
#
# Look for a vlan tag reservation request. We only
# support a single tag, not a range.
#
my $vlan_tag = GetSuggestedVlanFromHop($edgehop);
if ($vlan_tag) {
my $result = ReserveLocalVlanTag($slice_experiment,
$lanname, $vlan_tag);
if (GeniResponse::IsResponse($result)) {
$response = $result;
goto bad;
}
# Record newly reserved tags for rollback.
if (ref($result)) {
$vlan_reservations{$lanname} = $result;
}
}
#
# Stick in a reference to the fake node.
......@@ -1756,6 +1787,7 @@ sub GetTicketAuxAux($$$$$$$$$)
$iface_vport = $external_vportmap{$node_nickname};
$external_vportmap{$node_nickname} += 1;
$external_linkmap{$lanname} = $linkref;
goto stitch;
}
else {
......@@ -1845,7 +1877,7 @@ sub GetTicketAuxAux($$$$$$$$$)
# This is the magic for libvtop.
$virtexperiment->NewTableRow("virt_lan_settings",
{"vname" => $lanname,
"capkey" => "portvlan",
"capkey" => "sharedvlan",
"capval" => $shared_vlan});
# Clear all this.
......@@ -2243,6 +2275,10 @@ sub GetTicketAuxAux($$$$$$$$$)
GeniXML::SetText("vlantag", $linkref, $tag);
#
# Change all of the stitching hops to our edge point, since
# that is how our network is setup.
#
my @hoplist = @{ $stitching_paths{$linkname}->{'hoplist'} };
foreach my $hop (@hoplist) {
my $hopurn = GetHopLinkID($hop);
......@@ -2250,24 +2286,7 @@ sub GetTicketAuxAux($$$$$$$$$)
next
if (!defined($auth) || $auth ne $OURDOMAIN);
#
# Need to change a couple of fields buried down inside. Ick.
#
my $tmp = FindFirst("n:link", $hop);
$tmp = (FindFirst("n:switchingCapabilityDescriptor", $tmp) ||
FindFirst("n:switchingCapabilityDescriptors", $tmp))
if (defined($tmp));
$tmp = FindFirst("n:switchingCapabilitySpecificInfo", $tmp)
if (defined($tmp));
if (defined($tmp) &&
FindFirst("n:switchingCapabilitySpecificInfo_L2sc", $tmp)) {
$tmp = FindFirst("n:switchingCapabilitySpecificInfo_L2sc",
$tmp)
}
if (defined($tmp)) {
SetText("vlanRangeAvailability", $tmp, "$tag");
SetText("suggestedVLANRange", $tmp, "$tag");
}
SetVlanTagInHop($hop, $tag);
}
next;
}
......@@ -2276,14 +2295,20 @@ sub GetTicketAuxAux($$$$$$$$$)
# Chainmode
#
while ($retries) {
my $edgeurn = $stitching_paths{$linkname}->{'edgeurn'};
#
# Already have a reserved tag? This could happen if the other CM
# acted first and talked to this CM before we saw the ticket
# request. Or this is an update and we already have tags reserved.
# request. Or this is an update and we already have tags
# reserved.
#
# If we just reserved the tag above, we still need to talk
# to the other side.
#
my $tag = VLan::GetReservedVlanTag($slice_experiment, $linkname);
last
if (defined($tag));
if (defined($tag) && !exists($vlan_reservations{$linkname}));
my ($fh, $filename) = tempfile(UNLINK => 0);
if (!defined($fh)) {
......@@ -2293,7 +2318,8 @@ sub GetTicketAuxAux($$$$$$$$$)
}
print $fh GeniXML::Serialize($rspec);
close($fh);
system("$RESERVEVLANS '$slice_urn' '$linkname' $filename");
system("$RESERVEVLANS ".
"'$slice_urn' '$linkname' '$edgeurn' $filename");
if ($CHILD_ERROR) {
unlink($filename);
......@@ -2337,6 +2363,20 @@ sub GetTicketAuxAux($$$$$$$$$)
$tag = VLan::GetReservedVlanTag($slice_experiment, $linkname);
if (defined($tag)) {
GeniXML::SetText("vlantag", $linkref, $tag);
#
# Change all of the stitching hops to our edge point, since
# that is how our network is setup.
#
my @hoplist = @{ $stitching_paths{$linkname}->{'hoplist'} };
foreach my $hop (@hoplist) {
my $hopurn = GetHopLinkID($hop);
my ($auth,undef,undef) = GeniHRN::Parse($hopurn);
next
if (!defined($auth) || $auth ne $OURDOMAIN);
SetVlanTagInHop($hop, $tag);
}
last;
}
# This should not happen.
......@@ -2349,8 +2389,12 @@ sub GetTicketAuxAux($$$$$$$$$)
again:
$retries--;
}
if (!$retries) {
$response = GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"Could not reserve vlan tag for $linkname");
goto bad;
}
}
print GeniXML::Serialize($rspec);
#
......@@ -2434,6 +2478,16 @@ sub GetTicketAuxAux($$$$$$$$$)
$slice_experiment->RemoveVirtualState()
if (defined($slice_experiment));
}
#
# Clear any new vlan tag reservations we made during this call.
#
foreach my $linkname (%vlan_reservations) {
my ($lanid, $vlan_tag) = @{ $vlan_reservations{$linkname} };
# If this is a new ticket, there is no lan object yet,
# so need to call this as a function instead of a method.
VLan::ClearReservedVlanTag($lanid, $vlan_tag);
}
if ($v2 && $level == 0) {
CleanupDeadSlice($slice, 1)
if (defined($slice));
......@@ -3439,7 +3493,8 @@ sub SliverWorkAux($$$$$$$)
my $ipAddress;
if (defined($vinterface)) {
$ipAddress = $vinterface->IP();
} else {
}
elsif (defined($interface)) {
$ipAddress = $interface->IP();
}
# Manifest goes back to the user.
......@@ -6121,5 +6176,127 @@ sub GetHopLinkID($)
return $result;
}
sub GetHopCapabilitySection($)
{
my ($hopref) = @_;
#
# Dig out the section we need from the hop.
#
my $tmp = FindFirst("n:link", $hopref);
$tmp = (FindFirst("n:switchingCapabilityDescriptor", $tmp) ||
FindFirst("n:switchingCapabilityDescriptors", $tmp))
if (defined($tmp));
$tmp = FindFirst("n:switchingCapabilitySpecificInfo", $tmp)
if (defined($tmp));
if (defined($tmp) &&
FindFirst("n:switchingCapabilitySpecificInfo_L2sc", $tmp)) {
$tmp = FindFirst("n:switchingCapabilitySpecificInfo_L2sc", $tmp)
}
return $tmp;
}
sub GetSuggestedVlanFromHop($)
{
my ($hopref) = @_;
my $capref = GetHopCapabilitySection($hopref);
return undef
if (!defined($capref));
my $tag = GeniXML::GetText("suggestedVLANRange", $capref);
return $tag;
}
sub SetVlanTagInHop($$)
{
my ($hopref, $tag) = @_;
my $capref = GetHopCapabilitySection($hopref);
return undef
if (!defined($capref));
GeniXML::SetText("vlanRangeAvailability", $capref, "$tag");
GeniXML::SetText("suggestedVLANRange", $capref, "$tag");
return 0;
}
sub ReserveLocalVlanTag($$$)
{
my ($experiment, $lanname, $tag) = @_;
my $createdvlan = 0;
my $vlan = VLan->Lookup($experiment, $lanname);
#
# Do we already have the link and tag?
#
if (defined($vlan)) {
if ($vlan->HasVlanTagReserved($tag)) {
# Indicates tag already reserved.
return 0;
}
#
# Not allowed to change the tag, sorry.
#
if ($vlan->GetReservedVlanTag()) {
return GeniResponse->Create(GENIRESPONSE_BADARGS, undef,
"Already have a tag for $lanname");
}
}
else {
#
# If this is an update to a ticket, there is no lan
# object, it is still uninstantiated.
#
my $curtag = VLan::GetReservedVlanTag($experiment, $lanname);
if (defined($curtag)) {
if ($curtag == $tag) {
# Indicates tag already reserved.
return 0;
}
return GeniResponse->Create(GENIRESPONSE_BADARGS, undef,
"Already have a tag for $lanname");
}
}
#
# Lets see if the tag is available.
#
if (!VLan->VlanTagAvailable($tag)) {
return GeniResponse->Create(GENIRESPONSE_BADARGS, undef,
"vlan tag for $lanname not available");
}
#
# Reserve the tag. In order to do this, we have to create
# a lan entry long enough for snmpit to actually create the
# reservation. Then we kill it off until the ticket is actually
# redeemed.
#
if (!defined($vlan)) {
$vlan = VLan->Create($experiment, $lanname);
if (!defined($vlan)) {
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"Internal Error creating vlan object");
}
$createdvlan = 1;
}
my $lanid = $vlan->lanid();
my $pid = $experiment->pid();
my $eid = $experiment->eid();
print STDERR "Trying to reserve vlan tag $tag for $lanname\n";
system("$SNMPIT -A $pid $eid $lanid,$tag");
if ($?) {
$vlan->Destroy()
if ($createdvlan);
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"Error reserving vlan tag for $lanname");
}
$vlan->Destroy()
if ($createdvlan);
print STDERR "Reserved tag $tag for $lanname\n";
return [$lanid, $tag];
}
# _Always_ make sure that this 1 is at the end of the file...
1;
......@@ -1820,31 +1820,98 @@ sub ReserveVlanTags($)
}
#
# Go through the component hops and find the one that refers to us.
# This is our external network point.
# Need to dig inside the stitching section to find the path.
#
my $stitching_path;
foreach my $ref (GeniXML::FindNodesNS("n:stitching",
$rspec,
$GeniXML::STITCH_NS)->get_nodelist()){
foreach my $path (GeniXML::FindNodes("n:path",
$ref)->get_nodelist()) {
my $path_id = GeniXML::GetText("id", $path);
if ($path_id eq $linkname) {
$stitching_path = $path;
last;
}
}
}
if (!defined($stitching_path)) {
$response = GeniResponse->Create(GENIRESPONSE_BADARGS, undef,
"Could not find path in rspec");
goto done;
}
#
# Look at the hop list to find the edge point.
#
my @hoplist = GeniXML::FindNodes("n:hop", $stitching_path)->get_nodelist();
if (! @hoplist) {
$response = GeniResponse->Create(GENIRESPONSE_BADARGS, undef,
"No hops in the stitching path");
goto done;
}
if (!GeniHRN::IsValid(GeniCM::GetHopLinkID($hoplist[0]))) {
$response = GeniResponse->Create(GENIRESPONSE_BADARGS, undef,
"Invalid URN in first hop in path");
goto done;
}
my ($hopauth) = GeniHRN::Parse(GeniCM::GetHopLinkID($hoplist[0]));
if ($hopauth ne $OURDOMAIN) {
# Reverse the list to make life easier.
@hoplist = reverse(@hoplist);
}
#
# Go through the hop list to find the edge point. This will
# be the first hop that is in a different domain.
#
my $hopref;
foreach my $ref (GeniXML::FindNodes("n:component_hop",
$linkref)->get_nodelist()) {
my $component_urn = GeniXML::GetNodeId($ref);
my ($domain,undef,undef) = GeniHRN::Parse($component_urn);
if (defined($domain) and $domain eq $me->domain()) {
$hopref = $ref;
my $lasthop;
foreach my $hop (@hoplist) {
my $hopurn = GeniCM::GetHopLinkID($hop);
next
if (! GeniHRN::IsValid($hopurn));
my ($auth,undef,undef) = GeniHRN::Parse($hopurn);
next
if (!defined($auth));
if ($auth ne $OURDOMAIN) {
$hopref = $lasthop;
last;
}
$lasthop = $hop;
}
if (!defined($hopref)) {
$response = GeniResponse->Create(GENIRESPONSE_BADARGS, undef,
"Could not find hop in link");
$response = GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"Could not find the edge hop");
goto done;
}
my $hop_urn = GeniXML::GetNodeId($hopref);
my (undef,undef,$network_id) = GeniHRN::Parse($hop_urn);
my $hopurn = GeniCM::GetHopLinkID($hopref);
my (undef,undef,$network_stuff) = GeniHRN::Parse($hopurn);
my (undef,undef,$network_id) = split('//', $network_stuff);
my $network = ExternalNetwork->Lookup($network_id);
if (!defined($network)) {
$response = GeniResponse->Create(GENIRESPONSE_BADARGS, undef,
"$hop_urn is not an external network");
"$hopurn is not an external network");
goto done;
}
#
# Special case; if the lan has a tag reserved already, the tag we
# got must be an exact match. This can happen if the ticket is
# being updated before redeem, at the other side.
#
if (my $t = VLan::GetReservedVlanTag($slice_experiment, $linkname)) {
if ((grep {$_ == $t} @{ $taglist })) {
$actualtag = $t;
goto gottag;
}
$response = GeniResponse->Create(GENIRESPONSE_SEARCHFAILED, undef,
"Already have a tag reserved");
goto done;
}
......@@ -1972,6 +2039,7 @@ sub ReserveVlanTags($)
goto done;
}
gottag:
print STDERR "Agreed on tag $actualtag\n";
GeniXML::SetText("vlantag", $linkref, $actualtag);
$response = GeniResponse->Create(GENIRESPONSE_SUCCESS,
GeniXML::Serialize($rspec));
......
......@@ -796,6 +796,14 @@ sub Release($$)
my @nodes = ();
my @vhosts = ();
#
# Release unused reserved vlantags.
#
$experiment->ClearUnusedReservedVlanTags();
#
# Release nodes.
#
foreach my $ref (GeniXML::FindNodes("n:node",
$self->rspec())->get_nodelist()) {
# Skip lan nodes; they are fake.
......
#!/usr/bin/perl -w
#
# GENIPUBLIC-COPYRIGHT
# Copyright (c) 2008-2011 University of Utah and the Flux Group.
# Copyright (c) 2008-2012 University of Utah and the Flux Group.
# All rights reserved.
#
use strict;
......@@ -15,7 +15,8 @@ use Data::Dumper;
#
sub usage()
{
print STDERR "Usage: reservevlans <slice_urn> <linkname> <rspec>\n";
print STDERR
"Usage: reservevlans <slice_urn> <linkname> <hopurn> <rspec>\n";
exit(1);
}
my $optlist = "";
......@@ -40,6 +41,7 @@ sub fatal($);
sub busy();
sub ReserveLocalTags(@);
sub ReserveRemoteTags($$@);
sub GetHopLinkID($);
#
# Turn off line buffering on output
......@@ -71,11 +73,12 @@ if (! getopts($optlist, \%options)) {
usage();
}
usage()
if (@ARGV != 3);
if (@ARGV != 4);
my $slice_urn = $ARGV[0];
my $linkname = $ARGV[1];
my $rspecfile = $ARGV[2];
my $hopurn = $ARGV[2];
my $rspecfile = $ARGV[3];
#
# Load the CM cert to act as caller context.
......@@ -138,28 +141,11 @@ if (!defined($other_manager)) {
fatal("Who is the other manager?");
}
#
# 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 ($domain,undef,undef) = GeniHRN::Parse($component_urn);
if (defined($domain) and $domain eq $me->domain()) {
$hopref = $ref;
last;
}
}
if (!defined($hopref)) {
fatal("Could not find hop in link");
}
my $hop_urn = GeniXML::GetNodeId($hopref);
my (undef,undef,$network_id) = GeniHRN::Parse($hop_urn);
my (undef,undef,$network_stuff) = GeniHRN::Parse($hopurn);
my (undef,undef,$network_id) = split('//', $network_stuff);
my $network = ExternalNetwork->Lookup($network_id);
if (!defined($network)) {
fatal("$hop_urn is not an external network");
fatal("$hopurn is not an external network");
}
# The bounds of the vlan tags we can use for this network point.
my $mintag = $network->min_vlan();
......@@ -180,15 +166,6 @@ my $vlan = VLan->Lookup($experiment, $linkname);
if (defined($vlan)) {
fatal("There is already a lan object for $linkname; $vlan");
}
#
# The point of this is to create the VLan object, just long enough to
# get a lanid and a tag assigned.
#
$vlan = VLan->Create($experi