line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# ============================================================================= |
2
|
|
|
|
|
|
|
package Net::SNMP::Util; |
3
|
|
|
|
|
|
|
# ----------------------------------------------------------------------------- |
4
|
|
|
|
|
|
|
$Net::SNMP::Util::VERSION = '1.04'; |
5
|
|
|
|
|
|
|
# ----------------------------------------------------------------------------- |
6
|
6
|
|
|
6
|
|
656091
|
use strict; |
|
6
|
|
|
|
|
17
|
|
|
6
|
|
|
|
|
280
|
|
7
|
6
|
|
|
6
|
|
39
|
use warnings; |
|
6
|
|
|
|
|
12
|
|
|
6
|
|
|
|
|
242
|
|
8
|
|
|
|
|
|
|
|
9
|
6
|
|
|
6
|
|
36
|
use constant DEBUG => 0; |
|
6
|
|
|
|
|
16
|
|
|
6
|
|
|
|
|
1697
|
|
10
|
|
|
|
|
|
|
do { require Data::Dumper; import Data::Dumper; } if DEBUG; |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
=head1 NAME |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
Net::SNMP::Util - Utility functions for Net::SNMP |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
=head1 SYNOPSIS |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
@hosts = qw( host1 host2 host3 ); |
20
|
|
|
|
|
|
|
%oids = ( |
21
|
|
|
|
|
|
|
'ifType' => '1.3.6.1.2.1.2.2.1.3', |
22
|
|
|
|
|
|
|
'ifXData => [ '1.3.6.1.2.1.31.1.1.1.1', # ifName |
23
|
|
|
|
|
|
|
'1.3.6.1.2.1.31.1.1.1.15' ], # ifHighSpeed |
24
|
|
|
|
|
|
|
'someMib' => '1.3.6.1.4.1.99999.12.3' |
25
|
|
|
|
|
|
|
); |
26
|
|
|
|
|
|
|
%snmpparams = ( |
27
|
|
|
|
|
|
|
-version => 2, |
28
|
|
|
|
|
|
|
-community => "comname" |
29
|
|
|
|
|
|
|
); |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
# Blocking Function |
32
|
|
|
|
|
|
|
use Net::SNMP::Util; |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
($result,$error) = snmpawlk( |
35
|
|
|
|
|
|
|
hosts => \@hosts, |
36
|
|
|
|
|
|
|
oids => \%oids, |
37
|
|
|
|
|
|
|
snmp => \%snmpparams |
38
|
|
|
|
|
|
|
); |
39
|
|
|
|
|
|
|
die "[ERROR] $error\n" unless defined $result; |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
# Non-blocking One |
42
|
|
|
|
|
|
|
use Net::SNMP::Util qw(:para); |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
($result,$error) = snmpparawalk( |
45
|
|
|
|
|
|
|
hosts => \@hosts, |
46
|
|
|
|
|
|
|
oids => \%oids, |
47
|
|
|
|
|
|
|
snmp => \%snmpparams |
48
|
|
|
|
|
|
|
); |
49
|
|
|
|
|
|
|
die "[ERROR] $error\n" unless defined $result; |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
# output result sample |
52
|
|
|
|
|
|
|
foreach $host ( @hosts ){ |
53
|
|
|
|
|
|
|
foreach $index ( sort keys %{$result->{$host}{ifType}} ){ |
54
|
|
|
|
|
|
|
printf "$host - $index - type:%d - %s (%d kbps)\n", |
55
|
|
|
|
|
|
|
$result->{$host}{ifType}{$index}, |
56
|
|
|
|
|
|
|
$result->{$host}{ifXData}[0]{$index}, # ifName |
57
|
|
|
|
|
|
|
$result->{$host}{ifXData}[1]{$index}; # ifHighSpeed |
58
|
|
|
|
|
|
|
} |
59
|
|
|
|
|
|
|
} |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
=head1 DESCRIPTION |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
This module, C, gives you functions of SNMP getting operation |
65
|
|
|
|
|
|
|
interfaces using L communicating with B and B. |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
=head1 OVERVIEW |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
Functions of C are grouped by type whether using B |
71
|
|
|
|
|
|
|
or B. |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
=head2 Blocking Functions |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
Blocking functions, C, C and C, are exported |
77
|
|
|
|
|
|
|
by defalut. These functions use C blocking object and exchange SNMP |
78
|
|
|
|
|
|
|
messages serially. |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
=head2 Non-blocking Functions |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
Using tag C<":para"> or C<":parallel">, Non-Blocking functions which use |
84
|
|
|
|
|
|
|
C B are exported. These functions can exchange |
85
|
|
|
|
|
|
|
SNMP messages to multiple hosts and treat response MIB values in order of |
86
|
|
|
|
|
|
|
message receiving while the loop. These functions will apparently behave in |
87
|
|
|
|
|
|
|
parallel, so they have "para" in its own names. |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
=head2 Arguments |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
The way of passing arguments is unified whether function is Non-blocking or |
93
|
|
|
|
|
|
|
Blocking. |
94
|
|
|
|
|
|
|
Basically pass arguments with name and following value like hash pair below; |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
$r = snmpwalk( hosts => $hostsval, |
97
|
|
|
|
|
|
|
oids => $oidval, |
98
|
|
|
|
|
|
|
snmp => $snmpval ); |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
Mostly original C functions' arguments are able to be passed. |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
$r = snmpparabulk( |
103
|
|
|
|
|
|
|
hosts => $hostsval, oids => $oidval, snmp => $snmpval |
104
|
|
|
|
|
|
|
-maxrepetitions => 20, |
105
|
|
|
|
|
|
|
-delay => 2, |
106
|
|
|
|
|
|
|
); |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
But some original parameter, C<-callback>, C<-nonrepeaters> and C<-varbindlist> |
109
|
|
|
|
|
|
|
are not supported by reason of a algorithm. |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
=head3 Argument "hosts" |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
By argument C<"hosts">, specify hosts to communicate. This takes a hash or |
115
|
|
|
|
|
|
|
array reference or hostname. |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
When only hash reference using, it is possible to use prepared C |
118
|
|
|
|
|
|
|
object like below; |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
# Using hash reference with prepared Net::SNMP object |
121
|
|
|
|
|
|
|
$session1 = Net::SNMP->session( -hostname=>"www.freshes.org", ... ); |
122
|
|
|
|
|
|
|
$session2 = Net::SNMP->session( -hostname=>"192.168.10.8", ... ); |
123
|
|
|
|
|
|
|
$r = snmpwalk( hosts => { |
124
|
|
|
|
|
|
|
"peach" => $session1, |
125
|
|
|
|
|
|
|
"berry" => $session2 |
126
|
|
|
|
|
|
|
}, ... |
127
|
|
|
|
|
|
|
); |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
In this way, keys of hash are not specifying target hosts but just used to |
130
|
|
|
|
|
|
|
classfy result. |
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
Except such way of using prepered object like above, a temporary C |
133
|
|
|
|
|
|
|
session object will be made, used and deleted internally and automaticaly. See |
134
|
|
|
|
|
|
|
the way below, this example will make temporary session with hash parameters of |
135
|
|
|
|
|
|
|
Csession()>; |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
# Using hash reference with parameters |
138
|
|
|
|
|
|
|
$r = snmpwalk( hosts => { |
139
|
|
|
|
|
|
|
"pine" => { |
140
|
|
|
|
|
|
|
-hostname => "192.168.10.9", |
141
|
|
|
|
|
|
|
}, |
142
|
|
|
|
|
|
|
"passion" => { |
143
|
|
|
|
|
|
|
-hostname => "exchanger.local", |
144
|
|
|
|
|
|
|
-port => 10161, |
145
|
|
|
|
|
|
|
} |
146
|
|
|
|
|
|
|
}, ... |
147
|
|
|
|
|
|
|
); |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
More hash argument C<"snmp"> are given, it will be used as common parameters |
150
|
|
|
|
|
|
|
for each temporary session making. This argument C<"snmp"> hash is not only |
151
|
|
|
|
|
|
|
for hash but also for specifying by array rererence or hostname string. |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
# hash "snmp" using examples |
154
|
|
|
|
|
|
|
$r = snmpwalk( hosts => { |
155
|
|
|
|
|
|
|
"peach" => { -hostname => "www.freshes.org" }, |
156
|
|
|
|
|
|
|
"berry" => { -hostname => "192.168.10.8" }, |
157
|
|
|
|
|
|
|
"pine" => { -hostname => "192.168.20.8", }, |
158
|
|
|
|
|
|
|
"passion" => { -hostname => "exchanger.local", |
159
|
|
|
|
|
|
|
-port => 10161, }, |
160
|
|
|
|
|
|
|
}, |
161
|
|
|
|
|
|
|
snmp => { -community => "4leaf-clover", |
162
|
|
|
|
|
|
|
-timeout => 10, |
163
|
|
|
|
|
|
|
-retries => 2, |
164
|
|
|
|
|
|
|
}, ... |
165
|
|
|
|
|
|
|
); |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
# Using array reference or string |
168
|
|
|
|
|
|
|
$r5 = snmpwalk( hosts => [ "dream","rouge","lemonade","mint","aqua" ], |
169
|
|
|
|
|
|
|
snmp => { -version => 1, |
170
|
|
|
|
|
|
|
-community => "yes5", |
171
|
|
|
|
|
|
|
}, ... |
172
|
|
|
|
|
|
|
); |
173
|
|
|
|
|
|
|
$r6 = snmpwalk( hosts => "milkyrose", |
174
|
|
|
|
|
|
|
snmp => { -version => 2, |
175
|
|
|
|
|
|
|
-community => "yes5gogo", |
176
|
|
|
|
|
|
|
}, ... |
177
|
|
|
|
|
|
|
); |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
Note that values of arguments C<"host"> in array reference case or hostname |
180
|
|
|
|
|
|
|
string are used as values of C<-hostname> parameters for C, and |
181
|
|
|
|
|
|
|
at the same, time used as classfying key of result. |
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
=head3 Arguments "oids" |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
Specify OIDs to investigate by hash reference argument named C<"oids">. Keys |
187
|
|
|
|
|
|
|
of this hash will be used as just classfying of result. Values must be an |
188
|
|
|
|
|
|
|
array reference listing OIDs, or singular OID string. And this hash allows |
189
|
|
|
|
|
|
|
that these two types are mixed into it. |
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
$r = snmpwalk( hosts => \@hosts, |
192
|
|
|
|
|
|
|
oids => { |
193
|
|
|
|
|
|
|
"system" => "1.3.6.1.2.1.1", |
194
|
|
|
|
|
|
|
"ifInfo" => [ "1.3.6.1.2.1.2.2.1.3", # ifType |
195
|
|
|
|
|
|
|
"1.3.6.1.2.1.31.1.1.1.1", ] # ifName |
196
|
|
|
|
|
|
|
}, ... |
197
|
|
|
|
|
|
|
); |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
Each value of this C<"oids"> hash will make one B. So singular |
200
|
|
|
|
|
|
|
OID value makes Var Bindings contains one OID, and multiple OID specified by |
201
|
|
|
|
|
|
|
array reference makes one contains several OIDs. |
202
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
It is allowed to specify arguments C<"oids"> as array reference. In this case, |
204
|
|
|
|
|
|
|
result content will not be classfied by keys of OID name but keys of |
205
|
|
|
|
|
|
|
suboids. See section of "Return Values" below. |
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
=head3 Argument "snmp" |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
If argument C<"hosts"> is specified, hash argument C<"snmp"> will mean common |
211
|
|
|
|
|
|
|
parameters to Csession()> mentioned above. |
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
Well, it is possible to omit parameter C<"host">. In this case, value of |
214
|
|
|
|
|
|
|
C<"snmp"> will be used to specify the target. Same as argument "hosts", |
215
|
|
|
|
|
|
|
giving prepared C session object is allowed. |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
# Prepared session |
218
|
|
|
|
|
|
|
$session = Net::SNMP->session( -hostname => "blossom", ... ); |
219
|
|
|
|
|
|
|
$r = snmpwalk( snmp => $session, |
220
|
|
|
|
|
|
|
oids => \%oids, |
221
|
|
|
|
|
|
|
... |
222
|
|
|
|
|
|
|
); |
223
|
|
|
|
|
|
|
# Temporary session |
224
|
|
|
|
|
|
|
$r = snmpwalk( snmp => { -hostname => "marine", |
225
|
|
|
|
|
|
|
-community => "heartcatchers", |
226
|
|
|
|
|
|
|
}, |
227
|
|
|
|
|
|
|
oids => \%oids, |
228
|
|
|
|
|
|
|
... |
229
|
|
|
|
|
|
|
); |
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
=head3 Forbiddings |
233
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
These case below causes an error; |
235
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
=over |
237
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
=item * |
239
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
Argument C<"snmp"> with prepared C object and C<"hosts"> are |
241
|
|
|
|
|
|
|
specified at the same time. |
242
|
|
|
|
|
|
|
Chomp C<"hosts"> or let parameter C<"snmp"> a hash reference. |
243
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
# NG |
245
|
|
|
|
|
|
|
$session = Net::SNMP->session( ... ); |
246
|
|
|
|
|
|
|
$r = snmpwalk( hosts => \%something, |
247
|
|
|
|
|
|
|
snmp => $session, |
248
|
|
|
|
|
|
|
); |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
=item * |
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
Non-blocking prepared C object are given as C<"hosts"> or C<"snmp"> |
253
|
|
|
|
|
|
|
value to Blocking functions. |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
=item * |
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
Blocking prepared C object are given as C<"hosts"> or C<"snmp"> |
258
|
|
|
|
|
|
|
value to Non-blocking functions. |
259
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
=back |
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
=head2 Return Values |
264
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
=head3 Errors |
266
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
In list context, a hash reference result value and errors string will be |
268
|
|
|
|
|
|
|
returned. In scalar, only result value will be returned. In both case, critical |
269
|
|
|
|
|
|
|
errors will make result value B and make errors string. |
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
If several hosts checking and some errors occured while communicating, each |
272
|
|
|
|
|
|
|
error messages will be chained to errors string. For checking errors by host |
273
|
|
|
|
|
|
|
individually or in scalar context, use functions C. This function |
274
|
|
|
|
|
|
|
will return a hash reference which contains error messages for each hosts. |
275
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
=head3 Gained MIB Values |
277
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
In success, gained MIB value will be packed into a hash and its reference will |
279
|
|
|
|
|
|
|
be returned. |
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
For example, case of C and C operations; |
282
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
snmpget( oids => { sysContact => "1.3.6.1.2.1.1.4.0", |
284
|
|
|
|
|
|
|
sysInfo => [ "1.3.6.1.2.1.1.5.0", # sysName |
285
|
|
|
|
|
|
|
"1.3.6.1.2.1.1.6.0" ], # sysLocation |
286
|
|
|
|
|
|
|
}, ... |
287
|
|
|
|
|
|
|
); |
288
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
yeilds; |
290
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
{ |
292
|
|
|
|
|
|
|
sysContact => "Cure Flower ", |
293
|
|
|
|
|
|
|
sysInfo => [ "palace", "some place, some world" ], |
294
|
|
|
|
|
|
|
} |
295
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
Other functions, value will be a more hash which contains pairs of key as |
297
|
|
|
|
|
|
|
sub OID and its values. |
298
|
|
|
|
|
|
|
For example; |
299
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
snmpwalk( oids => { "system" => "1.3.6.1.2.1.1", |
301
|
|
|
|
|
|
|
"ifInfo" => [ "1.3.6.1.2.1.2.2.1.3", # ifType |
302
|
|
|
|
|
|
|
"1.3.6.1.2.1.31.1.1.1.1", ] # ifName |
303
|
|
|
|
|
|
|
}, ... |
304
|
|
|
|
|
|
|
); |
305
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
yeilds; |
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
{ |
309
|
|
|
|
|
|
|
"system" => { |
310
|
|
|
|
|
|
|
"1.0" => "Testing system the fighters are strong enough", |
311
|
|
|
|
|
|
|
"2.0" => "1.3.6.1.4.1.99999.1", |
312
|
|
|
|
|
|
|
... , |
313
|
|
|
|
|
|
|
}, |
314
|
|
|
|
|
|
|
"ifInfo" => [ |
315
|
|
|
|
|
|
|
{ |
316
|
|
|
|
|
|
|
"1" => 62, # 1.3.6.1.2.1.2.2.1.3.1 |
317
|
|
|
|
|
|
|
"10101" => 62, # 1.3.6.1.2.1.2.2.1.3.10101 |
318
|
|
|
|
|
|
|
... |
319
|
|
|
|
|
|
|
}, |
320
|
|
|
|
|
|
|
{ |
321
|
|
|
|
|
|
|
"1" => "mgmt", # 1.3.6.1.2.1.31.1.1.1.1.1 |
322
|
|
|
|
|
|
|
"10101" => "1/1", # 1.3.6.1.2.1.31.1.1.1.1.10101 |
323
|
|
|
|
|
|
|
... |
324
|
|
|
|
|
|
|
} |
325
|
|
|
|
|
|
|
] |
326
|
|
|
|
|
|
|
} |
327
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
As stated above, when OIDs are specified in an array, values also will be |
329
|
|
|
|
|
|
|
contained in an array. |
330
|
|
|
|
|
|
|
|
331
|
|
|
|
|
|
|
If parameter C<"snmp"> decides target host without C<"hosts">, result data |
332
|
|
|
|
|
|
|
will be the same as above examples yields. If not so, parameter C<"hosts"> |
333
|
|
|
|
|
|
|
is specified, result data of each host will be contained to parentally |
334
|
|
|
|
|
|
|
hash which key will be identified by hostname. |
335
|
|
|
|
|
|
|
For example; |
336
|
|
|
|
|
|
|
|
337
|
|
|
|
|
|
|
$r1 = snmpget( |
338
|
|
|
|
|
|
|
hosts => [ "bloom", "eaglet" ], |
339
|
|
|
|
|
|
|
oids => { |
340
|
|
|
|
|
|
|
system => [ "1.3.6.1.2.1.1.1.0", "1.3.6.1.2.1.1.3.0" ], |
341
|
|
|
|
|
|
|
}, ... |
342
|
|
|
|
|
|
|
); |
343
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
$r2 = snmpwalk( |
345
|
|
|
|
|
|
|
hosts => { |
346
|
|
|
|
|
|
|
"kaoru" => { -hostname => '192.168.11.10', ... }, |
347
|
|
|
|
|
|
|
"michiru" => { -hostname => '192.168.12.10', ... }, |
348
|
|
|
|
|
|
|
}, |
349
|
|
|
|
|
|
|
oids => { "system" => "1.3.6.1.2.1.1", |
350
|
|
|
|
|
|
|
"ifInfo" => [ "1.3.6.1.2.1.2.2.1.3", # ifType |
351
|
|
|
|
|
|
|
"1.3.6.1.2.1.31.1.1.1.1", ] # ifName |
352
|
|
|
|
|
|
|
}, ... |
353
|
|
|
|
|
|
|
); |
354
|
|
|
|
|
|
|
|
355
|
|
|
|
|
|
|
returns hashref; |
356
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
# $r1 |
358
|
|
|
|
|
|
|
{ |
359
|
|
|
|
|
|
|
"bloom" => { # hostname |
360
|
|
|
|
|
|
|
"system" => [ ...VALUES... ] |
361
|
|
|
|
|
|
|
}, |
362
|
|
|
|
|
|
|
"eaglet" => { # hostname |
363
|
|
|
|
|
|
|
"system" => [ ...VALUES... ] |
364
|
|
|
|
|
|
|
} |
365
|
|
|
|
|
|
|
} |
366
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
# $r2 |
368
|
|
|
|
|
|
|
{ |
369
|
|
|
|
|
|
|
"system" => { |
370
|
|
|
|
|
|
|
"1.0" => "...", "2.0" => "...", ... |
371
|
|
|
|
|
|
|
}, |
372
|
|
|
|
|
|
|
"ifInfo" => [ |
373
|
|
|
|
|
|
|
{ |
374
|
|
|
|
|
|
|
"1" => 62, # 1.3.6.1.2.1.2.2.1.3.1 |
375
|
|
|
|
|
|
|
"10101" => 62, # 1.3.6.1.2.1.2.2.1.3.10101 |
376
|
|
|
|
|
|
|
... |
377
|
|
|
|
|
|
|
}, |
378
|
|
|
|
|
|
|
{ |
379
|
|
|
|
|
|
|
"1" => "mgmt", # 1.3.6.1.2.1.31.1.1.1.1.1 |
380
|
|
|
|
|
|
|
"10101" => "1/1", # 1.3.6.1.2.1.31.1.1.1.1.10101 |
381
|
|
|
|
|
|
|
... |
382
|
|
|
|
|
|
|
} |
383
|
|
|
|
|
|
|
] |
384
|
|
|
|
|
|
|
} |
385
|
|
|
|
|
|
|
|
386
|
|
|
|
|
|
|
If OIDs specifying by C<"oids"> are not a hash but an array reference, values |
387
|
|
|
|
|
|
|
of gained data will be not hash but array. |
388
|
|
|
|
|
|
|
For example, |
389
|
|
|
|
|
|
|
|
390
|
|
|
|
|
|
|
snmpget( oids => [ "1.3.6.1.2.1.1.5.0", # sysName |
391
|
|
|
|
|
|
|
"1.3.6.1.2.1.1.6.0" ], # sysLocation |
392
|
|
|
|
|
|
|
}, ... |
393
|
|
|
|
|
|
|
); |
394
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
yeilds; |
396
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
[ "takocafe", # string of sysName |
398
|
|
|
|
|
|
|
"Wakabadai-park, Tokyo" ], # string of sysLocation |
399
|
|
|
|
|
|
|
|
400
|
|
|
|
|
|
|
|
401
|
|
|
|
|
|
|
=head2 Callback function |
402
|
|
|
|
|
|
|
|
403
|
|
|
|
|
|
|
Apart from original C<-callback> option of functions of C, |
404
|
|
|
|
|
|
|
functions of C provides another callback logic, by specifying |
405
|
|
|
|
|
|
|
common option, C<-mycallback>. This option is possible to be used whether |
406
|
|
|
|
|
|
|
Non-blocking or Blocking. |
407
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
This callback function will be called when each MIB value recieving with |
409
|
|
|
|
|
|
|
passing arguments; session object, host name, key name and reference to array |
410
|
|
|
|
|
|
|
of values. |
411
|
|
|
|
|
|
|
|
412
|
|
|
|
|
|
|
For example, C and C operations, array contains |
413
|
|
|
|
|
|
|
values which order is same as a member of parameter C<"oids"> specifys. |
414
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
snmpget( |
416
|
|
|
|
|
|
|
hosts => \%hosts, |
417
|
|
|
|
|
|
|
oids => { someMIB1 => $oid1, |
418
|
|
|
|
|
|
|
someMIB2 => [ $oid2, $oid3, $oid4 ] |
419
|
|
|
|
|
|
|
}, |
420
|
|
|
|
|
|
|
-mycallback => sub { |
421
|
|
|
|
|
|
|
($session, $host, $key, $valref) = @_; |
422
|
|
|
|
|
|
|
# $valref will be; |
423
|
|
|
|
|
|
|
# [ $val1 ] when $key is "someMIB1" |
424
|
|
|
|
|
|
|
# or |
425
|
|
|
|
|
|
|
# [ $val2, $val3, $val4 ] when $key is "someMIB2" |
426
|
|
|
|
|
|
|
} |
427
|
|
|
|
|
|
|
); |
428
|
|
|
|
|
|
|
|
429
|
|
|
|
|
|
|
Other functions, passing array reference will contain more array references |
430
|
|
|
|
|
|
|
which will have two value, sub OID and value. Values ordering rule is, same |
431
|
|
|
|
|
|
|
as above, a member of parameter C<"oids"> specifys. |
432
|
|
|
|
|
|
|
|
433
|
|
|
|
|
|
|
snmpwalk( |
434
|
|
|
|
|
|
|
hosts => \%hosts, |
435
|
|
|
|
|
|
|
oids => { someMIB1 => $oid1, |
436
|
|
|
|
|
|
|
someMIB2 => [ $oid2, $oid3, $oid4 ] |
437
|
|
|
|
|
|
|
}, |
438
|
|
|
|
|
|
|
-mycallback => sub { |
439
|
|
|
|
|
|
|
($session, $host, $key, $valref) = @_; |
440
|
|
|
|
|
|
|
# $valref will be; |
441
|
|
|
|
|
|
|
# [ [ $suboid1, $val1 ] ] when $key is "someMIB1" |
442
|
|
|
|
|
|
|
# or |
443
|
|
|
|
|
|
|
# [ [ $suboid2,$val2 ], [ $suboid3,$val3 ], [ $suboid4,$val4 ] ] |
444
|
|
|
|
|
|
|
# when $key is "someMIB2" |
445
|
|
|
|
|
|
|
} |
446
|
|
|
|
|
|
|
); |
447
|
|
|
|
|
|
|
|
448
|
|
|
|
|
|
|
|
449
|
|
|
|
|
|
|
=cut |
450
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
# ============================================================================= |
452
|
|
|
|
|
|
|
|
453
|
6
|
|
|
6
|
|
43
|
use Carp qw(); |
|
6
|
|
|
|
|
13
|
|
|
6
|
|
|
|
|
120
|
|
454
|
6
|
|
|
6
|
|
37
|
use Scalar::Util qw(); |
|
6
|
|
|
|
|
14
|
|
|
6
|
|
|
|
|
108
|
|
455
|
6
|
|
|
6
|
|
1466
|
use Net::SNMP; |
|
6
|
|
|
|
|
90342
|
|
|
6
|
|
|
|
|
996
|
|
456
|
|
|
|
|
|
|
|
457
|
6
|
|
|
6
|
|
48
|
use base qw( Exporter ); |
|
6
|
|
|
|
|
11
|
|
|
6
|
|
|
|
|
36327
|
|
458
|
|
|
|
|
|
|
our (@EXPORT, @EXPORT_OK, %EXPORT_TAGS, $VERSION); |
459
|
|
|
|
|
|
|
@EXPORT = qw( get_errstr get_errhash snmpget snmpwalk snmpbulk snmpbulk ); |
460
|
|
|
|
|
|
|
@EXPORT_OK = (); |
461
|
|
|
|
|
|
|
%EXPORT_TAGS = ( |
462
|
|
|
|
|
|
|
para => [ @EXPORT, |
463
|
|
|
|
|
|
|
qw( snmpparaget snmpparawalk snmpparabulk snmpparabulkwalk ) ], |
464
|
|
|
|
|
|
|
); |
465
|
|
|
|
|
|
|
Exporter::export_ok_tags( qw(para) ); |
466
|
|
|
|
|
|
|
$EXPORT_TAGS{all} = [ @EXPORT, @EXPORT_OK ]; |
467
|
|
|
|
|
|
|
$EXPORT_TAGS{parallel} = $EXPORT_TAGS{para}; |
468
|
|
|
|
|
|
|
|
469
|
|
|
|
|
|
|
my $_error; |
470
|
|
|
|
|
|
|
my $_errhash; |
471
|
|
|
|
|
|
|
|
472
|
|
|
|
|
|
|
|
473
|
|
|
|
|
|
|
# ============================================================================ |
474
|
|
|
|
|
|
|
# private object methods |
475
|
|
|
|
|
|
|
# ============================================================================ |
476
|
|
|
|
|
|
|
sub _getmanager |
477
|
|
|
|
|
|
|
{ |
478
|
96
|
|
|
96
|
|
124
|
my $class = shift; |
479
|
96
|
|
|
|
|
188
|
my ($command, $session, $table, $error, $host, $key, $boids, $mycb) = @_; |
480
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
# check OIDs are array and init storing value |
482
|
96
|
|
|
|
|
136
|
my @baseoids = (); |
483
|
96
|
|
|
|
|
140
|
my $vbtype = ref($boids); |
484
|
96
|
100
|
|
|
|
256
|
if ( $vbtype eq 'ARRAY' ){ |
485
|
48
|
|
|
|
|
159
|
$table->{$host}{$key} = []; |
486
|
48
|
|
|
|
|
82
|
push @baseoids, @{$boids}; |
|
48
|
|
|
|
|
132
|
|
487
|
|
|
|
|
|
|
} else { |
488
|
48
|
|
|
|
|
137
|
$table->{$host}{$key} = {}; |
489
|
48
|
|
|
|
|
99
|
push @baseoids, $boids; |
490
|
|
|
|
|
|
|
} |
491
|
|
|
|
|
|
|
|
492
|
96
|
|
|
|
|
1366
|
my $self = { |
493
|
|
|
|
|
|
|
command => $command, # get, get_next or get_bulk |
494
|
|
|
|
|
|
|
session => $session, # Net::SNMP session object |
495
|
|
|
|
|
|
|
table => $table, # Storing table |
496
|
|
|
|
|
|
|
error => $error, # hashref to storage of error |
497
|
|
|
|
|
|
|
host => $host, # hostname |
498
|
|
|
|
|
|
|
key => $key, # given keyname by oids |
499
|
|
|
|
|
|
|
baseoids => \@baseoids, # baseoid of requested |
500
|
|
|
|
|
|
|
curoids => [@baseoids],# current digging OID |
501
|
|
|
|
|
|
|
mycb => $mycb, # my callback |
502
|
|
|
|
|
|
|
isMulOid => $vbtype # given oid is plural or not |
503
|
|
|
|
|
|
|
}; |
504
|
96
|
|
|
|
|
397
|
Scalar::Util::weaken($self->{session}); # Avoid for circular references |
505
|
96
|
|
|
|
|
401
|
bless $self, $class; |
506
|
|
|
|
|
|
|
} |
507
|
|
|
|
|
|
|
|
508
|
|
|
|
|
|
|
# get current grabing oids to investigate |
509
|
|
|
|
|
|
|
sub _get_oids |
510
|
|
|
|
|
|
|
{ |
511
|
508
|
|
|
508
|
|
607
|
grep { defined $_ } @{$_[0]->{curoids}}; |
|
764
|
|
|
|
|
2646
|
|
|
508
|
|
|
|
|
978
|
|
512
|
|
|
|
|
|
|
} |
513
|
|
|
|
|
|
|
|
514
|
|
|
|
|
|
|
# stringify |
515
|
|
|
|
|
|
|
sub _stringify |
516
|
|
|
|
|
|
|
{ |
517
|
1
|
|
|
1
|
|
2
|
my $self = shift; |
518
|
1
|
|
|
|
|
5
|
sprintf("%s::%s::%s", |
519
|
|
|
|
|
|
|
$self->{host}, $self->{key}, join('-',$self->_get_oids()) |
520
|
|
|
|
|
|
|
); |
521
|
|
|
|
|
|
|
} |
522
|
|
|
|
|
|
|
|
523
|
|
|
|
|
|
|
# memorize error message |
524
|
|
|
|
|
|
|
sub _memo_error |
525
|
|
|
|
|
|
|
{ |
526
|
1
|
|
|
1
|
|
3
|
my ($self, $flag) = @_; |
527
|
1
|
|
|
|
|
3
|
my ($host, $key) = ($self->{host}, $self->{key}); |
528
|
1
|
50
|
|
|
|
9
|
$self->{error}{$host}{$key} = sprintf( '%s%s %s', |
529
|
|
|
|
|
|
|
defined($flag)? "($flag)": '', |
530
|
|
|
|
|
|
|
$self->_stringify(), |
531
|
|
|
|
|
|
|
$self->{session}->error() |
532
|
|
|
|
|
|
|
); |
533
|
|
|
|
|
|
|
} |
534
|
|
|
|
|
|
|
|
535
|
|
|
|
|
|
|
#return Net::SNMP getting operation function |
536
|
|
|
|
|
|
|
sub _exec_operation |
537
|
|
|
|
|
|
|
{ |
538
|
352
|
|
|
352
|
|
427
|
my $self = shift; |
539
|
352
|
|
|
|
|
489
|
my $com = $self->{command}; |
540
|
|
|
|
|
|
|
|
541
|
352
|
|
|
|
|
307
|
printf "[DEBUG] %s) execute %s\n", $com, $self->_stringify() if DEBUG; |
542
|
|
|
|
|
|
|
|
543
|
|
|
|
|
|
|
return |
544
|
352
|
50
|
|
|
|
1676
|
( $com eq 'get' )? $self->{session}->get_request(@_): |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
545
|
|
|
|
|
|
|
( $com eq 'get_next' )? $self->{session}->get_next_request(@_): |
546
|
|
|
|
|
|
|
( $com eq 'get_bulk' )? $self->{session}->get_bulk_request(@_): |
547
|
|
|
|
|
|
|
undef; |
548
|
|
|
|
|
|
|
} |
549
|
|
|
|
|
|
|
|
550
|
|
|
|
|
|
|
# kicker of varBindList treator |
551
|
|
|
|
|
|
|
sub _treat_varbindings |
552
|
|
|
|
|
|
|
{ |
553
|
351
|
|
|
351
|
|
448
|
my $self = shift; |
554
|
351
|
|
|
|
|
590
|
my $com = $self->{command}; |
555
|
|
|
|
|
|
|
|
556
|
351
|
|
|
|
|
331
|
printf "[DEBUG] %s) checking %s\n", $com, $self->_stringify() if DEBUG; |
557
|
|
|
|
|
|
|
|
558
|
|
|
|
|
|
|
return |
559
|
351
|
50
|
|
|
|
1270
|
( $com eq 'get' )? $self->_treat_get_varbindings(): |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
560
|
|
|
|
|
|
|
( $com eq 'get_next' )? $self->_treat_getnext_varbindings(): |
561
|
|
|
|
|
|
|
( $com eq 'get_bulk' )? $self->_treat_getbulk_varbindings(): |
562
|
|
|
|
|
|
|
undef; |
563
|
|
|
|
|
|
|
} |
564
|
|
|
|
|
|
|
|
565
|
|
|
|
|
|
|
|
566
|
|
|
|
|
|
|
# treating varBindList yeilded by GetRequest |
567
|
|
|
|
|
|
|
sub _treat_get_varbindings |
568
|
|
|
|
|
|
|
{ |
569
|
28
|
|
|
28
|
|
35
|
my $self = shift; |
570
|
28
|
|
|
|
|
42
|
my ($session, $host, $key) = map { $self->{$_} } qw(session host key); |
|
84
|
|
|
|
|
212
|
|
571
|
|
|
|
|
|
|
|
572
|
|
|
|
|
|
|
# get varBindList and names |
573
|
28
|
|
|
|
|
93
|
my $vlist = $session->var_bind_list(); |
574
|
28
|
50
|
|
|
|
273
|
return undef unless defined $vlist; # error |
575
|
28
|
50
|
|
|
|
27
|
return 0 unless %{$vlist}; # if result is empty |
|
28
|
|
|
|
|
78
|
|
576
|
|
|
|
|
|
|
|
577
|
28
|
|
|
|
|
81
|
my @ret = map { $vlist->{$_} } $session->var_bind_names(); |
|
42
|
|
|
|
|
352
|
|
578
|
|
|
|
|
|
|
|
579
|
|
|
|
|
|
|
# kick my callback |
580
|
28
|
50
|
|
|
|
84
|
if ( defined $self->{mycb} ){ |
581
|
0
|
|
|
|
|
0
|
my $r = $self->{mycb}->( $session, $host, $key, \@ret); |
582
|
0
|
0
|
|
|
|
0
|
return 0 unless $r; # avoiding to store |
583
|
|
|
|
|
|
|
} |
584
|
|
|
|
|
|
|
|
585
|
|
|
|
|
|
|
# store data |
586
|
28
|
100
|
|
|
|
56
|
if ( $self->{isMulOid} ){ |
587
|
14
|
|
|
|
|
17
|
push @{$self->{table}{$host}{$key}}, @ret; |
|
14
|
|
|
|
|
41
|
|
588
|
|
|
|
|
|
|
} else { |
589
|
14
|
|
|
|
|
39
|
$self->{table}{$host}{$key} = $ret[0]; |
590
|
|
|
|
|
|
|
} |
591
|
28
|
|
|
|
|
236
|
return 0; |
592
|
|
|
|
|
|
|
} |
593
|
|
|
|
|
|
|
|
594
|
|
|
|
|
|
|
|
595
|
|
|
|
|
|
|
# treating varBindList yeilded by GetNextRequest |
596
|
|
|
|
|
|
|
sub _treat_getnext_varbindings |
597
|
|
|
|
|
|
|
{ |
598
|
168
|
|
|
168
|
|
164
|
my $self = shift; |
599
|
168
|
|
|
|
|
199
|
my ($session, $host, $key) = map { $self->{$_} } qw(session host key); |
|
504
|
|
|
|
|
848
|
|
600
|
|
|
|
|
|
|
|
601
|
168
|
|
|
|
|
179
|
printf "[DEBUG] %s) parsing %s\n", "get_next", $self->_stringify() if DEBUG; |
602
|
|
|
|
|
|
|
|
603
|
|
|
|
|
|
|
# get varBindList and names |
604
|
168
|
|
|
|
|
369
|
my $vlist = $session->var_bind_list(); |
605
|
|
|
|
|
|
|
|
606
|
|
|
|
|
|
|
# printf "[DEBUG] %s) vlist:%s\n", "get_next", Dumper($vlist) if DEBUG; |
607
|
|
|
|
|
|
|
|
608
|
168
|
50
|
|
|
|
1477
|
return undef unless defined $vlist; # error |
609
|
168
|
50
|
|
|
|
159
|
return 0 unless %{$vlist}; # if result is empty |
|
168
|
|
|
|
|
313
|
|
610
|
|
|
|
|
|
|
|
611
|
168
|
|
|
|
|
374
|
my @names = $session->var_bind_names(); |
612
|
168
|
|
|
|
|
1640
|
my $types = $session->var_bind_types(); |
613
|
|
|
|
|
|
|
|
614
|
|
|
|
|
|
|
# check out of the branch of each oid in varBindList |
615
|
168
|
|
|
|
|
1094
|
my @ret = (); |
616
|
168
|
|
|
|
|
161
|
my $num = @{$self->{baseoids}}; |
|
168
|
|
|
|
|
241
|
|
617
|
168
|
|
|
|
|
166
|
my $c = 0; |
618
|
168
|
|
|
|
|
324
|
for ( my $i=0; $i<$num; $i++ ) |
619
|
|
|
|
|
|
|
{ |
620
|
252
|
50
|
|
|
|
480
|
next unless defined $self->{curoids}[$i]; |
621
|
|
|
|
|
|
|
|
622
|
252
|
|
|
|
|
304
|
my $baseoid = $self->{baseoids}[$i]; |
623
|
252
|
|
|
|
|
263
|
my $name = shift @names; |
624
|
252
|
|
|
|
|
320
|
my $type = $types->{$name}; |
625
|
|
|
|
|
|
|
|
626
|
252
|
100
|
66
|
|
|
3524
|
if ( $name !~ /^\.?\Q$baseoid.\E(.+)$/ || |
627
|
|
|
|
|
|
|
$type == ENDOFMIBVIEW |
628
|
|
|
|
|
|
|
){ |
629
|
|
|
|
|
|
|
# the leaf is not-exists or out of branch |
630
|
42
|
|
|
|
|
50
|
$ret[$i] = undef; |
631
|
42
|
|
|
|
|
146
|
$self->{curoids}[$i] = undef; |
632
|
|
|
|
|
|
|
} |
633
|
|
|
|
|
|
|
else { |
634
|
|
|
|
|
|
|
# the leaf is within the branch |
635
|
210
|
|
|
|
|
1367
|
$ret[$i] = [ $1, $vlist->{$name} ]; |
636
|
210
|
|
|
|
|
374
|
$self->{curoids}[$i] = $name; |
637
|
210
|
|
|
|
|
687
|
$c++; |
638
|
|
|
|
|
|
|
} |
639
|
|
|
|
|
|
|
} |
640
|
168
|
100
|
|
|
|
467
|
return 0 if !$c; # all necessary oids are checked |
641
|
|
|
|
|
|
|
|
642
|
|
|
|
|
|
|
# kick my callback |
643
|
140
|
50
|
|
|
|
252
|
if ( defined $self->{mycb} ){ |
644
|
0
|
|
|
|
|
0
|
my $r = $self->{mycb}->( $session, $host, $key, \@ret); |
645
|
0
|
0
|
|
|
|
0
|
return 0 unless defined $r; # to stop operate |
646
|
0
|
0
|
|
|
|
0
|
return 1 unless $r; # to avoid to store |
647
|
|
|
|
|
|
|
} |
648
|
|
|
|
|
|
|
|
649
|
|
|
|
|
|
|
# store data |
650
|
140
|
100
|
|
|
|
207
|
if ( $self->{isMulOid} ){ |
651
|
70
|
|
|
|
|
146
|
for ( my $i=0; $i<$num; $i++ ){ |
652
|
140
|
50
|
|
|
|
232
|
next unless defined $ret[$i]; |
653
|
140
|
50
|
|
|
|
101
|
next unless @{$ret[$i]}; |
|
140
|
|
|
|
|
245
|
|
654
|
140
|
|
|
|
|
138
|
my ($suboid, $val) = @{$ret[$i]}; |
|
140
|
|
|
|
|
208
|
|
655
|
140
|
|
|
|
|
499
|
$self->{table}{$host}{$key}->[$i]{$suboid} = $val; |
656
|
|
|
|
|
|
|
} |
657
|
|
|
|
|
|
|
} else { |
658
|
70
|
|
|
|
|
64
|
my ($suboid, $val) = @{$ret[0]}; |
|
70
|
|
|
|
|
109
|
|
659
|
70
|
|
|
|
|
194
|
$self->{table}{$host}{$key}->{$suboid} = $val; |
660
|
|
|
|
|
|
|
} |
661
|
|
|
|
|
|
|
|
662
|
140
|
|
|
|
|
562
|
return 1; # return valid number for next investigation |
663
|
|
|
|
|
|
|
} |
664
|
|
|
|
|
|
|
|
665
|
|
|
|
|
|
|
|
666
|
|
|
|
|
|
|
# treating varBindList yeilded by GetBulkRequest |
667
|
|
|
|
|
|
|
sub _treat_getbulk_varbindings |
668
|
|
|
|
|
|
|
{ |
669
|
155
|
|
|
155
|
|
204
|
my $self = shift; |
670
|
155
|
|
|
|
|
226
|
my ($session, $host, $key) = map { $self->{$_} } qw(session host key); |
|
465
|
|
|
|
|
1001
|
|
671
|
|
|
|
|
|
|
|
672
|
|
|
|
|
|
|
# get varBindList and names |
673
|
155
|
|
|
|
|
637
|
my $vlist = $session->var_bind_list(); |
674
|
|
|
|
|
|
|
|
675
|
155
|
50
|
|
|
|
1668
|
return undef unless defined $vlist; # error |
676
|
155
|
50
|
|
|
|
156
|
return 0 unless %{$vlist}; # if result is empty |
|
155
|
|
|
|
|
477
|
|
677
|
|
|
|
|
|
|
|
678
|
155
|
|
|
|
|
434
|
my @names = $session->var_bind_names(); |
679
|
155
|
|
|
|
|
2175
|
my $types = $session->var_bind_types(); |
680
|
|
|
|
|
|
|
|
681
|
|
|
|
|
|
|
# check out of the branch of each oid in varBindList |
682
|
155
|
|
|
|
|
1372
|
my @ret = (); |
683
|
155
|
|
|
|
|
180
|
my $num0= @{$self->{baseoids}}; |
|
155
|
|
|
|
|
249
|
|
684
|
155
|
|
|
|
|
169
|
my $num = @{[$self->_get_oids()]}; |
|
155
|
|
|
|
|
293
|
|
685
|
|
|
|
|
|
|
|
686
|
155
|
|
|
|
|
253
|
my $c; |
687
|
155
|
|
|
|
|
348
|
while ( @names ){ |
688
|
417
|
|
|
|
|
1142
|
my @n = splice(@names,0,$num); |
689
|
417
|
|
|
|
|
1206
|
for ( my $i=0,$c=0; $i<$num0; $i++ ) |
690
|
|
|
|
|
|
|
{ |
691
|
626
|
100
|
|
|
|
1533
|
next unless defined $self->{curoids}[$i]; |
692
|
|
|
|
|
|
|
|
693
|
599
|
|
|
|
|
956
|
my $baseoid = $self->{baseoids}[$i]; |
694
|
599
|
|
|
|
|
732
|
my $name = shift @n; |
695
|
599
|
|
|
|
|
1114
|
my $type = $types->{$name}; |
696
|
|
|
|
|
|
|
|
697
|
599
|
100
|
100
|
|
|
10001
|
if ( $name !~ /^\.?\Q$baseoid.\E(.+)$/ || |
698
|
|
|
|
|
|
|
$type == ENDOFMIBVIEW |
699
|
|
|
|
|
|
|
){ |
700
|
|
|
|
|
|
|
# the leaf is not-exists or out of branch |
701
|
88
|
|
|
|
|
2068
|
$self->{curoids}[$i] = 0; |
702
|
|
|
|
|
|
|
} |
703
|
|
|
|
|
|
|
else { |
704
|
|
|
|
|
|
|
# the leaf is within the branch |
705
|
511
|
|
|
|
|
2455
|
push @{$ret[$i]}, [ $1, $vlist->{$name} ]; |
|
511
|
|
|
|
|
2435
|
|
706
|
511
|
|
|
|
|
1342
|
$self->{curoids}[$i] = $name; |
707
|
511
|
|
|
|
|
1829
|
$c++; |
708
|
|
|
|
|
|
|
} |
709
|
|
|
|
|
|
|
} |
710
|
417
|
100
|
|
|
|
1400
|
last if !$c; # no more check |
711
|
|
|
|
|
|
|
} |
712
|
155
|
|
|
|
|
395
|
for ( my $i=0; $i<$num0; $i++ ){ |
713
|
233
|
|
100
|
|
|
1016
|
$self->{curoids}[$i] ||= undef; |
714
|
|
|
|
|
|
|
} |
715
|
|
|
|
|
|
|
|
716
|
|
|
|
|
|
|
# kick my callback |
717
|
155
|
50
|
|
|
|
623
|
if ( defined $self->{mycb} ){ |
718
|
0
|
|
|
|
|
0
|
my $r = $self->{mycb}->( $session, $host, $key, \@ret); |
719
|
0
|
0
|
|
|
|
0
|
return 0 unless defined $r; # to stop operate |
720
|
0
|
0
|
|
|
|
0
|
return 1 unless $r; # to avoid to store |
721
|
|
|
|
|
|
|
} |
722
|
|
|
|
|
|
|
|
723
|
|
|
|
|
|
|
# store data |
724
|
155
|
100
|
|
|
|
283
|
if ( $self->{isMulOid} ){ |
725
|
78
|
|
|
|
|
203
|
for ( my $i=0; $i<$num0; $i++ ){ |
726
|
156
|
|
|
|
|
160
|
foreach my $leaf ( @{$ret[$i]} ){ |
|
156
|
|
|
|
|
378
|
|
727
|
323
|
50
|
|
|
|
625
|
next unless defined $leaf; |
728
|
323
|
|
|
|
|
319
|
my ($suboid, $val) = @{$leaf}; |
|
323
|
|
|
|
|
537
|
|
729
|
323
|
|
|
|
|
1482
|
$self->{table}{$host}{$key}->[$i]{$suboid} = $val; |
730
|
|
|
|
|
|
|
} |
731
|
|
|
|
|
|
|
} |
732
|
|
|
|
|
|
|
} else { |
733
|
77
|
|
|
|
|
86
|
foreach my $leaf ( @{$ret[0]} ){ |
|
77
|
|
|
|
|
181
|
|
734
|
188
|
50
|
|
|
|
355
|
next unless defined $leaf; |
735
|
188
|
|
|
|
|
276
|
my ($suboid, $val) = @{$leaf}; |
|
188
|
|
|
|
|
300
|
|
736
|
188
|
|
|
|
|
667
|
$self->{table}{$host}{$key}->{$suboid} = $val; |
737
|
|
|
|
|
|
|
} |
738
|
|
|
|
|
|
|
} |
739
|
|
|
|
|
|
|
|
740
|
155
|
|
|
|
|
1234
|
return $c; # return valid number for next investigation |
741
|
|
|
|
|
|
|
} |
742
|
|
|
|
|
|
|
|
743
|
|
|
|
|
|
|
# ============================================================================= |
744
|
|
|
|
|
|
|
|
745
|
|
|
|
|
|
|
sub _parse_params |
746
|
|
|
|
|
|
|
{ |
747
|
50
|
50
|
|
50
|
|
191
|
if ( @_ & 1 ){ |
748
|
0
|
|
|
|
|
0
|
Carp::carp("Odd number of arguments."); |
749
|
0
|
|
|
|
|
0
|
return (undef, "Odd number of arguments."); |
750
|
|
|
|
|
|
|
} |
751
|
50
|
|
|
|
|
263
|
my %p = @_; |
752
|
50
|
|
|
|
|
95
|
my %sessions = (); |
753
|
50
|
|
|
|
|
91
|
my (%istmp,$oids,$mycb) = (); |
754
|
50
|
|
|
|
|
73
|
my $arghosts = 1; |
755
|
|
|
|
|
|
|
|
756
|
50
|
|
|
|
|
60
|
my $nonblocking = 0; |
757
|
50
|
50
|
|
|
|
145
|
if ( defined $p{nonblocking} ){ |
758
|
50
|
|
|
|
|
103
|
$nonblocking = delete $p{nonblocking}; |
759
|
|
|
|
|
|
|
} |
760
|
|
|
|
|
|
|
|
761
|
|
|
|
|
|
|
# --- checking "snmp" --- |
762
|
50
|
|
|
|
|
69
|
my $snmphash = undef; |
763
|
50
|
|
|
|
|
55
|
my $snmpobj = undef; |
764
|
50
|
|
|
|
|
76
|
my %errhash = (); |
765
|
|
|
|
|
|
|
|
766
|
50
|
100
|
|
|
|
152
|
if ( defined $p{snmp} ){ |
767
|
29
|
|
|
|
|
67
|
my $type = ref($p{snmp}); |
768
|
29
|
100
|
|
|
|
84
|
if ( $type eq 'HASH' ){ |
|
|
50
|
|
|
|
|
|
769
|
25
|
|
|
|
|
57
|
$snmphash = delete $p{snmp}; |
770
|
|
|
|
|
|
|
} |
771
|
|
|
|
|
|
|
elsif ( $type eq 'Net::SNMP' ){ |
772
|
4
|
|
|
|
|
38
|
$snmpobj = delete $p{snmp}; |
773
|
|
|
|
|
|
|
} |
774
|
|
|
|
|
|
|
else { |
775
|
0
|
|
|
|
|
0
|
return (undef, q(Parameter "snmp" must be a hash reference or Net::SNMP object.)); |
776
|
|
|
|
|
|
|
} |
777
|
|
|
|
|
|
|
} |
778
|
|
|
|
|
|
|
|
779
|
|
|
|
|
|
|
# --- parsing "hosts" --- |
780
|
50
|
100
|
|
|
|
120
|
if ( defined $p{hosts} ) |
781
|
|
|
|
|
|
|
{ |
782
|
37
|
100
|
|
|
|
84
|
if ( defined $snmpobj ){ |
783
|
2
|
|
|
|
|
11
|
return ( undef, q(In case specifying parameters both "hosts" and "snmp", ). |
784
|
|
|
|
|
|
|
q("snmp" must be not Net::SNMP object but a hash reference.) ); |
785
|
|
|
|
|
|
|
} |
786
|
|
|
|
|
|
|
|
787
|
35
|
|
|
|
|
73
|
my $type = ref($p{hosts}); |
788
|
|
|
|
|
|
|
|
789
|
|
|
|
|
|
|
# hosts => \%hashref; |
790
|
35
|
100
|
|
|
|
127
|
if ( $type eq 'HASH' ){ |
|
|
100
|
|
|
|
|
|
791
|
|
|
|
|
|
|
# regard key as hostname and value as Net::SNMP object or parameter |
792
|
15
|
|
|
|
|
25
|
while ( my ($host, $value) = each %{$p{hosts}} ) |
|
50
|
|
|
|
|
206
|
|
793
|
|
|
|
|
|
|
{ |
794
|
37
|
|
|
|
|
91
|
$type = ref($value); |
795
|
|
|
|
|
|
|
|
796
|
|
|
|
|
|
|
# treat value as Net::SNMP object |
797
|
37
|
100
|
|
|
|
120
|
if ( $type eq 'Net::SNMP' ){ |
|
|
100
|
|
|
|
|
|
798
|
13
|
100
|
66
|
|
|
53
|
if ( $nonblocking && !$value->nonblocking() ){ |
799
|
1
|
|
|
|
|
12
|
$errhash{$host} = "About $host, blocking Net::SNMP object ". |
800
|
|
|
|
|
|
|
"was specified to call non-blocking function."; |
801
|
1
|
|
|
|
|
3
|
next; |
802
|
|
|
|
|
|
|
} |
803
|
12
|
100
|
66
|
|
|
101
|
if ( !$nonblocking && $value->nonblocking() ){ |
804
|
1
|
|
|
|
|
13
|
$errhash{$host} = "About $host, non-blocking Net::SNMP object ". |
805
|
|
|
|
|
|
|
"was specified to call blocking function."; |
806
|
1
|
|
|
|
|
3
|
next; |
807
|
|
|
|
|
|
|
} |
808
|
11
|
|
|
|
|
92
|
$sessions{$host} = $value; |
809
|
|
|
|
|
|
|
} |
810
|
|
|
|
|
|
|
|
811
|
|
|
|
|
|
|
# if hashref, make temporary sessions. |
812
|
|
|
|
|
|
|
elsif ( $type eq 'HASH' ){ |
813
|
11
|
|
|
|
|
61
|
my ($s, $e) = Net::SNMP->session( |
814
|
11
|
|
|
|
|
71
|
%{$snmphash}, |
815
|
|
|
|
|
|
|
-nonblocking => $nonblocking, |
816
|
|
|
|
|
|
|
-hostname => $host, |
817
|
11
|
|
|
|
|
20
|
%{$value} |
818
|
|
|
|
|
|
|
); |
819
|
11
|
50
|
|
|
|
12591
|
unless ( defined($s) ){ |
820
|
0
|
|
|
|
|
0
|
$errhash{$host} = "$host, session making error: $e"; |
821
|
0
|
|
|
|
|
0
|
next; |
822
|
|
|
|
|
|
|
} |
823
|
11
|
|
|
|
|
29
|
$sessions{$host} = $s; |
824
|
11
|
|
|
|
|
35
|
$istmp{$host} = 1; |
825
|
|
|
|
|
|
|
} |
826
|
|
|
|
|
|
|
|
827
|
|
|
|
|
|
|
# othre cases cause error. |
828
|
|
|
|
|
|
|
else { |
829
|
|
|
|
|
|
|
# othre reference without string will be an error |
830
|
13
|
100
|
66
|
|
|
88
|
if ( !$type && defined($value) ){ |
831
|
11
|
|
|
|
|
76
|
my ($s, $e) = Net::SNMP->session( |
832
|
11
|
|
|
|
|
19
|
%{$snmphash}, |
833
|
|
|
|
|
|
|
-nonblocking => $nonblocking, |
834
|
|
|
|
|
|
|
-hostname => $value, |
835
|
|
|
|
|
|
|
); |
836
|
11
|
50
|
|
|
|
3937
|
unless ( defined($s) ){ |
837
|
0
|
|
|
|
|
0
|
$errhash{$host} = "$host, session making error: $e"; |
838
|
0
|
|
|
|
|
0
|
next; |
839
|
|
|
|
|
|
|
} |
840
|
11
|
|
|
|
|
22
|
$sessions{$host} = $s; |
841
|
11
|
|
|
|
|
35
|
$istmp{$host} = 1; |
842
|
|
|
|
|
|
|
} else { |
843
|
2
|
|
|
|
|
14
|
return (undef, qq(Value of "$host" must be a string,). |
844
|
|
|
|
|
|
|
qq( an array reference or a hash reference)); |
845
|
|
|
|
|
|
|
} |
846
|
|
|
|
|
|
|
} |
847
|
|
|
|
|
|
|
} |
848
|
|
|
|
|
|
|
} |
849
|
|
|
|
|
|
|
|
850
|
|
|
|
|
|
|
# hosts => \@arrayref; |
851
|
|
|
|
|
|
|
elsif ( $type eq 'ARRAY' ){ |
852
|
|
|
|
|
|
|
# regard it as hostname list |
853
|
9
|
|
|
|
|
13
|
foreach my $host ( @{$p{hosts}} ){ |
|
9
|
|
|
|
|
28
|
|
854
|
18
|
|
|
|
|
119
|
my ($s, $e) = Net::SNMP->session( |
855
|
18
|
|
|
|
|
29
|
%{$snmphash}, |
856
|
|
|
|
|
|
|
-nonblocking => $nonblocking, |
857
|
|
|
|
|
|
|
-hostname => $host, |
858
|
|
|
|
|
|
|
); |
859
|
18
|
50
|
|
|
|
8107
|
unless ( defined($s) ){ |
860
|
0
|
|
|
|
|
0
|
$errhash{$host} = "$host, session making error: $e"; |
861
|
0
|
|
|
|
|
0
|
next; |
862
|
|
|
|
|
|
|
} |
863
|
18
|
|
|
|
|
43
|
$sessions{$host} = $s; |
864
|
18
|
|
|
|
|
54
|
$istmp{$host} = 1; |
865
|
|
|
|
|
|
|
} |
866
|
|
|
|
|
|
|
|
867
|
|
|
|
|
|
|
} else { |
868
|
|
|
|
|
|
|
# othre reference will be an error |
869
|
11
|
100
|
|
|
|
35
|
if ( $type ){ |
870
|
2
|
|
|
|
|
10
|
return (undef, q(Parameter "hosts" must be a string, an array reference or a hash reference)); |
871
|
|
|
|
|
|
|
} |
872
|
|
|
|
|
|
|
|
873
|
|
|
|
|
|
|
# but string is ok. it will be regards as hostname. |
874
|
|
|
|
|
|
|
else { |
875
|
9
|
|
|
|
|
17
|
my $host = $p{hosts}; |
876
|
9
|
|
|
|
|
69
|
my ($s, $e) = Net::SNMP->session( |
877
|
9
|
|
|
|
|
57
|
%{$snmphash}, |
878
|
|
|
|
|
|
|
-nonblocking => $nonblocking, |
879
|
|
|
|
|
|
|
-hostname => $host, |
880
|
|
|
|
|
|
|
); |
881
|
9
|
50
|
|
|
|
4401
|
unless ( defined($s) ){ |
882
|
0
|
|
|
|
|
0
|
$errhash{$host} = "$host, session making error: $e"; |
883
|
|
|
|
|
|
|
} else { |
884
|
9
|
|
|
|
|
26
|
$sessions{$host} = $s; |
885
|
9
|
|
|
|
|
24
|
$istmp{$host} = 1; |
886
|
|
|
|
|
|
|
} |
887
|
|
|
|
|
|
|
} |
888
|
|
|
|
|
|
|
} |
889
|
31
|
|
|
|
|
99
|
delete $p{hosts}; |
890
|
|
|
|
|
|
|
|
891
|
|
|
|
|
|
|
# Erase "snmp" parameter (hashref). |
892
|
|
|
|
|
|
|
# this is no longer need. |
893
|
31
|
|
|
|
|
52
|
$snmphash = undef; |
894
|
|
|
|
|
|
|
} |
895
|
|
|
|
|
|
|
else { |
896
|
13
|
|
|
|
|
25
|
$arghosts = 0; |
897
|
|
|
|
|
|
|
} |
898
|
|
|
|
|
|
|
|
899
|
|
|
|
|
|
|
# --- parsing "snmp" --- |
900
|
|
|
|
|
|
|
# This parsing will be invoked when parameter "host" isn't specified. |
901
|
44
|
100
|
|
|
|
131
|
if ( defined $snmpobj ){ |
902
|
|
|
|
|
|
|
# Net::SNMP object is given, use it as it is. |
903
|
2
|
100
|
66
|
|
|
18
|
if ( $nonblocking && !$snmpobj->nonblocking() ){ |
904
|
1
|
|
|
|
|
10
|
return (undef, "Blocking Net::SNMP object was specified to call non-blocking function."); |
905
|
|
|
|
|
|
|
} |
906
|
1
|
50
|
33
|
|
|
7
|
if ( !$nonblocking && $snmpobj->nonblocking() ){ |
907
|
1
|
|
|
|
|
9
|
return (undef, "Non-Blocking Net::SNMP object was specified to call blocking function."); |
908
|
|
|
|
|
|
|
} |
909
|
0
|
|
|
|
|
0
|
$sessions{$snmpobj->hostname()} = $snmpobj; |
910
|
|
|
|
|
|
|
} |
911
|
42
|
100
|
|
|
|
91
|
if ( defined $snmphash ){ |
912
|
|
|
|
|
|
|
# Hash reference is given, use it as parameter for making temp session |
913
|
9
|
|
|
|
|
64
|
my ($s, $e) = Net::SNMP->session( |
914
|
9
|
|
|
|
|
15
|
%{$snmphash}, |
915
|
|
|
|
|
|
|
-nonblocking => $nonblocking |
916
|
|
|
|
|
|
|
); |
917
|
9
|
50
|
|
|
|
4678
|
return (undef, "Making session error; $e") unless defined $s; |
918
|
|
|
|
|
|
|
|
919
|
9
|
|
|
|
|
39
|
$sessions{$s->hostname()} = $s; |
920
|
9
|
|
|
|
|
52
|
$istmp{$s->hostname()} = 1; |
921
|
|
|
|
|
|
|
} |
922
|
|
|
|
|
|
|
|
923
|
|
|
|
|
|
|
# --- parsing "oids" --- |
924
|
42
|
100
|
|
|
|
152
|
if ( exists($p{oids}) ){ |
925
|
40
|
|
|
|
|
94
|
my $type = ref($p{oids}); |
926
|
40
|
100
|
|
|
|
105
|
if ( $type eq 'HASH' ) { |
927
|
14
|
|
|
|
|
26
|
$oids = $p{oids}; |
928
|
|
|
|
|
|
|
} |
929
|
|
|
|
|
|
|
else { |
930
|
26
|
|
|
|
|
96
|
$oids = { |
931
|
|
|
|
|
|
|
'_ANONY_' => $p{oids} |
932
|
|
|
|
|
|
|
}; |
933
|
|
|
|
|
|
|
} |
934
|
|
|
|
|
|
|
# Check type of each oid |
935
|
40
|
|
|
|
|
64
|
foreach my $oid ( values %{$oids} ){ |
|
40
|
|
|
|
|
122
|
|
936
|
54
|
50
|
|
|
|
124
|
unless ( defined $oid ){ |
937
|
0
|
|
|
|
|
0
|
return (undef, "Undefined value specified as OID"); |
938
|
|
|
|
|
|
|
} |
939
|
54
|
|
|
|
|
73
|
$type = ref($oid); |
940
|
54
|
50
|
66
|
|
|
270
|
if ( $type && $type ne 'ARRAY' ){ |
941
|
0
|
|
|
|
|
0
|
return (undef, "Each OID values must be an array reference or string"); |
942
|
|
|
|
|
|
|
} |
943
|
|
|
|
|
|
|
} |
944
|
40
|
|
|
|
|
242
|
delete $p{oids}; |
945
|
|
|
|
|
|
|
} |
946
|
42
|
100
|
|
|
|
119
|
unless ( defined $oids ){ |
947
|
2
|
|
|
|
|
10
|
return (undef, q(Parameter "oids" is not given)); |
948
|
|
|
|
|
|
|
} |
949
|
|
|
|
|
|
|
|
950
|
|
|
|
|
|
|
# --- parsing "-mycallback" --- |
951
|
40
|
|
|
|
|
76
|
foreach ( qw( mycallback -mycallback ) ){ |
952
|
80
|
50
|
|
|
|
219
|
if ( defined($p{$_}) ){ |
953
|
0
|
|
|
|
|
0
|
$mycb = delete $p{$_}; |
954
|
0
|
0
|
|
|
|
0
|
unless ( ref($mycb) eq 'CODE' ){ |
955
|
0
|
|
|
|
|
0
|
Carp::carp("Non code given as -mycallback, ignored."); |
956
|
0
|
|
|
|
|
0
|
$mycb = undef; |
957
|
|
|
|
|
|
|
} |
958
|
|
|
|
|
|
|
} |
959
|
|
|
|
|
|
|
} |
960
|
40
|
|
|
|
|
80
|
foreach ( qw( callback -callback ) ){ |
961
|
80
|
50
|
|
|
|
198
|
if ( defined($p{$_}) ){ |
962
|
0
|
|
|
|
|
0
|
Carp::carp("option $_ is ignored."); |
963
|
0
|
|
|
|
|
0
|
delete $p{$_}; |
964
|
|
|
|
|
|
|
} |
965
|
|
|
|
|
|
|
} |
966
|
|
|
|
|
|
|
|
967
|
|
|
|
|
|
|
# --- parsing end --- |
968
|
40
|
|
|
|
|
182
|
return (\%sessions,\%errhash,\%istmp,$oids,\%p,$mycb,$arghosts); |
969
|
|
|
|
|
|
|
|
970
|
|
|
|
|
|
|
} |
971
|
|
|
|
|
|
|
|
972
|
|
|
|
|
|
|
|
973
|
|
|
|
|
|
|
# ============================================================================= |
974
|
|
|
|
|
|
|
|
975
|
|
|
|
|
|
|
=head1 BLOCKING FUNCTIONS |
976
|
|
|
|
|
|
|
|
977
|
|
|
|
|
|
|
C exports bloking functions defalut. |
978
|
|
|
|
|
|
|
|
979
|
|
|
|
|
|
|
=cut |
980
|
|
|
|
|
|
|
|
981
|
|
|
|
|
|
|
# ----------------------------------------------------------------------------- |
982
|
|
|
|
|
|
|
sub _snmpkick |
983
|
|
|
|
|
|
|
{ |
984
|
44
|
|
|
44
|
|
79
|
my $command = shift; |
985
|
|
|
|
|
|
|
|
986
|
44
|
|
|
|
|
121
|
_clear_error(); |
987
|
44
|
|
|
|
|
168
|
my ($sessions,$error,$istmp,$oids,$opts,$mycb,$arghosts) = _parse_params( |
988
|
|
|
|
|
|
|
@_, |
989
|
|
|
|
|
|
|
nonblocking => 0 |
990
|
|
|
|
|
|
|
); |
991
|
44
|
100
|
|
|
|
119
|
return _retresults(undef, $error) unless defined $sessions; |
992
|
|
|
|
|
|
|
|
993
|
39
|
|
|
|
|
58
|
my $table = {}; |
994
|
39
|
|
|
|
|
129
|
while ( my ($host,$session) = each %{$sessions} ) |
|
108
|
|
|
|
|
395
|
|
995
|
|
|
|
|
|
|
{ |
996
|
69
|
|
|
|
|
79
|
foreach my $key ( keys %{$oids} ){ |
|
69
|
|
|
|
|
152
|
|
997
|
|
|
|
|
|
|
|
998
|
96
|
|
|
|
|
158
|
my $oid = $oids->{$key}; |
999
|
|
|
|
|
|
|
# memo: dont use "while...(each %{$oids})" here. |
1000
|
|
|
|
|
|
|
# because when $result is undef by error, not-resetted |
1001
|
|
|
|
|
|
|
# iterating counter of %{$oids} will be used at next |
1002
|
|
|
|
|
|
|
# $host's loop... |
1003
|
96
|
|
|
|
|
336
|
my $manager = __PACKAGE__->_getmanager( |
1004
|
|
|
|
|
|
|
$command, $session, $table, $error, $host, $key, $oid, $mycb |
1005
|
|
|
|
|
|
|
); |
1006
|
|
|
|
|
|
|
|
1007
|
96
|
|
|
|
|
122
|
my $result; |
1008
|
96
|
|
|
|
|
105
|
do { |
1009
|
352
|
|
|
|
|
1190
|
$result = $manager->_exec_operation( |
1010
|
352
|
|
|
|
|
399
|
%{$opts}, |
1011
|
|
|
|
|
|
|
-varbindlist => [ $manager->_get_oids() ], |
1012
|
|
|
|
|
|
|
); |
1013
|
352
|
100
|
|
|
|
308755
|
unless ( defined $result ){ |
1014
|
1
|
|
|
|
|
6
|
$manager->_memo_error(); |
1015
|
|
|
|
|
|
|
# if some error occuer, terminate process of |
1016
|
|
|
|
|
|
|
# error host and delete data at Blocking Mode |
1017
|
1
|
|
|
|
|
14
|
delete $table->{$host}; |
1018
|
1
|
|
|
|
|
8
|
last; |
1019
|
|
|
|
|
|
|
} |
1020
|
|
|
|
|
|
|
} while ( $manager->_treat_varbindings() ); |
1021
|
|
|
|
|
|
|
} |
1022
|
|
|
|
|
|
|
} |
1023
|
|
|
|
|
|
|
|
1024
|
|
|
|
|
|
|
# closing temporary session and finishing |
1025
|
39
|
|
|
|
|
61
|
while ( my ($host,$session) = each %{$sessions} ){ |
|
108
|
|
|
|
|
353
|
|
1026
|
69
|
100
|
|
|
|
179
|
if ( $istmp->{$host} ){ |
1027
|
58
|
|
|
|
|
208
|
$session->close(); |
1028
|
58
|
|
|
|
|
2035
|
undef $session; |
1029
|
|
|
|
|
|
|
} |
1030
|
|
|
|
|
|
|
} |
1031
|
|
|
|
|
|
|
|
1032
|
39
|
|
|
|
|
139
|
return _retresults($table, $error, $arghosts); |
1033
|
|
|
|
|
|
|
} |
1034
|
|
|
|
|
|
|
|
1035
|
|
|
|
|
|
|
|
1036
|
|
|
|
|
|
|
# ============================================================================= |
1037
|
|
|
|
|
|
|
|
1038
|
|
|
|
|
|
|
=head2 snmpget() |
1039
|
|
|
|
|
|
|
|
1040
|
|
|
|
|
|
|
C is a Blocking function which gather MIB values with SNMP |
1041
|
|
|
|
|
|
|
GetRequest operation via Cget_request()>. |
1042
|
|
|
|
|
|
|
|
1043
|
|
|
|
|
|
|
=cut |
1044
|
|
|
|
|
|
|
|
1045
|
|
|
|
|
|
|
# ----------------------------------------------------------------------------- |
1046
|
|
|
|
|
|
|
sub snmpget |
1047
|
|
|
|
|
|
|
{ |
1048
|
18
|
|
|
18
|
1
|
157352
|
_snmpkick('get', @_); |
1049
|
|
|
|
|
|
|
} |
1050
|
|
|
|
|
|
|
|
1051
|
|
|
|
|
|
|
|
1052
|
|
|
|
|
|
|
# ============================================================================= |
1053
|
|
|
|
|
|
|
|
1054
|
|
|
|
|
|
|
=head2 snmpwalk() |
1055
|
|
|
|
|
|
|
|
1056
|
|
|
|
|
|
|
C is a Blocking function which gather MIB values with SNMP |
1057
|
|
|
|
|
|
|
GetNextRequest operation via Cget_next_request()>. |
1058
|
|
|
|
|
|
|
|
1059
|
|
|
|
|
|
|
=cut |
1060
|
|
|
|
|
|
|
|
1061
|
|
|
|
|
|
|
# ----------------------------------------------------------------------------- |
1062
|
|
|
|
|
|
|
sub snmpwalk |
1063
|
|
|
|
|
|
|
{ |
1064
|
12
|
|
|
12
|
1
|
35931
|
_snmpkick('get_next', @_); |
1065
|
|
|
|
|
|
|
} |
1066
|
|
|
|
|
|
|
|
1067
|
|
|
|
|
|
|
|
1068
|
|
|
|
|
|
|
# ============================================================================= |
1069
|
|
|
|
|
|
|
|
1070
|
|
|
|
|
|
|
=head2 snmpbulk() |
1071
|
|
|
|
|
|
|
|
1072
|
|
|
|
|
|
|
C is a Blocking function which gather MIB values with SNMP |
1073
|
|
|
|
|
|
|
GetBulkRequest operation via Cget_bulk_request()>. So using |
1074
|
|
|
|
|
|
|
this function needs that target devices are acceptable for SNMP version 2c or |
1075
|
|
|
|
|
|
|
more. |
1076
|
|
|
|
|
|
|
|
1077
|
|
|
|
|
|
|
Note that C<-maxrepetitions> should be passed with some value. C |
1078
|
|
|
|
|
|
|
will set this parameter 0 by defalut. |
1079
|
|
|
|
|
|
|
Also note that reason of algorithm, -nonrepeaters is not supported. |
1080
|
|
|
|
|
|
|
|
1081
|
|
|
|
|
|
|
=head2 snmpbulkwalk() |
1082
|
|
|
|
|
|
|
|
1083
|
|
|
|
|
|
|
An alias of C. |
1084
|
|
|
|
|
|
|
|
1085
|
|
|
|
|
|
|
=cut |
1086
|
|
|
|
|
|
|
|
1087
|
|
|
|
|
|
|
# ----------------------------------------------------------------------------- |
1088
|
|
|
|
|
|
|
sub snmpbulk |
1089
|
|
|
|
|
|
|
{ |
1090
|
14
|
|
|
14
|
1
|
42253
|
_snmpkick('get_bulk', @_, -nonrepeaters=>0 ); |
1091
|
|
|
|
|
|
|
} |
1092
|
|
|
|
|
|
|
|
1093
|
0
|
|
|
0
|
1
|
0
|
sub snmpbulkwalk { snmpbulk(@_) } |
1094
|
|
|
|
|
|
|
|
1095
|
|
|
|
|
|
|
|
1096
|
|
|
|
|
|
|
# ============================================================================= |
1097
|
|
|
|
|
|
|
|
1098
|
|
|
|
|
|
|
=head1 NON-BLOCKING FUNCTIONS |
1099
|
|
|
|
|
|
|
|
1100
|
|
|
|
|
|
|
C gives some Non-blocking functions. Use these Non-blocking |
1101
|
|
|
|
|
|
|
functions, import them with ":para" tag at C |
1102
|
|
|
|
|
|
|
|
1103
|
|
|
|
|
|
|
=cut |
1104
|
|
|
|
|
|
|
|
1105
|
|
|
|
|
|
|
# ----------------------------------------------------------------------------- |
1106
|
|
|
|
|
|
|
sub _snmpparakick |
1107
|
|
|
|
|
|
|
{ |
1108
|
6
|
|
|
6
|
|
12
|
my $command = shift; |
1109
|
|
|
|
|
|
|
|
1110
|
6
|
|
|
|
|
16
|
_clear_error(); |
1111
|
6
|
|
|
|
|
19
|
my ($sessions,$error,$istmp,$oids,$opts,$mycb,$arghosts) = _parse_params( |
1112
|
|
|
|
|
|
|
@_, |
1113
|
|
|
|
|
|
|
nonblocking => 1 |
1114
|
|
|
|
|
|
|
); |
1115
|
6
|
100
|
|
|
|
26
|
return _retresults(undef, $error) unless defined $sessions; |
1116
|
|
|
|
|
|
|
|
1117
|
|
|
|
|
|
|
# define callback subroutine |
1118
|
|
|
|
|
|
|
my $callback = sub { |
1119
|
0
|
|
|
0
|
|
0
|
my $s = shift; |
1120
|
0
|
|
|
|
|
0
|
my ($this_cb, $m, $opts) = @_; |
1121
|
|
|
|
|
|
|
|
1122
|
|
|
|
|
|
|
# treat VarBindList |
1123
|
0
|
|
|
|
|
0
|
my $r = $m->_treat_varbindings(); |
1124
|
0
|
0
|
|
|
|
0
|
$m->_memo_error() unless defined $r; # undef means get some error |
1125
|
0
|
0
|
|
|
|
0
|
return unless $r; # not true value terminates |
1126
|
|
|
|
|
|
|
|
1127
|
|
|
|
|
|
|
# request again (at get_next or get_bulk) |
1128
|
0
|
|
|
|
|
0
|
$r = $m->_exec_operation( |
1129
|
0
|
|
|
|
|
0
|
%{$opts}, |
1130
|
|
|
|
|
|
|
-varbindlist => [ $m->_get_oids() ], |
1131
|
|
|
|
|
|
|
-callback => [ $this_cb, @_ ], |
1132
|
|
|
|
|
|
|
); |
1133
|
0
|
0
|
|
|
|
0
|
$m->_memo_error() unless defined $r; |
1134
|
1
|
|
|
|
|
7
|
}; |
1135
|
|
|
|
|
|
|
|
1136
|
|
|
|
|
|
|
# making first request operation |
1137
|
1
|
|
|
|
|
2
|
my $table = {}; |
1138
|
1
|
|
|
|
|
2
|
while ( my ($host,$session) = each %{$sessions} ) |
|
1
|
|
|
|
|
11
|
|
1139
|
|
|
|
|
|
|
{ |
1140
|
0
|
|
|
|
|
0
|
while ( my ($key, $oid) = each %{$oids} ) |
|
0
|
|
|
|
|
0
|
|
1141
|
|
|
|
|
|
|
{ |
1142
|
0
|
|
|
|
|
0
|
my $manager = __PACKAGE__->_getmanager( |
1143
|
|
|
|
|
|
|
$command, $session, $table, $error, $host, $key, $oid, $mycb |
1144
|
|
|
|
|
|
|
); |
1145
|
0
|
|
|
|
|
0
|
my $result = $manager->_exec_operation( |
1146
|
0
|
|
|
|
|
0
|
%{$opts}, |
1147
|
|
|
|
|
|
|
-varbindlist => [ $manager->_get_oids() ], |
1148
|
|
|
|
|
|
|
-callback => [ $callback, $callback, $manager, $opts ], |
1149
|
|
|
|
|
|
|
); |
1150
|
0
|
0
|
|
|
|
0
|
$manager->_memo_error() unless defined $result; |
1151
|
|
|
|
|
|
|
} |
1152
|
|
|
|
|
|
|
} |
1153
|
|
|
|
|
|
|
|
1154
|
|
|
|
|
|
|
# execute to communicate |
1155
|
1
|
|
|
|
|
6
|
snmp_dispatcher(); |
1156
|
|
|
|
|
|
|
|
1157
|
|
|
|
|
|
|
# closing temporary session and finishing |
1158
|
1
|
|
|
|
|
34
|
while ( my ($host,$session) = each %{$sessions} ){ |
|
1
|
|
|
|
|
5
|
|
1159
|
0
|
0
|
|
|
|
0
|
if ( $istmp->{$host} ){ |
1160
|
0
|
|
|
|
|
0
|
$session->close(); |
1161
|
0
|
|
|
|
|
0
|
undef $session; |
1162
|
|
|
|
|
|
|
} |
1163
|
|
|
|
|
|
|
} |
1164
|
|
|
|
|
|
|
|
1165
|
1
|
|
|
|
|
3
|
return _retresults($table, $error, $arghosts); |
1166
|
|
|
|
|
|
|
} |
1167
|
|
|
|
|
|
|
|
1168
|
|
|
|
|
|
|
|
1169
|
|
|
|
|
|
|
# ============================================================================= |
1170
|
|
|
|
|
|
|
|
1171
|
|
|
|
|
|
|
=head2 snmpparaget() |
1172
|
|
|
|
|
|
|
|
1173
|
|
|
|
|
|
|
C is a Non-blocking function which gather MIB values with SNMP |
1174
|
|
|
|
|
|
|
GetRequest operation via Cget_request()>. |
1175
|
|
|
|
|
|
|
|
1176
|
|
|
|
|
|
|
=cut |
1177
|
|
|
|
|
|
|
|
1178
|
|
|
|
|
|
|
# ----------------------------------------------------------------------------- |
1179
|
|
|
|
|
|
|
sub snmpparaget |
1180
|
|
|
|
|
|
|
{ |
1181
|
6
|
|
|
6
|
1
|
43900
|
_snmpparakick('get', @_); |
1182
|
|
|
|
|
|
|
} |
1183
|
|
|
|
|
|
|
|
1184
|
|
|
|
|
|
|
|
1185
|
|
|
|
|
|
|
# ============================================================================= |
1186
|
|
|
|
|
|
|
|
1187
|
|
|
|
|
|
|
=head2 snmpparawalk() |
1188
|
|
|
|
|
|
|
|
1189
|
|
|
|
|
|
|
C is a Non-blocking function which gather MIB values with SNMP |
1190
|
|
|
|
|
|
|
GetNextRequest operation via Cget_next_request()>. |
1191
|
|
|
|
|
|
|
|
1192
|
|
|
|
|
|
|
=cut |
1193
|
|
|
|
|
|
|
|
1194
|
|
|
|
|
|
|
# ----------------------------------------------------------------------------- |
1195
|
|
|
|
|
|
|
sub snmpparawalk |
1196
|
|
|
|
|
|
|
{ |
1197
|
0
|
|
|
0
|
1
|
0
|
_snmpparakick('get_next', @_); |
1198
|
|
|
|
|
|
|
} |
1199
|
|
|
|
|
|
|
|
1200
|
|
|
|
|
|
|
|
1201
|
|
|
|
|
|
|
# ============================================================================= |
1202
|
|
|
|
|
|
|
|
1203
|
|
|
|
|
|
|
=head2 snmpparabulk() |
1204
|
|
|
|
|
|
|
|
1205
|
|
|
|
|
|
|
C is a Non-blocking function which gather MIB values with SNMP |
1206
|
|
|
|
|
|
|
GetBulkRequest operation via Cget_bulk_request()>. So using |
1207
|
|
|
|
|
|
|
this function needs that target devices are acceptable for SNMP version 2c or |
1208
|
|
|
|
|
|
|
more. |
1209
|
|
|
|
|
|
|
|
1210
|
|
|
|
|
|
|
Note that C<-maxrepetitions> should be passwd with some value. C |
1211
|
|
|
|
|
|
|
will set this parameter 0 by defalut. |
1212
|
|
|
|
|
|
|
Also note that reason of algorithm, -nonrepeaters is not supported. |
1213
|
|
|
|
|
|
|
|
1214
|
|
|
|
|
|
|
=head2 snmpparabulkwalk() |
1215
|
|
|
|
|
|
|
|
1216
|
|
|
|
|
|
|
An alias of C. |
1217
|
|
|
|
|
|
|
|
1218
|
|
|
|
|
|
|
=cut |
1219
|
|
|
|
|
|
|
|
1220
|
|
|
|
|
|
|
|
1221
|
|
|
|
|
|
|
# ----------------------------------------------------------------------------- |
1222
|
|
|
|
|
|
|
sub snmpparabulk |
1223
|
|
|
|
|
|
|
{ |
1224
|
0
|
|
|
0
|
1
|
0
|
_snmpparakick('get_bulk', @_, -nonrepeaters=>0 ); |
1225
|
|
|
|
|
|
|
} |
1226
|
|
|
|
|
|
|
|
1227
|
0
|
|
|
0
|
1
|
0
|
sub snmpparabulkwalk { snmpparabulk(@_) } |
1228
|
|
|
|
|
|
|
|
1229
|
|
|
|
|
|
|
|
1230
|
|
|
|
|
|
|
# ============================================================================= |
1231
|
|
|
|
|
|
|
|
1232
|
|
|
|
|
|
|
=head1 OTHER FUNCTIONS |
1233
|
|
|
|
|
|
|
|
1234
|
|
|
|
|
|
|
=head2 get_errstr() |
1235
|
|
|
|
|
|
|
|
1236
|
|
|
|
|
|
|
$lasterror = get_errstr(); |
1237
|
|
|
|
|
|
|
|
1238
|
|
|
|
|
|
|
C returns last error message string that is chained all of error |
1239
|
|
|
|
|
|
|
messages for each hosts. |
1240
|
|
|
|
|
|
|
|
1241
|
|
|
|
|
|
|
=head2 get_errhash() |
1242
|
|
|
|
|
|
|
|
1243
|
|
|
|
|
|
|
$lasterror = get_errhash(); |
1244
|
|
|
|
|
|
|
|
1245
|
|
|
|
|
|
|
C returns hash reference which contains last error messages |
1246
|
|
|
|
|
|
|
identified by host names. |
1247
|
|
|
|
|
|
|
|
1248
|
|
|
|
|
|
|
=cut |
1249
|
|
|
|
|
|
|
|
1250
|
|
|
|
|
|
|
# ----------------------------------------------------------------------------- |
1251
|
|
|
|
|
|
|
|
1252
|
|
|
|
|
|
|
sub _clear_error { |
1253
|
50
|
|
|
50
|
|
113
|
$_error = |
1254
|
|
|
|
|
|
|
$_errhash = {}; |
1255
|
|
|
|
|
|
|
} |
1256
|
|
|
|
|
|
|
|
1257
|
|
|
|
|
|
|
sub get_errstr { |
1258
|
0
|
|
|
0
|
1
|
0
|
return $_error; |
1259
|
|
|
|
|
|
|
} |
1260
|
|
|
|
|
|
|
sub get_errhash { |
1261
|
0
|
|
|
0
|
1
|
0
|
return $_errhash; |
1262
|
|
|
|
|
|
|
} |
1263
|
|
|
|
|
|
|
|
1264
|
|
|
|
|
|
|
sub _retresults { |
1265
|
50
|
|
|
50
|
|
85
|
my ($table, $error, $arghosts) = @_; |
1266
|
|
|
|
|
|
|
|
1267
|
50
|
50
|
|
|
|
242
|
return unless defined wantarray; |
1268
|
|
|
|
|
|
|
|
1269
|
50
|
|
|
|
|
99
|
my %ret = (); |
1270
|
50
|
100
|
100
|
|
|
143
|
if ( defined($table) && %{$table} ) |
|
40
|
|
|
|
|
247
|
|
1271
|
|
|
|
|
|
|
{ |
1272
|
38
|
|
|
|
|
123
|
while ( my ($host,$keys) = each %{$table} ) |
|
106
|
|
|
|
|
349
|
|
1273
|
|
|
|
|
|
|
{ |
1274
|
68
|
|
|
|
|
95
|
while ( my ($key, $mibvals) = each %{$keys} ) |
|
122
|
|
|
|
|
384
|
|
1275
|
|
|
|
|
|
|
{ |
1276
|
95
|
100
|
|
|
|
225
|
if ( $key eq '_ANONY_' ){ |
1277
|
|
|
|
|
|
|
|
1278
|
41
|
|
|
|
|
63
|
$table->{$host} = $mibvals; |
1279
|
41
|
|
|
|
|
115
|
last; |
1280
|
|
|
|
|
|
|
} |
1281
|
|
|
|
|
|
|
} |
1282
|
|
|
|
|
|
|
} |
1283
|
|
|
|
|
|
|
# No "hosts" option and specified target host by "snmp", |
1284
|
|
|
|
|
|
|
# the result will not contain hash of hosts. |
1285
|
38
|
100
|
|
|
|
100
|
$table = (values %{$table})[0] if !$arghosts; |
|
9
|
|
|
|
|
21
|
|
1286
|
|
|
|
|
|
|
} |
1287
|
|
|
|
|
|
|
|
1288
|
50
|
|
|
|
|
87
|
my $message = ''; |
1289
|
50
|
50
|
|
|
|
203
|
if ( $error ){ |
1290
|
50
|
100
|
|
|
|
141
|
if ( ref($error) eq 'HASH' ){ |
1291
|
40
|
|
|
|
|
53
|
foreach my $h ( keys %{$error} ){ |
|
40
|
|
|
|
|
128
|
|
1292
|
3
|
100
|
|
|
|
15
|
if ( ref($error->{$h}) eq 'HASH' ){ |
1293
|
1
|
|
|
|
|
3
|
$error->{$h} = join('; ', values %{$error->{$h}}); |
|
1
|
|
|
|
|
7
|
|
1294
|
|
|
|
|
|
|
} |
1295
|
|
|
|
|
|
|
} |
1296
|
40
|
100
|
|
|
|
65
|
if ( %{$error} ){ |
|
40
|
|
|
|
|
107
|
|
1297
|
3
|
|
|
|
|
6
|
$message = join("; ", (values %{$error})); |
|
3
|
|
|
|
|
10
|
|
1298
|
|
|
|
|
|
|
} |
1299
|
|
|
|
|
|
|
} |
1300
|
|
|
|
|
|
|
else { |
1301
|
10
|
|
|
|
|
12
|
$message = $error; |
1302
|
10
|
|
|
|
|
17
|
$error = undef; |
1303
|
|
|
|
|
|
|
} |
1304
|
|
|
|
|
|
|
} |
1305
|
|
|
|
|
|
|
|
1306
|
50
|
|
|
|
|
75
|
$_error = $message; |
1307
|
50
|
|
|
|
|
84
|
$_errhash = $error; |
1308
|
50
|
50
|
|
|
|
409
|
return wantarray? ($table, $message): $table; |
1309
|
|
|
|
|
|
|
} |
1310
|
|
|
|
|
|
|
|
1311
|
|
|
|
|
|
|
# ============================================================================= |
1312
|
|
|
|
|
|
|
|
1313
|
|
|
|
|
|
|
=head1 APPENDIX |
1314
|
|
|
|
|
|
|
|
1315
|
|
|
|
|
|
|
C has sub modules; C and |
1316
|
|
|
|
|
|
|
C. |
1317
|
|
|
|
|
|
|
|
1318
|
|
|
|
|
|
|
L gives MIBname-OID converter utilities. |
1319
|
|
|
|
|
|
|
For example, you can specify basic OIDs when call function like below; |
1320
|
|
|
|
|
|
|
|
1321
|
|
|
|
|
|
|
use Net::SNMP::Util::OID qw(if*); # import if* MIB name maps |
1322
|
|
|
|
|
|
|
|
1323
|
|
|
|
|
|
|
%oids = ( |
1324
|
|
|
|
|
|
|
sysInfo => [ |
1325
|
|
|
|
|
|
|
oid( "ifDescr", "ifType" ) # equals '1.3.6.1.2.1.2.2.1.2','1.3.6.1.2.1.2.2.1.3' |
1326
|
|
|
|
|
|
|
], |
1327
|
|
|
|
|
|
|
oidm("ifName") # equals "ifName" => "1.3.6.1.2.1.31.1.1.1.1" |
1328
|
|
|
|
|
|
|
); |
1329
|
|
|
|
|
|
|
($result,$error) = snmpparaawlk( |
1330
|
|
|
|
|
|
|
hosts => \@hosts, |
1331
|
|
|
|
|
|
|
oids => \%oids, |
1332
|
|
|
|
|
|
|
snmp => \%snmpparams |
1333
|
|
|
|
|
|
|
); |
1334
|
|
|
|
|
|
|
|
1335
|
|
|
|
|
|
|
L gives MIBEnumValue-Text convertor utilities. |
1336
|
|
|
|
|
|
|
For example, you can convert value of ifAdminStatus, ifOperStatus and ifType |
1337
|
|
|
|
|
|
|
like below; |
1338
|
|
|
|
|
|
|
|
1339
|
|
|
|
|
|
|
use Net::SNMP::Util::TC; |
1340
|
|
|
|
|
|
|
|
1341
|
|
|
|
|
|
|
$tc = Net::SNMP::Util::TC->new; |
1342
|
|
|
|
|
|
|
$astat = $tc->ifAdminStatus( $value_admin_stat ); # "up", "down" or etc. |
1343
|
|
|
|
|
|
|
$ostat = $tc->ifOperStatus( $value_oper_stat ); |
1344
|
|
|
|
|
|
|
$iftype = $tc->ifType( $value_iftype ); # "ethernet-csmacd" or etc. |
1345
|
|
|
|
|
|
|
|
1346
|
|
|
|
|
|
|
|
1347
|
|
|
|
|
|
|
=head1 PRACTICAL EXAMPLES |
1348
|
|
|
|
|
|
|
|
1349
|
|
|
|
|
|
|
=head2 1. Check system information simply |
1350
|
|
|
|
|
|
|
|
1351
|
|
|
|
|
|
|
This example get some system entry MIB values from several hosts with C. |
1352
|
|
|
|
|
|
|
|
1353
|
|
|
|
|
|
|
#!/usr/local/bin/perl |
1354
|
|
|
|
|
|
|
use strict; |
1355
|
|
|
|
|
|
|
use warnings; |
1356
|
|
|
|
|
|
|
use Getopt::Std; |
1357
|
|
|
|
|
|
|
use Net::SNMP::Util; |
1358
|
|
|
|
|
|
|
|
1359
|
|
|
|
|
|
|
my %opt; |
1360
|
|
|
|
|
|
|
getopts('hv:c:r:t:', \%opt); |
1361
|
|
|
|
|
|
|
|
1362
|
|
|
|
|
|
|
sub HELP_MESSAGE { |
1363
|
|
|
|
|
|
|
print "Usage: $0 [-v VERSION] [-c COMMUNITY_NAME] ". |
1364
|
|
|
|
|
|
|
"[-r RETRIES] [-t TIMEOUT] HOST [,HOST2 ...]\n"; |
1365
|
|
|
|
|
|
|
exit 1; |
1366
|
|
|
|
|
|
|
} |
1367
|
|
|
|
|
|
|
HELP_MESSAGE() if ( !@ARGV || $opt{h} ); |
1368
|
|
|
|
|
|
|
|
1369
|
|
|
|
|
|
|
(my $version = ($opt{v}||2)) =~ tr/1-3//cd; # now "2c" is ok |
1370
|
|
|
|
|
|
|
my ($ret, $err) = snmpget( |
1371
|
|
|
|
|
|
|
hosts => \@ARGV, |
1372
|
|
|
|
|
|
|
snmp => { -version => $version, |
1373
|
|
|
|
|
|
|
-timeout => $opt{t} || 5, |
1374
|
|
|
|
|
|
|
-retries => $opt{r} || 1, |
1375
|
|
|
|
|
|
|
-community => $opt{c} || "public" }, |
1376
|
|
|
|
|
|
|
oids => { descr => '1.3.6.1.2.1.1.1.0', |
1377
|
|
|
|
|
|
|
uptime => '1.3.6.1.2.1.1.3.0', |
1378
|
|
|
|
|
|
|
name => '1.3.6.1.2.1.1.5.0', |
1379
|
|
|
|
|
|
|
location => '1.3.6.1.2.1.1.6.0', |
1380
|
|
|
|
|
|
|
} |
1381
|
|
|
|
|
|
|
); |
1382
|
|
|
|
|
|
|
die "[ERROR] $err\n" unless defined $ret; |
1383
|
|
|
|
|
|
|
|
1384
|
|
|
|
|
|
|
foreach my $h ( @ARGV ){ |
1385
|
|
|
|
|
|
|
if ( $ret->{$h} ){ |
1386
|
|
|
|
|
|
|
printf "%s @%s (up %s) - %s\n", |
1387
|
|
|
|
|
|
|
map { $ret->{$h}{$_} or 'N/A' } qw(name location uptime descr); |
1388
|
|
|
|
|
|
|
} else { |
1389
|
|
|
|
|
|
|
printf "%s [ERROR]%s\n", $h, $err->{$h}; |
1390
|
|
|
|
|
|
|
} |
1391
|
|
|
|
|
|
|
} |
1392
|
|
|
|
|
|
|
|
1393
|
|
|
|
|
|
|
__END__ |
1394
|
|
|
|
|
|
|
|
1395
|
|
|
|
|
|
|
|
1396
|
|
|
|
|
|
|
=head2 2. Realtime monitor of host interfaces (SNMPv2c) |
1397
|
|
|
|
|
|
|
|
1398
|
|
|
|
|
|
|
This program shows realtime traffic throughput of interfaces of a host on your |
1399
|
|
|
|
|
|
|
console with using C and callbacking. |
1400
|
|
|
|
|
|
|
|
1401
|
|
|
|
|
|
|
Notice: This program is for devices which can deal SNMP version 2c. |
1402
|
|
|
|
|
|
|
|
1403
|
|
|
|
|
|
|
#!/usr/local/bin/perl |
1404
|
|
|
|
|
|
|
|
1405
|
|
|
|
|
|
|
use strict; |
1406
|
|
|
|
|
|
|
use warnings; |
1407
|
|
|
|
|
|
|
use Getopt::Std; |
1408
|
|
|
|
|
|
|
use Term::ANSIScreen qw/:color :screen :constants/; |
1409
|
|
|
|
|
|
|
use Net::SNMP::Util; |
1410
|
|
|
|
|
|
|
|
1411
|
|
|
|
|
|
|
my %opt; |
1412
|
|
|
|
|
|
|
getopts('hv:c:w:x:', \%opt); |
1413
|
|
|
|
|
|
|
my $host = shift @ARGV; |
1414
|
|
|
|
|
|
|
|
1415
|
|
|
|
|
|
|
sub HELP_MESSAGE { |
1416
|
|
|
|
|
|
|
print "Usage: $0 [-c COMMUNITY_NAME] [-w WAIT] [-x REGEXP] HOST\n"; |
1417
|
|
|
|
|
|
|
exit 1; |
1418
|
|
|
|
|
|
|
} |
1419
|
|
|
|
|
|
|
HELP_MESSAGE() if ( !$host || $opt{h} ); |
1420
|
|
|
|
|
|
|
|
1421
|
|
|
|
|
|
|
my ($wait,$regexp) = ($opt{w}||5, $opt{x}? qr/$opt{x}/: ''); |
1422
|
|
|
|
|
|
|
my $console = Term::ANSIScreen->new(); |
1423
|
|
|
|
|
|
|
local $| = 1; |
1424
|
|
|
|
|
|
|
|
1425
|
|
|
|
|
|
|
# make session |
1426
|
|
|
|
|
|
|
my ($ses, $err) = Net::SNMP->session( |
1427
|
|
|
|
|
|
|
-hostname => $host, |
1428
|
|
|
|
|
|
|
-version => "2", |
1429
|
|
|
|
|
|
|
-community => ($opt{c} || "public") |
1430
|
|
|
|
|
|
|
); |
1431
|
|
|
|
|
|
|
die "[ERROR] $err\n" unless defined $ses; |
1432
|
|
|
|
|
|
|
|
1433
|
|
|
|
|
|
|
# main loop |
1434
|
|
|
|
|
|
|
my (%pdata, %cdata); # flag, previous and current octets data |
1435
|
|
|
|
|
|
|
my $first = 1; |
1436
|
|
|
|
|
|
|
while ( 1 ){ |
1437
|
|
|
|
|
|
|
%cdata = (); |
1438
|
|
|
|
|
|
|
(my $ret, $err) = snmpwalk( |
1439
|
|
|
|
|
|
|
snmp => $ses, |
1440
|
|
|
|
|
|
|
oids => { |
1441
|
|
|
|
|
|
|
sysUpTime => '1.3.6.1.2.1.1.3', |
1442
|
|
|
|
|
|
|
ifTable => [ |
1443
|
|
|
|
|
|
|
'1.3.6.1.2.1.31.1.1.1.1', # [0] ifName |
1444
|
|
|
|
|
|
|
'1.3.6.1.2.1.2.2.1.7', # [1] ifAdminStatus |
1445
|
|
|
|
|
|
|
'1.3.6.1.2.1.2.2.1.8', # [2] ifOperStatus |
1446
|
|
|
|
|
|
|
'1.3.6.1.2.1.31.1.1.1.6', # [3] ifHCInOctets |
1447
|
|
|
|
|
|
|
'1.3.6.1.2.1.31.1.1.1.10', # [4] ifHCOutOctets |
1448
|
|
|
|
|
|
|
'1.3.6.1.2.1.31.1.1.1.15', # [5] ifHighSpeed |
1449
|
|
|
|
|
|
|
] }, |
1450
|
|
|
|
|
|
|
-mycallback => sub { |
1451
|
|
|
|
|
|
|
my ($s, $host, $key, $val) = @_; |
1452
|
|
|
|
|
|
|
return 1 if $key ne 'ifTable'; |
1453
|
|
|
|
|
|
|
my $name = $val->[0][1]; |
1454
|
|
|
|
|
|
|
return 0 if ( $regexp && $name !~ /$regexp/ ); |
1455
|
|
|
|
|
|
|
# storing current octets data |
1456
|
|
|
|
|
|
|
$cdata{$name}{t} = time; |
1457
|
|
|
|
|
|
|
$cdata{$name}{i} = $val->[3][1]; |
1458
|
|
|
|
|
|
|
$cdata{$name}{o} = $val->[4][1]; |
1459
|
|
|
|
|
|
|
return 1; |
1460
|
|
|
|
|
|
|
} |
1461
|
|
|
|
|
|
|
); |
1462
|
|
|
|
|
|
|
die "[ERROR] $err\n" unless $ret; |
1463
|
|
|
|
|
|
|
|
1464
|
|
|
|
|
|
|
# header |
1465
|
|
|
|
|
|
|
$console->Cls(); |
1466
|
|
|
|
|
|
|
$console->Cursor(0, 0); |
1467
|
|
|
|
|
|
|
|
1468
|
|
|
|
|
|
|
printf "%s, up %s - %s\n\n", |
1469
|
|
|
|
|
|
|
BOLD.$host.CLEAR, $ret->{sysUpTime}{0}, scalar(localtime(time)); |
1470
|
|
|
|
|
|
|
|
1471
|
|
|
|
|
|
|
# matrix |
1472
|
|
|
|
|
|
|
printf "%s%-30s (%-10s) %2s %2s %10s %10s %10s%s\n", |
1473
|
|
|
|
|
|
|
UNDERSCORE, qw/ifName ifIndex Ad Op BW(Mbps) InBps(M) OutBps(M)/, CLEAR; |
1474
|
|
|
|
|
|
|
|
1475
|
|
|
|
|
|
|
my $iftable = $ret->{ifTable}; |
1476
|
|
|
|
|
|
|
foreach my $i ( sort { $a <=> $b } keys %{$iftable->[1]} ) |
1477
|
|
|
|
|
|
|
{ |
1478
|
|
|
|
|
|
|
my ($name, $astat, $ostat, $bw) |
1479
|
|
|
|
|
|
|
= map { $iftable->[$_]{$i} } qw( 0 1 2 5 ); |
1480
|
|
|
|
|
|
|
if ( $first ){ |
1481
|
|
|
|
|
|
|
printf "%-30s (%-10d) %2d %2d %10.1f %10s %10s\n", |
1482
|
|
|
|
|
|
|
$name, $i, $astat, $ostat, $bw/1000, '-', '-'; |
1483
|
|
|
|
|
|
|
next; # skip first |
1484
|
|
|
|
|
|
|
} |
1485
|
|
|
|
|
|
|
|
1486
|
|
|
|
|
|
|
# calculate (k)bps |
1487
|
|
|
|
|
|
|
my $td = $cdata{$name}{t} - $pdata{$name}{t}; |
1488
|
|
|
|
|
|
|
my ($inbps, $outbps) = map { |
1489
|
|
|
|
|
|
|
my $delta = $cdata{$name}{$_} - $pdata{$name}{$_}; |
1490
|
|
|
|
|
|
|
$delta<0? 0: $delta / $td / 1000; # Kbps |
1491
|
|
|
|
|
|
|
} qw( i o ); |
1492
|
|
|
|
|
|
|
|
1493
|
|
|
|
|
|
|
printf "%-30s (%-10d) %2d %2d %10.1f %10.1f %10.1f\n", |
1494
|
|
|
|
|
|
|
$name, $i, $astat, $ostat, map { $_/1000 } ($bw, $inbps, $outbps); |
1495
|
|
|
|
|
|
|
} |
1496
|
|
|
|
|
|
|
|
1497
|
|
|
|
|
|
|
%pdata = %cdata; |
1498
|
|
|
|
|
|
|
$first = 0; |
1499
|
|
|
|
|
|
|
sleep $wait; |
1500
|
|
|
|
|
|
|
} |
1501
|
|
|
|
|
|
|
|
1502
|
|
|
|
|
|
|
__END__ |
1503
|
|
|
|
|
|
|
|
1504
|
|
|
|
|
|
|
|
1505
|
|
|
|
|
|
|
=head2 3. Tiny MRTG with RRDTool (SNMPv2c) |
1506
|
|
|
|
|
|
|
|
1507
|
|
|
|
|
|
|
With installing Tobias Oetiker's RRDTool and RRD::Simple, this sample will do |
1508
|
|
|
|
|
|
|
like MRTG. (It is better to execute this by cron.) |
1509
|
|
|
|
|
|
|
|
1510
|
|
|
|
|
|
|
If Environmental variables, PATH2DATADIR and URL2HTMLDIR, are defined, files will |
1511
|
|
|
|
|
|
|
be stored under PATH2DATADIR and URL pathes will include URL2HTMLDIR in html. |
1512
|
|
|
|
|
|
|
Or Modify $datadir and $htmldir to decide these path and URL where browser can |
1513
|
|
|
|
|
|
|
access through your http service. |
1514
|
|
|
|
|
|
|
|
1515
|
|
|
|
|
|
|
Notice: This program is for devices which can deal SNMP version 2c. |
1516
|
|
|
|
|
|
|
|
1517
|
|
|
|
|
|
|
#!/usr/local/bin/perl |
1518
|
|
|
|
|
|
|
use strict; |
1519
|
|
|
|
|
|
|
use warnings; |
1520
|
|
|
|
|
|
|
use Getopt::Std; |
1521
|
|
|
|
|
|
|
use CGI qw(:html); |
1522
|
|
|
|
|
|
|
use RRD::Simple; # install the "RRDTool" and RRD::Simple |
1523
|
|
|
|
|
|
|
use Net::SNMP::Util qw(:para); |
1524
|
|
|
|
|
|
|
|
1525
|
|
|
|
|
|
|
my %opt; |
1526
|
|
|
|
|
|
|
getopts('hc:x:', \%opt); |
1527
|
|
|
|
|
|
|
my @hosts = @ARGV; |
1528
|
|
|
|
|
|
|
|
1529
|
|
|
|
|
|
|
sub HELP_MESSAGE { |
1530
|
|
|
|
|
|
|
print "Usage: $0 [-c COMMUNITY_NAME] [-x REGEXP] HOST [HOST [...]]\n"; |
1531
|
|
|
|
|
|
|
exit 1; |
1532
|
|
|
|
|
|
|
} |
1533
|
|
|
|
|
|
|
HELP_MESSAGE() if ( !@hosts || $opt{h} ); |
1534
|
|
|
|
|
|
|
|
1535
|
|
|
|
|
|
|
my $datadir = $ENV{PATH2DATADIR} || "/path/to/datadir"; # !!! Modify !!! |
1536
|
|
|
|
|
|
|
my $htmldir = $ENV{URL2HTMLDIR} || "/path/to/htmldir"; # !!! Modify !!! |
1537
|
|
|
|
|
|
|
my $regexp = $opt{x}? qr/$opt{x}/: ''; |
1538
|
|
|
|
|
|
|
my %sesopts = ( -version => 2, -community=> ($opt{c} || 'public') ); |
1539
|
|
|
|
|
|
|
|
1540
|
|
|
|
|
|
|
sub escname { |
1541
|
|
|
|
|
|
|
my $n = shift; |
1542
|
|
|
|
|
|
|
$n =~ tr/\\\/\*\?\|"<>:,;%/_/; |
1543
|
|
|
|
|
|
|
return $n; |
1544
|
|
|
|
|
|
|
} |
1545
|
|
|
|
|
|
|
|
1546
|
|
|
|
|
|
|
# gather traffic data and store to RRD |
1547
|
|
|
|
|
|
|
my ($result, $error) = snmpparawalk( |
1548
|
|
|
|
|
|
|
hosts => \@hosts, |
1549
|
|
|
|
|
|
|
snmp => \%sesopts, |
1550
|
|
|
|
|
|
|
oids => { |
1551
|
|
|
|
|
|
|
ifData => [ '1.3.6.1.2.1.31.1.1.1.1', # ifName |
1552
|
|
|
|
|
|
|
'1.3.6.1.2.1.31.1.1.1.6', # ifHCInOctets |
1553
|
|
|
|
|
|
|
'1.3.6.1.2.1.31.1.1.1.10' ] # ifHCOutOctets |
1554
|
|
|
|
|
|
|
}, |
1555
|
|
|
|
|
|
|
|
1556
|
|
|
|
|
|
|
# this callback will work everything of necessary |
1557
|
|
|
|
|
|
|
-mycallback => sub { |
1558
|
|
|
|
|
|
|
my ($s, $host, $key, $val) = @_; |
1559
|
|
|
|
|
|
|
# val=[[index,name], [index,inOcts], [index,outOcts]] |
1560
|
|
|
|
|
|
|
my ($index, $name) = @{$val->[0]}; |
1561
|
|
|
|
|
|
|
|
1562
|
|
|
|
|
|
|
# check necessarity by ifName |
1563
|
|
|
|
|
|
|
return 0 if ( $regexp && $name !~ /$regexp/ ); |
1564
|
|
|
|
|
|
|
|
1565
|
|
|
|
|
|
|
my $basename = "$host.".escname($name); |
1566
|
|
|
|
|
|
|
my $rrdfile = "$datadir/$basename.rrd"; |
1567
|
|
|
|
|
|
|
|
1568
|
|
|
|
|
|
|
# treat RRD |
1569
|
|
|
|
|
|
|
my $rrd = RRD::Simple->new( file => $rrdfile ); |
1570
|
|
|
|
|
|
|
|
1571
|
|
|
|
|
|
|
#eval { # wanna catch an error, uncomment here. |
1572
|
|
|
|
|
|
|
|
1573
|
|
|
|
|
|
|
$rrd->create($rrdfile, 'mrtg', |
1574
|
|
|
|
|
|
|
'in' => 'COUNTER', 'out' => 'COUNTER' |
1575
|
|
|
|
|
|
|
) unless -e $rrdfile; |
1576
|
|
|
|
|
|
|
|
1577
|
|
|
|
|
|
|
$rrd->update( $rrdfile, time, |
1578
|
|
|
|
|
|
|
'in' => $val->[1][1], 'out' => $val->[2][1] |
1579
|
|
|
|
|
|
|
); |
1580
|
|
|
|
|
|
|
|
1581
|
|
|
|
|
|
|
$rrd->graph( $rrdfile, |
1582
|
|
|
|
|
|
|
destination => $datadir, |
1583
|
|
|
|
|
|
|
basename => $basename, |
1584
|
|
|
|
|
|
|
title => "$host :: $name", |
1585
|
|
|
|
|
|
|
sources => [ qw( in out ) ], |
1586
|
|
|
|
|
|
|
source_labels => [ qw( incoming outgoing ) ], |
1587
|
|
|
|
|
|
|
source_colors => [ qw( 00cc00 0000ff ) ], |
1588
|
|
|
|
|
|
|
source_drawtypes => [ qw( AREA LINE1 ) ] |
1589
|
|
|
|
|
|
|
); |
1590
|
|
|
|
|
|
|
|
1591
|
|
|
|
|
|
|
#}; warn "[EVAL ERROR] $@" if $@; |
1592
|
|
|
|
|
|
|
|
1593
|
|
|
|
|
|
|
return 1; |
1594
|
|
|
|
|
|
|
} |
1595
|
|
|
|
|
|
|
); |
1596
|
|
|
|
|
|
|
die "[ERROR] $error\n" unless $result; |
1597
|
|
|
|
|
|
|
|
1598
|
|
|
|
|
|
|
# make html |
1599
|
|
|
|
|
|
|
sub mkimgtag { |
1600
|
|
|
|
|
|
|
my ($host, $name, $type) = @_; |
1601
|
|
|
|
|
|
|
my $basename = escname($name); |
1602
|
|
|
|
|
|
|
img({ -src => "$htmldir/$host.$basename-$type.png", |
1603
|
|
|
|
|
|
|
-alt => "$host $name $type", |
1604
|
|
|
|
|
|
|
-title => "$type graph of $host $name", |
1605
|
|
|
|
|
|
|
-border=> 0 }); |
1606
|
|
|
|
|
|
|
} |
1607
|
|
|
|
|
|
|
|
1608
|
|
|
|
|
|
|
open(HTML,"> $datadir/index.html") or die "$!"; |
1609
|
|
|
|
|
|
|
print HTML start_html( |
1610
|
|
|
|
|
|
|
-title=> 'Traffic Monitor', |
1611
|
|
|
|
|
|
|
-head => meta({ -http_equiv => 'refresh', |
1612
|
|
|
|
|
|
|
-content => 300 }) |
1613
|
|
|
|
|
|
|
), h1('Traffic Monitor'); |
1614
|
|
|
|
|
|
|
|
1615
|
|
|
|
|
|
|
foreach my $host ( sort @hosts ){ |
1616
|
|
|
|
|
|
|
print HTML h2($host); |
1617
|
|
|
|
|
|
|
foreach my $i ( sort keys %{$result->{$host}{ifData}[0]} ){ |
1618
|
|
|
|
|
|
|
my $name = $result->{$host}{ifData}[0]{$i}; |
1619
|
|
|
|
|
|
|
my $subhtml = "$host.".escname($name).".html"; |
1620
|
|
|
|
|
|
|
|
1621
|
|
|
|
|
|
|
printf HTML a( {-href=>"$htmldir/$subhtml"}, |
1622
|
|
|
|
|
|
|
mkimgtag($host, $name, 'daily') |
1623
|
|
|
|
|
|
|
); |
1624
|
|
|
|
|
|
|
|
1625
|
|
|
|
|
|
|
if ( open(HTML2,"> $datadir/$subhtml") ){ |
1626
|
|
|
|
|
|
|
print HTML2 start_html( |
1627
|
|
|
|
|
|
|
-title=> 'Traffic Monitor', |
1628
|
|
|
|
|
|
|
-head => meta({ -http_equiv => 'refresh', |
1629
|
|
|
|
|
|
|
-content => 300 }) ), |
1630
|
|
|
|
|
|
|
h1("$host $name"), |
1631
|
|
|
|
|
|
|
(map { h2($_).p(mkimgtag($host, $name, $_)) } |
1632
|
|
|
|
|
|
|
qw(daily weekly monthly annual)), |
1633
|
|
|
|
|
|
|
end_html(); |
1634
|
|
|
|
|
|
|
close(HTML2); |
1635
|
|
|
|
|
|
|
} else { |
1636
|
|
|
|
|
|
|
warn "$!"; |
1637
|
|
|
|
|
|
|
} |
1638
|
|
|
|
|
|
|
} |
1639
|
|
|
|
|
|
|
} |
1640
|
|
|
|
|
|
|
|
1641
|
|
|
|
|
|
|
print HTML end_html(); |
1642
|
|
|
|
|
|
|
close(HTML); |
1643
|
|
|
|
|
|
|
|
1644
|
|
|
|
|
|
|
__END__ |
1645
|
|
|
|
|
|
|
|
1646
|
|
|
|
|
|
|
|
1647
|
|
|
|
|
|
|
=head1 REQUIREMENTS |
1648
|
|
|
|
|
|
|
|
1649
|
|
|
|
|
|
|
See C. |
1650
|
|
|
|
|
|
|
|
1651
|
|
|
|
|
|
|
=head1 AUTHOR |
1652
|
|
|
|
|
|
|
|
1653
|
|
|
|
|
|
|
t.onodera, C<< >> |
1654
|
|
|
|
|
|
|
|
1655
|
|
|
|
|
|
|
=head1 TO DO |
1656
|
|
|
|
|
|
|
|
1657
|
|
|
|
|
|
|
- Implementation of simple trapping functions |
1658
|
|
|
|
|
|
|
|
1659
|
|
|
|
|
|
|
=head1 SEE ALSO |
1660
|
|
|
|
|
|
|
|
1661
|
|
|
|
|
|
|
=over |
1662
|
|
|
|
|
|
|
|
1663
|
|
|
|
|
|
|
=item * |
1664
|
|
|
|
|
|
|
|
1665
|
|
|
|
|
|
|
L - Core module of C which brings us good SNMP |
1666
|
|
|
|
|
|
|
implementations. |
1667
|
|
|
|
|
|
|
|
1668
|
|
|
|
|
|
|
=item * |
1669
|
|
|
|
|
|
|
|
1670
|
|
|
|
|
|
|
L - Sub module of C which provides |
1671
|
|
|
|
|
|
|
easy and simple functions to treat OID. |
1672
|
|
|
|
|
|
|
|
1673
|
|
|
|
|
|
|
=item * |
1674
|
|
|
|
|
|
|
|
1675
|
|
|
|
|
|
|
L - Sub module of C which provides |
1676
|
|
|
|
|
|
|
easy and simple functions to treat textual conversion. |
1677
|
|
|
|
|
|
|
|
1678
|
|
|
|
|
|
|
=back |
1679
|
|
|
|
|
|
|
|
1680
|
|
|
|
|
|
|
=head1 LICENSE AND COPYRIGHT |
1681
|
|
|
|
|
|
|
|
1682
|
|
|
|
|
|
|
Copyright(C) 2011- Takahiro Ondoera. |
1683
|
|
|
|
|
|
|
|
1684
|
|
|
|
|
|
|
This program is free software; you may redistribute it and/or modify it under |
1685
|
|
|
|
|
|
|
the same terms as the Perl 5 programming language system itself. |
1686
|
|
|
|
|
|
|
|
1687
|
|
|
|
|
|
|
=cut |
1688
|
|
|
|
|
|
|
|
1689
|
|
|
|
|
|
|
1; # End of Net::SNMP::Util |