File Coverage

blib/lib/Net/SNMP/Mixin/Dot1dBase.pm
Criterion Covered Total %
statement 65 92 70.6
branch 20 36 55.5
condition 3 6 50.0
subroutine 16 16 100.0
pod 3 3 100.0
total 107 153 69.9


line stmt bran cond sub pod time code
1             package Net::SNMP::Mixin::Dot1dBase;
2              
3 4     4   327399 use strict;
  4         8  
  4         103  
4 4     4   18 use warnings;
  4         7  
  4         135  
5              
6             #
7             # store this package name in a handy variable,
8             # used for unambiguous prefix of mixin attributes
9             # storage in object hash
10             #
11             my $prefix = __PACKAGE__;
12              
13             #
14             # this module import config
15             #
16 4     4   21 use Carp ();
  4         8  
  4         89  
17 4     4   476 use Net::SNMP::Mixin::Util qw/idx2val normalize_mac push_error get_init_slot/;
  4         77088  
  4         27  
18              
19             #
20             # this module export config
21             #
22             my @mixin_methods;
23              
24             BEGIN {
25 4     4   1968 @mixin_methods = (
26             qw/
27             get_dot1d_base_group
28             map_bridge_ports2if_indexes
29             map_if_indexes2bridge_ports
30             /
31             );
32             }
33              
34 4         37 use Sub::Exporter -setup => {
35             exports => [@mixin_methods],
36             groups => { default => [@mixin_methods], },
37 4     4   27 };
  4         7  
38              
39             #
40             # SNMP oid constants used in this module
41             #
42             use constant {
43 4         1715 DOT1D_BASE_BRIDGE_ADDRESS => '1.3.6.1.2.1.17.1.1.0',
44             DOT1D_BASE_NUM_PORTS => '1.3.6.1.2.1.17.1.2.0',
45             DOT1D_BASE_TYPE => '1.3.6.1.2.1.17.1.3.0',
46              
47             DOT1D_BASE_PORT_IF_INDEX => '1.3.6.1.2.1.17.1.4.1.2',
48 4     4   1800 };
  4         7  
49              
50             =head1 NAME
51              
52             Net::SNMP::Mixin::Dot1dBase - mixin class for the switch dot1d base values
53              
54             =cut
55              
56             our $VERSION = '0.10';
57              
58             =head1 SYNOPSIS
59              
60             A Net::SNMP mixin class for Dot1d base info.
61              
62             use Net::SNMP;
63             use Net::SNMP::Mixin;
64              
65             # class based mixin
66             Net::SNMP->mixer('Net::SNMP::Mixin::Dot1dBase');
67              
68             # ...
69              
70             my $session = Net::SNMP->session( -hostname => 'foo.bar.com' );
71              
72             $session->mixer('Net::SNMP::Mixin::Dot1dBase');
73             $session->init_mixins;
74             snmp_dispatcher() if $session->nonblocking;
75             $session->init_ok;
76             die $session->errors if $session->errors;
77              
78             my $base_group = $session->get_dot1d_base_group;
79              
80             printf "BridgeAddr: %s NumPorts: %d Type: %d\n",
81             $base_group->{dot1dBaseBridgeAddress},
82             $base_group->{dot1dBaseNumPorts},
83             $base_group->{dot1dBaseType};
84              
85             my $map = $session->map_bridge_ports2if_indexes;
86              
87             foreach my $bridge_port ( sort {$a <=> $b} keys %$map ) {
88             my $if_index = $map->{$bridge_port};
89             printf "bridgePort: %4d -> ifIndex: %4\n", $bridge_port, $if_index;
90             }
91              
92              
93             =head1 DESCRIPTION
94              
95             A mixin class for basic switch information from the BRIDGE-MIB.
96              
97             Besides the bridge address and the number of bridge ports, it's primary use is the mapping between dot1dBasePorts and ifIndexes.
98              
99             =head1 MIXIN METHODS
100              
101             =head2 B<< OBJ->get_dot1d_base_group() >>
102              
103             Returns the dot1dBase group as a hash reference:
104              
105             {
106             dot1dBaseBridgeAddress => MacAddress,
107             dot1dBaseNumPorts => INTEGER,
108             dot1dBaseType => INTEGER,
109             }
110              
111             =cut
112              
113             sub get_dot1d_base_group {
114 1     1 1 25245 my $session = shift;
115 1         6 my $agent = $session->hostname;
116              
117 1 50       11 Carp::croak "$agent: '$prefix' not initialized,"
118             unless $session->init_ok($prefix);
119              
120 0         0 my $result = { %{ $session->{$prefix}{dot1dBase} } };
  0         0  
121              
122             # normalize the MAC address
123             $result->{dot1dBaseBridgeAddress} =
124 0         0 normalize_mac( $result->{dot1dBaseBridgeAddress} );
125              
126 0         0 return $result;
127             }
128              
129             =head2 B<< OBJ->map_bridge_ports2if_indexes() >>
130              
131             Returns a reference to a hash with the following entries:
132              
133             {
134             # INTEGER INTEGER
135             dot1dBasePort => dot1dBasePortIfIndex,
136             }
137              
138             =cut
139              
140             sub map_bridge_ports2if_indexes {
141 1     1 1 632 my ( $session, ) = @_;
142 1         5 my $agent = $session->hostname;
143              
144 1 50       5 Carp::croak "$agent: '$prefix' not initialized,"
145             unless $session->init_ok($prefix);
146              
147             # datastructure:
148             # $session->{$prefix}{dot1dBasePortIfIndex}{$dot1d_base_port} = ifIndex
149             #
150              
151 0         0 my $result = {};
152              
153 0         0 while ( my ( $bridge_port, $if_index ) = each %{ $session->{$prefix}{dot1dBasePortIfIndex} } ) {
  0         0  
154 0         0 $result->{$bridge_port} = $if_index;
155             }
156              
157 0         0 return $result;
158             }
159              
160             =head2 B<< OBJ->map_if_indexes2bridge_ports() >>
161              
162             Returns a reference to a hash with the following entries:
163              
164             {
165             # INTEGER INTEGER
166             dot1dBasePortIfIndex => dot1dBasePort ,
167             }
168              
169             =cut
170              
171             sub map_if_indexes2bridge_ports {
172 1     1 1 618 my ( $session, ) = @_;
173 1         4 my $agent = $session->hostname;
174              
175 1 50       6 Carp::croak "$agent: '$prefix' not initialized,"
176             unless $session->init_ok($prefix);
177              
178             # datastructure:
179             # $session->{$prefix}{dot1dBasePortIfIndex}{$dot1d_base_port} = ifIndex
180             #
181              
182 0         0 my $result = {};
183              
184 0         0 while ( my ( $bridge_port, $if_index ) = each %{ $session->{$prefix}{dot1dBasePortIfIndex} } ) {
  0         0  
185 0         0 $result->{$if_index} = $bridge_port;
186             }
187              
188 0         0 return $result;
189             }
190              
191             =head1 INITIALIZATION
192              
193             =cut
194              
195             =head2 B<< OBJ->_init($reload) >>
196              
197             Fetch the dot1d base related snmp values from the host. Don't call this method direct!
198              
199             =cut
200              
201             #
202             # due to the asynchron nature, we don't know what init job is really the last, we decrement
203             # the value after each callback
204             #
205 4     4   26 use constant THIS_INIT_JOBS => 2;
  4         9  
  4         2459  
206              
207             sub _init {
208 4     4   8301 my ( $session, $reload ) = @_;
209 4         12 my $agent = $session->hostname;
210              
211             die "$agent: $prefix already initialized and reload not forced.\n"
212             if exists get_init_slot($session)->{$prefix}
213 4 50 66     29 && get_init_slot($session)->{$prefix} == 0
      33        
214             && not $reload;
215              
216             # set number of async init jobs for proper initialization
217 4         116 get_init_slot($session)->{$prefix} = THIS_INIT_JOBS;
218              
219             # initialize the object for dot1dbase infos
220 4         42 _fetch_dot1d_base($session);
221 4 100       19 return if $session->error;
222              
223             # LLDP, Dot1Q, STP, LLDP, ... tables are indexed
224             # by dot1dbaseports and not ifIndexes
225             # table to map between dot1dBasePort <-> ifIndex
226              
227 2         14 _fetch_dot1d_base_ports($session);
228 2 50       11 return if $session->error;
229              
230 2         12 return 1;
231             }
232              
233             =head1 PRIVATE METHODS
234              
235             Only for developers or maintainers.
236              
237             =head2 B<< _fetch_dot1d_base($session) >>
238              
239             Fetch values from the dot1dBase group once during object initialization.
240              
241             =cut
242              
243             sub _fetch_dot1d_base {
244 4     4   8 my $session = shift;
245 4         15 my $result;
246              
247             # fetch the dot1dBase group
248 4 100       25 $result = $session->get_request(
249             -varbindlist => [
250              
251             DOT1D_BASE_BRIDGE_ADDRESS,
252             DOT1D_BASE_NUM_PORTS,
253             DOT1D_BASE_TYPE,
254             ],
255              
256             # define callback if in nonblocking mode
257             $session->nonblocking ? ( -callback => \&_dot1d_base_cb ) : (),
258             );
259              
260 4 100       2009283 unless ( defined $result ) {
261 2 50       15 if ( my $err_msg = $session->error ) {
262 2         64 push_error( $session, "$prefix: $err_msg" );
263             }
264 2         96 return;
265             }
266              
267             # in nonblocking mode the callback will be called asynchronously
268 2 50       7 return 1 if $session->nonblocking;
269              
270             # call the callback function in blocking mode by hand
271 0         0 _dot1d_base_cb($session);
272              
273             }
274              
275             =head2 B<< _dot1d_base_cb($session) >>
276              
277             The callback for _fetch_dot1d_base.
278              
279             =cut
280              
281             sub _dot1d_base_cb {
282 2     2   2004474 my $session = shift;
283 2         15 my $vbl = $session->var_bind_list;
284              
285 2 50       29 unless ( defined $vbl ) {
286 2 50       9 if ( my $err_msg = $session->error ) {
287 2         29 push_error( $session, "$prefix: $err_msg" );
288             }
289 2         88 return;
290             }
291              
292             $session->{$prefix}{dot1dBase}{dot1dBaseBridgeAddress} =
293 0         0 $vbl->{ DOT1D_BASE_BRIDGE_ADDRESS() };
294              
295             $session->{$prefix}{dot1dBase}{dot1dBaseNumPorts} =
296 0         0 $vbl->{ DOT1D_BASE_NUM_PORTS() };
297              
298 0         0 $session->{$prefix}{dot1dBase}{dot1dBaseType} = $vbl->{ DOT1D_BASE_TYPE() };
299              
300             # this init job is finished
301 0         0 get_init_slot($session)->{$prefix}--;
302              
303 0         0 return 1;
304             }
305              
306             =head2 B<< _fetch_dot1d_base_ports($session) >>
307              
308             Populate the object with the dot1dBasePorts.
309              
310             =cut
311              
312             sub _fetch_dot1d_base_ports {
313 2     2   4 my $session = shift;
314 2         4 my $result;
315              
316             # fetch the dot1dBasePorts, in blocking or nonblocking mode
317 2 50       5 $result = $session->get_entries(
318             -columns => [ DOT1D_BASE_PORT_IF_INDEX, ],
319              
320             # define callback if in nonblocking mode
321             $session->nonblocking ? ( -callback => \&_dot1d_base_ports_cb ) : (),
322             );
323              
324 2 50       1602 unless ( defined $result ) {
325 0 0       0 if ( my $err_msg = $session->error ) {
326 0         0 push_error( $session, "$prefix: $err_msg" );
327             }
328 0         0 return;
329             }
330              
331             # in nonblocking mode the callback will be called asynchronously
332 2 50       7 return 1 if $session->nonblocking;
333              
334             # call the callback funktion in blocking mode by hand
335 0         0 _dot1d_base_ports_cb($session);
336              
337             }
338              
339             =head2 B<< _dot1d_base_ports_cb($session) >>
340              
341             The callback for _fetch_dot1d_base_ports.
342              
343             =cut
344              
345             sub _dot1d_base_ports_cb {
346 2     2   857 my $session = shift;
347 2         7 my $vbl = $session->var_bind_list;
348              
349 2 50       17 unless ( defined $vbl ) {
350 2 50       7 if ( my $err_msg = $session->error ) {
351 2         17 push_error( $session, "$prefix: $err_msg" );
352             }
353 2         44 return;
354             }
355              
356             # mangle result table to get plain idx->value
357              
358             $session->{$prefix}{dot1dBasePortIfIndex} =
359 0           idx2val( $vbl, DOT1D_BASE_PORT_IF_INDEX );
360              
361             # this init job is finished
362 0           get_init_slot($session)->{$prefix}--;
363              
364 0           return 1;
365             }
366              
367             =head1 REQUIREMENTS
368              
369             L<< Net::SNMP >>, L<< Net::SNMP::Mixin >>
370              
371             =head1 AUTHOR
372              
373             Karl Gaissmaier
374              
375             =head1 COPYRIGHT & LICENSE
376              
377             Copyright 2008-2021 Karl Gaissmaier, all rights reserved.
378              
379             This program is free software; you can redistribute it and/or modify it
380             under the same terms as Perl itself.
381              
382             =cut
383              
384             unless ( caller() ) {
385             print "$prefix compiles and initializes successful.\n";
386             }
387              
388             1;
389              
390             # vim: sw=2