|
Packit |
857059 |
/* BEGIN_ICS_COPYRIGHT7 ****************************************
|
|
Packit |
857059 |
|
|
Packit |
857059 |
Copyright (c) 2015-2017, Intel Corporation
|
|
Packit |
857059 |
|
|
Packit |
857059 |
Redistribution and use in source and binary forms, with or without
|
|
Packit |
857059 |
modification, are permitted provided that the following conditions are met:
|
|
Packit |
857059 |
|
|
Packit |
857059 |
* Redistributions of source code must retain the above copyright notice,
|
|
Packit |
857059 |
this list of conditions and the following disclaimer.
|
|
Packit |
857059 |
* Redistributions in binary form must reproduce the above copyright
|
|
Packit |
857059 |
notice, this list of conditions and the following disclaimer in the
|
|
Packit |
857059 |
documentation and/or other materials provided with the distribution.
|
|
Packit |
857059 |
* Neither the name of Intel Corporation nor the names of its contributors
|
|
Packit |
857059 |
may be used to endorse or promote products derived from this software
|
|
Packit |
857059 |
without specific prior written permission.
|
|
Packit |
857059 |
|
|
Packit |
857059 |
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
Packit |
857059 |
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
Packit |
857059 |
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
Packit |
857059 |
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
|
Packit |
857059 |
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
Packit |
857059 |
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
Packit |
857059 |
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
Packit |
857059 |
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
Packit |
857059 |
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
Packit |
857059 |
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
Packit |
857059 |
|
|
Packit |
857059 |
** END_ICS_COPYRIGHT7 ****************************************/
|
|
Packit |
857059 |
|
|
Packit |
857059 |
/* [ICS VERSION STRING: unknown] */
|
|
Packit |
857059 |
|
|
Packit |
857059 |
#include <iba/ibt.h>
|
|
Packit |
857059 |
#include <iba/ipublic.h>
|
|
Packit |
857059 |
#include <stdio.h>
|
|
Packit |
857059 |
#include <stdlib.h>
|
|
Packit |
857059 |
#include <stdarg.h>
|
|
Packit |
857059 |
#include <unistd.h>
|
|
Packit |
857059 |
#include <ctype.h>
|
|
Packit |
857059 |
#define _GNU_SOURCE
|
|
Packit |
857059 |
#include <ixml_ib.h>
|
|
Packit |
857059 |
#include <topology.h>
|
|
Packit |
857059 |
#include <getopt.h>
|
|
Packit |
857059 |
#include <limits.h>
|
|
Packit |
857059 |
#include <math.h>
|
|
Packit |
857059 |
#include <arpa/inet.h>
|
|
Packit |
857059 |
#include <stl_helper.h>
|
|
Packit |
857059 |
#include <time.h>
|
|
Packit |
857059 |
#include <string.h>
|
|
Packit |
857059 |
|
|
Packit |
857059 |
|
|
Packit |
857059 |
#define MYTAG MAKE_MEM_TAG('o','2', 'r', 'm')
|
|
Packit |
857059 |
|
|
Packit |
857059 |
#define DBGPRINT(format, args...) \
|
|
Packit |
857059 |
do { if (g_verbose) { fflush(stdout); fprintf(stderr, format, ##args); } } while (0)
|
|
Packit |
857059 |
|
|
Packit |
857059 |
#define PROGRESS_PRINT(newline, format, args...) \
|
|
Packit |
857059 |
do { if (! g_quiet) { ProgressPrint(newline, format, ##args); } } while (0)
|
|
Packit |
857059 |
|
|
Packit |
857059 |
#define PROGRESS_FREQ 1000
|
|
Packit |
857059 |
|
|
Packit |
857059 |
#define MIN_LIST_ITEMS 10 // for neighbor sw and fi DLISTs
|
|
Packit |
857059 |
|
|
Packit |
857059 |
// macro to always return a valid pointer for use in %s formats
|
|
Packit |
857059 |
#define OPTIONAL_STR(s) (s?s:"")
|
|
Packit |
857059 |
|
|
Packit |
857059 |
#define RANGE_IN_MIDDLE 0 // should ranges in middle of name be permitted
|
|
Packit |
857059 |
|
|
Packit |
857059 |
uint8 g_verbose = 0;
|
|
Packit |
857059 |
uint8 g_quiet = 0; // omit progress output
|
|
Packit |
857059 |
#define MAX_FOCUS 10
|
|
Packit |
857059 |
char *g_focus_arg[MAX_FOCUS];
|
|
Packit |
857059 |
Point g_focus[MAX_FOCUS];
|
|
Packit |
857059 |
int g_num_focus = 0;
|
|
Packit |
857059 |
char* g_prefix = NULL; // prefix for all FIs
|
|
Packit |
857059 |
char* g_suffix = NULL; // suffix for all FIs
|
|
Packit |
857059 |
|
|
Packit |
857059 |
// All the information about the fabric
|
|
Packit |
857059 |
FabricData_t g_Fabric;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
// In order to allow removal of spaces, sorting and compacting
|
|
Packit |
857059 |
// names into ranges (eg. compute[1-10]) we keep a NameData per
|
|
Packit |
857059 |
// name we want to show. The NameData includes the reformated full name
|
|
Packit |
857059 |
// and the parsed elements of body, numeric range and end
|
|
Packit |
857059 |
typedef struct NameData_s {
|
|
Packit |
857059 |
cl_map_item_t NameListEntry; // nameList, key is name
|
|
Packit |
857059 |
char name[NODE_DESCRIPTION_ARRAY_SIZE]; // full name
|
|
Packit |
857059 |
|
|
Packit |
857059 |
// a name is broken into four parts, body is alphanumeric
|
|
Packit |
857059 |
// start,end is a numeric part at the end of the body
|
|
Packit |
857059 |
// prefix is a prefix we will add afterwards such as opa- for IPoIB on OPA
|
|
Packit |
857059 |
// suffix is a suffix we will add afterwards such as -opa for IPoIB on OPA
|
|
Packit |
857059 |
const char *prefix;
|
|
Packit |
857059 |
char body[NODE_DESCRIPTION_ARRAY_SIZE];
|
|
Packit |
857059 |
uint32 start, end; // numeric range
|
|
Packit |
857059 |
boolean leadzero; // did original name have leading zeros for number
|
|
Packit |
857059 |
int8 numlen; // number of characters in number in original name
|
|
Packit |
857059 |
const char *suffix;
|
|
Packit |
857059 |
} NameData_t;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
// This will be attached to each switch node via ExpectedNode.context
|
|
Packit |
857059 |
typedef struct SwitchLists_s {
|
|
Packit |
857059 |
cl_qmap_t fiNeighborNames;// filtered list of neighbor FIs NameData_t
|
|
Packit |
857059 |
cl_qmap_t swNeighborNames;// filtered list of neighbor SWs NameData_t
|
|
Packit |
857059 |
uint8 tier; // tier in tree of given switch
|
|
Packit |
857059 |
// (distance from FIs)
|
|
Packit |
857059 |
DLIST swNeighbors; // list of all neighbor SWs ExpectedNode*
|
|
Packit |
857059 |
} SwitchLists_t;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
boolean CompareExpectedNodeFocus(ExpectedNode *enodep);
|
|
Packit |
857059 |
boolean CompareExpectedLinkFocus(ExpectedLink *elinkp);
|
|
Packit |
857059 |
|
|
Packit |
857059 |
// -------------- output of Expected* functions --------------------
|
|
Packit |
857059 |
// these next few functions are for error output and debug
|
|
Packit |
857059 |
// They allow dumping of the input topology file which was parsed
|
|
Packit |
857059 |
// output goes to stderr
|
|
Packit |
857059 |
|
|
Packit |
857059 |
// show 1 port selector in link data in brief form
|
|
Packit |
857059 |
void ShowExpectedLinkPortSelBriefSummary(ExpectedLink *elinkp, PortSelector *portselp,
|
|
Packit |
857059 |
uint8 side, int indent, int detail)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
DEBUG_ASSERT(side == 1 || side == 2);
|
|
Packit |
857059 |
fprintf(stderr, "%*s%4s ", indent, "",
|
|
Packit |
857059 |
(side == 1)?
|
|
Packit |
857059 |
elinkp->expected_rate?
|
|
Packit |
857059 |
StlStaticRateToText(elinkp->expected_rate)
|
|
Packit |
857059 |
:""
|
|
Packit |
857059 |
: "<-> ");
|
|
Packit |
857059 |
if (side == 1 && elinkp->expected_mtu)
|
|
Packit |
857059 |
fprintf(stderr, "%5s ", IbMTUToText(elinkp->expected_mtu));
|
|
Packit |
857059 |
else
|
|
Packit |
857059 |
fprintf(stderr, " ");
|
|
Packit |
857059 |
|
|
Packit |
857059 |
if (portselp) {
|
|
Packit |
857059 |
if (portselp->NodeGUID)
|
|
Packit |
857059 |
fprintf(stderr, "0x%016"PRIx64, portselp->NodeGUID);
|
|
Packit |
857059 |
else
|
|
Packit |
857059 |
fprintf(stderr, " ");
|
|
Packit |
857059 |
if (portselp->gotPortNum)
|
|
Packit |
857059 |
fprintf(stderr, " %3u ",portselp->PortNum);
|
|
Packit |
857059 |
else if (portselp->PortGUID)
|
|
Packit |
857059 |
fprintf(stderr, " 0x%016"PRIx64, portselp->PortGUID);
|
|
Packit |
857059 |
else
|
|
Packit |
857059 |
fprintf(stderr, " ");
|
|
Packit |
857059 |
if (portselp->NodeType)
|
|
Packit |
857059 |
fprintf(stderr, " %s",
|
|
Packit |
857059 |
StlNodeTypeToText(portselp->NodeType));
|
|
Packit |
857059 |
else
|
|
Packit |
857059 |
fprintf(stderr, " ");
|
|
Packit |
857059 |
if (portselp->NodeDesc)
|
|
Packit |
857059 |
fprintf(stderr, " %.*s\n",
|
|
Packit |
857059 |
NODE_DESCRIPTION_ARRAY_SIZE, portselp->NodeDesc);
|
|
Packit |
857059 |
else
|
|
Packit |
857059 |
fprintf(stderr, "\n");
|
|
Packit |
857059 |
if (detail) {
|
|
Packit |
857059 |
if (portselp->details) {
|
|
Packit |
857059 |
fprintf(stderr, "%*sPortDetails: %s\n", indent+4, "", portselp->details);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
} else {
|
|
Packit |
857059 |
fprintf(stderr, "unspecified\n");
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
|
|
Packit |
857059 |
// show cable information for a link in multi-line format with field headings
|
|
Packit |
857059 |
void ShowExpectedLinkSummary(ExpectedLink *elinkp,
|
|
Packit |
857059 |
int indent, int detail)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
// From Side (Port 1)
|
|
Packit |
857059 |
ShowExpectedLinkPortSelBriefSummary(elinkp, elinkp->portselp1,
|
|
Packit |
857059 |
1, indent, detail);
|
|
Packit |
857059 |
// To Side (Port 2)
|
|
Packit |
857059 |
ShowExpectedLinkPortSelBriefSummary(elinkp, elinkp->portselp2,
|
|
Packit |
857059 |
2, indent, detail);
|
|
Packit |
857059 |
if (elinkp->details) {
|
|
Packit |
857059 |
fprintf(stderr, "%*sLinkDetails: %s\n", indent, "", elinkp->details);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
if (elinkp->CableData.length || elinkp->CableData.label
|
|
Packit |
857059 |
|| elinkp->CableData.details) {
|
|
Packit |
857059 |
fprintf(stderr, "%*sCableLabel: %-*s CableLen: %-*s\n",
|
|
Packit |
857059 |
indent, "",
|
|
Packit |
857059 |
CABLE_LABEL_STRLEN, OPTIONAL_STR(elinkp->CableData.label),
|
|
Packit |
857059 |
CABLE_LENGTH_STRLEN, OPTIONAL_STR(elinkp->CableData.length));
|
|
Packit |
857059 |
fprintf(stderr, "%*sCableDetails: %s\n",
|
|
Packit |
857059 |
indent, "",
|
|
Packit |
857059 |
OPTIONAL_STR(elinkp->CableData.details));
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
// Verify links in fabric against specified topology
|
|
Packit |
857059 |
void ShowExpectedLinksReport(/*Point *focus,*/ int indent, int detail)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
LIST_ITEM *p;
|
|
Packit |
857059 |
uint32 input_checked = 0;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
fprintf(stderr, "%*sLinks Topology Expected\n", indent, "");
|
|
Packit |
857059 |
|
|
Packit |
857059 |
fprintf(stderr, "%*sRate MTU NodeGUID Port or PortGUID Type Name\n", indent, "");
|
|
Packit |
857059 |
if (detail && (g_Fabric.flags & FF_CABLEDATA)) {
|
|
Packit |
857059 |
//fprintf(stderr, "%*sPortDetails\n", indent+4, "");
|
|
Packit |
857059 |
//fprintf(stderr, "%*sLinkDetails\n", indent+4, "");
|
|
Packit |
857059 |
fprintf(stderr, "%*sCable: %-*s %-*s\n", indent+4, "",
|
|
Packit |
857059 |
CABLE_LABEL_STRLEN, "CableLabel",
|
|
Packit |
857059 |
CABLE_LENGTH_STRLEN, "CableLen");
|
|
Packit |
857059 |
fprintf(stderr, "%*s%s\n", indent+4, "", "CableDetails");
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
for (p=QListHead(&g_Fabric.ExpectedLinks); p != NULL; p = QListNext(&g_Fabric.ExpectedLinks, p)) {
|
|
Packit |
857059 |
ExpectedLink *elinkp = (ExpectedLink *)QListObj(p);
|
|
Packit |
857059 |
|
|
Packit |
857059 |
if (! elinkp)
|
|
Packit |
857059 |
continue;
|
|
Packit |
857059 |
if (! CompareExpectedLinkFocus(elinkp))
|
|
Packit |
857059 |
continue;
|
|
Packit |
857059 |
input_checked++;
|
|
Packit |
857059 |
ShowExpectedLinkSummary(elinkp, indent, detail);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
if (detail && input_checked)
|
|
Packit |
857059 |
fprintf(stderr, "\n"); // blank line between links
|
|
Packit |
857059 |
fprintf(stderr, "%*s%u of %u Input Links Shown\n", indent, "",
|
|
Packit |
857059 |
input_checked, QListCount(&g_Fabric.ExpectedLinks));
|
|
Packit |
857059 |
|
|
Packit |
857059 |
return;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
// output brief summary of an expected IB Node
|
|
Packit |
857059 |
void ShowExpectedNodeBriefSummary(ExpectedNode *enodep, int indent, int detail)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
fprintf(stderr, "%*s", indent, "");
|
|
Packit |
857059 |
if (enodep->NodeGUID)
|
|
Packit |
857059 |
fprintf(stderr, "0x%016"PRIx64, enodep->NodeGUID);
|
|
Packit |
857059 |
else
|
|
Packit |
857059 |
fprintf(stderr, " ");
|
|
Packit |
857059 |
if (enodep->NodeType)
|
|
Packit |
857059 |
fprintf(stderr, " %s", StlNodeTypeToText(enodep->NodeType));
|
|
Packit |
857059 |
else
|
|
Packit |
857059 |
fprintf(stderr, " ");
|
|
Packit |
857059 |
if (enodep->NodeDesc)
|
|
Packit |
857059 |
fprintf(stderr, " %s\n", enodep->NodeDesc);
|
|
Packit |
857059 |
else
|
|
Packit |
857059 |
fprintf(stderr, "\n");
|
|
Packit |
857059 |
if (enodep->details)
|
|
Packit |
857059 |
fprintf(stderr, "%*sNodeDetails: %s\n", indent+4, "", enodep->details);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
// Verify nodes in fabric against specified topology
|
|
Packit |
857059 |
void ShowExpectedNodesReport(/*Point *focus,*/ uint8 NodeType, int indent, int detail)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
LIST_ITEM *p;
|
|
Packit |
857059 |
uint32 input_checked = 0;
|
|
Packit |
857059 |
const char *NodeTypeText = StlNodeTypeToText(NodeType);
|
|
Packit |
857059 |
QUICK_LIST *input_listp;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
switch (NodeType) {
|
|
Packit |
857059 |
case STL_NODE_FI:
|
|
Packit |
857059 |
input_listp = &g_Fabric.ExpectedFIs;
|
|
Packit |
857059 |
break;
|
|
Packit |
857059 |
case STL_NODE_SW:
|
|
Packit |
857059 |
input_listp = &g_Fabric.ExpectedSWs;
|
|
Packit |
857059 |
break;
|
|
Packit |
857059 |
default:
|
|
Packit |
857059 |
ASSERT(0);
|
|
Packit |
857059 |
break;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
// intro for report
|
|
Packit |
857059 |
fprintf(stderr, "%*s%ss Topology Expected\n", indent, "", NodeTypeText);
|
|
Packit |
857059 |
for (p=QListHead(input_listp); p != NULL; p = QListNext(input_listp, p)) {
|
|
Packit |
857059 |
ExpectedNode *enodep = (ExpectedNode *)QListObj(p);
|
|
Packit |
857059 |
|
|
Packit |
857059 |
if (! enodep)
|
|
Packit |
857059 |
continue;
|
|
Packit |
857059 |
input_checked++;
|
|
Packit |
857059 |
ShowExpectedNodeBriefSummary(enodep, indent, detail);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
if (detail && input_checked)
|
|
Packit |
857059 |
fprintf(stderr, "\n"); // blank line between links
|
|
Packit |
857059 |
fprintf(stderr, "%*s%u of %u Input %ss Shown\n", indent, "",
|
|
Packit |
857059 |
input_checked, QListCount(input_listp), NodeTypeText);
|
|
Packit |
857059 |
return;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
// --------------------- NameData functions ----------------------------
|
|
Packit |
857059 |
|
|
Packit |
857059 |
// when using GUIDs as name, put whole value in body
|
|
Packit |
857059 |
void SetNameToGuid(NameData_t *namep, EUI64 guid)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
sprintf(namep->name, "0x%016"PRIx64, guid);
|
|
Packit |
857059 |
namep->prefix = NULL;
|
|
Packit |
857059 |
StringCopy(namep->body, namep->name, NODE_DESCRIPTION_ARRAY_SIZE);
|
|
Packit |
857059 |
namep->start = 0;
|
|
Packit |
857059 |
namep->end = 0;
|
|
Packit |
857059 |
namep->leadzero = FALSE;
|
|
Packit |
857059 |
namep->numlen = 0;
|
|
Packit |
857059 |
namep->suffix = NULL;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
// Name processing copy Modes:
|
|
Packit |
857059 |
// underscore - simple conversion of space to underscore
|
|
Packit |
857059 |
// trunc - take all chars after 1st space and remove
|
|
Packit |
857059 |
// host405 hfi1_0 -> host405
|
|
Packit |
857059 |
// can be useful for single and multi-rail hosts
|
|
Packit |
857059 |
// can also be useful to produce a more concise slurm file
|
|
Packit |
857059 |
// by treating large switches as a single black box entity
|
|
Packit |
857059 |
// flip - take all chars after 1st space and put at start of name
|
|
Packit |
857059 |
// any additional spaces converted to underscore
|
|
Packit |
857059 |
// opacore7 Leaf101 -> Leaf101_opacore7
|
|
Packit |
857059 |
// can be useful so can sort and combine to get ranges
|
|
Packit |
857059 |
// such as Leaf101_opacore[1-7]
|
|
Packit |
857059 |
// guid - use text representation of hex GUID
|
|
Packit |
857059 |
// TBD - future - could add multi-rail suffix addition or replace modes
|
|
Packit |
857059 |
// - algortihmic suffix (hf1_0 -> -opa1, hfi1_1 -> -opa2)
|
|
Packit |
857059 |
typedef enum {
|
|
Packit |
857059 |
NAME_MODE_UNDERSCORE = 1,
|
|
Packit |
857059 |
NAME_MODE_FLIP = 2,
|
|
Packit |
857059 |
NAME_MODE_TRUNC = 3,
|
|
Packit |
857059 |
NAME_MODE_GUID = 4
|
|
Packit |
857059 |
} name_mode_t;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
|
|
Packit |
857059 |
// translate and copy name into a NameData, separating out body and number
|
|
Packit |
857059 |
// and adding prefix and suffix
|
|
Packit |
857059 |
void CopyName(NameData_t *namep, const char *name, EUI64 guid, name_mode_t mode,
|
|
Packit |
857059 |
const char *prefix, const char *suffix)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
int len = 0;
|
|
Packit |
857059 |
int i;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
if (! name || mode == NAME_MODE_GUID) {
|
|
Packit |
857059 |
DEBUG_ASSERT(guid);
|
|
Packit |
857059 |
SetNameToGuid(namep, guid);
|
|
Packit |
857059 |
return;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
if (mode == NAME_MODE_UNDERSCORE) {
|
|
Packit |
857059 |
// change spaces to underscore
|
|
Packit |
857059 |
int l;
|
|
Packit |
857059 |
char *d;
|
|
Packit |
857059 |
StringCopy(namep->name, name, sizeof(namep->name));
|
|
Packit |
857059 |
len = strnlen(namep->name, sizeof(namep->name));
|
|
Packit |
857059 |
for (l=len, d=namep->name; l; d++, l--)
|
|
Packit |
857059 |
if (isspace(*d))
|
|
Packit |
857059 |
*d = '_';
|
|
Packit |
857059 |
} else if (mode == NAME_MODE_TRUNC) {
|
|
Packit |
857059 |
// truncate at 1st space
|
|
Packit |
857059 |
int l;
|
|
Packit |
857059 |
char *d;
|
|
Packit |
857059 |
StringCopy(namep->name, name, sizeof(namep->name));
|
|
Packit |
857059 |
len = strnlen(namep->name, sizeof(namep->name));
|
|
Packit |
857059 |
for (l=len, d=namep->name; l; d++, l--) {
|
|
Packit |
857059 |
if (isspace(*d)) {
|
|
Packit |
857059 |
*d = '\0';
|
|
Packit |
857059 |
break;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
len = (d - namep->name);
|
|
Packit |
857059 |
} else if (mode == NAME_MODE_FLIP) {
|
|
Packit |
857059 |
// put content after 1st space at start of string,
|
|
Packit |
857059 |
// replacing space w/underscore
|
|
Packit |
857059 |
int l;
|
|
Packit |
857059 |
const char *s;
|
|
Packit |
857059 |
char *d = namep->name;
|
|
Packit |
857059 |
for (l=sizeof(namep->name), s=name; l && *s && ! isspace(*s); s++, l--)
|
|
Packit |
857059 |
;
|
|
Packit |
857059 |
if (l && *s) {
|
|
Packit |
857059 |
// we found a space
|
|
Packit |
857059 |
DEBUG_ASSERT(isspace(*s));
|
|
Packit |
857059 |
s++; l--;
|
|
Packit |
857059 |
// copy remaining characters to start of string
|
|
Packit |
857059 |
for (; l && *s; s++, l--)
|
|
Packit |
857059 |
if(!isspace(*s))
|
|
Packit |
857059 |
*d++ = *s;
|
|
Packit |
857059 |
*d++ = '_';
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
// now copy up to the 1st space into the remainder
|
|
Packit |
857059 |
for (l=sizeof(namep->name) - (d-namep->name), s=name; l && *s && ! isspace(*s); s++, d++, l--)
|
|
Packit |
857059 |
*d = *s;
|
|
Packit |
857059 |
if (l)
|
|
Packit |
857059 |
*d='\0';
|
|
Packit |
857059 |
len = (d - namep->name);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
namep->prefix = prefix;
|
|
Packit |
857059 |
StringCopy(namep->body, namep->name, sizeof(namep->body));
|
|
Packit |
857059 |
// assume no number
|
|
Packit |
857059 |
namep->numlen = 0;
|
|
Packit |
857059 |
namep->start = 0;
|
|
Packit |
857059 |
namep->end = 0;
|
|
Packit |
857059 |
if (len) {
|
|
Packit |
857059 |
for (i=len; i> 0 && isdigit(namep->body[i-1]); i--)
|
|
Packit |
857059 |
;
|
|
Packit |
857059 |
if (i != len) {
|
|
Packit |
857059 |
// we have a number, starting at body[i]
|
|
Packit |
857059 |
if (FSUCCESS == StringToUint32(&namep->start, &namep->body[i], NULL, 10, FALSE)) {
|
|
Packit |
857059 |
namep->numlen = len - i;
|
|
Packit |
857059 |
namep->end = namep->start;
|
|
Packit |
857059 |
namep->leadzero = (namep->numlen > 1 && namep->body[i] == '0');
|
|
Packit |
857059 |
namep->body[i] = '\0';
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
namep->suffix = suffix;
|
|
Packit |
857059 |
DBGPRINT("name=%s, prefix=%s body=%s, suffix=%s\n", namep->name,
|
|
Packit |
857059 |
namep->prefix?namep->prefix:"", namep->body,
|
|
Packit |
857059 |
namep->suffix?namep->suffix:"");
|
|
Packit |
857059 |
DBGPRINT("numlen=%u, leadzero=%d, start=%u end=%u\n", namep->numlen,
|
|
Packit |
857059 |
namep->leadzero, namep->start, namep->end);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
void PrintName(const NameData_t *namep)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
if (namep->prefix)
|
|
Packit |
857059 |
printf("%s", namep->prefix);
|
|
Packit |
857059 |
printf("%.*s", NODE_DESCRIPTION_ARRAY_SIZE, namep->body);
|
|
Packit |
857059 |
if (namep->numlen) {
|
|
Packit |
857059 |
if (namep->leadzero)
|
|
Packit |
857059 |
if (namep->start != namep->end)
|
|
Packit |
857059 |
printf("[%0*u-%0*u]", namep->numlen, namep->start, namep->numlen, namep->end);
|
|
Packit |
857059 |
else
|
|
Packit |
857059 |
printf("%0*u", namep->numlen, namep->start);
|
|
Packit |
857059 |
else
|
|
Packit |
857059 |
if (namep->start != namep->end)
|
|
Packit |
857059 |
printf("[%u-%u]", namep->start, namep->end);
|
|
Packit |
857059 |
else
|
|
Packit |
857059 |
printf("%u", namep->start);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
if (namep->suffix)
|
|
Packit |
857059 |
printf("%s", namep->suffix);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
// is name2 numerically sequential and after name1
|
|
Packit |
857059 |
// if so we can consider combining them
|
|
Packit |
857059 |
boolean SequentialNames(const NameData_t *name1p, const NameData_t *name2p)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
// to optimize speed of compare, we do the faster checks 1st
|
|
Packit |
857059 |
if (! name1p->numlen || ! name2p->numlen)
|
|
Packit |
857059 |
return FALSE; // only sequential if have numbers
|
|
Packit |
857059 |
if (name1p->end+1 != name2p->start)
|
|
Packit |
857059 |
return FALSE; // not in sequence
|
|
Packit |
857059 |
if (name1p->leadzero && name1p->numlen == name2p->numlen) {
|
|
Packit |
857059 |
// ok, leading zeros in the lower numbered namep and constant length
|
|
Packit |
857059 |
} else if (!name2p->leadzero && ! name2p->leadzero) {
|
|
Packit |
857059 |
// ok, no leading zeros, all good
|
|
Packit |
857059 |
} else {
|
|
Packit |
857059 |
return FALSE; // number representation inconsistent
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
#if ! RANGE_IN_MIDDLE
|
|
Packit |
857059 |
if (name1p->suffix || name2p->suffix)
|
|
Packit |
857059 |
return FALSE; // can't have range in middle of a name
|
|
Packit |
857059 |
#endif
|
|
Packit |
857059 |
if (name1p->prefix) {
|
|
Packit |
857059 |
if (!name2p->prefix || 0 != strncmp(name1p->prefix, name2p->prefix, NODE_DESCRIPTION_ARRAY_SIZE))
|
|
Packit |
857059 |
return FALSE; // different prefix
|
|
Packit |
857059 |
} else if (name2p->prefix) {
|
|
Packit |
857059 |
return FALSE; // different prefix
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
if (0 != strncmp(name1p->body, name2p->body, NODE_DESCRIPTION_ARRAY_SIZE))
|
|
Packit |
857059 |
return FALSE; // different body
|
|
Packit |
857059 |
|
|
Packit |
857059 |
if (name1p->suffix) {
|
|
Packit |
857059 |
if (!name2p->suffix || 0 != strncmp(name1p->suffix, name2p->suffix, NODE_DESCRIPTION_ARRAY_SIZE))
|
|
Packit |
857059 |
return FALSE; // different suffix
|
|
Packit |
857059 |
} else if (name2p->suffix) {
|
|
Packit |
857059 |
return FALSE; // different suffix
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
return TRUE;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
// compare two names and return:
|
|
Packit |
857059 |
// -1 - name1 < name2
|
|
Packit |
857059 |
// 0 - name1 == name2
|
|
Packit |
857059 |
// 1 - name1 > name2
|
|
Packit |
857059 |
int CompareNameData(IN const uint64 name1, IN const uint64 name2)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
const NameData_t *name1p = (const NameData_t*)name1;
|
|
Packit |
857059 |
const NameData_t *name2p = (const NameData_t*)name2;
|
|
Packit |
857059 |
int ret;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
DBGPRINT("CompareNameData: %s, %s\n", name1p->name, name2p->name);
|
|
Packit |
857059 |
if (name1p->prefix) {
|
|
Packit |
857059 |
if (!name2p->prefix) {
|
|
Packit |
857059 |
return 1;
|
|
Packit |
857059 |
} else {
|
|
Packit |
857059 |
ret = strncmp(name1p->prefix, name2p->prefix, NODE_DESCRIPTION_ARRAY_SIZE);
|
|
Packit |
857059 |
if (ret)
|
|
Packit |
857059 |
return ret;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
} else if (name2p->prefix) {
|
|
Packit |
857059 |
return -1;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
ret = strncmp(name1p->body, name2p->body, NODE_DESCRIPTION_ARRAY_SIZE);
|
|
Packit |
857059 |
if (ret)
|
|
Packit |
857059 |
return ret;
|
|
Packit |
857059 |
if (! name1p->numlen || ! name2p->numlen) {
|
|
Packit |
857059 |
// if only 1 has a number, put one without a number 1st
|
|
Packit |
857059 |
if (name1p->numlen)
|
|
Packit |
857059 |
return 1;
|
|
Packit |
857059 |
else if (name2p->numlen)
|
|
Packit |
857059 |
return -1;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
// for RANGE_IN_MIDDLE we want items with same suffix together so we can
|
|
Packit |
857059 |
// find best opportunities to combine, so sort by suffix prior to sorting
|
|
Packit |
857059 |
// by numeric field
|
|
Packit |
857059 |
// for ! RANGE_IN_MIDDLE, we want to sort by suffix after sort by numeric
|
|
Packit |
857059 |
if (name1p->suffix) {
|
|
Packit |
857059 |
if (!name2p->suffix) {
|
|
Packit |
857059 |
ret = 1;
|
|
Packit |
857059 |
} else {
|
|
Packit |
857059 |
ret = strncmp(name1p->suffix, name2p->suffix, NODE_DESCRIPTION_ARRAY_SIZE);
|
|
Packit |
857059 |
if (ret)
|
|
Packit |
857059 |
return ret;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
} else if (name2p->suffix) {
|
|
Packit |
857059 |
ret = -1;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
#if RANGE_IN_MIDDLE
|
|
Packit |
857059 |
if (ret)
|
|
Packit |
857059 |
return ret;
|
|
Packit |
857059 |
#endif
|
|
Packit |
857059 |
if (! name1p->numlen && ! name2p->numlen)
|
|
Packit |
857059 |
return ret;
|
|
Packit |
857059 |
// if we see two styles of format, we want to sort those with shorter
|
|
Packit |
857059 |
// numeric fields first. c0, c1, c000, c001 so we can find best
|
|
Packit |
857059 |
// opportunities to combine sequential ranges
|
|
Packit |
857059 |
if (name1p->leadzero || name2p->leadzero) {
|
|
Packit |
857059 |
if (name1p->numlen < name2p->numlen)
|
|
Packit |
857059 |
return -1;
|
|
Packit |
857059 |
else if (name1p->numlen > name2p->numlen)
|
|
Packit |
857059 |
return -1;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
if (name1p->start < name2p->start)
|
|
Packit |
857059 |
return -1;
|
|
Packit |
857059 |
else if (name1p->start > name2p->start)
|
|
Packit |
857059 |
return 1;
|
|
Packit |
857059 |
else
|
|
Packit |
857059 |
return ret;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
// updates name1p to include name2p
|
|
Packit |
857059 |
// only valid if name1p and name2p are sequential
|
|
Packit |
857059 |
// before or after this update, name2p should be remove from list
|
|
Packit |
857059 |
void CombineNames(NameData_t *name1p, const NameData_t *name2p)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
DEBUG_ASSERT(SequentialNames(name1p, name2p));
|
|
Packit |
857059 |
DBGPRINT("Combining: %s, %s\n", name1p->name, name2p->name);
|
|
Packit |
857059 |
name1p->end = name2p->end;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
// --------------------- NameData list functions ----------------------------
|
|
Packit |
857059 |
|
|
Packit |
857059 |
void InitNameList(cl_qmap_t *listp)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
cl_qmap_init(listp, CompareNameData);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
// add name to list if not already on list
|
|
Packit |
857059 |
// the algorithm assumes duplicates are relatively infrequent so its simpler
|
|
Packit |
857059 |
// to just build the final NameData for comparison and throw it away on a
|
|
Packit |
857059 |
// duplicate. Alternatives would be more complex and have an extra copy
|
|
Packit |
857059 |
// of the name string for each non-dup
|
|
Packit |
857059 |
// rationale:
|
|
Packit |
857059 |
// - hosts on a switch will have no dups
|
|
Packit |
857059 |
// - ISLs will have dups limited to trunk size of link (1-4 typical)
|
|
Packit |
857059 |
FSTATUS AddNameList(cl_qmap_t *listp, const char* name, EUI64 guid, name_mode_t mode,
|
|
Packit |
857059 |
const char *prefix, const char *suffix)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
NameData_t *namep;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
if (name)
|
|
Packit |
857059 |
DBGPRINT("AddNameList: %s 0x%016"PRIx64"\n", name, guid);
|
|
Packit |
857059 |
else
|
|
Packit |
857059 |
DBGPRINT("AddNameList: NULL 0x%016"PRIx64"\n", guid);
|
|
Packit |
857059 |
namep = (NameData_t *)MemoryAllocate2AndClear(sizeof(NameData_t), IBA_MEM_FLAG_PREMPTABLE, MYTAG);
|
|
Packit |
857059 |
if (! namep) {
|
|
Packit |
857059 |
fprintf(stderr, "Out of memory\n");
|
|
Packit |
857059 |
return FINSUFFICIENT_MEMORY;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
CopyName(namep, name, guid, mode, prefix, suffix);
|
|
Packit |
857059 |
if (cl_qmap_insert(listp, (uint64)(uintn)namep, &namep->NameListEntry) != &namep->NameListEntry) {
|
|
Packit |
857059 |
// name already on list
|
|
Packit |
857059 |
MemoryDeallocate(namep);
|
|
Packit |
857059 |
return FSUCCESS;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
DBGPRINT("AddNameList: created new entry\n");
|
|
Packit |
857059 |
return FSUCCESS;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
// take the sorted list and convert sequential names to a numeric range
|
|
Packit |
857059 |
// two styles of numeric ranges: name[0-10] and name[00-10] indicate if
|
|
Packit |
857059 |
// leading zeros were present in the original names
|
|
Packit |
857059 |
void CompactNameList(cl_qmap_t *listp)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
cl_map_item_t *p;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
DBGPRINT("compacting name list\n");
|
|
Packit |
857059 |
for (p=cl_qmap_head(listp); p != cl_qmap_end(listp);) {
|
|
Packit |
857059 |
NameData_t *name1p = PARENT_STRUCT(p, NameData_t, NameListEntry);
|
|
Packit |
857059 |
NameData_t *name2p;
|
|
Packit |
857059 |
cl_map_item_t *next= cl_qmap_next(p);
|
|
Packit |
857059 |
if (next == cl_qmap_end(listp))
|
|
Packit |
857059 |
break;
|
|
Packit |
857059 |
DBGPRINT("compacting name list: p: %p, next: %p\n", p, next);
|
|
Packit |
857059 |
name2p = PARENT_STRUCT(next, NameData_t, NameListEntry);
|
|
Packit |
857059 |
if (SequentialNames(name1p, name2p)) {
|
|
Packit |
857059 |
cl_qmap_remove_item(listp, next);
|
|
Packit |
857059 |
CombineNames(name1p, name2p);
|
|
Packit |
857059 |
MemoryDeallocate(name2p);
|
|
Packit |
857059 |
} else {
|
|
Packit |
857059 |
p = cl_qmap_next(p);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
void FreeNameList(cl_qmap_t *listp)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
cl_map_item_t *p;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
for (p=cl_qmap_head(listp); p != cl_qmap_end(listp); p = cl_qmap_head(listp)) {
|
|
Packit |
857059 |
NameData_t *namep = PARENT_STRUCT(p, NameData_t, NameListEntry);
|
|
Packit |
857059 |
cl_qmap_remove_item(listp, p);
|
|
Packit |
857059 |
MemoryDeallocate(namep);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
// --------------------- SwitchLists functions ----------------------------
|
|
Packit |
857059 |
|
|
Packit |
857059 |
static __inline cl_qmap_t *GetSwitchFiNeighNameList(ExpectedNode *enodep)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
return &((SwitchLists_t*)enodep->context)->fiNeighborNames;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
static __inline cl_qmap_t *GetSwitchSwNeighNameList(ExpectedNode *enodep)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
return &((SwitchLists_t*)enodep->context)->swNeighborNames;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
static __inline uint8 GetSwitchTier(ExpectedNode *enodep)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
return ((SwitchLists_t*)enodep->context)->tier;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
static __inline DLIST *GetSwitchSwNeighList(ExpectedNode *enodep)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
return &((SwitchLists_t*)enodep->context)->swNeighbors;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
FSTATUS AllocSwitchLists(ExpectedNode *enodep)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
enodep->context = MemoryAllocate2AndClear(sizeof(SwitchLists_t), IBA_MEM_FLAG_PREMPTABLE, MYTAG);
|
|
Packit |
857059 |
if (! enodep->context)
|
|
Packit |
857059 |
return FINSUFFICIENT_MEMORY;
|
|
Packit |
857059 |
InitNameList(GetSwitchFiNeighNameList(enodep));
|
|
Packit |
857059 |
InitNameList(GetSwitchSwNeighNameList(enodep));
|
|
Packit |
857059 |
ListInitState(&((SwitchLists_t*)enodep->context)->swNeighbors);
|
|
Packit |
857059 |
if (! ListInit(&((SwitchLists_t*)enodep->context)->swNeighbors, MIN_LIST_ITEMS))
|
|
Packit |
857059 |
goto fail;
|
|
Packit |
857059 |
return FSUCCESS;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
fail:
|
|
Packit |
857059 |
MemoryDeallocate(enodep->context);
|
|
Packit |
857059 |
return FINSUFFICIENT_MEMORY;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
void FreeSwitchLists(ExpectedNode *enodep)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
if (enodep->context) {
|
|
Packit |
857059 |
FreeNameList(GetSwitchFiNeighNameList(enodep));
|
|
Packit |
857059 |
FreeNameList(GetSwitchSwNeighNameList(enodep));
|
|
Packit |
857059 |
ListDestroy(&((SwitchLists_t*)enodep->context)->swNeighbors);
|
|
Packit |
857059 |
MemoryDeallocate(enodep->context);
|
|
Packit |
857059 |
enodep->context = NULL;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
FSTATUS AddSwitchFiNameList(ExpectedNode *enodep, const char* name, EUI64 guid, name_mode_t mode,
|
|
Packit |
857059 |
const char *prefix, const char *suffix)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
if (! enodep->context) {
|
|
Packit |
857059 |
FSTATUS status = AllocSwitchLists(enodep);
|
|
Packit |
857059 |
if (FSUCCESS != status)
|
|
Packit |
857059 |
return status;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
return AddNameList(GetSwitchFiNeighNameList(enodep), name, guid, mode,
|
|
Packit |
857059 |
prefix, suffix);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
FSTATUS AddSwitchSwNameList(ExpectedNode *enodep, const char* name, EUI64 guid, name_mode_t mode,
|
|
Packit |
857059 |
const char *prefix, const char *suffix)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
if (! enodep->context) {
|
|
Packit |
857059 |
FSTATUS status = AllocSwitchLists(enodep);
|
|
Packit |
857059 |
if (FSUCCESS != status)
|
|
Packit |
857059 |
return status;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
return AddNameList(GetSwitchSwNeighNameList(enodep), name, guid, mode,
|
|
Packit |
857059 |
prefix, suffix);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
FSTATUS SetSwitchTier(ExpectedNode *enodep, uint8 tier)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
if (! enodep->context) {
|
|
Packit |
857059 |
FSTATUS status = AllocSwitchLists(enodep);
|
|
Packit |
857059 |
if (FSUCCESS != status)
|
|
Packit |
857059 |
return status;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
((SwitchLists_t*)enodep->context)->tier = tier;
|
|
Packit |
857059 |
return FSUCCESS;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
FSTATUS AddSwitchSwNeighbor(ExpectedNode *enodep, ExpectedNode *swnodep)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
if (! enodep->context) {
|
|
Packit |
857059 |
FSTATUS status = AllocSwitchLists(enodep);
|
|
Packit |
857059 |
if (FSUCCESS != status)
|
|
Packit |
857059 |
return status;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
if (! ListInsertTail(&((SwitchLists_t*)enodep->context)->swNeighbors, swnodep))
|
|
Packit |
857059 |
return FINSUFFICIENT_MEMORY;
|
|
Packit |
857059 |
return FSUCCESS;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
// analyze the expected links to determine the swNeighbors for each switch.
|
|
Packit |
857059 |
// TBD - Future - would be nice to be able to filter out selected hosts such as
|
|
Packit |
857059 |
// service nodes connected to core, but would need to figure out how to
|
|
Packit |
857059 |
// filter out edge switches left with no hosts so they aren't mistaken for
|
|
Packit |
857059 |
// core switches. For now, SLURM uses with impure trees or other topologies
|
|
Packit |
857059 |
// should use the -o slurm option which will provide a brief report which does
|
|
Packit |
857059 |
// not list all the ISLs
|
|
Packit |
857059 |
void BuildSwitchNeighList(boolean get_isls)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
LIST_ITEM *q;
|
|
Packit |
857059 |
LIST_ITEM *p;
|
|
Packit |
857059 |
uint8 tier = 0;
|
|
Packit |
857059 |
boolean found;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
if (! get_isls)
|
|
Packit |
857059 |
return;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
// now populate swNeighbors for each switch and identify tier 1 switches
|
|
Packit |
857059 |
for (q=QListHead(&g_Fabric.ExpectedLinks); q != NULL; q = QListNext(&g_Fabric.ExpectedLinks, q)) {
|
|
Packit |
857059 |
ExpectedLink *elinkp = (ExpectedLink *)QListObj(q);
|
|
Packit |
857059 |
|
|
Packit |
857059 |
if (! elinkp->portselp1 || ! elinkp->portselp1->enodep
|
|
Packit |
857059 |
|| ! elinkp->portselp2 || ! elinkp->portselp2->enodep) {
|
|
Packit |
857059 |
// Skipping Link, unresolved
|
|
Packit |
857059 |
continue;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
// figure out the types on both ends
|
|
Packit |
857059 |
switch (elinkp->portselp1->enodep->NodeType) {
|
|
Packit |
857059 |
case STL_NODE_FI:
|
|
Packit |
857059 |
switch (elinkp->portselp2->enodep->NodeType) {
|
|
Packit |
857059 |
case STL_NODE_FI: // FI<->FI
|
|
Packit |
857059 |
// Skipping Link, unexpected FI<->FI link
|
|
Packit |
857059 |
break;
|
|
Packit |
857059 |
case STL_NODE_SW: // FI<->SW
|
|
Packit |
857059 |
(void)SetSwitchTier(elinkp->portselp2->enodep, 1);
|
|
Packit |
857059 |
break;
|
|
Packit |
857059 |
default: // should not happen, enodep should always have type
|
|
Packit |
857059 |
// Skipping Link, unspecified NodeType
|
|
Packit |
857059 |
break;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
break;
|
|
Packit |
857059 |
case STL_NODE_SW:
|
|
Packit |
857059 |
switch (elinkp->portselp2->NodeType) {
|
|
Packit |
857059 |
case STL_NODE_FI: // SW<->FI
|
|
Packit |
857059 |
(void)SetSwitchTier(elinkp->portselp1->enodep, 1);
|
|
Packit |
857059 |
break;
|
|
Packit |
857059 |
case STL_NODE_SW: // SW<->SW
|
|
Packit |
857059 |
(void)AddSwitchSwNeighbor(elinkp->portselp1->enodep, elinkp->portselp2->enodep);
|
|
Packit |
857059 |
(void)AddSwitchSwNeighbor(elinkp->portselp2->enodep, elinkp->portselp1->enodep);
|
|
Packit |
857059 |
break;
|
|
Packit |
857059 |
default: // should not happen, enodep should always have type
|
|
Packit |
857059 |
// Skipping Link, unspecified NodeType
|
|
Packit |
857059 |
break;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
break;
|
|
Packit |
857059 |
default: // should not happen, enodep should always have type
|
|
Packit |
857059 |
// Skipping Link, unspecified NodeType
|
|
Packit |
857059 |
continue;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
// now we have tier 1 switches identified, need to walk up the tree to
|
|
Packit |
857059 |
// identify higher tier switches (higher is closer to core and further from
|
|
Packit |
857059 |
// FIs)
|
|
Packit |
857059 |
// This algorithm is based on Topology/route.c:DetermineSwitchTiers except
|
|
Packit |
857059 |
// this works with ExpectedNode while route.c works with NodeData
|
|
Packit |
857059 |
//
|
|
Packit |
857059 |
// switches connected to tier 1 switches are tier 2, etc
|
|
Packit |
857059 |
|
|
Packit |
857059 |
// This algorithm works fine for pure trees, however for impure trees
|
|
Packit |
857059 |
// it can yield unexpected results, for example a core switch with an HFI
|
|
Packit |
857059 |
// will be considered a tier 1 switch.
|
|
Packit |
857059 |
tier=2;
|
|
Packit |
857059 |
do {
|
|
Packit |
857059 |
found = FALSE;
|
|
Packit |
857059 |
for (p=QListHead(&g_Fabric.ExpectedSWs); p != NULL; p = QListNext(&g_Fabric.ExpectedSWs, p)) {
|
|
Packit |
857059 |
ExpectedNode *enodep = (ExpectedNode *)QListObj(p);
|
|
Packit |
857059 |
LIST_ITERATOR i;
|
|
Packit |
857059 |
if (GetSwitchTier(enodep) != tier-1)
|
|
Packit |
857059 |
continue;
|
|
Packit |
857059 |
for (i=ListHead(GetSwitchSwNeighList(enodep)); i != NULL;
|
|
Packit |
857059 |
i = ListNext(GetSwitchSwNeighList(enodep),i)) {
|
|
Packit |
857059 |
ExpectedNode* nswnodep = (ExpectedNode*)ListObj(i);
|
|
Packit |
857059 |
if (! GetSwitchTier(nswnodep)) {
|
|
Packit |
857059 |
SetSwitchTier(nswnodep, tier);
|
|
Packit |
857059 |
found = TRUE;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
tier++;
|
|
Packit |
857059 |
} while (found);
|
|
Packit |
857059 |
return;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
// Analyze ExpectedLinks and build lists of neighbors in ExpectedSW's context
|
|
Packit |
857059 |
// pointer in preparation for output generation
|
|
Packit |
857059 |
// The algorithm here assumes:
|
|
Packit |
857059 |
// - ExpectedSWs and ExpectedLinks are both supplied and consistent
|
|
Packit |
857059 |
// - NodeDesc and/or NodeGUID is listed for each entry
|
|
Packit |
857059 |
// - All entries in both have NodeType
|
|
Packit |
857059 |
// The above will all be true if the topology.xml was autogenerated by
|
|
Packit |
857059 |
// opaxlattopologory or opareport -o topology
|
|
Packit |
857059 |
void BuildAllSwitchLists(name_mode_t switch_name_mode, name_mode_t node_name_mode, boolean get_isls, boolean get_hfis)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
LIST_ITEM *q;
|
|
Packit |
857059 |
uint32 input_checked = 0;
|
|
Packit |
857059 |
uint32 bad_input = 0;
|
|
Packit |
857059 |
uint32 fi_links = 0;
|
|
Packit |
857059 |
uint32 isl_links = 0;
|
|
Packit |
857059 |
uint32 bad_isl_links = 0;
|
|
Packit |
857059 |
uint32 ix = 0;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
BuildSwitchNeighList(get_isls);
|
|
Packit |
857059 |
|
|
Packit |
857059 |
PROGRESS_PRINT(TRUE, "Processing Links...");
|
|
Packit |
857059 |
for (q=QListHead(&g_Fabric.ExpectedLinks); q != NULL; q = QListNext(&g_Fabric.ExpectedLinks, q)) {
|
|
Packit |
857059 |
ExpectedLink *elinkp = (ExpectedLink *)QListObj(q);
|
|
Packit |
857059 |
ExpectedNode *swenodep = NULL;
|
|
Packit |
857059 |
ExpectedNode *nswenodep = NULL;
|
|
Packit |
857059 |
ExpectedNode *fienodep = NULL;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
if ((ix++ % PROGRESS_FREQ) == 0) {
|
|
Packit |
857059 |
PROGRESS_PRINT(FALSE, "Processed %6d of %6d Links...",
|
|
Packit |
857059 |
ix, QListCount(&g_Fabric.ExpectedLinks));
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
if (! elinkp->portselp1 || ! elinkp->portselp1->enodep
|
|
Packit |
857059 |
|| ! elinkp->portselp2 || ! elinkp->portselp2->enodep) {
|
|
Packit |
857059 |
fprintf(stderr, "Skipping Link (topology file line %"PRIu64"), unresolved:\n", elinkp->lineno);
|
|
Packit |
857059 |
ShowExpectedLinkSummary(elinkp, 4, 0);
|
|
Packit |
857059 |
bad_input++;
|
|
Packit |
857059 |
continue;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
// figure out the types on both ends, want FI-SW and SW-SW links
|
|
Packit |
857059 |
switch (elinkp->portselp1->enodep->NodeType) {
|
|
Packit |
857059 |
case STL_NODE_FI:
|
|
Packit |
857059 |
switch (elinkp->portselp2->enodep->NodeType) {
|
|
Packit |
857059 |
case STL_NODE_FI:
|
|
Packit |
857059 |
fprintf(stderr, "Skipping Link (topology file line %"PRIu64"), unexpected FI<->FI link:\n", elinkp->lineno);
|
|
Packit |
857059 |
ShowExpectedLinkSummary(elinkp, 4, 0);
|
|
Packit |
857059 |
bad_input++;
|
|
Packit |
857059 |
continue;
|
|
Packit |
857059 |
case STL_NODE_SW:
|
|
Packit |
857059 |
fienodep = elinkp->portselp1->enodep;
|
|
Packit |
857059 |
swenodep = elinkp->portselp2->enodep;
|
|
Packit |
857059 |
break;
|
|
Packit |
857059 |
default:
|
|
Packit |
857059 |
fprintf(stderr, "Skipping Link (topology file line %"PRIu64"), unspecified NodeType:\n", elinkp->lineno);
|
|
Packit |
857059 |
ShowExpectedLinkSummary(elinkp, 4, 0);
|
|
Packit |
857059 |
bad_input++;
|
|
Packit |
857059 |
continue;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
break;
|
|
Packit |
857059 |
case STL_NODE_SW:
|
|
Packit |
857059 |
switch (elinkp->portselp2->enodep->NodeType) {
|
|
Packit |
857059 |
case STL_NODE_FI:
|
|
Packit |
857059 |
swenodep = elinkp->portselp1->enodep;
|
|
Packit |
857059 |
fienodep = elinkp->portselp2->enodep;
|
|
Packit |
857059 |
break;
|
|
Packit |
857059 |
case STL_NODE_SW:
|
|
Packit |
857059 |
swenodep = elinkp->portselp1->enodep;
|
|
Packit |
857059 |
nswenodep = elinkp->portselp2->enodep;
|
|
Packit |
857059 |
break;
|
|
Packit |
857059 |
default:
|
|
Packit |
857059 |
fprintf(stderr, "Skipping Link (topology file line %"PRIu64"), unspecified NodeType:\n", elinkp->lineno);
|
|
Packit |
857059 |
ShowExpectedLinkSummary(elinkp, 4, 0);
|
|
Packit |
857059 |
bad_input++;
|
|
Packit |
857059 |
continue;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
break;
|
|
Packit |
857059 |
default:
|
|
Packit |
857059 |
fprintf(stderr, "Skipping Link (topology file line %"PRIu64"), unspecified NodeType:\n", elinkp->lineno);
|
|
Packit |
857059 |
ShowExpectedLinkSummary(elinkp, 4, 0);
|
|
Packit |
857059 |
bad_input++;
|
|
Packit |
857059 |
continue;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
// now swenodep is a SW
|
|
Packit |
857059 |
// if neighbor is a FI, fienodep is non-NULL
|
|
Packit |
857059 |
// if neighbor is a SW, nswenodep is non-NULL
|
|
Packit |
857059 |
DEBUG_ASSERT(swenodep);
|
|
Packit |
857059 |
DEBUG_ASSERT(nswenodep || fienodep);
|
|
Packit |
857059 |
|
|
Packit |
857059 |
if ( ! get_hfis && ! nswenodep)
|
|
Packit |
857059 |
continue; // skip FI-SW link
|
|
Packit |
857059 |
if ( ! get_isls && ! fienodep)
|
|
Packit |
857059 |
continue; // skip SW-SW link
|
|
Packit |
857059 |
if (! CompareExpectedLinkFocus(elinkp))
|
|
Packit |
857059 |
continue;
|
|
Packit |
857059 |
input_checked++;
|
|
Packit |
857059 |
if (fienodep) { // FI<->SW
|
|
Packit |
857059 |
(void)AddSwitchFiNameList(swenodep, fienodep->NodeDesc, fienodep->NodeGUID, node_name_mode, g_prefix, g_suffix);
|
|
Packit |
857059 |
fi_links++;
|
|
Packit |
857059 |
} else { // SW<->SW
|
|
Packit |
857059 |
// only add downlink which goes from upper tier switch to lower tier
|
|
Packit |
857059 |
// SLURM wants just one direction reported for each link, so
|
|
Packit |
857059 |
// we only report downlinks in pure trees and warn if any links are
|
|
Packit |
857059 |
// found which are not tier X to tier X-1 or tier X+1
|
|
Packit |
857059 |
if (GetSwitchTier(swenodep) == GetSwitchTier(nswenodep)+1) {
|
|
Packit |
857059 |
(void)AddSwitchSwNameList(swenodep, nswenodep->NodeDesc, nswenodep->NodeGUID, switch_name_mode, NULL, NULL);
|
|
Packit |
857059 |
isl_links++;
|
|
Packit |
857059 |
} else if (GetSwitchTier(nswenodep) == GetSwitchTier(swenodep)+1) {
|
|
Packit |
857059 |
(void)AddSwitchSwNameList(nswenodep, swenodep->NodeDesc, swenodep->NodeGUID, switch_name_mode, NULL, NULL);
|
|
Packit |
857059 |
isl_links++;
|
|
Packit |
857059 |
} else {
|
|
Packit |
857059 |
// This is a best attempt but will not catch all issues
|
|
Packit |
857059 |
// for example a 3 tier fabric with an HFI on the core will
|
|
Packit |
857059 |
// treat the core as a tier 1 which is connected to tier 2
|
|
Packit |
857059 |
// switches and hence not reported as an issue
|
|
Packit |
857059 |
fprintf(stderr, "Skipping Link (topology file line %"PRIu64"), not a pure tree:\n", elinkp->lineno);
|
|
Packit |
857059 |
ShowExpectedLinkSummary(elinkp, 4, 0);
|
|
Packit |
857059 |
bad_isl_links++;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
PROGRESS_PRINT(TRUE, "Done Processing Links");
|
|
Packit |
857059 |
fprintf(stderr, "%u of %u Input Links Selected, %u Bad Input Skipped\n",
|
|
Packit |
857059 |
input_checked, QListCount(&g_Fabric.ExpectedLinks), bad_input);
|
|
Packit |
857059 |
if (get_hfis)
|
|
Packit |
857059 |
fprintf(stderr, "%u Input FI Links Shown\n",
|
|
Packit |
857059 |
fi_links);
|
|
Packit |
857059 |
if (get_isls)
|
|
Packit |
857059 |
fprintf(stderr, "%u Input ISLs Shown, %u Bad ISLs Skipped\n",
|
|
Packit |
857059 |
isl_links, bad_isl_links);
|
|
Packit |
857059 |
return;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
void FreeAllSwitchNamelists(void)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
LIST_ITEM *p;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
for (p=QListHead(&g_Fabric.ExpectedSWs); p != NULL; p = QListNext(&g_Fabric.ExpectedSWs, p)) {
|
|
Packit |
857059 |
ExpectedNode *enodep = (ExpectedNode *)QListObj(p);
|
|
Packit |
857059 |
|
|
Packit |
857059 |
FreeSwitchLists(enodep);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
// --------------------- Focus functions ----------------------------
|
|
Packit |
857059 |
|
|
Packit |
857059 |
// compare against all -F options provided
|
|
Packit |
857059 |
// if matches any one of the -F options, returns TRUE
|
|
Packit |
857059 |
boolean CompareExpectedNodeFocus(ExpectedNode *enodep)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
int i;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
if (! g_num_focus)
|
|
Packit |
857059 |
return TRUE; // match everything if no focus
|
|
Packit |
857059 |
for (i=0; i < g_num_focus; i++)
|
|
Packit |
857059 |
if (CompareExpectedNodePoint(enodep, &g_focus[i]))
|
|
Packit |
857059 |
return TRUE;
|
|
Packit |
857059 |
return FALSE;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
// compare against all -F options provided
|
|
Packit |
857059 |
// if matches any one of the -F options, returns TRUE
|
|
Packit |
857059 |
boolean CompareExpectedLinkFocus(ExpectedLink *elinkp)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
int i;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
if (! g_num_focus)
|
|
Packit |
857059 |
return TRUE; // match everything if no focus
|
|
Packit |
857059 |
for (i=0; i < g_num_focus; i++)
|
|
Packit |
857059 |
if (CompareExpectedLinkPoint(elinkp, &g_focus[i]))
|
|
Packit |
857059 |
return TRUE;
|
|
Packit |
857059 |
return FALSE;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
// --------------------- Output functions ----------------------------
|
|
Packit |
857059 |
|
|
Packit |
857059 |
// output a comment indicating when and how the output was generated
|
|
Packit |
857059 |
void PrintComment(const char* commentchar, int argc, char **argv)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
char datestr[80] = "";
|
|
Packit |
857059 |
int i;
|
|
Packit |
857059 |
time_t now;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
time(&now;;
|
|
Packit |
857059 |
Top_formattime(datestr, sizeof(datestr), now);
|
|
Packit |
857059 |
printf("%s generated on %s\n", commentchar, datestr);
|
|
Packit |
857059 |
printf("%s using:", commentchar);
|
|
Packit |
857059 |
for (i=0; i
|
|
Packit |
857059 |
printf(" %s ", argv[i]);
|
|
Packit |
857059 |
printf("\n");
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
|
|
Packit |
857059 |
// Output FastFabric hosts list
|
|
Packit |
857059 |
// The algorithm here assumes:
|
|
Packit |
857059 |
// - ExpectedFIs is supplied
|
|
Packit |
857059 |
// - NodeDesc is listed for each entry
|
|
Packit |
857059 |
// - All entries have NodeType
|
|
Packit |
857059 |
// - this host should be omitted as its the fastfabric host
|
|
Packit |
857059 |
// The above will all be true if the topology.xml was autogenerated by
|
|
Packit |
857059 |
// opaxlattopologory or opareport -o topology
|
|
Packit |
857059 |
void ShowFastFabricHosts(name_mode_t node_name_mode)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
LIST_ITEM *p;
|
|
Packit |
857059 |
uint32 input_checked = 0;
|
|
Packit |
857059 |
uint32 bad_input = 0;
|
|
Packit |
857059 |
cl_qmap_t host_list;
|
|
Packit |
857059 |
cl_map_item_t *q;
|
|
Packit |
857059 |
char myhostname[NODE_DESCRIPTION_ARRAY_SIZE];
|
|
Packit |
857059 |
int i;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
ASSERT(node_name_mode != NAME_MODE_GUID);
|
|
Packit |
857059 |
|
|
Packit |
857059 |
if (0 != gethostname(myhostname, sizeof(myhostname))) {
|
|
Packit |
857059 |
// odd, just ignore filtering out our hostname
|
|
Packit |
857059 |
myhostname[0] = '\0';
|
|
Packit |
857059 |
} else {
|
|
Packit |
857059 |
// if hostname is truncated, might lack a trailing NUL
|
|
Packit |
857059 |
myhostname[NODE_DESCRIPTION_ARRAY_SIZE-1] = '\0';
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
// truncate any domain names
|
|
Packit |
857059 |
for (i=0; i< sizeof(myhostname); i++) {
|
|
Packit |
857059 |
if (myhostname[i] == '.') {
|
|
Packit |
857059 |
myhostname[i] = '\0';
|
|
Packit |
857059 |
break;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
DBGPRINT("myhostname=%.*s\n", NODE_DESCRIPTION_ARRAY_SIZE, myhostname);
|
|
Packit |
857059 |
|
|
Packit |
857059 |
InitNameList(&host_list);
|
|
Packit |
857059 |
for (p=QListHead(&g_Fabric.ExpectedFIs); p != NULL; p = QListNext(&g_Fabric.ExpectedFIs, p)) {
|
|
Packit |
857059 |
ExpectedNode *enodep = (ExpectedNode *)QListObj(p);
|
|
Packit |
857059 |
|
|
Packit |
857059 |
if (! enodep->NodeDesc) {
|
|
Packit |
857059 |
fprintf(stderr, "Skipping FI (topology file line %"PRIu64"), no name\n", enodep->lineno);
|
|
Packit |
857059 |
ShowExpectedNodeBriefSummary(enodep, 4, 0);
|
|
Packit |
857059 |
bad_input++;
|
|
Packit |
857059 |
continue;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
// be paranoid, this is probably not possible since we are checking
|
|
Packit |
857059 |
// ExpectedFIs list
|
|
Packit |
857059 |
if (enodep->NodeType != STL_NODE_FI) {
|
|
Packit |
857059 |
fprintf(stderr, "Skipping FI (topology file line %"PRIu64"), unspecified NodeType\n", enodep->lineno);
|
|
Packit |
857059 |
ShowExpectedNodeBriefSummary(enodep, 4, 0);
|
|
Packit |
857059 |
bad_input++;
|
|
Packit |
857059 |
continue; //unspecified type
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
if (! CompareExpectedNodeFocus(enodep))
|
|
Packit |
857059 |
continue;
|
|
Packit |
857059 |
input_checked++;
|
|
Packit |
857059 |
// put hosts in a list, if there are multi-rail hosts
|
|
Packit |
857059 |
// a given host will only be listed once
|
|
Packit |
857059 |
if (FSUCCESS != AddNameList(&host_list, enodep->NodeDesc, 0, node_name_mode, g_prefix, g_suffix)) {
|
|
Packit |
857059 |
// unexpected error
|
|
Packit |
857059 |
continue;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
// CompactNameList(&host_list); // FastFabric does not support ranges
|
|
Packit |
857059 |
|
|
Packit |
857059 |
for (q=cl_qmap_head(&host_list); q != cl_qmap_end(&host_list); q = cl_qmap_next(q)) {
|
|
Packit |
857059 |
NameData_t *namep = PARENT_STRUCT(q, NameData_t, NameListEntry);
|
|
Packit |
857059 |
if (0 == strncmp(myhostname, namep->name, NODE_DESCRIPTION_ARRAY_SIZE))
|
|
Packit |
857059 |
printf("#"); // comment out our host
|
|
Packit |
857059 |
PrintName(namep);
|
|
Packit |
857059 |
printf("\n");
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
FreeNameList(&host_list);
|
|
Packit |
857059 |
fprintf(stderr, "%u of %u Input FIs Shown, %u Bad Input Skipped\n",
|
|
Packit |
857059 |
input_checked, QListCount(&g_Fabric.ExpectedFIs), bad_input);
|
|
Packit |
857059 |
|
|
Packit |
857059 |
return;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
// Output SLURM topology file fake ISL single list of the form:
|
|
Packit |
857059 |
// SwitchName=fake Switches=abc,def,ghi
|
|
Packit |
857059 |
// This output form allows for faster SLURM operation by assuming that once
|
|
Packit |
857059 |
// scheduling gets outside a single edge switch, its roughly equivalent latency
|
|
Packit |
857059 |
// This also supports impure tree and other topologies
|
|
Packit |
857059 |
void ShowSlurmFakeISLs(name_mode_t switch_name_mode)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
LIST_ITEM *p;
|
|
Packit |
857059 |
ExpectedNode fake = {
|
|
Packit |
857059 |
NodeType: STL_NODE_SW,
|
|
Packit |
857059 |
NodeDesc: "fake",
|
|
Packit |
857059 |
NodeGUID: 0x00066A0102FFFFFF
|
|
Packit |
857059 |
};
|
|
Packit |
857059 |
|
|
Packit |
857059 |
// build list of neighbors for "fake" core switch listing all switches
|
|
Packit |
857059 |
// which have unfiltered FIs
|
|
Packit |
857059 |
for (p=QListHead(&g_Fabric.ExpectedSWs); p != NULL; p = QListNext(&g_Fabric.ExpectedSWs, p)) {
|
|
Packit |
857059 |
ExpectedNode *enodep = (ExpectedNode *)QListObj(p);
|
|
Packit |
857059 |
cl_qmap_t *neigh_list;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
if (! enodep->context) // switch has no neighbors
|
|
Packit |
857059 |
continue;
|
|
Packit |
857059 |
neigh_list = GetSwitchFiNeighNameList(enodep);
|
|
Packit |
857059 |
if (cl_qmap_head(neigh_list) == cl_qmap_end(neigh_list))
|
|
Packit |
857059 |
continue; // switch has no FI neighbors
|
|
Packit |
857059 |
(void)AddSwitchSwNameList(&fake, enodep->NodeDesc, enodep->NodeGUID, switch_name_mode, NULL, NULL);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
if (! fake.context)
|
|
Packit |
857059 |
return; // there are no switches with FIs
|
|
Packit |
857059 |
|
|
Packit |
857059 |
printf("# Fake Switch to Switch Connectivity\n");
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
ExpectedNode *enodep = &fak;;
|
|
Packit |
857059 |
int first=1;
|
|
Packit |
857059 |
cl_qmap_t *neigh_list;
|
|
Packit |
857059 |
cl_map_item_t *np;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
neigh_list = GetSwitchSwNeighNameList(enodep);
|
|
Packit |
857059 |
// if using GUIDs for names, simply skip compact and will
|
|
Packit |
857059 |
// get no ranges in output
|
|
Packit |
857059 |
if (switch_name_mode != NAME_MODE_GUID)
|
|
Packit |
857059 |
CompactNameList(neigh_list);
|
|
Packit |
857059 |
for (np=cl_qmap_head(neigh_list); np != cl_qmap_end(neigh_list); np = cl_qmap_next(np)) {
|
|
Packit |
857059 |
NameData_t *namep = PARENT_STRUCT(np, NameData_t, NameListEntry);
|
|
Packit |
857059 |
if (first) {
|
|
Packit |
857059 |
NameData_t nameData = { };
|
|
Packit |
857059 |
printf("SwitchName=");
|
|
Packit |
857059 |
CopyName(&nameData, enodep->NodeDesc, enodep->NodeGUID, switch_name_mode, NULL, NULL);
|
|
Packit |
857059 |
PrintName(&nameData);
|
|
Packit |
857059 |
printf(" Switches=");
|
|
Packit |
857059 |
first=0;
|
|
Packit |
857059 |
} else {
|
|
Packit |
857059 |
printf(",");
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
PrintName(namep);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
if (! first)
|
|
Packit |
857059 |
printf("\n");
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
FreeSwitchLists(&fake);
|
|
Packit |
857059 |
|
|
Packit |
857059 |
return;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
// Output SLURM topology file ISL lists for each switch of the form:
|
|
Packit |
857059 |
// SwitchName=xyz Switches=abc,def,ghi
|
|
Packit |
857059 |
void ShowSlurmISLs(name_mode_t switch_name_mode)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
LIST_ITEM *p;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
printf("# Switch to Switch Connectivity\n");
|
|
Packit |
857059 |
for (p=QListHead(&g_Fabric.ExpectedSWs); p != NULL; p = QListNext(&g_Fabric.ExpectedSWs, p)) {
|
|
Packit |
857059 |
ExpectedNode *enodep = (ExpectedNode *)QListObj(p);
|
|
Packit |
857059 |
cl_qmap_t *neigh_list;
|
|
Packit |
857059 |
int first=1;
|
|
Packit |
857059 |
cl_map_item_t *np;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
if (! enodep->context) // switch has no neighbors
|
|
Packit |
857059 |
continue;
|
|
Packit |
857059 |
neigh_list = GetSwitchSwNeighNameList(enodep);
|
|
Packit |
857059 |
// if using GUIDs for names, simply skip compact and will
|
|
Packit |
857059 |
// get no ranges in output
|
|
Packit |
857059 |
if (switch_name_mode != NAME_MODE_GUID)
|
|
Packit |
857059 |
CompactNameList(neigh_list);
|
|
Packit |
857059 |
for (np=cl_qmap_head(neigh_list); np != cl_qmap_end(neigh_list); np = cl_qmap_next(np)) {
|
|
Packit |
857059 |
NameData_t *namep = PARENT_STRUCT(np, NameData_t, NameListEntry);
|
|
Packit |
857059 |
if (first) {
|
|
Packit |
857059 |
NameData_t nameData = { };
|
|
Packit |
857059 |
printf("SwitchName=");
|
|
Packit |
857059 |
CopyName(&nameData, enodep->NodeDesc, enodep->NodeGUID, switch_name_mode, NULL, NULL);
|
|
Packit |
857059 |
PrintName(&nameData);
|
|
Packit |
857059 |
printf(" Switches=");
|
|
Packit |
857059 |
first=0;
|
|
Packit |
857059 |
} else {
|
|
Packit |
857059 |
printf(",");
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
PrintName(namep);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
if (! first)
|
|
Packit |
857059 |
printf("\n");
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
return;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
// Output SLURM topology file FI lists for each switch of the form:
|
|
Packit |
857059 |
// SwitchName=xyz Nodes=abc,def,ghi
|
|
Packit |
857059 |
void ShowSlurmNodes(name_mode_t switch_name_mode, name_mode_t node_name_mode)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
LIST_ITEM *p;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
printf("# Switch to FI Connectivity\n");
|
|
Packit |
857059 |
for (p=QListHead(&g_Fabric.ExpectedSWs); p != NULL; p = QListNext(&g_Fabric.ExpectedSWs, p)) {
|
|
Packit |
857059 |
ExpectedNode *enodep = (ExpectedNode *)QListObj(p);
|
|
Packit |
857059 |
cl_qmap_t *neigh_list;
|
|
Packit |
857059 |
int first=1;
|
|
Packit |
857059 |
cl_map_item_t *np;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
if (! enodep->context) // switch has no FI neighbors
|
|
Packit |
857059 |
continue;
|
|
Packit |
857059 |
neigh_list = GetSwitchFiNeighNameList(enodep);
|
|
Packit |
857059 |
// if using GUIDs for names, simply skip compact and will
|
|
Packit |
857059 |
// get no ranges in output
|
|
Packit |
857059 |
if (node_name_mode != NAME_MODE_GUID)
|
|
Packit |
857059 |
CompactNameList(neigh_list);
|
|
Packit |
857059 |
for (np=cl_qmap_head(neigh_list); np != cl_qmap_end(neigh_list); np = cl_qmap_next(np)) {
|
|
Packit |
857059 |
NameData_t *namep = PARENT_STRUCT(np, NameData_t, NameListEntry);
|
|
Packit |
857059 |
if (first) {
|
|
Packit |
857059 |
NameData_t nameData = { };
|
|
Packit |
857059 |
printf("SwitchName=");
|
|
Packit |
857059 |
CopyName(&nameData, enodep->NodeDesc, enodep->NodeGUID, switch_name_mode, NULL, NULL);
|
|
Packit |
857059 |
PrintName(&nameData);
|
|
Packit |
857059 |
printf(" Nodes=");
|
|
Packit |
857059 |
first=0;
|
|
Packit |
857059 |
} else {
|
|
Packit |
857059 |
printf(",");
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
PrintName(namep);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
if (! first)
|
|
Packit |
857059 |
printf("\n");
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
return;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
// command line options, each has a short and long flag name
|
|
Packit |
857059 |
struct option options[] = {
|
|
Packit |
857059 |
{ "verbose", no_argument, NULL, 'v' },
|
|
Packit |
857059 |
{ "quiet", no_argument, NULL, 'q' },
|
|
Packit |
857059 |
{ "output", required_argument, NULL, 'o' },
|
|
Packit |
857059 |
{ "guid", no_argument, NULL, 'g' },
|
|
Packit |
857059 |
{ "underscore", no_argument, NULL, 'u' },
|
|
Packit |
857059 |
{ "trunc", no_argument, NULL, 't' },
|
|
Packit |
857059 |
{ "prefix", required_argument, NULL, 'p' },
|
|
Packit |
857059 |
{ "suffix", required_argument, NULL, 's' },
|
|
Packit |
857059 |
{ "strict", required_argument, NULL, 'S' },
|
|
Packit |
857059 |
{ "check", required_argument, NULL, 'C' },
|
|
Packit |
857059 |
{ "focus", no_argument, NULL, 'F' },
|
|
Packit |
857059 |
{ "help", no_argument, NULL, '$' }, // use an invalid option character
|
|
Packit |
857059 |
|
|
Packit |
857059 |
{ 0 }
|
|
Packit |
857059 |
};
|
|
Packit |
857059 |
|
|
Packit |
857059 |
void Usage_full(void)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
fprintf(stderr, "Usage: opa2rm [-v] [-q] -o output [-g|-u|-t] [-F point]\n"
|
|
Packit |
857059 |
" [-p prefix] [-s suffix] topology_input\n");
|
|
Packit |
857059 |
fprintf(stderr, " or\n");
|
|
Packit |
857059 |
fprintf(stderr, " opa2rm --help\n");
|
|
Packit |
857059 |
fprintf(stderr, " --help - produce full help text\n");
|
|
Packit |
857059 |
fprintf(stderr, " -v/--verbose - verbose output\n");
|
|
Packit |
857059 |
fprintf(stderr, " -q/--quiet - disable progress reports\n");
|
|
Packit |
857059 |
fprintf(stderr, " -o/--output output - output type\n");
|
|
Packit |
857059 |
fprintf(stderr, " slurm - SLURM tree nodes\n");
|
|
Packit |
857059 |
fprintf(stderr, " Supports variety of topologies\n");
|
|
Packit |
857059 |
fprintf(stderr, " slurmfull - SLURM fat tree nodes and ISLs\n");
|
|
Packit |
857059 |
fprintf(stderr, " Only supports pure trees\n");
|
|
Packit |
857059 |
fprintf(stderr, " hosts - fastfabric hosts file\n");
|
|
Packit |
857059 |
fprintf(stderr, " omitting this host\n");
|
|
Packit |
857059 |
fprintf(stderr, " -g/--guid - output switch GUIDs instead of names\n");
|
|
Packit |
857059 |
fprintf(stderr, " -u/--underscore - change spaces in switch names to underscores\n");
|
|
Packit |
857059 |
fprintf(stderr, " -t/--trunc - merely truncate switch names at 1st space\n");
|
|
Packit |
857059 |
fprintf(stderr, " This will treat large director switches as a\n");
|
|
Packit |
857059 |
fprintf(stderr, " single big switch.\n");
|
|
Packit |
857059 |
fprintf(stderr, " If none of -g, -u nor -t are specified\n");
|
|
Packit |
857059 |
fprintf(stderr, " switch name suffixes after the first space\n");
|
|
Packit |
857059 |
fprintf(stderr, " will be placed at the start of the name.\n");
|
|
Packit |
857059 |
fprintf(stderr, " So 'core5 Leaf 101' becomes 'Leaf101_core5'\n");
|
|
Packit |
857059 |
fprintf(stderr, " -p/--prefix prefix - prefix to prepend to all FI hostnames\n");
|
|
Packit |
857059 |
fprintf(stderr, " -s/--suffix suffix - suffix to append to all FI hostnames\n");
|
|
Packit |
857059 |
fprintf(stderr, " -F/--focus point - focus area for output\n");
|
|
Packit |
857059 |
fprintf(stderr, " Limits scope of output to links\n");
|
|
Packit |
857059 |
fprintf(stderr, " which match any of the given focus points.\n");
|
|
Packit |
857059 |
fprintf(stderr, " May be specified up to %d times\n", MAX_FOCUS);
|
|
Packit |
857059 |
fprintf(stderr, " -C/--check - perform more topology file validation.\n");
|
|
Packit |
857059 |
fprintf(stderr, " Requires all links resolve against nodes,\n");
|
|
Packit |
857059 |
fprintf(stderr, " all nodes connected to same fabric and\n");
|
|
Packit |
857059 |
fprintf(stderr, " treats any resolution errors as fatal.\n");
|
|
Packit |
857059 |
fprintf(stderr, " -S/--strict - perform strict topology file validation.\n");
|
|
Packit |
857059 |
fprintf(stderr, " Performs all checks in -C, and\n");;
|
|
Packit |
857059 |
fprintf(stderr, " requires all nodes list PortNum and\n");
|
|
Packit |
857059 |
fprintf(stderr, " all nodes list ports used.\n");
|
|
Packit |
857059 |
fprintf(stderr, " topology_input - topology_input file to use\n");
|
|
Packit |
857059 |
fprintf(stderr, " '-' may be used to specify stdin\n");
|
|
Packit |
857059 |
// list only subset of formats applicable to ExpectedLink and useful here
|
|
Packit |
857059 |
// omit gid, portguid, nodeguid
|
|
Packit |
857059 |
fprintf(stderr, "Point Syntax:\n");
|
|
Packit |
857059 |
fprintf(stderr, " node:value - value is node description (node name)\n");
|
|
Packit |
857059 |
fprintf(stderr, " node:value1:port:value2 - value1 is node description (node name)\n");
|
|
Packit |
857059 |
fprintf(stderr, " value2 is port #\n");
|
|
Packit |
857059 |
fprintf(stderr, " nodepat:value - value is glob pattern for node description (node\n");
|
|
Packit |
857059 |
fprintf(stderr, " name)\n");
|
|
Packit |
857059 |
fprintf(stderr, " nodepat:value1:port:value2 - value1 is glob pattern for node description\n");
|
|
Packit |
857059 |
fprintf(stderr, " (node name), value2 is port #\n");
|
|
Packit |
857059 |
fprintf(stderr, " nodetype:value - value is node type (SW or FI)\n");
|
|
Packit |
857059 |
fprintf(stderr, " nodetype:value1:port:value2\n");
|
|
Packit |
857059 |
fprintf(stderr, " - value1 is node type (SW or FI)\n");
|
|
Packit |
857059 |
fprintf(stderr, " value2 is port #\n");
|
|
Packit |
857059 |
fprintf(stderr, " rate:value - value is string for rate (25g, 50g, 75g, 100g)\n");
|
|
Packit |
857059 |
fprintf(stderr, " omits switch mgmt port 0\n");
|
|
Packit |
857059 |
fprintf(stderr, " mtucap:value - value is MTU size (2048, 4096, 8192, 10240)\n");
|
|
Packit |
857059 |
fprintf(stderr, " omits switch mgmt port 0\n");
|
|
Packit |
857059 |
fprintf(stderr, " labelpat:value - value is glob pattern for cable label\n");
|
|
Packit |
857059 |
fprintf(stderr, " lengthpat:value - value is glob pattern for cable length\n");
|
|
Packit |
857059 |
fprintf(stderr, " cabledetpat:value - value is glob pattern for cable details\n");
|
|
Packit |
857059 |
fprintf(stderr, " linkdetpat:value - value is glob pattern for link details\n");
|
|
Packit |
857059 |
fprintf(stderr, " portdetpat:value - value is glob pattern for port details\n");
|
|
Packit |
857059 |
fprintf(stderr, " to value\n");
|
|
Packit |
857059 |
fprintf(stderr, "Examples:\n");
|
|
Packit |
857059 |
fprintf(stderr, " opa2rm -o slurm topology.xml\n");
|
|
Packit |
857059 |
fprintf(stderr, " opa2rm -o slurm -p 'opa-' topology.xml\n");
|
|
Packit |
857059 |
fprintf(stderr, " opa2rm -o slurm -s '-opa' topology.xml\n");
|
|
Packit |
857059 |
fprintf(stderr, " opa2rm -o slurm -F 'nodepat:compute*' -F 'nodepat:opacore1 *' topology.xml\n");
|
|
Packit |
857059 |
fprintf(stderr, " opa2rm -o hosts -F 'nodedetpat:compute*' topology.xml\n");
|
|
Packit |
857059 |
fprintf(stderr, " opa2rm -o hosts topology.xml\n");
|
|
Packit |
857059 |
exit(0);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
void Usage(void)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
fprintf(stderr, "Usage: opa2rm [-v] [-q] -o output [-g|-u|-t] topology_input\n");
|
|
Packit |
857059 |
fprintf(stderr, " or\n");
|
|
Packit |
857059 |
fprintf(stderr, " opa2rm --help\n");
|
|
Packit |
857059 |
fprintf(stderr, " --help - produce full help text\n");
|
|
Packit |
857059 |
fprintf(stderr, " -v/--verbose - verbose output\n");
|
|
Packit |
857059 |
fprintf(stderr, " -q/--quiet - disable progress reports\n");
|
|
Packit |
857059 |
fprintf(stderr, " -o/--output output - output type\n");
|
|
Packit |
857059 |
fprintf(stderr, " slurm - SLURM tree nodes\n");
|
|
Packit |
857059 |
fprintf(stderr, " Supports variety of topologies\n");
|
|
Packit |
857059 |
fprintf(stderr, " slurmfull - SLURM fat tree nodes and ISLs\n");
|
|
Packit |
857059 |
fprintf(stderr, " Only supports pure trees\n");
|
|
Packit |
857059 |
fprintf(stderr, " hosts - fastfabric hosts file\n");
|
|
Packit |
857059 |
fprintf(stderr, " omitting this host\n");
|
|
Packit |
857059 |
fprintf(stderr, " -g/--guid - output switch GUIDs instead of names\n");
|
|
Packit |
857059 |
fprintf(stderr, " -u/--underscore - instead of flipping any switch name suffix to\n");
|
|
Packit |
857059 |
fprintf(stderr, " start, merely change spaces to underscore\n");
|
|
Packit |
857059 |
fprintf(stderr, " -t/--trunc - instead of flipping any switch name suffix to\n");
|
|
Packit |
857059 |
fprintf(stderr, " start, merely truncate at 1st space\n");
|
|
Packit |
857059 |
fprintf(stderr, " topology_input - topology_input file to use\n");
|
|
Packit |
857059 |
fprintf(stderr, " '-' may be used to specify stdin\n");
|
|
Packit |
857059 |
exit(2);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
typedef enum { // bitmask indicating selected reports
|
|
Packit |
857059 |
REPORT_NONE =0x0,
|
|
Packit |
857059 |
REPORT_SLURM =0x1,
|
|
Packit |
857059 |
REPORT_SLURMFULL =0x2,
|
|
Packit |
857059 |
REPORT_HOSTS =0x4,
|
|
Packit |
857059 |
} report_t;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
|
|
Packit |
857059 |
// convert a output type argument to the proper constant
|
|
Packit |
857059 |
report_t checkOutputType(const char* name)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
if (0 == strcmp(optarg, "slurm")) {
|
|
Packit |
857059 |
return REPORT_SLURM;
|
|
Packit |
857059 |
} else if (0 == strcmp(optarg, "slurmfull")) {
|
|
Packit |
857059 |
return (REPORT_SLURMFULL);
|
|
Packit |
857059 |
} else if (0 == strcmp(optarg, "hosts")) {
|
|
Packit |
857059 |
return (REPORT_HOSTS);
|
|
Packit |
857059 |
} else {
|
|
Packit |
857059 |
fprintf(stderr, "opa2rm: Invalid Output Type: %s\n", name);
|
|
Packit |
857059 |
Usage();
|
|
Packit |
857059 |
// NOTREACHED
|
|
Packit |
857059 |
return REPORT_NONE;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
int main(int argc, char ** argv)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
int c;
|
|
Packit |
857059 |
report_t report = REPORT_NONE;
|
|
Packit |
857059 |
int i;
|
|
Packit |
857059 |
name_mode_t switch_name_mode = NAME_MODE_FLIP;
|
|
Packit |
857059 |
name_mode_t node_name_mode = NAME_MODE_TRUNC;
|
|
Packit |
857059 |
char* topology_in_file = NULL; // input file being parsed
|
|
Packit |
857059 |
int exitstatus = 0;
|
|
Packit |
857059 |
TopoVal_t validation = TOPOVAL_NONE;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
Top_setcmdname("opa2rm");
|
|
Packit |
857059 |
g_quiet = ! isatty(2); // disable progress if stderr is not tty
|
|
Packit |
857059 |
|
|
Packit |
857059 |
// process command line arguments
|
|
Packit |
857059 |
while (-1 != (c = getopt_long(argc,argv, "vqo:gutp:s:F:SC",
|
|
Packit |
857059 |
options, &i)))
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
switch (c)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
case '$':
|
|
Packit |
857059 |
Usage_full();
|
|
Packit |
857059 |
break;
|
|
Packit |
857059 |
case 'v':
|
|
Packit |
857059 |
g_verbose++;
|
|
Packit |
857059 |
break;
|
|
Packit |
857059 |
case 'q':
|
|
Packit |
857059 |
g_quiet = 1;
|
|
Packit |
857059 |
break;
|
|
Packit |
857059 |
case 'o':
|
|
Packit |
857059 |
report = (report_t) report | checkOutputType(optarg);
|
|
Packit |
857059 |
break;
|
|
Packit |
857059 |
case 'g':
|
|
Packit |
857059 |
switch_name_mode = NAME_MODE_GUID;
|
|
Packit |
857059 |
break;
|
|
Packit |
857059 |
case 'u':
|
|
Packit |
857059 |
switch_name_mode = NAME_MODE_UNDERSCORE;
|
|
Packit |
857059 |
break;
|
|
Packit |
857059 |
case 't':
|
|
Packit |
857059 |
switch_name_mode = NAME_MODE_TRUNC;
|
|
Packit |
857059 |
break;
|
|
Packit |
857059 |
case 'p':
|
|
Packit |
857059 |
g_prefix = optarg;
|
|
Packit |
857059 |
break;
|
|
Packit |
857059 |
case 's':
|
|
Packit |
857059 |
g_suffix = optarg;
|
|
Packit |
857059 |
break;
|
|
Packit |
857059 |
case 'F': // focus for report
|
|
Packit |
857059 |
if (g_num_focus >= MAX_FOCUS) {
|
|
Packit |
857059 |
fprintf(stderr, "opa2rm: -F option may only be specified %d times\n", MAX_FOCUS);
|
|
Packit |
857059 |
Usage();
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
PointInit(&g_focus[g_num_focus]);
|
|
Packit |
857059 |
g_focus_arg[g_num_focus++] = optarg;
|
|
Packit |
857059 |
break;
|
|
Packit |
857059 |
case 'S':
|
|
Packit |
857059 |
validation = TOPOVAL_STRICT;
|
|
Packit |
857059 |
break;
|
|
Packit |
857059 |
case 'C':
|
|
Packit |
857059 |
validation = TOPOVAL_SOMEWHAT_STRICT;
|
|
Packit |
857059 |
break;
|
|
Packit |
857059 |
default:
|
|
Packit |
857059 |
fprintf(stderr, "opa2rm: Invalid option -%c\n", c);
|
|
Packit |
857059 |
Usage();
|
|
Packit |
857059 |
break;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
} /* end while */
|
|
Packit |
857059 |
// Name algorithms just check for NULL, so convert empty strings to NULL
|
|
Packit |
857059 |
if (g_suffix && 0 == strlen(g_suffix))
|
|
Packit |
857059 |
g_suffix = NULL;
|
|
Packit |
857059 |
if (g_prefix && 0 == strlen(g_prefix))
|
|
Packit |
857059 |
g_prefix = NULL;
|
|
Packit |
857059 |
// slurm report generation requires cross referenced elinkp and enodep
|
|
Packit |
857059 |
if (validation < TOPOVAL_LOOSE
|
|
Packit |
857059 |
&& (report & (REPORT_SLURM|REPORT_SLURMFULL)))
|
|
Packit |
857059 |
validation = TOPOVAL_LOOSE;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
if (optind < argc) {
|
|
Packit |
857059 |
topology_in_file = argv[optind++];
|
|
Packit |
857059 |
if (!topology_in_file){
|
|
Packit |
857059 |
fprintf(stderr, "opa2rm: Error: null input filename\n");
|
|
Packit |
857059 |
exitstatus = 1;
|
|
Packit |
857059 |
goto done;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
} else {
|
|
Packit |
857059 |
fprintf(stderr, "opa2rm: Missing topology_input argument\n");
|
|
Packit |
857059 |
Usage();
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
if (optind < argc)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
fprintf(stderr, "opa2rm: Unexpected extra arguments\n");
|
|
Packit |
857059 |
Usage();
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
if (report == REPORT_NONE)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
fprintf(stderr, "opa2rm: '-o output' option must be specified\n");
|
|
Packit |
857059 |
Usage();
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
if (FSUCCESS != InitFabricData(&g_Fabric, FF_NONE)) {
|
|
Packit |
857059 |
fprintf(stderr, "opa2rm: Unable to initialize fabric storage area\n");
|
|
Packit |
857059 |
exitstatus = 1;
|
|
Packit |
857059 |
goto done;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
// parse topology input file
|
|
Packit |
857059 |
if (FSUCCESS != Xml2ParseTopology(topology_in_file, g_quiet, &g_Fabric,
|
|
Packit |
857059 |
validation)) {
|
|
Packit |
857059 |
exitstatus = 1;
|
|
Packit |
857059 |
goto done;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
if (g_verbose > 3)
|
|
Packit |
857059 |
Xml2PrintTopology(stderr, &g_Fabric); // for debug
|
|
Packit |
857059 |
if (! (g_Fabric.flags & FF_EXPECTED_NODES)) {
|
|
Packit |
857059 |
printf("opa2rm: Incomplete topology file: no Nodes information provided\n");
|
|
Packit |
857059 |
exitstatus = 1;
|
|
Packit |
857059 |
goto done;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
if (! (g_Fabric.flags & (FF_EXPECTED_LINKS|FF_EXPECTED_EXTLINKS))) {
|
|
Packit |
857059 |
printf("opa2rm: Incomplete topology file: no LinkSummary nor ExternalLinkSummary information provided\n");
|
|
Packit |
857059 |
exitstatus = 1;
|
|
Packit |
857059 |
goto done;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
for (i=0; i < g_num_focus; i++) {
|
|
Packit |
857059 |
char *p;
|
|
Packit |
857059 |
FSTATUS status;
|
|
Packit |
857059 |
uint8 find_flag =
|
|
Packit |
857059 |
((report & (REPORT_SLURM|REPORT_SLURMFULL))?FIND_FLAG_ELINK:0)
|
|
Packit |
857059 |
| ((report & (REPORT_HOSTS))?FIND_FLAG_ENODE:0);
|
|
Packit |
857059 |
status = ParseFocusPoint(0, &g_Fabric, g_focus_arg[i], &g_focus[i],
|
|
Packit |
857059 |
find_flag, &p, TRUE);
|
|
Packit |
857059 |
if (FINVALID_PARAMETER == status || *p != '\0') {
|
|
Packit |
857059 |
fprintf(stderr, "opa2rm: Invalid Point Syntax: '%s'\n", g_focus_arg[i]);
|
|
Packit |
857059 |
fprintf(stderr, "opa2rm: %*s^\n", (int)(p-g_focus_arg[i]), "");
|
|
Packit |
857059 |
Usage_full();
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
if (FSUCCESS != status) {
|
|
Packit |
857059 |
fprintf(stderr, "opa2rm: Unable to resolve Point: '%s': %s\n", g_focus_arg[i], iba_fstatus_msg(status));
|
|
Packit |
857059 |
exitstatus = 1;
|
|
Packit |
857059 |
goto done;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
if (g_verbose > 1 ) {
|
|
Packit |
857059 |
ShowExpectedLinksReport(0, g_verbose);
|
|
Packit |
857059 |
ShowExpectedNodesReport(STL_NODE_FI, 0, g_verbose);
|
|
Packit |
857059 |
ShowExpectedNodesReport(STL_NODE_SW, 0, g_verbose);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
if (report & REPORT_HOSTS) {
|
|
Packit |
857059 |
PrintComment("#", argc, argv);
|
|
Packit |
857059 |
ShowFastFabricHosts(node_name_mode);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
if (report & (REPORT_SLURM|REPORT_SLURMFULL)) {
|
|
Packit |
857059 |
BuildAllSwitchLists(switch_name_mode, node_name_mode,
|
|
Packit |
857059 |
0 != (report&REPORT_SLURMFULL), 1);
|
|
Packit |
857059 |
PrintComment("#", argc, argv);
|
|
Packit |
857059 |
ShowSlurmNodes(switch_name_mode, node_name_mode);
|
|
Packit |
857059 |
if (report & REPORT_SLURM) {
|
|
Packit |
857059 |
printf("\n");
|
|
Packit |
857059 |
ShowSlurmFakeISLs(switch_name_mode);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
if (report & REPORT_SLURMFULL) {
|
|
Packit |
857059 |
printf("\n");
|
|
Packit |
857059 |
ShowSlurmISLs(switch_name_mode);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
FreeAllSwitchNamelists();
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
DestroyFabricData(&g_Fabric);
|
|
Packit |
857059 |
done:
|
|
Packit |
857059 |
|
|
Packit |
857059 |
for (i=0; i < g_num_focus; i++)
|
|
Packit |
857059 |
PointDestroy(&g_focus[i]);
|
|
Packit |
857059 |
|
|
Packit |
857059 |
if (exitstatus == 2)
|
|
Packit |
857059 |
Usage();
|
|
Packit |
857059 |
|
|
Packit |
857059 |
return exitstatus;
|
|
Packit |
857059 |
}
|