File Coverage

blib/lib/Net/SNMP/Mixin/Dot1qFdb.pm
Criterion Covered Total %
statement 44 70 62.8
branch 15 26 57.6
condition 1 6 16.6
subroutine 13 13 100.0
pod 1 1 100.0
total 74 116 63.7


line stmt bran cond sub pod time code
1             package Net::SNMP::Mixin::Dot1qFdb;
2              
3 4     4   397664 use strict;
  4         10  
  4         161  
4 4     4   53 use warnings;
  4         7  
  4         199  
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         14  
  4         108  
17 4     4   4366 use Net::SNMP::Mixin::Util qw/idx2val normalize_mac/;
  4         116959  
  4         56  
18              
19             #
20             # this module export config
21             #
22             my @mixin_methods;
23              
24             BEGIN {
25 4     4   1637 @mixin_methods = ( qw/ get_dot1q_fdb_entries /);
26             }
27              
28 4         37 use Sub::Exporter -setup => {
29             exports => [@mixin_methods],
30             groups => { default => [@mixin_methods], },
31 4     4   37 };
  4         11  
32              
33             #
34             # SNMP oid constants used in this module
35             #
36             use constant {
37 4         5268 DOT1Q_TP_FDB_TABLE => '1.3.6.1.2.1.17.7.1.2.2',
38             DOT1Q_TP_FDB_ADDRESS => '1.3.6.1.2.1.17.7.1.2.2.1.1',
39             DOT1Q_TP_FDB_PORT => '1.3.6.1.2.1.17.7.1.2.2.1.2',
40             DOT1Q_TP_FDB_STATUS => '1.3.6.1.2.1.17.7.1.2.2.1.3',
41              
42             DOT1Q_VLAN_CURRENT_FDB_ID => '1.3.6.1.2.1.17.7.1.4.2.1.3',
43 4     4   2436 };
  4         10  
44              
45             =head1 NAME
46              
47             Net::SNMP::Mixin::Dot1qFdb - mixin class for 802.1-Q switch forwarding databases
48              
49             =head1 VERSION
50              
51             Version 0.04
52              
53             =cut
54              
55             our $VERSION = '0.04';
56              
57             =head1 SYNOPSIS
58              
59             use Net::SNMP;
60             use Net::SNMP::Mixin qw/mixer init_mixins/;
61              
62             my $session = Net::SNMP->session( -hostname => 'foo.bar.com' );
63             $session->mixer('Net::SNMP::Mixin::Dot1qFdb');
64             $session->init_mixins();
65             snmp_dispatcher() if $session->nonblocking;
66             die $session->error if $session->error;
67              
68             foreach my $fdb_entry ( $session->get_dot1q_fdb_entries() ) {
69             my $mac = $fdb_entry->{MacAddress};
70             my $fdb_id = $fdb_entry->{fdbId};
71             my $vlan_id = $fdb_entry->{vlanId};
72             my $port = $fdb_entry->{dot1dBasePort};
73             my $status = $fdb_entry->{fdbStatus};
74              
75             print "$mac, $fdb_id, $vlan_id, $port, $status\n";
76             }
77              
78             =head1 DESCRIPTION
79              
80             A Net::SNMP mixin class for forwarding database info of 802.1-Q compatible switches. The switches must support parts of the standard Q-BRIDGE-MIB.
81              
82             Sorry to disappoint you, Cisco isn't standard conform, but you knew this already, for sure!
83              
84             =head1 MIXIN METHODS
85              
86             =head2 B<< @fdb = OBJ->get_dot1q_fdb_entries() >>
87              
88             Returns a list of fdb entries. Every list element is a reference to a hash with the following fields and values:
89              
90             {
91             MacAddress => 'XX:XX:XX:XX:XX:XX',
92             dot1dBasePort => Integer,
93             fdbId => Integer,
94             vlanId => Integer,
95             fdbStatus => Integer,
96             fdbStatusString => String,
97             }
98              
99             =over
100              
101             =item MacAddress
102              
103             MacAddress received, in normalized IEEE form XX:XX:XX:XX:XX:XX.
104              
105             =item dot1dBasePort
106              
107             The receiving bride-port for the MAC address.
108              
109             =item fdbId
110              
111             MacAddress is member of the FDB with this fdbId. dot1q bridges support many forwarding databases.
112              
113             =item vlanId
114              
115             Every fdbId is related to a distinct vlanId.
116              
117             =item fdbStatus
118              
119             The status of this entry. The meanings of the values are:
120              
121             1 = other
122             2 = invalid
123             3 = learned
124             4 = self
125             5 = mgmt
126              
127             For more information please see the corresponding Q-BRIDGE-MIB.
128              
129             =item fdbStatusString
130              
131             The status of this entry in string form, see above.
132              
133             =back
134              
135             =cut
136              
137             sub get_dot1q_fdb_entries {
138 1     1 1 87418 my $session = shift;
139 1 50       90 Carp::croak "'$prefix' not initialized,"
140             unless $session->{$prefix}{__initialized};
141              
142             #
143             # the port's current state translation table
144             #
145 0         0 my %fdp_entry_status_enum = (
146             1 => 'other',
147             2 => 'invalid',
148             3 => 'learned',
149             4 => 'self',
150             5 => 'mgmt',
151             );
152              
153             # stash for return values
154 0         0 my @fdb_entries = ();
155              
156 0         0 my ( @digits, $fdb_id, $vlan_id, $mac, $mac_string, $port, $status,
157             $status_string );
158              
159             # index is fdbId.MacAddress
160 0         0 foreach my $idx ( keys %{ $session->{$prefix}{dot1qTpFdbPort} } ) {
  0         0  
161 0         0 $port = $session->{$prefix}{dot1qTpFdbPort}{$idx};
162 0         0 $status = $session->{$prefix}{dot1qTpFdbStatus}{$idx};
163              
164             # the snmp get_table() isn't a snapshot, it can be, that
165             # the MAC has already timeout in the FDB when the
166             # status is fetched
167 0 0 0     0 next unless defined $port && defined $status;
168              
169 0         0 $status_string = $fdp_entry_status_enum{$status};
170              
171             # split the idx to fdb_id and mac address
172             # index is fdbId.MacAddress, value is the bridge port
173 0         0 @digits = split /\./, $idx;
174              
175 0         0 $fdb_id = $digits[0];
176 0         0 $vlan_id = $session->{$prefix}{fdb_id2vlan_id}{$fdb_id};
177              
178 0         0 $mac = pack( 'C6', @digits[ 1 .. 6 ] );
179 0         0 $mac_string = normalize_mac($mac);
180              
181 0         0 push @fdb_entries,
182             {
183             dot1dBasePort => $port,
184             MacAddress => $mac_string,
185             fdbId => $fdb_id,
186             vlanId => $vlan_id,
187             fdbStatus => $status,
188             fdbStatusString => $status_string,
189             };
190             }
191              
192 0         0 return @fdb_entries;
193             }
194              
195             =head1 INITIALIZATION
196              
197             =cut
198              
199             =head2 B<< OBJ->_init($reload) >>
200              
201             Fetch the fdb related snmp values from the host. Don't call this method direct!
202              
203             =cut
204              
205             sub _init {
206 4     4   11901 my ( $session, $reload ) = @_;
207              
208 4 50 33     38 die "$prefix already initalized and reload not forced.\n"
209             if $session->{$prefix}{__initialized} && not $reload;
210              
211             # initialize the object for forwarding databases infos
212 4         11 _fetch_dot1q_fdbid($session);
213 4 100       37 return if $session->error;
214              
215 2         17 _fetch_dot1q_tp_fdb_entries($session);
216 2 50       15 return if $session->error;
217              
218 2         14 return 1;
219             }
220              
221             =head1 PRIVATE METHODS
222              
223             Only for developers or maintainers.
224              
225             =head2 B<< _fetch_dot1q_fdbid() >>
226              
227             Fetch some columns from the VlanCurrentTable once during object initialization. MAC addresses in the forwarding database are related to fbd ids and the fbd ids are related to vlan ids by this column.
228              
229             =cut
230              
231             sub _fetch_dot1q_fdbid() {
232 4     4   12 my $session = shift;
233 4         7 my $result;
234              
235             # fetch the dot1qVlanFdbId from dot1qVlanCurrentTable
236 4 100       31 $result = $session->get_table(
237             -baseoid => DOT1Q_VLAN_CURRENT_FDB_ID,
238              
239             # define callback if in nonblocking mode
240             $session->nonblocking ? ( -callback => \&_dot1q_fdbid_cb ) : (),
241             );
242              
243 4 100       2018741 return unless defined $result;
244 2 50       10 return 1 if $session->nonblocking;
245              
246             # call the callback function in blocking mode by hand
247 0         0 _dot1q_fdbid_cb($session);
248              
249             }
250              
251             sub _dot1q_fdbid_cb {
252 2     2   2006756 my $session = shift;
253 2         10 my $vbl = $session->var_bind_list;
254              
255 2 50       25 return unless defined $vbl;
256              
257             # mangle result table to get plain vlan_id => fdb_id
258             #
259             # 1.3.6.1.2.1.17.7.1.4.2.1.3.0.n => m
260             # | | | |
261             # DOT1Q_VLAN_CURRENT_FDB_ID -------/ | | |
262             # dot1qVlanTimeMark ---------/ | |
263             # dot1qVlanIndex -----------/ |
264             # dot1qVlanFdbId ----------------/
265              
266             # vlan_id => fdb_id
267 0         0 $session->{$prefix}{vlan_id2fdb_id} =
268             idx2val( $vbl, DOT1Q_VLAN_CURRENT_FDB_ID, 1 );
269              
270             # build reverse map fdb_id => vlan_id
271 0         0 while ( my ( $vlan_id, $fdb_id ) =
  0         0  
272             each %{ $session->{$prefix}{vlan_id2fdb_id} } )
273             {
274              
275 0         0 $session->{$prefix}{fdb_id2vlan_id}{$fdb_id} = $vlan_id;
276             }
277              
278 0         0 $session->{$prefix}{__initialized}++;
279             }
280              
281             =head2 B<< _fetch_dot1q_tp_fdb_table() >>
282              
283             Fetch the forwarding databases from the dot1qTpFdbTable once during object initialization.
284              
285             =cut
286              
287             sub _fetch_dot1q_tp_fdb_entries() {
288 2     2   4 my $session = shift;
289 2         4 my $result;
290              
291             # fetch the forwarding databases from dot1qTpFdbTable
292 2 50       11 $result = $session->get_entries(
293             -columns => [ DOT1Q_TP_FDB_PORT, DOT1Q_TP_FDB_STATUS ],
294              
295             # define callback if in nonblocking mode
296             $session->nonblocking
297             ? ( -callback => \&_dot1q_tp_fdb_entries_cb )
298             : (),
299             );
300              
301 2 50       2164 return unless defined $result;
302 2 50       10 return 1 if $session->nonblocking;
303              
304             # call the callback function in blocking mode by hand
305 0         0 _dot1q_tp_fdb_entries_cb($session);
306              
307             }
308              
309             sub _dot1q_tp_fdb_entries_cb {
310 2     2   7696 my $session = shift;
311 2         11 my $vbl = $session->var_bind_list;
312              
313 2 50       27 return unless defined $vbl;
314              
315             # mangle result table to get plain idx->value
316             # index is fdbId.MacAddress, value is the bridge port
317 0           $session->{$prefix}{dot1qTpFdbPort} = idx2val( $vbl, DOT1Q_TP_FDB_PORT );
318              
319             # mangle result table to get plain idx->value
320             # index is fdbId.MacAddress, value is the entry status
321 0           $session->{$prefix}{dot1qTpFdbStatus} = idx2val( $vbl, DOT1Q_TP_FDB_STATUS );
322              
323 0           $session->{$prefix}{__initialized}++;
324             }
325              
326             =head1 SEE ALSO
327              
328             L<< Net::SNMP::Mixin::Dot1dBase >> for a mapping between ifIndexes and dot1dBasePorts.
329              
330             =head1 REQUIREMENTS
331              
332             L<< Net::SNMP >>, L<< Net::SNMP::Mixin >>
333              
334             =head1 BUGS, PATCHES & FIXES
335              
336             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.
337              
338             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 .
339              
340             RT: http://rt.cpan.org/Public/Dist/Display.html?Name=Net-SNMP-Mixin-Dot1qFdb
341              
342             =head1 AUTHOR
343              
344             Karl Gaissmaier
345              
346             =head1 COPYRIGHT & LICENSE
347              
348             Copyright 2008 Karl Gaissmaier, all rights reserved.
349              
350             This program is free software; you can redistribute it and/or modify it
351             under the same terms as Perl itself.
352              
353             =cut
354              
355             unless ( caller() ) {
356             print "$prefix compiles and initializes successful.\n";
357             }
358              
359             1;
360              
361             # vim: sw=2