1# SNMP::Info::CiscoStpExtensions
2#
3# Copyright (c)2009 Carlos Vicente
4# All rights reserved.
5#
6# Redistribution and use in source and binary forms, with or without
7# modification, are permitted provided that the following conditions are met:
8#
9#     * Redistributions of source code must retain the above copyright notice,
10#       this list of conditions and the following disclaimer.
11#     * Redistributions in binary form must reproduce the above copyright notice,
12#       this list of conditions and the following disclaimer in the documentation
13#       and/or other materials provided with the distribution.
14#     * Neither the name of the author nor the
15#       names of its contributors may be used to endorse or promote products
16#       derived from this software without specific prior written permission.
17#
18# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
22# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
25# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29package SNMP::Info::CiscoStpExtensions;
30
31use strict;
32use warnings;
33use Exporter;
34use SNMP::Info;
35use SNMP::Info::Bridge;
36
37our ($VERSION, $DEBUG, %MIBS, %FUNCS, %GLOBALS, %MUNGE, %PORTSTAT, $INIT);
38
39$VERSION = '3.81';
40
41@SNMP::Info::CiscoStpExtensions::ISA = qw/SNMP::Info::Bridge SNMP::Info Exporter/;
42@SNMP::Info::CiscoStpExtensions::EXPORT_OK = qw//;
43
44%MIBS    = (
45            %SNMP::Info::Bridge::MIBS,
46            'CISCO-STP-EXTENSIONS-MIB' => 'stpxSpanningTreeType',
47           );
48
49%GLOBALS = (
50            %SNMP::Info::Bridge::GLOBALS,
51            'stpx_mst_config_digest' => 'stpxSMSTConfigDigest',
52            'stpx_mst_region_name'   => 'stpxMSTRegionName',
53            'stpx_mst_region_rev'    => 'stpxSMSTRegionRevision',
54            'stpx_stp_type'          => 'stpxSpanningTreeType',
55            'stpx_bpduguard_enable'  => 'stpxFastStartBpduGuardEnable',
56            'stpx_bpdufilter_enable' => 'stpxFastStartBpduFilterEnable',
57            'stpx_faststart_default' => 'stpxFastStartGlobalDefaultMode',
58           );
59
60%FUNCS   = (
61            %SNMP::Info::Bridge::FUNCS,
62            'stpx_rootguard_enabled'      => 'stpxRootGuardConfigEnabled',
63            'stpx_loopguard_enabled'      => 'stpxLoopGuardConfigEnabled',
64            'stpx_faststart_enabled'      => 'stpxFastStartPortEnable',
65            'stpx_faststart_operational'  => 'stpxFastStartPortMode',
66            'stpx_port_bpduguard_mode'    => 'stpxFastStartPortBpduGuardMode',
67            'stpx_port_bpdufilter_mode'   => 'stpxFastStartPortBpduFilterMode',
68            'stpx_smst_root'              => 'stpxSMSTInstanceCISTRegionalRoot',
69            'stpx_smst_vlans_mapped_1k2k' => 'stpxSMSTInstanceVlansMapped1k2k',
70            'stpx_smst_vlans_mapped_3k4k' => 'stpxSMSTInstanceVlansMapped3k4k',
71           );
72
73%MUNGE   = (
74            %SNMP::Info::Bridge::MUNGE,
75           'stpx_mst_config_digest'      => \&SNMP::Info::CiscoStpExtensions::oct2str,
76           );
77
78
79# Report version of STP via standard method
80sub stp_ver {
81     my $self = shift;
82     my $stp_ver = $self->SUPER::stp_ver();
83     if ( !defined($stp_ver) || $stp_ver eq 'unknown' ){
84         if ( defined $self->stpx_stp_type() ){
85             $stp_ver = $self->stpx_stp_type();
86         }
87     }
88     return $stp_ver;
89}
90
91sub mst_config_digest {
92    my $self = shift;
93    return $self->stpx_mst_config_digest;
94}
95
96sub mst_region_name {
97    my $self = shift;
98    return $self->stpx_mst_region_name;
99}
100
101sub mst_region_rev {
102    my $self = shift;
103    return $self->stpx_mst_region_rev;
104}
105
106
107sub mst_vlan2instance {
108    my $self = shift;
109
110    # Get MST vlan-to-instance mapping
111    my $m1k2k = $self->stpx_smst_vlans_mapped_1k2k;
112    my $m3k4k = $self->stpx_smst_vlans_mapped_3k4k;
113
114    # Get list of VLANs
115    my $vlan_membership = $self->i_vlan_membership;
116    my @vlans;
117    foreach my $iid ( keys %$vlan_membership ){
118        if ( my $vm = $vlan_membership->{$iid} ){
119            foreach my $vid ( @$vm ){
120                push @vlans, $vid;
121            }
122        }
123    }
124    my %res;
125    foreach my $vlan ( @vlans ){
126        if ( $vlan < 2048 ){
127            foreach my $inst ( keys %$m1k2k ){
128                my $list = $m1k2k->{$inst};
129                my $vlanlist = [split(//, unpack("B*", $list))];
130                if ( @$vlanlist[$vlan] ){
131                    $res{$vlan} = $inst;
132                    last;
133                }
134            }
135        }else{
136            foreach my $inst ( keys %$m3k4k ){
137                my $list = $m3k4k->{$inst};
138                my $vlanlist = [split(//, unpack("B*", $list))];
139                if ( @$vlanlist[$vlan-2048] ){
140                    $res{$vlan} = $inst;
141                    last;
142                }
143            }
144        }
145    }
146    return \%res;
147}
148
149sub i_rootguard_enabled {
150    my $self    = shift;
151    my $partial = shift;
152
153    my $rg_enabled = $self->stpx_rootguard_enabled();
154    my $bp_index   = $self->bp_index($partial);
155
156    my %res;
157    foreach my $index ( keys %$rg_enabled ){
158        my $enabled = $rg_enabled->{$index};
159        my $iid     = $bp_index->{$index};
160        next unless defined $iid;
161        next unless defined $enabled;
162        $res{$iid} = $enabled;
163    }
164    return \%res;
165}
166
167sub i_loopguard_enabled {
168    my $self    = shift;
169    my $partial = shift;
170
171    my $lg_enabled = $self->stpx_loopguard_enabled();
172    my $bp_index   = $self->bp_index($partial);
173
174    my %res;
175    foreach my $index ( keys %$lg_enabled ){
176        my $enabled = $lg_enabled->{$index};
177        my $iid     = $bp_index->{$index};
178        next unless defined $iid;
179        next unless defined $enabled;
180        $res{$iid} = $enabled;
181    }
182    return \%res;
183}
184
185sub i_bpduguard_enabled {
186    my $self    = shift;
187    my $partial = shift;
188
189    my $bpdugm_default = $self->stpx_bpduguard_enable();
190    my $bp_index       = $self->bp_index($partial);
191    my $bpdugm         = $self->stpx_port_bpduguard_mode();
192
193    my %res;
194    foreach my $index ( keys %$bpdugm ){
195        my $mode = $bpdugm->{$index};
196        my $iid  = $bp_index->{$index};
197        next unless defined $iid;
198        next unless defined $mode;
199        if ( $mode eq 'default' ){
200            $res{$iid} =  $bpdugm_default;
201        }else{
202            $res{$iid} = $mode;
203        }
204    }
205    return \%res;
206}
207
208sub i_bpdufilter_enabled {
209    my $self    = shift;
210    my $partial = shift;
211
212    my $bpdufm_default = $self->stpx_bpdufilter_enable();
213    my $bp_index       = $self->bp_index($partial);
214    my $bpdufm         = $self->stpx_port_bpdufilter_mode();
215
216    my %res;
217    foreach my $index ( keys %$bpdufm ){
218        my $mode = $bpdufm->{$index};
219        my $iid  = $bp_index->{$index};
220        next unless defined $iid;
221        next unless defined $mode;
222        if ( $mode eq 'default' ){
223            $res{$iid} =  $bpdufm_default;
224        }else{
225            $res{$iid} = $mode;
226        }
227    }
228    return \%res;
229}
230
231sub i_faststart_enabled {
232    my $self    = shift;
233    my $partial = shift;
234
235    my $faststart_default = $self->stpx_faststart_default();
236    my $bp_index          = $self->bp_index($partial);
237    my $faststart         = $self->stpx_faststart_enabled();
238    my $faststart_oper    = $self->stpx_faststart_operational();
239
240    my %res;
241    # stpxFastStartPortEnable is deprecated in favour of stpxFastStartPortMode
242    # see https://github.com/netdisco/netdisco/issues/12
243    foreach my $index ( keys %$faststart, keys %$faststart_oper ){
244        my $mode = $faststart_oper->{$index} || $faststart->{$index};
245        my $iid  = $bp_index->{$index};
246        next unless defined $iid;
247        next unless defined $mode;
248        if ( $mode eq 'default' ){
249            $res{$iid} =  $faststart_default;
250        }else{
251            $res{$iid} = $mode;
252        }
253        $res{$iid} = 'enable'  if $res{$iid} eq 'true';
254        $res{$iid} = 'disable' if $res{$iid} eq 'false';
255        $res{$iid} = 1 if $res{$iid} =~ m/enable/i; # enableForTrunk
256        $res{$iid} = 0 if $res{$iid} eq 'disable';
257    }
258    return \%res;
259}
260
261
262sub oct2str {
263    my ($v) = @_;
264    return sprintf('%s', unpack('H*', $v));
265}
266
2671;
268__END__
269
270=head1 NAME
271
272SNMP::Info::CiscoStpExtensions - SNMP Interface to C<CISCO-STP-EXTENSIONS-MIB>
273
274=head1 AUTHOR
275
276Carlos Vicente
277
278=head1 SYNOPSIS
279
280   my $stpx = new SNMP::Info(
281                         AutoSpecify => 1,
282                         Debug       => 1,
283                         DestHost    => 'myswitch',
284                         Community   => 'public',
285                         Version     => 2
286                       )
287
288   or die "Can't connect to DestHost.\n";
289
290   my $class = $stpx->class();
291   print " Using device sub class : $class\n";
292
293=head1 DESCRIPTION
294
295Create or use a subclass of SNMP::Info that inherits this class.  Do not use
296directly.
297
298For debugging you can call new() directly as you would in SNMP::Info
299
300 my $stpx = new SNMP::Info::CiscoStpExtensions(...);
301
302=head2 Inherited Classes
303
304=over
305
306=item SNMP::Info
307
308=item SNMP::Info::Bridge
309
310=back
311
312=head2 Required MIBs
313
314=over
315
316=item F<CISCO-STP-EXTENSIONS-MIB>
317
318=back
319
320=head1 GLOBALS
321
322These are methods that return scalar values from SNMP
323
324=over
325
326=item $stpx->stp_ver()
327
328Returns the particular STP version running on this device.
329Meant to override SNMP::Info::Brigde::stp_ver()
330
331Values: C<pvstPlus>, C<mistp>, C<mistpPvstPlus>, C<mst>, C<rapidPvstPlus>
332
333(C<stpxSpanningTreeType>)
334
335=back
336
337=head1 TABLE METHODS
338
339These are methods that return tables of information in the form of a reference
340to a hash.
341
342=over
343
344=item $stpx->mst_config_digest()
345
346Returns the Multiple Spanning Tree (MST) configuration digest
347
348(C<stpxSMSTConfigDigest>)
349
350=item $stpx->mst_region_name()
351
352Returns the Multiple Spanning Tree (MST) region name
353
354(C<stpxMSTRegionName>)
355
356=item $stpx->mst_region_rev()
357
358Returns the Multiple Spanning Tree (MST) region name
359
360(C<stpxSMSTRegionRevision>)
361
362=item $stpx->mst_vlan2instance()
363
364Returns the mapping of vlan to MST instance in the form of a hash reference
365with key = VLAN id, value = STP instance
366
367=item $stpx->i_rootguard_enabled()
368
369Returns 1 or 0 depending on whether C<RootGuard> is enabled on a given port.
370Format is a hash reference with key = C<ifIndex>, value = [1|0]
371
372(C<stpxRootGuardConfigEnabled>)
373
374=item $stpx->i_loopguard_enabled()
375
376Returns 1 or 0 depending on whether C<LoopGuard> is enabled on a given port.
377Format is a hash reference with key = C<ifIndex>, value = [1|0]
378
379(C<stpxLoopGuardConfigEnabled>)
380
381=item $stpx->i_bpduguard_enabled()
382
383Returns 1 or 0 depending on whether C<BpduGuard> is enabled on a given port.
384Format is a hash reference with key = C<ifIndex>, value = [1|0]
385
386(C<stpxFastStartPortBpduGuardMode>)
387
388=item $stpx->i_bpdufilter_enabled()
389
390Returns 1 or 0 depending on whether C<BpduFilter> is enabled on a given port.
391Format is a hash reference with key = C<ifIndex>, value = [1|0]
392
393(C<stpxFastStartBpduFilterEnable>)
394
395=item $stpx->i_faststart_enabled()
396
397Returns 1 or 0 depending on whether FastStart (aka PortFast) is enabled on a
398given port.  Format is a hash reference with key = C<ifIndex>, value = [1|0]
399
400(C<stpxFastStartPortEnable> and C<stpxFastStartPortMode>)
401
402=back
403
404=head1 MUNGES
405
406=over
407
408=item oct2str()
409
410Unpacks H* into a string
411
412=back
413
414=cut
415