# -*-perl-*-
# genDevConfig plugin module
#
# Copyright (C) 2002 Francois Mikus
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
package CiscoIOS;
use strict;
use Common::Log;
use genConfig::Utils;
use genConfig::File;
use genConfig::SNMP;
### Start package init
use genConfig::Plugin;
our @ISA = qw(genConfig::Plugin);
my $VERSION = 1.12;
### End package init
###############################################################################
# These are device types we can handle in this plugin
# the names should be contained in the sysdescr string
# returned by the devices. The name is a regular expression.
###############################################################################
my @types = ( 'IOS ',
'^C\d\d\d+ Software \(',
'Cisco Systems Catalyst'
);
###############################################################################
### SAA RTR Agent type definitions.
###############################################################################
my (%rttAgentType) = ( '2' => 'ipIcmpEcho',
'3' => 'ipUdpEchoAppl',
'4' => 'snaRUEcho',
'5' => 'snaLU0EchoAppl',
'6' => 'snaLU2EchoAppl',
'7' => 'snaLU62Echo',
'8' => 'snaLU62EchoAppl',
'9' => 'appleTalkEcho',
'10' => 'appleTalkEchoAppl',
'11' => 'decNetEcho',
'12' => 'decNetEchoAppl',
'13' => 'ipxEcho',
'14' => 'ipxEchoAppl',
'15' => 'isoClnsEcho',
'16' => 'isoClnsEchoAppl',
'17' => 'vinesEcho',
'18' => 'vinesEchoAppl',
'19' => 'xnsEcho',
'20' => 'xnsEchoAppl',
'21' => 'apolloEcho',
'22' => 'apolloEchoAppl',
'23' => 'netbiosEchoAppl',
'24' => 'ipTcpConn',
'25' => 'httpAppl',
'26' => 'dnsAppl',
'27' => 'jitterAppl',
'28' => 'dlswAppl',
'29' => 'dhcpAppl',
'30' => 'ftpAppl',
'31' => 'mplsLspPingAppl',
'32' => 'voipAppl',
'33' => 'rtpAppl',
'34' => 'icmpJitterAppl'
);
my(%rttprotocol)=('1' => 'notApplicable',
'2' => 'ipIcmpEcho',
'3' => 'ipUdpEchoAppl',
'4' => 'snaRUEcho',
'5' => 'snaLU0EchoAppl',
'6' => 'snaLU2EchoAppl',
'7' => 'snaLU62Echo',
'8' => 'snaLU62EchoAppl',
'9' => 'appleTalkEcho',
'10' => 'appleTalkEchoAppl',
'11' => 'decNetEcho',
'12' => 'decNetEchoAppl',
'13' => 'ipxEcho',
'14' => 'ipxEchoAppl',
'15' => 'isoClnsEcho',
'16' => 'isoClnsEchoAppl',
'17' => 'vinesEcho',
'18' => 'vinesEchoAppl',
'19' => 'xnsEcho',
'20' => 'xnsEchoAppl',
'21' => 'apolloEcho',
'22' => 'apolloEchoAppl',
'23' => 'netbiosEchoAppl',
'24' => 'ipTcpConn',
'25' => 'httpAppl',
'26' => 'dnsAppl',
'27' => 'jitterAppl',
'28' => 'dlswAppl',
'29' => 'dhcpAppl',
'30' => 'ftpAppl',
'31' => 'mplsLspPingAppl',
'32' => 'voipAppl',
'33' => 'rtpAppl',
'34' => 'icmpJitterAppl'
);
# These are the OIDS used by this plugin
# the OIDS should only be those necessary for index mapping or
# recognizing if a feature is supported or not by the device.
my %OIDS = (
### from mib-2.entityMIB.entityMIBObjects.entityPhysical.
### entPhysicalTable.entPhysicalEntry
'entPhysicalDescr.1' => '1.3.6.1.2.1.47.1.1.1.1.2.1',
'entPhysicalName' => '1.3.6.1.2.1.47.1.1.1.1.7',
'entPhysicalDescr' => '1.3.6.1.2.1.47.1.1.1.1.2',
'entPhysicalModelName' => '1.3.6.1.2.1.47.1.1.1.1.13',
### from cisco.ciscoMgmt.ciscoRttMonMIB.ciscoRttMonObjects.
### rttMonCtrl.rttMonCtrlAdminTable.rttMonCtrlAdminEntry. *
'rttMonCtrlAdminTag' => '1.3.6.1.4.1.9.9.42.1.2.1.1.3',
'rttMonCtrlOperState' => '1.3.6.1.4.1.9.9.42.1.2.9.1.10',
### from cisco.ciscoMgmt.ciscoRttMonMIB.ciscoRttMonObjects...
### I can't figure out in what format the TargetAdress is encoded in?
### If anyone can figure it out it would be very cool.
'rttMonEchoAdminProtocol' => '1.3.6.1.4.1.9.9.42.1.2.2.1.1',
'rttMonEchoAdminTargetAddress' => '1.3.6.1.4.1.9.9.42.1.2.2.1.2',
'ccarConfigAccIdx' => '1.3.6.1.4.1.9.9.113.1.1.1.1.4',
'cbwfqObject' => '1.3.6.1.4.1.9.9.166.1.7.1.1.1',
'cbwfqPolicy' => '1.3.6.1.4.1.9.9.166.1.5.1.1.2',
'cbQosPolicyDirection' => '1.3.6.1.4.1.9.9.166.1.1.1.1.3',
'cbQosIfIndex' => '1.3.6.1.4.1.9.9.166.1.1.1.1.4',
### from Cisco OLD-CHASSIS-MIB
'cardIfSlotNumber' => '1.3.6.1.4.1.9.3.6.13.1.2',
'cardIfPortNumber' => '1.3.6.1.4.1.9.3.6.13.1.3',
### from CISCO-PROCESS-MIB
###
'cpmCPUTotal1minRev' => '1.3.6.1.4.1.9.9.109.1.1.1.1.7',
'cpmCPUTotalPhysicalIndex' => '1.3.6.1.4.1.9.9.109.1.1.1.1.2',
### from cisco.ciscoMgmt.ciscoFrameRelayMIB.ciscoFrMIBObjects.
### cfrCircuitObjs.cfrExtCircuitTable.cfrExtCircuitEntry
'cfrExtCircuitSubifIndex' => '1.3.6.1.4.1.9.9.49.1.2.2.1.3',
### from mib-2.transmission.frame-relay.frCircuitTable.
### frCircuitEntry.
'frCircuitState' => '1.3.6.1.2.1.10.32.2.1.3',
### from cisco.local.linterfaces.lifTable.lifEntry
'CiscolocIfDescr' => '1.3.6.1.4.1.9.2.2.1.1.28',
### from Cisco ESSWITCH-MIB
'swPortName' => '1.3.6.1.4.1.437.1.1.3.3.1.1.3',
### from mib-2.transmission.dialControlMib.dialControlMibObjects.
### dialCtlPeer.dialCtlPeerCfgTable.dialCtlPeerCfgEntry.
'dialCtlPeerCfgOriginateAddress' => '1.3.6.1.2.1.10.21.1.2.1.1.4',
'dialCtlPeerCfgIfType' => '1.3.6.1.2.1.10.21.1.2.1.1.2',
### from rfc1406.dsx1ConfigTable (6).dsx1ConfigEntry (1).
'dsx1TotalIndex' => '1.3.6.1.2.1.10.18.9.1.1',
);
###############################################################################
### Private variables
###############################################################################
my (%frCircuitState, %cfrExtCircuitSubifIndex);
my (%PeerCfgOrigAddr, %PeerCfgIfType);
my $peerid;
my $snmp;
my $customfile;
my $script = "CiscoIOS genDevConfig Module";
###############################################################################
###############################################################################
#-------------------------------------------------------------------------------
# plugin_name
# IN :
# OUT: returns the plugin name defined in $script
#-------------------------------------------------------------------------------
sub plugin_name {
my $self = shift;
return $script;
}
#-------------------------------------------------------------------------------
# can_handle
# IN : opts reference
# OUT: returns a true if the device can be handled by this plugin
#-------------------------------------------------------------------------------
sub can_handle {
my($self, $opts) = @_;
# Validation is based on sysDescr, but could also be based
# on sysObject OIDs or other well referenced value.
return (grep { $opts->{sysDescr} =~ m/$_/gi } @types)
}
#-------------------------------------------------------------------------------
# discover
# IN : options reference
# OUT: N/A
#-------------------------------------------------------------------------------
sub discover {
my($self, $opts) = @_;
### Add our OIDs to the the global OID list
register_oids(%OIDS);
###
### START DEVICE DISCOVERY SECTION
###
### Figure out the IOS version number. We need this
### to figure out which oid to use to get interface descriptions and which
### MIBs are supported.
($opts->{vendor_soft_ver}) = ($opts->{sysDescr} =~ m/Version\s+([\d\.]+)\(\d/o);
if (defined $opts->{vendor_soft_ver}) {
$opts->{vendor_descr_oid} = ($opts->{vendor_soft_ver} ge "11.1") # IOS 11.1 supports ifAlias
? "ifAlias" : "CiscolocIfDescr";
$opts->{req_framestats} = 0 if ($opts->{vendor_soft_ver} le "11.2"); # Demote framestats for unsupported IOS
## 12.2+ supports ifInOctets/ifOutOctets on
#fast ethernet sub-interfaces (ifType 53 & 135).
$opts->{req_vlans} = 0 if ($opts->{req_vlans} && $opts->{sysDescr} =~ / C\d\d\d0 / && $opts->{vendor_soft_ver} lt "12.0");
$opts->{req_vlans} = 0 if ($opts->{req_vlans} && $opts->{sysDescr} !~ / C\d\d\d0 |Catalyst 4000/ && $opts->{vendor_soft_ver} lt "12.2");
} elsif ($opts->{sysDescr} =~ m/Cisco Systems Catalyst/) {
$opts->{vendor_descr_oid} = "swPortName";
} else { ### Maybe it's a Micro Switch...
$opts->{vendor_descr_oid} = "ifName";
}
# Some platforms support additional CPU monitoring
# currently it's only for cisco 12k and 75xx platforms
$opts->{req_vipstats} = 0 unless ($opts->{chassisstats} && ($opts->{sysDescr} =~ / GS / || $opts->{sysDescr} =~ / RSP /));
if ($opts->{sysDescr} =~ /IOS\s+(\(tm\)|Software,)/) {
($opts->{model}) = $opts->{sysDescr} =~ /IOS\s+(?:\(tm\)|Software,)\s+(\S+)/;
Info("Found an IOS device: model: $opts->{model}");
} elsif ($opts->{sysDescr} =~ /Cisco Systems Catalyst/) {
($opts->{model}) = $opts->{sysDescr} =~ /Cisco Systems Catalyst (\d+)/;
Info("Found an IOS device (alternate sysDescr) : $opts->{model}");
} elsif ($opts->{sysDescr} =~ /C\d\d\d+ Software \(/ ) {
($opts->{model}) = $opts->{sysDescr} =~ /(\S+) Software \(/;
Info("Found an IOS device (alternate sysDescr) : $opts->{model}");
}
if ($opts->{model} =~ /MSFC/) {
$opts->{chassisPhysicalDescr} = $opts->{model};
}
#else {
# ($opts->{chassisPhysicalDescr}) = get('entPhysicalDescr.1');
#}
#I do not understand my own code here, I know there can be two cpu's
# but what should I do with the info for the second one...
# Default feature promotions for IOS Devices
# Note: Auto-demote extended mib-ii as we already use cisco proprietary
# mibs.
$opts->{ciscobox} = 1 if ($opts->{req_vendorbox});
$opts->{ciscoint} = 1 if ($opts->{req_vendorint});
$opts->{extendedint} = 0 if ($opts->{req_extendedint});
$opts->{namedonly} = 1 if ($opts->{req_namedonly});
$opts->{framestats} = 1 if ($opts->{req_framestats});
$opts->{voip} = 1 if ($opts->{req_voip});
$opts->{vipstats} = 1 if ($opts->{req_vipstats});
$opts->{class} = 'cisco';
if ($opts->{model} eq 'C3500XL' || $opts->{model} eq 'C2900XL') {
$opts->{chassisttype} = 'Catalyst-XL-Switch';
$opts->{chassisname} = 'Chassis';
$opts->{usev2c} = 1 if ($opts->{req_usev2c});
} elsif ($opts->{model} eq "C3550") {
$opts->{chassisttype} = 'Catalyst-3550-Switch';
$opts->{chassisname} = 'Chassis';
$opts->{usev2c} = 1 if ($opts->{req_usev2c});
} elsif ($opts->{model} eq "C2950") {
$opts->{chassisttype} = 'Catalyst-2950-Switch';
$opts->{chassisname} = 'Chassis';
$opts->{usev2c} = 1 if ($opts->{req_usev2c});
} elsif ($opts->{model} eq "1900") {
$opts->{chassisttype} = 'Catalyst-1900-Switch';
$opts->{chassisname} = 'Chassis';
} elsif ($opts->{model} eq "C1200") {
$opts->{chassisttype} = 'Cisco-1200-AP';
$opts->{chassisname} = 'Chassis';
} elsif ($opts->{model} eq "7500") {
$opts->{chassisttype} = 'Cisco-7500-Router';
$opts->{chassisname} = 'Chassis';
$opts->{usev2c} = 1 if ($opts->{req_usev2c});
} elsif ($opts->{model} eq "7200") {
$opts->{chassisttype} = 'Cisco-7200-Router';
$opts->{chassisname} = 'Chassis';
$opts->{usev2c} = 1 if ($opts->{req_usev2c});
} elsif ($opts->{model} eq "7000") {
$opts->{chassisttype} = 'Cisco-7000-Router';
$opts->{chassisname} = 'Chassis';
$opts->{usev2c} = 1 if ($opts->{req_usev2c});
} elsif ($opts->{model} =~ /4500/) {
$opts->{chassisttype} = 'Cisco-4500-Router';
$opts->{chassisname} = 'Chassis';
} elsif ($opts->{model} =~ /3600/) {
$opts->{chassisttype} = 'Cisco-3600-Router';
$opts->{chassisname} = 'Chassis';
} elsif ($opts->{model} =~ /2800/) {
$opts->{chassisttype} = 'Cisco-2800-Router';
$opts->{chassisname} = 'Chassis';
} elsif ($opts->{model} =~ /2600/) {
$opts->{chassisttype} = 'Cisco-2600-Router';
$opts->{chassisname} = 'Chassis';
} elsif ($opts->{model} =~ /1700/) {
$opts->{chassisttype} = 'Cisco-1700-Router';
$opts->{chassisname} = 'Chassis';
} elsif ($opts->{model} =~ /1600/) {
$opts->{chassisttype} = 'Cisco-1600-Router';
$opts->{chassisname} = 'Chassis';
} elsif ($opts->{model} =~ /3000/) {
$opts->{chassisttype} = 'Cisco-Terminal';
$opts->{chassisname} = 'Chassis-Terminal';
$opts->{collect} = 0;
} elsif ($opts->{model} =~ /80./) {
$opts->{chassisttype} = 'Cisco-800-Router';
$opts->{chassisname} = 'Chassis';
} elsif ($opts->{model} =~ /2500/) {
$opts->{chassisttype} = 'Cisco-2500-Router';
$opts->{chassisname} = 'Chassis';
} elsif ($opts->{model} =~ /c6sup2_rp/) {
$opts->{chassisttype} = 'Cisco-Generic-Router';
$opts->{chassisname} = 'Chassis';
$opts->{usev2c} = 1 if ($opts->{req_usev2c});
} elsif ($opts->{model} =~ /WS-X5530/) {
$opts->{chassisttype} = 'Cisco-Generic-Router';
$opts->{chassisname} = 'Chassis';
$opts->{usev2c} = 1 if ($opts->{req_usev2c});
} elsif ($opts->{model} =~ /MSFC2/) {
$opts->{chassisttype} = 'Cisco-Generic-Router';
$opts->{chassisname} = 'Chassis';
$opts->{usev2c} = 1 if ($opts->{req_usev2c});
} elsif ($opts->{model} =~ /LS1010/) {
$opts->{chassisttype} = 'Cisco-Generic-Router';
$opts->{chassisname} = 'Chassis';
$opts->{usev2c} = 1 if ($opts->{req_usev2c});
} elsif ($opts->{model} =~ /C5RSM/) {
$opts->{chassisttype} = 'Cisco-Generic-Router';
$opts->{chassisname} = 'Chassis';
$opts->{usev2c} = 1 if ($opts->{req_usev2c});
} elsif ($opts->{model} eq 'GS') {
$opts->{chassisttype} = 'Cisco-Generic-Router';
$opts->{chassisname} = 'Chassis';
$opts->{usev2c} = 1 if ($opts->{req_usev2c});
} elsif ($opts->{model} =~ /RSP/) {
$opts->{chassisttype} = 'Cisco-7500-Router';
$opts->{chassisname} = 'Chassis';
$opts->{usev2c} = 1 if ($opts->{req_usev2c});
} elsif ($opts->{ciscobox}) { # Default Cisco config
$opts->{chassisttype} = 'Cisco-Generic-Router';
$opts->{chassisname} = 'Chassis';
$opts->{usev2c} = 1 if ($opts->{req_usev2c});
}
return;
}
#-------------------------------------------------------------------------------
# custom_targets
# IN : data reference for transient data, options reference
# OUT: N/A
#-------------------------------------------------------------------------------
sub custom_targets {
my ($self,$data,$opts) = @_;
# Saving local copies of runtime data
my %ifspeed = %{$data->{ifspeed}};
my %ifdescr = %{$data->{ifdescr}};
my %intdescr = %{$data->{intdescr}};
my %iftype = %{$data->{iftype}};
my %ifmtu = %{$data->{ifmtu}};
my %slotPortMapping = %{$data->{slotPortMapping}};
my %slotPortList = %{$data->{slotPortList}};
my %slotNameList = %{$data->{slotNameList}};
my %slotList = %{$data->{slotList}};
my $file = $opts->{file};
my $hasSlotMapping = 0;
###
### START DEVICE CUSTOM CONFIG SECTION
###
### Cisco Specific Slot/Port mapping tables
my %cardIfSlotNumber;
my %cardIfPortNumber;
if ($opts->{ciscobox}) {
%cardIfSlotNumber = gettable('cardIfSlotNumber');
%cardIfPortNumber = gettable('cardIfPortNumber');
# Build a Slot/Port Mapping that is vendor independant
foreach my $index (keys %cardIfSlotNumber) {
if (defined($cardIfPortNumber{$index})){
next if $cardIfSlotNumber{$index} eq "-1"; # Bug fix for invalid slots numbers
$slotPortMapping{$index} = "$cardIfSlotNumber{$index}/$cardIfPortNumber{$index}";
$hasSlotMapping = 1;
} else {
$slotPortMapping{$index} = "$cardIfSlotNumber{$index}/0";
$hasSlotMapping = 1;
}
}
# Build the Slot/Port mapping for boxes that do not return slot info.
foreach my $int (keys %ifdescr) {
next unless $ifdescr{$int} =~ m(([a-zA-Z]+)(\d+)/(\d+));
### Build a mapping between the ifDescr and its associated Slot.
$slotPortList{$ifdescr{$int}} = $2;
### Build a mapping between the Slot number and its name.
$slotNameList{$2} = "$1_$2";
### Build a list of existing slots.
$slotList{$2}++;
}
}
### Get frame relay DLCI info if needed.
if ($opts->{framestats}) {
%frCircuitState = gettable('frCircuitState');
%cfrExtCircuitSubifIndex = reverse gettable('cfrExtCircuitSubifIndex');
}
### Get VoIP dial peer info if needed.
if ($opts->{voip}) {
%PeerCfgOrigAddr = gettable('dialCtlPeerCfgOriginateAddress');
%PeerCfgIfType = gettable('dialCtlPeerCfgIfType');
}
### Get RFC1406 (T1) Information if needed
### Theoretically, ref1406 is generic and should be in the main file
### I'll leave that up to Francois
my (%dsx1TotalIndex);
%dsx1TotalIndex = gettable( 'dsx1TotalIndex' );
### Get SAA(RTR) Agent information if needed.
my (%rttMonEchoAdminProtocol, %rttMonEchoAdminTargetAddress, %rttMonCtrlOperState, %rttMonCtrlAdminTag);
if ($opts->{rtragents}) {
%rttMonEchoAdminProtocol = gettable('rttMonEchoAdminProtocol');
%rttMonCtrlOperState = gettable('rttMonCtrlOperState');
%rttMonCtrlAdminTag = gettable('rttMonCtrlAdminTag');
%rttMonEchoAdminTargetAddress = gettable('rttMonEchoAdminTargetAddress');
}
### Walk cpu statistics for VIPs on Cisco 12000 and 7500s with RSPs
### CPU Statistics per VIP
my %cpu1min;
my %physindex;
my %cpunames;
my %cpudescrs;
my %cpumodels;
if ($opts->{vipstats}) {
%cpu1min = gettable('cpmCPUTotal1minRev');
%physindex = gettable('cpmCPUTotalPhysicalIndex');
%cpunames = gettable('entPhysicalName');
%cpudescrs = gettable('entPhysicalDescr');
%cpumodels = gettable('entPhysicalModelName');
}
### Walk ccarStatSwitchedPkts if this is a cisco router
### Traffic shaping counters based on CAR
my %cisco_car;
if ($opts->{ciscobox}) {
%cisco_car = gettable('ccarConfigAccIdx');
}
### Walk 1.3.6.1.4.1.9.9.166.1.7.1.1.1 if this is a cisco router
### Traffic shaping counters based on Class Based Weighted Fair Queued QoS
my %cisco_cbwfq_obj; # Object
my %cisco_cbwfq_pol; # Policy
if ($opts->{ciscobox}) {
%cisco_cbwfq_obj = gettable('cbwfqObject');
%cisco_cbwfq_pol = gettable('cbwfqPolicy');
}
### Building CPU VIP Stats for Cisco 7500, 12000 series routers
if ($opts->{vipstats}) {
foreach my $cpu (keys %cpu1min) {
next if ( defined $physindex{$cpu} && ($physindex{$cpu} == 0 ));
my ($cpuname) = $cpunames{$physindex{$cpu}};
my ($slotnum) = $cpuname;
$slotnum =~ /(.*) ([0-9]+$)/;
$slotnum = $2;
my ($cpudescr) = $cpudescrs{$physindex{$cpu}};
my ($cpumodel) = $cpumodels{$physindex{$cpu}};
my($target) = "cpu_" . $cpuname;
$target =~ s/[\/\s:,\.]/\_/g;
my $ldesc = $opts->{devicename} if ($opts->{devicename});
$ldesc .= "
" . $cpuname;
$ldesc .= "
" . $cpudescr;
$ldesc .= "
" . $cpumodel;
$cpudescr =~ s/,.*$//g;
my $sdesc = "CPU " . $cpuname . ": " . $cpudescr;
$file->writetarget($target, '',
'cpu' => $cpu,
'long-desc' => $ldesc,
'short-desc' => $sdesc,
'target-type' => "cisco-vip-cpu",
'display-name' => "%auto-target-name%",
'inst' => 0,
'order' => $opts->{order},
);
$opts->{order} -= 1;
}
}
### Build frame relay stats config if required.
my %dlcis;
if ($opts->{framestats}) {
foreach my $key (keys %frCircuitState) {
next if ($frCircuitState{$key} != 2); # active DLCIs only.
my($inst, $dlci) = split(/\./,$key);
push(@{$dlcis{$ifdescr{$inst}}}, $dlci);
}
}
### Build RFC1406 T1 Statistics
if ( %dsx1TotalIndex ) {
foreach my $key ( keys %dsx1TotalIndex ) {
my $ifindex = $key;
my $ifacedescr = ( 0 != $ifindex ) ? $ifdescr{$ifindex} : "";
my $ifacealias = ( 0 != $ifindex ) ? $intdescr{$ifindex} : "";
my $mungedname = $ifacedescr;
$mungedname =~ s/[\/\s:,\.]/\_/g;
my ($targetname) = $mungedname;
my $ldesc = "
Controller $ifacedescr
$ifacealias";
$file->writetarget($targetname, '',
'inst' => $key,
'order' => $opts->{order},
'interface-name' => $ifacedescr,
'long-desc' => $ldesc,
'short-desc' => $ifacedescr,
'target-type' => 'cisco-controller'
);
$opts->{order} -= 1;
}
}
### Build the Class Based Weighted Fair Queued QoS Statistics
### Cisco Only
if (%cisco_cbwfq_obj && %cisco_cbwfq_pol) {
my %servicepolicy;
my $qostype = 'cisco-cbwfq-qos';
foreach my $key (keys %cisco_cbwfq_obj) {
my $name_cell;
my $config_id1_cell;
my $config_id2_cell;
my $pol_id_cell;
my $obj_id_cell;
my $targetname;
my $targetdesc;
my $instance;
my ($ldesc, $sdesc);
my $ifindex;
my $policydirection;
my $ifdescr;
my $ifacedescr;
my $policy; # id: iface.directon
my %dup_hash;
$name_cell = $cisco_cbwfq_obj{$key};
$config_id1_cell = $key;
foreach $key (keys %cisco_cbwfq_pol) {
($pol_id_cell, $obj_id_cell)= split(/\./,$key);
$config_id2_cell = $cisco_cbwfq_pol{$key};
if ($config_id1_cell == $config_id2_cell) {
if ( exists $dup_hash{$pol_id_cell} ) {
next if $dup_hash{$pol_id_cell} = $config_id2_cell;
} else {
$dup_hash{$pol_id_cell} = $config_id2_cell;
}
($policydirection) = get('cbQosPolicyDirection' . "." . $pol_id_cell);
$policydirection = $policydirection == 1 ? "input" : "output";
($ifindex) = get('cbQosIfIndex' . "." . $pol_id_cell);
#print "ifindex=$ifindex, policydirection=$policydirection, pol_id_cell=$pol_id_cell\n";
$ifdescr = ( 0 != $ifindex ) ? $ifdescr{$ifindex} . "." . $ifindex : "";
# $ifdescr = $ifdescr{$ifindex} . "." . $ifindex;
#print "ifdesc=$ifdescr\n";
$ifacedescr = $ifdescr;
$ifacedescr =~ s/[\/\s:,\.]/\_/g;
$instance = "\'$pol_id_cell.$obj_id_cell\'";
$ldesc = "CBWFQ QoS for $ifdescr\[$policydirection\]: $name_cell";
$sdesc = "QoS $ifdescr\[$policydirection\]: $name_cell";
$targetdesc = "QoS_$ifdescr\_$policydirection\_$name_cell";
$targetname = "qos_$ifacedescr\_$policydirection\_$name_cell";
$file->writetarget($targetname, '',
'interface-name' => $targetdesc,
'long-desc' => $ldesc,
'short-desc' => $sdesc,
'target-type' => $qostype,
'inst' => $instance,
'hide' => 'true',
'order' => $opts->{order},
);
$opts->{order} -= 1;
$policy = "$ifdescr,$policydirection";
if (exists($servicepolicy{$policy})) {
$servicepolicy{$policy} = "$servicepolicy{$policy};$targetname";
} else {
$servicepolicy{$policy} = "$targetname";
}
}
}
}
foreach my $key (keys %servicepolicy) {
my $targetname;
my $targetdesc;
my ($ldesc, $sdesc);
my $policydirection;
my $ifdescr;
my $ifacedescr;
($ifdescr, $policydirection)= split(/\,/,$key);
$ifacedescr = $ifdescr;
$ifacedescr =~ s/[\/\s:,\.]/\_/g;
$ldesc = "CBWFQ QoS for $ifdescr\[$policydirection\]";
$sdesc = "QoS $ifdescr\[$policydirection\]";
$targetdesc = "QoS_$ifdescr\_$policydirection";
$targetname = "qos_$ifacedescr\_$policydirection";
$file->writetarget($targetname, '',
'interface-name'=> $targetdesc,
'long-desc' => $ldesc,
'short-desc' => $sdesc,
'target-type' => $qostype,
'mtargets' => "$servicepolicy{$key}",
'order' => $opts->{order},
);
$opts->{order} -= 1;
}
}
### Build Cisco Traffic shaping based on CAR
if ($opts->{ciscobox} && keys(%cisco_car)) {
my $key;
my ($ifindex,$direction,$rowindex,$rest);
my $ifname;
my $filename;
my ($sdesc,$ldesc);
my $acl;
foreach $key (keys(%cisco_car)) {
my @config = ();
($ifindex,$direction,$rowindex)=split/\./,$key;
$ifname=$ifdescr{$ifindex};
$ifname =~ s/[\/\s:]/\_/g;
$rest=$direction.".".$rowindex;
if ($direction eq "1"){
$direction="input";
} else {
$direction="output"
}
if($cisco_car{$key}==0){
$acl="ANY";
}else{
$acl="ACL".$cisco_car{$key};
}
$ifname.="_".$acl."_".$direction."_ratelimit";
$sdesc="rate-limit $direction $ifdescr{$ifindex} - $intdescr{$ifindex}";
$ldesc="$ifdescr{$ifindex} $acl $direction ratelimit - $intdescr{$ifindex}";
push(@config,
'order' => $opts->{order},
'short-desc' => $sdesc,
'long-desc' => $ldesc,
'interface-name' => $ifdescr{$ifindex},
'rest' => $rest,
'target-type' => 'rate-limit'
);
$file->writetarget($ifname , '', @config);
$opts->{order} -= 1;
}
}
### Build the SAA(RTR) rtt agent stats for the specified instances
if ($opts->{rtragents} && %rttMonCtrlOperState) {
foreach my $key (keys %rttMonCtrlOperState) {
my ($ldesc, $sdesc);
### More verbose output
#Debug ("RtrOperStatus for rtr $key: $rttMonCtrlOperState{$key}\n");
### Process only active agents
#Debug ("rttMonCtrlOperState for rtr $key: $rttMonCtrlOperState{$key}\n");
next if ($rttMonCtrlOperState{$key} != 6);
my ($protocol) = $rttprotocol{$rttMonEchoAdminProtocol{$key}};
my ($type) = $rttAgentType{$rttMonEchoAdminProtocol{$key}};
next if (!defined $type);
my ($address) = translateRttTargetAddr($type, $rttMonEchoAdminTargetAddress{$key});
# $ldesc = 'SAA(RTR) Performance agent for round-trip time using ' . $protocol .
# ' for destination '. $address . " - " . $rttMonCtrlAdminTag{$key} .
# '
Operational values: 1(Ok) 2(Disconnct) 4(Timeout) 5(Busy)" .
# ' 6(NoConnection) 7(LackIntRes) 8(BadSeqID) 9(BadData) 16(Error)' ;
# $sdesc = 'SAA(RTR) Performance agent for round-trip time using ' . $protocol .
# ' for destination ip: ' . $address . ' tag: ' . $rttMonCtrlAdminTag{$key};
$ldesc = 'Cisco SLA (RTR) using ' . $protocol .
' for destination '. $address . " - " . $rttMonCtrlAdminTag{$key} . '' ;
$sdesc = 'Cisco SLA (RTR) using ' . $protocol .
' for destination ip: ' . $address . ' tag: ' . $rttMonCtrlAdminTag{$key};
#Debug ("Destination for $key tag: $rttMonCtrlAdminTag{$key} addr: $address\n");
my ($targetname) = 'SaaRtt_Agent_' . $key;
$file->writetarget($targetname, '',
'inst' => $key,
'order' => $opts->{order},
'interface-name' => $targetname,
'long-desc' => $ldesc,
'short-desc' => $sdesc,
'target-type' => $type
);
$opts->{order} -= 1;
}
}
## Avoids creating empty directory if no VOIP targets found.
if ($opts->{voip} && %PeerCfgOrigAddr) {
my $customdir = subdir("$opts->{rdir}/dialpeers",$opts->{lowercase});
$customfile = $opts->{dpfile} = new genConfig::File("$customdir/targets");
genConfig::File::set_file_header("# Generated by $script\n".
"# Args: $opts->{savedargs}\n".
"# Date: ". scalar(localtime(time)). "\n\n");
Info ("Writing dialpeer default configuration");
$customfile->writetarget('--default--', '',
'directory-desc' => 'Dial Peer Stats',
'target-type' => 'dial-peer',
);
foreach my $key (keys %PeerCfgOrigAddr) {
Debug ("PeerCfgOrigAddr for peer $key: $PeerCfgOrigAddr{$key}\n");
}
} else {
$opts->{voip} = 0;
}
# Saving local copies of runtime data
%{$data->{ifspeed}} = %ifspeed;
%{$data->{ifdescr}} = %ifdescr;
%{$data->{intdescr}} = %intdescr;
%{$data->{iftype}} = %iftype;
%{$data->{ifmtu}} = %ifmtu;
%{$data->{slotPortMapping}} = %slotPortMapping;
%{$data->{slotPortList}} = %slotPortList;
%{$data->{slotNameList}} = %slotNameList;
%{$data->{slotList}} = %slotList;
return;
}
#-------------------------------------------------------------------------------
# custom_interfaces
# IN : current ifIndex,
# data reference for transient data
# options reference
# OUT: N/A
#-------------------------------------------------------------------------------
sub custom_interfaces {
my ($self,$index,$data,$opts) = @_;
# Saving local copies of runtime data
my %ifspeed = %{$data->{ifspeed}};
my %ifdescr = %{$data->{ifdescr}}; # What is used for processing
my %intdescr = %{$data->{intdescr}}; # What is displayed for an interface
my %iftype = %{$data->{iftype}};
my %ifmtu = %{$data->{ifmtu}};
my %slotPortMapping = %{$data->{slotPortMapping}};
my @config = @{$data->{config}};
my $hc = $data->{hc};
my $class = $data->{class};
my $match = $data->{match};
my $customsdesc = $data->{customsdesc};
my $customldesc = $data->{customldesc};
###
### START DEVICE CUSTOM INTERFACE CONFIG SECTION
###
$peerid = '';
if ($iftype{$index} == 103 || $iftype{$index} == 104) {
### If it's a dial peer interface, get it's peer ID and add it
### to the config.
if ($opts->{voip}) {
($peerid) = $ifdescr{$index} =~ /Peer:\s+(\d+)/;
push(@config, 'peer-id' => $peerid);
$customfile = $opts->{dpfile}; # Select the file to store configs
$customsdesc .= $PeerCfgOrigAddr{$peerid.'.'.$index};
$customldesc = "Call Address: $PeerCfgOrigAddr{$peerid.'.'.$index}";
}
# Set any non-sticky variables
$opts->{show_max} = 0; # Do not display max and max_octets for dp interfaces
$opts->{nomtucheck} = 1; # Do not skip the interface due to insane mtu
$opts->{nospeedcheck} = 1; #Do not skip the interface due to insane speed
$match = 1;
} elsif ($iftype{$index} == 32 && $ifdescr{$index} =~ /\.\d+$/) {
### If we're collecting frame relay stats and this is a frame relay
### interface, get the main interface description and the DLCI
### add them to the config. (frame stats are stored under the main
### interface index, so that's what we need from the instance map)
### Otherwise set the interface as a simple sub-interface.
if ($opts->{framestats} && ($ifdescr{$index} =~ /\.\d+$/) &&
exists $cfrExtCircuitSubifIndex{$index}) {
if (defined $opts->{vendor_soft_ver} &&
($opts->{vendor_soft_ver} lt "11.1") &&
!defined $intdescr{$index}) {
### This is a frame-relay sub-interface *and* the router
### is running an IOS older than 11.1. Therefore, we can
### get neither ifAlias nor ciscoLocIfDesc. Do something
### useful.
$intdescr{$index} = "Cisco PVCs descriptions require IOS 11.1+.";
}
my $dspname = $ifdescr{$index};
my ($mainif, $dlci);
($mainif, $dlci) = split(/\./, $cfrExtCircuitSubifIndex{$index});
$ifdescr{$index} = $ifdescr{$mainif};
push(@config, 'dlci' => $dlci,
'display-name' => "$opts->{devicename} $dspname",
'target-type' => 'frame-interface');
$match = 1;
} else {
push(@config, 'target-type' => 'sub-interface' . $hc);
$match = 1;
}
$opts->{nomtucheck} = 1;
} elsif ($opts->{ciscoint}) {
### Collect extra info from Cisco MIB
# Override global classification to only apply minimal thresholds
#$class = '-access' if (($iftype{$index} == 81 ) || ($iftype{$index} == 77) || ($iftype{$index} == 23)); # ISDN
# Check if NU Cast packet statistics are required
my ($nu) = $opts->{nustats} ? '-nu' : '';
push(@config, 'target-type' => 'cisco-interface' . $nu . $hc);
$match = 1;
}
###
### END INTERFACE CUSTOM CONFIG SECTION
###
# Saving local copies of runtime data
%{$data->{ifspeed}} = %ifspeed;
%{$data->{ifdescr}} = %ifdescr;
%{$data->{intdescr}} = %intdescr;
%{$data->{iftype}} = %iftype;
%{$data->{ifmtu}} = %ifmtu;
%{$data->{slotPortMapping}} = %slotPortMapping;
@{$data->{config}} = @config;
$data->{hc} = $hc;
$data->{class} = $class;
$data->{match} = $match;
$data->{customsdesc} = $customsdesc;
$data->{customldesc} = $customldesc;
return;
}
#-------------------------------------------------------------------------------
# custom_files
# IN : options hash
# OUT: returns the options hash
#-------------------------------------------------------------------------------
sub custom_files {
my ($self,$data,$opts) = @_;
# Saving local copies of runtime data
my $file = ${$data->{file}};
my $c = ${$data->{c}};
my $target = ${$data->{target}};
my @config = @{$data->{config}};
my $wmatch = ${$data->{wmatch}};
###
### START FILE CUSTOM CONFIG SECTION
###
if ($peerid) {
$customfile->write("\n");
Info ("Writing dialpeer configuration");
$customfile->writetarget($target, $c, @config);
$wmatch = 1;
}
###
### END FILE CUSTOM CONFIG SECTION
###
# Save return value in the reference hash
${$data->{wmatch}} = $wmatch;
}
1;