File Coverage

blib/lib/Net/SNMP/Mixin/NXOSDot1dBase.pm
Criterion Covered Total %
statement 65 93 69.8
branch 20 36 55.5
condition 3 6 50.0
subroutine 16 16 100.0
pod 3 3 100.0
total 107 154 69.4


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