diff options
Diffstat (limited to 'torrus/perllib/Torrus/DevDiscover/CiscoIOS.pm')
-rw-r--r-- | torrus/perllib/Torrus/DevDiscover/CiscoIOS.pm | 687 |
1 files changed, 687 insertions, 0 deletions
diff --git a/torrus/perllib/Torrus/DevDiscover/CiscoIOS.pm b/torrus/perllib/Torrus/DevDiscover/CiscoIOS.pm new file mode 100644 index 000000000..6bd6d91c2 --- /dev/null +++ b/torrus/perllib/Torrus/DevDiscover/CiscoIOS.pm @@ -0,0 +1,687 @@ +# Copyright (C) 2002 Stanislav Sinyagin +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + +# $Id: CiscoIOS.pm,v 1.1 2010-12-27 00:03:47 ivan Exp $ +# Stanislav Sinyagin <ssinyagin@yahoo.com> + +# Cisco IOS devices discovery +# To do: +# SA Agent MIB +# DiffServ MIB + +package Torrus::DevDiscover::CiscoIOS; + +use strict; +use Torrus::Log; + + +$Torrus::DevDiscover::registry{'CiscoIOS'} = { + 'sequence' => 500, + 'checkdevtype' => \&checkdevtype, + 'discover' => \&discover, + 'buildConfig' => \&buildConfig + }; + + +our %oiddef = + ( + # CISCO-SMI + 'ciscoProducts' => '1.3.6.1.4.1.9.1', + # CISCO-PRODUCTS-MIB + 'ciscoLS1010' => '1.3.6.1.4.1.9.1.107', + # CISCO-IMAGE-MIB + 'ciscoImageTable' => '1.3.6.1.4.1.9.9.25.1.1', + # CISCO-ENHANCED-IMAGE-MIB + 'ceImageTable' => '1.3.6.1.4.1.9.9.249.1.1.1', + # OLD-CISCO-MEMORY-MIB + 'bufferElFree' => '1.3.6.1.4.1.9.2.1.9.0', + # CISCO-IPSEC-FLOW-MONITOR-MIB + 'cipSecGlobalHcInOctets' => '1.3.6.1.4.1.9.9.171.1.3.1.4.0', + # CISCO-BGP4-MIB + 'cbgpPeerAddrFamilyName' => '1.3.6.1.4.1.9.9.187.1.2.3.1.3', + 'cbgpPeerAcceptedPrefixes' => '1.3.6.1.4.1.9.9.187.1.2.4.1.1', + 'cbgpPeerPrefixAdminLimit' => '1.3.6.1.4.1.9.9.187.1.2.4.1.3', + # CISCO-CAR-MIB + 'ccarConfigTable' => '1.3.6.1.4.1.9.9.113.1.1.1', + 'ccarConfigType' => '1.3.6.1.4.1.9.9.113.1.1.1.1.3', + 'ccarConfigAccIdx' => '1.3.6.1.4.1.9.9.113.1.1.1.1.4', + 'ccarConfigRate' => '1.3.6.1.4.1.9.9.113.1.1.1.1.5', + 'ccarConfigLimit' => '1.3.6.1.4.1.9.9.113.1.1.1.1.6', + 'ccarConfigExtLimit' => '1.3.6.1.4.1.9.9.113.1.1.1.1.7', + 'ccarConfigConformAction' => '1.3.6.1.4.1.9.9.113.1.1.1.1.8', + 'ccarConfigExceedAction' => '1.3.6.1.4.1.9.9.113.1.1.1.1.9', + # CISCO-VPDN-MGMT-MIB + 'cvpdnSystemTunnelTotal' => '1.3.6.1.4.1.9.10.24.1.1.4.1.2' + ); + + +# Not all interfaces are normally needed to monitor. +# You may override the interface filtering in devdiscover-siteconfig.pl: +# redefine $Torrus::DevDiscover::CiscoIOS::interfaceFilter +# or define $Torrus::DevDiscover::CiscoIOS::interfaceFilterOverlay + +our $interfaceFilter; +our $interfaceFilterOverlay; +my %ciscoInterfaceFilter; + +if( not defined( $interfaceFilter ) ) +{ + $interfaceFilter = \%ciscoInterfaceFilter; +} + + +# Key is some unique symbolic name, does not mean anything +# ifType is the number to match the interface type +# ifDescr is the regexp to match the interface description +%ciscoInterfaceFilter = + ( + 'Null0' => { + 'ifType' => 1, # other + 'ifDescr' => '^Null' + }, + + 'E1 N/N/N' => { + 'ifType' => 18, # ds1 + 'ifDescr' => '^E1' + }, + + 'Virtual-AccessN' => { + 'ifType' => 23, # ppp + 'ifDescr' => '^Virtual-Access' + }, + + 'DialerN' => { + 'ifType' => 23, # ppp + 'ifDescr' => '^Dialer' + }, + + 'LoopbackN' => { + 'ifType' => 24, # softwareLoopback + 'ifDescr' => '^Loopback' + }, + + 'SerialN:N-Bearer Channel' => { + 'ifType' => 81, # ds0, Digital Signal Level 0 + 'ifDescr' => '^Serial.*Bearer\s+Channel' + }, + + 'Voice Encapsulation (POTS) Peer: N' => { + 'ifType' => 103 # voiceEncap + }, + + 'Voice Over IP Peer: N' => { + 'ifType' => 104 # voiceOverIp + }, + + 'ATMN/N/N.N-atm subif' => { + 'ifType' => 134, # atmSubInterface + 'ifDescr' => '^ATM[0-9\/]+\.[0-9]+\s+subif' + }, + + 'BundleN' => { + 'ifType' => 127, # docsCableMaclayer + 'ifDescr' => '^Bundle' + }, + + 'EOBCN/N' => { + 'ifType' => 53, # propVirtual + 'ifDescr' => '^EOBC' + }, + + 'FIFON/N' => { + 'ifType' => 53, # propVirtual + 'ifDescr' => '^FIFO' + }, + ); + +our %tunnelType = + ( + # CISCO-VPDN-MGMT-MIB Tunnel Types + '1' => 'L2F', + '2' => 'L2TP', + '3' => 'PPTP' + ); + + +sub checkdevtype +{ + my $dd = shift; + my $devdetails = shift; + + if( not $dd->oidBaseMatch + ( 'ciscoProducts', + $devdetails->snmpVar( $dd->oiddef('sysObjectID') ) ) ) + { + return 0; + } + + my $session = $dd->session(); + if( not $dd->checkSnmpTable('ciscoImageTable') ) + { + if( $dd->checkSnmpTable('ceImageTable') ) + { + # IOS XR has a new MIB for software image management + $devdetails->setCap('CiscoIOSXR'); + } + else + { + return 0; + } + } + + # On some Layer3 switching devices, VlanXXX interfaces give some + # useful stats, while on others the stats are not relevant at all + + if( $devdetails->param('CiscoIOS::enable-vlan-interfaces') ne 'yes' ) + { + $interfaceFilter->{'VlanN'} = { + 'ifType' => 53, # propVirtual + 'ifDescr' => '^Vlan\d+' + }; + } + + # same thing with unrouted VLAN interfaces + if( $devdetails->param('CiscoIOS::enable-unrouted-vlan-interfaces') + ne 'yes' ) + { + $interfaceFilter->{'unrouted VLAN N'} => { + 'ifType' => 53, # propVirtual + 'ifDescr' => '^unrouted\s+VLAN\s+\d+' + }; + } + + &Torrus::DevDiscover::RFC2863_IF_MIB::addInterfaceFilter + ($devdetails, $interfaceFilter); + + if( defined( $interfaceFilterOverlay ) ) + { + &Torrus::DevDiscover::RFC2863_IF_MIB::addInterfaceFilter + ($devdetails, $interfaceFilterOverlay); + } + + $devdetails->setCap('interfaceIndexingManaged'); + + return 1; +} + + +my %ccarConfigType = + ( 1 => 'all', + 2 => 'quickAcc', + 3 => 'standardAcc' ); + +my %ccarAction = + ( 1 => 'drop', + 2 => 'xmit', + 3 => 'continue', + 4 => 'precedXmit', + 5 => 'precedCont' ); + + + +sub discover +{ + my $dd = shift; + my $devdetails = shift; + + my $session = $dd->session(); + my $data = $devdetails->data(); + + # Old mkroutercfg used cisco-interface-counters + if( $Torrus::DevDiscover::CiscoIOS::useCiscoInterfaceCounters ) + { + foreach my $interface ( values %{$data->{'interfaces'}} ) + { + $interface->{'hasHCOctets'} = 0; + $interface->{'hasOctets'} = 0; + push( @{$interface->{'templates'}}, + 'CiscoIOS::cisco-interface-counters' ); + } + } + else + { + # This is a well-known bug in IOS: HC counters are implemented, + # but always zero. We can catch this only for active interfaces. + + foreach my $ifIndex ( sort {$a<=>$b} keys %{$data->{'interfaces'}} ) + { + my $interface = $data->{'interfaces'}{$ifIndex}; + + if( $interface->{'hasHCOctets'} and + ( ( + $devdetails->snmpVar( $dd->oiddef('ifHCInOctets') + . '.' . $ifIndex ) == 0 and + $devdetails->snmpVar( $dd->oiddef('ifInOctets') + . '.' . $ifIndex ) > 0 + ) + or + ( + $devdetails->snmpVar( $dd->oiddef('ifHCOutOctets') + . '.' . $ifIndex ) == 0 and + $devdetails->snmpVar( $dd->oiddef('ifOutOctets') + . '.' . $ifIndex ) > 0 + ) ) ) + { + Debug('Disabling HC octets for ' . $ifIndex . ': ' . + $interface->{'ifDescr'}); + + $interface->{'hasHCOctets'} = 0; + $interface->{'hasHCUcastPkts'} = 0; + } + } + } + + if( $devdetails->param('CiscoIOS::enable-membuf-stats') eq 'yes' ) + { + # Old Memory Buffers, if we have bufferElFree we assume + # the rest as they are "required" + + if( $dd->checkSnmpOID('bufferElFree') ) + { + $devdetails->setCap('old-ciscoMemoryBuffers'); + push( @{$data->{'templates'}}, + 'CiscoIOS::old-cisco-memory-buffers' ); + } + } + + if( $devdetails->param('CiscoIOS::disable-ipsec-stats') ne 'yes' ) + { + if( $dd->checkSnmpOID('cipSecGlobalHcInOctets') ) + { + $devdetails->setCap('ciscoIPSecGlobalStats'); + push( @{$data->{'templates'}}, + 'CiscoIOS::cisco-ipsec-flow-globals' ); + } + + if( $dd->oidBaseMatch + ( 'ciscoLS1010', + $devdetails->snmpVar( $dd->oiddef('sysObjectID') ) ) ) + { + $data->{'param'}{'snmp-oids-per-pdu'} = 10; + } + } + + if( $devdetails->param('CiscoIOS::disable-bgp-stats') ne 'yes' ) + { + my $peerTable = + $session->get_table( -baseoid => + $dd->oiddef('cbgpPeerAcceptedPrefixes') ); + if( defined( $peerTable ) and scalar( %{$peerTable} ) > 0 ) + { + $devdetails->storeSnmpVars( $peerTable ); + $devdetails->setCap('CiscoBGP'); + + my $limitsTable = + $session->get_table( -baseoid => + $dd->oiddef('cbgpPeerPrefixAdminLimit') ); + $limitsTable = {} if not defined( $limitsTable ); + + $data->{'cbgpPeers'} = {}; + + # retrieve AS numbers for neighbor peers + Torrus::DevDiscover::RFC1657_BGP4_MIB::discover($dd, $devdetails); + + # list of indices for peers that are not IPv4 Unicast + my @nonV4Unicast; + + # Number of peers for each AS + my %asNumbers; + + foreach my $INDEX + ( $devdetails-> + getSnmpIndices( $dd->oiddef('cbgpPeerAcceptedPrefixes') ) ) + { + my ($a1, $a2, $a3, $a4, $afi, $safi) = split(/\./, $INDEX); + my $peerIP = join('.', $a1, $a2, $a3, $a4); + + my $peer = { + 'peerIP' => $peerIP, + 'addrFamily' => 'IPv4 Unicast' + }; + + if( $afi != 1 and $safi != 1 ) + { + push( @nonV4Unicast, $INDEX ); + } + + my $desc = + $devdetails->param('peer-ipaddr-description-' . + join('_', split('\.', $peerIP))); + if( length( $desc ) > 0 ) + { + $peer->{'description'} = $desc; + } + + my $peerAS = $data->{'bgpPeerAS'}{$peerIP}; + if( defined( $peerAS ) ) + { + $peer->{'peerAS'} = $data->{'bgpPeerAS'}{$peerIP}; + $asNumbers{$peer->{'peerAS'}}++; + + my $desc = + $devdetails->param('bgp-as-description-' . $peerAS); + if( length( $desc ) > 0 ) + { + if( defined( $peer->{'description'} ) ) + { + Warn('Conflicting descriptions for peer ' . + $peerIP); + } + $peer->{'description'} = $desc; + } + } + else + { + Error('Cannot find AS number for BGP peer ' . $peerIP); + next; + } + + if( defined( $peer->{'description'} ) ) + { + $peer->{'description'} .= ' '; + } + $peer->{'description'} .= '[' . $peerIP . ']'; + + $peer->{'prefixLimit'} = + $limitsTable->{$dd->oiddef('cbgpPeerPrefixAdminLimit') . + '.' . $INDEX}; + + $data->{'cbgpPeers'}{$INDEX} = $peer; + } + + if( scalar( @nonV4Unicast ) > 0 ) + { + my $addrFamTable = + $session->get_table + ( -baseoid => $dd->oiddef('cbgpPeerAddrFamilyName') ); + + foreach my $INDEX ( @nonV4Unicast ) + { + my $peer = $data->{'cbgpPeers'}{$INDEX}; + + my $fam = $addrFamTable->{ + $dd->oiddef('cbgpPeerAddrFamilyName') . + '.' . $INDEX}; + + $peer->{'addrFamily'} = $fam; + $peer->{'otherAddrFamily'} = 1; + $peer->{'description'} .= ' ' . $fam; + } + } + + # Construct the subtree names from AS, peer IP, and address + # family + foreach my $INDEX ( keys %{$data->{'cbgpPeers'}} ) + { + my $peer = $data->{'cbgpPeers'}{$INDEX}; + + my $subtreeName = 'AS' . $peer->{'peerAS'}; + if( $asNumbers{$peer->{'peerAS'}} > 1 ) + { + $subtreeName .= '_' . $peer->{'peerIP'}; + } + + if( $peer->{'otherAddrFamily'} ) + { + my $fam = $data->{'cbgpPeers'}{$INDEX}{'addrFamily'}; + $fam =~ s/\W/_/g; + $subtreeName .= '_' . $fam; + } + + $peer->{'subtreeName'} = $subtreeName; + } + } + } + + + if( $devdetails->param('CiscoIOS::disable-car-stats') ne 'yes' ) + { + my $carTable = + $session->get_table( -baseoid => + $dd->oiddef('ccarConfigTable') ); + if( defined( $carTable ) and scalar( %{$carTable} ) > 0 ) + { + $devdetails->storeSnmpVars( $carTable ); + $devdetails->setCap('CiscoCAR'); + + $data->{'ccar'} = {}; + + foreach my $INDEX + ( $devdetails-> + getSnmpIndices( $dd->oiddef('ccarConfigType') ) ) + { + my ($ifIndex, $dir, $carIndex) = split(/\./, $INDEX); + my $interface = $data->{'interfaces'}{$ifIndex}; + + my $car = { + 'ifIndex' => $ifIndex, + 'direction' => $dir, + 'carIndex' => $carIndex }; + + $car->{'configType'} = + $ccarConfigType{ $carTable->{$dd->oiddef + ('ccarConfigType') . + '.' . $INDEX} }; + + $car->{'accIdx'} = $carTable->{$dd->oiddef + ('ccarConfigAccIdx') . + '.' . $INDEX}; + + $car->{'rate'} = $carTable->{$dd->oiddef + ('ccarConfigRate') . + '.' . $INDEX}; + + + $car->{'limit'} = $carTable->{$dd->oiddef + ('ccarConfigLimit') . + '.' . $INDEX}; + + $car->{'extLimit'} = $carTable->{$dd->oiddef + ('ccarConfigExtLimit') . + '.' . $INDEX}; + $car->{'conformAction'} = + $ccarAction{ $carTable->{$dd->oiddef + ('ccarConfigConformAction') . + '.' . $INDEX} }; + + $car->{'exceedAction'} = + $ccarAction{ $carTable->{$dd->oiddef + ('ccarConfigExceedAction') . + '.' . $INDEX} }; + + $data->{'ccar'}{$INDEX} = $car; + } + } + } + + + if( $devdetails->param('CiscoIOS::disable-vpdn-stats') ne 'yes' ) + { + if( $dd->checkSnmpTable( 'cvpdnSystemTunnelTotal' ) ) + { + # Find the Tunnel type + my $tableTun = $session->get_table( + -baseoid => $dd->oiddef('cvpdnSystemTunnelTotal') ); + + if( $tableTun ) + { + $devdetails->setCap('ciscoVPDN'); + + $devdetails->storeSnmpVars( $tableTun ); + + # VPDN indexing: 1: l2f, 2: l2tp, 3: pptp + foreach my $typeIndex ( + $devdetails->getSnmpIndices( + $dd->oiddef('cvpdnSystemTunnelTotal') ) ) + { + Debug("CISCO-VPDN-MGMT-MIB: found Tunnel type " . + $tunnelType{$typeIndex} ); + + $data->{'ciscoVPDN'}{$typeIndex} = $tunnelType{$typeIndex}; + } + } + } + } + + if( $devdetails->param('CiscoIOS::short-device-comment') eq 'yes' ) + { + # Remove serials from device comment + # 1841 chassis, Hw Serial#: 3625140487, Hw Revision: 6.0 + + $data->{'param'}{'comment'} =~ s/, Hw.*//o; + } + + return 1; +} + + +sub buildConfig +{ + my $devdetails = shift; + my $cb = shift; + my $devNode = shift; + + my $data = $devdetails->data(); + + if( $devdetails->hasCap('CiscoBGP') ) + { + my $countersNode = + $cb->addSubtree( $devNode, 'BGP_Prefixes', + { + 'node-display-name' => 'BGP Prefixes', + 'comment' => 'Accepted prefixes', + } ); + + foreach my $INDEX ( sort + { $data->{'cbgpPeers'}{$a}{'subtreeName'} <=> + $data->{'cbgpPeers'}{$b}{'subtreeName'} } + keys %{$data->{'cbgpPeers'}} ) + { + my $peer = $data->{'cbgpPeers'}{$INDEX}; + + my $param = { + 'peer-index' => $INDEX, + 'peer-ipaddr' => $peer->{'peerIP'}, + 'comment' => $peer->{'description'}, + 'descriptive-nickname' => $peer->{'subtreeName'}, + 'precedence' => 65000 - $peer->{'peerAS'} + }; + + if( defined( $peer->{'prefixLimit'} ) and + $peer->{'prefixLimit'} > 0 ) + { + $param->{'upper-limit'} = $peer->{'prefixLimit'}; + $param->{'graph-upper-limit'} = $peer->{'prefixLimit'} * 1.03; + } + + $cb->addLeaf + ( $countersNode, $peer->{'subtreeName'}, $param, + ['CiscoIOS::cisco-bgp'] ); + } + } + + + if( $devdetails->hasCap('CiscoCAR') ) + { + my $countersNode = + $cb->addSubtree( $devNode, 'CAR_Stats', { + 'comment' => 'Committed Access Rate statistics', + 'node-display-name' => 'CAR', }, + ['CiscoIOS::cisco-car-subtree']); + + foreach my $INDEX ( sort keys %{$data->{'ccar'}} ) + { + my $car = $data->{'ccar'}{$INDEX}; + my $interface = $data->{'interfaces'}{$car->{'ifIndex'}}; + + my $subtreeName = + $interface->{$data->{'nameref'}{'ifSubtreeName'}}; + + $subtreeName .= ($car->{'direction'} == 1) ? '_IN':'_OUT'; + if( $car->{'carIndex'} > 1 ) + { + $subtreeName .= '_' . $car->{'carIndex'}; + } + + my $param = { + 'searchable' => 'yes', + 'car-direction' => $car->{'direction'}, + 'car-index' => $car->{'carIndex'} }; + + $param->{'interface-name'} = + $interface->{'param'}{'interface-name'}; + $param->{'interface-nick'} = + $interface->{'param'}{'interface-nick'}; + $param->{'comment'} = + $interface->{'param'}{'comment'}; + + my $legend = sprintf("Type: %s;", $car->{'configType'}); + if( $car->{'accIdx'} > 0 ) + { + $legend .= sprintf("Access list: %d;", $car->{'accIdx'}); + } + + $legend .= + sprintf("Rate: %d bps; Limit: %d bytes; Ext limit: %d bytes;" . + "Conform action: %s; Exceed action: %s", + $car->{'rate'}, + $car->{'limit'}, + $car->{'extLimit'}, + $car->{'conformAction'}, + $car->{'exceedAction'}); + + $param->{'legend'} = $legend; + + $cb->addSubtree + ( $countersNode, + $subtreeName, + $param, + ['CiscoIOS::cisco-car']); + } + } + + + if( $devdetails->hasCap('ciscoVPDN') ) + { + my $tunnelNode = $cb->addSubtree + ( $devNode, 'VPDN_Statistics', + {'node-display-name' => 'VPDN Statistics'}, + [ 'CiscoIOS::cisco-vpdn-subtree' ] ); + + foreach my $INDEX ( sort keys %{$data->{'ciscoVPDN'}} ) + { + my $tunnelProtocol = $data->{'ciscoVPDN'}{$INDEX}; + + $cb->addSubtree( $tunnelNode, $tunnelProtocol, + { 'comment' => $tunnelProtocol . ' information', + 'tunIndex' => $INDEX, + 'tunFile' => lc($tunnelProtocol) }, + [ 'CiscoIOS::cisco-vpdn-leaf' ] ); + } + } +} + + + + +1; + + +# Local Variables: +# mode: perl +# indent-tabs-mode: nil +# perl-indent-level: 4 +# End: |