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 eb4691d2 authored by Robert Ricci's avatar Robert Ricci

Add support for Cisco stacks that do not use VTP to maintain a single

VLAN domain. This means that we have to create and delete VLANs on
all switches, instead of just the 'leader'. This behavior is
controlled through the new single_domain column in the
switch_stack_types table.
parent 60563956
......@@ -894,6 +894,7 @@ CREATE TABLE switch_stack_types (
stack_id varchar(10) NOT NULL default '',
stack_type varchar(10) default NULL,
supports_private tinyint(1) NOT NULL default '0',
single_domain tinyint(1) NOT NULL default '1',
PRIMARY KEY (stack_id)
) TYPE=MyISAM;
......
......@@ -407,7 +407,8 @@ foreach my $command (@commands) {
#
my @stacks;
foreach my $stack_id (keys %stacks) {
my ($stack_type, $supports_private) = getStackType($stack_id);
my ($stack_type, $supports_private, $single_domain)
= getStackType($stack_id);
#
# Safety check - make sure the stack supports private VLANs if -y was
# given
......@@ -421,7 +422,7 @@ foreach my $command (@commands) {
/cisco/ && do {
require snmpit_cisco_stack;
$stack = new snmpit_cisco_stack($stack_id,$debug,$COMMUNITY,
$supports_private, @{$stacks{$stack_id}});
$supports_private, $single_domain, @{$stacks{$stack_id}});
last;
}; # /cisco/
/intel/ && do {
......
......@@ -532,10 +532,11 @@ sub findVlan($$;$) {
#
# Create a VLAN on this switch, with the given identifier (which comes from
# the database.) Picks its own switch-specific VLAN number to use.
# the database.) If $vlan_number is given, attempts to use it when creating
# the vlan - otherwise, picks its own Cisco-specific VLAN number.
#
# usage: createVlan($self, $vlan_id [,$private_type [,$private_primary,
# $private_port]])
# usage: createVlan($self, $vlan_id, $vlan_number, [,$private_type
# [,$private_primary, $private_port]])
# returns the new VLAN number on success
# returns 0 on failure
# if $private_type is given, creates a private VLAN - if private_type
......@@ -545,6 +546,7 @@ sub findVlan($$;$) {
sub createVlan($$;$$$) {
my $self = shift;
my $vlan_id = shift;
my $vlan_number = shift;
my ($private_type,$private_primary,$private_port);
if (@_) {
......@@ -565,6 +567,16 @@ sub createVlan($$;$$$) {
my $VlanSAID = 'vtpVlanEditDot10Said'; # vlan # is index
my $VlanRowStatus = 'vtpVlanEditRowStatus'; # vlan # is index
#
# If they gave a VLAN number, make sure it exists
#
if ($vlan_number) {
if ($self->vlanNumberExists($vlan_number)) {
print STDERR "ERROR: VLAN $vlan_number already exists\n";
return 0;
}
}
#
# We may have to do this multiple times - a few times, we've had the
# Cisco give no errors, but fail to actually create the VLAN. So, we'll
......@@ -573,7 +585,6 @@ sub createVlan($$;$$$) {
#
my $max_tries = 3;
my $tries_remaining = $max_tries;
my $vlan_number;
while ($tries_remaining) {
#
# Try to wait out transient failures
......@@ -589,27 +600,29 @@ sub createVlan($$;$$$) {
next;
}
#
# Find a free VLAN number to use. Since 1 is the default VLAN on
# Ciscos, we start with number 2.
# XXX: The maximum VLAN number is hardcoded at 1000
#
$vlan_number = 2; # We need to start at 2
my $RetVal = snmpitGetFatal($self->{SESS},
[$VlanRowStatus,"1.$vlan_number"]);
$self->debug("Row $vlan_number got '$RetVal'\n",2);
while (($RetVal ne 'NOSUCHINSTANCE') && ($vlan_number <= 1000)) {
$vlan_number += 1;
$RetVal = snmpitGetFatal($self->{SESS},
[$VlanRowStatus,"1.$vlan_number"]);
$self->debug("Row $vlan_number got '$RetVal'\n",2);
}
if ($vlan_number > 1000) {
if (!$vlan_number) {
#
# We must have failed to find one
# Find a free VLAN number to use. Since 1 is the default VLAN on
# Ciscos, we start with number 2.
# XXX: The maximum VLAN number is hardcoded at 1000
#
print STDERR "ERROR: Failed to find a free VLAN number\n";
next;
$vlan_number = 2; # We need to start at 2
my $RetVal = snmpitGetFatal($self->{SESS},
[$VlanRowStatus,"1.$vlan_number"]);
$self->debug("Row $vlan_number got '$RetVal'\n",2);
while (($RetVal ne 'NOSUCHINSTANCE') && ($vlan_number <= 1000)) {
$vlan_number += 1;
$RetVal = snmpitGetFatal($self->{SESS},
[$VlanRowStatus,"1.$vlan_number"]);
$self->debug("Row $vlan_number got '$RetVal'\n",2);
}
if ($vlan_number > 1000) {
#
# We must have failed to find one
#
print STDERR "ERROR: Failed to find a free VLAN number\n";
next;
}
}
$self->debug("Using Row $vlan_number\n");
......@@ -626,7 +639,7 @@ sub createVlan($$;$$$) {
# Perform the actual creation. Yes, this next line MUST happen all in
# one set command....
#
$RetVal = $self->{SESS}->set([[$VlanRowStatus,"1.$vlan_number",
my $RetVal = $self->{SESS}->set([[$VlanRowStatus,"1.$vlan_number",
"createAndGo","INTEGER"],
[$VlanType,"1.$vlan_number","ethernet","INTEGER"],
[$VlanName,"1.$vlan_number",$vlan_id,"OCTETSTR"],
......
......@@ -45,6 +45,7 @@ sub new($$$#@) {
my $debuglevel = shift;
my $community = shift;
my $supports_private = shift;
my $uses_vtp = shift;
my @devicenames = @_;
#
......@@ -71,6 +72,11 @@ sub new($$$#@) {
#
@{$self->{DEVICENAMES}} = @devicenames;
#
# Whether or not this stack uses VTP to keep the VLANs synchronized
#
$self->{VTP} = $uses_vtp;
#
# Make a device-dependant object for each switch
#
......@@ -269,10 +275,40 @@ sub createVlan($$$;$$$) {
my @otherargs = @_;
#
# We just need to create the VLAN on the stack leader
# What we do here depends on whether this stack uses VTP to synchronize
# VLANs or not
#
my $vlan_number = $self->{LEADER}->createVlan($vlan_id,@otherargs);
my $okay = ($vlan_number != 0);
my $okay;
if ($self->{VTP}) {
#
# We just need to create the VLAN on the stack leader
#
#
my $vlan_number = $self->{LEADER}->createVlan($vlan_id,undef,@otherargs);
$okay = ($vlan_number != 0);
} else {
#
# We need to create the VLAN on all devices
# XXX - should we do the leader first?
#
my $vlan_number = undef;
foreach my $devicename (sort {tbsort($a,$b)} keys %{$self->{DEVICES}}) {
my $device = $self->{DEVICES}{$devicename};
my $res = $self->{LEADER}->createVlan($vlan_id,undef,@otherargs);
if (!$res) {
#
# Ooops, failed. Don't try any more
#
$okay = 0;
last;
} else {
#
# Use the VLAN number we just got back for the other switches
#
$vlan_number = $res;
}
}
}
#
# We need to add the ports to VLANs at the stack level, since they are
......@@ -422,27 +458,39 @@ sub removeVlan($@) {
}
$errors += $device->removePortsFromVlan(@existant_vlans);
#
# If this stack doesn't use VTP, delete the VLAN, too, while
# we're at it. If it does, we remove all VLANs down below (we can't
# do it until the ports have been cleared from all switches.)
#
if (!$self->{VTP}) {
my $ok = $device->removeVlan(@existant_vlans);
if (!$ok) { $errors++; }
}
}
#
# For efficiency, we remove all VLANs from the leader in one function
# call. This can save a _lot_ of locking and unlocking.
#
if (!$errors) {
if ($self->{VTP}) {
#
# Make a list of all the VLANs that really did exist
# For efficiency, we remove all VLANs from the leader in one function
# call. This can save a _lot_ of locking and unlocking.
#
my @vlan_numbers;
my ($key, $value);
while (($key, $value) = each %vlan_numbers) {
if ($value) {
push @vlan_numbers, $value;
if (!$errors) {
#
# Make a list of all the VLANs that really did exist
#
my @vlan_numbers;
my ($key, $value);
while (($key, $value) = each %vlan_numbers) {
if ($value) {
push @vlan_numbers, $value;
}
}
}
my $ok = $self->{LEADER}->removeVlan(@vlan_numbers);
if (!$ok) {
$errors++;
my $ok = $self->{LEADER}->removeVlan(@vlan_numbers);
if (!$ok) {
$errors++;
}
}
}
......
......@@ -332,19 +332,20 @@ sub getSwitchStack($) {
#
# Returns the type of the given stack_id. If called in list context, also
# returns whether or not the stack supports private VLANs
# returns whether or not the stack supports private VLANs, and whether it
# uses a single VLAN domain
#
sub getStackType($) {
my $stack = shift;
my $result = DBQueryFatal("SELECT stack_type, supports_private " .
"FROM switch_stack_types WHERE stack_id='$stack'");
my $result = DBQueryFatal("SELECT stack_type, supports_private, " .
" single_domain FROM switch_stack_types WHERE stack_id='$stack'");
if (!$result->numrows()) {
print STDERR "No stack found called $stack\n";
return undef;
} else {
my ($stack_type,$supports_private) = ($result->fetchrow());
my ($stack_type,$supports_private,$single_domain) = ($result->fetchrow());
if (defined wantarray) {
return ($stack_type,$supports_private);
return ($stack_type,$supports_private,$single_domain);
} else {
return $stack_type;
}
......
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