1219820Sjeff#!/usr/bin/perl 2219820Sjeff# 3219820Sjeff# Copyright (c) 2006 The Regents of the University of California. 4219820Sjeff# Copyright (c) 2006-2008 Voltaire, Inc. All rights reserved. 5219820Sjeff# 6219820Sjeff# Produced at Lawrence Livermore National Laboratory. 7219820Sjeff# Written by Ira Weiny <weiny2@llnl.gov>. 8219820Sjeff# Erez Strauss from Voltaire for help in the get_link_ends code. 9219820Sjeff# 10219820Sjeff# This software is available to you under a choice of one of two 11219820Sjeff# licenses. You may choose to be licensed under the terms of the GNU 12219820Sjeff# General Public License (GPL) Version 2, available from the file 13219820Sjeff# COPYING in the main directory of this source tree, or the 14219820Sjeff# OpenIB.org BSD license below: 15219820Sjeff# 16219820Sjeff# Redistribution and use in source and binary forms, with or 17219820Sjeff# without modification, are permitted provided that the following 18219820Sjeff# conditions are met: 19219820Sjeff# 20219820Sjeff# - Redistributions of source code must retain the above 21219820Sjeff# copyright notice, this list of conditions and the following 22219820Sjeff# disclaimer. 23219820Sjeff# 24219820Sjeff# - Redistributions in binary form must reproduce the above 25219820Sjeff# copyright notice, this list of conditions and the following 26219820Sjeff# disclaimer in the documentation and/or other materials 27219820Sjeff# provided with the distribution. 28219820Sjeff# 29219820Sjeff# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 30219820Sjeff# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 31219820Sjeff# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 32219820Sjeff# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 33219820Sjeff# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 34219820Sjeff# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 35219820Sjeff# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 36219820Sjeff# SOFTWARE. 37219820Sjeff# 38219820Sjeff 39219820Sjeffuse strict; 40219820Sjeff 41219820Sjeff%IBswcountlimits::cur_counts = (); 42219820Sjeff%IBswcountlimits::new_counts = (); 43219820Sjeff@IBswcountlimits::suppress_errors = (); 44219820Sjeff$IBswcountlimits::link_ends = undef; 45219820Sjeff$IBswcountlimits::pause_time = 10; 46219820Sjeff$IBswcountlimits::cache_dir = "/var/cache/infiniband-diags"; 47219820Sjeff 48219820Sjeff# all the PerfMgt counters 49219820Sjeff@IBswcountlimits::counters = ( 50219820Sjeff "SymbolErrors", "LinkRecovers", 51219820Sjeff "LinkDowned", "RcvErrors", 52219820Sjeff "RcvRemotePhysErrors", "RcvSwRelayErrors", 53219820Sjeff "XmtDiscards", "XmtConstraintErrors", 54219820Sjeff "RcvConstraintErrors", "LinkIntegrityErrors", 55219820Sjeff "ExcBufOverrunErrors", "VL15Dropped", 56219820Sjeff "XmtData", "RcvData", 57219820Sjeff "XmtPkts", "RcvPkts" 58219820Sjeff); 59219820Sjeff 60219820Sjeff# non-critical counters 61219820Sjeff%IBswcountlimits::error_counters = ( 62219820Sjeff "SymbolErrors", 63219820Sjeff"No action is required except if counter is increasing along with LinkRecovers", 64219820Sjeff "LinkRecovers", 65219820Sjeff"If this is increasing along with SymbolErrors this may indicate a bad link, run ibswportwatch.pl on this port", 66219820Sjeff "LinkDowned", 67219820Sjeff "Number of times the port has gone down (Usually for valid reasons)", 68219820Sjeff "RcvErrors", 69219820Sjeff"This is a bad link, if the link is internal to a 288 try setting SDR, otherwise check the cable", 70219820Sjeff "RcvRemotePhysErrors", 71219820Sjeff "This indicates a problem ELSEWHERE in the fabric.", 72219820Sjeff "XmtDiscards", 73219820Sjeff"This is a symptom of congestion and may require tweaking either HOQ or switch lifetime values", 74219820Sjeff "XmtConstraintErrors", 75219820Sjeff "This is a result of bad partitioning, check partition configuration.", 76219820Sjeff "RcvConstraintErrors", 77219820Sjeff "This is a result of bad partitioning, check partition configuration.", 78219820Sjeff "LinkIntegrityErrors", 79219820Sjeff "May indicate a bad link, run ibswportwatch.pl on this port", 80219820Sjeff "ExcBufOverrunErrors", 81219820Sjeff"This is a flow control state machine error and can be caused by packets with physical errors", 82219820Sjeff "VL15Dropped", 83219820Sjeff "check with ibswportwatch.pl, if increasing in SMALL increments, OK", 84219820Sjeff "RcvSwRelayErrors", 85219820Sjeff "This counter can increase due to a valid network event" 86219820Sjeff); 87219820Sjeff 88219820Sjeffsub check_counters 89219820Sjeff{ 90219820Sjeff my $print_action = $_[0]; 91219820Sjeff my $actions = undef; 92219820Sjeff 93219820Sjeff COUNTER: foreach my $cnt (keys %IBswcountlimits::error_counters) { 94219820Sjeff if ($IBswcountlimits::cur_counts{$cnt} > 0) { 95219820Sjeff foreach my $sup_cnt (@IBswcountlimits::suppress_errors) { 96219820Sjeff if ("$cnt" eq $sup_cnt) { next COUNTER; } 97219820Sjeff } 98219820Sjeff print " [$cnt == $IBswcountlimits::cur_counts{$cnt}]"; 99219820Sjeff if ("$print_action" eq "yes") { 100219820Sjeff $actions = join " ", 101219820Sjeff ( 102219820Sjeff $actions, 103219820Sjeff " $cnt: $IBswcountlimits::error_counters{$cnt}\n" 104219820Sjeff ); 105219820Sjeff } 106219820Sjeff } 107219820Sjeff } 108219820Sjeff 109219820Sjeff if ($actions) { 110219820Sjeff print "\n Actions:\n$actions"; 111219820Sjeff } 112219820Sjeff} 113219820Sjeff 114219820Sjeff# Data counters 115219820Sjeff%IBswcountlimits::data_counters = ( 116219820Sjeff "XmtData", 117219820Sjeff"Total number of data octets, divided by 4, transmitted on all VLs from the port", 118219820Sjeff "RcvData", 119219820Sjeff"Total number of data octets, divided by 4, received on all VLs to the port", 120219820Sjeff "XmtPkts", 121219820Sjeff"Total number of packets, excluding link packets, transmitted on all VLs from the port", 122219820Sjeff "RcvPkts", 123219820Sjeff"Total number of packets, excluding link packets, received on all VLs to the port" 124219820Sjeff); 125219820Sjeff 126219820Sjeffsub check_data_counters 127219820Sjeff{ 128219820Sjeff my $print_action = $_[0]; 129219820Sjeff my $actions = undef; 130219820Sjeff 131219820Sjeff COUNTER: foreach my $cnt (keys %IBswcountlimits::data_counters) { 132219820Sjeff print " [$cnt == $IBswcountlimits::cur_counts{$cnt}]"; 133219820Sjeff if ("$print_action" eq "yes") { 134219820Sjeff $actions = join " ", 135219820Sjeff ( 136219820Sjeff $actions, 137219820Sjeff " $cnt: $IBswcountlimits::data_counters{$cnt}\n" 138219820Sjeff ); 139219820Sjeff } 140219820Sjeff } 141219820Sjeff if ($actions) { 142219820Sjeff print "\n Descriptions:\n$actions"; 143219820Sjeff } 144219820Sjeff} 145219820Sjeff 146219820Sjeffsub print_data_rates 147219820Sjeff{ 148219820Sjeff COUNTER: foreach my $cnt (keys %IBswcountlimits::data_counters) { 149219820Sjeff my $cnt_per_second = calculate_rate( 150219820Sjeff $IBswcountlimits::cur_counts{$cnt}, 151219820Sjeff $IBswcountlimits::new_counts{$cnt} 152219820Sjeff ); 153219820Sjeff print " $cnt_per_second $cnt/second\n"; 154219820Sjeff } 155219820Sjeff} 156219820Sjeff 157219820Sjeff# ========================================================================= 158219820Sjeff# Rate dependent counters 159219820Sjeff# calculate the count/sec 160219820Sjeff# calculate_rate old_count new_count 161219820Sjeffsub calculate_rate 162219820Sjeff{ 163219820Sjeff my $rate = 0; 164219820Sjeff my $old_val = $_[0]; 165219820Sjeff my $new_val = $_[1]; 166219820Sjeff my $rate = ($new_val - $old_val) / $IBswcountlimits::pause_time; 167219820Sjeff return ($rate); 168219820Sjeff} 169219820Sjeff%IBswcountlimits::rate_dep_thresholds = ( 170219820Sjeff "SymbolErrors", 10, "LinkRecovers", 10, 171219820Sjeff "RcvErrors", 10, "LinkIntegrityErrors", 10, 172219820Sjeff "XmtDiscards", 10 173219820Sjeff); 174219820Sjeff 175219820Sjeffsub check_counter_rates 176219820Sjeff{ 177219820Sjeff foreach my $rate_count (keys %IBswcountlimits::rate_dep_thresholds) { 178219820Sjeff my $rate = calculate_rate( 179219820Sjeff $IBswcountlimits::cur_counts{$rate_count}, 180219820Sjeff $IBswcountlimits::new_counts{$rate_count} 181219820Sjeff ); 182219820Sjeff if ($rate > $IBswcountlimits::rate_dep_thresholds{$rate_count}) { 183219820Sjeff print "Detected excessive rate for $rate_count ($rate cnts/sec)\n"; 184219820Sjeff } elsif ($rate > 0) { 185219820Sjeff print "Detected rate for $rate_count ($rate cnts/sec)\n"; 186219820Sjeff } 187219820Sjeff } 188219820Sjeff} 189219820Sjeff 190219820Sjeff# ========================================================================= 191219820Sjeff# 192219820Sjeffsub clear_counters 193219820Sjeff{ 194219820Sjeff # clear the counters 195219820Sjeff foreach my $count (@IBswcountlimits::counters) { 196219820Sjeff $IBswcountlimits::cur_counts{$count} = 0; 197219820Sjeff } 198219820Sjeff} 199219820Sjeff 200219820Sjeff# ========================================================================= 201219820Sjeff# 202219820Sjeffsub any_counts 203219820Sjeff{ 204219820Sjeff my $total = 0; 205219820Sjeff my $count = 0; 206219820Sjeff foreach $count (keys %IBswcountlimits::critical) { 207219820Sjeff $total = $total + $IBswcountlimits::cur_counts{$count}; 208219820Sjeff } 209219820Sjeff COUNTER: foreach $count (keys %IBswcountlimits::error_counters) { 210219820Sjeff foreach my $sup_cnt (@IBswcountlimits::suppress_errors) { 211219820Sjeff if ("$count" eq $sup_cnt) { next COUNTER; } 212219820Sjeff } 213219820Sjeff $total = $total + $IBswcountlimits::cur_counts{$count}; 214219820Sjeff } 215219820Sjeff return ($total); 216219820Sjeff} 217219820Sjeff 218219820Sjeff# ========================================================================= 219219820Sjeff# 220219820Sjeffsub ensure_cache_dir 221219820Sjeff{ 222219820Sjeff if (!(-d "$IBswcountlimits::cache_dir") && 223219820Sjeff !mkdir($IBswcountlimits::cache_dir, 0700)) { 224219820Sjeff die "cannot create $IBswcountlimits::cache_dir: $!\n"; 225219820Sjeff } 226219820Sjeff} 227219820Sjeff 228219820Sjeff# ========================================================================= 229219820Sjeff# get_cache_file(ca_name, ca_port) 230219820Sjeff# 231219820Sjeffsub get_cache_file 232219820Sjeff{ 233219820Sjeff my $ca_name = $_[0]; 234219820Sjeff my $ca_port = $_[1]; 235219820Sjeff ensure_cache_dir; 236219820Sjeff return ( 237219820Sjeff "$IBswcountlimits::cache_dir/ibnetdiscover-$ca_name-$ca_port.topology"); 238219820Sjeff} 239219820Sjeff 240219820Sjeff# ========================================================================= 241219820Sjeff# get_ca_name_port_param_string(ca_name, ca_port) 242219820Sjeff# 243219820Sjeffsub get_ca_name_port_param_string 244219820Sjeff{ 245219820Sjeff my $ca_name = $_[0]; 246219820Sjeff my $ca_port = $_[1]; 247219820Sjeff 248219820Sjeff if ("$ca_name" ne "") { $ca_name = "-C $ca_name"; } 249219820Sjeff if ("$ca_port" ne "") { $ca_port = "-P $ca_port"; } 250219820Sjeff 251219820Sjeff return ("$ca_name $ca_port"); 252219820Sjeff} 253219820Sjeff 254219820Sjeff# ========================================================================= 255219820Sjeff# generate_ibnetdiscover_topology(ca_name, ca_port) 256219820Sjeff# 257219820Sjeffsub generate_ibnetdiscover_topology 258219820Sjeff{ 259219820Sjeff my $ca_name = $_[0]; 260219820Sjeff my $ca_port = $_[1]; 261219820Sjeff my $cache_file = get_cache_file($ca_name, $ca_port); 262219820Sjeff my $extra_params = get_ca_name_port_param_string($ca_name, $ca_port); 263219820Sjeff 264219820Sjeff if (`ibnetdiscover -g $extra_params > $cache_file`) { 265219820Sjeff die "Execution of ibnetdiscover failed: $!\n"; 266219820Sjeff } 267219820Sjeff} 268219820Sjeff 269219820Sjeff# ========================================================================= 270219820Sjeff# get_link_ends(regenerate_map, ca_name, ca_port) 271219820Sjeff# 272219820Sjeffsub get_link_ends 273219820Sjeff{ 274219820Sjeff my $regenerate_map = $_[0]; 275219820Sjeff my $ca_name = $_[1]; 276219820Sjeff my $ca_port = $_[2]; 277219820Sjeff 278219820Sjeff my $cache_file = get_cache_file($ca_name, $ca_port); 279219820Sjeff 280219820Sjeff if ($regenerate_map || !(-f "$cache_file")) { 281219820Sjeff generate_ibnetdiscover_topology($ca_name, $ca_port); 282219820Sjeff } 283219820Sjeff open IBNET_TOPO, "<$cache_file" 284219820Sjeff or die "Failed to open ibnet topology: $!\n"; 285219820Sjeff my $in_switch = "no"; 286219820Sjeff my $desc = ""; 287219820Sjeff my $guid = ""; 288219820Sjeff my $loc_sw_lid = ""; 289219820Sjeff 290219820Sjeff my $loc_port = ""; 291219820Sjeff my $line = ""; 292219820Sjeff 293219820Sjeff while ($line = <IBNET_TOPO>) { 294219820Sjeff if ($line =~ /^Switch.*\"S-(.*)\"\s+#.*\"(.*)\".* lid (\d+).*/) { 295219820Sjeff $guid = $1; 296219820Sjeff $desc = $2; 297219820Sjeff $loc_sw_lid = $3; 298219820Sjeff $in_switch = "yes"; 299219820Sjeff } 300219820Sjeff if ($in_switch eq "yes") { 301219820Sjeff my $rec = undef; 302219820Sjeff if ($line =~ 303219820Sjeff/^\[(\d+)\]\s+\"[HSR]-(.+)\"\[(\d+)\](\(.+\))?\s+#.*\"(.*)\"\.* lid (\d+).*/ 304219820Sjeff ) 305219820Sjeff { 306219820Sjeff $loc_port = $1; 307219820Sjeff my $rem_guid = $2; 308219820Sjeff my $rem_port = $3; 309219820Sjeff my $rem_port_guid = $4; 310219820Sjeff my $rem_desc = $5; 311219820Sjeff my $rem_lid = $6; 312219820Sjeff $rec = { 313219820Sjeff loc_guid => "0x$guid", 314219820Sjeff loc_port => $loc_port, 315219820Sjeff loc_ext_port => "", 316219820Sjeff loc_desc => $desc, 317219820Sjeff loc_sw_lid => $loc_sw_lid, 318219820Sjeff rem_guid => "0x$rem_guid", 319219820Sjeff rem_lid => $rem_lid, 320219820Sjeff rem_port => $rem_port, 321219820Sjeff rem_ext_port => "", 322219820Sjeff rem_desc => $rem_desc, 323219820Sjeff rem_port_guid => $rem_port_guid 324219820Sjeff }; 325219820Sjeff } 326219820Sjeff if ($line =~ 327219820Sjeff/^\[(\d+)\]\[ext (\d+)\]\s+\"[HSR]-(.+)\"\[(\d+)\](\(.+\))?\s+#.*\"(.*)\"\.* lid (\d+).*/ 328219820Sjeff ) 329219820Sjeff { 330219820Sjeff $loc_port = $1; 331219820Sjeff my $loc_ext_port = $2; 332219820Sjeff my $rem_guid = $3; 333219820Sjeff my $rem_port = $4; 334219820Sjeff my $rem_port_guid = $5; 335219820Sjeff my $rem_desc = $6; 336219820Sjeff my $rem_lid = $7; 337219820Sjeff $rec = { 338219820Sjeff loc_guid => "0x$guid", 339219820Sjeff loc_port => $loc_port, 340219820Sjeff loc_ext_port => $loc_ext_port, 341219820Sjeff loc_desc => $desc, 342219820Sjeff loc_sw_lid => $loc_sw_lid, 343219820Sjeff rem_guid => "0x$rem_guid", 344219820Sjeff rem_lid => $rem_lid, 345219820Sjeff rem_port => $rem_port, 346219820Sjeff rem_ext_port => "", 347219820Sjeff rem_desc => $rem_desc, 348219820Sjeff rem_port_guid => $rem_port_guid 349219820Sjeff }; 350219820Sjeff } 351219820Sjeff if ($line =~ 352219820Sjeff/^\[(\d+)\]\s+\"[HSR]-(.+)\"\[(\d+)\]\[ext (\d+)\](\(.+\))?\s+#.*\"(.*)\"\.* lid (\d+).*/ 353219820Sjeff ) 354219820Sjeff { 355219820Sjeff $loc_port = $1; 356219820Sjeff my $rem_guid = $2; 357219820Sjeff my $rem_port = $3; 358219820Sjeff my $rem_ext_port = $4; 359219820Sjeff my $rem_port_guid = $5; 360219820Sjeff my $rem_desc = $6; 361219820Sjeff my $rem_lid = $7; 362219820Sjeff $rec = { 363219820Sjeff loc_guid => "0x$guid", 364219820Sjeff loc_port => $loc_port, 365219820Sjeff loc_ext_port => "", 366219820Sjeff loc_desc => $desc, 367219820Sjeff loc_sw_lid => $loc_sw_lid, 368219820Sjeff rem_guid => "0x$rem_guid", 369219820Sjeff rem_lid => $rem_lid, 370219820Sjeff rem_port => $rem_port, 371219820Sjeff rem_ext_port => $rem_ext_port, 372219820Sjeff rem_desc => $rem_desc, 373219820Sjeff rem_port_guid => $rem_port_guid 374219820Sjeff }; 375219820Sjeff } 376219820Sjeff if ($line =~ 377219820Sjeff/^\[(\d+)\]\[ext (\d+)\]\s+\"[HSR]-(.+)\"\[(\d+)\]\[ext (\d+)\](\(.+\))?\s+#.*\"(.*)\"\.* lid (\d+).*/ 378219820Sjeff ) 379219820Sjeff { 380219820Sjeff $loc_port = $1; 381219820Sjeff my $loc_ext_port = $2; 382219820Sjeff my $rem_guid = $3; 383219820Sjeff my $rem_port = $4; 384219820Sjeff my $rem_ext_port = $5; 385219820Sjeff my $rem_port_guid = $6; 386219820Sjeff my $rem_desc = $7; 387219820Sjeff my $rem_lid = $8; 388219820Sjeff $rec = { 389219820Sjeff loc_guid => "0x$guid", 390219820Sjeff loc_port => $loc_port, 391219820Sjeff loc_ext_port => $loc_ext_port, 392219820Sjeff loc_desc => $desc, 393219820Sjeff loc_sw_lid => $loc_sw_lid, 394219820Sjeff rem_guid => "0x$rem_guid", 395219820Sjeff rem_lid => $rem_lid, 396219820Sjeff rem_port => $rem_port, 397219820Sjeff rem_ext_port => $rem_ext_port, 398219820Sjeff rem_desc => $rem_desc, 399219820Sjeff rem_port_guid => $rem_port_guid 400219820Sjeff }; 401219820Sjeff } 402219820Sjeff if ($rec) { 403219820Sjeff $rec->{rem_port_guid} =~ s/\((.*)\)/$1/; 404219820Sjeff $IBswcountlimits::link_ends{"0x$guid"}{$loc_port} = $rec; 405219820Sjeff } 406219820Sjeff } 407219820Sjeff 408219820Sjeff if ($line =~ /^Ca.*/ || $line =~ /^Rt.*/) { $in_switch = "no"; } 409219820Sjeff } 410219820Sjeff close IBNET_TOPO; 411219820Sjeff} 412219820Sjeff 413219820Sjeff# ========================================================================= 414219820Sjeff# get_num_ports(switch_guid, ca_name, ca_port) 415219820Sjeff# 416219820Sjeffsub get_num_ports 417219820Sjeff{ 418219820Sjeff my $guid = $_[0]; 419219820Sjeff my $ca_name = $_[1]; 420219820Sjeff my $ca_port = $_[2]; 421219820Sjeff my $num_ports = 0; 422219820Sjeff my $extra_params = get_ca_name_port_param_string($ca_name, $ca_port); 423219820Sjeff 424219820Sjeff my $data = `smpquery $extra_params -G nodeinfo $guid` || 425219820Sjeff die "'smpquery $extra_params -G nodeinfo $guid' faild\n"; 426219820Sjeff my @lines = split("\n", $data); 427219820Sjeff my $pkt_lifetime = ""; 428219820Sjeff foreach my $line (@lines) { 429219820Sjeff if ($line =~ /^NumPorts:\.+(.*)/) { $num_ports = $1; } 430219820Sjeff } 431219820Sjeff return ($num_ports); 432219820Sjeff} 433219820Sjeff 434219820Sjeff# ========================================================================= 435219820Sjeff# format_guid(guid) 436219820Sjeff# The diags store the guids as strings. This converts the guid supplied 437219820Sjeff# to the correct string format. 438219820Sjeff# eg: 0x0008f10400411f56 == 0x8f10400411f56 439219820Sjeff# 440219820Sjeffsub format_guid 441219820Sjeff{ 442219820Sjeff my $guid = $_[0]; 443219820Sjeff my $guid_str = ""; 444219820Sjeff 445219820Sjeff $guid =~ tr/[A-F]/[a-f]/; 446219820Sjeff if ($guid =~ /0x(.*)/) { 447219820Sjeff $guid_str = sprintf("0x%016s", $1); 448219820Sjeff } else { 449219820Sjeff $guid_str = sprintf("0x%016s", $guid); 450219820Sjeff } 451219820Sjeff return ($guid_str); 452219820Sjeff} 453219820Sjeff 454219820Sjeff# ========================================================================= 455219820Sjeff# convert_dr_to_guid(direct_route) 456219820Sjeff# 457219820Sjeffsub convert_dr_to_guid 458219820Sjeff{ 459219820Sjeff my $guid = undef; 460219820Sjeff 461219820Sjeff my $data = `smpquery nodeinfo -D $_[0]` || 462219820Sjeff die "'mpquery nodeinfo -D $_[0]' failed\n"; 463219820Sjeff my @lines = split("\n", $data); 464219820Sjeff foreach my $line (@lines) { 465219820Sjeff if ($line =~ /^PortGuid:\.+(.*)/) { $guid = $1; } 466219820Sjeff } 467219820Sjeff return format_guid($guid); 468219820Sjeff} 469219820Sjeff 470219820Sjeff# ========================================================================= 471219820Sjeff# get_node_type(guid_or_direct_route) 472219820Sjeff# 473219820Sjeffsub get_node_type 474219820Sjeff{ 475219820Sjeff my $type = undef; 476219820Sjeff my $query_arg = "smpquery nodeinfo "; 477219820Sjeff if ($_[0] =~ /x/) { 478219820Sjeff # assume arg is a guid if contains an x 479219820Sjeff $query_arg .= "-G " . $_[0]; 480219820Sjeff } else { 481219820Sjeff # assume arg is a direct path 482219820Sjeff $query_arg .= "-D " . $_[0]; 483219820Sjeff } 484219820Sjeff 485219820Sjeff my $data = `$query_arg` || 486219820Sjeff die "'$query_arg' failed\n"; 487219820Sjeff my @lines = split("\n", $data); 488219820Sjeff foreach my $line (@lines) { 489219820Sjeff if ($line =~ /^NodeType:\.+(.*)/) { $type = $1; } 490219820Sjeff } 491219820Sjeff return $type; 492219820Sjeff} 493219820Sjeff 494219820Sjeff# ========================================================================= 495219820Sjeff# is_switch(guid_or_direct_route) 496219820Sjeff# 497219820Sjeffsub is_switch 498219820Sjeff{ 499219820Sjeff my $node_type = &get_node_type($_[0]); 500219820Sjeff return ($node_type =~ /Switch/); 501219820Sjeff} 502