Blame IbaTools/opa2rm/opa2rm.c

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
}