All new accounts created on Gitlab now require administrator approval. If you invite any collaborators, please let Flux staff know so they can approve the accounts.

Commit 4a12f575 authored by Leigh B Stoller's avatar Leigh B Stoller

Checkpoint MLE work.

parent 7f025cdf
......@@ -283,7 +283,7 @@ sub Create($$$)
my $mask = $argref->{'mask'};
my $card = $argref->{'card'};
my $port = $argref->{'port'};
my $iftype = $argref->{'type'};
my $iftype = $argref->{'type'} || $argref->{'interface_type'};
my $ifrole = $argref->{'role'};
my $uuid = $argref->{'uuid'};
my $max_speed = $argref->{'max_speed'};
......@@ -319,7 +319,7 @@ sub Create($$$)
}
}
if (! (defined($card) && defined($ifrole) && defined($MAC) &&
defined($IP) && defined($port) && defined($mask) &&
defined($IP) && defined($port) &&
defined($iftype) && defined($iface) && defined($max_speed) &&
defined($duplex) && defined($uuid))) {
print STDERR "Interface::Create: Missing fields in arguments:\n";
......@@ -351,7 +351,8 @@ sub Create($$$)
if (!DBQueryWarn("insert into interfaces set ".
" node_id='$node_id', logical='$logical', " .
" card=$card, port=$port, role='$ifrole', ".
" mac='$MAC', IP='$IP', mask='$mask', " .
" mac='$MAC', IP='$IP', " .
(defined($mask) ? "mask='$mask', " : "") .
" interface_type='$iftype', iface='$iface', " .
" current_speed='$max_speed', duplex='$duplex', ".
" uuid='$uuid'")) {
......@@ -819,8 +820,131 @@ sub Update($$)
##############################################################################
#
# This class exists entirely for the mapper, to make it easy to track
# and display logical wires and interfaces while the mapper is running.
# A wrapper class for a wire.
#
package Interface::Wire;
use libdb;
use Node;
use libtestbed;
use English;
use overload ('""' => 'Stringify');
#
# Lookup a wire, using the interface of the "pc" side.
#
sub Lookup($$)
{
my ($class, $interface) = @_;
if (!ref($interface)) {
# Allow "nodeid:card:port" argument.
if ($interface =~ /^([-\w]*):(\w+):(\w+)$/) {
$interface = Interface->Lookup($1, $2, $3);
return undef
if (!defined($interface));
}
else {
return undef;
}
}
my $node_id1 = $interface->node_id();
my $card1 = $interface->card();
my $port1 = $interface->port();
my $query_result =
DBQueryWarn("select * from wires ".
"where node_id1='$node_id1' and ".
" card1='$card1' and port1='$port1'");
return undef
if (!$query_result || !$query_result->numrows);
my $wire = {};
$wire->{"DBROW"} = $query_result->fetchrow_hashref();
bless($wire, $class);
return $wire;
}
sub field($$) { return $_[0]->{'DBROW'}->{$_[1]}; }
sub node_id1($) { return $_[0]->field('node_id1'); }
sub node_id2($) { return $_[0]->field('node_id2'); }
sub card1($) { return $_[0]->field('card1'); }
sub card2($) { return $_[0]->field('card2'); }
sub port1($) { return $_[0]->field('port1'); }
sub port2($) { return $_[0]->field('port2'); }
sub type($) { return $_[0]->field('type'); }
sub logical($) { return $_[0]->field('logical'); }
#
# A wire has two interfaces, but we do not always create interface
# table entries for both sides; the switch side is generally not in
# the interfaces table.
#
sub Interfaces($)
{
my ($self) = @_;
return (Interface->Lookup($self->node_id1(),
$self->card1(), $self->port1()),
Interface->Lookup($self->node_id2(),
$self->card2(), $self->port2()));
}
#
# Stringify for output.
#
sub Stringify($)
{
my ($self) = @_;
my $node1 = $self->node_id1();
my $node2 = $self->node_id2();
my $card1 = $self->card1();
my $card2 = $self->card2();
my $port1 = $self->port1();
my $port2 = $self->port2();
return "[Wire: $node1:$card1:$port1/$node2:$card2:$port2]";
}
#
# Activate a (logical) wire by setting the type. Default to "Node".
#
sub Activate($;$)
{
my ($self, $type) = @_;
my $node_id1 = $self->node_id1();
my $card1 = $self->card1();
my $port1 = $self->port1();
$type = "Node" if (!defined($type));
return -1
if (!DBQueryWarn("update wires set type='$type' ".
"where node_id1='$node_id1' and ".
" card1=$card1 and port1=$port1"));
return 0;
}
sub DeActivate($)
{
my ($self) = @_;
my $node_id1 = $self->node_id1();
my $card1 = $self->card1();
my $port1 = $self->port1();
return -1
if (!DBQueryWarn("update wires set type='Unused' ".
"where node_id1='$node_id1' and ".
" card1=$card1 and port1=$port1"));
return 0;
}
##############################################################################
#
# A wrapper class for a "logical wire". This is a wire that exists
# cause it was created with a layer 1 switch. Basically the same as
# wire above, but this class is handy for the mapper and for display.
# Not really intended to be used outside the mapper. Use the class above.
#
package Interface::LogicalWire;
use libdb;
......@@ -878,6 +1002,7 @@ sub Create($$$$$$)
$argref->{'card'} = $interfaceA->card() + 200;
$argref->{'iface'} = "eth" . $argref->{'card'};
$argref->{'logical'} = 1;
$argref->{'uuid'} = undef;
if (!$impotent) {
$interfaceA = Interface->Create($pnodeA, $argref);
......@@ -901,6 +1026,7 @@ sub Create($$$$$$)
$argref->{'card'} = $interfaceB->card() + 200;
$argref->{'iface'} = "eth" . $argref->{'card'};
$argref->{'logical'} = 1;
$argref->{'uuid'} = undef;
if (!$impotent) {
$interfaceB = Interface->Create($pnodeB, $argref);
......@@ -912,15 +1038,22 @@ sub Create($$$$$$)
$interfaceB = Interface->MakeFake($pnodeB, $argref);
}
}
#
# For consistency and because we still have an implicit assumption
# the switch is node_id2 in the wires table.
#
my ($interface1,$interface2) = ($interfaceA, $interfaceB);
if ($pnodeA->isswitch() && !$pnodeB->isswitch()) {
($interface1,$interface2) = ($interfaceB, $interfaceA);
}
# Create a wires table entry, ordered properly.
if (!$impotent) {
my $node_id1 = ($pnodeA->isswitch() ?
$pnodeB->node_id() : $pnodeA->node_id());
my $node_id2 = ($pnodeB->isswitch() ?
$pnodeA->node_id() : $pnodeB->node_id());
my $card1 = $interfaceA->card();
my $port1 = $interfaceA->port();
my $card2 = $interfaceB->card();
my $port2 = $interfaceB->port();
my $node_id1 = $interface1->node_id();
my $node_id2 = $interface2->node_id();
my $card1 = $interface1->card();
my $port1 = $interface1->port();
my $card2 = $interface2->card();
my $port2 = $interface2->port();
#
# The wire is not active yet. When snmpit tuns and actually
......@@ -928,29 +1061,50 @@ sub Create($$$$$$)
# reflect that. Use the 'Unused' type to indicate it is not
# active.
#
if (!DBQueryWarn("insert into wires set".
if (!DBQueryWarn("replace into wires set".
" type='Unused', logical=1, " .
" node_id1='$node_id1',card1=$card1,port1=$port1, " .
" node_id2='$node_id2',card2=$card2,port2=$port2")) {
return undef;
}
}
my $self = {};
$self->{"nodeA"} = $nodeA;
$self->{"portA"} = $portA;
$self->{"lportA"} = $interfaceA->iface();
$self->{"nodeB"} = $nodeB;
$self->{"portB"} = $portB;
$self->{"lportB"} = $interfaceB->iface();
my $self = {};
#
# Do not reorder here; the caller will just be confused.
#
$self->{"interfaceA"} = $interfaceA;
$self->{"interfaceB"} = $interfaceB;
$self->{"interface1"} = $interface1;
$self->{"interface2"} = $interface2;
bless($self, $class);
return $self;
}
sub nodeA($) { return $_[0]->{'nodeA'}; }
sub portA($) { return $_[0]->{'portA'}; }
sub lportA($) { return $_[0]->{'lportA'}; }
sub nodeB($) { return $_[0]->{'nodeB'}; }
sub portB($) { return $_[0]->{'portB'}; }
sub lportB($) { return $_[0]->{'lportB'}; }
sub interfaceA($) { return $_[0]->{'interfaceA'}; }
sub interfaceB($) { return $_[0]->{'interfaceB'}; }
sub nodeA($) { return $_[0]->interfaceA()->node_id(); }
sub nodeB($) { return $_[0]->interfaceB()->node_id(); }
sub ifaceA($) { return $_[0]->interfaceA()->iface(); }
sub ifaceB($) { return $_[0]->interfaceB()->iface(); }
# Wires table ordering.
sub interface1($) { return $_[0]->{'interface1'}; }
sub interface2($) { return $_[0]->{'interface2'}; }
#
# The wires table is indexed by node_id1,card1,port1 ... return
# something that allows us to find that wires table entry.
#
sub WireID($)
{
my ($self) = @_;
my $interface1 = $self->interface1();
my $node_id1 = $interface1->node_id();
my $card1 = $interface1->card();
my $port1 = $interface1->port();
return "$node_id1:$card1:$port1";
}
#
# Stringify for output.
......@@ -958,15 +1112,16 @@ sub lportB($) { return $_[0]->{'lportB'}; }
sub Stringify($)
{
my ($self) = @_;
my $interfaceA = $self->interfaceA();
my $interfaceB = $self->interfaceB();
my $nodeA = $self->nodeA();
my $nodeB = $self->nodeB();
my $portA = $self->portA();
my $portB = $self->portB();
my $lportA = $self->lportA();
my $lportB = $self->lportB();
return "[LogicalWire: $nodeA:$portA:$lportA/$nodeB:$portB:$lportB]";
my $nodeA = $self->nodeA();
my $nodeB = $self->nodeB();
my $ifaceA = $self->ifaceA();
my $ifaceB = $self->ifaceB();
return "[LogicalWire: $nodeA:$ifaceA/$nodeB:$ifaceB]";
}
......
......@@ -596,6 +596,39 @@ sub GotTrunks($$)
return $query_result->numrows;
}
#
# Get the set of lans that are linked to this lan. Optionally provide the
# type, say to look for just vlans.
#
sub GetLinkedTo($$;$)
{
my ($class, $lan, $type) = @_;
if (! ref($lan)) {
$lan = Lan->Lookup($lan);
return ()
if (!defined($lan));
}
my $exptidx = $lan->exptidx();
my $lanid = $lan->lanid();
my @result = ();
my $query_result =
DBQueryWarn("select lanid from lans ".
"where link='$lanid' ".
(defined($type) ? "and type='$type'" : ""));
return ()
if (!$query_result || !$query_result->numrows);
while (my ($id) = $query_result->fetchrow_array()) {
my $vlan = Lan->Lookup($id);
return undef
if (!defined($vlan));
push(@result, $vlan);
}
return @result;
}
#
# Stringify for output.
#
......@@ -2261,6 +2294,7 @@ sub id($) { return $_[0]->GetLan()->lanid(); }
sub vname($) { return $_[0]->GetLan()->vname(); }
sub ready($) { return $_[0]->GetLan()->ready(); }
sub type($) { return $_[0]->GetLan()->type(); }
sub link($) { return $_[0]->GetLan()->link(); }
sub GetLan($) { return $_[0]->{'LAN'}; }
sub GetExperiment($) { return $_[0]->GetLan()->GetExperiment(); }
sub vlanid($) { return $_[0]->lanid(); }
......@@ -2977,6 +3011,29 @@ sub ExperimentVLans($$$)
return 0;
}
#
# Find a vlan by looking an interface in the vlan.
#
sub FindVlanByInterface($$$)
{
my ($class, $experiment, $interface) = @_;
my $exptidx = $experiment->idx();
my $iface = $interface->iface();
my @vlans = ();
#
# We do not do this often, so worry about optimizing later.
#
return undef
if (VLan->ExperimentVLans($experiment, \@vlans) != 0);
foreach my $vlan (@vlans) {
return $vlan
if ($vlan->IsMember($interface->node_id(), $interface->iface()));
}
return undef;
}
#
# Utility function to add a vlan to the switch infrastructure.
#
......@@ -3246,6 +3303,27 @@ sub StaleVlanList($$$)
return 0;
}
#
# Get the set of lans that are linked to this lan. Optionally provide the
# type, say to look for just vlans.
#
sub GetLinkedTo($$;$)
{
my ($class, $lan, $type) = @_;
my @result = Lan->GetLinkedTo($lan, $type);
return @result
if (!@result);
# Convert to VLan;
my @tmp = ();
foreach my $lan (@result) {
bless($lan, $class);
push(@tmp, $lan);
}
return @tmp;
}
############################################################################
#
# Another convenience package, for tunnels.
......
......@@ -1688,16 +1688,23 @@ sub LoadInterfaces($)
sub GetInterface($$$)
{
my ($self, $iface, $pref) = @_;
my $interface;
# Must be a real reference.
return -1
if (! (ref($self) && ref($pref)));
$self->LoadInterfaces() == 0
or return -1;
if (exists($self->{'IFACES'}->{$iface})) {
# Might be undef if we already tried.
$interface = $self->{'IFACES'}->{$iface};
}
else {
$interface = Interface->LookupByIface($self, $iface);
$self->{'IFACES'}->{$iface} = $interface;
}
$$pref = $interface;
return -1
if (!exists($self->{'IFACES'}->{$iface}));
$$pref = $self->{'IFACES'}->{$iface};
if (!defined($interface));
return 0;
}
......
......@@ -5408,6 +5408,12 @@ sub InterpLinksAux($)
$self->impotent() ||
$self->alloconly());
$protovlans{$lan} = $protolink;
$protolink->SetType("wire");
$protolink->SetRole("link");
$protolink->AddInterface($nodeA, $vnodeA,
$vportA, $portA);
$protolink->AddInterface($nodeB, $vnodeB,
$vportB, $portB);
#
# The layer one link when it is in existence, is just like
......@@ -5427,27 +5433,20 @@ sub InterpLinksAux($)
$self->printdb("Created $logicalwire for $virtlan\n");
#
# There is no reasonable place to store the association of
# logical interface/wire with the physical interfaces.
# Do it in the member settings.
#
$protolink->SetType("wire");
$protolink->SetRole("link");
$protolink->AddInterface($nodeA, $vnodeA,
$vportA, $portA, undef,
{'logical_iface' =>
$logicalwire->lportA()});
$protolink->AddInterface($nodeB, $vnodeB,
$vportB, $portB, undef,
{'logical_iface' =>
$logicalwire->lportB()});
#
# Stash this into segment so we can find it later, as when
# doing the link at the next layer up.
#
$virtlan->_logicalwire($logicalwire);
#
# And stash into the lan entry for snmpit later, which will
# need to find the wire so it can mark it as active once
# the layer 1 link is created.
#
$protolink->SetAttribute("logicalwireid",
$logicalwire->WireID());
next;
}
elsif ($virtlan->_layer() == 2 && $virtlan->_vpath()) {
......@@ -5529,8 +5528,8 @@ sub InterpLinksAux($)
$self->printdb("$virtlan; $firstwire, $lastwire\n");
$portA = $firstwire->lportA();
$portB = $lastwire->lportB();
$portA = $firstwire->ifaceA();
$portB = $lastwire->ifaceB();
}
if ($virtlan->usevirtiface()) {
my $protovlan;
......
......@@ -898,8 +898,40 @@ COMMAND: foreach my $command (@commands) {
debug("Device names: " . join(",",@devicenames) . "\n");
debug("Ports: " . join(",",@ports) . "\n");
if (@vlans) { debug("VLANs: " . join(",",@vlans) . "\n") };
#
# Order the vlans using the dependency information in the link field.
#
if (@vlans) {
my %vlans = map { $_ => VLan->Lookup($_) } @vlans;
my @newvlans = ();
my %newvlans = ();
#
# The "link" field in the vlan points to the vlan it is dependent
# on. So, we actually build up the list in reverse order, and then
# flip it around at the end.
#
while (@vlans) {
my @tmp = ();
foreach my $vlanid (@vlans) {
my $vlan = $vlans{$vlanid};
if (!$vlan->link() || exists($newvlans{$vlan->link()})) {
push(@newvlans, $vlanid);
$newvlans{$vlanid} = $vlanid;
}
else {
push(@tmp, $vlanid);
}
}
@vlans = @tmp
}
@vlans = reverse(@newvlans);
debug("VLANs: " . join(",",@vlans) . "\n");
print "VLANs: " . join(",",@vlans) . "\n";
}
my %stacks = ();
if (! $ELABINELAB) {
#
......@@ -1877,6 +1909,28 @@ sub CreateOneVlan($$$@)
}
}
}
#
# Look for a layer 1 link; There is a logical wire that needs to be
# activated once it is created.
#
my $vlan = VLan->Lookup($vlanid);
if ($vlan->type() eq "wire") {
my $wireid;
if ($vlan->GetAttribute("logicalwireid", \$wireid) == 0) {
my $wire = Interface::Wire->Lookup($wireid);
if (!defined($wire)) {
print STDERR "Could not logical wire for $vlan ($wireid)\n";
$errors++;
}
else {
if ($wire->Activate() != 0) {
print STDERR "Could not activate $wire for $vlan\n";
$errors++;
}
}
}
}
return $errors;
}
......@@ -1888,6 +1942,7 @@ sub CreateOneVlan($$$@)
sub doReset($@) {
my $stacks = shift;
my @vlans = @_;
my %wires = ();
#
# Hand over to outer boss.
......@@ -1907,6 +1962,41 @@ sub doReset($@) {
$debug = 1;
#
# Look for a layer 1 link; There is a logical wire that needs to be
# deactivated once it is created, but must ensure that the logical
# wire is not actually in use.
#
foreach my $vlan_id (@vlans) {
my $vlan = VLan->Lookup($vlan_id);
my $wireid;
next
if (! $vlan->type() eq "wire");
if ($vlan->GetAttribute("logicalwireid", \$wireid) == 0) {
my $wire = Interface::Wire->Lookup($wireid);
if (!defined($wire)) {
print STDERR "Could not logical wire for $vlan ($wireid)\n";
return -1;
}
# need the interfaces.
my ($interface1, $interface2) = $wire->Interfaces();
if (!defined($interface1)) {
print STDERR "No interface for logical wire $wire\n";
return -1;
}
# Find the vlan that uses this interface.
my $vlanusing = Lan->FindVlanByInterface($experiment, $interface1);
if (defined($vlanusing) && $vlanusing->CreatedOnSwitches()) {
print STDERR "Logical wire $wire is in use by $vlanusing; ".
"not allowed to remove $vlan\n";
return -1;
}
$wires{$vlan->lanid()} = $wire;
}
}
#
# Just remove the VLAN from every stack on which it exists. We keep a
# list and do them all at once for efficiency.
......@@ -1935,6 +2025,17 @@ sub doReset($@) {
clearReservedVlanTag($vlan_id)
if ($opt{C});
VLan->RecordVLanDeletion($vlan_id);
# Deactivate the logical wire.
if (exists($wires{$vlan_id})) {
my $wire = $wires{$vlan_id};
print "Deactivating logical wire $wire\n";
if ($wire->DeActivate() != 0) {
print STDERR "Could not deactivate $wire for vlan $vlan_id\n";
$errors++;
}
}
}
return $errors;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment