File Coverage

blib/lib/Net/SNMP/Mixin/Dot1dStp.pm
Criterion Covered Total %
statement 62 140 44.2
branch 19 42 45.2
condition 3 6 50.0
subroutine 15 17 88.2
pod 2 2 100.0
total 101 207 48.7


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