File Coverage

blib/lib/Net/SNMP/Mixin/ArubaCX/Dot1qFdb.pm
Criterion Covered Total %
statement 46 66 69.7
branch 12 20 60.0
condition 3 9 33.3
subroutine 12 12 100.0
pod 1 1 100.0
total 74 108 68.5


line stmt bran cond sub pod time code
1             package Net::SNMP::Mixin::ArubaCX::Dot1qFdb;
2              
3 4     4   411127 use strict;
  4         13  
  4         142  
4 4     4   26 use warnings;
  4         10  
  4         177  
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   25 use Carp ();
  4         26  
  4         115  
17 4     4   637 use Net::SNMP::Mixin::Util qw/idx2val normalize_mac push_error get_init_slot/;
  4         101010  
  4         40  
18              
19             #
20             # this module export config
21             #
22             my @mixin_methods;
23              
24             BEGIN {
25 4     4   2444 @mixin_methods = (qw/ get_dot1q_fdb_entries /);
26             }
27              
28 4         40 use Sub::Exporter -setup => {
29             exports => [@mixin_methods],
30             groups => { default => [@mixin_methods], },
31 4     4   39 };
  4         10  
32              
33             #
34             # SNMP oid constants used in this module
35             #
36             use constant {
37 4         1794 DOT1Q_TP_FDB_TABLE => '1.3.6.1.2.1.17.7.1.2.2',
38             DOT1Q_TP_FDB_PORT => '1.3.6.1.2.1.17.7.1.2.2.1.2',
39             DOT1Q_TP_FDB_STATUS => '1.3.6.1.2.1.17.7.1.2.2.1.3',
40              
41 4     4   2150 };
  4         10  
42              
43             =head1 NAME
44              
45             Net::SNMP::Mixin::ArubaCX::Dot1qFdb - mixin class for ArubaCX switch forwarding databases
46              
47             =cut
48              
49             our $VERSION = '0.02';
50              
51             =head1 SYNOPSIS
52              
53             use Net::SNMP;
54             use Net::SNMP::Mixin;
55              
56             my $session = Net::SNMP->session( -hostname => 'foo.bar.com' );
57             $session->mixer('Net::SNMP::Mixin::ArubaCX::Dot1qFdb');
58             $session->init_mixins();
59             snmp_dispatcher() if $session->nonblocking;
60             $session->init_ok();
61             die $session->errors if $session->errors;
62              
63             foreach my $fdb_entry ( $session->get_dot1q_fdb_entries() ) {
64             my $mac = $fdb_entry->{MacAddress};
65             my $vlan_id = $fdb_entry->{vlanId};
66             my $port = $fdb_entry->{dot1dBasePort};
67             my $status = $fdb_entry->{fdbStatus};
68              
69             print "$mac, $vlan_id, $port, $status\n";
70             }
71              
72             =head1 DESCRIPTION
73              
74             A Net::SNMP mixin class for forwarding database info of ArubaCX 802.1-Q limited MIBs.
75              
76             =head1 MIXIN METHODS
77              
78             =head2 B<< @fdb = OBJ->get_dot1q_fdb_entries() >>
79              
80             Returns a list of fdb entries. Every list element is a reference to a hash with the following fields and values:
81              
82             {
83             MacAddress => 'XX:XX:XX:XX:XX:XX',
84             dot1dBasePort => Integer,
85             vlanId => Integer,
86             fdbStatus => Integer,
87             fdbStatusString => String,
88             }
89              
90             =over
91              
92             =item MacAddress
93              
94             MacAddress received, in normalized IEEE form XX:XX:XX:XX:XX:XX.
95              
96             =item dot1dBasePort
97              
98             The receiving bride-port for the MAC address.
99              
100             =item vlanId
101              
102             Every MacAdress is related to a distinct vlanId.
103              
104             =item fdbStatus
105              
106             The status of this entry. The meanings of the values are:
107              
108             1 = other
109             2 = invalid
110             3 = learned
111             4 = self
112             5 = mgmt
113              
114             For more information please see the corresponding Q-BRIDGE-MIB.
115              
116             =item fdbStatusString
117              
118             The status of this entry in string form, see above.
119              
120             =back
121              
122             =cut
123              
124             sub get_dot1q_fdb_entries {
125 1     1 1 31618 my $session = shift;
126 1         6 my $agent = $session->hostname;
127              
128 1 50       10 Carp::croak "$agent: '$prefix' not initialized,"
129             unless $session->init_ok($prefix);
130              
131             #
132             # the port's current state translation table
133             #
134 0         0 my %fdp_entry_status_enum = (
135             1 => 'other',
136             2 => 'invalid',
137             3 => 'learned',
138             4 => 'self',
139             5 => 'mgmt',
140             );
141              
142             # stash for return values
143 0         0 my @fdb_entries = ();
144              
145 0         0 my ( @digits, $vlan_id, $mac, $mac_string, $port, $status, $status_string );
146              
147             # index is VlanId.MacAddress
148 0         0 foreach my $idx ( keys %{ $session->{$prefix}{dot1qTpFdbPort} } ) {
  0         0  
149 0         0 $port = $session->{$prefix}{dot1qTpFdbPort}{$idx};
150 0         0 $status = $session->{$prefix}{dot1qTpFdbStatus}{$idx};
151              
152             # the snmp get_table() isn't a snapshot, it can be, that
153             # the MAC has already timeout in the FDB when the
154             # status is fetched
155 0 0 0     0 next unless defined $port && defined $status;
156              
157 0         0 $status_string = $fdp_entry_status_enum{$status};
158              
159             # split the idx to vlan_id and mac address
160             # index is VlanId.MacAddress, value is the bridge port
161 0         0 @digits = split /\./, $idx;
162              
163 0         0 $vlan_id = $digits[0];
164              
165 0         0 $mac = pack( 'C6', @digits[ 1 .. 6 ] );
166 0         0 $mac_string = normalize_mac($mac);
167              
168 0         0 push @fdb_entries,
169             {
170             dot1dBasePort => $port,
171             MacAddress => $mac_string,
172             vlanId => $vlan_id,
173             fdbStatus => $status,
174             fdbStatusString => $status_string,
175             };
176             }
177              
178 0         0 return @fdb_entries;
179             }
180              
181             =head1 INITIALIZATION
182              
183             =cut
184              
185             =head2 B<< OBJ->_init($reload) >>
186              
187             Fetch the fdb related snmp values from the host. Don't call this method direct!
188              
189             =cut
190              
191             #
192             # due to the asynchron nature, we don't know what init job is really the last, we decrement
193             # the value after each callback
194             #
195 4     4   43 use constant THIS_INIT_JOBS => 1;
  4         9  
  4         2162  
196              
197             sub _init {
198 4     4   9885 my ( $session, $reload ) = @_;
199 4         16 my $agent = $session->hostname;
200              
201             die "$agent: $prefix already initialized and reload not forced.\n"
202             if exists get_init_slot($session)->{$prefix}
203 4 50 66     32 && get_init_slot($session)->{$prefix} == 0
      33        
204             && not $reload;
205              
206             # set number of async init jobs for proper initialization
207 4         136 get_init_slot($session)->{$prefix} = THIS_INIT_JOBS;
208              
209 4         58 _fetch_dot1q_tp_fdb_entries($session);
210 4 100       30 return if $session->error;
211              
212 2         22 return 1;
213             }
214              
215             =head1 PRIVATE METHODS
216              
217             Only for developers or maintainers.
218              
219             =head2 B<< _fetch_dot1q_tp_fdb_table() >>
220              
221             Fetch the forwarding databases from the dot1qTpFdbTable once during object initialization.
222              
223             =cut
224              
225             sub _fetch_dot1q_tp_fdb_entries() {
226 4     4   12 my $session = shift;
227 4         21 my $result;
228              
229             # fetch the forwarding databases from dot1qTpFdbTable
230 4 100       31 $result = $session->get_entries(
231             -columns => [ DOT1Q_TP_FDB_PORT, DOT1Q_TP_FDB_STATUS ],
232              
233             # define callback if in nonblocking mode
234             $session->nonblocking
235             ? ( -callback => \&_dot1q_tp_fdb_entries_cb )
236             : (),
237             );
238              
239 4 100       2012361 unless ( defined $result ) {
240 2         15 my $err_msg = $session->{_error} = $session->error;
241 2 50       53 push_error( $session, "$prefix: $err_msg" ) if $err_msg;
242 2         157 return;
243             }
244              
245 2 50       12 return 1 if $session->nonblocking;
246              
247             # call the callback function in blocking mode by hand
248 0         0 _dot1q_tp_fdb_entries_cb($session);
249              
250             }
251              
252             sub _dot1q_tp_fdb_entries_cb {
253 2     2   2006332 my $session = shift;
254 2         13 my $vbl = $session->var_bind_list;
255              
256 2 50       30 unless ( defined $vbl ) {
257 2 50       18 if ( my $err_msg = $session->{_error} = $session->error ) {
258 2         42 push_error( $session, "$prefix: $err_msg" );
259             }
260 2         98 return;
261             }
262              
263             # mangle result table to get plain idx->value
264             # index is fdbId.MacAddress, value is the bridge port
265 0           $session->{$prefix}{dot1qTpFdbPort} = idx2val( $vbl, DOT1Q_TP_FDB_PORT );
266              
267             # mangle result table to get plain idx->value
268             # index is fdbId.MacAddress, value is the entry status
269 0           $session->{$prefix}{dot1qTpFdbStatus} = idx2val( $vbl, DOT1Q_TP_FDB_STATUS );
270              
271             # this init job is finished
272 0           get_init_slot($session)->{$prefix}--;
273              
274 0           return 1;
275             }
276              
277             =head1 SEE ALSO
278              
279             L<< Net::SNMP::Mixin::Dot1dBase >> for a mapping between ifIndexes and bridgePorts.
280              
281             =head1 REQUIREMENTS
282              
283             L<< Net::SNMP >>, L<< Net::SNMP::Mixin >>
284              
285             =head1 AUTHOR
286              
287             Karl Gaissmaier
288              
289             =head1 COPYRIGHT & LICENSE
290              
291             Copyright 2021 Karl Gaissmaier, all rights reserved.
292              
293             This program is free software; you can redistribute it and/or modify it
294             under the same terms as Perl itself.
295              
296             =cut
297              
298             unless ( caller() ) {
299             print "$prefix compiles and initializes successful.\n";
300             }
301              
302             1;
303              
304             # vim: sw=2