buried more whitesapce
[torrus-plus.git] / plugins / cbqos / Collector / Cisco_cbQoS.pm
bloba285de97fa373f16aff9394f65ead8fc57503c87
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;
26 use strict;
27 use warnings;
29 use Torrus::ConfigTree;
30 use Torrus::Collector::SNMP;
31 use Torrus::Log;
32 use Net::hostent;
33 use Socket;
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;
51 my %oiddef =
53 # IF-MIB
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',
84 my %oidrev;
86 while( my($name, $oid) = each %oiddef )
88 $oidrev{$oid} = $name;
91 my $policyActionTranslation = {
92 'transmit' => 1,
93 'setIpDSCP' => 2,
94 'setIpPrecedence' => 3,
95 'setQosGroup' => 4,
96 'drop' => 5,
97 'setMplsExp' => 6,
98 'setAtmClp' => 7,
99 'setFrDe' => 8,
100 'setL2Cos' => 9,
101 'setDiscardClass' => 10
104 my %cbQosValueTranslation =
106 'cbQosIfType' => {
107 'mainInterface' => 1,
108 'subInterface' => 2,
109 'frDLCI' => 3,
110 'atmPVC' => 4,
111 'controlPlane' => 5,
112 'vlanPort' => 6 },
114 'cbQosPolicyDirection' => {
115 'input' => 1,
116 'output' => 2 },
118 'cbQosObjectsType' => {
119 'policymap' => 1,
120 'classmap' => 2,
121 'matchStatement' => 3,
122 'queueing' => 4,
123 'randomDetect' => 5,
124 'trafficShaping' => 6,
125 'police' => 7,
126 'set' => 8 },
128 'cbQosPoliceCfgConformAction' => $policyActionTranslation,
129 'cbQosPoliceCfgExceedAction' => $policyActionTranslation,
130 'cbQosPoliceCfgViolateAction' => $policyActionTranslation
134 sub translateCbQoSValue
136 my $value = shift;
137 my $name = shift;
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};
150 return $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 =
174 # 'policymap'
175 1 => {
176 'name-oid' => 'cbQosPolicyMapName' },
178 # 'classmap'
179 2 => {
180 'name-param' => 'cbqos-class-map-name',
181 'name-oid' => 'cbQosCMName' },
183 # 'matchStatement'
184 3 => {
185 'name-param' => 'cbqos-match-statement-name',
186 'name-oid' => 'cbQosMatchStmtName' },
188 # 'queueing'
189 4 => {
190 'name-param' => 'cbqos-queueing-bandwidth',
191 'name-oid' => 'cbQosQueueingCfgBandwidth' },
193 # 'randomDetect'
194 5 => {},
196 # 'trafficShaping'
197 6 => {
198 'name-param' => 'cbqos-shaping-rate',
199 'name-oid' => 'cbQosTSCfgRate' },
201 # 'police'
202 7 => {
203 'name-param' => 'cbqos-police-rate',
204 'name-oid' => 'cbQosPoliceCfgRate' }
207 my %ServicePolicyTable;
208 my %ServicePolicyMapping;
209 my %ObjectsTable;
210 my %CfgTable;
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
220 sub initTarget
222 my $collector = shift;
223 my $token = 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 );
233 my $hosthash =
234 Torrus::Collector::SNMP::getHostHash( $collector, $token );
235 if( not defined( $hosthash ) )
237 $collector->deleteTarget($token);
238 return 0;
240 $tref->{'hosthash'} = $hosthash;
242 return Torrus::Collector::Cisco_cbQoS::initTargetAttributes
243 ( $collector, $token );
247 # Recursively create the object name
249 sub make_full_name
251 my $objhash = shift;
252 my $hosthash = shift;
253 my $attr = shift;
254 my $cref = shift;
257 # Compose the object ID as "parent:type:name" string
258 my $objectID = '';
260 my $parentIndex = $attr->{'cbQosParentObjectsIndex'};
261 if( $parentIndex > 0 )
263 $objectID =
264 make_full_name($objhash, $hosthash,
265 $objhash->{$parentIndex}, $cref);
268 if( $objectID ) {
269 $objectID .= ':';
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;
286 return $objectID;
290 sub initTargetAttributes
292 my $collector = shift;
293 my $token = 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;
302 return 1;
305 my $hosthash = $tref->{'hosthash'};
307 if( Torrus::Collector::SNMP::isHostDead( $collector, $hosthash ) )
309 return 0;
312 if( not Torrus::Collector::SNMP::checkUnreachableRetry
313 ( $collector, $hosthash ) )
315 return 1;
318 my $ifDescr = $collector->param($token, 'cbqos-interface-name');
319 my $ifIndex =
320 Torrus::Collector::SNMP::lookupMap( $collector, $token,
321 $hosthash,
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;
328 return 1;
330 elsif( $ifIndex eq 'notfound' )
332 Error("Cannot find ifDescr mapping for $ifDescr at $hosthash");
333 return
336 my $session = Torrus::Collector::SNMP::openBlockingSession
337 ( $collector, $token, $hosthash );
338 if( not defined($session) )
340 return 0;
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);
351 my $ref = {};
352 $ServicePolicyTable{$hosthash} = $ref;
354 my $result =
355 $session->get_table
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 );
370 else
372 return 0;
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");
387 else
389 $ref->{$policyIndex}{$entryName} = $val;
393 my $mapRef = {};
394 $ServicePolicyMapping{$hosthash} = $mapRef;
396 for my $policyIndex ( keys %{$ref} )
398 my $mapString = '';
399 for my $entryName ( @servicePolicyTableEntries )
401 $mapString .=
402 sprintf( '%d:', $ref->{$policyIndex}{$entryName} );
404 $mapRef->{$mapString} = $policyIndex;
408 # Retrieve config information from cbQosxxxCfgTable
410 if( not defined $CfgTable{$hosthash} )
412 my $ref = {};
413 $CfgTable{$hosthash} = $ref;
415 for my $table ( 'cbQosPolicyMapName', 'cbQosCMName',
416 'cbQosMatchStmtName', 'cbQosQueueingCfgBandwidth',
417 'cbQosTSCfgRate', 'cbQosPoliceCfgRate' )
419 my $result =
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
427 $val =~ s/^\s+//;
428 $val =~ s/\s+$//;
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");
439 else
441 $ref->{$cfgIndex}{$entryName} = $val;
448 # Retrieve and translate cbQosObjectsTable
450 if( not defined $ObjectsTable{$hosthash} )
452 my $ref = {};
453 $ObjectsTable{$hosthash} = $ref;
455 my $result =
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 );
470 else
472 return 0;
476 my $confIndexOid = $oiddef{'cbQosConfigIndex'};
477 my $objTypeOid = $oiddef{'cbQosObjectsType'};
479 my %objects;
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} );
503 my $objectID =
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};
528 my $mapString = '';
529 for my $entryName ( @servicePolicyTableEntries )
531 $mapString .=
532 sprintf( '%d:', $policyParamValues{$entryName} );
535 my $thePolicyIndex = $mapRef->{$mapString};
536 if( not defined( $thePolicyIndex ) )
538 Error('Cannot find cbQosServicePolicyTable mapping for ' .
539 $mapString);
540 return
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);
554 return
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;
580 sub postProcess
582 my $collector = shift;
583 my $cref = shift;
585 # We use some SNMP collector internals
586 my $scref = $collector->collectorData( 'snmp' );
588 my %remapping_hosts;
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);
626 return;
630 # Callback executed by Collector
632 sub deleteTarget
634 my $collector = shift;
635 my $token = shift;
637 my $cref = $collector->collectorData( 'cisco-cbqos' );
639 delete $cref->{'QosEnabled'}{$token};
641 Torrus::Collector::SNMP::deleteTarget( $collector, $token );
643 return;
651 # Local Variables:
652 # mode: perl
653 # indent-tabs-mode: nil
654 # perl-indent-level: 4
655 # End: