1#!/usr/bin/perl 2# 3# Copyright (c) 2008 Voltaire, Inc. All rights reserved. 4# Copyright (c) 2006 The Regents of the University of California. 5# 6# Produced at Lawrence Livermore National Laboratory. 7# Written by Ira Weiny <weiny2@llnl.gov>. 8# 9# This software is available to you under a choice of one of two 10# licenses. You may choose to be licensed under the terms of the GNU 11# General Public License (GPL) Version 2, available from the file 12# COPYING in the main directory of this source tree, or the 13# OpenIB.org BSD license below: 14# 15# Redistribution and use in source and binary forms, with or 16# without modification, are permitted provided that the following 17# conditions are met: 18# 19# - Redistributions of source code must retain the above 20# copyright notice, this list of conditions and the following 21# disclaimer. 22# 23# - Redistributions in binary form must reproduce the above 24# copyright notice, this list of conditions and the following 25# disclaimer in the documentation and/or other materials 26# provided with the distribution. 27# 28# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 29# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 30# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 31# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 32# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 33# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 34# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 35# SOFTWARE. 36# 37 38use strict; 39 40use Getopt::Std; 41use IBswcountlimits; 42 43my $print_action = "no"; 44my $report_port_info = undef; 45my $single_switch = undef; 46my $include_data_counters = undef; 47my $cache_file = ""; 48my $switch_found = "no"; 49 50# ========================================================================= 51# 52sub report_counts 53{ 54 my $addr = $_[0]; 55 my $port = $_[1]; 56 my $ca_name = $_[2]; 57 my $ca_port = $_[3]; 58 my $extra_params = get_ca_name_port_param_string($ca_name, $ca_port); 59 60 if (any_counts()) { 61 print(" GUID $addr port $port:"); 62 check_counters($print_action); 63 if ($include_data_counters) { 64 check_data_counters($print_action); 65 } 66 print("\n"); 67 68 if ($report_port_info) { 69 my $lid = ""; 70 my $speed = ""; 71 my $width = ""; 72 my $data = `smpquery $extra_params -G portinfo $addr $port`; 73 my @lines = split("\n", $data); 74 foreach my $line (@lines) { 75 if ($line =~ /^# Port info: Lid (\w+) port.*/) { $lid = $1; } 76 if ($line =~ /^LinkSpeedActive:\.+(.*)/) { $speed = $1; } 77 if ($line =~ /^LinkWidthActive:\.+(.*)/) { $width = $1; } 78 } 79 my $hr = $IBswcountlimits::link_ends{"$addr"}{$port}; 80 if ($hr) { 81 printf( 82" Link info: %6s %4s[%2s] ==(%3s %s)==> %18s %4s[%2s] \"%s\"\n", 83 $lid, $port, 84 $hr->{loc_ext_port}, $width, 85 $speed, $hr->{rem_guid}, 86 $hr->{rem_port}, $hr->{rem_ext_port}, 87 $hr->{rem_desc} 88 ); 89 } else { 90 printf( 91" Link info: %6s %4s[ ] ==(%3s %s)==> (Disconnected)\n", 92 $lid, $port, $width, $speed); 93 } 94 } 95 } 96} 97 98# ========================================================================= 99# use perfquery to get the counters. 100sub get_counts 101{ 102 my $addr = $_[0]; 103 my $port = $_[1]; 104 my $ca_name = $_[2]; 105 my $ca_port = $_[3]; 106 my $extra_params = get_ca_name_port_param_string($ca_name, $ca_port); 107 108 my $data = `perfquery $extra_params -G $addr $port` || 109 die "'perfquery $extra_params -G $addr $port' FAILED.\n"; 110 my @lines = split("\n", $data); 111 foreach my $line (@lines) { 112 foreach my $count (@IBswcountlimits::counters) { 113 if ($line =~ /^$count:\.+(\d+)/) { 114 $IBswcountlimits::cur_counts{$count} = $1; 115 } 116 } 117 } 118} 119 120# ========================================================================= 121# 122my %switches = (); 123 124sub get_switches 125{ 126 my $data = `ibswitches $cache_file` || 127 die "'ibswitches $cache_file' failed.\n"; 128 my @lines = split("\n", $data); 129 foreach my $line (@lines) { 130 if ($line =~ /^Switch\s+:\s+(\w+)\s+ports\s+(\d+)\s+.*/) { 131 $switches{$1} = $2; 132 } 133 } 134} 135 136# ========================================================================= 137# 138sub usage_and_exit 139{ 140 my $prog = $_[0]; 141 print 142"Usage: $prog [-a -c -r -R -s <err1,err2,...> -S <switch_guid> -D <direct route> -d -C <ca_name> -P <ca_port>]\n"; 143 print " Report counters on all switches in subnet\n"; 144 print " -a Report an action to take\n"; 145 print " -c suppress some of the common counters\n"; 146 print " -r report port configuration information\n"; 147 print " -R Recalculate ibnetdiscover information\n"; 148 print " -s <err1,err2,...> suppress errors listed\n"; 149 print 150" -D <direct route> output only the switch specified by direct route path\n"; 151 print " -S <switch_guid> query only <switch_guid> (hex format)\n"; 152 print " -d include the data counters in the output\n"; 153 print " -C <ca_name> use selected Channel Adaptor name for queries\n"; 154 print " -P <ca_port> use selected channel adaptor port for queries\n"; 155 exit 2; 156} 157 158my $argv0 = `basename $0`; 159my $regenerate_map = undef; 160my $single_switch = undef; 161my $direct_route = undef; 162my $ca_name = ""; 163my $ca_port = ""; 164 165chomp $argv0; 166if (!getopts("has:crRS:D:dC:P:")) { usage_and_exit $argv0; } 167if (defined $Getopt::Std::opt_h) { usage_and_exit $argv0; } 168if (defined $Getopt::Std::opt_a) { $print_action = "yes"; } 169if (defined $Getopt::Std::opt_s) { 170 @IBswcountlimits::suppress_errors = split(",", $Getopt::Std::opt_s); 171} 172if (defined $Getopt::Std::opt_c) { 173 @IBswcountlimits::suppress_errors = split(",", "RcvSwRelayErrors"); 174} 175if (defined $Getopt::Std::opt_r) { $report_port_info = $Getopt::Std::opt_r; } 176if (defined $Getopt::Std::opt_R) { $regenerate_map = $Getopt::Std::opt_R; } 177if (defined $Getopt::Std::opt_D) { $direct_route = $Getopt::Std::opt_D; } 178if (defined $Getopt::Std::opt_S) { 179 $single_switch = format_guid($Getopt::Std::opt_S); 180} 181if (defined $Getopt::Std::opt_d) { 182 $include_data_counters = $Getopt::Std::opt_d; 183} 184if (defined $Getopt::Std::opt_C) { $ca_name = $Getopt::Std::opt_C; } 185if (defined $Getopt::Std::opt_P) { $ca_port = $Getopt::Std::opt_P; } 186 187$cache_file = get_cache_file($ca_name, $ca_port); 188 189sub main 190{ 191 if (@IBswcountlimits::suppress_errors) { 192 my $msg = join(",", @IBswcountlimits::suppress_errors); 193 print "Suppressing: $msg\n"; 194 } 195 get_link_ends($regenerate_map, $ca_name, $ca_port); 196 get_switches; 197 if (defined($direct_route)) { 198 # convert DR to guid, then use original single_switch option 199 $single_switch = convert_dr_to_guid($direct_route); 200 if (!defined($single_switch) || !is_switch($single_switch)) { 201 printf("The direct route (%s) does not map to a switch.\n", 202 $direct_route); 203 return; 204 } 205 } 206 foreach my $sw_addr (keys %switches) { 207 if ($single_switch && $sw_addr ne "$single_switch") { 208 next; 209 } else { 210 $switch_found = "yes"; 211 } 212 213 my $switch_prompt = "no"; 214 foreach my $sw_port (1 .. $switches{$sw_addr}) { 215 clear_counters; 216 get_counts($sw_addr, $sw_port, $ca_name, $ca_port); 217 if (any_counts() && $switch_prompt eq "no") { 218 my $hr = $IBswcountlimits::link_ends{"$sw_addr"}{$sw_port}; 219 printf("Errors for %18s \"%s\"\n", $sw_addr, $hr->{loc_desc}); 220 $switch_prompt = "yes"; 221 } 222 report_counts($sw_addr, $sw_port); 223 } 224 } 225 if ($single_switch && $switch_found ne "yes") { 226 printf("Switch \"%s\" not found.\n", $single_switch); 227 } 228} 229main; 230 231