diff --git a/ChangeLog b/ChangeLog index 75139d6b..90f7bb54 100644 --- a/ChangeLog +++ b/ChangeLog @@ -8,6 +8,11 @@ version 1.09 + Added support for CISCO-PAE-MIB in CiscoPortSecurity (Kesy) + Updates to fan, power supply, and serial number methods in L2::HP (Jeroen van Ingen) + + Use Cisco Client Association MIBs for Aironet client reporting + via fw_mac + + Support VLANs on Aironet + + Get the proper radio MAC address from aironet in MBSS mode + + Additional wireless statistics from Aironet * Silence warnings from Cisco devices which don't return values for extended VLAN range (1024-4096) diff --git a/Info/Layer2/Aironet.pm b/Info/Layer2/Aironet.pm index f1e83743..8957d778 100644 --- a/Info/Layer2/Aironet.pm +++ b/Info/Layer2/Aironet.pm @@ -39,38 +39,50 @@ use SNMP::Info::Layer2; use SNMP::Info::Entity; use SNMP::Info::EtherLike; use SNMP::Info::CiscoStats; -use SNMP::Info::CiscoVTP; use SNMP::Info::CDP; +use SNMP::Info::IEEE802dot11; @SNMP::Info::Layer2::Aironet::ISA = qw/SNMP::Info::Layer2 SNMP::Info::Entity SNMP::Info::EtherLike - SNMP::Info::CiscoStats SNMP::Info::CiscoVTP SNMP::Info::CDP Exporter/; + SNMP::Info::CiscoStats SNMP::Info::CDP Exporter/; @SNMP::Info::Layer2::Aironet::EXPORT_OK = qw//; use vars qw/$VERSION %FUNCS %GLOBALS %MIBS %MUNGE $AUTOLOAD $INIT $DEBUG/; %GLOBALS = ( + %SNMP::Info::IEEE802dot11::GLOBALS, %SNMP::Info::Layer2::GLOBALS, %SNMP::Info::Entity::GLOBALS, %SNMP::Info::EtherLike::GLOBALS, %SNMP::Info::CiscoStats::GLOBALS, - %SNMP::Info::CiscoVTP::GLOBALS, %SNMP::Info::CDP::GLOBALS, 'serial' => 'entPhysicalSerialNum.1', 'descr' => 'sysDescr' ); -%FUNCS = (%SNMP::Info::Layer2::FUNCS, +%FUNCS = ( + %SNMP::Info::IEEE802dot11::FUNCS, + %SNMP::Info::Layer2::FUNCS, %SNMP::Info::Entity::FUNCS, %SNMP::Info::EtherLike::FUNCS, %SNMP::Info::CiscoStats::FUNCS, - %SNMP::Info::CiscoVTP::FUNCS, %SNMP::Info::CDP::FUNCS, 'i_ssidlist' => 'cd11IfAuxSsid', 'i_ssidbcast' => 'cd11IfAuxSsidBroadcastSsid', 'i_80211channel' => 'cd11IfPhyDsssCurrentChannel', + 'c_dot11subif' => 'cDot11ClientSubIfIndex', + 'cd11_txrate' => 'cDot11ClientCurrentTxRateSet', + 'cd11_uptime' => 'cDot11ClientUpTime', + 'cd11_sigstrength' => 'cDot11ClientSignalStrength', + 'cd11_sigqual' => 'cDot11ClientSigQuality', + 'cd11_rxpkt' => 'cDot11ClientPacketsReceived', + 'cd11_txpkt' => 'cDot11ClientPacketsSent', + 'cd11_rxbyte' => 'cDot11ClientBytesReceived', + 'cd11_txbyte' => 'cDot11ClientBytesSent', + 'mbss_mac_addr' => 'cdot11MbssidIfMacAddress', ); %MIBS = ( + %SNMP::Info::IEEE802dot11::MIBS, %SNMP::Info::Layer2::MIBS, %SNMP::Info::Entity::MIBS, %SNMP::Info::EtherLike::MIBS, @@ -78,16 +90,25 @@ use vars qw/$VERSION %FUNCS %GLOBALS %MIBS %MUNGE $AUTOLOAD $INIT $DEBUG/; %SNMP::Info::CiscoVTP::MIBS, %SNMP::Info::CDP::MIBS, 'CISCO-DOT11-IF-MIB' => 'cd11IfAuxSsid', + 'CISCO-DOT11-ASSOCIATION-MIB' => 'cDot11ClientSubIfIndex', + 'CISCO-DOT11-SSID-SECURITY-MIB' => 'cdot11SecVlanNameId', + 'CISCO-VLAN-IFTABLE-RELATIONSHIP-MIB' => 'cviRoutedVlanIfIndex', ); -%MUNGE = (%SNMP::Info::Layer2::MUNGE, +%MUNGE = ( + %SNMP::Info::IEEE802dot11::MUNGE, + %SNMP::Info::Layer2::MUNGE, %SNMP::Info::Entity::MUNGE, %SNMP::Info::EtherLike::MUNGE, %SNMP::Info::CiscoStats::MUNGE, - %SNMP::Info::CiscoVTP::MUNGE, %SNMP::Info::CDP::MUNGE, + 'cd11_txrate' => \&munge_cd11_txrate, + 'mbss_mac_addr' => \&SNMP::Info::munge_mac, ); +# Use 802.11 power level without putting IEEE802dot11 in @ISA +*SNMP::Info::Layer2::Aironet::dot11_cur_tx_pwr_mw = + \&SNMP::Info::IEEE802dot11::dot11_cur_tx_pwr_mw; sub vendor { # Sorry, but it's true. @@ -132,6 +153,207 @@ sub i_duplex { return \%i_duplex; } +# +# IOS 12.3 introduces the cDot11ClientSubIfIndex in the +# cDot11ClientConfigInfoTable, which supplies the ifIndex +# of the VLAN Subinterface if one exists, or of the primary +# interface if there are not subinterfaces. 12.2 used the +# Q-BRIDGE-MIB dot1qTpFdbTable but that was removed in 12.3. +sub _aironet_special { + my $aironet = shift; + my $os_ver = $aironet->os_ver(); + if (defined($os_ver) && $os_ver =~ /^(\d+)\.(\d+)(\D|$)/ && (($1 == 12 && $2 >= 3) || $1 > 12)) { + return 1; + } +} + +# +# INDEX { ifIndex, cd11IfAuxSsid, cDot11ClientAddress } +sub _aironet_breakout_dot11idx { + my $oid = shift; + + my @parts = split(/\./, $oid); + my $ifindex = shift(@parts); + my $ssidlen = shift(@parts); + my $ssid = pack("C*", splice(@parts, 0, $ssidlen)); + my $mac = join(":", map {sprintf "%02x", $_} @parts); + return ($ifindex, $ssid, $mac); +} + +sub fw_mac { + my $aironet = shift; + + return qb_fw_mac($aironet) unless _aironet_special($aironet); + my $c_dot11subif = $aironet->c_dot11subif(); + my $fw_mac = {}; + + foreach my $i (keys %$c_dot11subif) { + my ($ifindex, $ssid, $mac) = _aironet_breakout_dot11idx($i); + $fw_mac->{$i} = $mac; + } + return $fw_mac; +} + +sub fw_port { + my $aironet = shift; + + return $aironet->qb_fw_port() unless _aironet_special($aironet); + my $c_dot11subif = $aironet->c_dot11subif(); + my $fw_port = {}; + + foreach my $i (keys %$c_dot11subif) { + my ($ifindex, $ssid, $mac) = _aironet_breakout_dot11idx($i); + $fw_port->{$i} = $c_dot11subif->{$i} || $ifindex; + } + return $fw_port; +} + +sub bp_index { + my $aironet = shift; + + return $aironet->orig_bp_index() unless _aironet_special($aironet); + my $c_dot11subif = $aironet->c_dot11subif(); + my $bp_index = {}; + + foreach my $i (keys %$c_dot11subif) { + my ($ifindex, $ssid, $mac) = _aironet_breakout_dot11idx($i); + my ($i) = $c_dot11subif->{$i} || $ifindex; + $bp_index->{$i} = $i; + } + return $bp_index; +} + +### +# +# VLAN support +# +sub v_name { + my $aironet = shift; + + my $v_name = {}; + my $vlan_nameid = $aironet->cdot11SecVlanNameId(); + foreach my $i (keys %$vlan_nameid) { + my @parts = split(/\./, $i); + my $namelen = shift(@parts); + + my $name = pack("C*", @parts); + $v_name->{$i} = $name; + } + return $v_name; +} + +sub v_index { + my $aironet = shift; + + return $aironet->cdot11SecVlanNameId(); +} + +sub i_vlan { + my $aironet = shift; + + my $i_vlan = {}; + my $idxmap = $aironet->cviRoutedVlanIfIndex(); + foreach my $i (keys %$idxmap) { + my @parts = split(/\./, $i); + $i_vlan->{$idxmap->{$i}} = $parts[0]; + } + return $i_vlan; +} + +# The MIB reports in units of half a megabit, e.g., +# 5.5Mbps is reported as 11. +sub munge_cd11_txrate { + my $txrates = shift; + my @rates = unpack("C*", $txrates); + map {$_ *= 0.5} @rates; + \@rates; +} + +# cd11 INDEX +sub cd11_port { + my $aironet = shift; + my $cd11_sigstrength = $aironet->cd11_sigstrength(); + my $interfaces = $aironet->interfaces(); + my %ret; + foreach (keys %$cd11_sigstrength) { + my ($ifindex, $ssid, $mac) = _aironet_breakout_dot11idx($_); + $ret{$_} = $interfaces->{$ifindex}; + } + return \%ret; +} + +sub cd11_ssid { + my $aironet = shift; + my $cd11_sigstrength = $aironet->cd11_sigstrength(); + my %ret; + foreach (keys %$cd11_sigstrength) { + my ($ifindex, $ssid, $mac) = _aironet_breakout_dot11idx($_); + $ret{$_} = $ssid; + } + return \%ret; +} + +sub cd11_mac { + my $aironet = shift; + my $cd11_sigstrength = $aironet->cd11_sigstrength(); + my %ret; + foreach (keys %$cd11_sigstrength) { + my ($ifindex, $ssid, $mac) = _aironet_breakout_dot11idx($_); + $ret{$_} = $mac; + } + return \%ret; +} + +# When using MBSS, the ifTable reports the +# base MAC address, but the actual association is +# with a different MAC address for MBSS. +# This convoluted path seems to be necessary +# to get the right overrides. +sub i_mac { + my $aironet = shift; + # no partial is possible due to the levels + # of indirection. + my $idx; + + # Start with the ifPhysAddress, and override + my $mbss_mac = $aironet->orig_i_mac(); + + my $mbss_mac_addr = $aironet->mbss_mac_addr(); + my $ssid_vlan = $aironet->cdot11SecAuxSsidVlan(); + my $vlan_map = $aironet->cviRoutedVlanIfIndex(); + my $ifstack = $aironet->ifStackStatus(); + + my $vlan_list = {}; + foreach $idx (keys %$vlan_map) { + my ($vlan, $num) = split(/\./, $idx); + push(@{$vlan_list->{$vlan}}, $vlan_map->{$idx}); + } + + my $stack = {}; + foreach $idx (keys %$ifstack) { + my ($upper, $lower) = split(/\./, $idx); + $stack->{$upper}->{$lower} = $ifstack->{$idx}; + } + + # mbss_mac_addr index is (radio, ssid). + # ssid_vlan maps ssid->vlan. + # vlan_map maps vlan->[list of interfaces] + # ifstack allows us to pick the right interface + foreach my $idx (keys %$mbss_mac_addr) { + my ($interface, @ssid) = split(/\./, $idx); + my $vlan = $ssid_vlan->{join(".", scalar(@ssid), @ssid)}; + next unless defined($vlan); + foreach my $vlanif (@{$vlan_list->{$vlan}}) { + if (defined($stack->{$vlanif}->{$interface})) { + $mbss_mac->{$vlanif} = $mbss_mac_addr->{$idx}; + } + } + } + + return $mbss_mac; +} + + 1; __END__