Commit 4a12f575 authored by Leigh Stoller's avatar Leigh 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