/* BEGIN_ICS_COPYRIGHT7 ****************************************
Copyright (c) 2015-2019, Intel Corporation
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 Intel Corporation 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.
** END_ICS_COPYRIGHT7 ****************************************/
/* [ICS VERSION STRING: unknown] */
#include "opareport.h"
#ifdef IB_STACK_OPENIB
#include <opamgt_priv.h>
#include <opamgt_sa_priv.h>
#endif
#include <getopt.h>
#include <limits.h>
#include <math.h>
#include <arpa/inet.h>
#include <stl_helper.h>
#include <ib_utils_openib.h>
#include <umad.h>
#include <time.h>
#include <string.h>
#include "stl_print.h"
// Used for expanding various enumarations into text equivalents
#define SHOW_BUF_SIZE 81
// what to output when g_noname set
char *g_name_marker = "xxxxxxxxxx";
// amount to subtract from threshold before compare
// 0-> Greater (report error if > threshold)
// 1-> Equal (report error if >= threshold)
uint32 g_threshold_compare = 0;
/* indicates overall set of reports for Slow Link reports
* also used to indicate which portion of the report is being done
*/
typedef enum {
LINK_EXPECTED_REPORT = 1,
LINK_CONFIG_REPORT =2,
LINK_CONN_REPORT =3
} LinkReport_t;
uint8 g_verbose = 0;
int g_exitstatus = 0;
int g_persist = 0; // omit transient data like LIDs
int g_hard = 0; // omit software configured items
int g_noname = 0; // omit names
char* g_snapshot_in_file = NULL; // input file being parsed
char* g_topology_in_file = NULL; // input file being parsed
int g_interval = 0; // interval for port stats in seconds
int g_clearstats = 0; // clear port stats
int g_clearallstats = 0; // clear all port stats
int g_limitstats = 0; // limit stats to specific focus ports
STL_PORT_COUNTERS_DATA g_Thresholds;
STL_CLEAR_PORT_STATUS g_CounterSelectMask;
EUI64 g_portGuid = -1; // local port to use to access fabric
IB_PORT_ATTRIBUTES *g_portAttrib = NULL;// attributes for our local port
int g_quietfocus = 0; // do not include focus desc in report
int g_max_lft = 0; // Size of largest switch LFT
int g_quiet = 0; // omit progress output
uint32 g_begin = 0; // begin time for interval
uint32 g_end = 0; // end time for interval
int g_use_scsc = 0; // should validatecreditloops use scsc tables
int g_rc = 0; // should validateroutes use rc
int g_ms_timeout = OMGT_DEF_TIMEOUT_MS;
// All the information about the fabric
FabricData_t g_Fabric;
void XmlPrintHex64(const char *tag, uint64 value, int indent)
{
printf("%*s<%s>0x%016"PRIx64"</%s>\n", indent, "",tag, value, tag);
}
void XmlPrintHex32(const char *tag, uint32 value, int indent)
{
printf("%*s<%s>0x%08x</%s>\n", indent, "",tag, value, tag);
}
void XmlPrintHex16(const char *tag, uint16 value, int indent)
{
printf("%*s<%s>0x%04x</%s>\n", indent, "",tag, value, tag);
}
void XmlPrintHex8(const char *tag, uint8 value, int indent)
{
printf("%*s<%s>0x%02x</%s>\n", indent, "",tag, value, tag);
}
void XmlPrintDec(const char *tag, unsigned value, int indent)
{
printf("%*s<%s>%u</%s>\n", indent, "",tag, value, tag);
}
void XmlPrintDec64(const char *tag, uint64 value, int indent)
{
printf("%*s<%s>%"PRIu64"</%s>\n", indent, "",tag, value, tag);
}
void XmlPrintHex(const char *tag, unsigned value, int indent)
{
printf("%*s<%s>0x%x</%s>\n", indent, "",tag, value, tag);
}
void XmlPrintStrLen(const char *tag, const char* value, int len, int indent)
{
printf("%*s<%s>", indent, "",tag);
/* print string taking care to translate special XML characters */
for (;len && *value; --len, ++value) {
if (*value == '&')
printf("&");
else if (*value == '<')
printf("<");
else if (*value == '>')
printf(">");
else if (*value == '\'')
printf("'");
else if (*value == '"')
printf(""");
else if (iscntrl(*value)) {
//table in asciitab.h indiciates character codes permitted in XML strings
//Only 3 control characters below 0x1f are permitted:
//0x9 (BT_S), 0xa (BT_LRF), and 0xd (BT_CR)
if ((unsigned char)*value <= 0x08
|| ((unsigned char)*value >= 0x0b
&& (unsigned char)*value <= 0x0c)
|| ((unsigned char)*value >= 0x0e
&& (unsigned char)*value <= 0x1f)) {
// characters which XML does not permit in character fields
printf("!");
} else {
printf("&#x%x;", (unsigned)(unsigned char)*value);
}
} else if ((unsigned char)*value > 0x7f)
// permitted but generate 2 characters back after parsing, so omit
printf("!");
else
putchar((int)(unsigned)(unsigned char)*value);
}
printf("</%s>\n", tag);
}
void XmlPrintStr(const char *tag, const char* value, int indent)
{
XmlPrintStrLen(tag, value, IB_INT32_MAX, indent);
}
void XmlPrintOptionalStr(const char *tag, const char* value, int indent)
{
if (value)
XmlPrintStrLen(tag, value, IB_INT32_MAX, indent);
}
void XmlPrintBool(const char *tag, unsigned value, int indent)
{
if (value)
XmlPrintStr(tag, "True", indent);
else
XmlPrintStr(tag, "False", indent);
}
void XmlPrintMLID(const char *tag, STL_LID value, int indent)
{
// should never be less than 4 hex digits, upper bit should never be 0
printf("%*s<%s>0x%04x</%s>\n", indent, "",tag, value, tag);
}
void XmlPrintLID(const char *tag, STL_LID value, int indent)
{
printf("%*s<%s>0x%.*x</%s>\n", indent, "", tag, (value <= IB_MAX_UCAST_LID ? 4:8), value, tag);
}
void XmlPrintPKey(const char *tag, IB_P_KEY value, int indent)
{
printf("%*s<%s>0x%04x</%s>\n", indent, "",tag, value, tag);
}
void XmlPrintGID(const char *tag, IB_GID value, int indent)
{
printf("%*s<%s>0x%016"PRIx64":%016"PRIx64"</%s>\n",
indent, "", tag,
value.Type.Global.SubnetPrefix,
value.Type.Global.InterfaceID, tag);
}
void XmlPrintNodeType(uint8 value, int indent)
{
XmlPrintStr("NodeType", StlNodeTypeToText(value), indent);
XmlPrintDec("NodeType_Int", value, indent);
}
void XmlPrintNodeDesc(const char *value, int indent)
{
if (! g_noname)
XmlPrintStrLen("NodeDesc", value, NODE_DESCRIPTION_ARRAY_SIZE, indent);
}
void XmlPrintIocIDString(const char *value, int indent)
{
if (! g_noname)
XmlPrintStrLen("IDString", value, IOC_IDSTRING_SIZE, indent);
}
void XmlPrintServiceName(const uchar *value, int indent)
{
/* service names are critical, g_noname NA */
XmlPrintStrLen("Name", (const char*)value, IOC_SERVICE_NAME_SIZE, indent);
}
void XmlPrintRate(uint8 value, int indent)
{
XmlPrintStr("Rate", StlStaticRateToText(value), indent);
XmlPrintDec("Rate_Int", value, indent);
}
void XmlPrintLinkWidth(const char* tag_prefix, uint8 value, int indent)
{
char buf[64];
XmlPrintStr(tag_prefix, StlLinkWidthToText(value, buf, sizeof(buf)), indent);
printf("%*s<%s_Int>%u</%s_Int>\n", indent, "",tag_prefix, value, tag_prefix);
}
void XmlPrintLinkSpeed(const char* tag_prefix, uint16 value, int indent)
{
char buf[64];
XmlPrintStr(tag_prefix, StlLinkSpeedToText(value, buf, sizeof(buf)), indent);
printf("%*s<%s_Int>%u</%s_Int>\n", indent, "",tag_prefix, value, tag_prefix);
}
void XmlPrintPortLtpCrc(const char* tag_prefix, uint16 value, int indent)
{
char buf[64];
XmlPrintStr(tag_prefix, StlPortLtpCrcModeToText(value, buf, sizeof(buf)), indent);
printf("%*s<%s_Int>%u</%s_Int>\n", indent, "", tag_prefix, value, tag_prefix);
}
// for predictable output order, should be called with the from port of the
// link record, with the exception of trace routes
void XmlPrintLinkStartTag(const char* tag, PortData *portp, int indent)
{
//if (! portp->from)
// portp = portp->neighbor;
printf("%*s<%s id=\"0x%016"PRIx64":%u\">\n", indent, "", tag,
portp->nodep->NodeInfo.NodeGUID, portp->PortNum);
}
void XmlPrintTagHeader(const char *tag, int indent)
{
printf("%*s<%s>\n", indent, "", tag);
}
void XmlPrintTagFooter(const char *tag, int indent)
{
printf("%*s</%s>\n", indent, "", tag);
}
void XmlPrintGroupRecord (McGroupData *pMcGroupRecord, int indent, int detail)
{
char buf[8];
XmlPrintGID("MGID",pMcGroupRecord->MGID,indent+8);
XmlPrintMLID("MLID",pMcGroupRecord->MLID, indent+8);
XmlPrintPKey("P_Key", pMcGroupRecord->GroupInfo.P_Key, indent+8);
XmlPrintDec("Mtu", GetBytesFromMtu(pMcGroupRecord->GroupInfo.Mtu), indent+8);
XmlPrintRate(pMcGroupRecord->GroupInfo.Rate,indent+8);
FormatTimeoutMult(buf, pMcGroupRecord->GroupInfo.PktLifeTime);
XmlPrintStr("PktLifeTime", buf, indent+8);
XmlPrintDec("PktLifeTime_Int", pMcGroupRecord->GroupInfo.PktLifeTime, indent+8);
XmlPrintHex32("Q_Key", pMcGroupRecord->GroupInfo.Q_Key, indent+8);
XmlPrintDec("SL", pMcGroupRecord->GroupInfo.u1.s.SL, indent+8);
XmlPrintHex("HopLimit", pMcGroupRecord->GroupInfo.u1.s.HopLimit, indent+8);
XmlPrintHex("FlowLabel", pMcGroupRecord->GroupInfo.u1.s.FlowLabel, indent+8);
XmlPrintHex8("TClass", pMcGroupRecord->GroupInfo.TClass, indent+8);
}
void McMembershipXmlOutput(const char *tag, McMemberData *pMCGG, int indent)
{
uint8 Memberstatus;
Memberstatus = (pMCGG->MemberInfo.JoinSendOnlyMember<<2 |
pMCGG->MemberInfo.JoinNonMember<<1|
pMCGG->MemberInfo.JoinFullMember);
XmlPrintDec(tag, Memberstatus, indent);
}
void DisplaySeparator(void)
{
printf("-------------------------------------------------------------------------------\n");
}
void DisplayGroupRecord(McGroupData *pMcGroupRecord, int indent, int detail)
{
char buf[8];
printf("%*sMGID: 0x%016"PRIx64":0x%016"PRIx64"\n",
indent, "",
pMcGroupRecord->MGID.AsReg64s.H,
pMcGroupRecord->MGID.AsReg64s.L);
FormatTimeoutMult(buf, pMcGroupRecord->GroupInfo.PktLifeTime);
printf("%*sMLID: 0x%08x PKey: 0x%04x Mtu: %5s Rate: %4s PktLifeTime: %s\n",
indent, "",
pMcGroupRecord->MLID,
pMcGroupRecord->GroupInfo.P_Key,
IbMTUToText(pMcGroupRecord->GroupInfo.Mtu),
StlStaticRateToText(pMcGroupRecord->GroupInfo.Rate),
buf);
printf("%*sQKey: 0x%08x SL: %2d FlowLabel: 0x%05x HopLimit: 0x%02x TClass: 0x%02x\n",
indent, "",
pMcGroupRecord->GroupInfo.Q_Key,
pMcGroupRecord->GroupInfo.u1.s.SL,
pMcGroupRecord->GroupInfo.u1.s.FlowLabel,
pMcGroupRecord->GroupInfo.u1.s.HopLimit,
pMcGroupRecord->GroupInfo.TClass);
}
void ShowPathRecord(IB_PATH_RECORD *pPathRecord, Format_t format,
int indent, int detail)
{
char buf[8];
switch (format) {
case FORMAT_TEXT:
printf("%*sSGID: 0x%016"PRIx64":%016"PRIx64"\n",
indent, "",
pPathRecord->SGID.Type.Global.SubnetPrefix,
pPathRecord->SGID.Type.Global.InterfaceID);
printf("%*sDGID: 0x%016"PRIx64":%016"PRIx64"\n",
indent, "",
pPathRecord->DGID.Type.Global.SubnetPrefix,
pPathRecord->DGID.Type.Global.InterfaceID);
printf("%*sSLID: 0x%.*x DLID: 0x%.*x Reversible: %s",
indent, "", (pPathRecord->SLID <= IB_MAX_UCAST_LID ? 4:8), pPathRecord->SLID,
(pPathRecord->DLID <= IB_MAX_UCAST_LID ? 4:8), pPathRecord->DLID,
pPathRecord->Reversible?"Y":"N");
// If this is from a snapshot, stop here - the remaining values cannot be
// deduced.
if (g_snapshot_in_file) {
printf("\n");
break;
}
printf(" PKey: 0x%04x\n", pPathRecord->P_Key);
printf("%*sRaw: %s FlowLabel: 0x%05x HopLimit: 0x%02x TClass: 0x%02x\n",
indent, "", pPathRecord->u1.s.RawTraffic?"Y":"N",
pPathRecord->u1.s.FlowLabel, pPathRecord->u1.s.HopLimit,
pPathRecord->TClass);
FormatTimeoutMult(buf, pPathRecord->PktLifeTime);
printf("%*sSL: %2d Mtu: %5s Rate: %4s PktLifeTime: %s Pref: %d\n",
indent, "", pPathRecord->u2.s.SL, IbMTUToText(pPathRecord->Mtu),
StlStaticRateToText(pPathRecord->Rate), buf,
pPathRecord->Preference);
break;
case FORMAT_XML:
// TBD does this get a unique ID? Is PKey needed too
//printf("%*s<PathRecord id=\"0x%016"PRIx64":%016"PRIx64"-%016"PRIx64":%016"PRIx64"-%04x-%04x\">\n", indent, "",
// pPathRecord->SGID.Type.Global.SubnetPrefix,
// pPathRecord->SGID.Type.Global.InterfaceID,
// pPathRecord->DGID.Type.Global.SubnetPrefix,
// pPathRecord->DGID.Type.Global.InterfaceID,
// pPathRecord->SLID, pPathRecord->DLID);
printf("%*s<PathRecord>\n", indent, "");
XmlPrintGID("SGID", pPathRecord->SGID, indent+4);
XmlPrintGID("DGID", pPathRecord->DGID, indent+4);
XmlPrintLID("SLID", pPathRecord->SLID, indent+4);
XmlPrintLID("DLID", pPathRecord->DLID, indent+4);
XmlPrintStr("Reversible", pPathRecord->Reversible?"Y":"N", indent+4);
XmlPrintDec("Reversible_Int", pPathRecord->Reversible, indent+4);
// If this is from a snapshot, stop here - the remaining values cannot be
// deduced.
if (g_snapshot_in_file) {
printf("%*s</PathRecord>\n", indent, "");
break;
}
XmlPrintPKey("PKey", pPathRecord->P_Key, indent+4);
XmlPrintStr("Raw", pPathRecord->u1.s.RawTraffic?"Y":"N", indent+4);
XmlPrintDec("Raw_Int", pPathRecord->u1.s.RawTraffic, indent+4);
XmlPrintHex("FlowLabel", pPathRecord->u1.s.FlowLabel, indent+4);
XmlPrintHex8("HopLimit", pPathRecord->u1.s.HopLimit, indent+4);
XmlPrintHex8("TClass", pPathRecord->TClass, indent+4);
XmlPrintDec("SL", pPathRecord->u2.s.SL, indent+4);
XmlPrintDec("Mtu", GetBytesFromMtu(pPathRecord->Mtu), indent+4);
XmlPrintRate(pPathRecord->Rate, indent+4);
FormatTimeoutMult(buf, pPathRecord->PktLifeTime);
XmlPrintStr("PktLifeTime", buf, indent+4);
XmlPrintDec("PktLifeTime_Int", pPathRecord->PktLifeTime, indent+4);
XmlPrintDec("Preference", pPathRecord->Preference, indent+4);
printf("%*s</PathRecord>\n", indent, "");
break;
default:
break;
}
}
void ShowTraceRecord(STL_TRACE_RECORD *pTraceRecord, Format_t format, int indent, int detail)
{
switch (format) {
case FORMAT_TEXT:
// DisplayTraceRecord(pTraceRecord, indent);
printf("%*sIDGeneration: 0x%04x\n",
indent, "", pTraceRecord->IDGeneration);
printf("%*sNodeType: 0x%02x\n",
indent, "", pTraceRecord->NodeType);
printf("%*sNodeID: 0x%016"PRIx64" ChassisID: %016"PRIx64"\n",
indent, "", pTraceRecord->NodeID, pTraceRecord->ChassisID);
printf("%*sEntryPortID: 0x%016"PRIx64" ExitPortID: %016"PRIx64"\n",
indent, "", pTraceRecord->EntryPortID, pTraceRecord->ExitPortID);
printf("%*sEntryPort: 0x%02x ExitPort: 0x%02x\n",
indent, "", pTraceRecord->EntryPort, pTraceRecord->ExitPort);
break;
case FORMAT_XML:
// TBD id may not be unique, may need different id based on NodeType
printf("%*s<TraceRecord>\n", indent, "");
XmlPrintHex16("IDGeneration", pTraceRecord->IDGeneration, indent+4);
XmlPrintNodeType(pTraceRecord->NodeType, indent+4);
XmlPrintHex64("NodeID", pTraceRecord->NodeID, indent+4);
XmlPrintHex64("ChassisID", pTraceRecord->ChassisID, indent+4);
XmlPrintHex64("EntryPortID", pTraceRecord->EntryPortID, indent+4);
XmlPrintHex64("ExitPortID", pTraceRecord->ExitPortID, indent+4);
XmlPrintHex8("EntryPort", pTraceRecord->EntryPort, indent+4);
XmlPrintHex8("ExitPort", pTraceRecord->ExitPort, indent+4);
printf("%*s</TraceRecord>\n", indent, "");
break;
default:
break;
}
}
// header used before a series of links
void ShowLinkBriefSummaryHeader(Format_t format, int indent, int detail)
{
switch (format) {
case FORMAT_TEXT:
printf("%*sRate NodeGUID Port Type Name\n", indent, "");
if (detail && (g_Fabric.flags & FF_CABLEDATA)) {
//printf("%*sPortDetails\n", indent+4, "");
//printf("%*sLinkDetails\n", indent+4, "");
printf("%*sCable: %-*s %-*s\n", indent+4, "",
CABLE_LABEL_STRLEN, "CableLabel",
CABLE_LENGTH_STRLEN, "CableLen");
printf("%*s%s\n", indent+4, "", "CableDetails");
}
break;
case FORMAT_XML:
break;
default:
break;
}
}
#define MAX_CABLE_LENGTH_STR_LEN 8 // ~2-3 digits (poss. decimal pt) plus 'm'
void ShowCableSummary(uint8_t *pCableData, Format_t format, int indent, int detail, uint8 portType)
{
// CableInfo is organized in 128-byte pages but is stored in 64-byte half-pages
// For portType STANDARD we use STL_CIB_STD_HIGH_PAGE_ADDR to STL_CIB_STD_END_ADDR
// inclusive (128-255)
// To avoid compiler warnings, data pointer is used for the data portion
// of the STL_CABLE_INFO
STL_CABLE_INFO_STD *pCableInfo = (STL_CABLE_INFO_STD *)pCableData;
CableTypeInfoType cableTypeInfo;
boolean cableLenValid; // Copper cable length valid
boolean qsfp_dd;
char tempStr[STL_CIB_STD_MAX_STRING + 1] = {'\0'};
char tempStr2[32] = {'\0'};
char tempBuf[192];
unsigned int i;
if (pCableData)
qsfp_dd = (*pCableData == STL_CIB_STD_QSFP_DD);
else {
fprintf(stderr, "ShowCableSummary: cableInfoData pointer is invalid\n");
return;
}
if (qsfp_dd) {
ShowCableSummaryDD(pCableData, format, indent, detail, portType);
return;
}
StlCableInfoDecodeCableType(pCableInfo->dev_tech.s.xmit_tech, pCableInfo->connector, pCableInfo->ident, &cableTypeInfo);
cableLenValid = cableTypeInfo.cableLengthValid;
switch (format) {
case FORMAT_TEXT:
switch (portType) {
case STL_PORT_TYPE_STANDARD:
if (detail <= 6) {
//line1
memset(tempBuf, ' ', sizeof(tempBuf));
i = 0;
StringCopy(&tempBuf[i], cableTypeInfo.cableTypeShortDesc, strlen(cableTypeInfo.cableTypeShortDesc)+1);
tempBuf[i + strlen(cableTypeInfo.cableTypeShortDesc)] = ',';
#if 0
i = STL_CIB_LINE1_FIELD1;
strncpy(&tempBuf[i], cableTypeInfo.cableTypeShortDesc, strlen(cableTypeInfo.cableTypeShortDesc));
tempBuf[i + strlen(cableTypeInfo.cableTypeShortDesc)] = ',';
tempBuf[i + 1 + strlen(cableTypeInfo.cableTypeShortDesc)] = ' ';
#endif
i = STL_CIB_LINE1_FIELD2;
StlCableInfoOM4LengthToText(pCableInfo->len_om4, cableLenValid, MAX_CABLE_LENGTH_STR_LEN, &tempBuf[i]);
tempBuf[i + strlen(&tempBuf[i])] = ' ';
i = STL_CIB_LINE1_FIELD3;
memcpy(tempStr, pCableInfo->vendor_name, sizeof(pCableInfo->vendor_name));
StlCableInfoTrimTrailingWS(tempStr, sizeof(pCableInfo->vendor_name));
memcpy(&tempBuf[i], tempStr, strlen(tempStr));
i = STL_CIB_LINE1_FIELD4;
strcpy(&tempBuf[i], "P/N ");
i = STL_CIB_LINE1_FIELD5;
memcpy(tempStr, pCableInfo->vendor_pn, sizeof(pCableInfo->vendor_pn));
StlCableInfoTrimTrailingWS(tempStr, sizeof(pCableInfo->vendor_pn));
memcpy(&tempBuf[i], tempStr, strlen(tempStr));
i = STL_CIB_LINE1_FIELD6;
strcpy(&tempBuf[i], "Rev ");
i = STL_CIB_LINE1_FIELD7;
memcpy(tempStr, pCableInfo->vendor_rev, sizeof(pCableInfo->vendor_rev));
StlCableInfoTrimTrailingWS(tempStr, sizeof(pCableInfo->vendor_rev));
memcpy(&tempBuf[i], tempStr, strlen(tempStr));
i = STL_CIB_LINE1_FIELD8;
tempBuf[i] = '\0';
printf("%*s%s\n", indent, "", tempBuf);
if (detail <=1)
break;
//line2
memset(tempBuf, ' ', sizeof(tempBuf));
i = 0;
StringCopy(&tempBuf[i], StlCableInfoPowerClassToText(pCableInfo->ext_ident.s.pwr_class_low, pCableInfo->ext_ident.s.pwr_class_high),
strlen(StlCableInfoPowerClassToText(pCableInfo->ext_ident.s.pwr_class_low, pCableInfo->ext_ident.s.pwr_class_high)) + 1);
tempBuf[i + strlen(&tempBuf[i])] = ' ';
i = STL_CIB_LINE2_FIELD2;
strcpy(&tempBuf[i], "S/N ");
i = STL_CIB_LINE2_FIELD3;
memcpy(tempStr, pCableInfo->vendor_sn, sizeof(pCableInfo->vendor_sn));
StlCableInfoTrimTrailingWS(tempStr, sizeof(pCableInfo->vendor_sn));
memcpy(&tempBuf[i], tempStr, strlen(tempStr));
i = STL_CIB_LINE2_FIELD4;
strcpy(&tempBuf[i], "Mfg ");
i = STL_CIB_LINE2_FIELD5;
StlCableInfoDateCodeToText(pCableInfo->date_code, &tempBuf[i]);
printf("%*s%s\n", indent, "", tempBuf);
//line3
memset(tempBuf, ' ', sizeof(tempBuf));
i = 0;
sprintf(&tempBuf[i], "OUI 0x%02X%02X%02X", pCableInfo->vendor_oui[0], pCableInfo->vendor_oui[1], pCableInfo->vendor_oui[2]);
printf("%*s%s\n", indent, "", tempBuf);
break;
} else {
printf("%*sQSFP Interpreted CableInfo:\n", indent, "");
printf("%*sIdentifier: 0x%x\n", indent+4, "", pCableInfo->ident);
memcpy(tempBuf, cableTypeInfo.connectorType, sizeof(cableTypeInfo.connectorType));
printf("%*sConnector: %s\n", indent+4, "", tempBuf);
StlCableInfoCableTypeToTextLong(pCableInfo->dev_tech.s.xmit_tech, pCableInfo->connector, tempBuf);
printf("%*sDeviceTech: %s\n", indent+4, "", tempBuf);
StlCableInfoOM4LengthToText(pCableInfo->len_om4, cableLenValid, sizeof(tempBuf), tempBuf);
printf("%*sOM4Length: %s\n", indent+4, "", tempBuf);
memcpy(tempStr, pCableInfo->vendor_name, sizeof(pCableInfo->vendor_name));
StlCableInfoTrimTrailingWS(tempStr, sizeof(pCableInfo->vendor_name));
printf("%*sVendorName: %s\n", indent+4, "", tempStr);
printf( "%*sVendorOUI: 0x%02x%02x%02x\n", indent+4, "", pCableInfo->vendor_oui[0],
pCableInfo->vendor_oui[1], pCableInfo->vendor_oui[2] );
memcpy(tempStr, pCableInfo->vendor_pn, sizeof(pCableInfo->vendor_pn));
StlCableInfoTrimTrailingWS(tempStr, sizeof(pCableInfo->vendor_pn));
printf("%*sVendorPN: %s\n", indent+4, "", tempStr);
memcpy(tempStr, pCableInfo->vendor_rev, sizeof(pCableInfo->vendor_rev));
StlCableInfoTrimTrailingWS(tempStr, sizeof(pCableInfo->vendor_rev));
printf("%*sVendorRev: %s\n", indent+4, "", tempStr);
memcpy(tempBuf, StlCableInfoPowerClassToText(pCableInfo->ext_ident.s.pwr_class_low, pCableInfo->ext_ident.s.pwr_class_high),
strlen(StlCableInfoPowerClassToText(pCableInfo->ext_ident.s.pwr_class_low, pCableInfo->ext_ident.s.pwr_class_high)));
tempStr[strlen(StlCableInfoPowerClassToText(pCableInfo->ext_ident.s.pwr_class_low, pCableInfo->ext_ident.s.pwr_class_high))] = '\0';
printf("%*sPoweClass: %s\n", indent+4, "", tempStr);
memcpy(tempStr, pCableInfo->vendor_sn, sizeof(pCableInfo->vendor_sn));
StlCableInfoTrimTrailingWS(tempStr, sizeof(pCableInfo->vendor_sn));
printf("%*sVendorSN: %s\n", indent+4, "", tempStr);
StlCableInfoDateCodeToText(pCableInfo->date_code, tempBuf);
printf("%*sDateCode: %s\n", indent+4, "", tempBuf);
}
break;
case STL_PORT_TYPE_SI_PHOTONICS:
default:
//printf("%*sCableInfo: N/A for Port Type: %s \n", indent, "", StlPortTypeToText(portType));
break;
}
break;
case FORMAT_XML:
switch (portType) {
case STL_PORT_TYPE_STANDARD:
printf("%*s<CableInfo>\n", indent, "");
if (detail <= 6) {
StringCopy(tempStr2, cableTypeInfo.cableTypeShortDesc, sizeof(tempStr2));
XmlPrintStr("DeviceTechShort", tempStr2, indent+4);
//maps to text line 1
StlCableInfoOM4LengthToText(pCableInfo->len_om4, cableLenValid, sizeof(tempBuf), tempBuf);
XmlPrintStr("OM4Length", tempBuf, indent+4);
XmlPrintStr("Length", tempBuf, indent+4);
memcpy(tempStr, pCableInfo->vendor_name, sizeof(pCableInfo->vendor_name));
StlCableInfoTrimTrailingWS(tempStr, sizeof(pCableInfo->vendor_name));
XmlPrintStrLen("VendorName", tempStr, sizeof(pCableInfo->vendor_name), indent+4);
memcpy(tempStr, pCableInfo->vendor_pn, sizeof(pCableInfo->vendor_pn));
StlCableInfoTrimTrailingWS(tempStr, sizeof(pCableInfo->vendor_pn));
XmlPrintStrLen("VendorPN", tempStr, sizeof(pCableInfo->vendor_pn), indent+4);
memcpy(tempStr, pCableInfo->vendor_rev, sizeof(pCableInfo->vendor_rev));
StlCableInfoTrimTrailingWS(tempStr, sizeof(pCableInfo->vendor_rev));
XmlPrintStrLen("VendorRev", tempStr, sizeof(pCableInfo->vendor_rev), indent+4);
memcpy(tempStr, pCableInfo->vendor_sn, sizeof(pCableInfo->vendor_sn));
StlCableInfoTrimTrailingWS(tempStr, sizeof(pCableInfo->vendor_sn));
XmlPrintStrLen("VendorSN", tempStr, sizeof(pCableInfo->vendor_sn), indent+4);
StlCableInfoDateCodeToText(pCableInfo->date_code, tempBuf);
XmlPrintStrLen("DateCode", (char*)tempBuf, sizeof(tempBuf), indent+4);
XmlPrintHex("VendorOUI", (pCableInfo->vendor_oui[0]<<16) + (pCableInfo->vendor_oui[1]<<8) + pCableInfo->vendor_oui[2], indent+4);
} else {
snprintf(tempBuf, 5, "0x%x", pCableInfo->ident);
XmlPrintStr("Identifier", tempBuf, indent+4);
memcpy(tempBuf, cableTypeInfo.connectorType, sizeof(cableTypeInfo.connectorType));
XmlPrintStr("Connector", tempBuf, indent+4);
StlCableInfoCableTypeToTextLong(pCableInfo->dev_tech.s.xmit_tech, pCableInfo->connector, tempBuf);
XmlPrintStr("DeviceTech", tempBuf, indent+4);
StlCableInfoOM4LengthToText(pCableInfo->len_om4, cableLenValid, sizeof(tempBuf), tempBuf);
XmlPrintStr("OM4Length", tempBuf, indent+4);
XmlPrintStr("Length", tempBuf, indent+4);
memcpy(tempStr, pCableInfo->vendor_name, sizeof(pCableInfo->vendor_name));
StlCableInfoTrimTrailingWS(tempStr, sizeof(pCableInfo->vendor_name));
XmlPrintStrLen("VendorName", tempStr, sizeof(pCableInfo->vendor_name), indent+4);
memcpy(tempStr, pCableInfo->vendor_pn, sizeof(pCableInfo->vendor_pn));
StlCableInfoTrimTrailingWS(tempStr, sizeof(pCableInfo->vendor_pn));
XmlPrintStrLen("VendorPN", tempStr, sizeof(pCableInfo->vendor_pn), indent+4);
memcpy(tempStr, pCableInfo->vendor_rev, sizeof(pCableInfo->vendor_rev));
StlCableInfoTrimTrailingWS(tempStr, sizeof(pCableInfo->vendor_rev));
XmlPrintStrLen("VendorRev", tempStr, sizeof(pCableInfo->vendor_rev), indent+4);
StringCopy(tempBuf, StlCableInfoPowerClassToText(pCableInfo->ext_ident.s.pwr_class_low, pCableInfo->ext_ident.s.pwr_class_high),
strlen(StlCableInfoPowerClassToText(pCableInfo->ext_ident.s.pwr_class_low, pCableInfo->ext_ident.s.pwr_class_high)) + 1);
XmlPrintStr("PowerClass", tempBuf, indent+4);
memcpy(tempStr, pCableInfo->vendor_sn, sizeof(pCableInfo->vendor_sn));
StlCableInfoTrimTrailingWS(tempStr, sizeof(pCableInfo->vendor_sn));
XmlPrintStrLen("VendorSN", tempStr, sizeof(pCableInfo->vendor_sn), indent+4);
StlCableInfoDateCodeToText(pCableInfo->date_code, tempBuf);
XmlPrintStrLen("DateCode", (char*)tempBuf, sizeof(tempBuf), indent+4);
XmlPrintHex("VendorOUI", (pCableInfo->vendor_oui[0]<<16) + (pCableInfo->vendor_oui[1]<<8) + pCableInfo->vendor_oui[2], indent+4);
}
printf("%*s</CableInfo>\n", indent, "");
break;
case STL_PORT_TYPE_SI_PHOTONICS:
default:
break;
}
break;
default:
break;
}
} // End of ShowCableSummary()
void ShowCableSummaryDD(uint8_t *pCableData, Format_t format, int indent, int detail, uint8 portType)
{
// CableInfo is organized in 128-byte pages but is stored in 64-byte half-pages
// For portType STANDARD we use STL_CIB_STD_HIGH_PAGE_ADDR to STL_CIB_STD_END_ADDR
// inclusive (128-255)
// To avoid compiler warnings, data pointer is used for the data portion
// of the STL_CABLE_INFO
STL_CABLE_INFO_UP0_DD *pCableInfo = (STL_CABLE_INFO_UP0_DD *)pCableData;
CableTypeInfoType cableTypeInfo;
char tempStr[STL_CIB_STD_MAX_STRING + 1] = {'\0'};
char tempStr2[32] = {'\0'};
char tempBuf[192];
unsigned int i;
boolean cableLenValid;
StlCableInfoDecodeCableType(pCableInfo->cable_type, pCableInfo->connector, pCableInfo->ident, &cableTypeInfo);
cableLenValid = cableTypeInfo.cableLengthValid;
switch (format) {
case FORMAT_TEXT:
switch (portType) {
case STL_PORT_TYPE_STANDARD:
if (detail <= 6) {
//line1
memset(tempBuf, ' ', sizeof(tempBuf));
i = 0;
StringCopy(&tempBuf[i], cableTypeInfo.cableTypeShortDesc, strlen(cableTypeInfo.cableTypeShortDesc)+1);
tempBuf[i + strlen(cableTypeInfo.cableTypeShortDesc)] = ',';
#if 0
i = STL_CIB_LINE1_FIELD1;
strncpy(&tempBuf[i], cableTypeInfo.cableTypeShortDesc, strlen(cableTypeInfo.cableTypeShortDesc));
tempBuf[i + strlen(cableTypeInfo.cableTypeShortDesc)] = ',';
tempBuf[i + 1 + strlen(cableTypeInfo.cableTypeShortDesc)] = ' ';
#endif
i = STL_CIB_LINE1_FIELD2;
StlCableInfoDDCableLengthToText(pCableInfo->cableLengthEnc, cableLenValid, MAX_CABLE_LENGTH_STR_LEN, &tempBuf[i]);
tempBuf[i + strlen(&tempBuf[i])] = ' ';
i = STL_CIB_LINE1_FIELD3;
memcpy(tempStr, pCableInfo->vendor_name, sizeof(pCableInfo->vendor_name));
StlCableInfoTrimTrailingWS(tempStr, sizeof(pCableInfo->vendor_name));
memcpy(&tempBuf[i], tempStr, strlen(tempStr));
i = STL_CIB_LINE1_FIELD4;
strcpy(&tempBuf[i], "P/N ");
i = STL_CIB_LINE1_FIELD5;
memcpy(tempStr, pCableInfo->vendor_pn, sizeof(pCableInfo->vendor_pn));
StlCableInfoTrimTrailingWS(tempStr, sizeof(pCableInfo->vendor_pn));
memcpy(&tempBuf[i], tempStr, strlen(tempStr));
i = STL_CIB_LINE1_FIELD6;
strcpy(&tempBuf[i], "Rev ");
i = STL_CIB_LINE1_FIELD7;
memcpy(tempStr, pCableInfo->vendor_rev, sizeof(pCableInfo->vendor_rev));
StlCableInfoTrimTrailingWS(tempStr, sizeof(pCableInfo->vendor_rev));
memcpy(&tempBuf[i], tempStr, strlen(tempStr));
i = STL_CIB_LINE1_FIELD8;
tempBuf[i] = '\0';
printf("%*s%s\n", indent, "", tempBuf);
if (detail <=1)
break;
//line2
memset(tempBuf, ' ', sizeof(tempBuf));
i = 0;
snprintf(&tempBuf[i], 20, "%.2f W max", (float)pCableInfo->powerMax / 4.0);
tempBuf[i + strlen(&tempBuf[i])] = ' ';
i = STL_CIB_LINE2_FIELD2;
strcpy(&tempBuf[i], "S/N ");
i = STL_CIB_LINE2_FIELD3;
memcpy(tempStr, pCableInfo->vendor_sn, sizeof(pCableInfo->vendor_sn));
StlCableInfoTrimTrailingWS(tempStr, sizeof(pCableInfo->vendor_sn));
memcpy(&tempBuf[i], tempStr, strlen(tempStr));
i = STL_CIB_LINE2_FIELD4;
strcpy(&tempBuf[i], "Mfg ");
i = STL_CIB_LINE2_FIELD5;
StlCableInfoDateCodeToText(pCableInfo->date_code, &tempBuf[i]);
printf("%*s%s\n", indent, "", tempBuf);
//line3
memset(tempBuf, ' ', sizeof(tempBuf));
i = 0;
sprintf(&tempBuf[i], "OUI 0x%02X%02X%02X", pCableInfo->vendor_oui[0], pCableInfo->vendor_oui[1], pCableInfo->vendor_oui[2]);
printf("%*s%s\n", indent, "", tempBuf);
break;
} else {
printf("%*sQSFP Interpreted CableInfo:\n", indent, "");
printf("%*sIdentifier: 0x%x\n", indent+4, "", pCableInfo->ident);
snprintf(tempBuf, 20, "%.2f W max", (float)pCableInfo->powerMax / 4.0);
printf("%*sPowerMax: %s\n", indent+4, "", tempBuf);
memcpy(tempBuf, cableTypeInfo.connectorType, sizeof(cableTypeInfo.connectorType));
printf("%*sConnector: %s\n", indent+4, "", tempBuf);
StlCableInfoCableTypeToTextLong(pCableInfo->cable_type, pCableInfo->connector, tempBuf);
printf("%*sDeviceTech: %s\n", indent+4, "", tempBuf);
StlCableInfoDDCableLengthToText(pCableInfo->cableLengthEnc, cableLenValid, sizeof(tempBuf), tempBuf);
printf("%*sCableLength: %s\n", indent+4, "", tempBuf);
memcpy(tempStr, pCableInfo->vendor_name, sizeof(pCableInfo->vendor_name));
StlCableInfoTrimTrailingWS(tempStr, sizeof(pCableInfo->vendor_name));
printf("%*sVendorName: %s\n", indent+4, "", tempStr);
printf( "%*sVendorOUI: 0x%02x%02x%02x\n", indent+4, "", pCableInfo->vendor_oui[0],
pCableInfo->vendor_oui[1], pCableInfo->vendor_oui[2] );
memcpy(tempStr, pCableInfo->vendor_pn, sizeof(pCableInfo->vendor_pn));
StlCableInfoTrimTrailingWS(tempStr, sizeof(pCableInfo->vendor_pn));
printf("%*sVendorPN: %s\n", indent+4, "", tempStr);
memcpy(tempStr, pCableInfo->vendor_rev, sizeof(pCableInfo->vendor_rev));
StlCableInfoTrimTrailingWS(tempStr, sizeof(pCableInfo->vendor_rev));
printf("%*sVendorRev: %s\n", indent+4, "", tempStr);
memcpy(tempStr, pCableInfo->vendor_sn, sizeof(pCableInfo->vendor_sn));
StlCableInfoTrimTrailingWS(tempStr, sizeof(pCableInfo->vendor_sn));
printf("%*sVendorSN: %s\n", indent+4, "", tempStr);
StlCableInfoDateCodeToText(pCableInfo->date_code, tempBuf);
printf("%*sDateCode: %s\n", indent+4, "", tempBuf);
}
break;
case STL_PORT_TYPE_SI_PHOTONICS:
default:
//printf("%*sCableInfo: N/A for Port Type: %s \n", indent, "", StlPortTypeToText(portType));
break;
}
break;
case FORMAT_XML:
switch (portType) {
case STL_PORT_TYPE_STANDARD:
printf("%*s<CableInfo>\n", indent, "");
if (detail <= 6) {
StringCopy(tempStr2, cableTypeInfo.cableTypeShortDesc, sizeof(tempStr2));
XmlPrintStr("DeviceTechShort", tempStr2, indent+4);
//maps to text line 1
StlCableInfoDDCableLengthToText(pCableInfo->cableLengthEnc, cableLenValid, sizeof(tempBuf), tempBuf);
XmlPrintStr("CableLength", tempBuf, indent+4);
XmlPrintStr("Length", tempBuf, indent+4);
memcpy(tempStr, pCableInfo->vendor_name, sizeof(pCableInfo->vendor_name));
StlCableInfoTrimTrailingWS(tempStr, sizeof(pCableInfo->vendor_name));
XmlPrintStrLen("VendorName", tempStr, sizeof(pCableInfo->vendor_name), indent+4);
memcpy(tempStr, pCableInfo->vendor_pn, sizeof(pCableInfo->vendor_pn));
StlCableInfoTrimTrailingWS(tempStr, sizeof(pCableInfo->vendor_pn));
XmlPrintStrLen("VendorPN", tempStr, sizeof(pCableInfo->vendor_pn), indent+4);
memcpy(tempStr, pCableInfo->vendor_rev, sizeof(pCableInfo->vendor_rev));
StlCableInfoTrimTrailingWS(tempStr, sizeof(pCableInfo->vendor_rev));
XmlPrintStrLen("VendorRev", tempStr, sizeof(pCableInfo->vendor_rev), indent+4);
snprintf(tempBuf, 20, "%.2f W max", (float)pCableInfo->powerMax / 4.0);
XmlPrintStr("PowerMax", tempBuf, indent+4);
memcpy(tempStr, pCableInfo->vendor_sn, sizeof(pCableInfo->vendor_sn));
StlCableInfoTrimTrailingWS(tempStr, sizeof(pCableInfo->vendor_sn));
XmlPrintStrLen("VendorSN", tempStr, sizeof(pCableInfo->vendor_sn), indent+4);
StlCableInfoDateCodeToText(pCableInfo->date_code, tempBuf);
XmlPrintStrLen("DateCode", (char*)tempBuf, sizeof(tempBuf), indent+4);
XmlPrintHex("VendorOUI", (pCableInfo->vendor_oui[0]<<16) + (pCableInfo->vendor_oui[1]<<8) + pCableInfo->vendor_oui[2], indent+4);
} else {
StlCableInfoCableTypeToTextShort(pCableInfo->cable_type, pCableInfo->connector, tempBuf);
snprintf(tempBuf, 5, "0x%x", pCableInfo->ident);
XmlPrintStr("Identifier", tempBuf, indent+4);
snprintf(tempBuf, 20, "%.2f W max", (float)pCableInfo->powerMax / 4.0);
XmlPrintStr("PowerMax", tempBuf, indent+4);
memcpy(tempBuf, cableTypeInfo.connectorType, sizeof(cableTypeInfo.connectorType));
XmlPrintStr("Connector", tempBuf, indent+4);
StlCableInfoCableTypeToTextLong(pCableInfo->cable_type, pCableInfo->connector, tempBuf);
XmlPrintStr("DeviceTech", tempBuf, indent+4);
//maps to text line 1
StlCableInfoDDCableLengthToText(pCableInfo->cableLengthEnc, cableLenValid, sizeof(tempBuf), tempBuf);
XmlPrintStr("CableLength", tempBuf, indent+4);
XmlPrintStr("Length", tempBuf, indent+4);
memcpy(tempStr, pCableInfo->vendor_name, sizeof(pCableInfo->vendor_name));
StlCableInfoTrimTrailingWS(tempStr, sizeof(pCableInfo->vendor_name));
XmlPrintStrLen("VendorName", tempStr, sizeof(pCableInfo->vendor_name), indent+4);
XmlPrintHex("VendorOUI", (pCableInfo->vendor_oui[0]<<16) + (pCableInfo->vendor_oui[1]<<8) + pCableInfo->vendor_oui[2], indent+4);
memcpy(tempStr, pCableInfo->vendor_pn, sizeof(pCableInfo->vendor_pn));
StlCableInfoTrimTrailingWS(tempStr, sizeof(pCableInfo->vendor_pn));
XmlPrintStrLen("VendorPN", tempStr, sizeof(pCableInfo->vendor_pn), indent+4);
memcpy(tempStr, pCableInfo->vendor_rev, sizeof(pCableInfo->vendor_rev));
StlCableInfoTrimTrailingWS(tempStr, sizeof(pCableInfo->vendor_rev));
XmlPrintStrLen("VendorRev", tempStr, sizeof(pCableInfo->vendor_rev), indent+4);
memcpy(tempStr, pCableInfo->vendor_sn, sizeof(pCableInfo->vendor_sn));
StlCableInfoTrimTrailingWS(tempStr, sizeof(pCableInfo->vendor_sn));
XmlPrintStrLen("VendorSN", tempStr, sizeof(pCableInfo->vendor_sn), indent+4);
StlCableInfoDateCodeToText(pCableInfo->date_code, tempBuf);
XmlPrintStrLen("DateCode", (char*)tempBuf, sizeof(tempBuf), indent+4);
}
printf("%*s</CableInfo>\n", indent, "");
break;
case STL_PORT_TYPE_SI_PHOTONICS:
default:
//printf("%*s<CableInfo>\n", indent, "");
//XmlPrintStr("PortTypeNotSupported", StlPortTypeToText(portType), indent+4 );
//printf("%*s</CableInfo>\n", indent, "");
break;
}
break;
default:
break;
}
} // End of ShowCableSummaryDD()
// show 1 port in a link in brief 1 line form
void ShowLinkPortBriefSummary(PortData *portp, const char *prefix,
uint64 context, LinkPortSummaryDetailCallback_t *callback,
Format_t format, int indent, int detail)
{
switch (format) {
case FORMAT_TEXT:
printf("%*s%4s ", indent, "", prefix);
printf("0x%016"PRIx64" %3u %2s %.*s\n",
portp->nodep->NodeInfo.NodeGUID,
portp->PortNum,
StlNodeTypeToText(portp->nodep->NodeInfo.NodeType),
NODE_DESCRIPTION_ARRAY_SIZE,
g_noname?g_name_marker:(char*)portp->nodep->NodeDesc.NodeString);
if (portp->nodep->enodep && portp->nodep->enodep->details) {
printf("%*sNodeDetails: %s\n", indent+4, "", portp->nodep->enodep->details);
}
if (detail) {
PortSelector* portselp = GetPortSelector(portp);
if (portselp && portselp->details) {
printf("%*sPortDetails: %s\n", indent+4, "", portselp->details);
}
}
if (detail > 1 && portp->pCableInfoData)
ShowCableSummary(portp->pCableInfoData, FORMAT_TEXT, indent+4, detail-1, portp->PortInfo.PortPhysConfig.s.PortType);
if (portp->pPortCounters && detail > 3 && ! g_persist && ! g_hard)
ShowPortCounters(portp->pPortCounters, format, indent+4, detail-3);
break;
case FORMAT_XML:
// MTU is output as part of LinkFrom directly in <Link> tag
printf("%*s<Port id=\"0x%016"PRIx64":%u\">\n", indent, "",
portp->nodep->NodeInfo.NodeGUID, portp->PortNum);
XmlPrintHex64("NodeGUID",
portp->nodep->NodeInfo.NodeGUID, indent+4);
if (portp->PortGUID)
XmlPrintHex64("PortGUID", portp->PortGUID, indent+4);
XmlPrintDec("PortNum", portp->PortNum, indent+4);
XmlPrintNodeType(portp->nodep->NodeInfo.NodeType,
indent+4);
XmlPrintNodeDesc((char*)portp->nodep->NodeDesc.NodeString, indent+4);
if (portp->nodep->enodep && portp->nodep->enodep->details) {
XmlPrintOptionalStr("NodeDetails", portp->nodep->enodep->details, indent+4);
}
if (detail) {
PortSelector* portselp = GetPortSelector(portp);
if (portselp && portselp->details) {
XmlPrintOptionalStr("PortDetails", portselp->details, indent+4);
}
}
if (portp->pPortCounters && detail > 3 && ! g_persist && ! g_hard)
ShowPortCounters(portp->pPortCounters, format, indent+4, detail-3);
break;
default:
break;
}
if (callback && detail)
(*callback)(context, portp, format, indent+4, detail-1);
if (format == FORMAT_XML)
printf("%*s</Port>\n", indent, "");
}
// show 1 port in a link in multi-line form with heading per field
void ShowLinkPortSummary(PortData *portp, const char *prefix,
Format_t format, int indent, int detail)
{
switch (format) {
case FORMAT_TEXT:
printf("%*s%4s Name: %.*s\n",
indent, "", prefix,
NODE_DESCRIPTION_ARRAY_SIZE,
g_noname?g_name_marker:(char*)portp->nodep->NodeDesc.NodeString);
printf("%*sNodeGUID: 0x%016"PRIx64" Type: %s PortNum: %3u\n",
indent+4, "",
portp->nodep->NodeInfo.NodeGUID,
StlNodeTypeToText(portp->nodep->NodeInfo.NodeType),
portp->PortNum);
if (portp->nodep->enodep && portp->nodep->enodep->details) {
printf("%*sNodeDetails: %s\n", indent+4, "", portp->nodep->enodep->details);
}
if (detail) {
PortSelector* portselp = GetPortSelector(portp);
if (portselp && portselp->details) {
printf("%*sPortDetails: %s\n", indent+4, "", portselp->details);
}
}
break;
case FORMAT_XML:
ShowLinkPortBriefSummary(portp, prefix,
0, NULL, format, indent, detail);
break;
default:
break;
}
}
// show cable information for a link in brief summary format
void ShowExpectedLinkBriefSummary(ExpectedLink *elinkp,
Format_t format, int indent, int detail)
{
if (! elinkp)
return;
switch (format) {
case FORMAT_TEXT:
if (elinkp->details) {
printf("%*sLinkDetails: %s\n", indent, "", elinkp->details);
}
if (elinkp->CableData.length || elinkp->CableData.label
|| elinkp->CableData.details) {
// TBD should g_noname suppress some of this?
printf("%*sCable: %-*s %-*s\n",
indent, "",
CABLE_LABEL_STRLEN, OPTIONAL_STR(elinkp->CableData.label),
CABLE_LENGTH_STRLEN, OPTIONAL_STR(elinkp->CableData.length));
if (elinkp->CableData.details)
printf("%*s%s\n", indent, "", elinkp->CableData.details);
}
break;
case FORMAT_XML:
indent-= 4; // hack to fix indent level
if (elinkp->details) {
XmlPrintOptionalStr("LinkDetails", elinkp->details, indent);
}
if (elinkp->CableData.length || elinkp->CableData.label
|| elinkp->CableData.details) {
printf("%*s<Cable>\n", indent, "");
XmlPrintOptionalStr("CableLabel", elinkp->CableData.label, indent+4);
XmlPrintOptionalStr("CableLength", elinkp->CableData.length, indent+4);
XmlPrintOptionalStr("CableDetails", elinkp->CableData.details, indent+4);
printf("%*s</Cable>\n", indent, "");
}
break;
default:
break;
}
}
// show cable information for a link in multi-line format with field headings
void ShowExpectedLinkSummary(ExpectedLink *elinkp,
Format_t format, int indent, int detail)
{
if (! elinkp)
return;
ASSERT(elinkp->portp1 && elinkp->portp1->neighbor == elinkp->portp2);
switch (format) {
case FORMAT_TEXT:
if (elinkp->details) {
printf("%*sLinkDetails: %s\n", indent, "", elinkp->details);
}
if (elinkp->CableData.length || elinkp->CableData.label
|| elinkp->CableData.details) {
printf("%*sCableLabel: %-*s CableLen: %-*s\n",
indent, "",
CABLE_LABEL_STRLEN, OPTIONAL_STR(elinkp->CableData.label),
CABLE_LENGTH_STRLEN, OPTIONAL_STR(elinkp->CableData.length));
printf("%*sCableDetails: %s\n",
indent, "",
OPTIONAL_STR(elinkp->CableData.details));
}
break;
case FORMAT_XML:
ShowExpectedLinkBriefSummary(elinkp, format, indent, detail);
break;
default:
break;
}
}
// show from side of a link, need to later call ShowLinkToBriefSummary
// useful when traversing trace route and don't have both sides of link handy
void ShowLinkFromBriefSummary(PortData *portp1,
uint64 context, LinkPortSummaryDetailCallback_t *callback,
Format_t format, int indent, int detail)
{
if (format == FORMAT_XML) {
XmlPrintLinkStartTag("Link", portp1, indent);
indent+=4;
XmlPrintRate(portp1->rate, indent);
XmlPrintDec("Internal", isInternalLink(portp1)?1:0, indent);
if (detail)
ShowExpectedLinkBriefSummary(portp1->elinkp, format, indent+4, detail-1);
}
ShowLinkPortBriefSummary(portp1, StlStaticRateToText(portp1->rate),
context, callback, format, indent, detail);
}
// show to side of a link, need to call ShowLinkFromBriefSummary before this
// useful when traversing trace route and don't have both sides of link handy
// portp2 can be NULL to "close" the From Summary without additional
// port information and no cable information
// This is useful when reporting trace routes which stay within a single port
void ShowLinkToBriefSummary(PortData *portp2, const char* toprefix, boolean close_link,
uint64 context, LinkPortSummaryDetailCallback_t *callback,
Format_t format, int indent, int detail)
{
if (format == FORMAT_XML)
indent +=4;
// portp2 should not be NULL, but code this defensively
if (portp2) {
ShowLinkPortBriefSummary(portp2, toprefix,
context, callback, format, indent, detail);
DEBUG_ASSERT(portp2->elinkp == portp2->neighbor->elinkp);
if (detail && format != FORMAT_XML)
ShowExpectedLinkBriefSummary(portp2->elinkp, format, indent+4, detail-1);
else if ((detail > 1 && portp2->pCableInfoData) && format==FORMAT_XML)
ShowCableSummary(portp2->pCableInfoData, FORMAT_XML, indent, detail-1, portp2->PortInfo.PortPhysConfig.s.PortType);
}
if (format == FORMAT_XML && close_link)
printf("%*s</Link>\n", indent-4, "");
}
// show both sides of a link, portp1 should be the "from" port
void ShowLinkBriefSummary(PortData *portp1, const char* toprefix, Format_t format, int indent, int detail)
{
ShowLinkFromBriefSummary(portp1, 0, NULL, format, indent, detail);
ShowLinkToBriefSummary(portp1->neighbor, toprefix, TRUE, 0, NULL, format, indent, detail);
}
/*
* There are 6 cases for routes:
* 1. FI - FI
* 2. FI to self
* 3. SW Port 0 to FI
* 4. FI to SW Port 0
* 5. SW Port 0 to SW Port 0
* 6. SW Port 0 to self
*
* Two self consistent Perspectives of these cases:
*
* Perspective 1: Show all "Links" along the route
* - every Link is a connection between 2 devices
* - every Link involves 2 Ports on different devices
* - never show SW Port 0 in a route
* - never show any ports for a "talk to self" route
* - similarly -F route:... would only select ports which -o route would show
*
* Perspective 2: Show all "Ports" along the route
* - route is a list of Ports (not Links)
* - show every port, including port 0 at start and/or end
* - for "talk to self" routes, show just the 1 port involved
* - similarly -F route:... would select all ports involved in the route
*
* The code below implements Perspective 1. Some code in #if 0 and some
* comments discuss possible approaches to implement perspective 2.
* If the future, perspective 2 could become runtime if flags based on a
* new parameter to this function.
*/
/* obtain and output the trace route information for the given path between
* the given pair of ports. The ports are provided to aid in tranversing
* the PortData and NodeData records and as an easy way to verify the
* concistency of the trace route query results against our previous
* port, node and link record queries.
*/
FSTATUS ShowTraceRoute(EUI64 portGuid, PortData *portp1, PortData *portp2,
IB_PATH_RECORD *pathp,
Format_t format, int indent, int detail)
{
FSTATUS status;
STL_TRACE_RECORD *pTraceRecords = NULL;
uint32 NumTraceRecords;
int i = -1;
uint32 links = 0;
PortData *p = portp1;
int p_shown = 0;
PQUERY_RESULT_VALUES pQueryResults = NULL;
struct omgt_port *omgt_port_session = NULL;
if (format == FORMAT_XML) {
printf("%*s<Route>\n", indent, "");
indent+=4;
}
ShowPathRecord(pathp, format, indent, detail);
if (portp1 == portp2) {
/* special case, internal loopback */
#if 0 // enable for perspective 2
//as coded below this results a <Link> with just 1 <Port>
//For perspective 2, should instead output a list of Ports
//(one port in this case) and show MTU and Rate per Port
if (detail) {
// detail=0 avoids link info and cable info, LinkTo needed to close
// XML output's <Link> tag
//ShowLinkBriefSummaryHeader(format, indent+4, 0);
//ShowLinkFromBriefSummary(portp1, 0, NULL, format, indent+4, 0);
//ShowLinkToBriefSummary(NULL, "-> ", TRUE, 0, NULL, format, indent+4, 0);
show port portp1 in report
}
output "1 Ports Traversed"
#else
switch (format) {
case FORMAT_TEXT:
printf("%*s0 Links Traversed\n", indent, "");
break;
case FORMAT_XML:
printf("%*s<LinksTraversed>0</LinksTraversed>\n", indent, "");
break;
default:
break;
}
#endif
status = FSUCCESS;
goto done;
}
if (portp1->neighbor == portp2) {
/* special case, single link traversed */
// Since portp1 has a neighbor, neither port is SW Port 0
#if 0 // enable for perspective 2
if (detail) {
show port portp1 in report
show port portp2 in report
}
output "2 Ports Traversed"
#else
if (detail) {
ShowLinkBriefSummaryHeader(format, indent+4, detail-1);
ShowLinkBriefSummary(portp1, "-> ", format, indent+4, detail-1);
}
switch (format) {
case FORMAT_TEXT:
printf("%*s1 Links Traversed\n", indent, "");
break;
case FORMAT_XML:
printf("%*s<LinksTraversed>1</LinksTraversed>\n", indent, "");
break;
default:
break;
}
#endif
status = FSUCCESS;
goto done;
}
if (!(g_Fabric.flags & FF_SMADIRECT) && ! g_snapshot_in_file) {
struct omgt_params params = {.debug_file = g_verbose > 2 ? stdout : NULL};
status = omgt_open_port_by_guid(&omgt_port_session, portGuid, ¶ms);
if (status != FSUCCESS) {
fprintf(stderr, "Unable to open fabric interface.\n");
goto done;
} else {
omgt_set_timeout(omgt_port_session, g_ms_timeout);
status = GetTraceRoute(omgt_port_session, pathp, &pQueryResults);
if (FSUCCESS != status) {
g_exitstatus = 1;
goto done;
}
}
NumTraceRecords = ((STL_TRACE_RECORD_RESULTS*)pQueryResults->QueryResult)->NumTraceRecords;
pTraceRecords = ((STL_TRACE_RECORD_RESULTS*)pQueryResults->QueryResult)->TraceRecords;
} else {
status = GenTraceRoutePath(&g_Fabric, pathp, g_rc, &pTraceRecords, &NumTraceRecords);
if (FSUCCESS != status) {
if (status == FUNAVAILABLE) {
fprintf(stderr, "opareport: Routing Tables not available in snapshot\n");
g_exitstatus = 1;
} else if (status == FNOT_DONE) {
switch (format) {
case FORMAT_TEXT:
printf("%*sRoute Incomplete\n", indent, "");
break;
case FORMAT_XML:
printf("%*s<LinksTraversed>0</LinksTraversed> <!-- Route Incomplete -->\n", indent, "");
break;
default:
break;
}
// don't fail just because some routes are incomplete
status = FSUCCESS;
} else {
fprintf(stderr, "opareport: Unable to determine route: (status=0x%x): %s\n", status, iba_fstatus_msg(status));
g_exitstatus = 1;
}
goto done;
}
}
ASSERT(NumTraceRecords > 0);
//printf("%*s%d Hops\n", indent, "", NumTraceRecords-1);
/* the first Trace record should be the exit from portp1, however
* not all versions of the SM report this record
*/
if (detail)
ShowLinkBriefSummaryHeader(format, indent+4, detail-1);
if (pTraceRecords[0].NodeType != portp1->nodep->NodeInfo.NodeType) {
/* workaround SM bug, did not report initial exit port */
// assume portp1 is not a Switch Port 0
p = portp1->neighbor;
if (! p) {
DBGPRINT("incorrect 1st trace record\n");
goto badroute;
}
if (detail) {
#if 0 // enable for perspective 2
show port portp1 in report
#else
ShowLinkFromBriefSummary(portp1, 0, NULL, format, indent+4, detail-1);
#endif
}
}
for (i=0; i< NumTraceRecords; i++) {
if (g_verbose)
ShowTraceRecord(&pTraceRecords[i], format, indent+4, detail-1);
if (p != portp1) {
if (detail) {
#if 0 // enable for perspective 2
show port p in report
#else
ShowLinkToBriefSummary(p, "-> ", TRUE, 0, NULL, format, indent+4, detail-1);
#endif
}
links++;
p_shown = 1;
}
if (pTraceRecords[i].NodeType != STL_NODE_FI) {
#if 0 // enable for perspective 2
if (i==0 && p == portp1) // must be starting at switch Port 0
output portp1 to report
#endif
p = FindNodePort(p->nodep, pTraceRecords[i].ExitPort);
if (! p) {
DBGPRINT("SW port not found\n");
goto badroute;
}
if (0 == p->PortNum) {
/* Switch Port 0 thus must be final port */
if (i+1 != NumTraceRecords) {
DBGPRINT("final switch port 0 error\n");
goto badroute;
}
#if 0 // enable for perspective 2
if (detail)
show port p in report
#endif
break;
}
if (detail) {
#if 0 // enable for perspective 2
show port p in report
#else
ShowLinkFromBriefSummary(p, 0, NULL, format, indent+4, detail-1);
#endif
}
if (p == portp2) {
// this should not happen. If we reach portp2 as the exit
// port of a switch, that implies portp2 must be port 0 of
// the switch which the test above should have caught
// but it doesn't hurt to have this redundant test here to be
// safe.
/* final port must be Switch Port 0 */
if (i+1 != NumTraceRecords) {
DBGPRINT("final switch port 0 error\n");
goto badroute;
}
} else {
p = p->neighbor;
if (! p) {
DBGPRINT("incorrect neighbor port\n");
goto badroute;
}
p_shown = 0;
}
} else if (i == 0) {
/* since we caught FI to FI case above, SM must have given us
* initial Node in path
*/
if (detail) {
#if 0 // enable for perspective 2
show port portp1 in report
#else
ShowLinkFromBriefSummary(portp1, 0, NULL, format, indent+4, detail-1);
#endif
}
/* unfortunately spec says Exit and Entry Port are 0 for FI, so
* can't verify consistency with portp1
*/
p = portp1->neighbor;
if (! p) {
DBGPRINT("1st port with no neighbor\n");
goto badroute;
}
p_shown = 0;
} else if (i+1 != NumTraceRecords) {
DBGPRINT("extra unexpected trace records\n");
goto badroute;
}
}
if (! p_shown) {
/* workaround SM bug, did not report final hop in route */
if (detail) {
#if 0 // enable for perspective 2
show port p in report
#else
ShowLinkToBriefSummary(p, "-> ", TRUE, 0, NULL, format, indent+4, detail-1);
#endif
}
}
if (p != portp2) {
DBGPRINT("ended at wrong port\n");
goto badroute;
}
#if 0 // enable for perspective 2
show Ports Traversed
#else
switch (format) {
case FORMAT_TEXT:
printf("%*s%u Links Traversed\n", indent, "", links);
break;
case FORMAT_XML:
printf("%*s<LinksTraversed>%u</LinksTraversed>\n", indent, "", links);
break;
default:
break;
}
#endif
done:
if (format == FORMAT_XML) {
indent-=4;
printf("%*s</Route>\n", indent, "");
}
if (pQueryResults)
omgt_free_query_result_buffer(pQueryResults);
if (omgt_port_session != NULL)
omgt_close_port(omgt_port_session);
if (g_snapshot_in_file && pTraceRecords)
MemoryDeallocate(pTraceRecords);
return status;
badroute:
status = FSUCCESS; // might as well process what we can
fprintf(stderr, "%*sRoute reported by SM inconsistent with Trace Route\n", indent+4, "");
if (g_verbose && i+1 < NumTraceRecords) {
if (format == FORMAT_TEXT)
printf("%*sRemainder of Route:\n", indent+4, "");
// Don't repeat records we already output above
for (i=i+1; i< NumTraceRecords; i++)
ShowTraceRecord(&pTraceRecords[i], format, indent+8, detail-1);
}
goto done;
}
/* show trace routes for all paths between 2 given ports */
FSTATUS ShowPortsTraceRoutes(EUI64 portGuid, PortData *portp1, PortData *portp2, Format_t format, int indent, int detail)
{
FSTATUS status;
PQUERY_RESULT_VALUES pQueryResults = NULL;
uint32 NumPathRecords;
IB_PATH_RECORD *pPathRecords = NULL;
struct omgt_port *omgt_port_session = NULL;
switch (format) {
case FORMAT_TEXT:
printf("%*sRoutes between ports:\n", indent, "");
ShowLinkPortBriefSummary(portp1, " ", 0, NULL, format, indent, 0);
ShowLinkPortBriefSummary(portp2, "and ", 0, NULL, format, indent, 0);
break;
case FORMAT_XML:
printf("%*s<PortRoutes>\n", indent, "");
ShowLinkPortBriefSummary(portp1, " ", 0, NULL, format, indent+4, 0);
ShowLinkPortBriefSummary(portp2, "and ", 0, NULL, format, indent+4, 0);
break;
default:
break;
}
if (! g_snapshot_in_file) {
struct omgt_params params = {.debug_file = g_verbose > 2 ? stdout : NULL};
status = omgt_open_port_by_guid(&omgt_port_session, portGuid, ¶ms);
if (FSUCCESS != status)
goto done;
omgt_set_timeout(omgt_port_session, g_ms_timeout);
status = GetPaths(omgt_port_session, portp1, portp2, &pQueryResults);
if (FSUCCESS != status)
goto done;
NumPathRecords = ((PATH_RESULTS*)pQueryResults->QueryResult)->NumPathRecords;
pPathRecords = ((PATH_RESULTS*)pQueryResults->QueryResult)->PathRecords;
} else {
status = GenPaths(&g_Fabric, portp1, portp2, &pPathRecords, &NumPathRecords);
if (FSUCCESS != status)
goto done;
}
switch (format) {
case FORMAT_TEXT:
printf("%*s%d Paths\n", indent, "", NumPathRecords);
break;
case FORMAT_XML:
printf("%*s<Paths>%d</Paths>\n", indent+4, "", NumPathRecords);
break;
default:
break;
}
if (detail) {
int i;
for (i=0; i< NumPathRecords; i++) {
ShowTraceRoute(portGuid, portp1, portp2, &pPathRecords[i], format, indent+4, detail-1);
}
}
done:
if (format == FORMAT_XML)
printf("%*s</PortRoutes>\n", indent, "");
if (pQueryResults)
omgt_free_query_result_buffer(pQueryResults);
if (omgt_port_session != NULL)
omgt_close_port(omgt_port_session);
if (g_snapshot_in_file && pPathRecords)
MemoryDeallocate(pPathRecords);
return status;
}
/* show trace routes for all paths between given port and node */
FSTATUS ShowPortNodeTraceRoutes(EUI64 portGuid, PortData *portp1, NodeData *nodep2, Format_t format, int indent, int detail)
{
cl_map_item_t *p;
for (p=cl_qmap_head(&nodep2->Ports); p != cl_qmap_end(&nodep2->Ports); p = cl_qmap_next(p)) {
PortData *portp2= PARENT_STRUCT(p, PortData, NodePortsEntry);
ShowPortsTraceRoutes(portGuid, portp1, portp2, format, indent, detail);
}
return FSUCCESS;
}
/* show trace routes for all paths between given port and point */
FSTATUS ShowPortPointTraceRoutes(EUI64 portGuid, PortData *portp1, Point *point2, Format_t format, int indent, int detail)
{
switch (point2->Type) {
case POINT_TYPE_PORT:
return ShowPortsTraceRoutes(portGuid, portp1, point2->u.portp, format, indent, detail);
case POINT_TYPE_PORT_LIST:
{
LIST_ITERATOR i;
DLIST *pList = &point2->u.portList;
for (i=ListHead(pList); i != NULL; i = ListNext(pList, i)) {
PortData *portp = (PortData*)ListObj(i);
ShowPortsTraceRoutes(portGuid, portp1, portp, format, indent, detail);
}
}
return FSUCCESS;
case POINT_TYPE_NODE:
return ShowPortNodeTraceRoutes(portGuid, portp1, point2->u.nodep, format, indent, detail);
case POINT_TYPE_NODE_LIST:
{
LIST_ITERATOR i;
DLIST *pList = &point2->u.nodeList;
for (i=ListHead(pList); i != NULL; i = ListNext(pList, i)) {
NodeData *nodep = (NodeData*)ListObj(i);
ShowPortNodeTraceRoutes(portGuid, portp1, nodep, format, indent, detail);
}
}
return FSUCCESS;
case POINT_TYPE_IOC:
return ShowPortNodeTraceRoutes(portGuid, portp1, point2->u.iocp->ioup->nodep, format, indent, detail);
case POINT_TYPE_IOC_LIST:
{
LIST_ITERATOR i;
DLIST *pList = &point2->u.nodeList;
for (i=ListHead(pList); i != NULL; i = ListNext(pList, i)) {
IocData *iocp = (IocData*)ListObj(i);
ShowPortNodeTraceRoutes(portGuid, portp1, iocp->ioup->nodep, format, indent, detail);
}
}
return FSUCCESS;
case POINT_TYPE_SYSTEM:
{
cl_map_item_t *p;
SystemData *systemp = point2->u.systemp;
for (p=cl_qmap_head(&systemp->Nodes); p != cl_qmap_end(&systemp->Nodes); p = cl_qmap_next(p)) {
NodeData *nodep = PARENT_STRUCT(p, NodeData, SystemNodesEntry);
ShowPortNodeTraceRoutes(portGuid, portp1, nodep, format, indent, detail);
}
return FSUCCESS;
}
default:
return FINVALID_PARAMETER;
}
}
/* show trace routes for all paths between given node and point */
FSTATUS ShowNodePointTraceRoutes(EUI64 portGuid, NodeData *nodep1, Point *point2, Format_t format, int indent, int detail)
{
cl_map_item_t *p;
for (p=cl_qmap_head(&nodep1->Ports); p != cl_qmap_end(&nodep1->Ports); p = cl_qmap_next(p)) {
PortData *portp1 = PARENT_STRUCT(p, PortData, NodePortsEntry);
ShowPortPointTraceRoutes(portGuid, portp1, point2, format, indent, detail);
}
return FSUCCESS;
}
/* show trace routes for all paths between 2 given points */
FSTATUS ShowPointsTraceRoutes(EUI64 portGuid, Point *point1, Point *point2, Format_t format, int indent, int detail)
{
switch (point1->Type) {
case POINT_TYPE_PORT:
return ShowPortPointTraceRoutes(portGuid, point1->u.portp, point2, format, indent, detail);
case POINT_TYPE_PORT_LIST:
{
LIST_ITERATOR i;
DLIST *pList = &point1->u.portList;
for (i=ListHead(pList); i != NULL; i = ListNext(pList, i)) {
PortData *portp = (PortData*)ListObj(i);
ShowPortPointTraceRoutes(portGuid, portp, point2, format, indent, detail);
}
}
return FSUCCESS;
case POINT_TYPE_NODE:
return ShowNodePointTraceRoutes(portGuid, point1->u.nodep, point2, format, indent, detail);
case POINT_TYPE_NODE_LIST:
{
LIST_ITERATOR i;
DLIST *pList = &point1->u.nodeList;
for (i=ListHead(pList); i != NULL; i = ListNext(pList, i)) {
NodeData *nodep = (NodeData*)ListObj(i);
ShowNodePointTraceRoutes(portGuid, nodep, point2, format, indent, detail);
}
}
return FSUCCESS;
case POINT_TYPE_IOC:
return ShowNodePointTraceRoutes(portGuid, point1->u.iocp->ioup->nodep, point2, format, indent, detail);
case POINT_TYPE_IOC_LIST:
{
LIST_ITERATOR i;
DLIST *pList = &point1->u.iocList;
for (i=ListHead(pList); i != NULL; i = ListNext(pList, i)) {
IocData *iocp = (IocData*)ListObj(i);
ShowNodePointTraceRoutes(portGuid, iocp->ioup->nodep, point2, format, indent, detail);
}
}
return FSUCCESS;
case POINT_TYPE_SYSTEM:
{
cl_map_item_t *p;
SystemData *systemp = point1->u.systemp;
for (p=cl_qmap_head(&systemp->Nodes); p != cl_qmap_end(&systemp->Nodes); p = cl_qmap_next(p)) {
NodeData *nodep = PARENT_STRUCT(p, NodeData, SystemNodesEntry);
ShowNodePointTraceRoutes(portGuid, nodep, point2, format, indent, detail);
}
return FSUCCESS;
}
default:
return FINVALID_PARAMETER;
}
}
void ShowPointNodeBriefSummary(const char* prefix, NodeData *nodep, Format_t format, int indent, int detail)
{
switch (format) {
case FORMAT_TEXT:
printf("%*s%s0x%016"PRIx64" %s %.*s\n",
indent, "", prefix,
nodep->NodeInfo.NodeGUID,
StlNodeTypeToText(nodep->NodeInfo.NodeType),
NODE_DESCRIPTION_ARRAY_SIZE,
g_noname?g_name_marker:(char*)nodep->NodeDesc.NodeString);
if (nodep->enodep && nodep->enodep->details) {
printf("%*sNodeDetails: %s\n", indent+4, "", nodep->enodep->details);
}
break;
case FORMAT_XML:
printf("%*s<Node id=\"0x%016"PRIx64"\">\n", indent, "",
nodep->NodeInfo.NodeGUID);
XmlPrintHex64("NodeGUID", nodep->NodeInfo.NodeGUID,
indent+4);
XmlPrintNodeType(nodep->NodeInfo.NodeType, indent+4);
XmlPrintNodeDesc(
(char*)nodep->NodeDesc.NodeString, indent+4);
if (nodep->enodep && nodep->enodep->details) {
XmlPrintOptionalStr("NodeDetails", nodep->enodep->details, indent+4);
}
printf("%*s</Node>\n", indent, "");
break;
default:
break;
}
}
void ShowPointPortBriefSummary(const char* prefix, PortData *portp, Format_t format, int indent, int detail)
{
switch (format) {
case FORMAT_TEXT:
if (portp->PortGUID)
printf("%*s%s%3u 0x%016"PRIx64"\n",
indent, "", prefix,
portp->PortNum,
portp->PortGUID);
else
printf("%*s%s%3u\n",
indent, "", prefix,
portp->PortNum);
ShowPointNodeBriefSummary("in Node: ", portp->nodep, format,
indent+4, detail);
break;
case FORMAT_XML:
printf("%*s<Port id=\"0x%016"PRIx64":%u\">\n", indent, "",
portp->nodep->NodeInfo.NodeGUID, portp->PortNum);
XmlPrintDec("PortNum", portp->PortNum, indent+4);
if (portp->PortGUID)
XmlPrintHex64("PortGUID", portp->PortGUID, indent+4);
ShowPointNodeBriefSummary("in Node: ", portp->nodep, format,
indent+4, detail);
printf("%*s</Port>\n", indent, "");
break;
default:
break;
}
}
// show 1 port selector in link data in brief form
// designed to be called for side 1 then side 2
void ShowExpectedLinkPortSelBriefSummary(const char* prefix,
ExpectedLink *elinkp, PortSelector *portselp,
uint8 side, ExpectedLinkSummaryDetailCallback_t *callback,
Format_t format, int indent, int detail)
{
DEBUG_ASSERT(side == 1 || side == 2);
switch (format) {
case FORMAT_TEXT:
{
int prefix_len = strlen(prefix);
if (side == 1) {
printf("%*s%s%4s ", indent, "", prefix,
elinkp->expected_rate?
StlStaticRateToText(elinkp->expected_rate)
:" ");
} else {
printf("%*s%*s%4s ", indent, "", prefix_len, "",
"<-> ");
}
if (side == 1 && elinkp->expected_mtu)
printf("%5s ",
IbMTUToText(elinkp->expected_mtu));
else
printf(" ");
if (portselp) {
if (portselp->NodeGUID)
printf("0x%016"PRIx64, portselp->NodeGUID);
else
printf(" ");
if (portselp->gotPortNum)
printf(" %3u ",portselp->PortNum);
else if (portselp->PortGUID)
printf(" 0x%016"PRIx64, portselp->PortGUID);
else
printf(" ");
if (portselp->NodeType)
printf(" %s",
StlNodeTypeToText(portselp->NodeType));
else
printf(" ");
if (portselp->NodeDesc)
printf(" %.*s\n",
NODE_DESCRIPTION_ARRAY_SIZE, g_noname?g_name_marker:portselp->NodeDesc);
else
printf("\n");
if (detail) {
if (portselp->details) {
// TBD should g_noname suppress some of this?
printf("%*sPortDetails: %s\n", indent+4+prefix_len, "", portselp->details);
}
}
}
}
break;
case FORMAT_XML:
// MTU is output as part of LinkFrom directly in <Link> tag
if (portselp) {
printf("%*s<Port id=\"%u\">\n", indent, "", side);
if (portselp->NodeGUID)
XmlPrintHex64("NodeGUID", portselp->NodeGUID, indent+4);
if (portselp->gotPortNum)
XmlPrintDec("PortNum", portselp->PortNum, indent+4);
if (portselp->PortGUID)
XmlPrintHex64("PortGUID", portselp->PortGUID, indent+4);
if (portselp->NodeType)
XmlPrintNodeType(portselp->NodeType, indent+4);
if (portselp->NodeDesc)
XmlPrintNodeDesc(portselp->NodeDesc, indent+4);
if (detail) {
if (portselp->details) {
// TBD should g_noname suppress some of this?
XmlPrintOptionalStr("PortDetails", portselp->details, indent+4);
}
}
}
break;
default:
break;
}
if (callback && detail)
(*callback)(elinkp, side, format, indent+4, detail-1);
if (format == FORMAT_XML)
printf("%*s</Port>\n", indent, "");
}
void ShowPointExpectedLinkBriefSummary(const char* prefix, ExpectedLink *elinkp, Format_t format, int indent, int detail)
{
// top level information about link
if (format == FORMAT_XML) {
printf("%*s<InputLink id=\"0x%016"PRIx64"\">\n", indent, "", (uint64)(uintn)elinkp);
indent+=4;
if (elinkp->expected_rate)
XmlPrintRate(elinkp->expected_rate, indent);
if (elinkp->expected_mtu)
XmlPrintDec("MTU",
GetBytesFromMtu(elinkp->expected_mtu), indent);
XmlPrintDec("Internal", elinkp->internal, indent);
if (detail)
ShowExpectedLinkBriefSummary(elinkp, format, indent+4, detail-1);
}
// From Side (Port 1)
ShowExpectedLinkPortSelBriefSummary(prefix, elinkp, elinkp->portselp1,
1, NULL, format, indent, detail);
// To Side (Port 2)
ShowExpectedLinkPortSelBriefSummary(prefix, elinkp, elinkp->portselp2,
2, NULL, format, indent, detail);
// Summary information about Link itself
if (detail && format != FORMAT_XML)
ShowExpectedLinkBriefSummary(elinkp, format, indent+4, detail-1);
if (format == FORMAT_XML)
printf("%*s</InputLink>\n", indent-4, "");
}
void ShowPointBriefSummary(Point* point, uint8 find_flag, Format_t format, int indent, int detail)
{
ASSERT(PointValid(point));
if (find_flag & FIND_FLAG_FABRIC) {
switch (point->Type) {
case POINT_TYPE_NONE:
break;
case POINT_TYPE_PORT:
ShowPointPortBriefSummary("Port: ", point->u.portp, format, indent, detail);
break;
case POINT_TYPE_PORT_LIST:
{
LIST_ITERATOR i;
DLIST *pList = &point->u.portList;
switch (format) {
case FORMAT_TEXT:
printf("%*s%u Ports:\n",
indent, "",
ListCount(pList));
break;
case FORMAT_XML:
printf("%*s<Ports>\n", indent, "");
XmlPrintDec("Count", ListCount(pList), indent+4);
break;
default:
break;
}
for (i=ListHead(pList); i != NULL; i = ListNext(pList, i)) {
PortData *portp = (PortData*)ListObj(i);
ShowPointPortBriefSummary("", portp, format, indent+4, detail);
}
if (format == FORMAT_XML) {
printf("%*s</Ports>\n",
indent, "");
}
break;
}
case POINT_TYPE_NODE:
ShowPointNodeBriefSummary("Node: ", point->u.nodep, format, indent, detail);
break;
case POINT_TYPE_NODE_LIST:
{
LIST_ITERATOR i;
DLIST *pList = &point->u.nodeList;
switch (format) {
case FORMAT_TEXT:
printf("%*s%u Nodes:\n",
indent, "",
ListCount(pList));
break;
case FORMAT_XML:
printf("%*s<Nodes>\n", indent, "");
XmlPrintDec("Count", ListCount(pList), indent+4);
break;
default:
break;
}
for (i=ListHead(pList); i != NULL; i = ListNext(pList, i)) {
NodeData *nodep = (NodeData*)ListObj(i);
ShowPointNodeBriefSummary("", nodep, format, indent+4, detail);
}
if (format == FORMAT_XML) {
printf("%*s</Nodes>\n", indent, "");
}
break;
}
case POINT_TYPE_IOC:
// TBD extract this and list code into common function
switch (format) {
case FORMAT_TEXT:
printf("%*sIoc: %3u 0x%016"PRIx64" %.*s\n",
indent, "",
point->u.iocp->IocSlot,
point->u.iocp->IocProfile.IocGUID,
IOC_IDSTRING_SIZE,
g_noname?g_name_marker:(char*)point->u.iocp->IocProfile.IDString);
break;
case FORMAT_XML:
printf("%*s<Ioc id=\"0x%016"PRIx64"\">\n", indent, "",
point->u.iocp->IocProfile.IocGUID);
XmlPrintDec("Slot", point->u.iocp->IocSlot, indent+4);
XmlPrintHex64("IocGUID", point->u.iocp->IocProfile.IocGUID, indent+4);
XmlPrintIocIDString(
(char*)point->u.iocp->IocProfile.IDString, indent+4);
break;
default:
break;
}
ShowPointNodeBriefSummary("in Node: ", point->u.iocp->ioup->nodep,
format, indent+4, detail);
if (format == FORMAT_XML) {
printf("%*s</Ioc>\n", indent, "");
}
break;
case POINT_TYPE_IOC_LIST:
{
LIST_ITERATOR i;
DLIST *pList = &point->u.iocList;
switch (format) {
case FORMAT_TEXT:
printf("%*s%u IOCs:\n",
indent, "",
ListCount(pList));
break;
case FORMAT_XML:
printf("%*s<IOCs>\n", indent, "");
XmlPrintDec("Count", ListCount(pList), indent+4);
break;
default:
break;
}
for (i=ListHead(pList); i != NULL; i = ListNext(pList, i)) {
IocData *iocp = (IocData*)ListObj(i);
switch (format) {
case FORMAT_TEXT:
printf("%*s%3u 0x%016"PRIx64" %.*s\n",
indent+4, "",
iocp->IocSlot,
iocp->IocProfile.IocGUID,
IOC_IDSTRING_SIZE,
g_noname?g_name_marker:(char*)iocp->IocProfile.IDString);
break;
case FORMAT_XML:
printf("%*s<Ioc id=\"0x%016"PRIx64"\">\n", indent+4, "",
iocp->IocProfile.IocGUID);
XmlPrintDec("Slot", iocp->IocSlot, indent+8);
XmlPrintHex64("IocGUID", iocp->IocProfile.IocGUID, indent+8);
XmlPrintIocIDString(
(char*)iocp->IocProfile.IDString, indent+8);
break;
default:
break;
}
ShowPointNodeBriefSummary("in Node: ", iocp->ioup->nodep,
format, indent+8, detail);
if (format == FORMAT_XML) {
printf("%*s</Ioc>\n", indent+4, "");
}
}
if (format == FORMAT_XML) {
printf("%*s</IOCs>\n",
indent, "");
}
break;
}
case POINT_TYPE_SYSTEM:
{
SystemData *systemp = point->u.systemp;
cl_map_item_t *p;
switch (format) {
case FORMAT_TEXT:
printf("%*sSystem: 0x%016"PRIx64"\n",
indent, "",
systemp->SystemImageGUID);
break;
case FORMAT_XML:
printf("%*s<System id=\"0x%016"PRIx64"\">\n", indent, "",
systemp->SystemImageGUID?systemp->SystemImageGUID:
PARENT_STRUCT(cl_qmap_head(&systemp->Nodes), NodeData, SystemNodesEntry)->NodeInfo.NodeGUID);
XmlPrintHex64("SystemImageGUID", systemp->SystemImageGUID, indent+4);
break;
default:
break;
}
for (p=cl_qmap_head(&systemp->Nodes); p != cl_qmap_end(&systemp->Nodes); p = cl_qmap_next(p)) {
NodeData *nodep = PARENT_STRUCT(p, NodeData, SystemNodesEntry);
ShowPointNodeBriefSummary("Node: ", nodep, format, indent+4, detail);
}
if (format == FORMAT_XML) {
printf("%*s</System>\n", indent, "");
}
break;
}
case POINT_TYPE_NODE_PAIR_LIST:
{
LIST_ITERATOR i, j;
int noOfLeftNodes, noOfRightNodes;
DLIST *pList1 = &point->u.nodePairList.nodePairList1;
DLIST *pList2 = &point->u.nodePairList.nodePairList2;
noOfLeftNodes = ListCount(pList1);
noOfRightNodes = ListCount(pList2);
if (noOfLeftNodes != noOfRightNodes) {
fprintf(stderr, "Pairs are not complete \n");
break;
}
switch (format) {
case FORMAT_TEXT:
printf("%*s%u Node Pairs:\n",
indent, "",
ListCount(pList1));
break;
case FORMAT_XML:
printf("%*s<NodePairs>\n", indent, "");
XmlPrintDec("Count", ListCount(pList1), indent+4);
break;
default:
break;
}
for (i = ListHead(pList1), j = ListHead(pList2); (i != NULL && j != NULL);
i = ListNext(pList1, i), j = ListNext(pList2, j) ) {
NodeData *nodep1 = (NodeData*)ListObj(i);
NodeData *nodep2 = (NodeData*)ListObj(j);
ShowPointNodeBriefSummary("NodePair: ", nodep1, format, indent+4, detail);
ShowPointNodeBriefSummary(" ", nodep2, format, indent+4, detail);
}
if (format == FORMAT_XML) {
printf("%*s</NodePairs>\n", indent, "");
}
break;
}
}
}
if (find_flag & FIND_FLAG_ENODE) {
switch (point->EnodeType) {
case POINT_ENODE_TYPE_NONE:
break;
case POINT_ENODE_TYPE_NODE:
ShowExpectedNodeBriefSummary("Input Node: ", point->u2.enodep, "InputNode", TRUE, format, indent, detail);
break;
case POINT_ENODE_TYPE_NODE_LIST:
{
LIST_ITERATOR i;
DLIST *pList = &point->u2.enodeList;
switch (format) {
case FORMAT_TEXT:
printf("%*s%u Input Nodes:\n",
indent, "",
ListCount(pList));
break;
case FORMAT_XML:
printf("%*s<InputNodes>\n", indent, "");
XmlPrintDec("Count", ListCount(pList), indent+4);
break;
default:
break;
}
for (i=ListHead(pList); i != NULL; i = ListNext(pList, i)) {
ExpectedNode *enodep = (ExpectedNode*)ListObj(i);
ShowExpectedNodeBriefSummary("", enodep, "InputNode", TRUE, format, indent+4, detail);
}
if (format == FORMAT_XML) {
printf("%*s</InputNodes>\n", indent, "");
}
break;
}
}
}
if (find_flag & FIND_FLAG_ESM) {
switch (point->EsmType) {
case POINT_ESM_TYPE_NONE:
break;
case POINT_ESM_TYPE_SM:
ShowExpectedSMBriefSummary("Input SM: ", point->u3.esmp, "InputSM", TRUE, format, indent, detail);
break;
case POINT_ESM_TYPE_SM_LIST:
{
LIST_ITERATOR i;
DLIST *pList = &point->u3.esmList;
switch (format) {
case FORMAT_TEXT:
printf("%*s%u Input SMs:\n",
indent, "",
ListCount(pList));
break;
case FORMAT_XML:
printf("%*s<InputSMs>\n", indent, "");
XmlPrintDec("Count", ListCount(pList), indent+4);
break;
default:
break;
}
for (i=ListHead(pList); i != NULL; i = ListNext(pList, i)) {
ExpectedSM *esmp = (ExpectedSM*)ListObj(i);
ShowExpectedSMBriefSummary("", esmp, "InputSM", TRUE, format, indent+4, detail);
}
if (format == FORMAT_XML) {
printf("%*s</InputSMs>\n", indent, "");
}
break;
}
}
}
if (find_flag & FIND_FLAG_ELINK) {
switch (point->ElinkType) {
case POINT_ELINK_TYPE_NONE:
break;
case POINT_ELINK_TYPE_LINK:
ShowPointExpectedLinkBriefSummary("Input Link: ", point->u4.elinkp, format, indent, detail);
break;
case POINT_ELINK_TYPE_LINK_LIST:
{
LIST_ITERATOR i;
DLIST *pList = &point->u4.elinkList;
switch (format) {
case FORMAT_TEXT:
printf("%*s%u Input Links:\n",
indent, "",
ListCount(pList));
break;
case FORMAT_XML:
printf("%*s<InputLinks>\n", indent, "");
XmlPrintDec("Count", ListCount(pList), indent+4);
break;
default:
break;
}
for (i=ListHead(pList); i != NULL; i = ListNext(pList, i)) {
ExpectedLink *elinkp = (ExpectedLink*)ListObj(i);
ShowPointExpectedLinkBriefSummary("", elinkp, format, indent+4, detail);
}
if (format == FORMAT_XML) {
printf("%*s</InputLinks>\n", indent, "");
}
break;
}
}
}
}
void ShowPointFocus(Point* focus, uint8 find_flag, Format_t format, int indent, int detail)
{
if (! focus || g_quietfocus)
return;
if (PointValid(focus)) {
switch (format) {
case FORMAT_TEXT:
printf("%*sFocused on:\n", indent, "");
break;
case FORMAT_XML:
printf("%*s<Focus>\n", indent, "");
break;
default:
break;
}
ShowPointBriefSummary(focus, find_flag, format, indent+4, detail);
if (format == FORMAT_XML)
printf("%*s</Focus>\n", indent, "");
}
if (format == FORMAT_TEXT)
printf("\n");
}
// output verbose summary of a IO Service Entry
void ShowIoServiceSummary(IOC_SERVICE *srvp, Format_t format, int indent, int detail)
{
switch (format) {
case FORMAT_TEXT:
printf("%*sName: %.*s\n", indent, "", IOC_SERVICE_NAME_SIZE, srvp->Name);
printf("%*sId: 0x%016"PRIx64"\n", indent, "", srvp->Id);
break;
case FORMAT_XML:
printf("%*s<IocService id=\"%.*s\">\n", indent, "", IOC_SERVICE_NAME_SIZE, srvp->Name);
XmlPrintServiceName(srvp->Name, indent+4);
printf("%*s<Id>0x%016"PRIx64"</Id>\n", indent+4, "", srvp->Id);
printf("%*s</IocService>\n", indent, "");
break;
default:
break;
}
}
// output verbose summary of a IOC
void ShowIocSummary(IocData *iocp, Format_t format, int indent, int detail)
{
IOC_PROFILE *pIocProfile = &iocp->IocProfile;
switch (format) {
case FORMAT_TEXT:
printf("%*sIocSlot: %3u GUID: 0x%016"PRIx64"\n",
indent, "", iocp->IocSlot, pIocProfile->IocGUID);
printf("%*sID String: %.*s\n",
indent+4, "",
IOC_IDSTRING_SIZE,
g_noname?g_name_marker:(char*)pIocProfile->IDString);
printf("%*sIO Class: 0x%x SubClass: 0x%x Protocol: 0x%x Protocol Ver: 0x%x\n",
indent+4, "",
pIocProfile->IOClass,
pIocProfile->IOSubClass,
pIocProfile->Protocol,
pIocProfile->ProtocolVer);
printf("%*sVendorID: 0x%x DeviceID: 0x%x Rev: 0x%x\n",
indent+4, "",
pIocProfile->ven.v.VendorId,
pIocProfile->DeviceId,
pIocProfile->DeviceVersion);
if (detail) {
printf("%*sSubsystem: VendorID: 0x%x DeviceID: 0x%x\n",
indent+4, "",
pIocProfile->sub.s.SubSystemVendorID,
pIocProfile->SubSystemID);
printf("%*sCapability: 0x%02x: %s%s%s%s%s%s%s%s\n",
indent+4, "",
pIocProfile->ccm.CntlCapMask,
pIocProfile->ccm.ctlrCapMask.ST?"ST ":"",
pIocProfile->ccm.ctlrCapMask.SF?"SF ":"",
pIocProfile->ccm.ctlrCapMask.RT?"RT ":"",
pIocProfile->ccm.ctlrCapMask.RF?"RF ":"",
pIocProfile->ccm.ctlrCapMask.WT?"WT ":"",
pIocProfile->ccm.ctlrCapMask.WF?"WF ":"",
pIocProfile->ccm.ctlrCapMask.AT?"AT ":"",
pIocProfile->ccm.ctlrCapMask.AF?"AF ":"");
printf("%*sSend Depth: %u Size: %u; RDMA Read Depth: %u RDMA Size: %u\n",
indent+4, "",
pIocProfile->SendMsgDepth,
pIocProfile->SendMsgSize,
pIocProfile->RDMAReadDepth,
pIocProfile->RDMASize);
}
printf("%*s%u Services%s\n", indent+4, "", pIocProfile->ServiceEntries, detail?":":"");
break;
case FORMAT_XML:
printf("%*s<Ioc id=\"0x%016"PRIx64"\">\n", indent, "",
pIocProfile->IocGUID);
XmlPrintDec("IocSlot", iocp->IocSlot, indent+4);
XmlPrintHex64("IocGUID", pIocProfile->IocGUID, indent+4);
XmlPrintIocIDString((char*)pIocProfile->IDString, indent+4);
XmlPrintHex("IOClass", pIocProfile->IOClass, indent+4);
XmlPrintHex("IOSubClass", pIocProfile->IOSubClass, indent+4);
XmlPrintHex("Protocol", pIocProfile->Protocol, indent+4);
XmlPrintHex("ProtocolVer", pIocProfile->ProtocolVer, indent+4);
XmlPrintHex("VendorID", pIocProfile->ven.v.VendorId, indent+4);
XmlPrintHex("DeviceId", pIocProfile->DeviceId, indent+4);
XmlPrintHex("DeviceVersion", pIocProfile->DeviceVersion, indent+4);
if (detail) {
XmlPrintHex("SubSystemVendorID",
pIocProfile->sub.s.SubSystemVendorID, indent+4);
XmlPrintHex("SubSystemID",
pIocProfile->SubSystemID, indent+4);
XmlPrintHex8("CapabilityMask", pIocProfile->ccm.CntlCapMask,
indent+4);
printf("%*s<Capability>%s%s%s%s%s%s%s%s</Capability>\n",
indent+4, "",
pIocProfile->ccm.ctlrCapMask.ST?"ST ":"",
pIocProfile->ccm.ctlrCapMask.SF?"SF ":"",
pIocProfile->ccm.ctlrCapMask.RT?"RT ":"",
pIocProfile->ccm.ctlrCapMask.RF?"RF ":"",
pIocProfile->ccm.ctlrCapMask.WT?"WT ":"",
pIocProfile->ccm.ctlrCapMask.WF?"WF ":"",
pIocProfile->ccm.ctlrCapMask.AT?"AT ":"",
pIocProfile->ccm.ctlrCapMask.AF?"AF ":"");
XmlPrintDec("SendMsgDepth", pIocProfile->SendMsgDepth, indent+4);
XmlPrintDec("SendMsgSize", pIocProfile->SendMsgSize, indent+4);
XmlPrintDec("RDMAReadDepth", pIocProfile->RDMAReadDepth, indent+4);
XmlPrintDec("RDMASize", pIocProfile->RDMASize, indent+4);
}
printf("%*s<ServicesCount>%u</ServicesCount>\n", indent+4, "", pIocProfile->ServiceEntries);
break;
default:
break;
}
if (detail) {
unsigned i;
if (format == FORMAT_XML) {
printf("%*s<Services>\n", indent+4, "");
}
for (i=0; i < pIocProfile->ServiceEntries; i++) {
ShowIoServiceSummary(&iocp->Services[i], format, indent+8, detail-1);
}
if (format == FORMAT_XML) {
printf("%*s</Services>\n", indent+4, "");
}
}
if (format == FORMAT_XML) {
printf("%*s</Ioc>\n", indent, "");
}
}
// output verbose summary of a IOU
void ShowIouSummary(IouData *ioup, Point *focus, Format_t format, int indent, int detail)
{
IOUnitInfo *pIouInfo = &ioup->IouInfo;
switch (format) {
case FORMAT_TEXT:
if (g_persist || g_hard)
printf("%*sMax IOCs: %3u Change ID: xxxxx DiagDeviceId: %u Rom: %u\n",
indent, "", pIouInfo->MaxControllers,
pIouInfo->DiagDeviceId, pIouInfo->OptionRom);
else
printf("%*sMax IOCs: %3u Change ID: %5u DiagDeviceId: %u Rom: %u\n",
indent, "", pIouInfo->MaxControllers, pIouInfo->Change_ID,
pIouInfo->DiagDeviceId, pIouInfo->OptionRom);
break;
case FORMAT_XML:
printf("%*s<Iou id=\"0x%016"PRIx64"\">\n", indent, "",
ioup->nodep->NodeInfo.NodeGUID);
XmlPrintDec("MaxIOCs", pIouInfo->MaxControllers, indent+4);
if (! (g_persist || g_hard))
XmlPrintDec("ChangeID", pIouInfo->Change_ID, indent+4);
XmlPrintDec("DiagDeviceId", pIouInfo->DiagDeviceId, indent+4);
XmlPrintDec("OptionRom", pIouInfo->OptionRom, indent+4);
break;
default:
break;
}
if (detail) {
LIST_ITEM *p;
for (p=QListHead(&ioup->Iocs); p != NULL; p = QListNext(&ioup->Iocs, p)) {
IocData *iocp = (IocData *)QListObj(p);
if (! CompareIocPoint(iocp, focus))
continue;
ShowIocSummary(iocp, format, indent+4, detail-1);
}
}
if (format == FORMAT_XML) {
printf("%*s</Iou>\n", indent, "");
}
}
// output verbose summary of SL-to-SC table
void ShowSLSCTable(NodeData *nodep, PortData *portp, Format_t format, int indent, int detail)
{
STL_SLSCMAP *pSLSC = portp->pQOS->SL2SCMap;
int i;
if (format == FORMAT_XML) {
printf("%*s<SLtoSCMap>\n", indent, "");
indent+=4;
} else {
printf("%*sSLtoSC:\n", indent, "");
printf("%*sSL: 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15\n",
indent, "");
}
switch (format) {
case FORMAT_TEXT:
printf("%*sSC: ", indent, "");
for (i = 0; i < STL_MAX_SLS; i++) {
if (i == 16) {
printf("\n%*sSL: 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31\n",
indent, "");
printf("%*sSC: ", indent, "");
}
printf("%02u ", pSLSC->SLSCMap[i].SC);
}
printf("\n");
break;
case FORMAT_XML:
for (i=0; i<STL_MAX_SLS; i++)
printf("%*s<SC SL=\"%u\">%u</SC>\n", indent, "", i, pSLSC->SLSCMap[i].SC);
break;
default:
break;
} // End of switch (format)
switch (format) {
case FORMAT_TEXT:
break;
case FORMAT_XML:
indent-=4;
printf("%*s</SLtoSCMap>\n", indent, "");
break;
default:
break;
}
} // End of ShowSLSCTable
// output verbose summary of SC-to-SL table
void ShowSCSLTable(NodeData *nodep, PortData *portp, Format_t format, int indent, int detail)
{
STL_SCSLMAP *pSCSL = portp->pQOS->SC2SLMap;
int i;
if (format == FORMAT_XML) {
printf("%*s<SCtoSLMap>\n", indent, "");
indent+=4;
} else {
printf("%*sSCtoSL:\n", indent, "");
printf("%*sSC: 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15\n",
indent, "");
}
switch (format) {
case FORMAT_TEXT:
printf("%*sSL: ", indent, "");
for (i = 0; i < STL_MAX_SCS; i++) {
if (i == 16) {
printf("\n%*sSC: 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31\n",
indent, "");
printf("%*sSL: ", indent, "");
}
printf("%02u ", pSCSL->SCSLMap[i].SL);
}
printf("\n");
break;
case FORMAT_XML:
for (i=0; i<STL_MAX_SCS; i++)
printf("%*s<SL SC=\"%u\">%u</SC>\n", indent, "", i, pSCSL->SCSLMap[i].SL);
break;
default:
break;
} // End of switch (format)
switch (format) {
case FORMAT_TEXT:
break;
case FORMAT_XML:
indent-=4;
printf("%*s</SCtoSLMap>\n", indent, "");
break;
default:
break;
}
} // End of ShowSCSLTable
// output verbose summary of SC-to-SC table
void ShowSCSCTable(NodeData *nodep, PortData *portp, int tab, Format_t format, int indent, int detail)
{
LIST_ITEM *p;
int i;
if (format == FORMAT_XML) {
if (tab == 0) printf("%*s<SCtoSCMap>\n", indent, "");
else printf("%*s<SCtoSCExtMap>\n", indent, "");
indent+=4;
} else {
if (tab == 0) printf("%*sSCtoSC:\n", indent, "");
else printf("%*sSCtoSCExt:\n", indent, "");
}
for (p=QListHead(&portp->pQOS->SC2SCMapList[tab]); p != NULL; p = QListNext(&portp->pQOS->SC2SCMapList[tab], p))
{
PortMaskSC2SCMap *pSC2SC = (PortMaskSC2SCMap *)QListObj(p);
ASSERT(nodep->NodeInfo.NodeType == STL_NODE_SW);
char outports[nodep->NodeInfo.NumPorts*3];
FormatStlPortMask(outports, pSC2SC->outports, nodep->NodeInfo.NumPorts, nodep->NodeInfo.NumPorts*3);
switch (format) {
case FORMAT_TEXT:
printf("%*s%s\n", indent, "", outports);
printf("%*s SC: 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15\n",
indent, "");
printf("%*s SC': ", indent, "");
for (i = 0; i < STL_MAX_SCS; i++) {
if (i == 16) {
printf("\n%*s SC: 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31\n",
indent, "");
printf("%*s SC': ", indent, "");
}
printf("%02u ", pSC2SC->SC2SCMap->SCSCMap[i].SC);
}
printf("\n");
break;
case FORMAT_XML:
printf("%*s<OutputPorts ports=\"%s\">\n", indent, "", &outports[7]); // don't want to print the 1st 7 chars of the string
indent+=4;
for (i=0; i<STL_MAX_SCS; i++)
printf("%*s<SC SC=\"%u\">%u</SC>\n", indent, "", i, pSC2SC->SC2SCMap->SCSCMap[i].SC);
indent-=4;
printf("%*s</OutputPorts>\n", indent, "");
break;
default:
break;
} // End of switch (format)
} // End of for ( p=QListHead(&portp->pQOS->SC2SCMapList)
switch (format) {
case FORMAT_TEXT:
break;
case FORMAT_XML:
indent-=4;
printf("%*s</SCtoSCMap>\n", indent, "");
break;
default:
break;
}
} // End of ShowSCSCTable
// output verbose summary of VL arbitration table
void ShowVLArbTable(PortData *portp, Format_t format, int indent, int detail)
{
// Adjust these to tweak the width of the print out.
const int VLWT_PER_LINE=6;
const int VL_PER_LINE=4;
int t, i, j;
STL_VLARB_TABLE *pVLArb = portp->pQOS->u.VLArbTable;
int vlarb;
int res = getVLArb(portp, &vlarb);
if (res) {
fprintf(stderr, "Error-%s: failed to determine if VLArb is in use.\n", __func__);
return;
}
if (!vlarb)
return;
if (format == FORMAT_TEXT) {
for (t=0; t<STL_VLARB_PREEMPT_MATRIX; t++) {
if (t==STL_VLARB_LOW_ELEMENTS) printf("%*sVL Arbitration Low:\n", indent, "");
else if (t==STL_VLARB_HIGH_ELEMENTS) printf("%*sVL Arbitration High:\n", indent, "");
else printf("%*sVL Arbitration Preempt:\n", indent, "");
for (i=0, j=0; i<VLARB_TABLE_LENGTH; i++) {
if (j==0) {
printf("%*s", indent+4, "");
j++;
}
if (pVLArb[t].Elements[i].Weight) {
printf("%02d/%03d ",
pVLArb[t].Elements[i].s.VL,
pVLArb[t].Elements[i].Weight);
j=j+1;
}
if (j==VLWT_PER_LINE) {
j=0;
printf("\n");
}
}
if (j!=0) printf("\n");
}
printf("%*sVL Preemption Matrix:\n", indent, "");
for (i=0; i<STL_MAX_VLS; i+=VL_PER_LINE) {
printf("%*s", indent+4, "");
for (j=0; j<VL_PER_LINE; j++) {
printf("%02d:%08x ", i+j, pVLArb[STL_VLARB_PREEMPT_MATRIX].Matrix[i+j]);
}
printf("\n");
}
} else if (format == FORMAT_XML) {
for (t=0; t < STL_VLARB_PREEMPT_MATRIX; t++) {
if (t==0) printf("%*s<VLArbitrationLow>\n", indent, "");
else if (t==1) printf("%*s<VLArbitrationHigh>\n", indent, "");
else printf("%*s<VLArbitrationPreempt>\n", indent, "");
for (i=0; i<VLARB_TABLE_LENGTH; i++) {
if (pVLArb[t].Elements[i].Weight) {
printf("%*s<Weight VL=\"%u\">%u</Weight>\n", indent+4, "",
pVLArb[t].Elements[i].s.VL,
pVLArb[t].Elements[i].Weight);
}
}
if (t==0) printf("%*s</VLArbitrationLow>\n", indent, "");
else if (t==1) printf("%*s</VLArbitrationHigh>\n", indent, "");
else printf("%*s</VLArbitrationPreempt>\n", indent, "");
}
printf("%*s<VLPreemptionMatrix>\n", indent, "");
for (i=0; i<STL_MAX_VLS; i++) {
printf("%*s<Element VL=\"%u\">%u</Element>\n", indent+4, "",
i, pVLArb[STL_VLARB_PREEMPT_MATRIX].Matrix[i]);
}
printf("%*s</VLPreemptionMatrix>\n", indent, "");
}
} // End of ShowVLArbTable
// output verbose summary of P-Key table
void ShowPKeyTable(NodeData *nodep, PortData *portp, Format_t format, int indent, int detail)
{
#define PKEY_PER_LINE 6
int ix, ix_line, last=0;
STL_PKEY_ELEMENT *pPKey = portp->pPartitionTable;
int ix_capacity = PortPartitionTableSize(portp);
switch (format) {
case FORMAT_XML:
printf("%*s<PKeyTable>\n", indent, "");
indent+=4;
break;
case FORMAT_TEXT:
default:
break;
}
if (pPKey && ix_capacity)
{
for (ix = 0; ix < ix_capacity; ix++ )
{
if (pPKey[ix].AsReg16 & 0x7FFF)
last = ix;
}
for (ix = 0; ix <= last; )
{
switch (format) {
case FORMAT_TEXT:
printf("%*s%12s", indent, "", !ix ? "P_Key Table:" : "");
for ( ix_line = PKEY_PER_LINE;
ix_line > 0 && ix <= last; ix++) {
printf("0x%04X ", pPKey[ix].AsReg16);
ix_line--;
}
printf("\n");
break;
case FORMAT_XML:
XmlPrintHex16("PKey", pPKey[ix].AsReg16, indent);
ix++;
break;
default:
break;
} // End of switch (format)
}
}
switch (format) {
case FORMAT_XML:
indent-=4;
printf("%*s</PKeyTable>\n", indent, "");
break;
case FORMAT_TEXT:
default:
break;
}
} // End of ShowPKeyTable
// output verbose summary of PortCounters
void ShowPortCounters(STL_PORT_COUNTERS_DATA *pPortCounters, Format_t format, int indent, int detail)
{
if (detail < 1) return;
switch (format) {
case FORMAT_TEXT:
if (detail >= 3) {
printf("%*sPerformance: Transmit\n",
indent, "");
printf("%*s Xmit Data %20"PRIu64" MB (%"PRIu64" Flits)\n",
indent, "",
pPortCounters->portXmitData/FLITS_PER_MB,
pPortCounters->portXmitData);
printf("%*s Xmit Pkts %20"PRIu64"\n",
indent, "",
pPortCounters->portXmitPkts);
printf("%*s MC Xmt Pkts %20"PRIu64"\n",
indent, "",
pPortCounters->portMulticastXmitPkts);
printf("%*sPerformance: Receive\n",
indent, "");
printf("%*s Rcv Data %20"PRIu64" MB (%"PRIu64" Flits)\n",
indent, "",
pPortCounters->portRcvData/FLITS_PER_MB,
pPortCounters->portRcvData);
printf("%*s Rcv Pkts %20"PRIu64"\n",
indent, "",
pPortCounters->portRcvPkts);
printf("%*s MC Rcv Pkts %20"PRIu64"\n",
indent, "",
pPortCounters->portMulticastRcvPkts);
printf("%*sPerformance: Congestion\n",
indent, "");
printf("%*s Congestion Discards %20"PRIu64"\n",
indent, "",
pPortCounters->swPortCongestion);
printf("%*s Rcv FECN %20"PRIu64"\n",
indent, "",
pPortCounters->portRcvFECN);
printf("%*s Rcv BECN %20"PRIu64"\n",
indent, "",
pPortCounters->portRcvBECN);
printf("%*s Mark FECN %20"PRIu64"\n",
indent, "",
pPortCounters->portMarkFECN);
printf("%*s Xmit Time Congestion %20"PRIu64"\n",
indent, "",
pPortCounters->portXmitTimeCong);
printf("%*s Xmit Wait %20"PRIu64"\n",
indent, "",
pPortCounters->portXmitWait);
printf("%*sPerformance: Bubbles\n",
indent, "");
printf("%*s Xmit Wasted BW %20"PRIu64"\n",
indent, "",
pPortCounters->portXmitWastedBW);
printf("%*s Xmit Wait Data %20"PRIu64"\n",
indent, "",
pPortCounters->portXmitWaitData);
printf("%*s Rcv Bubble %20"PRIu64"\n",
indent, "",
pPortCounters->portRcvBubble);
printf("%*sErrors: Signal Integrity\n",
indent, "");
printf("%*s Link Qual Indicator %20u (%s)\n",
indent, "",
pPortCounters->lq.s.linkQualityIndicator,
StlLinkQualToText(pPortCounters->lq.s.linkQualityIndicator));
printf("%*s Uncorrectable Errors %20u\n", //8 bit
indent, "",
pPortCounters->uncorrectableErrors);
printf("%*s Link Downed %20u\n", // 32 bit
indent, "",
pPortCounters->linkDowned);
printf("%*s Rcv Errors %20"PRIu64"\n",
indent, "",
pPortCounters->portRcvErrors);
printf("%*s Exc. Buffer Overrun %20"PRIu64"\n",
indent, "",
pPortCounters->excessiveBufferOverruns);
printf("%*s FM Config Errors %20"PRIu64"\n",
indent, "",
pPortCounters->fmConfigErrors);
printf("%*s Link Error Recovery %20u\n", // 32 bit
indent, "",
pPortCounters->linkErrorRecovery);
printf("%*s Local Link Integ Err %20"PRIu64"\n",
indent, "",
pPortCounters->localLinkIntegrityErrors);
printf("%*s Rcv Rmt Phys Err %20"PRIu64"\n",
indent, "",
pPortCounters->portRcvRemotePhysicalErrors);
printf("%*sErrors: Security\n",
indent, "");
printf("%*s Xmit Constraint %20"PRIu64"\n",
indent, "",
pPortCounters->portXmitConstraintErrors);
printf("%*s Rcv Constraint %20"PRIu64"\n",
indent, "",
pPortCounters->portRcvConstraintErrors);
printf("%*sErrors: Routing and Other\n",
indent, "");
printf("%*s Rcv Sw Relay Err %20"PRIu64"\n",
indent, "",
pPortCounters->portRcvSwitchRelayErrors);
printf("%*s Xmit Discards %20"PRIu64"\n",
indent, "",
pPortCounters->portXmitDiscards);
} else if (detail == 2) {
printf("%*sPortStatus:\n", indent, "");
printf("%*sXmit Data %20"PRIu64" MB | Xmit Pkts %20"PRIu64"\n", indent+4, "",
pPortCounters->portXmitData/FLITS_PER_MB, pPortCounters->portXmitPkts);
printf("%*sRcv Data %20"PRIu64" MB | Rcv Pkts %20"PRIu64"\n", indent+4, "",
pPortCounters->portRcvData/FLITS_PER_MB, pPortCounters->portRcvPkts);
if (pPortCounters->portMulticastXmitPkts || pPortCounters->portMulticastRcvPkts) {
printf("%*sMC Xmit Pkts %20"PRIu64" | MC Rcv Pkts %20"PRIu64"\n", indent+4, "",
pPortCounters->portMulticastXmitPkts, pPortCounters->portMulticastRcvPkts);
}
printf("%*sLink Qual Indicator %20u (%s)\n", indent+4, "",
pPortCounters->lq.s.linkQualityIndicator,
StlLinkQualToText(pPortCounters->lq.s.linkQualityIndicator));
boolean isLeft = TRUE, isAny = FALSE;
#define NON_ZERO_64(cntr, name) \
if (cntr) { \
printf("%*s%-22s%20"PRIu64"%s", isLeft ? indent+4 : 0, "", name, cntr, isLeft ? " | " : "\n"); \
isLeft = !isLeft; isAny = TRUE;\
}
#define NON_ZERO(cntr, name) \
if (cntr) { \
printf("%*s%-22s%20u%s", isLeft ? indent+4 : 0, "", name, cntr, isLeft ? " | " : "\n"); \
isLeft = !isLeft; isAny = TRUE; \
}
NON_ZERO_64(pPortCounters->swPortCongestion, "Congestion Discards");
NON_ZERO_64(pPortCounters->portRcvFECN, "Rcv FECN");
NON_ZERO_64(pPortCounters->portRcvBECN, "Rcv BECN");
NON_ZERO_64(pPortCounters->portMarkFECN, "Mark FECN");
NON_ZERO_64(pPortCounters->portXmitTimeCong, "Xmit Time Congestion");
NON_ZERO_64(pPortCounters->portXmitWait, "Xmit Wait");
NON_ZERO_64(pPortCounters->portXmitWastedBW, "Xmit Wasted BW");
NON_ZERO_64(pPortCounters->portXmitWaitData, "Xmit Wait Data");
NON_ZERO_64(pPortCounters->portRcvBubble, "Rcv Bubble");
NON_ZERO(pPortCounters->uncorrectableErrors, "Uncorrectable Errors");
NON_ZERO(pPortCounters->linkDowned, "Link Downed");
NON_ZERO_64(pPortCounters->portRcvErrors, "Rcv Errors");
NON_ZERO_64(pPortCounters->excessiveBufferOverruns, "Exc Buffer Overrun");
NON_ZERO_64(pPortCounters->fmConfigErrors, "FM Config Errors");
NON_ZERO(pPortCounters->linkErrorRecovery, "Link Error Recovery");
NON_ZERO_64(pPortCounters->localLinkIntegrityErrors, "Local Link Integ Err");
NON_ZERO_64(pPortCounters->portRcvRemotePhysicalErrors, "Rcv Rmt Phys Err");
NON_ZERO_64(pPortCounters->portXmitConstraintErrors, "Xmit Constraint");
NON_ZERO_64(pPortCounters->portRcvConstraintErrors, "Rcv Constraint");
NON_ZERO_64(pPortCounters->portRcvSwitchRelayErrors, "Rcv Sw Relay Err");
NON_ZERO_64(pPortCounters->portXmitDiscards, "Xmit Discards");
if (isAny && !isLeft) printf("\n");
#undef NON_ZERO_64
#undef NON_ZERO
} else if (detail == 1) {
printf("%*sPortStatus:\n", indent, "");
printf("%*sXmit Data %20"PRIu64" MB | Xmit Pkts %20"PRIu64"\n", indent+4, "",
pPortCounters->portXmitData/FLITS_PER_MB, pPortCounters->portXmitPkts);
printf("%*sRcv Data %20"PRIu64" MB | Rcv Pkts %20"PRIu64"\n", indent+4, "",
pPortCounters->portRcvData/FLITS_PER_MB, pPortCounters->portRcvPkts);
printf("%*sLink Qual Indicator %20u (%s)\n", indent+4, "",
pPortCounters->lq.s.linkQualityIndicator,
StlLinkQualToText(pPortCounters->lq.s.linkQualityIndicator));
}
break;
case FORMAT_XML:
printf("%*s<Performance>\n", indent, "");
// Data movement
XmlPrintDec64("XmitDataMB", pPortCounters->portXmitData/FLITS_PER_MB, indent+4);
printf("%*s<XmitData>%"PRIu64"</XmitData> <!-- in Flits -->\n",
indent+4, "", pPortCounters->portXmitData);
XmlPrintDec64("RcvDataMB", pPortCounters->portRcvData/FLITS_PER_MB, indent+4);
XmlPrintDec64("XmitPkts", pPortCounters->portXmitPkts, indent+4);
printf("%*s<RcvData>%"PRIu64"</RcvData> <!-- in Flits -->\n",
indent+4, "", pPortCounters->portRcvData);
XmlPrintDec64("RcvPkts", pPortCounters->portRcvPkts, indent+4);
XmlPrintDec64("MulticastXmitPkts", pPortCounters->portMulticastXmitPkts, indent+4);
XmlPrintDec64("MulticastRcvPkts", pPortCounters->portMulticastRcvPkts, indent+4);
// Signal Integrity and Node/Link Stability
XmlPrintDec("LinkQualityIndicator", pPortCounters->lq.s.linkQualityIndicator, indent+4);
XmlPrintDec("UncorrectableErrors", pPortCounters->uncorrectableErrors, indent+4); // 8 bit
XmlPrintDec("LinkDowned", pPortCounters->linkDowned, indent+4); // 32 bit
XmlPrintDec64("RcvErrors", pPortCounters->portRcvErrors, indent+4);
XmlPrintDec64("ExcessiveBufferOverruns", pPortCounters->excessiveBufferOverruns, indent+4);
XmlPrintDec64("FMConfigErrors", pPortCounters->fmConfigErrors, indent+4);
XmlPrintDec("LinkErrorRecovery", pPortCounters->linkErrorRecovery, indent+4); // 32 bit
XmlPrintDec64("LocalLinkIntegrityErrors", pPortCounters->localLinkIntegrityErrors, indent+4);
XmlPrintDec64("RcvRemotePhysicalErrors", pPortCounters->portRcvRemotePhysicalErrors, indent+4);
// Security
XmlPrintDec64("XmitConstraintErrors", pPortCounters->portXmitConstraintErrors, indent+4);
XmlPrintDec64("RcvConstraintErrors", pPortCounters->portRcvConstraintErrors, indent+4);
// Routing or Down nodes still being sent to
XmlPrintDec64("RcvSwitchRelayErrors", pPortCounters->portRcvSwitchRelayErrors, indent+4);
XmlPrintDec64("XmitDiscards", pPortCounters->portXmitDiscards, indent+4);
// Congestion
XmlPrintDec64("CongDiscards", pPortCounters->swPortCongestion, indent+4);
XmlPrintDec64("RcvFECN", pPortCounters->portRcvFECN, indent+4);
XmlPrintDec64("RcvBECN", pPortCounters->portRcvBECN, indent+4);
XmlPrintDec64("MarkFECN", pPortCounters->portMarkFECN, indent+4);
XmlPrintDec64("XmitTimeCong", pPortCounters->portXmitTimeCong, indent+4);
XmlPrintDec64("XmitWait", pPortCounters->portXmitWait, indent+4);
// Bubbles
XmlPrintDec64("XmitWastedBW", pPortCounters->portXmitWastedBW, indent+4);
XmlPrintDec64("XmitWaitData", pPortCounters->portXmitWaitData, indent+4);
XmlPrintDec64("RcvBubble", pPortCounters->portRcvBubble, indent+4);
printf("%*s</Performance>\n", indent, "");
break;
default:
break;
}
}
void ShowPortLinkDownReasonLog(PortData *portp, Format_t format, int indent, int detail)
{
int i, idx = STL_LINKDOWN_REASON_LAST_INDEX(portp->LinkDownReasons);
if (idx == -1) return;
STL_LINKDOWN_REASON *ldr = &portp->LinkDownReasons[idx];
for (i = 0; i < STL_NUM_LINKDOWN_REASONS; ++i) {
if (ldr->Timestamp == 0) break;
switch (format) {
case FORMAT_TEXT:
printf("%*s", indent, "");
if (ldr->LinkDownReason)
printf("LinkDownReasonLog: %s ", StlLinkDownReasonToText(ldr->LinkDownReason));
if (ldr->NeighborLinkDownReason)
printf("NeighborLinkDownReasonLog: %s", StlLinkDownReasonToText(ldr->NeighborLinkDownReason));
printf("\n%*sTimestamp: %s", indent+4, "", ctime((time_t *)&ldr->Timestamp)); // ctime ends in '\n'
break;
case FORMAT_XML:
printf("%*s<LinkDownReasonLog idx=\"%u\">\n", indent, "", idx);
XmlPrintDec("LinkDownReason", ldr->LinkDownReason, indent+4);
XmlPrintDec("NeighborLinkDownReason", ldr->NeighborLinkDownReason, indent+4);
XmlPrintDec64("Timestamp", ldr->Timestamp, indent+4);
printf("%*s</LinkDownReasonLog>\n", indent, "");
break;
default:
return;
}
if (idx == 0) idx = STL_NUM_LINKDOWN_REASONS;
idx--;
ldr = &portp->LinkDownReasons[idx];
}
}
// output verbose summary of an STL Port
void ShowPortSummary(PortData *portp, Format_t format, int indent, int detail)
{
STL_PORT_INFO *pPortInfo = &portp->PortInfo;
char buf1[SHOW_BUF_SIZE], buf2[SHOW_BUF_SIZE], buf3[SHOW_BUF_SIZE], buf4[SHOW_BUF_SIZE];
switch (format) {
case FORMAT_TEXT:
if (portp->PortGUID)
if (g_persist || g_hard)
printf("%*sPortNum: %3u LID: xxxxxxxxxx GUID: 0x%016"PRIx64"\n",
indent, "", portp->PortNum, portp->PortGUID);
else
printf("%*sPortNum: %3u LID: 0x%.*x GUID: 0x%016"PRIx64"\n",
indent, "", portp->PortNum,
(portp->EndPortLID <= IB_MAX_UCAST_LID ? 4:8),
portp->EndPortLID, portp->PortGUID);
else
printf("%*sPortNum: %3u\n",
indent, "", portp->PortNum);
{
PortSelector* portselp = GetPortSelector(portp);
if (portselp && portselp->details) {
printf("%*sPortDetails: %s\n", indent+4, "", portselp->details);
}
}
if (portp->neighbor) {
ShowLinkPortSummary(portp->neighbor, "Neighbor: ", format, indent+4, detail);
if (detail-1)
ShowExpectedLinkSummary(portp->neighbor->elinkp, format, indent+8, detail-1);
}
if (detail) {
if (g_hard) {
printf( "%*sLocalPort: %-3d PortState: xxxxxx PhysState: xxxxxxxx\n",
indent+4, "", pPortInfo->LocalPortNum);
printf( "%*sNeighborNormal: x\n", indent+4, "");
}
else {
uint8 ldr = 0;
if (pPortInfo->LinkDownReason)
ldr = pPortInfo->LinkDownReason;
else if (pPortInfo->NeighborLinkDownReason)
ldr = pPortInfo->NeighborLinkDownReason;
// SM will have cleared ldr for ports in Armed and Active
if (pPortInfo->PortStates.s.PortState == IB_PORT_INIT
&& pPortInfo->s3.LinkInitReason) {
printf( "%*sLocalPort: %-3d PortState: %-6s (%-13s) PhysState: %-8s\n",
indent+4, "",
pPortInfo->LocalPortNum,
IbPortStateToText(pPortInfo->PortStates.s.PortState),
StlLinkInitReasonToText(pPortInfo->s3.LinkInitReason),
StlPortPhysStateToText(pPortInfo->PortStates.s.PortPhysicalState));
} else if (pPortInfo->PortStates.s.PortState == IB_PORT_DOWN && ldr && ! g_persist) {
printf( "%*sLocalPort: %-3d PortState: %-6s (%-13s) PhysState: %-8s\n",
indent+4, "",
pPortInfo->LocalPortNum,
IbPortStateToText(pPortInfo->PortStates.s.PortState),
StlLinkDownReasonToText(ldr),
StlPortPhysStateToText(pPortInfo->PortStates.s.PortPhysicalState));
} else {
printf( "%*sLocalPort: %-3d PortState: %-6s PhysState: %-8s\n",
indent+4, "",
pPortInfo->LocalPortNum,
IbPortStateToText(pPortInfo->PortStates.s.PortState),
StlPortPhysStateToText(pPortInfo->PortStates.s.PortPhysicalState));
}
if (pPortInfo->PortStates.s.PortPhysicalState == STL_PORT_PHYS_OFFLINE
|| pPortInfo->PortStates.s.PortPhysicalState == IB_PORT_PHYS_DISABLED)
printf("%*sOfflineDisabledReason: %-14s\n",
indent+4, "",
StlPortOfflineDisabledReasonToText(pPortInfo->PortStates.s.OfflineDisabledReason));
printf( "%*sIsSMConfigurationStarted: %-5s NeighborNormal: %-5s\n",
indent+4, "",
pPortInfo->PortStates.s.IsSMConfigurationStarted?"True":"False",
pPortInfo->PortStates.s.NeighborNormal?"True":"False");
}
printf("%*sPortType: %-3s\n", indent+4, "", StlPortTypeToText(pPortInfo->PortPhysConfig.s.PortType));
printf("%*sBundleNextPort: %-3u BundleLane: %-3u\n", indent+4, "",
pPortInfo->BundleNextPort,
pPortInfo->BundleLane);
if (g_hard) {
printf( "%*sLID: xxxxxxxxxx LMC: x Subnet: xxxxxxxxxxxxxxxxxx\n",
indent+4, "");
printf( "%*sSMLID: xxxxxxxxxx SMSL: xx RespTimeout: xxxxxxx",
indent+4, "");
printf( " SubnetTimeout: xxxxxxx\n");
} else if (g_persist) {
printf( "%*sLID: xxxxxxxxxx LMC: %u Subnet: 0x%016"PRIx64"\n",
indent+4, "",
pPortInfo->s1.LMC,
pPortInfo->SubnetPrefix);
FormatTimeoutMult(buf1, pPortInfo->Resp.TimeValue);
printf( "%*sSMLID: xxxxxxxxxx SMSL: %2u RespTimeout: %s",
indent+4, "",
pPortInfo->s2.MasterSMSL, buf1);
FormatTimeoutMult(buf1, pPortInfo->Subnet.Timeout);
printf( " SubnetTimeout: %s\n", buf1);
} else {
if (pPortInfo->LID == STL_LID_PERMISSIVE)
printf( "%*sLID: DontCare LMC: %u Subnet: 0x%016"PRIx64"\n",
indent+4, "",
pPortInfo->s1.LMC,
pPortInfo->SubnetPrefix);
else
printf( "%*sLID: 0x%.*x LMC: %u Subnet: 0x%016"PRIx64"\n",
indent+4, "",
(pPortInfo->LID <= IB_MAX_UCAST_LID ? 4:8),
pPortInfo->LID, pPortInfo->s1.LMC,
pPortInfo->SubnetPrefix);
FormatTimeoutMult(buf1, pPortInfo->Resp.TimeValue);
printf( "%*sSMLID: 0x%.*x SMSL: %2u RespTimeout: %s",
indent+4, "",(pPortInfo->MasterSMLID <= IB_MAX_UCAST_LID ? 4:8),
pPortInfo->MasterSMLID, pPortInfo->s2.MasterSMSL, buf1);
FormatTimeoutMult(buf1, pPortInfo->Subnet.Timeout);
printf( " SubnetTimeout: %s\n", buf1);
}
if (g_hard)
printf( "%*sM_KEY: xxxxxxxxxxxxxxxxxx Lease: xxxxxxx Protect: xxxxxxxx\n",
indent+4, "");
else
printf( "%*sM_KEY: 0x%016"PRIx64" Lease: %5u s Protect: %s\n",
indent+4, "",
pPortInfo->M_Key, pPortInfo->M_KeyLeasePeriod,
IbMKeyProtectToText(pPortInfo->s1.M_KeyProtectBits));
printf("%*sMTU Supported: (0x%x) %s bytes\n",
indent+4, "",
pPortInfo->MTU.Cap,
IbMTUToText(pPortInfo->MTU.Cap));
if (! g_hard)
{
FormatStlVLStalls(buf1, pPortInfo, sizeof(buf1));
printf("%*sVLStallCount (per VL): %s\n", indent+4, "", buf1);
printf("%*sMTU Active by VL:\n", indent+4, "");
printf("%*s00:%5s 01:%5s 02:%5s 03:%5s 04:%5s 05:%5s 06:%5s 07:%5s\n",
indent+4, "",
IbMTUToText(GET_STL_PORT_INFO_NeighborMTU(pPortInfo, 0)),
IbMTUToText(GET_STL_PORT_INFO_NeighborMTU(pPortInfo, 1)),
IbMTUToText(GET_STL_PORT_INFO_NeighborMTU(pPortInfo, 2)),
IbMTUToText(GET_STL_PORT_INFO_NeighborMTU(pPortInfo, 3)),
IbMTUToText(GET_STL_PORT_INFO_NeighborMTU(pPortInfo, 4)),
IbMTUToText(GET_STL_PORT_INFO_NeighborMTU(pPortInfo, 5)),
IbMTUToText(GET_STL_PORT_INFO_NeighborMTU(pPortInfo, 6)),
IbMTUToText(GET_STL_PORT_INFO_NeighborMTU(pPortInfo, 7)));
printf("%*s08:%5s 09:%5s 10:%5s 11:%5s 12:%5s 13:%5s 14:%5s 15:%5s\n",
indent+4, "",
IbMTUToText(GET_STL_PORT_INFO_NeighborMTU(pPortInfo, 8)),
IbMTUToText(GET_STL_PORT_INFO_NeighborMTU(pPortInfo, 9)),
IbMTUToText(GET_STL_PORT_INFO_NeighborMTU(pPortInfo, 10)),
IbMTUToText(GET_STL_PORT_INFO_NeighborMTU(pPortInfo, 11)),
IbMTUToText(GET_STL_PORT_INFO_NeighborMTU(pPortInfo, 12)),
IbMTUToText(GET_STL_PORT_INFO_NeighborMTU(pPortInfo, 13)),
IbMTUToText(GET_STL_PORT_INFO_NeighborMTU(pPortInfo, 14)),
IbMTUToText(GET_STL_PORT_INFO_NeighborMTU(pPortInfo, 15)));
printf("%*s16:%5s 17:%5s 18:%5s 19:%5s 20:%5s 21:%5s 22:%5s 23:%5s\n",
indent+4, "",
IbMTUToText(GET_STL_PORT_INFO_NeighborMTU(pPortInfo, 16)),
IbMTUToText(GET_STL_PORT_INFO_NeighborMTU(pPortInfo, 17)),
IbMTUToText(GET_STL_PORT_INFO_NeighborMTU(pPortInfo, 18)),
IbMTUToText(GET_STL_PORT_INFO_NeighborMTU(pPortInfo, 19)),
IbMTUToText(GET_STL_PORT_INFO_NeighborMTU(pPortInfo, 20)),
IbMTUToText(GET_STL_PORT_INFO_NeighborMTU(pPortInfo, 21)),
IbMTUToText(GET_STL_PORT_INFO_NeighborMTU(pPortInfo, 22)),
IbMTUToText(GET_STL_PORT_INFO_NeighborMTU(pPortInfo, 23)));
printf("%*s24:%5s 25:%5s 26:%5s 27:%5s 28:%5s 29:%5s 30:%5s 31:%5s\n",
indent+4, "",
IbMTUToText(GET_STL_PORT_INFO_NeighborMTU(pPortInfo, 24)),
IbMTUToText(GET_STL_PORT_INFO_NeighborMTU(pPortInfo, 25)),
IbMTUToText(GET_STL_PORT_INFO_NeighborMTU(pPortInfo, 26)),
IbMTUToText(GET_STL_PORT_INFO_NeighborMTU(pPortInfo, 27)),
IbMTUToText(GET_STL_PORT_INFO_NeighborMTU(pPortInfo, 28)),
IbMTUToText(GET_STL_PORT_INFO_NeighborMTU(pPortInfo, 29)),
IbMTUToText(GET_STL_PORT_INFO_NeighborMTU(pPortInfo, 30)),
IbMTUToText(GET_STL_PORT_INFO_NeighborMTU(pPortInfo, 31)));
}
if (g_hard)
printf( "%*sLinkWidth: Active: xxxx Supported: %7s Enabled: xxxxxxx\n",
indent+4, "",
StlLinkWidthToText(pPortInfo->LinkWidth.Supported, buf1, sizeof(buf1)));
else
printf( "%*sLinkWidth: Active: %4s Supported: %7s Enabled: %7s\n",
indent+4, "",
StlLinkWidthToText(pPortInfo->LinkWidth.Active, buf1, sizeof(buf1)),
StlLinkWidthToText(pPortInfo->LinkWidth.Supported, buf2, sizeof(buf2)),
StlLinkWidthToText(pPortInfo->LinkWidth.Enabled, buf3, sizeof(buf3)));
if (g_hard)
printf( "%*sLinkWidthDnGrade: Active: Tx: xx Rx: xx Supported: %7s Enabled: xxxxxxx\n",
indent+4, "",
StlLinkWidthToText(pPortInfo->LinkWidthDowngrade.Supported, buf1, sizeof(buf1)));
else
printf( "%*sLinkWidthDnGrade: ActiveTx: %2.2s Rx: %2.2s Supported: %7s Enabled: %7s\n",
indent+4, "",
StlLinkWidthToText(pPortInfo->LinkWidthDowngrade.TxActive, buf1, sizeof(buf1)),
StlLinkWidthToText(pPortInfo->LinkWidthDowngrade.RxActive, buf2, sizeof(buf2)),
StlLinkWidthToText(pPortInfo->LinkWidthDowngrade.Supported, buf3, sizeof(buf3)),
StlLinkWidthToText(pPortInfo->LinkWidthDowngrade.Enabled, buf4, sizeof(buf4)));
if (g_hard)
printf("%*sPortLinkMode: Active: xxxx Supported: %-16s Enabled: xxxx\n",
indent+4, "",
StlPortLinkModeToText(pPortInfo->PortLinkMode.s.Supported, buf1, sizeof(buf1)));
else
printf("%*sPortLinkMode: Active: %-8s Supported: %-16s Enabled: %-8s\n",
indent+4, "",
StlPortLinkModeToText(pPortInfo->PortLinkMode.s.Active, buf1, sizeof(buf1)),
StlPortLinkModeToText(pPortInfo->PortLinkMode.s.Supported, buf2, sizeof(buf2)),
StlPortLinkModeToText(pPortInfo->PortLinkMode.s.Enabled, buf3, sizeof(buf3)));
if (g_hard)
printf("%*sPortLTPCRCMode: Act: xxxx Sup: %-21s En: xxxx\n",
indent+4, "",
StlPortLtpCrcModeToText(pPortInfo->PortLTPCRCMode.s.Supported, buf1, sizeof(buf1)));
else
printf("%*sPortLTPCRCMode: Act: %-6s Sup: %-21s En: %-21s\n",
indent+4, "",
StlPortLtpCrcModeToText(pPortInfo->PortLTPCRCMode.s.Active, buf1, sizeof(buf1)),
StlPortLtpCrcModeToText(pPortInfo->PortLTPCRCMode.s.Supported, buf2, sizeof(buf2)),
StlPortLtpCrcModeToText(pPortInfo->PortLTPCRCMode.s.Enabled, buf3, sizeof(buf3)));
if (g_hard)
printf( "%*sLinkSpeed: Active: xxxxxxx Supported: %10s Enabled: xxxxxxxxxx\n",
indent+4, "",
StlLinkSpeedToText(pPortInfo->LinkSpeed.Supported, buf1, sizeof(buf1)));
else
printf( "%*sLinkSpeed: Active: %7s Supported: %10s Enabled: %10s\n",
indent+4, "",
StlLinkSpeedToText(pPortInfo->LinkSpeed.Active, buf1, sizeof(buf1)),
StlLinkSpeedToText(pPortInfo->LinkSpeed.Supported, buf2, sizeof(buf2)),
StlLinkSpeedToText(pPortInfo->LinkSpeed.Enabled, buf3, sizeof(buf3)));
printf("%*sSM_TrapQP: 0x%x SA_QP: 0x%x IPAddr Prim/Sec: %s / %s\n",
indent+4, "",
pPortInfo->SM_TrapQP.s.QueuePair, pPortInfo->SA_QP.s.QueuePair,
inet_ntop(AF_INET6, pPortInfo->IPAddrIPV6.addr, buf1, sizeof(buf1)),
inet_ntop(AF_INET, pPortInfo->IPAddrIPV4.addr, buf2, sizeof(buf2)));
if (g_hard) {
printf( "%*sVLs: Active: xxxx Supported: %2u+1 HOQLife: xxxxxxxxx\n",
indent+4, "",
pPortInfo->VL.s2.Cap);
} else {
printf( "%*sVLs: Active: %2u+1 Supported: %2u+1 \n",
indent+4, "",
pPortInfo->s4.OperationalVL,
pPortInfo->VL.s2.Cap);
#if 0
if (pPortInfo->XmitQ.HOQLife > IB_LIFETIME_MAX)
{
strncpy(buf1, "Infinite", 9);
} else {
FormatTimeoutMult(buf1, pPortInfo->XmitQ.HOQLife);
}
printf( "%s\n", buf1);
#else
int i;
printf("%*sHOQLife (Per VL):", indent+8, "");
for (i = 0; i < STL_MAX_VLS; i++) {
if (!(i % 5)) printf("\n%*s", indent+8, "");
printf("VL%2d: 0x%x ", i, (uint32)pPortInfo->XmitQ[i].HOQLife);
}
printf("\n\n");
#endif
}
if (pPortInfo->CapabilityMask3.s.VLSchedulingConfig == VL_SCHED_MODE_VLARB) {
if (g_hard) {
printf( "%*sVL Arb Cap: High: %4u Low: %4u HiLimit: xxxx PreemptLimit xxxx\n",
indent+4, "", pPortInfo->VL.ArbitrationHighCap,
pPortInfo->VL.ArbitrationLowCap);
} else {
printf( "%*sVL Arb Cap: High: %4u Low: %4u HiLimit: %4u PreemptLimit %4u\n",
indent+4, "", pPortInfo->VL.ArbitrationHighCap,
pPortInfo->VL.ArbitrationLowCap, pPortInfo->VL.HighLimit,
pPortInfo->VL.PreemptingLimit);
}
}
printf("%*sVLFlowControlDisabledMask: 0x%08x\n", indent+4, "", pPortInfo->FlowControlMask);
printf("%*sNeighborMode MgmtAllowed: %3s FwAuthenBypass: %3s NeighborNodeType: %s\n",
indent+4, "",
pPortInfo->PortNeighborMode.MgmtAllowed?"Yes":"No",
pPortInfo->PortNeighborMode.NeighborFWAuthenBypass?"On":"Off",
OpaNeighborNodeTypeToText(pPortInfo->PortNeighborMode.NeighborNodeType));
FormatStlCapabilityMask(buf1, pPortInfo->CapabilityMask);
printf( "%*sCapability 0x%08x: %s\n",
indent+4, "",
pPortInfo->CapabilityMask.AsReg32, buf1);
FormatStlCapabilityMask3(buf1, pPortInfo->CapabilityMask3, sizeof(buf1));
printf("%*sCapability3 0x%04x: %s\n",
indent+4, "",
pPortInfo->CapabilityMask3.AsReg16, buf1);
if (g_persist || g_hard)
printf( "%*sViolations: M_Key: xxxxx P_Key: xxxxx Q_Key: xxxxx\n",
indent+4, "");
else
printf( "%*sViolations: M_Key: %5u P_Key: %5u Q_Key: %5u\n",
indent+4, "",
pPortInfo->Violations.M_Key, pPortInfo->Violations.P_Key,
pPortInfo->Violations.Q_Key);
if (g_hard)
printf("%*sPortMode ActiveOptimize xxxxx PassThrough: xxxxx VLMarker: xxxxx\n",
indent+4, "");
else
printf("%*sPortMode ActiveOptimize: %3s PassThrough: %3s VLMarker: %3s\n",
indent+4, "",
pPortInfo->PortMode.s.IsActiveOptimizeEnabled?"On":"Off",
pPortInfo->PortMode.s.IsPassThroughEnabled?"On":"Off",
pPortInfo->PortMode.s.IsVLMarkerEnabled?"On":"Off");
if (g_hard) {
printf("%*sFlitCtrlInterleave Distance Max: %2u Enabled: xxxxx\n",
indent, "", pPortInfo->FlitControl.Interleave.s.DistanceSupported);
printf("%*sMaxNestLevelTxEnabled: xxxx MaxNestLevelRxSupported: %u\n",
indent+4, "",
pPortInfo->FlitControl.Interleave.s.MaxNestLevelRxSupported);
} else {
printf("%*sFlitCtrlInterleave Distance Max: %2u Enabled: %2u\n",
indent+4, "", pPortInfo->FlitControl.Interleave.s.DistanceSupported,
pPortInfo->FlitControl.Interleave.s.DistanceEnabled);
printf("%*sMaxNestLevelTxEnabled: %u MaxNestLevelRxSupported: %u\n",
indent+4, "",
pPortInfo->FlitControl.Interleave.s.MaxNestLevelTxEnabled,
pPortInfo->FlitControl.Interleave.s.MaxNestLevelRxSupported);
}
if (g_hard) {
printf("%*sSmallPktLimit: xxxx MaxSmallPktLimit: 0x%02x PreemptionLimit: xxxx\n",
indent+4, "",
pPortInfo->FlitControl.Preemption.MaxSmallPktLimit);
} else {
printf("%*sSmallPktLimit: 0x%02x MaxSmallPktLimit: 0x%02x PreemptionLimit: 0x%02x\n",
indent+4, "",
pPortInfo->FlitControl.Preemption.SmallPktLimit,
pPortInfo->FlitControl.Preemption.MaxSmallPktLimit,
pPortInfo->FlitControl.Preemption.PreemptionLimit);
// Convert Flits to bytes and display in decimal
printf("%*sFlitCtrlPreemption MinInital: %"PRIu64" MinTail: %"PRIu64" LargePktLim: 0x%02x\n",
indent+4, "",
(uint64_t)(pPortInfo->FlitControl.Preemption.MinInitial * BYTES_PER_FLIT),
(uint64_t)(pPortInfo->FlitControl.Preemption.MinTail * BYTES_PER_FLIT),
pPortInfo->FlitControl.Preemption.LargePktLimit);
}
if (!g_hard) {
if (pPortInfo->CapabilityMask3.s.IsMAXLIDSupported)
printf("%*sMaxLID: %u\n",
indent+4, "", pPortInfo->MaxLID);
}
if (g_hard)
printf("%*sBufferUnits: VL15Init 0x%04x; VL15CreditRate xxxxxx; CreditAck 0x%x; BufferAlloc 0x%x\n",
indent+4, "",
pPortInfo->BufferUnits.s.VL15Init,
pPortInfo->BufferUnits.s.CreditAck,
pPortInfo->BufferUnits.s.BufferAlloc);
else
printf("%*sBufferUnits: VL15Init 0x%04x; VL15CreditRate 0x%02x; CreditAck 0x%x; BufferAlloc 0x%x\n",
indent+4, "",
pPortInfo->BufferUnits.s.VL15Init,
pPortInfo->BufferUnits.s.VL15CreditRate,
pPortInfo->BufferUnits.s.CreditAck,
pPortInfo->BufferUnits.s.BufferAlloc);
if (! g_hard)
{
FormatStlPortErrorAction(buf1, pPortInfo, SHOW_BUF_SIZE);
printf("%*sPortErrorActions: 0x%x: %s\n", indent+4, "", pPortInfo->PortErrorAction.AsReg32, buf1);
}
if (!g_persist && !g_hard)
printf("%*sReplayDepth Buffer 0x%02x; Wire 0x%02x\n", indent+4, "",
(pPortInfo->ReplayDepthH.BufferDepthH << 8) | pPortInfo->ReplayDepth.BufferDepth,
(pPortInfo->ReplayDepthH.WireDepthH << 8) | pPortInfo->ReplayDepth.WireDepth);
else
printf("%*sReplayDepth Buffer 0x%02x; Wire xxxx\n", indent+4, "",
(pPortInfo->ReplayDepthH.BufferDepthH << 8) | pPortInfo->ReplayDepth.BufferDepth);
if (g_hard)
printf( "%*sDiagCode: xxxxxx\n", indent+4, "");
else
printf( "%*sDiagCode: 0x%04x\n",
indent+4, "",
pPortInfo->DiagCode.AsReg16);
printf("%*sOverallBufferSpace: 0x%04x\n", indent+4, "",
pPortInfo->OverallBufferSpace);
if (g_hard)
printf( "%*sP_Key Enforcement: In: xxx Out: xxx\n",
indent+4, "");
else
printf( "%*sP_Key Enforcement: In: %3s Out: %3s\n",
indent+4, "",
pPortInfo->s3.PartitionEnforcementInbound?"On":"Off",
pPortInfo->s3.PartitionEnforcementOutbound?"On":"Off");
if (detail > 1) {
ShowPortLinkDownReasonLog(portp, format, indent+4, detail-2);
}
if ( portp->nodep && portp->pQOS &&
(detail > 1) && !g_persist && !g_hard ) {
if ( portp->pQOS->SL2SCMap ) {
ShowSLSCTable(portp->nodep, portp, format, indent+4, detail-2);
}
if ( portp->pQOS->SC2SLMap ) {
ShowSCSLTable(portp->nodep, portp, format, indent+4, detail-2);
}
int i = 0;
for(i=0; i<SC2SCMAPLIST_MAX; i++) {
if ( !(QListIsEmpty(&portp->pQOS->SC2SCMapList[i])) ) {
ShowSCSCTable(portp->nodep, portp, i, format, indent+4, detail-2);
}
}
}
if (portp->pQOS && (detail > 1) && !g_persist && !g_hard) {
ShowVLArbTable(portp, format, indent+4, detail-2);
}
if ( portp->nodep && portp->pPartitionTable && (detail > 1) &&
!g_persist && !g_hard ) {
ShowPKeyTable(portp->nodep, portp, format, indent+4, detail-2);
}
if (portp->pPortCounters && detail > 2 && ! g_persist && ! g_hard) {
ShowPortCounters(portp->pPortCounters, format, indent+4, detail-2);
}
} else {
if (g_hard)
printf("%*sWidth: xxxx Speed: xxxxxxx Downgraded? xxx\n",
indent+4, "");
else
printf("%*sWidth: %4s Speed: %7s Downgraded? %s\n",
indent+4, "",
StlLinkWidthToText(pPortInfo->LinkWidth.Active, buf1, sizeof(buf1)),
StlLinkSpeedToText(pPortInfo->LinkSpeed.Active, buf2, sizeof(buf2)),
((pPortInfo->LinkWidth.Active == pPortInfo->LinkWidthDowngrade.TxActive) &&
(pPortInfo->LinkWidth.Active == pPortInfo->LinkWidthDowngrade.RxActive))?
" No": "Yes");
}
if (detail && portp->pCableInfoData)
ShowCableSummary(portp->pCableInfoData, FORMAT_TEXT, indent+4, detail, pPortInfo->PortPhysConfig.s.PortType);
break;
case FORMAT_XML:
printf("%*s<PortInfo id=\"0x%016"PRIx64":%u\">\n", indent, "",
portp->nodep->NodeInfo.NodeGUID, portp->PortNum);
XmlPrintDec("PortNum", portp->PortNum, indent+4);
if (portp->PortGUID) {
if (! (g_persist || g_hard))
XmlPrintLID("LID", portp->EndPortLID,
indent+4);
XmlPrintHex64("GUID", portp->PortGUID, indent+4);
}
{
PortSelector* portselp = GetPortSelector(portp);
if (portselp && portselp->details) {
XmlPrintOptionalStr("PortDetails", portselp->details, indent+4);
}
}
if (portp->neighbor) {
printf("%*s<Neighbor>\n", indent+4, "");
ShowLinkPortSummary(portp->neighbor, "Neighbor: ", format, indent+8, detail);
if (detail-1)
ShowExpectedLinkSummary(portp->neighbor->elinkp, format, indent+12, detail-1);
printf("%*s</Neighbor>\n", indent+4, "");
}
if (detail) {
if (g_hard) {
// noop
XmlPrintDec("LocalPort", pPortInfo->LocalPortNum, indent+4);
XmlPrintStr("PortType", StlPortTypeToText(pPortInfo->PortPhysConfig.s.PortType), indent+4);
XmlPrintHex("PortType_Int", pPortInfo->PortPhysConfig.s.PortType, indent+4);
} else {
XmlPrintDec("LocalPort", pPortInfo->LocalPortNum, indent+4);
XmlPrintStr("PortState",
IbPortStateToText(pPortInfo->PortStates.s.PortState), indent+4);
XmlPrintDec("PortState_Int",
pPortInfo->PortStates.s.PortState, indent+4);
if (pPortInfo->PortStates.s.PortState == IB_PORT_INIT) {
XmlPrintStr("InitReason",
StlLinkInitReasonToText(pPortInfo->s3.LinkInitReason), indent+4);
XmlPrintDec("InitReason_Int",
pPortInfo->s3.LinkInitReason, indent+4);
}
XmlPrintStr("PortType", StlPortTypeToText(pPortInfo->PortPhysConfig.s.PortType), indent+4);
XmlPrintHex("PortType_Int", pPortInfo->PortPhysConfig.s.PortType, indent+4);
XmlPrintStr("PhysState",
StlPortPhysStateToText(pPortInfo->PortStates.s.PortPhysicalState),
indent+4);
XmlPrintDec("PhysState_Int",
pPortInfo->PortStates.s.PortPhysicalState, indent+4);
XmlPrintStr("IsSMConfigurationStarted", pPortInfo->PortStates.s.IsSMConfigurationStarted?"True":"False", indent+4);
XmlPrintStr("NeighborNormal", pPortInfo->PortStates.s.NeighborNormal?"True":"False", indent+4);
if (pPortInfo->PortStates.s.PortPhysicalState == STL_PORT_PHYS_OFFLINE
|| pPortInfo->PortStates.s.PortPhysicalState == IB_PORT_PHYS_DISABLED) {
XmlPrintStr("OfflineDisabledReason",
StlPortOfflineDisabledReasonToText(pPortInfo->PortStates.s.OfflineDisabledReason),
indent+4);
XmlPrintDec("OfflineDisabledReason_Int",
pPortInfo->PortStates.s.OfflineDisabledReason, indent+4);
}
}
if (g_hard) {
// noop
} else {
if (! g_persist)
XmlPrintLID("LID", pPortInfo->LID, indent+4);
XmlPrintDec("LMC", pPortInfo->s1.LMC, indent+4);
XmlPrintHex64("SubnetPrefix", pPortInfo->SubnetPrefix, indent+4);
if (! g_persist)
XmlPrintLID("SMLID", pPortInfo->MasterSMLID, indent+4);
XmlPrintDec("SMSL", pPortInfo->s2.MasterSMSL, indent+4);
FormatTimeoutMult(buf1, pPortInfo->Resp.TimeValue);
XmlPrintStr("RespTimeout", buf1, indent+4);
XmlPrintDec("RespTimeout_Int", pPortInfo->Resp.TimeValue,
indent+4);
FormatTimeoutMult(buf1, pPortInfo->Subnet.Timeout);
XmlPrintStr("SubnetTimeout", buf1, indent+4);
XmlPrintDec("SubnetTimeout_Int", pPortInfo->Subnet.Timeout,
indent+4);
}
if (g_hard) {
// noop
} else {
XmlPrintHex64("M_KEY", pPortInfo->M_Key, indent+4);
printf("%*s<Lease>%u</Lease> <!-- seconds -->\n",
indent+4, "",
pPortInfo->M_KeyLeasePeriod);
XmlPrintStr("Protect",
IbMKeyProtectToText(pPortInfo->s1.M_KeyProtectBits),
indent+4);
XmlPrintDec("Protect_Int",
pPortInfo->s1.M_KeyProtectBits, indent+4);
}
XmlPrintDec("MTUSupported",
GetBytesFromMtu(pPortInfo->MTU.Cap), indent+4);
if (! g_hard)
{
int i;
char indxStr[5];
printf("%*s<ActiveMTU>\n", indent+4, "");
for (i = 0; i < STL_MAX_VLS; ++i)
{
snprintf(indxStr, sizeof(indxStr), "VL%u", i);
XmlPrintDec(indxStr, GetBytesFromMtu(GET_STL_PORT_INFO_NeighborMTU(pPortInfo, i)), indent+8);
}
printf("%*s</ActiveMTU>\n", indent+4, "");
}
if (! g_hard)
{
int i;
char indxStr[5];
printf("%*s<VLStall>\n", indent+4, "");
for (i = 0; i < STL_MAX_VLS; ++i)
{
snprintf(indxStr, sizeof(indxStr), "VL%u", i);
XmlPrintDec(indxStr, pPortInfo->XmitQ[i].VLStallCount, indent+8);
}
printf("%*s</VLStall>\n", indent+4, "");
}
if (! g_hard) {
XmlPrintLinkWidth("LinkWidthActive",
pPortInfo->LinkWidth.Active, indent+4);
}
XmlPrintLinkWidth("LinkWidthSupported",
pPortInfo->LinkWidth.Supported, indent+4);
if (! g_hard) {
XmlPrintLinkWidth("LinkWidthEnabled",
pPortInfo->LinkWidth.Enabled, indent+4);
}
if (! g_hard) {
XmlPrintLinkWidth("LinkWidthDnGradeTxActive",
pPortInfo->LinkWidthDowngrade.TxActive, indent+4);
XmlPrintLinkWidth("LinkWidthDnGradeRxActive",
pPortInfo->LinkWidthDowngrade.RxActive, indent+4);
}
XmlPrintLinkWidth("LinkWidthDnGradeSupported",
pPortInfo->LinkWidthDowngrade.Supported, indent+4);
if (! g_hard) {
XmlPrintLinkWidth("LinkWidthDnGradeEnabled",
pPortInfo->LinkWidthDowngrade.Enabled, indent+4);
}
if (! g_hard) {
XmlPrintLinkSpeed("LinkSpeedActive",
pPortInfo->LinkSpeed.Active, indent+4);
}
XmlPrintLinkSpeed("LinkSpeedSupported",
pPortInfo->LinkSpeed.Supported, indent+4);
if (! g_hard) {
XmlPrintLinkSpeed("LinkSpeedEnabled",
pPortInfo->LinkSpeed.Enabled, indent+4);
}
if (! g_hard) {
XmlPrintStr("PortLinkModeActive",
StlPortLinkModeToText(pPortInfo->PortLinkMode.s.Active,
buf1, sizeof(buf1)), indent+4);
}
XmlPrintStr("PortLinkModeSupported",
StlPortLinkModeToText(pPortInfo->PortLinkMode.s.Supported,
buf1, sizeof(buf1)), indent+4);
if (! g_hard) {
XmlPrintStr("PortLinkModeEnabled",
StlPortLinkModeToText(pPortInfo->PortLinkMode.s.Enabled,
buf1, sizeof(buf1)), indent+4);
}
if (! g_hard) {
XmlPrintPortLtpCrc("PortLTPCRCModeActive",
pPortInfo->PortLTPCRCMode.s.Active, indent+4);
}
XmlPrintPortLtpCrc("PortLTPCRCModeSupported",
pPortInfo->PortLTPCRCMode.s.Supported, indent+4);
if (! g_hard) {
XmlPrintPortLtpCrc("PortLTPCRCModeEnabled",
pPortInfo->PortLTPCRCMode.s.Enabled, indent+4);
}
XmlPrintDec("SM_TrapQP", pPortInfo->SM_TrapQP.s.QueuePair, indent+4);
XmlPrintDec("SA_QP", pPortInfo->SA_QP.s.QueuePair, indent+4);
XmlPrintStr("IPV6", inet_ntop(AF_INET6, pPortInfo->IPAddrIPV6.addr, buf1, sizeof(buf1)), indent+4);
XmlPrintStr("IPV4", inet_ntop(AF_INET, pPortInfo->IPAddrIPV4.addr, buf2, sizeof(buf2)), indent+4);
if (! g_hard) {
printf( "%*s<VLsActive>%u+1</VLsActive>\n",
indent+4, "",
pPortInfo->s4.OperationalVL);
XmlPrintDec("VLsActive_Int",
pPortInfo->s4.OperationalVL, indent+4);
}
printf( "%*s<VLsSupported>%u+1</VLsSupported>\n",
indent+4, "",
pPortInfo->VL.s2.Cap);
XmlPrintDec("VLsSupported_Int",
pPortInfo->VL.s2.Cap, indent+4);
if (! g_hard)
{
int i;
char indxStr[5];
printf("%*s<HOQLife>\n", indent+4, "");
for (i = 0; i < STL_MAX_VLS; ++i)
{
snprintf(indxStr, sizeof(indxStr), "VL%u", i);
if (pPortInfo->XmitQ[i].HOQLife > IB_LIFETIME_MAX)
{
strncpy(buf1, "Infinite", 9);
} else {
FormatTimeoutMult(buf1, pPortInfo->XmitQ[i].HOQLife);
}
XmlPrintStr(indxStr, buf1, indent+8);
}
printf("%*s</HOQLife>\n", indent+4, "");
printf("%*s<HOQLife_Int>\n", indent+4, "");
for (i = 0; i < STL_MAX_VLS; ++i)
{
snprintf(indxStr, sizeof(indxStr), "VL%u", i);
if (pPortInfo->XmitQ[i].HOQLife > IB_LIFETIME_MAX)
{
strncpy(buf1, "Infinite", 9);
} else {
FormatTimeoutMult(buf1, pPortInfo->XmitQ[i].HOQLife);
}
XmlPrintDec(indxStr, pPortInfo->XmitQ[i].HOQLife, indent+8);
}
printf("%*s</HOQLife_Int>\n", indent+4, "");
}
if (pPortInfo->CapabilityMask3.s.VLSchedulingConfig == VL_SCHED_MODE_VLARB) {
XmlPrintDec("VLArbHighCap", pPortInfo->VL.ArbitrationHighCap,
indent+4);
XmlPrintDec("VLArbLowCap", pPortInfo->VL.ArbitrationLowCap,
indent+4);
if (! g_hard) {
XmlPrintDec("VLArbHighLimit", pPortInfo->VL.HighLimit,
indent+4);
XmlPrintDec("VLArbPreemptLimit", pPortInfo->VL.PreemptingLimit,
indent+4);
}
}
XmlPrintHex32("VLFlowControlDisabledMask", pPortInfo->FlowControlMask, indent+4);
XmlPrintStr("NeighborModeMgmntAllowed", pPortInfo->PortNeighborMode.MgmtAllowed?"Yes":"No", indent+4);
XmlPrintStr("NeighborModeFWAuthenBypass", pPortInfo->PortNeighborMode.NeighborFWAuthenBypass?"Yes":"No", indent+4);
XmlPrintStr("NeighborModeNeighborNodeType",
OpaNeighborNodeTypeToText(pPortInfo->PortNeighborMode.NeighborNodeType),
indent+4);
FormatStlCapabilityMask(buf1, pPortInfo->CapabilityMask);
XmlPrintHex32("CapabilityMask",
pPortInfo->CapabilityMask.AsReg32,
indent+4);
XmlPrintStr("Capability", buf1, indent+4);
XmlPrintHex16("CapabilityMask3", pPortInfo->CapabilityMask3.AsReg16, indent+4);
FormatStlCapabilityMask3(buf1, pPortInfo->CapabilityMask3, sizeof(buf1));
XmlPrintStr("Capability3", buf1, indent+4);
if (g_persist || g_hard) {
// noop
} else {
XmlPrintDec("ViolationsM_Key",
pPortInfo->Violations.M_Key, indent+4);
XmlPrintDec("ViolationsP_Key",
pPortInfo->Violations.P_Key, indent+4);
XmlPrintDec("ViolationsQ_Key",
pPortInfo->Violations.Q_Key, indent+4);
}
if (g_hard) {
// noop
} else {
XmlPrintHex16( "DiagCode", pPortInfo->DiagCode.AsReg16, indent+4);
}
XmlPrintHex16("OverallBufferSpace", pPortInfo->OverallBufferSpace, indent+4);
if (! g_hard && ! g_persist) {
XmlPrintHex8("LinkDownReason", pPortInfo->LinkDownReason, indent+4);
XmlPrintHex8("NeighborLinkDownReason", pPortInfo->NeighborLinkDownReason, indent+4);
}
if (! g_hard ) {
XmlPrintStr("ActiveOptimize", pPortInfo->PortMode.s.IsActiveOptimizeEnabled?"On":"Off", indent+4);
XmlPrintStr("PassThrough", pPortInfo->PortMode.s.IsPassThroughEnabled?"On":"Off", indent+4);
XmlPrintStr("VLMarker", pPortInfo->PortMode.s.IsVLMarkerEnabled?"On":"Off", indent+4);
}
XmlPrintDec("FlitCtrlInterleaveDistanceMax", pPortInfo->FlitControl.Interleave.s.DistanceSupported,indent+4);
if (! g_hard) {
XmlPrintDec("MaxNestLevelRxSupported", pPortInfo->FlitControl.Interleave.s.MaxNestLevelRxSupported,indent+4);
XmlPrintDec("FlitControlInterleaveDistance", pPortInfo->FlitControl.Interleave.s.DistanceEnabled, indent+4);
}
XmlPrintDec("SmallPktLimitMax", pPortInfo->FlitControl.Preemption.MaxSmallPktLimit, indent+4);
if (! g_hard) {
XmlPrintDec("SmallPktLimit", pPortInfo->FlitControl.Preemption.SmallPktLimit, indent+4);
XmlPrintDec("PreemptionLimit", pPortInfo->FlitControl.Preemption.PreemptionLimit, indent+4);
// Convert Flits to bytes and display in decimal
XmlPrintDec("MinInitial", pPortInfo->FlitControl.Preemption.MinInitial, indent+4);
// Convert Flits to bytes and display in decimal
XmlPrintDec("MinTail", (pPortInfo->FlitControl.Preemption.MinTail * BYTES_PER_FLIT), indent+4);
XmlPrintDec("LargePktLimit", (pPortInfo->FlitControl.Preemption.LargePktLimit * BYTES_PER_FLIT), indent+4);
}
if (! g_hard ) {
if(pPortInfo->CapabilityMask3.s.IsMAXLIDSupported)
XmlPrintLID("MaxLID", pPortInfo->MaxLID, indent+4);
}
if (! g_hard )
XmlPrintHex32("PortErrorAction", pPortInfo->PortErrorAction.AsReg32, indent+4);
XmlPrintHex16("VL15Init", pPortInfo->BufferUnits.s.VL15Init, indent+4);
XmlPrintHex8("CreditAck", pPortInfo->BufferUnits.s.CreditAck, indent+4);
XmlPrintHex8("BufferAlloc", pPortInfo->BufferUnits.s.BufferAlloc, indent+4);
XmlPrintHex16("ReplayDepthBuffer", (pPortInfo->ReplayDepthH.BufferDepthH << 8) | pPortInfo->ReplayDepth.BufferDepth, indent+4);
if (!g_persist && !g_hard)
XmlPrintHex16("ReplayDepthWire", (pPortInfo->ReplayDepthH.WireDepthH << 8) | pPortInfo->ReplayDepth.WireDepth, indent+4);
if (! g_hard) {
XmlPrintHex8("VL15CreditRate", pPortInfo->BufferUnits.s.VL15CreditRate, indent+4);
}
if (! g_hard) {
XmlPrintStr( "P_KeyEnforcementInbound",
pPortInfo->s3.PartitionEnforcementInbound?"On":"Off",
indent+4);
XmlPrintDec( "P_KeyEnforcementInbound_Int",
pPortInfo->s3.PartitionEnforcementInbound,
indent+4);
XmlPrintStr("P_KeyEnforcementOutbound",
pPortInfo->s3.PartitionEnforcementOutbound?"On":"Off",
indent+4);
XmlPrintDec("P_KeyEnforcementOutbound_Int",
pPortInfo->s3.PartitionEnforcementOutbound,
indent+4);
}
if (detail > 1) {
ShowPortLinkDownReasonLog(portp, format, indent+4, detail-2);
}
if ( portp->nodep && portp->pQOS &&
(detail > 1) && !g_persist && !g_hard ) {
if ( portp->pQOS->SL2SCMap ) {
ShowSLSCTable(portp->nodep, portp, format, indent+8, detail-2);
}
if ( portp->pQOS->SC2SLMap ) {
ShowSCSLTable(portp->nodep, portp, format, indent+8, detail-2);
}
int i = 0;
for(i=0; i<SC2SCMAPLIST_MAX; i++) {
if ( !(QListIsEmpty(&portp->pQOS->SC2SCMapList[i])) ) {
ShowSCSCTable(portp->nodep, portp, i, format, indent+8, detail-2);
}
}
}
if (portp->pQOS && (detail > 1) && !g_persist && !g_hard) {
ShowVLArbTable(portp, format, indent+8, detail-2);
}
if ( portp->nodep && portp->pPartitionTable && (detail > 1) &&
!g_persist && !g_hard ) {
ShowPKeyTable(portp->nodep, portp, format, indent+8, detail-2);
}
if (portp->pPortCounters && detail > 2 && ! g_persist && ! g_hard) {
ShowPortCounters(portp->pPortCounters, format, indent+8, detail-2);
}
} else {
if (! g_hard) {
XmlPrintLinkWidth("LinkWidthActive",
pPortInfo->LinkWidth.Active, indent+4);
XmlPrintLinkSpeed("LinkSpeedActive",
pPortInfo->LinkSpeed.Active, indent+4);
}
}
if (detail && portp->pCableInfoData)
ShowCableSummary(portp->pCableInfoData, FORMAT_XML, indent+4, detail, pPortInfo->PortPhysConfig.s.PortType);
printf("%*s</PortInfo>\n", indent, "");
break;
default:
break;
}
} // End of ShowPortSummary()
// output verbose summary of a IB Node
void ShowNodeSummary(NodeData *nodep, Point *focus, Format_t format, int indent, int detail)
{
cl_map_item_t *p;
char buf1[SHOW_BUF_SIZE], buf2[SHOW_BUF_SIZE];
switch (format) {
case FORMAT_TEXT:
// omit fields which are port specific:
// LID, PortGUID, LocalPortNum
// TBD - is PartitionCap per Port or per Node?
printf("%*sName: %.*s\n",
indent, "",
STL_NODE_DESCRIPTION_ARRAY_SIZE,
g_noname?g_name_marker:(char*)nodep->NodeDesc.NodeString);
printf("%*sNodeGUID: 0x%016"PRIx64" Type: %s\n",
indent+4, "", nodep->NodeInfo.NodeGUID,
StlNodeTypeToText(nodep->NodeInfo.NodeType));
if (nodep->enodep && nodep->enodep->details) {
printf("%*sNodeDetails: %s\n", indent+4, "", nodep->enodep->details);
}
printf("%*sPorts: %d PartitionCap: %d SystemImageGuid: 0x%016"PRIx64"\n",
indent+4, "", nodep->NodeInfo.NumPorts,
nodep->NodeInfo.PartitionCap,
nodep->NodeInfo.SystemImageGUID);
printf("%*sBaseVer: %d SmaVer: %d VendorID: 0x%x DeviceID: 0x%x Rev: 0x%x\n",
indent+4, "", nodep->NodeInfo.BaseVersion,
nodep->NodeInfo.ClassVersion,
nodep->NodeInfo.u1.s.VendorID,
nodep->NodeInfo.DeviceID,
nodep->NodeInfo.Revision);
if (nodep->pSwitchInfo) {
STL_SWITCHINFO_RECORD *pSwitchInfoRecord = nodep->pSwitchInfo;
STL_SWITCH_INFO *pSwitchInfo = &pSwitchInfoRecord->SwitchInfoData;
if (g_persist || g_hard)
printf("%*sLID: xxxxxxxxxx", indent+4, "");
else
printf("%*sLID: 0x%.*x", indent+4, "", (pSwitchInfoRecord->RID.LID <= IB_MAX_UCAST_LID ? 4:8),
pSwitchInfoRecord->RID.LID);
printf( " LinearFDBCap: %5u ",
pSwitchInfo->LinearFDBCap );
if (g_persist || g_hard)
printf("LinearFDBTop: xxxxxxxxxx");
else
printf( "LinearFDBTop: 0x%08x",
pSwitchInfo->LinearFDBTop );
printf( " MCFDBCap: %5u\n",
pSwitchInfo->MulticastFDBCap );
printf("%*sPartEnfCap: %5u ", indent+4, "", pSwitchInfo->PartitionEnforcementCap);
if (g_persist || g_hard) {
printf("U1: 0x%02x PortStateChange: x SwitchLifeTime x\n",
pSwitchInfo->u1.AsReg8);
printf("%*sU2: 0x%02x: %s\n",
indent+4, "",
pSwitchInfo->u2.AsReg8,
pSwitchInfo->u2.s.EnhancedPort0?"E0 ": "");
} else {
printf("U1: 0x%02x PortStateChange: %1u SwitchLifeTime %2u\n",
pSwitchInfo->u1.AsReg8,
pSwitchInfo->u1.s.PortStateChange,
pSwitchInfo->u1.s.LifeTimeValue);
printf("%*sU2: 0x%02x: %s\n",
indent+4, "",
pSwitchInfo->u2.AsReg8,
pSwitchInfo->u2.s.EnhancedPort0?"E0 ": "");
}
if (! (g_persist || g_hard)) {
printf("%*sAR: 0x%04x: %s%s%s%sF%u T%u\n",
indent+4, "",
pSwitchInfo->AdaptiveRouting.AsReg16,
pSwitchInfo->AdaptiveRouting.s.Enable?"On ": "",
pSwitchInfo->AdaptiveRouting.s.Pause?"Pause ": "",
pSwitchInfo->AdaptiveRouting.s.Algorithm?((pSwitchInfo->AdaptiveRouting.s.Algorithm==2)?"RGreedy ":"Greedy "): "Random ",
pSwitchInfo->AdaptiveRouting.s.LostRoutesOnly?"LostOnly ": "",
pSwitchInfo->AdaptiveRouting.s.Frequency,
pSwitchInfo->AdaptiveRouting.s.Threshold);
} else {
printf("%*sAR: xxxxxx: x\n", indent+4, "");
}
printf("%*sCapabilityMask: 0x%04x: %s%s\n",
indent+4, "",
pSwitchInfo->CapabilityMask.AsReg16,
pSwitchInfo->CapabilityMask.s.IsAddrRangeConfigSupported?"ARC ":"",
pSwitchInfo->CapabilityMask.s.IsAdaptiveRoutingSupported?"AR ":"");
if (! (g_persist || g_hard)) {
printf("%*sRouting Mode: Supported: 0x%x Enabled 0x%x\n",
indent+4, "",
pSwitchInfo->RoutingMode.Supported,
pSwitchInfo->RoutingMode.Enabled);
} else {
printf("%*sRouting Mode: Supported: 0x%x Enabled x\n",
indent+4, "",
pSwitchInfo->RoutingMode.Supported);
}
{
printf("%*sIPAddrIPV6: %s IPAddrIPV4: %s\n",
indent+4, "",
inet_ntop(AF_INET6,
pSwitchInfo->IPAddrIPV6.addr,
buf1, sizeof(buf1)),
inet_ntop(AF_INET,
pSwitchInfo->IPAddrIPV4.addr,
buf2, sizeof(buf2)));
}
}
printf("%*s%u Connected Ports%s\n", indent, "",
CountInitializedPorts(&g_Fabric, nodep), detail?":":"");
break;
case FORMAT_XML:
// omit fields which are port specific:
// LID, PortGUID, LocalPortNum
// TBD - is PartitionCap per Port or per Node?
printf("%*s<Node id=\"0x%016"PRIx64"\">\n", indent, "",
nodep->NodeInfo.NodeGUID);
XmlPrintNodeDesc((char*)nodep->NodeDesc.NodeString, indent+4);
XmlPrintNodeType(nodep->NodeInfo.NodeType, indent+4);
if (nodep->enodep && nodep->enodep->details) {
XmlPrintOptionalStr("NodeDetails", nodep->enodep->details, indent+4);
}
XmlPrintDec("BaseVer", nodep->NodeInfo.BaseVersion, indent+4);
XmlPrintDec("SmaVer", nodep->NodeInfo.ClassVersion, indent+4);
XmlPrintDec("NumPorts", nodep->NodeInfo.NumPorts, indent+4);
XmlPrintHex64("SystemImageGUID", nodep->NodeInfo.SystemImageGUID, indent+4);
XmlPrintHex64("NodeGUID", nodep->NodeInfo.NodeGUID, indent+4);
XmlPrintDec("PartitionCap", nodep->NodeInfo.PartitionCap, indent+4);
XmlPrintHex("DeviceID", nodep->NodeInfo.DeviceID, indent+4);
XmlPrintHex("Revision", nodep->NodeInfo.Revision, indent+4);
XmlPrintHex("VendorID", nodep->NodeInfo.u1.s.VendorID, indent+4);
if (nodep->pSwitchInfo) {
STL_SWITCHINFO_RECORD *pSwitchInfoRecord = nodep->pSwitchInfo;
STL_SWITCH_INFO *pSwitchInfo = &pSwitchInfoRecord->SwitchInfoData;
if (! (g_persist || g_hard))
XmlPrintLID("LID", pSwitchInfoRecord->RID.LID, indent+4);
XmlPrintDec("LinearFDBCap", pSwitchInfo->LinearFDBCap, indent+4);
XmlPrintDec("MulticastFDBCap", pSwitchInfo->MulticastFDBCap, indent+4);
if (! (g_persist || g_hard))
XmlPrintDec("LinearFDBTop", pSwitchInfo->LinearFDBTop, indent+4);
{
XmlPrintStr("IPAddrIPV6",
inet_ntop(AF_INET6,
pSwitchInfo->IPAddrIPV6.addr,
buf1, sizeof(buf1)),
indent+4);
XmlPrintStr("IPAddrIPV4",
inet_ntop(AF_INET,
pSwitchInfo->IPAddrIPV4.addr,
buf1, sizeof(buf1)),
indent+4);
}
XmlPrintHex8("U1",pSwitchInfo->u1.AsReg8,indent+4);
if ( ! (g_persist || g_hard)) {
XmlPrintDec("PortStateChange",
pSwitchInfo->u1.s.PortStateChange,
indent+4);
XmlPrintDec("SwitchLifeTime",
pSwitchInfo->u1.s.LifeTimeValue,
indent+4);
}
XmlPrintDec("PartitionEnforcementCap",
pSwitchInfo->PartitionEnforcementCap,
indent+4);
XmlPrintHex8("RoutingModeSupported",
pSwitchInfo->RoutingMode.Supported, indent+4);
if (!g_hard && !g_persist) {
XmlPrintHex8("RoutingModeEnabled",
pSwitchInfo->RoutingMode.Enabled, indent+4);
}
XmlPrintHex8("U2",
pSwitchInfo->u2.AsReg8, indent+4);
printf("%*s<Capability>%s</Capability>\n",
indent+4, "",
pSwitchInfo->u2.s.EnhancedPort0?"E0 ": "");
if ( ! (g_persist || g_hard)) {
XmlPrintHex8("AdaptiveRouting",
pSwitchInfo->AdaptiveRouting.AsReg16, indent+4);
XmlPrintDec("LostRoutesOnly",
pSwitchInfo->AdaptiveRouting.s.LostRoutesOnly, indent+4);
XmlPrintDec("Pause",
pSwitchInfo->AdaptiveRouting.s.Pause, indent+4);
XmlPrintDec("Enable",
pSwitchInfo->AdaptiveRouting.s.Enable, indent+4);
XmlPrintDec("Algorithm",
pSwitchInfo->AdaptiveRouting.s.Algorithm, indent+4);
XmlPrintDec("Frequency",
pSwitchInfo->AdaptiveRouting.s.Frequency, indent+4);
XmlPrintDec("Threshold",
pSwitchInfo->AdaptiveRouting.s.Threshold, indent+4);
}
if (pSwitchInfo->CapabilityMask.AsReg16) {
// only output if there are some vendor capabilities
XmlPrintHex16("StlCapabilityMask",
pSwitchInfo->CapabilityMask.AsReg16, indent+4);
printf("%*s<StlCapability>%s</StlCapability>\n",
indent+4, "",
pSwitchInfo->CapabilityMask.s.IsAdaptiveRoutingSupported?"AR ": "");
}
}
XmlPrintDec("ConnectedPorts", CountInitializedPorts(&g_Fabric, nodep),
indent+4);
break;
default:
break;
}
if (detail) {
for (p=cl_qmap_head(&nodep->Ports); p != cl_qmap_end(&nodep->Ports); p = cl_qmap_next(p)) {
PortData *portp = PARENT_STRUCT(p, PortData, NodePortsEntry);
if (! ComparePortPoint(portp, focus))
continue;
ShowPortSummary(portp, format, indent+4, detail-1);
}
}
if (nodep->ioup) {
/* IOU report is brief, do it at top level detail for Node */
ShowIouSummary(nodep->ioup, focus, format, indent+4, detail);
}
if (format == FORMAT_XML) {
printf("%*s</Node>\n", indent, "");
}
} // End of ShowNodeSummary()
// output verbose summary of a IB System
void ShowSystemSummary(SystemData *systemp, Point *focus,
Format_t format, int indent, int detail)
{
cl_map_item_t *p;
switch (format) {
case FORMAT_TEXT:
printf("%*sSystemImageGUID: 0x%016"PRIx64"\n", indent, "", systemp->SystemImageGUID);
printf("%*s%u Connected Nodes%s\n", indent, "", (unsigned)cl_qmap_count(&systemp->Nodes), detail?":":"");
break;
case FORMAT_XML:
printf("%*s<System id=\"0x%016"PRIx64"\">\n", indent, "",
systemp->SystemImageGUID?systemp->SystemImageGUID:
PARENT_STRUCT(cl_qmap_head(&systemp->Nodes), NodeData, SystemNodesEntry)->NodeInfo.NodeGUID);
XmlPrintHex64("SystemImageGUID", systemp->SystemImageGUID, indent+4);
XmlPrintDec("ConnectedNodes", (unsigned)cl_qmap_count(&systemp->Nodes),
indent+4);
break;
default:
break;
}
if (detail) {
for (p=cl_qmap_head(&systemp->Nodes); p != cl_qmap_end(&systemp->Nodes); p = cl_qmap_next(p)) {
NodeData *nodep = PARENT_STRUCT(p, NodeData, SystemNodesEntry);
if (! CompareNodePoint(nodep, focus))
continue;
ShowNodeSummary(nodep, focus, format, indent+4, detail-1);
}
}
if (format == FORMAT_XML) {
printf("%*s</System>\n", indent, "");
}
}
// output verbose summary of IB SMs
void ShowSMSummary(SMData *smp, Format_t format, int indent, int detail)
{
switch (format) {
case FORMAT_TEXT:
if (g_hard || g_persist)
printf("%*sState: xxxxxxxxxxx Name: %.*s\n",
indent, "",
NODE_DESCRIPTION_ARRAY_SIZE,
g_noname?g_name_marker:(char*)smp->portp->nodep->NodeDesc.NodeString);
else
printf("%*sState: %-11s Name: %.*s\n",
indent, "",
IbSMStateToText(smp->SMInfoRecord.SMInfo.u.s.SMStateCurrent),
NODE_DESCRIPTION_ARRAY_SIZE,
g_noname?g_name_marker:(char*)smp->portp->nodep->NodeDesc.NodeString);
printf("%*sNodeGUID: 0x%016"PRIx64" Type: %s\n",
indent+4, "", smp->portp->nodep->NodeInfo.NodeGUID,
StlNodeTypeToText(smp->portp->nodep->NodeInfo.NodeType));
if (smp->portp->nodep->enodep && smp->portp->nodep->enodep->details) {
printf("%*sNodeDetails: %s\n", indent+4, "", smp->portp->nodep->enodep->details);
}
if (smp->esmp && smp->esmp->details) {
printf("%*sSMDetails: %s\n", indent+4, "", smp->esmp->details);
}
if (detail) {
if (g_hard || g_persist)
printf("%*sPortNum: %3u LID: xxxxxxxxxx PortGUID: 0x%016"PRIx64"\n",
indent+4, "", smp->portp->PortNum,
smp->SMInfoRecord.SMInfo.PortGUID);
else
printf("%*sPortNum: %3u LID: 0x%.*x PortGUID: 0x%016"PRIx64"\n",
indent+4, "", smp->portp->PortNum,
(smp->SMInfoRecord.RID.LID <= IB_MAX_UCAST_LID ? 4:8),
smp->SMInfoRecord.RID.LID, smp->SMInfoRecord.SMInfo.PortGUID);
if (g_hard)
printf("%*sSM_Key: xxxxxxxxxxxxxxxxxx Priority: xxx ActCount: xxxxxxxxxx\n",
indent+4, "");
else if (g_persist)
printf("%*sSM_Key: xxxxxxxxxxxxxxxxxx Priority: %3d ActCount: xxxxxxxxxx\n",
indent+4, "",
smp->SMInfoRecord.SMInfo.u.s.Priority);
else
printf("%*sSM_Key: 0x%016"PRIx64" Priority: %3d ActCount: 0x%08x\n",
indent+4, "",
smp->SMInfoRecord.SMInfo.SM_Key,
smp->SMInfoRecord.SMInfo.u.s.Priority,
smp->SMInfoRecord.SMInfo.ActCount);
}
break;
case FORMAT_XML:
printf("%*s<SM id=\"0x%016"PRIx64":%u\">\n", indent, "",
smp->portp->nodep->NodeInfo.NodeGUID,
smp->portp->PortNum);
if (! (g_hard || g_persist)) {
XmlPrintStr("State",
IbSMStateToText(smp->SMInfoRecord.SMInfo.u.s.SMStateCurrent),
indent+4);
XmlPrintDec("State_Int",
smp->SMInfoRecord.SMInfo.u.s.SMStateCurrent,
indent+4);
}
XmlPrintNodeDesc(
(char*)smp->portp->nodep->NodeDesc.NodeString, indent+4);
XmlPrintHex64("NodeGUID",
smp->portp->nodep->NodeInfo.NodeGUID,
indent+4);
XmlPrintNodeType(smp->portp->nodep->NodeInfo.NodeType,
indent+4);
if (smp->portp->nodep->enodep && smp->portp->nodep->enodep->details) {
XmlPrintOptionalStr("NodeDetails", smp->portp->nodep->enodep->details, indent+4);
}
if (smp->esmp && smp->esmp->details) {
XmlPrintOptionalStr("SMDetails", smp->esmp->details, indent+4);
}
if (detail) {
XmlPrintDec("PortNum", smp->portp->PortNum, indent+4);
if (! (g_hard || g_persist))
XmlPrintLID("LID",
smp->SMInfoRecord.RID.LID, indent+4);
XmlPrintHex64("PortGUID",
smp->SMInfoRecord.SMInfo.PortGUID, indent+4);
if (g_hard) {
// noop
} else if (g_persist)
XmlPrintDec("Priority",
smp->SMInfoRecord.SMInfo.u.s.Priority, indent+4);
else {
XmlPrintHex64("SM_Key",
smp->SMInfoRecord.SMInfo.SM_Key, indent+4);
XmlPrintDec("Priority",
smp->SMInfoRecord.SMInfo.u.s.Priority, indent+4);
XmlPrintHex32("ActCount",
smp->SMInfoRecord.SMInfo.ActCount, indent+4);
}
}
printf("%*s</SM>\n", indent, "");
break;
default:
break;
}
}
void ShowAllSMSummary(Point *focus, Format_t format, int indent, int detail)
{
cl_map_item_t *p;
uint32 count = 0;
switch (format) {
case FORMAT_TEXT:
printf("%*s%u Connected SMs in Fabric%s\n", indent, "", (unsigned)cl_qmap_count(&g_Fabric.AllSMs), detail?":":"");
break;
case FORMAT_XML:
printf("%*s<SMs>\n", indent, "");
XmlPrintDec("ConnectedSMCount", (unsigned)cl_qmap_count(&g_Fabric.AllSMs),
indent+4);
break;
default:
break;
}
for (p=cl_qmap_head(&g_Fabric.AllSMs); p != cl_qmap_end(&g_Fabric.AllSMs); p = cl_qmap_next(p)) {
SMData *smp = PARENT_STRUCT(p, SMData, AllSMsEntry);
if (! CompareSmPoint(smp, focus))
continue;
if (detail)
ShowSMSummary(smp, format, indent+4, detail-1);
count++;
}
switch (format) {
case FORMAT_TEXT:
if (PointValid(focus))
printf("%*s%u Matching SMs Found\n", indent, "", count);
break;
case FORMAT_XML:
if (PointValid(focus))
XmlPrintDec("MatchingSMs", count, indent+4);
printf("%*s</SMs>\n", indent, "");
break;
default:
break;
}
}
// output verbose summary of all IB Components (Systems, Nodes, Ports, SMs)
void ShowComponentReport(Point *focus, Format_t format, int indent, int detail)
{
cl_map_item_t *p;
uint32 count = 0;
switch (format) {
case FORMAT_TEXT:
printf("%*sComponent Summary\n", indent, "");
break;
case FORMAT_XML:
printf("%*s<ComponentSummary>\n", indent, "");
indent+=4;
break;
default:
break;
}
ShowPointFocus(focus, FIND_FLAG_FABRIC, format, indent, detail);
switch (format) {
case FORMAT_TEXT:
printf("%*s%u Connected Systems%s\n", indent, "", (unsigned)cl_qmap_count(&g_Fabric.AllSystems), detail?":":"");
break;
case FORMAT_XML:
printf("%*s<Systems>\n", indent, "");
XmlPrintDec("ConnectedSystems", (unsigned)cl_qmap_count(&g_Fabric.AllSystems),
indent+4);
break;
default:
break;
}
for (p=cl_qmap_head(&g_Fabric.AllSystems); p != cl_qmap_end(&g_Fabric.AllSystems); p = cl_qmap_next(p)) {
SystemData *systemp = PARENT_STRUCT(p, SystemData, AllSystemsEntry);
if (! CompareSystemPoint(systemp, focus))
continue;
if (detail)
ShowSystemSummary(systemp, focus, format, indent+4, detail-1);
count++;
}
switch (format) {
case FORMAT_TEXT:
if (PointValid(focus))
printf("%*s%u Matching Systems Found\n", indent, "", count);
if (detail)
printf("\n");
break;
case FORMAT_XML:
if (PointValid(focus))
XmlPrintDec("MatchingSystems", count, indent+4);
printf("%*s</Systems>\n", indent, "");
break;
default:
break;
}
ShowAllSMSummary(focus, format, indent, detail);
switch (format) {
case FORMAT_TEXT:
DisplaySeparator();
break;
case FORMAT_XML:
indent-=4;
printf("%*s</ComponentSummary>\n", indent, "");
break;
default:
break;
}
}
// output verbose summary of all IB Node Types
void ShowNodeTypeReport(Point *focus, Format_t format, int indent, int detail)
{
LIST_ITEM *p;
uint32 count;
switch (format) {
case FORMAT_TEXT:
printf("%*sNode Type Summary\n", indent, "");
break;
case FORMAT_XML:
printf("%*s<NodeTypeSummary>\n", indent, "");
indent+=4;
break;
default:
break;
}
ShowPointFocus(focus, FIND_FLAG_FABRIC, format, indent, detail);
switch (format) {
case FORMAT_TEXT:
printf("%*s%u Connected FIs in Fabric%s\n", indent, "", (unsigned)QListCount(&g_Fabric.AllFIs), detail?":":"");
break;
case FORMAT_XML:
printf("%*s<FIs>\n", indent, "");
indent+=4;
XmlPrintDec("ConnectedFICount", (unsigned)QListCount(&g_Fabric.AllFIs), indent);
break;
default:
break;
}
count = 0;
for (p=QListHead(&g_Fabric.AllFIs); p != NULL; p = QListNext(&g_Fabric.AllFIs, p)) {
NodeData *nodep = (NodeData *)QListObj(p);
if (! CompareNodePoint(nodep, focus))
continue;
if (detail)
ShowNodeSummary(nodep, focus, format, indent+4, detail-1);
count++;
}
switch (format) {
case FORMAT_TEXT:
if (PointValid(focus))
printf("%*s%u Matching FIs Found\n", indent, "", count);
if (detail)
printf("\n");
break;
case FORMAT_XML:
if (PointValid(focus))
XmlPrintDec("MatchingFIs", count, indent+4);
indent-=4;
printf("%*s</FIs>\n", indent, "");
break;
default:
break;
}
switch (format) {
case FORMAT_TEXT:
printf("%*s%u Connected Switches in Fabric%s\n", indent, "", (unsigned)QListCount(&g_Fabric.AllSWs), detail?":":"");
break;
case FORMAT_XML:
printf("%*s<Switches>\n", indent, "");
indent+=4;
XmlPrintDec("ConnectedSwitchCount", (unsigned)QListCount(&g_Fabric.AllSWs),
indent);
break;
default:
break;
}
count = 0;
for (p=QListHead(&g_Fabric.AllSWs); p != NULL; p = QListNext(&g_Fabric.AllSWs, p)) {
NodeData *nodep = (NodeData *)QListObj(p);
if (! CompareNodePoint(nodep, focus))
continue;
if (detail)
ShowNodeSummary(nodep, focus, format, indent+4, detail-1);
count++;
}
switch (format) {
case FORMAT_TEXT:
if (PointValid(focus))
printf("%*s%u Matching Switches Found\n", indent, "", count);
if (detail)
printf("\n");
break;
case FORMAT_XML:
if (PointValid(focus))
XmlPrintDec("MatchingSwitches", count, indent+4);
indent-=4;
printf("%*s</Switches>\n", indent, "");
break;
default:
break;
}
ShowAllSMSummary(focus, format, indent, detail);
switch (format) {
case FORMAT_TEXT:
DisplaySeparator();
break;
case FORMAT_XML:
indent-=4;
printf("%*s</NodeTypeSummary>\n", indent, "");
break;
default:
break;
}
}
// output verbose summary of all IOUs
void ShowAllIOUReport(Point *focus, Format_t format, int indent, int detail)
{
LIST_ITEM *p;
uint32 count = 0;
switch (format) {
case FORMAT_TEXT:
printf("%*sIOU Summary\n", indent, "");
break;
case FORMAT_XML:
printf("%*s<IOUSummary>\n", indent, "");
indent+=4;
break;
default:
break;
}
ShowPointFocus(focus, FIND_FLAG_FABRIC, format, indent, detail);
switch (format) {
case FORMAT_TEXT:
printf("%*s%u IOUs in Fabric%s\n", indent, "", (unsigned)QListCount(&g_Fabric.AllIOUs), detail?":":"");
break;
case FORMAT_XML:
printf("%*s<IOUs>\n", indent, "");
indent+=4;
XmlPrintDec("ConnectedIOUCount", (unsigned)QListCount(&g_Fabric.AllIOUs), indent);
break;
default:
break;
}
for (p=QListHead(&g_Fabric.AllIOUs); p != NULL; p = QListNext(&g_Fabric.AllIOUs, p)) {
IouData *ioup = (IouData *)QListObj(p);
if (! CompareIouPoint(ioup, focus))
continue;
if (detail)
ShowNodeSummary(ioup->nodep, focus, format, indent+4, detail-1);
count++;
}
switch (format) {
case FORMAT_TEXT:
if (PointValid(focus))
printf("%*s%u Matching IOUs Found\n", indent, "", count);
DisplaySeparator();
break;
case FORMAT_XML:
if (PointValid(focus))
XmlPrintDec("MatchingIOUs", count, indent);
indent-=4;
printf("%*s</IOUs>\n", indent, "");
indent-=4;
printf("%*s</IOUSummary>\n", indent, "");
break;
default:
break;
}
}
void ShowOtherPortSummaryHeader(Format_t format, int indent, int detail)
{
switch (format) {
case FORMAT_TEXT:
printf("%*sNodeGUID Port Type Name\n", indent, "");
break;
case FORMAT_XML:
break;
default:
break;
}
}
// show a non-connected port in a node
void ShowOtherPortSummary(NodeData *nodep, uint8 portNum,
Format_t format, int indent, int detail)
{
switch (format) {
case FORMAT_TEXT:
printf("%*s0x%016"PRIx64" %3u %s %.*s\n",
indent, "",
nodep->NodeInfo.NodeGUID,
portNum,
StlNodeTypeToText(nodep->NodeInfo.NodeType),
NODE_DESCRIPTION_ARRAY_SIZE,
g_noname?g_name_marker:(char*)nodep->NodeDesc.NodeString);
if (nodep->enodep && nodep->enodep->details) {
printf("%*sNodeDetails: %s\n", indent+4, "", nodep->enodep->details);
}
break;
case FORMAT_XML:
printf("%*s<OtherPort id=\"0x%016"PRIx64":%u\">\n", indent, "",
nodep->NodeInfo.NodeGUID, portNum);
XmlPrintHex64("NodeGUID",
nodep->NodeInfo.NodeGUID, indent+4);
XmlPrintDec("PortNum", portNum, indent+4);
XmlPrintNodeType(nodep->NodeInfo.NodeType,
indent+4);
XmlPrintNodeDesc((char*)nodep->NodeDesc.NodeString, indent+4);
if (nodep->enodep && nodep->enodep->details) {
XmlPrintOptionalStr("NodeDetails", nodep->enodep->details, indent+4);
}
break;
default:
break;
}
if (format == FORMAT_XML)
printf("%*s</OtherPort>\n", indent, "");
}
// show a non-connected port in a node
void ShowNodeOtherPortSummary(NodeData *nodep,
Format_t format, int indent, int detail)
{
cl_map_item_t *p;
uint8 port;
for (port=1, p=cl_qmap_head(&nodep->Ports); p != cl_qmap_end(&nodep->Ports);)
{
PortData *portp = PARENT_STRUCT(p, PortData, NodePortsEntry);
if (portp->PortNum == 0)
{
p = cl_qmap_next(p);
continue; /* skip switch port 0 */
}
if (portp->PortNum != port) {
ShowOtherPortSummary(nodep, port, format, indent, detail);
} else {
if (! IsPortInitialized(portp->PortInfo.PortStates))
ShowOtherPortSummary(nodep, port, format, indent, detail);
p = cl_qmap_next(p);
}
port++;
}
/* output remaining ports after last connected port */
for (; port <= nodep->NodeInfo.NumPorts; port++)
ShowOtherPortSummary(nodep, port, format, indent, detail);
}
// output verbose summary of IB ports not connected to this fabric
void ShowOtherPortsReport(Point *focus, Format_t format, int indent, int detail)
{
LIST_ITEM *p;
uint32 node_count;
uint32 port_count;
uint32 other_port_count;
switch (format) {
case FORMAT_TEXT:
printf("%*sOther Ports Summary\n", indent, "");
break;
case FORMAT_XML:
printf("%*s<OtherPortsSummary>\n", indent, "");
indent+=4;
break;
default:
break;
}
ShowPointFocus(focus, FIND_FLAG_FABRIC, format, indent, detail);
switch (format) {
case FORMAT_TEXT:
printf("%*s%u Connected FIs in Fabric%s\n", indent, "", (unsigned)QListCount(&g_Fabric.AllFIs), detail?":":"");
break;
case FORMAT_XML:
printf("%*s<FIs>\n", indent, "");
indent+=4;
XmlPrintDec("ConnectedFICount", (unsigned)QListCount(&g_Fabric.AllFIs), indent);
break;
default:
break;
}
node_count = 0;
port_count = 0;
other_port_count = 0;
for (p=QListHead(&g_Fabric.AllFIs); p != NULL; p = QListNext(&g_Fabric.AllFIs, p)) {
NodeData *nodep = (NodeData *)QListObj(p);
uint32 initialized_port_count;
if (! CompareNodePoint(nodep, focus))
continue;
initialized_port_count = CountInitializedPorts(&g_Fabric, nodep);
port_count += initialized_port_count;
if (initialized_port_count >= nodep->NodeInfo.NumPorts)
continue;
// for FIs otherports will include ports connected to other fabrics
if (node_count == 0 && detail)
ShowOtherPortSummaryHeader(format, indent+4, detail-1);
other_port_count += nodep->NodeInfo.NumPorts - initialized_port_count;
if (detail)
ShowNodeOtherPortSummary(nodep, format, indent+4, detail-1);
node_count++;
}
switch (format) {
case FORMAT_TEXT:
if (PointValid(focus))
printf("%*s%u Matching FIs Found\n", indent, "", node_count);
printf("%*s%u Connected FI Ports\n", indent, "", port_count);
printf("%*s%u Other FI Ports\n", indent, "", other_port_count);
if (detail)
printf("\n");
break;
case FORMAT_XML:
if (PointValid(focus))
XmlPrintDec("MatchingFIs", node_count, indent+4);
XmlPrintDec("ConnectedFIPorts", port_count, indent+4);
XmlPrintDec("OtherCAPorts", other_port_count, indent+4);
indent-=4;
printf("%*s</FIs>\n", indent, "");
break;
default:
break;
}
switch (format) {
case FORMAT_TEXT:
printf("%*s%u Connected Switches in Fabric%s\n", indent, "", (unsigned)QListCount(&g_Fabric.AllSWs), detail?":":"");
break;
case FORMAT_XML:
printf("%*s<Switches>\n", indent, "");
indent+=4;
XmlPrintDec("ConnectedSwitchCount", (unsigned)QListCount(&g_Fabric.AllSWs),
indent);
break;
default:
break;
}
node_count = 0;
port_count = 0;
other_port_count = 0;
for (p=QListHead(&g_Fabric.AllSWs); p != NULL; p = QListNext(&g_Fabric.AllSWs, p)) {
NodeData *nodep = (NodeData *)QListObj(p);
uint32 initialized_port_count;
if (! CompareNodePoint(nodep, focus))
continue;
initialized_port_count = CountInitializedPorts(&g_Fabric, nodep);
/* don't count switch port 0 */
if (initialized_port_count) {
PortData *portp = PARENT_STRUCT(cl_qmap_head(&nodep->Ports), PortData, NodePortsEntry);
if (portp->PortNum == 0 && IsPortInitialized(portp->PortInfo.PortStates))
initialized_port_count--;
}
port_count += initialized_port_count;
if (initialized_port_count >= nodep->NodeInfo.NumPorts)
continue;
if (node_count == 0 && detail)
ShowOtherPortSummaryHeader(format, indent+4, detail-1);
other_port_count += nodep->NodeInfo.NumPorts - initialized_port_count;
if (detail)
ShowNodeOtherPortSummary(nodep, format, indent+4, detail-1);
node_count++;
}
switch (format) {
case FORMAT_TEXT:
if (PointValid(focus))
printf("%*s%u Matching Switches Found\n", indent, "", node_count);
printf("%*s%u Connected Switch Ports\n", indent, "", port_count);
printf("%*s%u Other Switch Ports\n", indent, "", other_port_count);
if (detail)
printf("\n");
break;
case FORMAT_XML:
if (PointValid(focus))
XmlPrintDec("MatchingSwitches", node_count, indent+4);
XmlPrintDec("ConnectedSwitchPorts", port_count, indent+4);
XmlPrintDec("OtherSwitchPorts", other_port_count, indent+4);
indent-=4;
printf("%*s</Switches>\n", indent, "");
break;
default:
break;
}
switch (format) {
case FORMAT_TEXT:
DisplaySeparator();
break;
case FORMAT_XML:
indent-=4;
printf("%*s</OtherPortsSummary>\n", indent, "");
break;
default:
break;
}
}
// undocumented report on sizes
void ShowSizesReport(void)
{
printf("sizeof(SystemData)=%u\n", (unsigned)sizeof(SystemData));
printf("sizeof(NodeData)=%u\n", (unsigned)sizeof(NodeData));
printf("sizeof(PortData)=%u\n", (unsigned)sizeof(PortData));
printf("sizeof(QOSData)=%u (up to 1 per port)\n", (unsigned)sizeof(QOSData));
printf("sizeof(STL_PORT_COUNTERS_DATA)=%u (up to 1 per port)\n", (unsigned)sizeof(STL_PORT_COUNTERS_DATA));
printf("sizeof(STL_PKEY_ELEMENT)=%u (up to 1 per port per pkey)\n", (unsigned)sizeof(STL_PKEY_ELEMENT));
printf("sizeof(IouData)=%u\n", (unsigned)sizeof(IouData));
printf("sizeof(IocData)=%u\n", (unsigned)sizeof(IocData));
printf("sizeof(IOC_SERVICE)=%u\n", (unsigned)sizeof(IOC_SERVICE));
printf("sizeof(SMData)=%u\n", (unsigned)sizeof(SMData));
printf("sizeof(STL_SWITCHINFO_RECORD)=%u (up to 1 per switch)\n", (unsigned)sizeof(STL_SMINFO_RECORD));
printf("sizeof(IB_PATH_RECORD)=%u (up to 1 per port)\n", (unsigned)sizeof(IB_PATH_RECORD));
printf("sizeof(STL_NODE_RECORD)=%u\n", (unsigned)sizeof(STL_NODE_RECORD));
printf("sizeof(STL_PORTINFO_RECORD)=%u\n", (unsigned)sizeof(STL_PORTINFO_RECORD));
printf("sizeof(STL_LINK_RECORD)=%u\n", (unsigned)sizeof(STL_LINK_RECORD));
}
// output brief summary of a IB Port
void ShowPortBriefSummary(PortData *portp, Format_t format, int indent, int detail)
{
char buf1[SHOW_BUF_SIZE], buf2[SHOW_BUF_SIZE];
switch (format) {
case FORMAT_TEXT:
if (portp->PortGUID)
if (g_hard || g_persist)
printf("%*s%3u xxxxxx 0x%016"PRIx64,
indent, "", portp->PortNum,
portp->PortGUID);
else
printf("%*s%3u 0x%04x 0x%016"PRIx64,
indent, "", portp->PortNum,
portp->EndPortLID, portp->PortGUID);
else
printf("%*s%3u ",
indent, "", portp->PortNum);
if (g_hard)
printf(" xxxx xxxxxxx\n");
else
printf(" %4s %7s\n",
StlLinkWidthToText(portp->PortInfo.LinkWidth.Active, buf1, sizeof(buf1)),
StlLinkSpeedToText(portp->PortInfo.LinkSpeed.Active, buf2, sizeof(buf2)));
break;
case FORMAT_XML:
printf("%*s<Port id=\"0x%016"PRIx64":%u\">\n", indent, "",
portp->nodep->NodeInfo.NodeGUID, portp->PortNum);
XmlPrintDec("PortNum", portp->PortNum, indent+4);
if (portp->PortGUID) {
if (! (g_hard || g_persist)) {
XmlPrintLID("LID",
portp->EndPortLID, indent+4);
if (portp->PortInfo.s1.LMC)
XmlPrintDec("LMC",
portp->PortInfo.s1.LMC, indent+4);
}
XmlPrintHex64("PortGUID", portp->PortGUID, indent+4);
}
if (g_hard) {
// noop
} else {
XmlPrintLinkWidth("LinkWidthActive",
portp->PortInfo.LinkWidth.Active, indent+4);
XmlPrintLinkSpeed("LinkSpeedActive",
portp->PortInfo.LinkSpeed.Active, indent+4);
}
printf("%*s</Port>\n", indent, "");
break;
default:
break;
}
}
void ShowPortBriefSummaryHeadings(Format_t format, int indent, int detail)
{
switch (format) {
case FORMAT_TEXT:
printf("%*sPort LID PortGUID Width Speed\n", indent, "");
break;
case FORMAT_XML:
break;
default:
break;
}
}
static void PrintXmlNodeSummaryBrief(NodeData *nodep, int indent)
{
printf("%*s<Node id=\"0x%016"PRIx64"\">\n", indent, "", nodep->NodeInfo.NodeGUID);
XmlPrintHex64("NodeGUID",nodep->NodeInfo.NodeGUID, indent+4);
XmlPrintNodeType(nodep->NodeInfo.NodeType, indent+4);
XmlPrintNodeDesc((char*)nodep->NodeDesc.NodeString, indent+4);
if (nodep->enodep && nodep->enodep->details) {
XmlPrintOptionalStr("NodeDetails", nodep->enodep->details, indent+4);
}
}
static void PrintBriefNodePorts(NodeData *nodep, Point *focus, Format_t format,
int indent, int detail)
{
cl_map_item_t *p;
for (p=cl_qmap_head(&nodep->Ports); p != cl_qmap_end(&nodep->Ports); p = cl_qmap_next(p)) {
PortData *portp = PARENT_STRUCT(p, PortData, NodePortsEntry);
if (! ComparePortPoint(portp, focus))
continue;
ShowPortBriefSummary(portp, format, indent+4, detail-1);
}
}
// output brief summary of a IB Node
void ShowNodeBriefSummary(NodeData *nodep, Point *focus,
boolean close_node, Format_t format, int indent, int detail)
{
switch (format) {
case FORMAT_TEXT:
printf("%*s0x%016"PRIx64" %s %.*s\n",
indent, "", nodep->NodeInfo.NodeGUID,
StlNodeTypeToText(nodep->NodeInfo.NodeType),
NODE_DESCRIPTION_ARRAY_SIZE,
g_noname?g_name_marker:(char*)nodep->NodeDesc.NodeString);
if (nodep->enodep && nodep->enodep->details) {
printf("%*sNodeDetails: %s\n", indent+4, "", nodep->enodep->details);
}
break;
case FORMAT_XML:
PrintXmlNodeSummaryBrief(nodep, indent);
break;
default:
break;
}
if (detail)
PrintBriefNodePorts(nodep, focus, format, indent, detail);
if (close_node && format == FORMAT_XML) {
printf("%*s</Node>\n", indent, "");
}
}
void ShowTopologyNodeBriefSummary(NodeData *nodep, Point *focus, int indent, int detail)
{
PrintXmlNodeSummaryBrief(nodep, indent);
// Print node/port xml tag only for opareport option -d3 or greater detail level
if (detail >= 2)
PrintBriefNodePorts(nodep, focus, FORMAT_XML, indent, detail);
printf("%*s</Node>\n", indent, "");
}
// output brief summary of an expected IB Node
void ShowExpectedNodeBriefSummary(const char *prefix, ExpectedNode *enodep,
const char *xml_tag, boolean close_node, Format_t format,
int indent, int detail)
{
switch (format) {
case FORMAT_TEXT:
printf("%*s%s", indent, "", prefix);
if (enodep->NodeGUID)
printf("0x%016"PRIx64, enodep->NodeGUID);
else
printf("%*s", 18, "");
if (enodep->NodeType)
printf(" %s", StlNodeTypeToText(enodep->NodeType));
else
printf(" ");
if (enodep->NodeDesc)
printf(" %.*s\n", NODE_DESCRIPTION_ARRAY_SIZE,
g_noname?g_name_marker:enodep->NodeDesc);
else
printf("\n");
if (enodep->details)
printf("%*sNodeDetails: %s\n", indent+4, "", enodep->details);
break;
case FORMAT_XML:
printf("%*s<%s id=\"0x%016"PRIx64"\">\n", indent, "",
xml_tag, (uint64)(uintn)enodep);
if (enodep->NodeGUID)
XmlPrintHex64("NodeGUID", enodep->NodeGUID, indent+4);
if (enodep->NodeType)
XmlPrintNodeType(enodep->NodeType, indent+4);
if (enodep->NodeDesc)
XmlPrintNodeDesc(enodep->NodeDesc, indent+4);
if (enodep->details)
XmlPrintOptionalStr("NodeDetails", enodep->details, indent+4);
break;
default:
break;
}
if (close_node && format == FORMAT_XML) {
printf("%*s</%s>\n", indent, "", xml_tag);
}
}
void ShowNodeBriefSummaryHeadings(Format_t format, int indent, int detail)
{
switch (format) {
case FORMAT_TEXT:
printf("%*sNodeGUID Type Name\n", indent, "");
if (detail)
ShowPortBriefSummaryHeadings(format, indent+4, detail-1);
break;
case FORMAT_XML:
break;
default:
break;
}
}
// output brief summary of a IB System
void ShowSystemBriefSummary(SystemData *systemp, Point *focus,
Format_t format, int indent, int detail)
{
cl_map_item_t *p;
switch (format) {
case FORMAT_TEXT:
printf("%*s0x%016"PRIx64"\n", indent, "", systemp->SystemImageGUID);
break;
case FORMAT_XML:
printf("%*s<BriefSystem id=\"0x%016"PRIx64"\">\n", indent, "",
systemp->SystemImageGUID?systemp->SystemImageGUID:
PARENT_STRUCT(cl_qmap_head(&systemp->Nodes), NodeData, SystemNodesEntry)->NodeInfo.NodeGUID);
XmlPrintHex64("SystemImageGUID", systemp->SystemImageGUID, indent+4);
break;
default:
break;
}
if (detail) {
for (p=cl_qmap_head(&systemp->Nodes); p != cl_qmap_end(&systemp->Nodes); p = cl_qmap_next(p)) {
NodeData *nodep = PARENT_STRUCT(p, NodeData, SystemNodesEntry);
if (! CompareNodePoint(nodep, focus))
continue;
ShowNodeBriefSummary(nodep, focus, TRUE, format, indent+4, detail-1);
}
}
if (format == FORMAT_XML) {
printf("%*s</BriefSystem>\n", indent, "");
}
}
void ShowSystemBriefSummaryHeadings(Format_t format, int indent, int detail)
{
switch (format) {
case FORMAT_TEXT:
printf("%*sSystemImage GUID\n", indent, "");
if (detail)
ShowNodeBriefSummaryHeadings(format, indent+4, detail-1);
break;
case FORMAT_XML:
break;
default:
break;
}
}
void ShowSMBriefSummary(SMData *smp, Format_t format, int indent, int detail)
{
switch (format) {
case FORMAT_TEXT:
if (g_hard || g_persist)
printf("%*sxxxxxxxxxxx 0x%016"PRIx64" %.*s\n",
indent, "",
smp->portp->nodep->NodeInfo.NodeGUID,
NODE_DESCRIPTION_ARRAY_SIZE,
g_noname?g_name_marker:(char*)smp->portp->nodep->NodeDesc.NodeString);
else
printf("%*s%-11s 0x%016"PRIx64" %.*s\n",
indent, "",
IbSMStateToText(smp->SMInfoRecord.SMInfo.u.s.SMStateCurrent),
smp->portp->nodep->NodeInfo.NodeGUID,
NODE_DESCRIPTION_ARRAY_SIZE,
g_noname?g_name_marker:(char*)smp->portp->nodep->NodeDesc.NodeString);
if (smp->portp->nodep->enodep && smp->portp->nodep->enodep->details) {
printf("%*sNodeDetails: %s\n", indent+4, "", smp->portp->nodep->enodep->details);
}
if (smp->esmp && smp->esmp->details) {
printf("%*sSMDetails: %s\n", indent+4, "", smp->esmp->details);
}
break;
case FORMAT_XML:
printf("%*s<SM id=\"0x%016"PRIx64":%u\">\n", indent, "",
smp->portp->nodep->NodeInfo.NodeGUID,
smp->portp->PortNum);
if ( ! (g_hard || g_persist)) {
XmlPrintStr("SMState",
IbSMStateToText(smp->SMInfoRecord.SMInfo.u.s.SMStateCurrent),
indent+4);
XmlPrintDec("SMState_Int",
smp->SMInfoRecord.SMInfo.u.s.SMStateCurrent, indent+4);
}
XmlPrintHex64("NodeGUID",
smp->portp->nodep->NodeInfo.NodeGUID,
indent+4);
XmlPrintNodeDesc(
(char*)smp->portp->nodep->NodeDesc.NodeString, indent+4);
if (smp->portp->nodep->enodep && smp->portp->nodep->enodep->details) {
XmlPrintOptionalStr("NodeDetails", smp->portp->nodep->enodep->details, indent+4);
}
if (smp->esmp && smp->esmp->details) {
XmlPrintOptionalStr("SMDetails", smp->esmp->details, indent+4);
}
// we output this additional information to aid topology SM verify
XmlPrintDec("PortNum", smp->portp->PortNum, indent+4);
if (smp->portp->PortGUID) {
XmlPrintHex64("PortGUID", smp->portp->PortGUID, indent+4);
}
XmlPrintNodeType(smp->portp->nodep->NodeInfo.NodeType,
indent+4);
printf("%*s</SM>\n", indent, "");
break;
default:
break;
}
}
void ShowSMBriefSummaryHeadings(Format_t format, int indent, int detail)
{
switch (format) {
case FORMAT_TEXT:
printf("%*sState GUID Name\n", indent, "");
break;
case FORMAT_XML:
break;
default:
break;
}
}
void ShowVerifySMBriefSummary(SMData *smp,
boolean close_sm, Format_t format, int indent, int detail)
{
switch (format) {
case FORMAT_TEXT:
printf("%*s0x%016"PRIx64" %3u", indent, "",
smp->portp->nodep->NodeInfo.NodeGUID,
smp->portp->PortNum);
if (smp->portp->PortGUID)
printf(" 0x%016"PRIx64, smp->portp->PortGUID);
else
printf(" ");
printf(" %s %.*s\n",
StlNodeTypeToText(smp->portp->nodep->NodeInfo.NodeType),
NODE_DESCRIPTION_ARRAY_SIZE,
g_noname?g_name_marker:(char*)smp->portp->nodep->NodeDesc.NodeString);
if (smp->portp->nodep->enodep && smp->portp->nodep->enodep->details) {
printf("%*sNodeDetails: %s\n", indent+4, "", smp->portp->nodep->enodep->details);
}
if (smp->esmp && smp->esmp->details) {
printf("%*sSMDetails: %s\n", indent+4, "", smp->esmp->details);
}
break;
case FORMAT_XML:
printf("%*s<SM id=\"0x%016"PRIx64":%u\">\n", indent, "",
smp->portp->nodep->NodeInfo.NodeGUID,
smp->portp->PortNum);
XmlPrintHex64("NodeGUID",
smp->portp->nodep->NodeInfo.NodeGUID,
indent+4);
XmlPrintDec("PortNum", smp->portp->PortNum, indent+4);
if (smp->portp->PortGUID) {
XmlPrintHex64("PortGUID", smp->portp->PortGUID, indent+4);
}
XmlPrintNodeType(smp->portp->nodep->NodeInfo.NodeType,
indent+4);
XmlPrintNodeDesc(
(char*)smp->portp->nodep->NodeDesc.NodeString, indent+4);
if (smp->portp->nodep->enodep && smp->portp->nodep->enodep->details) {
XmlPrintOptionalStr("NodeDetails", smp->portp->nodep->enodep->details, indent+4);
}
if (smp->esmp && smp->esmp->details) {
XmlPrintOptionalStr("SMDetails", smp->esmp->details, indent+4);
}
if (close_sm)
printf("%*s</SM>\n", indent, "");
break;
default:
break;
}
}
void ShowExpectedSMBriefSummary(const char *prefix, ExpectedSM *esmp,
const char *xml_tag, boolean close_sm, Format_t format, int indent, int detail)
{
switch (format) {
case FORMAT_TEXT:
printf("%*s%s", indent, "", prefix);
if (esmp->NodeGUID)
printf("0x%016"PRIx64, esmp->NodeGUID);
else
printf(" ");
if (esmp->gotPortNum)
printf(" %3u", esmp->PortNum);
else
printf(" ");
if (esmp->PortGUID)
printf(" 0x%016"PRIx64, esmp->PortGUID);
else
printf(" ");
if (esmp->NodeType)
printf(" %s", StlNodeTypeToText(esmp->NodeType));
else
printf(" ");
if (esmp->NodeDesc)
printf(" %s\n", g_noname?g_name_marker:esmp->NodeDesc);
else
printf("\n");
if (esmp->smp && esmp->smp->portp->nodep->enodep && esmp->smp->portp->nodep->enodep->details)
printf("%*sNodeDetails: %s\n", indent+4, "", esmp->smp->portp->nodep->enodep->details);
if (esmp->details)
printf("%*sSMDetails: %s\n", indent+4, "", esmp->details);
break;
case FORMAT_XML:
printf("%*s<%s id=\"0x%016"PRIx64"\">\n", indent, "",
xml_tag, (uint64)(uintn)esmp);
if (esmp->NodeGUID)
XmlPrintHex64("NodeGUID", esmp->NodeGUID, indent+4);
if (esmp->gotPortNum)
XmlPrintDec("PortNum", esmp->PortNum, indent+4);
if (esmp->NodeType)
XmlPrintNodeType(esmp->NodeType, indent+4);
if (esmp->NodeDesc)
XmlPrintNodeDesc(esmp->NodeDesc, indent+4);
if (esmp->smp && esmp->smp->portp->nodep->enodep && esmp->smp->portp->nodep->enodep->details)
XmlPrintOptionalStr("NodeDetails", esmp->smp->portp->nodep->enodep->details, indent+4);
if (esmp->details)
XmlPrintOptionalStr("SMDetails", esmp->details, indent+4);
if (esmp->PortGUID) {
XmlPrintHex64("PortGUID", esmp->PortGUID, indent+4);
}
if (close_sm)
printf("%*s</%s>\n", indent, "", xml_tag);
break;
default:
break;
}
}
void ShowVerifySMBriefSummaryHeadings(Format_t format, int indent, int detail)
{
switch (format) {
case FORMAT_TEXT:
printf("%*sNodeGUID Port PortGUID Type Name\n", indent, "");
break;
case FORMAT_XML:
break;
default:
break;
}
}
// output brief summary of IB SMs
void ShowAllSMBriefSummary(Point *focus, Format_t format, int indent, int detail)
{
uint32 count = 0;
cl_map_item_t *p;
switch (format) {
case FORMAT_TEXT:
printf("%*s%u Connected SMs in Fabric%s\n", indent, "", (unsigned)cl_qmap_count(&g_Fabric.AllSMs), detail?":":"");
break;
case FORMAT_XML:
printf("%*s<SMs>\n", indent, "");
indent+=4;
XmlPrintDec("ConnectedSMCount", (unsigned)cl_qmap_count(&g_Fabric.AllSMs), indent);
break;
default:
break;
}
for (p=cl_qmap_head(&g_Fabric.AllSMs); p != cl_qmap_end(&g_Fabric.AllSMs); p = cl_qmap_next(p)) {
SMData *smp = PARENT_STRUCT(p, SMData, AllSMsEntry);
if (! CompareSmPoint(smp, focus))
continue;
if (detail) {
if (! count)
ShowSMBriefSummaryHeadings(format, indent, detail-1);
ShowSMBriefSummary(smp, format, indent, detail-1);
}
count++;
}
switch (format) {
case FORMAT_TEXT:
if (PointValid(focus))
printf("%*s%u Matching SMs Found\n", indent, "", count);
break;
case FORMAT_XML:
if (PointValid(focus))
XmlPrintDec("MatchingSMs", count, indent+4);
indent-=4;
printf("%*s</SMs>\n", indent, "");
break;
default:
break;
}
}
// output verbose summary of all IB Components (Systems, Nodes, Ports)
void ShowComponentBriefReport(Point *focus, Format_t format, int indent, int detail)
{
cl_map_item_t *p;
uint32 count = 0;
switch (format) {
case FORMAT_TEXT:
printf("%*sComponent Brief Summary\n", indent, "");
break;
case FORMAT_XML:
printf("%*s<Components>\n", indent, "");
indent+=4;
break;
default:
break;
}
ShowPointFocus(focus, FIND_FLAG_FABRIC, format, indent, detail);
switch (format) {
case FORMAT_TEXT:
printf("%*s%u Connected Systems in Fabric%s\n", indent, "", (unsigned)cl_qmap_count(&g_Fabric.AllSystems), detail?":":"");
break;
case FORMAT_XML:
printf("%*s<Systems>\n", indent, "");
indent+=4;
XmlPrintDec("ConnectedSystemCount", (unsigned)cl_qmap_count(&g_Fabric.AllSystems), indent);
break;
default:
break;
}
for (p=cl_qmap_head(&g_Fabric.AllSystems); p != cl_qmap_end(&g_Fabric.AllSystems); p = cl_qmap_next(p)) {
SystemData *systemp = PARENT_STRUCT(p, SystemData, AllSystemsEntry);
if (! CompareSystemPoint(systemp, focus))
continue;
if (detail) {
if (! count)
ShowSystemBriefSummaryHeadings(format, indent, detail-1);
ShowSystemBriefSummary(systemp, focus, format, indent, detail-1);
}
count++;
}
switch (format) {
case FORMAT_TEXT:
if (PointValid(focus))
printf("%*s%u Matching Systems Found\n", indent, "", count);
printf("\n");
break;
case FORMAT_XML:
if (PointValid(focus))
XmlPrintDec("MatchingSystems", count, indent);
indent-=4;
printf("%*s</Systems>\n", indent, "");
break;
default:
break;
}
ShowAllSMBriefSummary(focus, format, indent, detail);
switch (format) {
case FORMAT_TEXT:
DisplaySeparator();
break;
case FORMAT_XML:
indent-=4;
printf("%*s</Components>\n", indent, "");
break;
default:
break;
}
}
// output brief summary of all IB Node Types
void ShowNodeTypeBriefReport(Point *focus, Format_t format, report_t report, int indent, int detail)
{
LIST_ITEM *p;
uint32 count;
switch (format) {
case FORMAT_TEXT:
printf("%*sNode Type Brief Summary\n", indent, "");
break;
case FORMAT_XML:
printf("%*s<Nodes>\n", indent, "");
indent+=4;
break;
default:
break;
}
ShowPointFocus(focus, FIND_FLAG_FABRIC, format, indent, detail);
switch (format) {
case FORMAT_TEXT:
printf("%*s%u Connected FIs in Fabric%s\n", indent, "", (unsigned)QListCount(&g_Fabric.AllFIs), detail?":":"");
break;
case FORMAT_XML:
printf("%*s<FIs>\n", indent, "");
indent+=4;
XmlPrintDec("ConnectedFICount", (unsigned)QListCount(&g_Fabric.AllFIs), indent);
break;
default:
break;
}
count = 0;
for (p=QListHead(&g_Fabric.AllFIs); p != NULL; p = QListNext(&g_Fabric.AllFIs, p)) {
NodeData *nodep = (NodeData *)QListObj(p);
if (! CompareNodePoint(nodep, focus))
continue;
if (detail) {
if (! count)
ShowNodeBriefSummaryHeadings(format, indent, detail-1);
if (report == REPORT_TOPOLOGY)
ShowTopologyNodeBriefSummary(nodep, focus, indent, detail-1);
else
ShowNodeBriefSummary(nodep, focus, TRUE, format, indent, detail-1);
}
count++;
}
switch (format) {
case FORMAT_TEXT:
if (PointValid(focus))
printf("%*s%u Matching FI Found\n", indent, "", count);
if (detail)
printf("\n");
break;
case FORMAT_XML:
if (PointValid(focus))
XmlPrintDec("MatchingFIs", count, indent);
indent-=4;
printf("%*s</FIs>\n", indent, "");
break;
default:
break;
}
switch (format) {
case FORMAT_TEXT:
printf("%*s%u Connected Switches in Fabric%s\n", indent, "", (unsigned)QListCount(&g_Fabric.AllSWs), detail?":":"");
break;
case FORMAT_XML:
printf("%*s<Switches>\n", indent, "");
indent+=4;
XmlPrintDec("ConnectedSwitchCount", (unsigned)QListCount(&g_Fabric.AllSWs), indent);
break;
default:
break;
}
count = 0;
for (p=QListHead(&g_Fabric.AllSWs); p != NULL; p = QListNext(&g_Fabric.AllSWs, p)) {
NodeData *nodep = (NodeData *)QListObj(p);
if (! CompareNodePoint(nodep, focus))
continue;
if (detail) {
if (! count)
ShowNodeBriefSummaryHeadings(format, indent, detail-1);
if (report == REPORT_TOPOLOGY)
ShowTopologyNodeBriefSummary(nodep, focus, indent, detail-1);
else
ShowNodeBriefSummary(nodep, focus, TRUE, format, indent, detail-1);
}
count++;
}
switch (format) {
case FORMAT_TEXT:
if (PointValid(focus))
printf("%*s%u Matching Switches Found\n", indent, "", count);
if (detail)
printf("\n");
break;
case FORMAT_XML:
if (PointValid(focus))
XmlPrintDec("MatchingSwitches", count, indent);
indent-=4;
printf("%*s</Switches>\n", indent, "");
break;
default:
break;
}
ShowAllSMBriefSummary(focus, format, indent, detail);
switch (format) {
case FORMAT_TEXT:
DisplaySeparator();
break;
case FORMAT_XML:
indent-=4;
printf("%*s</Nodes>\n", indent, "");
break;
default:
break;
}
}
static _inline
boolean PortCounterBelowThreshold(uint32 value, uint32 threshold)
{
return (threshold && value < threshold);
}
static _inline
boolean PortCounterExceedsThreshold(uint32 value, uint32 threshold)
{
return (threshold && value > threshold - g_threshold_compare);
}
static _inline
boolean PortCounterExceedsThreshold64(uint64 value, uint64 threshold)
{
return (threshold && value > threshold - g_threshold_compare);
}
// check the last port counters against the new vs threshold
// returns: TRUE - one or more counters exceed threshold
// FALSE - all counters below threshold
static boolean PortCountersExceedThreshold(PortData *portp)
{
STL_PORT_COUNTERS_DATA *pPortCounters = portp->pPortCounters;
if (! pPortCounters)
return FALSE;
#define EXCEEDS_THRESHOLD(field) \
PortCounterExceedsThreshold(pPortCounters->field, g_Thresholds.field)
#define EXCEEDS_THRESHOLD64(field) \
PortCounterExceedsThreshold64(pPortCounters->field, g_Thresholds.field)
#define BELOW_THRESHOLD_LQI(field) \
PortCounterBelowThreshold(pPortCounters->lq.s.field, g_Thresholds.lq.s.field)
#define EXCEEDS_THRESHOLD_NLD(field) \
PortCounterExceedsThreshold(pPortCounters->lq.s.field, g_Thresholds.lq.s.field)
// Data movement
return EXCEEDS_THRESHOLD64(portXmitData)
|| EXCEEDS_THRESHOLD64(portRcvData)
|| EXCEEDS_THRESHOLD64(portXmitPkts)
|| EXCEEDS_THRESHOLD64(portRcvPkts)
|| EXCEEDS_THRESHOLD64(portMulticastXmitPkts)
|| EXCEEDS_THRESHOLD64(portMulticastRcvPkts)
// Signal Integrity and Node/Link Stability
|| BELOW_THRESHOLD_LQI(linkQualityIndicator)
|| EXCEEDS_THRESHOLD(uncorrectableErrors)
|| EXCEEDS_THRESHOLD(linkDowned)
|| EXCEEDS_THRESHOLD64(portRcvErrors)
|| EXCEEDS_THRESHOLD64(fmConfigErrors)
|| EXCEEDS_THRESHOLD64(excessiveBufferOverruns)
|| EXCEEDS_THRESHOLD(linkErrorRecovery)
|| EXCEEDS_THRESHOLD64(localLinkIntegrityErrors)
|| EXCEEDS_THRESHOLD64(portRcvRemotePhysicalErrors)
|| EXCEEDS_THRESHOLD_NLD(numLanesDown)
// Security
|| EXCEEDS_THRESHOLD64(portXmitConstraintErrors)
|| EXCEEDS_THRESHOLD64(portRcvConstraintErrors)
// Routing or Down nodes still being sent to
|| EXCEEDS_THRESHOLD64(portRcvSwitchRelayErrors)
|| EXCEEDS_THRESHOLD64(portXmitDiscards)
// Congestion
|| EXCEEDS_THRESHOLD64(swPortCongestion)
|| EXCEEDS_THRESHOLD64(portRcvFECN)
|| EXCEEDS_THRESHOLD64(portRcvBECN)
|| EXCEEDS_THRESHOLD64(portMarkFECN)
|| EXCEEDS_THRESHOLD64(portXmitTimeCong)
|| EXCEEDS_THRESHOLD64(portXmitWait)
// Bubbles
|| EXCEEDS_THRESHOLD64(portXmitWastedBW)
|| EXCEEDS_THRESHOLD64(portXmitWaitData)
|| EXCEEDS_THRESHOLD64(portRcvBubble);
#undef EXCEEDS_THRESHOLD
#undef EXCEEDS_THRESHOLD64
#undef BELOW_THRESHOLD_LQI
#undef EXCEEDS_THRESHOLD_NLD
}
void ShowPortCounterBelowThreshold(const char* field, uint32 value, uint32 threshold, Format_t format, int indent, int detail)
{
if (PortCounterBelowThreshold(value, threshold))
{
switch (format) {
case FORMAT_TEXT:
printf("%*s%s: %u Below Threshold: %u\n",
indent, "", field, value, threshold);
break;
case FORMAT_XML:
// old format
printf("%*s<%s>\n", indent, "", field);
XmlPrintDec("Value", value, indent+4);
XmlPrintDec("LowerThreshold", threshold, indent+4);
printf("%*s</%s>\n", indent, "", field);
// new format
printf("%*s<%sValue>%u</%sValue>\n", indent, "", field, value, field);
printf("%*s<%sThreshold>%u</%sThreshold>\n", indent, "", field, threshold, field);
break;
default:
break;
}
}
}
void ShowPortCounterExceedingThreshold(const char* field, uint32 value, uint32 threshold, Format_t format, int indent, int detail)
{
if (PortCounterExceedsThreshold(value, threshold))
{
switch (format) {
case FORMAT_TEXT:
printf("%*s%s: %u Exceeds Threshold: %u\n",
indent, "", field, value, threshold);
break;
case FORMAT_XML:
// old format
printf("%*s<%s>\n", indent, "", field);
XmlPrintDec("Value", value, indent+4);
XmlPrintDec("Threshold", threshold, indent+4);
printf("%*s</%s>\n", indent, "", field);
// new format
printf("%*s<%sValue>%u</%sValue>\n", indent, "", field, value, field);
printf("%*s<%sThreshold>%u</%sThreshold>\n", indent, "", field, threshold, field);
break;
default:
break;
}
}
}
void ShowPortCounterExceedingThreshold64(const char* field, uint64 value, uint64 threshold, Format_t format, int indent, int detail)
{
if (PortCounterExceedsThreshold64(value, threshold))
{
switch (format) {
case FORMAT_TEXT:
printf("%*s%s: %"PRIu64" Exceeds Threshold: %"PRIu64"\n",
indent, "", field, value, threshold);
break;
case FORMAT_XML:
// old format
printf("%*s<%s>\n", indent, "", field);
XmlPrintDec64("Value", value, indent+4);
XmlPrintDec64("Threshold", threshold, indent+4);
printf("%*s</%s>\n", indent, "", field);
// new format
printf("%*s<%sValue>%"PRIu64"</%sValue>\n", indent, "", field, value, field);
printf("%*s<%sThreshold>%"PRIu64"</%sThreshold>\n", indent, "", field, threshold, field);
break;
default:
break;
}
}
}
void ShowPortCounterExceedingMbThreshold64(const char* field, uint64 value, uint64 threshold, Format_t format, int indent, int detail)
{
if (PortCounterExceedsThreshold(value, threshold))
{
switch (format) {
case FORMAT_TEXT:
printf("%*s%s: %"PRIu64" MB Exceeds Threshold: %u MB\n",
indent, "", field, value/FLITS_PER_MB, (unsigned int)(threshold/FLITS_PER_MB));
break;
case FORMAT_XML:
// old format
printf("%*s<%s>\n", indent, "", field);
XmlPrintDec64("ValueMB", value/FLITS_PER_MB, indent+4);
XmlPrintDec64("ThresholdMB", threshold/FLITS_PER_MB, indent+4);
printf("%*s</%s>\n", indent, "", field);
// new format
printf("%*s<%sValueMB>%"PRIu64"</%sValueMB>\n", indent, "", field, value/FLITS_PER_MB, field);
printf("%*s<%sThresholdMB>%u</%sThresholdMB>\n", indent, "", field, (unsigned int)(threshold/FLITS_PER_MB), field);
break;
default:
break;
}
}
}
void ShowLinkPortErrorSummary(PortData *portp, Format_t format, int indent, int detail)
{
STL_PORT_COUNTERS_DATA *pPortCounters = portp->pPortCounters;
if (! pPortCounters)
return;
#define SHOW_BELOW_LQI_THRESHOLD(field, name) \
ShowPortCounterBelowThreshold(#name, pPortCounters->lq.s.field, g_Thresholds.lq.s.field, format, indent, detail)
#define SHOW_EXCEEDING_THRESHOLD(field, name) \
ShowPortCounterExceedingThreshold(#name, pPortCounters->field, g_Thresholds.field, format, indent, detail)
#define SHOW_EXCEEDING_THRESHOLD64(field, name) \
ShowPortCounterExceedingThreshold64(#name, pPortCounters->field, g_Thresholds.field, format, indent, detail)
#define SHOW_EXCEEDING_MB_THRESHOLD(field, name) \
ShowPortCounterExceedingMbThreshold64(#name, pPortCounters->field, g_Thresholds.field, format, indent, detail)
#define SHOW_EXCEEDING_NLD_THRESHOLD(field, name) \
ShowPortCounterExceedingThreshold(#name, pPortCounters->lq.s.field, g_Thresholds.lq.s.field, format, indent, detail)
// Data movement
SHOW_EXCEEDING_MB_THRESHOLD(portXmitData, XmitData);
SHOW_EXCEEDING_MB_THRESHOLD(portRcvData, RcvData);
SHOW_EXCEEDING_THRESHOLD64(portXmitPkts, XmitPkts);
SHOW_EXCEEDING_THRESHOLD64(portRcvPkts, RcvPkts);
SHOW_EXCEEDING_THRESHOLD64(portMulticastXmitPkts, MulticastXmitPkts);
SHOW_EXCEEDING_THRESHOLD64(portMulticastRcvPkts, MulticastRcvPkts);
// Signal Integrity and Node/Link Stability
SHOW_BELOW_LQI_THRESHOLD(linkQualityIndicator, LinkQualityIndicator);
SHOW_EXCEEDING_THRESHOLD(linkDowned, LinkDowned);
SHOW_EXCEEDING_THRESHOLD(uncorrectableErrors, UncorrectableErrors);
SHOW_EXCEEDING_THRESHOLD64(fmConfigErrors, FMConfigErrors);
SHOW_EXCEEDING_THRESHOLD64(portRcvErrors, RcvErrors);
SHOW_EXCEEDING_THRESHOLD64(excessiveBufferOverruns, ExcessiveBufferOverruns);
SHOW_EXCEEDING_THRESHOLD(linkErrorRecovery, LinkErrorRecovery);
SHOW_EXCEEDING_THRESHOLD64(localLinkIntegrityErrors, LocalLinkIntegrityErrors);
SHOW_EXCEEDING_THRESHOLD64(portRcvRemotePhysicalErrors, RcvRemotePhysicalErrors);
SHOW_EXCEEDING_NLD_THRESHOLD(numLanesDown, NumLanesDown);
// Security
SHOW_EXCEEDING_THRESHOLD64(portXmitConstraintErrors, XmitConstraintErrors);
SHOW_EXCEEDING_THRESHOLD64(portRcvConstraintErrors, RcvConstraintErrors);
// Routing or Down nodes still being sent to
SHOW_EXCEEDING_THRESHOLD64(portRcvSwitchRelayErrors, RcvSwitchRelayErrors);
SHOW_EXCEEDING_THRESHOLD64(portXmitDiscards, XmitDiscards);
// Congestion
SHOW_EXCEEDING_THRESHOLD64(swPortCongestion, CongDiscards);
SHOW_EXCEEDING_THRESHOLD64(portRcvFECN, RcvFECN);
SHOW_EXCEEDING_THRESHOLD64(portRcvBECN, RcvBECN);
SHOW_EXCEEDING_THRESHOLD64(portMarkFECN, MarkFECN);
SHOW_EXCEEDING_THRESHOLD64(portXmitTimeCong, XmitTimeCong);
SHOW_EXCEEDING_THRESHOLD64(portXmitWait, XmitWait);
// Bubbles
SHOW_EXCEEDING_THRESHOLD64(portXmitWastedBW, XmitWastedBW);
SHOW_EXCEEDING_THRESHOLD64(portXmitWaitData, XmitWaitData);
SHOW_EXCEEDING_THRESHOLD64(portRcvBubble, RcvBubble);
#undef SHOW_BELOW_LQI_THRESHOLD
#undef SHOW_EXCEEDING_THRESHOLD
#undef SHOW_EXCEEDING_THRESHOLD64
#undef SHOW_EXCEEDING_MB_THRESHOLD
#undef SHOW_EXCEEDING_NLD_THRESHOLD
}
// returns TRUE if thresholds are configured
boolean ShowThresholds(Format_t format, int indent, int detail)
{
boolean didoutput = FALSE;
switch (format) {
case FORMAT_TEXT:
printf("%*sConfigured Thresholds:\n",indent, "");
break;
case FORMAT_XML:
printf("%*s<ConfiguredThresholds>\n",indent, "");
break;
default:
break;
}
#define SHOW_THRESHOLD(field, name) \
do { if (g_Thresholds.field) { switch (format) { \
case FORMAT_TEXT: printf("%*s%-30s %lu\n", indent+4, "", #name, (uint64)g_Thresholds.field); break; \
case FORMAT_XML: printf("%*s<%s>%lu</%s>\n", indent+4, "", #name, (uint64)g_Thresholds.field, #name); break; \
default: break; } didoutput = TRUE; } } while (0)
#define SHOW_THRESHOLD_LQI_NLD(field, name) \
do { if (g_Thresholds.lq.s.field) { switch (format) { \
case FORMAT_TEXT: printf("%*s%-30s %lu\n", indent+4, "", #name, (uint64)g_Thresholds.lq.s.field); break; \
case FORMAT_XML: printf("%*s<%s>%lu</%s>\n", indent+4, "", #name, (uint64)g_Thresholds.lq.s.field, #name); break; \
default: break; } didoutput = TRUE; } } while (0)
#define SHOW_MB_THRESHOLD(field, name) \
do { if (g_Thresholds.field) { switch (format) { \
case FORMAT_TEXT: printf("%*s%-30s %lu MB\n", indent+4, "", #name, (uint64)g_Thresholds.field/FLITS_PER_MB); break; \
case FORMAT_XML: printf("%*s<%sMB>%lu</%sMB>\n", indent+4, "", #name, (uint64)g_Thresholds.field/FLITS_PER_MB, #name); break; \
default: break; } didoutput = TRUE; } } while (0)
// Data movement
SHOW_MB_THRESHOLD(portXmitData, XmitData);
SHOW_MB_THRESHOLD(portRcvData, RcvData);
SHOW_THRESHOLD(portXmitPkts, XmitPkts);
SHOW_THRESHOLD(portRcvPkts, RcvPkts);
SHOW_THRESHOLD(portMulticastXmitPkts, MulticastXmitPkts);
SHOW_THRESHOLD(portMulticastRcvPkts, MulticastRcvPkts);
// Signal Integrity and Node/Link Stability
SHOW_THRESHOLD_LQI_NLD(linkQualityIndicator, LinkQualityIndicator);
SHOW_THRESHOLD(uncorrectableErrors, UncorrectableErrors);
SHOW_THRESHOLD(linkDowned, LinkDowned);
SHOW_THRESHOLD(portRcvErrors, RcvErrors);
SHOW_THRESHOLD(excessiveBufferOverruns, ExcessiveBufferOverruns);
SHOW_THRESHOLD(fmConfigErrors, FMConfigErrors);
SHOW_THRESHOLD(linkErrorRecovery, LinkErrorRecovery);
SHOW_THRESHOLD(localLinkIntegrityErrors, LocalLinkIntegrityErrors);
SHOW_THRESHOLD(portRcvRemotePhysicalErrors, RcvRemotePhysicalErrors);
SHOW_THRESHOLD_LQI_NLD(numLanesDown, NumLanesDown);
// Security
SHOW_THRESHOLD(portXmitConstraintErrors, XmitConstraintErrors);
SHOW_THRESHOLD(portRcvConstraintErrors, RcvConstraintErrors);
// Routing or Down nodes still being sent to
SHOW_THRESHOLD(portRcvSwitchRelayErrors, RcvSwitchRelayErrors);
SHOW_THRESHOLD(portXmitDiscards, XmitDiscards);
// Congestion
SHOW_THRESHOLD(swPortCongestion, CongDiscards);
SHOW_THRESHOLD(portRcvFECN, RcvFECN);
SHOW_THRESHOLD(portRcvBECN, RcvBECN);
SHOW_THRESHOLD(portMarkFECN, MarkFECN);
SHOW_THRESHOLD(portXmitTimeCong, XmitTimeCong);
SHOW_THRESHOLD(portXmitWait, XmitWait);
// Bubbles
SHOW_THRESHOLD(portXmitWastedBW, XmitWastedBW);
SHOW_THRESHOLD(portXmitWaitData, XmitWaitData);
SHOW_THRESHOLD(portRcvBubble, RcvBubble);
switch (format) {
case FORMAT_TEXT:
if (! didoutput)
printf("%*sNone\n", indent+4, "");
break;
case FORMAT_XML:
printf("%*s</ConfiguredThresholds>\n",indent, "");
break;
default:
break;
}
#undef SHOW_THRESHOLD
#undef SHOW_MB_THRESHOLD
#undef SHOW_THRESHOLD_LQI_NLD
return didoutput;
}
// returns TRUE if thresholds are configured for any counters
boolean NeedClearCounters(void)
{
boolean needclear = FALSE;
#define CHECK_COUNTER(field) \
do { needclear |= (0 != g_CounterSelectMask.CounterSelectMask.s.field); } while(0)
// Data movement
CHECK_COUNTER(PortXmitData);
CHECK_COUNTER(PortRcvData);
CHECK_COUNTER(PortXmitPkts);
CHECK_COUNTER(PortRcvPkts);
CHECK_COUNTER(PortMulticastXmitPkts);
CHECK_COUNTER(PortMulticastRcvPkts);
// Signal Integrity and Node/Link Stability
// LinkQualityIndicator N/A since readonly can't clear
CHECK_COUNTER(UncorrectableErrors);
CHECK_COUNTER(LinkDowned);
CHECK_COUNTER(PortRcvErrors);
CHECK_COUNTER(ExcessiveBufferOverruns);
CHECK_COUNTER(FMConfigErrors);
CHECK_COUNTER(LinkErrorRecovery);
CHECK_COUNTER(LocalLinkIntegrityErrors);
CHECK_COUNTER(PortRcvRemotePhysicalErrors);
// Security
CHECK_COUNTER(PortXmitConstraintErrors);
CHECK_COUNTER(PortRcvConstraintErrors);
// Routing or Down nodes still being sent to
CHECK_COUNTER(PortRcvSwitchRelayErrors);
CHECK_COUNTER(PortXmitDiscards);
// Congestion
CHECK_COUNTER(SwPortCongestion);
CHECK_COUNTER(PortRcvFECN);
CHECK_COUNTER(PortRcvBECN);
CHECK_COUNTER(PortMarkFECN);
CHECK_COUNTER(PortXmitTimeCong);
CHECK_COUNTER(PortXmitWait);
// Bubbles
CHECK_COUNTER(PortXmitWastedBW);
CHECK_COUNTER(PortXmitWaitData);
CHECK_COUNTER(PortRcvBubble);
#undef CHECK_COUNTER
return needclear;
}
// returns TRUE if thresholds are configured or clearall
boolean ShowClearedCounters(Format_t format, int indent, int detail, boolean clearall)
{
boolean didoutput = FALSE;
switch (format) {
case FORMAT_TEXT:
printf("%*sConfigured Counters to Clear:\n",indent, "");
break;
case FORMAT_XML:
printf("%*s<ClearedCounters>\n",indent, "");
break;
default:
break;
}
#define SHOW_COUNTER(field, name) \
do { if (clearall || g_CounterSelectMask.CounterSelectMask.s.field) { switch (format) { case FORMAT_TEXT: printf("%*s%-30s\n", indent+4, "", #name); break; case FORMAT_XML: printf("%*s<%s></%s>\n", indent+4, "", #name, #name); break; default: break; } didoutput = TRUE; } } while (0)
// Data movement
SHOW_COUNTER(PortXmitData, XmitData);
SHOW_COUNTER(PortRcvData, RcvData);
SHOW_COUNTER(PortXmitPkts, XmitPkts);
SHOW_COUNTER(PortRcvPkts, RcvPkts);
SHOW_COUNTER(PortMulticastXmitPkts, MulticastXmitPkts);
SHOW_COUNTER(PortMulticastRcvPkts, MulticastRcvPkts);
// Signal Integrity and Node/Link Stability
// LinkQualityIndicator N/A since readonly can't clear
SHOW_COUNTER(UncorrectableErrors, UncorrectableErrors);
SHOW_COUNTER(LinkDowned, LinkDowned);
SHOW_COUNTER(PortRcvErrors, RcvErrors);
SHOW_COUNTER(ExcessiveBufferOverruns, ExcessiveBufferOverruns);
SHOW_COUNTER(FMConfigErrors, FMConfigErrors);
SHOW_COUNTER(LinkErrorRecovery, LinkErrorRecovery);
SHOW_COUNTER(LocalLinkIntegrityErrors, LocalLinkIntegrityErrors);
SHOW_COUNTER(PortRcvRemotePhysicalErrors, RcvRemotePhysicalErrors);
// Security
SHOW_COUNTER(PortXmitConstraintErrors, XmitConstraintErrors);
SHOW_COUNTER(PortRcvConstraintErrors, RcvConstraintErrors);
// Routing or Down nodes still being sent to
SHOW_COUNTER(PortRcvSwitchRelayErrors, RcvSwitchRelayErrors);
SHOW_COUNTER(PortXmitDiscards, XmitDiscards);
// Congestion
SHOW_COUNTER(SwPortCongestion, CongDiscards);
SHOW_COUNTER(PortRcvFECN, RcvFECN);
SHOW_COUNTER(PortRcvBECN, RcvBECN);
SHOW_COUNTER(PortMarkFECN, MarkFECN);
SHOW_COUNTER(PortXmitTimeCong, XmitTimeCong);
SHOW_COUNTER(PortXmitWait, XmitWait);
// Bubbles
SHOW_COUNTER(PortXmitWastedBW, XmitWastedBW);
SHOW_COUNTER(PortXmitWaitData, XmitWaitData);
SHOW_COUNTER(PortRcvBubble, RcvBubble);
switch (format) {
case FORMAT_TEXT:
if (! didoutput)
printf("%*sNone\n", indent+4, "");
break;
case FORMAT_XML:
printf("%*s</ClearedCounters>\n",indent, "");
break;
default:
break;
}
#undef SHOW_COUNTER
return didoutput;
}
void ShowSlowLinkPortSummaryHeader(LinkReport_t report, Format_t format, int indent, int detail)
{
ShowLinkBriefSummaryHeader(format, indent, detail);
if (detail) {
switch (format) {
case FORMAT_TEXT:
switch (report) {
case LINK_EXPECTED_REPORT:
printf("%*s Active Enabled\n", indent+4, "");
printf("%*s Lanes, Used(Tx), Used(Rx), Rate, Lanes, DownTo, Rates\n", indent+4, "");
break;
case LINK_CONFIG_REPORT:
printf("%*s Enabled Supported\n", indent+4, "");
printf("%*s Lanes, Used, Rate, Lanes, DownTo, Rates\n", indent+4, "");
break;
case LINK_CONN_REPORT:
printf("%*s Supported\n", indent+4, "");
printf("%*s Lanes, DownTo, Rate\n", indent+4, "");
break;
}
DisplaySeparator();
break;
case FORMAT_XML:
break;
default:
break;
}
}
}
void ShowSlowLinkReasonSummary(LinkReport_t report, PortData *portp, Format_t format, int indent, int detail)
{
char buf1[SHOW_BUF_SIZE], buf2[SHOW_BUF_SIZE], buf3[SHOW_BUF_SIZE], buf4[SHOW_BUF_SIZE];
char buf5[SHOW_BUF_SIZE], buf6[SHOW_BUF_SIZE], buf7[SHOW_BUF_SIZE];
switch (format) {
case FORMAT_TEXT:
switch (report) {
case LINK_EXPECTED_REPORT:
printf("%*s %-6s %-9s %-9s %-8s %-9s %-8s %-12s\n", indent, "",
StlLinkWidthToText(portp->PortInfo.LinkWidth.Active, buf1, sizeof(buf1)),
StlLinkWidthToText(portp->PortInfo.LinkWidthDowngrade.TxActive, buf5, sizeof(buf5)),
StlLinkWidthToText(portp->PortInfo.LinkWidthDowngrade.RxActive, buf7, sizeof(buf7)),
StlLinkSpeedToText(portp->PortInfo.LinkSpeed.Active, buf2, sizeof(buf2)),
StlLinkWidthToText(portp->PortInfo.LinkWidth.Enabled, buf3, sizeof(buf3)),
StlLinkWidthToText(portp->PortInfo.LinkWidthDowngrade.Enabled, buf6, sizeof(buf6)),
StlLinkSpeedToText(portp->PortInfo.LinkSpeed.Enabled, buf4, sizeof(buf4)));
break;
case LINK_CONFIG_REPORT:
printf("%*s %-8s %-7s %-13s %-9s %-8s %-12s\n", indent, "",
StlLinkWidthToText(portp->PortInfo.LinkWidth.Enabled, buf1, sizeof(buf1)),
StlLinkWidthToText(portp->PortInfo.LinkWidthDowngrade.Enabled, buf5, sizeof(buf5)),
StlLinkSpeedToText(portp->PortInfo.LinkSpeed.Enabled, buf2, sizeof(buf2)),
StlLinkWidthToText(portp->PortInfo.LinkWidth.Supported, buf3, sizeof(buf3)),
StlLinkWidthToText(portp->PortInfo.LinkWidthDowngrade.Supported, buf6, sizeof(buf6)),
StlLinkSpeedToText(portp->PortInfo.LinkSpeed.Supported, buf4, sizeof(buf4)));
break;
case LINK_CONN_REPORT:
printf("%*s %-12s %-12s %-12s\n", indent, "",
StlLinkWidthToText(portp->PortInfo.LinkWidth.Supported, buf1, sizeof(buf1)),
StlLinkWidthToText(portp->PortInfo.LinkWidthDowngrade.Supported, buf5, sizeof(buf5)),
StlLinkSpeedToText(portp->PortInfo.LinkSpeed.Supported, buf2, sizeof(buf2)));
break;
}
break;
case FORMAT_XML:
switch (report) {
case LINK_EXPECTED_REPORT:
XmlPrintLinkWidth("LinkWidthActive",
portp->PortInfo.LinkWidth.Active, indent);
XmlPrintLinkWidth("LinkWidthDnGradeTxActive",
portp->PortInfo.LinkWidthDowngrade.TxActive, indent);
XmlPrintLinkWidth("LinkWidthDnGradeRxActive",
portp->PortInfo.LinkWidthDowngrade.RxActive, indent);
XmlPrintLinkSpeed("LinkSpeedActive",
portp->PortInfo.LinkSpeed.Active, indent);
XmlPrintLinkWidth("LinkWidthEnabled",
portp->PortInfo.LinkWidth.Enabled, indent);
XmlPrintLinkWidth("LinkWidthDnGradeEnabled",
portp->PortInfo.LinkWidthDowngrade.Enabled, indent);
XmlPrintLinkSpeed("LinkSpeedEnabled",
portp->PortInfo.LinkSpeed.Enabled, indent);
break;
case LINK_CONFIG_REPORT:
XmlPrintLinkWidth("LinkWidthEnabled",
portp->PortInfo.LinkWidth.Enabled, indent);
XmlPrintLinkWidth("LinkWidthDnGradeEnabled",
portp->PortInfo.LinkWidthDowngrade.Enabled, indent);
XmlPrintLinkSpeed("LinkSpeedEnabled",
portp->PortInfo.LinkSpeed.Enabled, indent);
XmlPrintLinkWidth("LinkWidthSupported",
portp->PortInfo.LinkWidth.Supported, indent);
XmlPrintLinkWidth("LinkWidthDnGradeSupported",
portp->PortInfo.LinkWidthDowngrade.Supported, indent);
XmlPrintLinkSpeed("LinkSpeedSupported",
portp->PortInfo.LinkSpeed.Supported, indent);
break;
case LINK_CONN_REPORT:
XmlPrintLinkWidth("LinkWidthSupported",
portp->PortInfo.LinkWidth.Supported, indent);
XmlPrintLinkWidth("LinkWidthDnGradeSupported",
portp->PortInfo.LinkWidthDowngrade.Supported, indent);
XmlPrintLinkSpeed("LinkSpeedSupported",
portp->PortInfo.LinkSpeed.Supported, indent);
break;
}
break;
default:
break;
}
}
void ShowSlowLinkReasonSummaryCallback(uint64 context, PortData *portp,
Format_t format, int indent, int detail)
{
ShowSlowLinkReasonSummary((LinkReport_t)context, portp, format, indent, detail);
}
void ShowSlowLinkSummary(LinkReport_t report, PortData *portp1, Format_t format, int indent, int detail)
{
ShowLinkFromBriefSummary(portp1,
(uint64)(uintn)report, ShowSlowLinkReasonSummaryCallback,
format, indent, detail);
ShowLinkToBriefSummary(portp1->neighbor, "<-> ", TRUE,
(uint64)(uintn)report, ShowSlowLinkReasonSummaryCallback,
format, indent, detail);
}
void ShowLinkPortErrorSummaryCallback(uint64 context, PortData *portp,
Format_t format, int indent, int detail)
{
ShowLinkPortErrorSummary(portp, format, indent, detail);
}
// show link errors from portp1 to its neighbor
void ShowLinkErrorSummary(PortData *portp1, Format_t format, int indent, int detail)
{
ShowLinkFromBriefSummary(portp1, 0, ShowLinkPortErrorSummaryCallback, format, indent, detail);
ShowLinkToBriefSummary(portp1->neighbor, "<-> ", TRUE, 0, ShowLinkPortErrorSummaryCallback, format, indent, detail);
}
// output summary of Links for given report
void ShowLinksReport(Point *focus, report_t report, Format_t format, int indent, int detail)
{
LIST_ITEM *p;
uint32 count = 0;
char *xml_prefix = "";
char *prefix = "";
switch (report) {
default: // should not happen, but just in case
ASSERT(0);
case REPORT_LINKS:
xml_prefix = "";
prefix = "";
break;
case REPORT_EXTLINKS:
xml_prefix = "Ext";
prefix = "External ";
break;
case REPORT_FILINKS:
xml_prefix = "FI";
prefix = "FI ";
break;
case REPORT_ISLINKS:
xml_prefix = "IS";
prefix = "Inter-Switch ";
break;
case REPORT_EXTISLINKS:
xml_prefix = "ExtIS";
prefix = "External Inter-Switch ";
break;
}
switch (format) {
case FORMAT_TEXT:
printf("%*s%sLink Summary\n", indent, "", prefix);
break;
case FORMAT_XML:
printf("%*s<%sLinkSummary>\n", indent, "", xml_prefix);
indent+=4;
break;
default:
break;
}
ShowPointFocus(focus, FIND_FLAG_FABRIC, format, indent, detail);
switch (format) {
case FORMAT_TEXT:
switch (report) {
default: // should not happen, but just in case
case REPORT_LINKS:
printf("%*s%u Links in Fabric%s\n", indent, "", g_Fabric.LinkCount, detail?":":""); break;
case REPORT_EXTLINKS:
printf("%*s%u External Links in Fabric%s\n", indent, "", g_Fabric.ExtLinkCount, detail?":":""); break;
case REPORT_FILINKS:
printf("%*s%u FI Links in Fabric%s\n", indent, "", g_Fabric.FILinkCount, detail?":":""); break;
case REPORT_ISLINKS:
printf("%*s%u Inter-Switch Links in Fabric%s\n", indent, "", g_Fabric.ISLinkCount, detail?":":""); break;
case REPORT_EXTISLINKS:
printf("%*s%u External Inter-Switch Links in Fabric%s\n", indent, "", g_Fabric.ExtISLinkCount, detail?":":""); break;
}
break;
case FORMAT_XML:
switch (report) {
default: // should not happen, but just in case
case REPORT_LINKS:
XmlPrintDec("LinkCount", g_Fabric.LinkCount, indent); break;
case REPORT_EXTLINKS:
XmlPrintDec("ExternalLinkCount", g_Fabric.ExtLinkCount, indent); break;
case REPORT_FILINKS:
XmlPrintDec("FILinkCount", g_Fabric.FILinkCount, indent); break;
case REPORT_ISLINKS:
XmlPrintDec("ISLinkCount", g_Fabric.ISLinkCount, indent); break;
case REPORT_EXTISLINKS:
XmlPrintDec("ExternalISLinkCount", g_Fabric.ExtISLinkCount, indent); break;
}
break;
default:
break;
}
if (detail)
ShowLinkBriefSummaryHeader(format, indent, detail-1);
for (p=QListHead(&g_Fabric.AllPorts); p != NULL; p = QListNext(&g_Fabric.AllPorts, p)) {
PortData *portp1 = (PortData *)QListObj(p);
// to avoid duplicated processing, only process "from" ports in link
if (! portp1->from)
continue;
switch (report) {
default: // should not happen, but just in case
case REPORT_LINKS:
break; // always show
case REPORT_EXTLINKS:
if (isInternalLink(portp1))
continue;
break;
case REPORT_FILINKS:
if (! isFILink(portp1))
continue;
break;
case REPORT_ISLINKS:
if (! isISLink(portp1))
continue;
break;
case REPORT_EXTISLINKS:
if (isInternalLink(portp1))
continue;
if (! isISLink(portp1))
continue;
break;
}
if (! ComparePortPoint(portp1, focus) && ! ComparePortPoint(portp1->neighbor, focus))
continue;
count++;
if (detail)
ShowLinkBriefSummary(portp1, "<-> ", format, indent, detail-1);
}
switch (format) {
case FORMAT_TEXT:
if (PointValid(focus))
printf("%*s%u Matching Links Found\n", indent, "", count);
DisplaySeparator();
break;
case FORMAT_XML:
if (PointValid(focus))
XmlPrintDec("MatchingLinks", count, indent);
indent-=4;
printf("%*s</%sLinkSummary>\n", indent, "", xml_prefix);
break;
default:
break;
}
}
// output summary of all slow IB Links
// detail = 0,1 -> link running < best enabled speed/width
// detail = 2 -> links running < best supported speed/width
// detail = >2 -> links running < max supported speed/width
// one_report indicates if only a single vs stacked reports
// (stacked means separate sections for each previous part of report)
void ShowSlowLinkReport(LinkReport_t report, boolean one_report, Point *focus, Format_t format, int indent, int detail)
{
LIST_ITEM *p;
int loops;
int firstloop = 1;
int loop;
char *xmltag="";
switch (report) {
default:
case LINK_EXPECTED_REPORT:
loops = 1;
switch (format) {
case FORMAT_TEXT:
printf("%*sLinks running slower than expected Summary\n", indent, "");
break;
case FORMAT_XML:
printf("%*s<LinksExpected> <!-- Links running slower than expected Summary -->\n", indent, "");
xmltag="LinksExpected";
break;
default:
break;
}
break;
case LINK_CONFIG_REPORT:
loops = 2;
if (one_report) {
firstloop = 2;
switch (format) {
case FORMAT_TEXT:
printf("%*sLinks configured slower than supported Summary\n", indent, "");
break;
case FORMAT_XML:
printf("%*s<LinksConfig> <!-- Links configured slower than supported Summary -->\n", indent, "");
xmltag="LinksConfig";
break;
default:
break;
}
} else {
switch (format) {
case FORMAT_TEXT:
printf("%*sLinks running slower than supported Summary\n", indent, "");
break;
case FORMAT_XML:
printf("%*s<LinksRunningSupported> <!-- Links running slower than supported Summary -->\n", indent, "");
xmltag="LinksRunningSupported";
break;
default:
break;
}
}
break;
case LINK_CONN_REPORT:
loops = 3;
if (one_report) {
firstloop = 3;
switch (format) {
case FORMAT_TEXT:
printf("%*sLinks connected with mismatched supported speeds Summary\n", indent, "");
break;
case FORMAT_XML:
printf("%*s<LinksMismatched> <!-- Links connected with mismatched supported speeds Summary -->\n", indent, "");
xmltag="LinksMismatched";
break;
default:
break;
}
} else {
switch (format) {
case FORMAT_TEXT:
printf("%*sLinks running slower than faster port Summary\n", indent, "");
break;
case FORMAT_XML:
printf("%*s<LinksRunningSlower> <!-- Links running slower than faster port Summary -->\n", indent, "");
xmltag="LinksRunningSlower";
break;
default:
break;
}
}
break;
}
if (format == FORMAT_XML)
indent+=4;
ShowPointFocus(focus, FIND_FLAG_FABRIC, format, indent, detail);
if (format == FORMAT_XML)
indent-=4;
for (loop = firstloop; loop <= loops; ++loop) {
uint32 badcount = 0;
uint32 checked = 0;
LinkReport_t loop_report;
switch (loop) {
case 1:
switch (format) {
case FORMAT_TEXT:
printf("%*sLinks running slower than expected:\n", indent, "");
break;
case FORMAT_XML:
/* already output above */
break;
default:
break;
}
loop_report = LINK_EXPECTED_REPORT;
break;
case 2:
switch (format) {
case FORMAT_TEXT:
printf("%*sLinks configured to run slower than supported:\n", indent, "");
break;
case FORMAT_XML:
if (loop != firstloop) {
printf("</%s>\n", xmltag);
printf("%*s<LinksConfig> <!-- Links configured slower than supported Summary -->\n", indent, "");
xmltag="LinksConfig";
}
break;
default:
break;
}
loop_report = LINK_CONFIG_REPORT;
if (g_hard) {
switch (format) {
case FORMAT_TEXT:
printf("%*sReport skipped: -H option specified\n", indent, "");
break;
case FORMAT_XML:
printf("%*s<!-- Report skipped: -H option specified -->\n", indent, "");
break;
default:
break;
}
continue;
}
break;
case 3:
switch (format) {
case FORMAT_TEXT:
printf("%*sLinks connected with mismatched speed potential:\n", indent, "");
break;
case FORMAT_XML:
if (loop != firstloop) {
printf("</%s>\n", xmltag);
printf("%*s<LinksMismatched> <!-- Links connected with mismatched supported speeds Summary -->\n", indent, "");
xmltag="LinksMismatched";
}
break;
default:
break;
}
loop_report = LINK_CONN_REPORT;
break;
default:
ASSERT(0);
continue;
break;
}
if (format == FORMAT_XML)
indent+=4;
for (p=QListHead(&g_Fabric.AllPorts); p != NULL; p = QListNext(&g_Fabric.AllPorts, p)) {
PortData *portp1, *portp2;
STL_PORT_INFO *pi1, *pi2;
portp1 = (PortData *)QListObj(p);
// to avoid duplicated processing, only process "from" ports in link
if (! portp1->from)
continue;
portp2 = portp1->neighbor;
if (! ComparePortPoint(portp1, focus) && ! ComparePortPoint(portp2, focus))
continue;
checked++;
pi1 = &portp1->PortInfo;
pi2 = &portp2->PortInfo;
// If the data is invalid, declare the test failed
if ( /* Active speed, width, widthDowngrade should all be a single bit value */
/* - else is invalid data */
(pi1->LinkSpeed.Active != StlBestLinkSpeed(pi1->LinkSpeed.Active)) ||
(pi2->LinkSpeed.Active != StlBestLinkSpeed(pi2->LinkSpeed.Active)) ||
(pi1->LinkWidth.Active != StlBestLinkWidth(pi1->LinkWidth.Active)) ||
(pi2->LinkWidth.Active != StlBestLinkWidth(pi2->LinkWidth.Active)) ||
(pi1->LinkWidthDowngrade.TxActive != StlBestLinkWidth(pi1->LinkWidthDowngrade.TxActive)) ||
(pi2->LinkWidthDowngrade.TxActive != StlBestLinkWidth(pi2->LinkWidthDowngrade.TxActive)) ||
(pi1->LinkWidthDowngrade.RxActive != StlBestLinkWidth(pi1->LinkWidthDowngrade.RxActive)) ||
(pi2->LinkWidthDowngrade.RxActive != StlBestLinkWidth(pi2->LinkWidthDowngrade.RxActive)) ) {
printf(" The speed, width, or widthdowngrade value retrieved is not valid. \n");
goto show;
}
// Links running slower than expected (not at highest supported speed that is enabled)
if (firstloop <= 1) {
if (
/* Active speed should match highest speed enabled on both ports */
(pi1->LinkSpeed.Active == StlExpectedLinkSpeed(
pi1->LinkSpeed.Enabled, pi2->LinkSpeed.Enabled)) &&
(pi2->LinkSpeed.Active == StlExpectedLinkSpeed(
pi1->LinkSpeed.Enabled, pi2->LinkSpeed.Enabled)) &&
/* Actual width (the downgrade width) should match highest width enabled on both ports */
(pi1->LinkWidthDowngrade.TxActive == StlExpectedLinkWidth(
pi1->LinkWidthDowngrade.Enabled, pi2->LinkWidthDowngrade.Enabled)) &&
(pi2->LinkWidthDowngrade.TxActive == StlExpectedLinkWidth(
pi1->LinkWidthDowngrade.Enabled, pi2->LinkWidthDowngrade.Enabled)) &&
(pi1->LinkWidthDowngrade.RxActive == StlExpectedLinkWidth(
pi1->LinkWidthDowngrade.Enabled, pi2->LinkWidthDowngrade.Enabled)) &&
(pi2->LinkWidthDowngrade.RxActive == StlExpectedLinkWidth(
pi1->LinkWidthDowngrade.Enabled, pi2->LinkWidthDowngrade.Enabled)) &&
/* Active width should match highest width enabled on both ports */
(pi1->LinkWidth.Active == StlExpectedLinkWidth(
pi1->LinkWidth.Enabled, pi2->LinkWidth.Enabled)) &&
(pi2->LinkWidth.Active == StlExpectedLinkWidth(
pi1->LinkWidth.Enabled, pi2->LinkWidth.Enabled)) &&
/* And then finally, Actual width (the downgrade width) should match the active width */
(pi1->LinkWidthDowngrade.TxActive == pi1->LinkWidth.Active) &&
(pi2->LinkWidthDowngrade.TxActive == pi2->LinkWidth.Active) &&
(pi1->LinkWidthDowngrade.RxActive == pi1->LinkWidth.Active) &&
(pi2->LinkWidthDowngrade.RxActive == pi2->LinkWidth.Active) ) {
/* active matches the best enabled, cable is good */
if (loop == 1)
continue;
} else {
/* bad cable, active doesn't match best enabled */
if (loop > 1)
continue; /* already reported on loop 1 */
else
goto show;
}
}
// links configured to run slower than expected (not configured to highest speed supported)
if (firstloop <= 2) {
if (
/* The highest supported speed should be what is configured as enabled */
(StlBestLinkSpeed(pi1->LinkSpeed.Enabled) == StlExpectedLinkSpeed(
pi1->LinkSpeed.Supported, pi2->LinkSpeed.Supported)) &&
(StlBestLinkSpeed(pi2->LinkSpeed.Enabled) == StlExpectedLinkSpeed(
pi1->LinkSpeed.Supported, pi2->LinkSpeed.Supported)) &&
/* The highest supported widthdowngrade should be what is configured as enabled */
(StlBestLinkWidth(pi1->LinkWidthDowngrade.Enabled) == StlExpectedLinkWidth(
pi1->LinkWidthDowngrade.Supported, pi2->LinkWidthDowngrade.Supported)) &&
(StlBestLinkWidth(pi2->LinkWidthDowngrade.Enabled) == StlExpectedLinkWidth(
pi1->LinkWidthDowngrade.Supported, pi2->LinkWidthDowngrade.Supported)) &&
/* The highest supported width should be what is configured as enabled */
(StlBestLinkWidth(pi1->LinkWidth.Enabled) == StlExpectedLinkWidth(
pi1->LinkWidth.Supported, pi2->LinkWidth.Supported)) &&
(StlBestLinkWidth(pi2->LinkWidth.Enabled) == StlExpectedLinkWidth(
pi1->LinkWidth.Supported, pi2->LinkWidth.Supported)) ) {
/* configured matches the best supported, config is good */
if (loop == 2)
continue;
} else {
/* bad config, active doesn't match best supported */
if (loop > 2)
continue; /* already reported on loop 2 */
else
goto show;
}
}
// Link connected with mismatched speed potential (bi-directional link not symetric)
if (firstloop <= 3) {
if (
/* Bidirectional speed and width should match */
(StlBestLinkSpeed(pi1->LinkSpeed.Supported) == StlBestLinkSpeed(pi2->LinkSpeed.Supported)) &&
(StlBestLinkWidth(pi1->LinkWidthDowngrade.Supported) == StlBestLinkWidth(pi2->LinkWidthDowngrade.Supported)) &&
(StlBestLinkWidth(pi1->LinkWidth.Supported) == StlBestLinkWidth(pi2->LinkWidth.Supported)) ) {
/* match, connection choice is good */
if (loop == 3)
continue;
} else {
/* bad config, active doesn't match best supported */
if (loop > 3)
continue; /* already reported on loop 3 */
else
goto show;
}
}
/* bad connection choice, active doesn't match best supported */
show:
if (detail) {
if (! badcount)
ShowSlowLinkPortSummaryHeader(loop_report, format, indent, detail-1);
ShowSlowLinkSummary(loop_report, portp1, format, indent, detail-1);
}
badcount++;
}
switch (format) {
case FORMAT_TEXT:
printf("%*s%u of %u Links Checked, %u Errors found\n", indent, "",
checked, g_Fabric.LinkCount, badcount);
break;
case FORMAT_XML:
XmlPrintDec("LinksChecked", checked, indent);
XmlPrintDec("TotalLinks", g_Fabric.LinkCount, indent);
XmlPrintDec("LinksWithErrors", badcount, indent);
break;
default:
break;
}
if (format == FORMAT_XML)
indent-=4;
}
switch (format) {
case FORMAT_TEXT:
DisplaySeparator();
break;
case FORMAT_XML:
printf("</%s>\n", xmltag);
break;
default:
break;
}
}
void ShowLinkInfoReport(Point *focus, Format_t format, int indent, int detail)
{
cl_map_item_t *p;
PortData *portp1, *portp2;
NodeData *nodep;
LIST_ITEM *q;
printf("%*sLinkInfo Summary\n", indent, "");
ShowPointFocus(focus, FIND_FLAG_FABRIC, format, indent, detail);
printf( "%*s%u Links in Fabric%s\n", indent, "",g_Fabric.LinkCount, detail?":":"" );
if (detail) {
printf("%*s NodeGUID Type LID LMC Name \n", indent, "");
printf("%*sEgress LinkSpeed Type NodeGUID Port LID Name \n", indent, "");
}
// First the switches
for (q=QListHead(&g_Fabric.AllSWs); q != NULL; q = QListNext(&g_Fabric.AllSWs, q)) {
nodep = (NodeData *)QListObj(q);
portp1 = FindNodePort(nodep, 0);
if (!portp1)
continue;
if (!ComparePortPoint(portp1, focus))
continue;
printf("%*s0x%016"PRIx64" %s %5u %u %.*s \n", indent, "",
portp1->nodep->NodeInfo.NodeGUID,
StlNodeTypeToText(portp1->nodep->NodeInfo.NodeType),
portp1->EndPortLID, portp1->PortInfo.s1.LMC, NODE_DESCRIPTION_ARRAY_SIZE,
g_noname?g_name_marker:(char*)portp1->nodep->NodeDesc.NodeString);
for ( p=cl_qmap_head(&nodep->Ports);
p != cl_qmap_end(&nodep->Ports);
p = cl_qmap_next(p) ){
portp2 = PARENT_STRUCT(p, PortData, NodePortsEntry);
if (!portp2)
continue;
if (portp2->neighbor) {
printf("%3u %s %s 0x%016"PRIx64" %3u %5u %.*s \n", portp2->PortNum,
StlStaticRateToText(portp2->rate), StlNodeTypeToText(portp2->neighbor->nodep->NodeInfo.NodeType),
portp2->neighbor->nodep->NodeInfo.NodeGUID, portp2->neighbor->PortNum,
portp2->neighbor->EndPortLID, NODE_DESCRIPTION_ARRAY_SIZE,
g_noname?g_name_marker:(char*)portp2->neighbor->nodep->NodeDesc.NodeString);
}
} // End of ( p=cl_qmap_head(&nodep->Ports)
} // End of for (q=QListHead(&g_Fabric.AllSWs);
// now the FIs
for (q=QListHead(&g_Fabric.AllFIs); q != NULL; q = QListNext(&g_Fabric.AllFIs, q)) {
nodep = (NodeData *)QListObj(q);
for ( p=cl_qmap_head(&nodep->Ports);
p != cl_qmap_end(&nodep->Ports);
p = cl_qmap_next(p) ){
portp1 = PARENT_STRUCT(p, PortData, NodePortsEntry);
if (!portp1)
continue;
if (! ComparePortPoint(portp1, focus))
continue;
printf("%*s0x%016"PRIx64" %s %5u %u %.*s\n", indent, "",
portp1->nodep->NodeInfo.NodeGUID,
StlNodeTypeToText(portp1->nodep->NodeInfo.NodeType),
portp1->EndPortLID, portp1->PortInfo.s1.LMC,NODE_DESCRIPTION_ARRAY_SIZE,
g_noname?g_name_marker:(char*)portp1->nodep->NodeDesc.NodeString);
if (portp1->neighbor){
printf("%3u %s %s 0x%016"PRIx64" %3u %5u %.*s\n", portp1->PortNum,
StlStaticRateToText(portp1->rate), StlNodeTypeToText(portp1->neighbor->nodep->NodeInfo.NodeType),
portp1->neighbor->nodep->NodeInfo.NodeGUID, portp1->neighbor->PortNum,
portp1->neighbor->EndPortLID, NODE_DESCRIPTION_ARRAY_SIZE,
g_noname?g_name_marker:(char*)portp1->neighbor->nodep->NodeDesc.NodeString);
}
} // End of ( p=cl_qmap_head(&nodep->Ports)
} // End of for (q=QListHead(&g_Fabric.AllFIs);
}
void ShowRoutesReport(EUI64 portGuid, Point *point1, Point *point2, Format_t format, int indent, int detail)
{
switch (format) {
case FORMAT_TEXT:
printf("%*sRoutes Summary Between:\n", indent, "");
break;
case FORMAT_XML:
printf("%*s<RoutesSummary>\n", indent, "");
indent+=4;
break;
default:
break;
}
switch (format) {
case FORMAT_TEXT:
ShowPointBriefSummary(point1, FIND_FLAG_FABRIC, format, indent+4, detail);
printf("and ");
ShowPointBriefSummary(point2, FIND_FLAG_FABRIC, format, indent, detail);
break;
case FORMAT_XML:
ShowPointBriefSummary(point1, FIND_FLAG_FABRIC, format, indent, detail);
ShowPointBriefSummary(point2, FIND_FLAG_FABRIC, format, indent, detail);
break;
default:
break;
}
if (format == FORMAT_TEXT)
printf("\n");
if (g_hard || g_persist) {
switch (format) {
case FORMAT_TEXT:
printf("%*sReport skipped: -H or -P option specified\n", indent, "");
break;
case FORMAT_XML:
printf("%*s<!-- Report skipped: -H or -P option specified -->\n", indent, "");
break;
default:
break;
}
goto done;
}
if (! (g_Fabric.flags & FF_ROUTES) && g_snapshot_in_file) {
switch (format) {
case FORMAT_TEXT:
printf("%*sReport skipped: provided snapshot was created without -r option\n", indent, "");
break;
case FORMAT_XML:
printf("%*s<!-- Report skipped: provided snapshot was created without -r option -->\n", indent, "");
break;
default:
break;
}
goto done;
}
(void)ShowPointsTraceRoutes(portGuid, point1, point2, format, indent, detail);
done:
switch (format) {
case FORMAT_TEXT:
DisplaySeparator();
break;
case FORMAT_XML:
indent-=4;
printf("%*s</RoutesSummary>\n", indent, "");
break;
default:
break;
}
}
static FSTATUS ValidateCLTimeGetCallback(uint64_t *address, pthread_mutex_t *lock)
{
uint64_t usecs;
struct timespec now;
// the system routine clock_gettime is not thread safe, so
// must request global lock.
pthread_mutex_lock(lock);
if (address == 0) {
pthread_mutex_unlock(lock);
return (FINVALID_PARAMETER);
}
clock_gettime(CLOCK_MONOTONIC, &now);
pthread_mutex_unlock(lock);
usecs = now.tv_sec;
usecs *= 1000000;
usecs += (now.tv_nsec / 1000);
// round up anything greater than 0.5 usecs
if (now.tv_nsec % 1000 > 500)
usecs++;
*address = usecs;
return (FSUCCESS);
}
static void ValidateCLRouteCallback(PortData *portp1, PortData *portp2, void *context)
{
FSTATUS status;
Format_t format = FORMAT_TEXT;
int indent = 0;
int detail = 0;
PQUERY_RESULT_VALUES pQueryResults = NULL;
uint32 NumPathRecords;
IB_PATH_RECORD *pPathRecords = NULL;
ValidateCreditLoopRoutesContext_t *cp = (ValidateCreditLoopRoutesContext_t *) context;
struct omgt_port *omgt_port_session = NULL;
if (cp) {
format = cp->format;
indent = cp->indent;
detail = cp->detail;
}
switch (format) {
case FORMAT_TEXT:
printf("%*sRoutes Summary Between:\n", indent, "");
break;
case FORMAT_XML:
printf("%*s<RoutesSummary>\n", indent, "");
indent += 4;
break;
default:
break;
}
switch (format) {
case FORMAT_TEXT:
ShowPointPortBriefSummary("Port: ", portp1, format, indent, detail);
printf("and ");
ShowPointPortBriefSummary("Port: ", portp2, format, indent, detail);
break;
case FORMAT_XML:
ShowPointPortBriefSummary("Port: ", portp1, format, indent, detail);
ShowPointPortBriefSummary("Port: ", portp2, format, indent, detail);
break;
default:
break;
}
if (format == FORMAT_TEXT)
printf("\n");
if (g_hard || g_persist) {
switch (format) {
case FORMAT_TEXT:
printf("%*sReport skipped: -H or -P option specified\n", indent, "");
break;
case FORMAT_XML:
printf("%*s<!-- Report skipped: -H or -P option specified -->\n", indent, "");
break;
default:
break;
}
goto done;
}
if (!(g_Fabric.flags & FF_ROUTES) && g_snapshot_in_file) {
switch (format) {
case FORMAT_TEXT:
printf("%*sReport skipped: provided snapshot was created without -r option\n", indent, "");
break;
case FORMAT_XML:
printf("%*s<!-- Report skipped: provided snapshot was created without -r option -->\n", indent, "");
break;
default:
break;
}
goto done;
}
switch (format) {
case FORMAT_TEXT:
printf("%*sRoutes between ports:\n", indent, "");
ShowLinkPortBriefSummary(portp1, " ", 0, NULL, format, indent, 0);
ShowLinkPortBriefSummary(portp2, "and ", 0, NULL, format, indent, 0);
break;
case FORMAT_XML:
printf("%*s<PortRoutes>\n", indent, "");
ShowLinkPortBriefSummary(portp1, " ", 0, NULL, format, indent + 4, 0);
ShowLinkPortBriefSummary(portp2, "and ", 0, NULL, format, indent + 4, 0);
break;
default:
break;
}
if (!g_snapshot_in_file) {
struct omgt_params params = {.debug_file = g_verbose > 2 ? stdout : NULL};
status = omgt_open_port_by_guid(&omgt_port_session, g_portGuid, ¶ms);
if (FSUCCESS != status)
goto done;
omgt_set_timeout(omgt_port_session, g_ms_timeout);
status = GetPaths(omgt_port_session, portp1, portp2, &pQueryResults);
if (FSUCCESS != status)
goto done;
NumPathRecords = ((PATH_RESULTS *)pQueryResults->QueryResult)->NumPathRecords;
pPathRecords = ((PATH_RESULTS *)pQueryResults->QueryResult)->PathRecords;
} else {
status = GenPaths(&g_Fabric, portp1, portp2, &pPathRecords, &NumPathRecords);
if (FSUCCESS != status)
goto done;
}
switch (format) {
case FORMAT_TEXT:
printf("%*s%d Paths\n", indent, "", NumPathRecords);
break;
case FORMAT_XML:
printf("%*s<Paths>%d</Paths>\n", indent + 4, "", NumPathRecords);
break;
default:
break;
}
if (detail) {
int i;
for (i = 0; i < NumPathRecords; i++) {
ShowTraceRoute(g_portGuid, portp1, portp2, &pPathRecords[i], format, indent + 4, detail - 1);
}
}
done:
if (format == FORMAT_XML)
printf("%*s</PortRoutes>\n", indent, "");
if (pQueryResults)
omgt_free_query_result_buffer(pQueryResults);
if (omgt_port_session != NULL)
omgt_close_port(omgt_port_session);
if (g_snapshot_in_file && pPathRecords)
MemoryDeallocate(pPathRecords);
switch (format) {
case FORMAT_TEXT:
DisplaySeparator();
break;
case FORMAT_XML:
indent -= 4;
printf("%*s</RoutesSummary>\n", indent, "");
break;
default:
break;
}
}
static void ValidateCLFabricSummaryCallback(FabricData_t *fabricp, const char *name,
uint32 totalPaths, uint32 totalBadPaths,
void *context)
{
ValidateCreditLoopRoutesContext_t *cp = (ValidateCreditLoopRoutesContext_t *) context;
int indent = cp->indent;
char title[100]={0};
if (!cp->detail)
return;
switch (cp->format) {
case FORMAT_TEXT:
/*printf("%*s%s summary: %d devices, %d HFIs, %d switches, %d connections, %d routing decisions, %d analyzed routes, %d incomplete routes\n",
indent, "",
name, (int)cl_qmap_count(&fabricp->map_guid_to_ib_device), QListCount(&fabricp->FIs), QListCount(&fabricp->Switches),
fabricp->ConnectionCount, fabricp->RouteCount, totalPaths, totalBadPaths);*/ // DEBUG_CODE --- ???
printf("%*s%s summary: %d devices, %d HFIs, %d switches,\n",
indent, "",
name, (int)cl_qmap_count(&fabricp->map_guid_to_ib_device), QListCount(&fabricp->FIs), QListCount(&fabricp->Switches));
printf("%*s\t%d connections, %d routing decisions,\n",
indent, "",
fabricp->ConnectionCount, fabricp->RouteCount);
printf("%*s\t%d analyzed routes, %d incomplete routes\n",
indent, "",
totalPaths, totalBadPaths);
break;
case FORMAT_XML:
snprintf(title, sizeof(title), "CreditLoop%sSummary", name);
XmlPrintTagHeader(title, indent);
indent+= 4;
XmlPrintDec("Devices", cl_qmap_count(&fabricp->map_guid_to_ib_device), indent);
XmlPrintDec("HFIs", QListCount(&fabricp->FIs), indent);
XmlPrintDec("Switches", QListCount(&fabricp->Switches), indent);
XmlPrintDec("Connections", fabricp->ConnectionCount, indent);
XmlPrintDec("RoutingDecisions", fabricp->RouteCount, indent);
XmlPrintDec("AnalyzedRoutes", totalPaths, indent);
XmlPrintDec("IncompleteRoutes", totalBadPaths, indent);
snprintf(title, sizeof(title), "CreditLoop%sSummary", name);
XmlPrintTagFooter(title, indent-4);
break;
default:
break;
}
}
static void ValidateCLDataSummaryCallback(clGraphData_t *graphp, const char *name, void *context)
{
ValidateCreditLoopRoutesContext_t *cp = (ValidateCreditLoopRoutesContext_t *) context;
int indent = cp->indent;
char title[100]={0};
if (!cp->detail)
return;
switch (cp->format) {
case FORMAT_TEXT:
printf("%*s%s summary: %d vertices and %d arcs\n",
indent, "",
name, graphp->NumActiveVertices, (int)cl_qmap_count(&graphp->Arcs));
break;
case FORMAT_XML:
snprintf(title, sizeof(title), "CreditLoop%sSummary", name);
printf("\n");
XmlPrintTagHeader(title, indent);
indent+= 4;
XmlPrintDec("Vertices", graphp->NumActiveVertices, indent);
XmlPrintDec("Arcs", cl_qmap_count(&graphp->Arcs), indent);
snprintf(title, sizeof(title), "CreditLoop%sSummary", name);
XmlPrintTagFooter(title, indent-4);
break;
default:
break;
}
}
static void ValidateCLRouteSummaryCallback(uint32 routesPresent,
uint32 routesMissing,
uint32 hopsHistogramEntries,
uint32 *hopsHistogram,
void *context)
{
ValidateCreditLoopRoutesContext_t *cp = (ValidateCreditLoopRoutesContext_t *) context;
int indent = cp->indent;
uint32 hh;
if (!cp->detail)
return;
switch (cp->format) {
case FORMAT_TEXT:
printf("%*sRouting summary: %d routes present, %d routes missing\n",
indent, "", routesPresent, routesMissing);
//PYTHON: for h in hopsHistogram :
for (hh = 0; hh < hopsHistogramEntries; hh++) {
if (hopsHistogram[hh])
printf("%*sHops summary: %d routes have %d hops\n", indent, "", hopsHistogram[hh], hh);
}
break;
case FORMAT_XML:
printf("\n");
XmlPrintTagHeader("CreditLoopRoutingSummary", indent);
indent+= 4;
XmlPrintTagHeader("RoutingSummary", indent);
XmlPrintDec("RoutesPresent", routesPresent, indent+4);
XmlPrintDec("RoutesMissing", routesMissing, indent+4);
XmlPrintTagFooter("RoutingSummary", indent);
//PYTHON: for h in hopsHistogram :
for (hh = 0; hh < hopsHistogramEntries; hh++) {
if (hopsHistogram[hh]) {
printf("\n");
XmlPrintTagHeader("HopsSummary", indent);
XmlPrintDec("Routes", hopsHistogram[hh], indent+4);
XmlPrintDec("Hops", hh, indent+4);
XmlPrintTagFooter("HopsSummary", indent);
}
}
XmlPrintTagFooter("CreditLoopRoutingSummary", indent-4);
break;
default:
break;
}
}
static void ValidateCLLinkSummaryCallback(uint32 id, const char *name, uint32 cycle, uint8 header, int indent, void *context)
{
ValidateCreditLoopRoutesContext_t *cp = (ValidateCreditLoopRoutesContext_t *) context;
switch (cp->format) {
case FORMAT_TEXT:
if (header)
printf("%*sLINK %d (%s) is in a CYCLE of %d:\n", indent, "", id, name, cycle);
break;
case FORMAT_XML:
if (header) {
printf("\n");
XmlPrintTagHeader("LinkSummary", indent);
XmlPrintDec("LinkCycle", cycle, indent+4);
XmlPrintDec("LinkId", id, indent+4);
XmlPrintStr("LinkName", name, indent+4);
} else {
XmlPrintTagFooter("LinkSummary", indent);
}
break;
default:
break;
}
}
static void ValidateCLLinkStepSummaryCallback(uint32 id, const char *name, uint32 step, uint8 header, int indent, void *context)
{
ValidateCreditLoopRoutesContext_t *cp = (ValidateCreditLoopRoutesContext_t *) context;
switch (cp->format) {
case FORMAT_TEXT:
if (header) {
if (cp->detail >= 4)
printf("%*s----------------------------------------\n", indent, "");
printf("%*s%d: LINK %d (%s)\n", indent, "", step, id, name);
}
break;
case FORMAT_XML:
if (header) {
printf("\n");
XmlPrintTagHeader("LinkStepSummary", indent);
XmlPrintDec("LinkStep", step, indent+4);
XmlPrintDec("LinkId", id, indent+4);
XmlPrintStr("LinkName", name, indent+4);
} else {
XmlPrintTagFooter("LinkStepSummary", indent);
}
break;
default:
break;
}
}
static void ShowCLPathRecord(IB_PATH_RECORD *pPathRecord, Format_t format, int indent)
{
char buf[8];
switch (format) {
case FORMAT_TEXT:
printf("%*sSGID: 0x%016"PRIx64":%016"PRIx64"\n",
indent, "",
pPathRecord->SGID.Type.Global.SubnetPrefix,
pPathRecord->SGID.Type.Global.InterfaceID);
printf("%*sDGID: 0x%016"PRIx64":%016"PRIx64"\n",
indent, "",
pPathRecord->DGID.Type.Global.SubnetPrefix,
pPathRecord->DGID.Type.Global.InterfaceID);
printf("%*sSLID: 0x%.*x DLID: 0x%.*x Reversible: %s PKey: 0x%04x\n",
indent, "", (pPathRecord->SLID <= IB_MAX_UCAST_LID ? 4:8), pPathRecord->SLID,
(pPathRecord->DLID <= IB_MAX_UCAST_LID ? 4:8), pPathRecord->DLID,
pPathRecord->Reversible ? "Y" : "N", pPathRecord->P_Key);
printf("%*sRaw: %s FlowLabel: 0x%05x HopLimit: 0x%02x TClass: 0x%02x\n",
indent, "", pPathRecord->u1.s.RawTraffic ? "Y" : "N",
pPathRecord->u1.s.FlowLabel, pPathRecord->u1.s.HopLimit,
pPathRecord->TClass);
FormatTimeoutMult(buf, pPathRecord->PktLifeTime);
printf("%*sSL: %2d Mtu: %5s Rate: %4s PktLifeTime: %s Pref: %d\n",
indent, "", pPathRecord->u2.s.SL, IbMTUToText(pPathRecord->Mtu),
StlStaticRateToText(pPathRecord->Rate), buf,
pPathRecord->Preference);
break;
case FORMAT_XML:
XmlPrintTagHeader("PathRecord", indent);
XmlPrintGID("SGID", pPathRecord->SGID, indent + 4);
XmlPrintGID("DGID", pPathRecord->DGID, indent + 4);
XmlPrintLID("SLID", pPathRecord->SLID, indent + 4);
XmlPrintLID("DLID", pPathRecord->DLID, indent + 4);
XmlPrintStr("Reversible", pPathRecord->Reversible ? "Y" : "N", indent + 4);
XmlPrintDec("Reversible_Int", pPathRecord->Reversible, indent + 4);
XmlPrintPKey("PKey", pPathRecord->P_Key, indent + 4);
XmlPrintStr("Raw", pPathRecord->u1.s.RawTraffic ? "Y" : "N", indent + 4);
XmlPrintDec("Raw_Int", pPathRecord->u1.s.RawTraffic, indent + 4);
XmlPrintHex("FlowLabel", pPathRecord->u1.s.FlowLabel, indent + 4);
XmlPrintHex8("HopLimit", pPathRecord->u1.s.HopLimit, indent + 4);
XmlPrintHex8("TClass", pPathRecord->TClass, indent + 4);
XmlPrintDec("SL", pPathRecord->u2.s.SL, indent + 4);
XmlPrintDec("Mtu", GetBytesFromMtu(pPathRecord->Mtu), indent + 4);
XmlPrintRate(pPathRecord->Rate, indent + 4);
FormatTimeoutMult(buf, pPathRecord->PktLifeTime);
XmlPrintStr("PktLifeTime", buf, indent + 4);
XmlPrintDec("PktLifeTime_Int", pPathRecord->PktLifeTime, indent + 4);
XmlPrintDec("Preference", pPathRecord->Preference, indent + 4);
XmlPrintTagFooter("PathRecord", indent);
break;
default:
break;
}
}
static void ShowCLTraceRecord(FabricData_t *fabricp, STL_TRACE_RECORD *pTraceRecord, uint32 record, Format_t format, int indent)
{
NodeData *nodep;
switch (format) {
case FORMAT_TEXT:
printf("%*sTrace Record[%d]", indent, "", record);
indent += 4;
printf("%*sIDGeneration: 0x%04x\n",
indent, "", pTraceRecord->IDGeneration);
printf("%*sNodeType: 0x%02x\n",
indent, "", pTraceRecord->NodeType);
printf("%*sNodeID: 0x%016"PRIx64" ChassisID: %016"PRIx64"\n",
indent, "", pTraceRecord->NodeID, pTraceRecord->ChassisID);
printf("%*sEntryPortID: 0x%016"PRIx64" ExitPortID: %016"PRIx64"\n",
indent, "", pTraceRecord->EntryPortID, pTraceRecord->ExitPortID);
printf("%*sEntryPort: 0x%02x ExitPort: 0x%02x\n",
indent, "", pTraceRecord->EntryPort, pTraceRecord->ExitPort);
if ((nodep = FindNodeGuid(fabricp, pTraceRecord->NodeID)))
printf("%*sNodeDesc: %s\n", indent, "", nodep->NodeDesc.NodeString);
break;
case FORMAT_XML:
XmlPrintTagHeader("TraceRecord", indent);
// TraceRecordId not a standard trace record field. The field was
// added to assist the person analyzing this data.
XmlPrintDec("TraceRecordId", record, indent + 4);
XmlPrintHex16("IDGeneration", pTraceRecord->IDGeneration, indent + 4);
XmlPrintNodeType(pTraceRecord->NodeType, indent + 4);
XmlPrintHex64("NodeID", pTraceRecord->NodeID, indent + 4);
XmlPrintHex64("ChassisID", pTraceRecord->ChassisID, indent + 4);
XmlPrintHex64("EntryPortID", pTraceRecord->EntryPortID, indent + 4);
XmlPrintHex64("ExitPortID", pTraceRecord->ExitPortID, indent + 4);
XmlPrintHex8("EntryPort", pTraceRecord->EntryPort, indent + 4);
XmlPrintHex8("ExitPort", pTraceRecord->ExitPort, indent + 4);
XmlPrintTagFooter("TraceRecord", indent);
break;
default:
break;
}
}
static void ValidateCLPathSummaryCallback(FabricData_t *fabricp, clConnData_t *connp, int indent, void *context)
{
FSTATUS status;
ValidateCreditLoopRoutesContext_t *cp = (ValidateCreditLoopRoutesContext_t *) context;
int i, xmlFmt = (cp->format == 1) ? 1 : 0;
uint32 NumTraceRecords;
STL_TRACE_RECORD *pTraceRecords = NULL;
PQUERY_RESULT_VALUES pQueryResults = NULL;
struct omgt_port *omgt_port_session = NULL;
//
// display path record associated with the route
if (xmlFmt)
XmlPrintTagHeader("Route", indent);
else
printf("%*sPath Record\n", indent, "");
ShowCLPathRecord(&connp->PathInfo.path, cp->format, indent+4);
//
// retrieve trace records associated with the route
if (!((fabricp->flags & FF_ROUTES) && g_snapshot_in_file)) {
struct omgt_params params = {.debug_file = g_verbose > 2 ? stdout : NULL};
if(omgt_open_port_by_guid(&omgt_port_session, g_portGuid, ¶ms))
return;
omgt_set_timeout(omgt_port_session, g_ms_timeout);
if (GetTraceRoute(omgt_port_session, &connp->PathInfo.path, &pQueryResults)) {
omgt_close_port(omgt_port_session);
return;
}
NumTraceRecords = ((STL_TRACE_RECORD_RESULTS *)pQueryResults->QueryResult)->NumTraceRecords;
pTraceRecords = ((STL_TRACE_RECORD_RESULTS *)pQueryResults->QueryResult)->TraceRecords;
} else {
if ((status = GenTraceRoutePath(fabricp, &connp->PathInfo.path, g_rc, &pTraceRecords, &NumTraceRecords))) {
if (status == FUNAVAILABLE) {
fprintf(stderr, "opareport: Routing Tables not available in snapshot\n");
goto done;
} else if (status == FNOT_DONE) {
if (!xmlFmt)
printf("%*sRoute Incomplete\n", indent, "");
else
printf("%*s<LinksTraversed>0</LinksTraversed> <!-- Route Incomplete -->\n", indent, "");
// don't fail just because some routes are incomplete
} else {
fprintf(stderr, "opareport: Unable to determine route: (status=0x%x): %s\n", status, iba_fstatus_msg(status));
if (status == FINSUFFICIENT_MEMORY)
exit(0);
}
goto done;
}
}
//
// display trace records associated with the route
printf("\n");
if (xmlFmt)
XmlPrintDec("TraceRecords", NumTraceRecords, indent+4);
else
printf("%*sTrace Records (%d)\n", indent, "", NumTraceRecords);
for (i = 0; i < NumTraceRecords;/* i++*/) {
ShowCLTraceRecord(fabricp, &pTraceRecords[i], i, cp->format, indent+4);
if (++i < NumTraceRecords)
printf("\n");
}
if (xmlFmt)
XmlPrintTagFooter("Route", indent);
else
printf("\n");
done:
if (pQueryResults)
omgt_free_query_result_buffer(pQueryResults);
if (omgt_port_session != NULL)
omgt_close_port(omgt_port_session);
}
// output summary of all IB Links with errors > threshold
void ShowLinkErrorReport(Point *focus, Format_t format, int indent, int detail)
{
LIST_ITEM *p;
uint32 count = 0;
uint32 checked = 0;
switch (format) {
case FORMAT_TEXT:
printf("%*sLinks with errors %s threshold Summary\n", indent, "",
g_threshold_compare?">=":">");
break;
case FORMAT_XML:
printf("%*s<LinkErrors> <!-- Links with errors %s threshold Summary -->\n", indent, "",
g_threshold_compare?">=":">");
indent+=4;
break;
default:
break;
}
if (g_hard || g_persist) {
switch (format) {
case FORMAT_TEXT:
printf("%*sReport skipped: -H or -P option specified\n", indent, "");
break;
case FORMAT_XML:
printf("%*s<!-- Report skipped: -H or -P option specified -->\n", indent, "");
break;
default:
break;
}
goto done;
} else if (! (g_Fabric.flags & FF_STATS) && ! g_snapshot_in_file) {
switch (format) {
case FORMAT_TEXT:
printf("%*sReport skipped: -s nor -X option not specified\n", indent, "");
break;
case FORMAT_XML:
printf("%*s<!-- Report skipped: -s nor -X option not specified -->\n", indent, "");
break;
default:
break;
}
goto done;
} else if (! (g_Fabric.flags & FF_STATS) && g_snapshot_in_file) {
switch (format) {
case FORMAT_TEXT:
printf("%*sReport skipped: provided snapshot was created without -s option\n", indent, "");
break;
case FORMAT_XML:
printf("%*s<!-- Report skipped: provided snapshot was created without -s option -->\n", indent, "");
break;
default:
break;
}
goto done;
}
ShowPointFocus(focus, FIND_FLAG_FABRIC, format, indent, detail);
if (g_limitstats) {
switch (format) {
case FORMAT_TEXT:
printf("Check limited, will not check neighbor ports\n");
break;
case FORMAT_XML:
printf("<!-- Check limited, will not check neighbor ports -->\n");
break;
default:
break;
}
}
if (! ShowThresholds(format, indent, detail)) {
switch (format) {
case FORMAT_TEXT:
printf("%*sReport skipped: no thresholds configured\n", indent, "");
break;
case FORMAT_XML:
printf("%*s<!-- Report skipped: no thresholds configured -->\n", indent, "");
break;
default:
break;
}
goto done;
}
for (p=QListHead(&g_Fabric.AllPorts); p != NULL; p = QListNext(&g_Fabric.AllPorts, p)) {
PortData *portp1, *portp2;
portp1 = (PortData *)QListObj(p);
// to avoid duplicated processing, only process "from" ports in link
if (! portp1->from)
continue;
portp2 = portp1->neighbor;
// if g_limitstats is set, we will not have PortCounters for
// ports outside our focus, so we will not report nor check them
if (! ComparePortPoint(portp1, focus) && ! ComparePortPoint(portp2, focus))
continue;
checked++;
if (PortCountersExceedThreshold(portp1) || PortCountersExceedThreshold(portp2))
{
if (detail) {
if (count) {
if (format == FORMAT_TEXT) {
printf("\n"); // blank line between links
}
} else {
ShowLinkBriefSummaryHeader(format, indent, detail-1);
}
ShowLinkErrorSummary(portp1, format, indent, detail-1);
}
count++;
}
}
switch (format) {
case FORMAT_TEXT:
printf("%*s%u of %u Links Checked, %u Errors found\n", indent, "",
checked, g_Fabric.LinkCount, count);
break;
case FORMAT_XML:
XmlPrintDec("LinksChecked", checked, indent);
XmlPrintDec("TotalLinks", g_Fabric.LinkCount, indent);
XmlPrintDec("LinksWithErrors", count, indent);
break;
default:
break;
}
done:
switch (format) {
case FORMAT_TEXT:
DisplaySeparator();
break;
case FORMAT_XML:
indent-=4;
printf("%*s</LinkErrors>\n", indent, "");
break;
default:
break;
}
}
/* clear all PortCounters on all ports in fabric
*/
FSTATUS ClearAllPortCountersAndShow(EUI64 portGuid, Point *focus, boolean clearall, Format_t format, boolean quiet)
{
uint32 node_count=0;
uint32 port_count=0;
uint32 nrsp_node_count=0;
uint32 nrsp_port_count=0;
int indent = 0;
if (! quiet) {
switch (format) {
case FORMAT_TEXT:
printf("Clearing Port Counters\n");
break;
case FORMAT_XML:
printf("<ClearCounters>\n");
indent+=4;
break;
default:
break;
}
ShowPointFocus(focus, FIND_FLAG_FABRIC, format, indent, 0);
if (g_limitstats) {
switch (format) {
case FORMAT_TEXT:
printf("Clear limited, will not clear neighbor ports\n");
break;
case FORMAT_XML:
printf("<!-- Clear limited, will not clear neighbor ports -->\n");
break;
default:
break;
}
}
if (! ShowClearedCounters(format, indent, 10, clearall)) {
switch (format) {
case FORMAT_TEXT:
printf("%*sClear skipped: no thresholds configured\n", 0, "");
break;
case FORMAT_XML:
printf("%*s<!-- Clear skipped: no thresholds configured -->\n", 0, "");
break;
default:
break;
}
goto done;
}
} else if (! clearall && ! NeedClearCounters()) {
goto done;
}
(void)ClearAllPortCounters(portGuid, g_portAttrib->GIDTable[0], &g_Fabric, focus,
clearall?0xffffffff:g_CounterSelectMask.CounterSelectMask.AsReg32,
g_limitstats, g_quiet, &node_count, &port_count,
&nrsp_node_count, &nrsp_port_count);
if (! quiet) {
switch (format) {
case FORMAT_TEXT:
printf("%*sCleared %u Ports on %u Nodes\n", indent, "", port_count, node_count);
if (nrsp_port_count)
printf("%*sUnable to clear %u Ports on %u Nodes\n", indent, "", nrsp_port_count, nrsp_node_count);
break;
case FORMAT_XML:
XmlPrintDec("ClearedPorts", port_count, indent);
XmlPrintDec("ClearedNodes", node_count, indent);
if (nrsp_port_count) {
XmlPrintDec("NoRespPorts", nrsp_port_count, indent);
XmlPrintDec("NoRespNodes", nrsp_node_count, indent);
}
indent-=4;
printf("</ClearCounters>\n");
break;
default:
break;
}
} else {
PROGRESS_PRINT(TRUE, "Cleared %u Ports on %u Nodes\n", port_count, node_count);
if (nrsp_port_count)
PROGRESS_PRINT(TRUE, "Unable to clear %u Ports on %u Nodes\n", nrsp_port_count, nrsp_node_count);
}
done:
return FSUCCESS; // TBD
}
// output summary of all LIDs
void ShowAllLIDReport(Point *focus, Format_t format, int indent, int detail)
{
cl_map_item_t *pMap;
NodeData *nodep;
PortData *portp;
PortSelector* portselp;
uint8 lmc_range = 0; // (2 ** lmc) - 1
uint32 ct_lid;
switch (format) {
case FORMAT_TEXT:
printf("%*sLID Summary\n", indent, "");
break;
case FORMAT_XML:
printf("%*s<LIDSummary>\n", indent, "");
indent+=4;
break;
default:
break;
}
ShowPointFocus(focus, FIND_FLAG_FABRIC, format, indent, detail);
switch (format) {
case FORMAT_TEXT:
printf( "%*s%u LID(s) in Fabric%s\n", indent, "",g_Fabric.lidCount, detail?":":"" );
break;
case FORMAT_XML:
XmlPrintDec("FabricLIDCount", g_Fabric.lidCount, indent);
break;
default:
break;
}
// Report LID Summary
ct_lid = 0;
for ( pMap=cl_qmap_head(&g_Fabric.u.AllLids);
pMap != cl_qmap_end(&g_Fabric.u.AllLids);
pMap = cl_qmap_next(pMap) ) {
portp = PARENT_STRUCT(pMap, PortData, AllLidsEntry);
portselp = GetPortSelector(portp);
nodep = portp->nodep;
if (!ComparePortPoint(portp, focus))
continue;
lmc_range = (1 << portp->PortInfo.s1.LMC) - 1;
if (detail) {
if (!ct_lid) {
switch (format) {
case FORMAT_TEXT:
printf("%*s LID(Range) NodeGUID Port Type Name\n", indent, "");
if (g_topology_in_file)
printf("%*s NodeDetails PortDetails\n", indent, "");
break;
case FORMAT_XML:
break;
default:
break;
}
}
switch (format) {
case FORMAT_TEXT:
printf( "%*s0x%.*x", indent, "", (portp->PortInfo.LID <= IB_MAX_UCAST_LID ? 4:8),
portp->PortInfo.LID);
if (!lmc_range)
printf(" ");
else
printf( "-0x%.*x", ((portp->PortInfo.LID + lmc_range) <= IB_MAX_UCAST_LID ? 4:8),
portp->PortInfo.LID + lmc_range );
printf( " 0x%016"PRIx64" %3u %s %s\n",
nodep->NodeInfo.NodeGUID, portp->PortNum,
StlNodeTypeToText(nodep->NodeInfo.NodeType),
(char*)nodep->NodeDesc.NodeString );
if (nodep->enodep && nodep->enodep->details)
printf( "%*s %s\n",
indent, "", nodep->enodep->details );
if (portselp && portselp->details)
printf( "%*s %s\n",
indent, "", portselp->details );
break;
case FORMAT_XML:
if (!ct_lid)
printf("%*s<LIDs>\n", indent, "");
printf( "%*s<Value LID=\"0x%.*x\">\n", indent+4, "",
(portp->PortInfo.LID <= IB_MAX_UCAST_LID ? 4:8),
portp->PortInfo.LID );
if (lmc_range)
XmlPrintLID( "EndLID",
portp->PortInfo.LID + lmc_range, indent+8 );
XmlPrintHex64( "NodeGUID",
nodep->NodeInfo.NodeGUID, indent+8 );
XmlPrintDec("PortNum", portp->PortNum, indent+8);
if (portselp && portselp->details)
XmlPrintStr("PortDetails", portselp->details, indent+8);
XmlPrintStr( "NodeType",
StlNodeTypeToText(nodep->NodeInfo.NodeType),
indent+8 );
XmlPrintStr( "NodeDesc",
(char*)nodep->NodeDesc.NodeString, indent+8 );
if (nodep->enodep && nodep->enodep->details)
XmlPrintStr("NodeDetails", nodep->enodep->details, indent+8);
printf("%*s</Value>\n", indent+4, "");
break;
default:
break;
}
} // End of if (detail)
ct_lid = ct_lid + lmc_range + 1;
} // End of for ( pMap=cl_qmap_head(&g_Fabric.AllLids)
switch (format) {
case FORMAT_TEXT:
printf("%*s%u Reported LID(s)\n", indent, "", ct_lid);
DisplaySeparator();
break;
case FORMAT_XML:
if (detail && ct_lid)
printf("%*s</LIDs>\n", indent, "");
XmlPrintDec("ReportedLIDCount", ct_lid, indent);
indent-=4;
printf("%*s</LIDSummary>\n", indent, "");
break;
default:
break;
}
} // End of ShowAllLIDReport()
// output linear FDB
void ShowLinearFDBReport(Point *focus, Format_t format, int indent, int detail)
{
int ix_lid;
LIST_ITEM *pList;
cl_map_item_t *pMap;
NodeData *nodep;
SwitchData *switchp;
PortData *portp;
PortSelector* portselp;
uint32 ct_node = 0;
uint32 ct_lid;
switch (format) {
case FORMAT_TEXT:
printf("%*sLinear FDB Tables\n", indent, "");
break;
case FORMAT_XML:
printf("%*s<LinearFDBs>\n", indent, "");
indent+=4;
break;
default:
break;
}
if (! (g_Fabric.flags & FF_ROUTES) && g_snapshot_in_file) {
switch (format) {
case FORMAT_TEXT:
printf("%*sReport skipped: provided snapshot was created without -r option\n", indent, "");
break;
case FORMAT_XML:
printf("%*s<!-- Report skipped: provided snapshot was created without -r option -->\n", indent, "");
break;
default:
break;
}
goto done;
}
ShowPointFocus(focus, FIND_FLAG_FABRIC, format, indent, detail);
switch (format) {
case FORMAT_TEXT:
printf( "%*s%u Connected Switches in Fabric%s\n", indent, "",
(unsigned)QListCount(&g_Fabric.AllSWs), detail?":":"" );
break;
case FORMAT_XML:
XmlPrintDec("ConnectedSwitchCount", (unsigned)QListCount(&g_Fabric.AllSWs), indent);
break;
default:
break;
}
// Report Linear FDB
for ( pList=QListHead(&g_Fabric.AllSWs); pList != NULL;
pList = QListNext(&g_Fabric.AllSWs, pList) ) {
nodep = QListObj(pList);
switchp = nodep->switchp;
if (!CompareNodePoint(nodep, focus))
continue;
if (!switchp || !switchp->LinearFDB)
continue;
if (detail) {
if (!ct_node) {
ShowNodeBriefSummaryHeadings(format, indent, 0);
switch (format) {
case FORMAT_TEXT:
printf("%*s Egress Neighbor\n", indent+4, "");
printf("%*s LID Port Port Name\n", indent+4, "");
if (g_topology_in_file)
printf("%*s PortDetails NodeDetails\n", indent+4, "");
break;
case FORMAT_XML:
break;
default:
break;
}
}
ShowNodeBriefSummary(nodep, focus, FALSE, format, indent, 0);
ct_lid = 0;
for (ix_lid = 0; ix_lid < switchp->LinearFDBSize; ix_lid++) {
if (STL_LFT_PORT_BLOCK(switchp->LinearFDB, ix_lid) == 0xFF)
continue;
switch (format) {
case FORMAT_TEXT:
printf( "%*s0x%04x %3u", indent+4, "", (uint32)ix_lid, STL_LFT_PORT_BLOCK(switchp->LinearFDB, ix_lid) );
break;
case FORMAT_XML:
if (!ct_lid++)
printf("%*s<LinearFDB>\n", indent+4, "");
printf( "%*s<Value LID=\"0x%.*x\">\n", indent+8, "", (ix_lid <= IB_MAX_UCAST_LID ? 4:8),
(uint16)ix_lid );
XmlPrintDec("EgressPort", STL_LFT_PORT_BLOCK(switchp->LinearFDB, ix_lid), indent+12);
break;
default:
break;
}
for ( pMap=cl_qmap_head(&nodep->Ports);
pMap != cl_qmap_end(&nodep->Ports);
pMap = cl_qmap_next(pMap) ) {
portp = PARENT_STRUCT(pMap, PortData, NodePortsEntry);
if (!portp)
continue;
if (portp->PortNum == STL_LFT_PORT_BLOCK(switchp->LinearFDB, ix_lid)) {
portselp = GetPortSelector(portp);
switch (format) {
case FORMAT_TEXT:
if (portp->neighbor) {
printf( " %3u %s",
portp->neighbor->PortNum, g_noname?g_name_marker:
(char*)portp->neighbor->nodep->NodeDesc.NodeString );
if ( portp->neighbor->nodep->enodep &&
portp->neighbor->nodep->enodep->details )
printf( "\n%*s %s",
indent+4, "", portp->neighbor->nodep->enodep->details );
}
if (portselp && portselp->details)
printf( "\n%*s %s",
indent+4, "", portselp->details );
break;
case FORMAT_XML:
if (portselp && portselp->details)
XmlPrintStr("PortDetails", portselp->details, indent+12);
if (portp->neighbor) {
XmlPrintDec("NeighborPort", portp->neighbor->PortNum, indent+12);
XmlPrintStr("NeighborNodeDesc",
g_noname?g_name_marker:
(char *)portp->neighbor->nodep->NodeDesc.NodeString, indent+12);
if ( portp->neighbor->nodep->enodep &&
portp->neighbor->nodep->enodep->details )
XmlPrintStr("NeighborNodeDetails", portp->neighbor->nodep->enodep->details, indent+12);
}
printf("%*s</Value>\n", indent+8, "");
break;
default:
break;
}
break;
} // End of if (portp->PortNum == switchp->LinearFDB[ix_lid])
} // End of for ( pMap=cl_qmap_head(&nodep->Ports)
switch (format) {
case FORMAT_TEXT:
printf("\n");
break;
case FORMAT_XML:
break;
default:
break;
}
} // End of for (ix_lid = 0; ix_lid < switchp->LinearFDBSize
switch (format) {
case FORMAT_XML:
if (ct_lid)
printf("%*s</LinearFDB>\n", indent+4, "");
printf("%*s</Node>\n", indent, "");
break;
default:
break;
}
} // End of if (detail)
ct_node++;
} // End of for (pList=QListHead(&g_Fabric.AllSWs); pList != NULL
done:
switch (format) {
case FORMAT_TEXT:
printf("%*s%d Reported Switch(es)\n", indent, "", ct_node);
DisplaySeparator();
break;
case FORMAT_XML:
XmlPrintDec("ReportedSwitchCount", (unsigned)ct_node, indent);
indent-=4;
printf("%*s</LinearFDBs>\n", indent, "");
break;
default:
break;
}
} // End of ShowLinearFDBReport()
// Used by ShowPGReport.
static uint32 ones64(uint64 x)
{
x -= ((x >> 1) & 0x5555555555555555ULL);
x = (((x >> 2) & 0x3333333333333333ULL) + (x & 0x3333333333333333ULL));
x = (((x >> 4) + x) & 0x0f0f0f0f0f0f0f0fULL);
x += (x >> 8);
x += (x >> 16);
x += (x >> 32);
return(x & 0x0000003f);
}
// Information about port groups
void ShowPGReport(Point *focus, Format_t format, int indent, int detail)
{
int ix_lid;
LIST_ITEM *pList;
NodeData *nodep;
SwitchData *switchp;
uint16 pgCount;
uint32 ct_node = 0;
/* Statistics block */
uint32 overallSwitchCount = 0;
uint32 overallGroupCount = 0;
uint32 overallMaxGroupSize = 0;
uint32 overallMinGroupSize = 256;
uint32 overallSumGroupSize = 0;
uint32 overallMaxGroupCount = 0;
uint32 overallMinGroupCount = 256;
uint32 overallMaxLidsGroup = 0;
uint32 overallMinLidsGroup = 0xffffffff;
uint32 overallSumLidsGroup = 0;
switch (format) {
case FORMAT_TEXT:
printf("%*sPort Groups\n", indent, "");
break;
case FORMAT_XML:
printf("%*s<PortGroups>\n", indent, "");
indent+=4;
break;
default:
break;
}
if (! (g_Fabric.flags & FF_ROUTES) && g_snapshot_in_file) {
switch (format) {
case FORMAT_TEXT:
printf("%*sReport skipped: provided snapshot was created without -r option\n", indent, "");
break;
case FORMAT_XML:
printf("%*s<!-- Report skipped: provided snapshot was created without -r option -->\n", indent, "");
break;
default:
break;
}
goto done;
}
overallSwitchCount = QListCount(&g_Fabric.AllSWs);
ShowPointFocus(focus, FIND_FLAG_FABRIC, format, indent, detail);
switch (format) {
case FORMAT_TEXT:
printf( "%*s%u Connected Switches in Fabric%s\n", indent, "",
overallSwitchCount, detail?":":"" );
break;
case FORMAT_XML:
XmlPrintDec("ConnectedSwitchCount", overallSwitchCount, indent);
break;
default:
break;
}
// Summary data about Port Group Tables
for ( pList=QListHead(&g_Fabric.AllSWs); pList != NULL;
pList = QListNext(&g_Fabric.AllSWs, pList) ) {
/* Statistics block */
uint32 maxGroupSize = 0;
uint32 minGroupSize = 256;
uint32 sumGroupSize = 0;
uint32 maxLidsGroup = 0;
uint32 minLidsGroup = 0xffffffff;
uint32 sumLidsGroup = 0;
uint32 LidsGroup[256];
memset(LidsGroup,0,sizeof(LidsGroup));
nodep = QListObj(pList);
switchp = nodep->switchp;
if (!CompareNodePoint(nodep, focus))
continue;
if (!switchp || !switchp->PortGroupElements || !switchp->PortGroupFDB)
continue;
if (nodep->pSwitchInfo &&
nodep->pSwitchInfo->SwitchInfoData.AdaptiveRouting.s.Enable &&
nodep->pSwitchInfo->SwitchInfoData.PortGroupTop != 0) {
pgCount = nodep->pSwitchInfo->SwitchInfoData.PortGroupTop;
} else {
pgCount = 0;
}
overallGroupCount += pgCount;
overallMaxGroupCount = MAX(overallMaxGroupCount, pgCount);
overallMinGroupCount = MIN(overallMinGroupCount, pgCount);
switch (format) {
case FORMAT_XML:
printf("%*s<PortGroupSummary>\n", indent, "");
break;
default:
break;
}
if (!ct_node) {
ShowNodeBriefSummaryHeadings(format, indent, 0);
}
if (format == FORMAT_TEXT) {
printf("\n");
}
ShowNodeBriefSummary(nodep, focus, FALSE, format, indent, 0);
if (format == FORMAT_TEXT && detail > 2) {
printf("%*s Group : Ports\n",indent+4,"");
}
if (pgCount == 0) {
switch (format) {
case FORMAT_TEXT:
printf("%*s(no groups)\n", indent+4, "");
break;
case FORMAT_XML:
break;
default:
break;
}
} else {
for (ix_lid = 0;
switchp->PortGroupElements && ix_lid < pgCount;
ix_lid++) {
uint32 bitCount = ones64((uint64_t)switchp->PortGroupElements[ix_lid]);
maxGroupSize = MAX(maxGroupSize, bitCount);
minGroupSize = MIN(minGroupSize, bitCount);
sumGroupSize += bitCount;
if (detail > 2) {
uint64_t msk;
int j;
if (format == FORMAT_TEXT) {
printf("%*s %3d : ", indent+4, "",
ix_lid);
if (switchp->PortGroupElements[ix_lid]==0) {
printf("None");
} else for (msk = 1, j = 0;j < 64;msk<<= 1, j++) {
if (switchp->PortGroupElements[ix_lid] & msk) {
printf("%d, ", j+1);
}
}
printf("\n");
} else if (format == FORMAT_XML) {
printf( "%*s<Value ID=\"%d\">\n", indent+4, "",
ix_lid);
XmlPrintHex64("PortGroup",
switchp->PortGroupElements[ix_lid],
indent+8);
printf("%*s</Value>\n", indent+4, "");
}
}
}
overallMaxGroupSize = MAX(maxGroupSize,overallMaxGroupSize);
overallMinGroupSize = MIN(minGroupSize,overallMinGroupSize);
overallSumGroupSize += sumGroupSize;
if (detail > 2 && format == FORMAT_TEXT) {
printf("\n");
}
switch (format) {
case FORMAT_TEXT:
printf("%*s Num Groups : %d\n", indent+4, "", pgCount);
printf("%*sMax Ports/Group : %d\n", indent+4, "", maxGroupSize);
printf("%*sMin Ports/Group : %d\n", indent+4, "", minGroupSize);
printf("%*sAvg Ports/Group : %.1f\n", indent+4, "",
(float)sumGroupSize/(float)pgCount);
break;
case FORMAT_XML:
XmlPrintDec("NumGroups", pgCount, indent+4);
XmlPrintDec("MaxGroupSize",maxGroupSize, indent+4);
XmlPrintDec("MinGroupSize",minGroupSize, indent+4);
break;
}
}
if (pgCount && switchp->PortGroupFDB) {
uint8 g;
for (ix_lid = 1; ix_lid < switchp->LinearFDBSize; ix_lid++) {
if (STL_LFT_PORT_BLOCK(switchp->LinearFDB, ix_lid) == 0xFF)
continue;
if (ix_lid >= switchp->PortGroupFDBSize)
break;
g = STL_PGFT_PORT_BLOCK(switchp->PortGroupFDB,ix_lid);
LidsGroup[g]++;
}
for (g=0; g < pgCount; g++) {
sumLidsGroup += LidsGroup[g];
maxLidsGroup = MAX(maxLidsGroup,LidsGroup[g]);
minLidsGroup = MIN(minLidsGroup,LidsGroup[g]);
}
overallSumLidsGroup += sumLidsGroup;
overallMaxLidsGroup = MAX(maxLidsGroup,overallMaxLidsGroup);
overallMinLidsGroup = MIN(minLidsGroup,overallMinLidsGroup);
switch (format) {
case FORMAT_TEXT:
printf("%*s Max Lids/Group : %d\n", indent+4, "", maxLidsGroup);
printf("%*s Min Lids/Group : %d\n", indent+4, "", minLidsGroup);
printf("%*s Avg Lids/Group : %.1f\n", indent+4, "",
(float)sumLidsGroup/(float)pgCount);
break;
case FORMAT_XML:
XmlPrintDec("MaxLidsGroup",maxLidsGroup, indent+4);
XmlPrintDec("MinLidsGroup",minLidsGroup, indent+4);
break;
}
if (detail > 2) {
uint32_t currGroup = 0xFFFF;
STL_LID startLid = 0;
switch (format) {
case FORMAT_TEXT:
printf("%*s---- Lid Range ---- Group #\n", indent+4, "");
break;
case FORMAT_XML:
printf("%*s<PortGroupForwardingTable>\n", indent+4, "");
break;
default:
break;
}
for (ix_lid = 1; ix_lid < switchp->LinearFDBSize; ix_lid++) {
if (ix_lid >= switchp->PortGroupFDBSize)
break;
g = STL_PGFT_PORT_BLOCK(switchp->PortGroupFDB,ix_lid);
if (format == FORMAT_XML) {
if (g == 0xFF)
continue;
printf( "%*s<Value LID=\"0x%.*x\">\n", indent+8, "",
(ix_lid <= IB_MAX_UCAST_LID ? 4:8), ix_lid );
XmlPrintHex("PortGroup", g, indent+12);
printf("%*s</Value>\n", indent+8, "");
} else {
if (g == currGroup)
continue;
if (currGroup != 0xFFFF) {
if (currGroup != 0xFF) {
printf("%*s0x%08x - %08x %3u\n", indent+4, "",
startLid, ix_lid-1, currGroup);
} else {
printf("%*s0x%08x - %08x (none)\n",
indent+4, "", startLid, ix_lid-1);
}
}
currGroup = g;
startLid = ix_lid;
}
}
switch (format) {
case FORMAT_XML:
printf("%*s</PortGroupForwardingTable>\n", indent+4, "");
break;
default:
if (currGroup != 0xFF) {
printf("%*s0x%08x - %08x %3u\n", indent+4, "",
startLid, ix_lid-1, currGroup);
} else {
printf("%*s0x%08x - %08x (none)\n", indent+4, "",
startLid, ix_lid-1);
}
break;
}
}
}
switch (format) {
case FORMAT_XML:
printf("%*s</Node>\n", indent, "");
printf("%*s</PortGroupSummary>\n", indent, "");
break;
default:
break;
}
ct_node++;
} // End of for (pList=QListHead(&g_Fabric.AllSWs); pList != NULL
if (overallGroupCount != 0) {
switch (format) {
case FORMAT_TEXT:
printf("\n%*sSummary:\n", indent, "");
printf("%*s Num Groups : %d\n", indent+4, "",
overallGroupCount);
printf("%*sMax Ports/Group : %d\n", indent+4, "",
overallMaxGroupSize);
printf("%*sMin Ports/Group : %d\n", indent+4, "",
overallMinGroupSize);
printf("%*sAvg Ports/Group : %.1f\n", indent+4, "",
(float)overallSumGroupSize/(float)overallGroupCount);
printf("%*s Max Lids/Group : %d\n", indent+4, "",
overallMaxLidsGroup);
printf("%*s Min Lids/Group : %d\n", indent+4, "",
overallMinLidsGroup);
printf("%*s Avg Lids/Group : %.1f\n", indent+4, "",
(float)overallSumLidsGroup/(float)overallGroupCount);
break;
case FORMAT_XML:
break;
}
} else if (format == FORMAT_TEXT) {
printf("\n%*sNo port groups found.\n",indent,"");
}
done:
switch (format) {
case FORMAT_TEXT:
printf("%*s%d Reported Switch(es)\n", indent, "", ct_node);
DisplaySeparator();
break;
case FORMAT_XML:
XmlPrintDec("ReportedSwitchCount", (unsigned)ct_node, indent);
indent-=4;
printf("%*s</PortGroups>\n", indent, "");
break;
default:
break;
}
} // End of ShowPGReport()
// Used by PGRouteHop to print out the current node when a adaptive routing
// error is detected. Since PGRouteHop is recursive, this has the effect
// of printing out each hop in the failed route.
//
// nodep - the current node.
// lid - the lid of the current node.
// length - the recursive depth/hop count/path length at this point.
static void POP_NODEDATA(NodeData *nodep, STL_LID lid,
uint32_t length, Format_t format, int indent)
{
switch(format) {
case FORMAT_XML:
printf("%*s<Hop Value=\"%d\">\n",indent+4,"", length);
XmlPrintHex64( "NodeGUID", nodep->NodeInfo.NodeGUID, indent+8 );
printf("%*s</Hop>\n",indent+4,"");
break;
default:
printf("%*sHop %d: 0x%016"PRIx64", (LID 0x%x)\n",indent+4,"", \
length, nodep->NodeInfo.NodeGUID, lid); \
break;
}
}
// Note that 128 is an arbitrary limit, but it will be able to
// cope with a 2D mesh/torus that's 64 switches in each dimension,
// which is more than twice the # of LIDs available in STL gen1.
#define MAX_HOPS 128
// Used by ShowValidatePGReport.
// olid = originating lid (original slid)
// dlid = destination lid
// nodep = current hop
// length = hop count so far.
// mhops = maximum # of hops we are allowed to traverse.
// lftonly = ignore the port group forwarding table
//
// Returns the total hopcount or -1.
//
static int32_t PGRouteHop(STL_LID olid, NodeData *nodep, STL_LID dlid,
int32_t length, int32_t mhops, int32_t lftonly,
Format_t format, int indent)
{
PortData *portp;
SwitchData *switchp;
uint8_t ep;
uint8_t pg;
NodeData *nnodep;
PortData *nportp;
uint32_t i;
int32_t pl1, pl2;
STL_LID slid;
STL_PORTMASK pgm;
// Add the link that was traversed to get here:
length++;
// If we've already tested this dlid from this switch,
// don't do it again.
if (((uint8_t*)nodep->context)[dlid] != 0) {
return length+((uint8_t*)nodep->context)[dlid];
}
portp = FindNodePort(nodep,0);
if (!portp) {
printf("%*sUnable to find port 0\n", indent, "");
return -1;
}
slid = portp->PortInfo.LID;
switchp = nodep->switchp;
if (dlid == slid) {
// Inability to route to yourself is checked at the
// top level, so we can just return success here.
return length;
}
// Have we exceeded the maximum # of hops permitted?
if (length > mhops) {
switch(format) {
case FORMAT_XML:
printf("%*s<ARError Value=\"HopsExceeded\">\n",indent+4,"");
XmlPrintDec("SLID",olid,indent+8);
XmlPrintDec("DLID",dlid,indent+8);
break;
default:
printf("%*sERROR: Path from 0x%x to 0x%x exceeds normal path length or max hops.\n",
indent, "", olid, dlid);
break;
}
POP_NODEDATA(nodep, slid, length, format, indent);
return -1;
}
ep = STL_LFT_PORT_BLOCK(switchp->LinearFDB,dlid);
pg = STL_PGFT_PORT_BLOCK(switchp->PortGroupFDB,dlid);
//
// if LFT[dlid] == 0xff then we think this dlid is unused,
// which is inconsistent with the parent switch.
//
if (ep == 0xff) {
printf("%*sNo path to LID 0x%x\n",
indent, "", dlid);
POP_NODEDATA(nodep, slid, length, format, indent);
return -1;
}
// Find our LFT neighbor node.
portp = FindNodePort(nodep,ep);
if (!portp) {
printf("%*sUnable to find port %d\n",
indent, "", ep);
return -1;
}
nportp = portp->neighbor;
nnodep = nportp->nodep;
// If our neighbor isn't a switch, then the route better
// terminate and PGFT[dlid] should be 0xff.
if (nnodep->NodeInfo.NodeType != STL_NODE_SW) {
STL_LID mask = ~0 << nportp->PortInfo.s1.LMC;
if ((dlid & mask) != (nportp->PortInfo.LID & mask)) {
switch(format) {
case FORMAT_XML:
printf("%*s<ARError Value=\"BadTermination\">\n",indent+4,"");
XmlPrintDec("SLID",olid,indent+8);
XmlPrintDec("DLID",dlid,indent+8);
break;
default:
printf("%*sERROR: Path from 0x%x to 0x%x terminates at the wrong "
"device:\n",
indent, "", olid, dlid);
break;
}
POP_NODEDATA(nnodep, nportp->PortInfo.LID, length+1, format, indent);
POP_NODEDATA(nodep, slid, length, format, indent);
return -1;
} else if (pg != 0xff) {
switch(format) {
case FORMAT_XML:
printf("%*s<ARError Value=\"BadMembership\">\n",indent+4,"");
XmlPrintDec("SLID",olid,indent+8);
XmlPrintDec("DLID",dlid,indent+8);
break;
default:
printf("%*sERROR: LFT Path from 0x%x to 0x%x terminates but is also "
"in the PGFT: (1)\n",
indent, "", olid, dlid);
break;
}
POP_NODEDATA(nnodep, nportp->PortInfo.LID, length+1, format, indent);
POP_NODEDATA(nodep, slid, length, format, indent);
return -1;
}
// Everything checks out. Include the egress link in our count.
((uint8_t*)nodep->context)[dlid]=1;
return length+1; //success.
}
// Test the LFT route for this DLID. There is another report that
// does this, but we want the hop count to compare the PGFT entries
// against.
pl1 = PGRouteHop(slid, nnodep, dlid, length, mhops, 1, format, indent);
if (pl1 < 0) {
POP_NODEDATA(nodep, slid, length, format, indent);
return pl1;
} else if (lftonly != 0) {
// done.
return pl1;
}
// If the DLID is in the PGFT, then test the route from this switch to
// DLID via each port in the matching port group.
if (pg != 0xff) for (i=1, pgm = switchp->PortGroupElements[pg];
pgm != 0; pgm>>=1, i++) {
if (pgm & 1 && i != ep) {
// We only test a port if (a) it is a member of the port group and
// (b) it is not the lft egress port (we already checked that).
// TODO Can we avoid revisiting the same node in the tier0 case?
portp = FindNodePort(nodep,i);
if (!portp) {
printf("%*sUnable to find port %d\n",
indent, "", i);
return -1;
}
nportp = portp->neighbor;
nnodep = nportp->nodep;
if (nnodep->NodeInfo.NodeType != STL_NODE_SW) {
STL_LID mask = ~0 << nportp->PortInfo.s1.LMC;
if ((dlid & mask) != (nportp->PortInfo.LID & mask)) {
switch(format) {
case FORMAT_XML:
printf("%*s<ARError Value=\"BadTermination\">\n",indent+4,"");
XmlPrintDec("SLID",olid,indent+8);
XmlPrintDec("DLID",dlid,indent+8);
break;
default:
printf("%*sERROR: AR Path from 0x%x to 0x%x terminates at the "
"wrong device:\n", indent, "", olid, dlid);
break;
}
} else {
// Even if this is the right device, we still have
// a problem.
switch(format) {
case FORMAT_XML:
printf("%*s<ARError Value=\"BadMembership\">\n",indent+4,"");
XmlPrintDec("SLID",olid,indent+8);
XmlPrintDec("DLID",dlid,indent+8);
break;
default:
printf("%*sERROR: AR Path from 0x%x to 0x%x terminates but LFT "
"path does not: (2)\n",
indent, "", olid, dlid);
break;
}
}
POP_NODEDATA(nnodep, nportp->PortInfo.LID, length+1, format,
indent);
POP_NODEDATA(nodep, slid, length, format, indent);
return -1;
}
// Calculate the length of the path from here to dlid
// via nnodep. It should be the same as the LFT path length.
pl2 = PGRouteHop(slid, nnodep, dlid, length, mhops, 0, format, indent);
if (pl2 < 0) {
// There was a problem further along. Just pop our
// position in the path and return.
POP_NODEDATA(nodep, slid, length, format, indent);
return -1;
} else if (pl2 != pl1) {
// This path was either shorter or longer than
// the linear path. Either way, that's a problem.
switch(format) {
case FORMAT_XML:
printf("%*s<ARError Value=\"InconsistentHopCount\">\n",indent+4,"");
XmlPrintDec("SLID",olid,indent+8);
XmlPrintDec("DLID",dlid,indent+8);
XmlPrintDec("PL1",pl1-1,indent+8);
XmlPrintDec("PL2",pl2-1,indent+8);
break;
default:
printf("%*sERROR: Paths from 0x%016"PRIx64", (LID 0x%x)"
" to LID 0x%x have inconsistent hop counts: %d vs %d\n",
indent, "",
nodep->NodeInfo.NodeGUID, slid, dlid, pl1-1, pl2-1);
break;
}
POP_NODEDATA(nnodep, nportp->EndPortLID, length,
format, indent);
return -1;
}
}
}
((uint8_t*)nodep->context)[dlid]=pl1 - length;
return pl1;
}
// Used by ShowValidatePGReport.
static int compare_masks(const void *a, const void *b)
{
STL_PORTMASK *pm1 = (STL_PORTMASK*)a;
STL_PORTMASK *pm2 = (STL_PORTMASK*)b;
if (*pm1<*pm2) return -1;
if (*pm1>*pm2) return 1;
return 0;
}
void ShowValidatePGReport(Format_t format, int indent, int detail)
{
LIST_ITEM *pList;
uint32_t routeCount = 0;
uint32_t ct_node = 0;
if (! (g_Fabric.flags & FF_ROUTES) && g_snapshot_in_file) {
switch (format) {
case FORMAT_TEXT:
printf("%*sReport skipped: provided snapshot was created without -r option\n", indent, "");
break;
case FORMAT_XML:
printf("%*s<!-- Report skipped: provided snapshot was created without -r option -->\n", indent, "");
break;
default:
break;
}
return;
}
switch (format) {
case FORMAT_TEXT:
printf("%*sValidate Port Groups\n", indent, "");
break;
case FORMAT_XML:
printf("%*s<ValidatePortGroups>\n", indent, "");
indent+=4;
break;
default:
break;
}
switch (format) {
case FORMAT_TEXT:
printf( "%*s%u LID(s) in Fabric%s\n", indent, "",
(unsigned)cl_qmap_count(&g_Fabric.u.AllLids), detail?":":"" );
printf("%*s%u Connected HFIs in Fabric%s\n", indent, "",
(unsigned)QListCount(&g_Fabric.AllFIs), detail?":":"");
printf( "%*s%u Connected Switch(es) in Fabric%s\n", indent, "",
(unsigned)QListCount(&g_Fabric.AllSWs), detail?":":"" );
break;
case FORMAT_XML:
XmlPrintDec("FabricLIDCount",
(unsigned)cl_qmap_count(&g_Fabric.u.AllLids), indent);
XmlPrintDec("ConnectedHFICount",
(unsigned)QListCount(&g_Fabric.AllFIs), indent);
XmlPrintDec("ConnectedSwitchCount",
(unsigned)QListCount(&g_Fabric.AllSWs), indent);
break;
default:
break;
}
// Allocate buffers for optimizing the search.
for ( pList=QListHead(&g_Fabric.AllSWs); pList != NULL;
pList = QListNext(&g_Fabric.AllSWs, pList) ) {
NodeData *nodep = (NodeData*)QListObj(pList);
STL_SWITCHINFO_RECORD *switchp = nodep->pSwitchInfo;
assert(switchp);
nodep->context = MemoryAllocate2AndClear(
switchp->SwitchInfoData.LinearFDBTop+1,
IBA_MEM_FLAG_PREMPTABLE, MYTAG);
assert(nodep->context);
}
for ( pList=QListHead(&g_Fabric.AllSWs); pList != NULL;
pList = QListNext(&g_Fabric.AllSWs, pList) ) {
NodeData *nodep = (NodeData*)QListObj(pList);
SwitchData *switchp = nodep->switchp;
STL_PORTMASK pgt[MAX_PGT_ELEMENTS];
STL_PORTMASK pgo;
int i;
int pgCount = 0;
int dupPGFound = 0;
if (!ct_node) {
ShowNodeBriefSummaryHeadings(format, indent, 0);
ct_node++;
}
ShowNodeBriefSummary(nodep, NULL, FALSE, format, indent, 0);
if (nodep->pSwitchInfo &&
nodep->pSwitchInfo->SwitchInfoData.AdaptiveRouting.s.Enable &&
nodep->pSwitchInfo->SwitchInfoData.PortGroupTop != 0) {
pgCount = nodep->pSwitchInfo->SwitchInfoData.PortGroupTop;
} else if (nodep->pSwitchInfo && nodep->pSwitchInfo->SwitchInfoData.AdaptiveRouting.s.Enable == 0) {
if (format == FORMAT_XML) printf("%*s</Node>\n", indent, "");
else printf("%*sAdaptive Routing Disabled.\n", indent+4, "");
continue;
} else if (nodep->pSwitchInfo && nodep->pSwitchInfo->SwitchInfoData.PortGroupTop == 0) {
if (format == FORMAT_XML) printf("%*s</Node>\n", indent, "");
else printf("%*sNo port groups defined.\n", indent+4, "");
continue;
} else {
if (format != FORMAT_XML) printf("%*sNo switch info.\n", indent+4, "");
}
// The first test is to check for duplicate port groups.
memcpy(pgt, switchp->PortGroupElements,
pgCount*sizeof(STL_PORTMASK));
qsort(pgt,pgCount,sizeof(STL_PORTMASK),compare_masks);
pgo=pgt[0];
for (i=1;i<pgCount; i++) {
if (pgo == pgt[i]) {
switch (format) {
case FORMAT_XML:
XmlPrintHex64("DuplicatePortGroup",(EUI64)pgo, indent+4);
break;
default:
printf("%*sDuplicate port groups with value 0x%016llx.\n",
indent, "",
(long long unsigned int)pgo);
break;
}
dupPGFound = 1;
}
pgo = pgt[i];
}
if (dupPGFound) {
if (format != FORMAT_XML) {
printf("%*sPort Groups:\n",indent,"");
} else {
printf("%*s<PortGroups>\n",indent+4,"");
}
for (i=0; i<pgCount; i++) {
switch (format) {
case FORMAT_XML:
printf("%*s<PortGroup Id=%d>\n",indent+8,"",i);
XmlPrintHex64( "Value",
switchp->PortGroupElements[i], indent+12);
printf("%*s</PortGroup>\n",indent+8,"");
break;
default:
printf("%*sPG %3d : 0x%016llx\n",indent+4,"",i,
(long long unsigned int)switchp->PortGroupElements[i]);
break;
}
}
if (format == FORMAT_XML) {
printf("%*s</PortGroups>\n",indent+4,"");
}
}
//
// Now validate all routes from this switch.
//
{
PortData *portp = FindNodePort(nodep,0);
if (!portp) {
printf("%*sUnable to find port 0\n",
indent, "");
return;
}
STL_LID slid = portp->PortInfo.LID;
STL_LID dlid;
uint32_t lidCount;
uint32_t arOkay;
uint32_t arCount;
if (nodep->pSwitchInfo &&
nodep->pSwitchInfo->SwitchInfoData.LinearFDBTop != 0) {
lidCount = nodep->pSwitchInfo->SwitchInfoData.LinearFDBTop+1;
} else {
lidCount = switchp->LinearFDBSize;
}
if (detail>2) {
switch (format) {
case FORMAT_XML:
printf("%*s<AdaptiveRoutes>\n",indent+4,"");
break;
default:
printf("%*sRoute List:\n", indent, "");
printf("%*sGuid - Lid - Hops - Alts\n", indent+4, "");
break;
}
}
// Check all DLIDs, even the unused ones.
for(dlid = 1; dlid < lidCount; dlid++) {
uint8_t ep = STL_LFT_PORT_BLOCK(switchp->LinearFDB,dlid);
uint8_t pg;
NodeData *nnodep;
PortData *nportp;
int32_t pl1, pl2;
STL_PORTMASK pgm;
arOkay = 1;
arCount = 0;
if (dlid >= switchp->PortGroupFDBSize)
pg = 0xff;
else
pg = STL_PGFT_PORT_BLOCK(switchp->PortGroupFDB,dlid);
//
// Make sure the switch correctly routes to itself.
// LFT[dlid] should be zero and PGFT[dlid] should be 0xff.
//
if (dlid == slid) {
if (ep != 0) switch (format) {
case FORMAT_XML:
printf("%*s<ARError Value=\"Port0Error\" />\n",
indent+4,"");
break;
default:
printf("%*sERROR: Switch cannot route to itself.\n",
indent, "");
break;
}
if (pg != 0xff) switch (format) {
case FORMAT_XML:
printf("%*s<ARError Value=\"Port0ARError\" />\n",
indent+4,"");
break;
default:
printf("%*sERROR: Switch is in its own port group "
"forwarding table (LID 0x%x).\n",
indent, "", dlid);
}
continue;
}
//
// if the dlid is not in use, it should not be in the PGFT.
//
if (ep == 0xff) {
if (pg != 0xff) switch (format) {
case FORMAT_XML:
printf("%*s<ARError Value=\"BadDLID\" />\n",
indent+4,"");
break;
default:
printf("%*sERROR: LID 0x%x is in the PGFT but not the LFT.\n",
indent, "", dlid);
}
continue; // dlid is not in use.
} else if (ep == 0)
continue; // FIXME MWHEINZ extra LID going to management card? LMC?
else {
if (dlid >= switchp->PortGroupFDBSize) {
switch (format) {
case FORMAT_XML:
printf("%*s<ARError Value=\"BadDLID\" />\n",
indent+4,"");
break;
default:
printf("%*sERROR: LID 0x%x is in the LFT but not the PGFT.\n",
indent, "", dlid);
}
continue;
}
}
// Find our LFT neighbor node.
portp = FindNodePort(nodep,ep);
if (!portp) {
printf("%*sUnable to find port %d\n",
indent, "", ep);
return;
}
nportp = portp->neighbor;
nnodep = nportp->nodep;
// If our neighbor isn't a switch, then the route better
// terminate and PGFT[dlid] should be 0xff.
if (nnodep->NodeInfo.NodeType != STL_NODE_SW) {
STL_LID mask = ~0 << nportp->PortInfo.s1.LMC;
if ((dlid & mask) != (nportp->PortInfo.LID & mask)) {
switch(format) {
case FORMAT_XML:
printf("%*s<ARError Value=\"BadTermination\">\n",
indent+4,"");
XmlPrintDec("DLID",dlid,indent+8);
printf("%*s</ARError>\n",indent+4,"");
break;
default:
printf("%*sPath to 0x%x terminates at the "
"wrong device:\n", indent, "", dlid);
break;
}
} else if (pg != 0xff) {
switch(format) {
case FORMAT_XML:
printf("%*s<ARError Value=\"BadMembership\">\n",indent+4,"");
XmlPrintDec("SLID",slid,indent+8);
XmlPrintDec("DLID",dlid,indent+8);
printf("%*s</ARError>\n",indent+4,"");
break;
default:
printf("%*sERROR: LFT path from 0x%x to 0x%x terminates but is also "
"in the PGFT. (3)\n",
indent, "", slid, dlid);
break;
}
}
pl1 = 1;
} else {
// Test the LFT route for this DLID. There is another report
// that does this, but we want the hop count to compare the
// PGFT entries against.
pl1 = PGRouteHop(slid, nnodep, dlid, 0, MAX_HOPS, 1, format, indent);
if (pl1 < 0) {
if (format==FORMAT_XML) {
printf("%*s</ARError>\n",indent+4,"");
}
continue;
}
// If the DLID is in the PGFT, then test the route from this
// switch to DLID via each port in the matching port group.
if (pg != 0xff) for (i=1, pgm = switchp->PortGroupElements[pg];
pgm != 0; pgm>>=1, i++) {
if (pgm & 1) {
// FIXME MWHEINZ can we avoid revisiting the same node in the tier0 case?
portp = FindNodePort(nodep,i);
if (!portp) {
printf("%*sUnable to find port %d\n",
indent, "", i);
return;
}
nportp = portp->neighbor;
nnodep = nportp->nodep;
if (nnodep->NodeInfo.NodeType != STL_NODE_SW) {
STL_LID mask = ~0 << nportp->PortInfo.s1.LMC;
if ((dlid & mask) != (nportp->PortInfo.LID & mask)) switch(format) {
case FORMAT_XML:
printf("%*s<ARError Value=\"BadTermination\">\n",
indent+4,"");
XmlPrintDec("DLID",dlid,indent+8);
printf("%*s</ARError>\n",indent+4,"");
break;
default:
printf("%*sERROR: AR Path from 0x%x to 0x%x "
"terminates at the wrong device.\n",
indent, "", slid, dlid);
} else {
// Even if this is the right device, we still have
// a problem.
switch(format) {
case FORMAT_XML:
printf("%*s<ARError Value=\"BadMembership\">\n",indent+4,"");
XmlPrintDec("SLID",slid,indent+8);
XmlPrintDec("DLID",dlid,indent+8);
printf("%*s</ARError>\n",indent+4,"");
break;
default:
printf("%*sERROR: AR Path from 0x%x to 0x%x terminates but LFT "
"path does not. (4)\n",
indent, "", slid, dlid);
break;
}
}
continue;
}
// Calculate the length of the path from here to dlid
// via nnodep. It should be the same as the LFT path
// length.
pl2 = PGRouteHop(slid, nnodep, dlid, 0, pl1, 0, format, indent);
if (pl2 < 0) {
POP_NODEDATA(nnodep,
nportp->EndPortLID, 1,
format, indent);
// PGRouteHop detected an error.
if (format==FORMAT_XML) {
printf("%*s</ARError>\n",indent+4,"");
}
break; // stop looking...
} else if (pl2 != pl1) {
// This path was shorter or longer than the
// linear path. Either way, that's a problem.
switch(format) {
case FORMAT_XML:
printf("%*s<ARError Value=\"InconsistentHopCount\">\n",
indent+4,"");
XmlPrintDec("SLID",slid,indent+8);
XmlPrintDec("DLID",dlid,indent+8);
XmlPrintDec("PL1",pl1-1,indent+8);
XmlPrintDec("PL2",pl2-1,indent+8);
break;
default:
printf("%*sERROR: Paths from 0x%016"PRIx64", (LID 0x%x)"
" to LID 0x%x have inconsistent hop counts: %d vs %d\n",
indent, "",
nodep->NodeInfo.NodeGUID, slid, dlid, pl1-1, pl2-1);
break;
}
arOkay = 0;
break;
}
arCount++;
}
routeCount++;
}
((uint8_t*)nodep->context)[dlid]=pl1;
}
if (detail>2 && arOkay) {
PortData *destPortp = FindLid(&g_Fabric,dlid);
EUI64 portGuid = (destPortp)?destPortp->PortGUID:0x0ll;
switch (format) {
case FORMAT_XML:
printf("%*s<Route>\n",indent+4,"");
XmlPrintHex("DLID",dlid, indent+8);
XmlPrintHex("PortGUID", portGuid, indent+8);
XmlPrintHex("HopCount",pl1, indent+8);
XmlPrintDec("Alternates", arCount, indent+8);
printf("%*s</Route>\n",indent+4,"");
break;
default:
printf("%*s0x%016llx - 0x%08x - %2d - %2d\n",
indent+4, "", (long long unsigned int)portGuid,
dlid, pl1-1, arCount);
break;
}
}
}
if (detail>2) switch (format) {
case FORMAT_XML:
printf("%*s</AdaptiveRoutes>\n",indent+4,"");
break;
case FORMAT_TEXT:
break;
}
}
if (format == FORMAT_XML) {
printf("%*s</Node>\n", indent, "");
}
} // for ( pList=QListHead(&g_Fabric.AllSWs);
switch (format) {
case FORMAT_XML:
XmlPrintDec("RoutesTested",routeCount,indent);
printf("%*s</ValidatePortGroups>\n", indent-4, "");
break;
default:
printf("%*sAlternate Routes Tested: %d\n", indent, "", routeCount);
break;
}
}
FSTATUS ShowMcGroups(FabricData_t *fabricp, Format_t format, int detail, int indent)
{
LIST_ITEM *n1, *p1;
if (detail >= 0)
switch (format) {
case FORMAT_TEXT:
if (fabricp->NumOfMcGroups == 1)
printf("Number of MC Group: %d\n", fabricp->NumOfMcGroups);
else
printf("Number of MC Groups: %d\n", fabricp->NumOfMcGroups);
if (detail > 0 ) printf("\n");
break;
case FORMAT_XML:
printf("%*s<NumMcGroups>%d</NumMcGroups>\n",indent+4,"",fabricp->NumOfMcGroups);
break;
default:
break;
}
// collecting information about MC Groups
for (n1 = QListHead (&fabricp->AllMcGroups); n1 != NULL; n1 = QListNext(&fabricp->AllMcGroups, n1)) {
McGroupData *pmcgroup = (McGroupData *)QListObj(n1);
//for this PortGID get member group information
// do not get info on empty groups
McMemberData *pMCGM = (McMemberData *)QListObj(QListHead(&pmcgroup->AllMcGroupMembers));
if ((pMCGM->MemberInfo.RID.PortGID.AsReg64s.H ==0) && (pMCGM->MemberInfo.RID.PortGID.AsReg64s.L==0))
continue;
if (detail > 0 )
switch (format) {
case FORMAT_TEXT:
DisplayGroupRecord (pmcgroup, indent, detail);
printf("Number of Group Members: %d\n", pmcgroup->NumOfMembers);
break;
case FORMAT_XML:
printf("%*s<%s id=\"0x%016"PRIx64":0x%016"PRIx64"\">\n", indent+4, "", "MulticastGroup",
pmcgroup->MGID.AsReg64s.H, pmcgroup->MGID.AsReg64s.L);
printf("%*s<NumMcGMembers>%d</NumMcGMembers>\n",indent+8,"", pmcgroup->NumOfMembers);
XmlPrintGroupRecord (pmcgroup, indent, detail);
break;
default:
break;
}
if (detail > 1 ) {
//if the list is not empty)
for (p1=QListHead(&pmcgroup->AllMcGroupMembers); p1 != NULL; p1 = QListNext(&pmcgroup->AllMcGroupMembers, p1)) {
McMemberData *pMCGG = (McMemberData *)QListObj(p1);
if ((pMCGG->MemberInfo.RID.PortGID.AsReg64s.H !=0) || (pMCGG->MemberInfo.RID.PortGID.AsReg64s.L!=0)) {
switch (format) { // do not print "zero" members
case FORMAT_TEXT:
printf("PortGid: 0x%016"PRIx64":0x%016"PRIx64" Membership: %s%s%s\n",
pMCGG->MemberInfo.RID.PortGID.AsReg64s.H,
pMCGG->MemberInfo.RID.PortGID.AsReg64s.L,
pMCGG->MemberInfo.JoinFullMember ? "Full " : "",
pMCGG->MemberInfo.JoinNonMember ? "Non " : "",
pMCGG->MemberInfo.JoinSendOnlyMember ? "Sendonly " : "");
break;
case FORMAT_XML:
printf("%*s<%s id=\"0x%016"PRIx64":0x%016"PRIx64"\">\n", indent+8, "", "McMembers",
pMCGG->MemberInfo.RID.PortGID.AsReg64s.H, pMCGG->MemberInfo.RID.PortGID.AsReg64s.L);
XmlPrintGID("GID",pMCGG->MemberInfo.RID.PortGID,indent+12);
XmlPrintTagHeader("Membership", indent+12);
XmlPrintStr("Full", pMCGG->MemberInfo.JoinFullMember? "1":"0", indent+16);
XmlPrintStr("NonMember", pMCGG->MemberInfo.JoinNonMember? "1":"0", indent+16);
XmlPrintStr("SendOnly", pMCGG->MemberInfo.JoinSendOnlyMember? "1":"0", indent+16);
XmlPrintTagFooter("Membership", indent+12);
McMembershipXmlOutput("Membership_Int", pMCGG,indent+12);
break;
default:
break;
}// case end
// this list is sorted/keyed by NodeGUID
PortData *portp=FindPortGuid(fabricp, pMCGG->MemberInfo.RID.PortGID.AsReg64s.L);
if (portp !=NULL) {
switch (format) {
case FORMAT_TEXT:
printf("Name: %.*s \n", NODE_DESCRIPTION_ARRAY_SIZE,
g_noname?g_name_marker:(char*)portp->nodep->NodeDesc.NodeString);
break;
case FORMAT_XML:
XmlPrintNodeDesc((char*)portp->nodep->NodeDesc.NodeString, indent+12);
// print end tag
break;
default:
break;
}// end case
} //end if
else {
switch (format) {
case FORMAT_TEXT:
printf("Name: Not available\n");
break;
default:
break;
}
}
if (format == FORMAT_XML)
printf("%*s</McMembers>\n", indent+8, "");
}
} // end for p1
}//end if detail
if (detail > 0)
switch (format) {
case FORMAT_TEXT:
printf("\n");
break;
case FORMAT_XML:
printf("%*s</MulticastGroup>\n", indent+4, "");
break;
}
} //end for n1
return FSUCCESS;
} //end of ShowMcGroups
//output multicast groups
void ShowMulticastGroupsReport(Format_t format, int indent, int detail)
{
FSTATUS status;
if (g_hard) {
fprintf(stderr, "opareport -H -o mcgroups: No report provided for -H\n" );
g_exitstatus=1;
}
switch (format) {
case FORMAT_TEXT:
printf("%*sMulticast Group Summary\n",indent, "");
break;
case FORMAT_XML:
printf("%*s<MCGroupSummary>\n",indent,"");
indent+=4;
break;
default:
break;
}
status = ShowMcGroups(&g_Fabric,format, detail, indent);
if (status != FSUCCESS) {
fprintf(stderr, "opareport -o mcgroups: Unable to find multicast group members (status=0x%x): %s\n", status, iba_fstatus_msg(status));
g_exitstatus=1;
}
switch (format) {
case FORMAT_TEXT:
DisplaySeparator();
break;
case FORMAT_XML:
indent-=4;
printf("%*s</MCGroupSummary>\n",indent, "");
break;
default:
break;
}
return;
} //end of ShowMulticastGroupsReport
// output multicast FDB
void ShowMulticastFDBReport(Point *focus, Format_t format, int indent, int detail)
{
int ix_lid, ix_port, ix_pos;
LIST_ITEM *pList;
NodeData *nodep;
SwitchData *switchp;
STL_PORTMASK **pPortMask;
uint64 portMask;
uint32 ct_node = 0;
uint32 ct_lid, ct_port;
switch (format) {
case FORMAT_TEXT:
printf("%*sMulticast FDB Tables\n", indent, "");
break;
case FORMAT_XML:
printf("%*s<MulticastFDBs>\n", indent, "");
indent+=4;
break;
default:
break;
}
if (! (g_Fabric.flags & FF_ROUTES) && g_snapshot_in_file) {
switch (format) {
case FORMAT_TEXT:
printf("%*sReport skipped: provided snapshot was created without -r option\n", indent, "");
break;
case FORMAT_XML:
printf("%*s<!-- Report skipped: provided snapshot was created without -r option -->\n", indent, "");
break;
default:
break;
}
goto done;
}
ShowPointFocus(focus, FIND_FLAG_FABRIC, format, indent, detail);
switch (format) {
case FORMAT_TEXT:
printf( "%*s%u Connected Switches in Fabric%s\n", indent, "",
(unsigned)QListCount(&g_Fabric.AllSWs), detail?":":"" );
break;
case FORMAT_XML:
XmlPrintDec("ConnectedSwitchCount", (unsigned)QListCount(&g_Fabric.AllSWs), indent);
break;
default:
break;
}
// Report Multicast FDB
for ( pList=QListHead(&g_Fabric.AllSWs); pList != NULL;
pList = QListNext(&g_Fabric.AllSWs, pList) ) {
nodep = QListObj(pList);
switchp = nodep->switchp;
if (!CompareNodePoint(nodep, focus))
continue;
if (!switchp || !switchp->MulticastFDB[0])
continue;
if (detail) {
if (!ct_node) {
ShowNodeBriefSummaryHeadings(format, indent, 0);
switch (format) {
case FORMAT_TEXT:
printf("%*s LID Ports\n", indent+4, "");
break;
case FORMAT_XML:
break;
default:
break;
}
}
ShowNodeBriefSummary(nodep, focus, FALSE, format, indent, 0);
ct_lid = 0;
const size_t NumMcfdbEntries = switchp->MulticastFDBSize - STL_LID_MULTICAST_BEGIN;
for ( ix_lid = 0, pPortMask = switchp->MulticastFDB; ix_lid < NumMcfdbEntries; ix_lid++ ) {
for ( ix_pos = 0; ix_pos < STL_NUM_MFT_POSITIONS_MASK; ix_pos++) {
portMask = pPortMask[ix_pos][ix_lid];
if (!portMask)
continue;
switch (format) {
case FORMAT_TEXT:
printf("%*s0x%08x", indent+4, "", (uint32)(ix_lid + STL_LID_MULTICAST_BEGIN));
break;
case FORMAT_XML:
if (!ix_pos && !ct_lid++)
printf("%*s<MulticastFDB>\n", indent+4, "");
printf( "%*s<Value pos=\"%d\" LID=\"0x%08x\">", indent+8, "",
ix_pos, (ix_lid + STL_LID_MULTICAST_BEGIN) );
break;
default:
break;
}
switch (format) {
case FORMAT_TEXT:
ct_port = 0;
for (ix_port = 0; ix_port < STL_PORT_MASK_WIDTH; portMask >>= 1, ix_port++) {
if (!(portMask & 1))
continue;
printf(" %02u", (uint32)(ix_pos*STL_PORT_MASK_WIDTH)+ix_port);
if (++ct_port%20 == 0)
printf("\n%*s ", indent+4, "");
} // End of for (ix_port = 0; ix_port < STL_PORT_MASK_WIDTH
break;
case FORMAT_XML:
printf("0x%"PRIx64, portMask);
break;
default:
break;
}
switch (format) {
case FORMAT_TEXT:
printf("\n");
break;
case FORMAT_XML:
printf("</Value>\n");
break;
default:
break;
}
} // End of for ( ix_pos = 0; ix_pos < STL_NUM_MFT_POSITIONS_MASK
} // End of for ( ix_lid = 0; pPortMask = switchp->MulticastFDB
switch (format) {
case FORMAT_XML:
if (ct_lid)
printf("%*s</MulticastFDB>\n", indent+4, "");
printf("%*s</Node>\n", indent, "");
break;
default:
break;
}
} // End of if (detail)
ct_node++;
} // End of for (pList=QListHead(&g_Fabric.AllSWs); pList != NULL
done:
switch (format) {
case FORMAT_TEXT:
printf("%*s%d Reported Switch(es)\n", indent, "", ct_node);
DisplaySeparator();
break;
case FORMAT_XML:
XmlPrintDec("ReportedSwitchCount", (unsigned)ct_node, indent);
indent-=4;
printf("%*s</MulticastFDBs>\n", indent, "");
break;
default:
break;
}
} // End of ShowMulticastFDBReport()
// output port usage in linear FDB
void ShowPortUsageReport(Point *focus, Format_t format, int indent, int detail)
{
int ix_lid, ix_port, ix_lmc;
LIST_ITEM *pList;
cl_map_item_t *pMap, *pMap_2;
NodeData *nodep;
SwitchData *switchp;
PortData *portp;
uint32 ct_node = 0;
uint32 ct_port;
uint16 tb_nodeData[g_max_lft+1];
uint32 tb_usageCaAll[256];
uint32 tb_usageCaBase[256];
uint32 tb_usageSwitch[256];
switch (format) {
case FORMAT_TEXT:
printf("%*sPort Usage\n", indent, "");
break;
case FORMAT_XML:
printf("%*s<PortUsage>\n", indent, "");
indent+=4;
break;
default:
break;
}
if (! (g_Fabric.flags & FF_ROUTES) && g_snapshot_in_file) {
switch (format) {
case FORMAT_TEXT:
printf("%*sReport skipped: provided snapshot was created without -r option\n", indent, "");
break;
case FORMAT_XML:
printf("%*s<!-- Report skipped: provided snapshot was created without -r option -->\n", indent, "");
break;
default:
break;
}
goto done;
}
ShowPointFocus(focus, FIND_FLAG_FABRIC, format, indent, detail);
switch (format) {
case FORMAT_TEXT:
printf( "%*s%u Connected Switch(es) in Fabric%s\n", indent, "",
(unsigned)QListCount(&g_Fabric.AllSWs), detail?":":"" );
break;
case FORMAT_XML:
XmlPrintDec("ConnectedSwitchCount", (unsigned)QListCount(&g_Fabric.AllSWs), indent);
break;
default:
break;
}
// Report Port Usage in Linear FDB
// Make list of node type and lmc by LID
memset(tb_nodeData, 0xFF, (g_max_lft+1) * sizeof(uint16));
for ( pMap=cl_qmap_head(&g_Fabric.AllNodes);
pMap != cl_qmap_end(&g_Fabric.AllNodes);
pMap = cl_qmap_next(pMap) ) {
nodep = PARENT_STRUCT(pMap, NodeData, AllNodesEntry);
for ( pMap_2=cl_qmap_head(&nodep->Ports); pMap_2 != cl_qmap_end(&nodep->Ports);
pMap_2 = cl_qmap_next(pMap_2) ) {
portp = PARENT_STRUCT(pMap_2, PortData, NodePortsEntry);
if ((nodep->NodeInfo.NodeType == STL_NODE_FI) ||
((nodep->NodeInfo.NodeType == STL_NODE_SW) && (portp->PortNum ==0))) {
if ( portp->PortInfo.LID &&
(portp->PortInfo.LID <= g_max_lft) ) {
for ( ix_lmc = (1 << portp->PortInfo.s1.LMC) - 1;
ix_lmc >= 0; ix_lmc-- ) {
tb_nodeData[portp->PortInfo.LID + ix_lmc] =
(ix_lmc << 8) + nodep->NodeInfo.NodeType;
}
}
}
} // End of for ( pMap_2=cl_qmap_head(&nodep->Ports)
} // End of for ( pMap=cl_qmap_head(&g_Fabric.AllNodes)
for ( pList=QListHead(&g_Fabric.AllSWs); pList != NULL;
pList = QListNext(&g_Fabric.AllSWs, pList) ) {
nodep = QListObj(pList);
switchp = nodep->switchp;
if (! CompareNodePoint(nodep, focus))
continue;
if (!switchp || !switchp->LinearFDB)
continue;
if (detail) {
ShowNodeBriefSummaryHeadings(format, indent, 0);
switch (format) {
case FORMAT_TEXT:
printf("%*sPort Total FI-All FI-Base Switch\n", indent+4, "");
ShowNodeBriefSummary(nodep, focus, FALSE, format, indent, 0);
break;
case FORMAT_XML:
ShowNodeBriefSummary(nodep, focus, FALSE, format, indent, 0);
break;
default:
break;
}
memset(tb_usageCaAll, 0, 256 * sizeof(uint32));
memset(tb_usageCaBase, 0, 256 * sizeof(uint32));
memset(tb_usageSwitch, 0, 256 * sizeof(uint32));
for (ix_lid = 0; ix_lid < switchp->LinearFDBSize; ix_lid++) {
if ( STL_LFT_PORT_BLOCK(switchp->LinearFDB, ix_lid) == 0 || STL_LFT_PORT_BLOCK(switchp->LinearFDB, ix_lid) == 0xFF )
continue;
ix_lmc = (tb_nodeData[ix_lid] >> 8) & 0xFF;
ix_port = STL_LFT_PORT_BLOCK(switchp->LinearFDB, ix_lid);
switch (tb_nodeData[ix_lid] & 0xFF) {
case STL_NODE_FI:
tb_usageCaAll[ix_port]++;
if (!ix_lmc)
tb_usageCaBase[ix_port]++;
break;
case STL_NODE_SW:
tb_usageSwitch[ix_port]++;
break;
default:
break;
} // End of switch (tb_nodeData[ix_lid] & 0xFF)
} // End of for (ix_lid = 0; ix_lid < switchp->LinearFDBSize
ct_node++;
ct_port = 0;
for (ix_port = 0; ix_port < 256; ix_port++) {
if ( !tb_usageCaAll[ix_port] && !tb_usageCaBase[ix_port] &&
!tb_usageSwitch[ix_port])
continue;
switch (format) {
case FORMAT_TEXT:
printf( "%*s%3u %5u %5u %5u %5u\n", indent+4, "",
(uint32)ix_port, tb_usageCaAll[ix_port] +
tb_usageSwitch[ix_port],
tb_usageCaAll[ix_port], tb_usageCaBase[ix_port],
tb_usageSwitch[ix_port]);
break;
case FORMAT_XML:
if (!ct_port++)
printf("%*s<Ports>\n", indent+4, "");
printf("%*s<Value Port=\"%d\">\n", indent+8, "", ix_port);
XmlPrintDec( "TotalLid", tb_usageCaAll[ix_port] +
tb_usageSwitch[ix_port], indent+12 );
if (tb_usageCaAll[ix_port])
XmlPrintDec("CaAllLid", tb_usageCaAll[ix_port], indent+12);
if (tb_usageCaBase[ix_port])
XmlPrintDec("CaBaseLid", tb_usageCaBase[ix_port], indent+12);
if (tb_usageSwitch[ix_port])
XmlPrintDec("SwitchLid", tb_usageSwitch[ix_port], indent+12);
printf("%*s</Value>\n", indent+8, "");
break;
default:
break;
}
} // End of for (ix_port = 0; ix_port < 256; ix_port++)
switch (format) {
case FORMAT_XML:
if (ct_port)
printf("%*s</Ports>\n", indent+4, "");
printf("%*s</Node>\n", indent, "");
break;
default:
break;
}
} // End of if (detail)
} // End of for ( pList=QListHead(&g_Fabric.AllSWs); pList != NULL
done:
switch (format) {
case FORMAT_TEXT:
printf("%*s%d Reported Switch(es)\n", indent, "", ct_node);
DisplaySeparator();
break;
case FORMAT_XML:
XmlPrintDec("ReportedSwitchCount", (unsigned)ct_node, indent);
indent-=4;
printf("%*s</PortUsage>\n", indent, "");
break;
default:
break;
}
} // End of ShowPortUsageReport()
struct ShowPathContext {
Format_t format;
int indent;
int detail;
};
void ReportCallback(PortData *portp1, PortData *portp2, STL_LID dlid, boolean isBaseLid, boolean flag /* TRUE=uplink or recv */, void *context)
{
struct ShowPathContext *ShowPathContext = (struct ShowPathContext*)context;
int indent = ShowPathContext->indent;
switch (ShowPathContext->format) {
case FORMAT_TEXT:
// output portp1
// output -> dlid portp2
printf("%*s 0x%016"PRIx64" %3u %s %.*s\n",
indent, "",
portp1->nodep->NodeInfo.NodeGUID,
portp1->PortNum,
StlNodeTypeToText(portp1->nodep->NodeInfo.NodeType),
NODE_DESCRIPTION_ARRAY_SIZE,
g_noname?g_name_marker:(char*)portp1->nodep->NodeDesc.NodeString);
printf("%*s-> 0x%08x 0x%016"PRIx64" %3u %s %.*s\n",
indent, "", dlid,
portp2->nodep->NodeInfo.NodeGUID,
portp2->PortNum,
StlNodeTypeToText(portp2->nodep->NodeInfo.NodeType),
NODE_DESCRIPTION_ARRAY_SIZE,
g_noname?g_name_marker:(char*)portp2->nodep->NodeDesc.NodeString);
break;
case FORMAT_XML:
printf("%*s<Path>\n", indent, "");
printf("%*s<Port id=\"0x%016"PRIx64":%u\">\n", indent+4, "",
portp1->nodep->NodeInfo.NodeGUID, portp1->PortNum);
XmlPrintHex64("NodeGUID",
portp1->nodep->NodeInfo.NodeGUID, indent+8);
if (portp1->PortGUID)
XmlPrintHex64("PortGUID", portp1->PortGUID, indent+8);
XmlPrintDec("PortNum", portp1->PortNum, indent+8);
XmlPrintNodeType(portp1->nodep->NodeInfo.NodeType,
indent+8);
XmlPrintNodeDesc((char*)portp1->nodep->NodeDesc.NodeString, indent+8);
printf("%*s</Port>\n", indent+4, "");
printf("%*s<Port id=\"0x%016"PRIx64":%u\">\n", indent+4, "",
portp2->nodep->NodeInfo.NodeGUID, portp2->PortNum);
XmlPrintLID("DLID", dlid, indent+8);
XmlPrintHex64("NodeGUID",
portp2->nodep->NodeInfo.NodeGUID, indent+8);
if (portp2->PortGUID)
XmlPrintHex64("PortGUID", portp2->PortGUID, indent+8);
XmlPrintDec("PortNum", portp2->PortNum, indent+8);
XmlPrintNodeType(portp2->nodep->NodeInfo.NodeType,
indent+8);
XmlPrintNodeDesc((char*)portp2->nodep->NodeDesc.NodeString, indent+8);
printf("%*s</Port>\n", indent+4, "");
printf("%*s</Path>\n", indent, "");
break;
default:
break;
}
}
// Standard Deviation is computed as:
// SQRT(S0 * S2 - (S1*S1))/S0
// Where:
// S0 = sum(data^0) = N
// S1 = sum(data^1) = sum(data) [held in Total]
// S2 = sum(data^2) [held in Total2]
struct statistics_s {
uint32 min; // must initialize to IB_UINT32_MAX
uint32 max;
uint32 total; // total of datum
uint64 total2; // total of datum^2
uint32 avg;
float stddev;
};
// add a single data point to the statistical variables
static _inline
void add_datum(struct statistics_s *stat, uint32 datum)
{
stat->min = MIN(datum, stat->min);
stat->max = MAX(datum, stat->max);
stat->total += datum;
stat->total2 += ((uint64)datum * (uint64)datum);
}
// add data points tabulated for stats2 to the running stat statistics
static _inline
void add_datums(struct statistics_s *stat, struct statistics_s *stat2)
{
stat->min = MIN(stat2->min, stat->min);
stat->max = MAX(stat2->max, stat->max);
stat->total += stat2->total;
stat->total2 += stat2->total2;
}
// compute summary statistics
static _inline
void compute_statistics(struct statistics_s *stat, uint32 n)
{
if (n) {
stat->avg = stat->total / n;
stat->stddev = sqrt(n * stat->total2
- ((uint64)(stat->total)*(uint64)(stat->total)))/n;
} else {
stat->min = 0; // make output a litle cleaner
}
}
// print text format of statistics
static _inline
void print_text_statistics(int indent, const char* title, struct statistics_s *stat)
{
printf("%*s%s Total: %u Avg: %u StdDev: %u\n", indent, "", title,
stat->total, stat->avg, (unsigned)stat->stddev);
printf("%*s Min: %u Max: %u\n", (int)(indent+strlen(title)-1), "",
stat->min, stat->max);
}
// print XML format of statistics
static _inline
void print_xml_statistics(int indent, const char* title, struct statistics_s *stat)
{
char buf[64];
snprintf(buf, sizeof(buf), "%sTotal", title);
XmlPrintDec(buf, (unsigned)stat->total, indent);
snprintf(buf, sizeof(buf), "%sAvg", title);
XmlPrintDec(buf, (unsigned)stat->avg, indent);
snprintf(buf, sizeof(buf),"%sStdDev", title);
XmlPrintDec(buf, (unsigned)stat->stddev, indent);
snprintf(buf, sizeof(buf), "%sMin", title);
XmlPrintDec(buf, (unsigned)stat->min, indent);
snprintf(buf, sizeof(buf), "%sMax", title);
XmlPrintDec(buf, (unsigned)stat->max, indent);
}
// output path usage in linear FDBs
void ShowPathUsageReport(Point *focus, Format_t format, int indent, int detail)
{
LIST_ITEM *pList;
NodeData *nodep;
SwitchData *switchp;
uint32 ct_node = 0;
uint32 ct_port;
FSTATUS status;
uint32 totalPorts = 0;
uint32 totalPaths;
uint32 badPaths;
struct ShowPathContext ShowPathContext = { format:format, detail:detail };
struct statistics_s fabricRecvBasePaths = { min:IB_UINT32_MAX };
struct statistics_s fabricXmitBasePaths = { min:IB_UINT32_MAX };
struct statistics_s fabricRecvNonBasePaths = { min:IB_UINT32_MAX };
struct statistics_s fabricXmitNonBasePaths = { min:IB_UINT32_MAX };
struct statistics_s fabricRecvAllPaths = { min:IB_UINT32_MAX };
struct statistics_s fabricXmitAllPaths = { min:IB_UINT32_MAX };
if (! (g_Fabric.flags & FF_ROUTES) && g_snapshot_in_file) {
switch (format) {
case FORMAT_TEXT:
printf("%*sReport skipped: provided snapshot was created without -r option\n", indent, "");
break;
case FORMAT_XML:
printf("%*s<!-- Report skipped: provided snapshot was created without -r option -->\n", indent, "");
break;
default:
break;
}
return;
}
/* If there is a node pair list or node list then only tabulate routes in the focus */
status = TabulateCARoutes(&g_Fabric, focus, &totalPaths, &badPaths, FALSE);
if (status != FSUCCESS) {
fprintf(stderr, "opareport: -o pathusage: Unable to tabulate routes (status=0x%x): %s\n", status, iba_fstatus_msg(status));
g_exitstatus = 1;
}
switch (format) {
case FORMAT_TEXT:
printf("%*sPath Usage\n", indent, "");
break;
case FORMAT_XML:
printf("%*s<PathUsage>\n", indent, "");
indent+=4;
break;
default:
break;
}
ShowPointFocus(focus, FIND_FLAG_FABRIC, format, indent, detail);
switch (format) {
case FORMAT_TEXT:
printf( "%*s%u Connected Switch(es) in Fabric%s\n", indent, "",
(unsigned)QListCount(&g_Fabric.AllSWs), detail?":":"" );
break;
case FORMAT_XML:
XmlPrintDec("ConnectedSwitchCount", (unsigned)QListCount(&g_Fabric.AllSWs), indent);
break;
default:
break;
}
// Report Path Usage in Linear FDB
for ( pList=QListHead(&g_Fabric.AllSWs); pList != NULL;
pList = QListNext(&g_Fabric.AllSWs, pList) ) {
cl_map_item_t *p;
struct statistics_s swRecvBasePaths = { min:IB_UINT32_MAX };
struct statistics_s swXmitBasePaths = { min:IB_UINT32_MAX };
struct statistics_s swRecvNonBasePaths = { min:IB_UINT32_MAX };
struct statistics_s swXmitNonBasePaths = { min:IB_UINT32_MAX };
struct statistics_s swRecvAllPaths = { min:IB_UINT32_MAX };
struct statistics_s swXmitAllPaths = { min:IB_UINT32_MAX };
nodep = QListObj(pList);
switchp = nodep->switchp;
if (!switchp || !switchp->LinearFDB)
continue;
//If haveSW flag is set, then Switches are present in the focus
if(PointHaveSw(focus)) {
// filter on switches that are listed in the focus
if( ! CompareNodePoint(nodep, focus))
continue;
}
if (detail) {
switch (format) {
case FORMAT_TEXT:
printf("%*sNodeGUID Type Name\n", indent, "");
if (detail > 1)
printf("%*sPort Rcv: FI-All FI-Base FI-NonBase Xmt: FI-All FI-Base FI-NonBase\n", indent+4, "");
if (detail > 2)
printf("%*s DLID NodeGUID Port Type Name\n", indent+8, "");
printf("%*s0x%016"PRIx64" %s %s\n", indent, "",
nodep->NodeInfo.NodeGUID,
StlNodeTypeToText(nodep->NodeInfo.NodeType),
(char*)nodep->NodeDesc.NodeString);
break;
case FORMAT_XML:
printf( "%*s<Node id=\"0x%016"PRIx64"\">\n", indent, "",
nodep->NodeInfo.NodeGUID );
XmlPrintHex64( "NodeGUID",
nodep->NodeInfo.NodeGUID, indent+4 );
XmlPrintStr( "NodeType",
StlNodeTypeToText(nodep->NodeInfo.NodeType),
indent+4 );
XmlPrintStr( "NodeDesc",
(char*)nodep->NodeDesc.NodeString, indent+4 );
break;
default:
break;
}
indent += 4;
}
ct_node++;
ct_port = 0;
for (p=cl_qmap_head(&nodep->Ports); p != cl_qmap_end(&nodep->Ports); p = cl_qmap_next(p)) {
PortData *portp= PARENT_STRUCT(p, PortData, NodePortsEntry);
uint32 recvNonBasePaths;
uint32 xmitNonBasePaths;
if (! portp->PortNum)
continue; // skip switch port 0
// only report on ISLs, FI-SW links are boring
if (! portp->neighbor
|| portp->neighbor->nodep->NodeInfo.NodeType != STL_NODE_SW)
continue;
totalPorts++;
ct_port++;
recvNonBasePaths = portp->analysisData.routes.recvAllPaths - portp->analysisData.routes.recvBasePaths;
xmitNonBasePaths = portp->analysisData.routes.xmitAllPaths - portp->analysisData.routes.xmitBasePaths;
add_datum(&swRecvBasePaths, portp->analysisData.routes.recvBasePaths);
add_datum(&swXmitBasePaths, portp->analysisData.routes.xmitBasePaths);
add_datum(&swRecvNonBasePaths, recvNonBasePaths);
add_datum(&swXmitNonBasePaths, xmitNonBasePaths);
add_datum(&swRecvAllPaths, portp->analysisData.routes.recvAllPaths);
add_datum(&swXmitAllPaths, portp->analysisData.routes.xmitAllPaths);
if (detail > 1) {
switch (format) {
case FORMAT_TEXT:
printf( "%*s%3u %10u %10u %10u %10u %10u %10u\n", indent, "",
(uint32)portp->PortNum,
portp->analysisData.routes.recvAllPaths, portp->analysisData.routes.recvBasePaths,
recvNonBasePaths,
portp->analysisData.routes.xmitAllPaths, portp->analysisData.routes.xmitBasePaths,
xmitNonBasePaths);
if (detail > 2) {
ShowPathContext.indent = indent+4;
(void)ReportCARoutes(&g_Fabric, portp, ReportCallback,
&ShowPathContext, FALSE);
}
break;
case FORMAT_XML:
if (1 == ct_port)
printf("%*s<Ports>\n", indent, "");
printf("%*s<Value Port=\"%d\">\n", indent+4, "", portp->PortNum);
XmlPrintDec("CaRecvAllPath", portp->analysisData.routes.recvAllPaths, indent+8);
XmlPrintDec("CaRecvBaseLid", portp->analysisData.routes.recvBasePaths, indent+8);
XmlPrintDec("CaRecvNonBaseLid", recvNonBasePaths, indent+8);
XmlPrintDec("CaXmitAllPath", portp->analysisData.routes.xmitAllPaths, indent+8);
XmlPrintDec("CaXmitBaseLid", portp->analysisData.routes.xmitBasePaths, indent+8);
XmlPrintDec("CaXmitNonBaseLid", xmitNonBasePaths, indent+8);
if (detail > 2) {
ShowPathContext.indent = indent+8;
(void)ReportCARoutes(&g_Fabric, portp, ReportCallback,
&ShowPathContext, FALSE);
}
printf("%*s</Value>\n", indent+4, "");
break;
default:
break;
}
}
} // End of for all ports
if (detail > 1 && ct_port && format == FORMAT_XML)
printf("%*s</Ports>\n", indent, "");
// if there are no paths through switch, add_datums is no net change
add_datums(&fabricRecvBasePaths, &swRecvBasePaths);
add_datums(&fabricXmitBasePaths, &swXmitBasePaths);
add_datums(&fabricRecvNonBasePaths, &swRecvNonBasePaths);
add_datums(&fabricXmitNonBasePaths, &swXmitNonBasePaths);
add_datums(&fabricRecvAllPaths, &swRecvAllPaths);
add_datums(&fabricXmitAllPaths, &swXmitAllPaths);
compute_statistics(&swRecvBasePaths, ct_port);
compute_statistics(&swXmitBasePaths, ct_port);
compute_statistics(&swRecvNonBasePaths, ct_port);
compute_statistics(&swXmitNonBasePaths, ct_port);
compute_statistics(&swRecvAllPaths, ct_port);
compute_statistics(&swXmitAllPaths, ct_port);
if (detail) {
switch (format) {
case FORMAT_TEXT:
printf("%*s%d Reported Port(s)\n", indent, "", ct_port);
if (ct_port) {
print_text_statistics(indent, "Recv All Paths: ", &swRecvAllPaths);
print_text_statistics(indent, "Recv Base Paths: ", &swRecvBasePaths);
print_text_statistics(indent, "Recv Non-Base Paths:", &swRecvNonBasePaths);
print_text_statistics(indent, "Xmit All Paths: ", &swXmitAllPaths);
print_text_statistics(indent, "Xmit Base Paths: ", &swXmitBasePaths);
print_text_statistics(indent, "Xmit Non-Base Paths:", &swXmitNonBasePaths);
}
indent-=4;
break;
case FORMAT_XML:
XmlPrintDec("ReportedPortCount", (unsigned)ct_port, indent);
if (ct_port) {
print_xml_statistics(indent, "RecvAllPaths", &swRecvAllPaths);
print_xml_statistics(indent, "RecvBasePaths", &swRecvBasePaths);
print_xml_statistics(indent, "RecvNonBasePaths", &swRecvNonBasePaths);
print_xml_statistics(indent, "XmitAllPaths", &swXmitAllPaths);
print_xml_statistics(indent, "XmitBasePaths", &swXmitBasePaths);
print_xml_statistics(indent, "XmitNonBasePaths", &swXmitNonBasePaths);
}
indent-=4;
printf("%*s</Node>\n", indent, "");
break;
default:
break;
}
} // End of if (detail)
} // End of for ( pList=QListHead(&g_Fabric.AllSWs); pList != NULL
if (totalPorts) {
compute_statistics(&fabricRecvBasePaths, totalPorts);
compute_statistics(&fabricXmitBasePaths, totalPorts);
compute_statistics(&fabricRecvNonBasePaths, totalPorts);
compute_statistics(&fabricXmitNonBasePaths, totalPorts);
compute_statistics(&fabricRecvAllPaths, totalPorts);
compute_statistics(&fabricXmitAllPaths, totalPorts);
}
switch (format) {
case FORMAT_TEXT:
printf("%*s%d Reported Switch(es)\n", indent, "", ct_node);
printf("%*s%d Reported Port(s)\n", indent, "", totalPorts);
printf("%*s%d Incomplete Route(s)\n", indent, "", badPaths);
if (totalPorts) {
print_text_statistics(indent, "Recv All Paths: ", &fabricRecvAllPaths);
print_text_statistics(indent, "Recv Base Paths: ", &fabricRecvBasePaths);
print_text_statistics(indent, "Recv Non-Base Paths:", &fabricRecvNonBasePaths);
print_text_statistics(indent, "Xmit All Paths: ", &fabricXmitAllPaths);
print_text_statistics(indent, "Xmit Base Paths: ", &fabricXmitBasePaths);
print_text_statistics(indent, "Xmit Non-Base Paths:", &fabricXmitNonBasePaths);
}
break;
case FORMAT_XML:
XmlPrintDec("ReportedSwitchCount", (unsigned)ct_node, indent);
XmlPrintDec("ReportedPortCount", (unsigned)totalPorts, indent);
XmlPrintDec("IncompleteRoutes", (unsigned)badPaths, indent);
if (totalPorts) {
print_xml_statistics(indent, "RecvAllPaths", &fabricRecvAllPaths);
print_xml_statistics(indent, "RecvBasePaths", &fabricRecvBasePaths);
print_xml_statistics(indent, "RecvNonBasePaths", &fabricRecvNonBasePaths);
print_xml_statistics(indent, "XmitAllPaths", &fabricXmitAllPaths);
print_xml_statistics(indent, "XmitBasePaths", &fabricXmitBasePaths);
print_xml_statistics(indent, "XmitNonBasePaths", &fabricXmitNonBasePaths);
}
break;
default:
break;
}
switch (format) {
case FORMAT_TEXT:
DisplaySeparator();
break;
case FORMAT_XML:
indent-=4;
printf("%*s</PathUsage>\n", indent, "");
break;
default:
break;
}
} // End of ShowPathUsageReport()
// output path usage in linear FDBs
void ShowTreePathUsageReport(Point *focus, Format_t format, int indent,
int detail)
{
LIST_ITEM *pList;
NodeData *nodep;
SwitchData *switchp;
uint32 ct_node = 0;
uint32 ct_port = 0;
FSTATUS status;
uint32 totalPorts = 0;
uint32 totalPaths;
uint32 badPaths;
struct ShowPathContext ShowPathContext = { format:format, detail:detail };
uint32 fabricUplinkCount = 0;
uint32 fabricDownlinkCount = 0;
struct statistics_s fabricDownlinkBasePaths = { min:IB_UINT32_MAX };
struct statistics_s fabricUplinkBasePaths = { min:IB_UINT32_MAX };
struct statistics_s fabricDownlinkNonBasePaths = { min:IB_UINT32_MAX };
struct statistics_s fabricUplinkNonBasePaths = { min:IB_UINT32_MAX };
struct statistics_s fabricDownlinkAllPaths = { min:IB_UINT32_MAX };
struct statistics_s fabricUplinkAllPaths = { min:IB_UINT32_MAX };
if (! (g_Fabric.flags & FF_ROUTES) && g_snapshot_in_file) {
switch (format) {
case FORMAT_TEXT:
printf("%*sReport skipped: provided snapshot was created without -r option\n", indent, "");
break;
case FORMAT_XML:
printf("%*s<!-- Report skipped: provided snapshot was created without -r option -->\n", indent, "");
break;
default:
break;
}
return;
}
/* If there is a focus then only tabulate routes in the focus */
status = TabulateCARoutes(&g_Fabric, focus, &totalPaths, &badPaths, TRUE);
if (status != FSUCCESS) {
fprintf(stderr, "opareport: -o treepathusage: Unable to tabulate routes (status=0x%x): %s\n", status, iba_fstatus_msg(status));
g_exitstatus = 1;
}
switch (format) {
case FORMAT_TEXT:
printf("%*sTree Path Usage\n", indent, "");
break;
case FORMAT_XML:
printf("%*s<TreePathUsage>\n", indent, "");
indent+=4;
break;
default:
break;
}
ShowPointFocus(focus, FIND_FLAG_FABRIC, format, indent, detail);
switch (format) {
case FORMAT_TEXT:
printf( "%*s%u Connected Switch(es) in Fabric%s\n", indent, "",
(unsigned)QListCount(&g_Fabric.AllSWs), detail?":":"" );
break;
case FORMAT_XML:
XmlPrintDec("ConnectedSwitchCount", (unsigned)QListCount(&g_Fabric.AllSWs), indent);
break;
default:
break;
}
// Report Tree Path Usage in Linear FDB
for ( pList=QListHead(&g_Fabric.AllSWs); pList != NULL;
pList = QListNext(&g_Fabric.AllSWs, pList) ) {
cl_map_item_t *p;
uint32 swUplinkCount = 0;
uint32 swDownlinkCount = 0;
struct statistics_s swDownlinkBasePaths = { min:IB_UINT32_MAX };
struct statistics_s swUplinkBasePaths = { min:IB_UINT32_MAX };
struct statistics_s swDownlinkNonBasePaths = { min:IB_UINT32_MAX };
struct statistics_s swUplinkNonBasePaths = { min:IB_UINT32_MAX };
struct statistics_s swDownlinkAllPaths = { min:IB_UINT32_MAX };
struct statistics_s swUplinkAllPaths = { min:IB_UINT32_MAX };
nodep = QListObj(pList);
switchp = nodep->switchp;
if (!switchp || !switchp->LinearFDB)
continue;
//If haveSW flag is set, then Switches are present in the focus
if(PointHaveSw(focus)) {
// filter on switches that are listed in the focus
if( ! CompareNodePoint(nodep, focus))
continue;
}
if (detail) {
switch (format) {
case FORMAT_TEXT:
printf("%*sNodeGUID Type Tier Name\n", indent, "");
if (detail > 1)
printf("%*sPort Up: FI-All FI-Base FI-NonBase Down: FI-All FI-Base FI-NonBase\n", indent+4, "");
if (detail > 2)
printf("%*s DLID NodeGUID Port Type Name\n", indent+8, "");
printf("%*s0x%016"PRIx64" %s %4u %s\n", indent, "",
nodep->NodeInfo.NodeGUID,
StlNodeTypeToText(nodep->NodeInfo.NodeType),
nodep->analysis,
(char*)nodep->NodeDesc.NodeString);
break;
case FORMAT_XML:
printf( "%*s<Node id=\"0x%016"PRIx64"\">\n", indent, "",
nodep->NodeInfo.NodeGUID );
XmlPrintHex64( "NodeGUID",
nodep->NodeInfo.NodeGUID, indent+4 );
XmlPrintStr( "NodeType",
StlNodeTypeToText(nodep->NodeInfo.NodeType),
indent+4 );
XmlPrintDec( "Tier", nodep->analysis, indent+4 );
XmlPrintStr( "NodeDesc",
(char*)nodep->NodeDesc.NodeString, indent+4 );
break;
default:
break;
}
indent += 4;
}
ct_node++;
ct_port = 0;
for (p=cl_qmap_head(&nodep->Ports); p != cl_qmap_end(&nodep->Ports); p = cl_qmap_next(p)) {
PortData *portp= PARENT_STRUCT(p, PortData, NodePortsEntry);
uint32 downlinkNonBasePaths;
uint32 uplinkNonBasePaths;
if (! portp->PortNum)
continue; // skip switch port 0
// only report on ISLs, FI-SW links are boring
if (! portp->neighbor
|| portp->neighbor->nodep->NodeInfo.NodeType != STL_NODE_SW)
continue;
totalPorts++;
ct_port++;
if (portp->analysisData.fatTreeRoutes.uplinkAllPaths)
swUplinkCount++;
if (portp->analysisData.fatTreeRoutes.downlinkAllPaths)
swDownlinkCount++;
downlinkNonBasePaths = portp->analysisData.fatTreeRoutes.downlinkAllPaths - portp->analysisData.fatTreeRoutes.downlinkBasePaths;
uplinkNonBasePaths = portp->analysisData.fatTreeRoutes.uplinkAllPaths - portp->analysisData.fatTreeRoutes.uplinkBasePaths;
add_datum(&swDownlinkBasePaths, portp->analysisData.fatTreeRoutes.downlinkBasePaths);
add_datum(&swUplinkBasePaths, portp->analysisData.fatTreeRoutes.uplinkBasePaths);
add_datum(&swDownlinkNonBasePaths, downlinkNonBasePaths);
add_datum(&swUplinkNonBasePaths, uplinkNonBasePaths);
add_datum(&swDownlinkAllPaths, portp->analysisData.fatTreeRoutes.downlinkAllPaths);
add_datum(&swUplinkAllPaths, portp->analysisData.fatTreeRoutes.uplinkAllPaths);
if (detail > 1) {
switch (format) {
case FORMAT_TEXT:
printf( "%*s%3u %10u %10u %10u %10u %10u %10u\n", indent, "",
(uint32)portp->PortNum,
portp->analysisData.fatTreeRoutes.uplinkAllPaths, portp->analysisData.fatTreeRoutes.uplinkBasePaths,
uplinkNonBasePaths,
portp->analysisData.fatTreeRoutes.downlinkAllPaths, portp->analysisData.fatTreeRoutes.downlinkBasePaths,
downlinkNonBasePaths);
if (detail > 2) {
ShowPathContext.indent = indent+4;
(void)ReportCARoutes(&g_Fabric, portp, ReportCallback,
&ShowPathContext, TRUE);
}
break;
case FORMAT_XML:
if (1 == ct_port)
printf("%*s<Ports>\n", indent, "");
printf("%*s<Value Port=\"%d\">\n", indent+4, "", portp->PortNum);
XmlPrintDec("CaUplinkAllPath", portp->analysisData.fatTreeRoutes.uplinkAllPaths, indent+8);
XmlPrintDec("CaUplinkBaseLid", portp->analysisData.fatTreeRoutes.uplinkBasePaths, indent+8);
XmlPrintDec("CaUplinkNonBaseLid", uplinkNonBasePaths, indent+8);
XmlPrintDec("CaDownlinkAllPath", portp->analysisData.fatTreeRoutes.downlinkAllPaths, indent+8);
XmlPrintDec("CaDownlinkBaseLid", portp->analysisData.fatTreeRoutes.downlinkBasePaths, indent+8);
XmlPrintDec("CaDownlinkNonBaseLid", downlinkNonBasePaths, indent+8);
if (detail > 2) {
ShowPathContext.indent = indent+8;
(void)ReportCARoutes(&g_Fabric, portp, ReportCallback,
&ShowPathContext, TRUE);
}
printf("%*s</Value>\n", indent+4, "");
break;
default:
break;
}
}
} // End of for all ports
if (detail > 1 && ct_port && format == FORMAT_XML)
printf("%*s</Ports>\n", indent, "");
// if there are no uplinks, add_datums is no net change
fabricUplinkCount += swUplinkCount;
add_datums(&fabricUplinkBasePaths, &swUplinkBasePaths);
add_datums(&fabricUplinkNonBasePaths, &swUplinkNonBasePaths);
add_datums(&fabricUplinkAllPaths, &swUplinkAllPaths);
// if there are no downlinks, add_datums is no net change
fabricDownlinkCount += swDownlinkCount;
add_datums(&fabricDownlinkBasePaths, &swDownlinkBasePaths);
add_datums(&fabricDownlinkNonBasePaths, &swDownlinkNonBasePaths);
add_datums(&fabricDownlinkAllPaths, &swDownlinkAllPaths);
compute_statistics(&swUplinkBasePaths, swUplinkCount);
compute_statistics(&swUplinkNonBasePaths, swUplinkCount);
compute_statistics(&swUplinkAllPaths, swUplinkCount);
compute_statistics(&swDownlinkBasePaths, swDownlinkCount);
compute_statistics(&swDownlinkNonBasePaths, swDownlinkCount);
compute_statistics(&swDownlinkAllPaths, swDownlinkCount);
if (detail) {
switch (format) {
case FORMAT_TEXT:
printf("%*s%d Reported Port(s)\n", indent, "", ct_port);
printf("%*s%d Incomplete Route(s)\n", indent, "", badPaths);
if (ct_port) {
printf("%*s%u Uplink Port(s) %u Downlink Port(s)\n", indent, "", swUplinkCount, swDownlinkCount);
if (swUplinkCount) {
print_text_statistics(indent, "Up All Paths: ", &swUplinkAllPaths);
print_text_statistics(indent, "Up Base Paths: ", &swUplinkBasePaths);
print_text_statistics(indent, "Up Non-Base Paths:", &swUplinkNonBasePaths);
}
if (swDownlinkCount) {
print_text_statistics(indent, "Down All Paths: ", &swDownlinkAllPaths);
print_text_statistics(indent, "Down Base Paths: ", &swDownlinkBasePaths);
print_text_statistics(indent, "Down Non-Base Paths:", &swDownlinkNonBasePaths);
}
}
indent-=4;
break;
case FORMAT_XML:
XmlPrintDec("ReportedPortCount", (unsigned)ct_port, indent);
XmlPrintDec("IncompleteRoutes", (unsigned)badPaths, indent);
if (ct_port) {
XmlPrintDec("UplinkPortCount", (unsigned)swUplinkCount, indent);
XmlPrintDec("DownlinkPortCount", (unsigned)swDownlinkCount, indent);
// always output, even if count is 0, simplifies scripts
print_xml_statistics(indent, "UplinkAllPaths", &swUplinkAllPaths);
print_xml_statistics(indent, "UplinkBasePaths", &swUplinkBasePaths);
print_xml_statistics(indent, "UplinkNonBasePaths", &swUplinkNonBasePaths);
print_xml_statistics(indent, "DownlinkAllPaths", &swDownlinkAllPaths);
print_xml_statistics(indent, "DownlinkBasePaths", &swDownlinkBasePaths);
print_xml_statistics(indent, "DownlinkNonBasePaths", &swDownlinkNonBasePaths);
}
indent-=4;
printf("%*s</Node>\n", indent, "");
break;
default:
break;
}
} // End of if (detail)
} // End of for ( pList=QListHead(&g_Fabric.AllSWs); pList != NULL
compute_statistics(&fabricUplinkBasePaths, fabricUplinkCount);
compute_statistics(&fabricUplinkNonBasePaths, fabricUplinkCount);
compute_statistics(&fabricUplinkAllPaths, fabricUplinkCount);
compute_statistics(&fabricDownlinkBasePaths, fabricDownlinkCount);
compute_statistics(&fabricDownlinkNonBasePaths, fabricDownlinkCount);
compute_statistics(&fabricDownlinkAllPaths, fabricDownlinkCount);
switch (format) {
case FORMAT_TEXT:
printf("%*s%d Reported Switch(es)\n", indent, "", ct_node);
printf("%*s%d Reported Port(s)\n", indent, "", totalPorts);
if (totalPorts) {
printf("%*s%u Uplink Port(s) %u Downlink Port(s)\n", indent, "", fabricUplinkCount, fabricDownlinkCount);
if (fabricUplinkCount) {
print_text_statistics(indent, "Up All Paths: ", &fabricUplinkAllPaths);
print_text_statistics(indent, "Up Base Paths: ", &fabricUplinkBasePaths);
print_text_statistics(indent, "Up Non-Base Paths:", &fabricUplinkNonBasePaths);
}
if (fabricDownlinkCount) {
print_text_statistics(indent, "Down All Paths: ", &fabricDownlinkAllPaths);
print_text_statistics(indent, "Down Base Paths: ", &fabricDownlinkBasePaths);
print_text_statistics(indent, "Down Non-Base Paths:", &fabricDownlinkNonBasePaths);
}
}
break;
case FORMAT_XML:
XmlPrintDec("ReportedSwitchCount", (unsigned)ct_node, indent);
XmlPrintDec("ReportedPortCount", (unsigned)totalPorts, indent);
if (totalPorts) {
XmlPrintDec("UplinkPortCount", (unsigned)fabricUplinkCount, indent);
XmlPrintDec("DownlinkPortCount", (unsigned)fabricDownlinkCount, indent);
// always output, even if count is 0, simplifies scripts
print_xml_statistics(indent, "UplinkAllPaths", &fabricUplinkAllPaths);
print_xml_statistics(indent, "UplinkBasePaths", &fabricUplinkBasePaths);
print_xml_statistics(indent, "UplinkNonBasePaths", &fabricUplinkNonBasePaths);
print_xml_statistics(indent, "DownlinkAllPaths", &fabricDownlinkAllPaths);
print_xml_statistics(indent, "DownlinkBasePaths", &fabricDownlinkBasePaths);
print_xml_statistics(indent, "DownlinkNonBasePaths", &fabricDownlinkNonBasePaths);
}
break;
default:
break;
}
switch (format) {
case FORMAT_TEXT:
DisplaySeparator();
break;
case FORMAT_XML:
indent-=4;
printf("%*s</TreePathUsage>\n", indent, "");
break;
default:
break;
}
} // End of ShowTreePathUsageReport()
struct ValidateRoutesContext {
Format_t format;
int indent;
int detail;
};
void ValidateRouteCallback(PortData *portp1, PortData *portp2, STL_LID dlid, boolean isBaseLid, uint8 SL, void *context)
{
struct ValidateRoutesContext *ValidateRoutesContext = (struct ValidateRoutesContext*)context;
int indent = ValidateRoutesContext->indent;
if (! ValidateRoutesContext->detail)
return;
switch (ValidateRoutesContext->format) {
case FORMAT_TEXT:
// output portp1
// output -> dlid portp2
printf("%*s 0x%016"PRIx64" %3u ",
indent, "",
portp1->nodep->NodeInfo.NodeGUID,
portp1->PortNum);
if (g_use_scsc) printf("%2u", SL);
printf(" %s %.*s\n",
StlNodeTypeToText(portp1->nodep->NodeInfo.NodeType),
NODE_DESCRIPTION_ARRAY_SIZE,
g_noname?g_name_marker:(char*)portp1->nodep->NodeDesc.NodeString);
printf("%*s-> 0x%08x 0x%016"PRIx64" %3u ",
indent, "", dlid,
portp2->nodep->NodeInfo.NodeGUID,
portp2->PortNum);
if (g_use_scsc) printf(" ");
printf(" %s %.*s\n",
StlNodeTypeToText(portp2->nodep->NodeInfo.NodeType),
NODE_DESCRIPTION_ARRAY_SIZE,
g_noname?g_name_marker:(char*)portp2->nodep->NodeDesc.NodeString);
if (ValidateRoutesContext->detail >= 2) {
printf("%*sIncompletePath:\n", indent, "");
printf("%*sNodeGUID Port Type ", indent+4, "");
if (g_use_scsc) printf("VL ");
printf("Name\n");
} else {
printf("\n");
}
break;
case FORMAT_XML:
printf("%*s<Path>\n", indent, "");
printf("%*s<Port id=\"0x%016"PRIx64":%u\">\n", indent+4, "",
portp1->nodep->NodeInfo.NodeGUID, portp1->PortNum);
XmlPrintHex64("NodeGUID",
portp1->nodep->NodeInfo.NodeGUID, indent+8);
if (portp1->PortGUID)
XmlPrintHex64("PortGUID", portp1->PortGUID, indent+8);
XmlPrintDec("PortNum", portp1->PortNum, indent+8);
XmlPrintNodeType(portp1->nodep->NodeInfo.NodeType,
indent+8);
XmlPrintNodeDesc((char*)portp1->nodep->NodeDesc.NodeString, indent+8);
printf("%*s</Port>\n", indent+4, "");
printf("%*s<Port id=\"0x%016"PRIx64":%u\">\n", indent+4, "",
portp2->nodep->NodeInfo.NodeGUID, portp2->PortNum);
XmlPrintLID("DLID", dlid, indent+8);
XmlPrintHex64("NodeGUID",
portp2->nodep->NodeInfo.NodeGUID, indent+8);
if (portp2->PortGUID)
XmlPrintHex64("PortGUID", portp2->PortGUID, indent+8);
XmlPrintDec("PortNum", portp2->PortNum, indent+8);
XmlPrintNodeType(portp2->nodep->NodeInfo.NodeType,
indent+8);
XmlPrintNodeDesc((char*)portp2->nodep->NodeDesc.NodeString, indent+8);
printf("%*s</Port>\n", indent+4, "");
if (g_use_scsc) XmlPrintDec("SL", SL, indent+4);
if (ValidateRoutesContext->detail >= 2)
printf("%*s<IncompletePath>\n", indent+4, "");
else
printf("%*s</Path>\n", indent, "");
break;
default:
break;
}
}
struct MCRoutesContext {
Format_t format;
int indent;
int detail;
MCROUTESTATUS status;
};
void PrintMCRouteMembers(McNodeLoopInc *LoopIncp, void *context)
{
struct MCRoutesContext *MCRoutesContext = (struct MCRoutesContext*)context;
int indent = MCRoutesContext->indent;
if (! MCRoutesContext->detail)
return;
switch (MCRoutesContext->format) {
case FORMAT_TEXT:
printf("0x%016"PRIx64"\t%s\t%.*s\t%3u\t",
LoopIncp->pPort->nodep->NodeInfo.NodeGUID,
StlNodeTypeToText(LoopIncp->pPort->nodep->NodeInfo.NodeType),
NODE_DESCRIPTION_ARRAY_SIZE,
g_noname?g_name_marker:(char*)LoopIncp->pPort->nodep->NodeDesc.NodeString,
LoopIncp->entryPort);
if(LoopIncp->exitPort != 0)
printf("%3u\n",LoopIncp->exitPort);
else
printf("-\n");
break;
case FORMAT_XML:
printf("%*s<Port id=\"0x%016"PRIx64":%u\">\n", indent+4, "",
LoopIncp->pPort->nodep->NodeInfo.NodeGUID, LoopIncp->pPort->PortNum);
XmlPrintHex64("NodeGUID",
LoopIncp->pPort->nodep->NodeInfo.NodeGUID, indent+8);
if (LoopIncp->pPort->PortGUID)
XmlPrintHex64("PortGUID", LoopIncp->pPort->PortGUID, indent+8);
XmlPrintNodeType(LoopIncp->pPort->nodep->NodeInfo.NodeType,
indent+8);
XmlPrintNodeDesc((char*)LoopIncp->pPort->nodep->NodeDesc.NodeString, indent+8);
XmlPrintDec("EntryPort", LoopIncp->entryPort, indent+8);
if(LoopIncp->exitPort != 0)
XmlPrintDec("ExitPort", LoopIncp->exitPort, indent+8);
printf("%*s</Port>\n", indent+4, "");
break;
default:
break;
}
}
void PrintEndMCRoute(void *context)
{
struct MCRoutesContext *MCRoutesContext = (struct MCRoutesContext*)context;
int indent = MCRoutesContext->indent+4;
if (MCRoutesContext->detail <= 1)
return;
switch (MCRoutesContext->format) {
case FORMAT_TEXT:
printf("\n");
break;
case FORMAT_XML:
printf("%*s</McPath>\n", indent-4, "");
break;
default:
break;
}
return;
}
void PrintInitMCRoute(uint32 count,void *context)
{
struct MCRoutesContext *MCRoutesContext = (struct MCRoutesContext*)context;
int indent = MCRoutesContext->indent+4;
MCROUTESTATUS mcstatus = MCRoutesContext->status;
char statusstr[80], statusxml[80];
if (MCRoutesContext->detail <= 1)
return;
if (count == 0) {
if (MCRoutesContext->format== FORMAT_XML)
printf("%*s<McPath>\n", indent-4, "");
}
else {
switch (mcstatus) {
case MC_NO_TRACE:
strncpy(statusstr,"Unable to trace route",sizeof(statusstr));
strncpy(statusxml,"UnableToTraceRoute",sizeof(statusxml));
break;
case MC_NOT_FOUND:
strncpy(statusstr,"No start point",sizeof(statusstr));
strncpy(statusxml,"NoStartPoint",sizeof(statusxml));
break;
case MC_UNAVAILABLE:
strncpy(statusstr,"No MFT Route Table",sizeof(statusstr));
strncpy(statusxml,"NoMFTRouteTable",sizeof(statusxml));
break;
case MC_LOOP:
strncpy(statusstr,"Found Loop",sizeof(statusstr));
strncpy(statusxml,"FoundLoop",sizeof(statusxml));
break;
case MC_NOGROUP:
strncpy(statusstr,"End-node does not belong to McGroup",sizeof(statusstr));
strncpy(statusxml,"EndNodeNoGroup",sizeof(statusxml));
break;
default:
strcpy(statusstr,"");
strcpy(statusxml,"");
break;
}
switch (MCRoutesContext->format) {
case FORMAT_TEXT:
printf("%s. Num. of paths: %d\n",statusstr,count);
if (MCRoutesContext->detail >= 2) {
printf(" NodeGUID\t\tType\tName\tEntry Port\tExitPort\n");
} else
printf("\n");
break;
case FORMAT_XML:
printf("%*s<%s>%d</%s>\n", indent-4, "",statusxml,count,statusxml);
break;
default:
break;
}
}
}
void ValidateRouteCallback2(PortData *portp, uint8 vl, void *context)
{
struct ValidateRoutesContext *ValidateRoutesContext = (struct ValidateRoutesContext*)context;
int indent = ValidateRoutesContext->indent+4;
if (ValidateRoutesContext->detail <= 1)
return;
if (! portp) {
// special case, indicates end of path
switch (ValidateRoutesContext->format) {
case FORMAT_TEXT:
printf("\n");
break;
case FORMAT_XML:
printf("%*s</IncompletePath>\n", indent, "");
printf("%*s</Path>\n", indent-4, "");
break;
default:
break;
}
return;
}
switch (ValidateRoutesContext->format) {
case FORMAT_TEXT:
// output portp1
// output -> dlid portp2
printf("%*s0x%016"PRIx64" %3u %s ",
indent, "",
portp->nodep->NodeInfo.NodeGUID,
portp->PortNum,
StlNodeTypeToText(portp->nodep->NodeInfo.NodeType));
if (g_use_scsc) printf(" %2d ", vl);
printf("%.*s\n",
NODE_DESCRIPTION_ARRAY_SIZE,
g_noname?g_name_marker:(char*)portp->nodep->NodeDesc.NodeString);
break;
case FORMAT_XML:
printf("%*s<Port id=\"0x%016"PRIx64":%u\">\n", indent+4, "",
portp->nodep->NodeInfo.NodeGUID, portp->PortNum);
XmlPrintHex64("NodeGUID",
portp->nodep->NodeInfo.NodeGUID, indent+8);
if (portp->PortGUID)
XmlPrintHex64("PortGUID", portp->PortGUID, indent+8);
XmlPrintDec("PortNum", portp->PortNum, indent+8);
XmlPrintNodeType(portp->nodep->NodeInfo.NodeType,
indent+8);
if (g_use_scsc) XmlPrintDec("VL", vl, indent+8);
XmlPrintNodeDesc((char*)portp->nodep->NodeDesc.NodeString, indent+8);
printf("%*s</Port>\n", indent+4, "");
break;
default:
break;
}
}
// Validate all routes in linear FDBs
void ShowValidateRoutesReport(Format_t format, int indent, int detail)
{
FSTATUS status;
uint32 totalPaths;
uint32 badPaths;
struct ValidateRoutesContext ValidateRoutesContext = { format:format, detail:detail };
if (! (g_Fabric.flags & FF_ROUTES) && g_snapshot_in_file) {
switch (format) {
case FORMAT_TEXT:
printf("%*sReport skipped: provided snapshot was created without -r option\n", indent, "");
break;
case FORMAT_XML:
printf("%*s<!-- Report skipped: provided snapshot was created without -r option -->\n", indent, "");
break;
default:
break;
}
return;
}
switch (format) {
case FORMAT_TEXT:
printf("%*sValidate Routes\n", indent, "");
break;
case FORMAT_XML:
printf("%*s<ValidateRoutes>\n", indent, "");
indent+=4;
break;
default:
break;
}
switch (format) {
case FORMAT_TEXT:
printf( "%*s%u LID(s) in Fabric%s\n", indent, "",
(unsigned)cl_qmap_count(&g_Fabric.u.AllLids), detail?":":"" );
printf("%*s%u Connected FIs in Fabric%s\n", indent, "", (unsigned)QListCount(&g_Fabric.AllFIs), detail?":":"");
printf( "%*s%u Connected Switch(es) in Fabric%s\n", indent, "",
(unsigned)QListCount(&g_Fabric.AllSWs), detail?":":"" );
break;
case FORMAT_XML:
XmlPrintDec("FabricLIDCount", (unsigned)cl_qmap_count(&g_Fabric.u.AllLids), indent);
XmlPrintDec("ConnectedFICount", (unsigned)QListCount(&g_Fabric.AllFIs), indent);
XmlPrintDec("ConnectedSwitchCount", (unsigned)QListCount(&g_Fabric.AllSWs), indent);
break;
default:
break;
}
if (detail) {
switch (format) {
case FORMAT_TEXT:
printf("%*sIncomplete Paths:\n", indent, "");
if (g_use_scsc) printf("%*s DLID NodeGUID Port SL Type Name\n", indent, "");
else printf("%*s DLID NodeGUID Port Type Name\n", indent, "");
break;
case FORMAT_XML:
printf( "%*s<IncompletePaths>\n", indent, "");
indent+=4;
break;
default:
break;
}
}
ValidateRoutesContext.indent = indent;
status = ValidateAllRoutes(&g_Fabric, g_portGuid, (uint8)g_rc, &totalPaths, &badPaths,
ValidateRouteCallback, &ValidateRoutesContext,
detail >=2 ?ValidateRouteCallback2:NULL,
&ValidateRoutesContext, ((g_Fabric.flags & FF_QOSDATA) && g_use_scsc));
if (status != FSUCCESS) {
fprintf(stderr, "opareport: -o validateroutes: Unable to validate routes (status=0x%x): %s\n", status, iba_fstatus_msg(status));
g_exitstatus = 1;
}
if (detail) {
switch (format) {
case FORMAT_TEXT:
break;
case FORMAT_XML:
indent-=4;
printf( "%*s</IncompletePaths>\n", indent, "");
break;
default:
break;
}
}
switch (format) {
case FORMAT_TEXT:
printf("%*s%d Analyzed Routes\n", indent, "", totalPaths);
printf("%*s%d Incomplete Route(s)\n", indent, "", badPaths);
break;
case FORMAT_XML:
XmlPrintDec("AnalyzedRoutes", (unsigned)totalPaths, indent);
XmlPrintDec("IncompleteRoutes", (unsigned)badPaths, indent);
break;
default:
break;
}
switch (format) {
case FORMAT_TEXT:
DisplaySeparator();
break;
case FORMAT_XML:
indent-=4;
printf("%*s</ValidateRoutes>\n", indent, "");
break;
default:
break;
}
} // End of ShowValidateRoutesReport()
void PrintHeadGroup(STL_LID mlid, void *context)
{
struct MCRoutesContext *MCRoutesContext = (struct MCRoutesContext*)context;
int indent = MCRoutesContext->indent;
int NOM=0;
LIST_ITEM *p;
if (! MCRoutesContext->detail)
return;
//Search number of members for MLID mcgroup
for ( p= QListHead(&g_Fabric.AllMcGroups); p!=NULL; p=QListNext(&g_Fabric.AllMcGroups,p)){
McGroupData *pMCGD = (McGroupData *)QListObj(p);
if (pMCGD->MLID == mlid) {
NOM = pMCGD->NumOfMembers;
break;
}
}
if (NOM !=0) {
switch (MCRoutesContext->format) {
case FORMAT_TEXT:
printf("MC Group 0x%04x\n", mlid);
printf("Number of Members:%d \n", NOM);
break;
case FORMAT_XML:
XmlPrintMLID("MLID",mlid,indent+4);
printf("%*s<MCGroupMembers>%d</MCGroupMembers>\n", indent+4, "",NOM);
break;
}
}
return;
}
// Validate MC routes in multicast tables MCDBs
void ShowValidateMCRoutesReport(Format_t format, int indent, int detail)
{
FSTATUS status;
uint32 totalPaths, badPaths=0, listcount=0;
LIST_ITEM *p, *q;
int i;
struct MCRoutesContext MCRoutesContext = { format:format, detail:detail, status:MC_NO_TRACE };
if (! (g_Fabric.flags & FF_ROUTES) && g_snapshot_in_file) {
switch (format) {
case FORMAT_TEXT:
printf("%*sReport skipped: provided snapshot was created without -r option\n", indent, "");
break;
case FORMAT_XML:
printf("%*s<!-- Report skipped: provided snapshot was created without -r option -->\n", indent, "");
break;
default:
break;
}
return;
}
if (QListCount(&g_Fabric.AllSWs) ==0) {
printf("Cannot Validate MC Routes: No Switches Connected\n");
return;
}
switch (format) {
case FORMAT_TEXT:
printf("%*sValidate Multicast Routes\n", indent, "");
break;
case FORMAT_XML:
printf("%*s<ValidateMCRoutes>\n", indent, "");
indent+=4;
break;
default:
break;
}
///////////////////////////////////////////////////////////////////////
//Get MCGroups
switch (format) { // do not print "zero" members
case FORMAT_TEXT:
printf(" %d Multicast groups\n", g_Fabric.NumOfMcGroups);
break;
case FORMAT_XML:
printf("%*s<MCGroup>%d</MCGroup>\n", indent, "",g_Fabric.NumOfMcGroups);
break;
default:
break;
}// case end
MCRoutesContext.indent = indent;
status = ValidateAllMCRoutes(&g_Fabric, &totalPaths);
if (status != FSUCCESS) {
fprintf(stderr, "opareport: -o validatemcroutes: Unable to validate multicast routes (status=0x%x): %s\n", status, iba_fstatus_msg(status));
FreeValidateMCRoutes(&g_Fabric);
g_exitstatus = 1;
return;
}
// Display all MC routes with problems:
for (i=0;i<MAXMCROUTESTATUS;i++) {
MCRoutesContext.status = g_Fabric.AllMcLoopIncRoutes[i].status;
listcount = QListCount(&g_Fabric.AllMcLoopIncRoutes[i].AllMcRouteStatus);
badPaths+=listcount;
if (listcount <= 0) // do not print "zero" members
continue;
PrintInitMCRoute(listcount,&MCRoutesContext); // print init
if (QListCount(&g_Fabric.AllMcLoopIncRoutes[i].AllMcRouteStatus) <= 0)
continue;
for (p = QListHead(&g_Fabric.AllMcLoopIncRoutes[i].AllMcRouteStatus); p!= NULL;
p = QListNext( &g_Fabric.AllMcLoopIncRoutes[i].AllMcRouteStatus,p) ) {
McLoopInc *pmcloop = (McLoopInc *) QListObj(p);
if (pmcloop == NULL)
continue;
PrintInitMCRoute(0,&MCRoutesContext); // print MC route members
PrintHeadGroup(pmcloop->mlid,&MCRoutesContext);
for (q = QListHead(&pmcloop->AllMcNodeLoopIncR ); q!= NULL;
q = QListNext(&pmcloop->AllMcNodeLoopIncR,q)) {
McNodeLoopInc *pmcnodeloop = (McNodeLoopInc *) QListObj(q);
PrintMCRouteMembers(pmcnodeloop, &MCRoutesContext); // print node
} // end for q
PrintEndMCRoute(&MCRoutesContext); // print closure
}// end for p
}
switch (format) {
case FORMAT_TEXT:
printf(" Total Analyzed MC Routes from Entry Switch to HFI: %d\n MC Bad Paths %d\n",totalPaths, badPaths);
break;
case FORMAT_XML:
printf("%*s<AnalyzedMCRoutes>%d</AnalyzedMCRoutes>\n", indent, "",totalPaths);
printf("%*s<BadMCRoutes>%d</BadMCRoutes>\n", indent, "",badPaths);
indent-=4;
break;
default:
break;
}// case end
switch (format) {
case FORMAT_TEXT:
printf("\n");
DisplaySeparator();
break;
case FORMAT_XML:
printf("%*s</ValidateMCRoutes>\n", indent, "");
indent-=4;
break;
default:
break;
}
// delete MC routes structure
// deallocate memory for the MC route
FreeValidateMCRoutes(&g_Fabric);
} // End of ShowValidateMCRoutesReport()
// Validate all routes for credit loops
void ShowValidateCreditLoopsReport(Format_t format, int indent, int detail)
{
FSTATUS status;
ValidateCreditLoopRoutesContext_t ValidateCreditLoopRoutesContext = { format:format, detail:detail };
if (!(g_Fabric.flags & FF_ROUTES) && g_snapshot_in_file) {
switch (format) {
case FORMAT_TEXT:
printf("%*sReport skipped: provided snapshot was created without -r option\n", indent, "");
break;
case FORMAT_XML:
printf("%*s<!-- Report skipped: provided snapshot was created without -r option -->\n", indent, "");
break;
default:
break;
}
return;
}
switch (format) {
case FORMAT_TEXT:
printf("%*sValidate Credit Loop Routes\n", indent, "");
break;
case FORMAT_XML:
printf("\n");
printf("%*s<ValidateCreditLoopRoutes>\n", indent, "");
indent += 4;
break;
default:
break;
}
ValidateCreditLoopRoutesContext.indent = indent;
ValidateCreditLoopRoutesContext.quiet = g_quiet;
status = ValidateAllCreditLoopRoutes(&g_Fabric, g_portGuid, (uint8)g_rc,
ValidateCLRouteCallback,
ValidateCLFabricSummaryCallback,
ValidateCLDataSummaryCallback,
ValidateCLRouteSummaryCallback,
ValidateCLLinkSummaryCallback,
ValidateCLLinkStepSummaryCallback,
ValidateCLPathSummaryCallback,
ValidateCLTimeGetCallback,
&ValidateCreditLoopRoutesContext,
((g_Fabric.flags & FF_ROUTES) && g_snapshot_in_file),
((g_Fabric.flags & FF_QOSDATA) && g_use_scsc));
if (status != FSUCCESS) {
fprintf(stderr, "opareport: -o validateroutes: Unable to validate credit loop routes (status=0x%x): %s\n", status, iba_fstatus_msg(status));
g_exitstatus = 1;
}
switch (format) {
case FORMAT_TEXT:
DisplaySeparator();
break;
case FORMAT_XML:
indent -= 4;
printf("%*s</ValidateCreditLoopRoutes>\n", indent, "");
break;
default:
break;
}
} // End of ShowValidateCreditLoopsReport()
// output LID usage in linear FDB (undocumented)
void ShowLIDUsageReport(Point *focus, Format_t format, int indent, int detail)
{
int ix_lid;
LIST_ITEM *pList;
NodeData *nodep;
SwitchData *switchp;
uint32 ct_node = 0;
uint32 ct_lid = 0;
uint16 usageLinearFDBSize = 0;
uint32 tb_usageLID[g_max_lft+1];
switch (format) {
case FORMAT_TEXT:
printf("%*sLID Usage\n", indent, "");
break;
case FORMAT_XML:
printf("%*s<LIDUsage>\n", indent, "");
indent+=4;
break;
default:
break;
}
if (! (g_Fabric.flags & FF_ROUTES) && g_snapshot_in_file) {
switch (format) {
case FORMAT_TEXT:
printf("%*sReport skipped: provided snapshot was created without -r option\n", indent, "");
break;
case FORMAT_XML:
printf("%*s<!-- Report skipped: provided snapshot was created without -r option -->\n", indent, "");
break;
default:
break;
}
goto done;
}
ShowPointFocus(focus, FIND_FLAG_FABRIC, format, indent, detail);
switch (format) {
case FORMAT_TEXT:
printf( "%*s%u Connected Switch(es) in Fabric%s\n", indent, "",
(unsigned)QListCount(&g_Fabric.AllSWs), detail?":":"" );
break;
case FORMAT_XML:
XmlPrintDec("ConnectedSwitchCount", (unsigned)QListCount(&g_Fabric.AllSWs), indent);
break;
default:
break;
}
// Report LID usage in Linear FDB
memset(tb_usageLID, 0, (g_max_lft+1) * sizeof(uint32));
for ( pList=QListHead(&g_Fabric.AllSWs); pList != NULL;
pList = QListNext(&g_Fabric.AllSWs, pList) ) {
nodep = QListObj(pList);
switchp = nodep->switchp;
if (! CompareNodePoint(nodep, focus))
continue;
if (!switchp || !switchp->LinearFDB )
continue;
if (detail) {
if (!ct_node) {
ShowNodeBriefSummaryHeadings(format, indent, 0);
switch (format) {
case FORMAT_TEXT:
printf("%*s LID Count\n", indent+4, "");
case FORMAT_XML:
break;
default:
break;
}
}
ShowNodeBriefSummary(nodep, focus, TRUE, format, indent, 0);
if (switchp->LinearFDBSize > usageLinearFDBSize)
usageLinearFDBSize = switchp->LinearFDBSize;
for (ix_lid = 0; ix_lid < switchp->LinearFDBSize; ix_lid++) {
if (STL_LFT_PORT_BLOCK(switchp->LinearFDB, ix_lid) == 0xFF)
continue;
tb_usageLID[ix_lid]++;
} // End of for (ix_lid = 0; ix_lid < switchp->LinearFDBSize
} // End of if (detail)
ct_node++;
} // End of for ( pList=QListHead(&g_Fabric.AllSWs); pList != NULL
for (ix_lid = 0; ix_lid < usageLinearFDBSize; ix_lid++)
if (tb_usageLID[ix_lid])
switch (format) {
case FORMAT_TEXT:
printf( "%*s0x%.*x %u\n", indent+4, "", (ix_lid <= IB_MAX_UCAST_LID ? 4:8) , (uint32)ix_lid,
tb_usageLID[ix_lid] );
break;
case FORMAT_XML:
if (!ct_lid++)
printf("%*s<LIDs>\n", indent, "");
printf( "%*s<Value LID=\"0x%.*x\">%u</Value>\n", indent+4, "", (ix_lid <= IB_MAX_UCAST_LID ? 4:8),
(uint32)ix_lid, tb_usageLID[ix_lid] );
break;
default:
break;
}
done:
switch (format) {
case FORMAT_TEXT:
printf("%*s%d Reported Switch(es)\n", indent, "", ct_node);
DisplaySeparator();
break;
case FORMAT_XML:
if (ct_lid)
printf("%*s</LIDs>\n", indent, "");
XmlPrintDec("ReportedSwitchCount", (unsigned)ct_node, indent);
indent-=4;
printf("%*s</LIDUsage>\n", indent, "");
break;
default:
break;
}
} // End of ShowLIDUsageReport()
// output vFabric information
void ShowVFInfoReport(Point *focus, Format_t format, int indent, int detail)
{
LIST_ITEM *p;
int cnt = 0;
ShowPointFocus(focus, FIND_FLAG_FABRIC, format, indent, detail);
switch (format) {
case FORMAT_TEXT:
printf("%*svFabrics:\n", indent, "");
break;
case FORMAT_XML:
printf("%*s<vFabrics>\n", indent, "");
indent += 4;
break;
default:
break;
}
PrintDest_t print;
PrintDestInitFile(&print, stdout);
// Report vFabric records
if (detail) {
for (p = QListHead(&g_Fabric.AllVFs); p; p = QListNext(&g_Fabric.AllVFs, p), cnt++)
{
VFData_t *pVFData = (VFData_t *)QListObj(p);
STL_VFINFO_RECORD *pR = &pVFData->record;
char buf[8];
switch (format) {
case FORMAT_TEXT:
if (cnt)
printf("\n");
PrintStlVfInfoRecord_detail(&print, indent, detail, pR, 0);
break;
case FORMAT_XML:
printf("%*s<vFabric>\n", indent, "");
indent += 4;
XmlPrintDec("Index", pR->vfIndex, indent);
XmlPrintStr("Name", (char *)pR->vfName, indent);
// ServiceID and MGID are always zero when SA query asks for
// all VFs
//XmlPrintHex64("ServiceID", pR->ServiceID, indent);
//printf( "%*s<MGID>0x%016"PRIx64":0x%016"PRIx64"</MGID>\n",
// indent, "", pR->MGID.AsReg64s.H, pR->MGID.AsReg64s.L );
XmlPrintPKey("PKey", pR->pKey, indent);
XmlPrintDec("SL", pR->s1.slBase, indent);
if (pR->slMulticastSpecified)
XmlPrintDec("MulticastSL", pR->slMulticast, indent);
if (detail >1) {
printf( "%*s<Select>%s%s</Select>\n", indent, "",
(pR->s1.selectFlags & STL_VFINFO_REC_SEL_PKEY_QUERY) ? "PKEY " : "",
(pR->s1.selectFlags & STL_VFINFO_REC_SEL_SL_QUERY) ? "SL " : "" );
XmlPrintHex8("Select_Hex", pR->s1.selectFlags, indent);
// get the value of Packet Lifetime Multiplier
snprintf(buf, sizeof(buf), "%d", 1<<pR->s1.pktLifeTimeInc);
XmlPrintStr( "PktLifeTimeMult",
pR->s1.pktLifeSpecified ? buf : "unspecified",
indent );
if (pR->s1.mtuSpecified)
XmlPrintDec("MaxMtu", GetBytesFromMtu(pR->s1.mtu), indent);
else
XmlPrintStr("MaxMtu", "unlimited", indent);
XmlPrintStr( "MaxRate",
pR->s1.rateSpecified ? StlStaticRateToText(pR->s1.rate) : "unlimited",
indent );
printf( "%*s<Options>%s%s%s</Options>\n", indent, "",
(pR->optionFlags & STL_VFINFO_REC_OPT_SECURITY) ? "Security " : "",
(pR->optionFlags & STL_VFINFO_REC_OPT_QOS) ? "QoS " : "",
(pR->optionFlags & STL_VFINFO_REC_OPT_FLOW_DISABLE) ? "FlowCtrlDisable " : "" );
XmlPrintHex8("Options_Hex", pR->optionFlags, indent);
printf("%*s<QOS>\n", indent, "");
indent += 4;
if (pR->optionFlags & STL_VFINFO_REC_OPT_QOS)
{
XmlPrintDec("Bandwidth_Percent", pR->bandwidthPercent, indent);
XmlPrintBool("Priority", pR->priority, indent);
}
indent -= 4;
printf("%*s</QOS>\n", indent, "");
XmlPrintDec("PreemptionRank", pR->preemptionRank, indent);
FormatTimeoutMult(buf, pR->hoqLife);
XmlPrintStr("HoQLife", buf, indent);
XmlPrintDec("HoQLife_Int", pR->hoqLife, indent);
}
break;
default:
break;
} // End of switch (format)
// we need QOSDATA to have the SL2SC and PKey tables which are
// used by isVFMember
if (detail > 2 && (g_Fabric.flags & FF_QOSDATA)) {
LIST_ITEM *q;
cl_map_item_t *r;
if (format == FORMAT_TEXT)
printf("%*s NodeGUID Port Type Name\n", indent, "");
// show all endpoints (FIs and switch port 0) which are in
// the given vFabric
for (q=QListHead(&g_Fabric.AllFIs); q != NULL; q = QListNext(&g_Fabric.AllFIs, q)) {
NodeData *nodep = (NodeData *)QListObj(q);
for (r=cl_qmap_head(&nodep->Ports); r != cl_qmap_end(&nodep->Ports); r = cl_qmap_next(r)) {
PortData *portp = PARENT_STRUCT(r, PortData, NodePortsEntry);
if (! ComparePortPoint(portp, focus))
continue;
if (isVFMember(portp, pVFData))
ShowLinkPortBriefSummary(portp, "", 0, NULL,
format, indent, 0);
}
}
//for all SWs
for (q=QListHead(&g_Fabric.AllSWs); q != NULL; q = QListNext(&g_Fabric.AllSWs, q)) {
NodeData *nodep = (NodeData *)QListObj(q);
PortData *portp = FindNodePort(nodep,0);
if (!portp)
continue;
if (! ComparePortPoint(portp, focus))
continue;
if (isVFMember(portp, pVFData))
ShowLinkPortBriefSummary(portp, "", 0, NULL,
format, indent, 0);
}
}
switch (format) {
case FORMAT_TEXT:
break;
case FORMAT_XML:
indent -= 4;
printf("%*s</vFabric>\n", indent, "");
break;
default:
break;
}
} // End of for each VF
}
switch (format) {
case FORMAT_TEXT:
if (cnt)
printf("\n");
printf("%*s%u VFs\n", indent, "", QListCount(&g_Fabric.AllVFs));
DisplaySeparator();
break;
case FORMAT_XML:
XmlPrintDec("Count", QListCount(&g_Fabric.AllVFs), indent);
indent -= 4;
printf("%*s</vFabrics>\n", indent, "");
break;
default:
break;
}
} // End of ShowVFInfoReport()
void ShowBCTForPortText(PortData *port, Format_t format, int indent, int detail)
{
PortData *rport = port->neighbor;
uint16_t bytesPerAU = 0;
uint32_t remLim = 0;
uint8_t vl;
indent+=4;
if (rport) {
printf("%*sRemote Port 0x%016"PRIx64" %u %s %.*s (LID %u)\n", indent, "",
rport->nodep->NodeInfo.NodeGUID,
rport->PortNum,
StlNodeTypeToText(rport->nodep->NodeInfo.NodeType),
NODE_DESCRIPTION_ARRAY_SIZE,
g_noname?g_name_marker:(char*)rport->nodep->NodeDesc.NodeString,
rport->EndPortLID);
bytesPerAU = 8 * (1 << rport->PortInfo.BufferUnits.s.BufferAlloc);
remLim = rport->PortInfo.OverallBufferSpace;
}
printf("%*sBufferControlTable\n", indent, "");
indent +=4;
if (bytesPerAU)
printf("%*sOverallBufferSpace (AU/B): %6u/%8u\n", indent, "",
remLim, remLim * bytesPerAU);
uint16_t bufferDepth = (port->PortInfo.ReplayDepthH.BufferDepthH << 8) | port->PortInfo.ReplayDepth.BufferDepth;
printf("%*sTx Buffer Depth (LTP/B): %6u/%8u\n", indent, "",
bufferDepth, bufferDepth * BYTES_PER_LTP);
if (!g_persist && !g_hard) {
uint16_t wireDepth = (port->PortInfo.ReplayDepthH.WireDepthH << 8) | port->PortInfo.ReplayDepth.WireDepth;
printf("%*sWire Depth (LTP/B): %6u/%8u\n", indent, "",
wireDepth, wireDepth * BYTES_PER_LTP);
} else {
printf("%*sWire Depth (LTP/B): xxxxxx/xxxxxxxx\n", indent, "");
}
printf("%*sTxOverallSharedLimit (AU/B): %6u/", indent, "",
port->pBufCtrlTable->TxOverallSharedLimit);
if (bytesPerAU)
printf("%8u\n", port->pBufCtrlTable->TxOverallSharedLimit * bytesPerAU);
else
printf(" N/A\n");
indent += 4;
printf("%*sVL | Dedicated ( Bytes) | Shared ( Bytes) | MTU\n", indent, "");
for (vl = 0; vl < STL_MAX_VLS; vl++) {
if (port->pBufCtrlTable->VL[vl].TxDedicatedLimit == 0 && port->pBufCtrlTable->VL[vl].TxSharedLimit == 0)
continue;
uint32_t dBytes = 0;
uint32_t sBytes = 0;
uint16_t mtu = 0;
if (bytesPerAU) {
dBytes = port->pBufCtrlTable->VL[vl].TxDedicatedLimit * bytesPerAU;
sBytes = port->pBufCtrlTable->VL[vl].TxSharedLimit * bytesPerAU;
}
if (vl%2 == 0) {
mtu = port->PortInfo.NeighborMTU[vl/2].s.VL0_to_MTU;
} else {
mtu = port->PortInfo.NeighborMTU[vl/2].s.VL1_to_MTU;
}
mtu = GetBytesFromMtu(mtu);
printf("%*s%2d | %6u (%8u) | %6u (%8u) | %6u\n", indent, "",
vl,
port->pBufCtrlTable->VL[vl].TxDedicatedLimit, dBytes,
port->pBufCtrlTable->VL[vl].TxSharedLimit, sBytes,
mtu);
}
}
void ShowBCTForPortXML(PortData *port, Format_t format, int indent, int detail)
{
PortData *rport = port->neighbor;
uint16_t bytesPerAU = 0;
uint32_t remLim = 0;
uint8_t vl;
indent+=4;
if (rport) {
printf("%*s<RemotePort id=\"0x%016"PRIx64":%u\"/>\n", indent, "",
rport->nodep->NodeInfo.NodeGUID, rport->PortNum);
bytesPerAU = 8 * (1 << rport->PortInfo.BufferUnits.s.BufferAlloc);
remLim = rport->PortInfo.OverallBufferSpace;
}
printf("%*s<BufferControlTable>\n", indent, "");
indent += 4;
uint16_t bufferDepth = (port->PortInfo.ReplayDepthH.BufferDepthH << 8) | port->PortInfo.ReplayDepth.BufferDepth;
printf("%*s<ReplayDepthBufferDepth>%u</ReplayDepthBufferDepth>\n", indent, "",
bufferDepth);
printf("%*s<ReplayDepthBufferDepthBytes>%u</ReplayDepthBufferDepthBytes>\n", indent, "",
bufferDepth * BYTES_PER_LTP);
if (!g_persist && !g_hard) {
uint16_t wireDepth = (port->PortInfo.ReplayDepthH.WireDepthH << 8) | port->PortInfo.ReplayDepth.WireDepth;
printf("%*s<ReplayDepthWireDepth>%u</ReplayDepthWireDepth>\n", indent, "",
wireDepth);
printf("%*s<ReplayDepthWireDepthBytes>%u</ReplayDepthWireDepthBytes>\n", indent, "",
wireDepth * BYTES_PER_LTP);
}
if (bytesPerAU) {
printf("%*s<OverallBufferSpace>%u</OverallBufferSpace>\n", indent, "", remLim);
printf("%*s<OverallBufferSpaceBytes>%u</OverallBufferSpaceBytes>\n", indent, "",
remLim * bytesPerAU);
}
printf("%*s<TxOverallSharedLimit>%u</TxOverallSharedLimit>\n", indent, "",
port->pBufCtrlTable->TxOverallSharedLimit);
if (bytesPerAU)
printf("%*s<TxOverallSharedLimitBytes>%u</TxOverallSharedLimitBytes>\n", indent, "",
port->pBufCtrlTable->TxOverallSharedLimit * bytesPerAU);
for (vl = 0; vl < STL_MAX_VLS; vl++)
{
if (port->pBufCtrlTable->VL[vl].TxDedicatedLimit == 0 && port->pBufCtrlTable->VL[vl].TxSharedLimit == 0)
continue;
printf("%*s<VLLimit vl=\"%d\">\n", indent, "", vl);
indent += 4;
printf("%*s<TxDedicatedLimit>%u</TxDedicatedLimit>\n", indent, "",
port->pBufCtrlTable->VL[vl].TxDedicatedLimit);
if (bytesPerAU)
printf("%*s<TxDedicatedLimitBytes>%u</TxDedicatedLimitBytes>\n", indent, "",
port->pBufCtrlTable->VL[vl].TxDedicatedLimit * bytesPerAU);
printf("%*s<TxSharedLimit>%u</TxSharedLimit>\n", indent, "",
port->pBufCtrlTable->VL[vl].TxSharedLimit);
if (bytesPerAU)
printf("%*s<TxSharedLimitBytes>%u</TxSharedLimitBytes>\n", indent, "",
port->pBufCtrlTable->VL[vl].TxSharedLimit * bytesPerAU);
indent -= 4;
printf("%*s</VLLimit>\n", indent, "");
}
indent -= 4;
printf("%*s</BufferControlTable>\n", indent, "");
}
void ShowAllBCTReports(Point *focus, Format_t format, int indent, int detail)
{
int ct_port = 0;
LIST_ITEM *p;
ShowPointFocus(focus, FIND_FLAG_FABRIC, format, indent, detail);
switch (format) {
case FORMAT_TEXT:
printf("%*sBufferControlTable Report\n", indent, "");
break;
case FORMAT_XML:
indent+=4;
printf("%*s<BufferControlTableReport>\n", indent, "");
break;
default:
break;
}
indent+=4;
if (g_snapshot_in_file && !(g_Fabric.flags & FF_BUFCTRLTABLE)) {
switch (format) {
case FORMAT_TEXT:
printf("%*sReport skipped: provided snapshot was created without -V option\n", indent, "");
break;
case FORMAT_XML:
printf("%*s<!-- Report skipped: provided snapshot was created without -V option -->\n", indent, "");
break;
default:
break;
}
goto done;
}
for (p=QListHead(&g_Fabric.AllPorts); p != NULL; p = QListNext(&g_Fabric.AllPorts, p)) {
PortData *port = (PortData *)QListObj(p);
if (!ComparePortPoint(port, focus))
continue;
if (port->nodep->NodeInfo.NodeType == STL_NODE_SW && port->PortNum == 0)
continue;
if (! port->pBufCtrlTable)
continue;
switch (format) {
case FORMAT_TEXT:
printf("%*sPort 0x%016"PRIx64" %u %s %.*s (LID %u)\n", indent, "",
port->nodep->NodeInfo.NodeGUID,
port->PortNum,
StlNodeTypeToText(port->nodep->NodeInfo.NodeType),
NODE_DESCRIPTION_ARRAY_SIZE,
g_noname?g_name_marker:(char*)port->nodep->NodeDesc.NodeString,
port->EndPortLID);
ShowBCTForPortText(port, format, indent, detail);
break;
case FORMAT_XML:
printf("%*s<Port id=\"0x%016"PRIx64":%u\">\n", indent, "",
port->nodep->NodeInfo.NodeGUID, port->PortNum);
XmlPrintHex64("NodeGUID",
port->nodep->NodeInfo.NodeGUID, indent+4);
if (port->PortGUID)
XmlPrintHex64("PortGUID", port->PortGUID, indent+4);
XmlPrintDec("PortNum", port->PortNum, indent+4);
XmlPrintNodeType(port->nodep->NodeInfo.NodeType,
indent+4);
XmlPrintNodeDesc((char*)port->nodep->NodeDesc.NodeString, indent+4);
ShowBCTForPortXML(port, format, indent, detail);
printf("%*s</Port>\n", indent, "");
break;
default:
break;
}
ct_port++;
}
done:
switch (format) {
case FORMAT_TEXT:
indent -= 4;
printf("%*s%d Reported Port(s)\n", indent, "", ct_port);
DisplaySeparator();
break;
case FORMAT_XML:
XmlPrintDec("ReportedPortCount", (unsigned)ct_port, indent);
indent -= 4;
printf("%*s</BufferControlTableReport>\n", indent, "");
break;
default:
break;
}
}
void CheckVFAllocation(PortData *port, int indent, int format, int detail)
{
// caller checks FF_QOSDATA, but play it safe
if (detail <= 3 || !(g_Fabric.flags & FF_QOSDATA))
return;
// we need QOSDATA to have the SL2SC and PKey tables which are used by
// isVFMember
int sl, sc, vl, ded, share;
STL_VFINFO_RECORD *pR;
LIST_ITEM *p;
uint8_t vfsPerVl[STL_MAX_VLS] = {0};
uint8_t slsPerVl[STL_MAX_VLS] = {0};
uint32_t vlSlsMap[STL_MAX_VLS] = {0};
for (p = QListHead(&g_Fabric.AllVFs); p; p = QListNext(&g_Fabric.AllVFs, p)) {
VFData_t *pVFData = (VFData_t *)QListObj(p);
STL_VFINFO_RECORD *pR = &pVFData->record;
// check that every VF that the port is a member of has a VL assigned to it
if (!isVFMember(port, pVFData))
continue;
sl = pR->s1.slBase;
sc = port->pQOS->SL2SCMap->SLSCMap[sl].SC;
vl = port->pQOS->SC2VLMaps[Enum_SCVLt].SCVLMap[sc].VL;
if (vl == 15) {
// no VL allocated for this VF
switch (format) {
case FORMAT_TEXT:
printf("%*sNo VL allocated for VF: %s\n", indent, "", pR->vfName);
break;
case FORMAT_XML:
printf("%*s<VFNoVLAllocated>%s</VFNoVLAllocated>", indent, "", pR->vfName);
break;
default:
break;
}
continue;
}
// check that every VF that the port is a member of has buffers
// allocated to it
// skip port 0 since it doesn't get configured for buffers
// and will confuse user by saying no buffers allocated
if ((g_Fabric.flags & FF_BUFCTRLTABLE) && port->pBufCtrlTable
&& port->PortNum) {
ded = port->pBufCtrlTable->VL[vl].TxDedicatedLimit;
share = port->pBufCtrlTable->VL[vl].TxSharedLimit;
if (!ded && !share) {
switch (format) {
case FORMAT_TEXT:
printf("%*sNo buffers allocated for VF: %s\n", indent, "", pR->vfName);
break;
case FORMAT_XML:
printf("%*s<VFNoBufferAllocated>%s</VFNoBufferAllocated>", indent, "", pR->vfName);
break;
default:
break;
}
}
}
int slSet[2] = {
pR->s1.slBase,
(pR->slMulticastSpecified? pR->slMulticast: -1)
};
// if qos is enabled, make note that this VL has a vfabric mapped
// to it, so we can check for contracted links
if (pR->optionFlags & STL_VFINFO_REC_OPT_QOS) {
uint32_t vls = 0;
int i;
for (i = 0; i < 2; ++i) {
sl = slSet[i];
if (sl == -1) continue;
sc = port->pQOS->SL2SCMap->SLSCMap[sl].SC;
vl = port->pQOS->SC2VLMaps[Enum_SCVLt].SCVLMap[sc].VL;
if (vl == 15) continue;
if (!(vlSlsMap[vl] & (1 << sl))) {
// Only count VFs that reach this VL via an SL
// that hasn't been shared before
if (!(vls & (1 << vl))) {
// Only count this (VF,VL) pair once
++vfsPerVl[vl];
vls |= 1 << vl;
}
// Only count this (SL,VL) pair once
slsPerVl[vl]++;
vlSlsMap[vl] |= (1 << sl);
}
}
}
}
// check for contracted links
for (vl = 0; vl < STL_MAX_VLS; vl++) {
if (slsPerVl[vl]>1){
switch (format) {
case FORMAT_TEXT:
printf("%*sContracted link: %d unique SLs in %d unique VFs (not counting shared SLs) mapped to VL %d\n", indent, "", slsPerVl[vl], vfsPerVl[vl], vl);
break;
case FORMAT_XML:
printf("%*s<ContractedLink VL=\"%d\">%d</ContractedLink>\n", indent, "", vl, slsPerVl[vl]);
break;
default:
break;
}
}
}
// check that every allocated buffer is mapped to a VF
// skip port 0 since it doesn't get configured for buffers
// and will confuse user by saying no buffers allocated
if ((g_Fabric.flags & FF_BUFCTRLTABLE) && port->pBufCtrlTable
&& port->PortNum) {
for (vl=0; vl<STL_MAX_VLS; vl++) {
// skip VL 15
if (vl==15)
continue;
ded = port->pBufCtrlTable->VL[vl].TxDedicatedLimit;
share = port->pBufCtrlTable->VL[vl].TxSharedLimit;
if (!ded && !share)
continue;
// this VL has buffers dedicated to it
// first need to find out if there is an SC for this VL
boolean match_found = FALSE;
for (sc=0; sc<STL_MAX_SCS; sc++) {
if (vl == port->pQOS->SC2VLMaps[Enum_SCVLt].SCVLMap[sc].VL) {
match_found = TRUE;
break;
}
}
if (match_found) {
// now find the Sl for this SC
match_found = FALSE;
for (sl=0; sl<STL_MAX_SLS; sl++) {
if (sc == port->pQOS->SL2SCMap->SLSCMap[sl].SC) {
match_found = TRUE;
break;
}
}
if (match_found) {
// now find the vfabric
match_found = FALSE;
for (p = QListHead(&g_Fabric.AllVFs); p; p = QListNext(&g_Fabric.AllVFs, p)) {
pR = &((VFData_t *)QListObj(p))->record;
if (sl == pR->s1.slBase ||
(pR->slMulticastSpecified && sl == pR->slMulticast)) {
match_found = TRUE;
break;
}
}
}
}
// we never found a match
if (!match_found) {
switch (format) {
case FORMAT_TEXT:
printf("%*sBuffers allocated to VL: %d, but it is not mapped to any VirtualFabric\n",indent, "", vl);
break;
case FORMAT_XML:
printf("%*s<VLExtraBuffersAllocated>%d</VLExtraBuffersAllocated>\n", indent, "", vl);
break;
default:
break;
}
}
}
}
if (port->neighbor && port->neighbor->pQOS) {
// check that SCVLt matches SCVLnt of the neighbor
for (sc=0; sc<STL_MAX_VLS; sc++) {
int vl1 = port->pQOS->SC2VLMaps[Enum_SCVLt].SCVLMap[sc].VL;
int vl2 = port->neighbor->pQOS->SC2VLMaps[Enum_SCVLnt].SCVLMap[sc].VL;
if (vl1!=vl2) {
switch (format) {
case FORMAT_TEXT:
printf("%*sSCVLt/SCVLnt mapping mismatch:\n", indent, "");
printf("%*s%s Port %d: SC %d -> VL %d\n", indent+4, "",
port->nodep->NodeDesc.NodeString, port->PortNum, sc, vl1);
printf("%*sNeighbor %s Port %d: SC %d -> VL %d\n", indent+4, "",
port->neighbor->nodep->NodeDesc.NodeString, port->neighbor->PortNum, sc, vl2);
break;
case FORMAT_XML:
printf("%*s<SCVLMismatch>\n", indent, "");
printf("%*s<Local SC=%d>%d</Local>\n", indent+4, "",
sc, vl1);
printf("%*s<Neighbor SC=%d>%d</Neighbor>\n", indent+4, "",
sc, vl2);
printf("%*s</SCVLMismatch>\n", indent, "");
break;
default:
break;
}
}
}
}
switch (format) {
case FORMAT_TEXT:
printf("%*sVF Allocation Validated\n", indent, "");
break;
default:
break;
}
}
void ShowPortVFMembershipText(PortData *port, int indent, int detail)
{
int sc, vl, ded, share;
LIST_ITEM *p;
// we need QOSDATA to have the SL2SC and PKey tables which are used by
// isVFMember
if (! (g_Fabric.flags & FF_QOSDATA)) // caller checks, should be true
return;
printf("%*sVF Membership:\n", indent, "");
indent+=4;
printf("%*sVF Name\tVF Index\tBaseSL\tBaseSC\tBaseVL", indent, "");
printf("\t\tMcastSL\tMcastSC\tMcastVL");
if ((g_Fabric.flags & FF_BUFCTRLTABLE) && port->pBufCtrlTable
&& detail>2 && port->PortNum)
printf("\tDedicated\tShared");
printf("\n");
// look over every vFabric
for (p = QListHead(&g_Fabric.AllVFs); p; p = QListNext(&g_Fabric.AllVFs, p)) {
VFData_t *pVFData = (VFData_t *)QListObj(p);
STL_VFINFO_RECORD *pR = &pVFData->record;
if (!isVFMember(port, pVFData))
continue;
printf("%*s%-4s\t%d", indent, "", pR->vfName, pR->vfIndex);
uint8_t sls[2] = {
pR->s1.slBase,
(pR->slMulticastSpecified? pR->slMulticast: pR->s1.slBase)
};
int i;
for (i = 0; i < 2; ++i) {
int sl = sls[i];
sc = port->pQOS->SL2SCMap->SLSCMap[sl].SC;
vl = port->pQOS->SC2VLMaps[Enum_SCVLt].SCVLMap[sc].VL;
if (i > 0 && sl == pR->s1.slBase)
printf("\t\tN/A\tN/A\tN/A");
else
printf("\t\t%d\t%d\t%d", sl, sc, vl);
}
if ((g_Fabric.flags & FF_BUFCTRLTABLE) && port->pBufCtrlTable
&& detail>2 && port->PortNum) {
ded = port->pBufCtrlTable->VL[vl].TxDedicatedLimit;
share = port->pBufCtrlTable->VL[vl].TxSharedLimit;
printf("\t%d\t\t%d", ded, share);
}
printf("\n");
}
printf("\n");
CheckVFAllocation(port, indent, FORMAT_TEXT, detail);
}
void ShowPortVFMembershipXML(PortData *port, int indent, int detail)
{
int sc, vl, ded, share;
LIST_ITEM *p;
// we need QOSDATA to have the SL2SC and PKey tables which are used by
// isVFMember
if (! (g_Fabric.flags & FF_QOSDATA)) // caller checks, should be true
return;
printf("%*s<VFMembership>\n", indent, "");
indent+=4;
for (p = QListHead(&g_Fabric.AllVFs); p; p = QListNext(&g_Fabric.AllVFs, p)) {
VFData_t *pVFData = (VFData_t *)QListObj(p);
STL_VFINFO_RECORD *pR = &pVFData->record;
if (!isVFMember(port, pVFData))
continue;
printf("%*s<VirtualFabric id=\"%d\">\n", indent, "", pR->vfIndex);
indent+=4;
XmlPrintStr("Name", (char *)pR->vfName, indent);
XmlPrintDec("Index", pR->vfIndex, indent);
XmlPrintDec("BaseSL", pR->s1.slBase, indent);
sc = port->pQOS->SL2SCMap->SLSCMap[pR->s1.slBase].SC;
vl = port->pQOS->SC2VLMaps[Enum_SCVLt].SCVLMap[sc].VL;
XmlPrintDec("BaseSC", sc, indent);
XmlPrintDec("VL", vl, indent);
if (pR->slMulticastSpecified) {
sc = port->pQOS->SL2SCMap->SLSCMap[pR->slMulticast].SC;
vl = port->pQOS->SC2VLMaps[Enum_SCVLt].SCVLMap[sc].VL;
XmlPrintDec("MulticastSL", pR->slMulticast, indent);
XmlPrintDec("MulticastSC", sc, indent);
XmlPrintDec("MulticastVL", vl, indent);
}
if ((g_Fabric.flags & FF_BUFCTRLTABLE) && port->pBufCtrlTable
&& detail>2 && port->PortNum) {
ded = port->pBufCtrlTable->VL[vl].TxDedicatedLimit;
share = port->pBufCtrlTable->VL[vl].TxSharedLimit;
XmlPrintDec("DedicatedBuffer", ded, indent);
XmlPrintDec("SharedBuffer", share, indent);
}
indent-=4;
printf("%*s</VirtualFabric>\n", indent, "");
}
indent-=4;
printf("%*s</VFMembership>\n", indent, "");
CheckVFAllocation(port, indent, FORMAT_XML, detail);
}
void ShowVFMemberReport(Point *focus, Format_t format, int indent, int detail)
{
int ct_port = 0;
LIST_ITEM *p;
switch (format) {
case FORMAT_TEXT:
printf("%*sVF Membership Report\n", indent, "");
break;
case FORMAT_XML:
indent +=4;
printf("%*s<VFMembershipReport>\n", indent, "");
break;
default:
break;
}
ShowPointFocus(focus, FIND_FLAG_FABRIC, format, indent, detail);
// we need QOSDATA to have the SL2SC and PKey tables which are used by
// isVFMember
if (! (g_Fabric.flags & FF_QOSDATA) && g_snapshot_in_file) {
switch (format) {
case FORMAT_TEXT:
printf("%*sReport skipped: provided snapshot was created without -V option\n", indent, "");
break;
case FORMAT_XML:
printf("%*s<!-- Report skipped: provided snapshot was created without -V option -->\n", indent, "");
break;
default:
break;
}
goto done;
}
for (p=QListHead(&g_Fabric.AllPorts); p != NULL; p = QListNext(&g_Fabric.AllPorts, p)) {
PortData *port = (PortData *)QListObj(p);
PortData *neighbor = (PortData *)port->neighbor;
// VF Membership is based on SL2SC tables so N/A to ISLs
if (port->nodep->NodeInfo.NodeType == STL_NODE_SW && port->PortNum) {
if (! (neighbor && neighbor->nodep->NodeInfo.NodeType == STL_NODE_FI))
continue;
}
if (!ComparePortPoint(port, focus))
continue;
switch (format) {
case FORMAT_TEXT:
printf("%*s%.*s\n", indent, "",
NODE_DESCRIPTION_ARRAY_SIZE,
g_noname?g_name_marker:(char*)port->nodep->NodeDesc.NodeString );
printf("%*sLID %u\t%s\tNodeGUID 0x%016"PRIx64"\n", indent, "",
port->EndPortLID,
StlNodeTypeToText(port->nodep->NodeInfo.NodeType),
port->nodep->NodeInfo.NodeGUID );
printf("%*sPort %u\n", indent, "", port->PortNum);
if (neighbor) {
indent+=4;
printf("%*sNeighbor Node: %.*s\n", indent, "",
NODE_DESCRIPTION_ARRAY_SIZE,
g_noname?g_name_marker:(char*)neighbor->nodep->NodeDesc.NodeString );
printf("%*sLID %u\t%s\tNodeGUID 0x%016"PRIx64"\n", indent, "",
neighbor->EndPortLID,
StlNodeTypeToText(neighbor->nodep->NodeInfo.NodeType),
neighbor->nodep->NodeInfo.NodeGUID);
printf("%*sPort %u\n", indent, "", neighbor->PortNum);
indent-=4;
}
if (port->nodep->NodeInfo.NodeType == STL_NODE_SW && port->PortNum) {
if (neighbor && neighbor->nodep->NodeInfo.NodeType == STL_NODE_FI) {
// if the node is a switch and the neighbor is a CA,
// use the mappings from the CA
ShowPortVFMembershipText(neighbor, indent, detail);
}
// if the node is a switch and the neighbor is a switch
// then there is no VF membership
} else {
// node is a CA or switch port 0
ShowPortVFMembershipText(port, indent, detail);
}
printf("\n");
break;
case FORMAT_XML:
indent+=4;
printf("%*s<Port id=\"0x%016"PRIx64":%u\">\n", indent, "",
port->nodep->NodeInfo.NodeGUID, port->PortNum);
indent+=4;
XmlPrintHex64("NodeGUID",
port->nodep->NodeInfo.NodeGUID, indent);
XmlPrintDec("PortNum", port->PortNum, indent);
XmlPrintNodeType(port->nodep->NodeInfo.NodeType, indent);
XmlPrintNodeDesc((char*)port->nodep->NodeDesc.NodeString, indent);
if (port->nodep->NodeInfo.NodeType == STL_NODE_SW && port->PortNum) {
if (neighbor && neighbor->nodep->NodeInfo.NodeType == STL_NODE_FI) {
// if the node is a switch and the neighbor is a CA,
// use the mappings from the CA
ShowPortVFMembershipXML(neighbor, indent, detail);
}
// if the node is a switch and the neighbor is a switch
// then there is no VF membership
} else {
// node is a CA or switch port 0
ShowPortVFMembershipXML(port, indent, detail);
}
indent-=4;
printf("%*s</Port>\n", indent, "");
indent-=4;
break;
default:
break;
}
ct_port++;
}
switch (format) {
case FORMAT_TEXT:
indent -= 4;
printf("%*s%d Reported Port(s)\n", indent, "", ct_port);
break;
case FORMAT_XML:
XmlPrintDec("ReportedPortCount", (unsigned)ct_port, indent+4);
break;
default:
break;
}
done:
switch (format) {
case FORMAT_TEXT:
DisplaySeparator();
break;
case FORMAT_XML:
printf("%*s</VFMembershipReport>\n", indent, "");
break;
default:
break;
}
}
static void printQuarantinedNodeRecord(int indent, const STL_QUARANTINED_NODE_RECORD *pQuarantinedNodeRecord)
{
int violStrLen = 256;
char violationString[violStrLen];
int previousViolation = 0;
memset(violationString, 0, sizeof(violationString));
if(pQuarantinedNodeRecord->quarantineReasons & STL_QUARANTINE_REASON_SPOOF_GENERIC) {
strncat(violationString, "NodeGUID/NodeType Spoofing", violStrLen - strlen(violationString));
previousViolation = 1;
}
if(pQuarantinedNodeRecord->quarantineReasons & STL_QUARANTINE_REASON_TOPO_NODE_DESC) {
strncat(violationString, previousViolation ? ", NodeDesc Mismatch" : "NodeDesc Mismatch",
violStrLen - strlen(violationString));
previousViolation = 1;
}
if(pQuarantinedNodeRecord->quarantineReasons & STL_QUARANTINE_REASON_TOPO_NODE_GUID) {
strncat(violationString, previousViolation ? ", NodeGUID Mismatch" : "NodeGUID Mismatch",
violStrLen - strlen(violationString));
previousViolation = 1;
}
if(pQuarantinedNodeRecord->quarantineReasons & STL_QUARANTINE_REASON_TOPO_PORT_GUID) {
strncat(violationString, previousViolation ? ", PortGUID Mismatch" : "PortGUID Mismatch",
violStrLen - strlen(violationString));
previousViolation = 1;
}
if(pQuarantinedNodeRecord->quarantineReasons & STL_QUARANTINE_REASON_TOPO_UNDEFINED_LINK) {
strncat(violationString, previousViolation ? ", Undefined Link" : "Undefined Link",
violStrLen - strlen(violationString));
previousViolation = 1;
}
if(pQuarantinedNodeRecord->quarantineReasons & STL_QUARANTINE_REASON_SMALL_MTU_SIZE) {
strncat(violationString, previousViolation ? ", Small MTU Size" : "Small MTU Size",
violStrLen - strlen(violationString));
previousViolation = 1;
}
if(pQuarantinedNodeRecord->quarantineReasons & STL_QUARANTINE_REASON_VL_COUNT) {
strncat(violationString, previousViolation ? ", Incorrect VL Count" : "Incorrect VL Count",
violStrLen - strlen(violationString));
previousViolation = 1;
}
printf("%*sConnected to Port %d of (LID: 0x%x, NodeGUID: 0x%016" PRIx64 ")\n", indent, "", pQuarantinedNodeRecord->trustedPortNum, pQuarantinedNodeRecord->trustedLid, pQuarantinedNodeRecord->trustedNodeGUID);
printf("%*s Offending Node Actual NodeGUID: 0x%016" PRIx64 "\n", indent, "", pQuarantinedNodeRecord->trustedNeighborNodeGUID);
printf("%*s Violation(s): %s\n", indent, "", violationString);
if(pQuarantinedNodeRecord->quarantineReasons & STL_QUARANTINE_REASON_TOPO_NODE_DESC) {
printf("%*s Expected Node Description: %.*s\n", indent, "", STL_NODE_DESCRIPTION_ARRAY_SIZE, pQuarantinedNodeRecord->expectedNodeInfo.nodeDesc.NodeString);
}
if(pQuarantinedNodeRecord->quarantineReasons & STL_QUARANTINE_REASON_TOPO_NODE_GUID) {
printf("%*s Expected NodeGUID: 0x%016" PRIx64 "\n", indent, "", pQuarantinedNodeRecord->expectedNodeInfo.nodeGUID);
}
if(pQuarantinedNodeRecord->quarantineReasons & STL_QUARANTINE_REASON_TOPO_PORT_GUID) {
printf("%*s Expected PortGUID: 0x%016" PRIx64 "\n", indent, "", pQuarantinedNodeRecord->expectedNodeInfo.portGUID);
}
if(pQuarantinedNodeRecord->quarantineReasons & STL_QUARANTINE_REASON_SPOOF_GENERIC) {
printf("%*s <SPOOFED NODE REPORTED INFORMATION (May be falsified)>\n", indent, "");
} else {
printf("%*s Received node Information:\n", indent, "");
}
printf("%*s Node Description: %.*s\n", indent, "", NODE_DESCRIPTION_ARRAY_SIZE, pQuarantinedNodeRecord->NodeDesc.NodeString);
printf("%*s Type: %s Ports: %d PortNum: %d PartitionCap: %d\n", indent, "", StlNodeTypeToText(pQuarantinedNodeRecord->NodeInfo.NodeType), pQuarantinedNodeRecord->NodeInfo.NumPorts, pQuarantinedNodeRecord->NodeInfo.u1.s.LocalPortNum, pQuarantinedNodeRecord->NodeInfo.PartitionCap);
printf("%*s NodeGUID: 0x%016" PRIx64 " PortGUID: 0x%016" PRIx64 "\n", indent, "", pQuarantinedNodeRecord->NodeInfo.NodeGUID, pQuarantinedNodeRecord->NodeInfo.PortGUID);
printf("%*s SystemImageGuid: 0x%016" PRIx64 " BaseVersion: %d SmaVersion: %d\n", indent, "", pQuarantinedNodeRecord->NodeInfo.SystemImageGUID, pQuarantinedNodeRecord->NodeInfo.BaseVersion, pQuarantinedNodeRecord->NodeInfo.ClassVersion);
printf("%*s VendorID: 0x%x DeviceId: 0x%x Revision: 0x%x\n", indent, "", pQuarantinedNodeRecord->NodeInfo.u1.s.VendorID, pQuarantinedNodeRecord->NodeInfo.DeviceID, pQuarantinedNodeRecord->NodeInfo.Revision);
}
void ShowQuarantineNodeReport(Point *focus, Format_t format, int indent, int detail)
{
int ix;
PQUERY_RESULT_VALUES pQueryResults = NULL;
STL_QUARANTINED_NODE_RECORD_RESULTS *pQNRR;
STL_QUARANTINED_NODE_RECORD *pR;
struct omgt_port *omgt_port_session = NULL;
ShowPointFocus(focus, FIND_FLAG_FABRIC, format, indent, detail);
struct omgt_params params = {.debug_file = g_verbose > 2 ? stdout : NULL};
if(omgt_open_port_by_guid(&omgt_port_session, g_portGuid, ¶ms) != FSUCCESS)
return;
omgt_set_timeout(omgt_port_session, g_ms_timeout);
if ( !(( pQueryResults =
GetAllQuarantinedNodes(omgt_port_session, &g_Fabric, focus, g_quiet) )) )
return;
pQNRR = (STL_QUARANTINED_NODE_RECORD_RESULTS *)pQueryResults->QueryResult;
pR = pQNRR->QuarantinedNodeRecords;
if (!pQNRR->NumQuarantinedNodeRecords) { /* no quarantined nodes found. */
return;
}
switch (format) {
case FORMAT_TEXT:
printf("%*sQuarantinedNodes:\n", indent, "");
break;
case FORMAT_XML:
indent +=4;
printf("%*s<QuarantinedNodes>\n", indent, "");
indent +=4;
break;
default:
break;
}
// dump quarantined records data
for (ix = 0; ix < pQNRR->NumQuarantinedNodeRecords; ix++, pR++)
{
switch (format) {
case FORMAT_TEXT:
if (ix > 0)
DisplaySeparator();
printQuarantinedNodeRecord(indent, pR);
break;
case FORMAT_XML:
printf("%*s<QNode>\n", indent, "");
indent += 4;
XmlPrintHex64("TrustedNodeGUID", pR->trustedNodeGUID, indent);
XmlPrintDec("TrustedPortNum", pR->trustedPortNum, indent);
XmlPrintLID("TrustedLID", pR->trustedLid, indent);
XmlPrintHex64("NodeGUID", pR->NodeInfo.NodeGUID, indent);
XmlPrintHex64("PortGUID", pR->NodeInfo.PortGUID, indent);
XmlPrintNodeType(pR->NodeInfo.NodeType, indent);
XmlPrintNodeDesc((char*)pR->NodeDesc.NodeString, indent);
XmlPrintDec("BaseVer", pR->NodeInfo.BaseVersion, indent);
XmlPrintDec("SmaVer", pR->NodeInfo.ClassVersion, indent);
XmlPrintDec("NumPorts", pR->NodeInfo.NumPorts, indent);
XmlPrintHex64("SystemImageGUID", pR->NodeInfo.SystemImageGUID, indent);
XmlPrintDec("PartitionCap", pR->NodeInfo.PartitionCap, indent);
XmlPrintHex("DeviceID", pR->NodeInfo.DeviceID, indent);
XmlPrintHex("Revision", pR->NodeInfo.Revision, indent);
XmlPrintHex("VendorID", pR->NodeInfo.u1.s.VendorID, indent);
if(pR->quarantineReasons) {
int expectedInfo = 0;
printf("%*s<QuarantineReasons>\n", indent, "");
indent += 4;
if(pR->quarantineReasons & STL_QUARANTINE_REASON_SPOOF_GENERIC) {
printf("%*s<Reason>NodeGUID/NodeType Spoofing</Reason>\n", indent, "");
}
if(pR->quarantineReasons & STL_QUARANTINE_REASON_TOPO_NODE_DESC) {
printf("%*s<Reason>NodeDesc Mismatch</Reason>\n", indent, "");
expectedInfo = 1;
}
if(pR->quarantineReasons & STL_QUARANTINE_REASON_TOPO_NODE_GUID) {
printf("%*s<Reason>NodeGUID Mismatch</Reason>\n", indent, "");
expectedInfo = 1;
}
if(pR->quarantineReasons & STL_QUARANTINE_REASON_TOPO_PORT_GUID) {
printf("%*s<Reason>PortGUID Mismatch</Reason>\n", indent, "");
expectedInfo = 1;
}
if(pR->quarantineReasons & STL_QUARANTINE_REASON_TOPO_UNDEFINED_LINK) {
printf("%*s<Reason>Undefined Link</Reason>\n", indent, "");
}
if(pR->quarantineReasons & STL_QUARANTINE_REASON_SMALL_MTU_SIZE) {
printf("%*s<Reason>Small MTU Size</Reason>\n", indent, "");
}
if(pR->quarantineReasons & STL_QUARANTINE_REASON_VL_COUNT) {
printf("%*s<Reason>Incorrect VL Count</Reason>\n", indent, "");
}
indent -= 4;
printf("%*s</QuarantineReasons>\n", indent, "");
if(expectedInfo) {
printf("%*s<ExpectedInfo>\n", indent, "");
indent += 4;
if(pR->quarantineReasons & STL_QUARANTINE_REASON_TOPO_NODE_DESC) {
XmlPrintStrLen("ExpectedNodeDesc", (char*) pR->expectedNodeInfo.nodeDesc.NodeString, STL_NODE_DESCRIPTION_ARRAY_SIZE, indent);
}
if(pR->quarantineReasons & STL_QUARANTINE_REASON_TOPO_NODE_GUID) {
XmlPrintHex64("ExpectedNodeGUID", pR->expectedNodeInfo.nodeGUID, indent);
}
if(pR->quarantineReasons & STL_QUARANTINE_REASON_TOPO_PORT_GUID) {
XmlPrintHex64("ExpectedPortGUID", pR->expectedNodeInfo.portGUID, indent);
}
indent -= 4;
printf("%*s</ExpectedInfo>\n", indent, "");
}
}
indent -= 4;
printf("%*s</QNode>\n", indent, "");
default:
break;
} // End of switch (format)
} // End of for (ix = 0; ix < pQNRR->NumQuarantinedNodeRecords; ix++, pR++)
switch (format) {
case FORMAT_TEXT:
DisplaySeparator();
break;
case FORMAT_XML:
indent -= 4;
printf("%*s</QuarantinedNodes>\n", indent, "");
break;
default:
break;
}
if (pQueryResults != NULL)
omgt_free_query_result_buffer(pQueryResults);
if (omgt_port_session != NULL)
omgt_close_port(omgt_port_session);
}
static void printDGMemberRecord(int indent, const STL_DEVICE_GROUP_MEMBER_RECORD *pRecord)
{
printf("%*s LID: 0x%.*x\n", indent, "", (pRecord->LID <= IB_MAX_UCAST_LID ? 4:8) , pRecord->LID);
printf("%*s PortNum: %d\n", indent, "", pRecord->Port);
printf("%*s PortGUID: 0x%016" PRIx64 "\n", indent, "", pRecord->GUID);
printf("%*s NodeDesc: %s\n\n", indent, "", pRecord->NodeDescription.NodeString);
}
void ShowDGMemberReport(Point *focus, Format_t format, int indent, int detail)
{
int ix, printDGName=1;
int groupIndex, memberIndex;
PQUERY_RESULT_VALUES pQueryResults = NULL;
STL_DEVICE_GROUP_MEMBER_RECORD_RESULTS *pDGMR;
STL_DEVICE_GROUP_MEMBER_RECORD *pR;
struct omgt_port *omgt_port_session = NULL;
ShowPointFocus(focus, FIND_FLAG_FABRIC, format, indent, detail);
struct omgt_params params = {.debug_file = g_verbose > 2 ? stdout : NULL};
if(omgt_open_port_by_guid(&omgt_port_session, g_portGuid, ¶ms) != FSUCCESS)
return;
omgt_set_timeout(omgt_port_session, g_ms_timeout);
if ( !(( pQueryResults =
GetAllDeviceGroupMemberRecords(omgt_port_session, &g_Fabric, focus, g_quiet) )) )
return;
pDGMR = (STL_DEVICE_GROUP_MEMBER_RECORD_RESULTS *)pQueryResults->QueryResult;
pR = pDGMR->Records;
if (!pDGMR->NumRecords) { /* no device group member records were found. */
return;
}
switch (format) {
case FORMAT_TEXT:
printf("%*sDG Membership Report\n", indent, "");
break;
case FORMAT_XML:
indent +=4;
printf("%*s<DGMembershipReport>\n", indent, "");
indent +=4;
break;
default:
break;
}
groupIndex=0;
memberIndex=0;
// dump device group member record data
for (ix = 0; ix < pDGMR->NumRecords; ix++, pR++)
{
switch (format) {
case FORMAT_TEXT:
if (printDGName) {
++groupIndex;
if (ix > 0)
DisplaySeparator();
printf("%*sDevice Group: %s\n", indent, "", pR->DeviceGroupName);
}
printDGMemberRecord(indent, pR);
printDGName=0;
// detect last record or last member of device group
if (ix < (pDGMR->NumRecords-1) &&
strncmp((char*)&pR->DeviceGroupName, (char*)&((pR+1)->DeviceGroupName), MAX_DG_NAME)) {
printDGName=1;
}
break;
case FORMAT_XML:
if (printDGName) {
printf("%*s<DGGroup id=\"%d\">\n", indent, "", groupIndex);
++groupIndex;
memberIndex=0;
XmlPrintStrLen("Name", (char*)pR->DeviceGroupName, sizeof(pR->DeviceGroupName), indent);
indent += 4;
}
printf("%*s<DGMember id=\"%d\">\n", indent, "", memberIndex);
++memberIndex;
XmlPrintLID("LID", pR->LID, indent+4);
XmlPrintDec("PortNum", pR->Port, indent+4);
XmlPrintHex64("PortGUID", pR->GUID, indent+4);
XmlPrintNodeDesc((char*)pR->NodeDescription.NodeString, indent+4);
printf("%*s</DGMember>\n", indent, "");
printDGName=0;
// detect last record or last member of device group
if ((ix == pDGMR->NumRecords-1) ||
(ix < (pDGMR->NumRecords-1) &&
strncmp((char*)&pR->DeviceGroupName, (char*)&((pR+1)->DeviceGroupName), MAX_DG_NAME))) {
indent -= 4;
printf("%*s</DGGroup>\n", indent, "");
printDGName=1;
}
default:
break;
} // End of switch (format)
} // End of for (ix = 0; ix < pDGMR->NumRecords; ix++, pR++)
switch (format) {
case FORMAT_TEXT:
printf("%*s%d Reported Device Group(s)\n", indent+4, "", groupIndex);
DisplaySeparator();
break;
case FORMAT_XML:
XmlPrintDec("ReportedDeviceGroupCount", (unsigned)groupIndex, indent);
indent -= 4;
printf("%*s</DGMembershipReport>\n", indent, "");
break;
default:
break;
}
if (pQueryResults != NULL)
omgt_free_query_result_buffer(pQueryResults);
if (omgt_port_session != NULL)
omgt_close_port(omgt_port_session);
}
// CableInfo is organized in 128-byte pages but is stored in 64-byte half-pages
// STL_CABLE_INFO_UP0_DD/STL_CABLE_INFO_STD use STL_CIB_STD_HIGH_PAGE_ADDR to
// STL_CIB_STD_END_ADDR inclusive (128-255). STL_CABLE_INFO_LOW0_STD/STL_CABLE_INFO_LOW0_DD
// use STL_CIB_STD_LOW_PAGE_ADDR to 127.
FSTATUS ShowPortCableHealth(PortData *portp, int indent, char *buf, uint16 length ){
boolean qsfp_dd;
PrintDest_t destBuf;
CableTypeInfoType cableTypeInfo;
boolean cableLenValid; // Copper cable length valid
float rx_1, rx_2, rx_3, rx_4; // rx average optical power for lanes
float tx_1, tx_2, tx_3, tx_4; // tx average optical power for lanes
float temperature, voltage;
char tempStr[STL_CIB_STD_MAX_STRING + 1] = {'\0'};
// check input parameters
if (!portp)
return FINVALID_PARAMETER;
//Initialize the buffer to store cable info per port
PrintDestInitBuffer(&destBuf, buf, length);
PrintFunc(&destBuf,"%*s%s;%d;0x%016"PRIx64";",
indent,
"",
portp->nodep->NodeDesc.NodeString,
portp->nodep->NodeInfo.NodeType,
portp->nodep->NodeInfo.NodeGUID);
// LID is displayed as xxx when persist or hard flag is set
if (g_persist || g_hard){
PrintFunc(&destBuf,"xxxxxxxx;%3u;",portp->PortNum);
} else {
PrintFunc(&destBuf,"0x%x;%3u;",
portp->EndPortLID, portp->PortNum);
}
//check if cabledata exists
if (!portp->pCableInfoData){
PrintFunc(&destBuf,"NA;NA;NA;NA;NA;NA;NA;NA;NA;NA;NA;NA;NA;NA;NA;");
return FSUCCESS;
}
//Check for port type
if (STL_PORT_TYPE_STANDARD != portp->PortInfo.PortPhysConfig.s.PortType){
fprintf(stderr, "ShowPortCableHealth: Not a standard port\n");
return FUNAVAILABLE;
}
//Get cable type
qsfp_dd = (*(portp->pCableInfoData) == STL_CIB_STD_QSFP_DD);
//Handle DD cable info
if (qsfp_dd) {
//Handle data in Low Address page
STL_CABLE_INFO_LOW0_DD *pCableData = (STL_CABLE_INFO_LOW0_DD*)(portp->pCableInfoData + STL_CIB_STD_LOW_PAGE_ADDR);
//Access temperature and voltage
temperature = ntoh16(pCableData->temperature)/256.0;
voltage = ntoh16(pCableData->voltage)/10000.0;
PrintFunc(&destBuf,"%.2f;%.2f;",temperature, voltage);
//Rx and Tx data in High Address page 17 is not accessible so displayed as "NA"
PrintFunc(&destBuf,"NA;NA;NA;NA;NA;NA;NA;NA;");
//Handle Data in High address page 0
STL_CABLE_INFO_UP0_DD *pCableInfo = (STL_CABLE_INFO_UP0_DD *)(portp->pCableInfoData + STL_CIB_STD_HIGH_PAGE_ADDR);
StlCableInfoDecodeCableType(pCableInfo->cable_type, pCableInfo->connector, pCableInfo->ident, &cableTypeInfo);
cableLenValid = cableTypeInfo.cableLengthValid;
StlCableInfoDDCableLengthToText(pCableInfo->cableLengthEnc, cableLenValid, MAX_CABLE_LENGTH_STR_LEN, tempStr);
PrintFunc(&destBuf, "%s;", tempStr);
memset(tempStr, 0, STL_CIB_STD_MAX_STRING + 1);
memcpy(tempStr, (char *)pCableInfo->vendor_name, sizeof(pCableInfo->vendor_name));
StlCableInfoTrimTrailingWS(tempStr, sizeof(pCableInfo->vendor_name));
PrintFunc(&destBuf, "%s;", tempStr);
memset(tempStr, 0, STL_CIB_STD_MAX_STRING + 1);
memcpy(tempStr, (char *)pCableInfo->vendor_pn, sizeof(pCableInfo->vendor_pn));
StlCableInfoTrimTrailingWS(tempStr, sizeof(pCableInfo->vendor_pn));
PrintFunc(&destBuf, "%s;", tempStr);
memset(tempStr, 0, STL_CIB_STD_MAX_STRING + 1);
memcpy(tempStr, (char *)pCableInfo->vendor_sn, sizeof(pCableInfo->vendor_sn));
StlCableInfoTrimTrailingWS(tempStr, sizeof(pCableInfo->vendor_sn));
PrintFunc(&destBuf, "%s;", tempStr);
memset(tempStr, 0, STL_CIB_STD_MAX_STRING + 1);
StlCableInfoDateCodeToText(pCableInfo->date_code, tempStr);
PrintFunc(&destBuf, "%s;", tempStr);
//Handle cable info based on SFF-8636 Rev 2-5
}else {
//Handle data in Low Address page
STL_CABLE_INFO_LOW0_STD *pCableData = (STL_CABLE_INFO_LOW0_STD*)(portp->pCableInfoData + STL_CIB_STD_LOW_PAGE_ADDR);
//Access temperature and voltage
temperature = ntoh16(pCableData->temperature)/256.0;
voltage = ntoh16(pCableData->voltage)/10000.0;
PrintFunc(&destBuf,"%.2f;%.2f;",temperature, voltage);
//RX average optical power is stored in 2bytes, total of 8 bytes for RX_1, RX_2, RX_3, RX_4
rx_1 = ntoh16(pCableData->rxOpticalPwr1)/10000.0;
rx_2 = ntoh16(pCableData->rxOpticalPwr2)/10000.0;
rx_3 = ntoh16(pCableData->rxOpticalPwr3)/10000.0;
rx_4 = ntoh16(pCableData->rxOpticalPwr4)/10000.0;
//TX average optical power is stored in 2bytes, total of 8 bytes for TX_1, TX_2, TX_3, TX_4
tx_1 = ntoh16(pCableData->txOpticalPwr1)/10000.0;
tx_2 = ntoh16(pCableData->txOpticalPwr2)/10000.0;
tx_3 = ntoh16(pCableData->txOpticalPwr3)/10000.0;
tx_4 = ntoh16(pCableData->txOpticalPwr4)/10000.0;
PrintFunc(&destBuf,"%.2f;%.2f;%.2f;%.2f;%.2f;%.2f;%.2f;%.2f;",
rx_1, rx_2, rx_3, rx_4, tx_1, tx_2, tx_3, tx_4 );
//Handle Data in High address page 0
STL_CABLE_INFO_STD *pCableInfo = (STL_CABLE_INFO_STD *)(portp->pCableInfoData + STL_CIB_STD_HIGH_PAGE_ADDR);
StlCableInfoDecodeCableType(pCableInfo->dev_tech.s.xmit_tech, pCableInfo->connector, pCableInfo->ident, &cableTypeInfo);
cableLenValid = cableTypeInfo.cableLengthValid;
StlCableInfoOM4LengthToText(pCableInfo->len_om4, cableLenValid, MAX_CABLE_LENGTH_STR_LEN, tempStr);
PrintFunc(&destBuf, "%s;", tempStr);
memset(tempStr, 0, STL_CIB_STD_MAX_STRING + 1);
memcpy(tempStr, (char *)pCableInfo->vendor_name, sizeof(pCableInfo->vendor_name));
StlCableInfoTrimTrailingWS(tempStr, sizeof(pCableInfo->vendor_name));
PrintFunc(&destBuf, "%s;", tempStr);
memset(tempStr, 0, STL_CIB_STD_MAX_STRING + 1);
memcpy(tempStr, (char *)pCableInfo->vendor_pn, sizeof(pCableInfo->vendor_pn));
StlCableInfoTrimTrailingWS(tempStr, sizeof(pCableInfo->vendor_pn));
PrintFunc(&destBuf, "%s;", tempStr);
memset(tempStr, 0, STL_CIB_STD_MAX_STRING + 1);
memcpy(tempStr, (char *)pCableInfo->vendor_sn, sizeof(pCableInfo->vendor_sn));
StlCableInfoTrimTrailingWS(tempStr, sizeof(pCableInfo->vendor_sn));
PrintFunc(&destBuf, "%s;", tempStr);
memset(tempStr, 0, STL_CIB_STD_MAX_STRING + 1);
StlCableInfoDateCodeToText(pCableInfo->date_code, tempStr);
PrintFunc(&destBuf, "%s;", tempStr);
}
return FSUCCESS;
}
//Cable health Data length per port
#define STL_CABLEHEALTH_DATA_LENGTH_PER_PORT 256
//Cable Health Report Header string
#define STL_CABLEHEALTH_HEADER_STRING \
"Pri Node Name;" "Pri Node Type;" "Pri Node GUID;"\
"Pri LID;" "Pri PortNum;" "Pri Temperature;"\
"Pri Voltage;" "Pri RX_1;" "Pri RX_2;"\
"Pri RX_3;" "Pri RX_4;" "Pri TX_1;"\
"Pri TX_2;" "Pri TX_3;" "Pri TX_4;"\
"Pri Cable Length;" "Pri Vendor Name;" "Pri Vendor PartNumber;"\
"Pri Vendor SerialNumber;" "Pri Vendor Manufacture Date;"\
"Sec Node Name;" "Sec Node Type;" "Sec Node GUID;"\
"Sec LID;" "Sec PortNum;" "Sec Temperature;"\
"Sec Voltage;" "Sec RX_1;" "Sec RX_2;"\
"Sec RX_3;" "Sec RX_4;" "Sec TX_1;"\
"Sec TX_2;" "Sec TX_3;" "Sec TX_4;"\
"Sec Cable Length;" "Sec Vendor Name;" "Sec Vendor PartNumber;"\
"Sec Vendor SerialNumber;" "Sec Vendor Manufacture Date;"
#define CABLEHEALTH_EMPTY_FIELD ";;;;;;;;;;;;;;;"
void ShowCableHealthReport(Point *focus, Format_t format, int indent, int detail)
{
LIST_ITEM *p;
char tempBuf1[STL_CABLEHEALTH_DATA_LENGTH_PER_PORT];
char tempBuf2[STL_CABLEHEALTH_DATA_LENGTH_PER_PORT];
boolean first_entry = 1;
FSTATUS status1 = FERROR;
FSTATUS status2 = FERROR;
PrintDest_t destFile;
PrintDestInitFile(&destFile, stdout);
ShowPointFocus(focus, FIND_FLAG_FABRIC, format, indent, detail);
for (p=QListHead(&g_Fabric.AllPorts); p != NULL; p = QListNext(&g_Fabric.AllPorts, p)) {
PortData *portp1, *portp2;
portp1 = (PortData *)QListObj(p);
// skip backplane (ISL) ports
if(isInternalLink(portp1))
continue;
// to avoid duplicated processing, only process "from" ports in link
if (!portp1->from)
continue;
if (! ComparePortPoint(portp1, focus) && ! ComparePortPoint(portp1->neighbor, focus))
continue;
//Get Cable Health report for from-port
memset(tempBuf1, 0, STL_CABLEHEALTH_DATA_LENGTH_PER_PORT);
status1 = ShowPortCableHealth(portp1, indent, tempBuf1, STL_CABLEHEALTH_DATA_LENGTH_PER_PORT);
// get port on the other side
portp2 = portp1->neighbor;
if(portp2) {
//Get Cable Health report for to-port
memset(tempBuf2, 0, STL_CABLEHEALTH_DATA_LENGTH_PER_PORT);
status2 = ShowPortCableHealth(portp2, indent, tempBuf2, STL_CABLEHEALTH_DATA_LENGTH_PER_PORT);
}
if((FSUCCESS == status1)|| (FSUCCESS == status2)) {
//show header once
if(first_entry ){
PrintFunc(&destFile, "%s\n", "Cable Health Report");
PrintFunc(&destFile, "%s\n", STL_CABLEHEALTH_HEADER_STRING);
first_entry = 0;
}
PrintFunc(&destFile, "%s%s\n",
(FSUCCESS == status1)?tempBuf1:
strncat(tempBuf1,CABLEHEALTH_EMPTY_FIELD,strlen(CABLEHEALTH_EMPTY_FIELD) + 1),
(FSUCCESS == status2)?tempBuf2:
strncat(tempBuf2,CABLEHEALTH_EMPTY_FIELD,strlen(CABLEHEALTH_EMPTY_FIELD) + 1));
}
}
if(first_entry)
fprintf(stderr, "No Cable Health Records Returned\n");
}
// command line options, each has a short and long flag name
struct option options[] = {
// basic controls
{ "verbose", no_argument, NULL, 'v' },
{ "quiet", no_argument, NULL, 'q' },
{ "hfi", required_argument, NULL, 'h' },
{ "port", required_argument, NULL, 'p' },
{ "output", required_argument, NULL, 'o' },
{ "detail", required_argument, NULL, 'd' },
{ "persist", no_argument, NULL, 'P' },
{ "hard", no_argument, NULL, 'H' },
{ "noname", no_argument, NULL, 'N' },
{ "stats", no_argument, NULL, 's' },
{ "interval", required_argument, NULL, 'i' },
{ "clear", no_argument, NULL, 'C' },
{ "clearall", no_argument, NULL, 'a' },
{ "smadirect", no_argument, NULL, 'm' },
{ "pmadirect", no_argument, NULL, 'M' },
{ "routes", no_argument, NULL, 'r' },
{ "limit", no_argument, NULL, 'L' },
{ "config", required_argument, NULL, 'c' },
{ "focus", required_argument, NULL, 'F' },
{ "src", required_argument, NULL, 'S' },
{ "dest", required_argument, NULL, 'D' },
{ "xml", no_argument, NULL, 'x' },
{ "infile", required_argument, NULL, 'X' },
{ "topology", required_argument, NULL, 'T' },
{ "quietfocus", no_argument, NULL, 'Q' },
{ "vltables", no_argument, NULL, 'V' },
{ "allports", no_argument, NULL, 'A' },
{ "begin", required_argument, NULL, 'b'},
{ "end", required_argument, NULL, 'e'},
{ "rc", required_argument, NULL, 'z' },
{ "timeout", required_argument, NULL, '!' },
{ "help", no_argument, NULL, '$' }, // use an invalid option character
{ 0 }
};
void Usage_full(void)
{
fprintf(stderr, "Usage: opareport [-v][-q] [-h hfi] [-p port] [-o report] [-d detail]\n"
" [-P|-H] [-N] [-x] [-X snapshot_input] [-T topology_input]\n"
" [-s] [-r] [-V] [-i seconds] [-b date_time] [-e date_time]\n"
" [-C] [-a] [-m] [-M] [-A] [-c file] [-L] [-F point]\n"
" [-S point] [-D point] [-Q]\n");
fprintf(stderr, " or\n");
fprintf(stderr, " opareport --help\n");
fprintf(stderr, " --help - produce full help text\n");
fprintf(stderr, " -v/--verbose - verbose output\n");
fprintf(stderr, " -q/--quiet - disable progress reports\n");
fprintf(stderr, " -h/--hfi hfi - hfi, numbered 1..n, 0= -p port will be a\n");
fprintf(stderr, " system wide port num (default is 0)\n");
fprintf(stderr, " -p/--port port - port, numbered 1..n, 0=1st active\n");
fprintf(stderr, " (default is 1st active)\n");
fprintf(stderr, " --timeout - timeout(wait time for response) in ms, default is 1000ms\n");
fprintf(stderr, " -o/--output report - report type for output\n");
fprintf(stderr, " -d/--detail level - level of detail 0-n for output, default is 2\n");
fprintf(stderr, " -P/--persist - only include data persistent across reboots\n");
fprintf(stderr, " -H/--hard - only include permanent hardware data\n");
fprintf(stderr, " -N/--noname - omit node and IOC names\n");
fprintf(stderr, " -x/--xml - output in xml\n");
fprintf(stderr, " -X/--infile snapshot_input\n");
fprintf(stderr, " - generate report using data in snapshot_input\n");
fprintf(stderr, " snapshot_input must have been generated via\n");
fprintf(stderr, " previous -o snapshot run.\n");
fprintf(stderr, " When used, -s, -i, -C and -a options are ignored\n");
fprintf(stderr, " '-' may be used to specify stdin\n");
fprintf(stderr, " -T/--topology topology_input\n");
fprintf(stderr, " - use topology_input file to augment and\n");
fprintf(stderr, " verify fabric information. When used various\n");
fprintf(stderr, " reports can be augmented with information\n");
fprintf(stderr, " not available electronically (such as cable\n");
fprintf(stderr, " labels).\n");
fprintf(stderr, " '-' may be used to specify stdin\n");
fprintf(stderr, " -s/--stats - get performance stats for all ports\n");
fprintf(stderr, " -i/--interval seconds - obtain performance stats over interval seconds\n");
fprintf(stderr, " clears all stats, waits interval seconds,\n");
fprintf(stderr, " then generates report. Implies -s\n");
fprintf(stderr, " -b/--begin date_time - obtain past performance stats over interval\n");
fprintf(stderr, " beginning at date_time. Implies -s\n");
fprintf(stderr, " -e/--end date_time - obtain past performance stats over interval\n");
fprintf(stderr, " ending at date_time. Implies -s\n");
fprintf(stderr, " For both -b and -e, date_time may be a time\n");
fprintf(stderr, " entered as HH:MM[:SS] or date as mm/dd/YYYY,\n");
fprintf(stderr, " dd.mm.YYYY, YYYY-mm-dd or date followed by time\n");
fprintf(stderr, " e.g. \"2016-07-04 14:40\". Relative times are\n");
fprintf(stderr, " taken as \"x [second|minute|hour|day](s) ago.\"\n");
fprintf(stderr, " -C/--clear - clear performance stats for all ports\n");
fprintf(stderr, " - only stats with error thresholds are cleared\n");
fprintf(stderr, " - clear occurs after generating report\n");
fprintf(stderr, " -a/--clearall - clear all performance stats for all ports\n");
fprintf(stderr, " -m/--smadirect - access fabric information directly from SMA\n");
fprintf(stderr, " -M/--pmadirect - access performance stats via direct PMA\n");
fprintf(stderr, " -A/--allports - also get PortInfo for down switch ports.\n");
fprintf(stderr, " uses direct SMA to get this data.\n");
fprintf(stderr, " If used with -M will also get PMA stats\n");
fprintf(stderr, " for down switch ports.\n");
fprintf(stderr, " -c/--config file - error thresholds config file, default is\n");
fprintf(stderr, " %s\n", CONFIG_FILE);
fprintf(stderr, " -L/--limit - For port error counters check (-o errors)\n");
fprintf(stderr, " and port counters clear (-C or -i) with -F\n");
fprintf(stderr, " limit operation to exact specified focus.\n");
fprintf(stderr, " Normally the neighbor of each selected\n");
fprintf(stderr, " port would also be checked/cleared\n");
fprintf(stderr, " Does not affect other reports\n");
fprintf(stderr, " -F/--focus point - focus area for report\n");
fprintf(stderr, " Limits output to reflect a subsection of\n");
fprintf(stderr, " the fabric. May not work with all reports.\n");
fprintf(stderr, " (For example, route, mcgroups, and the verify*\n");
fprintf(stderr, " reports may ignore the option or not generate\n");
fprintf(stderr, " useful results.)\n");
fprintf(stderr, " -S/--src point - source for trace route, default is local port\n");
fprintf(stderr, " -D/--dest point - destination for trace route\n");
fprintf(stderr, " -Q/--quietfocus - do not include focus description in report\n");
fprintf(stderr, "The -h and -p options permit a variety of selections:\n");
fprintf(stderr, " -h 0 - 1st active port in system (this is the default)\n");
fprintf(stderr, " -h 0 -p 0 - 1st active port in system\n");
fprintf(stderr, " -h x - 1st active port on HFI x\n");
fprintf(stderr, " -h x -p 0 - 1st active port on HFI x\n");
fprintf(stderr, " -h 0 -p y - port y within system (irrespective of which\n");
fprintf(stderr, " ports are active)\n");
fprintf(stderr, " -h x -p y - HFI x, port y\n");
fprintf(stderr, "Snapshot specific Options:\n");
fprintf(stderr, " -r/--routes - get routing tables for all switches\n");
fprintf(stderr, " -V/--vltables - get the P-Key tables for all nodes and\n");
fprintf(stderr, " QOS VL-related tables for all ports\n");
fprintf(stderr, "Report Types:\n");
fprintf(stderr, " comps - summary of all systems and SMs in fabric\n");
fprintf(stderr, " brcomps - brief summary of all systems and SMs in fabric\n");
fprintf(stderr, " nodes - summary of all node types and SMs in fabric\n");
fprintf(stderr, " brnodes - brief summary of all node types and SMs in\n");
fprintf(stderr, " fabric\n");
fprintf(stderr, " ious - summary of all IO Units in fabric\n");
fprintf(stderr, " lids - summary of all LIDs in fabric\n");
fprintf(stderr, " linkinfo - summary of all links with LIDs in fabric\n");
fprintf(stderr, " links - summary of all links\n");
fprintf(stderr, " extlinks - summary of links external to systems\n");
fprintf(stderr, " filinks - summary of links to FIs\n");
fprintf(stderr, " islinks - summary of inter-switch links\n");
fprintf(stderr, " extislinks - summary of inter-switch links external to systems\n");
fprintf(stderr, " slowlinks - summary of links running slower than expected\n");
fprintf(stderr, " slowconfiglinks - summary of links configured to run slower than\n");
fprintf(stderr, " supported includes slowlinks\n");
fprintf(stderr, " slowconnlinks - summary of links connected with mismatched speed\n");
fprintf(stderr, " potential includes slowconfiglinks\n");
fprintf(stderr, " misconfiglinks - summary of links configured to run slower than\n");
fprintf(stderr, " supported\n");
fprintf(stderr, " misconnlinks - summary of links connected with mismatched speed\n");
fprintf(stderr, " potential\n");
fprintf(stderr, " errors - summary of links whose errors exceed counts in\n");
fprintf(stderr, " config file\n");
fprintf(stderr, " otherports - summary of ports not connected to this fabric\n");
fprintf(stderr, " linear - summary of linear forwarding data base (FDB) for\n");
fprintf(stderr, " each Switch\n");
fprintf(stderr, " mcast - summary of multicast FDB for each Switch\n");
fprintf(stderr, " mcgroups - summary of multicast groups\n");
fprintf(stderr, " portusage - summary of ports referenced in linear FDB for\n");
fprintf(stderr, " each Switch, broken down by NodeType of DLID\n");
fprintf(stderr, " pathusage - summary of number of FI to FI paths routed\n");
fprintf(stderr, " through each switch port\n");
fprintf(stderr, " treepathusage - analysis of number of FI to FI paths routed\n");
fprintf(stderr, " through each switch port for a fat tree\n");
fprintf(stderr, " portgroups - summary of adaptive routing port groups for each\n");
fprintf(stderr, " Switch\n");
fprintf(stderr, " quarantinednodes - summary of quarantined nodes\n");
fprintf(stderr, " validateroutes - validate all routes in the fabric\n");
fprintf(stderr, " validatevlroutes - validate all routes in the fabric using SLSC,\n");
fprintf(stderr, " SCSC, and SCVL tables\n");
fprintf(stderr, " validatepgs - validate all port groups in the fabric\n");
fprintf(stderr, " validatecreditloops - validate topology configuration of the fabric to\n");
fprintf(stderr, " identify any existing credit loops\n");
fprintf(stderr, " validatevlcreditloops - validate topology configuration of the fabric\n");
fprintf(stderr, " including SLSC, SCSC, and SCVL tables to identify\n");
fprintf(stderr, " any existing credit loops\n");
fprintf(stderr, " validatemcroutes - validate multicast routes of the fabric to\n");
fprintf(stderr, " identify loops in multicast forwarding tables and\n");
fprintf(stderr, " detect MFT-multicast membership inconsistencies.\n");
fprintf(stderr, " vfinfo - summary of vFabric information\n");
fprintf(stderr, " vfmember - summary of vFabric membership information\n");
fprintf(stderr, " dgmember - summary of DeviceGroup membership information\n");
fprintf(stderr, " verifyfis - compare fabric (or snapshot) FIs to supplied\n");
fprintf(stderr, " topology and identify differences and omissions\n");
fprintf(stderr, " verifysws - compare fabric (or snapshot) Switches to\n");
fprintf(stderr, " supplied topology and identify differences and\n");
fprintf(stderr, " omissions\n");
fprintf(stderr, " verifynodes - verifyfis and verifysws reports\n");
fprintf(stderr, " verifysms - compare fabric (or snapshot) SMs to supplied\n");
fprintf(stderr, " topology and identify differences and omissions\n");
fprintf(stderr, " verifylinks - compare fabric (or snapshot) links to supplied\n");
fprintf(stderr, " topology and identify differences and omissions\n");
fprintf(stderr, " verifyextlinks - compare fabric (or snapshot) links to supplied\n");
fprintf(stderr, " topology and identify differences and omissions\n");
fprintf(stderr, " limit analysis to links external to systems\n");
fprintf(stderr, " verifyfilinks - compare fabric (or snapshot) links to supplied\n");
fprintf(stderr, " topology and identify differences and omissions\n");
fprintf(stderr, " limit analysis to links to FIs\n");
fprintf(stderr, " verifyislinks - compare fabric (or snapshot) links to supplied\n");
fprintf(stderr, " topology and identify differences and omissions\n");
fprintf(stderr, " limit analysis to inter-switch links\n");
fprintf(stderr, " verifyextislinks - compare fabric (or snapshot) links to supplied\n");
fprintf(stderr, " topology and identify differences and omissions\n");
fprintf(stderr, " limit analysis to inter-switch links external to\n");
fprintf(stderr, " systems\n");
fprintf(stderr, " verifyall - verifyfis, verifysws, verifysms and verifylinks\n");
fprintf(stderr, " reports\n");
fprintf(stderr, " all - comp, nodes, ious, links, extlinks,\n");
fprintf(stderr, " slowconnlinks, and errors reports\n");
fprintf(stderr, " route - trace route between -S and -D points\n");
fprintf(stderr, " bfrctrl - report Buffer Control Tables for all ports\n");
fprintf(stderr, " snapshot - output snapshot of fabric state for later use as\n");
fprintf(stderr, " snapshot_input implies -x. May not be combined\n");
fprintf(stderr, " with other reports. When selected, -F, -P, -H,\n");
fprintf(stderr, " -N options are ignored\n");
fprintf(stderr, " topology - output the topology of the fabric for later use\n");
fprintf(stderr, " as topology_input implies -x. May not be\n");
fprintf(stderr, " combined with other reports\n");
fprintf(stderr, " Use with detail level 3 or more to get Port element\n");
fprintf(stderr, " under Node in output xml\n");
fprintf(stderr, " none - no report, useful if just want to clear stats\n");
fprintf(stderr, "Point Syntax:\n");
fprintf(stderr, " gid:value - value is numeric port gid of form: subnet:guid\n");
fprintf(stderr, " lid:value - value is numeric lid\n");
fprintf(stderr, " lid:value:node - value is numeric lid, selects node with given\n");
fprintf(stderr, " lid\n");
fprintf(stderr, " lid:value:port:value2 - value is numeric lid of node, value2 is port #\n");
fprintf(stderr, " portguid:value - value is numeric port guid\n");
fprintf(stderr, " nodeguid:value - value is numeric node guid\n");
fprintf(stderr, " nodeguid:value1:port:value2\n");
fprintf(stderr, " - value1 is numeric node guid, value2 is port #\n");
fprintf(stderr, " iocguid:value - value is numeric IOC guid\n");
fprintf(stderr, " iocguid:value1:port:value2 - value1 is numeric IOC guid, value2 is port #\n");
fprintf(stderr, " systemguid:value - value is numeric system image guid\n");
fprintf(stderr, " systemguid:value1:port:value2\n");
fprintf(stderr, " - value1 is numeric system image guid\n");
fprintf(stderr, " value2 is port #\n");
fprintf(stderr, " ioc:value - value is IOC Profile ID String (IOC Name)\n");
fprintf(stderr, " ioc:value1:port:value2 - value1 is IOC Profile ID String (IOC Name)\n");
fprintf(stderr, " value2 is port #\n");
fprintf(stderr, " iocpat:value - value is glob pattern for IOC Profile ID String\n");
fprintf(stderr, " (IOC Name)\n");
fprintf(stderr, " iocpat:value1:port:value2 - value1 is glob pattern for IOC Profile ID String\n");
fprintf(stderr, " (IOC Name), value2 is port #\n");
fprintf(stderr, " ioctype:value - value is IOC type (SRP or OTHER)\n");
fprintf(stderr, " ioctype:value1:port:value2 - value1 is IOC type (SRP or OTHER)\n");
fprintf(stderr, " value2 is port #\n");
fprintf(stderr, " node:value - value is node description (node name)\n");
fprintf(stderr, " node:value1:port:value2 - value1 is node description (node name)\n");
fprintf(stderr, " value2 is port #\n");
fprintf(stderr, " nodepat:value - value is glob pattern for node description (node\n");
fprintf(stderr, " name)\n");
fprintf(stderr, " nodepat:value1:port:value2 - value1 is glob pattern for node description\n");
fprintf(stderr, " (node name), value2 is port #\n");
fprintf(stderr, " nodedetpat:value - value is glob pattern for node details\n");
fprintf(stderr, " nodedetpat:value1:port:value2\n");
fprintf(stderr, " - value1 is glob pattern for node details,\n");
fprintf(stderr, " value2 is port #\n");
fprintf(stderr, " nodetype:value - value is node type (SW or FI)\n");
fprintf(stderr, " nodetype:value1:port:value2\n");
fprintf(stderr, " - value1 is node type (SW or FI)\n");
fprintf(stderr, " value2 is port #\n");
fprintf(stderr, " rate:value - value is string for rate (25g, 50g, 75g, 100g)\n");
fprintf(stderr, " omits switch mgmt port 0\n");
fprintf(stderr, " portstate:value - value is string for state (down, init, armed,\n");
fprintf(stderr, " active, notactive, initarmed)\n");
fprintf(stderr, " portphysstate:value - value is string for phys state (polling,\n");
fprintf(stderr, " disabled, training, linkup, recovery, offline,\n");
fprintf(stderr, " test)\n");
fprintf(stderr, " mtucap:value - value is MTU size (2048, 4096, 8192, 10240)\n");
fprintf(stderr, " omits switch mgmt port 0\n");
fprintf(stderr, " labelpat:value - value is glob pattern for cable label\n");
fprintf(stderr, " lengthpat:value - value is glob pattern for cable length\n");
fprintf(stderr, " cabledetpat:value - value is glob pattern for cable details\n");
fprintf(stderr, " cabinflenpat:value - value is glob pattern for cable info length\n");
fprintf(stderr, " cabinfvendnamepat:value - value is glob pattern for cable info vendor name\n");
fprintf(stderr, " cabinfvendpnpat:value - value is glob pattern for cable info vendor PN\n");
fprintf(stderr, " cabinfvendrevpat:value - value is glob pattern for cable info vendor rev\n");
fprintf(stderr, " cabinfvendsnpat:value - value is glob pattern for cable info vendor SN\n");
fprintf(stderr, " cabinftype:value - value is either 'optical', 'passive_copper', \n");
fprintf(stderr, " 'active_copper' or 'unknown' \n");
fprintf(stderr, " linkdetpat:value - value is glob pattern for link details\n");
fprintf(stderr, " portdetpat:value - value is glob pattern for port details\n");
fprintf(stderr, " sm - master SM\n");
fprintf(stderr, " smdetpat:value - value is glob pattern for sm details\n");
fprintf(stderr, " route:point1:point2 - all ports along the routes between the 2 given\n");
fprintf(stderr, " points\n");
fprintf(stderr, " led:value - value is either 'on' or 'off' for LED port beacon\n");
fprintf(stderr, " linkqual:value - ports with a link quality equal to value\n");
fprintf(stderr, " linkqualLE:value - ports with a link quality less than or equal to\n");
fprintf(stderr, " value\n");
fprintf(stderr, " linkqualGE:value - ports with a link quality greater than or equal\n");
fprintf(stderr, " to value\n");
fprintf(stderr, " nodepatfile:FILENAME - name of file with list of nodes\n");
fprintf(stderr, " nodepairpatfile:FILENAME - name of file with list of node pairs separated by colon\n");
fprintf(stderr, " ldr - ports with a non-zero link down reason or neighbor\n");
fprintf(stderr, " link down reason\n");
fprintf(stderr, " ldr:value - ports with a link down reason or neighbor link down\n");
fprintf(stderr, " reason equal to value\n");
fprintf(stderr, "Examples:\n");
fprintf(stderr, " opareport -o comps -d 3\n");
fprintf(stderr, " opareport -o errors -o slowlinks\n");
fprintf(stderr, " opareport -o nodes -F portguid:0x00066a00a000447b\n");
fprintf(stderr, " opareport -o nodes -F nodeguid:0x001175019800447b:port:1\n");
fprintf(stderr, " opareport -o nodes -F nodeguid:0x001175019800447b\n");
fprintf(stderr, " opareport -o nodes -F 'node:duster hfi1_0'\n");
fprintf(stderr, " opareport -o nodes -F 'node:duster hfi1_0:port:1'\n");
fprintf(stderr, " opareport -o nodes -F 'nodepat:d*'\n");
fprintf(stderr, " opareport -o nodes -F 'nodepat:d*:port:1'\n");
fprintf(stderr, " opareport -o nodes -F 'nodedetpat:compute*'\n");
fprintf(stderr, " opareport -o nodes -F 'nodedetpat:compute*:port:1'\n");
fprintf(stderr, " opareport -o nodes -F nodetype:FI\n");
fprintf(stderr, " opareport -o nodes -F nodetype:FI:port:1\n");
fprintf(stderr, " opareport -o nodes -F lid:1\n");
fprintf(stderr, " opareport -o nodes -F led:on\n");
fprintf(stderr, " opareport -o nodes -F led:off\n");
fprintf(stderr, " opareport -o nodes -F lid:1:node\n");
fprintf(stderr, " opareport -o nodes -F lid:1:port:2\n");
fprintf(stderr, " opareport -o nodes -F gid:0xfe80000000000000:0x00066a00a000447b\n");
fprintf(stderr, " opareport -o nodes -F systemguid:0x001175019800447b\n");
fprintf(stderr, " opareport -o nodes -F systemguid:0x001175019800447b:port:1\n");
fprintf(stderr, " opareport -o nodes -F iocguid:0x00117501300001e0\n");
fprintf(stderr, " opareport -o nodes -F iocguid:0x00117501300001e0:port:2\n");
fprintf(stderr, " opareport -o nodes -F 'ioc:Chassis 0x00066A005000010C, Slot 2, IOC 1'\n");
fprintf(stderr, " opareport -o nodes -F 'ioc:Chassis 0x00066A005000010C, Slot 2, IOC 1:port:2'\n");
fprintf(stderr, " opareport -o nodes -F 'iocpat:*Slot 2*'\n");
fprintf(stderr, " opareport -o nodes -F 'iocpat:*Slot 2*:port:2'\n");
fprintf(stderr, " opareport -o nodes -F ioctype:SRP\n");
fprintf(stderr, " opareport -o nodes -F ioctype:SRP:port:2\n");
fprintf(stderr, " opareport -o extlinks -F rate:100g\n");
fprintf(stderr, " opareport -o extlinks -F portstate:armed\n");
fprintf(stderr, " opareport -o extlinks -F portphysstate:linkup\n");
fprintf(stderr, " opareport -o extlinks -F 'labelpat:S1345*'\n");
fprintf(stderr, " opareport -o extlinks -F 'lengthpat:11m'\n");
fprintf(stderr, " opareport -o extlinks -F 'cabledetpat:*hitachi*'\n");
fprintf(stderr, " opareport -o extlinks -F 'linkdetpat:*core ISL*'\n");
fprintf(stderr, " opareport -o extlinks -F 'portdetpat:*mgmt*'\n");
fprintf(stderr, " opareport -o links -F mtucap:2048\n");
fprintf(stderr, " opareport -o nodes -F sm\n");
fprintf(stderr, " opareport -o nodes -F 'smdetpat:primary*'\n");
fprintf(stderr, " opareport -o nodes -F 'route:node:duster hfi1_0:node:cuda hfi1_0'\n");
fprintf(stderr, " opareport -o nodes -F \\\n");
fprintf(stderr, " 'route:node:duster hfi1_0:port:1:node:cuda hfi1_0:port:2'\n");
fprintf(stderr, " opareport -o treepathusage -F nodepairpatfile:FILENAME\n");
fprintf(stderr, " opareport -o pathusage -F nodepatfile:FILENAME\n");
fprintf(stderr, " opareport -s -o snapshot > file\n");
fprintf(stderr, " opareport -o topology > topology.xml\n");
fprintf(stderr, " opareport -o errors -X file\n");
fprintf(stderr, " opareport -s --begin \"2 days ago\"\n");
fprintf(stderr, " opareport -s --begin \"12:30\" --end \"14:00\"\n");
fprintf(stderr, " opareport -o linkinfo -x > file\n");
exit(0);
}
void Usage(void)
{
fprintf(stderr, "Usage: opareport [-v][-q] [-o report] [-d detail] [-x] [-s] [-i seconds] [-C]\n");
fprintf(stderr, " [-b date_time] [-e date_time]\n");
fprintf(stderr, " or\n");
fprintf(stderr, " opareport --help\n");
fprintf(stderr, " --help - produce full help text\n");
fprintf(stderr, " -v/--verbose - verbose output\n");
fprintf(stderr, " -q/--quiet - disable progress reports\n");
fprintf(stderr, " -o/--output report - report type for output\n");
fprintf(stderr, " -d/--detail level - level of detail 0-n for output, default is 2\n");
fprintf(stderr, " -x/--xml - output in xml\n");
fprintf(stderr, " -s/--stats - get performance stats for all ports\n");
fprintf(stderr, " -i/--interval seconds - obtain performance stats over interval seconds\n");
fprintf(stderr, " clears all stats, waits interval seconds,\n");
fprintf(stderr, " then generates report. Implies -s\n");
fprintf(stderr, " -b/--begin date_time - obtain past performance stats over interval\n");
fprintf(stderr, " beginning at date_time. Implies -s\n");
fprintf(stderr, " -e/--end date_time - obtain past performance stats over interval\n");
fprintf(stderr, " ending at date_time. Implies -s\n");
fprintf(stderr, " -C/--clear - clear performance stats for all ports\n");
fprintf(stderr, " - only stats with error thresholds are cleared\n");
fprintf(stderr, " - clear occurs after generating report\n");
fprintf(stderr, "Report Types (abridged):\n");
fprintf(stderr, " comps - summary of all systems and SMs in fabric\n");
fprintf(stderr, " brcomps - brief summary of all systems and SMs in fabric\n");
fprintf(stderr, " nodes - summary of all node types and SMs in fabric\n");
fprintf(stderr, " brnodes - brief summary of all node types and SMs in\n");
fprintf(stderr, " fabric\n");
fprintf(stderr, " ious - summary of all IO Units in fabric\n");
fprintf(stderr, " lids - summary of all LIDs in fabric\n");
fprintf(stderr, " links - summary of all links\n");
fprintf(stderr, " extlinks - summary of links external to systems\n");
fprintf(stderr, " slowlinks - summary of links running slower than expected\n");
fprintf(stderr, " slowconfiglinks - summary of links configured to run slower than\n");
fprintf(stderr, " supported includes slowlinks\n");
fprintf(stderr, " slowconnlinks - summary of links connected with mismatched speed\n");
fprintf(stderr, " potential includes slowconfiglinks\n");
fprintf(stderr, " misconfiglinks - summary of links configured to run slower than\n");
fprintf(stderr, " supported\n");
fprintf(stderr, " misconnlinks - summary of links connected with mismatched speed\n");
fprintf(stderr, " potential\n");
fprintf(stderr, " errors - summary of links whose errors exceed counts in\n");
fprintf(stderr, " config file\n");
fprintf(stderr, " otherports - summary of ports not connected to this fabric\n");
fprintf(stderr, " all - comp, nodes, ious, links, extlinks,\n");
fprintf(stderr, " slowconnlinks, and error reports\n");
fprintf(stderr, " none - no report, useful if just want to clear stats\n");
fprintf(stderr, "Examples:\n");
fprintf(stderr, " opareport -o comps -d 3\n");
fprintf(stderr, " opareport -o errors -o slowlinks\n");
exit(2);
}
int parse(const char* filename)
{
FILE *fp = NULL;
char param[80];
unsigned long long threshold;
int ret;
char buffer[81];
int skipping = 0;
fp = fopen(filename, "r");
if (fp == NULL) {
fprintf(stderr, "opareport: Can't open %s: %s\n", filename, strerror(errno));
return -1;
}
while (NULL != fgets(buffer, sizeof(buffer), fp))
{
// just ignore long lines
if (buffer[strlen(buffer)-1] != '\n') {
skipping=1;
continue;
}
if (skipping) {
skipping = 0;
continue;
}
ret = sscanf(buffer, "%70s\n", param);
if (ret != 1)
continue; // blank line
if ( param[0]=='#')
continue; // ignore comments
if (strcmp(param, "Threshold") == 0) {
char compare[21];
ret = sscanf(buffer,"%70s %20s\n", param, compare);
if (ret != 2) {
fprintf(stderr, "opareport: Invalid Config Line: %s, ignoring\n", buffer);
continue;
}
if (strcmp(compare, "Greater") == 0) {
g_threshold_compare = 0;
} else if (strcmp(compare, "Equal") == 0) {
g_threshold_compare = 1;
} else {
fprintf(stderr, "opareport: Invalid Threshold: %s, ignoring\n", compare);
}
continue;
}
ret = sscanf(buffer, "%70s %llu\n", param, &threshold);
if (ret == 2) {
if (param[0]=='#') {
// ignore comments
} else if (strcmp(param,"LinkQualityIndicator") == 0) {
if (threshold > 5) {
fprintf(stderr, "opareport: LinkQualityIndicator max threshold setting is 5, ignoring: %llu\n", threshold);
} else {
g_Thresholds.lq.s.linkQualityIndicator = threshold;
/* can't be cleared. */
}
} else if (strcmp(param,"NumLanesDown") == 0) {
if (threshold > 4) {
fprintf(stderr, "opareport: NumLanesDown max threshold setting is 4, ignoring: %llu\n", threshold);
} else {
g_Thresholds.lq.s.numLanesDown = threshold;
}
#define PARSE_THRESHOLD(field, sel, name, max) \
if (strcmp(param, #name) == 0) { \
if (threshold > (max)) { \
fprintf(stderr, "opareport: " #name " max threshold is %u, ignoring: %llu\n", (max), threshold); \
} else { \
g_Thresholds.field = threshold; \
if (threshold) { \
g_CounterSelectMask.CounterSelectMask.s.sel = 1; \
} \
} \
}
#define PARSE_THRESHOLD64(field, sel, name) \
if (strcmp(param, #name) == 0) { \
if (threshold >= UINT64_MAX) { \
fprintf(stderr, "opareport: " #name " max threshold is %llu, ignoring: %llu\n",(unsigned long long)UINT64_MAX-1, threshold); \
} else { \
g_Thresholds.field = threshold; \
if (threshold) { \
g_CounterSelectMask.CounterSelectMask.s.sel = 1; \
} \
} \
}
#define PARSE_MB_THRESHOLD(field, sel, name) \
if (strcmp(param, #name) == 0) { \
if (threshold > ((1ULL << 63)-1)/(FLITS_PER_MB/2)) { \
fprintf(stderr, "opareport: " #name " max threshold is %llu, ignoring: %llu\n", ((1ULL << 63)-1)/(FLITS_PER_MB/2), threshold); \
} else { \
threshold = threshold * FLITS_PER_MB; \
g_Thresholds.field = threshold; \
if (threshold) { \
g_CounterSelectMask.CounterSelectMask.s.sel = 1; \
} \
} \
}
// Data movement
} else PARSE_MB_THRESHOLD(portXmitData, PortXmitData, XmitData)
else PARSE_MB_THRESHOLD(portRcvData, PortRcvData, RcvData)
else PARSE_THRESHOLD64(portXmitPkts, PortXmitPkts, XmitPkts)
else PARSE_THRESHOLD64(portRcvPkts, PortRcvPkts, RcvPkts)
else PARSE_THRESHOLD64(portMulticastXmitPkts, PortMulticastXmitPkts, MulticastXmitPkts)
else PARSE_THRESHOLD64(portMulticastRcvPkts, PortMulticastRcvPkts, MulticastRcvPkts)
// Signal Integrity and Node/Link Stability
// LinkQualityIndicator parsed above
else PARSE_THRESHOLD(uncorrectableErrors, UncorrectableErrors, UncorrectableErrors, 255)
else PARSE_THRESHOLD(linkDowned, LinkDowned, LinkDowned, UINT_MAX)
else PARSE_THRESHOLD64(portRcvErrors, PortRcvErrors, RcvErrors)
else PARSE_THRESHOLD64(excessiveBufferOverruns, ExcessiveBufferOverruns, ExcessiveBufferOverruns)
else PARSE_THRESHOLD64(fmConfigErrors, FMConfigErrors, FMConfigErrors)
else PARSE_THRESHOLD(linkErrorRecovery, LinkErrorRecovery, LinkErrorRecovery, UINT_MAX)
else PARSE_THRESHOLD64(localLinkIntegrityErrors, LocalLinkIntegrityErrors, LocalLinkIntegrityErrors)
else PARSE_THRESHOLD64(portRcvRemotePhysicalErrors, PortRcvRemotePhysicalErrors, RcvRemotePhysicalErrors)
// Security
else PARSE_THRESHOLD64(portXmitConstraintErrors, PortXmitConstraintErrors, XmitConstraintErrors)
else PARSE_THRESHOLD64(portRcvConstraintErrors, PortRcvConstraintErrors, RcvConstraintErrors)
// Routing or Down nodes still being sent to
else PARSE_THRESHOLD64(portRcvSwitchRelayErrors, PortRcvSwitchRelayErrors, RcvSwitchRelayErrors)
else PARSE_THRESHOLD64(portXmitDiscards, PortXmitDiscards, XmitDiscards)
// Congestion
else PARSE_THRESHOLD64(swPortCongestion, SwPortCongestion, CongDiscards)
else PARSE_THRESHOLD64(portRcvFECN, PortRcvFECN, RcvFECN)
else PARSE_THRESHOLD64(portRcvBECN, PortRcvBECN, RcvBECN)
else PARSE_THRESHOLD64(portMarkFECN, PortMarkFECN, MarkFECN)
else PARSE_THRESHOLD64(portXmitTimeCong, PortXmitTimeCong, XmitTimeCong)
else PARSE_THRESHOLD64(portXmitWait, PortXmitWait, XmitWait)
// Bubbles
else PARSE_THRESHOLD64(portXmitWastedBW, PortXmitWastedBW, XmitWastedBW)
else PARSE_THRESHOLD64(portXmitWaitData, PortXmitWaitData, XmitWaitData)
else PARSE_THRESHOLD64(portRcvBubble, PortRcvBubble, RcvBubble)
#undef PARSE_THRESHOLD
#undef PARSE_MB_THRESHOLD
else {
fprintf(stderr, "opareport: Invalid parameter: %s, ignoring\n", param);
}
} else {
fprintf(stderr, "opareport: Invalid Config Line: %s, ignoring\n", buffer);
}
}
fclose(fp);
return 0;
}
// convert a output type argument to the proper constant
report_t checkOutputType(const char* name)
{
if (0 == strcmp(optarg, "comps")) {
return REPORT_COMP;
} else if (0 == strcmp(optarg, "brcomps")) {
return REPORT_BRCOMP;
} else if (0 == strcmp(optarg, "nodes")) {
return REPORT_NODES;
} else if (0 == strcmp(optarg, "brnodes")) {
return REPORT_BRNODES;
} else if (0 == strcmp(optarg, "ious")) {
return REPORT_IOUS;
} else if (0 == strcmp(optarg, "linkinfo")) {
return REPORT_LINKINFO;
} else if (0 == strcmp(optarg, "links")) {
return REPORT_LINKS;
} else if (0 == strcmp(optarg, "extlinks")) {
return REPORT_EXTLINKS;
} else if (0 == strcmp(optarg, "filinks")) {
return REPORT_FILINKS;
} else if (0 == strcmp(optarg, "islinks")) {
return REPORT_ISLINKS;
} else if (0 == strcmp(optarg, "extislinks")) {
return REPORT_EXTISLINKS;
} else if (0 == strcmp(optarg, "slowlinks")) {
return REPORT_SLOWLINKS;
} else if (0 == strcmp(optarg, "slowconfiglinks")) {
return REPORT_SLOWCONFIGLINKS;
} else if (0 == strcmp(optarg, "slowconnlinks")) {
return REPORT_SLOWCONNLINKS;
} else if (0 == strcmp(optarg, "misconfiglinks")) {
return REPORT_MISCONFIGLINKS;
} else if (0 == strcmp(optarg, "misconnlinks")) {
return REPORT_MISCONNLINKS;
} else if (0 == strcmp(optarg, "errors")) {
return REPORT_ERRORS;
} else if (0 == strcmp(optarg, "otherports")) {
return REPORT_OTHERPORTS;
} else if (0 == strcmp(optarg, "verifylinks")) {
return REPORT_VERIFYLINKS;
} else if (0 == strcmp(optarg, "verifyextlinks")) {
return REPORT_VERIFYEXTLINKS;
} else if (0 == strcmp(optarg, "verifyfilinks")) {
return REPORT_VERIFYFILINKS;
} else if (0 == strcmp(optarg, "verifyislinks")) {
return REPORT_VERIFYISLINKS;
} else if (0 == strcmp(optarg, "verifyextislinks")) {
return REPORT_VERIFYEXTISLINKS;
} else if (0 == strcmp(optarg, "verifynodes")) {
return REPORT_VERIFYFIS|REPORT_VERIFYSWS;
} else if (0 == strcmp(optarg, "verifyfis")) {
return REPORT_VERIFYFIS;
} else if (0 == strcmp(optarg, "verifysws")) {
return REPORT_VERIFYSWS;
} else if (0 == strcmp(optarg, "verifysms")) {
return REPORT_VERIFYSMS;
} else if (0 == strcmp(optarg, "verifyall")) {
/* verifylinks is a superset of verifyextlinks, verifyfilinks, */
/* verifyislinks, verifyextislinks */
return REPORT_VERIFYFIS|REPORT_VERIFYSWS|REPORT_VERIFYLINKS|REPORT_VERIFYSMS;
} else if (0 == strcmp(optarg, "route")) {
return REPORT_ROUTE;
} else if (0 == strcmp(optarg, "none")) {
return REPORT_SKIP;
} else if (0 == strcmp(optarg, "sizes")) {
return REPORT_SIZES;
} else if (0 == strcmp(optarg, "snapshot")) {
return REPORT_SNAPSHOT;
} else if (0 == strcmp(optarg, "lids")) {
return REPORT_LIDS;
} else if (0 == strcmp(optarg, "linear")) {
return REPORT_LINEARFDBS;
} else if (0 == strcmp(optarg, "mcast")) {
return REPORT_MCASTFDBS;
} else if (0 == strcmp(optarg, "mcgroups")) {
return REPORT_MCGROUPS;
} else if (0 == strcmp(optarg, "vfinfo")) {
return REPORT_VFINFO;
} else if (0 == strcmp(optarg, "validatemcroutes")) {
return REPORT_VALIDATEMCROUTES;
} else if (0 == strcmp(optarg, "portusage")) {
return REPORT_PORTUSAGE;
} else if (0 == strcmp(optarg, "lidusage")) {
return REPORT_LIDUSAGE;
} else if (0 == strcmp(optarg, "pathusage")) {
return REPORT_PATHUSAGE;
} else if (0 == strcmp(optarg, "treepathusage")) {
return REPORT_TREEPATHUSAGE;
} else if (0 == strcmp(optarg, "validateroutes")) {
return REPORT_VALIDATEROUTES;
} else if (0 == strcmp(optarg, "validatevlroutes")) {
return REPORT_VALIDATEVLROUTES;
} else if (0 == strcmp(optarg, "validatecreditloops")) {
return REPORT_VALIDATECREDITLOOPS;
} else if (0 == strcmp(optarg, "validatevlcreditloops")) {
return REPORT_VALIDATEVLCREDITLOOPS;
} else if (0 == strcmp(optarg, "bfrctrl")) {
return REPORT_BUFCTRLTABLES;
} else if (0 == strcmp(optarg, "portgroups")) {
return REPORT_PORTGROUPS;
} else if (0 == strcmp(optarg, "validatepgs")) {
return REPORT_VERIFYPGS;
} else if (0 == strcmp(optarg, "vfmember")) {
return REPORT_VFMEMBER;
} else if (0 == strcmp(optarg, "dgmember")) {
return REPORT_DGMEMBER;
} else if (0 == strcmp(optarg, "quarantinednodes")) {
return REPORT_QUARANTINE_NODES;
} else if (0 == strcmp(optarg, "topology")) {
return REPORT_TOPOLOGY;
} else if (0 == strcmp(optarg, "cablehealth")) {
return REPORT_CABLEHEALTH;
} else if (0 == strcmp(optarg, "all")) {
/* note we omit brcomp and brnodes since comp and nodes is superset */
/* similarly links is a suprset of filinks, islinks, extislinks */
/* omit snapshot */
return REPORT_COMP|REPORT_NODES|REPORT_IOUS|REPORT_LINKS
|REPORT_EXTLINKS|REPORT_SLOWCONNLINKS|REPORT_ERRORS;
} else {
fprintf(stderr, "opareport: Invalid Output Type: %s\n", name);
Usage();
// NOTREACHED
return 0;
}
}
int main(int argc, char ** argv)
{
FSTATUS fstatus;
int c;
uint8 hfi = 0;
uint8 port = 0;
boolean gothfi=FALSE, gotport=FALSE;
Format_t format = FORMAT_TEXT;
int detail = 2;
int index;
report_t report = REPORT_NONE;
int stats = 0; // get port stats
int routes = 0; // get routing FDB
int fl_vlqos = 0; // get QOS VL-related tables
int bfrctrl = 0; // get Buffer Control Tables
int mcgroups = 0; // get multicast group members
char *config_file = CONFIG_FILE;
char *route_src = NULL;
char *route_dest = NULL;
char *focus_arg = NULL;
Point focus;
uint32 temp;
FabricFlags_t sweepFlags = FF_NONE;
uint8 find_flag = FIND_FLAG_FABRIC; // always check fabric
Top_setcmdname("opareport");
PointInit(&focus);
g_quiet = ! isatty(2); // disable progress if stderr is not tty
// process command line arguments
while (-1 != (c = getopt_long(argc,argv, "vVAqh:p:o:d:PHNsri:CamK:MLc:S:D:F:xX:T:"
"Qb:e:", options, &index)))
{
switch (c)
{
case '$':
Usage_full();
// NOTREACHED
break;
case 'v':
g_verbose++;
if (g_verbose > 3) umad_debug(g_verbose-2);
break;
case 'q':
g_quiet = 1;
break;
case 'h': // hfi to issue query from
if (FSUCCESS != StringToUint8(&hfi, optarg, NULL, 0, TRUE)) {
fprintf(stderr, "opareport: Invalid HFI Number: %s\n", optarg);
Usage();
// NOTREACHED
}
gothfi=TRUE;
break;
case 'p': // port to issue query from
if (FSUCCESS != StringToUint8(&port, optarg, NULL, 0, TRUE)) {
fprintf(stderr, "opareport: Invalid Port Number: %s\n", optarg);
Usage();
// NOTREACHED
}
gotport=TRUE;
break;
case '!':
if (FSUCCESS != StringToInt32(&g_ms_timeout, optarg, NULL, 0, TRUE)) {
fprintf(stderr, "opareport: Invalid timeout value: %s\n", optarg);
Usage();
}
break;
case 'o': // select output record desired
report = (report_t) report | checkOutputType(optarg);
if (report & REPORT_ERRORS)
stats = 1;
if (report & (REPORT_MCGROUPS | REPORT_SNAPSHOT | REPORT_VALIDATEMCROUTES))
mcgroups = 1;
if ( report & ( REPORT_LINEARFDBS | REPORT_MCASTFDBS |
REPORT_PORTUSAGE | REPORT_LIDUSAGE |
REPORT_PATHUSAGE | REPORT_TREEPATHUSAGE |
REPORT_VALIDATEROUTES | REPORT_VALIDATECREDITLOOPS | REPORT_VALIDATEMCROUTES |
REPORT_PORTGROUPS | REPORT_VERIFYPGS |
REPORT_VALIDATEVLCREDITLOOPS | REPORT_VALIDATEVLROUTES ) )
routes = 1;
if (report & REPORT_BUFCTRLTABLES)
bfrctrl = 1;
if (report & (REPORT_VALIDATEVLCREDITLOOPS | REPORT_VALIDATEVLROUTES )) {
fl_vlqos = 1;
g_use_scsc = 1;
}
if (report & REPORT_VFMEMBER)
fl_vlqos = 1;
if (report & (REPORT_VERIFYFIS|REPORT_VERIFYSWS))
find_flag |= FIND_FLAG_ENODE;
if (report & REPORT_VERIFYSMS)
find_flag |= FIND_FLAG_ESM;
if (report & (REPORT_VERIFYLINKS|REPORT_VERIFYEXTLINKS
|REPORT_VERIFYFILINKS|REPORT_VERIFYISLINKS
|REPORT_VERIFYEXTISLINKS))
find_flag |= FIND_FLAG_ELINK;
if (report & REPORT_CABLEHEALTH)
sweepFlags |= FF_SMADIRECT|FF_CABLELOWPAGE;
break;
case 'd': // detail level
if (FSUCCESS != StringToUint32(&temp, optarg, NULL, 0, TRUE)) {
fprintf(stderr, "opareport: Invalid Detail Level: %s\n", optarg);
Usage();
// NOTREACHED
}
detail = (int)temp;
break;
case 'P': // persistent data only
g_persist = 1;
break;
case 'H': // hardware data only
g_hard = 1;
break;
case 'N': // omit names
g_noname = 1;
break;
case 's': // get performance stats
stats = 1;
break;
case 'i': // get performance stats over interval
if (FSUCCESS != StringToUint32(&temp, optarg, NULL, 0, TRUE)) {
fprintf(stderr, "opareport: Invalid Interval: %s\n", optarg);
Usage();
// NOTREACHED
}
g_interval = (int)temp;
break;
case 'C': // clear all monitored performance stats
g_clearstats = 1;
break;
case 'a': // clear all performance stats
g_clearallstats = 1;
break;
case 'm': // access fabric information through direct SMA
sweepFlags |= FF_SMADIRECT;
break;
case 'M': // access performance stats through direct PMA
sweepFlags |= FF_PMADIRECT;
break;
case 'A': // get PortInfo for all switch ports, including down ones
sweepFlags |= FF_DOWNPORTINFO;
break;
case 'r': // get routing FDBs
routes = 1;
break;
case 'L': // limit to specific ports
g_limitstats = 1;
break;
case 'c': // config file for thresholds in errors report
config_file = optarg;
break;
case 'S': // source for trace route
if (route_src) {
fprintf(stderr, "opareport: -S option may only be specified once\n");
Usage();
// NOTREACHED
}
route_src = optarg;
break;
case 'D': // dest for trace route
if (route_dest) {
fprintf(stderr, "opareport: -D option may only be specified once\n");
Usage();
// NOTREACHED
}
route_dest = optarg;
break;
case 'F': // focus for report
if (focus_arg) {
fprintf(stderr, "opareport: -F option may only be specified once\n");
Usage();
// NOTREACHED
}
focus_arg = optarg;
break;
case 'V': // get QOS VL-related tables
fl_vlqos = 1;
bfrctrl = 1;
break;
case 'x': // output in xml
format = FORMAT_XML;
break;
case 'X': // snapshot_input in xml
g_snapshot_in_file = optarg;
break;
case 'T': // topology_input in xml
g_topology_in_file = optarg;
break;
case 'Q': // do not include focus description in report
g_quietfocus = 1;
break;
case 'b':
if (FSUCCESS != StringToDateTime(&temp, optarg)) {
fprintf(stderr, "opareport: Invalid Date/Time: %s\n", optarg);
Usage();
// NOTREACHED
}
g_begin = temp;
break;
case 'e':
if (FSUCCESS != StringToDateTime(&temp, optarg)) {
fprintf(stderr, "opareport: Invalid Date/Time: %s\n", optarg);
Usage();
// NOTREACHED
}
g_end = temp;
break;
default:
fprintf(stderr, "opareport: Invalid option -%c\n", c);
Usage();
// NOTREACHED
break;
}
} /* end while */
if (optind < argc)
{
Usage();
// NOTREACHED
}
// check for incompatible reports
if (report & REPORT_TOPOLOGY) {
if((report != REPORT_TOPOLOGY)){
fprintf(stderr, "opareport: -o topology cannot be run with other reports\n");
Usage();
// NOTREACHED
} else {
format = FORMAT_XML;
}
}
if ((report & REPORT_SNAPSHOT) && (report != REPORT_SNAPSHOT)) {
fprintf(stderr, "opareport: -o snapshot cannot be run with other reports\n");
Usage();
// NOTREACHED
}
// check for missing required arguments
if ((report & REPORT_ROUTE) && route_dest == NULL) {
fprintf(stderr, "opareport: -o route require -D option\n");
Usage();
// NOTREACHED
}
// check for incompatible arguments
if (g_begin && g_end && (g_begin > g_end)){
fprintf(stderr, "opareport: begin time must be before end time\n");
Usage();
// NOTREACHED
}
// check for incompatible reports
if ((report & REPORT_CABLEHEALTH) && (report != REPORT_CABLEHEALTH)) {
fprintf(stderr, "opareport: -o cablehealth cannot be run with other reports.\n");
Usage();
// NOTREACHED
}
// check for incompatible arguments
if ((report & REPORT_CABLEHEALTH) && g_snapshot_in_file) {
fprintf(stderr, "opareport: -o cablehealth option is not permitted against a snapshot.\n");
Usage();
// NOTREACHED
}
// check for incompatible arguments
if ((report & REPORT_CABLEHEALTH) && (format == FORMAT_XML)) {
fprintf(stderr, "opareport: -o cablehealth option only supports CSV output\n");
Usage();
// NOTREACHED
}
// check for incompatible arguments
if ((report & REPORT_LINKINFO) && (format == FORMAT_XML)) {
fprintf(stderr, "opareport: -o linkinfo option does not support XML output\n");
Usage();
// NOTREACHED
}
// Warn for extraneous arguments and ignore them
if ((route_dest || route_src) && ! (report & REPORT_ROUTE)) {
fprintf(stderr, "opareport: -S or -D option given without -o route, ignoring -S and -D\n");
route_src = NULL;
route_dest = NULL;
}
if (focus_arg) {
char *name = "report";
int suppress = 0;
if (report & REPORT_ROUTE) { suppress = 1; name = "route"; }
if (report & REPORT_SNAPSHOT) { suppress = 1; name = "snapshot"; }
if (report & REPORT_MCGROUPS) { suppress = 1; name = "mcgroups"; }
if (report & REPORT_VALIDATEROUTES) { suppress = 1; name = "validateroutes"; }
if (report & REPORT_VALIDATECREDITLOOPS) { suppress = 1; name = "validatecreditloops"; }
if (report & REPORT_VALIDATEVLCREDITLOOPS) { suppress = 1; name = "validatevlcreditloops"; }
if (report & REPORT_VALIDATEMCROUTES) { suppress = 1; name = "validatemcroutes"; }
if (report & REPORT_VERIFYPGS) { suppress = 1; name = "validatepgs"; }
if (report & REPORT_SKIP) { suppress = 1; name = "none"; }
if (suppress) {
fprintf(stderr,"opareport: %s does not support -F option.\n", name);
fprintf(stderr," -F ignored for all reports.\n");
focus_arg = NULL;
}
}
if (report == REPORT_SNAPSHOT && g_limitstats) {
fprintf(stderr, "opareport: -L ignored for -o snapshot\n");
g_limitstats = 0;
}
if (g_limitstats && ! focus_arg) {
fprintf(stderr, "opareport: -L ignored when -F not specified\n");
g_limitstats = 0;
}
if ((report & REPORT_SNAPSHOT) && (g_noname || g_hard || g_persist)) {
fprintf(stderr, "opareport: -N, -H and -P ignored for -o snapshot\n");
g_noname = 0;
g_hard = 0;
g_persist = 0;
}
if ((report & REPORT_MCGROUPS ) && (sweepFlags & FF_SMADIRECT)) {
fprintf(stderr, "opareport: -m ignored for -o mcgroups\n");
}
if ((report & REPORT_VALIDATEMCROUTES ) && (sweepFlags & FF_SMADIRECT)) {
fprintf(stderr, "opareport: -m ignored for -o validatemcroutes\n");
}
//In a live cluster, implicitly fetch the routing tables when route report or route focus is requested with -m option
if (!g_snapshot_in_file && (sweepFlags & FF_SMADIRECT)&& ((report & REPORT_ROUTE ) || ( focus_arg && NULL != ComparePrefix(focus_arg, "route:"))))
routes = 1;
if ((report & REPORT_DGMEMBER) && g_snapshot_in_file) {
fprintf(stderr, "opareport: -o dgmember option is not permitted against a snapshot.\n");
Usage();
// NOTREACHED
}
if (g_snapshot_in_file && (g_interval || g_clearstats || g_clearallstats || g_begin || g_end)) {
fprintf(stderr, "opareport: -i, -C, -a, -b, and -e ignored for -X\n");
g_interval = 0;
g_clearstats = 0;
g_clearallstats = 0;
g_begin = 0;
g_end = 0;
}
if (g_snapshot_in_file) {
if (sweepFlags & FF_SMADIRECT)
fprintf(stderr, "opareport: -m ignored for -X\n");
if (sweepFlags & FF_PMADIRECT)
fprintf(stderr, "opareport: -M ignored for -X\n");
if (sweepFlags & FF_DOWNPORTINFO)
fprintf(stderr, "opareport: -A ignored for -X\n");
sweepFlags &= ~(FF_SMADIRECT|FF_PMADIRECT|FF_DOWNPORTINFO);
}
if (g_snapshot_in_file && stats) {
if (! (report & REPORT_ERRORS)) {
// -s must have been explicitly specified
fprintf(stderr, "opareport: -s ignored for -X\n");
}
stats = 0;
}
if (g_snapshot_in_file && (fl_vlqos || bfrctrl)) {
if (! (report & (REPORT_BUFCTRLTABLES|REPORT_VFINFO|REPORT_VFMEMBER))) {
// -V must have been explicitly specified
fprintf(stderr, "opareport: -V ignored for -X\n");
}
}
if (g_snapshot_in_file && routes) {
if ( ! ( report & ( REPORT_LINEARFDBS | REPORT_MCASTFDBS |
REPORT_PORTUSAGE | REPORT_LIDUSAGE | REPORT_PATHUSAGE |
REPORT_TREEPATHUSAGE | REPORT_VALIDATEROUTES | REPORT_VALIDATECREDITLOOPS |
REPORT_VALIDATEVLROUTES | REPORT_VALIDATEVLCREDITLOOPS | REPORT_VALIDATEMCROUTES) ) ) {
// -r must have been explicitly specified
fprintf(stderr, "opareport: -r ignored for -X\n");
}
}
if (g_limitstats && ! (report & (REPORT_ERRORS|REPORT_SNAPSHOT)) && ! g_clearstats && ! g_clearallstats && ! g_interval) {
fprintf(stderr, "opareport: -L ignored without -C, -a, -i, -o errors nor -o snapshot\n");
g_limitstats = 0;
}
if (g_interval && (g_hard || g_persist)) {
fprintf(stderr, "opareport: -i ignored with -H or -P\n");
g_interval = 0;
}
if ((report & REPORT_VFINFO) && detail > 2)
fl_vlqos = 1;
// check for unignored arguments which imply need to get stats
if (! g_snapshot_in_file && focus_arg && NULL != ComparePrefix(focus_arg, "linkqual"))
stats = 1; // using the linkqual focus option implies -s
if (g_interval || g_begin | g_end)
stats = 1;
// now that we have final value for "stats" option, make sure consistent
if ((sweepFlags & FF_DOWNPORTINFO) && ! (sweepFlags & FF_PMADIRECT)
&& (stats || g_interval || g_clearstats || g_clearallstats)) {
fprintf(stderr, "opareport: Use of -A requires performance stats be gathered directly (via -M)\n");
Usage();
// NOTREACHED
}
if (g_interval && focus_arg && NULL != ComparePrefix(focus_arg, "linkqual")) {
fprintf(stderr, "opareport: -i option not permitted in conjunction with -F linkqual, linkqualLE\n nor linkqualGE\n");
Usage();
// NOTREACHED
}
if (report == REPORT_NONE)
report = REPORT_BRNODES;
// Initialize Sweep Verbose option, for -X still used for Focus processing
fstatus = InitSweepVerbose(g_verbose?stderr:NULL);
if (fstatus != FSUCCESS) {
fprintf(stderr, "opareport: Initialize Verbose option (status=0x%x): %s\n", fstatus, iba_fstatus_msg(fstatus));
g_exitstatus = 1;
goto done;
}
// figure out which local port we will use to gather data
if (g_snapshot_in_file) {
if (gotport || gothfi)
fprintf(stderr, "opareport: -p and -h ignored for -X\n");
} else {
#ifdef IB_STACK_IBACCESS
// we must initialize user mode iba library first
fstatus = iba_init();
if (fstatus != FSUCCESS) {
fprintf(stderr, "opareport: iba_init failed (status=0x%x): %s\n", fstatus, iba_fstatus_msg(fstatus));
g_exitstatus = 1;
goto done;
}
#endif
// find portGuid for hfi/port specified
{
uint32 caCount, portCount;
fstatus = iba_get_portguid(hfi, port, NULL, &g_portGuid, NULL, &g_portAttrib,
&caCount, &portCount);
if (FNOT_FOUND == fstatus) {
fprintf(stderr, "opareport: %s\n",
iba_format_get_portguid_error(hfi, port, caCount, portCount));
g_exitstatus = 1;
goto done;
} else if (FSUCCESS != fstatus) {
fprintf(stderr, "opareport: iba_get_portguid Failed: %s\n",
iba_fstatus_msg(fstatus));
g_exitstatus = 1;
goto done;
}
DBGPRINT("USING SUBNET PREFIX 0x%016"PRIx64"\n", g_portAttrib->GIDTable[0].Type.Global.SubnetPrefix);
}
}
// get thresholds config file
if ((report & REPORT_ERRORS) || g_clearstats) {
if (0 != parse(config_file)) {
g_exitstatus = 1;
goto done;
}
}
// get the fabric data
if (g_snapshot_in_file) {
if (FSUCCESS != Xml2ParseSnapshot(g_snapshot_in_file, g_quiet, &g_Fabric, FF_NONE, 0)) {
g_exitstatus = 1;
goto done;
}
} else {
if (FSUCCESS != InitMad(g_portGuid, g_verbose?stderr:NULL)) {
g_exitstatus = 1;
goto done;
}
if (sweepFlags & FF_SMADIRECT) {
if (FSUCCESS != InitSmaMkey(0)) {
g_exitstatus = 1;
goto done;
}
}
if (FSUCCESS != Sweep(g_portGuid, &g_Fabric, sweepFlags, SWEEP_ALL, g_quiet, g_ms_timeout)) {
g_exitstatus = 1;
goto done;
}
}
// parse topology input file and cross reference to fabric data
if (g_topology_in_file) {
if (FSUCCESS != Xml2ParseTopology(g_topology_in_file, g_quiet, &g_Fabric, TOPOVAL_NONE)) {
g_exitstatus = 1;
goto done_fabric;
}
//if (g_verbose)
// Xml2PrintTopology(stdout, &g_Fabric); // for debug
}
// we can't do a linkqual focus until after the port counters have been collected
// nor can we do route focus with -m until FDBs are collected. So will handle route focus with and without -m later.
if (focus_arg && (NULL == ComparePrefix(focus_arg, "linkqual")) && (NULL == ComparePrefix(focus_arg, "route"))) {
char *p;
FSTATUS status;
status = ParseFocusPoint(g_snapshot_in_file?0:g_portGuid,
&g_Fabric, focus_arg, &focus, find_flag, &p, TRUE);
if (FINVALID_PARAMETER == status || (FSUCCESS == status && *p != '\0')) {
fprintf(stderr, "opareport: Invalid Point Syntax: '%s'\n", focus_arg);
fprintf(stderr, "opareport: %*s^\n", (int)(p-focus_arg), "");
PointDestroy(&focus);
Usage_full();
// NOTREACHED
}
if (FSUCCESS != status) {
fprintf(stderr, "opareport: Unable to resolve Point: '%s': %s\n", focus_arg, iba_fstatus_msg(status));
g_exitstatus = 1;
goto done_fabric;
}
}
// output the desired reports
if (g_interval) {
(void)ClearAllPortCountersAndShow(g_portGuid, &focus, TRUE, format, report == REPORT_SNAPSHOT);
PROGRESS_PRINT(TRUE, "Waiting %d seconds", g_interval);
sleep(g_interval);
}
if (!g_snapshot_in_file && stats && ! g_hard && ! g_persist) {
if (FSUCCESS != GetAllPortCounters(g_portGuid, g_portAttrib->GIDTable[0],
&g_Fabric, &focus, g_limitstats, g_quiet, g_begin, g_end)) {
g_exitstatus = 1;
report &= ~REPORT_ERRORS;
fprintf(stderr, "opareport: Failed to Get Port Counters\n");
}
}
// get other optional fabric data
// now that the port counters have been collected, we can do the link quality focus
if (focus_arg && NULL != ComparePrefix(focus_arg, "linkqual")) {
if (!(g_Fabric.flags & FF_STATS) && g_snapshot_in_file ) {
fprintf(stderr, "opareport: '-F linkqual' with snapshot must be created with -s option\n");
Usage();
// NOTREACHED
}
char *p;
FSTATUS status;
// use FIND_FLAG_FABRIC, no use checking anything other than fabric
status = ParseFocusPoint(g_snapshot_in_file?0:g_portGuid,
&g_Fabric, focus_arg, &focus, FIND_FLAG_FABRIC, &p, TRUE);
if (FINVALID_PARAMETER == status || (FSUCCESS == status && *p != '\0')) {
fprintf(stderr, "opareport: Invalid Point Syntax: '%s'\n", focus_arg);
fprintf(stderr, "opareport: %*s^\n", (int)(p-focus_arg), "");
PointDestroy(&focus);
Usage_full();
// NOTREACHED
}
if (FSUCCESS != status) {
fprintf(stderr, "opareport: Unable to resolve Point: '%s': %s\n", focus_arg, iba_fstatus_msg(status));
g_exitstatus = 1;
goto done_fabric;
}
}
if ((!g_snapshot_in_file && routes && ! g_hard && ! g_persist) || (g_snapshot_in_file && (report & REPORT_PORTUSAGE))) {
// Scanning through all switches is required to get LinearFDB to tabulate routes for path usage reports. It is not limited to switches in focus.
if (!g_snapshot_in_file && (FSUCCESS != GetAllFDBs(g_portGuid, &g_Fabric,
((report & REPORT_PATHUSAGE) || ((report & REPORT_TREEPATHUSAGE)))?NULL:&focus, g_quiet))) {
g_exitstatus = 1;
goto done_fabric;
}
/* Traverse the switches and find the largest LFT */
LIST_ITEM *p;
for (p=QListHead(&g_Fabric.AllSWs); p != NULL; p = QListNext(&g_Fabric.AllSWs, p)) {
NodeData *nodep;
SwitchData *switchp;
nodep = QListObj(p);
switchp = nodep->switchp;
if (!switchp || !switchp->LinearFDB) continue;
if (switchp->LinearFDBSize > g_max_lft) g_max_lft = switchp->LinearFDBSize;
}
}
// now that the FDBs have been fetched for -m option, , we can do the route focus
if (focus_arg && NULL != ComparePrefix(focus_arg, "route")) {
char *p;
FSTATUS status;
if ( !(g_Fabric.flags & FF_ROUTES) && g_snapshot_in_file ) {
fprintf(stderr, "opareport: '-F route:' with snapshot must be created with -r option\n");
Usage();
// NOTREACHED
}
status = ParseFocusPoint(g_snapshot_in_file?0:g_portGuid,
&g_Fabric, focus_arg, &focus, find_flag, &p, TRUE);
if (FINVALID_PARAMETER == status || (FSUCCESS == status && *p != '\0')) {
fprintf(stderr, "opareport: Invalid Point Syntax: '%s'\n", focus_arg);
fprintf(stderr, "opareport: %*s^\n", (int)(p-focus_arg), "");
PointDestroy(&focus);
Usage_full();
// NOTREACHED
}
if (FSUCCESS != status) {
fprintf(stderr, "opareport: Unable to resolve Point: '%s': %s\n", focus_arg, iba_fstatus_msg(status));
g_exitstatus = 1;
goto done_fabric;
}
}
if (!g_snapshot_in_file && fl_vlqos && ! g_hard && ! g_persist) {
if (FSUCCESS != GetAllPortVLInfo(g_portGuid, &g_Fabric, &focus, g_quiet, &g_use_scsc)) {
g_exitstatus = 1;
goto done_fabric;
}
}
if (!g_snapshot_in_file && bfrctrl && ! g_hard && ! g_persist) {
if (FSUCCESS != GetAllBCTs(g_portGuid, &g_Fabric, &focus, g_quiet)) {
g_exitstatus = 1;
goto done_fabric;
}
}
if (!g_snapshot_in_file && mcgroups && ! g_hard && ! g_persist) {
if (FSUCCESS != GetAllMCGroups(g_portGuid, &g_Fabric, &focus, g_quiet)) {
g_exitstatus = 1;
goto done_fabric;
}
}
if (format == FORMAT_XML && ! (report & REPORT_SNAPSHOT)) {
// TBD - use IXml functions for XML output
char datestr[80] = "";
int i;
printf("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n");
Top_formattime(datestr, sizeof(datestr), g_Fabric.time);
printf("<Report date=\"%s\" unixtime=\"%ld\" options=\"", datestr, g_Fabric.time);
for (i=1; i<argc; i++)
printf("%s%s", i>1?" ":"", argv[i]);
printf("\" >\n");
}
if (report & REPORT_COMP)
ShowComponentReport(&focus, format, 0, detail);
if (report & REPORT_BRCOMP)
ShowComponentBriefReport(&focus, format, 0, detail);
if (report & REPORT_NODES)
ShowNodeTypeReport(&focus, format, 0, detail);
if (report & REPORT_BRNODES)
ShowNodeTypeBriefReport(&focus, format, REPORT_BRNODES, 0, detail);
if (report & REPORT_IOUS)
ShowAllIOUReport(&focus, format, 0, detail);
if (report & REPORT_LINKS)
ShowLinksReport(&focus, REPORT_LINKS, format, 0, detail);
if (report & REPORT_EXTLINKS)
ShowLinksReport(&focus, REPORT_EXTLINKS, format, 0, detail);
if (report & REPORT_FILINKS)
ShowLinksReport(&focus, REPORT_FILINKS, format, 0, detail);
if (report & REPORT_ISLINKS)
ShowLinksReport(&focus, REPORT_ISLINKS, format, 0, detail);
if (report & REPORT_EXTISLINKS)
ShowLinksReport(&focus, REPORT_EXTISLINKS, format, 0, detail);
if (report & REPORT_SLOWLINKS)
ShowSlowLinkReport(LINK_EXPECTED_REPORT, FALSE, &focus, format, 0, detail);
if (report & REPORT_SLOWCONFIGLINKS)
ShowSlowLinkReport(LINK_CONFIG_REPORT, FALSE, &focus, format, 0, detail);
if (report & REPORT_SLOWCONNLINKS)
ShowSlowLinkReport(LINK_CONN_REPORT, FALSE, &focus, format, 0, detail);
if (report & REPORT_MISCONFIGLINKS)
ShowSlowLinkReport(LINK_CONFIG_REPORT, TRUE, &focus, format, 0, detail);
if (report & REPORT_MISCONNLINKS)
ShowSlowLinkReport(LINK_CONN_REPORT, TRUE, &focus, format, 0, detail);
if (report & REPORT_ERRORS)
ShowLinkErrorReport(&focus, format, 0, detail);
if (report & REPORT_OTHERPORTS)
ShowOtherPortsReport(&focus, format, 0, detail);
if (report & REPORT_VERIFYFIS)
ShowVerifyNodesReport(&focus, STL_NODE_FI, format, 0, detail);
if (report & REPORT_VERIFYSWS)
ShowVerifyNodesReport(&focus, STL_NODE_SW, format, 0, detail);
if (report & REPORT_VERIFYSMS)
ShowVerifySMsReport(&focus, format, 0, detail);
if (report & REPORT_VERIFYLINKS)
ShowVerifyLinksReport(&focus, REPORT_VERIFYLINKS, format, 0, detail);
if (report & REPORT_VERIFYEXTLINKS)
ShowVerifyLinksReport(&focus, REPORT_VERIFYEXTLINKS, format, 0, detail);
if (report & REPORT_VERIFYFILINKS)
ShowVerifyLinksReport(&focus, REPORT_VERIFYFILINKS, format, 0, detail);
if (report & REPORT_VERIFYISLINKS)
ShowVerifyLinksReport(&focus, REPORT_VERIFYISLINKS, format, 0, detail);
if (report & REPORT_VERIFYEXTISLINKS)
ShowVerifyLinksReport(&focus, REPORT_VERIFYEXTISLINKS, format, 0, detail);
if (report & REPORT_TOPOLOGY) {
ShowNodeTypeBriefReport(&focus, format, REPORT_TOPOLOGY, 0, detail);
ShowLinksReport(&focus, REPORT_LINKS, format, 0, detail);
}
if (report & REPORT_ROUTE) {
Point point1, point2;
int skip = 0;
PointInit(&point1);
PointInit(&point2);
if (route_src) {
char *p;
if (FSUCCESS != (fstatus = ParsePoint(&g_Fabric, route_src, &point1, FIND_FLAG_FABRIC, &p)) || *p != '\0') {
PointDestroy(&point1);
PointDestroy(&point2);
if (FINVALID_PARAMETER == fstatus || (FSUCCESS == fstatus && *p != '\0')) {
fprintf(stderr, "opareport: Invalid Source Point Syntax: '%s'\n", route_src);
fprintf(stderr, "opareport: %*s^\n", (int)(p-route_src), "");
}
fprintf(stderr, "opareport: Unable to resolve Source Point: '%s': %s\n", route_src, iba_fstatus_msg(fstatus));
switch (format) {
case FORMAT_TEXT:
printf("%*sReport skipped: Invalid source point syntax: %s:%s\n",0,"",
route_src, iba_fstatus_msg(fstatus));
break;
case FORMAT_XML:
printf("%*s<!-- Report skipped: Invalid source point syntax: %s:%s -->\n",0,"",
route_src, iba_fstatus_msg(fstatus));
break;
default:
break;
}
goto done_route;
}
} else {
PortData *portp1 = FindPortGuid(&g_Fabric, g_portGuid);
if (! portp1) {
fprintf(stderr, "opareport: Local Port GUID Not Found: 0x%016"PRIx64"\n", g_portGuid);
fprintf(stderr, "opareport: Skipping trace route report\n");
skip = 1;
} else {
point1.Type = POINT_TYPE_SYSTEM;
point1.u.systemp = portp1->nodep->systemp;
if (! point1.u.systemp) {
fprintf(stderr, "opareport: System for Local Port GUID Not Found: 0x%016"PRIx64"\n", g_portGuid);
fprintf(stderr, "opareport: Skipping trace route report\n");
skip = 1;
}
}
}
if ((!skip) && route_dest) {
char *p;
if (FSUCCESS != (fstatus = ParsePoint(&g_Fabric, route_dest, &point2, FIND_FLAG_FABRIC, &p)) || *p != '\0') {
PointDestroy(&point1);
PointDestroy(&point2);
if (FINVALID_PARAMETER == fstatus || (FSUCCESS == fstatus && *p != '\0')) {
fprintf(stderr, "opareport: Invalid Dest Point Syntax: '%s'\n", route_dest);
fprintf(stderr, "opareport: %*s^\n", (int)(p-route_dest), "");
}
switch (format) {
case FORMAT_TEXT:
printf("%*sReport skipped: Invalid destination point syntax: %s:%s\n",0,"",
route_dest, iba_fstatus_msg(fstatus));
break;
case FORMAT_XML:
printf("%*s<!-- Report skipped: Invalid destination point syntax: %s:%s -->\n",0,"",
route_dest, iba_fstatus_msg(fstatus));
break;
default:
break;
}
goto done_route;
}
ShowRoutesReport(g_portGuid, &point1, &point2, format, 0, detail);
}
done_route:
PointDestroy(&point1);
PointDestroy(&point2);
}
if (report & REPORT_SIZES)
ShowSizesReport();
if (report == REPORT_SNAPSHOT) {
SnapshotOutputInfo_t info;
info.fabricp = &g_Fabric;
info.argc = argc;
info.argv = argv;
Xml2PrintSnapshot(stdout, &info);
}
if (report & REPORT_LIDS)
ShowAllLIDReport(&focus, format, 0, detail);
if (report & REPORT_LINEARFDBS)
ShowLinearFDBReport(&focus, format, 0, detail);
if (report & REPORT_MCASTFDBS)
ShowMulticastFDBReport(&focus, format, 0, detail);
if (report & REPORT_MCGROUPS)
ShowMulticastGroupsReport(format, 0, detail);
if (report & REPORT_PORTUSAGE)
ShowPortUsageReport(&focus, format, 0, detail);
if (report & REPORT_PATHUSAGE)
ShowPathUsageReport(&focus, format, 0, detail);
if (report & REPORT_TREEPATHUSAGE)
ShowTreePathUsageReport(&focus, format, 0, detail);
if (report & REPORT_VALIDATEROUTES || report & REPORT_VALIDATEVLROUTES) {
ShowValidateRoutesReport(format, 0, detail);
}
if (report & REPORT_VALIDATECREDITLOOPS || report & REPORT_VALIDATEVLCREDITLOOPS) {
ShowValidateCreditLoopsReport(format, 0, detail);
}
if (report & REPORT_VALIDATEMCROUTES) {
ShowValidateMCRoutesReport(format, 0, detail);
}
if (report & REPORT_VFINFO)
ShowVFInfoReport(&focus, format, 0, detail);
if (report & REPORT_PORTGROUPS)
ShowPGReport(&focus, format, 0, detail);
if (report & REPORT_VERIFYPGS)
ShowValidatePGReport(format, 0, detail);
// Undocumented LID usage report
if (report & REPORT_LIDUSAGE)
ShowLIDUsageReport(&focus, format, 0, detail);
if (report & REPORT_BUFCTRLTABLES)
ShowAllBCTReports(&focus, format, 0, detail);
if (report & REPORT_VFMEMBER)
ShowVFMemberReport(&focus, format, 0, detail);
if (report & REPORT_DGMEMBER)
ShowDGMemberReport(&focus, format, 0, detail);
if (report & REPORT_QUARANTINE_NODES)
ShowQuarantineNodeReport(&focus, format, 0, detail);
if (report & REPORT_CABLEHEALTH)
ShowCableHealthReport(&focus, format, 0, detail);
if (report & REPORT_LINKINFO)
ShowLinkInfoReport(&focus, format, 0, detail);
if (g_clearstats || g_clearallstats)
(void)ClearAllPortCountersAndShow(g_portGuid, &focus, g_clearallstats, format, report == REPORT_SNAPSHOT);
if (format == FORMAT_XML && ! (report & REPORT_SNAPSHOT)) {
printf("</Report>\n");
}
done_fabric:
DestroyFabricData(&g_Fabric);
done:
PointDestroy(&focus);
DestroyMad();
if (g_exitstatus == 2) {
Usage();
// NOTREACHED
}
return g_exitstatus;
}