File Coverage

blib/lib/Net/SNMP/Mixin/NXOSDot1dStp.pm
Criterion Covered Total %
statement 80 159 50.3
branch 22 46 47.8
condition 3 6 50.0
subroutine 16 18 88.8
pod 2 2 100.0
total 123 231 53.2


line stmt bran cond sub pod time code
1             package Net::SNMP::Mixin::NXOSDot1dStp;
2              
3 4     4   391416 use strict;
  4         13  
  4         129  
4 4     4   22 use warnings;
  4         20  
  4         161  
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   33 use Carp ();
  4         17  
  4         113  
17 4     4   530 use Net::SNMP::Mixin::Util qw/idx2val hex2octet normalize_mac push_error get_init_slot/;
  4         93928  
  4         36  
18              
19             #
20             # this module export config
21             #
22             my @mixin_methods;
23              
24             BEGIN {
25 4     4   2760 @mixin_methods = (
26             qw/
27             get_dot1d_stp_group
28             get_dot1d_stp_port_table
29             /
30             );
31             }
32              
33 4         47 use Sub::Exporter -setup => {
34             exports => [@mixin_methods],
35             groups => { default => [@mixin_methods], },
36 4     4   31 };
  4         10  
37              
38             #
39             # SNMP oid constants used in this module
40             #
41             use constant {
42 4         3241 DOT1D_STP_GROUP => '1.3.6.1.2.1.17.2',
43              
44             DOT1D_STP_PROTO => '1.3.6.1.2.1.17.2.1.0',
45             DOT1D_STP_PRIO => '1.3.6.1.2.1.17.2.2.0',
46             DOT1D_STP_TIME_SINCE_TOPO_CHANGE => '1.3.6.1.2.1.17.2.3.0',
47             DOT1D_STP_TOPO_CHANGES => '1.3.6.1.2.1.17.2.4.0',
48             DOT1D_STP_DESIGNATED_ROOT => '1.3.6.1.2.1.17.2.5.0',
49             DOT1D_STP_ROOT_COST => '1.3.6.1.2.1.17.2.6.0',
50             DOT1D_STP_ROOT_PORT => '1.3.6.1.2.1.17.2.7.0',
51             DOT1D_STP_MAX_AGE => '1.3.6.1.2.1.17.2.8.0',
52             DOT1D_STP_HELLO_TIME => '1.3.6.1.2.1.17.2.9.0',
53             DOT1D_STP_HOLD_TIME => '1.3.6.1.2.1.17.2.10.0',
54             DOT1D_STP_FWD_DELAY => '1.3.6.1.2.1.17.2.11.0',
55             DOT1D_STP_BRIDGE_MAX_AGE => '1.3.6.1.2.1.17.2.12.0',
56             DOT1D_STP_BRIDGE_HELLO_TIME => '1.3.6.1.2.1.17.2.13.0',
57             DOT1D_STP_BRIDGE_FWD_DELAY => '1.3.6.1.2.1.17.2.14.0',
58              
59             DOT1D_STP_PORT_TABLE => '1.3.6.1.2.1.17.2.15',
60              
61             DOT1D_STP_PORT_PRIO => '1.3.6.1.2.1.17.2.15.1.2',
62             DOT1D_STP_PORT_STATE => '1.3.6.1.2.1.17.2.15.1.3',
63             DOT1D_STP_PORT_ENABLE => '1.3.6.1.2.1.17.2.15.1.4',
64             DOT1D_STP_PORT_PATH_COST => '1.3.6.1.2.1.17.2.15.1.5',
65             DOT1D_STP_PORT_DESIGNATED_ROOT => '1.3.6.1.2.1.17.2.15.1.6',
66             DOT1D_STP_PORT_DESIGNATED_COST => '1.3.6.1.2.1.17.2.15.1.7',
67             DOT1D_STP_PORT_DESIGNATED_BRIDGE => '1.3.6.1.2.1.17.2.15.1.8',
68             DOT1D_STP_PORT_DESIGNATED_PORT => '1.3.6.1.2.1.17.2.15.1.9',
69             DOT1D_STP_PORT_FORWARD_TRANSITIONS => '1.3.6.1.2.1.17.2.15.1.10',
70 4     4   2426 };
  4         12  
71              
72             =head1 NAME
73              
74             Net::SNMP::Mixin::NXOSDot1dStp - mixin class for 802.1D spanning tree information from Cisco NXOS devices.
75              
76             =head1 VERSION
77              
78             Version 0.01
79              
80             =cut
81              
82             our $VERSION = '0.01';
83              
84             =head1 SYNOPSIS
85              
86             use Net::SNMP;
87             use Net::SNMP::Mixin;
88              
89             my $session = Net::SNMP->session( -hostname => 'foo.bar.com' );
90             $session->mixer('Net::SNMP::Mixin::NXOSDot1dStp');
91             $session->init_mixins;
92              
93             snmp_dispatcher();
94             $session->init_ok();
95             die $session->errors if $session->errors;
96              
97             my $stp_group = $session->get_dot1d_stp_group;
98              
99             printf "TopoChanges: %d\n", $stp_group->{dot1dStpTopChanges};
100             printf "LastChange: %s\n", $stp_group->{dot1dStpTimeSinceTopologyChange};
101             printf "ThisRootPort: %d\n", $stp_group->{dot1dStpRootPort};
102             printf "ThisRootCost: %d\n", $stp_group->{dot1dStpRootCost};
103             printf "ThisStpPrio: %d\n", $stp_group->{dot1dStpPriority};
104             printf "RootBridgeMAC: %s\n", $stp_group->{dot1dStpDesignatedRootAddress};
105             printf "RootBridgePrio: %d\n", $stp_group->{dot1dStpDesignatedRootPriority};
106              
107             my $stp_ports = $session->get_dot1d_stp_port_table;
108             foreach my $port ( sort { $a <=> $b } keys %$stp_ports ) {
109             my $enabled = $stp_ports->{$port}{dot1dStpPortEnable};
110             next unless defined $enabled && $enabled == 1;
111              
112             printf "----------- STP Port: %d ---------\n", $port;
113             printf "PState: %d\n", $stp_ports->{$port}{dot1dStpPortState};
114             printf "PStateStr: %d\n", $stp_ports->{$port}{dot1dStpPortStateString};
115             printf "PPrio: %d\n", $stp_ports->{$port}{dot1dStpPortPriority};
116             printf "PCost: %d\n", $stp_ports->{$port}{dot1dStpPortPathCost};
117             printf "PDesigCost: %d\n", $stp_ports->{$port}{dot1dStpPortDesignatedCost};
118             printf "DBridgePrio: %d\n", $stp_ports->{$port}{dot1dStpPortDesignatedBridgePriority};
119             printf "DBridgeMAC: %d\n", $stp_ports->{$port}{dot1dStpPortDesignatedBridgeAddress};
120             printf "DPortPrio: %d\n", $stp_ports->{$port}{dot1dStpPortDesignatedPortPriority};
121             printf "DPortNr: %d\n", $stp_ports->{$port}{dot1dStpPortDesignatedPortNumber};
122             }
123              
124             =head1 DESCRIPTION
125              
126             This mixin reads data from the B<< dot1dStp >> group out of the BRIDGE-MIB. Normally it's implemented by those bridges that support the Spanning Tree Protocol. For Cisco NXOS devices the B<< mst-0 >> context is used behind the scenes.
127              
128             =head1 MIXIN METHODS
129              
130             =cut
131              
132             =head2 B<< OBJ->get_dot1d_stp_group() >>
133              
134             Returns the dot1dStp group as a hash reference:
135              
136             {
137             dot1dStpProtocolSpecification => INTEGER,
138             dot1dStpPriority => INTEGER,
139             dot1dStpTimeSinceTopologyChange => TIME_TICKS,
140             dot1dStpTopChanges => COUNTER,
141             dot1dStpRootCost => INTEGER,
142             dot1dStpRootPort => INTEGER,
143             dot1dStpMaxAge => TIMEOUT,
144             dot1dStpHelloTime => TIMEOUT,
145             dot1dStpHoldTime => INTEGER,
146             dot1dStpForwardDelay => TIMEOUT,
147             dot1dStpBridgeMaxAge => TIMEOUT,
148             dot1dStpBridgeHelloTime => TIMEOUT,
149             dot1dStpBridgeForwardDelay => TIMEOUT,
150             dot1dStpDesignatedRoot => BridgeId,
151             dot1dStpDesignatedRootPriority => INTEGER,
152             dot1dStpDesignatedRootAddress => MacAddress,
153             }
154              
155              
156             The dot1dStpDesignatedRoot is a BridgeId struct of priority and MacAddress. The mixin method splits this already into dot1dStpDesignatedRootPriority and dot1dStpDesignatedRootAddress for your convenience.
157              
158             =cut
159              
160             sub get_dot1d_stp_group {
161 1     1 1 30724 my $session = shift;
162 1         7 my $agent = $session->hostname;
163              
164 1 50       11 Carp::croak "$agent: '$prefix' not initialized,"
165             unless $session->init_ok($prefix);
166              
167             # just a shallow copy for shallow values
168 0         0 my $result = { %{ $session->{$prefix}{dot1dStpGroup} } };
  0         0  
169              
170             # split BridgeId in priority and address
171             my ( $root_bridge_prio, $root_bridge_address ) =
172 0         0 _unpack_bridge_id( $result->{dot1dStpDesignatedRoot} );
173              
174 0         0 $result->{dot1dStpDesignatedRootPriority} = $root_bridge_prio;
175 0         0 $result->{dot1dStpDesignatedRootAddress} = $root_bridge_address;
176              
177 0         0 return $result;
178             }
179              
180             =head2 B<< OBJ->get_dot1d_stp_port_table() >>
181              
182             Returns the dot1dStpPortTable as a hash reference. The keys are the dot1d STP port numbers for which this entry contains Spanning Tree Protocol management information:
183              
184             {
185             INTEGER => { # dot1dStpPort
186              
187             dot1dStpPortPriority => INTEGER,
188             dot1dStpPortState => INTEGER,
189             dot1dStpPortStateString => String,
190             dot1dStpPortEnable => INTEGER,
191             dot1dStpPortPathCost => INTEGER,
192             dot1dStpPortDesignatedRootId => BridgeId,
193             dot1dStpPortDesignatedCost => INTEGER,
194             dot1dStpPortDesignatedBridgeId => BridgeId,
195             dot1dStpPortDesignatedPort => PortId,
196             dot1dStpPortForwardTransitions => COUNTER,
197              
198             # dot1dStpPortDesignatedRootId is a struct (BridgeId) of
199             # priority and MacAddress
200             #
201             dot1dStpPortDesignatedRootPriority => INTEGER,
202             dot1dStpPortDesignatedRootAddress => MacAddress,
203              
204             # dot1dStpPortDesignatedBridgeId is a struct (BridgeId) of
205             # priority and MacAddress
206             #
207             dot1dStpPortDesignatedBridgePriority => INTEGER,
208             dot1dStpPortDesignatedBridgeAddress => MacAddress,
209              
210             # dot1dStpPortDesignatedPort is a struct (PortId) of
211             # priority and bridge port number
212             #
213             dot1dStpPortDesignatedPortPriority => INTEGER,
214             dot1dStpPortDesignatedPortNumber => INTEGER,
215              
216             },
217              
218             ... ,
219             }
220              
221             The structs BridgeId and PortId are already splitted by this mixin method into the relevant values for your convenience.
222              
223             The dot1dStpPort has the same value as the dot1dBasePort and isn't necessarily the ifIndex of the switch.
224              
225             See also the L<< Net::SNMP::Mixin::Dot1dBase >> for a mixin to get the mapping between the ifIndexes and the dot1dBasePorts if needed.
226              
227             =cut
228              
229             sub get_dot1d_stp_port_table {
230 1     1 1 727 my $session = shift;
231 1         5 my $agent = $session->hostname;
232              
233 1 50       7 Carp::croak "$agent: '$prefix' not initialized,"
234             unless $session->init_ok($prefix);
235              
236             # stash for return values
237 0         0 my $result = {};
238              
239             #
240             # the port's current state translation table
241             #
242 0         0 my %port_state_enum = (
243             1 => 'disabled',
244             2 => 'blocking',
245             3 => 'listening',
246             4 => 'learning',
247             5 => 'forwarding',
248             6 => 'broken',
249             );
250              
251             # the MIB tables are stored in {column}{row}{value} order
252             # but we return {row}{column}{value}
253             #
254             # grab all rows from one random choosen column
255 0         0 my @rows = keys %{ $session->{$prefix}{dot1dStpPortTbl}{dot1dStpPortPriority} };
  0         0  
256              
257 0         0 foreach my $row (@rows) {
258              
259             # loop over all columns
260 0         0 foreach my $column ( keys %{ $session->{$prefix}{dot1dStpPortTbl} } ) {
  0         0  
261              
262             # rebuild in reverse order: result(row,column) = stash(column,row)
263             # side effect: make a shallow copy for shallow values
264              
265 0         0 $result->{$row}{$column} = $session->{$prefix}{dot1dStpPortTbl}{$column}{$row};
266             }
267              
268             # additonal calculated values from the structs
269             #
270 0         0 $result->{$row}{dot1dStpPortStateString} = $port_state_enum{ $result->{$row}{dot1dStpPortState} };
271              
272 0         0 my ( $prio, $addr, $port );
273              
274             # split dot1dStpPortDesignatedRoot
275 0         0 ( $prio, $addr ) = _unpack_bridge_id( $result->{$row}{dot1dStpPortDesignatedRoot} );
276              
277 0         0 $result->{$row}{dot1dStpPortDesignatedRootPriority} = $prio;
278 0         0 $result->{$row}{dot1dStpPortDesignatedRootAddress} = $addr;
279              
280             # split dot1dStpPortDesignatedBridge
281 0         0 ( $prio, $addr ) = _unpack_bridge_id( $result->{$row}{dot1dStpPortDesignatedBridge} );
282              
283 0         0 $result->{$row}{dot1dStpPortDesignatedBridgePriority} = $prio;
284 0         0 $result->{$row}{dot1dStpPortDesignatedBridgeAddress} = $addr;
285              
286             # split dot1dStpPortDesignatedPort
287 0         0 ( $prio, $port ) = _unpack_bridge_port_id( $result->{$row}{dot1dStpPortDesignatedPort} );
288              
289 0         0 $result->{$row}{dot1dStpPortDesignatedPortPriority} = $prio;
290 0         0 $result->{$row}{dot1dStpPortDesignatedPortNumber} = $port;
291             }
292              
293 0         0 return $result;
294             }
295              
296             =head1 INITIALIZATION
297              
298             =head2 B<< OBJ->_init($reload) >>
299              
300             Fetch the dot1dSTP related snmp values from the host. Don't call this method direct!
301              
302             =cut
303              
304             #
305             # due to the asynchron nature, we don't know what init job is really the last, we decrement
306             # the value after each callback
307             #
308 4     4   34 use constant THIS_INIT_JOBS => 2;
  4         9  
  4         6344  
309              
310             sub _init {
311 4     4   9384 my ( $session, $reload ) = @_;
312              
313 4         12 my $agent = $session->hostname;
314              
315             die "$agent: $prefix already initialized and reload not forced.\n"
316             if exists get_init_slot($session)->{$prefix}
317 4 50 66     28 && get_init_slot($session)->{$prefix} == 0
      33        
318             && not $reload;
319              
320             # set number of async init jobs for proper initialization
321 4         107 get_init_slot($session)->{$prefix} = THIS_INIT_JOBS;
322              
323             # awful hack, fork a new session with original parameters but community@mst-0
324 4         45 my $ctx_session = _clone_ctx_session( $session, 'mst-0' );
325              
326             # link to parent session
327 4         8 $ctx_session->{_PARENT_SESSION} = $session;
328              
329             # populate the object with needed mib values
330             #
331             # initialize the object for STP infos
332 4         14 _fetch_dot1d_stp_group($ctx_session);
333 4 100       25 return if $session->error;
334              
335 1         9 _fetch_dot1d_stp_port_tbl($ctx_session);
336 1 50       9 return if $session->error;
337              
338 1         8 return 1;
339             }
340              
341             =head1 PRIVATE SUBROUTINES
342              
343             =head2 B<< _fetch_dot1d_stp_group($session) >>
344              
345             Fetch the local system data from the dot1dStp tree once during object initialization.
346              
347             =cut
348              
349             sub _fetch_dot1d_stp_group {
350 4     4   8 my $ctx_session = shift;
351 4         7 my $session = $ctx_session->{_PARENT_SESSION};
352              
353 4 100       17 my $result = $ctx_session->get_entries(
354             -columns => [ DOT1D_STP_GROUP, ],
355             -endindex => '14.0',
356              
357             # define callback if in nonblocking mode
358             $ctx_session->nonblocking ? ( -callback => \&_dot1d_stp_group_cb ) : (),
359              
360             );
361              
362 4 100       2010467 unless ( defined $result ) {
363 2         12 my $err_msg = $session->{_error} = $ctx_session->error;
364 2 50       37 push_error( $session, "$prefix: $err_msg" ) if $err_msg;
365 2         102 return;
366             }
367              
368             # in nonblocking mode the callback will be called asynchronously
369 2 50       8 return 1 if $ctx_session->nonblocking;
370              
371             # ok we are in synchronous mode, call the result mangling function by hand
372 0         0 _dot1d_stp_group_cb($ctx_session);
373              
374             }
375              
376             =head2 B<< _dot1d_stp_group_cb($session) >>
377              
378             The callback for _fetch_dot1d_stp_group.
379              
380             =cut
381              
382             sub _dot1d_stp_group_cb {
383 2     2   2005734 my $ctx_session = shift;
384 2         12 my $session = $ctx_session->{_PARENT_SESSION};
385              
386 2         11 my $vbl = $ctx_session->var_bind_list;
387              
388 2 50       29 unless ( defined $vbl ) {
389 2 50       13 if ( my $err_msg = $session->{_error} = $ctx_session->error ) {
390 2         41 push_error( $session, "$prefix: $err_msg" );
391             }
392 2         128 return;
393             }
394              
395 0 0       0 unless ( defined $vbl->{ DOT1D_STP_PROTO() } ) {
396 0         0 my $err_msg = "No Spanning Tree Protocol running";
397 0         0 push_error( $session, "$prefix: $err_msg" );
398 0         0 return;
399             }
400              
401 0         0 my $stash_ptr = $session->{$prefix}{dot1dStpGroup} = {};
402              
403 0         0 $stash_ptr->{dot1dStpProtocolSpecification} = $vbl->{ DOT1D_STP_PROTO() };
404 0         0 $stash_ptr->{dot1dStpPriority} = $vbl->{ DOT1D_STP_PRIO() };
405 0         0 $stash_ptr->{dot1dStpTimeSinceTopologyChange} = $vbl->{ DOT1D_STP_TIME_SINCE_TOPO_CHANGE() };
406 0         0 $stash_ptr->{dot1dStpTopChanges} = $vbl->{ DOT1D_STP_TOPO_CHANGES() };
407 0         0 $stash_ptr->{dot1dStpDesignatedRoot} = $vbl->{ DOT1D_STP_DESIGNATED_ROOT() };
408 0         0 $stash_ptr->{dot1dStpRootCost} = $vbl->{ DOT1D_STP_ROOT_COST() };
409 0         0 $stash_ptr->{dot1dStpRootPort} = $vbl->{ DOT1D_STP_ROOT_PORT() };
410 0         0 $stash_ptr->{dot1dStpMaxAge} = $vbl->{ DOT1D_STP_MAX_AGE() };
411 0         0 $stash_ptr->{dot1dStpHelloTime} = $vbl->{ DOT1D_STP_HELLO_TIME() };
412 0         0 $stash_ptr->{dot1dStpHoldTime} = $vbl->{ DOT1D_STP_HOLD_TIME() };
413 0         0 $stash_ptr->{dot1dStpForwardDelay} = $vbl->{ DOT1D_STP_FWD_DELAY() };
414 0         0 $stash_ptr->{dot1dStpBridgeMaxAge} = $vbl->{ DOT1D_STP_BRIDGE_MAX_AGE() };
415 0         0 $stash_ptr->{dot1dStpBridgeHelloTime} = $vbl->{ DOT1D_STP_BRIDGE_HELLO_TIME() };
416 0         0 $stash_ptr->{dot1dStpBridgeForwardDelay} = $vbl->{ DOT1D_STP_BRIDGE_FWD_DELAY() };
417              
418             # this init job is finished
419              
420 0         0 get_init_slot($session)->{$prefix}--;
421              
422 0         0 return 1;
423             }
424              
425             =head2 B<< _fetch_dot1d_stp_port_tbl($session) >>
426              
427             Fetch the dot1dStpPortTable once during object initialization.
428              
429             =cut
430              
431             sub _fetch_dot1d_stp_port_tbl {
432 1     1   3 my $ctx_session = shift;
433 1         2 my $session = $ctx_session->{_PARENT_SESSION};
434              
435             # fetch the dot1dStpPortTable
436 1 50       8 my $result = $ctx_session->get_entries(
437             -columns => [
438             DOT1D_STP_PORT_PRIO, DOT1D_STP_PORT_STATE,
439             DOT1D_STP_PORT_ENABLE, DOT1D_STP_PORT_PATH_COST,
440             DOT1D_STP_PORT_DESIGNATED_ROOT, DOT1D_STP_PORT_DESIGNATED_COST,
441             DOT1D_STP_PORT_DESIGNATED_BRIDGE, DOT1D_STP_PORT_DESIGNATED_PORT,
442             DOT1D_STP_PORT_FORWARD_TRANSITIONS,
443             ],
444              
445             # define callback if in nonblocking mode
446             $ctx_session->nonblocking ? ( -callback => \&_dot1d_stp_port_tbl_cb ) : (),
447             );
448              
449 1 50       2207 unless ( defined $result ) {
450              
451             # Net::SNMP looses sometimes error messages in nonblocking
452             # mode, so we save them in an extra buffer
453 0         0 my $err_msg = $session->{_error} = $ctx_session->error;
454 0 0       0 push_error( $session, "$prefix: $err_msg" ) if $err_msg;
455 0         0 return;
456             }
457              
458             # in nonblocking mode the callback will be called asynchronously
459 1 50       4 return 1 if $ctx_session->nonblocking;
460              
461             # ok we are in synchronous mode, call the result mangling function
462             # by hand
463 0         0 _dot1d_stp_port_tbl_cb($ctx_session);
464              
465             }
466              
467             =head2 B<< _dot1d_stp_port_tbl_cb($session) >>
468              
469             The callback for _fetch_dot1d_stp_port_tbl().
470              
471             =cut
472              
473             sub _dot1d_stp_port_tbl_cb {
474 1     1   438 my $ctx_session = shift;
475 1         4 my $session = $ctx_session->{_PARENT_SESSION};
476              
477 1         5 my $vbl = $ctx_session->var_bind_list;
478              
479 1 50       11 unless ( defined $vbl ) {
480 1 50       4 if ( my $err_msg = $session->{_error} = $ctx_session->error ) {
481 1         12 push_error( $session, "$prefix: $err_msg" );
482             }
483 1         31 return;
484             }
485              
486 0         0 my $stash_ptr = $session->{$prefix}{dot1dStpPortTbl} = {};
487              
488 0         0 $stash_ptr->{dot1dStpPortPriority} = idx2val( $vbl, DOT1D_STP_PORT_PRIO );
489 0         0 $stash_ptr->{dot1dStpPortState} = idx2val( $vbl, DOT1D_STP_PORT_STATE );
490 0         0 $stash_ptr->{dot1dStpPortEnable} = idx2val( $vbl, DOT1D_STP_PORT_ENABLE );
491 0         0 $stash_ptr->{dot1dStpPortPathCost} = idx2val( $vbl, DOT1D_STP_PORT_PATH_COST );
492 0         0 $stash_ptr->{dot1dStpPortDesignatedRoot} = idx2val( $vbl, DOT1D_STP_PORT_DESIGNATED_ROOT );
493 0         0 $stash_ptr->{dot1dStpPortDesignatedCost} = idx2val( $vbl, DOT1D_STP_PORT_DESIGNATED_COST );
494 0         0 $stash_ptr->{dot1dStpPortDesignatedBridge} = idx2val( $vbl, DOT1D_STP_PORT_DESIGNATED_BRIDGE );
495 0         0 $stash_ptr->{dot1dStpPortDesignatedPort} = idx2val( $vbl, DOT1D_STP_PORT_DESIGNATED_PORT );
496 0         0 $stash_ptr->{dot1dStpPortForwardTransitions} = idx2val( $vbl, DOT1D_STP_PORT_FORWARD_TRANSITIONS );
497              
498             # this init job is finished
499 0         0 get_init_slot($session)->{$prefix}--;
500              
501 0         0 return 1;
502             }
503              
504             =head2 B<< _unpack_bridge_id($bridgeId) >>
505              
506             Split a bridge id in priority and MAC address. Returns a list of (bridgePrio, bridgeMac).
507              
508             =cut
509              
510             sub _unpack_bridge_id {
511 0     0   0 my $bridgeId = shift;
512 0 0       0 return unless $bridgeId;
513              
514             # convert to untranslated OCTET_STRING in case it's
515             # already translated by Net::SNMP
516 0         0 $bridgeId = hex2octet($bridgeId);
517              
518             # the bridgeId struct is the concatenation of:
519             # dot1dStpPriority and dot1dStpBridgeMAC
520             #
521             # unpack the struct
522 0         0 my ( $bridgePrio, $bridgeMac ) = unpack 'nH*', $bridgeId;
523              
524             # convert to a normalized adress format
525 0         0 $bridgeMac = normalize_mac($bridgeMac);
526              
527 0         0 return ( $bridgePrio, $bridgeMac );
528             }
529              
530             =head2 B<< _unpack_bridge_port_id($bridgePortId) >>
531              
532             Split a bridge port id in priority and bridge port number. Returns a list of (portPrio, portNumber).
533              
534             =cut
535              
536             sub _unpack_bridge_port_id {
537 0     0   0 my $portId = shift;
538 0 0       0 return unless $portId;
539              
540             # convert to untranslated OCTET_STRING in case it's
541             # already translated by Net::SNMP
542 0         0 $portId = hex2octet($portId);
543              
544             # the portId is the concatenation of:
545             # portPriority(4bit) and dot1dBasePort(12bit)
546             #
547 0         0 my $portPrio = ( unpack 'n', $portId ) >> 12;
548 0         0 my $dot1dBasePort = ( unpack 'n', $portId ) & 0x0FFF;
549              
550             # priority <0-15> (default: 8 ) - The range of 0-240 is
551             # divided into 16 steps. These steps are numbered from
552             # 0 to 15. It is multiplied by 16 to calculate the
553             # priority value used by the STP protocol.
554              
555 0         0 $portPrio *= 16;
556              
557 0         0 return ( $portPrio, $dot1dBasePort );
558             }
559              
560             # awful HACK
561             # make new session for context, clone original params from parent session
562             # two steps needed: Net::SNMP->new() -> Net::SNMP->open()
563             sub _clone_ctx_session {
564 4     4   14 my ( $session, $ctx ) = @_;
565              
566 4         21 my $hostname = $session->hostname;
567 4         27 my $nonblocking = $session->nonblocking;
568 4         26 my $debug = $session->debug;
569 4         38 my $community = $session->security->{_community};
570 4         39 my $version = $session->version + 1; # 0,1,2
571              
572 4 50       38 die "$hostname: $prefix, SNMPv3 not supported," if $version eq 3;
573              
574             # STEP 1
575 4         29 my ( $ctx_session, $error ) = Net::SNMP->new(
576             -hostname => $hostname,
577             -version => $version,
578             -debug => $debug,
579             -nonblocking => $nonblocking,
580             -community => $community . '@' . $ctx, # e.g. public => public@mst-0
581             );
582              
583 4 50       2270 die "$hostname: $prefix, can't create ctx_session: $error\n" if $error;
584              
585             # clone more complex parameters from session
586 4         11 $ctx_session->{_translate} = $session->{_translate};
587 4         11 $ctx_session->{_transport_argv} = $session->{_transport_argv};
588              
589             # STEP 2
590             # open socket for this transport
591 4         17 $ctx_session->open();
592              
593 4 50       1270 unless ( defined $ctx_session->transport() ) {
594 0         0 my $error = $ctx_session->error;
595 0         0 die "$hostname: $prefix, can't open ctx_session: $error\n";
596             }
597              
598 4         27 return $ctx_session;
599             }
600              
601             =head1 LIMITATIONS
602              
603             Due to the hack with the B<< mst-0 >> context behind the scenes, this is currently B<< NOT >> supported for SNMPv3.
604              
605             =head1 SEE ALSO
606              
607             L<< Net::SNMP::Mixin::Dot1dBase >>
608              
609             =head1 REQUIREMENTS
610              
611             L<< Net::SNMP >>, L<< Net::SNMP::Mixin >>
612              
613             =head1 BUGS, PATCHES & FIXES
614              
615             There are no known bugs at the time of this release. However, if you spot a bug or are experiencing difficulties that are not explained within the POD documentation, please submit a bug to the RT system (see link below). However, it would help greatly if you are able to pinpoint problems or even supply a patch.
616              
617             Fixes are dependant upon their severity and my availablity. Should a fix not be forthcoming, please feel free to (politely) remind me by sending an email to gaissmai@cpan.org .
618              
619             RT: http://rt.cpan.org/Public/Dist/Display.html?Name=Net-SNMP-Mixin-NXOSDot1dStp
620              
621             =head1 AUTHOR
622              
623             Karl Gaissmaier
624              
625             =head1 COPYRIGHT & LICENSE
626              
627             Copyright 2020 Karl Gaissmaier, all rights reserved.
628              
629             This program is free software; you can redistribute it and/or modify it
630             under the same terms as Perl itself.
631              
632             =cut
633              
634             unless ( caller() ) {
635             print "$prefix compiles and initializes successful.\n";
636             }
637              
638             1;
639              
640             # vim: sw=2