1# =============================================================================
2package Net::SNMP::Util::OID;
3# -----------------------------------------------------------------------------
4$Net::SNMP::Util::OID::VERSION = '1.04';
5# -----------------------------------------------------------------------------
6use warnings;
7use strict;
8
9=head1 NAME
10
11Net::SNMP::Util::OID - OID mapper functions for Net::SNMP::Util
12
13=head1 SYNOPSIS
14
15    # load system and interfaces MIB map
16    use Net::SNMP::Util::OID qw(sys* if*);
17
18    printf "OID of sysDescr is %s\n", oid("sysDescr");
19    # "1.3.6.1.2.1.1.1"
20
21    printf "1.3.6.1.2.1.2.2.1.3 specifys %s\n", oidt("1.3.6.1.2.1.2.2.1.3");
22    # ifType
23
24    printf "OID of MIB %s is %s\n", oidm("ifName");
25    # "ifName", "1.3.6.1.2.1.31.1.1.1.1"
26
27    oid_load("someMib1" => "1.3.6.1.4.1.99999.1.2.3",
28             "someMib2" => "1.3.6.1.4.1.99999.4.5.6");
29    printf "OID of MIB %s is %s\n", oidm("someMib1");
30
31
32=head1 DESCRIPTION
33
34Module C<Net::SNMP::Util::OID> gives some functions which treats mapping data
35between MIB name and OID.
36
37=head2 Basic entry group importing
38
39This module is preparing some basic MIB and OID maps mainly definded RFC-1213.
40For example, if you want to treat some MIB and OID with among 'system' and
41'snmp' entry group's, declare with C<use> pragma and gives arguments with
42tailing '*' like;
43
44    use Net::SNMP::Util::OID qw(system* snmp*);
45
46So, note that no declaring with this tagging couldn't treat mapping data.
47
48    use Net::SNMP::Util::OID;
49    $oid = oid("ifType");       # Null string will return!
50
51The prepared entrys are; C<system*>, C<interfaces*>, C<at*>, C<ip*>, C<icmp*>,
52 C<tcp*>, C<udp*>, C<egp*>, C<snmp*>, C<tcp*> and C<ifXTable*>.
53And there are few sugar syntaxs. Only one character '*' means all prepared
54mapping, 'sys*' means 'system*' and 'if*' means importing 'interfaces' and
55'ifXTable' at same time.
56
57
58=head1 EXPORT
59
60This module, C<Net::SNMP::Util::OID>, exports C<oid_load()>, C<oid()>, C<oidt()>
61and C<oidm()>.
62
63=cut
64
65use Carp qw();
66use List::Util;
67
68use base qw( Exporter );
69our (@EXPORT, @EXPORT_OK, %EXPORT_TAGS, $VERSION);
70@EXPORT = qw( oid_load oid oidt oidp );
71
72my %_OIDs = ();
73my %_MIBs = ();
74my @_Cache = ();
75my $_CacheNum = 10;     # Number of caching pairs
76
77use constant DEBUG => 0;
78
79
80# =============================================================================
81my %_OID_base = qw(
82        iso             1
83        org             1.3
84        dod             1.3.6
85        internet        1.3.6.1
86        directory       1.3.6.1.1
87        mgmt            1.3.6.1.2
88        experimental    1.3.6.1.3
89        private         1.3.6.1.4
90        security        1.3.6.1.5
91        snmpV2          1.3.6.1.6
92);
93
94my %_OID_mgmt = (
95
96    # --- from RFC-1213 ---
97    'system' => {
98        system              => '1.3.6.1.2.1.1',
99        sysDescr            => '1.3.6.1.2.1.1.1.0',
100        sysObjectID         => '1.3.6.1.2.1.1.2.0',
101        sysUpTime           => '1.3.6.1.2.1.1.3.0',
102        sysUptime           => '1.3.6.1.2.1.1.3.0',
103        sysContact          => '1.3.6.1.2.1.1.4.0',
104        sysName             => '1.3.6.1.2.1.1.5.0',
105        sysLocation         => '1.3.6.1.2.1.1.6.0',
106        sysServices         => '1.3.6.1.2.1.1.7.0',
107
108        sysORLastChange     => '1.3.6.1.2.1.1.8.0',     # from RFC-1907,3418
109        sysORTable          => '1.3.6.1.2.1.1.9',       # from RFC-1907,3418
110        sysOREntry          => '1.3.6.1.2.1.1.9.1',     # from RFC-1907,3418
111        sysORIndex          => '1.3.6.1.2.1.1.9.1.1',   # from RFC-1907,3418
112        sysORID             => '1.3.6.1.2.1.1.9.1.2',   # from RFC-1907,3418
113        sysORDescr          => '1.3.6.1.2.1.1.9.1.3',   # from RFC-1907,3418
114        sysORUpTime         => '1.3.6.1.2.1.1.9.1.4',   # from RFC-1907,3418
115    },
116    interfaces => {
117        interfaces          => '1.3.6.1.2.1.2',
118        ifNumber            => '1.3.6.1.2.1.2.1.0',     # from RFC-2863
119        ifTable             => '1.3.6.1.2.1.2.2',
120        ifEntry             => '1.3.6.1.2.1.2.2.1',
121        ifIndex             => '1.3.6.1.2.1.2.2.1.1',
122        ifDescr             => '1.3.6.1.2.1.2.2.1.2',
123        ifType              => '1.3.6.1.2.1.2.2.1.3',
124        ifMtu               => '1.3.6.1.2.1.2.2.1.4',
125        ifSpeed             => '1.3.6.1.2.1.2.2.1.5',
126        ifPhysAddress       => '1.3.6.1.2.1.2.2.1.6',
127        ifAdminStatus       => '1.3.6.1.2.1.2.2.1.7',
128        ifOperStatus        => '1.3.6.1.2.1.2.2.1.8',
129        ifLastChange        => '1.3.6.1.2.1.2.2.1.9',
130        ifInOctets          => '1.3.6.1.2.1.2.2.1.10',
131        ifInUcastPkts       => '1.3.6.1.2.1.2.2.1.11',
132        ifInNUcastPkts      => '1.3.6.1.2.1.2.2.1.12',  # deprecated at RFC-2863
133        ifInDiscards        => '1.3.6.1.2.1.2.2.1.13',
134        ifInErrors          => '1.3.6.1.2.1.2.2.1.14',
135        ifInUnknownProtos   => '1.3.6.1.2.1.2.2.1.15',
136        ifOutOctets         => '1.3.6.1.2.1.2.2.1.16',
137        ifOutUcastPkts      => '1.3.6.1.2.1.2.2.1.17',
138        ifOutNUcastPkts     => '1.3.6.1.2.1.2.2.1.18',  # deprecated at RFC-2863
139        ifOutDiscards       => '1.3.6.1.2.1.2.2.1.19',
140        ifOutErrors         => '1.3.6.1.2.1.2.2.1.20',
141        ifOutQLen           => '1.3.6.1.2.1.2.2.1.21',  # deprecated at RFC-2863
142        ifSpecific          => '1.3.6.1.2.1.2.2.1.22',  # deprecated at RFC-2863
143    },
144    at => {
145        at                  => '1.3.6.1.2.1.3',
146        atTable             => '1.3.6.1.2.1.3.1',
147        atEntry             => '1.3.6.1.2.1.3.1.1',
148        atIfIndex           => '1.3.6.1.2.1.3.1.1.1',
149        atPhysAddress       => '1.3.6.1.2.1.3.1.1.2',
150        atNetAddress        => '1.3.6.1.2.1.3.1.1.3',
151    },
152    ip => {
153        ip                  => '1.3.6.1.2.1.4',
154        ipForwarding        => '1.3.6.1.2.1.4.1',
155        ipDefaultTTL        => '1.3.6.1.2.1.4.2',
156        ipInReceives        => '1.3.6.1.2.1.4.3',
157        ipInHdrErrors       => '1.3.6.1.2.1.4.4',
158        ipInAddrErrors      => '1.3.6.1.2.1.4.5',
159        ipForwDatagrams     => '1.3.6.1.2.1.4.6',
160        ipInUnknownProtos   => '1.3.6.1.2.1.4.7',
161        ipInDiscards        => '1.3.6.1.2.1.4.8',
162        ipInDelivers        => '1.3.6.1.2.1.4.9',
163        ipOutRequests       => '1.3.6.1.2.1.4.10',
164        ipOutDiscards       => '1.3.6.1.2.1.4.11',
165        ipOutNoRoutes       => '1.3.6.1.2.1.4.12',
166        ipReasmTimeout      => '1.3.6.1.2.1.4.13',
167        ipReasmReqds        => '1.3.6.1.2.1.4.14',
168        ipReasmOKs          => '1.3.6.1.2.1.4.15',
169        ipReasmFails        => '1.3.6.1.2.1.4.16',
170        ipFragOKs           => '1.3.6.1.2.1.4.17',
171        ipFragFails         => '1.3.6.1.2.1.4.18',
172        ipFragCreates       => '1.3.6.1.2.1.4.19',
173        ipAddrTable         => '1.3.6.1.2.1.4.20',
174        ipAddrEntry         => '1.3.6.1.2.1.4.20.1',
175        ipAdEntAddr         => '1.3.6.1.2.1.4.20.1.1',
176        ipAdEntIfIndex      => '1.3.6.1.2.1.4.20.1.2',
177        ipAdEntNetMask      => '1.3.6.1.2.1.4.20.1.3',
178        ipAdEntBcastAddr    => '1.3.6.1.2.1.4.20.1.4',
179        ipAdEntReasmMaxSize => '1.3.6.1.2.1.4.20.1.5',
180        ipRouteTable        => '1.3.6.1.2.1.4.21',
181        ipRouteEntry        => '1.3.6.1.2.1.4.21.1',
182        ipRouteDest         => '1.3.6.1.2.1.4.21.1.1',
183        ipRouteIfIndex      => '1.3.6.1.2.1.4.21.1.2',
184        ipRouteMetric1      => '1.3.6.1.2.1.4.21.1.3',
185        ipRouteMetric2      => '1.3.6.1.2.1.4.21.1.4',
186        ipRouteMetric3      => '1.3.6.1.2.1.4.21.1.5',
187        ipRouteMetric4      => '1.3.6.1.2.1.4.21.1.6',
188        ipRouteNextHop      => '1.3.6.1.2.1.4.21.1.7',
189        ipRouteType         => '1.3.6.1.2.1.4.21.1.8',
190        ipRouteProto        => '1.3.6.1.2.1.4.21.1.9',
191        ipRouteAge          => '1.3.6.1.2.1.4.21.1.10',
192        ipRouteMask         => '1.3.6.1.2.1.4.21.1.11',
193        ipRouteMetric5      => '1.3.6.1.2.1.4.21.1.12',
194        ipRouteInfo         => '1.3.6.1.2.1.4.21.1.13',
195        ipNetToMediaTable   => '1.3.6.1.2.1.4.22',
196        ipNetToMediaEntry   => '1.3.6.1.2.1.4.22.1',
197        ipNetToMediaIfIndex => '1.3.6.1.2.1.4.22.1.1',
198        ipNetToMediaPhysAddress => '1.3.6.1.2.1.4.22.1.2',
199        ipNetToMediaNetAddress  => '1.3.6.1.2.1.4.22.1.3',
200        ipNetToMediaType    => '1.3.6.1.2.1.4.22.1.4',
201        ipRoutingDiscards   => '1.3.6.1.2.1.4.23',
202    },
203    icmp => {
204        icmp                => '1.3.6.1.2.1.5',
205        icmpInMsgs          => '1.3.6.1.2.1.5.1',
206        icmpInErrors        => '1.3.6.1.2.1.5.2',
207        icmpInDestUnreachs  => '1.3.6.1.2.1.5.3',
208        icmpInTimeExcds     => '1.3.6.1.2.1.5.4',
209        icmpInParmProbs     => '1.3.6.1.2.1.5.5',
210        icmpInSrcQuenchs    => '1.3.6.1.2.1.5.6',
211        icmpInRedirects     => '1.3.6.1.2.1.5.7',
212        icmpInEchos         => '1.3.6.1.2.1.5.8',
213        icmpInEchoReps      => '1.3.6.1.2.1.5.9',
214        icmpInTimestamps    => '1.3.6.1.2.1.5.10',
215        icmpInTimestampReps => '1.3.6.1.2.1.5.11',
216        icmpInAddrMasks     => '1.3.6.1.2.1.5.12',
217        icmpInAddrMaskReps  => '1.3.6.1.2.1.5.13',
218        icmpOutMsgs         => '1.3.6.1.2.1.5.14',
219        icmpOutErrors       => '1.3.6.1.2.1.5.15',
220        icmpOutDestUnreachs => '1.3.6.1.2.1.5.16',
221        icmpOutTimeExcds    => '1.3.6.1.2.1.5.17',
222        icmpOutParmProbs    => '1.3.6.1.2.1.5.18',
223        icmpOutSrcQuenchs   => '1.3.6.1.2.1.5.19',
224        icmpOutRedirects    => '1.3.6.1.2.1.5.20',
225        icmpOutEchos        => '1.3.6.1.2.1.5.21',
226        icmpOutEchoReps     => '1.3.6.1.2.1.5.22',
227        icmpOutTimestamps   => '1.3.6.1.2.1.5.23',
228        icmpOutTimestampReps => '1.3.6.1.2.1.5.24',
229        icmpOutAddrMasks    => '1.3.6.1.2.1.5.25',
230        icmpOutAddrMaskReps => '1.3.6.1.2.1.5.26',
231    },
232    tcp => {
233        tcp                 => '1.3.6.1.2.1.6',
234        tcpRtoAlgorithm     => '1.3.6.1.2.1.6.1',
235        tcpRtoMin           => '1.3.6.1.2.1.6.2',
236        tcpRtoMax           => '1.3.6.1.2.1.6.3',
237        tcpMaxConn          => '1.3.6.1.2.1.6.4',
238        tcpActiveOpens      => '1.3.6.1.2.1.6.5',
239        tcpPassiveOpens     => '1.3.6.1.2.1.6.6',
240        tcpAttemptFails     => '1.3.6.1.2.1.6.7',
241        tcpEstabResets      => '1.3.6.1.2.1.6.8',
242        tcpCurrEstab        => '1.3.6.1.2.1.6.9',
243        tcpInSegs           => '1.3.6.1.2.1.6.10',
244        tcpOutSegs          => '1.3.6.1.2.1.6.11',
245        tcpRetransSegs      => '1.3.6.1.2.1.6.12',
246        tcpConnTable        => '1.3.6.1.2.1.6.13',
247        tcpConnEntry        => '1.3.6.1.2.1.6.13.1',
248        tcpConnState        => '1.3.6.1.2.1.6.13.1.1',
249        tcpConnLocalAddress => '1.3.6.1.2.1.6.13.1.2',
250        tcpConnLocalPort    => '1.3.6.1.2.1.6.13.1.3',
251        tcpConnRemAddress   => '1.3.6.1.2.1.6.13.1.4',
252        tcpConnRemPort      => '1.3.6.1.2.1.6.13.1.5',
253        tcpInErrs           => '1.3.6.1.2.1.6.14',
254        tcpOutRsts          => '1.3.6.1.2.1.6.15',
255    },
256    udp => {
257        udp                 => '1.3.6.1.2.1.7',
258        udpInDatagrams      => '1.3.6.1.2.1.7.1',
259        udpNoPorts          => '1.3.6.1.2.1.7.2',
260        udpInErrors         => '1.3.6.1.2.1.7.3',
261        udpOutDatagrams     => '1.3.6.1.2.1.7.4',
262        udpTable            => '1.3.6.1.2.1.7.5',
263        udpEntry            => '1.3.6.1.2.1.7.5.1',
264        udpLocalAddress     => '1.3.6.1.2.1.7.5.1.1',
265        udpLocalPort        => '1.3.6.1.2.1.7.5.1.2',
266    },
267    egp => {
268        egp                     => '1.3.6.1.2.1.8',
269        egpInMsgs               => '1.3.6.1.2.1.8.1',
270        egpInErrors             => '1.3.6.1.2.1.8.2',
271        egpOutMsgs              => '1.3.6.1.2.1.8.3',
272        egpOutErrors            => '1.3.6.1.2.1.8.4',
273        egpNeighTable           => '1.3.6.1.2.1.8.5',
274        egpNeighEntry           => '1.3.6.1.2.1.8.5.1',
275        egpNeighState           => '1.3.6.1.2.1.8.5.1.1',
276        egpNeighAddr            => '1.3.6.1.2.1.8.5.1.2',
277        egpNeighAs              => '1.3.6.1.2.1.8.5.1.3',
278        egpNeighInMsgs          => '1.3.6.1.2.1.8.5.1.4',
279        egpNeighInErrs          => '1.3.6.1.2.1.8.5.1.5',
280        egpNeighOutMsgs         => '1.3.6.1.2.1.8.5.1.6',
281        egpNeighOutErrs         => '1.3.6.1.2.1.8.5.1.7',
282        egpNeighInErrMsgs       => '1.3.6.1.2.1.8.5.1.8',
283        egpNeighOutErrMsgs      => '1.3.6.1.2.1.8.5.1.9',
284        egpNeighStateUps        => '1.3.6.1.2.1.8.5.1.10',
285        egpNeighStateDowns      => '1.3.6.1.2.1.8.5.1.11',
286        egpNeighIntervalHello   => '1.3.6.1.2.1.8.5.1.12',
287        egpNeighIntervalPoll    => '1.3.6.1.2.1.8.5.1.13',
288        egpNeighMode            => '1.3.6.1.2.1.8.5.1.14',
289        egpNeighEventTrigger    => '1.3.6.1.2.1.8.5.1.15',
290        egpAs                   => '1.3.6.1.2.1.8.6',
291    },
292    transmission => {
293        transmission            => '1.3.6.1.2.1.10',
294    },
295    snmp => {
296        snmp                    => '1.3.6.1.2.1.11',
297        snmpInPkts              => '1.3.6.1.2.1.11.1',
298        snmpOutPkts             => '1.3.6.1.2.1.11.2',
299        snmpInBadVersions       => '1.3.6.1.2.1.11.3',
300        snmpInBadCommunityNames => '1.3.6.1.2.1.11.4',
301        snmpInBadCommunityUses  => '1.3.6.1.2.1.11.5',
302        snmpInASNParseErrs      => '1.3.6.1.2.1.11.6',
303        snmpInTooBigs           => '1.3.6.1.2.1.11.8',
304        snmpInNoSuchNames       => '1.3.6.1.2.1.11.9',
305        snmpInBadValues         => '1.3.6.1.2.1.11.10',
306        snmpInReadOnlys         => '1.3.6.1.2.1.11.11',
307        snmpInGenErrs           => '1.3.6.1.2.1.11.12',
308        snmpInTotalReqVars      => '1.3.6.1.2.1.11.13',
309        snmpInTotalSetVars      => '1.3.6.1.2.1.11.14',
310        snmpInGetRequests       => '1.3.6.1.2.1.11.15',
311        snmpInGetNexts          => '1.3.6.1.2.1.11.16',
312        snmpInSetRequests       => '1.3.6.1.2.1.11.17',
313        snmpInGetResponses      => '1.3.6.1.2.1.11.18',
314        snmpInTraps             => '1.3.6.1.2.1.11.19',
315        snmpOutTooBigs          => '1.3.6.1.2.1.11.20',
316        snmpOutNoSuchNames      => '1.3.6.1.2.1.11.21',
317        snmpOutBadValues        => '1.3.6.1.2.1.11.22',
318        snmpOutGenErrs          => '1.3.6.1.2.1.11.24',
319        snmpOutGetRequests      => '1.3.6.1.2.1.11.25',
320        snmpOutGetNexts         => '1.3.6.1.2.1.11.26',
321        snmpOutSetRequests      => '1.3.6.1.2.1.11.27',
322        snmpOutGetResponses     => '1.3.6.1.2.1.11.28',
323        snmpOutTraps            => '1.3.6.1.2.1.11.29',
324        snmpEnableAuthenTraps   => '1.3.6.1.2.1.11.30',
325        snmpSilentDrops         => '1.3.6.1.2.1.11.31', # from RFC-1907,3418
326        snmpProxyDrops          => '1.3.6.1.2.1.11.32', # from RFC-1907,3418
327    },
328
329    # --- from RFC-2863 ---
330    'ifMIB' => {
331        ifMIB                   => '1.3.6.1.2.1.31',
332        ifMIBObjects            => '1.3.6.1.2.1.31.1',
333        ifConformance           => '1.3.6.1.2.1.31.2',
334    },
335
336    'ifXTable' => {
337        ifXTable                => '1.3.6.1.2.1.31.1.1',
338        ifXEntry                => '1.3.6.1.2.1.31.1.1.1',
339        ifName                  => '1.3.6.1.2.1.31.1.1.1.1',
340        ifInMulticastPkts       => '1.3.6.1.2.1.31.1.1.1.2',
341        ifInBroadcastPkts       => '1.3.6.1.2.1.31.1.1.1.3',
342        ifOutMulticastPkts      => '1.3.6.1.2.1.31.1.1.1.4',
343        ifOutBroadcastPkts      => '1.3.6.1.2.1.31.1.1.1.5',
344        ifHCInOctets            => '1.3.6.1.2.1.31.1.1.1.6',
345        ifHCInUcastPkts         => '1.3.6.1.2.1.31.1.1.1.7',
346        ifHCInMulticastPkts     => '1.3.6.1.2.1.31.1.1.1.8',
347        ifHCInBroadcastPkts     => '1.3.6.1.2.1.31.1.1.1.9',
348        ifHCOutOctets           => '1.3.6.1.2.1.31.1.1.1.10',
349        ifHCOutUcastPkts        => '1.3.6.1.2.1.31.1.1.1.11',
350        ifHCOutMulticastPkts    => '1.3.6.1.2.1.31.1.1.1.12',
351        ifHCOutBroadcastPkts    => '1.3.6.1.2.1.31.1.1.1.13',
352        ifLinkUpDownTrapEnable  => '1.3.6.1.2.1.31.1.1.1.14',
353        ifHighSpeed             => '1.3.6.1.2.1.31.1.1.1.15',
354        ifPromiscuousMode       => '1.3.6.1.2.1.31.1.1.1.16',
355        ifConnectorPresent      => '1.3.6.1.2.1.31.1.1.1.17',
356        ifAlias                 => '1.3.6.1.2.1.31.1.1.1.18',
357        ifCounterDiscontinuityTime => '1.3.6.1.2.1.31.1.1.1.19',
358    },
359);
360# =============================================================================
361our @MAPS = ( \%_OID_mgmt );
362
363sub import
364{
365    my $class = shift;
366    my @args  = ();
367    oid_load( \%_OID_base );
368
369    foreach ( map { lc } @_ ){
370        if ( /^(.*)\*$/ ){
371            # OID map loading
372            my $which = $1;
373            my @which = ();
374            my $found = 0;
375
376            if ( $which eq '' ){
377                foreach my $map ( @MAPS ){
378                    foreach my $w ( keys %{$map} ){
379                        oid_load( $map->{$w} );
380                    }
381                }
382                $found = 1;
383            }
384            else {
385                if ( $which eq 'if' ){
386                    push @which, qw( interfaces ifXTable ); # suger
387                }
388                elsif ( $which eq 'sys' ){
389                    push @which, 'system';                  # suger
390                }
391                else {
392                    push @which, $which;
393                }
394                my $found = _mapdata_loader(@which);
395                unless ( $found ){
396                    Carp::carp(qq(Not found mapping data of "$which*".));
397                }
398            }
399        }
400        else {
401            push @args, @_;
402        }
403    }
404
405    __PACKAGE__->export_to_level(1, @args);
406}
407
408
409# =============================================================================
410sub _mapdata_loader
411{
412    my $found = 0;
413
414    foreach my $map ( @MAPS ){
415        foreach my $which ( @_ ){
416            if ( exists $map->{$which} ){
417                oid_load( $map->{$which} );
418                $found = 1;
419            }
420        }
421    }
422    return $found;
423}
424
425
426# =============================================================================
427
428=head1 FUNCTIONS
429
430=head2 oid_load()
431
432    oid_load( $mib_name => $oid, ... );
433    oid_load( \%somehash, ... );
434
435Functions oid_load() takes hash pairs or a referances of hash as arguments, and
436store intarnally MIB name and OID (Object IDentifier) mapping data from them.
437
438=cut
439
440# -----------------------------------------------------------------------------
441sub _oid_load_sub
442{
443    my ($mib,$oid) = @_;
444
445    unless ( defined($mib) and defined($oid) ){
446        Carp::carp("Undefined MIB name or OID is given");
447        return;
448    }
449    unless ( $mib =~ /^[a-zA-Z][\w\-]*(\.[a-zA-Z][\w\-])*$/ ){
450        Carp::carp("Unrecognized MIB name, $mib, is given");
451        return;
452    }
453    unless ( $oid =~ /^\.?\d+(\.\d+)*$/ ){
454        Carp::carp("Unrecognized OID, $oid, is given");
455        return;
456    }
457    (my $soid = $oid) =~ s/^\.?1\.3\.6\.1\./_/;
458
459    $_OIDs{$mib}  = $oid;
460    $_MIBs{$soid} = $mib;
461}
462
463sub oid_load
464{
465    my @args = @_;
466    while ( $#args >= 0 )
467    {
468        my $mib = shift @args;
469        if ( ref($mib) eq 'HASH' ){
470            while ( my ($m, $o) = each %{$mib} ){
471                _oid_load_sub( $m => $o );
472            }
473            next;
474        }
475        my $oid = shift @args;
476        _oid_load_sub( $mib => $oid );
477    }
478}
479
480
481# =============================================================================
482
483=head2 oid
484
485    oid( $mib_name, ... )
486
487Function C<oid()> takes MIB names and returns OIDs of them.
488If OID is not found, given MIB name uses as returing value.
489
490This function treats sub OID of a part of given MIB name as well as sample
491below;
492
493    print oid("ifName.100");  # shows 1.3.6.1.2.1.31.1.1.1.1.100
494
495=cut
496
497# -----------------------------------------------------------------------------
498sub _check_cache
499{
500    my $str = shift;
501    my $grp = List::Util::first { $_->[0] eq $str } @_Cache;
502    if ( $grp ){
503        @_Cache = ( $grp, (grep { $_->[0] ne $str } @_Cache) );
504        return $grp->[1];
505    }
506    return undef;
507}
508
509sub _unshift_cache
510{
511    my ($mib,$oid) = @_;
512    unshift @_Cache, [ $mib, $oid ];
513    if ( @_Cache > $_CacheNum ){
514        pop @_Cache;
515    }
516}
517
518sub _oid_sub
519{
520    my $mib = shift || return '';
521
522    my $oid = _check_cache($mib);
523    unless ( defined $oid ){
524
525        $oid = $_OIDs{$mib};
526        unless ( defined $oid ){
527            # not found
528            return $mib;
529        }
530
531        _unshift_cache($mib, $oid); # cache refresh
532    }
533
534    return $oid;
535}
536
537sub oid
538{
539    my @ret = map {
540        my @t = ();
541        foreach my $s ( split(/\./) ){
542            $s = _oid_sub($s) if ( $s =~ /\D/ );
543            push @t, $s;
544        }
545        join('.',@t);
546    } @_;
547    return wantarray? @ret: $ret[0];
548}
549
550
551# =============================================================================
552
553=head2 oidt
554
555    oidt( $mib_oid, ... )
556
557Function C<oidt()> translates OID to MIB name.
558This returns null string C<''> if it can't find specified OID.
559
560=cut
561
562# -----------------------------------------------------------------------------
563sub oidt
564{
565
566    my @ret = ();
567    foreach my $oid ( @_ ){
568        (my $s = $oid) =~ s/^\.?1\.3\.6\.1\./_/;
569        my $mib = $_MIBs{$s} || $_MIBs{$oid};
570        unless ( defined $mib ){
571                push @ret, '';
572                next;
573        }
574        push @ret, $mib;
575    }
576    return wantarray? @ret: $ret[0];
577}
578
579
580# =============================================================================
581
582=head2 oidp
583
584    ($mib_name, $oid) = oidp( $mib_name )
585
586Function C<oidp()> takes a MIB name and returns array contains itself and it's
587OID search by C<oid()>.
588
589=cut
590
591
592# -----------------------------------------------------------------------------
593sub oidp
594{
595    my $mib = shift;
596    return ($mib, oid($mib));
597}
598
599
600=head1 AUTHOR
601
602t.onodera, C<< <cpan :: garakuta.net> >>
603
604=head1 SEE ALSO
605
606L<Net::SNMP::Util>, L<Net::SNMP::Util::TC>
607
608=head1 LICENSE AND COPYRIGHT
609
610Copyright(C) 2010 Takahiro Ondoera.
611
612This program is free software; you may redistribute it and/or modify it under
613the same terms as the Perl 5 programming language system itself.
614
615=cut
616
6171; # End of Net::SNMP::Util::OID