Commit 57def35b authored by Leigh Stoller's avatar Leigh Stoller

Various changes to MLE support, related to issue #317:

1. We now allow lans to be implemented by a path. We did not allow this
   before, cause some of the sanity checking code was a pain to
   implement for lans. Well, no more sanity checking, the user is
   responsible for doing things correctly (after all, they are doing
   experiments with their own switches!).

2. We now allow topologies with more then one switch to be wired
   together. The wires between switches are marked as "trunk" wires,
   which informs the configuration generation code in libosload_switch
   to create the trunks and do the little tagged/untagged magic that is
   required on procurve switches. The same information is used to mark
   the the logical wires between switches as trunks.

   Aside: this stuff needs some work; we have spanning tree on by
   default, which causes the trunks to not work correctly. When I turn
   that off, things start working. So need some help from others who now
   about spanning tree stuff.

3. Serious kludging in the Interface and Port libraries related to
   choice of primary keys in the wires table. In order to insert a
   logical wire (or interface) that represents a connection setup by the
   apcon, we have to overload the primary key since the node_id1 side of
   the logical wires is the same as the physical wire to the apcon. We
   have to have overload the node_id2 side too, but that is really just
   a problem when wiring two switches together. Anyway, the kludge just
   maps card1 to a different id, and the Port library unmaps it. It will
   do for now, but really need logical wires to be done better then
   this.
parent 9e55651a
......@@ -1280,14 +1280,21 @@ sub Stringify($)
#
# Activate a (logical) wire by setting the type. Default to "Node".
#
sub Activate($;$)
sub Activate($$)
{
my ($self, $type) = @_;
my ($self, $vlan) = @_;
my $node_id1 = $self->node_id1();
my $card1 = $self->card1();
my $port1 = $self->port1();
$type = "Node" if (!defined($type));
my $type = "Node";
#
# Unless it is supposed to be a trunk
#
if ($vlan->GetRole() eq "trunk") {
$type = "Trunk";
}
return -1
if (!DBQueryWarn("update wires set type='$type' ".
"where node_id1='$node_id1' and ".
......@@ -1429,65 +1436,63 @@ sub Create($$$$$$)
}
#
# Create interfaces, but not for things that are marked as
# switches since we do not put interfaces for switches into
# the interfaces table.
# Create logical interfaces
#
if (!$pnodeA->isswitch()) {
#
# Create a logical interface. Note we have to force a hash copy.
#
my %argref = %{ $interfaceA->{'DBROW'} };
my $argref = \%argref;
# Update the card and iface.
# XXX Need a better way to allocate the card numbers.
$argref->{'card'} = $interfaceA->card() + 200;
$argref->{'iface'} = "eth" . $argref->{'card'};
$argref->{'logical'} = 1;
$argref->{'uuid'} = undef;
if (!$impotent) {
$interfaceA = Interface->Create($pnodeA, $argref);
return undef
if (!defined($interfaceA));
}
else {
# Fake things up.
$interfaceA = Interface->MakeFake($pnodeA, $argref);
}
# Must create a real copy, especially for MakeFake();
my $argref = {};
foreach my $key (keys(%{ $interfaceA->{'DBROW'} })) {
$argref->{$key} = $interfaceA->{'DBROW'}->{$key};
}
if (!$pnodeB->isswitch()) {
#
# Create a logical interface. Note we have to force a hash copy.
#
my %argref = %{ $interfaceB->{'DBROW'} };
my $argref = \%argref;
# Update the card and iface.
# XXX Need a better way to allocate the card numbers.
$argref->{'card'} = $interfaceB->card() + 200;
$argref->{'iface'} = "eth" . $argref->{'card'};
$argref->{'logical'} = 1;
$argref->{'uuid'} = undef;
if (!$impotent) {
$interfaceB = Interface->Create($pnodeB, $argref);
return undef
if (!defined($interfaceB));
}
else {
# Fake things up.
$interfaceB = Interface->MakeFake($pnodeB, $argref);
}
# Update the card and iface.
# XXX Need a better way to allocate the card numbers.
$argref->{'card'} = $interfaceA->card() + 200;
$argref->{'iface'} = sprintf("eth%d%03d",
$argref->{'card'}, $argref->{'port'});
$argref->{'logical'} = 1;
$argref->{'uuid'} = undef;
if (!$impotent) {
$interfaceA = Interface->Create($pnodeA, $argref);
return undef
if (!defined($interfaceA));
}
else {
# Fake things up.
$interfaceA = Interface->MakeFake($pnodeA, $argref);
}
# Must create a real copy, especially for MakeFake();
$argref = {};
foreach my $key (keys(%{ $interfaceB->{'DBROW'} })) {
$argref->{$key} = $interfaceB->{'DBROW'}->{$key};
}
# Update the card and iface.
# XXX Need a better way to allocate the card numbers.
$argref->{'card'} = $interfaceB->card() + 200;
$argref->{'iface'} = sprintf("eth%d%03d",
$argref->{'card'}, $argref->{'port'});
$argref->{'logical'} = 1;
$argref->{'uuid'} = undef;
if (!$impotent) {
$interfaceB = Interface->Create($pnodeB, $argref);
return undef
if (!defined($interfaceB));
}
else {
# Fake things up.
$interfaceB = Interface->MakeFake($pnodeB, $argref);
}
#
# For consistency and because we still have an implicit assumption
# the switch is node_id2 in the wires table.
# the node is node_id1 in the wires table.
#
my ($interface1,$interface2) = ($interfaceA, $interfaceB);
my ($pnode1,$pnode2) = ($pnodeA, $pnodeB);
if ($pnodeA->isswitch() && !$pnodeB->isswitch()) {
($interface1,$interface2) = ($interfaceB, $interfaceA);
($pnode1,$pnode2) = ($pnodeB, $pnodeA);
}
# Create a wires table entry, ordered properly.
if (!$impotent) {
......@@ -1504,7 +1509,7 @@ sub Create($$$$$$)
# reflect that. Use the 'Unused' type to indicate it is not
# active.
#
if (!DBQueryWarn("replace into wires set".
if (!DBQueryWarn("insert into wires set".
" type='Unused', logical=1, " .
" node_id1='$node_id1',card1=$card1,port1=$port1, " .
" node_id2='$node_id2',card2=$card2,port2=$port2")) {
......@@ -1519,6 +1524,10 @@ sub Create($$$$$$)
$self->{"interfaceB"} = $interfaceB;
$self->{"interface1"} = $interface1;
$self->{"interface2"} = $interface2;
$self->{"pnodeA"} = $pnodeA;
$self->{"pnodeB"} = $pnodeB;
$self->{"pnode1"} = $pnode1;
$self->{"pnode2"} = $pnode2;
bless($self, $class);
return $self;
......@@ -1532,6 +1541,13 @@ sub ifaceB($) { return $_[0]->interfaceB()->iface(); }
# Wires table ordering.
sub interface1($) { return $_[0]->{'interface1'}; }
sub interface2($) { return $_[0]->{'interface2'}; }
sub iface1($) { return $_[0]->interface1()->iface(); }
sub iface2($) { return $_[0]->interface2()->iface(); }
# Convience
sub pnodeA($) { return $_[0]->{'pnodeA'}; }
sub pnodeB($) { return $_[0]->{'pnodeB'}; }
sub pnode1($) { return $_[0]->{'pnode1'}; }
sub pnode2($) { return $_[0]->{'pnode2'}; }
#
# The wires table is indexed by node_id1,card1,port1 ... return
......
......@@ -24,7 +24,7 @@
# or merely parse tokens from string and vice-verse must
# use the converters provided in this class.
#
# Copyright (c) 2011-2013 University of Utah and the Flux Group.
# Copyright (c) 2011-2013, 2017 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
......@@ -579,7 +579,6 @@ sub LookupByTriple($$;$$)
# XXX: Other cases are unhandled for now...
return undef;
}
$inst->{"WIRES_ROW"} = $rowref;
$query_result =
......@@ -657,7 +656,7 @@ sub LookupByWireType($$)
my $result = DBQueryFatal("SELECT node_id1, card1, port1, " .
"node_id2, card2, port2 FROM wires ".
"WHERE type='$wt' and logical=0");
"WHERE type='$wt'");
if ($result) {
while (my @row = $result->fetchrow()) {
......@@ -679,7 +678,6 @@ sub LookupByWireType($$)
sub field($$) { return (((! ref($_[0])) || ($_[0]->{'HAS_FIELDS'} == 0)) ?
-1 : $_[0]->{'INTERFACES_ROW'}->{$_[1]}); }
sub node_id($) { return field($_[0], 'node_id'); }
sub card($) { return field($_[0], 'card'); }
sub port($) { return field($_[0], 'port'); }
sub iface($) { return field($_[0], 'iface'); }
sub mac($) { return field($_[0], 'mac'); }
......@@ -690,6 +688,7 @@ sub mask($) { return field($_[0], 'mask'); }
sub uuid($) { return field($_[0], 'uuid'); }
sub trunk($) { return field($_[0], 'trunk'); }
sub trunk_mode($) { return field($_[0], 'trunk_mode'); }
sub logical($) { return field($_[0], 'logical'); }
# These two come from the "interface_state" table, which gives the
# current view vs. the "mandated" (mapped) state from the interfaces table.
sub tagged($) { return field($_[0], 'tagged'); }
......@@ -705,6 +704,20 @@ sub is_forced($) { return $_[0]->{"FORCED"};}
sub has_fields($) { return $_[0]->{"HAS_FIELDS"};}
sub raw_string($) { return $_[0]->{"RAW_STRING"};}
#
# When logical, convert the card back from logical number.
#
sub card($)
{
my ($self) = shift;
my $card = field($self, 'card');
if ($self->logical()) {
$card = $card - 200;
}
return $card;
}
sub switch_node_id($)
{
my $self = shift;
......@@ -825,12 +838,17 @@ sub other_end_card($)
return $self->raw_string();
}
}
my $card;
if ($self->node_id() eq $self->{'WIRES_ROW'}->{'node_id1'}) {
return $self->{'WIRES_ROW'}->{'card2'};
$card = $self->{'WIRES_ROW'}->{'card2'};
} else {
return $self->{'WIRES_ROW'}->{'card1'};
$card = $self->{'WIRES_ROW'}->{'card1'};
}
if ($self->logical()) {
$card = $card - 200;
}
return $card;
}
#
......
......@@ -13,6 +13,7 @@ use libtblog;
use libreboot;
use Node;
use Group;
use Lan;
use English;
use IPC::Open3;
use POSIX ":sys_wait_h";
......@@ -496,12 +497,10 @@ sub Reconfigure($$;$)
$self->dprint(2,"Reconfigure($node_id): trying to generate config first");
my @config = $self->generateConfig($nodeobject);
if ($self->debug()) {
foreach my $cl (@config) {
$self->dprint(4,"Reconfigure($node_id): config line: $cl\n");
}
if (!@config) {
tberror "$self Reconfigure($node_id): could not generate config!\n";
return -1;
}
if (!defined($self->_doTiptunnel($nodeobject))) {
tberror "$self Reconfigure($node_id): could not get tiptunnel info!\n";
return -1;
......@@ -1260,6 +1259,8 @@ sub generateConfig($$) {
my @passwdlines = ();
# XXX assume one control net port for now!
my ($cnetport,$cnetip,$cnetmask,$cnetgw);
my $experiment;
my @trunklines = ();
# install boss's root pubkey first!
my $rootpubkey;
......@@ -1271,6 +1272,7 @@ sub generateConfig($$) {
if (defined($nodeobject)) {
my $expt = $nodeobject->Reservation();
if (defined($expt)) {
$experiment = $expt;
my $group = Group->Lookup($expt->pid(),$expt->gid());
my $dopasswds =
......@@ -1338,6 +1340,65 @@ sub generateConfig($$) {
}
};
if (defined($experiment)) {
#
# Grab all the vlans for the experiment and find the trunks between
# switches that include this switch.
#
my $trunkindex = 3;
my @vlans;
if (VLan->ExperimentVLans($experiment, \@vlans) != 0) {
tberror("Could not get list of all vlans for $experiment\n");
return ();
}
foreach my $vlan (@vlans) {
my @members;
next
if ($vlan->type() ne "wire");
next
if ($vlan->GetRole() ne "trunk");
if ($vlan->MemberList(\@members)) {
tberror("Could not get member list of members for $vlan\n");
return ();
}
foreach my $member (@members) {
my ($membnode_id, $membiface);
if ($member->GetNodeIface(\$membnode_id, \$membiface)) {
tberror("Could not get node/iface for $member\n");
return ();
}
next
if ($membnode_id->node_id() ne $node_id);
my $interface = Interface->LookupByIface($nodeobject, $membiface);
if (!defined($interface)) {
tberror("Could not lookup interface for $member\n");
return ();
}
my $card = $interface->card();
my $port = $interface->port();
my @alpha = ("","A","B","C","D","E","F","G","H","I",
"J","K","L","M","N","O");
my $portname = $alpha[$card] . $port;
#
# A trunk has to be in at least one vlan in tagged mode, for
# snmpit to think it is a trunk.
#
push @trunklines, "trunk $portname trk${trunkindex} lacp";
push @trunklines, "vlan $trunkindex";
push @trunklines, " tagged Trk${trunkindex}";
push @trunklines, " exit";
push @trunklines, "vlan 1";
push @trunklines, " no untagged Trk${trunkindex}";
push @trunklines, " exit";
$trunkindex++;
}
}
}
my @cnetlines = ();
#
# We *HAVE* to remove anything that might have snuck into vlan 1
......@@ -1402,6 +1463,7 @@ sub generateConfig($$) {
my @config = (
"hostname \"" . $node_id . "\"",
@cnetlines,
@trunklines,
# this prompts; must handle manually!
#"include-credentials",
"aaa authentication ssh login public-key",
......@@ -1422,6 +1484,11 @@ sub generateConfig($$) {
"no banner motd",
);
if ($self->debug()) {
foreach my $cl (@config) {
$self->dprint(4,"Reconfigure($node_id): config line: $cl\n");
}
}
return @config;
}
......
This diff is collapsed.
# -*- tcl -*-
#
# Copyright (c) 2000-2013 University of Utah and the Flux Group.
# Copyright (c) 2000-2017 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
......@@ -426,6 +426,21 @@ Link instproc implemented_by {impl} {
}
}
#
# A lan can be implemented in terms of a path only.
#
Lan instproc implemented_by {impl} {
$self instvar implemented_by
$self instvar layer
if {[$impl info class] == "Path"} {
set implemented_by $impl
} else {
perror "\[$self implemented_by] must be a path!"
return
}
}
Lan instproc trace_snaplen {len} {
$self instvar nodelist
$self instvar linkq
......@@ -1248,6 +1263,7 @@ Lan instproc updatedb {DB} {
$self instvar member_settings
$self instvar mustdelay
$self instvar fixed_iface
$self instvar implemented_by
$self instvar ofenabled
$self instvar ofcontroller
$self instvar bridge_links
......@@ -1366,6 +1382,9 @@ Lan instproc updatedb {DB} {
lappend fields "fixed_iface"
}
if { $implemented_by != {} } {
lappend fields "implemented_by_path"
}
# IP aliases
set ipaliases [$node get_ipaliases_port $port]
if {[llength $ipaliases] > 0} {
......@@ -1396,7 +1415,9 @@ Lan instproc updatedb {DB} {
if {$fixed_iface($nodeport) != 0} {
lappend values $fixed_iface($nodeport)
}
if { $implemented_by != {} } {
lappend values $implemented_by
}
# IP aliases
if {[llength $ipaliases] > 0} {
set ipaliasesraw [join $ipaliases ","]
......
#!/usr/bin/perl -w
#
# Copyright (c) 2000-2016 University of Utah and the Flux Group.
# Copyright (c) 2000-2017 University of Utah and the Flux Group.
#
# {{{EMULAB-LGPL
#
......@@ -2171,7 +2171,7 @@ sub CreateOneVlan($$$@)
$errors++;
}
else {
if ($wire->Activate() != 0) {
if ($wire->Activate($vlan) != 0) {
print STDERR "Could not activate $wire for $vlan\n";
$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