/* BEGIN_ICS_COPYRIGHT7 ****************************************
Copyright (c) 2015-2020, 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] */
//===========================================================================//
// //
// FILE NAME //
// sm_userexits.c //
// //
// DESCRIPTION //
// This file contains the user exits as outlined in the design doc. //
// //
// DATA STRUCTURES //
// None //
// //
// FUNCTIONS //
// None //
// //
// DEPENDENCIES //
// ib_mad.h //
// ib_status.h //
// //
// //
//===========================================================================//
#include "os_g.h"
#include "ib_status.h"
#include "ib_mad.h"
#include "ib_macros.h"
#include "ib_sa.h"
#include "cs_g.h"
#include "mai_g.h"
#include "sm_l.h"
extern Lock_t tid_lock;
STL_LID loopPathLidStart = 0; // will be calculated to next 64 after max lid
STL_LID loopPathLidEnd=0;
int esmLoopTestOn = 0;
int esmLoopTestAllowAdaptiveRouting = 0;
int esmLoopTestFast = 0;
int esmLoopTestInjectNode = -1; // set to node index of switch to inject packets for or -1=all switches
int esmLoopTestNumPkts = 1;
int esmLoopTestPathLen = DEFAULT_LOOP_PATH_LENGTH;
int esmLoopTestMinISLRedundancy = 4; //min. number of different loops in which a single ISL should be included
uint32_t esmLoopTestTotalPktsInjected = 0;
uint8_t esmLoopTestInjectEachSweep = DEFAULT_LOOP_INJECT_EACH_SWEEP;
uint8_t esmLoopTestForceInject = 0;
uint8_t bkup_loop_path=0;
uint32_t bkup_path_loopweight=0;
extern void sm_forceSweep(const char* reason);
extern char * snprintfcat(char * buf, int * len, const char * format, ...);
typedef struct _Switches_Skip_Search {
uint32_t *nodes;
uint32_t count;
} Switches_Skip_Search_t;
typedef struct _PortLoopUsage {
uint8_t count;
uint8_t portno;
Node_t *neighbor;
} PortLoopUsage_t;
//---------------------------------------------------------------------------//
Status_t
sweep_userexit(SweepContext_t *sweep_context) {
IB_ENTER(__func__, 0, 0, 0, 0);
IB_EXIT(__func__, VSTATUS_OK);
return(VSTATUS_OK);
}
Status_t
forwarding_userexit(uint16_t *cost, int16_t *path) {
IB_ENTER(__func__, 0, 0, 0, 0);
IB_EXIT(__func__, VSTATUS_OK);
return(VSTATUS_OK);
}
Status_t
authorization_userexit(void) {
IB_ENTER(__func__, 0, 0, 0, 0);
IB_EXIT(__func__, VSTATUS_OK);
return(VSTATUS_OK);
}
Status_t
license_userexit(void) {
IB_ENTER(__func__, 0, 0, 0, 0);
IB_EXIT(__func__, VSTATUS_OK);
return(VSTATUS_OK);
}
static int checkForDupPath(Topology_t *top, uint16_t *nodeIdx, uint8_t *path) {
int i,j;
LoopPath_t *loopPath;
int dup = 0;
for (loopPath=top->loopPaths; loopPath != NULL && dup==0; loopPath = loopPath->next) {
if (nodeIdx[0] != loopPath->nodeIdx[0]) continue;
for (i=1, dup=1; i<=nodeIdx[0] && dup==1; i++) {
dup = 0;
for (j=1; j<=loopPath->nodeIdx[0]; j++) {
if (nodeIdx[i] == loopPath->nodeIdx[j] && path[i] == loopPath->path[j]) {
dup = 1;
break;
}
}
}
if (dup) {
/*IB_LOG_INFO_FMT(__func__,
"duplicate of loop path lid[0x%x] found.....", loopPath->lid);*/
return dup;
}
}
return dup;
}
static Status_t buildPathList(Topology_t *top, Node_t *node, Port_t *portp, uint16_t *nodeIdx, uint8_t *path) {
Status_t status=VSTATUS_OK;
LoopPath_t *loopPath=NULL, *lpLast=NULL, *lpTemp=NULL;
IB_ENTER(__func__, 0, 0, 0, 0);
if (!esmLoopTestFast) {
// check for duplicate paths
if (checkForDupPath(top, nodeIdx, path)) return(VSTATUS_OK);
}
// build up the path list
top->numLoopPaths++;
if ((status = vs_pool_alloc(&sm_pool, sizeof(LoopPath_t), (void *)&loopPath)) != VSTATUS_OK) {
IB_LOG_ERRORLX("can't allocate space for loop Path from node ", node->nodeInfo.NodeGUID);
return(VSTATUS_BAD);
}
memset(loopPath, 0, sizeof(LoopPath_t));
// move to end of loopPaths to add new one
if (top->loopPaths == NULL) {
top->loopPaths = loopPath;
} else {
lpTemp = top->loopPaths;
while (lpTemp != NULL) {
lpLast = lpTemp;
lpTemp = lpTemp->next;
}
lpLast->next = loopPath;
}
loopPathLidEnd = (loopPathLidEnd == 0) ? loopPathLidStart : (loopPathLidEnd+1);
loopPath->lid = loopPathLidEnd;
if (esmLoopTestFast) {
// With the faster loop test version, we do not find all loops exhaustively.
// In this scenario, to test both send/recv paths on each ISL, we need to
// inject packets both for forward (or clock-wise) direction and
// reverse (or anti-clockwise) direction
loopPathLidEnd++; //one more lid for reverse path
}
loopPath->startNodeno = node->index;
// start with path to node from SM node and add loop path
memcpy(loopPath->path, path, path[0]+1);
memcpy(loopPath->nodeIdx, nodeIdx, (nodeIdx[0]+1)*sizeof(uint16_t));
IB_EXIT(__func__, VSTATUS_OK);
return(VSTATUS_OK);
}
//
// update node lft to include loop paths for loop test
//
void
loopTest_userexit_updateLft(Topology_t *topop, Node_t *cnp) {
int i,j,ii=0;
LoopPath_t *loopPath;
Port_t *uePortp;
Node_t *nodep, *nr, *loopNode;
int nodeLftUpdatedForLoop;
Port_t *outPortp;
if (!esmLoopTestOn) return;
//
// update lft to include loop paths for loop test
//
if (smDebugPerf || sm_config.sm_debug_routing) {
IB_LOG_INFINI_INFO_FMT(__func__,
"updating LFT for node[%d:"FMT_U64"], topo->switch_head index=%d.....",
cnp->index, cnp->nodeInfo.NodeGUID, topop->switch_head->index);
}
for (loopPath=topop->loopPaths; loopPath != NULL; loopPath = loopPath->next) {
nodeLftUpdatedForLoop = 0;
// setup the node's loops first
for (j=1; j<=loopPath->path[0]; j++) {
if (cnp->index == loopPath->nodeIdx[j]) {
nodeLftUpdatedForLoop = 1;
// update lft for this lid for this switch
cnp->lft[loopPath->lid] = loopPath->path[j];
}
if (esmLoopTestFast) {
//update lft for the reverse path lid
outPortp = sm_find_port(topop, loopPath->nodeIdx[j], loopPath->path[j]);
if (outPortp && (cnp->index == outPortp->nodeno)) {
cnp->lft[loopPath->lid + 1] = outPortp->portno;
}
}
}
// see if we have to setup path to the loop's start node from the first switch
// since its a loop, the start node is the same for the reverse path too
if (topop->switch_head->index != loopPath->startNodeno && nodeLftUpdatedForLoop == 0) {
nodep = topop->switch_head;
// find node record for loop start node
if ((loopNode = sm_find_node(topop, loopPath->startNodeno)) == NULL) {
IB_LOG_ERROR_FMT(__func__,
"can't find node record for loop path[node index:GUID] %d:"FMT_U64,
nodep->index, nodep->nodeInfo.NodeGUID);
continue;
}
// see if we have to setup path to the node from the first switch
if (topop->node_head->nodeInfo.NodeType == NI_TYPE_CA) {
ii = 2; /* skip first node which is the FI */
} else {
ii = 1; /* first node is switch, star there */
}
for (i=ii; i<=loopNode->path[0]; i++) {
if (nodep->index == cnp->index && nodep->lft[loopPath->lid] == 0xff) {
if (smDebugPerf) {
IB_LOG_INFO_FMT(__func__,
"updating node[%d], lft[0x%x] to port %d.....",
nodep->index, loopPath->lid, loopNode->path[i]);
}
nodep->lft[loopPath->lid] = loopNode->path[i];
if (esmLoopTestFast) {
nodep->lft[loopPath->lid+1] = loopNode->path[i]; //reverse path
}
}
if (i < loopNode->path[0]) {
// find next node in path
if ((uePortp = sm_get_port(nodep,loopNode->path[i])) == NULL) {
IB_LOG_ERROR_FMT(__func__,
"failed to get port %d at other end of %d:"FMT_U64":%d",
loopNode->path[i], nodep->index, nodep->nodeInfo.NodeGUID, loopNode->path[i]);
break;
}
if ((nr = sm_find_node(topop, uePortp->nodeno)) == NULL) {
IB_LOG_ERROR_FMT(__func__,
"can't find node record at other end of %d:"FMT_U64":%d (nodeno=%d)",
nodep->index, nodep->nodeInfo.NodeGUID, loopNode->path[i], uePortp->nodeno);
break;
} else {
nodep = nr;
}
}
}
}
}
}
int setLoopTestFastMode(int flag)
{
if (esmLoopTestOn) {
IB_LOG_WARN0("Loop Test is already running, please stop loop test before changing fast mode");
IB_LOG_INFINI_INFO_FMT(__func__,
"Current loop test config - FastMode=%d, FastMode MinISLRedundancy=%d, InjectEachSweep=%d, TotalPktsInjected since start=%d",
esmLoopTestFast, esmLoopTestMinISLRedundancy, esmLoopTestInjectEachSweep,
esmLoopTestTotalPktsInjected);
return -1;
} else {
if (flag == 1) {
esmLoopTestFast = 1;
esmLoopTestInjectEachSweep = 0;
esmLoopTestPathLen = 4;
IB_LOG_INFINI_INFO("loop test fast mode ENABLED, will NOT inject packets every sweep, path length set to ",
esmLoopTestPathLen);
} else if (flag == 0) {
esmLoopTestFast = 0;
esmLoopTestInjectEachSweep = DEFAULT_LOOP_INJECT_EACH_SWEEP;
esmLoopTestPathLen = DEFAULT_LOOP_PATH_LENGTH;
IB_LOG_INFINI_INFO_FMT(__func__,
"loop test fast mode DISABLED, inject packets every sweep = %d, path length set to %d",
esmLoopTestInjectEachSweep, esmLoopTestPathLen);
} else {
IB_LOG_WARN0("argument should be 1 to turn ON or 0 to turn OFF");
IB_LOG_INFINI_INFO_FMT(__func__,
"Current loop test config - FastMode=%d, FastMode MinISLRedundancy=%d, InjectEachSweep=%d, TotalPktsInjected since start=%d",
esmLoopTestFast, esmLoopTestMinISLRedundancy, esmLoopTestInjectEachSweep,
esmLoopTestTotalPktsInjected);
return -1;
}
}
return 0;
}
void print_LoopCoverage(Topology_t *top)
{
int arr[256], index, i, printed;
char buf[512];
char *p;
uint32_t count = 0;
uint32_t loop_count = 0;
Node_t *node, *n2p;
Port_t *portp;
for_all_switch_nodes(top, node) {
memset(arr, 0, sizeof(arr));
index = 0;
for_all_physical_ports(node, portp) {
if (portp->state <= IB_PORT_DOWN)
continue;
if ((n2p = sm_find_node(top, portp->nodeno)) == NULL) {
IB_LOG_ERROR("can't find node structure for node index ", portp->nodeno);
} else if (n2p->nodeInfo.NodeType != NI_TYPE_SWITCH) {
continue; /* only interested in switches */
} else {
if (!portp->portData->inLoopCount) {
arr[index] = portp->index;
index++;
count++;
} else {
loop_count++;
}
}
}
i = 0;
p = buf;
while (arr[i] && i < 50) {
#ifdef __VXWORKS__
printed = sprintf(p, "%d ", arr[i]);
#else
printed = snprintf(p, 4, "%d ", arr[i]);
#endif
p += printed;
i++;
}
if (i) {
IB_LOG_INFINI_INFO_FMT(__func__, "Switch %s "FMT_U64" %d ISL ports are not part of any loop. Ports : %s",
node->nodeDesc.NodeString, node->nodeInfo.NodeGUID, i, buf);
}
}
if (loop_count) {
IB_LOG_INFINI_INFO_FMT(__func__, "Total %d ISL ports (hence %d ISLs) are in loop paths",
loop_count, (loop_count/2));
}
if (loop_count && count) {
IB_LOG_INFINI_INFO_FMT(__func__, "Loop Coverage: Partial - %d ISL ports (hence %d ISLs) are NOT in any loop",
count, (count/2));
} else if (loop_count && !count) {
IB_LOG_INFINI_INFO_FMT(__func__, "Loop Coverage: Full - all ISL ports covered");
} else if (!loop_count) {
IB_LOG_INFINI_INFO_FMT(__func__, "Loop Coverage: ZERO - NO ISL ports covered (loop path length is %d)", esmLoopTestPathLen);
}
if (loop_count) {
IB_LOG_INFINI_INFO_FMT(__func__, "Total %d Loop paths of length <= %d links. MinISLRedundancy is %d.",
((loopPathLidEnd-loopPathLidStart)+1)/2, esmLoopTestPathLen, esmLoopTestMinISLRedundancy);
IB_LOG_INFINI_INFO_FMT(__func__, "Total LIDs required for loop paths is %d.",
(loopPathLidEnd-loopPathLidStart)+1);
}
}
void free_skip_search(Switches_Skip_Search_t *s)
{
if (s->nodes) {
vs_pool_free(&sm_pool, (void *)s->nodes);
s->nodes = NULL;
}
}
void free_portList(PortLoopUsage_t **pp)
{
if (*pp) {
vs_pool_free(&sm_pool, (void *)(*pp));
*pp = NULL;
}
}
void add_to_skip_search(Switches_Skip_Search_t *s, Node_t *parent_node, Node_t *node)
{
Status_t status;
if (!s->nodes) {
if ((status = vs_pool_alloc(&sm_pool, sizeof(uint32_t) * parent_node->nodeInfo.NumPorts, (void *)&(s->nodes))) != VSTATUS_OK) {
s->nodes = NULL;
return;
} else {
memset(s->nodes, -1, sizeof(uint32_t) * parent_node->nodeInfo.NumPorts);
}
s->count = 0;
}
s->nodes[s->count] = node->index;
s->count++;
}
int switch_needs_search(Switches_Skip_Search_t *s, Node_t *node)
{
int i;
if (!s->nodes)
return 1;
for (i = 0; i < s->count; i++) {
if (s->nodes[i] == node->index) {
return 0;
}
}
return 1;
}
static int compare_port_usage(const void *a, const void *b)
{
return (((PortLoopUsage_t *)a)->count - ((PortLoopUsage_t *)b)->count);
}
Status_t getISLPortList(Topology_t *top, Node_t *nodep, PortLoopUsage_t **p_arr, int *count)
{
Port_t *portp;
PortLoopUsage_t *arr;
Node_t *neighNode;
Status_t status;
int i = 0;
if ((status = vs_pool_alloc(&sm_pool, sizeof(PortLoopUsage_t) * nodep->nodeInfo.NumPorts,
(void *)&(arr))) != VSTATUS_OK) {
IB_LOG_ERROR("failed to allocate array for sorting port usage ", status);
*p_arr = NULL;
*count = 0;
return status;
} else {
memset(arr, 0, sizeof(PortLoopUsage_t) * nodep->nodeInfo.NumPorts);
}
*p_arr = arr;
for_all_physical_ports(nodep, portp) {
if (portp->state <= IB_PORT_DOWN)
continue;
if ((neighNode = sm_find_node(top, portp->nodeno)) == NULL) {
IB_LOG_ERROR("can't find node structure for node index ", portp->nodeno);
continue;
}
if (neighNode->nodeInfo.NodeType != NI_TYPE_SWITCH)
continue;
arr[i].count = portp->portData->inLoopCount;
arr[i].portno = portp->index;
arr[i].neighbor = neighNode;
i++;
}
qsort(arr, i, sizeof(PortLoopUsage_t), compare_port_usage);
*count = i;
return VSTATUS_OK;
}
void restore_backup_loop_path(Topology_t *topo, uint16_t *nodeIdx, uint8_t *path, uint16_t *bkup_nodeIdx, uint8_t *bkup_path)
{
Node_t *neighNode;
Port_t *portp, *neighPortp;
int i;
memcpy(path, bkup_path, path[0]+1);
memcpy(nodeIdx, bkup_nodeIdx, (nodeIdx[0]+1)*sizeof(uint16_t));
for (i = 1; i < path[0]; i++) {
portp = sm_find_port(topo, nodeIdx[i], path[i]);
if (!sm_valid_port(portp))
continue;
INC_IN_LOOP_COUNT(portp->portData->inLoopCount);
neighNode = sm_find_node(topo, portp->nodeno);
if (!neighNode)
continue;
neighPortp = sm_get_port(neighNode, portp->portno);
if (!sm_valid_port(neighPortp))
continue;
INC_IN_LOOP_COUNT(neighPortp->portData->inLoopCount);
}
bkup_loop_path = 0;
}
void save_loop_path(Topology_t *topo, uint16_t *bkup_nodeIdx, uint8_t *bkup_path, uint16_t *nodeIdx, uint8_t *path)
{
Port_t *portp;
uint8_t backup = 0;
uint32_t loop_weight = 0;
int i;
for (i = 1; i < path[0]; i++) {
portp = sm_find_port(topo, nodeIdx[i], path[i]);
if (!sm_valid_port(portp))
continue;
loop_weight += portp->portData->inLoopCount;
}
if (bkup_loop_path && loop_weight) {
if ((loop_weight < bkup_path_loopweight) ||
((loop_weight == bkup_path_loopweight) && (path[0] > bkup_path[0]))) {
bkup_path_loopweight = loop_weight;
backup = 1;
}
} else {
bkup_loop_path = 1;
bkup_path_loopweight = loop_weight;
backup = 1;
}
if (backup) {
memcpy(bkup_path, path, path[0]+1);
memcpy(bkup_nodeIdx, nodeIdx, (nodeIdx[0]+1)*sizeof(uint16_t));
}
}
//
// Quick version - Optimized for time, doesn't try to find all possible
// loops for each ISL, but limits each ISL to esmLoopTestMinISLRedundancy loops.
//
// Note - this function is modeled after loopTest_userexit_findPaths and duplicates
// it a bit.
// TODO - Since this function is based on loopTest_userexit_findPaths, there is a bit
// of repeated code for each hop. This could be re-modeled to make the function
// a bit smaller.
//
Status_t
findLoopPaths_quick(Topology_t *top)
{
uint8_t path[64], bkup_path[10];
uint16_t nodeIdx[64], bkup_nodeIdx[10];
Node_t *node;
Port_t *portp, *n2portp, *n3portp, *n4portp, *otherPortp;
Node_t *n2p, *n3p, *n4p;
Status_t status=VSTATUS_OK;
int thisNodeIndex=0;
uint8_t found = 0, found_from_n3 = 0;
Switches_Skip_Search_t n1_skip_search, n2_skip_search, n3_skip_search;
PortLoopUsage_t *n1Arr, *n2Arr, *n3Arr, *n4Arr;
int i, j, k, l;
int n1_count = 0, n2_count = 0, n3_count = 0, n4_count = 0;
IB_ENTER(__func__, 0, 0, 0, 0);
n1_skip_search.nodes = NULL;
n2_skip_search.nodes = NULL;
n3_skip_search.nodes = NULL;
n1Arr = NULL;
n2Arr = NULL;
n3Arr = NULL;
n4Arr = NULL;
if (!esmLoopTestOn) return status;
loopPathLidEnd = 0; // reset end lid number
loopPathLidStart = ((sm_topop->maxLid + 64)/64)*64;
//
// loop test - find loop paths through the switches
//
for_all_switch_nodes(top, node) {
thisNodeIndex = node->index;
if (smDebugPerf) {
IB_LOG_INFO_FMT(__func__,
"checking for paths starting from node %d:"FMT_U64,node->index, node->nodeInfo.NodeGUID);
}
n1_skip_search.nodes = NULL;
if ((status = getISLPortList(top, node, &n1Arr, &n1_count)) != VSTATUS_OK)
goto err_exit;
for (l = 0; l < n1_count; l++) {
portp = sm_get_port(node, n1Arr[l].portno);
if (!portp)
continue;
if (portp->state <= IB_PORT_DOWN || (portp->portData->inLoopCount >= esmLoopTestMinISLRedundancy))
continue;
if (smDebugPerf) {
IB_LOG_INFO_FMT(__func__,
"checking for paths from node %d:"FMT_U64":%d",node->index, node->nodeInfo.NodeGUID, portp->index);
}
found = 0;
if (portp->nodeno == thisNodeIndex) {
// build up the path list
nodeIdx[0] = path[0] = 1; // one link deep
path[1] = portp->index; // out port
// check for duplicate paths
if (checkForDupPath(top, nodeIdx, path)) continue;
INC_IN_LOOP_COUNT(portp->portData->inLoopCount);
otherPortp = sm_get_port(node, portp->portno);
if (sm_valid_port(otherPortp))
INC_IN_LOOP_COUNT(otherPortp->portData->inLoopCount);
nodeIdx[1] = node->index;
if ((status = buildPathList(top, node, portp, nodeIdx, path)) != VSTATUS_OK) {
IB_LOG_ERRORLX("can't allocate space for loop Path from node ", node->nodeInfo.NodeGUID);
status = VSTATUS_BAD;
goto err_exit;
}
found = 1;
} else {
if (esmLoopTestPathLen < 2) continue;
// look beyond this port's node
n2p = n1Arr[l].neighbor;
// look for 2 link loops
if (!switch_needs_search(&n1_skip_search, n2p))
continue;
n2_skip_search.nodes = NULL;
if ((status = getISLPortList(top, n2p, &n2Arr, &n2_count)) != VSTATUS_OK)
goto err_exit;
for (i = 0; i < n2_count; i++) {
bkup_loop_path = 0;
bkup_path_loopweight = 0;
//try and find atleast esmLoopTestMinISLRedundancy loop paths for this ISL between node and n2p
if (found && (portp->portData->inLoopCount >= esmLoopTestMinISLRedundancy))
break;
n2portp = sm_get_port(n2p, n2Arr[i].portno);
if (!n2portp)
continue;
if (n2portp->state <= IB_PORT_DOWN || portp->portno == n2portp->index)
continue;
if (smDebugPerf) {
IB_LOG_INFO_FMT(__func__,
"checking for 2 link paths from node %d:"FMT_U64":%d through %d:"FMT_U64":%d",
node->index, node->nodeInfo.NodeGUID, portp->index, n2p->index, n2p->nodeInfo.NodeGUID, n2portp->index);
}
if (n2portp->nodeno == thisNodeIndex) {
nodeIdx[0] = path[0] = 2;
path[1] = portp->index;
path[2] = n2portp->index;
nodeIdx[1] = node->index;
nodeIdx[2] = n2p->index;
// check for duplicate paths
if (checkForDupPath(top, nodeIdx, path)) continue;
INC_IN_LOOP_COUNT(portp->portData->inLoopCount);
otherPortp = sm_get_port(n2p, portp->portno);
if (sm_valid_port(otherPortp))
INC_IN_LOOP_COUNT(otherPortp->portData->inLoopCount);
INC_IN_LOOP_COUNT(n2portp->portData->inLoopCount);
otherPortp = sm_get_port(node, n2portp->portno);
if (sm_valid_port(otherPortp))
INC_IN_LOOP_COUNT(otherPortp->portData->inLoopCount);
if (smDebugPerf) {
IB_LOG_INFO_FMT(__func__,
"found 2 link loop through %d:"FMT_U64":%d and %d:"FMT_U64":%d",
node->index, node->nodeInfo.NodeGUID, portp->index, n2p->index, n2p->nodeInfo.NodeGUID, n2portp->index);
}
if ((status = buildPathList(top, node, portp, nodeIdx, path)) != VSTATUS_OK) {
IB_LOG_ERRORLX("can't allocate space for loop Path from node ", node->nodeInfo.NodeGUID);
status = VSTATUS_BAD;
goto err_exit;
}
found = 1;
} else {
if (esmLoopTestPathLen < 3) continue;
// look beyond this port's node
n3p = n2Arr[i].neighbor;
if (!switch_needs_search(&n2_skip_search, n3p))
continue;
// look for 3 link loops
n3_skip_search.nodes = NULL;
if ((status = getISLPortList(top, n3p, &n3Arr, &n3_count)) != VSTATUS_OK)
goto err_exit;
found_from_n3 = 0;
for (j = 0; j < n3_count; j++) {
if (found_from_n3)
break;
n3portp = sm_get_port(n3p, n3Arr[j].portno);
if (!n3portp)
continue;
if ((n3portp->state <= IB_PORT_DOWN) ||
(n2p->index == n3p->index && n2portp->index == n3portp->index) ||
(n2portp->portno == n3portp->index)) continue;
if (smDebugPerf) {
IB_LOG_INFO_FMT(__func__,
"checking for 3 link paths from node %d:"FMT_U64":%d through %d:"FMT_U64":%d and %d:"FMT_U64":%d",
node->index, node->nodeInfo.NodeGUID, portp->index, n2p->index, n2p->nodeInfo.NodeGUID, n2portp->index,
n3p->index, n3p->nodeInfo.NodeGUID, n3portp->index);
}
if (n3portp->nodeno == thisNodeIndex) {
if (n3portp->portno == portp->index)
continue; //possible in case of loop back cable cases
nodeIdx[0] = path[0] = 3;
path[1] = portp->index;
path[2] = n2portp->index;
path[3] = n3portp->index;
nodeIdx[1] = node->index;
nodeIdx[2] = n2p->index;
nodeIdx[3] = n3p->index;
// check for duplicate paths
if (checkForDupPath(top, nodeIdx, path)) continue;
// If this ISL is already part of a loop, try and see if
// we can find a better ISL
if ((n2portp->portData->inLoopCount >= esmLoopTestMinISLRedundancy)
|| (n3portp->portData->inLoopCount >= esmLoopTestMinISLRedundancy)) {
save_loop_path(top, bkup_nodeIdx, bkup_path, nodeIdx, path);
continue;
} else {
bkup_loop_path = 0;
}
INC_IN_LOOP_COUNT(portp->portData->inLoopCount);
otherPortp = sm_get_port(n2p, portp->portno);
if (sm_valid_port(otherPortp))
INC_IN_LOOP_COUNT(otherPortp->portData->inLoopCount);
INC_IN_LOOP_COUNT(n2portp->portData->inLoopCount);
otherPortp = sm_get_port(n3p, n2portp->portno);
if (sm_valid_port(otherPortp))
INC_IN_LOOP_COUNT(otherPortp->portData->inLoopCount);
INC_IN_LOOP_COUNT(n3portp->portData->inLoopCount);
otherPortp = sm_get_port(node, n3portp->portno);
if (sm_valid_port(otherPortp))
INC_IN_LOOP_COUNT(otherPortp->portData->inLoopCount);
if (smDebugPerf) {
IB_LOG_INFO_FMT(__func__,
"found 3 link loop through %d:"FMT_U64":%d and %d:"FMT_U64":%d and %d:"FMT_U64":%d",
node->index, node->nodeInfo.NodeGUID, portp->index,
n2p->index, n2p->nodeInfo.NodeGUID, n2portp->index,
n3p->index, n3p->nodeInfo.NodeGUID, n3portp->index);
}
if ((status = buildPathList(top, node, portp, nodeIdx, path)) != VSTATUS_OK) {
IB_LOG_ERRORLX("can't allocate space for loop Path from node ", node->nodeInfo.NodeGUID);
status = VSTATUS_BAD;
goto err_exit;
}
found_from_n3 = 1;
found = 1;
break;
} else {
if (esmLoopTestPathLen < 4) continue;
// look beyond this port's node
n4p = n3Arr[j].neighbor;
if (!switch_needs_search(&n3_skip_search, n4p))
continue;
if ((status = getISLPortList(top, n4p, &n4Arr, &n4_count)) != VSTATUS_OK)
goto err_exit;
// look for 4 hop loops
for (k = 0; k < n4_count; k++) {
n4portp = sm_get_port(n4p, n4Arr[k].portno);
if (!n4portp)
continue;
if (n4portp->state <= IB_PORT_DOWN ||
(n3p->index == n4p->index && n3portp->index == n4portp->index) ||
n4p->index == n2p->index || //this case possible when the loop is between 3 switches
n3portp->portno == n4portp->index) continue;
if (n4portp->nodeno == thisNodeIndex) {
if (n4portp->portno == portp->index)
continue; //possible when the loop is between 3 switches.
nodeIdx[0] = path[0] = 4;
path[1] = portp->index;
path[2] = n2portp->index;
path[3] = n3portp->index;
path[4] = n4portp->index;
nodeIdx[1] = node->index;
nodeIdx[2] = n2p->index;
nodeIdx[3] = n3p->index;
nodeIdx[4] = n4p->index;
// check for duplicate paths
if (checkForDupPath(top, nodeIdx, path)) continue;
// This ISL is already part of a loop, try and see if
// we can find a better ISL
if ((n2portp->portData->inLoopCount >= esmLoopTestMinISLRedundancy) ||
(n3portp->portData->inLoopCount >= esmLoopTestMinISLRedundancy) ||
(n4portp->portData->inLoopCount >= esmLoopTestMinISLRedundancy)) {
save_loop_path(top, bkup_nodeIdx, bkup_path, nodeIdx, path);
continue;
} else {
bkup_loop_path = 0;
}
INC_IN_LOOP_COUNT(portp->portData->inLoopCount);
otherPortp = sm_get_port(n2p, portp->portno);
if (sm_valid_port(otherPortp))
INC_IN_LOOP_COUNT(otherPortp->portData->inLoopCount);
INC_IN_LOOP_COUNT(n2portp->portData->inLoopCount);
otherPortp = sm_get_port(n3p, n2portp->portno);
if (sm_valid_port(otherPortp))
INC_IN_LOOP_COUNT(otherPortp->portData->inLoopCount);
INC_IN_LOOP_COUNT(n3portp->portData->inLoopCount);
otherPortp = sm_get_port(n4p, n3portp->portno);
if (sm_valid_port(otherPortp))
INC_IN_LOOP_COUNT(otherPortp->portData->inLoopCount);
INC_IN_LOOP_COUNT(n4portp->portData->inLoopCount);
otherPortp = sm_get_port(node, n4portp->portno);
if (sm_valid_port(otherPortp))
INC_IN_LOOP_COUNT(otherPortp->portData->inLoopCount);
if (smDebugPerf) {
IB_LOG_INFO_FMT(__func__,
"found 4 link loop through %d:"FMT_U64":%d and %d:"FMT_U64":%d and %d:"FMT_U64":%d and %d:"FMT_U64":%d",
node->index, node->nodeInfo.NodeGUID, portp->index, n2p->index, n2p->nodeInfo.NodeGUID, n2portp->index,
n3p->index, n3p->nodeInfo.NodeGUID, n3portp->index, n4p->index, n4p->nodeInfo.NodeGUID, n4portp->index);
}
if ((status = buildPathList(top, node, portp, nodeIdx, path)) != VSTATUS_OK) {
IB_LOG_ERRORLX("can't allocate space for loop Path from node ", node->nodeInfo.NodeGUID);
status = VSTATUS_BAD;
goto err_exit;
}
found_from_n3 = 1;
found = 1;
break;
} else {
continue;
}
} // end for all physical ports of switch node 4
if (!found_from_n3) {
add_to_skip_search(&n3_skip_search, n3p, n4p);
}
if (n4Arr) {
vs_pool_free(&sm_pool, (void *)n4Arr);
n4Arr = NULL;
}
}
} // end for all physical ports of switch node 3
if (n3Arr) {
vs_pool_free(&sm_pool, (void *)n3Arr);
n3Arr = NULL;
}
if (n3_skip_search.nodes) {
vs_pool_free(&sm_pool, (void *)n3_skip_search.nodes);
n3_skip_search.nodes = NULL;
}
if (!found) {
add_to_skip_search(&n2_skip_search, n2p, n3p);
}
}
} // end for all physical ports of switch node 2
if (n2Arr) {
vs_pool_free(&sm_pool, (void *)n2Arr);
n2Arr = NULL;
}
if (n2_skip_search.nodes) {
vs_pool_free(&sm_pool, (void *)n2_skip_search.nodes);
n2_skip_search.nodes = NULL;
}
if (!found && !bkup_loop_path) {
add_to_skip_search(&n1_skip_search, node, n2p);
}
if (!found && bkup_loop_path) {
restore_backup_loop_path(top, nodeIdx, path, bkup_nodeIdx, bkup_path);
if ((status = buildPathList(top, node, portp, nodeIdx, path)) != VSTATUS_OK) {
IB_LOG_ERRORLX("can't allocate space for loop Path from node ", node->nodeInfo.NodeGUID);
status = VSTATUS_BAD;
goto err_exit;
}
found = 1;
}
}
} // end for all physical ports of switch node 1
if (n1Arr) {
vs_pool_free(&sm_pool, (void *)n1Arr);
n1Arr = NULL;
}
if (n1_skip_search.nodes) {
vs_pool_free(&sm_pool, (void *)n1_skip_search.nodes);
n1_skip_search.nodes = NULL;
}
} // end for all switches loop
print_LoopCoverage(top);
IB_EXIT(__func__, VSTATUS_OK);
return(VSTATUS_OK);
err_exit:
free_skip_search(&n1_skip_search);
free_skip_search(&n2_skip_search);
free_skip_search(&n3_skip_search);
free_portList(&n1Arr);
free_portList(&n2Arr);
free_portList(&n3Arr);
free_portList(&n4Arr);
return status;
}
//
// find every path up to 4 links long that start and end at a switch node.
// Each found path will get a lid assigned to it. The path to these lids
// is a concatenation of the path to the node when first discovered and
// the up to 4 link path found
//
Status_t
loopTest_userexit_findPaths(Topology_t *top) {
uint8_t path[64];
uint16_t nodeIdx[64];
Node_t *node;
Port_t *portp, *n2portp, *n3portp, *n4portp;
Node_t *n2p, *n3p, *n4p;
Status_t status=VSTATUS_OK;
int thisNodeIndex=0;
IB_ENTER(__func__, 0, 0, 0, 0);
if (!esmLoopTestOn) return status;
if (esmLoopTestFast) {
return findLoopPaths_quick(top);
}
loopPathLidEnd = 0; // reset end lid number
loopPathLidStart = ((sm_topop->maxLid + 64)/64)*64;
//
// loop test - find loop paths through the switches
//
for_all_switch_nodes(top, node) {
thisNodeIndex = node->index;
if (smDebugPerf) {
IB_LOG_INFO_FMT(__func__,
"checking for paths starting from node %d:"FMT_U64,node->index, node->nodeInfo.NodeGUID);
}
for_all_physical_ports(node, portp) {
if (portp->state <= IB_PORT_DOWN)
continue;
if (smDebugPerf) {
IB_LOG_INFO_FMT(__func__,
"checking for paths from node %d:"FMT_U64":%d",node->index, node->nodeInfo.NodeGUID, portp->index);
}
if (portp->nodeno == thisNodeIndex) {
// build up the path list
nodeIdx[0] = path[0] = 1; // one link deep
path[1] = portp->index; // out port
nodeIdx[1] = node->index;
if ((status = buildPathList(top, node, portp, nodeIdx, path)) != VSTATUS_OK) {
IB_LOG_ERRORLX("can't allocate space for loop Path from node ", node->nodeInfo.NodeGUID);
return(VSTATUS_BAD);
}
} else {
if (esmLoopTestPathLen < 2) continue;
// look beyond this port's node
if ((n2p = sm_find_node(top, portp->nodeno)) == NULL) {
IB_LOG_ERROR("can't find node structure for node index ", portp->nodeno);
} else if (n2p->nodeInfo.NodeType != NI_TYPE_SWITCH) {
continue; /* only interested in switches */
} else {
// look for 2 link loops
for_all_physical_ports(n2p, n2portp) {
if (n2portp->state <= IB_PORT_DOWN || portp->portno == n2portp->index)
continue;
if (smDebugPerf) {
IB_LOG_INFO_FMT(__func__,
"checking for 2 link paths from node %d:"FMT_U64":%d through %d:"FMT_U64":%d",
node->index, node->nodeInfo.NodeGUID, portp->index, n2p->index, n2p->nodeInfo.NodeGUID, n2portp->index);
}
if (n2portp->nodeno == thisNodeIndex) {
nodeIdx[0] = path[0] = 2;
path[1] = portp->index;
path[2] = n2portp->index;
nodeIdx[1] = node->index;
nodeIdx[2] = n2p->index;
if (smDebugPerf) {
IB_LOG_INFO_FMT(__func__,
"found 2 link loop through %d:"FMT_U64":%d and %d:"FMT_U64":%d",
node->index, node->nodeInfo.NodeGUID, portp->index, n2p->index, n2p->nodeInfo.NodeGUID, n2portp->index);
}
if ((status = buildPathList(top, node, portp, nodeIdx, path)) != VSTATUS_OK) {
IB_LOG_ERRORLX("can't allocate space for loop Path from node ", node->nodeInfo.NodeGUID);
return(VSTATUS_BAD);
}
} else {
if (esmLoopTestPathLen < 3) continue;
// look beyond this port's node
if ((n3p = sm_find_node(top, n2portp->nodeno)) == NULL) {
IB_LOG_ERROR("can't find node structure for node index ", n2portp->nodeno);
} else if (n3p->nodeInfo.NodeType != NI_TYPE_SWITCH) {
continue; /* only interested in switches */
} else {
// look for 3 link loops
for_all_physical_ports(n3p, n3portp) {
if ((n3portp->state <= IB_PORT_DOWN) ||
(n2p->index == n3p->index && n2portp->index == n3portp->index) ||
(n2portp->portno == n3portp->index)) continue;
if (smDebugPerf) {
IB_LOG_INFO_FMT(__func__,
"checking for 3 link paths from node %d:"FMT_U64":%d through %d:"FMT_U64":%d and %d:"FMT_U64":%d",
node->index, node->nodeInfo.NodeGUID, portp->index, n2p->index, n2p->nodeInfo.NodeGUID, n2portp->index,
n3p->index, n3p->nodeInfo.NodeGUID, n3portp->index);
}
if (n3portp->nodeno == thisNodeIndex) {
nodeIdx[0] = path[0] = 3;
path[1] = portp->index;
path[2] = n2portp->index;
path[3] = n3portp->index;
nodeIdx[1] = node->index;
nodeIdx[2] = n2p->index;
nodeIdx[3] = n3p->index;
if (smDebugPerf) {
IB_LOG_INFO_FMT(__func__,
"found 3 link loop through %d:"FMT_U64":%d and %d:"FMT_U64":%d and %d:"FMT_U64":%d",
node->index, node->nodeInfo.NodeGUID, portp->index,
n2p->index, n2p->nodeInfo.NodeGUID, n2portp->index,
n3p->index, n3p->nodeInfo.NodeGUID, n3portp->index);
}
if ((status = buildPathList(top, node, portp, nodeIdx, path)) != VSTATUS_OK) {
IB_LOG_ERRORLX("can't allocate space for loop Path from node ", node->nodeInfo.NodeGUID);
return(VSTATUS_BAD);
}
} else {
if (esmLoopTestPathLen < 4) continue;
// look beyond this port's node
if ((n4p = sm_find_node(top, n3portp->nodeno)) == NULL) {
IB_LOG_ERROR("can't find node structure for node index ", n3portp->nodeno);
} else if (n4p->nodeInfo.NodeType != NI_TYPE_SWITCH) {
continue; /* only interested in switches */
} else {
// look for 4 hop loops
for_all_physical_ports(n4p, n4portp) {
if (n4portp->state <= IB_PORT_DOWN ||
(n3p->index == n4p->index && n3portp->index == n4portp->index) ||
n3portp->portno == n4portp->index) continue;
if (n4portp->nodeno == thisNodeIndex) {
nodeIdx[0] = path[0] = 4;
path[1] = portp->index;
path[2] = n2portp->index;
path[3] = n3portp->index;
path[4] = n4portp->index;
nodeIdx[1] = node->index;
nodeIdx[2] = n2p->index;
nodeIdx[3] = n3p->index;
nodeIdx[4] = n4p->index;
if (smDebugPerf) {
IB_LOG_INFO_FMT(__func__,
"found 4 link loop through %d:"FMT_U64":%d and %d:"FMT_U64":%d and %d:"FMT_U64":%d and %d:"FMT_U64":%d",
node->index, node->nodeInfo.NodeGUID, portp->index, n2p->index, n2p->nodeInfo.NodeGUID, n2portp->index,
n3p->index, n3p->nodeInfo.NodeGUID, n3portp->index, n4p->index, n4p->nodeInfo.NodeGUID, n4portp->index);
}
if ((status = buildPathList(top, node, portp, nodeIdx, path)) != VSTATUS_OK) {
IB_LOG_ERRORLX("can't allocate space for loop Path from node ", node->nodeInfo.NodeGUID);
return(VSTATUS_BAD);
}
} else {
continue;
}
} // // end for all physical ports of switch node 4
}
}
} // end for all physical ports of switch node 3
}
}
} // end for all physical ports of switch node 2
}
}
} // end for all physical ports of switch node 1
} // end for all switches loop
IB_EXIT(__func__, VSTATUS_OK);
return(VSTATUS_OK);
}
//
// print loop paths
// user is responsible for freeing it using vs_pool_free()
// if buffering is specified
//
char* printLoopPaths(int nodeIdx, int buffer) {
int i,j,cnt=0;
LoopPath_t *loopPath;
Node_t *nodep = NULL;
Port_t *portp = NULL;
Port_t *outPortp=NULL;
char *buf = NULL;
int len = 1000;
if (buffer) {
if (vs_pool_alloc(&sm_pool, len, (void*)&buf) != VSTATUS_OK) {
IB_FATAL_ERROR_NODUMP("printLoopPaths: CAN'T ALLOCATE SPACE.");
return NULL;
}
buf[0] = '\0';
}
if (!esmLoopTestOn) {
buf = snprintfcat(buf, &len, "Loop Test is not currently running!\n");
} else {
(void)vs_rdlock(&old_topology_lock);
buf = snprintfcat(buf, &len, "\n");
for_all_switch_nodes(&old_topology, nodep) {
buf = snprintfcat(buf, &len, "Node Idx: %d, Guid: "FMT_U64" Desc %s\n",
(int)nodep->index, nodep->nodeInfo.NodeGUID, nodep->nodeDesc.NodeString);
}
buf = snprintfcat(buf, &len, "\n");
buf = snprintfcat(buf, &len, "--------------------------------------------------------------------------\n");
buf = snprintfcat(buf, &len, " Node Node Node Path\n");
buf = snprintfcat(buf, &len, " Idx Lid NODE GUID #Ports LID PATH[n:p->n:p]\n");
buf = snprintfcat(buf, &len, " ---- ------ ------------------ ------ ------ ---------------\n");
if (nodeIdx >= 0) {
if ( ((nodep = sm_find_node(&old_topology, nodeIdx)) == NULL) || nodep->nodeInfo.NodeType != NI_TYPE_SWITCH) {
buf = snprintfcat(buf, &len, "Node index %d is not a valid switch node\n", nodeIdx);
(void)vs_rwunlock(&old_topology_lock);
return buf;
}
for (loopPath=old_topology.loopPaths; loopPath != NULL; loopPath = loopPath->next) {
for (j=1; j<=loopPath->nodeIdx[0]; j++) {
if (nodeIdx == loopPath->nodeIdx[j]) {
cnt++;
// print out loop path
portp = sm_get_port(nodep,0);
buf = snprintfcat(buf, &len, " %4d 0x%04x "FMT_U64" %2d 0x%04x ",
(int)nodep->index, (sm_valid_port(portp)) ? (int)portp->portData->lid : -1,
nodep->nodeInfo.NodeGUID, (int)nodep->nodeInfo.NumPorts, (int)loopPath->lid);
for (i = 1; i <= (int)loopPath->path[0]; i++) {
outPortp = sm_find_port(&old_topology, loopPath->nodeIdx[i], loopPath->path[i]);
buf = snprintfcat(buf, &len, "%d:%d->%d:%d ", loopPath->nodeIdx[i], loopPath->path[i],
(outPortp)?(int)outPortp->nodeno:-1, (outPortp)?(int)outPortp->portno:0xffff);
}
buf = snprintfcat(buf, &len, "\n");
break;
}
}
}
} else {
// print every loop path
for (loopPath=old_topology.loopPaths; loopPath != NULL; loopPath = loopPath->next) {
if ((nodep = sm_find_node(&old_topology, loopPath->startNodeno)) != NULL) {
cnt++;
// print out loop path
portp = sm_get_port(nodep,0);
buf = snprintfcat(buf, &len, " %4d 0x%04x "FMT_U64" %2d 0x%04x ",
(int)nodep->index, (sm_valid_port(portp)) ? (int)portp->portData->lid : -1,
nodep->nodeInfo.NodeGUID, (int)nodep->nodeInfo.NumPorts, (int)loopPath->lid);
for (i = 1; i <= (int)loopPath->path[0]; i++) {
outPortp = sm_find_port(&old_topology, loopPath->nodeIdx[i], loopPath->path[i]);
buf = snprintfcat(buf, &len, "%d:%d->%d:%d ", loopPath->nodeIdx[i], loopPath->path[i],
(outPortp)?(int)outPortp->nodeno:0, (outPortp)?(int)outPortp->portno:0);
}
buf = snprintfcat(buf, &len, "\n");
}
}
}
// print out how many paths found
buf = snprintfcat(buf, &len, "--------------------------------------------------------------------------\n");
buf = snprintfcat(buf, &len, "There are %d total loop paths of <=%d links in length in the fabric!\n",
old_topology.numLoopPaths, esmLoopTestPathLen);
if (esmLoopTestFast) {
buf = snprintfcat(buf, &len, "Two LIDs are used per loop path to inject packets in clockwise and anti-clockwise directions\n");
}
if (nodeIdx >= 0) {
portp = sm_get_port(nodep,0);
buf = snprintfcat(buf, &len, "Node index=%d, GUID="FMT_U64", LID=0x%x has %d loops\n", nodeIdx, nodep->nodeInfo.NodeGUID,
(sm_valid_port(portp)) ? (int)portp->portData->lid : -1, cnt);
}
buf = snprintfcat(buf, &len, "--------------------------------------------------------------------------\n");
(void)vs_rwunlock(&old_topology_lock);
}
return buf;
}
//
// set loop path max length
//
void setLoopPathLength (int len) {
esmLoopTestPathLen = (len < 5 && len > 1) ? len : 3;
IB_LOG_INFINI_INFO("Loop path length = ", esmLoopTestPathLen);
if (esmLoopTestOn) sm_forceSweep("SM Loop Test Path Length Changed");
}
//
// Set esmLoopTestMinISLRedundancy which determines min number of loops in which each ISL should be included.
//
void setLoopMinISLRedundancy (int num) {
int new = 0;
new = (num > 0) ? num : 4;
if (new != esmLoopTestMinISLRedundancy) {
esmLoopTestMinISLRedundancy = new;
if (esmLoopTestOn) sm_forceSweep("SM Loop Test Minimum ISL Redundancy Changed");
}
IB_LOG_INFINI_INFO("Loop MinISLRedundancy = ", esmLoopTestMinISLRedundancy);
}
//
// print switch Linear Forwarding Table
//
char* printSwitchLft(int nodeIdx, int useNew, int haveLock, int buffer) {
int i;
Node_t *nodep;
Port_t *portp;
Topology_t * topop;
Lock_t * lockp;
char *buf = NULL;
int len = 1000;
if (buffer) {
if (vs_pool_alloc(&sm_pool, len, (void*)&buf) != VSTATUS_OK) {
IB_FATAL_ERROR_NODUMP("printSwitchLft: CAN'T ALLOCATE SPACE.");
return NULL;
}
buf[0] = '\0';
}
if (useNew) {
topop = &sm_newTopology;
lockp = &new_topology_lock;
} else {
topop = &old_topology;
lockp = &old_topology_lock;
}
if (topology_passcount >= 1 || useNew) {
if (!haveLock) {
if (lockp == &old_topology_lock) (void)vs_rdlock(lockp);
else (void)vs_lock(lockp);
}
if (nodeIdx < 0) {
// print all switches LFTs
for_all_switch_nodes(topop, nodep) {
if (nodep != NULL) {
portp = sm_get_port(nodep,0);
buf = snprintfcat(buf, &len, "Node[%.4d] LID=0x%.4X GUID="FMT_U64" [%s] Linear Forwarding Table\n",
(int)nodep->index, (sm_valid_port(portp)) ? (int)portp->portData->lid : -1, nodep->nodeInfo.NodeGUID, sm_nodeDescString(nodep));
buf = snprintfcat(buf, &len, " LID PORT\n");
buf = snprintfcat(buf, &len, " ------ ----\n");
for (i = 1; i <= topop->maxLid; i++) {
if (nodep->lft[i] != 0xff)
buf = snprintfcat(buf, &len, " 0x%04x %04d\n", i, nodep->lft[i]);
}
buf = snprintfcat(buf, &len, " --------------\n");
buf = snprintfcat(buf, &len, "\n");
}
}
} else {
if ((nodep = sm_find_node(topop, nodeIdx)) != NULL && nodep->nodeInfo.NodeType == NI_TYPE_SWITCH) {
portp = sm_get_port(nodep,0);
buf = snprintfcat(buf, &len, "Node[%.4d] LID=0x%.4X GUID="FMT_U64" [%s] Linear Forwarding Table\n",
(int)nodep->index, (sm_valid_port(portp)) ? (int)portp->portData->lid : -1, nodep->nodeInfo.NodeGUID, sm_nodeDescString(nodep));
buf = snprintfcat(buf, &len, " LID PORT\n");
buf = snprintfcat(buf, &len, " ------ ----\n");
for (i = 1; i <= topop->maxLid; i++) {
if (nodep->lft[i] != 0xff)
buf = snprintfcat(buf, &len, " 0x%04x %04d\n", i, nodep->lft[i]);
}
} else {
buf = snprintfcat(buf, &len, "Node index %d is not a valid switch!\n", nodeIdx);
}
}
if (!haveLock) {
if (lockp == &old_topology_lock) (void)vs_rwunlock(lockp);
else (void)vs_unlock(lockp);
}
} else {
buf = snprintfcat(buf, &len, "Sm is not MASTER or is not currently running!\n");
}
return buf;
}
// print running Loop Test Configuration to buffer
// user is responsible for freeing it using vs_pool_free()
// if buffering is specified
//
char* printLoopTestConfig(int buffer) {
char * buf = NULL;
int len = 500;
if (buffer) {
if (vs_pool_alloc(&sm_pool, len, (void*)&buf) != VSTATUS_OK) {
IB_FATAL_ERROR_NODUMP("printLoopTestConfig: CAN'T ALLOCATE SPACE.");
return NULL;
}
buf[0] = '\0';
}
if (esmLoopTestOn) {
buf = snprintfcat(buf, &len, "Loop Test is running with following parameters:\n");
buf = snprintfcat(buf, &len, " Max Path Length #Packets Inject Point\n");
buf = snprintfcat(buf, &len, " --------------- -------- ------------\n");
if (esmLoopTestInjectNode < 0) {
buf = snprintfcat(buf, &len, " %d %05d All Nodes\n", esmLoopTestPathLen, esmLoopTestNumPkts);
} else {
buf = snprintfcat(buf, &len, " %d %05d Node %d\n", esmLoopTestPathLen, esmLoopTestNumPkts, esmLoopTestInjectNode);
}
buf = snprintfcat(buf, &len, "\n");
buf = snprintfcat(buf, &len, "FastMode=%d, FastMode MinISLRedundancy=%d, InjectEachSweep=%d, TotalPktsInjected since start=%d\n",
esmLoopTestFast, esmLoopTestMinISLRedundancy, esmLoopTestInjectEachSweep, (int)esmLoopTestTotalPktsInjected);
} else {
buf = snprintfcat(buf, &len, "Loop Test is not currently running; enter 'smLooptestStart' or 'smLooptestFastModeStart' to start the Loop Test!\n");
}
return buf;
}