Commit 2e34180f authored by Robert Ricci's avatar Robert Ricci

Merge branch 'ofbranch'

parents 48918911 568e138f
......@@ -50,12 +50,19 @@ sub doTrunkDisable($$);
sub doRestorePortStatus($@);
sub doSynchLeader($);
sub CreateOneVlan($$@);
sub doOpenflowEnable($$);
sub doOpenflowDisable($$);
sub doSetOpenflowController($$$);
sub doSetOpenflowListener($$$);
sub doEnableOpenflowListener($$);
#
# Defaults
#
my $debug = 0;
my $quiet = 0;
my $minOpenflowListenerPort = 5000;
my $maxOpenflowListenerPort = 65535;
######################################################################
# Step 1 - Process command-line arguments
......@@ -78,6 +85,10 @@ Usage: $0 [-h] [-v level] [-q] [-n] [-i device] [-S stack]
[-d ports] [-e ports] [-a ports]
[-p <10|100|1000> ports] [-u <half|full> ports]
[-c]
[--of-disable name pid eid]
[--of-enable name pid eid]
[--of-controller name pid eid tcp:ip:port]
[--of-listener name pid eid]
General:
-h Display this help message
-v <level> Verbose mode
......@@ -116,6 +127,21 @@ VLAN Control:
WITH EXTREME CAUTION **
-F Create all vlans in the given stack on the leader for
use in leader->{ALLVLANSONLEADER} (Internal use only)
--of-enable <name> <pid> <eid>
Enable Openflow on VLAN with the name <name> that is
associated with the given experiment
--of-disable <name> <pid> <eid>
Disable Openflow on VLAN with the name <name> that is
associated with the given experiment
--of-controller <name> <pid> <eid> tcp:ip:port
Set controller for Openflow-enabled VLAN with the
name <name> that is associated with the given
experiment
--of-listener <name> <pid> <eid>
Enable listener for Openflow-enabled VLAN with the
name <name> that is associated with the given
experiment, snmpit will print out the listener
connection string
Port Control:
-s List all ports, and show configuration information
......@@ -142,13 +168,13 @@ END
return 1;
}
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','L=s','O', 'D', 'R', 'f', 'X', 'vlan_tag=i');
'y=s','x=s','z=s','F','L=s','O', 'D', 'R', 'f', 'X', 'vlan_tag=i',
'of-disable=s', 'of-enable=s', 'of-controller=s', 'of-listener=s');
# Unused: f,j
if ($opt{h}) {
......@@ -163,14 +189,16 @@ if ($opt{v}) {
if ($opt{q}) {
$quiet = 1;
if ($opt{m} || $opt{o} || $opt{t} || $opt{r} || $opt{X} || $opt{T} ||
$opt{E} || $opt{U} || $opt{u} || $opt{d} || $opt{p} || $opt{e}) {
$opt{E} || $opt{U} || $opt{u} || $opt{d} || $opt{p} || $opt{e} ||
$opt{'of-enable'} || $opt{'of-disable'} || $opt{'of-controller'} ||
$opt{'of-listener'}) {
my $nulldev;
open($nulldev, ">>/dev/null");
select $nulldev; # supresses print foo(); without explicit fileglob
}
}
#
#if ($opt{F}) { push @commands, ["synchleader"]; }
# Values that may have been passed on the command line
#
my $pid;
......@@ -180,6 +208,7 @@ my @ports;
my @optvlanids = ();
my $equaltrunking = 0;
my $this_user;
my $ofconnstr; # Openflow connection string, for controller
our $next_vlan_tag; # XXX see doMakeVlan for explanation
#
......@@ -245,6 +274,32 @@ if ($opt{t} || $opt{r} || $opt{D} || $opt{R} || $opt{X}) {
# Set the @ports array so that we'll do proper permission checking on it
#
@ports = ($opt{T});
} elsif ($opt{'of-controller'}) {
#
# Options that take the pid eid and connection string
#
if (@ARGV < 2) {
tberror "pid/eid reqired!";
exit &usage;
} else {
($pid, $eid) = (shift @ARGV, shift @ARGV);
}
if (@ARGV < 0) {
tberror "Controller connection string reqired!";
exit &usage;
} else {
$ofconnstr = shift @ARGV;
}
} elsif ($opt{'of-enable'} || $opt{'of-disable'} || $opt{'of-listener'}) {
#
# Options that need pid eid
#
if (@ARGV < 1) {
tberror "pid/eid reqired!";
exit &usage;
} else {
($pid, $eid) = (shift @ARGV, shift @ARGV);
}
} else {
#
# Everything else
......@@ -288,6 +343,10 @@ if ($opt{a}) { push @commands, ["portcontrol","auto"]; }
if ($opt{D}) { push @commands, ["expcnetcontrol", "disable"]; }
if ($opt{R}) { push @commands, ["expcnetcontrol", "enable"]; }
if ($opt{T}) { push @commands, ["trunkenable", $opt{T}]; }
if ($opt{'of-enable'}) { push @commands, ["ofenable", $opt{'of-enable'}]; }
if ($opt{'of-disable'}) { push @commands, ["ofdisable", $opt{'of-disable'}]; }
if ($opt{'of-controller'}) { push @commands, ["ofcontroller", $opt{'of-controller'}]; }
if ($opt{'of-listener'}) { push @commands, ["oflistener", $opt{'of-listener'}]; }
#
# Commands that can occur more than once
......@@ -719,6 +778,25 @@ COMMAND: foreach my $command (@commands) {
@args = %args;
last;
};
(/ofenable/ || /ofdisable/ || /ofcontroller/ || /oflistener/) && do {
@vlans = @args;
# Same to 'remove', we find stacks by VLAN
my ($vlanobj, $stack);
if ($supplied_switches) {
debug("Openflow operations: using supplied switches\n");
@devicenames = @supplied_switches;
} elsif (defined($experiment) &&
defined($vlanobj = VLan->Lookup($experiment,$vlans[0])) &&
defined($stack = $vlanobj->GetStack())) {
debug("Openflow operations: found stack $stack in database\n");
@devicenames = getSwitchesInStack($stack);
} else {
debug("Openflow operations: using test switches\n");
@devicenames = getTestSwitches();
}
last;
};
}
debug("Device names: " . join(",",@devicenames) . "\n");
......@@ -767,7 +845,8 @@ COMMAND: foreach my $command (@commands) {
SWITCH: for ($stack_type) {
(/cisco/ || /catalyst/) && do {
require snmpit_cisco_stack;
$stack = new snmpit_cisco_stack($stack_id,$debug,$single_domain, @{$stacks{$stack_id}});
$stack = new snmpit_cisco_stack($stack_id,$debug,$single_domain,
@{$stacks{$stack_id}});
last;
}; # /cisco/
/intel/ && do {
......@@ -915,6 +994,22 @@ COMMAND: foreach my $command (@commands) {
$exitval += doRestorePortStatus(\@stacks,@args);
last;
}; # /portstatus/ && do
(/ofenable/) && do {
$exitval += doOpenflowEnable(\@stacks,$vlans[0]);
last;
}; # /ofenable/ && do
(/ofdisable/) && do {
$exitval += doOpenflowDisable(\@stacks,$vlans[0]);
last;
}; # /ofdisable/ && do
(/ofcontroller/) && do {
$exitval += doSetOpenflowController(\@stacks,$vlans[0],$ofconnstr);
last;
}; # /ofcontroller/ && do
(/oflistener/) && do {
$exitval += doEnableOpenflowListener(\@stacks,$vlans[0]);
last;
}; # /oflistener/ && do
}
}
......@@ -2414,3 +2509,185 @@ sub doTrunkDisable($$) {
if (!$errors);
return $errors;
}
#
# Openflow lock and functions
#
use libtestbed;
my $of_lock_held = 0;
sub oflock() {
my $token = "of_snmpit";
my $old_umask = umask(0);
die if (TBScriptLock($token,0,1800) != TBSCRIPTLOCK_OKAY());
umask($old_umask);
$of_lock_held = 1;
}
sub ofunlock() {
if ($of_lock_held) { TBScriptUnlock(); $of_lock_held = 0;}
}
#
# doOpenflowEnable(stacks, vlan)
# Enable Openflow on a VLAN
#
sub doOpenflowEnable($$) {
my $stacks = shift;
my $vlan = shift;
my $errors = 0;
#
# Enabling Openflow on each stack
#
print "Enabling Openflow on VLAN $vlan ...\n"
if (!$quiet);
foreach my $stack (@$stacks) {
$errors += $stack->enableOpenflow($vlan);
}
if (!$errors) {
print "Done! \n" if (!$quiet);
}
return $errors;
}
#
# doOpenflowDisable(stack, vlan)
# Disable Openflow on a VLAN
#
sub doOpenflowDisable($$) {
my $stacks = shift;
my $vlan = shift;
my $errors = 0;
#
# Disabling Openflow on each stack
#
print "Disabling Openflow on VLAN $vlan ...\n"
if (!$quiet);
foreach my $stack (@$stacks) {
$errors += $stack->disableOpenflow($vlan);
}
#
# TODO:clear controllers/listeners here. Now in HP stack code.
#
if (!$errors) {
print "Done! \n" if (!$quiet);
}
return $errors;
}
#
# doSetOpenflowController(stack, vlan, controller)
# Set controller for an Openflow-enabled VLAN
#
sub doSetOpenflowController($$$) {
my $stacks = shift;
my $vlan = shift;
my $controller = shift;
my $errors = 0;
#
# Set controller on each stack
#
print "Set controller for VLAN $vlan ...\n"
if (!$quiet);
foreach my $stack (@$stacks) {
$errors += $stack->setOpenflowController($vlan, $controller);
}
if (!$errors) {
print "Done! \n" if (!$quiet);
}
return $errors;
}
#
# doSetOpenflowListener(stack, vlan, listener)
# Set listener for an Openflow-enabled VLAN
#
sub doSetOpenflowListener($$$) {
my $stacks = shift;
my $vlan = shift;
my $listener = shift;
my $errors = 0;
#
# Set controller on each stack
#
print "Set listener for VLAN $vlan ...\n"
if (!$quiet);
foreach my $stack (@$stacks) {
$errors += $stack->setOpenflowListener($vlan, $listener);
}
if (!$errors) {
print "Done! \n" if (!$quiet);
}
return $errors;
}
#
# doEnableOpenflowListener(stacks, vlan)
# enable openflow listener on the given VLAN
# this function prints out the connection string of the listener
#
sub doEnableOpenflowListener($$) {
my $stacks = shift;
my $vlan = shift;
my %usedports = ();
my $port = $minOpenflowListenerPort;
my $errors = 0;
my $set_ok = 0;
my $listenerConnStr;
#
# get used ports
#
# Here a big lock is better than many small locks, it avoids dead locks
# because multiple small locks have to be held one by one, which
# brings the risk of dead lock.
#
oflock();
foreach my $stack (@$stacks) {
my %tmports = $stack->getUsedOpenflowListenerPorts($vlan);
@usedports{ keys %tmports } = values %tmports;
}
# get the available port
while (defined($usedports{$port}) && $port <= $maxOpenflowListenerPort) {
$port++;
}
if ($port > $maxOpenflowListenerPort) {
print "ERROR: No port available for Openflow listener on VLAN $vlan. \n";
$errors++;
} else {
#
# set listener
#
$listenerConnStr = "ptcp:".$port;
my $err = doSetOpenflowListener($stacks, $vlan, $listenerConnStr);
if ($err == 0 && $set_ok == 0) {
$set_ok = 1;
}
}
if ($set_ok) {
print "Openflow listener connection string for VLAN $vlan is $listenerConnStr \n";
}
ofunlock();
return $errors;
}
......@@ -2263,5 +2263,89 @@ sub unlock($) {
$lock_held = 0;
}
#
# Enable Openflow
#
sub enableOpenflow($$) {
my $self = shift;
my $vlan = shift;
my $RetVal;
#
# Cisco switch doesn't support Openflow yet.
#
warn "ERROR: Cisco swith doesn't support Openflow now";
return 0;
}
#
# Disable Openflow
#
sub disableOpenflow($$) {
my $self = shift;
my $vlan = shift;
my $RetVal;
#
# Cisco switch doesn't support Openflow yet.
#
warn "ERROR: Cisco swith doesn't support Openflow now";
return 0;
}
#
# Set controller
#
sub setOpenflowController($$$) {
my $self = shift;
my $vlan = shift;
my $controller = shift;
my $RetVal;
#
# Cisco switch doesn't support Openflow yet.
#
warn "ERROR: Cisco swith doesn't support Openflow now";
return 0;
}
#
# Set listener
#
sub setOpenflowListener($$$) {
my $self = shift;
my $vlan = shift;
my $listener = shift;
my $RetVal;
#
# Cisco switch doesn't support Openflow yet.
#
warn "ERROR: Cisco swith doesn't support Openflow now";
return 0;
}
#
# Get used listener ports
#
sub getUsedOpenflowListenerPorts($) {
my $self = shift;
my %ports = ();
warn "ERROR: Cisco swith doesn't support Openflow now\n";
return %ports;
}
#
# Check if Openflow is supported on this switch
#
sub isOpenflowSupported($) {
#
# Cisco switch doesn't support Openflow yet.
#
return 0;
}
# End with true
1;
......@@ -1044,5 +1044,217 @@ sub switchesWithPortsInVlan($$) {
return @switches;
}
#
# Openflow enable function for Cisco stack
# Till now it just report an error.
#
# enableOpenflow(self, vlan_id)
# return # of errors
#
sub enableOpenflow($$) {
my $self = shift;
my $vlan_id = shift;
my $errors = 0;
foreach my $devicename (keys %{$self->{DEVICES}})
{
my $device = $self->{DEVICES}{$devicename};
my $vlan_number = $device->findVlan($vlan_id, 2);
if (!$vlan_number) {
#
# Not sure if this is an error or not.
# It might be possible that not all devices in a stack have the given VLAN.
#
print "$device has no VLAN $vlan_id, ignore it. \n" if $self->{DEBUG};
} else {
if ($device->isOpenflowSupported()) {
print "Enabling Openflow on $devicename for VLAN $vlan_id".
"..." if $self->{DEBUG};
my $ok = $device->enableOpenflow($vlan_number);
if (!$ok) { $errors++; }
else {print "Done! \n" if $self->{DEBUG};}
} else {
#
# TODO: Should this be an error?
#
warn "ERROR: Openflow is not supported on $devicename \n";
$errors++;
}
}
}
return $errors;
}
#
# Disable Openflow
#
# disableOpenflow(self, vlan_id);
# return # of errors
#
sub disableOpenflow($$) {
my $self = shift;
my $vlan_id = shift;
my $errors = 0;
foreach my $devicename (keys %{$self->{DEVICES}})
{
my $device = $self->{DEVICES}{$devicename};
my $vlan_number = $device->findVlan($vlan_id, 2);
if (!$vlan_number) {
#
# Not sure if this is an error or not.
# It might be possible that not all devices in a stack have the given VLAN.
#
print "$device has no VLAN $vlan_id, ignore it. \n" if $self->{DEBUG};
} else {
if ($device->isOpenflowSupported()) {
print "Disabling Openflow on $devicename for VLAN $vlan_id".
"..." if $self->{DEBUG};
my $ok = $device->disableOpenflow($vlan_number);
if (!$ok) { $errors++; }
else {print "Done! \n" if $self->{DEBUG};}
} else {
#
# TODO: Should this be an error?
#
warn "ERROR: Openflow is not supported on $devicename \n";
$errors++;
}
}
}
return $errors;
}
#
# Set Openflow controller on VLAN
#
# setController(self, vlan_id, controller);
# return # of errors
#
sub setOpenflowController($$$) {
my $self = shift;
my $vlan_id = shift;
my $controller = shift;
my $errors = 0;
foreach my $devicename (keys %{$self->{DEVICES}})
{
my $device = $self->{DEVICES}{$devicename};
my $vlan_number = $device->findVlan($vlan_id, 2);
if (!$vlan_number) {
#
# Not sure if this is an error or not.
# It might be possible that not all devices in a stack have the given VLAN.
#
print "$device has no VLAN $vlan_id, ignore it. \n" if $self->{DEBUG};
} else {
if ($device->isOpenflowSupported()) {
print "Setting Openflow controller on $devicename for VLAN $vlan_id".
"..." if $self->{DEBUG};
my $ok = $device->setOpenflowController($vlan_number, $controller);
if (!$ok) { $errors++; }
else {print "Done! \n" if $self->{DEBUG};}
} else {
#
# TODO: Should this be an error?
#
warn "ERROR: Openflow is not supported on $devicename \n";
$errors++;
}
}
}
return $errors;
}
#
# Set Openflow listener on VLAN
#
# setListener(self, vlan_id, listener);
# return # of errors
#
# This function might be replaced by a enableListener(vlan_id)
# that sets the listener on switches automatically and returns
# the listener connection string.
#
sub setOpenflowListener($$$) {
my $self = shift;
my $vlan_id = shift;
my $listener = shift;
my $errors = 0;
foreach my $devicename (keys %{$self->{DEVICES}})
{
my $device = $self->{DEVICES}{$devicename};
my $vlan_number = $device->findVlan($vlan_id, 2);
if (!$vlan_number) {
#
# Not sure if this is an error or not.
# It might be possible that not all devices in a stack have the given VLAN.
#
print "$device has no VLAN $vlan_id, ignore it. \n" if $self->{DEBUG};
} else {
if ($device->isOpenflowSupported()) {
print "Setting Openflow listener on $devicename for VLAN $vlan_id".
"..." if $self->{DEBUG};
my $ok = $device->setOpenflowListener($vlan_number, $listener);
if (!$ok) { $errors++; }
else {print "Done! \n" if $self->{DEBUG};}
} else {
#
# TODO: Should this be an error?
#
warn "ERROR: Openflow is not supported on $devicename \n";
$errors++;
}
}