# SNMP::Info::Layer3::Passport # # Copyright (c) 2016 Eric Miller # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # * Redistributions of source code must retain the above copyright notice, # this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # * Neither the name of the University of California, Santa Cruz nor the # names of its contributors may be used to endorse or promote products # derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE # LIABLE FOR # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. package SNMP::Info::Layer3::Passport; use warnings; use strict; use Exporter; use SNMP::Info::SONMP; use SNMP::Info::RapidCity; use SNMP::Info::Layer3; @SNMP::Info::Layer3::Passport::ISA = qw/SNMP::Info::SONMP SNMP::Info::RapidCity SNMP::Info::Layer3 Exporter/; @SNMP::Info::Layer3::Passport::EXPORT_OK = qw//; our ($VERSION, %GLOBALS, %FUNCS, %MIBS, %MUNGE); $VERSION = '3.68'; %MIBS = ( %SNMP::Info::Layer3::MIBS, %SNMP::Info::RapidCity::MIBS, %SNMP::Info::SONMP::MIBS, ); %GLOBALS = ( %SNMP::Info::Layer3::GLOBALS, %SNMP::Info::RapidCity::GLOBALS, %SNMP::Info::SONMP::GLOBALS, ); %FUNCS = ( %SNMP::Info::Layer3::FUNCS, %SNMP::Info::RapidCity::FUNCS, %SNMP::Info::SONMP::FUNCS, ); %MUNGE = ( %SNMP::Info::Layer3::MUNGE, %SNMP::Info::RapidCity::MUNGE, %SNMP::Info::SONMP::MUNGE, ); sub model { my $passport = shift; my $id = $passport->id(); unless ( defined $id ) { print " SNMP::Info::Layer3::Passport::model() - Device does not support sysObjectID\n" if $passport->debug(); return; } my $model = &SNMP::translateObj($id); return $id unless defined $model; $model =~ s/^rc(A)?//i; return $model; } sub vendor { return 'avaya'; } sub os { return 'passport'; } sub os_ver { my $passport = shift; my $descr = $passport->description(); return unless defined $descr; #ERS / Passport if ( $descr =~ m/(\d+\.\d+\.\d+\.\d+)/ ) { return $1; } #Accelar if ( $descr =~ m/(\d+\.\d+\.\d+)/ ) { return $1; } return; } sub i_index { my $passport = shift; my $partial = shift; my $i_index = $passport->orig_i_index($partial); my $model = $passport->model(); my %if_index; foreach my $iid ( keys %$i_index ) { my $index = $i_index->{$iid}; next unless defined $index; $if_index{$iid} = $index; } # Get VLAN Virtual Router Interfaces if (!defined $partial || (defined $model && ( ( $partial > 2000 && $model =~ /^8[8631]|16|VSP/ ) || ( $partial > 256 && $model =~ /^1[012][05]0/ ) ) ) ) { my $vlan_index = $passport->rc_vlan_if() || {}; foreach my $vid ( keys %$vlan_index ) { my $v_index = $vlan_index->{$vid}; next unless defined $v_index; next if $v_index == 0; next if ( defined $partial and $v_index !~ /^$partial$/ ); $if_index{$v_index} = $v_index; } } if ( defined $model and $model =~ /^8[86]/ ) { my $cpu_index = $passport->rc_cpu_ifindex($partial) || {}; my $virt_ip = $passport->rc_virt_ip(); # Get CPU Ethernet Interfaces foreach my $cid ( keys %$cpu_index ) { my $c_index = $cpu_index->{$cid}; next unless defined $c_index; next if $c_index == 0; $if_index{$c_index} = $c_index; } # Check for Virtual Mgmt Interface unless ( $virt_ip eq '0.0.0.0' ) { # Make up an index number, 1 is not reserved AFAIK $if_index{1} = 1; } } return \%if_index; } sub interfaces { my $passport = shift; my $partial = shift; my $i_index = $passport->i_index($partial); my $i_descr = $passport->orig_i_description($partial) || {}; my $model = $passport->model(); my $index_factor = $passport->index_factor(); my $port_offset = $passport->port_offset(); my $slot_offset = $passport->slot_offset(); my $vlan_index = {}; my %reverse_vlan; my $vlan_id = {}; if (!defined $partial || (defined $model && ( ( $partial > 2000 && $model =~ /^8[8631]|16|VSP/ ) || ( $partial > 256 && $model =~ /^1[012][05]0/ ) ) ) ) { $vlan_index = $passport->rc_vlan_if() || {}; %reverse_vlan = reverse %$vlan_index; $vlan_id = $passport->rc_vlan_id(); } my %if; foreach my $iid ( keys %$i_index ) { my $index = $i_index->{$iid}; next unless defined $index; if ( ( $index == 1 ) and ( $model =~ /^8[86]/ ) ) { $if{$index} = 'Cpu.Virtual'; } elsif ( ( $iid == 64 ) and ( $model =~ /^VSP[478]/ ) ) { $if{$index} = 'Mgmt.1'; } elsif ( ( $index == 192 ) and ( $model =~ /^8[86]03/ ) ) { $if{$index} = 'Cpu.3'; } elsif ( ( $index == 320 ) and ( $model =~ /^8[86][10][06]/ ) ) { $if{$index} = 'Cpu.5'; } elsif ( ( $index == 384 ) and ( $model =~ /^8[86][10][06]/ ) ) { $if{$index} = 'Cpu.6'; } elsif (( $index > 2000 and $model =~ /^8[8631]|16|VSP/ ) or ( $index > 256 and $model =~ /^1[012][05]0/ ) ) { my $v_index = $reverse_vlan{$iid}; my $v_id = $vlan_id->{$v_index}; next unless defined $v_id; my $v_port = 'Vlan' . "$v_id"; $if{$index} = $v_port; } else { if ($model =~ /VSP/ and $i_descr->{$iid} and $i_descr->{$iid} =~ m) { my $ps = $1; $ps =~ s|/|.|g; $if{$iid} = $ps; } else { my $port = ( $index % $index_factor ) + $port_offset; my $slot = int( $index / $index_factor ) + $slot_offset; my $slotport = "$slot.$port"; $if{$iid} = $slotport; } } } return \%if; } sub i_mac { my $passport = shift; my $partial = shift; my $i_mac = $passport->orig_i_mac($partial) || {}; my $model = $passport->model(); my %if_mac; foreach my $iid ( keys %$i_mac ) { my $mac = $i_mac->{$iid}; next unless defined $mac; $if_mac{$iid} = $mac; } # Get VLAN Virtual Router Interfaces if (!defined $partial || (defined $model && ( ( $partial > 2000 && $model =~ /^8[8631]|16|VSP/ ) || ( $partial > 256 && $model =~ /^1[012][05]0/ ) ) ) ) { my $vlan_index = $passport->rc_vlan_if() || {}; my $vlan_mac = $passport->rc_vlan_mac() || {}; foreach my $iid ( keys %$vlan_mac ) { my $v_mac = $vlan_mac->{$iid}; next unless defined $v_mac; my $v_id = $vlan_index->{$iid}; next unless defined $v_id; next if ( defined $partial and $v_id !~ /^$partial$/ ); $if_mac{$v_id} = $v_mac; } } if ( defined $model and $model =~ /^8[86]/ ) { my $cpu_mac = $passport->rc_cpu_mac($partial) || {}; my $virt_ip = $passport->rc_virt_ip() || '0.0.0.0'; # Get CPU Ethernet Interfaces foreach my $iid ( keys %$cpu_mac ) { my $mac = $cpu_mac->{$iid}; next unless defined $mac; $if_mac{$iid} = $mac; } # Check for Virtual Mgmt Interface unless ( ( $virt_ip eq '0.0.0.0' ) or ( defined $partial and $partial ne "1" ) ) { my $chassis_base_mac = $passport->rc_base_mac(); if ( defined $chassis_base_mac ) { my @virt_mac = split /:/, $chassis_base_mac; $virt_mac[0] = hex( $virt_mac[0] ); $virt_mac[1] = hex( $virt_mac[1] ); $virt_mac[2] = hex( $virt_mac[2] ); $virt_mac[3] = hex( $virt_mac[3] ); $virt_mac[4] = hex( $virt_mac[4] ) + 0x03; $virt_mac[5] = hex( $virt_mac[5] ) + 0xF8; my $mac = join( ':', map { sprintf "%02x", $_ } @virt_mac ); $if_mac{1} = $mac; } } } return \%if_mac; } sub i_description { my $passport = shift; my $partial = shift; my $i_descr = $passport->orig_i_description($partial) || {}; my $model = $passport->model(); my %descr; foreach my $iid ( keys %$i_descr ) { my $if_descr = $i_descr->{$iid}; next unless defined $if_descr; $descr{$iid} = $if_descr; } # Get VLAN Virtual Router Interfaces if (!defined $partial || (defined $model && ( ( $partial > 2000 && $model =~ /^8[8631]|16|VSP/ ) || ( $partial > 256 && $model =~ /^1[012][05]0/ ) ) ) ) { my $v_descr = $passport->v_name(); my $vlan_index = $passport->rc_vlan_if(); foreach my $vid ( keys %$v_descr ) { my $vl_descr = $v_descr->{$vid}; next unless defined $vl_descr; my $v_id = $vlan_index->{$vid}; next unless defined $v_id; next if ( defined $partial and $v_id !~ /^$partial$/ ); $descr{$v_id} = $vl_descr; } } return \%descr; } sub i_name { my $passport = shift; my $partial = shift; my $model = $passport->model(); my $i_index = $passport->i_index($partial) || {}; my $rc_alias = $passport->rc_alias($partial) || {}; my $i_alias = $passport->i_alias($partial) || {}; my $i_name2 = $passport->orig_i_name($partial) || {}; my $v_name = {}; my $vlan_index = {}; my %reverse_vlan; if (!defined $partial || (defined $model && ( ( $partial > 2000 && $model =~ /^8[8631]|16|VSP/ ) || ( $partial > 256 && $model =~ /^1[012][05]0/ ) ) ) ) { $v_name = $passport->v_name() || {}; $vlan_index = $passport->rc_vlan_if() || {}; %reverse_vlan = reverse %$vlan_index; } my %i_name; foreach my $iid ( keys %$i_index ) { if ( ( $iid == 1 ) and ( $model =~ /^8[86]/ ) ) { $i_name{$iid} = 'CPU Virtual Management IP'; } elsif ( ( $iid == 64 ) and ( $model =~ /^VSP[478]/ ) ) { $i_name{$iid} = 'Mgmt Port'; } elsif ( ( $iid == 192 ) and ( $model =~ /^8[86]03/ ) ) { $i_name{$iid} = 'CPU 3 Ethernet Port'; } elsif ( ( $iid == 320 ) and ( $model =~ /^8[86][10][06]/ ) ) { $i_name{$iid} = 'CPU 5 Ethernet Port'; } elsif ( ( $iid == 384 ) and ( $model =~ /^8[86][10][06]/ ) ) { $i_name{$iid} = 'CPU 6 Ethernet Port'; } elsif ( ( $iid > 2000 and defined $model and $model =~ /^8[8631]|16|VSP/ ) or ( $iid > 256 and defined $model and $model =~ /^1[012][05]0/ ) ) { my $vlan_idx = $reverse_vlan{$iid}; my $vlan_name = $v_name->{$vlan_idx}; next unless defined $vlan_name; $i_name{$iid} = $vlan_name; } else { my $name = $i_name2->{$iid}; my $pp_alias = $rc_alias->{$iid}; my $std_alias = $i_alias->{$iid}; my $alias = ( defined $pp_alias and $pp_alias !~ /^\s*$/ ) ? $pp_alias : $std_alias; $i_name{$iid} = ( defined $alias and $alias !~ /^\s*$/ ) ? $alias : $name; } } return \%i_name; } sub ip_index { my $passport = shift; my $partial = shift; my $model = $passport->model(); my $ip_index = $passport->SUPER::ip_index($partial) || {}; my %ip_index; foreach my $ip ( keys %$ip_index ) { my $iid = $ip_index->{$ip}; next unless defined $iid; # Skip VSP default CPU addresses next if ($ip =~ /^192\.168\.1\.1/); # Skip default CPU addresses next if ($ip =~ /^192\.168\.168\.16[89]/); $ip_index{$ip} = $iid; } # Only 8600 has CPU and Virtual Management IP if ( defined $model and $model =~ /^8[86]/ ) { my $cpu_ip = $passport->rc_cpu_ip($partial) || {}; my $virt_ip = $passport->rc_virt_ip($partial); # Get CPU Ethernet IP foreach my $cid ( keys %$cpu_ip ) { my $c_ip = $cpu_ip->{$cid}; next unless defined $c_ip; # Skip default CPU addresses next if ($c_ip =~ /192\.168\.168\.16[89]/); $ip_index{$c_ip} = $cid; } # Get Virtual Mgmt IP $ip_index{$virt_ip} = 1 if ( defined $virt_ip ); } return \%ip_index; } sub ip_netmask { my $passport = shift; my $partial = shift; my $model = $passport->model(); my $ip_mask = $passport->SUPER::ip_netmask($partial) || {}; my %ip_index; foreach my $iid ( keys %$ip_mask ) { # Skip VSP default CPU addresses next if ($iid =~ /^192\.168\.1\./); # Skip default CPU addresses next if ($iid =~ /^192\.168\.168\.16[89]/); my $mask = $ip_mask->{$iid}; next unless defined $mask; $ip_index{$iid} = $mask; } # Only 8600 has CPU and Virtual Management IP if ( defined $model and $model =~ /^8[86]/ ) { my $cpu_ip = $passport->rc_cpu_ip($partial) || {}; my $cpu_mask = $passport->rc_cpu_mask($partial) || {}; my $virt_ip = $passport->rc_virt_ip($partial); my $virt_mask = $passport->rc_virt_mask($partial) || {}; # Get CPU Ethernet IP foreach my $iid ( keys %$cpu_mask ) { my $c_ip = $cpu_ip->{$iid}; next unless defined $c_ip; # Skip default CPU addresses next if ($c_ip =~ /192\.168\.168\.16[89]/); my $c_mask = $cpu_mask->{$iid}; next unless defined $c_mask; $ip_index{$c_ip} = $c_mask; } # Get Virtual Mgmt IP $ip_index{$virt_ip} = $virt_mask if ( defined $virt_mask and defined $virt_ip ); } return \%ip_index; } sub root_ip { my $passport = shift; my $model = $passport->model(); my $rc_ip_addr = $passport->rc_ip_addr(); my $rc_ip_type = $passport->rc_ip_type(); my $virt_ip = $passport->rc_virt_ip(); my $router_ip = $passport->router_ip(); my $sonmp_topo_port = $passport->sonmp_topo_port(); my $sonmp_topo_ip = $passport->sonmp_topo_ip(); # Only 8600 and 1600 have CLIP or Management Virtual IP if ( defined $model and $model =~ /^8[86]|16|VSP/ ) { # Return CLIP (CircuitLess IP) foreach my $iid ( keys %$rc_ip_type ) { my $ip_type = $rc_ip_type->{$iid}; next unless ( ( defined $ip_type ) and ( $ip_type =~ /circuitLess/i ) ); my $ip = $rc_ip_addr->{$iid}; next unless defined $ip; return $ip if $passport->snmp_connect_ip($ip); } # Return Management Virtual IP address if ( ( defined $virt_ip ) and ( $virt_ip ne '0.0.0.0' ) ) { return $virt_ip if $passport->snmp_connect_ip($virt_ip); } } # Return OSPF Router ID if ( ( defined $router_ip ) and ( $router_ip ne '0.0.0.0' ) ) { foreach my $iid ( keys %$rc_ip_addr ) { my $ip = $rc_ip_addr->{$iid}; next unless $router_ip eq $ip; return $router_ip if $passport->snmp_connect_ip($router_ip); } } # Otherwise Return SONMP Advertised IP Address foreach my $entry ( keys %$sonmp_topo_port ) { my $port = $sonmp_topo_port->{$entry}; next unless $port == 0; my $ip = $sonmp_topo_ip->{$entry}; return $ip if (( defined $ip ) and ( $ip ne '0.0.0.0' ) and ( $passport->snmp_connect_ip($ip) ) ); } return; } # Required for SNMP::Info::SONMP sub index_factor { my $passport = shift; my $model = $passport->model(); my $index_factor = 64; # Older Accelar models use base 16 instead of 64 $index_factor = 16 if ( defined $model and $model =~ /^1[012][05]0/ ); return $index_factor; } sub slot_offset { my $passport = shift; my $model = $passport->model(); # Newer VSP 4K and 8K start at an index of 192 ~ slot 3 but really slot 1 return -2 if ( defined $model and $model =~ /^VSP[478]/ ); return 0; } sub port_offset { return 1; } # Bridge MIB does not map Bridge Port to ifIndex correctly sub bp_index { my $passport = shift; my $partial = shift; my $if_index = $passport->i_index($partial) || {}; my %bp_index; foreach my $iid ( keys %$if_index ) { $bp_index{$iid} = $iid; } # If we have MLT's map them to the designated port my $trunks = $passport->rc_mlt_index; my $dps = $passport->rc_mlt_dp || {}; if ( ref {} eq ref $trunks and scalar keys %$trunks ) { foreach my $m ( keys %$trunks ) { my $m_idx = $trunks->{$m}; next unless $m_idx; my $i_idx = $dps->{$m} ? $dps->{$m} : $m_idx; $bp_index{$m_idx} = $i_idx; } } return \%bp_index; } # We have devices which support BRIDGE-MIB, Q-BRIDGE-MIB, and RAPID-CITY # exclusively. Use standards-based first and fall back to RAPID-CITY. sub fw_mac { my $passport = shift; my $partial = shift; my $qb = $passport->SUPER::fw_mac($partial); return $qb if (ref {} eq ref $qb and scalar keys %$qb); my $qb_fw_port = $passport->rcBridgeTpFdbPort($partial); my $qb_fw_mac = {}; foreach my $idx ( keys %$qb_fw_port ) { my ( $fdb_id, $mac ) = _rc_fdbtable_index($idx); $qb_fw_mac->{$idx} = $mac; } return $qb_fw_mac; } sub fw_port { my $passport = shift; my $partial = shift; my $qb = $passport->SUPER::fw_port($partial); return $qb if (ref {} eq ref $qb and scalar keys %$qb); return $passport->rcBridgeTpFdbPort($partial); } sub fw_status { my $passport = shift; my $partial = shift; my $qb = $passport->SUPER::fw_status($partial); return $qb if (ref {} eq ref $qb and scalar keys %$qb); return $passport->rcBridgeTpFdbStatus($partial); } sub qb_fw_vlan { my $passport = shift; my $partial = shift; my $qb = $passport->SUPER::qb_fw_vlan($partial); return $qb if (ref {} eq ref $qb and scalar keys %$qb); my $qb_fw_port = $passport->rcBridgeTpFdbPort($partial); my $qb_fw_vlan = {}; foreach my $idx ( keys %$qb_fw_port ) { my ( $fdb_id, $mac ) = _rc_fdbtable_index($idx); $qb_fw_vlan->{$idx} = $fdb_id; } return $qb_fw_vlan; } # break up the rcBridgeTpFdbEntry INDEX into FDB ID and MAC Address. sub _rc_fdbtable_index { my $idx = shift; my @values = split( /\./, $idx ); my $fdb_id = shift(@values); return ( $fdb_id, join( ':', map { sprintf "%02x", $_ } @values ) ); } # Pseudo ENTITY-MIB methods sub e_index { my $passport = shift; my $model = $passport->model(); my $rc_ps_t = $passport->rc_ps_type() || {}; # We're going to hack an index: Slot/Mda/Position # We're going to put chassis and power supplies in a slot # which doesn't exist my %rc_e_index; # Make up a chassis index $rc_e_index{1} = 1; # Power supplies are common, handle them first foreach my $idx ( keys %$rc_ps_t ) { next unless $idx; # We should never have 90 slots, they will also # sort numerically at the bottom my $index = $idx + 90 . "0000"; $rc_e_index{$index} = $index; } # Older Accelars use RAPID-CITY::rcCardTable if ( defined $model and $model =~ /^1[012][05]0/ ) { my $rc_c_t = $passport->rc_c_type() || {}; foreach my $idx ( keys %$rc_c_t ) { next unless $idx; my $index = "$idx" . "0000"; $rc_e_index{$index} = $index; $index++; $rc_e_index{$index} = $index; } } # All newer models use RAPID-CITY::rc2kCardTable else { my $rc2_c_t = $passport->rc2k_c_ftype() || {}; my $rc2_m_t = $passport->rc2k_mda_type() || {}; foreach my $idx ( keys %$rc2_c_t ) { next unless $idx; my $index = "$idx" . "0000"; for ( 0 .. 2 ) { $rc_e_index{$index} = $index; $index++; } } foreach my $idx ( keys %$rc2_m_t ) { next unless $idx; next if $idx == 0; my ( $slot, $mda ) = split /\./, $idx; $mda = sprintf( "%02d", $mda ); my $index = "$idx" . "$mda" . "00"; $rc_e_index{$index} = $index; $index++; $rc_e_index{$index} = $index; } } return \%rc_e_index; } sub e_class { my $passport = shift; my $rc_e_idx = $passport->e_index() || {}; my %rc_e_class; foreach my $iid ( keys %$rc_e_idx ) { if ( $iid == 1 ) { $rc_e_class{$iid} = 'chassis'; } elsif ( $iid =~ /^9(\d)/ and length $iid > 5 ) { $rc_e_class{$iid} = 'powerSupply'; } elsif ( $iid =~ /0000$/ ) { $rc_e_class{$iid} = 'container'; } else { $rc_e_class{$iid} = 'module'; } } return \%rc_e_class; } sub e_descr { my $passport = shift; my $model = $passport->model(); my $rc_ps = $passport->rc_ps_detail() || {}; my $rc_ch = $passport->chassis() || ''; $rc_ch =~ s/a//; my %rc_e_descr; # Chassis $rc_e_descr{1} = $rc_ch; # Power supplies are common, handle them first foreach my $idx ( keys %$rc_ps ) { next unless $idx; my $ps = $rc_ps->{$idx}; next unless $ps; my $index = $idx + 90 . "0000"; $rc_e_descr{$index} = $ps; } # Older Accelars use RAPID-CITY::rcCardTable if ( defined $model and $model =~ /^1[012][05]0/ ) { my $rc_c_t = $passport->rc_c_type() || {}; foreach my $idx ( keys %$rc_c_t ) { next unless $idx; my $type = $rc_c_t->{$idx}; next unless $type; my $index = "$idx" . "0000"; $rc_e_descr{$index} = "Slot " . "$idx"; $index++; $rc_e_descr{$index} = $type; } } # All newer models use RAPID-CITY::rc2kCardTable else { my $rc2_cf = $passport->rc2k_c_fdesc() || {}; my $rc2_cb = $passport->rc2k_c_bdesc() || {}; my $rc2_m = $passport->rc2k_mda_desc() || {}; foreach my $idx ( keys %$rc2_cf ) { next unless $idx; my $cf = $rc2_cf->{$idx}; next unless $idx; my $cb = $rc2_cb->{$idx}; my $index = "$idx" . "0000"; $rc_e_descr{$index} = "Slot " . "$idx"; $index++; $rc_e_descr{$index} = $cf; $index++; $rc_e_descr{$index} = $cb; } foreach my $idx ( keys %$rc2_m ) { next unless $idx; my $cm = $rc2_m->{$idx}; next unless $cm; my ( $slot, $mda ) = split /\./, $idx; $mda = sprintf( "%02d", $mda ); my $index = "$idx" . "$mda" . "00"; $rc_e_descr{$index} = $cm; } } return \%rc_e_descr; } sub e_type { my $passport = shift; my $model = $passport->model(); my $rc_ps = $passport->rc_ps_type() || {}; my $rc_ch = $passport->chassis(); my %rc_e_type; # Chassis $rc_e_type{1} = $rc_ch; # Power supplies are common, handle them first foreach my $idx ( keys %$rc_ps ) { next unless $idx; my $ps = $rc_ps->{$idx}; next unless $ps; my $index = $idx + 90 . "0000"; $rc_e_type{$index} = $ps; } # Older Accelars use RAPID-CITY::rcCardTable if ( defined $model and $model =~ /^1[012][05]0/ ) { my $rc_c_t = $passport->rc_c_type() || {}; foreach my $idx ( keys %$rc_c_t ) { next unless $idx; my $type = $rc_c_t->{$idx}; next unless $type; my $index = "$idx" . "0000"; $rc_e_type{$index} = "zeroDotZero"; $index++; $rc_e_type{$index} = $type; } } # All newer models use RAPID-CITY::rc2kCardTable else { my $rc2_cf = $passport->rc2k_c_ftype() || {}; my $rc2_cb = $passport->rc2k_c_btype() || {}; my $rc2_m = $passport->rc2k_mda_type() || {}; foreach my $idx ( keys %$rc2_cf ) { next unless $idx; my $cf = $rc2_cf->{$idx}; next unless $idx; my $cb = $rc2_cb->{$idx}; my $index = "$idx" . "0000"; $rc_e_type{$index} = "zeroDotZero"; $index++; $rc_e_type{$index} = $cf; $index++; $rc_e_type{$index} = $cb; } foreach my $idx ( keys %$rc2_m ) { next unless $idx; my $cm = $rc2_m->{$idx}; next unless $cm; my ( $slot, $mda ) = split /\./, $idx; $mda = sprintf( "%02d", $mda ); my $index = "$idx" . "$mda" . "00"; $rc_e_type{$index} = $cm; } } return \%rc_e_type; } sub e_name { my $passport = shift; my $model = $passport->model(); my $rc_e_idx = $passport->e_index() || {}; my %rc_e_name; foreach my $iid ( keys %$rc_e_idx ) { if ( $iid == 1 ) { $rc_e_name{$iid} = 'Chassis'; next; } my $mod = int( substr( $iid, -4, 2 ) ); my $slot = substr( $iid, -6, 2 ); if ( $iid =~ /^9(\d)/ and length $iid > 5 ) { $rc_e_name{$iid} = "Power Supply $1"; } elsif ( $iid =~ /(00){2}$/ ) { $rc_e_name{$iid} = "Slot $slot"; } elsif ( $iid =~ /(00){1}$/ ) { $rc_e_name{$iid} = "Card $slot, MDA $mod"; } elsif ( defined $model and $model =~ /^1[012][05]0/ and $iid =~ /1$/ ) { $rc_e_name{$iid} = "Card $slot"; } elsif ( $iid =~ /1$/ ) { $rc_e_name{$iid} = "Card $slot (front)"; } elsif ( $iid =~ /2$/ ) { $rc_e_name{$iid} = "Card $slot (back)"; } } return \%rc_e_name; } sub e_hwver { my $passport = shift; my $model = $passport->model(); my $rc_ps = $passport->rc_ps_rev() || {}; my %rc_e_hwver; # Chassis $rc_e_hwver{1} = $passport->rc_ch_rev(); # Power supplies are common, handle them first foreach my $idx ( keys %$rc_ps ) { next unless $idx; my $ps = $rc_ps->{$idx}; next unless $ps; my $index = $idx + 90 . "0000"; $rc_e_hwver{$index} = $ps; } # Older Accelars use RAPID-CITY::rcCardTable if ( defined $model and $model =~ /^1[012][05]0/ ) { my $rc_c_t = $passport->rc_c_rev() || {}; foreach my $idx ( keys %$rc_c_t ) { next unless $idx; my $type = $rc_c_t->{$idx}; next unless $type; my $index = "$idx" . "0001"; $rc_e_hwver{$index} = $type; } } # All newer models use RAPID-CITY::rc2kCardTable else { my $rc2_cf = $passport->rc2k_c_frev() || {}; my $rc2_cb = $passport->rc2k_c_brev() || {}; my $rc2_m = $passport->rc2k_mda_rev() || {}; foreach my $idx ( keys %$rc2_cf ) { next unless $idx; my $cf = $rc2_cf->{$idx}; next unless $idx; my $cb = $rc2_cb->{$idx}; my $index = "$idx" . "0001"; $rc_e_hwver{$index} = $cf; $index++; $rc_e_hwver{$index} = $cb; } foreach my $idx ( keys %$rc2_m ) { next unless $idx; my $cm = $rc2_m->{$idx}; next unless $cm; my ( $slot, $mda ) = split /\./, $idx; $mda = sprintf( "%02d", $mda ); my $index = "$idx" . "$mda" . "00"; $rc_e_hwver{$index} = $cm; } } return \%rc_e_hwver; } sub e_vendor { my $passport = shift; my $rc_e_idx = $passport->e_index() || {}; my %rc_e_vendor; foreach my $iid ( keys %$rc_e_idx ) { $rc_e_vendor{$iid} = 'avaya'; } return \%rc_e_vendor; } sub e_serial { my $passport = shift; my $model = $passport->model(); my $rc_ps = $passport->rc_ps_serial() || {}; my %rc_e_serial; # Chassis $rc_e_serial{1} = $passport->rc_serial(); # Power supplies are common, handle them first foreach my $idx ( keys %$rc_ps ) { next unless $idx; my $ps = $rc_ps->{$idx}; next unless $ps; my $index = $idx + 90 . "0000"; $rc_e_serial{$index} = $ps; } # Older Accelars use RAPID-CITY::rcCardTable if ( defined $model and $model =~ /^1[012][05]0/ ) { my $rc_c_t = $passport->rc_c_serial() || {}; foreach my $idx ( keys %$rc_c_t ) { next unless $idx; my $type = $rc_c_t->{$idx}; next unless $type; my $index = "$idx" . "0001"; $rc_e_serial{$index} = $type; } } # All newer models use RAPID-CITY::rc2kCardTable else { my $rc2_cf = $passport->rc2k_c_fserial() || {}; my $rc2_cb = $passport->rc2k_c_bserial() || {}; my $rc2_m = $passport->rc2k_mda_serial() || {}; foreach my $idx ( keys %$rc2_cf ) { next unless $idx; my $cf = $rc2_cf->{$idx}; next unless $idx; my $cb = $rc2_cb->{$idx}; my $index = "$idx" . "0001"; $rc_e_serial{$index} = $cf; $index++; $rc_e_serial{$index} = $cb; } foreach my $idx ( keys %$rc2_m ) { next unless $idx; my $cm = $rc2_m->{$idx}; next unless $cm; my ( $slot, $mda ) = split /\./, $idx; $mda = sprintf( "%02d", $mda ); my $index = "$idx" . "$mda" . "00"; $rc_e_serial{$index} = $cm; } } return \%rc_e_serial; } sub e_pos { my $passport = shift; my $rc_e_idx = $passport->e_index() || {}; my %rc_e_pos; foreach my $iid ( keys %$rc_e_idx ) { next unless $iid; if ( $iid == 1 ) { $rc_e_pos{$iid} = -1; next; } my $sub = int( substr( $iid, -2, 2 ) ); my $mod = int( substr( $iid, -4, 2 ) ); my $slot = substr( $iid, -6, 2 ); if ( $iid =~ /(00){2}$/ ) { $rc_e_pos{$iid} = $slot; } elsif ( $iid =~ /(00){1}$/ ) { $rc_e_pos{$iid} = $mod * 100; } else { $rc_e_pos{$iid} = $sub; } } return \%rc_e_pos; } sub e_parent { my $passport = shift; my $rc_e_idx = $passport->e_index() || {}; my %rc_e_parent; foreach my $iid ( keys %$rc_e_idx ) { next unless $iid; if ( $iid == 1 ) { $rc_e_parent{$iid} = 0; next; } my $slot = substr( $iid, -6, 2 ); if ( $iid =~ /(00){1,2}$/ ) { $rc_e_parent{$iid} = 1; } else { $rc_e_parent{$iid} = "$slot" . "0000"; } } return \%rc_e_parent; } 1; __END__ =head1 NAME SNMP::Info::Layer3::Passport - SNMP Interface to modular Avaya Ethernet Routing Switch 8000 Series and VSP 9000 Series switches. =head1 AUTHOR Eric Miller =head1 SYNOPSIS # Let SNMP::Info determine the correct subclass for you. my $passport = new SNMP::Info( AutoSpecify => 1, Debug => 1, DestHost => 'myswitch', Community => 'public', Version => 2 ) or die "Can't connect to DestHost.\n"; my $class = $passport->class(); print "SNMP::Info determined this device to fall under subclass : $class\n"; =head1 DESCRIPTION Abstraction subclass for modular Avaya Ethernet Routing Switch 8000 Series (formerly Nortel/Bay Passport/Accelar) and VSP 9000 Series switches. These devices have some of the same characteristics as the stackable Avaya Ethernet Switches (Baystack). For example, extended interface information is gleaned from F. For speed or debugging purposes you can call the subclass directly, but not after determining a more specific class using the method above. my $passport = new SNMP::Info::Layer3::Passport(...); =head2 Inherited Classes =over =item SNMP::Info::SONMP =item SNMP::Info::RapidCity =item SNMP::Info::Layer3 =back =head2 Required MIBs =over =item Inherited Classes' MIBs See L for its own MIB requirements. See L for its own MIB requirements. See L for its own MIB requirements. =back =head1 GLOBALS These are methods that return scalar value from SNMP =over =item $passport->model() Returns model type. Checks $passport->id() against the F and then parses out C. =item $passport->vendor() Returns 'avaya' =item $passport->os() Returns 'passport' =item $passport->os_ver() Returns the software version extracted from C =item $passport->serial() Returns (C) =item $passport->root_ip() Returns the primary IP used to communicate with the device. Returns the first found: CLIP (CircuitLess IP), Management Virtual IP (C), OSPF Router ID (C), SONMP Advertised IP Address. =back =head2 Overrides =over =item $passport->index_factor() Required by SNMP::Info::SONMP. Returns 64 for 8600, 16 for Accelar. =item $passport->port_offset() Required by SNMP::Info::SONMP. Returns 1. =item $passport->slot_offset() Required by SNMP::Info::SONMP. Returns 0. =back =head2 Global Methods imported from SNMP::Info::SONMP See documentation in L for details. =head2 Global Methods imported from SNMP::Info::RapidCity See documentation in L for details. =head2 Globals imported from SNMP::Info::Layer3 See documentation in L for details. =head1 TABLE METHODS These are methods that return tables of information in the form of a reference to a hash. =head2 Overrides =over =item $passport->i_index() Returns SNMP IID to Interface index. Extends (C) by adding the index of the CPU virtual management IP (if present), each CPU Ethernet port, and each VLAN to ensure the virtual router ports are captured. =item $passport->interfaces() Returns reference to the map between IID and physical Port. Slot and port numbers on the Passport switches are determined by the formula: port = (C) + port_offset, slot = int(C). The physical port name is returned as slot.port. CPU Ethernet ports are prefixed with CPU and VLAN interfaces are returned as the VLAN ID prefixed with Vlan. =item $passport->i_mac() MAC address of the interface. Note this is just the MAC of the port, not anything connected to it. =item $passport->i_description() Description of the interface. Usually a little longer single word name that is both human and machine friendly. Not always. =item $passport->i_name() Crosses rc_alias() (C) with ifAlias() and returns the human set port name if exists. =item $passport->ip_index() Maps the IP Table to the IID. Extends (C) by adding the index of the CPU virtual management IP (if present) and each CPU Ethernet port. =item $passport->ip_netmask() Extends (C) by adding the mask of the CPU virtual management IP (if present) and each CPU Ethernet port. =item $passport->bp_index() Returns reference to hash of bridge port table entries map back to interface identifier (iid) Returns (C) for both key and value since some devices seem to have problems with F =back =head2 Forwarding Table These methods utilize, in order; F, F, and F to obtain the forwarding table information. =over =item $passport->fw_mac() Returns reference to hash of forwarding table MAC Addresses (C), (C), (C) =item $passport->fw_port() Returns reference to hash of forwarding table entries port interface identifier (iid) (C), (C), (C) =item $passport->fw_status() Returns reference to hash of forwarding table entries status (C), (C), (C) =item $passport->qb_fw_vlan() Returns reference to hash of forwarding table entries VLAN ID (C), (C) =back =head2 Pseudo F information These devices do not support F. These methods emulate Physical Table methods using the F. =over =item $passport->e_index() Returns reference to hash. Key and Value: Integer. The index is created by combining the slot, module, and position into a five or six digit integer. Slot can be either one or two digits while the module and position are each two digits padded with leading zero if required. =item $passport->e_class() Returns reference to hash. Key: IID, Value: General hardware type. This class only returns container, module, and power supply types. =item $passport->e_descr() Returns reference to hash. Key: IID, Value: Human friendly name. =item $passport->e_name() Returns reference to hash. Key: IID, Value: Human friendly name. =item $passport->e_hwver() Returns reference to hash. Key: IID, Value: Hardware version. =item $passport->e_vendor() Returns reference to hash. Key: IID, Value: avaya. =item $passport->e_serial() Returns reference to hash. Key: IID, Value: Serial number. =item $passport->e_pos() Returns reference to hash. Key: IID, Value: The relative position among all entities sharing the same parent. =item $passport->e_type() Returns reference to hash. Key: IID, Value: Type of component/sub-component. =item $passport->e_parent() Returns reference to hash. Key: IID, Value: The value of e_index() for the entity which 'contains' this entity. A value of zero indicates this entity is not contained in any other entity. =back =head2 Table Methods imported from SNMP::Info::SONMP See documentation in L for details. =head2 Table Methods imported from SNMP::Info::RapidCity See documentation in L for details. =head2 Table Methods imported from SNMP::Info::Layer3 See documentation in L for details. =cut