Commit 92bb918a authored by Robert Ricci's avatar Robert Ricci

Patch from Keith Slower @ Berkeley:

"I implemented and tested extensions to snmpit & friends so that an
elabinelab could additional request that an experimental interface be
placed in trunked mode, to discover the vlan tags associated with
vlans, and to request modifications to existing vlans belonging to an
elabinelab without tearing it down and reconstructing it."
parent 38800b60
......@@ -90,6 +90,7 @@ VLAN Control:
-l List all VLANs
-w Used with -l, includes device-specific VLAN number
-M Used with -l, print MAC addresses instead of port numbers
-L <out#in[,o2#i2,...]> stylized -l for snmpit.proxy of specific vlans
-m <name> [ports] Create a new VLAN with name <name>, if it doesn't exist,
and put [ports] in it
-y <type> When used with -m, the new VLAN becomes a private VLAN
......@@ -133,7 +134,7 @@ my %opt = ();
Getopt::Long::Configure("no_ignore_case");
GetOptions(\%opt, 'a','c','d','e','b','B=s@','g','h','i=s@','l','m=s@','M','n',
'N=s@','o=s@','p=s','q','r','s', 'S=s@','t','E=s','T=s','u=s','U','v=s','w',
'y=s','x=s','z=s','F');
'y=s','x=s','z=s','F','L=s');
# Unused: f,j
if ($opt{h}) {
......@@ -220,6 +221,7 @@ my @commands;
# Simple commands
#
if ($opt{l}) { push @commands, ["listvlans"]; }
if ($opt{L}) { push @commands, ["listvlans"]; }
if ($opt{s}) { push @commands, ["listports"]; }
if ($opt{g}) { push @commands, ["getstats"]; }
if ($opt{t}) { push @commands, ["tables"]; }
......@@ -764,22 +766,51 @@ sub parseStatusString($) {
sub doListVlans ($) {
my $stacks = shift;
my %vlans;
my @vlanList;
#
# We need to 'coallate' the results from each stack by putting together
# the results from each stack, based on the VLAN identifier
#
if ($ELABINELAB) {
#
# Sklower deliberately uglified this. The intent is that eventually
# $stack->listVlans() will call a $<remotedevobj>->listVlans() and
# it will just work. For now, we dup the code.
#
@vlanList = RemoteDoList();
foreach my $vlan (@vlanList) {
my ($id,$ddep,$memberref) = @$vlan;
${$vlans{$id}}[0] = $ddep;
push @{${$vlans{$id}}[1]}, @$memberref;
}
} else {
foreach my $stack (@$stacks) {
my @vlanList = $stack->listVlans();
@vlanList = $stack->listVlans();
foreach my $vlan (@vlanList) {
my ($id,$ddep,$memberref) = @$vlan;
${$vlans{$id}}[0] = $ddep;
push @{${$vlans{$id}}[1]}, @$memberref;
}
}
}
#
# less code to do this for snmpit.proxy than for it to popen snmpit
# parse the output, and glue it back together.
#
if ($opt{L}) {
my @results;
foreach my $pair (split ',', $opt{L}) {
my ($out,$in) = split "#", $pair;
my $vlan = "$in#" . ${$vlans{$out}}[0] . "#" .
join(' ', @{${$vlans{$out}}[1]});
push @results, $vlan;
}
print join(',', @results);
exit(0);
}
#
# These need to be declared here for the benefit of the format string
# See perlform(1) for help with formats
......@@ -1165,13 +1196,6 @@ sub doVlansFromTables($@) {
}
my ($stack) = @$stacks;
#
# Hand over to outer boss.
#
if ($ELABINELAB) {
return RemoteDoVlansFromTables(@vlans);
}
#
# Sanity check: make sure that this experiment does not use more VLANs than
# we can put on the stack. Note that we don't try to check how many are
......@@ -1204,6 +1228,13 @@ sub doVlansFromTables($@) {
}
$equaltrunking = $oEopt;
#
# Hand over to outer boss.
#
if ($ELABINELAB) {
return RemoteDoVlansFromTables(@vlans);
}
foreach my $vlan (@vlans) {
my @ports = getVlanPorts($vlan);
if ($stack->vlanExists($vlan)) {
......@@ -1529,6 +1560,11 @@ sub doTrunkEnable($$@) {
my $port = shift;
my @vlans = @_;
if ($ELABINELAB) {
my $mode = $equaltrunking ? "-E" : "-T";
return RemoteDoTrunking($mode,$port,@vlans);
}
#
# Sanity checking
#
......@@ -1553,6 +1589,10 @@ sub doTrunkDisable($$) {
my $stacks = shift;
my $port = shift;
if ($ELABINELAB) {
my @vlans=();
return RemoteDoTrunking("-U",$port,@vlans);
}
#
# Sanity checking
#
......
This diff is collapsed.
This diff is collapsed.
......@@ -12,7 +12,8 @@ package snmpit_remote;
use Exporter;
@ISA = ("Exporter");
@EXPORT = qw( RemoteDoVlansFromTables RemoteDoReset );
@EXPORT = qw( RemoteDoVlansFromTables RemoteDoReset
RemoteDoTrunking RemoteDoList);
# Must come after package declaration!
use lib '@prefix@/lib';
......@@ -48,6 +49,33 @@ sub ConfigXMLRPC()
$didsetup = 1;
return 0;
}
#
# All of these routines end in exactly the same way
# differing only in what the "op", and "arg" value of the hashes are.
#
sub commonTail($$)
{
my $op = shift();
my $arg = shift();
ConfigXMLRPC();
# sklower is temporarily going to way violate layering
# and reach down into the internals of libxmlrpc to
# grab the returned output string, until he can figure out
# the proper python for returning a blob.
my $response = libxmlrpc::CallMethod0("elabinelab", "vlans",
{"op" => $op, "arg" => $arg});
if (($config{"verbose"} || $response->{"code"}) &&
defined($response->{"output"}) && $response->{"output"} ne "") {
print $response->{"output"};
}
return ($response->{"code"}) ? undef : $response->{"output"};
}
#
# Ask outer boss to setup a bunch of vlans for an experiment.
......@@ -60,6 +88,9 @@ sub RemoteDoVlansFromTables(@)
return 0
if (! @vlans);
my $prefix = "" ;
TBGetSiteVar("federation/localprefix",\$prefix);
my $result =
DBQueryFatal("select virtual,members,id from vlans where " .
# Join "id='foo'" with ORs
......@@ -93,6 +124,10 @@ sub RemoteDoVlansFromTables(@)
}
my ($speed,$duplex) = $result->fetchrow();
if ($prefix ne "") {
$port =~ s/$prefix// ;
}
$vlantable->{$id}->{"members"}->{$port} = {};
$vlantable->{$id}->{"members"}->{$port}->{"speed"} = $speed;
$vlantable->{$id}->{"members"}->{$port}->{"duplex"} = $duplex;
......@@ -101,15 +136,22 @@ sub RemoteDoVlansFromTables(@)
return 0
if (! keys(%$vlantable));
ConfigXMLRPC();
my $rval = libxmlrpc::CallMethod("elabinelab", "vlans",
{"op" => "setup",
"arg" => $vlantable});
if (!defined($rval)) {
return -1;
}
return $rval;
my $errors = 0;
my $xmlback = commonTail("setup",$vlantable);
if (defined($xmlback)) {
foreach my $vlres (split ',', $xmlback) {
my ($name, $num) = split '#', $vlres;
$result =
DBQuery("update vlans set tag=$num where id='" . $name . "'");
if (!defined($result)) {
print STDERR "couldn't set vlan tag from returned vlan map " .
"for vlan $name\n";
$errors++;
}
}
} else { $errors = 1; }
return $errors;
}
#
......@@ -121,18 +163,75 @@ sub RemoteDoReset(@)
return 0
if (! @vlans);
my $res = commonTail("destroy", join(",", @vlans));
return !defined($res);
}
#
# Ask outer boss to set a port into trunk mode (snmpit -T or -E )
# 1st arg (mode) is "-T" (dual), "-E" (regular i.e. normal or equal)
# or "-U" to reset to the usual un-trunked mode.
#
sub RemoteDoTrunking($$@)
{
my $arg = {};
$arg->{"mode"} = shift();
my $port = shift();
my @vlans = @_;
$arg->{"vlans"} = @vlans ? join(",", @vlans) : "";
ConfigXMLRPC();
my $prefix = "" ;
TBGetSiteVar("federation/localprefix",\$prefix);
if ($prefix ne "") {
$port =~ s/$prefix// ;
}
$arg->{"port"} = $port;
my $res = commonTail("trunk", $arg);
return !defined($res);
}
#
# Ask outer boss to send the vlan names , numbers , and members
# snmpit -l -w (or restrict to a specific list of vlans)
# Result is returned in the format as if it were from a switch module.
#
sub RemoteDoList(@)
{
my @vlans = @_;
my %Names = ();
my %Members = ();
my @list = ();
my $arg = @vlans ? join(",", @vlans) : "";
my $xmlback = commonTail("list",$arg);
if (!defined($xmlback)) { return @list; }
my $prefix = "" ;
TBGetSiteVar("federation/localprefix",\$prefix);
#
# Walk the table for the VLAN members
#
foreach my $vlres (split ',', $xmlback) {
my ($name, $num, $mems) = split '#', $vlres;
$Names{$num} = $name;
@{$Members{$num}} = ();
foreach my $mem (split " ", $mems) {
push @{$Members{$num}}, $prefix . $mem;
}
}
my $rval = libxmlrpc::CallMethod("elabinelab", "vlans",
{"op" => "destroy",
"arg" => join(",", @vlans)});
if (!defined($rval)) {
return -1;
#
# Build a list from the name and membership lists
#
foreach my $vlan_id (sort keys %Names) {
if ($vlan_id != 1) {
push @list, [$Names{$vlan_id},$vlan_id,$Members{$vlan_id}];
}
}
return $rval;
return @list;
}
# End with true
1;
......@@ -380,9 +380,9 @@ class emulab:
if starting and ending:
comparison = "BETWEEN %s and %s"
sub = (starting, ending)
pass
elif starting:
comparison = "> %s"
pass
sub = (starting,)
pass
elif ending:
......@@ -4212,9 +4212,11 @@ class elabinelab:
return verifyerror
if (argdict["op"] != "setup" and
argdict["op"] != "list" and
argdict["op"] != "trunk" and
argdict["op"] != "destroy"):
return EmulabResponse(RESPONSE_BADARGS,
output="op must be setup or destroy")
output="op must be list, trunk, setup or destroy")
argstr = "-p " + self.pid + " -e " + self.eid + " " + argdict["op"];
......@@ -4222,10 +4224,10 @@ class elabinelab:
# Figure out how to convert the stuff we got into something we can
# pass on the command line to perl backend.
#
if argdict["op"] == "destroy":
if argdict["op"] == "destroy" or argdict["op"] == "list":
#
# Destroy is easy; just pass a list of id numbers out. The backend
# script does all the verification.
# Destroy and list are easy; just pass a list of id numbers out.
# The backend script does all the verification.
#
if (isinstance(argdict["arg"], types.IntType)):
argstr += " " + str(argdict["arg"])
......@@ -4237,6 +4239,17 @@ class elabinelab:
pass
pass
pass
elif argdict["op"] == "trunk":
#
# Trunk is syntactically like destroy or list with two extra args.
#
info = argdict["arg"]
argstr += " " + str(info["mode"]) + " " + str(info["port"])
tokens = info["vlans"].split(",")
for token in tokens:
argstr += " " + escapeshellarg(token)
pass
pass
else:
#
# Setup is harder. Pass a set of strings to the script,
......
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