File Coverage

blib/lib/Net/SNMP/Mixin/CiscoDot1qVlanStaticTrunks.pm
Criterion Covered Total %
statement 60 127 47.2
branch 21 48 43.7
condition 3 6 50.0
subroutine 16 19 84.2
pod 3 3 100.0
total 103 203 50.7


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