1# SNMP::Info
2#
3# Copyright (c) 2003-2012 Max Baker and SNMP::Info Developers
4# All rights reserved.
5#
6# Portions Copyright (c) 2002-2003, Regents of the University of California
7# All rights reserved.
8#
9# See COPYRIGHT at bottom
10
11package SNMP::Info;
12
13use warnings;
14use strict;
15use Exporter;
16use SNMP;
17use Carp;
18use Math::BigInt;
19use NetAddr::IP::Lite ':lower';
20
21@SNMP::Info::ISA       = qw/Exporter/;
22@SNMP::Info::EXPORT_OK = qw//;
23
24our
25    ($VERSION, %FUNCS, %GLOBALS, %MIBS, %MUNGE, $AUTOLOAD, $INIT, $DEBUG, %SPEED_MAP,
26     $NOSUCH, $BIGINT, $REPEATERS);
27
28$VERSION = '3.81';
29
30=head1 NAME
31
32SNMP::Info - OO Interface to Network devices and MIBs through SNMP
33
34=head1 VERSION
35
36SNMP::Info - Version 3.81
37
38=head1 AUTHOR
39
40SNMP::Info is maintained by team of Open Source authors headed by Eric Miller,
41Bill Fenner, Max Baker, Jeroen van Ingen and Oliver Gorwits.
42
43Please visit L<https://github.com/netdisco/snmp-info/> for the most up-to-date
44list of developers.
45
46SNMP::Info was originally created at UCSC for the Netdisco project L<http://netdisco.org>
47by Max Baker.
48
49=head1 DEVICES SUPPORTED
50
51There are now generic classes for most types of device and so the authors
52recommend loading SNMP::Info with AutoSpecify, and then reporting to the mail
53list any missing functionality (such as neighbor discovery tables).
54
55=head1 SYNOPSIS
56
57 use SNMP::Info;
58
59 my $info = new SNMP::Info(
60                            # Auto Discover more specific Device Class
61                            AutoSpecify => 1,
62                            Debug       => 1,
63                            # The rest is passed to SNMP::Session
64                            DestHost    => 'router',
65                            Community   => 'public',
66                            Version     => 2
67                          ) or die "Can't connect to device.\n";
68
69 my $err = $info->error();
70 die "SNMP Community or Version probably wrong connecting to device. $err\n" if defined $err;
71
72 my $name  = $info->name();
73 my $class = $info->class();
74 print "SNMP::Info is using this device class : $class\n";
75
76 # Find out the Duplex status for the ports
77 my $interfaces = $info->interfaces();
78 my $i_duplex   = $info->i_duplex();
79
80 # Get CDP Neighbor info
81 my $c_if       = $info->c_if();
82 my $c_ip       = $info->c_ip();
83 my $c_port     = $info->c_port();
84
85 # Print out data per port
86 foreach my $iid (keys %$interfaces){
87    my $duplex = $i_duplex->{$iid};
88    # Print out physical port name, not snmp iid
89    my $port  = $interfaces->{$iid};
90
91    print "$port: ";
92    print "$duplex duplex" if defined $duplex;
93
94    # The CDP Table has table entries different than the interface tables.
95    # So we use c_if to get the map from cdp table to interface table.
96
97    my %c_map = reverse %$c_if;
98    my $c_key = $c_map{$iid};
99    unless (defined $c_key) {
100         print "\n\n";
101         next;
102     }
103    my $neighbor_ip   = $c_ip->{$c_key};
104    my $neighbor_port = $c_port->{$c_key};
105
106    print " connected to $neighbor_ip / $neighbor_port\n" if defined $neighbor_ip;
107    print "\n";
108
109 }
110
111=head1 SUPPORT
112
113Please direct all support, help, and bug requests to the snmp-info-users
114Mailing List at L<http://lists.sourceforge.net/lists/listinfo/snmp-info-users>.
115
116=head1 DESCRIPTION
117
118SNMP::Info gives an object oriented interface to information obtained through
119SNMP.
120
121This module is geared towards network devices.  Subclasses exist for a number
122of network devices and common MIBs.
123
124The idea behind this module is to give a common interface to data from network
125devices, leaving the device-specific hacks behind the scenes in subclasses.
126
127In the SYNOPSIS example we fetch the name of all the ports on the device and
128the duplex setting for that port with two methods -- interfaces() and
129i_duplex().
130
131The information may be coming from any number of MIB files and is very vendor
132specific.  SNMP::Info provides you a common method for all supported devices.
133
134Adding support for your own device is easy, and takes little SNMP knowledge.
135
136The module is not limited to network devices. Any MIB or device can be given
137an objected oriented front-end by making a module that consists of a couple
138hashes.  See EXTENDING SNMP::INFO.
139
140=head1 REQUIREMENTS
141
142=over
143
144=item 1. Net-SNMP
145
146To use this module, you must have Net-SNMP installed on your system.
147More specifically you need the Perl modules that come with it.
148
149DO NOT INSTALL SNMP:: or Net::SNMP from CPAN!
150
151The SNMP module is matched to an install of net-snmp, and must be installed
152from the net-snmp source tree.
153
154The Perl module C<SNMP> is found inside the net-snmp distribution.  Go to the
155F<perl/> directory of the distribution to install it, or run
156C<./configure --with-perl-modules> from the top directory of the net-snmp
157distribution.
158
159Net-SNMP can be found at http://net-snmp.sourceforge.net
160
161Version 5.3.2 or greater is recommended.
162
163Versions 5.0.1, 5.0301 and 5.0203 have issues with bulkwalk and are not supported.
164
165B<Redhat Users>: Some versions that come with certain versions of
166Redhat/Fedora don't have the Perl library installed.  Uninstall the RPM and
167install by hand.
168
169=item 2. MIBS
170
171SNMP::Info operates on textual descriptors found in MIBs.
172
173If you are using SNMP::Info separate from Netdisco,
174download the Netdisco MIB package at L<https://github.com/netdisco/netdisco-mibs/releases/latest/>
175
176Make sure that your snmp.conf is updated to point to your MIB directory
177and that the MIBs are world-readable.
178
179=back
180
181=head1 DESIGN GOALS
182
183=over
184
185=item 1. Use of textual MIB leaf identifier and enumerated values
186
187=over
188
189=item * All values are retrieved via MIB Leaf node names
190
191For example SNMP::Info has an entry in its %GLOBALS hash for ``sysName''
192instead of 1.3.6.1.2.1.1.5.
193
194=item * Data returned is in the enumerated value form.
195
196For Example instead of looking up 1.3.6.1.2.1.2.2.1.3 and getting back C<23>
197
198SNMP::Info will ask for C<RFC1213-MIB::ifType> and will get back C<ppp>.
199
200=back
201
202=item 2. SNMP::Info is easily extended to new devices
203
204You can create a new subclass for a device by providing four hashes :
205%GLOBALS, %MIBS, %FUNCS, and %MUNGE.
206
207Or you can override any existing methods from a parent class by making a short
208subroutine.
209
210See the section EXTENDING SNMP::INFO for more details.
211
212When you make a new subclass for a device, please be sure to send it back
213to the developers (via a github pull request or the mailing list) for inclusion
214in the next version.
215
216=back
217
218=head1 SUBCLASSES
219
220These are the subclasses that implement MIBs and support devices:
221
222Required MIBs not included in the install instructions above are noted here.
223
224=head2 MIB Subclasses
225
226These subclasses implement method to access one or more MIBs.  These are not
227used directly, but rather inherited from device subclasses.
228
229For more info run C<perldoc> on any of the following module names.
230
231=over
232
233=item SNMP::Info::AdslLine
234
235SNMP Interface to the ADSL-LINE-MIB for ADSL interfaces.
236
237Requires the F<ADSL-LINE-MIB>, down loadable from Cisco.
238
239See documentation in L<SNMP::Info::AdslLine> for details.
240
241=item SNMP::Info::Aggregate
242
243SNMP Interface to F<IF-MIB> C<ifStackTable> Aggregated Links
244
245See documentation in L<SNMP::Info::Aggregate> for details.
246
247=item SNMP::Info::Airespace
248
249F<AIRESPACE-WIRELESS-MIB> and F<AIRESPACE-SWITCHING-MIB>.  Inherited by
250devices based on the Airespace wireless platform.
251
252See documentation in L<SNMP::Info::Airespace> for details.
253
254=item SNMP::Info::AMAP
255
256F<ALCATEL-IND1-INTERSWITCH-PROTOCOL-MIB>.  Alcatel Mapping Adjacency
257Protocol (AMAP) Support.
258
259See documentation in L<SNMP::Info::AMAP> for details.
260
261=item SNMP::Info::Bridge
262
263F<BRIDGE-MIB> (RFC1286).  F<Q-BRIDGE-MIB>. Inherited by devices with Layer2
264support.
265
266See documentation in L<SNMP::Info::Bridge> for details.
267
268=item SNMP::Info::CDP
269
270F<CISCO-CDP-MIB>.  Cisco Discovery Protocol (CDP) Support.  Inherited by
271Cisco, Enterasys, and HP devices.
272
273See documentation in L<SNMP::Info::CDP> for details.
274
275=item SNMP::Info::CiscoAgg
276
277SNMP Interface to Cisco Aggregated Links
278
279See documentation in L<SNMP::Info::CiscoAgg> for details.
280
281=item SNMP::Info::CiscoConfig
282
283F<CISCO-CONFIG-COPY-MIB>, F<CISCO-FLASH-MIB>, and F<OLD-CISCO-SYS-MIB>.
284These OIDs facilitate the writing of configuration files.
285
286See documentation in L<SNMP::Info::CiscoConfig> for details.
287
288=item SNMP::Info::CiscoPortSecurity
289
290F<CISCO-PORT-SECURITY-MIB> and F<CISCO-PAE-MIB>.
291
292See documentation in L<SNMP::Info::CiscoPortSecurity> for details.
293
294=item SNMP::Info::CiscoPower
295
296F<CISCO-POWER-ETHERNET-EXT-MIB>.
297
298See documentation in L<SNMP::Info::CiscoPower> for details.
299
300=item SNMP::Info::CiscoQOS
301
302F<CISCO-CLASS-BASED-QOS-MIB>. A collection of OIDs providing information about
303a Cisco device's QOS config.
304
305See documentation in L<SNMP::Info::CiscoQOS> for details.
306
307=item SNMP::Info::CiscoRTT
308
309F<CISCO-RTTMON-MIB>. A collection of OIDs providing information about a Cisco
310device's RTT values.
311
312See documentation in L<SNMP::Info::CiscoRTT> for details.
313
314=item SNMP::Info::CiscoStack
315
316F<CISCO-STACK-MIB>.
317
318See documentation in L<SNMP::Info::CiscoStack> for details.
319
320=item SNMP::Info::CiscoStats
321
322F<OLD-CISCO-CPU-MIB>, F<CISCO-PROCESS-MIB>, and F<CISCO-MEMORY-POOL-MIB>.
323Provides common interfaces for memory, cpu, and os statistics for Cisco
324devices.
325
326See documentation in L<SNMP::Info::CiscoStats> for details.
327
328=item SNMP::Info::CiscoStpExtensions
329
330F<CISCO-STP-EXTENSIONS-MIB>
331
332See documentation in L<SNMP::Info::CiscoStpExtensions> for details.
333
334=item SNMP::Info::CiscoVTP
335
336F<CISCO-VTP-MIB>, F<CISCO-VLAN-MEMBERSHIP-MIB>,
337F<CISCO-VLAN-IFTABLE-RELATIONSHIP-MIB>
338
339See documentation in L<SNMP::Info::CiscoVTP> for details.
340
341=item SNMP::Info::DocsisCM
342
343SNMP Interface for DOCSIS Cable Modems
344
345See documentation in L<SNMP::Info::DocsisCM> for details.
346
347=item SNMP::Info::DocsisHE
348
349SNMP Interface for DOCSIS CMTS
350
351See documentation in L<SNMP::Info::DocsisHE> for details.
352
353=item SNMP::Info::EDP
354
355Extreme Discovery Protocol.  F<EXTREME-EDP-MIB>
356
357See documentation in L<SNMP::Info::EDP> for details.
358
359=item SNMP::Info::Entity
360
361F<ENTITY-MIB>.  Used for device info in Cisco and other vendors.
362
363See documentation in L<SNMP::Info::Entity> for details.
364
365=item SNMP::Info::EtherLike
366
367F<EtherLike-MIB> (RFC1398) - Some Layer3 devices implement this MIB, as well
368as some Aironet Layer 2 devices (non Cisco).
369
370See documentation in L<SNMP::Info::EtherLike> for details.
371
372=item SNMP::Info::FDP
373
374Foundry (Brocade) Discovery Protocol.  F<FOUNDRY-SN-SWITCH-GROUP-MIB>
375
376See documentation in L<SNMP::Info::FDP> for details.
377
378=item SNMP::Info::IEEE802_Bridge
379
380SNMP Interface to data available through the F<IEEE8021-Q-BRIDGE-MIB>
381
382See documentation in L<SNMP::Info::IEEE802_Bridge> for details.
383
384=item SNMP::Info::IEEE802dot11
385
386F<IEEE802dot11-MIB>.  A collection of OIDs providing information about
387standards based 802.11 wireless devices.
388
389See documentation in L<SNMP::Info::IEEE802dot11> for details.
390
391=item SNMP::Info::IEEE802dot3ad
392
393SNMP Interface to IEEE Aggregated Links.  F<IEEE8023-LAG-MIB>
394
395See documentation in L<SNMP::Info::IEEE802dot3ad> for details.
396
397=item SNMP::Info::IPv6
398
399SNMP Interface for obtaining configured IPv6 addresses and mapping IPv6
400addresses to MAC addresses and interfaces, using information from F<IP-MIB>,
401F<IPV6-MIB> and/or F<CISCO-IETF-IP-MIB>.
402
403See documentation in L<SNMP::Info::IPv6> for details.
404
405=item SNMP::Info::LLDP
406
407F<LLDP-MIB>, F<LLDP-EXT-DOT1-MIB>, and F<LLDP-EXT-DOT3-MIB>.  Link Layer
408Discovery Protocol (LLDP) Support.
409
410See documentation in L<SNMP::Info::LLDP> for details.
411
412=item SNMP::Info::MAU
413
414F<MAU-MIB> (RFC2668).  Some Layer2 devices use this for extended Ethernet
415(Medium Attachment Unit) interface information.
416
417See documentation in L<SNMP::Info::MAU> for details.
418
419=item SNMP::Info::MRO
420
421Method resolution introspection for SNMP::Info
422
423See documentation in L<SNMP::Info::MRO> for details.
424
425=item SNMP::Info::NortelStack
426
427F<S5-AGENT-MIB>, F<S5-CHASSIS-MIB>.
428
429See documentation in L<SNMP::Info::NortelStack> for details.
430
431=item SNMP::Info::PowerEthernet
432
433F<POWER-ETHERNET-MIB>
434
435See documentation in L<SNMP::Info::PowerEthernet> for details.
436
437=item SNMP::Info::RapidCity
438
439F<RAPID-CITY>.  Inherited by Avaya switches for duplex and VLAN information.
440
441See documentation in L<SNMP::Info::RapidCity> for details.
442
443=item SNMP::Info::SONMP
444
445SynOptics Network Management Protocol (SONMP) F<SYNOPTICS-ROOT-MIB>,
446F<S5-ETH-MULTISEG-TOPOLOGY-MIB>.  Inherited by
447Avaya/Nortel/Bay/Synoptics switches and hubs.
448
449See documentation in L<SNMP::Info::SONMP> for details.
450
451=back
452
453=head2 Device Subclasses
454
455These subclasses inherit from one or more classes to provide a common
456interface to data obtainable from network devices.
457
458All the required MIB files are included in the netdisco-mib package.
459(See Above).
460
461=over 4
462
463=item SNMP::Info::Layer1
464
465Generic Layer1 Device subclass.
466
467See documentation in L<SNMP::Info::Layer1> for details.
468
469=over 4
470
471=item SNMP::Info::Layer1::Allied
472
473Subclass for Allied Telesis Repeaters / Hubs.
474
475Requires F<ATI-MIB>
476
477See documentation in L<SNMP::Info::Layer1::Allied> for details.
478
479=item SNMP::Info::Layer1::Asante
480
481Subclass for Asante 1012 Hubs.
482
483Requires F<ASANTE-HUB1012-MIB>
484
485See documentation in L<SNMP::Info::Layer1::Asante> for details.
486
487=item SNMP::Info::Layer1::Bayhub
488
489Subclass for Nortel/Bay hubs.  This includes System 5000, 100 series,
490200 series, and probably more.
491
492See documentation in L<SNMP::Info::Layer1::Bayhub> for details.
493
494=item SNMP::Info::Layer1::Cyclades
495
496Subclass for Cyclades/Avocent terminal servers.
497
498See documentation in L<SNMP::Info::Layer1::Cyclades> for details.
499
500=item SNMP::Info::Layer1::S3000
501
502Subclass for Bay/Synoptics hubs.  This includes System 3000, 281X, and
503probably more.
504
505See documentation in L<SNMP::Info::Layer1::S3000> for details.
506
507=back
508
509=item SNMP::Info::Layer2
510
511Generic Layer2 Device subclass.
512
513See documentation in L<SNMP::Info::Layer2> for details.
514
515=over
516
517=item SNMP::Info::Layer2::3Com
518
519Subclass for L2 3Com Switches.
520
521See documentation in L<SNMP::Info::Layer2::3Com> for details.
522
523=item SNMP::Info::Layer2::Adtran
524
525Subclass for Adtran devices.
526
527See documentation in L<SNMP::Info::Layer2::Adtran> for details.
528
529=item SNMP::Info::Layer2::Aerohive
530
531Subclass for Aerohive / Extreme access points.
532
533See documentation in L<SNMP::Info::Layer2::Aerohive> for details.
534
535=item SNMP::Info::Layer2::Airespace
536
537Subclass for Cisco (Airespace) wireless controllers.
538
539See documentation in L<SNMP::Info::Layer2::Airespace> for details.
540
541=item SNMP::Info::Layer2::Aironet
542
543Class for Cisco Aironet wireless devices that run IOS.  See also
544L<SNMP::Info::Layer3::Aironet> for Aironet devices that don't run IOS.
545
546See documentation in L<SNMP::Info::Layer2::Aironet> for details.
547
548=item SNMP::Info::Layer2::Allied
549
550Allied Telesis switches.
551
552See documentation in L<SNMP::Info::Layer2::Allied> for details.
553
554=item SNMP::Info::Layer2::Atmedia
555
556Subclass for atmedia encryptors.
557
558See documentation in L<SNMP::Info::Layer2::Atmedia> for details.
559
560=item SNMP::Info::Layer2::Baystack
561
562Subclass for Avaya/Nortel/Bay Ethernet Switch/Baystack switches.  This
563includes 303, 304, 350, 380, 410, 420, 425, 450, 460, 470 series,
5642500 series, 4000 series, 5000 series, Business Ethernet Switch (BES),
565Business Policy Switch (BPS), VSP 7000 series, and probably others.
566
567See documentation in L<SNMP::Info::Layer2::Baystack> for details.
568
569=item SNMP::Info::Layer2::C1900
570
571Subclass for Cisco Catalyst 1900 and 1900c Devices running CatOS.
572
573See documentation in L<SNMP::Info::Layer2::C1900> for details.
574
575=item SNMP::Info::Layer2::C2900
576
577Subclass for Cisco Catalyst 2900, 2950, 3500XL, and 3548 devices running IOS.
578
579See documentation in L<SNMP::Info::Layer2::C2900> for details.
580
581=item SNMP::Info::Layer2::Catalyst
582
583Subclass for Cisco Catalyst switches running CatOS.  These switches usually
584report a model number that starts with C<wsc>.   Note that this class
585does not support everything that has the name Catalyst.
586
587See documentation in L<SNMP::Info::Layer2::Catalyst> for details.
588
589=item SNMP::Info::Layer2::Centillion
590
591Subclass for Nortel/Bay Centillion and 5000BH ATM switches.
592
593See documentation in L<SNMP::Info::Layer2::Centillion> for details.
594
595=item SNMP::Info::Layer2::Cisco
596
597Generic Cisco subclass for layer 2 devices that are not yet supported
598in more specific subclasses and the base layer 2 Cisco class for
599other device specific layer 2 Cisco classes.
600
601See documentation in L<SNMP::Info::Layer2::Cisco> for details.
602
603=item SNMP::Info::Layer2::CiscoSB
604
605Subclass for Cisco's "Small Business" product line, acquired from
606Linksys.  This currently comprises the Sx300/500 line of switches.
607
608See documentation in L<SNMP::Info::Layer2::CiscoSB> for details.
609
610=item SNMP::Info::Layer2::Exinda
611
612Subclass for Exinda / GFI Network Orchestrator traffic shapers.
613
614See documentation in L<SNMP::Info::Layer2::Exinda> for details.
615
616=item SNMP::Info::Layer2::HP
617
618Subclass for more recent HP Procurve Switches.
619
620Requires F<HP-ICF-OID> and F<ENTITY-MIB> downloaded from HP.
621
622See documentation in L<SNMP::Info::Layer2::HP> for details.
623
624=item SNMP::Info::Layer2::HP4000
625
626Subclass for older HP Procurve Switches
627
628Requires F<HP-ICF-OID> and F<ENTITY-MIB> downloaded from HP.
629
630See documentation in L<SNMP::Info::Layer2::HP4000> for details.
631
632=item SNMP::Info::Layer2::HPVC
633
634Subclass for HP Virtual Connect Switches
635
636See documentation in L<SNMP::Info::Layer2::HPVC> for details.
637
638=item SNMP::Info::Layer2::Kentrox
639
640Class for Kentrox DataSMART DSU/CSU.
641
642See documentation in L<SNMP::Info::Layer2::Kentrox> for details.
643
644=item SNMP::Info::Layer2::N2270
645
646Subclass for Nortel 2270 wireless switches.
647
648See documentation in L<SNMP::Info::Layer2::N2270> for details.
649
650=item SNMP::Info::Layer2::NAP222x
651
652Subclass for Nortel 222x series wireless access points.
653
654See documentation in L<SNMP::Info::Layer2::NAP222x> for details.
655
656=item SNMP::Info::Layer2::Netgear
657
658Subclass for Netgear switches
659
660See documentation in L<SNMP::Info::Layer2::Netgear> for details.
661
662=item SNMP::Info::Layer2::Nexans
663
664Subclass for Nexans switches
665
666See documentation in L<SNMP::Info::Layer2::Nexans> for details.
667
668=item SNMP::Info::Layer2::NWSS2300
669
670SNMP Interface to Avaya (Trapeze) Wireless Controllers
671
672See documentation in L<SNMP::Info::Layer2::NWSS2300> for details.
673
674=item SNMP::Info::Layer2::Orinoco
675
676Subclass for Orinoco/Proxim wireless access points.
677
678See documentation in L<SNMP::Info::Layer2::Orinoco> for details.
679
680=item SNMP::Info::Layer2::Trapeze
681
682SNMP Interface to Juniper (Trapeze) Wireless Controllers
683
684See documentation in L<SNMP::Info::Layer2::Trapeze> for details.
685
686=item SNMP::Info::Layer2::Sixnet
687
688SNMP Interface to Sixnet industrial switches
689
690See documentation in L<SNMP::Info::Layer2::Sixnet> for details.
691
692=item SNMP::Info::Layer2::Ubiquiti
693
694SNMP Interface to Ubiquiti Access Points and other devices
695
696See documentation in L<SNMP::Info::Layer2::Ubiquiti> for details.
697
698=item SNMP::Info::Layer2::ZyXEL_DSLAM
699
700Zyxel DSLAMs.  Need I say more?
701
702See documentation in L<SNMP::Info::Layer2::ZyXEL_DSLAM> for details.
703
704=back
705
706=item SNMP::Info::Layer3
707
708Generic Layer3 and Layer2+3 Device subclass.
709
710See documentation in L<SNMP::Info::Layer3> for details.
711
712=over
713
714=item SNMP::Info::Layer3::Aironet
715
716Subclass for Cisco Aironet wireless access points (AP) not running IOS. These
717are usually older devices.
718
719Note L<SNMP::Info::Layer2::Aironet>
720
721See documentation in L<SNMP::Info::Layer3::Aironet> for details.
722
723=item SNMP::Info::Layer3::AlcatelLucent
724
725Alcatel-Lucent OmniSwitch Class.
726
727See documentation in L<SNMP::Info::Layer3::AlcatelLucent> for details.
728
729=item SNMP::Info::Layer3::AlteonAD
730
731Subclass for Radware Alteon Series ADC switches and Nortel BladeCenter
732Layer2-3 GbE Switch Modules.
733
734See documentation in L<SNMP::Info::Layer3::AlteonAD> for details.
735
736=item SNMP::Info::Layer3::Altiga
737
738See documentation in L<SNMP::Info::Layer3::Altiga> for details.
739
740=item SNMP::Info::Layer3::Arista
741
742See documentation in L<SNMP::Info::Layer3::Arista> for details.
743
744=item SNMP::Info::Layer3::Aruba
745
746Subclass for Aruba wireless switches.
747
748See documentation in L<SNMP::Info::Layer3::Aruba> for details.
749
750=item SNMP::Info::Layer3::ArubaCX
751
752SNMP Interface to L3 Devices running ArubaOS-CX
753
754See documentation in L<SNMP::Info::Layer3::ArubaCX> for details.
755
756=item SNMP::Info::Layer3::BayRS
757
758Subclass for Avaya/Nortel/Bay Multiprotocol/BayRS routers.  This includes
759BCN, BLN, ASN, ARN, AN, 2430, and 5430 routers.
760
761See documentation in L<SNMP::Info::Layer3::BayRS> for details.
762
763=item SNMP::Info::Layer3::BlueCoatSG
764
765Subclass for BlueCoat SG series proxy devices.
766
767See documentation in L<SNMP::Info::Layer3::BlueCoatSG> for details.
768
769=item SNMP::Info::Layer3::C3550
770
771Subclass for Cisco Catalyst 3550,3540,3560 2/3 switches running IOS.
772
773See documentation in L<SNMP::Info::Layer3::C3550> for details.
774
775=item SNMP::Info::Layer3::C4000
776
777This class covers Catalyst 4000s and 4500s.
778
779See documentation in L<SNMP::Info::Layer3::C4000> for details.
780
781=item SNMP::Info::Layer3::C6500
782
783This class covers Catalyst 6500 series running CatOS or IOS, as well as
784Catalyst 2960, 2970, 3750 and 3850 series, including blade switches
785CBS30x0 and CBS31x0 series, all running IOS.
786
787See documentation in L<SNMP::Info::Layer3::C6500> for details.
788
789=item SNMP::Info::Layer3::CheckPoint
790
791Subclass for CheckPoint devices.
792
793See documentation in L<SNMP::Info::Layer3::CheckPoint> for details.
794
795=item SNMP::Info::Layer3::Ciena
796
797Subclass for Ciena devices.
798
799See documentation in L<SNMP::Info::Layer3::Ciena> for details.
800
801=item SNMP::Info::Layer3::Cisco
802
803This is a simple wrapper around layer 3 for IOS devices and the base layer 3
804Cisco class for other device specific layer 3 Cisco classes.
805
806See documentation in L<SNMP::Info::Layer3::Cisco> for details.
807
808=item SNMP::Info::Layer3::CiscoASA
809
810Subclass for Cisco Adaptive Security Appliances.
811
812See documentation in L<SNMP::Info::Layer3::CiscoASA> for details.
813
814=item SNMP::Info::Layer3::CiscoFWSM
815
816Subclass for Cisco Firewall Services Modules.
817
818See documentation in L<SNMP::Info::Layer3::CiscoFWSM> for details.
819
820=item SNMP::Info::Layer3::CiscoSwitch
821
822Base class for L3 Cisco switches.  See documentation in
823L<SNMP::Info::Layer3::CiscoSwitch> for details.
824
825=item SNMP::Info::Layer3::Contivity
826
827Subclass for Avaya/Nortel Contivity/VPN Routers.
828
829See documentation in L<SNMP::Info::Layer3::Contivity> for details.
830
831=item SNMP::Info::Layer3::Cumulus
832
833Subclass for Cumulus Networks Routers.
834
835See documentation in L<SNMP::Info::Layer3::Cumulus> for details.
836
837=item SNMP::Info::Layer3::Dell
838
839Subclass for Dell PowerConnect switches. The IBM BladeCenter
840Gigabit Ethernet Switch Module and some Linksys switches
841also use this module based upon MIB support.
842
843See documentation in L<SNMP::Info::Layer3::Dell> for details.
844
845=item SNMP::Info::Layer3::DLink
846
847Subclass for DLink devices.
848
849See documentation in L<SNMP::Info::Layer3::DLink> for details.
850
851=item SNMP::Info::Layer3::Enterasys
852
853Subclass for Enterasys devices.
854
855See documentation in L<SNMP::Info::Layer3::Enterasys> for details.
856
857=item SNMP::Info::Layer3::ERX
858
859Subclass for Juniper ERX switches.
860
861See documentation in L<SNMP::Info::Layer3::ERX> for details.
862
863=item SNMP::Info::Layer3::Extreme
864
865Subclass for Extreme Networks switches.
866
867See documentation in L<SNMP::Info::Layer3::Extreme> for details.
868
869=item SNMP::Info::Layer3::F5
870
871Subclass for F5 devices.
872
873See documentation in L<SNMP::Info::Layer3::F5> for details.
874
875=item SNMP::Info::Layer3::Force10
876
877Subclass for Force10 devices.
878
879See documentation in L<SNMP::Info::Layer3::Force10> for details.
880
881=item SNMP::Info::Layer3::Fortinet
882
883Subclass for Fortinet devices.
884
885See documentation in L<SNMP::Info::Layer3::Fortinet> for details.
886
887=item SNMP::Info::Layer3::Foundry
888
889Subclass for Brocade (Foundry) Network devices.
890
891See documentation in L<SNMP::Info::Layer3::Foundry> for details.
892
893=item SNMP::Info::Layer3::Genua
894
895Subclass for Genua security devices.
896
897See documentation in L<SNMP::Info::Layer3::Genua> for details.
898
899=item SNMP::Info::Layer3::H3C
900
901SNMP Interface to Layer 3 Devices, H3C & HP A-series.
902
903See documentation in L<SNMP::Info::Layer3::H3C> for details.
904
905=item SNMP::Info::Layer3::HP9300
906
907Subclass for HP network devices which Foundry Networks was the
908Original Equipment Manufacturer (OEM) such as the HP ProCurve 9300 and 6300 series.
909
910See documentation in L<SNMP::Info::Layer3::HP9300> for details.
911
912=item SNMP::Info::Layer3::Huawei
913
914SNMP Interface to Huawei Layer 3 switches and routers.
915
916See documentation in L<SNMP::Info::Layer3::Huawei> for details.
917
918=item SNMP::Info::Layer3::IBMGbTor
919
920SNMP Interface to IBM Rackswitch (formerly Blade Network Technologies)
921network devices. Lenovo acquired these from IBM and is now selling
922them under the Lenovo brand.
923
924See documentation in L<SNMP::Info::Layer3::IBMGbTor> for details.
925
926=item SNMP::Info::Layer3::Juniper
927
928Subclass for Juniper devices.
929
930See documentation in L<SNMP::Info::Layer3::Juniper> for details.
931
932=item SNMP::Info::Layer3::Lantronix
933
934Subclass for Lantronix devices.
935
936See documentation in L<SNMP::Info::Layer3::Lantronix> for details.
937
938=item SNMP::Info::Layer3::Lenovo
939
940Subclass for Lenovo switches running CNOS.
941
942See documentation in L<SNMP::Info::Layer3::Lenovo> for details.
943
944=item SNMP::Info::Layer3::Microsoft
945
946Subclass for Generic Microsoft Routers running Microsoft Windows OS.
947
948See documentation in L<SNMP::Info::Layer3::Microsoft> for details.
949
950=item SNMP::Info::Layer3::Mikrotik
951
952Subclass for Mikrotik devices running RouterOS.
953
954See documentation in L<SNMP::Info::Layer3::Mikrotik> for details.
955
956=item SNMP::Info::Layer3::N1600
957
958Subclass for Avaya/Nortel Ethernet Routing Switch 1600 series.
959
960See documentation in L<SNMP::Info::Layer3::N1600> for details.
961
962=item SNMP::Info::Layer3::NetSNMP
963
964Subclass for host systems running Net-SNMP.
965
966See documentation in L<SNMP::Info::Layer3::NetSNMP> for details.
967
968=item SNMP::Info::Layer3::Netscreen
969
970Subclass for Juniper NetScreen.
971
972See documentation in L<SNMP::Info::Layer3::Netscreen> for details.
973
974=item SNMP::Info::Layer3::Nexus
975
976Subclass for Cisco Nexus devices running NX-OS.
977
978See documentation in L<SNMP::Info::Layer3::Nexus> for details.
979
980=item SNMP::Info::Layer3::OneAccess
981
982Subclass for OneAccess routers.
983
984See documentation in L<SNMP::Info::Layer3::OneAccess> for details.
985
986=item SNMP::Info::Layer3::PacketFront
987
988Subclass for PacketFront DRG series CPE.
989
990See documentation in L<SNMP::Info::Layer3::PacketFront> for details.
991
992=item SNMP::Info::Layer3::PaloAlto
993
994Subclass for Palo Alto firewalls.
995
996See documentation in L<SNMP::Info::Layer3::PaloAlto> for details.
997
998=item SNMP::Info::Layer3::Passport
999
1000Subclass for Avaya/Nortel Ethernet Routing Switch/Passport 8000 series,
1001Accelar, and VSP 9000 series switches.
1002
1003See documentation in L<SNMP::Info::Layer3::Passport> for details.
1004
1005=item SNMP::Info::Layer3::Pf
1006
1007Subclass for FreeBSD-Based Firewalls using Pf /Pf Sense
1008
1009See documentation in L<SNMP::Info::Layer3::Pf> for details.
1010
1011=item SNMP::Info::Layer3::Pica8
1012
1013Subclass for Pica8 devices.
1014
1015See documentation in L<SNMP::Info::Layer3::Pica8> for details.
1016
1017=item SNMP::Info::Layer3::Redlion
1018
1019Subclass for redlion routers.
1020
1021See documentation in L<SNMP::Info::Layer3::Redlion> for details.
1022
1023=item SNMP::Info::Layer3::Scalance
1024
1025Subclass for Siemens Scalance devices.
1026
1027See documentation in L<SNMP::Info::Layer3::Scalance> for details.
1028
1029=item SNMP::Info::Layer3::SonicWALL
1030
1031Subclass for generic SonicWALL devices.
1032
1033See documentation in L<SNMP::Info::Layer3::SonicWALL> for details.
1034
1035=item SNMP::Info::Layer3::Steelfusion
1036
1037Subclass for Riverbed Steelfusion WAN optimization appliances.
1038
1039See documentation in L<SNMP::Info::Layer3::Steelfusion> for details.
1040
1041=item SNMP::Info::Layer3::Steelhead
1042
1043Subclass for Riverbed Steelhead WAN optimization appliances.
1044
1045See documentation in L<SNMP::Info::Layer3::Steelhead> for details.
1046
1047=item SNMP::Info::Layer3::SteelheadEx
1048
1049Subclass for Riverbed SteelheadEx WAN optimization appliances.
1050
1051See documentation in L<SNMP::Info::Layer3::SteelheadEx> for details.
1052
1053=item SNMP::Info::Layer3::Sun
1054
1055Subclass for Generic Sun Routers running SunOS.
1056
1057See documentation in L<SNMP::Info::Layer3::Sun> for details.
1058
1059=item SNMP::Info::Layer3::Tasman
1060
1061Subclass for Avaya Secure Routers.
1062
1063See documentation in L<SNMP::Info::Layer3::Tasman> for details.
1064
1065=item SNMP::Info::Layer3::Teltonika
1066
1067Subclass for Teltonika RUT9xx series routers.
1068
1069See documentation in L<SNMP::Info::Layer3::Teltonika> for details.
1070
1071=item SNMP::Info::Layer3::Timetra
1072
1073Alcatel-Lucent SR Class.
1074
1075See documentation in L<SNMP::Info::Layer3::Timetra> for details.
1076
1077=item SNMP::Info::Layer3::VyOS
1078
1079Subclass for VyOS routers.
1080
1081See documentation in L<SNMP::Info::Layer3::VyOS> for details.
1082
1083=item SNMP::Info::Layer3::VMware
1084
1085Subclass for VMware ESXi hosts.
1086
1087See documentation in L<SNMP::Info::Layer3::VMware> for details.
1088
1089=item SNMP::Info::Layer3::Whiterabbit
1090
1091Subclass for whiterabbit devices.
1092
1093See documentation in L<SNMP::Info::Layer3::Whiterabbit> for details.
1094
1095=back
1096
1097=back
1098
1099=over 4
1100
1101=item SNMP::Info::Layer7
1102
1103Generic Layer7 Devices.
1104
1105See documentation in L<SNMP::Info::Layer7> for details.
1106
1107=over 4
1108
1109=item SNMP::Info::Layer7::APC
1110
1111Subclass for APC UPS devices.
1112
1113See documentation in L<SNMP::Info::Layer7::APC> for details.
1114
1115=item SNMP::Info::Layer7::Arbor
1116
1117Subclass for Arbor appliances.
1118
1119See documentation in L<SNMP::Info::Layer7::Arbor> for details.
1120
1121=item SNMP::Info::Layer7::CiscoIPS
1122
1123Subclass for Cisco IPS devices.
1124
1125See documentation in L<SNMP::Info::Layer7::CiscoIPS> for details.
1126
1127=item SNMP::Info::Layer7::Gigamon
1128
1129Subclass for Gigamon devices.
1130
1131See documentation in L<SNMP::Info::Layer7::Gigamon> for details.
1132
1133=item SNMP::Info::Layer7::Liebert
1134
1135Subclass for Liebert devices.
1136
1137See documentation in L<SNMP::Info::Layer7::Liebert> for details.
1138
1139=item SNMP::Info::Layer7::Neoteris
1140
1141Subclass for Pulse Secure / Juniper SSL VPN appliances.
1142
1143See documentation in L<SNMP::Info::Layer7::Neoteris> for details.
1144
1145=item SNMP::Info::Layer7::Netscaler
1146
1147Subclass for Citrix Netscaler appliances.
1148
1149See documentation in L<SNMP::Info::Layer7::Netscaler> for details.
1150
1151
1152=back
1153
1154=back
1155
1156=head1 Thanks
1157
1158Thanks for testing and coding help (in no particular order) to :
1159Alexander Barthel, Andy Ford, Alexander Hartmaier, Andrew Herrick, Alex
1160Kramarov, Bernhard Augenstein, Bradley Baetz, Brian Chow, Brian Wilson,
1161Carlos Vicente, Dana Watanabe, David Pinkoski, David Sieborger, Douglas
1162McKeown, Greg King, Ivan Auger, Jean-Philippe Luiggi, Jeroen van Ingen,
1163Justin Hunter, Kent Hamilton, Matthew Tuttle, Michael Robbert, Mike Hunter,
1164Nicolai Petri, Ralf Gross, Robert Kerr, Nick Nauwelaerts and people listed
1165on the Netdisco README!
1166
1167=head1 USAGE
1168
1169=head2 Constructor
1170
1171=over
1172
1173=item new()
1174
1175Creates a new object and connects via SNMP::Session.
1176
1177 my $info = new SNMP::Info( 'Debug'             => 1,
1178                            'AutoSpecify'       => 1,
1179                            'BigInt'            => 1,
1180                            'BulkWalk'          => 1,
1181                            'BulkRepeaters'     => 20,
1182                            'IgnoreNetSNMPConf' => 1,
1183                            'LoopDetect'        => 1,
1184                            'DestHost'          => 'myrouter',
1185                            'Community'         => 'public',
1186                            'Version'           => 2,
1187                            'MibDirs'           => ['dir1','dir2','dir3'],
1188                          ) or die;
1189
1190SNMP::Info Specific Arguments :
1191
1192=over
1193
1194=item AutoSpecify
1195
1196Returns an object of a more specific device class
1197
1198(default 0, which means "off")
1199
1200=item BigInt
1201
1202Return Math::BigInt objects for 64 bit counters.  Sets on a global scope,
1203not object.
1204
1205(default 0, which means "off")
1206
1207=item BulkWalk
1208
1209Set to C<0> to turn off BULKWALK commands for SNMPv2 connections.
1210
1211Note that BULKWALK is turned off for Net-SNMP versions 5.1.x because of a bug.
1212
1213(default 1, which means "on")
1214
1215=item BulkRepeaters
1216
1217Set number of MaxRepeaters for BULKWALK operation.  See
1218C<perldoc SNMP> -> bulkwalk() for more info.
1219
1220(default 20)
1221
1222=item LoopDetect
1223
1224Detects looping during getnext table column walks by comparing IIDs for each
1225instance.  A loop is detected if the same IID is seen more than once and the
1226walk is aborted.  Note:  This will not detect loops during a bulkwalk
1227operation, Net-SNMP's internal bulkwalk function must detect the loop.
1228
1229Set to C<0> to turn off loop detection.
1230
1231(default 1, which means "on")
1232
1233=item IgnoreNetSNMPConf
1234
1235Net-SNMP version 5.0 and higher read configuration files, snmp.conf or
1236snmp.local.conf, from /etc/snmp, /usr/share/snmp, /usr/lib(64)/snmp, or
1237$HOME/.snmp and uses those settings to automatically parse MIB files, etc.
1238
1239Set to C<1> "on" to ignore Net-SNMP configuration files by overriding the
1240C<SNMPCONFPATH> environmental variable during object initialization. Note:
1241MibDirs must be defined or Net-SNMP will not be able to load MIBs and
1242initialize the object.
1243
1244(default 0, which means "off")
1245
1246=item Debug
1247
1248Prints Lots of debugging messages.
1249Pass 2 to print even more debugging messages.
1250
1251(default 0, which means "off")
1252
1253=item DebugSNMP
1254
1255Set $SNMP::debugging level for Net-SNMP.
1256
1257See F<SNMP> for more details.
1258
1259=item MibDirs
1260
1261Array ref to list of directories in which to look for MIBs.  Note this will
1262be in addition to the ones setup in snmp.conf at the system level.
1263
1264(default use net-snmp settings only)
1265
1266=item RetryNoSuch
1267
1268When using SNMP Version 1, try reading values even if they come back as "no
1269such variable in this MIB".  Set to false if so desired.  This feature lets
1270you read SNMPv2 data from an SNMP version 1 connection, and should probably
1271be left on.
1272
1273(default 1, which means "on")
1274
1275=item Session
1276
1277SNMP::Session object to use instead of connecting on own.
1278
1279(default creates session automatically)
1280
1281=item Offline
1282
1283Causes SNMP::Info to avoid network activity and return data only from its
1284cache. If you ask for something not in the cache, an error is thrown.  See
1285also the C<cache()> and C<offline()> methods.
1286
1287(default 0, which means "online")
1288
1289=item Cache
1290
1291Pass in a HashRef to prime the cache of retrieved data. Useful for creating an
1292instance in C<Offline> mode from a previously dumped cache. See also the
1293C<cache()> method to retrieve a cache after running actial queries.
1294
1295=item OTHER
1296
1297All other arguments are passed to SNMP::Session.
1298
1299See SNMP::Session for a list of other possible arguments.
1300
1301=back
1302
1303A Note about the wrong Community string or wrong SNMP Version:
1304
1305If a connection is using the wrong community string or the wrong SNMP version,
1306the creation of the object will not fail.  The device still answers the call
1307on the SNMP port, but will not return information.  Check the error() method
1308after you create the device object to see if there was a problem in
1309connecting.
1310
1311A note about SNMP Versions :
1312
1313Some older devices don't support SNMP version 2, and will not return anything
1314when a connection under Version 2 is attempted.
1315
1316Some newer devices will support Version 1, but will not return all the data
1317they might have if you had connected under Version 1.
1318
1319When trying to get info from a new device, you may have to try version 2 and
1320then fallback to version 1.
1321
1322=cut
1323
1324sub new {
1325    my $proto     = shift;
1326    my $class     = ref($proto) || $proto;
1327    my %args      = @_;
1328    my %sess_args = %args;
1329    my $new_obj   = {};
1330    bless $new_obj, $class;
1331
1332    $new_obj->{class} = $class;
1333
1334    # load references to all the subclass data structures
1335    {
1336        no strict 'refs';    ## no critic (ProhibitNoStrict ProhibitProlongedStrictureOverride)
1337        $new_obj->{init}    = \${ $class . '::INIT' };
1338        $new_obj->{mibs}    = \%{ $class . '::MIBS' };
1339        $new_obj->{globals} = \%{ $class . '::GLOBALS' };
1340        $new_obj->{funcs}   = \%{ $class . '::FUNCS' };
1341        $new_obj->{munge}   = \%{ $class . '::MUNGE' };
1342    }
1343
1344    # SNMP::Info specific args :
1345    if ( defined $args{Debug} ) {
1346        $new_obj->debug( $args{Debug} );
1347        delete $sess_args{Debug};
1348    }
1349    else {
1350        $new_obj->debug( defined $DEBUG ? $DEBUG : 0 );
1351    }
1352
1353    if ( defined $args{DebugSNMP} ) {
1354        $SNMP::debugging = $args{DebugSNMP};
1355        delete $sess_args{DebugSNMP};
1356    }
1357
1358    my $auto_specific = 0;
1359    if ( defined $args{AutoSpecify} ) {
1360        $auto_specific = $args{AutoSpecify} || 0;
1361        delete $sess_args{AutoSpecify};
1362    }
1363
1364    if ( defined $args{BulkRepeaters} ) {
1365        $new_obj->{BulkRepeaters} = $args{BulkRepeaters};
1366        delete $sess_args{BulkRepeaters};
1367    }
1368
1369    if ( defined $args{BulkWalk} ) {
1370        $new_obj->{BulkWalk} = $args{BulkWalk};
1371        delete $sess_args{BulkWalk};
1372    }
1373
1374    if ( defined $args{LoopDetect} ) {
1375        $new_obj->{LoopDetect} = $args{LoopDetect};
1376        delete $sess_args{LoopDetect};
1377    }
1378
1379    if ( defined $args{IgnoreNetSNMPConf} ) {
1380        $new_obj->{IgnoreNetSNMPConf} = $args{IgnoreNetSNMPConf} || 0;
1381        delete $sess_args{IgnoreNetSNMPConf};
1382    }
1383
1384    if ( defined $args{Offline} ) {
1385        $new_obj->{Offline} = $args{Offline} || 0;
1386        delete $sess_args{Offline};
1387    }
1388
1389    if ( defined $args{Cache} and ref {} eq ref $args{Cache} ) {
1390        $new_obj->{$_} = $args{Cache}->{$_} for keys %{$args{Cache}};
1391        delete $sess_args{Cache};
1392    }
1393
1394    my $sess = undef;
1395    if ( defined $args{Session} ) {
1396        $sess = $args{Session};
1397        delete $sess_args{Session};
1398    }
1399    if ( defined $args{BigInt} ) {
1400        $BIGINT = $args{BigInt};
1401        delete $sess_args{BigInt};
1402    }
1403    if ( defined $args{MibDirs} ) {
1404        $new_obj->{mibdirs} = $args{MibDirs};
1405        delete $sess_args{MibDirs};
1406    }
1407
1408    # For IPv6 hosts set transport
1409    if ( defined $sess_args{DestHost} ) {
1410        $sess_args{DestHost} = resolve_desthost($sess_args{DestHost});
1411    }
1412
1413    $new_obj->{nosuch} = $args{RetryNoSuch} || $NOSUCH;
1414
1415    # Initialize mibs if not done
1416    my $init_ref = $new_obj->{init};
1417    unless ( defined $$init_ref and $$init_ref ) {
1418        $new_obj->init();
1419        $$init_ref = 1;
1420    }
1421
1422    # Connects to device unless open session is provided.
1423    $sess = SNMP::Session->new(
1424        'UseEnums' => 1,
1425        %sess_args, 'RetryNoSuch' => $new_obj->{nosuch}
1426    ) unless defined $sess;
1427
1428    # No session object created
1429    unless ( defined $sess ) {
1430        $new_obj->error_throw("SNMP::Info::new() Failed to Create Session. ");
1431        return;
1432    }
1433
1434    # Session object created but SNMP connection failed.
1435    my $sess_err = $sess->{ErrorStr} || '';
1436    if ($sess_err) {
1437        $new_obj->error_throw(
1438            "SNMP::Info::new() Net-SNMP session creation failed. $sess_err");
1439        return;
1440    }
1441
1442    # Save Args for later
1443    $new_obj->{store}     ||= {};
1444    $new_obj->{sess}      = $sess;
1445    $new_obj->{args}      = \%args;
1446    $new_obj->{snmp_ver}  = $sess->{Version}   || $args{Version}   || 2;
1447    $new_obj->{snmp_comm} = $sess->{Community} || $args{Community} || 'public';
1448    $new_obj->{snmp_user} = $sess->{SecName}   || $args{SecName}   || 'initial';
1449
1450    my $info = $auto_specific ? $new_obj->specify() : $new_obj;
1451
1452    if (defined $info and ($info->debug() > 1)) {
1453        require mro;
1454        print STDERR (ref $info) ." has resolution order: \n";
1455        print STDERR "  $_\n" foreach @{ mro::get_linear_isa( ref $info ) };
1456    }
1457
1458    return $info;
1459}
1460
1461=item update()
1462
1463Replace the existing session with a new one with updated values,
1464without re-identifying the device.  The only supported changes are
1465to Community or Context.
1466
1467Clears the object cache.
1468
1469This is useful, e.g., when a device supports multiple contexts
1470(via changes to the Community string, or via the SNMPv3 Context
1471parameter), but a context that you want to access does not support
1472the objects (e.g., C<sysObjectID>, C<sysDescr>) that we use to identify
1473the device.
1474
1475=cut
1476
1477sub update {
1478    my $obj         = shift;
1479    my %update_args = @_;
1480    my %sess_args   = ( %{ $obj->{args} }, %update_args );
1481
1482    # silently only update "the right" args
1483    delete $sess_args{Debug};
1484    delete $sess_args{DebugSNMP};
1485    delete $sess_args{AutoSpecify};
1486    delete $sess_args{BulkRepeaters};
1487    delete $sess_args{BulkWalk};
1488    delete $sess_args{LoopDetect};
1489    delete $sess_args{IgnoreNetSNMPConf};
1490    delete $sess_args{BigInt};
1491    delete $sess_args{MibDirs};
1492
1493    my $sess = SNMP::Session->new(
1494        'UseEnums' => 1,
1495        %sess_args, 'RetryNoSuch' => $obj->{nosuch}
1496    );
1497    unless ( defined $sess ) {
1498        $obj->error_throw(
1499            "SNMP::Info::update() Failed to Create new Session. ");
1500        return;
1501    }
1502
1503    # Session object created but SNMP connection failed.
1504    my $sess_err = $sess->{ErrorStr} || '';
1505    if ($sess_err) {
1506        $obj->error_throw(
1507            "SNMP::Info::update() Net-SNMP session creation failed. $sess_err"
1508        );
1509        return;
1510    }
1511    $obj->clear_cache();
1512    return $obj->session($sess);
1513}
1514
1515=back
1516
1517=head2 Data is Cached
1518
1519Methods and subroutines requesting data from a device will only load the data
1520once, and then return cached versions of that data.
1521
1522Run $info->load_METHOD() where method is something like 'i_name' to reload
1523data from a method.
1524
1525Run $info->clear_cache() to clear the cache to allow reload of both globals
1526and table methods.
1527
1528The cache can be retrieved or set using the $info->cache() method. This works
1529together with the C<Offline> option.
1530
1531=head2 Object Scalar Methods
1532
1533These are for package related data, not directly supplied
1534from SNMP.
1535
1536=over
1537
1538=item $info->clear_cache()
1539
1540Clears the cached data.  This includes GLOBALS data and TABLE METHOD data.
1541
1542=cut
1543
1544sub clear_cache {
1545    my $self = shift;
1546
1547    print "SNMP::Info::clear_cache() - Cache Cleared.\n" if $self->debug();
1548
1549    # Clear cached global values and table method flag for being cached
1550    foreach my $key ( keys %$self ) {
1551        next unless defined $key;
1552        next unless $key =~ /^_/;
1553        delete $self->{$key};
1554    }
1555
1556    # Clear store for tables
1557    return $self->store( {} );
1558
1559}
1560
1561=item $info->debug(1)
1562
1563Returns current debug status, and optionally toggles debugging info for this
1564object.
1565
1566=cut
1567
1568sub debug {
1569    my $self  = shift;
1570    my $debug = shift;
1571
1572    if ( defined $debug ) {
1573        $self->{debug} = $debug;
1574    }
1575
1576    return $self->{debug};
1577}
1578
1579=item $info->offline([1|0])
1580
1581Returns if offline mode is currently turned on for this object.
1582
1583Optionally sets the Offline parameter.
1584
1585=cut
1586
1587sub offline {
1588    my $self = shift;
1589    my $ol   = shift;
1590
1591    if ( defined $ol ) {
1592        $self->{Offline} = $ol;
1593    }
1594    return $self->{Offline};
1595}
1596
1597=item $info->cache([new_cache])
1598
1599Returns a HashRef of all cached data in this object. There will be a C<store>
1600key for table data and then one key for each leaf.
1601
1602Optionally sets the cache parameters if passed a HashRef.
1603
1604=cut
1605
1606sub cache {
1607    my $self = shift;
1608    my $data = shift;
1609
1610    if ( defined $data and ref {} eq ref $data ) {
1611        $self->{$_} = $data->{$_} for keys %$data;
1612    }
1613
1614    my $cache = { store => $self->{store} };
1615    foreach my $key ( keys %$self ) {
1616        next unless defined $key;
1617        next unless $key =~ /^_/;
1618        $cache->{$key} = $self->{$key};
1619    }
1620    return $cache;
1621}
1622
1623=item $info->bulkwalk([1|0])
1624
1625Returns if bulkwalk is currently turned on for this object.
1626
1627Optionally sets the bulkwalk parameter.
1628
1629=cut
1630
1631sub bulkwalk {
1632    my $self = shift;
1633    my $bw   = shift;
1634
1635    if ( defined $bw ) {
1636        $self->{BulkWalk} = $bw;
1637    }
1638    return $self->{BulkWalk};
1639}
1640
1641=item $info->loopdetect([1|0])
1642
1643Returns if loopdetect is currently turned on for this object.
1644
1645Optionally sets the loopdetect parameter.
1646
1647=cut
1648
1649sub loopdetect {
1650    my $self = shift;
1651    my $ld   = shift;
1652
1653    if ( defined $ld ) {
1654        $self->{LoopDetect} = $ld;
1655    }
1656    return $self->{LoopDetect};
1657}
1658
1659=item $info->device_type()
1660
1661Returns the Subclass name for this device.  C<SNMP::Info> is returned if no
1662more specific class is available.
1663
1664First the device is checked for Layer 3 support and a specific subclass,
1665then Layer 2 support and subclasses are checked.
1666
1667This means that Layer 2 / 3  switches and routers will fall under the
1668SNMP::Info::Layer3 subclasses.
1669
1670If the device still can be connected to via SNMP::Info, then
1671SNMP::Info is returned.
1672
1673=cut
1674
1675sub device_type {
1676    my $info = shift;
1677
1678    my $objtype = "SNMP::Info";
1679
1680    my $layers = $info->layers() || '00000000';
1681
1682    my $desc = $info->description() || 'undef';
1683    $desc =~ s/[\r\n\l]+/ /g;
1684
1685    # Some devices don't implement sysServices, but do return a description.
1686    # In that case, log a warning and continue.
1687    if ( $layers eq '00000000' ) {
1688        if ($desc ne 'undef') {
1689            carp("Device doesn't implement sysServices but did return sysDescr. Might give unexpected results.\n") if $info->debug();
1690        } else {
1691            # No sysServices, no sysDescr
1692            return;
1693        }
1694    }
1695
1696    my $id = $info->id() || 'undef';
1697    my $soid = $id;
1698
1699    # Hash for generic fallback to a device class if unable to determine using
1700    # the sysDescr regex.
1701    my %l3sysoidmap = (
1702        9     => 'SNMP::Info::Layer3::CiscoSwitch',
1703        11    => 'SNMP::Info::Layer2::HP',
1704        18    => 'SNMP::Info::Layer3::BayRS',
1705        42    => 'SNMP::Info::Layer3::Sun',
1706        43    => 'SNMP::Info::Layer2::3Com',
1707        45    => 'SNMP::Info::Layer2::Baystack',
1708        96    => 'SNMP::Info::Layer3::Whiterabbit',
1709        171   => 'SNMP::Info::Layer3::DLink',
1710        244   => 'SNMP::Info::Layer3::Lantronix',
1711        311   => 'SNMP::Info::Layer3::Microsoft',
1712        664   => 'SNMP::Info::Layer2::Adtran',
1713        674   => 'SNMP::Info::Layer3::Dell',
1714        1588  => 'SNMP::Info::Layer3::Foundry',
1715        1872  => 'SNMP::Info::Layer3::AlteonAD',
1716        1890  => 'SNMP::Info::Layer3::Redlion',
1717        1916  => 'SNMP::Info::Layer3::Extreme',
1718        1991  => 'SNMP::Info::Layer3::Foundry',
1719        2011  => 'SNMP::Info::Layer3::Huawei',
1720        2021  => 'SNMP::Info::Layer3::NetSNMP',
1721        2272  => 'SNMP::Info::Layer3::Passport',
1722        2620  => 'SNMP::Info::Layer3::CheckPoint',
1723        2636  => 'SNMP::Info::Layer3::Juniper',
1724        2925  => 'SNMP::Info::Layer1::Cyclades',
1725        3076  => 'SNMP::Info::Layer3::Altiga',
1726        3224  => 'SNMP::Info::Layer3::Netscreen',
1727        3375  => 'SNMP::Info::Layer3::F5',
1728        3417  => 'SNMP::Info::Layer3::BlueCoatSG',
1729        3717  => 'SNMP::Info::Layer3::Genua',
1730        4413  => 'SNMP::Info::Layer2::Ubiquiti',
1731        4526  => 'SNMP::Info::Layer2::Netgear',
1732        4874  => 'SNMP::Info::Layer3::ERX',
1733        5624  => 'SNMP::Info::Layer3::Enterasys',
1734        6027  => 'SNMP::Info::Layer3::Force10',
1735        6141  => 'SNMP::Info::Layer3::Ciena',
1736        6486  => 'SNMP::Info::Layer3::AlcatelLucent',
1737        6527  => 'SNMP::Info::Layer3::Timetra',
1738        6876  => 'SNMP::Info::Layer3::VMware',
1739        8072  => 'SNMP::Info::Layer3::NetSNMP',
1740        9303  => 'SNMP::Info::Layer3::PacketFront',
1741        10002 => 'SNMP::Info::Layer2::Ubiquiti',
1742        10418 => 'SNMP::Info::Layer1::Cyclades',
1743        12325 => 'SNMP::Info::Layer3::Pf',
1744        12356 => 'SNMP::Info::Layer3::Fortinet',
1745        13191 => 'SNMP::Info::Layer3::OneAccess',
1746        14179 => 'SNMP::Info::Layer2::Airespace',
1747        14525 => 'SNMP::Info::Layer2::Trapeze',
1748        14823 => 'SNMP::Info::Layer3::Aruba',
1749        14988 => 'SNMP::Info::Layer3::Mikrotik',
1750        17163 => 'SNMP::Info::Layer3::Steelhead',
1751        19046 => 'SNMP::Info::Layer3::Lenovo',
1752        21091 => 'SNMP::Info::Layer2::Exinda',
1753        25461 => 'SNMP::Info::Layer3::PaloAlto',
1754        25506 => 'SNMP::Info::Layer3::H3C',
1755        26543 => 'SNMP::Info::Layer3::IBMGbTor',
1756        26928 => 'SNMP::Info::Layer2::Aerohive',
1757        30065 => 'SNMP::Info::Layer3::Arista',
1758        30803 => 'SNMP::Info::Layer3::VyOS',
1759        35098 => 'SNMP::Info::Layer3::Pica8',
1760        40310 => 'SNMP::Info::Layer3::Cumulus',
1761        41112 => 'SNMP::Info::Layer2::Ubiquiti',
1762        44641 => 'SNMP::Info::Layer3::VyOS',
1763        47196 => 'SNMP::Info::Layer3::ArubaCX',
1764        48690 => 'SNMP::Info::Layer3::Teltonika',
1765    );
1766
1767    my %l2sysoidmap = (
1768        9     => 'SNMP::Info::Layer2::Cisco',
1769        11    => 'SNMP::Info::Layer2::HP',
1770        43    => 'SNMP::Info::Layer2::3Com',
1771        45    => 'SNMP::Info::Layer2::Baystack',
1772        96    => 'SNMP::Info::Layer3::Whiterabbit',
1773        171   => 'SNMP::Info::Layer3::DLink',
1774        207   => 'SNMP::Info::Layer2::Allied',
1775        266   => 'SNMP::Info::Layer2::Nexans',
1776        664   => 'SNMP::Info::Layer2::Adtran',
1777        674   => 'SNMP::Info::Layer3::Dell',
1778        1872  => 'SNMP::Info::Layer3::AlteonAD',
1779        1890  => 'SNMP::Info::Layer3::Redlion',
1780        1916  => 'SNMP::Info::Layer3::Extreme',
1781        1991  => 'SNMP::Info::Layer3::Foundry',
1782        2011  => 'SNMP::Info::Layer3::Huawei',
1783        2272  => 'SNMP::Info::Layer3::Passport',
1784        2925  => 'SNMP::Info::Layer1::Cyclades',
1785        3224  => 'SNMP::Info::Layer3::Netscreen',
1786        3375  => 'SNMP::Info::Layer3::F5',
1787        4526  => 'SNMP::Info::Layer2::Netgear',
1788        5624  => 'SNMP::Info::Layer3::Enterasys',
1789        6141  => 'SNMP::Info::Layer3::Ciena',
1790        6486  => 'SNMP::Info::Layer3::AlcatelLucent',
1791        9303  => 'SNMP::Info::Layer3::PacketFront',
1792        10418 => 'SNMP::Info::Layer1::Cyclades',
1793        11898 => 'SNMP::Info::Layer2::Orinoco',
1794        13458 => 'SNMP::Info::Layer2::Atmedia',
1795        14179 => 'SNMP::Info::Layer2::Airespace',
1796        14525 => 'SNMP::Info::Layer2::Trapeze',
1797        14823 => 'SNMP::Info::Layer3::Aruba',
1798        17163 => 'SNMP::Info::Layer3::Steelhead',
1799        20540 => 'SNMP::Info::Layer2::Sixnet',
1800        21091 => 'SNMP::Info::Layer2::Exinda',
1801        26543 => 'SNMP::Info::Layer3::IBMGbTor',
1802        26928 => 'SNMP::Info::Layer2::Aerohive',
1803        47196 => 'SNMP::Info::Layer3::ArubaCX',
1804        48690 => 'SNMP::Info::Layer3::Teltonika',
1805    );
1806
1807    my %l1sysoidmap = (
1808        2925  => 'SNMP::Info::Layer1::Cyclades',
1809        10418 => 'SNMP::Info::Layer1::Cyclades',
1810    );
1811
1812    my %l7sysoidmap = (
1813        318   => 'SNMP::Info::Layer7::APC',
1814        476   => 'SNMP::Info::Layer7::Liebert',
1815        5951  => 'SNMP::Info::Layer7::Netscaler',
1816        9694  => 'SNMP::Info::Layer7::Arbor',
1817        12532 => 'SNMP::Info::Layer7::Neoteris',
1818        14525 => 'SNMP::Info::Layer2::Trapeze',
1819        26866 => 'SNMP::Info::Layer7::Gigamon',
1820    );
1821
1822    # Get just the enterprise number for generic mapping
1823    $id = $1 if ( defined($id) && $id =~ /^\.1\.3\.6\.1\.4\.1\.(\d+)/ );
1824
1825    if ($info->debug()) {
1826        print "SNMP::Info $VERSION\n";
1827        print "SNMP::Info::device_type() layers:$layers id:$id sysDescr:\"$desc\"\n";
1828    }
1829
1830    # Layer 3 Supported
1831    #   (usually has layer2 as well, so we check for 3 first)
1832    if ( $info->has_layer(3) ) {
1833        $objtype = 'SNMP::Info::Layer3';
1834
1835        # Device Type Overrides
1836
1837        return $objtype unless ( defined $desc and length($desc) );
1838
1839        $objtype = 'SNMP::Info::Layer3::C3550' if $desc =~ /(C3550|C3560)/;
1840        $objtype = 'SNMP::Info::Layer3::C4000' if $desc =~ /Catalyst 4[05]00/;
1841        $objtype = 'SNMP::Info::Layer3::Foundry' if $desc =~ /foundry/i;
1842        $objtype = 'SNMP::Info::Layer3::ERX' if $desc =~ /erx/i;
1843
1844        # Aironet - older non-IOS
1845        $objtype = 'SNMP::Info::Layer3::Aironet'
1846            if ($desc =~ /Cisco/
1847            and $desc =~ /\D(CAP340|AP340|CAP350|350|1200)\D/ );
1848        $objtype = 'SNMP::Info::Layer3::Aironet'
1849            if ( $desc =~ /Aironet/ and $desc =~ /\D(AP4800)\D/ );
1850
1851        # Override voice gateway device (VG350) showing up as Aironet
1852        $objtype = 'SNMP::Info::Layer3::Cisco' if $desc =~ /VG350/;
1853
1854        # Cat6k with older SUPs (hybrid CatOS/IOS?)
1855        $objtype = 'SNMP::Info::Layer3::C6500' if $desc =~ /(c6sup2|c6sup1)/;
1856
1857        # Cat6k with Sup720, Sup720 or Sup2T (and Sup2 running native IOS?)
1858        $objtype = 'SNMP::Info::Layer3::C6500'
1859            if $desc =~ /(s72033_rp|s3223_rp|s32p3_rp|s222_rp|s2t54)/;
1860
1861        # Next one untested. Reported working by DA
1862        $objtype = 'SNMP::Info::Layer3::C6500'
1863            if ( $desc =~ /cisco/i and $desc =~ /3750/ );
1864
1865        # IOS 15.x on Catalyst 3850
1866        $objtype = 'SNMP::Info::Layer3::C6500'
1867            if ( $desc =~ /cisco/i and $desc =~ /CAT3K/ );
1868
1869        #   Cisco 2970
1870        $objtype = 'SNMP::Info::Layer3::C6500'
1871            if ( $desc =~ /(C2970|C2960)/ );
1872
1873        #   Cisco 3400 w/ Layer3 capable image
1874        $objtype = 'SNMP::Info::Layer3::C3550'
1875            if ( $desc =~ /(ME340x)/ );
1876
1877        # Various Cisco blade switches, CBS30x0 and CBS31x0 models
1878        $objtype = 'SNMP::Info::Layer3::C6500'
1879            if ( $desc =~ /cisco/i and $desc =~ /CBS3[0-9A-Za-z]{3}/ );
1880
1881        # Cisco Nexus running NX-OS
1882        $objtype = 'SNMP::Info::Layer3::Nexus'
1883            if ( $desc =~ /^Cisco\s+NX-OS/ );
1884
1885        # HP, older ProCurve models (1600, 2400, 2424m, 4000, 8000)
1886        $objtype = 'SNMP::Info::Layer2::HP4000'
1887            if $desc =~ /\b(J4093A|J4110A|J4120A|J4121A|J4122A|J4122B)\b/;
1888
1889        # HP, Foundry OEM
1890        $objtype = 'SNMP::Info::Layer3::HP9300'
1891            if $desc =~ /\b(J4874A|J4138A|J4139A|J4840A|J4841A)\b/;
1892
1893        # Nortel ERS (Passport) 1600 Series < version 2.1
1894        $objtype = 'SNMP::Info::Layer3::N1600'
1895            if $desc =~ /(Passport|Ethernet\s+Routing\s+Switch)-16/i;
1896
1897        #  ERS - BayStack Numbered
1898        $objtype = 'SNMP::Info::Layer2::Baystack'
1899            if ( $desc
1900            =~ /^(BayStack|Ethernet\s+Routing\s+Switch)\s[2345](\d){2,3}/i );
1901
1902        # Nortel Contivity
1903        $objtype = 'SNMP::Info::Layer3::Contivity'
1904          if $desc =~ /(\bCES\b|\bNVR\sV\d)/
1905              and (!defined $id or !defined $l3sysoidmap{$id});
1906
1907        # SonicWALL
1908        $objtype = 'SNMP::Info::Layer3::SonicWALL' if $desc =~ /SonicWALL/i;
1909
1910        # Allied Telesis Layer2 managed switches. They report they have L3 support
1911        $objtype = 'SNMP::Info::Layer2::Allied'
1912            if ( $desc =~ /Allied.*AT-80\d{2}\S*/i );
1913
1914        # Cisco ASA, newer versions which report layer 3 functionality
1915        # version >= 8.2 are known to do this
1916        $objtype = 'SNMP::Info::Layer3::CiscoASA'
1917            if ( $desc =~ /Cisco Adaptive Security Appliance/i );
1918
1919        # Cisco FTD includes an ASA running as lina process
1920        $objtype = 'SNMP::Info::Layer3::CiscoASA'
1921            if ( $desc =~ /Cisco Firepower Threat Defense/i );
1922
1923        # Cisco FWSM
1924        $objtype = 'SNMP::Info::Layer3::CiscoFWSM'
1925            if ( $desc =~ /Cisco Firewall Services Module/i );
1926
1927        #   Cisco Small Business (300 500) series override
1928        #   This is for enterprises(1).cisco(9).otherEnterprises(6).ciscosb(1)
1929        $objtype = 'SNMP::Info::Layer2::CiscoSB'
1930            if ( $soid =~ /^\.?1\.3\.6\.1\.4\.1\.9\.6\.1/ );
1931
1932        # Avaya Secure Router
1933        $objtype = 'SNMP::Info::Layer3::Tasman'
1934            if ( $desc =~ /^(avaya|nortel)\s+(SR|secure\srouter)\s+\d{4}/i );
1935
1936        # HP Virtual Connect blade switches
1937        $objtype = 'SNMP::Info::Layer2::HPVC'
1938            if ( $desc =~ /HP\sVC\s/ );
1939
1940        # Aironet - IOS
1941        # Starting with IOS 15, Aironet reports sysServices 6, even though
1942        # it still is the same layer2 access point.
1943        $objtype = 'SNMP::Info::Layer2::Aironet'
1944            if ($desc =~ /\b(C1100|C1130|C1140|AP1200|C350|C1200|C1240|C1250|C2700|C3700)\b/
1945            and $desc =~ /\bIOS\b/ );
1946
1947        # Airespace (WLC) Module
1948        $objtype = 'SNMP::Info::Layer2::Airespace'
1949            if ( $desc =~ /^Cisco Controller$/ );
1950
1951        #Nortel 2270
1952        $objtype = 'SNMP::Info::Layer2::N2270'
1953            if (
1954            $desc =~ /Nortel\s+(Networks\s+)??WLAN\s+-\s+Security\s+Switch/ );
1955
1956        # Nortel (Trapeze) WSS 2300 Series
1957        $objtype = 'SNMP::Info::Layer2::NWSS2300'
1958            if (
1959            $desc =~ /^(Nortel\s)??Wireless\sSecurity\sSwitch\s23[568][012]\b/);
1960
1961	# Siemens Simatic Scalance
1962        # Scalance overwrites layers later,
1963        # so if we don't add it here (layer3) and at other
1964        # it would flip/flop between those
1965        $objtype = 'SNMP::Info::Layer3::Scalance'
1966	    if ( $soid =~ /\.1\.3\.6\.1\.4\.1\.4329\.6\.1\.2/i );
1967
1968        # Aruba wireless switches (issue #403)
1969        $objtype = 'SNMP::Info::Layer3::Aruba'
1970            if ( $desc =~ /ArubaOS/ );
1971
1972        # Teltonika RUT9xx Series
1973        $objtype = 'SNMP::Info::Layer3::Teltonika'
1974            if (
1975            $desc =~ /\bTeltonika.*RUT9\d{2}\b/);
1976
1977        # Riverbed Steelfusion
1978        $objtype = 'SNMP::Info::Layer3::SteelheadEx'
1979            if ( $soid =~ /\.1\.3\.6\.1\.4\.1\.17163\.1\.51/i );
1980        $objtype = 'SNMP::Info::Layer3::Steelfusion'
1981            if ( $soid =~ /\.1\.3\.6\.1\.4\.1\.17163\.1\.52/i );
1982
1983        # Whiterabbit Timing
1984        $objtype = 'SNMP::Info::Layer3::Whiterabbit'
1985	    if ( $soid =~ /\.1\.3\.6\.1\.4\.1\.96\.100\.1000/i );
1986
1987        # Generic device classification based upon sysObjectID
1988        if (    ( $objtype eq 'SNMP::Info::Layer3' )
1989            and ( defined($id) )
1990            and ( exists( $l3sysoidmap{$id} ) ) )
1991        {
1992            $objtype = $l3sysoidmap{$id};
1993        }
1994        # Layer 2 Supported
1995    }
1996    elsif ( $info->has_layer(2) ) {
1997        $objtype = 'SNMP::Info::Layer2';
1998
1999        return $objtype unless ( defined $desc and $desc !~ /^\s*$/ );
2000
2001        # Device Type Overrides
2002
2003        #  Bay Hub (Needed here for layers override)
2004        $objtype = 'SNMP::Info::Layer1::Bayhub'
2005            if ( $desc =~ /\bNMM.*Agent/ );
2006        $objtype = 'SNMP::Info::Layer1::Bayhub'
2007            if ( $desc =~ /\bBay\s*Stack.*Hub/i );
2008
2009        #  Synoptics Hub (Needed here for layers override)
2010        #  This will override Bay Hub only for specific devices supported
2011        #  by this class
2012        $objtype = 'SNMP::Info::Layer1::S3000'
2013            if ( $desc =~ /\bNMM\s+(281|3000|3030)/i );
2014
2015        #   Catalyst 1900 series override
2016        $objtype = 'SNMP::Info::Layer2::C1900'
2017            if ( $desc =~ /catalyst/i and $desc =~ /\D19\d{2}/ );
2018
2019        #   Catalyst 2900 and 3500XL (IOS) series override
2020        $objtype = 'SNMP::Info::Layer2::C2900'
2021            if ( $desc =~ /(C2900XL|C2950|C3500XL|C2940|CGESM|CIGESM)/i );
2022
2023        #   Catalyst WS-C series override 2926,4k,5k,6k in Hybrid
2024        $objtype = 'SNMP::Info::Layer2::Catalyst' if ( $desc =~ /WS-C\d{4}/ );
2025
2026        #   Catalyst 3550 / 3548 Layer2 only switches
2027        #   Cisco 3400 w/ MetroBase Image
2028        $objtype = 'SNMP::Info::Layer3::C3550'
2029            if ( $desc =~ /(C3550|ME340x)/ );
2030
2031        # Cisco blade switches, CBS30x0 and CBS31x0 models with L2 only
2032        $objtype = 'SNMP::Info::Layer3::C6500'
2033            if ( $desc =~ /cisco/i and $desc =~ /CBS3[0-9A-Za-z]{3}/ );
2034
2035        #   Cisco 2970
2036        $objtype = 'SNMP::Info::Layer3::C6500'
2037            if ( $desc =~ /(C2970|C2960)/ );
2038
2039        #   Cisco Small Business (300 500) series override
2040        #   This is for enterprises(1).cisco(9).otherEnterprises(6).ciscosb(1)
2041        $objtype = 'SNMP::Info::Layer2::CiscoSB'
2042            if ( $soid =~ /^\.1\.3\.6\.1\.4\.1\.9\.6\.1/ );
2043
2044        # HP, older ProCurve models (1600, 2400, 2424m, 4000, 8000)
2045        $objtype = 'SNMP::Info::Layer2::HP4000'
2046            if $desc =~ /\b(J4093A|J4110A|J4120A|J4121A|J4122A|J4122B)\b/;
2047
2048        # HP, Foundry OEM
2049        $objtype = 'SNMP::Info::Layer3::HP9300'
2050            if $desc =~ /\b(J4874A|J4138A|J4139A|J4840A|J4841A)\b/;
2051
2052        # IBM BladeCenter 4-Port GB Ethernet Switch Module
2053        $objtype = 'SNMP::Info::Layer3::Dell'
2054            if ( $desc =~ /^IBM Gigabit Ethernet Switch Module$/ );
2055
2056        # Linksys 2024/2048
2057        $objtype = 'SNMP::Info::Layer3::Dell'
2058            if (
2059            $desc =~ /^(24|48)-Port 10\/100\/1000 Gigabit Switch (with |w\/)WebView$/ );
2060
2061        #  Centillion ATM
2062        $objtype = 'SNMP::Info::Layer2::Centillion' if ( $desc =~ /MCP/ );
2063
2064        #  BPS
2065        $objtype = 'SNMP::Info::Layer2::Baystack'
2066            if ( $desc =~ /Business\sPolicy\sSwitch/i );
2067
2068        #  BayStack Numbered
2069        $objtype = 'SNMP::Info::Layer2::Baystack'
2070            if ( $desc
2071            =~ /^(BayStack|Ethernet\s+(Routing\s+)??Switch)\s[2345](\d){2,3}/i
2072            );
2073
2074        # Kentrox DataSMART DSU/CSU
2075        $objtype = 'SNMP::Info::Layer2::Kentrox'
2076            if ( $desc =~ /^DataSMART/i );
2077
2078        #  Nortel Business Ethernet Switch
2079        $objtype = 'SNMP::Info::Layer2::Baystack'
2080            if ( $desc =~ /^Business Ethernet Switch\s[12]\d\d/i );
2081
2082        #  Nortel AP 222X
2083        $objtype = 'SNMP::Info::Layer2::NAP222x'
2084            if ( $desc =~ /Access\s+Point\s+222/ );
2085
2086        #  Orinoco
2087        $objtype = 'SNMP::Info::Layer2::Orinoco'
2088            if ( $desc =~ /(AP-\d{3}|WavePOINT)/ );
2089
2090        #  Aironet - IOS
2091        $objtype = 'SNMP::Info::Layer2::Aironet'
2092            if ($desc =~ /\b(C1100|C1130|C1140|AP1200|C350|C1200|C1240|C1250)\b/
2093            and $desc =~ /\bIOS\b/ );
2094
2095        # Aironet - non IOS
2096        $objtype = 'SNMP::Info::Layer3::Aironet'
2097            if ( $desc =~ /Cisco/ and $desc =~ /\D(BR500)\D/ );
2098
2099        # Airespace (WLC) Module
2100        $objtype = 'SNMP::Info::Layer2::Airespace'
2101            if ( $desc =~ /^Cisco Controller$/ );
2102
2103        #Nortel 2270
2104        $objtype = 'SNMP::Info::Layer2::N2270'
2105            if (
2106            $desc =~ /Nortel\s+(Networks\s+)??WLAN\s+-\s+Security\s+Switch/ );
2107
2108        # HP Virtual Connect blade switches
2109        $objtype = 'SNMP::Info::Layer2::HPVC'
2110            if ( $desc =~ /HP\sVC\s/ );
2111
2112        $objtype = 'SNMP::Info::Layer2::ZyXEL_DSLAM'
2113            if ( $desc =~ /8-port .DSL Module\(Annex .\)/i );
2114
2115        # Generic DOCSIS Cable Modem override
2116        # If sysDesc follows the DOCSIS standard
2117        $objtype = 'SNMP::Info::DocsisCM'
2118            if ( $desc =~ /<<HW_REV: .*; VENDOR: .*; BOOTR: .*; SW_REV: .*; MODEL: .*>>/i);
2119
2120        # Generic device classification based upon sysObjectID
2121        if (    ( $objtype eq 'SNMP::Info::Layer2' )
2122            and ( defined($id) )
2123            and ( exists( $l2sysoidmap{$id} ) ) )
2124        {
2125            $objtype = $l2sysoidmap{$id};
2126        }
2127
2128    }
2129    elsif ( $info->has_layer(1) ) {
2130        $objtype = 'SNMP::Info::Layer1';
2131
2132        #  Allied crap-o-hub
2133        $objtype = 'SNMP::Info::Layer1::Allied' if ( $desc =~ /allied/i );
2134        $objtype = 'SNMP::Info::Layer1::Asante' if ( $desc =~ /asante/i );
2135
2136        #  Bay Hub
2137        $objtype = 'SNMP::Info::Layer1::Bayhub'
2138            if ( $desc =~ /\bNMM.*Agent/ );
2139        $objtype = 'SNMP::Info::Layer1::Bayhub'
2140            if ( $desc =~ /\bBay\s*Stack.*Hub/i );
2141
2142        #  Synoptics Hub
2143        #  This will override Bay Hub only for specific devices supported
2144        #  by this class
2145        $objtype = 'SNMP::Info::Layer1::S3000'
2146            if ( $desc =~ /\bNMM\s+(281|3000|3030)/i );
2147
2148        # Generic device classification based upon sysObjectID
2149        if (    ( $objtype eq 'SNMP::Info::Layer1' )
2150            and ( defined($id) )
2151            and ( exists( $l1sysoidmap{$id} ) ) )
2152        {
2153            $objtype = $l1sysoidmap{$id};
2154        }
2155    }
2156    # These devices don't claim to have Layer1-3 but we like em anyways.
2157    else {
2158        $objtype = 'SNMP::Info::Layer2::ZyXEL_DSLAM'
2159            if ( $desc =~ /8-port .DSL Module\(Annex .\)/i );
2160
2161        # Aruba wireless switches
2162        $objtype = 'SNMP::Info::Layer3::Aruba'
2163            if ( $desc =~ /(ArubaOS|AirOS)/ );
2164
2165        # Alcatel-Lucent branded Aruba
2166        $objtype = 'SNMP::Info::Layer3::Aruba'
2167            if ( $desc =~ /^AOS-W/ );
2168
2169        # Cisco PIX
2170        $objtype = 'SNMP::Info::Layer3::Cisco'
2171            if ( $desc =~ /Cisco PIX Security Appliance/i );
2172
2173        # Cisco ASA, older version which doesn't report layer 3 functionality
2174        $objtype = 'SNMP::Info::Layer3::CiscoASA'
2175            if ( $desc =~ /Cisco Adaptive Security Appliance/i );
2176
2177        # HP Virtual Connect blade switches
2178        $objtype = 'SNMP::Info::Layer2::HPVC'
2179            if ( $desc =~ /HP\sVC\s/ );
2180
2181        # Nortel (Trapeze) WSS 2300 Series
2182        $objtype = 'SNMP::Info::Layer2::NWSS2300'
2183            if (
2184            $desc =~ /^(Nortel\s)??Wireless\sSecurity\sSwitch\s23[568][012]\b/);
2185
2186        # Cisco IPS, older version which doesn't report layer 3 functionality
2187        $objtype = 'SNMP::Info::Layer7::CiscoIPS'
2188            if ( $soid =~ /\.1\.3\.6\.1\.4\.1\.9\.1\.1545/i );
2189
2190	# Siemens Simatic Scalance
2191        # Scalance overwrites layers later,
2192        # so if we don't add it here (layer3) and at other
2193        # it would flip/flop between those
2194        $objtype = 'SNMP::Info::Layer3::Scalance'
2195	    if ( $soid =~ /\.1\.3\.6\.1\.4\.1\.4329\.6\.1\.2/i );
2196
2197	# Whiterabbit Timing
2198        $objtype = 'SNMP::Info::Layer3::Whiterabbit'
2199	    if ( $soid =~ /\.1\.3\.6\.1\.4\.1\.96\.100\.1000/i );
2200
2201        # Teltonika RUT9xx Series
2202        $objtype = 'SNMP::Info::Layer3::Teltonika'
2203            if (
2204            $desc =~ /\bTeltonika.*RUT9\d{2}\b/);
2205
2206        # Generic device classification based upon sysObjectID
2207        if ( defined($id) and $objtype eq 'SNMP::Info') {
2208            if ( defined $l3sysoidmap{$id} ) {
2209                $objtype = $l3sysoidmap{$id};
2210            } elsif ( defined $l2sysoidmap{$id}) {
2211                $objtype = $l2sysoidmap{$id};
2212            } elsif ( defined $l7sysoidmap{$id}) {
2213                $objtype = $l7sysoidmap{$id};
2214            } elsif ($info->has_layer(7)) {
2215                $objtype = 'SNMP::Info::Layer7'
2216            }
2217        }
2218    }
2219
2220    return $objtype;
2221}
2222
2223=item $info->error(no_clear)
2224
2225Returns Error message if there is an error, or undef if there is not.
2226
2227Reading the error will clear the error unless you set the no_clear flag.
2228
2229=cut
2230
2231sub error {
2232    my $self     = shift;
2233    my $no_clear = shift;
2234    my $err      = $self->{error};
2235
2236    $self->{error} = undef unless defined $no_clear and $no_clear;
2237    return $err;
2238}
2239
2240=item $info->has_layer(3)
2241
2242Returns non-zero if the device has the supplied layer in the OSI Model
2243
2244Returns if the device doesn't support the layers() call.
2245
2246=cut
2247
2248sub has_layer {
2249    my $self      = shift;
2250    my $check_for = shift;
2251
2252    my $layers = $self->layers();
2253    return unless defined $layers;
2254    return unless length($layers);
2255    return substr( $layers, 8 - $check_for, 1 );
2256}
2257
2258=item $info->snmp_comm()
2259
2260Returns SNMP Community string used in connection.
2261
2262=cut
2263
2264sub snmp_comm {
2265    my $self = shift;
2266    if ( $self->{snmp_ver} == 3 ) {
2267        return $self->{snmp_user};
2268    }
2269    else {
2270        return $self->{snmp_comm};
2271    }
2272}
2273
2274=item $info->snmp_ver()
2275
2276Returns SNMP Version used for this connection
2277
2278=cut
2279
2280sub snmp_ver {
2281    my $self = shift;
2282    return $self->{snmp_ver};
2283}
2284
2285=item $info->specify()
2286
2287Returns an object of a more-specific subclass.
2288
2289 my $info = new SNMP::Info(...);
2290 # Returns more specific object type
2291 my $specific = $info->specify();
2292
2293Usually this method is called internally from new(AutoSpecify => 1)
2294
2295See device_type() entry for how a subclass is chosen.
2296
2297=cut
2298
2299sub specify {
2300    my $self = shift;
2301
2302    my $device_type = $self->device_type();
2303    unless ( defined $device_type ) {
2304        $self->error_throw(
2305            "SNMP::Info::specify() - Could not get info from device");
2306        return;
2307    }
2308    return $self if $device_type eq 'SNMP::Info';
2309
2310    # Load Subclass
2311    # By evaling a string the contents of device_type now becomes a bareword.
2312    eval "require $device_type;";    ## no critic
2313    if ($@) {
2314        croak "SNMP::Info::specify() Loading $device_type Failed. $@\n";
2315    }
2316
2317    my $args    = $self->args();
2318    my $session = $self->session();
2319    my $sub_obj = $device_type->new(
2320        %$args,
2321        'Session'     => $session,
2322        'AutoSpecify' => 0
2323    );
2324
2325    unless ( defined $sub_obj ) {
2326        $self->error_throw(
2327            "SNMP::Info::specify() - Could not connect with new class ($device_type)"
2328        );
2329        return $self;
2330    }
2331
2332    $self->debug()
2333        and print "SNMP::Info::specify() - Changed Class to $device_type.\n";
2334
2335    return $sub_obj;
2336}
2337
2338=item $info->cisco_comm_indexing()
2339
2340Returns 0.  Is an overridable method used for vlan indexing for
2341snmp calls on certain Cisco devices.
2342
2343See L<ftp://ftp.cisco.com/pub/mibs/supportlists/wsc5000/wsc5000-communityIndexing.html>
2344
2345=cut
2346
2347sub cisco_comm_indexing {
2348    return 0;
2349}
2350
2351=back
2352
2353=head2 GLOBALS (Scalar Methods)
2354
2355These are methods to return scalar data from RFC1213.
2356
2357Some subset of these is probably available for any network device that speaks
2358SNMP.
2359
2360=over
2361
2362=item $info->uptime()
2363
2364Uptime in hundredths of seconds since device became available.
2365
2366(C<sysUpTime>)
2367
2368=item $info->contact()
2369
2370(C<sysContact>)
2371
2372=item $info->name()
2373
2374(C<sysName>)
2375
2376=item $info->location()
2377
2378(C<sysLocation>)
2379
2380=item $info->layers()
2381
2382This returns a binary encoded string where each
2383digit represents a layer of the OSI model served
2384by the device.
2385
2386    eg: 01000010  means layers 2 (physical) and 7 (Application)
2387                  are served.
2388
2389Note:  This string is 8 digits long.
2390
2391See $info->has_layer()
2392
2393(C<sysServices>)
2394
2395=item $info->ports()
2396
2397Number of interfaces available on this device.
2398
2399Not too useful as the number of SNMP interfaces usually does not
2400correspond with the number of physical ports
2401
2402(C<ifNumber>)
2403
2404=item $info->ipforwarding()
2405
2406The indication of whether the entity is acting as an IP gateway
2407
2408Returns either forwarding or not-forwarding
2409
2410(C<ipForwarding>)
2411
2412=back
2413
2414=head2 Table Methods
2415
2416Each of these methods returns a hash_reference to a hash keyed on the
2417interface index in SNMP.
2418
2419Example : $info->interfaces() might return
2420
2421    { '1.12' => 'FastEthernet/0',
2422      '2.15' => 'FastEthernet/1',
2423      '9.99' => 'FastEthernet/2'
2424    }
2425
2426The key is what you would see if you were to do an snmpwalk, and in some cases
2427changes between reboots of the network device.
2428
2429=head2 Partial Table Fetches
2430
2431If you want to get only a part of an SNMP table or a single instance from the
2432table and you know the IID for the part of the table that you want, you can
2433specify it in the call:
2434
2435    $local_routes = $info->ipr_route('192.168.0');
2436
2437This will only fetch entries in the table that start with C<192.168.0>, which
2438in this case are routes on the local network.
2439
2440Remember that you must supply the partial IID (a numeric OID).
2441
2442Partial table results are not cached.
2443
2444=head2 Interface Information
2445
2446=over
2447
2448=item $info->interfaces()
2449
2450This methods is overridden in each subclass to provide a
2451mapping between the Interface Table Index (iid) and the physical port name.
2452
2453=item $info->if_ignore()
2454
2455Returns a reference to a hash where key values that exist are
2456interfaces to ignore.
2457
2458Ignored interfaces are ones that are usually not physical ports or Virtual
2459Lans (VLANs) such as the Loopback interface, or the CPU interface.
2460
2461=cut
2462
2463sub if_ignore {
2464    my %nothing;
2465    return \%nothing;
2466}
2467
2468=item $info->bulkwalk_no()
2469
2470Returns 0.  Is an overridable method used for turn off bulkwalk for the
2471device class.
2472
2473=cut
2474
2475sub bulkwalk_no {
2476    return 0;
2477}
2478
2479=item $info->i_index()
2480
2481Default SNMP IID to Interface index.
2482
2483(C<ifIndex>)
2484
2485=item $info->i_description()
2486
2487Description of the interface. Usually a little longer single word name that is
2488both human and machine friendly.  Not always.
2489
2490(C<ifDescr>)
2491
2492=item $info->i_type()
2493
2494Interface type, such as Vlan, Ethernet, Serial
2495
2496(C<ifType>)
2497
2498=item $info->i_mtu()
2499
2500INTEGER. Interface MTU value.
2501
2502(C<ifMtu>)
2503
2504=item $info->i_speed()
2505
2506Speed of the link, human format.  See munge_speed() later in document for
2507details.
2508
2509(C<ifSpeed>, C<ifHighSpeed> if necessary)
2510
2511=cut
2512
2513sub i_speed {
2514    my $info    = shift;
2515    my $partial = shift;
2516
2517    my $i_speed = $info->orig_i_speed($partial);
2518
2519    my $i_speed_high = undef;
2520    foreach my $i ( keys %$i_speed ) {
2521        if ( $i_speed->{$i} eq "4294967295" ) {
2522            $i_speed_high = $info->i_speed_high($partial)
2523                unless defined($i_speed_high);
2524            $i_speed->{$i} = $i_speed_high->{$i} if ( $i_speed_high->{$i} );
2525        }
2526    }
2527    return $i_speed;
2528}
2529
2530=item $info->i_speed_raw()
2531
2532Speed of the link in bits per second without munging.
2533If i_speed_high is available it will be used and multiplied by 1_000_000.
2534
2535(C<ifSpeed>, C<ifHighSpeed> if necessary)
2536
2537=cut
2538
2539sub i_speed_raw {
2540    my $info    = shift;
2541    my $partial = shift;
2542
2543    # remove the speed formating
2544    my $munge_i_speed = delete $info->{munge}{i_speed};
2545    # also for highspeed interfaces e.g. TenGigabitEthernet
2546    my $munge_i_speed_high = delete $info->{munge}{i_speed_high};
2547
2548    my $i_speed_raw = $info->orig_i_speed($partial);
2549
2550    my $i_speed_high = undef;
2551    foreach my $i ( keys %$i_speed_raw ) {
2552        if ( $i_speed_raw->{$i} eq "4294967295" ) {
2553            $i_speed_high = $info->i_speed_high($partial)
2554                unless defined($i_speed_high);
2555            $i_speed_raw->{$i} = ( $i_speed_high->{$i} * 1_000_000 )
2556                if ( $i_speed_high->{$i} );
2557        }
2558    }
2559
2560    # restore the speed formating
2561    $info->{munge}{i_speed} = $munge_i_speed;
2562    $info->{munge}{i_speed_high} = $munge_i_speed_high;
2563
2564    return $i_speed_raw;
2565}
2566
2567=item $info->i_speed_high()
2568
2569Speed of a high-speed link, human format.  See munge_highspeed() later in
2570document for details.  You should not need to call this directly, as
2571i_speed() will call it if it needs to.
2572
2573(C<ifHighSpeed>)
2574
2575=item $info->i_mac()
2576
2577MAC address of the interface.  Note this is just the MAC of the port, not
2578anything connected to it.
2579
2580(C<ifPhysAddress>)
2581
2582=item $info->i_up()
2583
2584Link Status of the interface.  Typical values are 'up' and 'down'.
2585
2586(C<ifOperStatus>)
2587
2588=item $info->i_up_admin()
2589
2590Administrative status of the port.  Typical values are 'enabled' and 'disabled'.
2591
2592(C<ifAdminStatus>)
2593
2594=item $info->i_lastchange()
2595
2596The value of C<sysUpTime> when this port last changed states (up,down).
2597
2598(C<ifLastChange>)
2599
2600=item $info->i_name()
2601
2602Interface Name field.  Supported by a smaller subset of devices, this fields
2603is often human set.
2604
2605(C<ifName>)
2606
2607=item $info->i_alias()
2608
2609Interface Name field.  For certain devices this is a more human friendly form
2610of i_description().  For others it is a human set field like i_name().
2611
2612(C<ifAlias>)
2613
2614=back
2615
2616=head2 Interface Statistics
2617
2618=over
2619
2620=item $info->i_octet_in(), $info->i_octets_out(),
2621$info->i_octet_in64(), $info->i_octets_out64()
2622
2623Bandwidth.
2624
2625Number of octets sent/received on the interface including framing characters.
2626
262764 bit version may not exist on all devices.
2628
2629NOTE: To manipulate 64 bit counters you need to use Math::BigInt, since the
2630values are too large for a normal Perl scalar.   Set the global
2631$SNMP::Info::BIGINT to 1 , or pass the BigInt value to new() if you want
2632SNMP::Info to do it for you.
2633
2634
2635(C<ifInOctets>) (C<ifOutOctets>)
2636(C<ifHCInOctets>) (C<ifHCOutOctets>)
2637
2638=item $info->i_errors_in(), $info->i_errors_out()
2639
2640Number of packets that contained an error preventing delivery.  See C<IF-MIB>
2641for more info.
2642
2643(C<ifInErrors>) (C<ifOutErrors>)
2644
2645=item $info->i_pkts_ucast_in(), $info->i_pkts_ucast_out(),
2646$info->i_pkts_ucast_in64(), $info->i_pkts_ucast_out64()
2647
2648Number of packets not sent to a multicast or broadcast address.
2649
265064 bit version may not exist on all devices.
2651
2652(C<ifInUcastPkts>) (C<ifOutUcastPkts>)
2653(C<ifHCInUcastPkts>) (C<ifHCOutUcastPkts>)
2654
2655=item $info->i_pkts_nucast_in(), $info->i_pkts_nucast_out(),
2656
2657Number of packets sent to a multicast or broadcast address.
2658
2659These methods are deprecated by i_pkts_multi_in() and i_pkts_bcast_in()
2660according to C<IF-MIB>.  Actual device usage may vary.
2661
2662(C<ifInNUcastPkts>) (C<ifOutNUcastPkts>)
2663
2664=item $info->i_pkts_multi_in() $info->i_pkts_multi_out(),
2665$info->i_pkts_multi_in64(), $info->i_pkts_multi_out64()
2666
2667Number of packets sent to a multicast address.
2668
266964 bit version may not exist on all devices.
2670
2671(C<ifInMulticastPkts>) (C<ifOutMulticastPkts>)
2672(C<ifHCInMulticastPkts>) (C<ifHCOutMulticastPkts>)
2673
2674=item $info->i_pkts_bcast_in() $info->i_pkts_bcast_out(),
2675$info->i_pkts_bcast_in64() $info->i_pkts_bcast_out64()
2676
2677Number of packets sent to a broadcast address on an interface.
2678
267964 bit version may not exist on all devices.
2680
2681(C<ifInBroadcastPkts>) (C<ifOutBroadcastPkts>)
2682(C<ifHCInBroadcastPkts>) (C<ifHCOutBroadcastPkts>)
2683
2684=item $info->i_discards_in() $info->i_discards_out()
2685
2686"The number of inbound packets which were chosen to be discarded even though
2687no errors had been detected to prevent their being deliverable to a
2688higher-layer protocol.  One possible reason for discarding such a packet could
2689be to free up buffer space."  (C<IF-MIB>)
2690
2691(C<ifInDiscards>) (C<ifOutDiscards>)
2692
2693=item $info->i_bad_proto_in()
2694
2695"For packet-oriented interfaces, the number of packets received via the
2696interface which were discarded because of an unknown or unsupported protocol.
2697For character-oriented or fixed-length interfaces that support protocol
2698multiplexing the number of transmission units received via the interface which
2699were discarded because of an unknown or unsupported protocol.  For any
2700interface that does not support protocol multiplexing, this counter will always
2701be 0."
2702
2703(C<ifInUnknownProtos>)
2704
2705=item $info->i_qlen_out()
2706
2707"The length of the output packet queue (in packets)."
2708
2709(C<ifOutQLen>)
2710
2711=item $info->i_specific()
2712
2713See C<IF-MIB> for full description
2714
2715(C<ifSpecific>)
2716
2717=back
2718
2719=head2 IPv4 Address Table
2720
2721Each entry in this table is an IPv4 address in use on this device.  Usually
2722this is implemented in Layer3 Devices. These methods try the deprecated IPv4
2723address table C<IP-MIB::ipAddrTable> first due to its prevalence and will try
2724the current C<IP-MIB::ipAddressTable> if it doesn't return any results.
2725C<IP-MIB::ipAddressTable> results are filtered to only return IPv4 unicast
2726addresses and modified to match the return format of the older table for
2727backwards compatibility.
2728
2729See documentation in L<SNMP::Info::IPv6> for IPv6 Address Table.
2730
2731=over
2732
2733=item $info->ip_index()
2734
2735Maps the IPv4 addresses to the interface index
2736
2737(C<ipAdEntIfIndex>) or filtered and index modified (C<ipAddressIfIndex>)
2738
2739=item $info->ip_table()
2740
2741Maps the Table to the IPv4 address
2742
2743(C<ipAdEntAddr>) or address extracted from (C<ipAddressIfIndex>)
2744
2745=item $info->ip_netmask()
2746
2747Gives netmask setting for IPv4 table entry.
2748
2749(C<ipAdEntNetMask>) or netmask calculated from (C<ipAddressPrefix>)
2750
2751=item $info->ip_broadcast()
2752
2753Gives the value of the least-significant bit in the IPv4 broadcast address
2754either 1 or 0.
2755
2756(C<ipAdEntBcastAddr>), there is no equivalent from the
2757C<IP-MIB::ipAddressTable>
2758
2759=back
2760
2761=head2 IP Routing Table
2762
2763=over
2764
2765=item $info->ipr_route()
2766
2767The route in question.  A value of 0.0.0.0 is the default gateway route.
2768
2769(C<ipRouteDest>)
2770
2771=item $info->ipr_if()
2772
2773The interface (IID) that the route is on.  Use interfaces() to map.
2774
2775(C<ipRouteIfIndex>)
2776
2777=item $info->ipr_1()
2778
2779Primary routing metric for this route.
2780
2781(C<ipRouteMetric1>)
2782
2783=item $info->ipr_2()
2784
2785If metrics are not used, they should be set to -1
2786
2787(C<ipRouteMetric2>)
2788
2789=item $info->ipr_3()
2790
2791(C<ipRouteMetric3>)
2792
2793=item $info->ipr_4()
2794
2795(C<ipRouteMetric4>)
2796
2797=item $info->ipr_5()
2798
2799(C<ipRouteMetric5>)
2800
2801=item $info->ipr_dest()
2802
2803From RFC1213:
2804
2805  "The IP address of the next hop of this route.
2806  (In the case of a route bound to an interface
2807  which is realized via a broadcast media, the value
2808  of this field is the agent's IP address on that
2809  interface.)"
2810
2811(C<ipRouteNextHop>)
2812
2813=item $info->ipr_type()
2814
2815From RFC1213:
2816
2817    other(1),        -- none of the following
2818    invalid(2),      -- an invalidated route
2819                     -- route to directly
2820    direct(3),       -- connected (sub-)network
2821                     -- route to a non-local
2822    indirect(4)      -- host/network/sub-network
2823
2824
2825      "The type of route.  Note that the values
2826      direct(3) and indirect(4) refer to the notion of
2827      direct and indirect routing in the IP
2828      architecture.
2829
2830      Setting this object to the value invalid(2) has
2831      the effect of invalidating the corresponding entry
2832      in the ipRouteTable object.  That is, it
2833      effectively disassociates the destination
2834      identified with said entry from the route
2835      identified with said entry.  It is an
2836      implementation-specific matter as to whether the
2837      agent removes an invalidated entry from the table.
2838      Accordingly, management stations must be prepared
2839      to receive tabular information from agents that
2840      corresponds to entries not currently in use.
2841      Proper interpretation of such entries requires
2842      examination of the relevant ipRouteType object."
2843
2844(C<ipRouteType>)
2845
2846=item $info->ipr_proto()
2847
2848From RFC1213:
2849
2850    other(1),       -- none of the following
2851                    -- non-protocol information,
2852                    -- e.g., manually configured
2853    local(2),       -- entries
2854                    -- set via a network
2855    netmgmt(3),     -- management protocol
2856                    -- obtained via ICMP,
2857    icmp(4),        -- e.g., Redirect
2858                    -- the remaining values are
2859                    -- all gateway routing
2860                    -- protocols
2861    egp(5),
2862    ggp(6),
2863    hello(7),
2864    rip(8),
2865    is-is(9),
2866    es-is(10),
2867    ciscoIgrp(11),
2868    bbnSpfIgp(12),
2869    ospf(13),
2870    bgp(14)
2871
2872(C<ipRouteProto>)
2873
2874=item $info->ipr_age()
2875
2876Seconds since route was last updated or validated.
2877
2878(C<ipRouteAge>)
2879
2880=item $info->ipr_mask()
2881
2882Subnet Mask of route. 0.0.0.0 for default gateway.
2883
2884(C<ipRouteMask>)
2885
2886=item $info->ipr_info()
2887
2888Reference to MIB definition specific to routing protocol.
2889
2890(C<ipRouteInfo>)
2891
2892=back
2893
2894=head2 Topology Information
2895
2896Based upon the manufacturer and software version devices may support some
2897combination of Layer 2 topology protocol information.  SNMP::Info
2898supports querying Link Layer Discovery Protocol (LLDP), Cisco Discovery
2899Protocol (CDP), SynOptics/Bay/Nortel/Avaya Network Management Protocol
2900(SONMP), Foundry/Brocade Discovery Protocol (FDP), Extreme Discovery
2901Protocol (EDP), and Alcatel Mapping Adjacency Protocol (AMAP).
2902
2903For protocol specific information and implementation:
2904
2905=over
2906
2907=item AMAP: See L<SNMP::Info::AMAP> for details.
2908
2909=item CDP: See L<SNMP::Info::CDP> for details.
2910
2911=item EDP: See L<SNMP::Info::EDP> for details.
2912
2913=item FDP: See L<SNMP::Info::FDP> for details.
2914
2915=item LLDP: See L<SNMP::Info::LLDP> for details.
2916
2917=item SONMP: See L<SNMP::Info::SONMP> for details.
2918
2919=back
2920
2921=head3 Topology Capabilities
2922
2923=over
2924
2925=item $info->has_topo()
2926
2927Reports Layer 2 topology protocols which are supported and running on
2928a device.
2929
2930Returns either a reference to an array of protocols, possible values
2931being: C<lldp>, C<cdp>, C<sonmp>, C<fdp>, C<edp>, C<amap> or C<undef> if
2932no protocols are supported or running.
2933
2934=back
2935
2936=cut
2937
2938sub ip_index {
2939    my $self = shift;
2940
2941    my $o_ip_idx = $self->old_ip_index();
2942    return $o_ip_idx
2943        if ( ref {} eq ref $o_ip_idx and scalar keys %$o_ip_idx );
2944
2945    # Since callers may be using the old iid to get the IP, strip protocol
2946    # and length from the index
2947    my $n_ip_idx  = $self->new_ip_index() || {};
2948    my $n_ip_type = $self->new_ip_type()  || {};
2949
2950    my %ip_index;
2951    foreach my $iid ( keys %$n_ip_idx ) {
2952        next unless $n_ip_type->{$iid} and $n_ip_type->{$iid} eq 'unicast';
2953        my @parts = split( /\./, $iid );
2954        my $type  = shift(@parts);
2955        my $len   = shift(@parts);
2956        next unless ( ( $type == 1 ) and ( $len == 4 ) );
2957
2958        my $new_iid = join( ".", @parts );
2959        $ip_index{$new_iid} = $n_ip_idx->{$iid};
2960    }
2961    return \%ip_index;
2962}
2963
2964sub ip_table {
2965    my $self = shift;
2966
2967    my $o_ip_table = $self->old_ip_table();
2968    return $o_ip_table
2969        if ( ref {} eq ref $o_ip_table and scalar keys %$o_ip_table );
2970
2971    my $n_ip_idx  = $self->new_ip_index() || {};
2972    my $n_ip_type = $self->new_ip_type()  || {};
2973
2974    my %ip_table;
2975    foreach my $iid ( keys %$n_ip_idx ) {
2976        next unless $n_ip_type->{$iid} and $n_ip_type->{$iid} eq 'unicast';
2977        my @parts = split( /\./, $iid );
2978        my $type  = shift(@parts);
2979        my $len   = shift(@parts);
2980        next unless ( ( $type == 1 ) and ( $len == 4 ) );
2981
2982        my $new_iid = join( ".", @parts );
2983        $ip_table{$new_iid} = $new_iid;
2984    }
2985    return \%ip_table;
2986}
2987
2988sub ip_netmask {
2989    my $self = shift;
2990
2991    my $o_ip_mask = $self->old_ip_netmask();
2992    return $o_ip_mask
2993        if ( ref {} eq ref $o_ip_mask and scalar keys %$o_ip_mask );
2994
2995    my $n_ip_pfx  = $self->new_ip_prefix() || {};
2996    my $n_ip_type = $self->new_ip_type()   || {};
2997
2998    my %ip_netmask;
2999    foreach my $iid ( keys %$n_ip_pfx ) {
3000        next unless $n_ip_type->{$iid} and $n_ip_type->{$iid} eq 'unicast';
3001        my @parts = split( /\./, $iid );
3002        my $type  = shift(@parts);
3003        my $len   = shift(@parts);
3004        next unless ( ( $type == 1 ) and ( $len == 4 ) );
3005
3006        my $prefix = $n_ip_pfx->{$iid};
3007        next if ( !$prefix || $prefix =~ /0\.0$/ );
3008        if ( $prefix =~ /\.(\d+)$/ ) {
3009            $prefix = $1;
3010        }
3011        my $new_iid = join( ".", @parts );
3012        my $mask = NetAddr::IP::Lite->new( $new_iid . '/' . $prefix )->mask()
3013            || undef;
3014
3015        $ip_netmask{$new_iid} = $mask;
3016    }
3017    return \%ip_netmask;
3018}
3019
3020sub has_topo {
3021    my $self = shift;
3022
3023    my @topo_cap;
3024    push( @topo_cap, 'lldp' )
3025        if ( $self->can('hasLLDP') && $self->hasLLDP() );
3026    push( @topo_cap, 'cdp' ) if $self->can('hasCDP') && $self->hasCDP();
3027    push( @topo_cap, 'sonmp' )
3028        if $self->can('hasSONMP') && $self->hasSONMP();
3029    push( @topo_cap, 'fdp' ) if $self->can('hasFDP') && $self->hasFDP();
3030    push( @topo_cap, 'edp' ) if $self->can('hasEDP') && $self->hasEDP();
3031    push( @topo_cap, 'amap' ) if $self->can('hasAMAP') && $self->hasAMAP();
3032
3033    if (@topo_cap) {
3034        return \@topo_cap;
3035    }
3036    else {
3037        return;
3038    }
3039}
3040
3041sub _get_topo_data {
3042    my $self     = shift;
3043    my $partial  = shift;
3044    my $topo_cap = shift;
3045    my $method   = shift || '';
3046
3047    return unless $method =~ /(ip|if|port|id|platform|cap)/;
3048
3049    my %t_data;
3050    foreach my $proto (@$topo_cap) {
3051        next unless $proto =~ /(lldp|cdp|sonmp|fdp|edp|amap)/;
3052        my $method_name = "$proto" . "_$method";
3053        my $cdp = $self->$method_name($partial) || {};
3054
3055        foreach my $iid ( keys %$cdp ) {
3056            my $ip = $cdp->{$iid};
3057            next unless defined $ip;
3058
3059            $t_data{$iid} = $ip;
3060        }
3061    }
3062    return \%t_data;
3063}
3064
3065=head3 Common Topology Table Information
3066
3067The common topology table methods below will query the
3068device for information from the specified topology protocols and return a
3069single hash combining all information. As a result, there may be identical
3070topology information returned from the two protocols causing duplicate
3071entries.  It is the calling program's responsibility to identify any
3072duplicate entries and remove duplicates if necessary.  If it is necessary
3073to understand which protocol provided the information, utilize the protocol
3074specific methods directly rather than the generic methods.
3075
3076The methods support partial table fetches by providing a partial as the
3077first argument.
3078
3079If a reference to an array is provided as the second argument, those
3080protocols will be queried for information.  The supported array values are:
3081C<lldp>, C<cdp>, C<sonmp>, C<fdp>, C<edp>, C<amap>.
3082
3083If nothing is passed in as the second argument, the methods will call
3084has_topo() to determine supported and running topology protocols on the
3085device.
3086
3087=over
3088
3089=item $info->c_ip(partial, topology_protocol_arrayref)
3090
3091Returns reference to hash.  Key: iid, Value: remote IPv4 address
3092
3093If multiple entries exist with the same local port, c_if(), with the
3094same IPv4 address, c_ip(), it may be a duplicate entry.
3095
3096If multiple entries exist with the same local port, c_if(), with different
3097IPv4 addresses, c_ip(), there is either a device in between two or
3098more devices utilizing a different topology protocol or multiple devices
3099which are not directly connected.
3100
3101Use the protocol specific methods to dig deeper.
3102
3103=cut
3104
3105sub c_ip {
3106    my $self     = shift;
3107    my $partial  = shift;
3108    my $topo_cap = shift;
3109
3110    # Default to old behavior if not called with topo_cap
3111    if ( !$topo_cap ) {
3112        my $topo_test = $self->has_topo();
3113        if ($topo_test) {
3114            $topo_cap = $topo_test;
3115        }
3116        else {
3117            return;
3118        }
3119    }
3120    return _get_topo_data ($self, $partial, $topo_cap, 'ip');
3121}
3122
3123=item $info->c_if(partial, topology_protocol_arrayref)
3124
3125Returns reference to hash.  Key: iid, Value: local device port (interfaces)
3126
3127=cut
3128
3129sub c_if {
3130    my $self     = shift;
3131    my $partial  = shift;
3132    my $topo_cap = shift;
3133
3134    # Default to old behavior if not called with topo_cap
3135    if ( !$topo_cap ) {
3136        my $topo_test = $self->has_topo();
3137        if ($topo_test) {
3138            $topo_cap = $topo_test;
3139        }
3140        else {
3141            return;
3142        }
3143    }
3144    return _get_topo_data ($self, $partial, $topo_cap, 'if');
3145}
3146
3147=item $info->c_port(partial, topology_protocol_arrayref)
3148
3149Returns reference to hash. Key: iid, Value: remote port (interfaces)
3150
3151=cut
3152
3153sub c_port {
3154    my $self     = shift;
3155    my $partial  = shift;
3156    my $topo_cap = shift;
3157
3158    # Default to old behavior if not called with topo_cap
3159    if ( !$topo_cap ) {
3160        my $topo_test = $self->has_topo();
3161        if ($topo_test) {
3162            $topo_cap = $topo_test;
3163        }
3164        else {
3165            return;
3166        }
3167    }
3168    return _get_topo_data ($self, $partial, $topo_cap, 'port');
3169}
3170
3171=item $info->c_id(partial, topology_protocol_arrayref)
3172
3173Returns reference to hash. Key: iid, Value: string value used to identify the
3174chassis component associated with the remote system.
3175
3176Note: SONMP does not return this information.
3177
3178=cut
3179
3180sub c_id {
3181    my $self     = shift;
3182    my $partial  = shift;
3183    my $topo_cap = shift;
3184
3185    # Default to old behavior if not called with topo_cap
3186    if ( !$topo_cap ) {
3187        my $topo_test = $self->has_topo();
3188        if ($topo_test) {
3189            $topo_cap = $topo_test;
3190        }
3191        else {
3192            return;
3193        }
3194    }
3195    return _get_topo_data ($self, $partial, $topo_cap, 'id');
3196}
3197
3198=item $info->c_platform(partial, topology_protocol_arrayref)
3199
3200Returns reference to hash.  Key: iid, Value: Remote Device Type
3201
3202Note:  EDP does not provide this information.  LLDP uses (C<lldpRemSysDesc>)
3203or C<lldp_rem_sysname> as the closest match.
3204
3205=cut
3206
3207sub c_platform {
3208    my $self     = shift;
3209    my $partial  = shift;
3210    my $topo_cap = shift;
3211
3212    # Default to old behavior if not called with topo_cap
3213    if ( !$topo_cap ) {
3214        my $topo_test = $self->has_topo();
3215        if ($topo_test) {
3216            $topo_cap = $topo_test;
3217        }
3218        else {
3219            return;
3220        }
3221    }
3222    return _get_topo_data ($self, $partial, $topo_cap, 'platform');
3223}
3224
3225=item $info->c_cap(partial, topology_protocol_arrayref)
3226
3227Returns reference to hash of arrays.  Key: iid, Value: Array of capabilities
3228supported by the device.  See the specific protocol class for string values
3229which could be elements within the array.
3230
3231Note:  Only CDP and LLDP support this method.
3232
3233=cut
3234
3235sub c_cap {
3236    my $self     = shift;
3237    my $partial  = shift;
3238    my $topo_cap = shift;
3239
3240    # Default to old behavior if not called with topo_cap
3241    if ( !$topo_cap ) {
3242        my $topo_test = $self->has_topo();
3243        if ($topo_test) {
3244            $topo_cap = $topo_test;
3245        }
3246        else {
3247            return;
3248        }
3249    }
3250    return _get_topo_data ($self, $partial, $topo_cap, 'cap');
3251}
3252
3253=back
3254
3255=head1 SETTING DATA VIA SNMP
3256
3257This section explains how to use SNMP::Info to do SNMP Set operations.
3258
3259=over
3260
3261=item $info->set_METHOD($value)
3262
3263Sets the global METHOD to value.  Assumes that iid is .0
3264
3265Returns if failed, or the return value from SNMP::Session::set() (snmp_errno)
3266
3267 $info->set_location("Here!");
3268
3269=item $info->set_METHOD($value,$iid)
3270
3271Table Methods. Set iid of method to value.
3272
3273Returns if failed, or the return value from SNMP::Session::set() (snmp_errno)
3274
3275 # Disable a port administratively
3276 my %if_map = reverse %{$info->interfaces()}
3277 $info->set_i_up_admin('down', $if_map{'FastEthernet0/0'})
3278    or die "Couldn't disable the port. ",$info->error(1);
3279
3280=back
3281
3282NOTE: You must be connected to your device with a C<ReadWrite> community
3283string in order for set operations to work.
3284
3285NOTE: This will only set data listed in %FUNCS and %GLOBALS.  For data
3286acquired from overridden methods (subroutines) specific set_METHOD()
3287subroutines will need to be added if they haven't been already.
3288
3289=head1 Quiet Mode
3290
3291SNMP::Info will not chirp anything to STDOUT unless there is a serious error
3292(in which case it will probably die).
3293
3294To get lots of debug info, set the Debug flag when calling new() or
3295call $info->debug(1);
3296
3297When calling a method check the return value.  If the return value is undef
3298then check $info->error()
3299
3300Beware, calling $info->error() clears the error.
3301
3302 my $name = $info->name() or die "Couldn't get sysName!" . $name->error();
3303
3304=head1 EXTENDING SNMP::INFO
3305
3306To support a new class (vendor or platform) of device, add a Perl package with
3307the data structures and methods listed below.
3308
3309If this seems a little scary, then the SNMP::Info developers are usually happy
3310to accept the SNMP data from your device and make an attempt at the class
3311themselves. Usually a "beta" release will go to CPAN for you to verify the
3312implementation.
3313
3314=head2 Gathering MIB data for SNMP::Info Developers
3315
3316The preference is to open a pull request in the github project. This
3317allows all developers to have visibility into the request.  Please include
3318pointers to the applicable platform MIBs.  For development we will need an
3319C<snmpwalk> of the device.  There is a tool now included in the SNMP::Info
3320distribution to help with this task, although you'll most likely need to
3321download the distribution from CPAN as it's included in the "C<contrib/util>"
3322directory.
3323
3324The utility is named C<make_snmpdata.pl>. Run it with a command line like:
3325
3326 ./make_snmpdata.pl -c community -i -d device_ip \
3327  -m /home/netdisco-mibs/rfc:/home/netdisco-mibs/net-snmp:/home/netdisco-mibs/dir3 \
3328  SNMPv2-MIB IF-MIB EtherLike-MIB BRIDGE-MIB Q-BRIDGE-MIB ENTITY-MIB \
3329  POWER-ETHERNET-MIB IPV6-MIB LLDP-MIB DEVICE-SPECIFIC-MIB-NAME(s) > output.txt
3330
3331This will print to the file every MIB entry with data in a format that the
3332developers can use to emulate read operations without needing access to the
3333device.  Preference would be to mask any sensitive data in the output, zip
3334the file, and attach it to the github pull request. However, if you do not
3335feel comfortable uploading the output to the tracker you could e-mail it
3336to the developer that has claimed the ticket.
3337
3338=head2 Data Structures required in new Subclass
3339
3340A class inheriting this class must implement these data structures :
3341
3342=over
3343
3344=item $INIT
3345
3346Used to flag if the MIBs have been loaded yet.
3347
3348=cut
3349
3350$INIT = 0;
3351
3352=item %GLOBALS
3353
3354Contains a hash in the form ( method_name => SNMP MIB leaf name )
3355These are scalar values such as name, uptime, etc.
3356
3357To resolve MIB leaf name conflicts between private MIBs, you may prefix the
3358leaf name with the MIB replacing each - (dash) and : (colon) with
3359an _ (underscore).  For example, ALTEON_TIGON_SWITCH_MIB__agSoftwareVersion
3360would be used as the hash value instead of the net-snmp notation
3361ALTEON-TIGON-SWITCH-MIB::agSoftwareVersion.
3362
3363When choosing the name for the methods, be aware that other new
3364Sub Modules might inherit this one to get it's features.  Try to
3365choose a prefix for methods that will give it's own name space inside
3366the SNMP::Info methods.
3367
3368=cut
3369
3370%GLOBALS = (
3371
3372    # from SNMPv2-MIB
3373    'id'           => 'sysObjectID',
3374    'description'  => 'sysDescr',
3375    'uptime'       => 'sysUpTime',
3376    'contact'      => 'sysContact',
3377    'name'         => 'sysName',
3378    'location'     => 'sysLocation',
3379    'layers'       => 'sysServices',
3380    # IF-MIB
3381    'ports'        => 'ifNumber',
3382    # IP-MIB
3383    'ipforwarding' => 'ipForwarding',
3384);
3385
3386=item %FUNCS
3387
3388Contains a hash in the form ( method_name => SNMP MIB leaf name)
3389These are table entries, such as the C<ifIndex>
3390
3391To resolve MIB leaf name conflicts between private MIBs, you may prefix the
3392leaf name with the MIB replacing each - (dash) and : (colon) with
3393an _ (underscore).  For example, ALTEON_TS_PHYSICAL_MIB__agPortCurCfgPortName
3394would be used as the hash value instead of the net-snmp notation
3395ALTEON-TS-PHYSICAL-MIB::agPortCurCfgPortName.
3396
3397=cut
3398
3399%FUNCS = (
3400    # IF-MIB::IfEntry
3401    'interfaces' => 'ifIndex',
3402    # IF-MIB::IfXEntry
3403    'i_name'     => 'ifName',
3404
3405    # IF-MIB::IfEntry
3406    'i_index'           => 'ifIndex',
3407    'i_description'     => 'ifDescr',
3408    'i_type'            => 'ifType',
3409    'i_mtu'             => 'ifMtu',
3410    'i_speed'           => 'ifSpeed',
3411    'i_mac'             => 'ifPhysAddress',
3412    'i_up_admin'        => 'ifAdminStatus',
3413    'i_up'              => 'ifOperStatus',
3414    'i_lastchange'      => 'ifLastChange',
3415    'i_octet_in'        => 'ifInOctets',
3416    'i_pkts_ucast_in'   => 'ifInUcastPkts',
3417    'i_pkts_nucast_in'  => 'ifInNUcastPkts',
3418    'i_discards_in'     => 'ifInDiscards',
3419    'i_errors_in'       => 'ifInErrors',
3420    'i_bad_proto_in'    => 'ifInUnknownProtos',
3421    'i_octet_out'       => 'ifOutOctets',
3422    'i_pkts_ucast_out'  => 'ifOutUcastPkts',
3423    'i_pkts_nucast_out' => 'ifOutNUcastPkts',
3424    'i_discards_out'    => 'ifOutDiscards',
3425    'i_errors_out'      => 'ifOutErrors',
3426    'i_qlen_out'        => 'ifOutQLen',
3427    'i_specific'        => 'ifSpecific',
3428
3429    # IF-MIB::IfStackTable
3430    'i_stack_status'    => 'ifStackStatus',
3431
3432    # IP-MIB::ipAddrTable (deprecated IPv4 address table)
3433    'old_ip_index'     => 'ipAdEntIfIndex',
3434    'old_ip_table'     => 'ipAdEntAddr',
3435    'old_ip_netmask'   => 'ipAdEntNetMask',
3436    'ip_broadcast'     => 'ipAdEntBcastAddr',
3437
3438    # IP-MIB::ipAddressTable
3439    'new_ip_index'     => 'ipAddressIfIndex',
3440    'new_ip_prefix'    => 'ipAddressPrefix',
3441    'new_ip_type'      => 'ipAddressType',
3442
3443    # IF-MIB::ifXTable - Extension Table
3444    'i_speed_high'       => 'ifHighSpeed',
3445    'i_pkts_multi_in'    => 'ifInMulticastPkts',
3446    'i_pkts_multi_out'   => 'ifOutMulticastPkts',
3447    'i_pkts_bcast_in'    => 'ifInBroadcastPkts',
3448    'i_pkts_bcast_out'   => 'ifOutBroadcastPkts',
3449    'i_octet_in64'       => 'ifHCInOctets',
3450    'i_octet_out64'      => 'ifHCOutOctets',
3451    'i_pkts_ucast_in64'  => 'ifHCInUcastPkts',
3452    'i_pkts_ucast_out64' => 'ifHCOutUcastPkts',
3453    'i_pkts_multi_in64'  => 'ifHCInMulticastPkts',
3454    'i_pkts_multi_out64' => 'ifHCOutMulticastPkts',
3455    'i_pkts_bcast_in64'  => 'ifHCInBroadcastPkts',
3456    'i_pkts_bcast_out64' => 'ifHCOutBroadcastPkts',
3457    'i_alias'            => 'ifAlias',
3458
3459    # RFC-1213::ipRoute (deprecated Table IP Routing Table)
3460    'ipr_route' => 'ipRouteDest',
3461    'ipr_if'    => 'ipRouteIfIndex',
3462    'ipr_1'     => 'ipRouteMetric1',
3463    'ipr_2'     => 'ipRouteMetric2',
3464    'ipr_3'     => 'ipRouteMetric3',
3465    'ipr_4'     => 'ipRouteMetric4',
3466    'ipr_5'     => 'ipRouteMetric5',
3467    'ipr_dest'  => 'ipRouteNextHop',
3468    'ipr_type'  => 'ipRouteType',
3469    'ipr_proto' => 'ipRouteProto',
3470    'ipr_age'   => 'ipRouteAge',
3471    'ipr_mask'  => 'ipRouteMask',
3472    'ipr_info'  => 'ipRouteInfo',
3473);
3474
3475=item %MIBS
3476
3477A list of each mib needed.
3478
3479    ('MIB-NAME' => 'itemToTestForPresence')
3480
3481The value for each entry should be a MIB object to check for to make sure
3482that the MIB is present and has loaded correctly.
3483
3484$info->init() will throw an exception if a MIB does not load.
3485
3486=cut
3487
3488%MIBS = (
3489
3490    # Include these here for cases where the Net-SNMP default MIB list has
3491    # been overridden during the compilation of the local Net-SNMP library.
3492    # These cover the globals and funcs defined in this file.
3493    'SNMPv2-MIB'  => 'sysObjectID',
3494    # (#325) 'RFC1213-MIB' => 'ipRouteIfIndex',
3495    'IP-MIB'      => 'ipAdEntAddr',
3496    'IF-MIB'      => 'ifIndex',
3497);
3498
3499=item %MUNGE
3500
3501A map between method calls (from %FUNCS or %GLOBALS) and subroutine methods.
3502The subroutine called will be passed the data as it gets it from SNMP and
3503it should return that same data in a more human friendly format.
3504
3505Sample %MUNGE:
3506
3507 (my_ip     => \&munge_ip,
3508  my_mac    => \&munge_mac,
3509  my_layers => \&munge_dec2bin
3510 )
3511
3512=cut
3513
3514%MUNGE = (
3515    'ip'                 => \&munge_ip,
3516    'mac'                => \&munge_mac,
3517    'i_mac'              => \&munge_mac,
3518    'layers'             => \&munge_dec2bin,
3519    'i_speed'            => \&munge_speed,
3520    'i_speed_high'       => \&munge_highspeed,
3521    'i_octet_in64'       => \&munge_counter64,
3522    'i_octet_out64'      => \&munge_counter64,
3523    'i_pkts_ucast_in64'  => \&munge_counter64,
3524    'i_pkts_ucast_out64' => \&munge_counter64,
3525    'i_pkts_mutli_in64'  => \&munge_counter64,
3526    'i_pkts_multi_out64' => \&munge_counter64,
3527    'i_pkts_bcast_in64'  => \&munge_counter64,
3528    'i_pkts_bcast_out64' => \&munge_counter64,
3529    'i_up'               => \&munge_i_up,
3530);
3531
3532=back
3533
3534=head2 Sample Subclass
3535
3536Let's make a sample Layer 2 Device subclass.  This class
3537will inherit the Cisco Vlan module as an example.
3538
3539----------------------- snip --------------------------------
3540
3541 # SNMP::Info::Layer2::Sample
3542
3543 package SNMP::Info::Layer2::Sample;
3544
3545 $VERSION = 0.1;
3546
3547 use strict;
3548 use warnings;
3549
3550 use Exporter;
3551 use SNMP::Info::Layer2;
3552 use SNMP::Info::CiscoVTP;
3553
3554 @SNMP::Info::Layer2::Sample::ISA = qw/SNMP::Info::Layer2
3555                                       SNMP::Info::CiscoVTP Exporter/;
3556 @SNMP::Info::Layer2::Sample::EXPORT_OK = qw//;
3557
3558 our ($VERSION, %FUNCS, %GLOBALS, %MIBS, %MUNGE, $AUTOLOAD, $INIT, $DEBUG);
3559
3560 %MIBS    = (%SNMP::Info::Layer2::MIBS,
3561             %SNMP::Info::CiscoVTP::MIBS,
3562             'SUPER-DOOPER-MIB'  => 'supermibobject',
3563            );
3564
3565 %GLOBALS = (%SNMP::Info::Layer2::GLOBALS,
3566             %SNMP::Info::CiscoVTP::GLOBALS,
3567             'name'              => 'supermib_supername',
3568             'favorite_color'    => 'supermib_fav_color_object',
3569             'favorite_movie'    => 'supermib_fav_movie_val',
3570             );
3571
3572 %FUNCS   = (%SNMP::Info::Layer2::FUNCS,
3573             %SNMP::Info::CiscoVTP::FUNCS,
3574             # Super Dooper MIB - Super Hero Table
3575             'super_hero_index'  => 'SuperHeroIfIndex',
3576             'super_hero_name'   => 'SuperHeroIfName',
3577             'super_hero_powers' => 'SuperHeroIfPowers',
3578            );
3579
3580
3581 %MUNGE   = (%SNMP::Info::Layer2::MUNGE,
3582             %SNMP::Info::CiscoVTP::MUNGE,
3583             'super_hero_powers' => \&munge_powers,
3584            );
3585
3586 # Override uptime() method from %SNMP::Info::GLOBALS
3587 sub uptime {
3588     my $sample = shift;
3589
3590     my $name   = $sample->name();
3591
3592     # this is silly but you get the idea
3593     return '600' if defined $name ;
3594 }
3595
3596 # Create our own munge function
3597 sub munge_powers {
3598     my $power = shift;
3599
3600     # Take the returned obscure value and return something useful.
3601     return 'Fire' if $power =~ /reallyhot/i;
3602     return 'Ice'  if $power =~ /reallycold/i;
3603
3604     # Else
3605     return $power;
3606 }
3607
3608 # Copious Documentation here!!!
3609 =head1 NAME
3610 =head1 AUTHOR
3611 =head1 SYNOPSIS
3612 =head1 DESCRIPTION
3613 =head2 Inherited Classes
3614 =head2 Required MIBs
3615 =head1 GLOBALS
3616 =head2 Overrides
3617 =head1 TABLE METHODS
3618 =head2 Overrides
3619 =cut
3620
3621 1; # don't forget this line
3622----------------------- snip --------------------------------
3623
3624
3625=head1 SNMP::INFO INTERNALS
3626
3627=head2 Object Namespace
3628
3629Internal data is stored with bareword keys. For example $info->{debug}
3630
3631SNMP Data is stored or marked cached with keys starting with an underscore.
3632For example $info->{_name} is the cache for $info->name().
3633
3634Cached Table data is stored in $info->store() and marked cached per above.
3635
3636=head2 Package Globals
3637
3638These set the default value for an object upon creation.
3639
3640=over
3641
3642=item $DEBUG
3643
3644Default 0.  Sends copious debug info to stdout.  This global sets the object's
3645debug status in new() unless 'Debug' argument passed in new().  Change
3646objects' debug status with $info->debug().
3647
3648=cut
3649
3650$DEBUG = 0;
3651
3652=item $BIGINT
3653
3654Default 0.   Set to true to have 64 bit counters return Math::BigInt objects
3655instead of scalar string values.  See note under Interface Statistics about
365664 bit values.
3657
3658=cut
3659
3660$BIGINT = 0;
3661
3662=item $NOSUCH
3663
3664Default 1.  Set to false to disable RetryNoSuch option for SNMP::Session.  Or
3665see method in new() to do it on an object scope.
3666
3667=cut
3668
3669$NOSUCH = 1;
3670
3671=item $REPEATERS
3672
3673Default 20.  MaxRepeaters for BULKWALK operations.  See C<perldoc SNMP> for
3674more info.  Can change by passing L</BulkRepeaters> option in new()
3675
3676=cut
3677
3678$REPEATERS = 20;
3679
3680=back
3681
3682=head2 Data Munging Callback Subroutines
3683
3684=over
3685
3686=item munge_speed()
3687
3688Makes human friendly speed ratings using C<%SPEED_MAP>.
3689
3690 %SPEED_MAP = (
3691                '56000'      => '56 kbps',
3692                '64000'      => '64 kbps',
3693                '115000'     => '115 kbps',
3694                '1500000'    => '1.5 Mbps',
3695                '1536000'    => 'T1',
3696                '1544000'    => 'T1',
3697                '2000000'    => '2.0 Mbps',
3698                '2048000'    => '2.048 Mbps',
3699                '3072000'    => 'Dual T1',
3700                '3088000'    => 'Dual T1',
3701                '4000000'    => '4.0 Mbps',
3702                '10000000'   => '10 Mbps',
3703                '11000000'   => '11 Mbps',
3704                '16000000'   => '16 Mbps',
3705                '16777216'   => '16 Mbps',
3706                '20000000'   => '20 Mbps',
3707                '44210000'   => 'T3',
3708                '44736000'   => 'T3',
3709                '45000000'   => '45 Mbps',
3710                '45045000'   => 'DS3',
3711                '46359642'   => 'DS3',
3712                '51850000'   => 'OC-1',
3713                '54000000'   => '54 Mbps',
3714                '64000000'   => '64 Mbps',
3715                '100000000'  => '100 Mbps',
3716                '149760000'  => 'ATM on OC-3',
3717                '155000000'  => 'OC-3',
3718                '155519000'  => 'OC-3',
3719                '155520000'  => 'OC-3',
3720                '200000000'  => '200 Mbps',
3721                '400000000'  => '400 Mbps',
3722                '599040000'  => 'ATM on OC-12',
3723                '622000000'  => 'OC-12',
3724                '622080000'  => 'OC-12',
3725                '1000000000' => '1.0 Gbps',
3726                '2000000000' => '2.0 Gbps',
3727                '2488000000' => 'OC-48',
3728             )
3729
3730Note: high speed interfaces (usually 1 Gbps or faster) have their link
3731speed in C<ifHighSpeed>. i_speed() automatically determines whether to use
3732C<ifSpeed> or C<ifHighSpeed>; if the latter is used, the value is munged by
3733munge_highspeed(). SNMP::Info can return speeds up to terabit levels this way.
3734
3735=cut
3736
3737%SPEED_MAP = (
3738    '56000'      => '56 kbps',
3739    '64000'      => '64 kbps',
3740    '115000'     => '115 kbps',
3741    '1500000'    => '1.5 Mbps',
3742    '1536000'    => 'T1',
3743    '1544000'    => 'T1',
3744    '2000000'    => '2.0 Mbps',
3745    '2048000'    => '2.048 Mbps',
3746    '3072000'    => 'Dual T1',
3747    '3088000'    => 'Dual T1',
3748    '4000000'    => '4.0 Mbps',
3749    '10000000'   => '10 Mbps',
3750    '11000000'   => '11 Mbps',
3751    '16000000'   => '16 Mbps',
3752    '16777216'   => '16 Mbps',
3753    '20000000'   => '20 Mbps',
3754    '44210000'   => 'T3',
3755    '44736000'   => 'T3',
3756    '45000000'   => '45 Mbps',
3757    '45045000'   => 'DS3',
3758    '46359642'   => 'DS3',
3759    '51850000'   => 'OC-1',
3760    '54000000'   => '54 Mbps',
3761    '64000000'   => '64 Mbps',
3762    '100000000'  => '100 Mbps',
3763    '149760000'  => 'ATM on OC-3',
3764    '155000000'  => 'OC-3',
3765    '155519000'  => 'OC-3',
3766    '155520000'  => 'OC-3',
3767    '200000000'  => '200 Mbps',
3768    '400000000'  => '400 Mbps',
3769    '599040000'  => 'ATM on OC-12',
3770    '622000000'  => 'OC-12',
3771    '622080000'  => 'OC-12',
3772    '1000000000' => '1.0 Gbps',
3773    '2000000000' => '2.0 Gbps',
3774    '2488000000' => 'OC-48',
3775);
3776
3777sub munge_speed {
3778    my $speed = shift;
3779    my $map   = $SPEED_MAP{$speed};
3780
3781    #print "  $speed -> $map  " if (defined $map);
3782    return $map || $speed;
3783}
3784
3785=item munge_highspeed()
3786
3787Makes human friendly speed ratings for C<ifHighSpeed>.
3788
3789=cut
3790
3791sub munge_highspeed {
3792    my $speed = shift;
3793    my $fmt   = "%d Mbps";
3794
3795    if ( $speed > 9999999 ) {
3796        $fmt = "%d Tbps";
3797        $speed /= 1000000;
3798    }
3799    elsif ( $speed > 999999 ) {
3800        $fmt = "%.1f Tbps";
3801        $speed /= 1000000.0;
3802    }
3803    elsif ( $speed > 9999 ) {
3804        $fmt = "%d Gbps";
3805        $speed /= 1000;
3806    }
3807    elsif ( $speed > 999 ) {
3808        $fmt = "%.1f Gbps";
3809        $speed /= 1000.0;
3810    }
3811    return sprintf( $fmt, $speed );
3812}
3813
3814=item munge_ip()
3815
3816Takes a binary IP and makes it dotted ASCII.
3817
3818=cut
3819
3820sub munge_ip {
3821    my $ip = shift;
3822    return join( '.', unpack( 'C4', $ip ) );
3823}
3824
3825=item munge_mac()
3826
3827Takes an octet stream (HEX-STRING) and returns a colon separated ASCII hex
3828string.
3829
3830=cut
3831
3832sub munge_mac {
3833    my $mac = shift;
3834    return unless defined $mac;
3835    return unless length $mac;
3836    $mac = join( ':', map { sprintf "%02x", $_ } unpack( 'C*', $mac ) );
3837    return $mac if $mac =~ /^([0-9A-F][0-9A-F]:){5}[0-9A-F][0-9A-F]$/i;
3838    return;
3839}
3840
3841=item munge_prio_mac()
3842
3843Takes an 8-byte octet stream (HEX-STRING) and returns a colon separated ASCII
3844hex string.
3845
3846=cut
3847
3848sub munge_prio_mac {
3849    my $mac = shift;
3850    return unless defined $mac;
3851    return unless length $mac;
3852    $mac = join( ':', map { sprintf "%02x", $_ } unpack( 'C*', $mac ) );
3853    return $mac if $mac =~ /^([0-9A-F][0-9A-F]:){7}[0-9A-F][0-9A-F]$/i;
3854    return;
3855}
3856
3857=item munge_prio_port()
3858
3859Takes an 2-byte octet stream (HEX-STRING) and returns a colon separated ASCII
3860hex string.
3861
3862=cut
3863
3864sub munge_prio_port {
3865    my $priop = shift;
3866    return unless defined $priop;
3867    return unless length $priop;
3868    $priop = join( ':', map { sprintf "%02x", $_ } unpack( 'C*', $priop ) );
3869    return $priop if $priop =~ /^([0-9A-F][0-9A-F]:){1}[0-9A-F][0-9A-F]$/i;
3870    return;
3871}
3872
3873=item munge_octet2hex()
3874
3875Takes a binary octet stream and returns an ASCII hex string.
3876
3877=cut
3878
3879sub munge_octet2hex {
3880    my $oct = shift;
3881    return join( '', map { sprintf "%x", $_ } unpack( 'C*', $oct ) );
3882}
3883
3884=item munge_dec2bin()
3885
3886Takes a binary char and returns its ASCII binary representation.
3887
3888=cut
3889
3890sub munge_dec2bin {
3891    my $num = shift;
3892    return unless defined $num;
3893
3894    #return unless length($num);
3895    $num = unpack( "B32", pack( "N", $num ) );
3896
3897    # return last 8 characters only
3898    $num =~ s/.*(.{8})$/$1/;
3899    return $num;
3900}
3901
3902=item munge_bits()
3903
3904Takes a SNMP2 'BITS' field and returns the ASCII bit string.
3905
3906=cut
3907
3908sub munge_bits {
3909    my $bits = shift;
3910    return unless defined $bits;
3911
3912    return unpack( "B*", $bits );
3913}
3914
3915=item munge_counter64()
3916
3917If $BIGINT is set to true, then a Math::BigInt object is returned.
3918See Math::BigInt for details.
3919
3920=cut
3921
3922sub munge_counter64 {
3923    my $counter = shift;
3924    return          unless defined $counter;
3925    return $counter unless $BIGINT;
3926    my $bigint = Math::BigInt->new($counter);
3927    return $bigint;
3928}
3929
3930=item munge_i_up()
3931
3932Net-SNMP tends to load C<RFC1213-MIB> first, and so ignores the
3933updated enumeration for C<ifOperStatus> in C<IF-MIB>.  This munge
3934handles the "newer" definitions for the enumeration in IF-MIB.
3935
3936TODO: Get the precedence of MIBs and overriding of MIB data in Net-SNMP
3937figured out.  Hierarchy/precedence of MIBS in SNMP::Info.
3938
3939=cut
3940
3941sub munge_i_up {
3942    my $i_up = shift;
3943    return unless defined $i_up;
3944
3945    my %ifOperStatusMap = ( '4' => 'unknown',
3946                            '5' => 'dormant',
3947                            '6' => 'notPresent',
3948                            '7' => 'lowerLayerDown' );
3949    return $ifOperStatusMap{$i_up} || $i_up;
3950}
3951
3952=item munge_port_list()
3953
3954Takes an octet string representing a set of ports and returns a reference
3955to an array of binary values each array element representing a port.
3956
3957If the element has a value of '1', then that port is included in the set of
3958ports; the port is not included if it has a value of '0'.
3959
3960=cut
3961
3962sub munge_port_list {
3963    my $oct = shift;
3964    return unless defined $oct;
3965
3966    my $list = [ split( //, unpack( "B*", $oct ) ) ];
3967
3968    return $list;
3969}
3970
3971=item munge_null()
3972
3973Removes control characters from a string.
3974
3975=cut
3976
3977# munge_null() - removes nulls (\0) and other control characters
3978sub munge_null {
3979    my $text = shift || return;
3980
3981    $text =~ s/[[:cntrl:]]//g;
3982    return $text;
3983}
3984
3985=item munge_e_type()
3986
3987Takes an OID and return the object name if the right MIB is loaded.
3988
3989=cut
3990
3991sub munge_e_type {
3992    my $oid = shift;
3993
3994    my $name = &SNMP::translateObj($oid);
3995    return $name if defined($name);
3996    return $oid;
3997}
3998
3999=back
4000
4001=head2 Internally Used Functions
4002
4003=over
4004
4005=item resolve_desthost()
4006
4007Takes the SNMP::Session C<DestHost> argument and determines if it is an
4008'IPv4' or 'IPv6' host. 'IPv6' hosts are prefixed with the C<udp6:>
4009C<transport-specifier> as required by the underlying C<Net-SNMP> library.
4010If unable to determine the type of address or resolve a DNS name, dies with
4011C<croak>.
4012
4013=cut
4014
4015sub resolve_desthost {
4016    my $desthost = shift;
4017
4018    # If we have an IPv6 transport-specifier strip it
4019    $desthost =~ s/^(?:udp6:|udpv6:|udpipv6:)//x;
4020
4021    my $ip = NetAddr::IP::Lite->new($desthost);
4022
4023    if ($ip and $ip->bits == 32) {
4024        return $ip->addr;
4025    }
4026    elsif ($ip and $ip->bits == 128) {
4027        return 'udp6:' . $ip->addr;
4028    }
4029    else {
4030       croak "Unable to resolve DestHost: $desthost to an IP\n";
4031    }
4032}
4033
4034=item $info->init()
4035
4036Used internally.  Loads all entries in %MIBS.
4037
4038=cut
4039
4040sub init {
4041    my $self = shift;
4042
4043    # Get MibDirs if provided
4044    my $mibdirs = $self->{mibdirs} || [];
4045
4046    # SNMP::initMib and SNMP::addMibDirs both look for some initial MIBs
4047    # so if we are not using Net-SNMP configuration files we need to
4048    # specify where the MIBs are before those calls.
4049
4050    # Ignore snmp.conf and snmp.local.conf files if IgnoreNetSNMPConf
4051    # specified
4052    local $ENV{'SNMPCONFPATH'} = '' if $self->{IgnoreNetSNMPConf};
4053    # We need to provide MIBDIRS if we are not getting them from a
4054    # configuration file
4055    my $mibdir = join (':', @$mibdirs);
4056    local $ENV{'MIBDIRS'} = "$mibdir" if $self->{IgnoreNetSNMPConf};
4057
4058    SNMP::initMib;
4059
4060    my $version = $SNMP::VERSION;
4061    my ( $major, $minor, $rev ) = split( '\.', $version );
4062
4063    if ( $major < 5 ) {
4064
4065        # Seems to work under 4.2.0
4066    }
4067    elsif ( $major == 5 and $minor == 0 and $rev < 2 ) {
4068        carp("Net-SNMP 5.0.1 seems to be rather buggy. Upgrade.\n");
4069
4070        # This is a bug in net-snmp 5.0.1 perl module
4071        # see http://groups.google.com/groups?th=47aed6bf7be6a0f5
4072        SNMP::init_snmp("perl");
4073    }
4074
4075    foreach my $d (@$mibdirs) {
4076        next unless -d $d;
4077        print "SNMP::Info::init() - Adding new mibdir:$d\n"
4078          if $self->debug() > 1;
4079        SNMP::addMibDirs($d);
4080    }
4081
4082    my $mibs = $self->mibs();
4083
4084    foreach my $mib ( keys %$mibs ) {
4085
4086        #print "SNMP::Info::init() - Loading mib:$mib\n" if $self->debug();
4087        SNMP::loadModules("$mib");
4088
4089        unless ( defined $SNMP::MIB{ $mibs->{$mib} } ) {
4090            croak "The $mib did not load. See README for $self->{class}\n";
4091        }
4092    }
4093    return;
4094}
4095
4096=item $info->args()
4097
4098Returns a reference to the argument hash supplied to SNMP::Session
4099
4100=cut
4101
4102sub args {
4103    my $self = shift;
4104    return $self->{args};
4105}
4106
4107=item $info->class()
4108
4109Returns the class name of the object.
4110
4111=cut
4112
4113sub class {
4114    my $self = shift;
4115    return $self->{class};
4116}
4117
4118=item $info->error_throw(error message)
4119
4120Stores the error message for use by $info->error()
4121
4122If $info->debug() is true, then the error message is carped too.
4123
4124=cut
4125
4126sub error_throw {
4127    my $self  = shift;
4128    my $error = shift;
4129
4130    return unless defined $error;
4131    $self->{error} = $error;
4132
4133    if ( $self->debug() ) {
4134        $error =~ s/\n+$//;
4135        carp($error);
4136    }
4137    return;
4138}
4139
4140=item $info->funcs()
4141
4142Returns a reference to the %FUNCS hash.
4143
4144=cut
4145
4146sub funcs {
4147    my $self = shift;
4148    return $self->{funcs};
4149}
4150
4151=item $info->globals()
4152
4153Returns a reference to the %GLOBALS hash.
4154
4155=cut
4156
4157sub globals {
4158    my $self = shift;
4159    return $self->{globals};
4160}
4161
4162=item $info->mibs()
4163
4164Returns a reference to the %MIBS hash.
4165
4166=cut
4167
4168sub mibs {
4169    my $self = shift;
4170    return $self->{mibs};
4171}
4172
4173=item $info->munge()
4174
4175Returns a reference of the %MUNGE hash.
4176
4177=cut
4178
4179sub munge {
4180    my $self = shift;
4181    return $self->{munge};
4182}
4183
4184=item $info->nosuch()
4185
4186Returns NoSuch value set or not in new()
4187
4188=cut
4189
4190sub nosuch {
4191    my $self = shift;
4192    return $self->{nosuch};
4193}
4194
4195=item $info->session()
4196
4197Gets or Sets the SNMP::Session object.
4198
4199=cut
4200
4201sub session {
4202    my $self = shift;
4203    $self->{sess} = $_[0] if @_;
4204    return $self->{sess};
4205}
4206
4207=item $info->store(new_store)
4208
4209Returns or sets hash store for Table functions.
4210
4211Store is a hash reference in this format :
4212
4213$info->store = { attribute => { iid => value , iid2 => value2, ... } };
4214
4215=cut
4216
4217sub store {
4218    my $self = shift;
4219    $self->{store} = $_[0] if @_;
4220    return $self->{store};
4221}
4222
4223=item $info->_global()
4224
4225Used internally by AUTOLOAD to create dynamic methods from %GLOBALS or a
4226single instance MIB Leaf node name from a loaded MIB.
4227
4228Example: $info->name() on the first call dispatches to AUTOLOAD() which
4229calls $info->_global('name') creating the method name().
4230
4231These methods return data as a scalar.
4232
4233=cut
4234
4235sub _global {
4236    my $method = shift;
4237    my $oid    = shift;
4238
4239    return sub {
4240        my $self = shift;
4241
4242        my $sess = $self->session();
4243        return unless defined $sess;
4244
4245        my $load = $method =~ /^load/;
4246        my $raw  = $method =~ /raw$/;
4247
4248        my $attr = $method;
4249        $attr =~ s/^(load|orig)_//;
4250        $attr =~ s/_raw$//;
4251
4252        # Return cached data unless loading
4253        # We now store in raw format so munge before returning
4254        # unless expecting raw data
4255        if ( exists $self->{"_$attr"} && !$load ) {
4256            my $val = $self->{"_$attr"};
4257
4258            if ( !$raw ) {
4259                return $self->_munge($attr, $val);
4260            } else{
4261                return $val;
4262            }
4263        }
4264
4265        if ( $self->{Offline} ) {
4266            $self->error_throw(
4267                "SNMP::Info::_global: Offline but $attr is not in cache\n" );
4268            return;
4269        }
4270
4271        if ( $self->debug() ) {
4272            # Let's get the MIB Module and leaf name along with the OID
4273            my $qual_leaf = SNMP::translateObj($oid,0,1) || '';
4274            print "SNMP::Info::_global $method : $qual_leaf : $oid\n";
4275        }
4276        my $val = $sess->get($oid);
4277
4278        # Mark as gotten. Even if it fails below, we don't want to keep failing.
4279        $self->{"_$attr"} = undef;
4280
4281        if ( $sess->{ErrorStr} ) {
4282            $self->error_throw(
4283                "SNMP::Info::_global($method) $sess->{ErrorStr}");
4284            return;
4285        }
4286
4287        if ( defined $val and $val eq 'NOSUCHOBJECT' ) {
4288            $self->error_throw("SNMP::Info::_global($method) NOSUCHOBJECT");
4289            return;
4290        }
4291
4292        if ( defined $val and $val eq 'NOSUCHINSTANCE' ) {
4293            $self->error_throw("SNMP::Info::_global($method) NOSUCHINSTANCE");
4294            return;
4295        }
4296
4297        # Save Cached Value
4298        $self->_cache($attr, $val);
4299
4300        # Data Munging
4301        if ( !$raw ) {
4302            $val = $self->_munge($attr, $val);
4303        }
4304
4305        return $val;
4306    }
4307}
4308
4309=item $info->_set(attr,val,iid,type)
4310
4311Used internally by set_multi() to run an SNMP set command.  When run
4312clears attr cache.
4313
4314Attr can be passed as either a scalar or a reference to an array or array
4315of arrays when used with set_multi().
4316
4317Example:  $info->set_name('dog',3) uses autoload to resolve to
4318$info->_set('name','dog',3);
4319
4320=cut
4321
4322sub _set {
4323    my ( $self, $attr, $val, $iid, $type ) = @_;
4324    my $varbind_list_ref;
4325
4326    if ( !ref($attr) ) {
4327        $varbind_list_ref = [ [ $attr, $iid, $val, $type ] ];
4328    }
4329    elsif ( ref($attr) =~ /ARRAY/ ) {
4330        $varbind_list_ref = [$attr];
4331        $varbind_list_ref = $attr if ref( $$attr[0] ) =~ /ARRAY/;
4332    }
4333    else {
4334        $self->error_throw(
4335            "SNMP::Info::_set - Failed. Invalid arguments"
4336        );
4337        return;
4338    }
4339
4340    my $sess = $self->session();
4341    return unless defined $sess;
4342
4343    my $funcs   = $self->funcs();
4344    my $globals = $self->globals();
4345
4346    foreach my $var_list (@$varbind_list_ref) {
4347        my $list_attr = $var_list->[0];
4348        my $list_iid  = $var_list->[1];
4349        my $list_val  = $var_list->[2];
4350
4351        # Get rid of non-printable chars in $list_val for debug statements
4352        $list_val =~ s/\W//;
4353
4354        # Instance is 0 for scalars without a supplied instance
4355        $var_list->[1] = $list_iid = defined $list_iid ? $list_iid : '0';
4356
4357        # Lookup oid
4358        my $oid = undef;
4359        $oid = $list_attr             if SNMP::translateObj($list_attr);
4360        $oid = $globals->{$list_attr} if defined $globals->{$list_attr};
4361        $oid = $funcs->{$list_attr}   if defined $funcs->{$list_attr};
4362
4363        unless ( defined $oid ) {
4364            $self->error_throw(
4365                "SNMP::Info::_set($list_attr,$list_val) - Failed to find $list_attr in \%GLOBALS or \%FUNCS or loaded MIB."
4366            );
4367            return;
4368        }
4369
4370        # Check for fully qualified attr
4371        if ( $oid =~ /__/ ) {
4372            $oid =~ s/__/::/;
4373            $oid =~ s/_/-/g;
4374        }
4375
4376        $var_list->[0] = $oid;
4377
4378        $self->debug()
4379            and print
4380            "SNMP::Info::_set $list_attr.$list_iid ($oid.$list_iid) = $list_val\n";
4381        delete $self->{"_$list_attr"};
4382    }
4383
4384    my $rv = $sess->set($varbind_list_ref);
4385
4386    if ( $sess->{ErrorStr} ) {
4387        $self->error_throw("SNMP::Info::_set $sess->{ErrorStr}");
4388        return;
4389    }
4390
4391    return $rv;
4392}
4393
4394=item $info->_make_setter(val,iid)
4395
4396Used internally by AUTOLOAD to create dynamic methods from either %GLOBALS,
4397%FUNCS, or a valid mib leaf from a loaded MIB which runs an SNMP set command.
4398When run clears the attribute cache.
4399
4400Example:  $info->set_name('dog',3) dispatches to autoload to resolve to
4401$info->_set('name','dog',3) and _make_setter creates the set_name() method.
4402
4403=cut
4404
4405sub _make_setter {
4406    my $method = shift;
4407    my $oid    = shift;
4408
4409    return sub {
4410        my $self = shift;
4411        my $val  = shift;
4412        my $iid  = shift;
4413
4414        my $set_oid = $oid;
4415        my $globals = $self->globals();
4416        my $attr = $method;
4417        $attr =~ s/^set_//;
4418
4419        # The only thing which may give us the iid in $oid should be
4420        # a %GLOBALS entry appended with a number.  In that case strip it
4421        # from the OID and use it as $iid
4422        if ( defined $globals->{$attr} && $globals->{$attr} =~ /(\.\d+$)/ ) {
4423            $iid = $1;
4424            $set_oid =~ s/$iid//;
4425        }
4426
4427        # If we don't have $iid now we should be a %GLOBALS entry or single
4428        # instance MIB leaf so default to zero
4429        $iid = defined $iid ? $iid : '.0';
4430
4431        # prepend dot if necessary to $iid
4432        $iid = ".$iid" unless $iid =~ /^\./;
4433
4434        my $sess = $self->session();
4435        return unless defined $sess;
4436
4437        $set_oid .= "$iid";
4438
4439        $self->debug()
4440            and print "SNMP::Info::_set $method$iid ($set_oid) = $val\n";
4441        delete $self->{"_$attr"};
4442
4443        my $rv = $sess->set( $set_oid, $val );
4444
4445        if ( $sess->{ErrorStr} ) {
4446            $self->error_throw("SNMP::Info::_set $sess->{ErrorStr}");
4447            return;
4448        }
4449        return $rv;
4450    }
4451}
4452
4453=item $info->set_multi(arrayref)
4454
4455Used to run an SNMP set command on several new values in the one request.
4456Returns the result of $info->_set(method).
4457
4458Pass either a reference to a 4 element array [<obj>, <iid>, <val>, <type>] or
4459a reference to an array of 4 element arrays to specify multiple values.
4460
4461    <obj> - One of the following forms:
4462        1) leaf identifier (e.g., C<'sysContact'>)
4463        2) An entry in either %FUNCS, %GLOBALS (e.g., 'contact')
4464    <iid> - The dotted-decimal, instance identifier. For scalar MIB objects
4465             use '0'
4466    <val>  - The SNMP data value being set (e.g., 'netdisco')
4467    <type> - Optional as the MIB should be loaded.
4468
4469If one of the set assignments is invalid, then the request will be rejected
4470without applying any of the new values - regardless of the order they appear
4471in the list.
4472
4473Example:
4474    my $vlan_set = [
4475        ['qb_v_untagged',"$old_vlan_id","$old_untagged_portlist"],
4476        ['qb_v_egress',"$new_vlan_id","$new_egress_portlist"],
4477        ['qb_v_egress',"$old_vlan_id","$old_egress_portlist"],
4478        ['qb_v_untagged',"$new_vlan_id","$new_untagged_portlist"],
4479        ['qb_i_vlan',"$port","$new_vlan_id"],
4480    ];
4481
4482    $info->set_multi($vlan_set);
4483
4484=cut
4485
4486sub set_multi {
4487    my $self = shift;
4488
4489    return $self->_set(@_);
4490}
4491
4492=item $info->load_all()
4493
4494Debugging routine.  This does not include any overridden method or method
4495implemented by subroutine.
4496
4497Runs $info->load_METHOD() for each entry in $info->funcs();
4498
4499Returns $info->store() -- See store() entry.
4500
4501Note return value has changed since version 0.3
4502
4503=cut
4504
4505sub load_all {
4506    my $self = shift;
4507    my $sess = $self->session();
4508    return unless defined $sess;
4509
4510    my $funcs = $self->funcs();
4511
4512    foreach my $attrib ( keys %$funcs ) {
4513        $attrib = "load_$attrib";
4514        $self->$attrib();
4515    }
4516
4517    $self->{_all}++;
4518
4519    return unless defined wantarray;
4520
4521    return $self->store();
4522}
4523
4524=item $info->all()
4525
4526Runs $info->load_all() once then returns $info->store();
4527
4528Use $info->load_all() to reload the data.
4529
4530Note return value has changed since version 0.3
4531
4532=cut
4533
4534sub all {
4535    my $self = shift;
4536    my $sess = $self->session();
4537    return unless defined $sess;
4538
4539    $self->load_all() unless defined $self->{_all};
4540
4541    return $self->store();
4542}
4543
4544=item $info->_load_attr()
4545
4546Used internally by AUTOLOAD to create dynamic methods from %FUNCS
4547or a MIB Leaf node name contained within a table of a loaded MIB.
4548
4549Supports partial table fetches and single instance table fetches.
4550See L<SNMP::Info/"Partial Table Fetches">.
4551
4552These methods return data as a reference to a hash.
4553
4554=cut
4555
4556sub _load_attr {
4557    my $method = shift;
4558    my $oid    = shift;
4559
4560    return sub {
4561        my $self    = shift;
4562        my $partial = shift;
4563
4564        my $sess = $self->session();
4565        return unless defined $sess;
4566
4567        my $ver    = $self->snmp_ver();
4568
4569        my $load = $method =~ /^load/;
4570        my $raw  = $method =~ /raw$/;
4571
4572        my $attr = $method;
4573        $attr =~ s/^(load|orig)_//;
4574        $attr =~ s/_raw$//;
4575
4576        # Return cached data unless loading or partial
4577        # We now store in raw format so munge before returning
4578        # unless expecting raw data
4579        return $self->_show_attr($attr, $raw)
4580            if ( defined $self->{"_${attr}"}
4581            && !$load
4582            && !defined $partial );
4583
4584        if ( $self->{Offline} ) {
4585            $self->error_throw(
4586                "SNMP::Info::_load_attr: Offline but $attr is not in cache\n" );
4587            return;
4588        }
4589
4590        # We want the qualified leaf name so that we can
4591        # specify the Module (MIB) in the case of private leaf naming
4592        # conflicts.  Example: ALTEON-TIGON-SWITCH-MIB::agSoftwareVersion
4593        # and ALTEON-CHEETAH-SWITCH-MIB::agSoftwareVersion
4594        # Third argument to translateObj specifies the Module prefix
4595
4596        my $qual_leaf = SNMP::translateObj($oid,0,1) || '';
4597
4598        # We still want just the leaf since a SNMP get in the case of a
4599        # partial fetch may strip the Module portion upon return.  We need
4600        # the match to make sure we didn't leave the table during getnext
4601        # requests
4602
4603        my ($leaf) = $qual_leaf =~ /::(.+)$/;
4604
4605        # If we weren't able to translate, we'll only have an OID
4606        $leaf = $oid unless defined $leaf;
4607
4608        $self->debug()
4609            and print "SNMP::Info::_load_attr $method : $qual_leaf",
4610            defined $partial ? "($partial)" : '', " : $oid" ,
4611            defined $partial ? ".$partial" : '', "\n";
4612
4613        my $var = SNMP::Varbind->new( [$qual_leaf, $partial] );
4614
4615        # So devices speaking SNMP v.1 are not supposed to give out
4616        # data from SNMP2, but most do.  Net-SNMP, being very precise
4617        # will tell you that the SNMP OID doesn't exist for the device.
4618        # They have a flag RetryNoSuch that is used for get() operations,
4619        # but not for getnext().  We set this flag normally, and if we're
4620        # using V1, let's try and fetch the data even if we get one of those.
4621
4622        my $localstore = undef;
4623        my $errornum   = 0;
4624        my %seen       = ();
4625
4626        my $vars = [];
4627        my $bulkwalk_no
4628            = $self->can('bulkwalk_no') ? $self->bulkwalk_no() : 0;
4629        my $bulkwalk_on = defined $self->{BulkWalk} ? $self->{BulkWalk} : 1;
4630        my $can_bulkwalk = $bulkwalk_on && !$bulkwalk_no;
4631        my $repeaters = $self->{BulkRepeaters} || $REPEATERS;
4632        my $bulkwalk = $can_bulkwalk && $ver != 1;
4633        my $loopdetect
4634            = defined $self->{LoopDetect} ? $self->{LoopDetect} : 1;
4635
4636        if ( defined $partial ) {
4637
4638            # Try a GET, in case the partial is a leaf OID.
4639            # Would like to only do this if we know the OID is
4640            # long enough; implementing that would require a
4641            # lot of MIB mucking.
4642            my $try = $sess->get($var);
4643            $errornum = $sess->{ErrorNum};
4644            if ( defined($try) && $errornum == 0 && $try !~ /^NOSUCH/ ) {
4645                $var->[2] = $try;
4646                $vars     = [$var];
4647                $bulkwalk = 1;        # fake a bulkwalk return
4648            }
4649
4650            # We want to execute the while loop below for the getnext request.
4651            if (    $ver == 1
4652                and $sess->{ErrorNum}
4653                and $sess->{ErrorStr} =~ /nosuch/i )
4654            {
4655                $errornum = 0;
4656            }
4657        }
4658
4659        # Use BULKWALK if we can because its faster
4660        if ( $bulkwalk && @$vars == 0 ) {
4661            ($vars) = $sess->bulkwalk( 0, $repeaters, $var );
4662            if ( $sess->{ErrorNum} ) {
4663                $self->error_throw(
4664                    "SNMP::Info::_load_attr: BULKWALK " . $sess->{ErrorStr},
4665                    "\n" );
4666                return;
4667            }
4668        }
4669
4670        while ( !$errornum ) {
4671            if ($bulkwalk) {
4672                $var = shift @$vars or last;
4673            }
4674            else {
4675
4676                # GETNEXT instead of BULKWALK
4677                $sess->getnext($var);
4678                $errornum = $sess->{ErrorNum};
4679            }
4680
4681            if ( $self->debug() > 1 ) {
4682                use Data::Dumper;
4683                print "SNMP::Info::_load_attr $method : leaf = $oid , var = ",
4684                    Dumper($var);
4685            }
4686
4687            # Check if we've left the requested subtree
4688            last if $var->[0] !~ /$leaf$/;
4689            my $iid = $var->[1];
4690            my $val = $var->[2];
4691
4692            unless ( defined $iid ) {
4693                $self->error_throw(
4694                    "SNMP::Info::_load_attr: $method not here");
4695                next;
4696            }
4697
4698            # Check to make sure we are still in partial land
4699            if (    defined $partial
4700                and $iid !~ /^$partial$/
4701                and $iid !~ /^$partial\./ )
4702            {
4703                $self->debug()
4704                    and print "$iid makes us leave partial land.\n";
4705                last;
4706            }
4707
4708           # Check if last element, V2 devices may report ENDOFMIBVIEW even if
4709           # instance or object doesn't exist.
4710            if ( $val eq 'ENDOFMIBVIEW' ) {
4711                last;
4712            }
4713
4714            # Similarly for SNMPv1 - noSuchName return results in both $iid
4715            # and $val being empty strings.
4716            if ( $val eq '' and $iid eq '' ) {
4717                last;
4718            }
4719
4720         # Another check for SNMPv1 - noSuchName return may results in an $iid
4721         # we've already seen and $val an empty string.  If we don't catch
4722         # this here we erroneously report a loop below.
4723            if ( defined $seen{$iid} and $seen{$iid} and $val eq '' ) {
4724                last;
4725            }
4726
4727            if ($loopdetect) {
4728
4729                # Check to see if we've already seen this IID (looping)
4730                if ( defined $seen{$iid} and $seen{$iid} ) {
4731                    $self->error_throw("Looping on: $method iid:$iid. ");
4732                    last;
4733                }
4734                else {
4735                    $seen{$iid}++;
4736                }
4737            }
4738
4739            if ( $val eq 'NOSUCHOBJECT' ) {
4740                $self->error_throw(
4741                    "SNMP::Info::_load_attr: $method :  NOSUCHOBJECT");
4742                next;
4743            }
4744            if ( $val eq 'NOSUCHINSTANCE' ) {
4745                $self->error_throw(
4746                    "SNMP::Info::_load_attr: $method :  NOSUCHINSTANCE");
4747                next;
4748            }
4749
4750            $localstore->{$iid} = $val;
4751
4752        }
4753
4754        # Cache data if we are not getting partial data:
4755        if ( !defined $partial ) {
4756            $self->_cache($attr, $localstore);
4757        }
4758
4759        # Data Munging
4760        if ( !$raw ) {
4761            $localstore = $self->_munge($attr, $localstore);
4762        }
4763
4764        return $localstore;
4765    }
4766}
4767
4768=item $info->_show_attr()
4769
4770Used internally by AUTOLOAD to return data called by methods listed in %FUNCS.
4771
4772=cut
4773
4774sub _show_attr {
4775    my $self = shift;
4776    my $attr = shift;
4777    my $raw  = shift;
4778
4779    my $store = $self->store();
4780
4781    if ( !$raw ) {
4782        my $localstore = $store->{$attr};
4783        return $self->_munge($attr, $localstore);
4784    }
4785    else {
4786        return $store->{$attr};
4787    }
4788}
4789
4790=item $info->snmp_connect_ip(ip)
4791
4792Returns true or false based upon snmp connectivity to an IP.
4793
4794=cut
4795
4796sub snmp_connect_ip {
4797    my $self = shift;
4798    my $ip   = shift;
4799    my $ver  = $self->snmp_ver();
4800    my $comm = $self->snmp_comm();
4801
4802    return if $self->{Offline};
4803
4804    $ip = resolve_desthost($ip);
4805    return if ( $ip eq '0.0.0.0' ) or ( $ip =~ /^127\./ );
4806
4807    # Create session object
4808    my $snmp_test = SNMP::Session->new(
4809        'DestHost'  => $ip,
4810        'Community' => $comm,
4811        'Version'   => $ver
4812    );
4813
4814    # No session object created
4815    unless ( defined $snmp_test ) {
4816        return;
4817    }
4818
4819    # Session object created but SNMP connection failed.
4820    my $sess_err = $snmp_test->{ErrorStr} || '';
4821    if ($sess_err) {
4822        return;
4823    }
4824
4825    # Try to get some data from IP
4826    my $layers = $snmp_test->get('sysServices.0');
4827
4828    $sess_err = $snmp_test->{ErrorStr} || '';
4829    if ($sess_err) {
4830        return;
4831    }
4832
4833    return 1;
4834}
4835
4836=item modify_port_list(portlist,offset,replacement)
4837
4838Replaces the specified bit in a port_list array and
4839returns the packed bitmask
4840
4841=cut
4842
4843sub modify_port_list {
4844    my ( $self, $portlist, $offset, $replacement ) = @_;
4845
4846    print "Original port list: @$portlist \n" if $self->debug();
4847    @$portlist[$offset] = $replacement;
4848
4849    # Some devices do not populate the portlist with all possible ports.
4850    # If we have lengthened the list fill all undefined elements with zero.
4851    foreach my $item (@$portlist) {
4852        $item = '0' unless ( defined($item) );
4853    }
4854    print "Modified port list: @$portlist \n" if $self->debug();
4855
4856    return pack( "B*", join( '', @$portlist ) );
4857}
4858
4859=item $info->_cache(attr, data)
4860
4861Cache retrieved data so that if it's asked for again, we use the cache instead
4862of going back to Net-SNMP. Data is cached inside the blessed hashref C<$self>.
4863
4864Accepts the leaf and value (scalar, or hashref for a table). Does not return
4865anything useful.
4866
4867=cut
4868
4869sub _cache {
4870    my $self = shift;
4871    my ($attr, $data) = @_;
4872    my $store = $self->store();
4873
4874    if (ref {} eq ref $data) {
4875        $self->{"_${attr}"}++;
4876        $store->{$attr} = $data;
4877    }
4878    else {
4879        $self->{"_$attr"} = $data;
4880    }
4881}
4882
4883=item $info->_munge(attr, data)
4884
4885Raw data returned from Net-SNMP might not be formatted correctly or might have
4886platform-specific bugs or mistakes. The MUNGE feature of SNMP::Info allows for
4887fixups to take place.
4888
4889Accepts the leaf and value (scalar, or hashref for a table) and returns the raw
4890or the munged data, as appropriate. That is, you do not need to know whether
4891MUNGE is installed, and it's safe to call this method regardless.
4892
4893=cut
4894
4895sub _munge {
4896    my $self = shift;
4897    my ($attr, $data) = @_;
4898    my $munge = $self->munge();
4899
4900    return $data unless defined $munge->{$attr};
4901
4902    if (ref {} eq ref $data) {
4903        my $subref = $munge->{$attr};
4904        my %munged;
4905        foreach my $key ( keys %$data ) {
4906            my $value = $data->{$key};
4907            next unless defined $value;
4908            $munged{$key} = $subref->($value);
4909        }
4910        return \%munged;
4911    }
4912    else {
4913        return unless $data;
4914        my $subref = $munge->{$attr};
4915        return $subref->($data);
4916    }
4917}
4918
4919=item _validate_autoload_method(method)
4920
4921Used internally by AUTOLOAD to validate that a dynamic method should be
4922created.  Returns the OID of the MIB leaf node the method will get or set.
4923
4924=over
4925
4926=item 1. Returns unless method is listed in %FUNCS, %GLOBALS, or is MIB Leaf
4927node name in a loaded MIB for given class.
4928
4929=item 2. Translates the MIB Leaf node name to an OID.
4930
4931=item 3. Checks to see if the method access type is allowed for the resolved
4932OID.  Write access for set_ methods, read access for others.
4933
4934=back
4935
4936=cut
4937
4938sub _validate_autoload_method {
4939    my $self   = shift;
4940    my $method = shift;
4941
4942    my $setter = $method =~ /^set/;
4943    my $attr = $method;
4944    $attr =~ s/^(load|set|orig)_//;
4945    $attr =~ s/_raw$//;
4946
4947    my $globals = $self->globals();
4948    my $funcs   = $self->funcs();
4949
4950    my $leaf_name = $globals->{$attr} || $funcs->{$attr} || $attr;
4951
4952    # Check for fully qualified name
4953    if ( $leaf_name =~ /__/ ) {
4954        $leaf_name =~ s/__/::/;
4955        $leaf_name =~ s/_/-/g;
4956    }
4957
4958    # skip if offline
4959    if ( $self->{Offline} ) {
4960        return [1,(exists $self->{store}->{$method} ? 1: 0)];
4961    }
4962
4963    # (#325) lazy load legacy RFC1213-MIB only if needed
4964    SNMP::loadModules('RFC1213-MIB')
4965      if $leaf_name =~ m/^(?:RFC1213-MIB::|ipr_|ipRoute)/
4966         and not SNMP::translateObj($leaf_name);
4967
4968    # Translate MIB leaf node name to OID
4969    my $oid = SNMP::translateObj($leaf_name);
4970
4971    if ( $leaf_name =~ /^[.]?\d[\.\d]+$/ ) {
4972        $oid = $leaf_name;
4973    }
4974
4975    unless ( defined $oid ) {
4976        print
4977            "SNMP::Info::_validate_autoload_method($leaf_name) Unable to resolve method.\n"
4978            if $self->debug();
4979        return;
4980    }
4981
4982    # Validate that we have proper access for the operation
4983    my $access = '';
4984
4985    # Prevent autovivification by checking that MIB leaf exists
4986    if (exists $SNMP::MIB{$oid}) {
4987        $access = $SNMP::MIB{$oid}{'access'} || '';
4988    }
4989
4990    # If we were given a fully qualified OID because we don't have the MIB
4991    # file, it will translate above but we won't be able to check access so
4992    # skip the check and return
4993    if ($access && ($method =~ /^set/ && $access !~ /Write|Create/)
4994        || ($method !~ /^set/ && $access eq 'NoAccess')) {
4995
4996            print
4997                "SNMP::Info::_validate_autoload_method($attr : $oid) Not accessible for requested operation.\n"
4998                if $self->debug();
4999            return;
5000
5001    }
5002
5003     my $table_leaf = 0;
5004
5005    # This is an expensive check so we assume anything in the funcs and globals
5006    # hashes are known. Only for actual MIB leafs should we have to check the
5007    # MIB. If the parent of the leaf has indexes it is contained within a table.
5008    if ($funcs->{$attr}) {
5009      $table_leaf = 1;
5010     }
5011    elsif (!$globals->{$attr}) {
5012
5013        # Prevent autovivification
5014        if (exists $SNMP::MIB{$oid} &&
5015            exists $SNMP::MIB{$oid}{'parent'} &&
5016            exists $SNMP::MIB{$oid}{'parent'}{'indexes'} &&
5017            defined $SNMP::MIB{$oid}{'parent'}{'indexes'} &&
5018            scalar( @{$SNMP::MIB{$oid}{'parent'}{'indexes'}} ) > 0)
5019        {
5020            $table_leaf = 1;
5021        }
5022     }
5023
5024    # Tag on .0 for %GLOBALS and single instance MIB leafs unless
5025    # the leaf ends in a digit or we are going to use for a set operation
5026    if ( $table_leaf == 0 && ( $globals->{$attr} || $leaf_name ne $oid ) ) {
5027
5028        unless ( $leaf_name =~ /\d$/ || $setter ) {
5029            $oid .= ".0";
5030        }
5031    }
5032
5033    my $return = [ $oid, $table_leaf ];
5034    return $return;
5035}
5036
5037=item $info->can()
5038
5039Overrides UNIVERSAL::can() so that objects will correctly report their
5040capabilities to include dynamic methods generated at run time via AUTOLOAD.
5041
5042Calls parent can() first to see if method exists, if not validates that a
5043method should be created then dispatches to the appropriate internal method
5044for creation.
5045
5046Returns undef if the method does not exist and can not be created.
5047
5048=cut
5049
5050sub can {
5051    my $self   = shift;
5052    my $method = shift;
5053
5054    # use results of parent can()
5055    return $self->SUPER::can($method) if $self->SUPER::can($method);
5056
5057    return if $method eq 'CARP_TRACE';
5058
5059    my $validated = $self->_validate_autoload_method($method);
5060    return unless $validated;
5061
5062    my ($oid, $table) = @$validated;
5063
5064    # _validate_autoload_method validates, so we need to check for
5065    # set_ , funcs, table leafs, and everything else goes to _global
5066    my $funcs = $self->funcs();
5067
5068    # We need to resolve funcs with a prefix or suffix
5069    my $base_method = $method;
5070    $base_method =~ s/^(load|orig)_//;
5071    $base_method =~ s/_raw$//;
5072
5073    no strict 'refs';    ## no critic (ProhibitNoStrict )
5074
5075    # We could add load_/orig_/_raw alternatives to symbol table here on
5076    # first call of any type for a global or func since they all use the same
5077    # destination code, but they aren't used heavily in main code base so
5078    # we'll just create if/when they are called rather than pollute the
5079    # symbol table with entries that never get called.
5080
5081    # Between 2012-2020 we actually added the methods generated below to the
5082    # symbol table, but they were global to the SNMP::Info class, while
5083    # methods for different device classes may point to different SNMP
5084    # objects. This made interacting with multiple device types from a single
5085    # script somewhat unreliable.
5086
5087    # Check for set_ ing.
5088    if ( $method =~ /^set_/ ) {
5089        return _make_setter( $method, $oid, @_ );
5090    }
5091    elsif ( defined $funcs->{$base_method} || $table ) {
5092        return _load_attr( $method, $oid, @_ );
5093    }
5094    else {
5095        return _global( $method, $oid );
5096    }
5097}
5098
5099=back
5100
5101=head2 AUTOLOAD
5102
5103Each entry in either %FUNCS, %GLOBALS, or MIB Leaf node names present in
5104loaded MIBs are used by AUTOLOAD() to create dynamic methods.
5105
5106=over
5107
5108=item 1. Returns unless method is listed in %FUNCS, %GLOBALS, or is a MIB
5109Leaf node name in a loaded MIB for given class.
5110
5111=item 2. If the method exists in %GLOBALS or is a single instance MIB Leaf
5112node name from a loaded MIB, _global() generates the method.
5113
5114=item 3. If a set_ prefix is present _make_setter() generates the method.
5115
5116=item 4. If the method exists in %FUNCS or is a MIB Leaf node name contained
5117within a table from a loaded MIB, _load_attr() generates the method.
5118
5119=item 5. A load_ prefix forces reloading of data and does not use cached data.
5120
5121=item 6. A _raw suffix returns data ignoring any munge routines.
5122
5123=back
5124
5125Override any dynamic method listed in %GLOBALS, %FUNCS, or MIB Leaf node
5126name a by creating a subroutine with the same name.
5127
5128For example to override $info->name() create `` sub name {...}'' in your
5129subclass.
5130
5131=cut
5132
5133sub AUTOLOAD {
5134    my $self = shift;
5135    my ($sub_name) = $AUTOLOAD =~ /::(\w+)$/;
5136
5137   return if $sub_name eq 'CARP_TRACE';
5138
5139    # Typos in function calls in SNMP::Info subclasses turn into
5140    # AUTOLOAD requests for non-methods.  While this is deprecated,
5141    # we'll still get called, so report a less confusing error.
5142    if ( ref($self) !~ /SNMP::Info/ ) {
5143
5144        # croak reports one level too high.  die reports here.
5145        # I would really like to get the place that's likely to
5146        # have the typo, but perl doesn't want me to.
5147        croak(
5148            "SNMP::Info::AUTOLOAD($AUTOLOAD) called with no class (probably typo of function call to $sub_name)"
5149        );
5150    }
5151
5152    # This enables us to use SUPER:: for AUTOLOAD methods as well
5153    # as the true OO methods.  Method needs to be renamed to prevent
5154    # namespace collision when we insert into the symbol table later.
5155    if ( $AUTOLOAD =~ /SUPER::$sub_name$/ ) {
5156        $AUTOLOAD =~ s/SUPER::$sub_name/orig_$sub_name/;
5157        $sub_name = "orig_$sub_name";
5158    }
5159
5160    return unless my $meth_ref = $self->can($sub_name, @_);
5161    return $self->$meth_ref(@_);
5162
5163}
5164
5165# Skip AUTOLOAD()
5166sub DESTROY {}
5167
51681;
5169
5170=head1 COPYRIGHT AND LICENSE
5171
5172Changes from SNMP::Info Version 0.7 and on are:
5173Copyright (c) 2003-2010 Max Baker and SNMP::Info Developers
5174All rights reserved.
5175
5176Original Code is:
5177Copyright (c) 2002-2003, Regents of the University of California
5178All rights reserved.
5179
5180Redistribution and use in source and binary forms, with or without
5181modification, are permitted provided that the following conditions are met:
5182
5183    * Redistributions of source code must retain the above copyright notice,
5184      this list of conditions and the following disclaimer.
5185    * Redistributions in binary form must reproduce the above copyright
5186      notice, this list of conditions and the following disclaimer in the
5187      documentation and/or other materials provided with the distribution.
5188    * Neither the name of the University of California, Santa Cruz nor the
5189      names of its contributors may be used to endorse or promote products
5190      derived from this software without specific prior written permission.
5191
5192THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
5193AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
5194IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
5195DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
5196FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
5197DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
5198SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
5199CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
5200OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
5201OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5202
5203=cut
5204