1 # Copyright (C) 2002 Stanislav Sinyagin
3 # This program is free software; you can redistribute it and/or modify
4 # it under the terms of the GNU General Public License as published by
5 # the Free Software Foundation; either version 2 of the License, or
6 # (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software
15 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
17 # $Id: CiscoIOS.pm,v 1.1 2010-12-27 00:03:47 ivan Exp $
18 # Stanislav Sinyagin <ssinyagin@yahoo.com>
20 # Cisco IOS devices discovery
25 package Torrus::DevDiscover::CiscoIOS;
31 $Torrus::DevDiscover::registry{'CiscoIOS'} = {
33 'checkdevtype' => \&checkdevtype,
34 'discover' => \&discover,
35 'buildConfig' => \&buildConfig
42 'ciscoProducts' => '1.3.6.1.4.1.9.1',
44 'ciscoLS1010' => '1.3.6.1.4.1.9.1.107',
46 'ciscoImageTable' => '1.3.6.1.4.1.9.9.25.1.1',
47 # CISCO-ENHANCED-IMAGE-MIB
48 'ceImageTable' => '1.3.6.1.4.1.9.9.249.1.1.1',
49 # OLD-CISCO-MEMORY-MIB
50 'bufferElFree' => '1.3.6.1.4.1.9.2.1.9.0',
51 # CISCO-IPSEC-FLOW-MONITOR-MIB
52 'cipSecGlobalHcInOctets' => '1.3.6.1.4.1.9.9.171.1.3.1.4.0',
54 'cbgpPeerAddrFamilyName' => '1.3.6.1.4.1.9.9.187.1.2.3.1.3',
55 'cbgpPeerAcceptedPrefixes' => '1.3.6.1.4.1.9.9.187.1.2.4.1.1',
56 'cbgpPeerPrefixAdminLimit' => '1.3.6.1.4.1.9.9.187.1.2.4.1.3',
58 'ccarConfigTable' => '1.3.6.1.4.1.9.9.113.1.1.1',
59 'ccarConfigType' => '1.3.6.1.4.1.9.9.113.1.1.1.1.3',
60 'ccarConfigAccIdx' => '1.3.6.1.4.1.9.9.113.1.1.1.1.4',
61 'ccarConfigRate' => '1.3.6.1.4.1.9.9.113.1.1.1.1.5',
62 'ccarConfigLimit' => '1.3.6.1.4.1.9.9.113.1.1.1.1.6',
63 'ccarConfigExtLimit' => '1.3.6.1.4.1.9.9.113.1.1.1.1.7',
64 'ccarConfigConformAction' => '1.3.6.1.4.1.9.9.113.1.1.1.1.8',
65 'ccarConfigExceedAction' => '1.3.6.1.4.1.9.9.113.1.1.1.1.9',
67 'cvpdnSystemTunnelTotal' => '1.3.6.1.4.1.9.10.24.1.1.4.1.2'
71 # Not all interfaces are normally needed to monitor.
72 # You may override the interface filtering in devdiscover-siteconfig.pl:
73 # redefine $Torrus::DevDiscover::CiscoIOS::interfaceFilter
74 # or define $Torrus::DevDiscover::CiscoIOS::interfaceFilterOverlay
77 our $interfaceFilterOverlay;
78 my %ciscoInterfaceFilter;
80 if( not defined( $interfaceFilter ) )
82 $interfaceFilter = \%ciscoInterfaceFilter;
86 # Key is some unique symbolic name, does not mean anything
87 # ifType is the number to match the interface type
88 # ifDescr is the regexp to match the interface description
89 %ciscoInterfaceFilter =
92 'ifType' => 1, # other
101 'Virtual-AccessN' => {
102 'ifType' => 23, # ppp
103 'ifDescr' => '^Virtual-Access'
107 'ifType' => 23, # ppp
108 'ifDescr' => '^Dialer'
112 'ifType' => 24, # softwareLoopback
113 'ifDescr' => '^Loopback'
116 'SerialN:N-Bearer Channel' => {
117 'ifType' => 81, # ds0, Digital Signal Level 0
118 'ifDescr' => '^Serial.*Bearer\s+Channel'
121 'Voice Encapsulation (POTS) Peer: N' => {
122 'ifType' => 103 # voiceEncap
125 'Voice Over IP Peer: N' => {
126 'ifType' => 104 # voiceOverIp
129 'ATMN/N/N.N-atm subif' => {
130 'ifType' => 134, # atmSubInterface
131 'ifDescr' => '^ATM[0-9\/]+\.[0-9]+\s+subif'
135 'ifType' => 127, # docsCableMaclayer
136 'ifDescr' => '^Bundle'
140 'ifType' => 53, # propVirtual
145 'ifType' => 53, # propVirtual
152 # CISCO-VPDN-MGMT-MIB Tunnel Types
162 my $devdetails = shift;
164 if( not $dd->oidBaseMatch
166 $devdetails->snmpVar( $dd->oiddef('sysObjectID') ) ) )
171 my $session = $dd->session();
172 if( not $dd->checkSnmpTable('ciscoImageTable') )
174 if( $dd->checkSnmpTable('ceImageTable') )
176 # IOS XR has a new MIB for software image management
177 $devdetails->setCap('CiscoIOSXR');
185 # On some Layer3 switching devices, VlanXXX interfaces give some
186 # useful stats, while on others the stats are not relevant at all
188 if( $devdetails->param('CiscoIOS::enable-vlan-interfaces') ne 'yes' )
190 $interfaceFilter->{'VlanN'} = {
191 'ifType' => 53, # propVirtual
192 'ifDescr' => '^Vlan\d+'
196 # same thing with unrouted VLAN interfaces
197 if( $devdetails->param('CiscoIOS::enable-unrouted-vlan-interfaces')
200 $interfaceFilter->{'unrouted VLAN N'} => {
201 'ifType' => 53, # propVirtual
202 'ifDescr' => '^unrouted\s+VLAN\s+\d+'
206 &Torrus::DevDiscover::RFC2863_IF_MIB::addInterfaceFilter
207 ($devdetails, $interfaceFilter);
209 if( defined( $interfaceFilterOverlay ) )
211 &Torrus::DevDiscover::RFC2863_IF_MIB::addInterfaceFilter
212 ($devdetails, $interfaceFilterOverlay);
215 $devdetails->setCap('interfaceIndexingManaged');
224 3 => 'standardAcc' );
238 my $devdetails = shift;
240 my $session = $dd->session();
241 my $data = $devdetails->data();
243 # Old mkroutercfg used cisco-interface-counters
244 if( $Torrus::DevDiscover::CiscoIOS::useCiscoInterfaceCounters )
246 foreach my $interface ( values %{$data->{'interfaces'}} )
248 $interface->{'hasHCOctets'} = 0;
249 $interface->{'hasOctets'} = 0;
250 push( @{$interface->{'templates'}},
251 'CiscoIOS::cisco-interface-counters' );
256 # This is a well-known bug in IOS: HC counters are implemented,
257 # but always zero. We can catch this only for active interfaces.
259 foreach my $ifIndex ( sort {$a<=>$b} keys %{$data->{'interfaces'}} )
261 my $interface = $data->{'interfaces'}{$ifIndex};
263 if( $interface->{'hasHCOctets'} and
265 $devdetails->snmpVar( $dd->oiddef('ifHCInOctets')
266 . '.' . $ifIndex ) == 0 and
267 $devdetails->snmpVar( $dd->oiddef('ifInOctets')
268 . '.' . $ifIndex ) > 0
272 $devdetails->snmpVar( $dd->oiddef('ifHCOutOctets')
273 . '.' . $ifIndex ) == 0 and
274 $devdetails->snmpVar( $dd->oiddef('ifOutOctets')
275 . '.' . $ifIndex ) > 0
278 Debug('Disabling HC octets for ' . $ifIndex . ': ' .
279 $interface->{'ifDescr'});
281 $interface->{'hasHCOctets'} = 0;
282 $interface->{'hasHCUcastPkts'} = 0;
287 if( $devdetails->param('CiscoIOS::enable-membuf-stats') eq 'yes' )
289 # Old Memory Buffers, if we have bufferElFree we assume
290 # the rest as they are "required"
292 if( $dd->checkSnmpOID('bufferElFree') )
294 $devdetails->setCap('old-ciscoMemoryBuffers');
295 push( @{$data->{'templates'}},
296 'CiscoIOS::old-cisco-memory-buffers' );
300 if( $devdetails->param('CiscoIOS::disable-ipsec-stats') ne 'yes' )
302 if( $dd->checkSnmpOID('cipSecGlobalHcInOctets') )
304 $devdetails->setCap('ciscoIPSecGlobalStats');
305 push( @{$data->{'templates'}},
306 'CiscoIOS::cisco-ipsec-flow-globals' );
309 if( $dd->oidBaseMatch
311 $devdetails->snmpVar( $dd->oiddef('sysObjectID') ) ) )
313 $data->{'param'}{'snmp-oids-per-pdu'} = 10;
317 if( $devdetails->param('CiscoIOS::disable-bgp-stats') ne 'yes' )
320 $session->get_table( -baseoid =>
321 $dd->oiddef('cbgpPeerAcceptedPrefixes') );
322 if( defined( $peerTable ) and scalar( %{$peerTable} ) > 0 )
324 $devdetails->storeSnmpVars( $peerTable );
325 $devdetails->setCap('CiscoBGP');
328 $session->get_table( -baseoid =>
329 $dd->oiddef('cbgpPeerPrefixAdminLimit') );
330 $limitsTable = {} if not defined( $limitsTable );
332 $data->{'cbgpPeers'} = {};
334 # retrieve AS numbers for neighbor peers
335 Torrus::DevDiscover::RFC1657_BGP4_MIB::discover($dd, $devdetails);
337 # list of indices for peers that are not IPv4 Unicast
340 # Number of peers for each AS
345 getSnmpIndices( $dd->oiddef('cbgpPeerAcceptedPrefixes') ) )
347 my ($a1, $a2, $a3, $a4, $afi, $safi) = split(/\./, $INDEX);
348 my $peerIP = join('.', $a1, $a2, $a3, $a4);
352 'addrFamily' => 'IPv4 Unicast'
355 if( $afi != 1 and $safi != 1 )
357 push( @nonV4Unicast, $INDEX );
361 $devdetails->param('peer-ipaddr-description-' .
362 join('_', split('\.', $peerIP)));
363 if( length( $desc ) > 0 )
365 $peer->{'description'} = $desc;
368 my $peerAS = $data->{'bgpPeerAS'}{$peerIP};
369 if( defined( $peerAS ) )
371 $peer->{'peerAS'} = $data->{'bgpPeerAS'}{$peerIP};
372 $asNumbers{$peer->{'peerAS'}}++;
375 $devdetails->param('bgp-as-description-' . $peerAS);
376 if( length( $desc ) > 0 )
378 if( defined( $peer->{'description'} ) )
380 Warn('Conflicting descriptions for peer ' .
383 $peer->{'description'} = $desc;
388 Error('Cannot find AS number for BGP peer ' . $peerIP);
392 if( defined( $peer->{'description'} ) )
394 $peer->{'description'} .= ' ';
396 $peer->{'description'} .= '[' . $peerIP . ']';
398 $peer->{'prefixLimit'} =
399 $limitsTable->{$dd->oiddef('cbgpPeerPrefixAdminLimit') .
402 $data->{'cbgpPeers'}{$INDEX} = $peer;
405 if( scalar( @nonV4Unicast ) > 0 )
409 ( -baseoid => $dd->oiddef('cbgpPeerAddrFamilyName') );
411 foreach my $INDEX ( @nonV4Unicast )
413 my $peer = $data->{'cbgpPeers'}{$INDEX};
415 my $fam = $addrFamTable->{
416 $dd->oiddef('cbgpPeerAddrFamilyName') .
419 $peer->{'addrFamily'} = $fam;
420 $peer->{'otherAddrFamily'} = 1;
421 $peer->{'description'} .= ' ' . $fam;
425 # Construct the subtree names from AS, peer IP, and address
427 foreach my $INDEX ( keys %{$data->{'cbgpPeers'}} )
429 my $peer = $data->{'cbgpPeers'}{$INDEX};
431 my $subtreeName = 'AS' . $peer->{'peerAS'};
432 if( $asNumbers{$peer->{'peerAS'}} > 1 )
434 $subtreeName .= '_' . $peer->{'peerIP'};
437 if( $peer->{'otherAddrFamily'} )
439 my $fam = $data->{'cbgpPeers'}{$INDEX}{'addrFamily'};
441 $subtreeName .= '_' . $fam;
444 $peer->{'subtreeName'} = $subtreeName;
450 if( $devdetails->param('CiscoIOS::disable-car-stats') ne 'yes' )
453 $session->get_table( -baseoid =>
454 $dd->oiddef('ccarConfigTable') );
455 if( defined( $carTable ) and scalar( %{$carTable} ) > 0 )
457 $devdetails->storeSnmpVars( $carTable );
458 $devdetails->setCap('CiscoCAR');
460 $data->{'ccar'} = {};
464 getSnmpIndices( $dd->oiddef('ccarConfigType') ) )
466 my ($ifIndex, $dir, $carIndex) = split(/\./, $INDEX);
467 my $interface = $data->{'interfaces'}{$ifIndex};
470 'ifIndex' => $ifIndex,
472 'carIndex' => $carIndex };
474 $car->{'configType'} =
475 $ccarConfigType{ $carTable->{$dd->oiddef
479 $car->{'accIdx'} = $carTable->{$dd->oiddef
480 ('ccarConfigAccIdx') .
483 $car->{'rate'} = $carTable->{$dd->oiddef
488 $car->{'limit'} = $carTable->{$dd->oiddef
489 ('ccarConfigLimit') .
492 $car->{'extLimit'} = $carTable->{$dd->oiddef
493 ('ccarConfigExtLimit') .
495 $car->{'conformAction'} =
496 $ccarAction{ $carTable->{$dd->oiddef
497 ('ccarConfigConformAction') .
500 $car->{'exceedAction'} =
501 $ccarAction{ $carTable->{$dd->oiddef
502 ('ccarConfigExceedAction') .
505 $data->{'ccar'}{$INDEX} = $car;
511 if( $devdetails->param('CiscoIOS::disable-vpdn-stats') ne 'yes' )
513 if( $dd->checkSnmpTable( 'cvpdnSystemTunnelTotal' ) )
515 # Find the Tunnel type
516 my $tableTun = $session->get_table(
517 -baseoid => $dd->oiddef('cvpdnSystemTunnelTotal') );
521 $devdetails->setCap('ciscoVPDN');
523 $devdetails->storeSnmpVars( $tableTun );
525 # VPDN indexing: 1: l2f, 2: l2tp, 3: pptp
526 foreach my $typeIndex (
527 $devdetails->getSnmpIndices(
528 $dd->oiddef('cvpdnSystemTunnelTotal') ) )
530 Debug("CISCO-VPDN-MGMT-MIB: found Tunnel type " .
531 $tunnelType{$typeIndex} );
533 $data->{'ciscoVPDN'}{$typeIndex} = $tunnelType{$typeIndex};
539 if( $devdetails->param('CiscoIOS::short-device-comment') eq 'yes' )
541 # Remove serials from device comment
542 # 1841 chassis, Hw Serial#: 3625140487, Hw Revision: 6.0
544 $data->{'param'}{'comment'} =~ s/, Hw.*//o;
553 my $devdetails = shift;
557 my $data = $devdetails->data();
559 if( $devdetails->hasCap('CiscoBGP') )
562 $cb->addSubtree( $devNode, 'BGP_Prefixes',
564 'node-display-name' => 'BGP Prefixes',
565 'comment' => 'Accepted prefixes',
568 foreach my $INDEX ( sort
569 { $data->{'cbgpPeers'}{$a}{'subtreeName'} <=>
570 $data->{'cbgpPeers'}{$b}{'subtreeName'} }
571 keys %{$data->{'cbgpPeers'}} )
573 my $peer = $data->{'cbgpPeers'}{$INDEX};
576 'peer-index' => $INDEX,
577 'peer-ipaddr' => $peer->{'peerIP'},
578 'comment' => $peer->{'description'},
579 'descriptive-nickname' => $peer->{'subtreeName'},
580 'precedence' => 65000 - $peer->{'peerAS'}
583 if( defined( $peer->{'prefixLimit'} ) and
584 $peer->{'prefixLimit'} > 0 )
586 $param->{'upper-limit'} = $peer->{'prefixLimit'};
587 $param->{'graph-upper-limit'} = $peer->{'prefixLimit'} * 1.03;
591 ( $countersNode, $peer->{'subtreeName'}, $param,
592 ['CiscoIOS::cisco-bgp'] );
597 if( $devdetails->hasCap('CiscoCAR') )
600 $cb->addSubtree( $devNode, 'CAR_Stats', {
601 'comment' => 'Committed Access Rate statistics',
602 'node-display-name' => 'CAR', },
603 ['CiscoIOS::cisco-car-subtree']);
605 foreach my $INDEX ( sort keys %{$data->{'ccar'}} )
607 my $car = $data->{'ccar'}{$INDEX};
608 my $interface = $data->{'interfaces'}{$car->{'ifIndex'}};
611 $interface->{$data->{'nameref'}{'ifSubtreeName'}};
613 $subtreeName .= ($car->{'direction'} == 1) ? '_IN':'_OUT';
614 if( $car->{'carIndex'} > 1 )
616 $subtreeName .= '_' . $car->{'carIndex'};
620 'searchable' => 'yes',
621 'car-direction' => $car->{'direction'},
622 'car-index' => $car->{'carIndex'} };
624 $param->{'interface-name'} =
625 $interface->{'param'}{'interface-name'};
626 $param->{'interface-nick'} =
627 $interface->{'param'}{'interface-nick'};
628 $param->{'comment'} =
629 $interface->{'param'}{'comment'};
631 my $legend = sprintf("Type: %s;", $car->{'configType'});
632 if( $car->{'accIdx'} > 0 )
634 $legend .= sprintf("Access list: %d;", $car->{'accIdx'});
638 sprintf("Rate: %d bps; Limit: %d bytes; Ext limit: %d bytes;" .
639 "Conform action: %s; Exceed action: %s",
643 $car->{'conformAction'},
644 $car->{'exceedAction'});
646 $param->{'legend'} = $legend;
652 ['CiscoIOS::cisco-car']);
657 if( $devdetails->hasCap('ciscoVPDN') )
659 my $tunnelNode = $cb->addSubtree
660 ( $devNode, 'VPDN_Statistics',
661 {'node-display-name' => 'VPDN Statistics'},
662 [ 'CiscoIOS::cisco-vpdn-subtree' ] );
664 foreach my $INDEX ( sort keys %{$data->{'ciscoVPDN'}} )
666 my $tunnelProtocol = $data->{'ciscoVPDN'}{$INDEX};
668 $cb->addSubtree( $tunnelNode, $tunnelProtocol,
669 { 'comment' => $tunnelProtocol . ' information',
670 'tunIndex' => $INDEX,
671 'tunFile' => lc($tunnelProtocol) },
672 [ 'CiscoIOS::cisco-vpdn-leaf' ] );
685 # indent-tabs-mode: nil
686 # perl-indent-level: 4