...
 
Commits (3)
......@@ -53,8 +53,18 @@ my $VLAN_ID_PREFIX = "EV_";
# Port format
#
# 1. Port used by SNMP OID: (slot*1000)+port
# or, for a port-channel: 1000000 + port-channel#, we assume slot == 1000.
#
# 2. Port class instance.
# 3. Port used by SysDB on Arista switch, "EthernetX/Y", X: module/layer/level/slot, Y: port
# IMPORTANT - A special case is for port-channel:
# normally, port-channel should not be represented using Port instance,
# but just in case. If a port-channel
# is represented by a Port instance, the card should be 1000 and port is the
# port-channel number.
#
# 3. Port used by SysDB on Arista switch:
# - "EthernetX/Y", X: module/layer/level/slot, Y: port
# - "Port-ChannelX", X: the port-channel number, from 1-1000
#
# NOTE: 1. switch side port module # starts from 1, not 0
# 2. the wires table in DB must also take care of the format rules above.
......@@ -226,6 +236,8 @@ sub sysdb2Ifindex($$) {
if ($sbport =~ /^Ethernet(\d+)\/(\d+)$/) {
return $1*1000 + $2;
} elsif ($sbport =~ /^Port-Channel(\d+)$/) {
return 1000000 + int($1);
}
return undef;
......@@ -240,11 +252,38 @@ sub sysdb2PortInstance($$) {
$self->{NAME},
$1,
$2));
} elsif ($sbport =~ /^Port-Channel(\d+)$/) {
return Port->LookupByStringForced(
Port->Tokens2TripleString(
$self->{NAME},
1000,
$1));
}
return undef;
}
sub portInst2Sysdb($$) {
my ($self, $port) = @_;
if (int($port->card()) == 1000) { # This is a port-channel.
my $pcid = $port->port();
return "Port-Channel$pcid";
} else {
return "Ethernet".$port->card()."/".$port->port();
}
}
sub ifindex2Sysdb($$) {
my ($self, $ifindex) = @_;
if (int($ifindex /1000) == 1000) { # A port-channel.
return "Port-Channel".int($ifindex %1000);
} else {
return "Ethernet".int($ifindex /1000)."/".int($ifindex %1000);
}
}
#
# Converting port formats.
......@@ -273,7 +312,7 @@ sub convertPortFormat($$@) {
my $input = undef;
if (Port->isPort($sample)) {
$input = $PORT_FORMAT_PORT;
} elsif ($sample =~ /^Ethernet/) {
} elsif ($sample =~ /^Ethernet/ || $sample =~ /^Port-Channel/) {
$input = $PORT_FORMAT_SYSDB;
} else {
$input = $PORT_FORMAT_IFINDEX;
......@@ -293,7 +332,7 @@ sub convertPortFormat($$@) {
my @ifports = map int(int($_->card())*1000 +int($_->port())), @swports;
return @ifports;
} else {
my @sysdbports = map "Ethernet".$_->card()."/".$_->port(), @swports;
my @sysdbports = map $self->portInst2Sysdb($_), @swports; # "Ethernet".$_->card()."/".$_->port(), @swports;
return @sysdbports
}
} elsif ($input == $PORT_FORMAT_IFINDEX) {
......@@ -305,7 +344,7 @@ sub convertPortFormat($$@) {
$_ %1000)), @ports;
return @swports;
} else {
my @sysdbports = map "Ethernet".int($_ /1000)."/".int($_ %1000), @ports;
my @sysdbports = map $self->ifindex2Sysdb($_), @ports; # "Ethernet".int($_ /1000)."/".int($_ %1000), @ports;
return @sysdbports;
}
......@@ -640,6 +679,12 @@ sub setPortVlan($$@) {
$errors = scalar(@ports);
}
# enable/disable ports:
# if the vlan is '1', then disable ports(which means deleting the ports from
# some vlan).
my $onoroff = ($vlan_number ne "1")? "enable":"disable";
$errors += $self->portControl($onoroff, @ports);
return $errors;
}
......@@ -811,7 +856,7 @@ sub listVlans($) {
#
# List all ports on the device
#
# Specially for Arista switch: All ports are duplex, auto-negotiated.
# Specially for Arista switch: All ports are duplex.
#
# usage: listPorts($self)
# see snmpit_cisco_stack.pm for a description of return value format
......@@ -934,6 +979,8 @@ sub getStats() {
#
# usage: resetVlanIfOnTrunk(self, modport, vlan)
#
# note: the modport here is most likely a channel ifindex.
#
sub resetVlanIfOnTrunk($$$) {
my ($self, $modport, $vlan) = @_;
......@@ -966,13 +1013,20 @@ sub resetVlanIfOnTrunk($$$) {
# maintenance functions of vlans and so you should check for each port
# any way, and 2.) the check is cheap and can be done in convertPortFormat.
#
# NOTE: NOT-SUPPORTED We mostly use XML-RPC rather than SNMP.
#
sub getChannelIfIndex($@) {
my $self = shift;
my @ports = @_;
my $id = $self->{NAME}."::getChannelIfIndex";
my @swports = $self->convertPortFormat($PORT_FORMAT_SYSDB, @ports);
warn "ERROR: " . $self->{NAME} . "::getChannelIfIndex: not supported.\n";
my $resp = $self->callRPC($id, 'getPortChannel', \@swports);
if ($resp) {
my ($ifindex) = $self->convertPortFormat($PORT_FORMAT_IFINDEX, $resp);
$self->debug("$id gets $ifindex ($resp)\n",1);
return $ifindex;
}
return undef;
}
......@@ -991,8 +1045,7 @@ sub setVlansOnTrunk($$$$) {
my ($self, $modport, $value, @vlan_numbers) = @_;
my $id = $self->{NAME} . "::setVlansOnTrunk";
# NOTE: so-called $modport must be a Port instance!
my $swport = $self->convertPortFormat($PORT_FORMAT_SYSDB, $modport);
my ($swport) = $self->convertPortFormat($PORT_FORMAT_SYSDB, $modport);
my $resp = $self->callRPC($id, 'setAllowedVlansOnTrunkedPort', $swport,
($value?1:0), \@vlan_numbers);
if ($resp) {
......@@ -1018,7 +1071,7 @@ sub enablePortTrunking2($$$$) {
my $id = $self->{NAME} .
"::enablePortTrunking($port,$native_vlan,$equaltrunking)";
my $swport = $self->convertPortFormat($PORT_FORMAT_SYSDB, $port);
my ($swport) = $self->convertPortFormat($PORT_FORMAT_SYSDB, $port);
my $resp = $self->callRPC($id, 'enablePortTrunking',
$swport, $native_vlan, ($equaltrunking?1:0));
if ($resp) {
......@@ -1038,7 +1091,7 @@ sub disablePortTrunking($$) {
my ($self, $port) = @_;
my $id = $self->{NAME} . "::disablePortTrunking($port)";
my $swport = $self->convertPortFormat($PORT_FORMAT_SYSDB, $port);
my ($swport) = $self->convertPortFormat($PORT_FORMAT_SYSDB, $port);
my $resp = $self->callRPC($id, 'disablePortTrunking',
$swport);
if ($resp) {
......
......@@ -62,6 +62,19 @@ def vlanExists(sysdb, vlan_num):
bc = getBridgingConfig(sysdb)
return bc.vlanConfig.has_key(vlan_num)
def setPortAdminStatus(sysdb, port, enabled=1):
pc = sysdb['interface']['config']['all'].get(port)
if pc is None:
debug("setPortAdminStatus("+str(port)+","+str(enabled)+") error: can not get port.")
return
if enabled==1:
pc.adminEnabled=True
else:
pc.adminEnabled=False
#
# Not every port is active, or up. Inactive ports won't be listed
# under the IntfConfig folder and other interface folders, though
......@@ -74,6 +87,7 @@ def setPortStatus(sysdb, port, up=1):
if ic is None:
debug("setPortStatus("+str(port)+","+str(up)+") error: cannot get port.")
return
if up == 1:
ic.linkStatus = 'linkUp'
ic.operStatus = 'intfOperUp'
......@@ -203,6 +217,13 @@ def _removePortsFromVlan(vlan_num, ports):
else:
if pbc.accessVlan == int(vlan_num):
pbc.accessVlan = DEFAULT_VLAN_NUM
setPortAdminStatus(sysdbroot, p, 0)
elif pbc.switchportMode == 'trunk':
# This is hard to deal with, just remove the given vlan.
if pbc.trunkNativeVlan == int(vlan_num):
pbc.trunkNativeVlan = 0
disableVlanOnTrunkedPort(sysdbroot, p, vlan_num)
except:
print sign + " error: "+str(sys.exc_info())
......@@ -323,7 +344,8 @@ def _enablePortTrunking(port, native_vlan_num, tag_native):
pc.trunkNativeVlan = 0
else:
pc.trunkNativeVlan = int(native_vlan_num)
pc.trunkAllowedVlans = str(native_vlan_num)
pc.trunkAllowedVlans = str(native_vlan_num)
pc.enabled = True
setPortStatus(sysdbroot, str(port), 1)
retval = 1
......@@ -359,6 +381,7 @@ def _disablePortTrunking(port):
pc.enabled = True
setPortStatus(sysdbroot, str(port), 1)
retval = 1
except:
print sign + " error: "+str(sys.exc_info())
......@@ -377,6 +400,7 @@ def setBitmapByRanges(bmp, ranges, val = 1):
l, u = t
for i in range(l, u+1):
bmp[i] = val
return bmp
# Convert a string range to int tuple, e.g.:
......@@ -405,6 +429,7 @@ def bitmap2String(bmp):
if in_range==0:
in_range = 1
l = i
else:
if in_range==1:
in_range = 0
......@@ -418,6 +443,21 @@ def bitmap2String(bmp):
return s
#
# Disable the given VLAN on trunked port.
#
# Pre-condition: port must be trunked.
#
def disableVlanOnTrunkedPort(sysdb, port, vlan_num):
sign = "disableVlanOnTrunkedPort("+str(port)+","+str(vlan_num)+")"
debug(sign)
pc = getBridgingConfig(sysdb).switchIntfConfig.newMember(str(port))
bmp = string2Bitmap(pc.trunkAllowedVlans)
bmp[int(vlan_num)] = 0
pc.trunkAllowedVlans = bitmap2String(bmp)
#
# Set allowed VLANs on trunked port.
#
......@@ -434,6 +474,7 @@ def _setAllowedVlansOnTrunkedPort(port, allow, vnums):
debug(sign)
try:
pc = getBridgingConfig(sysdbroot).switchIntfConfig.newMember(str(port))
setPortStatus(sysdbroot, str(port), 1)
if pc.switchportMode == 'access':
pc.switchportMode = 'trunk'
......@@ -445,6 +486,7 @@ def _setAllowedVlansOnTrunkedPort(port, allow, vnums):
bmp = setBitmapByRanges(bmp, vlan_ranges)
else:
bmp = setBitmapByRanges(bmp, vlan_ranges, 0)
pc.trunkAllowedVlans = bitmap2String(bmp)
retval = 1
except:
......@@ -454,6 +496,40 @@ def _setAllowedVlansOnTrunkedPort(port, allow, vnums):
debug(sign + " returns " + str(retval))
return retval
#
# Get LACP logical port channel by its real physical ports
#
# Follow the algorithm in snmpit_hp, we just return the LAG of
# the first port that has LAG.
#
def _getPortChannel(ports):
retval = ""
sig = "_getChannelIfIndex("+str(ports)+")"
debug(sig)
try:
pcs = sysdbroot['lag']['input']['config']['cli'].phyIntf
for port in ports:
if pcs.has_key(str(port)):
pc = pcs[str(port)]
if pc.lag is not None:
retval = pc.lag.name
break
else: # match has_key()
# This seems unlikely, but just in case, and is not treated as error:
# In this case, some ports are not in port-channel at all, we
# simply ignore them.
print sig+" warning: port "+str(port)+" is not in port-channel.\n"
pass
except:
print sig + " error: "+str(sys.exc_info())
retval = ""
debug(sig + "returns "+str(retval))
return retval
#
# Exported methods list
#
......@@ -467,7 +543,8 @@ funcs = [(_createVlan, "createVlan"),
(_listVlans, "listVlans"),
(_enablePortTrunking, "enablePortTrunking"),
(_disablePortTrunking, "disablePortTrunking"),
(_setAllowedVlansOnTrunkedPort, "setAllowedVlansOnTrunkedPort")
(_setAllowedVlansOnTrunkedPort, "setAllowedVlansOnTrunkedPort"),
(_getPortChannel, "getPortChannel")
]
s = initRPCServer(BIND_ADDR, RPC_PORT, funcs)
......