import torrus 1.0.9
[freeside.git] / torrus / perllib / Torrus / DevDiscover / JunOS.pm
1 #
2 #  Copyright (C) 2007  Jon Nistor
3 #
4 #  This program is free software; you can redistribute it and/or modify
5 #  it under the terms of the GNU General Public License as published by
6 #  the Free Software Foundation; either version 2 of the License, or
7 #  (at your option) any later version.
8 #
9 #  This program is distributed in the hope that it will be useful,
10 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
11 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 #  GNU General Public License for more details.
13 #
14 #  You should have received a copy of the GNU General Public License
15 #  along with this program; if not, write to the Free Software
16 #  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
17
18 # $Id: JunOS.pm,v 1.1 2010-12-27 00:03:53 ivan Exp $
19 # Jon Nistor <nistor at snickers.org>
20
21 # Juniper JunOS Discovery Module
22 #
23 # NOTE: For Class of service, if you are noticing that you are not seeing
24 #       all of your queue names show up, this is by design of Juniper.
25 #       Solution: Put place-holder names for those queues such as:
26 #                 "UNUSED-queue-#"
27 #       This is in reference to JunOS 7.6
28 #
29 # NOTE: Options for this module:
30 #       JunOS::disable-cos
31 #       JunOS::disable-cos-red
32 #       JunOS::disable-cos-tail
33 #       JunOS::disable-firewall
34 #       JunOS::disable-operating
35 #       JunOS::disable-rpf
36
37 package Torrus::DevDiscover::JunOS;
38
39 use strict;
40 use Torrus::Log;
41
42
43 $Torrus::DevDiscover::registry{'JunOS'} = {
44     'sequence'     => 500,
45     'checkdevtype' => \&checkdevtype,
46     'discover'     => \&discover,
47     'buildConfig'  => \&buildConfig
48 };
49
50
51 our %oiddef =
52     (
53      # JUNIPER-SMI
54      'jnxProducts'          => '1.3.6.1.4.1.2636.1',
55      'jnxBoxDescr'          => '1.3.6.1.4.1.2636.3.1.2.0',
56      'jnxBoxSerialNo'       => '1.3.6.1.4.1.2636.3.1.3.0',
57
58      # Operating status
59      'jnxOperatingDescr'    => '1.3.6.1.4.1.2636.3.1.13.1.5',
60      'jnxOperatingTemp'     => '1.3.6.1.4.1.2636.3.1.13.1.7',
61      'jnxOperatingCPU'      => '1.3.6.1.4.1.2636.3.1.13.1.8',
62      'jnxOperatingISR'      => '1.3.6.1.4.1.2636.3.1.13.1.9',
63      'jnxOperatingDRAMSize' => '1.3.6.1.4.1.2636.3.1.13.1.10', # deprecated
64      'jnxOperatingBuffer'   => '1.3.6.1.4.1.2636.3.1.13.1.11',
65      'jnxOperatingMemory'   => '1.3.6.1.4.1.2636.3.1.13.1.15',
66
67      # Firewall filter
68      'jnxFWCounterDisplayFilterName' => '1.3.6.1.4.1.2636.3.5.2.1.6',
69      'jnxFWCounterDisplayName'       => '1.3.6.1.4.1.2636.3.5.2.1.7',
70      'jnxFWCounterDisplayType'       => '1.3.6.1.4.1.2636.3.5.2.1.8',
71
72      # Class of Service (jnxCosIfqStatsTable deprecated, use jnxCosQstatTable)
73      #             COS  - Class Of Service
74      #             RED  - Random Early Detection
75      #             PLP  - Packet Loss Priority
76      #             DSCP - Differential Service Code Point
77
78      'jnxCosFcIdToFcName'   => '1.3.6.1.4.1.2636.3.15.3.1.2',
79      'jnxCosQstatQedPkts'   => '1.3.6.1.4.1.2636.3.15.4.1.3',
80
81      # Reverse path forwarding
82      'jnxRpfStatsPackets'   => '1.3.6.1.4.1.2636.3.17.1.1.1.3'
83
84     );
85
86
87 # Not all interfaces are normally needed to monitor.
88 # You may override the interface filtering in devdiscover-siteconfig.pl:
89 # redefine $Torrus::DevDiscover::JunOS::interfaceFilter
90 # or define $Torrus::DevDiscover::JunOS::interfaceFilterOverlay
91
92 our $interfaceFilter;
93 our $interfaceFilterOverlay;
94 my %junosInterfaceFilter;
95
96 if( not defined( $interfaceFilter ) )
97 {
98     $interfaceFilter = \%junosInterfaceFilter;
99 }
100
101
102 # Key is some unique symbolic name, does not mean anything
103 # ifType is the number to match the interface type
104 # ifDescr is the regexp to match the interface description
105 %junosInterfaceFilter =
106     (
107      'lsi' => {
108          'ifType'  => 150,                   # mplsTunnel
109          'ifDescr' => '^lsi$'
110      },
111      
112      'other' => {
113          'ifType'  => 1,                     # other
114      },
115      
116      'loopback' => {
117          'ifType'  => 24,                    # softwareLoopback
118      },
119      
120      'propVirtual' => {
121          'ifType'  => 53,                    # propVirtual
122      },
123      
124      'gre_ipip_pime_pimd_mtun'  => {
125          'ifType'  => 131,                     # tunnel
126          'ifDescr' => '^(gre)|(ipip)|(pime)|(pimd)|(mtun)$'
127      },
128
129      'pd_pe_gr_ip_mt_lt' => {
130          'ifType'  => 131,                     # tunnel
131          'ifDescr' => '^(pd)|(pe)|(gr)|(ip)|(mt)|(lt)-\d+\/\d+\/\d+$'
132      },
133      
134      'ls' => {
135          'ifType'  => 108,                     # pppMultilinkBundle
136          'ifDescr' => '^ls-\d+\/\d+\/\d+$'
137      },
138     );
139
140
141
142 sub checkdevtype
143 {
144     my $dd = shift;
145     my $devdetails = shift;
146
147     if( not $dd->oidBaseMatch
148         ( 'jnxProducts',
149           $devdetails->snmpVar( $dd->oiddef('sysObjectID') ) )
150         )
151     {
152         return 0;
153     }
154
155     &Torrus::DevDiscover::RFC2863_IF_MIB::addInterfaceFilter
156         ($devdetails, $interfaceFilter);
157     
158     if( defined( $interfaceFilterOverlay ) )
159     {
160         &Torrus::DevDiscover::RFC2863_IF_MIB::addInterfaceFilter
161             ($devdetails, $interfaceFilterOverlay);
162     }
163
164     $devdetails->setCap('interfaceIndexingPersistent');
165
166     return 1;
167 }
168
169
170 sub discover
171 {
172     my $dd = shift;
173     my $devdetails = shift;
174
175     my $session = $dd->session();
176     my $data = $devdetails->data();
177
178     # NOTE: Comments and Serial number of device
179     my $chassisSerial =
180         $dd->retrieveSnmpOIDs( 'jnxBoxDescr', 'jnxBoxSerialNo' );
181
182     if( defined( $chassisSerial ) )
183     {
184         $data->{'param'}{'comment'} = $chassisSerial->{'jnxBoxDescr'} .
185             ', Hw Serial#: ' . $chassisSerial->{'jnxBoxSerialNo'};
186     } else
187     {
188         $data->{'param'}{'comment'} = "Juniper router";
189     }
190
191
192     # PROG: Class of Service
193     #
194     if( $devdetails->param('JunOS::disable-cos') ne 'yes' )
195     {
196         # Poll table to translate the CoS Index to a Name
197         my $cosQueueNumTable =
198             $session->get_table( -baseoid =>
199                                  $dd->oiddef('jnxCosFcIdToFcName') );
200         $devdetails->storeSnmpVars( $cosQueueNumTable );
201
202         if( $cosQueueNumTable )
203         {
204             $devdetails->setCap('jnxCoS');
205
206             # Find the index of the CoS queue name    
207             foreach my $cosFcIndex ( $devdetails->getSnmpIndices
208                                      ($dd->oiddef('jnxCosFcIdToFcName')) )
209             {
210                 my $cosFcNameOid = $dd->oiddef('jnxCosFcIdToFcName') . "." .
211                     $cosFcIndex;
212                 my $cosFcName    = $cosQueueNumTable->{$cosFcNameOid};
213
214                 Debug("JunOS::CoS  FC index: $cosFcIndex  name: $cosFcName");
215
216                 # Construct the data ...
217                 $data->{'jnxCos'}{'queue'}{$cosFcIndex} = $cosFcName;
218             }
219
220             # We need to find out all the interfaces that have CoS enabled
221             # on them. We will use jnxCosQstatQedPkts as our reference point.
222             my $cosIfIndex =
223                 $session->get_table( -baseoid =>
224                                      $dd->oiddef('jnxCosQstatQedPkts') );
225             $devdetails->storeSnmpVars( $cosIfIndex );
226
227             if( $cosIfIndex )            
228             {
229                 foreach my $INDEX ( $devdetails->getSnmpIndices
230                                 ($dd->oiddef('jnxCosQstatQedPkts')) )
231                 {
232                         my( $ifIndex, $cosQueueIndex ) = split( '\.', $INDEX );
233                         $data->{'jnxCos'}{'ifIndex'}{$ifIndex} = 1;
234                 } 
235             }
236         }
237     } # END JunOS::disable-cos
238
239
240     # PROG: Grab and store description of parts
241     #
242     if( $devdetails->param('JunOS::disable-operating') ne 'yes' )
243     {
244         my $tableDesc = $session->get_table( -baseoid =>
245                                              $dd->oiddef('jnxOperatingDescr'));
246         $devdetails->storeSnmpVars( $tableDesc );
247
248         if ( $tableDesc )
249         {
250             # PROG: Set Capability flag
251             $devdetails->setCap('jnxOperating');
252
253             # PROG: Poll tables for more info to match and index on
254             my $tableCPU =
255                 $session->get_table( -baseoid =>
256                                      $dd->oiddef('jnxOperatingCPU'));
257             $devdetails->storeSnmpVars( $tableCPU );
258
259             my $tableISR =
260                 $session->get_table( -baseoid =>
261                                      $dd->oiddef('jnxOperatingISR'));
262             $devdetails->storeSnmpVars( $tableISR );
263
264             my $tableMEM =
265                 $session->get_table( -baseoid =>
266                                      $dd->oiddef('jnxOperatingMemory'));
267             $devdetails->storeSnmpVars( $tableMEM );
268
269             my $tableTemp =
270                 $session->get_table( -baseoid =>
271                                      $dd->oiddef('jnxOperatingTemp'));
272             $devdetails->storeSnmpVars( $tableTemp );
273
274             # PROG: Build tables for all the oids
275             #       We are using the Descr oid base for matching. (cheap hack)
276             foreach my $opIndex ( $devdetails->getSnmpIndices
277                                   ($dd->oiddef('jnxOperatingDescr')) )
278             {
279                 my $opCPU  = $devdetails->snmpVar
280                     ($dd->oiddef('jnxOperatingCPU') . '.' . $opIndex);
281                 my $opDesc = $devdetails->snmpVar
282                     ($dd->oiddef('jnxOperatingDescr') . '.' . $opIndex);
283                 my $opMem  = $devdetails->snmpVar
284                     ($dd->oiddef('jnxOperatingMemory') . '.' . $opIndex);
285                 my $opISR  = $devdetails->snmpVar
286                     ($dd->oiddef('jnxOperatingISR') . '.' . $opIndex);
287                 my $opTemp = $devdetails->snmpVar
288                     ($dd->oiddef('jnxOperatingTemp')  . '.' . $opIndex);
289
290                 Debug("JunOS:: opIdx: $opIndex  Desc: $opDesc");
291                 Debug("JunOS::   CPU: $opCPU, CPU: $opISR, MEM: $opMem");
292                 Debug("JunOS::   Temp: $opTemp");
293
294                 # Construct the data
295                 $data->{'jnxOperating'}{$opIndex}{'index'} = $opIndex;
296                 $data->{'jnxOperating'}{$opIndex}{'cpu'}   = $opCPU;
297                 $data->{'jnxOperating'}{$opIndex}{'desc'}  = $opDesc;
298                 $data->{'jnxOperating'}{$opIndex}{'isr'}   = $opISR;
299                 $data->{'jnxOperating'}{$opIndex}{'mem'}   = $opMem;
300                 $data->{'jnxOperating'}{$opIndex}{'temp'}  = $opTemp;
301             }
302         } # END: if $tableDesc
303     } # END: JunOS::disable-operating
304
305
306     # PROG: Firewall statistics
307     if( $devdetails->param('JunOS::disable-firewall') ne 'yes' )
308     {
309         my $tableFWFilter =
310             $session->get_table( -baseoid =>
311                                  $dd->oiddef('jnxFWCounterDisplayFilterName'));
312         $devdetails->storeSnmpVars( $tableFWFilter );
313
314         if( $tableFWFilter )
315         {
316             # PROG: Set Capability flag
317             $devdetails->setCap('jnxFirewall');
318
319             # PROG: Poll tables for more info to match and index on
320             my $tableFWCounter =
321                 $session->get_table( -baseoid =>
322                                      $dd->oiddef('jnxFWCounterDisplayName') );
323             $devdetails->storeSnmpVars( $tableFWCounter );
324
325             # Firewall Type (counter = 2, policer = 3)
326             my $tableFWType  =
327                 $session->get_table( -baseoid =>
328                                      $dd->oiddef('jnxFWCounterDisplayType') );
329             $devdetails->storeSnmpVars( $tableFWType );
330
331             # PROG: Build tables for all the oids
332             #       We are using the FW Filter name as the Indexing
333             foreach my $fwIndex ( $devdetails->getSnmpIndices
334                                   ($dd->oiddef('jnxFWCounterDisplayName')) )
335             {
336                 my $fwFilter = $devdetails->snmpVar
337                     ($dd->oiddef('jnxFWCounterDisplayFilterName') .
338                      '.' . $fwIndex);
339                 my $fwCounter  = $devdetails->snmpVar
340                     ($dd->oiddef('jnxFWCounterDisplayName') .
341                      '.' . $fwIndex);
342                 my $fwType = $devdetails->snmpVar
343                     ($dd->oiddef('jnxFWCounterDisplayType') .
344                      '.' . $fwIndex);
345                 Debug("JunOS::fw Filter: $fwFilter");
346                 Debug("JunOS::fw         Counter: $fwCounter");
347                 Debug("JunOS::fw            Type: $fwType");
348
349                 # Construct the data
350                 $data->{'jnxFirewall'}{$fwFilter}{$fwCounter}{'oid'} =
351                     $fwIndex;
352                 $data->{'jnxFirewall'}{$fwFilter}{$fwCounter}{'type'} =
353                     $fwType;
354             }
355         } # END: if $tableFWfilter
356     } # END: JunOS::diable-firewall
357
358
359     # PROG: Check for RPF availability
360     if( $devdetails->param('JunOS::disable-rpf') ne 'yes' )
361     {
362         my $tableRPF =
363             $session->get_table( -baseoid =>
364                                  $dd->oiddef('jnxRpfStatsPackets') );
365         $devdetails->storeSnmpVars( $tableRPF );
366
367         if( $tableRPF )
368         {
369             # PROG: Set capability flag
370             $devdetails->setCap('jnxRPF');
371
372             # PROG: Find all the relevent interfaces
373             foreach my $rpfIndex ( $devdetails->getSnmpIndices
374                                    ($dd->oiddef('jnxRpfStatsPackets')) )
375             {
376                 my ($ifIndex,$addrFamily) = split('\.',$rpfIndex);
377                 if( defined( $data->{'interfaces'}{$ifIndex} ) )
378                 {
379                     my $ifAddrFam = $addrFamily == 1 ? 'ipv4' : 'ipv6';
380                     my $intName   = $data->{'interfaces'}{$ifIndex}{'ifName'};
381                     my $intNameT  = $data->{'interfaces'}{$ifIndex}{'ifNameT'};
382                     
383                     # Construct data
384                     $data->{'jnxRPF'}{$ifIndex}{'ifName'}  = $intName;
385                     $data->{'jnxRPF'}{$ifIndex}{'ifNameT'} = $intNameT;
386                     
387                     if( $addrFamily == 1 )
388                     {
389                         $data->{'jnxRPF'}{$ifIndex}{'ipv4'} = 1;
390                     }
391                     if( $addrFamily == 2 )
392                     {
393                         $data->{'jnxRPF'}{$ifIndex}{'ipv6'} = 2;
394                     }                    
395                 }
396             }
397         }
398     }
399
400     return 1;
401 }
402
403
404 sub buildConfig
405 {
406     my $devdetails = shift;
407     my $cb = shift;
408     my $devNode = shift;
409     my $data = $devdetails->data();
410
411
412     # PROG: Class of Service information
413     if( $devdetails->hasCap('jnxCoS') &&
414         ( keys %{$data->{'jnxCos'}{'ifIndex'}} > 0 )
415        )
416     {
417         # PROG: Add CoS information if it exists.
418         my $nodeTop = $cb->addSubtree( $devNode, 'CoS', undef,
419                                   [ 'JunOS::junos-cos-subtree']);
420
421         foreach my $ifIndex ( sort {$a <=> $b} keys
422                               %{$data->{'jnxCos'}{'ifIndex'}} )
423         {
424             my $interface = $data->{'interfaces'}{$ifIndex};
425             my $ifAlias   = $interface->{'ifAlias'};
426             my $ifDescr   = $interface->{'ifDescr'};
427             my $ifName    = $interface->{'ifNameT'};
428
429             next if( not $ifName );  # Skip since port is likely 'disabled'
430             # This might be better to match against ifType
431             # as well since not all of them support Q's.
432
433             # Add Subtree per port
434             my $nodePort =
435                 $cb->addSubtree( $nodeTop, $ifName,
436                                  { 'comment'    => $ifAlias,
437                                    'precedence' => 1000 - $ifIndex },
438                                  [ 'JunOS::junos-cos-subtree-interface' ]);
439
440             # Loop to create subtree's for each QueueName/ID pair
441             foreach my $cosIndex ( sort keys %{$data->{'jnxCos'}{'queue'}} )
442             {
443                 my $cosName  = $data->{'jnxCos'}{'queue'}{$cosIndex};
444                 
445                 # Add Leaf for each one
446                 Debug("JunOS::CoS  ifIndex: $ifIndex ($ifName -> $cosName)");
447                 my $nodeIFCOS =
448                     $cb->addSubtree( $nodePort, $cosName,
449                                      { 'comment'    => "Class: " . $cosName,
450                                        'cos-index'  => $cosIndex,
451                                        'cos-name'   => $cosName,
452                                        'ifDescr'    => $ifDescr,
453                                        'ifIndex'    => $ifIndex,
454                                        'ifName'     => $ifName,
455                                        'precedence' => 1000 - $cosIndex },
456                                      [ 'JunOS::junos-cos-leaf' ]);
457
458                 if( $devdetails->param('JunOS::disable-cos-tail') ne 'yes' )
459                 {
460                     $cb->addSubtree( $nodeIFCOS, "Tail_drop_stats",
461                                      { 'comment'  => 'Tail drop statistics' },
462                                      [ 'JunOS::junos-cos-tail' ]);
463                 }
464
465                 if( $devdetails->param('JunOS::disable-cos-red') ne 'yes' )
466                 {
467                     $cb->addSubtree
468                         ( $nodeIFCOS, "RED_stats",
469                           { 'comment'  => 'Random Early Detection' },
470                           [ 'JunOS::junos-cos-red' ]);
471                 }
472                 
473             } # end foreach (INDEX of queue's [Q-ID])
474         } # end foreach (INDEX of port)
475     } # end if HasCap->{CoS}
476
477
478     # PROG: Firewall Table (filters and counters)
479     if( $devdetails->hasCap('jnxFirewall') )
480     {
481         # Add subtree first
482         my $nodeFW = $cb->addSubtree( $devNode, 'Firewall', undef,
483                                       [ 'JunOS::junos-firewall-subtree' ]);
484
485         # Loop through and find all the filter names
486         foreach my $fwFilter
487             ( sort {$a <=> $b} keys %{$data->{'jnxFirewall'}} )
488         {
489             my $firewall  = $data->{'jnxFirewall'}{$fwFilter};
490
491             # Add subtree for FilterName
492             my $nodeFWFilter =
493                 $cb->addSubtree( $nodeFW, $fwFilter,
494                                  { 'comment' => 'Filter: ' . $fwFilter },
495                                  [ 'JunOS::junos-firewall-filter-subtree' ]);
496             
497             # Loop through and find all the counter names within the filter
498             foreach my $fwCounter ( sort {$a <=> $b} keys %{$firewall} )
499             {
500                 my $fwOid     = $firewall->{$fwCounter}{'oid'};
501                 my $fwType    = $firewall->{$fwCounter}{'type'};
502                 my @templates = ( 'JunOS::junos-firewall-filter' );
503
504                 # Figure out which templates to apply ...
505                 if ($fwType == 2)
506                 {
507                     # fwType is a counter ...
508                     push( @templates,
509                           'JunOS::junos-firewall-filter-counter',
510                           'JunOS::junos-firewall-filter-policer' );
511                 }
512                 elsif ($fwType == 3)
513                 {
514                     # fwType is a policer ...
515                     push( @templates,
516                           'JunOS::junos-firewall-filter-policer' );
517                 } # END: if $fwType
518
519                 # Finally, add the subtree...
520                 my $fwTypeName = $fwType == 2 ? 'Counter: ' : 'Policer: ';
521                 my $nodeFWCounter =
522                     $cb->addSubtree($nodeFWFilter, $fwCounter,
523                                     { 'comment'    => $fwTypeName . $fwCounter,
524                                       'fw-counter' => $fwCounter,
525                                       'fw-filter'  => $fwFilter,
526                                       'fw-index'   => $fwOid }, \@templates );
527             } # END foreach $fwCounter
528         } # END foreach $fwFilter
529     } # END: if hasCap jnxFirewall
530
531
532     # PROG: Operating Status Table
533     # NOTE: According to the Juniper MIB, the following is a statement:
534     #       jnxOperatingTemp: The temperature in Celsius (degrees C) of this
535     #                         subject.  Zero if unavailable or inapplicable.
536     #       The same applies for all values under Operating status table, if
537     #       Zero is shown it might be considered unavail or N/A.  We will
538     #       also take that into consideration.
539     # NOTE: Also so poorly written, its great.
540     if( $devdetails->hasCap('jnxOperating') )
541     {
542         my $nodeCPU  = $cb->addSubtree( $devNode, 'CPU_Usage', undef,
543                                         [ 'JunOS::junos-cpu-subtree' ]);
544
545         my $nodeMem  = $cb->addSubtree( $devNode, 'Memory_Usage', undef,
546                                         [ 'JunOS::junos-memory-subtree' ]);
547
548         my $nodeTemp =
549             $cb->addSubtree( $devNode, 'Temperature_Sensors', undef,
550                              [ 'JunOS::junos-temperature-subtree' ]);
551
552         
553         foreach my $opIndex
554             ( sort {$a <=> $b} keys %{$data->{'jnxOperating'}} )
555         {
556             my $operating = $data->{'jnxOperating'}{$opIndex};
557             my $jnxCPU    = $operating->{'cpu'};
558             my $jnxDesc   = $operating->{'desc'};
559             my $jnxMem    = $operating->{'mem'};
560             my $jnxTemp   = $operating->{'temp'};
561             my $jnxTag = $jnxDesc;
562             $jnxTag =~ s/\W+/_/go;
563             $jnxTag =~ s/_$//go;
564             # Fix the .'s into _'s for the RRD-DS and name of leaf
565             my $opIndexFix = $opIndex;
566             $opIndexFix =~ s/\./_/g;
567
568             # PROG: Find CPU that does not equal 0
569             if ($jnxCPU > 0)
570             {
571                 $cb->addSubtree( $nodeCPU, $jnxTag,
572                                  { 'comment'   => $jnxDesc,
573                                    'cpu-index' => $opIndex },
574                                  [ 'JunOS::junos-cpu' ]);
575             }
576
577             # PROG: Find memory that does not equal 0
578             if ($jnxMem > 0)
579             {
580                 $cb->addSubtree( $nodeMem, $jnxTag,
581                                  { 'comment'      => $jnxDesc,
582                                    'mem-index'    => $opIndex,
583                                    'mem-indexFix' => $opIndexFix },
584                                  [ 'JunOS::junos-memory' ]);
585             }
586
587             # PROG: Find Temperature that does not equal 0
588             if ($jnxTemp > 0)
589             {
590                 if ($jnxDesc =~ /(temp.* sensor|Engine)/) {
591                     # Small little hack to cleanup the sensor tags
592                     $jnxTag =~ s/_temp(erature|)_sensor//g;
593                     $cb->addLeaf( $nodeTemp, $jnxTag,
594                                   { 'comment'         => $jnxDesc,
595                                     'sensor-desc'     => $jnxDesc, 
596                                     'sensor-index'    => $opIndex,
597                                     'sensor-indexFix' => $opIndexFix },
598                                   [ 'JunOS::junos-temperature-sensor' ]);
599                 }
600             }
601         } # END foreach $opIndex
602     } # END if jnxOperating
603
604
605     # PROG: Reverse Forwarding Path (RPF)
606     if( $devdetails->hasCap('jnxRPF') )
607     {
608         # Add subtree first
609         my $nodeRPF = $cb->addSubtree( $devNode, 'RPF', undef,
610                                        [ 'JunOS::junos-rpf-subtree' ]);
611
612         # Loop through and find all interfaces with RPF enabled
613         foreach my $ifIndex ( sort {$a <=> $b} keys %{$data->{'jnxRPF'}} )
614         {
615             # Set some names
616             my $ifAlias = $data->{'interfaces'}{$ifIndex}{'ifAlias'};
617             my $ifName  = $data->{'interfaces'}{$ifIndex}{'ifName'};
618             my $ifNameT = $data->{'interfaces'}{$ifIndex}{'ifNameT'};
619             my $hasIPv4 = $data->{'jnxRPF'}{$ifIndex}{'ipv4'};
620             my $hasIPv6 = $data->{'jnxRPF'}{$ifIndex}{'ipv6'};
621
622             Debug("JunOS:: RPF  int: $ifName  IPv4: $hasIPv4  IPv6: $hasIPv6");
623
624             # PROG: Process IPv4 first ... 
625             if( $hasIPv4 )
626             {
627                 $cb->addSubtree( $nodeRPF, 'IPv4_' . $ifNameT,
628                                  { 'comment'    => $ifAlias,
629                                    'ifAddrType' => "ipv4",
630                                    'ifName'     => $ifName,
631                                    'ifNameT'    => $ifNameT,
632                                    'rpfIndex'   => $ifIndex . "." . $hasIPv4 },
633                                  [ 'JunOS::junos-rpf' ]);
634             }
635
636             if( $hasIPv6 )
637             {
638                 $cb->addSubtree( $nodeRPF, 'IPv6_' . $ifNameT,
639                                  { 'comment'    => $ifAlias,
640                                    'ifAddrType' => "ipv6",
641                                    'ifName'     => $ifName,
642                                    'ifNameT'    => $ifNameT,
643                                    'rpfIndex'   => $ifIndex . "." . $hasIPv6 },
644                                  [ 'JunOS::junos-rpf' ]);
645             }
646         }
647     } # END: if jnxRPF
648 }
649
650
651 1;
652
653 # Local Variables:
654 # mode: perl
655 # indent-tabs-mode: nil
656 # perl-indent-level: 4
657 # End: