1219820Sjeff#!/usr/bin/perl
2219820Sjeff#
3219820Sjeff# Copyright (c) 2008 Voltaire, Inc. All rights reserved.
4219820Sjeff# Copyright (c) 2006 The Regents of the University of California.
5219820Sjeff#
6219820Sjeff# Produced at Lawrence Livermore National Laboratory.
7219820Sjeff# Written by Ira Weiny <weiny2@llnl.gov>.
8219820Sjeff#
9219820Sjeff# This software is available to you under a choice of one of two
10219820Sjeff# licenses.  You may choose to be licensed under the terms of the GNU
11219820Sjeff# General Public License (GPL) Version 2, available from the file
12219820Sjeff# COPYING in the main directory of this source tree, or the
13219820Sjeff# OpenIB.org BSD license below:
14219820Sjeff#
15219820Sjeff#     Redistribution and use in source and binary forms, with or
16219820Sjeff#     without modification, are permitted provided that the following
17219820Sjeff#     conditions are met:
18219820Sjeff#
19219820Sjeff#      - Redistributions of source code must retain the above
20219820Sjeff#        copyright notice, this list of conditions and the following
21219820Sjeff#        disclaimer.
22219820Sjeff#
23219820Sjeff#      - Redistributions in binary form must reproduce the above
24219820Sjeff#        copyright notice, this list of conditions and the following
25219820Sjeff#        disclaimer in the documentation and/or other materials
26219820Sjeff#        provided with the distribution.
27219820Sjeff#
28219820Sjeff# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
29219820Sjeff# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
30219820Sjeff# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
31219820Sjeff# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
32219820Sjeff# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
33219820Sjeff# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
34219820Sjeff# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
35219820Sjeff# SOFTWARE.
36219820Sjeff#
37219820Sjeff
38219820Sjeffuse strict;
39219820Sjeff
40219820Sjeffuse Getopt::Std;
41219820Sjeffuse IBswcountlimits;
42219820Sjeff
43219820Sjeffmy $print_action          = "no";
44219820Sjeffmy $report_port_info      = undef;
45219820Sjeffmy $single_switch         = undef;
46219820Sjeffmy $include_data_counters = undef;
47219820Sjeffmy $cache_file            = "";
48219820Sjeffmy $switch_found          = "no";
49219820Sjeff
50219820Sjeff# =========================================================================
51219820Sjeff#
52219820Sjeffsub report_counts
53219820Sjeff{
54219820Sjeff	my $addr         = $_[0];
55219820Sjeff	my $port         = $_[1];
56219820Sjeff	my $ca_name      = $_[2];
57219820Sjeff	my $ca_port      = $_[3];
58219820Sjeff	my $extra_params = get_ca_name_port_param_string($ca_name, $ca_port);
59219820Sjeff
60219820Sjeff	if (any_counts()) {
61219820Sjeff		print("   GUID $addr port $port:");
62219820Sjeff		check_counters($print_action);
63219820Sjeff		if ($include_data_counters) {
64219820Sjeff			check_data_counters($print_action);
65219820Sjeff		}
66219820Sjeff		print("\n");
67219820Sjeff
68219820Sjeff		if ($report_port_info) {
69219820Sjeff			my $lid   = "";
70219820Sjeff			my $speed = "";
71219820Sjeff			my $width = "";
72219820Sjeff			my $data  = `smpquery $extra_params -G portinfo $addr $port`;
73219820Sjeff			my @lines = split("\n", $data);
74219820Sjeff			foreach my $line (@lines) {
75219820Sjeff				if ($line =~ /^# Port info: Lid (\w+) port.*/) { $lid   = $1; }
76219820Sjeff				if ($line =~ /^LinkSpeedActive:\.+(.*)/)       { $speed = $1; }
77219820Sjeff				if ($line =~ /^LinkWidthActive:\.+(.*)/)       { $width = $1; }
78219820Sjeff			}
79219820Sjeff			my $hr = $IBswcountlimits::link_ends{"$addr"}{$port};
80219820Sjeff			if ($hr) {
81219820Sjeff				printf(
82219820Sjeff"         Link info: %6s %4s[%2s]  ==(%3s %s)==>  %18s %4s[%2s] \"%s\"\n",
83219820Sjeff					$lid,                $port,
84219820Sjeff					$hr->{loc_ext_port}, $width,
85219820Sjeff					$speed,              $hr->{rem_guid},
86219820Sjeff					$hr->{rem_port},     $hr->{rem_ext_port},
87219820Sjeff					$hr->{rem_desc}
88219820Sjeff				);
89219820Sjeff			} else {
90219820Sjeff				printf(
91219820Sjeff"         Link info: %6s %4s[  ]  ==(%3s %s)==>     (Disconnected)\n",
92219820Sjeff					$lid, $port, $width, $speed);
93219820Sjeff			}
94219820Sjeff		}
95219820Sjeff	}
96219820Sjeff}
97219820Sjeff
98219820Sjeff# =========================================================================
99219820Sjeff# use perfquery to get the counters.
100219820Sjeffsub get_counts
101219820Sjeff{
102219820Sjeff	my $addr         = $_[0];
103219820Sjeff	my $port         = $_[1];
104219820Sjeff	my $ca_name      = $_[2];
105219820Sjeff	my $ca_port      = $_[3];
106219820Sjeff	my $extra_params = get_ca_name_port_param_string($ca_name, $ca_port);
107219820Sjeff
108219820Sjeff	my $data = `perfquery $extra_params -G $addr $port` ||
109219820Sjeff		die "'perfquery $extra_params -G $addr $port' FAILED.\n";
110219820Sjeff	my @lines = split("\n", $data);
111219820Sjeff	foreach my $line (@lines) {
112219820Sjeff		foreach my $count (@IBswcountlimits::counters) {
113219820Sjeff			if ($line =~ /^$count:\.+(\d+)/) {
114219820Sjeff				$IBswcountlimits::cur_counts{$count} = $1;
115219820Sjeff			}
116219820Sjeff		}
117219820Sjeff	}
118219820Sjeff}
119219820Sjeff
120219820Sjeff# =========================================================================
121219820Sjeff#
122219820Sjeffmy %switches = ();
123219820Sjeff
124219820Sjeffsub get_switches
125219820Sjeff{
126219820Sjeff	my $data = `ibswitches $cache_file` ||
127219820Sjeff		die "'ibswitches $cache_file' failed.\n";
128219820Sjeff	my @lines = split("\n", $data);
129219820Sjeff	foreach my $line (@lines) {
130219820Sjeff		if ($line =~ /^Switch\s+:\s+(\w+)\s+ports\s+(\d+)\s+.*/) {
131219820Sjeff			$switches{$1} = $2;
132219820Sjeff		}
133219820Sjeff	}
134219820Sjeff}
135219820Sjeff
136219820Sjeff# =========================================================================
137219820Sjeff#
138219820Sjeffsub usage_and_exit
139219820Sjeff{
140219820Sjeff	my $prog = $_[0];
141219820Sjeff	print
142219820Sjeff"Usage: $prog [-a -c -r -R -s <err1,err2,...> -S <switch_guid> -D <direct route> -d -C <ca_name> -P <ca_port>]\n";
143219820Sjeff	print "   Report counters on all switches in subnet\n";
144219820Sjeff	print "   -a Report an action to take\n";
145219820Sjeff	print "   -c suppress some of the common counters\n";
146219820Sjeff	print "   -r report port configuration information\n";
147219820Sjeff	print "   -R Recalculate ibnetdiscover information\n";
148219820Sjeff	print "   -s <err1,err2,...> suppress errors listed\n";
149219820Sjeff	print
150219820Sjeff"   -D <direct route> output only the switch specified by direct route path\n";
151219820Sjeff	print "   -S <switch_guid> query only <switch_guid> (hex format)\n";
152219820Sjeff	print "   -d include the data counters in the output\n";
153219820Sjeff	print "   -C <ca_name> use selected Channel Adaptor name for queries\n";
154219820Sjeff	print "   -P <ca_port> use selected channel adaptor port for queries\n";
155219820Sjeff	exit 2;
156219820Sjeff}
157219820Sjeff
158219820Sjeffmy $argv0          = `basename $0`;
159219820Sjeffmy $regenerate_map = undef;
160219820Sjeffmy $single_switch  = undef;
161219820Sjeffmy $direct_route   = undef;
162219820Sjeffmy $ca_name        = "";
163219820Sjeffmy $ca_port        = "";
164219820Sjeff
165219820Sjeffchomp $argv0;
166219820Sjeffif (!getopts("has:crRS:D:dC:P:")) { usage_and_exit $argv0; }
167219820Sjeffif (defined $Getopt::Std::opt_h)  { usage_and_exit $argv0; }
168219820Sjeffif (defined $Getopt::Std::opt_a) { $print_action = "yes"; }
169219820Sjeffif (defined $Getopt::Std::opt_s) {
170219820Sjeff	@IBswcountlimits::suppress_errors = split(",", $Getopt::Std::opt_s);
171219820Sjeff}
172219820Sjeffif (defined $Getopt::Std::opt_c) {
173219820Sjeff	@IBswcountlimits::suppress_errors = split(",", "RcvSwRelayErrors");
174219820Sjeff}
175219820Sjeffif (defined $Getopt::Std::opt_r) { $report_port_info = $Getopt::Std::opt_r; }
176219820Sjeffif (defined $Getopt::Std::opt_R) { $regenerate_map   = $Getopt::Std::opt_R; }
177219820Sjeffif (defined $Getopt::Std::opt_D) { $direct_route     = $Getopt::Std::opt_D; }
178219820Sjeffif (defined $Getopt::Std::opt_S) {
179219820Sjeff	$single_switch = format_guid($Getopt::Std::opt_S);
180219820Sjeff}
181219820Sjeffif (defined $Getopt::Std::opt_d) {
182219820Sjeff	$include_data_counters = $Getopt::Std::opt_d;
183219820Sjeff}
184219820Sjeffif (defined $Getopt::Std::opt_C) { $ca_name = $Getopt::Std::opt_C; }
185219820Sjeffif (defined $Getopt::Std::opt_P) { $ca_port = $Getopt::Std::opt_P; }
186219820Sjeff
187219820Sjeff$cache_file = get_cache_file($ca_name, $ca_port);
188219820Sjeff
189219820Sjeffsub main
190219820Sjeff{
191219820Sjeff	if (@IBswcountlimits::suppress_errors) {
192219820Sjeff		my $msg = join(",", @IBswcountlimits::suppress_errors);
193219820Sjeff		print "Suppressing: $msg\n";
194219820Sjeff	}
195219820Sjeff	get_link_ends($regenerate_map, $ca_name, $ca_port);
196219820Sjeff	get_switches;
197219820Sjeff	if (defined($direct_route)) {
198219820Sjeff		# convert DR to guid, then use original single_switch option
199219820Sjeff		$single_switch = convert_dr_to_guid($direct_route);
200219820Sjeff		if (!defined($single_switch) || !is_switch($single_switch)) {
201219820Sjeff			printf("The direct route (%s) does not map to a switch.\n",
202219820Sjeff				$direct_route);
203219820Sjeff			return;
204219820Sjeff		}
205219820Sjeff	}
206219820Sjeff	foreach my $sw_addr (keys %switches) {
207219820Sjeff		if ($single_switch && $sw_addr ne "$single_switch") {
208219820Sjeff			next;
209219820Sjeff		} else {
210219820Sjeff			$switch_found = "yes";
211219820Sjeff		}
212219820Sjeff
213219820Sjeff		my $switch_prompt = "no";
214219820Sjeff		foreach my $sw_port (1 .. $switches{$sw_addr}) {
215219820Sjeff			clear_counters;
216219820Sjeff			get_counts($sw_addr, $sw_port, $ca_name, $ca_port);
217219820Sjeff			if (any_counts() && $switch_prompt eq "no") {
218219820Sjeff				my $hr = $IBswcountlimits::link_ends{"$sw_addr"}{$sw_port};
219219820Sjeff				printf("Errors for %18s \"%s\"\n", $sw_addr, $hr->{loc_desc});
220219820Sjeff				$switch_prompt = "yes";
221219820Sjeff			}
222219820Sjeff			report_counts($sw_addr, $sw_port);
223219820Sjeff		}
224219820Sjeff	}
225219820Sjeff	if ($single_switch && $switch_found ne "yes") {
226219820Sjeff		printf("Switch \"%s\" not found.\n", $single_switch);
227219820Sjeff	}
228219820Sjeff}
229219820Sjeffmain;
230219820Sjeff
231