File Coverage

blib/lib/Net/SNMP/Mixin/CiscoDot1qVlanStatic.pm
Criterion Covered Total %
statement 73 158 46.2
branch 29 68 42.6
condition 4 8 50.0
subroutine 18 21 85.7
pod 3 3 100.0
total 127 258 49.2


line stmt bran cond sub pod time code
1             package Net::SNMP::Mixin::CiscoDot1qVlanStatic;
2              
3 4     4   495284 use strict;
  4         14  
  4         131  
4 4     4   23 use warnings;
  4         12  
  4         159  
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         11  
  4         92  
17              
18 4     4   23 use Net::SNMP::Mixin::Util qw/idx2val hex2octet push_error get_init_slot/;
  4         10  
  4         30  
19              
20             #
21             # this module export config
22             #
23             my @mixin_methods;
24              
25             BEGIN {
26 4     4   2329 @mixin_methods = qw/
27             map_vlan_id2name
28             map_vlan_id2if_idx
29             map_if_idx2vlan_id
30             /;
31             }
32              
33 4         43 use Sub::Exporter -setup => {
34             exports => [@mixin_methods],
35             groups => { default => [@mixin_methods], },
36 4     4   35 };
  4         8  
37              
38             #
39             # SNMP oid constants from CISCO-VTP-MIB and CISCO-VLAN-MEMBERSHIP-MIB
40             #
41             use constant {
42             ###
43             # trunk ports: CISCO-VTP-MIB
44 4         1832 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_NATIVE_VLAN => '1.3.6.1.4.1.9.9.46.1.6.1.1.5',
51             VLAN_TRUNK_PORT_ENCAPS_OPER_TYPE => '1.3.6.1.4.1.9.9.46.1.6.1.1.16',
52             VLAN_TRUNK_PORT_VLANS_ENABLED_2K => '1.3.6.1.4.1.9.9.46.1.6.1.1.17',
53             VLAN_TRUNK_PORT_VLANS_ENABLED_3K => '1.3.6.1.4.1.9.9.46.1.6.1.1.18',
54             VLAN_TRUNK_PORT_VLANS_ENABLED_4K => '1.3.6.1.4.1.9.9.46.1.6.1.1.19',
55              
56             ###
57             # access ports: CISCO-VLAN-MEMBERSHIP-MIB
58             # table maybe empty!
59             #
60             # "A table for configuring VLAN port membership.
61             # There is one row for each bridge port that is
62             # assigned to a static or dynamic access port. Trunk
63             # ports are not represented in this table. An entry
64             # may be created and deleted when ports are created or
65             # deleted via SNMP or the management console on a
66             # device."
67              
68             VM_MEMBERSHIP_TABLE => '1.3.6.1.4.1.9.9.68.1.2.2',
69             VM_VLAN_TYPE => '1.3.6.1.4.1.9.9.68.1.2.2.1.1',
70             VM_VLAN => '1.3.6.1.4.1.9.9.68.1.2.2.1.2',
71 4     4   2351 };
  4         10  
72              
73             =head1 NAME
74              
75             Net::SNMP::Mixin::CiscoDot1qVlanStatic - mixin class for static Cisco vlan info
76              
77             =head1 VERSION
78              
79             Version 0.02
80              
81             =cut
82              
83             our $VERSION = '0.02';
84              
85             =head1 SYNOPSIS
86              
87             use Net::SNMP;
88             use Net::SNMP::Mixin;
89              
90             # initialize session and mixin library
91             my $session = Net::SNMP->session( -hostname => 'foo.bar.com' );
92             $session->mixer('Net::SNMP::Mixin::CiscoDot1qVlanStatic');
93             $session->init_mixins;
94             snmp_dispatcher();
95             $session->init_ok();
96             die $session->errors if $session->errors;
97              
98             # show VLAN IDs and corresponding names
99             my $id2name = $session - map_vlan_id2name();
100             foreach my $id ( keys %{$id2name} ) {
101             printf "Vlan-Id: %4d => Vlan-Name: %s\n", $id, $id2name->{$id};
102             }
103              
104             # sorted by vlan_id
105             my $vlan_ids2if_idx = $session->map_vlan_id2if_idx();
106             foreach my $id ( keys %{$vlan_ids2if_idx} ) {
107             printf "Vlan-Id: %4d\n", $id;
108             printf "\tTagged-Ports: %s\n", ( join ',', @{ $vlan_ids2if_idx->{$id}{tagged} } );
109             printf "\tUntagged-Ports: %s\n", ( join ',', @{ $vlan_ids2if_idx->{$id}{untagged} } );
110             }
111              
112             # sorted by interface
113             my $ports2ids = $session->map_if_idx2vlan_id();
114             foreach my $if_idx ( keys %{$ports2ids} ) {
115             printf "Interface: %10d\n", $if_idx;
116             printf "\tTagged-Vlans: %s\n", ( join ',', @{ $ports2ids->{$if_idx}{tagged} } );
117             printf "\tUntagged-Vlans: %s\n", ( join ',', @{ $ports2ids->{$if_idx}{untagged} } );
118             }
119              
120             =head1 DESCRIPTION
121              
122             A mixin class for vlan related infos from the CISCO-VTP-MIB for 802.1Q-trunks and
123             CISCO-VLAN-MEMBERSHIP-MIB for access ports.
124             The mixin-module provides methods for mapping between vlan-ids and vlan-names und relations between
125             interfaces and vlan-ids, tagged or untagged on these ports.
126              
127             =head1 MIXIN METHODS
128              
129             =head2 B<< OBJ->map_vlan_id2name() >>
130              
131             Returns a hash reference with vlan-ids as keys and the corresponding vlan-names as values:
132              
133             {
134             vlan_id => vlan_name,
135             vlan_id => vlan_name,
136             ... ,
137             }
138              
139             =cut
140              
141             sub map_vlan_id2name {
142 1     1 1 29901 my $session = shift;
143             Carp::croak "'$prefix' not initialized,"
144 1 50       86 unless $session->{$prefix}{__initialized};
145              
146 0         0 return $session->{$prefix}{vlan_id2name};
147             }
148              
149             =head2 B<< OBJ->map_vlan_id2if_idx() >>
150              
151             Returns a hash reference with the vlan-ids as keys and tagged and untagged if_idx as values:
152              
153             {
154             vlan_id => {
155             tagged => [if_idx, ..., ],
156             untagged => [if_idx, ..., ],
157             },
158              
159             ... ,
160             }
161            
162             =cut
163              
164             sub map_vlan_id2if_idx {
165 1     1 1 599 my $session = shift;
166             Carp::croak "'$prefix' not initialized,"
167 1 50       89 unless $session->{$prefix}{__initialized};
168              
169 0         0 return _get_vlan_ids2if_idx($session);
170             }
171              
172             =head2 B<< OBJ->map_if_idx2vlan_id() >>
173              
174             Returns a hash reference with the interfaces as keys and tagged and untagged vlan-ids as values:
175              
176             {
177             if_idx => {
178             tagged => [vlan_id, ..., ],
179             untagged => [vlan_id, ..., ],
180             },
181              
182             ... ,
183             }
184            
185             =cut
186              
187             sub map_if_idx2vlan_id {
188 1     1 1 572 my $session = shift;
189             Carp::croak "'$prefix' not initialized,"
190 1 50       84 unless $session->{$prefix}{__initialized};
191              
192 0         0 return _get_if_idx2vlan_ids($session);
193             }
194              
195             =head1 INITIALIZATION
196              
197             =head2 B<< OBJ->_init($reload) >>
198              
199             Fetch basic Vlan related SNMP values from the host. Don't call this method direct!
200              
201             =cut
202              
203             #
204             # due to the asynchron nature, we don't know what init job is really the last, we decrement
205             # the value after each callback
206             #
207 4     4   37 use constant THIS_INIT_JOBS => 3;
  4         18  
  4         7052  
208              
209             sub _init {
210 4     4   9785 my ( $session, $reload ) = @_;
211              
212 4         18 my $agent = $session->hostname;
213              
214             die "$agent: $prefix already initialized and reload not forced.\n"
215             if exists get_init_slot($session)->{$prefix}
216 4 50 66     32 && get_init_slot($session)->{$prefix} == 0
      33        
217             && not $reload;
218              
219             # set number of async init jobs for proper initialization
220 4         116 get_init_slot($session)->{$prefix} = THIS_INIT_JOBS;
221              
222             # initialize the object for vtp vlan table
223 4         49 _fetch_vtp_vlan_tbl_entries($session);
224 4 100       117 return if $session->error;
225              
226             # initialize the object for vtp vlan trunk port table for trunk ports
227 2         21 _fetch_vtp_vlan_trunk_port_tbl_entries($session);
228 2 50       13 return if $session->error;
229              
230             # initialize the object for vlan membership table of access ports
231 2         16 _fetch_vm_membership_tbl_entries($session);
232 2 50       12 return if $session->error;
233              
234 2         14 return 1;
235             }
236              
237             =head1 PRIVATE METHODS
238              
239             Only for developers or maintainers.
240              
241             =head2 B<< _fetch_vtp_vlan_tbl_entries($session) >>
242              
243             Fetch selected rows from vtpVlanTable during object initialization.
244              
245             =cut
246              
247             sub _fetch_vtp_vlan_tbl_entries {
248 4     4   9 my $session = shift;
249 4         19 my $result;
250              
251             # fetch the vlan state and name from vlanTable
252 4 100       28 $result = $session->get_entries(
    50          
253             -columns => [ VLAN_STATE, VLAN_NAME, ],
254              
255             # define callback if in nonblocking mode
256             $session->nonblocking
257             ? ( -callback => \&_vtp_vlan_tbl_entries_cb )
258             : (),
259              
260             # dangerous for snmp version 2c and 3, big values
261             # snmp-error: Message size exceeded buffer maxMsgSize
262             #
263             $session->version ? ( -maxrepetitions => 3 ) : (),
264             );
265              
266 4 100       2011393 return unless defined $result;
267 2 50       21 return 1 if $session->nonblocking;
268              
269             # call the callback function in blocking mode by hand
270 0         0 _vtp_vlan_tbl_entries_cb($session);
271              
272             }
273              
274             =head2 B<< _vtp_vlan_tbl_entries_cb($session) >>
275              
276             The callback for _fetch_vtp_vlan_tbl_entries.
277              
278             =cut
279              
280             sub _vtp_vlan_tbl_entries_cb {
281 2     2   2005586 my $session = shift;
282 2         14 my $vbl = $session->var_bind_list;
283              
284 2 50       30 unless ( defined $vbl ) {
285 2 50       14 if ( my $err_msg = $session->error ) {
286 2         48 push_error( $session, "$prefix: $err_msg" );
287             }
288 2         125 return;
289             }
290              
291             # mangle result table to get plain
292             # VlanIndex => vlan-state
293             #
294 0         0 $session->{$prefix}{_VlanState} = idx2val( $vbl, VLAN_STATE, 1 );
295              
296             # mangle result table to get plain
297             # VlanIndex => vlan-name
298             #
299 0         0 $session->{$prefix}{vlan_id2name} = idx2val( $vbl, VLAN_NAME, 1 );
300              
301             # purge non operational vlans, see CISCO-VTP-MIB
302 0         0 foreach my $vlan_id ( keys %{ $session->{$prefix}{vlan_id2name} } ) {
  0         0  
303             delete $session->{$prefix}{vlan_id2name}{$vlan_id}
304 0 0       0 unless $session->{$prefix}{_VlanState}{$vlan_id} == 1;
305             }
306              
307             # this init job is finished
308 0         0 get_init_slot($session)->{$prefix}--;
309              
310 0         0 return 1;
311             }
312              
313             =head2 B<< _fetch_vtp_vlan_trunk_port_tbl_entries($session) >>
314              
315             Fetch selected rows from vlanTrunkPortTable during object initialization.
316              
317             =cut
318              
319             sub _fetch_vtp_vlan_trunk_port_tbl_entries {
320 2     2   6 my $session = shift;
321 2         5 my $result;
322              
323             # fetch selected entries from vlanTrunkPortTable
324 2 50       15 $result = $session->get_entries(
    50          
325             -columns => [
326             VLAN_TRUNK_PORT_ENCAPS_OPER_TYPE,
327             VLAN_TRUNK_PORT_NATIVE_VLAN,
328              
329             VLAN_TRUNK_PORT_VLANS_ENABLED_1K,
330             VLAN_TRUNK_PORT_VLANS_ENABLED_2K,
331             VLAN_TRUNK_PORT_VLANS_ENABLED_3K,
332             VLAN_TRUNK_PORT_VLANS_ENABLED_4K,
333             ],
334              
335             # define callback if in nonblocking mode
336             $session->nonblocking ? ( -callback => \&_vtp_vlan_trunk_port_tbl_entries_cb ) : (),
337              
338             # dangerous for snmp version 2c and 3, big values
339             # snmp-error: Message size exceeded buffer maxMsgSize
340             #
341             $session->version ? ( -maxrepetitions => 3 ) : (),
342             );
343              
344 2 50       3462 return unless defined $result;
345 2 50       10 return 1 if $session->nonblocking;
346              
347             # call the callback function in blocking mode by hand
348 0         0 _vtp_vlan_trunk_port_tbl_entries_cb($session);
349              
350             }
351              
352             =head2 B<< _vtp_vlan_trunk_port_tbl_entries_cb($session) >>
353              
354             The callback for _fetch_vtp_vlan_trunk_port_tbl_entries.
355              
356             =cut
357              
358             sub _vtp_vlan_trunk_port_tbl_entries_cb {
359 2     2   1297 my $session = shift;
360 2         11 my $vbl = $session->var_bind_list;
361              
362 2 50       26 unless ( defined $vbl ) {
363 2 50       10 if ( my $err_msg = $session->error ) {
364 2         28 push_error( $session, "$prefix: $err_msg" );
365             }
366 2         120 return;
367             }
368              
369             # mangle result table to get plain
370             # ifIndex => vlans-enabled-bitstring
371             #
372             $session->{$prefix}{_VlansEnabled1k} =
373 0         0 idx2val( $vbl, VLAN_TRUNK_PORT_VLANS_ENABLED_1K, );
374              
375             $session->{$prefix}{_VlansEnabled2k} =
376 0         0 idx2val( $vbl, VLAN_TRUNK_PORT_VLANS_ENABLED_2K, );
377              
378             $session->{$prefix}{_VlansEnabled3k} =
379 0         0 idx2val( $vbl, VLAN_TRUNK_PORT_VLANS_ENABLED_3K, );
380              
381             $session->{$prefix}{_VlansEnabled4k} =
382 0         0 idx2val( $vbl, VLAN_TRUNK_PORT_VLANS_ENABLED_4K, );
383              
384             $session->{$prefix}{_VlansEncapsOperType} =
385 0         0 idx2val( $vbl, VLAN_TRUNK_PORT_ENCAPS_OPER_TYPE, );
386              
387             $session->{$prefix}{NativeVlan} =
388 0         0 idx2val( $vbl, VLAN_TRUNK_PORT_NATIVE_VLAN, );
389              
390 0         0 $session->{$prefix}{__initialized}++;
391              
392 0         0 _calc_tagged_ports($session);
393              
394             # this init job is finished
395 0         0 get_init_slot($session)->{$prefix}--;
396              
397 0         0 return 1;
398             }
399              
400             sub _calc_tagged_ports {
401 0     0   0 my $session = shift;
402              
403             # prepare fillmask, see below
404 0         0 my $zeroes_1k = pack( 'B*', 0 x 1024 );
405              
406             # iterate over any hash to get the interfaces as keys
407 0         0 foreach my $if_idx ( keys %{ $session->{$prefix}{NativeVlan} } ) {
  0         0  
408              
409             # only dot1Q(4) is supported, see CISCO-VTP-MIB
410 0 0       0 if ( $session->{$prefix}{_VlansEncapsOperType}{$if_idx} != 4 ) {
411 0         0 $session->{$prefix}{TaggedVlans}{$if_idx} = undef;
412 0         0 next;
413             }
414              
415             # for all phys interfaces get the tagged vlans
416             # represented in OCTET-STRINGS
417              
418 0         0 my $vlans_1k = $session->{$prefix}{_VlansEnabled1k}{$if_idx};
419 0         0 my $vlans_2k = $session->{$prefix}{_VlansEnabled2k}{$if_idx};
420 0         0 my $vlans_3k = $session->{$prefix}{_VlansEnabled3k}{$if_idx};
421 0         0 my $vlans_4k = $session->{$prefix}{_VlansEnabled4k}{$if_idx};
422              
423             # It's important that the returned SNMP OCTET-STRINGs were untranslated by Net::SNMP!
424             # If already translated, we must convert it back to a pure OCTET-STRING
425             # and fill it with zeroes to a length of 128-OCTETS = 1024-BITS
426              
427 0         0 my $vlans_1k_octets = hex2octet($vlans_1k) ^ $zeroes_1k;
428 0         0 my $vlans_2k_octets = hex2octet($vlans_2k) ^ $zeroes_1k;
429 0         0 my $vlans_3k_octets = hex2octet($vlans_3k) ^ $zeroes_1k;
430 0         0 my $vlans_4k_octets = hex2octet($vlans_4k) ^ $zeroes_1k;
431              
432             # unpack it into a bit-string
433 0         0 my $vlans_1k_bits = unpack( 'B*', $vlans_1k_octets );
434 0         0 my $vlans_2k_bits = unpack( 'B*', $vlans_2k_octets );
435 0         0 my $vlans_3k_bits = unpack( 'B*', $vlans_3k_octets );
436 0         0 my $vlans_4k_bits = unpack( 'B*', $vlans_4k_octets );
437              
438             # concat all 4k possible vlan_ids as bitstring
439 0         0 $session->{$prefix}{TaggedVlans}{$if_idx} =
440             $vlans_1k_bits . $vlans_2k_bits . $vlans_3k_bits . $vlans_4k_bits;
441             }
442              
443             }
444              
445             =head2 B<< _fetch_vm_membership_tbl_entries($session) >>
446              
447             Fetch selected rows from vmMembershipTable during object initialization.
448             The table maybe empty if there is no switch port in access mode.
449              
450             =cut
451              
452             sub _fetch_vm_membership_tbl_entries {
453 2     2   6 my $session = shift;
454 2         4 my $result;
455              
456             # fetch selected entries from vmMembershipTable
457 2 50       9 $result = $session->get_entries(
    50          
458             -columns => [ VM_VLAN_TYPE, VM_VLAN ],
459              
460             # define callback if in nonblocking mode
461             $session->nonblocking ? ( -callback => \&_vm_membership_tbl_entries_cb ) : (),
462              
463             # dangerous for snmp version 2c and 3, big values
464             # snmp-error: Message size exceeded buffer maxMsgSize
465             #
466             $session->version ? ( -maxrepetitions => 3 ) : (),
467             );
468              
469 2 50       2346 return unless defined $result;
470 2 50       9 return 1 if $session->nonblocking;
471              
472             # call the callback function in blocking mode by hand
473 0         0 _vm_membership_tbl_entries_cb($session);
474              
475             }
476              
477             =head2 B<< _vm_membership_tbl_entries_cb($session) >>
478              
479             The callback for _fetch_vm_membership_tbl_entries.
480              
481             =cut
482              
483             sub _vm_membership_tbl_entries_cb {
484 2     2   1122 my $session = shift;
485 2         11 my $vbl = $session->var_bind_list;
486              
487 2 50       27 unless ( defined $vbl ) {
488 2   50     11 my $err_msg = $session->error // '';
489              
490 2 50       21 if ( $err_msg !~ m/The requested entries are empty or do not exist/i ) {
491 2 50       20 push_error( $session, "$prefix: $err_msg" ) if defined $err_msg;
492             }
493             else {
494             # the table maybe empty if the device has no access ports
495 0         0 $session->{$prefix}{AccessVlan} = {};
496              
497             # this init slot is finished even if table is empty!
498 0         0 get_init_slot($session)->{$prefix}--;
499             }
500              
501 2         64 return;
502             }
503              
504             # mangle result table to get plain
505             # ifIndex => values
506             #
507             $session->{$prefix}{_VlanType} =
508 0           idx2val( $vbl, VM_VLAN_TYPE, );
509              
510             $session->{$prefix}{_VlanId} =
511 0           idx2val( $vbl, VM_VLAN, );
512              
513 0           foreach my $if_idx ( keys %{ $session->{$prefix}{_VlanType} } ) {
  0            
514              
515             # only static(1) vlans are supported, see CISCO-VLAN-MEMBERSHIP-MIB
516 0 0         next if $session->{$prefix}{_VlanType}{$if_idx} != 1;
517              
518 0           $session->{$prefix}{AccessVlan}{$if_idx} = $session->{$prefix}{_VlanId}{$if_idx};
519             }
520              
521             # this init job is finished
522 0           get_init_slot($session)->{$prefix}--;
523              
524 0           return 1;
525             }
526              
527             # Process tagged/untagged ports for each vlan
528             sub _get_vlan_ids2if_idx {
529 0     0     my $session = shift;
530              
531 0           my $result;
532 0           foreach my $vlan_id ( sort keys %{ $session->{$prefix}{vlan_id2name} } ) {
  0            
533 0           $result->{$vlan_id}{tagged} = [];
534 0           $result->{$vlan_id}{untagged} = [];
535              
536             # iterate over any hash from VTP table to get all interfaces
537 0           foreach my $if_idx ( sort keys %{ $session->{$prefix}{NativeVlan} } ) {
  0            
538              
539             # access ports
540 0 0         if ( my $access_vlan = $session->{$prefix}{AccessVlan}{$if_idx} ) {
541 0 0         push( @{ $result->{$vlan_id}{untagged} }, $if_idx ) if $access_vlan == $vlan_id;
  0            
542              
543             # next interface
544 0           next;
545             }
546              
547             # trunk ports
548 0 0         next unless defined $session->{$prefix}{TaggedVlans}{$if_idx};
549              
550 0 0         if ( substr( $session->{$prefix}{TaggedVlans}{$if_idx}, $vlan_id, 1 ) eq 1 ) {
551 0 0         if ( $session->{$prefix}{NativeVlan}{$if_idx} != $vlan_id ) {
552              
553             # ... and it's not the native vlan of this trunk
554 0           push @{ $result->{$vlan_id}{tagged} }, $if_idx;
  0            
555             }
556             else {
557             # ... it's the native vlan of this trunk
558 0           push @{ $result->{$vlan_id}{untagged} }, $if_idx;
  0            
559             }
560             }
561             }
562             }
563              
564 0           return $result;
565             }
566              
567             # Process tagged/untagged vlans for each interface
568             #
569             # reverse datastructure vlan_ids to ports ==> ports to vlan ids
570             #
571             # FROM:
572             # vlan_id => {
573             # tagged => [if_idx, ..., ],
574             # untagged => [if_idx, ..., ],
575             # },
576             #
577             # TO:
578             # if_idx => {
579             # tagged => [vlan_id, ..., ],
580             # untagged => [vlan_id, ..., ],
581             # },
582             #
583             sub _get_if_idx2vlan_ids {
584 0     0     my $vlan_ids2if_idx = _get_vlan_ids2if_idx(shift);
585              
586 0           my $result;
587 0           foreach my $vlan_id ( keys %$vlan_ids2if_idx ) {
588 0           foreach my $if_idx ( @{ $vlan_ids2if_idx->{$vlan_id}{tagged} } ) {
  0            
589 0           push @{ $result->{$if_idx}{tagged} }, $vlan_id;
  0            
590             }
591 0           foreach my $if_idx ( @{ $vlan_ids2if_idx->{$vlan_id}{untagged} } ) {
  0            
592 0           push @{ $result->{$if_idx}{untagged} }, $vlan_id;
  0            
593             }
594             }
595 0           return $result;
596             }
597              
598             =head1 REQUIREMENTS
599              
600             L<< Net::SNMP >>, L<< Net::SNMP::Mixin >>
601              
602             =head1 BUGS, PATCHES & FIXES
603              
604             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.
605              
606             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 .
607              
608             RT: http://rt.cpan.org/Public/Dist/Display.html?Name=Net-SNMP-Mixin-CiscoDot1qVlanStatic
609              
610             =head1 AUTHOR
611              
612             Karl Gaissmaier
613              
614             =head1 COPYRIGHT & LICENSE
615              
616             Copyright 2020 Karl Gaissmaier, all rights reserved.
617              
618             This program is free software; you can redistribute it and/or modify it
619             under the same terms as Perl itself.
620              
621             =cut
622              
623             unless ( caller() ) {
624             print "$prefix compiles and initializes successful.\n";
625             }
626              
627             1;
628              
629             # vim: sw=2