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., 675 Mass Ave, Cambridge, MA 02139, USA.
17 # Stanislav Sinyagin <ssinyagin@yahoo.com>
19 ## no critic (Modules::RequireFilenameMatchesPackage)
22 package Torrus
::Collector
::Cisco_cbQoS
;
24 use Torrus
::Collector
::Cisco_cbQoS_Params
;
29 use Torrus
::ConfigTree
;
30 use Torrus
::Collector
::SNMP
;
34 use Net
::SNMP
qw(:snmp);
36 # Register the collector type
37 $Torrus::Collector
::collectorTypes
{'cisco-cbqos'} = 1;
40 # List of needed parameters and default values
42 $Torrus::Collector
::params
{'cisco-cbqos'} =
43 \
%Torrus::Collector
::Cisco_cbQoS_Params
::requiredLeafParams
;
45 # Copy parameters from SNMP collector
46 while( my($key, $val) = each %{$Torrus::Collector
::params
{'snmp'}} )
48 $Torrus::Collector
::params
{'cisco-cbqos'}{$key} = $val;
54 'ifDescr' => '1.3.6.1.2.1.2.2.1.2',
56 # CISCO-CLASS-BASED-QOS-MIB
57 'cbQosServicePolicyTable' => '1.3.6.1.4.1.9.9.166.1.1.1',
58 'cbQosPolicyIndex' => '1.3.6.1.4.1.9.9.166.1.1.1.1.1',
59 'cbQosIfType' => '1.3.6.1.4.1.9.9.166.1.1.1.1.2',
60 'cbQosPolicyDirection' => '1.3.6.1.4.1.9.9.166.1.1.1.1.3',
61 'cbQosIfIndex' => '1.3.6.1.4.1.9.9.166.1.1.1.1.4',
62 'cbQosFrDLCI' => '1.3.6.1.4.1.9.9.166.1.1.1.1.5',
63 'cbQosAtmVPI' => '1.3.6.1.4.1.9.9.166.1.1.1.1.6',
64 'cbQosAtmVCI' => '1.3.6.1.4.1.9.9.166.1.1.1.1.7',
65 # These two are accepted and ignored, probably will be supported later.
66 # In some older IOSes these object don't present in the table
67 'cbQosEntityIndex' => '1.3.6.1.4.1.9.9.166.1.1.1.1.8',
68 'cbQosVlanIndex' => '1.3.6.1.4.1.9.9.166.1.1.1.1.9',
70 'cbQosObjectsTable' => '1.3.6.1.4.1.9.9.166.1.5.1',
71 'cbQosObjectsIndex' => '1.3.6.1.4.1.9.9.166.1.5.1.1.1',
72 'cbQosConfigIndex' => '1.3.6.1.4.1.9.9.166.1.5.1.1.2',
73 'cbQosObjectsType' => '1.3.6.1.4.1.9.9.166.1.5.1.1.3',
74 'cbQosParentObjectsIndex' => '1.3.6.1.4.1.9.9.166.1.5.1.1.4',
76 'cbQosPolicyMapName' => '1.3.6.1.4.1.9.9.166.1.6.1.1.1',
77 'cbQosCMName' => '1.3.6.1.4.1.9.9.166.1.7.1.1.1',
78 'cbQosMatchStmtName' => '1.3.6.1.4.1.9.9.166.1.8.1.1.1',
79 'cbQosQueueingCfgBandwidth' => '1.3.6.1.4.1.9.9.166.1.9.1.1.1',
80 'cbQosPoliceCfgRate' => '1.3.6.1.4.1.9.9.166.1.12.1.1.1',
81 'cbQosTSCfgRate' => '1.3.6.1.4.1.9.9.166.1.13.1.1.1',
86 while( my($name, $oid) = each %oiddef )
88 $oidrev{$oid} = $name;
91 my $policyActionTranslation = {
94 'setIpPrecedence' => 3,
101 'setDiscardClass' => 10
104 my %cbQosValueTranslation =
107 'mainInterface' => 1,
114 'cbQosPolicyDirection' => {
118 'cbQosObjectsType' => {
121 'matchStatement' => 3,
124 'trafficShaping' => 6,
128 'cbQosPoliceCfgConformAction' => $policyActionTranslation,
129 'cbQosPoliceCfgExceedAction' => $policyActionTranslation,
130 'cbQosPoliceCfgViolateAction' => $policyActionTranslation
134 sub translateCbQoSValue
139 if( defined( $cbQosValueTranslation{$name} ) )
141 if( not defined( $cbQosValueTranslation{$name}{$value} ) )
143 die('Unknown value to translate for ' . $name .
144 ': "' . $value . '"');
147 $value = $cbQosValueTranslation{$name}{$value};
154 my %servicePolicyTableParams =
156 'cbQosIfType' => 'cbqos-interface-type',
157 'cbQosPolicyDirection' => 'cbqos-direction',
158 'cbQosFrDLCI' => 'cbqos-fr-dlci',
159 'cbQosAtmVPI' => 'cbqos-atm-vpi',
160 'cbQosAtmVCI' => 'cbqos-atm-vci'
164 # This list defines the order for entries mapping in
165 # $ServicePolicyMapping
167 my @servicePolicyTableEntries =
168 ( 'cbQosIfType', 'cbQosPolicyDirection', 'cbQosIfIndex',
169 'cbQosFrDLCI', 'cbQosAtmVPI', 'cbQosAtmVCI' );
172 my %objTypeAttributes =
176 'name-oid' => 'cbQosPolicyMapName' },
180 'name-param' => 'cbqos-class-map-name',
181 'name-oid' => 'cbQosCMName' },
185 'name-param' => 'cbqos-match-statement-name',
186 'name-oid' => 'cbQosMatchStmtName' },
190 'name-param' => 'cbqos-queueing-bandwidth',
191 'name-oid' => 'cbQosQueueingCfgBandwidth' },
198 'name-param' => 'cbqos-shaping-rate',
199 'name-oid' => 'cbQosTSCfgRate' },
203 'name-param' => 'cbqos-police-rate',
204 'name-oid' => 'cbQosPoliceCfgRate' }
207 my %ServicePolicyTable;
208 my %ServicePolicyMapping;
213 # This is first executed per target
215 $Torrus::Collector
::initTarget
{'cisco-cbqos'} =
216 \
&Torrus
::Collector
::Cisco_cbQoS
::initTarget
;
218 # Derive 'snmp-object' from cbQoS maps and pass the control to SNMP collector
222 my $collector = shift;
225 my $tref = $collector->tokenData( $token );
226 my $cref = $collector->collectorData( 'cisco-cbqos' );
228 $cref->{'QosEnabled'}{$token} = 1;
230 $collector->registerDeleteCallback
231 ( $token, \
&Torrus
::Collector
::Cisco_cbQoS
::deleteTarget
);
234 Torrus
::Collector
::SNMP
::getHostHash
( $collector, $token );
235 if( not defined( $hosthash ) )
237 $collector->deleteTarget($token);
240 $tref->{'hosthash'} = $hosthash;
242 return Torrus
::Collector
::Cisco_cbQoS
::initTargetAttributes
243 ( $collector, $token );
247 # Recursively create the object name
252 my $hosthash = shift;
257 # Compose the object ID as "parent:type:name" string
260 my $parentIndex = $attr->{'cbQosParentObjectsIndex'};
261 if( $parentIndex > 0 )
264 make_full_name
($objhash, $hosthash,
265 $objhash->{$parentIndex}, $cref);
272 my $objType = $attr->{'cbQosObjectsType'};
274 my $objCfgIndex = $attr->{'cbQosConfigIndex'};
276 my $objNameOid = $objTypeAttributes{$objType}{'name-oid'};
278 if( defined($objNameOid) )
280 $objectID .= $CfgTable{$hosthash}{
281 $objCfgIndex}{$objNameOid};
284 $objectID .= ':' . $objType;
290 sub initTargetAttributes
292 my $collector = shift;
295 my $tref = $collector->tokenData( $token );
296 my $cref = $collector->collectorData( 'cisco-cbqos' );
298 if( Torrus
::Collector
::SNMP
::activeMappingSessions
() > 0 )
300 # ifDescr mapping tables are not yet ready
301 $cref->{'cbQoSNeedsRemapping'}{$token} = 1;
305 my $hosthash = $tref->{'hosthash'};
307 if( Torrus
::Collector
::SNMP
::isHostDead
( $collector, $hosthash ) )
312 if( not Torrus
::Collector
::SNMP
::checkUnreachableRetry
313 ( $collector, $hosthash ) )
318 my $ifDescr = $collector->param($token, 'cbqos-interface-name');
320 Torrus
::Collector
::SNMP
::lookupMap
( $collector, $token,
322 $oiddef{'ifDescr'}, $ifDescr );
324 if( not defined( $ifIndex ) )
326 Debug
('ifDescr mapping tables are not yet ready for ' . $hosthash);
327 $cref->{'cbQoSNeedsRemapping'}{$token} = 1;
330 elsif( $ifIndex eq 'notfound' )
332 Error
("Cannot find ifDescr mapping for $ifDescr at $hosthash");
336 my $session = Torrus
::Collector
::SNMP
::openBlockingSession
337 ( $collector, $token, $hosthash );
338 if( not defined($session) )
343 my $maxrepetitions = $collector->param($token, 'snmp-maxrepetitions');
345 # Retrieve and translate cbQosServicePolicyTable
347 if( not defined $ServicePolicyTable{$hosthash} )
349 Debug
('Retrieving Cisco cbQoS maps from ' . $hosthash);
352 $ServicePolicyTable{$hosthash} = $ref;
356 ( -baseoid
=> $oiddef{'cbQosServicePolicyTable'},
357 -maxrepetitions
=> $maxrepetitions );
358 if( not defined( $result ) )
360 Error
('Error retrieving cbQosServicePolicyTable from ' .
361 $hosthash . ': ' . $session->error());
363 # When the remote agent is reacheable, but system objecs are
364 # not implemented, we get a positive error_status
365 if( $session->error_status() == 0 )
367 return Torrus
::Collector
::SNMP
::probablyDead
368 ( $collector, $hosthash );
376 while( my( $oid, $val ) = each %{$result} )
378 my $prefixlen = rindex( $oid, '.' );
379 my $prefixOid = substr( $oid, 0, $prefixlen );
380 my $policyIndex = substr( $oid, $prefixlen + 1 );
382 my $entryName = $oidrev{$prefixOid};
383 if( not defined $entryName )
385 Warn
("Unknown OID: $prefixOid");
389 $ref->{$policyIndex}{$entryName} = $val;
394 $ServicePolicyMapping{$hosthash} = $mapRef;
396 for my $policyIndex ( keys %{$ref} )
399 for my $entryName ( @servicePolicyTableEntries )
402 sprintf( '%d:', $ref->{$policyIndex}{$entryName} );
404 $mapRef->{$mapString} = $policyIndex;
408 # Retrieve config information from cbQosxxxCfgTable
410 if( not defined $CfgTable{$hosthash} )
413 $CfgTable{$hosthash} = $ref;
415 for my $table ( 'cbQosPolicyMapName', 'cbQosCMName',
416 'cbQosMatchStmtName', 'cbQosQueueingCfgBandwidth',
417 'cbQosTSCfgRate', 'cbQosPoliceCfgRate' )
420 $session->get_table( -baseoid
=> $oiddef{$table},
421 -maxrepetitions
=> $maxrepetitions );
422 if( defined( $result ) )
424 while( my( $oid, $val ) = each %{$result} )
426 # Chop heading and trailing space
430 my $prefixlen = rindex( $oid, '.' );
431 my $prefixOid = substr( $oid, 0, $prefixlen );
432 my $cfgIndex = substr( $oid, $prefixlen + 1 );
434 my $entryName = $oidrev{$prefixOid};
435 if( not defined $entryName )
437 Warn
("Unknown OID: $prefixOid");
441 $ref->{$cfgIndex}{$entryName} = $val;
448 # Retrieve and translate cbQosObjectsTable
450 if( not defined $ObjectsTable{$hosthash} )
453 $ObjectsTable{$hosthash} = $ref;
456 $session->get_table( -baseoid
=> $oiddef{'cbQosObjectsTable'},
457 -maxrepetitions
=> $maxrepetitions );
458 if( not defined( $result ) )
460 Error
('Error retrieving cbQosObjectsTable from ' . $hosthash .
461 ': ' . $session->error());
463 # When the remote agent is reacheable, but system objecs are
464 # not implemented, we get a positive error_status
465 if( $session->error_status() == 0 )
467 return Torrus
::Collector
::SNMP
::probablyDead
468 ( $collector, $hosthash );
476 my $confIndexOid = $oiddef{'cbQosConfigIndex'};
477 my $objTypeOid = $oiddef{'cbQosObjectsType'};
481 while( my( $oid, $val ) = each %{$result} )
483 my $prefixlen = rindex( $oid, '.' );
484 my $objIndex = substr( $oid, $prefixlen + 1 );
485 my $prefixOid = substr( $oid, 0, $prefixlen );
487 $prefixlen = rindex( $prefixOid, '.' );
488 my $policyIndex = substr( $prefixOid, $prefixlen + 1 );
489 $prefixOid = substr( $prefixOid, 0, $prefixlen );
491 my $entryName = $oidrev{$prefixOid};
493 $objects{$policyIndex}{$objIndex}{$entryName} = $val;
496 while( my( $policyIndex, $objhash ) = each %objects )
498 while( my( $objIndex, $attr ) = each %{$objhash} )
500 my $objType = $attr->{'cbQosObjectsType'};
501 next if not defined( $objTypeAttributes{$objType} );
504 make_full_name
( $objhash, $hosthash, $attr, $cref );
506 $ref->{$policyIndex}{$objectID} = $objIndex;
511 # Finished retrieving tables
512 # now find the snmp-object from token parameters
514 # Prepare values for cbQosServicePolicyTable match
516 my %policyParamValues = ( 'cbQosIfIndex' => $ifIndex );
517 while( my($name, $param) = each %servicePolicyTableParams )
519 my $val = $collector->param($token, $param);
520 $val = translateCbQoSValue
( $val, $name );
521 $policyParamValues{$name} = $val;
524 # Find the entry in cbQosServicePolicyTable
526 my $mapRef = $ServicePolicyMapping{$hosthash};
529 for my $entryName ( @servicePolicyTableEntries )
532 sprintf( '%d:', $policyParamValues{$entryName} );
535 my $thePolicyIndex = $mapRef->{$mapString};
536 if( not defined( $thePolicyIndex ) )
538 Error
('Cannot find cbQosServicePolicyTable mapping for ' .
543 # compose the object ID from token parameters as "parent:type:name" string
545 my $theObjectID = $collector->param($token, 'cbqos-full-name');
547 my $theObjectIndex = $ObjectsTable{$hosthash}->{
548 $thePolicyIndex}{$theObjectID};
550 if( not defined( $theObjectIndex ) )
552 Error
('Cannot find object index for ' . $thePolicyIndex . ':' .
553 '--' . $theObjectID);
557 # Finally we got the object to monitor!
559 # Prepare the object for snmp collector
560 my $theOid = $collector->param( $token, 'snmp-object' );
561 $theOid =~ s/POL/$thePolicyIndex/;
562 $theOid =~ s/OBJ/$theObjectIndex/;
563 $collector->setParam( $token, 'snmp-object', $theOid );
565 return Torrus
::Collector
::SNMP
::initTargetAttributes
( $collector, $token );
569 # Main collector cycle is actually the SNMP collector
571 $Torrus::Collector
::runCollector
{'cisco-cbqos'} =
572 \
&Torrus
::Collector
::SNMP
::runCollector
;
575 # Execute this after the collector has finished
577 $Torrus::Collector
::postProcess
{'cisco-cbqos'} =
578 \
&Torrus
::Collector
::Cisco_cbQoS
::postProcess
;
582 my $collector = shift;
585 # We use some SNMP collector internals
586 my $scref = $collector->collectorData( 'snmp' );
590 # Flush all QoS object mapping
591 for my $token ( keys %{$scref->{'needsRemapping'}},
592 keys %{$cref->{'cbQoSNeedsRemapping'}} )
594 if( $cref->{'QosEnabled'}{$token} )
596 my $tref = $collector->tokenData( $token );
597 my $hosthash = $tref->{'hosthash'};
599 if( not defined($remapping_hosts{$hosthash}) )
601 $remapping_hosts{$hosthash} = [];
603 push(@
{$remapping_hosts{$hosthash}}, $token);
607 while(my ($hosthash, $tokens) = each %remapping_hosts )
609 delete $ServicePolicyTable{$hosthash};
610 delete $ServicePolicyMapping{$hosthash};
611 delete $ObjectsTable{$hosthash};
612 delete $CfgTable{$hosthash};
614 for my $token (@
{$tokens})
616 delete $scref->{'needsRemapping'}{$token};
617 delete $cref->{'cbQoSNeedsRemapping'}{$token};
618 if( not Torrus
::Collector
::Cisco_cbQoS
::initTargetAttributes
619 ( $collector, $token ) )
621 $collector->deleteTarget($token);
630 # Callback executed by Collector
634 my $collector = shift;
637 my $cref = $collector->collectorData( 'cisco-cbqos' );
639 delete $cref->{'QosEnabled'}{$token};
641 Torrus
::Collector
::SNMP
::deleteTarget
( $collector, $token );
653 # indent-tabs-mode: nil
654 # perl-indent-level: 4