File Coverage

blib/lib/Net/SNMP/Mixin/CiscoDot1qVlanStaticTrunks.pm
Criterion Covered Total %
statement 52 115 45.2
branch 19 44 43.1
condition 1 3 33.3
subroutine 16 19 84.2
pod 3 3 100.0
total 91 184 49.4


line stmt bran cond sub pod time code
1             package Net::SNMP::Mixin::CiscoDot1qVlanStaticTrunks;
2              
3 4     4   721655 use strict;
  4         13  
  4         262  
4 4     4   25 use warnings;
  4         8  
  4         182  
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   24 use Carp ();
  4         12  
  4         83  
17 4     4   23 use Net::SNMP ();
  4         7  
  4         108  
18 4     4   5333 use Net::SNMP::Mixin::Util qw/idx2val hex2octet/;
  4         6484  
  4         38  
19              
20             #
21             # this module export config
22             #
23             my @mixin_methods;
24              
25             BEGIN {
26 4     4   2184 @mixin_methods = (
27             qw/
28             cisco_vlan_ids2names
29             cisco_vlan_ids2trunk_ports
30             cisco_trunk_ports2vlan_ids
31             /
32             );
33             }
34              
35 4         36 use Sub::Exporter -setup => {
36             exports => [@mixin_methods],
37             groups => { default => [@mixin_methods], },
38 4     4   75 };
  4         9  
39              
40             #
41             # SNMP oid constants from CISCO-VTP-MIB
42             #
43             use constant {
44 4         8681 VLAN_TBL => '1.3.6.1.4.1.9.9.46.1.3.1',
45             VLAN_STATE => '1.3.6.1.4.1.9.9.46.1.3.1.1.2',
46             VLAN_NAME => '1.3.6.1.4.1.9.9.46.1.3.1.1.4',
47              
48             VLAN_TRUNK_PORT_TBL => '1.3.6.1.4.1.9.9.46.1.6.1',
49             VLAN_TRUNK_PORT_VLANS_ENABLED_1K => '1.3.6.1.4.1.9.9.46.1.6.1.1.4',
50             VLAN_TRUNK_PORT_ENCAPS_OPER_TYPE => '1.3.6.1.4.1.9.9.46.1.6.1.1.16',
51             VLAN_TRUNK_PORT_VLANS_ENABLED_2K => '1.3.6.1.4.1.9.9.46.1.6.1.1.17',
52             VLAN_TRUNK_PORT_VLANS_ENABLED_3K => '1.3.6.1.4.1.9.9.46.1.6.1.1.18',
53             VLAN_TRUNK_PORT_VLANS_ENABLED_4K => '1.3.6.1.4.1.9.9.46.1.6.1.1.19',
54 4     4   2413 };
  4         10  
55              
56             =head1 NAME
57              
58             Net::SNMP::Mixin::CiscoDot1qVlanStaticTrunks - mixin class for static Cisco IEEE-trunks info
59              
60             =head1 VERSION
61              
62             Version 0.01
63              
64             =cut
65              
66             our $VERSION = '0.01';
67              
68             =head1 SYNOPSIS
69              
70             use Net::SNMP;
71             use Net::SNMP::Mixin qw/mixer init_mixins/;
72              
73             # initialize session and mixin library
74             my $session = Net::SNMP->session( -hostname => 'foo.bar.com' );
75             $session->mixer('Net::SNMP::Mixin::CiscoDot1qVlanStaticTrunks');
76             $session->init_mixins;
77             snmp_dispatcher() if $session->nonblocking;
78             die $session->error if $session->error;
79              
80             # show VLAN IDs and corresponding names
81             my $id2name = $session->cisco_vlan_ids2names();
82             foreach my $vlan_id ( keys %{$id2name} ) {
83             printf "Vlan-Id: %4d => Vlan-Name: %s\n", $vlan_id,
84             $id2name->{$vlan_id};
85             }
86              
87             # show ports for vlan_id
88             my $id2port = $session->cisco_vlan_ids2trunk_ports();
89             foreach my $vlan_id ( keys %{$id2port} ) {
90             printf "Vlan-Id: %4d\n", $vlan_id;
91             printf "\tTagged-Ports: %s\n",
92             ( join ',', @{ $id2port->{$vlan_id} } );
93             }
94              
95             # show tagged vlans for port
96             my $port2id = $session->cisco_trunk_ports2vlan_ids();
97             foreach my $port ( keys %{$port2id} ) {
98             printf "Port: %s\n", $port;
99             printf "\tVLANs: %s\n", ( join ',', @{ $port2id->{$port} } );
100             }
101              
102             =head1 DESCRIPTION
103              
104             A mixin class for vlan related infos from the CISCO-VTP-MIB for IEEE-trunks. The mixin-module provides methods for mapping between vlan-ids and vlan-names und relations between trunk-ports and tagged vlan-ids.
105              
106             =head1 MIXIN METHODS
107              
108             =head2 B<< OBJ->cisco_vlan_ids2names() >>
109              
110             Returns a hash reference with statically configured vlan-ids as keys and the corresponing vlan-names as values:
111              
112             {
113             vlan_id => vlan_name,
114             vlan_id => vlan_name,
115             ... ,
116             }
117              
118             =cut
119              
120             sub cisco_vlan_ids2names {
121 1     1 1 40584 my $session = shift;
122 1 50       124 Carp::croak "'$prefix' not initialized,"
123             unless $session->{$prefix}{__initialized};
124              
125 0         0 return $session->{$prefix}{VlanName};
126             }
127              
128             =head2 B<< OBJ->cisco_vlan_ids2trunk_ports() >>
129              
130             Returns a hash reference with the vlan-ids as keys and tagged port-lists as values:
131              
132             {
133             vlan_id => [port_list],
134             vlan_id => [port_list],
135             ... ,
136             }
137            
138             =cut
139              
140             sub cisco_vlan_ids2trunk_ports {
141 1     1 1 428 my $session = shift;
142 1 50       113 Carp::croak "'$prefix' not initialized,"
143             unless $session->{$prefix}{__initialized};
144              
145 0         0 delete $session->{$prefix}{vlans2ports};
146 0         0 _calc_vlans2ports($session);
147              
148 0         0 return $session->{$prefix}{vlans2ports};
149             }
150              
151             =head2 B<< OBJ->cisco_trunk_ports2vlan_ids() >>
152              
153             Returns a hash reference with the ifIndexes as keys and tagged vlan-ids as values:
154              
155             {
156             ifIndex => [vlan_id_list],
157             ifIndex => [vlan_id_list],
158             ... ,
159             }
160            
161            
162             =cut
163              
164             sub cisco_trunk_ports2vlan_ids {
165 1     1 1 487 my $session = shift;
166 1 50       124 Carp::croak "'$prefix' not initialized,"
167             unless $session->{$prefix}{__initialized};
168              
169 0         0 delete $session->{$prefix}{ports2vlans};
170 0         0 _calc_ports2vlans($session);
171              
172 0         0 return $session->{$prefix}{ports2vlans};
173             }
174              
175             =head1 INITIALIZATION
176              
177             =head2 B<< OBJ->_init($reload) >>
178              
179             Fetch basic Cisco-VTP Dot1Q Vlan related snmp values from the host. Don't call this method direct!
180              
181             =cut
182              
183             sub _init {
184 4     4   17570 my ( $session, $reload ) = @_;
185              
186 4 50 33     39 die "$prefix already initalized and reload not forced.\n"
187             if $session->{$prefix}{__initialized} && not $reload;
188              
189 4         11 delete $session->{$prefix}{__initialized};
190              
191             # initialize the object for vtp vlan table
192 4         14 _fetch_vtp_vlan_tbl_entries($session);
193 4 100       37 return if $session->error;
194              
195             # initialize the object for vtp vlan trunk port table
196 2         18 _fetch_vtp_vlan_trunk_port_tbl_entries($session);
197 2 50       19 return if $session->error;
198              
199 2         17 return 1;
200             }
201              
202             =head1 PRIVATE METHODS
203              
204             Only for developers or maintainers.
205              
206             =head2 B<< _fetch_vtp_vlan_tbl_entries($session) >>
207              
208             Fetch selected rows from vtpVlanTable during object initialization.
209              
210             =cut
211              
212             sub _fetch_vtp_vlan_tbl_entries {
213 4     4   9 my $session = shift;
214 4         6 my $result;
215              
216             # fetch the vlan state and vlan name from vlanTable
217 4 100       44 $result = $session->get_entries(
    50          
218             -columns => [ VLAN_STATE, VLAN_NAME, ],
219              
220             # define callback if in nonblocking mode
221             $session->nonblocking
222             ? ( -callback => \&_vtp_vlan_tbl_entries_cb )
223             : (),
224              
225             # dangerous for snmp version 2c and 3, big values
226             # snmp-error: Message size exceeded buffer maxMsgSize
227             #
228             $session->version ? ( -maxrepetitions => 3 ) : (),
229             );
230              
231 4 100       2012847 return unless defined $result;
232 2 50       8 return 1 if $session->nonblocking;
233              
234             # call the callback function in blocking mode by hand
235 0         0 _vtp_vlan_tbl_entries_cb($session);
236              
237             }
238              
239             =head2 B<< _vtp_vlan_tbl_entries_cb($session) >>
240              
241             The callback for _fetch_vtp_vlan_tbl_entries.
242              
243             =cut
244              
245             sub _vtp_vlan_tbl_entries_cb {
246 2     2   2005952 my $session = shift;
247 2         10 my $vbl = $session->var_bind_list;
248              
249 2 50       29 return unless defined $vbl;
250              
251             # mangle result table to get plain
252             # VlanIndex => vlan-state
253             #
254 0         0 $session->{$prefix}{VlanState} = idx2val( $vbl, VLAN_STATE, 1 );
255              
256             # mangle result table to get plain
257             # VlanIndex => vlan-name
258             #
259 0         0 $session->{$prefix}{VlanName} = idx2val( $vbl, VLAN_NAME, 1 );
260              
261 0         0 foreach my $vlan_id ( keys %{ $session->{$prefix}{VlanName} } ) {
  0         0  
262              
263             # delete unless the vlan is operational(1), see CISCO-VTP-MIB
264 0 0       0 delete $session->{$prefix}{VlanName}{$vlan_id}
265             unless $session->{$prefix}{VlanState}{$vlan_id} == 1;
266              
267             }
268              
269             }
270              
271             =head2 B<< _fetch_vtp_vlan_trunk_port_tbl_entries($session) >>
272              
273             Fetch selected rows from vlanTrunkPortTable during object initialization.
274              
275             =cut
276              
277             sub _fetch_vtp_vlan_trunk_port_tbl_entries {
278 2     2   5 my $session = shift;
279 2         3 my $result;
280              
281             # fetch selected entries from vlanTrunkPortTable
282 2 50       67 $result = $session->get_entries(
    50          
283             -columns => [
284             VLAN_TRUNK_PORT_VLANS_ENABLED_1K,
285             VLAN_TRUNK_PORT_VLANS_ENABLED_2K,
286             VLAN_TRUNK_PORT_VLANS_ENABLED_3K,
287             VLAN_TRUNK_PORT_VLANS_ENABLED_4K,
288             VLAN_TRUNK_PORT_ENCAPS_OPER_TYPE,
289             ],
290              
291             # define callback if in nonblocking mode
292             $session->nonblocking
293             ? ( -callback => \&_vtp_vlan_trunk_port_tbl_entries )
294             : (),
295              
296             # dangerous for snmp version 2c and 3, big values
297             # snmp-error: Message size exceeded buffer maxMsgSize
298             #
299             $session->version ? ( -maxrepetitions => 3 ) : (),
300             );
301              
302 2 50       3370 return unless defined $result;
303 2 50       7 return 1 if $session->nonblocking;
304              
305             # call the callback function in blocking mode by hand
306 0         0 _vtp_vlan_trunk_port_tbl_entries($session);
307              
308             }
309              
310             =head2 B<< _vtp_vlan_trunk_port_tbl_entries($session) >>
311              
312             The callback for _fetch_vtp_vlan_trunk_port_tbl_entries.
313              
314             =cut
315              
316             sub _vtp_vlan_trunk_port_tbl_entries {
317 2     2   709 my $session = shift;
318 2         11 my $vbl = $session->var_bind_list;
319              
320 2 50       24 return unless defined $vbl;
321              
322             # mangle result table to get plain
323             # ifIndex => vlans-enabled-bitstring
324             #
325 0           $session->{$prefix}{VlansEnabled1k} =
326             idx2val( $vbl, VLAN_TRUNK_PORT_VLANS_ENABLED_1K, );
327              
328 0           $session->{$prefix}{VlansEnabled2k} =
329             idx2val( $vbl, VLAN_TRUNK_PORT_VLANS_ENABLED_2K, );
330              
331 0           $session->{$prefix}{VlansEnabled3k} =
332             idx2val( $vbl, VLAN_TRUNK_PORT_VLANS_ENABLED_3K, );
333              
334 0           $session->{$prefix}{VlansEnabled4k} =
335             idx2val( $vbl, VLAN_TRUNK_PORT_VLANS_ENABLED_4K, );
336              
337 0           $session->{$prefix}{VlansEncapsOperType} =
338             idx2val( $vbl, VLAN_TRUNK_PORT_ENCAPS_OPER_TYPE, );
339              
340 0           $session->{$prefix}{__initialized}++;
341              
342 0           foreach my $if_idx ( keys %{ $session->{$prefix}{VlansEncapsOperType} } )
  0            
343             {
344              
345             # delete keys unless the trunk is dot1Q(4), see CISCO-VTP-MIB
346 0 0         if ( $session->{$prefix}{VlansEncapsOperType}{$if_idx} != 4 ) {
347              
348 0           delete $session->{$prefix}{VlansEnabled1k}{$if_idx};
349 0           delete $session->{$prefix}{VlansEnabled2k}{$if_idx};
350 0           delete $session->{$prefix}{VlansEnabled3k}{$if_idx};
351 0           delete $session->{$prefix}{VlansEnabled4k}{$if_idx};
352             }
353              
354             }
355              
356 0           _calc_vlans_enabled($session);
357             }
358              
359             sub _calc_vlans_enabled {
360 0     0     my $session = shift;
361              
362             # prepare fillmask, see below
363 0           my $zeroes_1k = pack( 'B*', 0 x 1024 );
364              
365 0           foreach my $if_idx ( keys %{ $session->{$prefix}{VlansEnabled1k} } ) {
  0            
366              
367             # for all phys interfaces get the tagged vlans
368             # represented in OCTET-STRINGS, maybe already
369             # translated to hex by Net::SNMP
370              
371 0           my $vlans_1k = $session->{$prefix}{VlansEnabled1k}{$if_idx};
372 0           my $vlans_2k = $session->{$prefix}{VlansEnabled2k}{$if_idx};
373 0           my $vlans_3k = $session->{$prefix}{VlansEnabled3k}{$if_idx};
374 0           my $vlans_4k = $session->{$prefix}{VlansEnabled4k}{$if_idx};
375              
376             # It's importend that the returned SNMP OCTET-STRINGs
377             # were untranslated by Net::SNMP!
378             # If already translated, we must convert it back to a
379             # pure OCTET-STRING and fill it with zeroes to a
380             # length of 128-OCTETS = 1024-BITS
381              
382 0           my $vlans_1k_octets = hex2octet($vlans_1k) ^ $zeroes_1k;
383 0           my $vlans_2k_octets = hex2octet($vlans_2k) ^ $zeroes_1k;
384 0           my $vlans_3k_octets = hex2octet($vlans_3k) ^ $zeroes_1k;
385 0           my $vlans_4k_octets = hex2octet($vlans_4k) ^ $zeroes_1k;
386              
387             # unpack it into a bit-string
388              
389 0           my $vlans_1k_bits = unpack( 'B*', $vlans_1k_octets );
390 0           my $vlans_2k_bits = unpack( 'B*', $vlans_2k_octets );
391 0           my $vlans_3k_bits = unpack( 'B*', $vlans_3k_octets );
392 0           my $vlans_4k_bits = unpack( 'B*', $vlans_4k_octets );
393              
394 0           $session->{$prefix}{VlansEnabled}{$if_idx} =
395             $vlans_1k_bits . $vlans_2k_bits . $vlans_3k_bits . $vlans_4k_bits;
396              
397             }
398             }
399              
400             # Process tag information for each phys interface
401             sub _calc_ports2vlans {
402 0     0     my $session = shift;
403              
404             # calculate the tagged vlans for each port
405              
406 0           foreach my $if_idx ( keys %{ $session->{$prefix}{VlansEnabled} } ) {
  0            
407              
408             # preset with empty arrayref
409 0 0         $session->{$prefix}{ports2vlans}{$if_idx} = []
410             unless exists $session->{$prefix}{ports2vlans}{$if_idx};
411              
412 0           foreach my $vlan_id ( keys %{ $session->{$prefix}{VlanName} } ) {
  0            
413              
414 0 0         if ( substr( $session->{$prefix}{VlansEnabled}{$if_idx}, $vlan_id, 1 ) eq 1 ) {
415 0           push @{ $session->{$prefix}{ports2vlans}{$if_idx} }, $vlan_id;
  0            
416             }
417              
418             }
419             }
420             }
421              
422             # Process tag information for each phys interface
423             sub _calc_vlans2ports {
424 0     0     my $session = shift;
425              
426             # calculate the tagged ports for each vlan
427              
428 0           foreach my $if_idx ( keys %{ $session->{$prefix}{VlansEnabled} } ) {
  0            
429              
430 0           foreach my $vlan_id ( keys %{ $session->{$prefix}{VlanName} } ) {
  0            
431              
432             # preset with empty arrayref
433 0 0         $session->{$prefix}{vlans2ports}{$vlan_id} = []
434             unless exists $session->{$prefix}{vlans2ports}{$vlan_id};
435              
436              
437 0 0         if ( substr( $session->{$prefix}{VlansEnabled}{$if_idx}, $vlan_id, 1 ) eq 1 ) {
438 0           push @{ $session->{$prefix}{vlans2ports}{$vlan_id} }, $if_idx;
  0            
439             }
440              
441             }
442             }
443             }
444              
445             =head1 REQUIREMENTS
446              
447             L<< Net::SNMP >>, L<< Net::SNMP::Mixin >>
448              
449             =head1 BUGS, PATCHES & FIXES
450              
451             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.
452              
453             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 .
454              
455             RT: http://rt.cpan.org/Public/Dist/Display.html?Name=Net-SNMP-Mixin-CiscoDot1qVlanStaticTrunks
456              
457             =head1 AUTHOR
458              
459             Karl Gaissmaier
460              
461             =head1 COPYRIGHT & LICENSE
462              
463             Copyright 2011 Karl Gaissmaier, all rights reserved.
464              
465             This program is free software; you can redistribute it and/or modify it
466             under the same terms as Perl itself.
467              
468             =cut
469              
470             unless ( caller() ) {
471             print "$prefix compiles and initializes successful.\n";
472             }
473              
474             1;
475              
476             # vim: sw=2
477             ## Please see file perltidy.ERR