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: RFC2863_IF_MIB.pm,v 1.1 2010-12-27 00:03:57 ivan Exp $
18 # Stanislav Sinyagin <ssinyagin@yahoo.com>
20 # Standard IF_MIB discovery, which should apply to most devices
22 package Torrus::DevDiscover::RFC2863_IF_MIB;
28 $Torrus::DevDiscover::registry{'RFC2863_IF_MIB'} = {
30 'checkdevtype' => \&checkdevtype,
31 'discover' => \&discover,
32 'buildConfig' => \&buildConfig,
33 'buildGlobalConfig' => \&buildGlobalConfig
39 'ifTable' => '1.3.6.1.2.1.2.2',
40 'ifDescr' => '1.3.6.1.2.1.2.2.1.2',
41 'ifType' => '1.3.6.1.2.1.2.2.1.3',
42 'ifSpeed' => '1.3.6.1.2.1.2.2.1.5',
43 'ifPhysAddress' => '1.3.6.1.2.1.2.2.1.6',
44 'ifAdminStatus' => '1.3.6.1.2.1.2.2.1.7',
45 'ifOperStatus' => '1.3.6.1.2.1.2.2.1.8',
46 'ifInOctets' => '1.3.6.1.2.1.2.2.1.10',
47 'ifInUcastPkts' => '1.3.6.1.2.1.2.2.1.11',
48 'ifInDiscards' => '1.3.6.1.2.1.2.2.1.13',
49 'ifInErrors' => '1.3.6.1.2.1.2.2.1.14',
50 'ifOutOctets' => '1.3.6.1.2.1.2.2.1.16',
51 'ifOutUcastPkts' => '1.3.6.1.2.1.2.2.1.17',
52 'ifOutDiscards' => '1.3.6.1.2.1.2.2.1.19',
53 'ifOutErrors' => '1.3.6.1.2.1.2.2.1.20',
54 'ifXTable' => '1.3.6.1.2.1.31.1.1',
55 'ifName' => '1.3.6.1.2.1.31.1.1.1.1',
56 'ifHCInOctets' => '1.3.6.1.2.1.31.1.1.1.6',
57 'ifHCInUcastPkts' => '1.3.6.1.2.1.31.1.1.1.7',
58 'ifHCOutOctets' => '1.3.6.1.2.1.31.1.1.1.10',
59 'ifHCOutUcastPkts' => '1.3.6.1.2.1.31.1.1.1.11',
60 'ifHighSpeed' => '1.3.6.1.2.1.31.1.1.1.15',
61 'ifAlias' => '1.3.6.1.2.1.31.1.1.1.18'
66 # Just curious, are there any devices without ifTable?
70 my $devdetails = shift;
72 return $dd->checkSnmpTable('ifTable');
79 my $devdetails = shift;
81 my $session = $dd->session();
84 $session->get_table( -baseoid => $dd->oiddef('ifTable') );
85 if( not defined $ifTable )
87 Error('Cannot retrieve ifTable');
90 $devdetails->storeSnmpVars( $ifTable );
93 $session->get_table( -baseoid => $dd->oiddef('ifXTable') );
94 if( defined $ifXTable )
96 $devdetails->storeSnmpVars( $ifXTable );
97 $devdetails->setCap('ifXTable');
99 if( $devdetails->hasOID( $dd->oiddef('ifName') ) )
101 $devdetails->setCap('ifName');
104 if( $devdetails->hasOID( $dd->oiddef('ifAlias') ) )
106 $devdetails->setCap('ifAlias');
109 if( $devdetails->hasOID( $dd->oiddef('ifHighSpeed') ) )
111 $devdetails->setCap('ifHighSpeed');
115 ## Fill in per-interface data. This is normally done within discover(),
116 ## but in our case we want to give other modules more control as early
119 # Define the tables used for subtree naming, interface indexing,
120 # and RRD file naming
121 my $data = $devdetails->data();
123 $data->{'param'}{'has-inout-leaves'} = 'yes';
125 ## Set default interface index mapping
127 $data->{'nameref'}{'ifSubtreeName'} = 'ifDescrT';
128 $data->{'nameref'}{'ifReferenceName'} = 'ifDescr';
130 if( $devdetails->hasCap('ifName') )
132 $data->{'nameref'}{'ifNick'} = 'ifNameT';
136 $data->{'nameref'}{'ifNick'} = 'ifDescrT';
139 if( $devdetails->hasCap('ifAlias') )
141 $data->{'nameref'}{'ifComment'} = 'ifAlias';
144 # Pre-populate the interfaces table, so that other modules may
145 # delete unneeded interfaces
147 $devdetails->param('RFC2863_IF_MIB::list-admindown-interfaces')
149 my $includeNotpresent =
150 $devdetails->param('RFC2863_IF_MIB::list-notpresent-interfaces')
152 my $excludeOperDown =
153 $devdetails->param('RFC2863_IF_MIB::exclude-down-interfaces')
156 ( $devdetails->getSnmpIndices( $dd->oiddef('ifDescr') ) )
159 $devdetails->snmpVar($dd->oiddef('ifAdminStatus') .'.'. $ifIndex);
161 $devdetails->snmpVar($dd->oiddef('ifOperStatus') .'.'. $ifIndex);
163 if( ( $admStatus == 1 or $includeAdmDown ) and
164 ( $operStatus != 6 or $includeNotpresent ) and
165 ( $operStatus != 2 or not $excludeOperDown ) )
168 $data->{'interfaces'}{$ifIndex} = $interface;
170 $interface->{'param'} = {};
171 $interface->{'vendor_templates'} = [];
173 $interface->{'ifType'} =
174 $devdetails->snmpVar($dd->oiddef('ifType') . '.' . $ifIndex);
176 my $descr = $devdetails->snmpVar($dd->oiddef('ifDescr') .
178 $interface->{'ifDescr'} = $descr;
180 # Some SNMP agents send extra zero byte at the end
182 $interface->{'ifDescrT'} = $descr;
184 if( $devdetails->hasCap('ifName') )
186 my $iname = $devdetails->snmpVar($dd->oiddef('ifName') .
190 $iname = $interface->{'ifDescr'};
191 Warn('Empty or invalid ifName for interface ' . $iname);
193 $interface->{'ifName'} = $iname;
195 $interface->{'ifNameT'} = $iname;
198 if( $devdetails->hasCap('ifAlias') )
200 $interface->{'ifAlias'} =
201 $devdetails->snmpVar($dd->oiddef('ifAlias') .
206 if( $devdetails->hasCap('ifHighSpeed') )
209 $devdetails->snmpVar($dd->oiddef('ifHighSpeed') . '.' .
220 $devdetails->snmpVar($dd->oiddef('ifSpeed') . '.' .
226 $interface->{'ifSpeed'} = $bw;
231 ## Process hints on interface indexing
232 ## The capability 'interfaceIndexingManaged' disables the hints
233 ## and lets the vendor discovery module to operate the indexing
235 if( not $devdetails->hasCap('interfaceIndexingManaged') and
236 not $devdetails->hasCap('interfaceIndexingPersistent') )
239 $devdetails->param('RFC2863_IF_MIB::ifindex-map-hint');
240 if( defined( $hint ) )
242 if( $hint eq 'ifName' )
244 if( not $devdetails->hasCap('ifName') )
246 Error('Cannot use ifName interface mapping: ifName is '.
247 'not supported by device');
252 $data->{'nameref'}{'ifReferenceName'} = 'ifName';
253 $data->{'param'}{'ifindex-table'} = '$ifName';
256 elsif( $hint eq 'ifPhysAddress' )
258 $data->{'param'}{'ifindex-map'} = '$IFIDX_MAC';
259 retrieveMacAddresses( $dd, $devdetails );
261 elsif( $hint eq 'ifIndex' )
263 $devdetails->setCap('interfaceIndexingPersistent');
267 Error('Unknown value of RFC2863_IF_MIB::ifindex-map-hint: ' .
273 $devdetails->param('RFC2863_IF_MIB::subtree-name-hint');
274 if( defined( $hint ) )
276 if( $hint eq 'ifName' )
278 $data->{'nameref'}{'ifSubtreeName'} = 'ifNameT';
282 Error('Unknown value of RFC2863_IF_MIB::subtree-name-hint: ' .
288 $devdetails->param('RFC2863_IF_MIB::nodeid-hint');
289 if( defined( $hint ) )
291 $data->{'nameref'}{'ifNodeid'} = $hint;
295 if( $devdetails->hasCap('interfaceIndexingPersistent') )
297 $data->{'param'}{'ifindex-map'} = '$IFIDX_IFINDEX';
298 storeIfIndexParams( $devdetails );
301 if( not defined( $data->{'nameref'}{'ifNodeid'} ) )
303 $data->{'nameref'}{'ifNodeid'} = 'ifNodeid';
306 if( not defined( $data->{'nameref'}{'ifNodeidPrefix'} ) )
308 $data->{'nameref'}{'ifNodeidPrefix'} = 'ifNodeidPrefix';
311 # Filter out the interfaces if needed
313 if( ref( $data->{'interfaceFilter'} ) )
315 foreach my $ifIndex ( sort {$a<=>$b} keys %{$data->{'interfaces'}} )
317 my $interface = $data->{'interfaces'}{$ifIndex};
320 foreach my $filterHash ( @{$data->{'interfaceFilter'}} )
323 foreach my $filter ( values %{$filterHash} )
327 if( defined( $filter->{'ifType'} ) and
328 $interface->{'ifType'} == $filter->{'ifType'} )
330 if( not defined( $filter->{'ifDescr'} ) or
331 $interface->{'ifDescr'} =~ $filter->{'ifDescr'} )
341 Debug('Excluding interface: ' .
342 $interface->{$data->{'nameref'}{'ifReferenceName'}});
343 delete $data->{'interfaces'}{$ifIndex};
348 my $suppressHCCounters =
349 $devdetails->param('RFC2863_IF_MIB::suppress-hc-counters') eq 'yes';
351 # Explore each interface capability
353 foreach my $ifIndex ( keys %{$data->{'interfaces'}} )
355 my $interface = $data->{'interfaces'}{$ifIndex};
357 if( $devdetails->hasOID( $dd->oiddef('ifInOctets') .
360 $devdetails->hasOID( $dd->oiddef('ifOutOctets') .
363 $interface->{'hasOctets'} = 1;
366 if( $devdetails->hasOID( $dd->oiddef('ifInUcastPkts') .
369 $devdetails->hasOID( $dd->oiddef('ifOutUcastPkts') .
372 $interface->{'hasUcastPkts'} = 1;
375 if( $devdetails->hasOID( $dd->oiddef('ifInDiscards') .
378 $interface->{'hasInDiscards'} = 1;
381 if( $devdetails->hasOID( $dd->oiddef('ifOutDiscards') .
384 $interface->{'hasOutDiscards'} = 1;
387 if( $devdetails->hasOID( $dd->oiddef('ifInErrors') .
390 $interface->{'hasInErrors'} = 1;
393 if( $devdetails->hasOID( $dd->oiddef('ifOutErrors') .
396 $interface->{'hasOutErrors'} = 1;
399 if( $devdetails->hasCap('ifXTable') and not $suppressHCCounters )
401 if( $devdetails->hasOID( $dd->oiddef('ifHCInOctets') .
404 $devdetails->hasOID( $dd->oiddef('ifHCOutOctets') .
407 $interface->{'hasHCOctets'} = 1;
410 if( $devdetails->hasOID( $dd->oiddef('ifHCInUcastPkts') .
413 $devdetails->hasOID( $dd->oiddef('ifHCOutUcastPkts') .
416 $interface->{'hasHCUcastPkts'} = 1;
421 push( @{$data->{'templates'}}, 'RFC2863_IF_MIB::rfc2863-ifmib-hostlevel' );
429 my $devdetails = shift;
432 my $globalData = shift;
434 my $data = $devdetails->data();
436 if( scalar( keys %{$data->{'interfaces'}} ) == 0 )
441 # Make sure that ifNick and ifSubtreeName are unique across interfaces
443 uniqueEntries( $devdetails, $data->{'nameref'}{'ifNick'} );
444 uniqueEntries( $devdetails, $data->{'nameref'}{'ifSubtreeName'} );
446 # If other discovery modules don't set nodeid reference, fall back to
447 # default interface reference
450 # Build interface parameters
454 foreach my $ifIndex ( keys %{$data->{'interfaces'}} )
456 my $interface = $data->{'interfaces'}{$ifIndex};
458 next if $interface->{'excluded'};
461 $interface->{'param'}{'searchable'} = 'yes';
463 $interface->{'param'}{'interface-iana-type'} = $interface->{'ifType'};
465 $interface->{'param'}{'interface-name'} =
466 $interface->{$data->{'nameref'}{'ifReferenceName'}};
468 $interface->{'param'}{'node-display-name'} =
469 $interface->{$data->{'nameref'}{'ifReferenceName'}};
471 $interface->{'param'}{'interface-nick'} =
472 $interface->{$data->{'nameref'}{'ifNick'}};
474 if( not defined( $interface->{$data->{'nameref'}{'ifNodeidPrefix'}} ) )
476 $interface->{$data->{'nameref'}{'ifNodeidPrefix'}} =
477 'if//%nodeid-device%//';
480 if( not defined( $interface->{$data->{'nameref'}{'ifNodeid'}} ) )
482 $interface->{$data->{'nameref'}{'ifNodeid'}} =
483 $interface->{$data->{'nameref'}{'ifReferenceName'}};
486 # A per-interface value which is used by leafs in IF-MIB templates
487 $interface->{'param'}{'nodeid-interface'} =
488 $interface->{$data->{'nameref'}{'ifNodeidPrefix'}} .
489 $interface->{$data->{'nameref'}{'ifNodeid'}};
491 $interface->{'param'}{'nodeid'} = '%nodeid-interface%';
493 if( defined $data->{'nameref'}{'ifComment'} and
494 not defined( $interface->{'param'}{'comment'} ) and
495 length( $interface->{$data->{'nameref'}{'ifComment'}} ) > 0 )
497 my $comment = $interface->{$data->{'nameref'}{'ifComment'}};
498 $interface->{'param'}{'comment'} = $comment;
499 $interface->{'param'}{'interface-comment'} = $comment;
502 # Order the interfaces by ifIndex, not by interface name
503 $interface->{'param'}{'precedence'} = sprintf('%d', 100000-$ifIndex);
505 $interface->{'param'}{'devdiscover-nodetype'} =
506 'RFC2863_IF_MIB::interface';
509 if( $nInterfaces == 0 )
514 if( $devdetails->param('RFC2863_IF_MIB::noout') eq 'yes' )
519 # explicitly excluded interfaces
521 my $excludeNameList =
522 $devdetails->param('RFC2863_IF_MIB::exclude-interfaces');
523 my $nExplExcluded = 0;
525 if( defined( $excludeNameList ) and length( $excludeNameList ) > 0 )
527 foreach my $name ( split( /\s*,\s*/, $excludeNameList ) )
529 $excludeName{$name} = 1;
533 # explicitly listed interfaces
536 $devdetails->param('RFC2863_IF_MIB::only-interfaces');
537 my $onlyNamesDefined = 0;
538 if( defined( $onlyNamesList ) and length( $onlyNamesList ) > 0 )
540 $onlyNamesDefined = 1;
541 foreach my $name ( split( /\s*,\s*/, $onlyNamesList ) )
543 $onlyName{$name} = 1;
549 if( $devdetails->param('RFC2863_IF_MIB::bandwidth-usage') eq 'yes' )
551 my $limits = $devdetails->param('RFC2863_IF_MIB::bandwidth-limits');
552 foreach my $intfLimit ( split( /\s*;\s*/, $limits ) )
554 my( $intf, $limitIn, $limitOut ) = split( /\s*:\s*/, $intfLimit );
555 $bandwidthLimits{$intf}{'In'} = $limitIn;
556 $bandwidthLimits{$intf}{'Out'} = $limitOut;
560 # tokenset member interfaces of the form
561 # Format: tset:intf,intf; tokenset:intf,intf;
562 # Format for global parameter:
563 # tset:host/intf,host/intf; tokenset:host/intf,host/intf;
565 my %tsetMemberApplied;
567 $devdetails->param('RFC2863_IF_MIB::tokenset-members');
568 if( defined( $tsetMembership ) and length( $tsetMembership ) > 0 )
570 foreach my $memList ( split( /\s*;\s*/, $tsetMembership ) )
572 my ($tset, $list) = split( /\s*:\s*/, $memList );
573 foreach my $intfName ( split( /\s*,\s*/, $list ) )
575 if( $intfName =~ /\// )
577 my( $host, $intf ) = split( '/', $intfName );
578 if( $host eq $devdetails->param('snmp-host') )
580 $tsetMember{$intf}{$tset} = 1;
585 $tsetMember{$intfName}{$tset} = 1;
592 # External storage serviceid assignment
594 $devdetails->param('RFC2863_IF_MIB::external-serviceid');
598 if( defined( $extSrv ) and length( $extSrv ) > 0 )
600 foreach my $srvDef ( split( /\s*,\s*/, $extSrv ) )
602 my ( $serviceid, $intfName, $direction, $trees ) =
603 split( /\s*:\s*/, $srvDef );
605 if( $intfName =~ /\// )
607 my( $host, $intf ) = split( '/', $intfName );
608 if( $host eq $devdetails->param('snmp-host') )
618 if( defined( $intfName ) and length( $intfName ) > 0 )
620 if( defined( $trees ) )
622 # Trees are listed with '|' as separator,
623 # whereas compiler expects commas
625 $trees =~ s/\s*\|\s*/,/g;
628 if( $direction eq 'Both' )
630 $extStorage{$intfName}{'In'} = $serviceid . '_IN';
631 $extStorageTrees{$serviceid . '_IN'} = $trees;
633 $extStorage{$intfName}{'Out'} = $serviceid . '_OUT';
634 $extStorageTrees{$serviceid . '_OUT'} = $trees;
638 $extStorage{$intfName}{$direction} = $serviceid;
639 $extStorageTrees{$serviceid} = $trees;
645 # Sums of several interfaces into single graphs (via CDef collector)
646 # RFC2863_IF_MIB::traffic-summaries: the list of sums to create;
647 # RFC2863_IF_MIB::traffic-XXX-path: the full path of the summary leaf
648 # RFC2863_IF_MIB::traffic-XXX-comment: description
649 # RFC2863_IF_MIB::traffic-XXX-interfaces: list of interfaces to add
650 # format: "intf,intf" or "host/intf, host/intf"
651 my $trafficSums = $devdetails->param('RFC2863_IF_MIB::traffic-summaries');
653 if( defined( $trafficSums ) )
655 foreach my $summary ( split( /\s*,\s*/, $trafficSums ) )
657 $globalData->{'RFC2863_IF_MIB::summaryAttr'}{
660 ('RFC2863_IF_MIB::traffic-' . $summary . '-path');
661 $globalData->{'RFC2863_IF_MIB::summaryAttr'}{
662 $summary}{'comment'} =
664 ('RFC2863_IF_MIB::traffic-' . $summary . '-comment');
666 $globalData->{'RFC2863_IF_MIB::summaryAttr'}{
667 $summary}{'data-dir'} = $devdetails->param('data-dir');
669 my $intfList = $devdetails->param
670 ('RFC2863_IF_MIB::traffic-' . $summary . '-interfaces');
672 # get the intreface names for this host
673 foreach my $intfName ( split( /\s*,\s*/, $intfList ) )
675 if( $intfName =~ /\// )
677 my( $host, $intf ) = split( '/', $intfName );
678 if( $host eq $devdetails->param('snmp-host') )
680 $trafficSummary{$intf}{$summary} = 1;
685 $trafficSummary{$intfName}{$summary} = 1;
691 # interface-level parameters to copy
692 my @intfCopyParams = ();
693 my $copyParams = $devdetails->param('RFC2863_IF_MIB::copy-params');
694 if( defined( $copyParams ) and length( $copyParams ) > 0 )
696 @intfCopyParams = split( /\s*,\s*/m, $copyParams );
699 # Build configuration tree
701 my $subtreeName = $devdetails->param('RFC2863_IF_MIB::subtree-name');
702 if( length( $subtreeName ) == 0 )
704 $subtreeName = 'Interface_Counters';
706 my $subtreeParams = {};
707 my $subtreeComment = $devdetails->param('RFC2863_IF_MIB::subtree-comment');
709 if( length( $subtreeComment ) > 0 )
711 $subtreeParams->{'comment'} = $subtreeComment;
714 if( $devdetails->param('RFC2863_IF_MIB::bandwidth-usage') eq 'yes' )
716 $subtreeParams->{'overview-shortcuts'} = 'traffic,errors,bandwidth';
720 $cb->addSubtree( $devNode, $subtreeName, $subtreeParams,
721 ['RFC2863_IF_MIB::rfc2863-ifmib-subtree'] );
723 foreach my $ifIndex ( sort {$a<=>$b} keys %{$data->{'interfaces'}} )
725 my $interface = $data->{'interfaces'}{$ifIndex};
727 if( $interface->{'selectorActions'}{'RemoveInterface'} )
729 $interface->{'excluded'} = 1;
730 Debug('Removing interface by selector action: ' .
731 $interface->{$data->{'nameref'}{'ifReferenceName'}});
734 # Some vendor-specific modules may exclude some interfaces
735 next if $interface->{'excluded'};
737 # Create a subtree for the interface
738 my $subtreeName = $interface->{$data->{'nameref'}{'ifSubtreeName'}};
740 if( $onlyNamesDefined )
742 if( not $onlyName{$subtreeName} )
744 $interface->{'excluded'} = 1;
750 if( $excludeName{$subtreeName} )
752 $interface->{'excluded'} = 1;
756 elsif( length( $subtreeName ) == 0 )
758 Warn('Excluding an interface with empty name: ifIndex=' .
765 if( $interface->{'hasHCOctets'} )
767 push( @templates, 'RFC2863_IF_MIB::ifxtable-hcoctets' );
769 elsif( $interface->{'hasOctets'} )
771 push( @templates, 'RFC2863_IF_MIB::iftable-octets' );
774 if( $interface->{'hasOctets'} or $interface->{'hasHCOctets'} )
776 $interface->{'hasChild'}{'Bytes_In'} = 1;
777 $interface->{'hasChild'}{'Bytes_Out'} = 1;
778 $interface->{'hasChild'}{'InOut_bps'} = 1;
780 foreach my $dir ( 'In', 'Out' )
782 if( defined( $interface->{'selectorActions'}->
783 {$dir . 'BytesMonitor'} ) )
785 $interface->{'childCustomizations'}->{
786 'Bytes_' . $dir}->{'monitor'} =
787 $interface->{'selectorActions'}->{
788 $dir . 'BytesMonitor'};
791 if( defined( $interface->{'selectorActions'}->
792 {$dir . 'BytesParameters'} ) )
796 $interface->{'selectorActions'}{
797 $dir . 'BytesParameters'});
799 foreach my $pair( @pairs )
801 my ($param, $val) = split('\s*=\s*', $pair);
802 $interface->{'childCustomizations'}->{
803 'Bytes_' . $dir}->{$param} = $val;
808 if( defined( $interface->{'selectorActions'}{'HoltWinters'} ) )
810 push( @templates, '::holt-winters-defaults' );
813 if( defined( $interface->{'selectorActions'}{'NotifyPolicy'} ) )
815 $interface->{'param'}{'notify-policy'} =
816 $interface->{'selectorActions'}{'NotifyPolicy'};
820 if( not $interface->{'selectorActions'}{'NoPacketCounters'} )
822 my $has_someting = 0;
823 if( $interface->{'hasHCUcastPkts'} )
825 push( @templates, 'RFC2863_IF_MIB::ifxtable-hcucast-packets' );
828 elsif( $interface->{'hasUcastPkts'} )
830 push( @templates, 'RFC2863_IF_MIB::iftable-ucast-packets' );
836 $interface->{'hasChild'}{'Packets_In'} = 1;
837 $interface->{'hasChild'}{'Packets_Out'} = 1;
841 if( not $interface->{'selectorActions'}{'NoDiscardCounters'} )
843 if( $interface->{'hasInDiscards'} )
845 push( @templates, 'RFC2863_IF_MIB::iftable-discards-in' );
846 $interface->{'hasChild'}{'Discards_In'} = 1;
849 ($interface->{'selectorActions'}->{'InDiscardsMonitor'}) )
851 $interface->{'childCustomizations'}->{
852 'Discards_In'}->{'monitor'} =
853 $interface->{'selectorActions'}{
854 'InDiscardsMonitor'};
858 if( $interface->{'hasOutDiscards'} )
860 push( @templates, 'RFC2863_IF_MIB::iftable-discards-out' );
861 $interface->{'hasChild'}{'Discards_Out'} = 1;
863 if( defined( $interface->{'selectorActions'}->{
864 'OutDiscardsMonitor'} ) )
866 $interface->{'childCustomizations'}->{
867 'Discards_Out'}->{'monitor'} =
868 $interface->{'selectorActions'}{
869 'OutDiscardsMonitor'};
875 if( not $interface->{'selectorActions'}{'NoErrorCounters'} )
877 if( $interface->{'hasInErrors'} )
879 push( @templates, 'RFC2863_IF_MIB::iftable-errors-in' );
880 $interface->{'hasChild'}{'Errors_In'} = 1;
882 if( defined( $interface->{'selectorActions'}->{
883 'InErrorsMonitor'} ) )
885 $interface->{'childCustomizations'}->{
886 'Errors_In'}->{'monitor'} =
887 $interface->{'selectorActions'}{'InErrorsMonitor'};
891 if( $interface->{'hasOutErrors'} )
893 push( @templates, 'RFC2863_IF_MIB::iftable-errors-out' );
894 $interface->{'hasChild'}{'Errors_Out'} = 1;
896 if( defined( $interface->{'selectorActions'}->{
897 'OutErrorsMonitor'} ) )
899 $interface->{'childCustomizations'}->{
900 'Errors_Out'}->{'monitor'} =
901 $interface->{'selectorActions'}{
907 if( defined( $interface->{'selectorActions'}{'TokensetMember'} ) )
911 $interface->{'selectorActions'}{'TokensetMember'}) )
913 $tsetMember{$subtreeName}{$tset} = 1;
917 if( defined( $interface->{'selectorActions'}{'Parameters'} ) )
919 my @pairs = split('\s*;\s*',
920 $interface->{'selectorActions'}{'Parameters'});
921 foreach my $pair( @pairs )
923 my ($param, $val) = split('\s*=\s*', $pair);
924 $interface->{'param'}{$param} = $val;
928 if( $devdetails->param('RFC2863_IF_MIB::bandwidth-usage') eq 'yes' )
930 if( defined( $bandwidthLimits{$subtreeName} ) )
932 $interface->{'param'}{'bandwidth-limit-in'} =
933 $bandwidthLimits{$subtreeName}{'In'};
934 $interface->{'param'}{'bandwidth-limit-out'} =
935 $bandwidthLimits{$subtreeName}{'Out'};
938 # We accept that parameters may be added by some other ways
940 if( defined( $interface->{'param'}{'bandwidth-limit-in'} ) and
941 defined( $interface->{'param'}{'bandwidth-limit-out'} ) )
944 'RFC2863_IF_MIB::interface-bandwidth-usage' );
948 if( ref( $interface->{'templates'} ) )
950 push( @templates, @{$interface->{'templates'}} );
953 # Add vendor templates
954 push( @templates, @{$interface->{'vendor_templates'}} );
956 # Add subtree only if there are template references
958 if( scalar( @templates ) > 0 )
960 # process interface-level parameters to copy
962 foreach my $param ( @intfCopyParams )
964 my $val = $devdetails->param('RFC2863_IF_MIB::' .
965 $param . '::' . $subtreeName );
966 if( defined( $val ) and length( $val ) > 0 )
968 $interface->{'param'}{$param} = $val;
972 if( defined( $tsetMember{$subtreeName} ) )
975 join( ',', sort keys %{$tsetMember{$subtreeName}} );
977 $interface->{'childCustomizations'}->{'InOut_bps'}->{
978 'tokenset-member'} = $tsetList;
979 $tsetMemberApplied{$subtreeName} = 1;
982 if( defined( $extStorage{$subtreeName} ) )
984 foreach my $dir ( 'In', 'Out' )
986 if( defined( $extStorage{$subtreeName}{$dir} ) )
988 my $serviceid = $extStorage{$subtreeName}{$dir};
991 'storage-type' => 'rrd,ext',
992 'ext-service-id' => $serviceid,
993 'ext-service-units' => 'bytes' };
995 if( defined( $extStorageTrees{$serviceid} )
996 and length( $extStorageTrees{$serviceid} ) > 0 )
998 $params->{'ext-service-trees'} =
999 $extStorageTrees{$serviceid};
1002 foreach my $param ( keys %{$params} )
1004 $interface->{'childCustomizations'}->{
1005 'Bytes_' . $dir}{$param} = $params->{$param};
1012 $cb->addSubtree( $countersNode, $subtreeName,
1013 $interface->{'param'}, \@templates );
1015 if( defined( $interface->{'childCustomizations'} ) )
1017 foreach my $childName
1018 ( sort keys %{$interface->{'childCustomizations'}} )
1020 if( $interface->{'hasChild'}{$childName} )
1023 ( $intfNode, $childName,
1024 $interface->{'childCustomizations'}->{
1030 # If the interafce is a member of traffic summary
1031 if( defined( $trafficSummary{$subtreeName} ) )
1033 foreach my $summary ( keys %{$trafficSummary{$subtreeName}} )
1035 addTrafficSummaryElement( $globalData,
1036 $summary, $intfNode );
1042 if( $nExplExcluded > 0 )
1044 Debug('Explicitly excluded ' . $nExplExcluded .
1045 ' RFC2863_IF_MIB interfaces');
1048 if( scalar( %tsetMember ) > 0 )
1051 foreach my $intfName ( keys %tsetMember )
1053 if( not $tsetMemberApplied{$intfName} )
1055 push( @failedIntf, $intfName );
1059 if( scalar( @failedIntf ) > 0 )
1061 Warn('The following interfaces were not added to tokensets, ' .
1062 'probably because they do not exist or are explicitly ' .
1064 join(' ', sort @failedIntf));
1068 $cb->{'statistics'}{'interfaces'} += $nInterfaces;
1069 if( $cb->{'statistics'}{'max-interfaces-per-host'} < $nInterfaces )
1071 $cb->{'statistics'}{'max-interfaces-per-host'} = $nInterfaces;
1076 sub addTrafficSummaryElement
1078 my $globalData = shift;
1079 my $summary = shift;
1082 if( not defined( $globalData->{
1083 'RFC2863_IF_MIB::summaryMembers'}{$summary} ) )
1085 $globalData->{'RFC2863_IF_MIB::summaryMembers'}{$summary} = [];
1088 push( @{$globalData->{'RFC2863_IF_MIB::summaryMembers'}{$summary}},
1093 sub buildGlobalConfig
1096 my $globalData = shift;
1098 if( not defined( $globalData->{'RFC2863_IF_MIB::summaryMembers'} ) )
1103 foreach my $summary ( keys %{$globalData->{
1104 'RFC2863_IF_MIB::summaryMembers'}} )
1106 next if scalar( @{$globalData->{
1107 'RFC2863_IF_MIB::summaryMembers'}{$summary}} ) == 0;
1109 my $attr = $globalData->{'RFC2863_IF_MIB::summaryAttr'}{$summary};
1110 my $path = $attr->{'path'};
1112 if( not defined( $path ) )
1114 Error('Missing the path for traffic summary ' . $summary);
1118 Debug('Building summary: ' . $summary);
1120 # Chop the first and last slashes
1124 # generate subtree path XML
1125 my $subtreeNode = undef;
1126 foreach my $subtreeName ( split( '/', $path ) )
1128 $subtreeNode = $cb->addSubtree( $subtreeNode, $subtreeName, {
1129 'comment' => $attr->{'comment'},
1130 'data-dir' => $attr->{'data-dir'} } );
1133 foreach my $dir ('In', 'Out')
1136 foreach my $member ( @{$globalData->{
1137 'RFC2863_IF_MIB::summaryMembers'}{$summary}} )
1139 my $memRef = '{' . $cb->getElementPath($member) .
1140 'Bytes_' . $dir . '}';
1141 if( length( $rpn ) == 0 )
1147 $rpn .= ',' . $memRef . ',+';
1153 'data-file' => 'summary_' . $summary . '.rrd',
1154 'rrd-ds' => 'Bytes' . $dir };
1156 $cb->addLeaf( $subtreeNode, 'Bytes_' . $dir, $param,
1157 ['::cdef-collector-defaults'] );
1166 # $filterHash is a hash reference
1167 # Key is some unique symbolic name, does not mean anything
1168 # $filterHash->{$key}{'ifType'} is the number to match the interface type
1169 # $filterHash->{$key}{'ifDescr'} is the regexp to match the interface
1172 sub addInterfaceFilter
1174 my $devdetails = shift;
1175 my $filterHash = shift;
1177 my $data = $devdetails->data();
1179 if( not ref( $data->{'interfaceFilter'} ) )
1181 $data->{'interfaceFilter'} = [];
1184 push( @{$data->{'interfaceFilter'}}, $filterHash );
1190 my $devdetails = shift;
1191 my $nameref = shift;
1193 my $data = $devdetails->data();
1196 foreach my $ifIndex ( sort {$a<=>$b} keys %{$data->{'interfaces'}} )
1198 my $interface = $data->{'interfaces'}{$ifIndex};
1200 my $entry = $interface->{$nameref};
1201 if( length($entry) == 0 )
1203 $entry = $interface->{$nameref} = '_';
1205 if( int( $count{$entry} ) > 0 )
1207 my $new_entry = sprintf('%s%d', $entry, int( $count{$entry} ) );
1208 $interface->{$nameref} = $new_entry;
1209 $count{$new_entry}++;
1215 # For devices which require MAC address-to-interface mapping,
1216 # this function fills in the appropriate interface-macaddr parameters.
1217 # To get use of MAC mapping, set
1218 # $data->{'param'}{'ifindex-map'} = '$IFIDX_MAC';
1221 sub retrieveMacAddresses
1224 my $devdetails = shift;
1226 my $data = $devdetails->data();
1228 foreach my $ifIndex ( sort {$a<=>$b} keys %{$data->{'interfaces'}} )
1230 my $interface = $data->{'interfaces'}{$ifIndex};
1232 my $macaddr = $devdetails->snmpVar($dd->oiddef('ifPhysAddress') .
1235 if( defined( $macaddr ) and length( $macaddr ) > 0 )
1237 $interface->{'MAC'} = $macaddr;
1238 $interface->{'param'}{'interface-macaddr'} = $macaddr;
1242 Warn('Excluding interface without MAC address: ' .
1243 $interface->{$data->{'nameref'}{'ifReferenceName'}});
1244 delete $data->{'interfaces'}{$ifIndex};
1250 # For devices with fixed ifIndex mapping it populates interface-index parameter
1253 sub storeIfIndexParams
1255 my $devdetails = shift;
1257 my $data = $devdetails->data();
1259 foreach my $ifIndex ( keys %{$data->{'interfaces'}} )
1261 my $interface = $data->{'interfaces'}{$ifIndex};
1262 $interface->{'param'}{'interface-index'} = $ifIndex;
1266 #######################################
1267 # Selectors interface
1270 $Torrus::DevDiscover::selectorsRegistry{'RFC2863_IF_MIB'} = {
1271 'getObjects' => \&getSelectorObjects,
1272 'getObjectName' => \&getSelectorObjectName,
1273 'checkAttribute' => \&checkSelectorAttribute,
1274 'applyAction' => \&applySelectorAction,
1278 ## Objects are interface indexes
1280 sub getSelectorObjects
1282 my $devdetails = shift;
1283 my $objType = shift;
1284 return sort {$a<=>$b} keys ( %{$devdetails->data()->{'interfaces'}} );
1288 sub checkSelectorAttribute
1290 my $devdetails = shift;
1292 my $objType = shift;
1294 my $checkval = shift;
1296 my $data = $devdetails->data();
1297 my $interface = $data->{'interfaces'}{$object};
1299 if( $attr =~ /^ifSubtreeName\d*$/ )
1301 my $value = $interface->{$data->{'nameref'}{'ifSubtreeName'}};
1303 foreach my $chkexpr ( split( /\s+/, $checkval ) )
1305 if( $value =~ $chkexpr )
1316 my $operator = '=~';
1317 if( $attr eq 'ifComment' )
1319 $value = $interface->{$data->{'nameref'}{'ifComment'}};
1321 elsif( $attr eq 'ifType' )
1323 $value = $interface->{'ifType'};
1328 Error('Unknown RFC2863_IF_MIB selector attribute: ' . $attr);
1332 return eval( '$value' . ' ' . $operator . '$checkval' ) ? 1:0;
1337 sub getSelectorObjectName
1339 my $devdetails = shift;
1341 my $objType = shift;
1343 my $data = $devdetails->data();
1344 my $interface = $data->{'interfaces'}{$object};
1345 return $interface->{$data->{'nameref'}{'ifSubtreeName'}};
1349 # Other discovery modules can add their interface actions here
1350 our %knownSelectorActions =
1351 ( 'InBytesMonitor' => 'RFC2863_IF_MIB',
1352 'OutBytesMonitor' => 'RFC2863_IF_MIB',
1353 'InDiscardsMonitor' => 'RFC2863_IF_MIB',
1354 'OutDiscardsMonitor' => 'RFC2863_IF_MIB',
1355 'InErrorsMonitor' => 'RFC2863_IF_MIB',
1356 'OutErrorsMonitor' => 'RFC2863_IF_MIB',
1357 'NotifyPolicy' => 'RFC2863_IF_MIB',
1358 'HoltWinters' => 'RFC2863_IF_MIB',
1359 'NoPacketCounters' => 'RFC2863_IF_MIB',
1360 'NoDiscardCounters' => 'RFC2863_IF_MIB',
1361 'NoErrorCounters' => 'RFC2863_IF_MIB',
1362 'RemoveInterface' => 'RFC2863_IF_MIB',
1363 'TokensetMember' => 'RFC2863_IF_MIB',
1364 'Parameters' => 'RFC2863_IF_MIB',
1365 'InBytesParameters' => 'RFC2863_IF_MIB',
1366 'OutBytesParameters' => 'RFC2863_IF_MIB',);
1369 sub applySelectorAction
1371 my $devdetails = shift;
1373 my $objType = shift;
1377 my $data = $devdetails->data();
1378 my $interface = $data->{'interfaces'}{$object};
1380 if( defined( $knownSelectorActions{$action} ) )
1382 if( not $devdetails->isDevType( $knownSelectorActions{$action} ) )
1384 Error('Action ' . $action . ' is applied to a device that is ' .
1385 'not of type ' . $knownSelectorActions{$action} .
1386 ': ' . $devdetails->param('system-id'));
1388 $interface->{'selectorActions'}{$action} = $arg;
1392 Error('Unknown RFC2863_IF_MIB selector action: ' . $action);
1402 # indent-tabs-mode: nil
1403 # perl-indent-level: 4