File Coverage

blib/lib/Net/SNMP/Mixin/Dot1qFdb.pm
Criterion Covered Total %
statement 50 78 64.1
branch 15 26 57.6
condition 3 9 33.3
subroutine 14 14 100.0
pod 1 1 100.0
total 83 128 64.8


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