xref: /freebsd/contrib/ofed/infiniband-diags/src/ibtracert.c (revision 87181516ef48be852d5e5fee53c6e0dbfc62f21e)
1*d6b92ffaSHans Petter Selasky /*
2*d6b92ffaSHans Petter Selasky  * Copyright (c) 2004-2009 Voltaire Inc.  All rights reserved.
3*d6b92ffaSHans Petter Selasky  * Copyright (c) 2009 HNR Consulting.  All rights reserved.
4*d6b92ffaSHans Petter Selasky  * Copyright (c) 2010,2011 Mellanox Technologies LTD.  All rights reserved.
5*d6b92ffaSHans Petter Selasky  *
6*d6b92ffaSHans Petter Selasky  * This software is available to you under a choice of one of two
7*d6b92ffaSHans Petter Selasky  * licenses.  You may choose to be licensed under the terms of the GNU
8*d6b92ffaSHans Petter Selasky  * General Public License (GPL) Version 2, available from the file
9*d6b92ffaSHans Petter Selasky  * COPYING in the main directory of this source tree, or the
10*d6b92ffaSHans Petter Selasky  * OpenIB.org BSD license below:
11*d6b92ffaSHans Petter Selasky  *
12*d6b92ffaSHans Petter Selasky  *     Redistribution and use in source and binary forms, with or
13*d6b92ffaSHans Petter Selasky  *     without modification, are permitted provided that the following
14*d6b92ffaSHans Petter Selasky  *     conditions are met:
15*d6b92ffaSHans Petter Selasky  *
16*d6b92ffaSHans Petter Selasky  *      - Redistributions of source code must retain the above
17*d6b92ffaSHans Petter Selasky  *        copyright notice, this list of conditions and the following
18*d6b92ffaSHans Petter Selasky  *        disclaimer.
19*d6b92ffaSHans Petter Selasky  *
20*d6b92ffaSHans Petter Selasky  *      - Redistributions in binary form must reproduce the above
21*d6b92ffaSHans Petter Selasky  *        copyright notice, this list of conditions and the following
22*d6b92ffaSHans Petter Selasky  *        disclaimer in the documentation and/or other materials
23*d6b92ffaSHans Petter Selasky  *        provided with the distribution.
24*d6b92ffaSHans Petter Selasky  *
25*d6b92ffaSHans Petter Selasky  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26*d6b92ffaSHans Petter Selasky  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27*d6b92ffaSHans Petter Selasky  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28*d6b92ffaSHans Petter Selasky  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29*d6b92ffaSHans Petter Selasky  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30*d6b92ffaSHans Petter Selasky  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31*d6b92ffaSHans Petter Selasky  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32*d6b92ffaSHans Petter Selasky  * SOFTWARE.
33*d6b92ffaSHans Petter Selasky  *
34*d6b92ffaSHans Petter Selasky  */
35*d6b92ffaSHans Petter Selasky 
36*d6b92ffaSHans Petter Selasky #if HAVE_CONFIG_H
37*d6b92ffaSHans Petter Selasky #  include <config.h>
38*d6b92ffaSHans Petter Selasky #endif				/* HAVE_CONFIG_H */
39*d6b92ffaSHans Petter Selasky 
40*d6b92ffaSHans Petter Selasky #define _GNU_SOURCE
41*d6b92ffaSHans Petter Selasky #include <stdio.h>
42*d6b92ffaSHans Petter Selasky #include <stdlib.h>
43*d6b92ffaSHans Petter Selasky #include <unistd.h>
44*d6b92ffaSHans Petter Selasky #include <ctype.h>
45*d6b92ffaSHans Petter Selasky #include <getopt.h>
46*d6b92ffaSHans Petter Selasky #include <netinet/in.h>
47*d6b92ffaSHans Petter Selasky #include <inttypes.h>
48*d6b92ffaSHans Petter Selasky 
49*d6b92ffaSHans Petter Selasky #include <infiniband/umad.h>
50*d6b92ffaSHans Petter Selasky #include <infiniband/mad.h>
51*d6b92ffaSHans Petter Selasky #include <complib/cl_nodenamemap.h>
52*d6b92ffaSHans Petter Selasky 
53*d6b92ffaSHans Petter Selasky #include "ibdiag_common.h"
54*d6b92ffaSHans Petter Selasky 
55*d6b92ffaSHans Petter Selasky struct ibmad_port *srcport;
56*d6b92ffaSHans Petter Selasky 
57*d6b92ffaSHans Petter Selasky #define MAXHOPS	63
58*d6b92ffaSHans Petter Selasky 
59*d6b92ffaSHans Petter Selasky static char *node_type_str[] = {
60*d6b92ffaSHans Petter Selasky 	"???",
61*d6b92ffaSHans Petter Selasky 	"ca",
62*d6b92ffaSHans Petter Selasky 	"switch",
63*d6b92ffaSHans Petter Selasky 	"router",
64*d6b92ffaSHans Petter Selasky 	"iwarp rnic"
65*d6b92ffaSHans Petter Selasky };
66*d6b92ffaSHans Petter Selasky 
67*d6b92ffaSHans Petter Selasky static int timeout = 0;		/* ms */
68*d6b92ffaSHans Petter Selasky static int force;
69*d6b92ffaSHans Petter Selasky static FILE *f;
70*d6b92ffaSHans Petter Selasky 
71*d6b92ffaSHans Petter Selasky static char *node_name_map_file = NULL;
72*d6b92ffaSHans Petter Selasky static nn_map_t *node_name_map = NULL;
73*d6b92ffaSHans Petter Selasky 
74*d6b92ffaSHans Petter Selasky typedef struct Port Port;
75*d6b92ffaSHans Petter Selasky typedef struct Switch Switch;
76*d6b92ffaSHans Petter Selasky typedef struct Node Node;
77*d6b92ffaSHans Petter Selasky 
78*d6b92ffaSHans Petter Selasky struct Port {
79*d6b92ffaSHans Petter Selasky 	Port *next;
80*d6b92ffaSHans Petter Selasky 	Port *remoteport;
81*d6b92ffaSHans Petter Selasky 	uint64_t portguid;
82*d6b92ffaSHans Petter Selasky 	int portnum;
83*d6b92ffaSHans Petter Selasky 	int lid;
84*d6b92ffaSHans Petter Selasky 	int lmc;
85*d6b92ffaSHans Petter Selasky 	int state;
86*d6b92ffaSHans Petter Selasky 	int physstate;
87*d6b92ffaSHans Petter Selasky 	char portinfo[64];
88*d6b92ffaSHans Petter Selasky };
89*d6b92ffaSHans Petter Selasky 
90*d6b92ffaSHans Petter Selasky struct Switch {
91*d6b92ffaSHans Petter Selasky 	int linearcap;
92*d6b92ffaSHans Petter Selasky 	int mccap;
93*d6b92ffaSHans Petter Selasky 	int linearFDBtop;
94*d6b92ffaSHans Petter Selasky 	int fdb_base;
95*d6b92ffaSHans Petter Selasky 	int enhsp0;
96*d6b92ffaSHans Petter Selasky 	int8_t fdb[64];
97*d6b92ffaSHans Petter Selasky 	char switchinfo[64];
98*d6b92ffaSHans Petter Selasky };
99*d6b92ffaSHans Petter Selasky 
100*d6b92ffaSHans Petter Selasky struct Node {
101*d6b92ffaSHans Petter Selasky 	Node *htnext;
102*d6b92ffaSHans Petter Selasky 	Node *dnext;
103*d6b92ffaSHans Petter Selasky 	Port *ports;
104*d6b92ffaSHans Petter Selasky 	ib_portid_t path;
105*d6b92ffaSHans Petter Selasky 	int type;
106*d6b92ffaSHans Petter Selasky 	int dist;
107*d6b92ffaSHans Petter Selasky 	int numports;
108*d6b92ffaSHans Petter Selasky 	int upport;
109*d6b92ffaSHans Petter Selasky 	Node *upnode;
110*d6b92ffaSHans Petter Selasky 	uint64_t nodeguid;	/* also portguid */
111*d6b92ffaSHans Petter Selasky 	char nodedesc[64];
112*d6b92ffaSHans Petter Selasky 	char nodeinfo[64];
113*d6b92ffaSHans Petter Selasky };
114*d6b92ffaSHans Petter Selasky 
115*d6b92ffaSHans Petter Selasky Node *nodesdist[MAXHOPS];
116*d6b92ffaSHans Petter Selasky uint64_t target_portguid;
117*d6b92ffaSHans Petter Selasky 
118*d6b92ffaSHans Petter Selasky /*
119*d6b92ffaSHans Petter Selasky  * is_port_inactive
120*d6b92ffaSHans Petter Selasky  * Checks whether or not the port state is other than active.
121*d6b92ffaSHans Petter Selasky  * The "sw" argument is only relevant when the port is on a
122*d6b92ffaSHans Petter Selasky  * switch; for HCAs and routers, this argument is ignored.
123*d6b92ffaSHans Petter Selasky  * Returns 1 when port is not active and 0 when active.
124*d6b92ffaSHans Petter Selasky  * Base switch port 0 is considered always active.
125*d6b92ffaSHans Petter Selasky  */
is_port_inactive(Node * node,Port * port,Switch * sw)126*d6b92ffaSHans Petter Selasky static int is_port_inactive(Node * node, Port * port, Switch * sw)
127*d6b92ffaSHans Petter Selasky {
128*d6b92ffaSHans Petter Selasky 	int res = 0;
129*d6b92ffaSHans Petter Selasky 	if (port->state != 4 &&
130*d6b92ffaSHans Petter Selasky 	    (node->type != IB_NODE_SWITCH ||
131*d6b92ffaSHans Petter Selasky 	     (node->type == IB_NODE_SWITCH && sw->enhsp0)))
132*d6b92ffaSHans Petter Selasky 		res = 1;
133*d6b92ffaSHans Petter Selasky 	return res;
134*d6b92ffaSHans Petter Selasky }
135*d6b92ffaSHans Petter Selasky 
get_node(Node * node,Port * port,ib_portid_t * portid)136*d6b92ffaSHans Petter Selasky static int get_node(Node * node, Port * port, ib_portid_t * portid)
137*d6b92ffaSHans Petter Selasky {
138*d6b92ffaSHans Petter Selasky 	void *pi = port->portinfo, *ni = node->nodeinfo, *nd = node->nodedesc;
139*d6b92ffaSHans Petter Selasky 	char *s, *e;
140*d6b92ffaSHans Petter Selasky 
141*d6b92ffaSHans Petter Selasky 	memset(ni, 0, sizeof(node->nodeinfo));
142*d6b92ffaSHans Petter Selasky 	if (!smp_query_via(ni, portid, IB_ATTR_NODE_INFO, 0, timeout, srcport))
143*d6b92ffaSHans Petter Selasky 		return -1;
144*d6b92ffaSHans Petter Selasky 
145*d6b92ffaSHans Petter Selasky 	memset(nd, 0, sizeof(node->nodedesc));
146*d6b92ffaSHans Petter Selasky 	if (!smp_query_via(nd, portid, IB_ATTR_NODE_DESC, 0, timeout, srcport))
147*d6b92ffaSHans Petter Selasky 		return -1;
148*d6b92ffaSHans Petter Selasky 
149*d6b92ffaSHans Petter Selasky 	for (s = nd, e = s + 64; s < e; s++) {
150*d6b92ffaSHans Petter Selasky 		if (!*s)
151*d6b92ffaSHans Petter Selasky 			break;
152*d6b92ffaSHans Petter Selasky 		if (!isprint(*s))
153*d6b92ffaSHans Petter Selasky 			*s = ' ';
154*d6b92ffaSHans Petter Selasky 	}
155*d6b92ffaSHans Petter Selasky 
156*d6b92ffaSHans Petter Selasky 	memset(pi, 0, sizeof(port->portinfo));
157*d6b92ffaSHans Petter Selasky 	if (!smp_query_via(pi, portid, IB_ATTR_PORT_INFO, 0, timeout, srcport))
158*d6b92ffaSHans Petter Selasky 		return -1;
159*d6b92ffaSHans Petter Selasky 
160*d6b92ffaSHans Petter Selasky 	mad_decode_field(ni, IB_NODE_GUID_F, &node->nodeguid);
161*d6b92ffaSHans Petter Selasky 	mad_decode_field(ni, IB_NODE_TYPE_F, &node->type);
162*d6b92ffaSHans Petter Selasky 	mad_decode_field(ni, IB_NODE_NPORTS_F, &node->numports);
163*d6b92ffaSHans Petter Selasky 
164*d6b92ffaSHans Petter Selasky 	mad_decode_field(ni, IB_NODE_PORT_GUID_F, &port->portguid);
165*d6b92ffaSHans Petter Selasky 	mad_decode_field(ni, IB_NODE_LOCAL_PORT_F, &port->portnum);
166*d6b92ffaSHans Petter Selasky 	mad_decode_field(pi, IB_PORT_LID_F, &port->lid);
167*d6b92ffaSHans Petter Selasky 	mad_decode_field(pi, IB_PORT_LMC_F, &port->lmc);
168*d6b92ffaSHans Petter Selasky 	mad_decode_field(pi, IB_PORT_STATE_F, &port->state);
169*d6b92ffaSHans Petter Selasky 
170*d6b92ffaSHans Petter Selasky 	DEBUG("portid %s: got node %" PRIx64 " '%s'", portid2str(portid),
171*d6b92ffaSHans Petter Selasky 	      node->nodeguid, node->nodedesc);
172*d6b92ffaSHans Petter Selasky 	return 0;
173*d6b92ffaSHans Petter Selasky }
174*d6b92ffaSHans Petter Selasky 
switch_lookup(Switch * sw,ib_portid_t * portid,int lid)175*d6b92ffaSHans Petter Selasky static int switch_lookup(Switch * sw, ib_portid_t * portid, int lid)
176*d6b92ffaSHans Petter Selasky {
177*d6b92ffaSHans Petter Selasky 	void *si = sw->switchinfo, *fdb = sw->fdb;
178*d6b92ffaSHans Petter Selasky 
179*d6b92ffaSHans Petter Selasky 	memset(si, 0, sizeof(sw->switchinfo));
180*d6b92ffaSHans Petter Selasky 	if (!smp_query_via(si, portid, IB_ATTR_SWITCH_INFO, 0, timeout,
181*d6b92ffaSHans Petter Selasky 			   srcport))
182*d6b92ffaSHans Petter Selasky 		return -1;
183*d6b92ffaSHans Petter Selasky 
184*d6b92ffaSHans Petter Selasky 	mad_decode_field(si, IB_SW_LINEAR_FDB_CAP_F, &sw->linearcap);
185*d6b92ffaSHans Petter Selasky 	mad_decode_field(si, IB_SW_LINEAR_FDB_TOP_F, &sw->linearFDBtop);
186*d6b92ffaSHans Petter Selasky 	mad_decode_field(si, IB_SW_ENHANCED_PORT0_F, &sw->enhsp0);
187*d6b92ffaSHans Petter Selasky 
188*d6b92ffaSHans Petter Selasky 	if (lid >= sw->linearcap && lid > sw->linearFDBtop)
189*d6b92ffaSHans Petter Selasky 		return -1;
190*d6b92ffaSHans Petter Selasky 
191*d6b92ffaSHans Petter Selasky 	memset(fdb, 0, sizeof(sw->fdb));
192*d6b92ffaSHans Petter Selasky 	if (!smp_query_via(fdb, portid, IB_ATTR_LINEARFORWTBL, lid / 64,
193*d6b92ffaSHans Petter Selasky 			   timeout, srcport))
194*d6b92ffaSHans Petter Selasky 		return -1;
195*d6b92ffaSHans Petter Selasky 
196*d6b92ffaSHans Petter Selasky 	DEBUG("portid %s: forward lid %d to port %d",
197*d6b92ffaSHans Petter Selasky 	      portid2str(portid), lid, sw->fdb[lid % 64]);
198*d6b92ffaSHans Petter Selasky 	return sw->fdb[lid % 64];
199*d6b92ffaSHans Petter Selasky }
200*d6b92ffaSHans Petter Selasky 
sameport(Port * a,Port * b)201*d6b92ffaSHans Petter Selasky static int sameport(Port * a, Port * b)
202*d6b92ffaSHans Petter Selasky {
203*d6b92ffaSHans Petter Selasky 	return a->portguid == b->portguid || (force && a->lid == b->lid);
204*d6b92ffaSHans Petter Selasky }
205*d6b92ffaSHans Petter Selasky 
extend_dpath(ib_dr_path_t * path,int nextport)206*d6b92ffaSHans Petter Selasky static int extend_dpath(ib_dr_path_t * path, int nextport)
207*d6b92ffaSHans Petter Selasky {
208*d6b92ffaSHans Petter Selasky 	if (path->cnt + 2 >= sizeof(path->p))
209*d6b92ffaSHans Petter Selasky 		return -1;
210*d6b92ffaSHans Petter Selasky 	++path->cnt;
211*d6b92ffaSHans Petter Selasky 	path->p[path->cnt] = (uint8_t) nextport;
212*d6b92ffaSHans Petter Selasky 	return path->cnt;
213*d6b92ffaSHans Petter Selasky }
214*d6b92ffaSHans Petter Selasky 
dump_endnode(int dump,char * prompt,Node * node,Port * port)215*d6b92ffaSHans Petter Selasky static void dump_endnode(int dump, char *prompt, Node * node, Port * port)
216*d6b92ffaSHans Petter Selasky {
217*d6b92ffaSHans Petter Selasky 	char *nodename = NULL;
218*d6b92ffaSHans Petter Selasky 
219*d6b92ffaSHans Petter Selasky 	if (!dump)
220*d6b92ffaSHans Petter Selasky 		return;
221*d6b92ffaSHans Petter Selasky 	if (dump == 1) {
222*d6b92ffaSHans Petter Selasky 		fprintf(f, "%s {0x%016" PRIx64 "}[%d]\n",
223*d6b92ffaSHans Petter Selasky 			prompt, node->nodeguid,
224*d6b92ffaSHans Petter Selasky 			node->type == IB_NODE_SWITCH ? 0 : port->portnum);
225*d6b92ffaSHans Petter Selasky 		return;
226*d6b92ffaSHans Petter Selasky 	}
227*d6b92ffaSHans Petter Selasky 
228*d6b92ffaSHans Petter Selasky 	nodename =
229*d6b92ffaSHans Petter Selasky 	    remap_node_name(node_name_map, node->nodeguid, node->nodedesc);
230*d6b92ffaSHans Petter Selasky 
231*d6b92ffaSHans Petter Selasky 	fprintf(f, "%s %s {0x%016" PRIx64 "} portnum %d lid %u-%u \"%s\"\n",
232*d6b92ffaSHans Petter Selasky 		prompt,
233*d6b92ffaSHans Petter Selasky 		(node->type <= IB_NODE_MAX ? node_type_str[node->type] : "???"),
234*d6b92ffaSHans Petter Selasky 		node->nodeguid,
235*d6b92ffaSHans Petter Selasky 		node->type == IB_NODE_SWITCH ? 0 : port->portnum, port->lid,
236*d6b92ffaSHans Petter Selasky 		port->lid + (1 << port->lmc) - 1, nodename);
237*d6b92ffaSHans Petter Selasky 
238*d6b92ffaSHans Petter Selasky 	free(nodename);
239*d6b92ffaSHans Petter Selasky }
240*d6b92ffaSHans Petter Selasky 
dump_route(int dump,Node * node,int outport,Port * port)241*d6b92ffaSHans Petter Selasky static void dump_route(int dump, Node * node, int outport, Port * port)
242*d6b92ffaSHans Petter Selasky {
243*d6b92ffaSHans Petter Selasky 	char *nodename = NULL;
244*d6b92ffaSHans Petter Selasky 
245*d6b92ffaSHans Petter Selasky 	if (!dump && !ibverbose)
246*d6b92ffaSHans Petter Selasky 		return;
247*d6b92ffaSHans Petter Selasky 
248*d6b92ffaSHans Petter Selasky 	nodename =
249*d6b92ffaSHans Petter Selasky 	    remap_node_name(node_name_map, node->nodeguid, node->nodedesc);
250*d6b92ffaSHans Petter Selasky 
251*d6b92ffaSHans Petter Selasky 	if (dump == 1)
252*d6b92ffaSHans Petter Selasky 		fprintf(f, "[%d] -> {0x%016" PRIx64 "}[%d]\n",
253*d6b92ffaSHans Petter Selasky 			outport, port->portguid, port->portnum);
254*d6b92ffaSHans Petter Selasky 	else
255*d6b92ffaSHans Petter Selasky 		fprintf(f, "[%d] -> %s port {0x%016" PRIx64
256*d6b92ffaSHans Petter Selasky 			"}[%d] lid %u-%u \"%s\"\n", outport,
257*d6b92ffaSHans Petter Selasky 			(node->type <=
258*d6b92ffaSHans Petter Selasky 			 IB_NODE_MAX ? node_type_str[node->type] : "???"),
259*d6b92ffaSHans Petter Selasky 			port->portguid, port->portnum, port->lid,
260*d6b92ffaSHans Petter Selasky 			port->lid + (1 << port->lmc) - 1, nodename);
261*d6b92ffaSHans Petter Selasky 
262*d6b92ffaSHans Petter Selasky 	free(nodename);
263*d6b92ffaSHans Petter Selasky }
264*d6b92ffaSHans Petter Selasky 
find_route(ib_portid_t * from,ib_portid_t * to,int dump)265*d6b92ffaSHans Petter Selasky static int find_route(ib_portid_t * from, ib_portid_t * to, int dump)
266*d6b92ffaSHans Petter Selasky {
267*d6b92ffaSHans Petter Selasky 	Node *node, fromnode, tonode, nextnode;
268*d6b92ffaSHans Petter Selasky 	Port *port, fromport, toport, nextport;
269*d6b92ffaSHans Petter Selasky 	Switch sw;
270*d6b92ffaSHans Petter Selasky 	int maxhops = MAXHOPS;
271*d6b92ffaSHans Petter Selasky 	int portnum, outport = 255, next_sw_outport = 255;
272*d6b92ffaSHans Petter Selasky 
273*d6b92ffaSHans Petter Selasky 	memset(&fromnode,0,sizeof(Node));
274*d6b92ffaSHans Petter Selasky 	memset(&tonode,0,sizeof(Node));
275*d6b92ffaSHans Petter Selasky 	memset(&nextnode,0,sizeof(Node));
276*d6b92ffaSHans Petter Selasky 	memset(&fromport,0,sizeof(Port));
277*d6b92ffaSHans Petter Selasky 	memset(&toport,0,sizeof(Port));
278*d6b92ffaSHans Petter Selasky 	memset(&nextport,0,sizeof(Port));
279*d6b92ffaSHans Petter Selasky 
280*d6b92ffaSHans Petter Selasky 	DEBUG("from %s", portid2str(from));
281*d6b92ffaSHans Petter Selasky 
282*d6b92ffaSHans Petter Selasky 	if (get_node(&fromnode, &fromport, from) < 0 ||
283*d6b92ffaSHans Petter Selasky 	    get_node(&tonode, &toport, to) < 0) {
284*d6b92ffaSHans Petter Selasky 		IBWARN("can't reach to/from ports");
285*d6b92ffaSHans Petter Selasky 		if (!force)
286*d6b92ffaSHans Petter Selasky 			return -1;
287*d6b92ffaSHans Petter Selasky 		if (to->lid > 0)
288*d6b92ffaSHans Petter Selasky 			toport.lid = to->lid;
289*d6b92ffaSHans Petter Selasky 		IBWARN("Force: look for lid %d", to->lid);
290*d6b92ffaSHans Petter Selasky 	}
291*d6b92ffaSHans Petter Selasky 
292*d6b92ffaSHans Petter Selasky 	node = &fromnode;
293*d6b92ffaSHans Petter Selasky 	port = &fromport;
294*d6b92ffaSHans Petter Selasky 	portnum = port->portnum;
295*d6b92ffaSHans Petter Selasky 
296*d6b92ffaSHans Petter Selasky 	dump_endnode(dump, "From", node, port);
297*d6b92ffaSHans Petter Selasky 	if (node->type == IB_NODE_SWITCH) {
298*d6b92ffaSHans Petter Selasky 		next_sw_outport = switch_lookup(&sw, from, to->lid);
299*d6b92ffaSHans Petter Selasky 		if (next_sw_outport < 0 || next_sw_outport > node->numports) {
300*d6b92ffaSHans Petter Selasky 			/* Need to print the port in badtbl */
301*d6b92ffaSHans Petter Selasky 			outport = next_sw_outport;
302*d6b92ffaSHans Petter Selasky 			goto badtbl;
303*d6b92ffaSHans Petter Selasky 		}
304*d6b92ffaSHans Petter Selasky 	}
305*d6b92ffaSHans Petter Selasky 
306*d6b92ffaSHans Petter Selasky 	while (maxhops--) {
307*d6b92ffaSHans Petter Selasky 		if (is_port_inactive(node, port, &sw))
308*d6b92ffaSHans Petter Selasky 			goto badport;
309*d6b92ffaSHans Petter Selasky 
310*d6b92ffaSHans Petter Selasky 		if (sameport(port, &toport))
311*d6b92ffaSHans Petter Selasky 			break;	/* found */
312*d6b92ffaSHans Petter Selasky 
313*d6b92ffaSHans Petter Selasky 		if (node->type == IB_NODE_SWITCH) {
314*d6b92ffaSHans Petter Selasky 			DEBUG("switch node");
315*d6b92ffaSHans Petter Selasky 			outport = next_sw_outport;
316*d6b92ffaSHans Petter Selasky 
317*d6b92ffaSHans Petter Selasky 			if (extend_dpath(&from->drpath, outport) < 0)
318*d6b92ffaSHans Petter Selasky 				goto badpath;
319*d6b92ffaSHans Petter Selasky 
320*d6b92ffaSHans Petter Selasky 			if (get_node(&nextnode, &nextport, from) < 0) {
321*d6b92ffaSHans Petter Selasky 				IBWARN("can't reach port at %s",
322*d6b92ffaSHans Petter Selasky 				       portid2str(from));
323*d6b92ffaSHans Petter Selasky 				return -1;
324*d6b92ffaSHans Petter Selasky 			}
325*d6b92ffaSHans Petter Selasky 			if (outport == 0) {
326*d6b92ffaSHans Petter Selasky 				if (!sameport(&nextport, &toport))
327*d6b92ffaSHans Petter Selasky 					goto badtbl;
328*d6b92ffaSHans Petter Selasky 				else
329*d6b92ffaSHans Petter Selasky 					break;	/* found SMA port */
330*d6b92ffaSHans Petter Selasky 			}
331*d6b92ffaSHans Petter Selasky 		} else if ((node->type == IB_NODE_CA) ||
332*d6b92ffaSHans Petter Selasky 			   (node->type == IB_NODE_ROUTER)) {
333*d6b92ffaSHans Petter Selasky 			int ca_src = 0;
334*d6b92ffaSHans Petter Selasky 
335*d6b92ffaSHans Petter Selasky 			outport = portnum;
336*d6b92ffaSHans Petter Selasky 			DEBUG("ca or router node");
337*d6b92ffaSHans Petter Selasky 			if (!sameport(port, &fromport)) {
338*d6b92ffaSHans Petter Selasky 				IBWARN
339*d6b92ffaSHans Petter Selasky 				    ("can't continue: reached CA or router port %"
340*d6b92ffaSHans Petter Selasky 				     PRIx64 ", lid %d", port->portguid,
341*d6b92ffaSHans Petter Selasky 				     port->lid);
342*d6b92ffaSHans Petter Selasky 				return -1;
343*d6b92ffaSHans Petter Selasky 			}
344*d6b92ffaSHans Petter Selasky 			/* we are at CA or router "from" - go one hop back to (hopefully) a switch */
345*d6b92ffaSHans Petter Selasky 			if (from->drpath.cnt > 0) {
346*d6b92ffaSHans Petter Selasky 				DEBUG("ca or router node - return back 1 hop");
347*d6b92ffaSHans Petter Selasky 				from->drpath.cnt--;
348*d6b92ffaSHans Petter Selasky 			} else {
349*d6b92ffaSHans Petter Selasky 				ca_src = 1;
350*d6b92ffaSHans Petter Selasky 				if (portnum
351*d6b92ffaSHans Petter Selasky 				    && extend_dpath(&from->drpath, portnum) < 0)
352*d6b92ffaSHans Petter Selasky 					goto badpath;
353*d6b92ffaSHans Petter Selasky 			}
354*d6b92ffaSHans Petter Selasky 			if (get_node(&nextnode, &nextport, from) < 0) {
355*d6b92ffaSHans Petter Selasky 				IBWARN("can't reach port at %s",
356*d6b92ffaSHans Petter Selasky 				       portid2str(from));
357*d6b92ffaSHans Petter Selasky 				return -1;
358*d6b92ffaSHans Petter Selasky 			}
359*d6b92ffaSHans Petter Selasky 			/* fix port num to be seen from the CA or router side */
360*d6b92ffaSHans Petter Selasky 			if (!ca_src)
361*d6b92ffaSHans Petter Selasky 				nextport.portnum =
362*d6b92ffaSHans Petter Selasky 				    from->drpath.p[from->drpath.cnt + 1];
363*d6b92ffaSHans Petter Selasky 		}
364*d6b92ffaSHans Petter Selasky 		/* only if the next node is a switch, get switch info */
365*d6b92ffaSHans Petter Selasky 		if (nextnode.type == IB_NODE_SWITCH) {
366*d6b92ffaSHans Petter Selasky 			next_sw_outport = switch_lookup(&sw, from, to->lid);
367*d6b92ffaSHans Petter Selasky 			if (next_sw_outport < 0 ||
368*d6b92ffaSHans Petter Selasky 			    next_sw_outport > nextnode.numports) {
369*d6b92ffaSHans Petter Selasky 				/* needed to print the port in badtbl */
370*d6b92ffaSHans Petter Selasky 				outport = next_sw_outport;
371*d6b92ffaSHans Petter Selasky 				goto badtbl;
372*d6b92ffaSHans Petter Selasky 			}
373*d6b92ffaSHans Petter Selasky 		}
374*d6b92ffaSHans Petter Selasky 
375*d6b92ffaSHans Petter Selasky 		port = &nextport;
376*d6b92ffaSHans Petter Selasky 		if (is_port_inactive(&nextnode, port, &sw))
377*d6b92ffaSHans Petter Selasky 			goto badoutport;
378*d6b92ffaSHans Petter Selasky 		node = &nextnode;
379*d6b92ffaSHans Petter Selasky 		portnum = port->portnum;
380*d6b92ffaSHans Petter Selasky 		dump_route(dump, node, outport, port);
381*d6b92ffaSHans Petter Selasky 	}
382*d6b92ffaSHans Petter Selasky 
383*d6b92ffaSHans Petter Selasky 	if (maxhops <= 0) {
384*d6b92ffaSHans Petter Selasky 		IBWARN("no route found after %d hops", MAXHOPS);
385*d6b92ffaSHans Petter Selasky 		return -1;
386*d6b92ffaSHans Petter Selasky 	}
387*d6b92ffaSHans Petter Selasky 	dump_endnode(dump, "To", node, port);
388*d6b92ffaSHans Petter Selasky 	return 0;
389*d6b92ffaSHans Petter Selasky 
390*d6b92ffaSHans Petter Selasky badport:
391*d6b92ffaSHans Petter Selasky 	IBWARN("Bad port state found: node \"%s\" port %d state %d",
392*d6b92ffaSHans Petter Selasky 	       clean_nodedesc(node->nodedesc), portnum, port->state);
393*d6b92ffaSHans Petter Selasky 	return -1;
394*d6b92ffaSHans Petter Selasky badoutport:
395*d6b92ffaSHans Petter Selasky 	IBWARN("Bad out port state found: node \"%s\" outport %d state %d",
396*d6b92ffaSHans Petter Selasky 	       clean_nodedesc(node->nodedesc), outport, port->state);
397*d6b92ffaSHans Petter Selasky 	return -1;
398*d6b92ffaSHans Petter Selasky badtbl:
399*d6b92ffaSHans Petter Selasky 	IBWARN
400*d6b92ffaSHans Petter Selasky 	    ("Bad forwarding table entry found at: node \"%s\" lid entry %d is %d (top %d)",
401*d6b92ffaSHans Petter Selasky 	     clean_nodedesc(node->nodedesc), to->lid, outport, sw.linearFDBtop);
402*d6b92ffaSHans Petter Selasky 	return -1;
403*d6b92ffaSHans Petter Selasky badpath:
404*d6b92ffaSHans Petter Selasky 	IBWARN("Direct path too long!");
405*d6b92ffaSHans Petter Selasky 	return -1;
406*d6b92ffaSHans Petter Selasky }
407*d6b92ffaSHans Petter Selasky 
408*d6b92ffaSHans Petter Selasky /**************************
409*d6b92ffaSHans Petter Selasky  * MC span part
410*d6b92ffaSHans Petter Selasky  */
411*d6b92ffaSHans Petter Selasky 
412*d6b92ffaSHans Petter Selasky #define HASHGUID(guid)		((uint32_t)(((uint32_t)(guid) * 101) ^ ((uint32_t)((guid) >> 32) * 103)))
413*d6b92ffaSHans Petter Selasky #define HTSZ 137
414*d6b92ffaSHans Petter Selasky 
insert_node(Node * new)415*d6b92ffaSHans Petter Selasky static int insert_node(Node * new)
416*d6b92ffaSHans Petter Selasky {
417*d6b92ffaSHans Petter Selasky 	static Node *nodestbl[HTSZ];
418*d6b92ffaSHans Petter Selasky 	int hash = HASHGUID(new->nodeguid) % HTSZ;
419*d6b92ffaSHans Petter Selasky 	Node *node;
420*d6b92ffaSHans Petter Selasky 
421*d6b92ffaSHans Petter Selasky 	for (node = nodestbl[hash]; node; node = node->htnext)
422*d6b92ffaSHans Petter Selasky 		if (node->nodeguid == new->nodeguid) {
423*d6b92ffaSHans Petter Selasky 			DEBUG("node %" PRIx64 " already exists", new->nodeguid);
424*d6b92ffaSHans Petter Selasky 			return -1;
425*d6b92ffaSHans Petter Selasky 		}
426*d6b92ffaSHans Petter Selasky 
427*d6b92ffaSHans Petter Selasky 	new->htnext = nodestbl[hash];
428*d6b92ffaSHans Petter Selasky 	nodestbl[hash] = new;
429*d6b92ffaSHans Petter Selasky 
430*d6b92ffaSHans Petter Selasky 	return 0;
431*d6b92ffaSHans Petter Selasky }
432*d6b92ffaSHans Petter Selasky 
get_port(Port * port,int portnum,ib_portid_t * portid)433*d6b92ffaSHans Petter Selasky static int get_port(Port * port, int portnum, ib_portid_t * portid)
434*d6b92ffaSHans Petter Selasky {
435*d6b92ffaSHans Petter Selasky 	char portinfo[64] = { 0 };
436*d6b92ffaSHans Petter Selasky 	void *pi = portinfo;
437*d6b92ffaSHans Petter Selasky 
438*d6b92ffaSHans Petter Selasky 	port->portnum = portnum;
439*d6b92ffaSHans Petter Selasky 
440*d6b92ffaSHans Petter Selasky 	if (!smp_query_via(pi, portid, IB_ATTR_PORT_INFO, portnum, timeout,
441*d6b92ffaSHans Petter Selasky 			   srcport))
442*d6b92ffaSHans Petter Selasky 		return -1;
443*d6b92ffaSHans Petter Selasky 
444*d6b92ffaSHans Petter Selasky 	mad_decode_field(pi, IB_PORT_LID_F, &port->lid);
445*d6b92ffaSHans Petter Selasky 	mad_decode_field(pi, IB_PORT_LMC_F, &port->lmc);
446*d6b92ffaSHans Petter Selasky 	mad_decode_field(pi, IB_PORT_STATE_F, &port->state);
447*d6b92ffaSHans Petter Selasky 	mad_decode_field(pi, IB_PORT_PHYS_STATE_F, &port->physstate);
448*d6b92ffaSHans Petter Selasky 
449*d6b92ffaSHans Petter Selasky 	VERBOSE("portid %s portnum %d: lid %d state %d physstate %d",
450*d6b92ffaSHans Petter Selasky 		portid2str(portid), portnum, port->lid, port->state,
451*d6b92ffaSHans Petter Selasky 		port->physstate);
452*d6b92ffaSHans Petter Selasky 	return 1;
453*d6b92ffaSHans Petter Selasky }
454*d6b92ffaSHans Petter Selasky 
link_port(Port * port,Node * node)455*d6b92ffaSHans Petter Selasky static void link_port(Port * port, Node * node)
456*d6b92ffaSHans Petter Selasky {
457*d6b92ffaSHans Petter Selasky 	port->next = node->ports;
458*d6b92ffaSHans Petter Selasky 	node->ports = port;
459*d6b92ffaSHans Petter Selasky }
460*d6b92ffaSHans Petter Selasky 
new_node(Node * node,Port * port,ib_portid_t * path,int dist)461*d6b92ffaSHans Petter Selasky static int new_node(Node * node, Port * port, ib_portid_t * path, int dist)
462*d6b92ffaSHans Petter Selasky {
463*d6b92ffaSHans Petter Selasky 	if (port->portguid == target_portguid) {
464*d6b92ffaSHans Petter Selasky 		node->dist = -1;	/* tag as target */
465*d6b92ffaSHans Petter Selasky 		link_port(port, node);
466*d6b92ffaSHans Petter Selasky 		dump_endnode(ibverbose, "found target", node, port);
467*d6b92ffaSHans Petter Selasky 		return 1;	/* found; */
468*d6b92ffaSHans Petter Selasky 	}
469*d6b92ffaSHans Petter Selasky 
470*d6b92ffaSHans Petter Selasky 	/* BFS search start with my self */
471*d6b92ffaSHans Petter Selasky 	if (insert_node(node) < 0)
472*d6b92ffaSHans Petter Selasky 		return -1;	/* known switch */
473*d6b92ffaSHans Petter Selasky 
474*d6b92ffaSHans Petter Selasky 	VERBOSE("insert dist %d node %p port %d lid %d", dist, node,
475*d6b92ffaSHans Petter Selasky 		port->portnum, port->lid);
476*d6b92ffaSHans Petter Selasky 
477*d6b92ffaSHans Petter Selasky 	link_port(port, node);
478*d6b92ffaSHans Petter Selasky 
479*d6b92ffaSHans Petter Selasky 	node->dist = dist;
480*d6b92ffaSHans Petter Selasky 	node->path = *path;
481*d6b92ffaSHans Petter Selasky 	node->dnext = nodesdist[dist];
482*d6b92ffaSHans Petter Selasky 	nodesdist[dist] = node;
483*d6b92ffaSHans Petter Selasky 
484*d6b92ffaSHans Petter Selasky 	return 0;
485*d6b92ffaSHans Petter Selasky }
486*d6b92ffaSHans Petter Selasky 
switch_mclookup(Node * node,ib_portid_t * portid,int mlid,char * map)487*d6b92ffaSHans Petter Selasky static int switch_mclookup(Node * node, ib_portid_t * portid, int mlid,
488*d6b92ffaSHans Petter Selasky 			   char *map)
489*d6b92ffaSHans Petter Selasky {
490*d6b92ffaSHans Petter Selasky 	Switch sw;
491*d6b92ffaSHans Petter Selasky 	char mdb[64];
492*d6b92ffaSHans Petter Selasky 	void *si = sw.switchinfo;
493*d6b92ffaSHans Petter Selasky 	uint16_t *msets = (uint16_t *) mdb;
494*d6b92ffaSHans Petter Selasky 	int maxsets, block, i, set;
495*d6b92ffaSHans Petter Selasky 
496*d6b92ffaSHans Petter Selasky 	memset(map, 0, 256);
497*d6b92ffaSHans Petter Selasky 
498*d6b92ffaSHans Petter Selasky 	memset(si, 0, sizeof(sw.switchinfo));
499*d6b92ffaSHans Petter Selasky 	if (!smp_query_via(si, portid, IB_ATTR_SWITCH_INFO, 0, timeout,
500*d6b92ffaSHans Petter Selasky 			   srcport))
501*d6b92ffaSHans Petter Selasky 		return -1;
502*d6b92ffaSHans Petter Selasky 
503*d6b92ffaSHans Petter Selasky 	mlid -= 0xc000;
504*d6b92ffaSHans Petter Selasky 
505*d6b92ffaSHans Petter Selasky 	mad_decode_field(si, IB_SW_MCAST_FDB_CAP_F, &sw.mccap);
506*d6b92ffaSHans Petter Selasky 
507*d6b92ffaSHans Petter Selasky 	if (mlid >= sw.mccap)
508*d6b92ffaSHans Petter Selasky 		return -1;
509*d6b92ffaSHans Petter Selasky 
510*d6b92ffaSHans Petter Selasky 	block = mlid / 32;
511*d6b92ffaSHans Petter Selasky 	maxsets = (node->numports + 15) / 16;	/* round up */
512*d6b92ffaSHans Petter Selasky 
513*d6b92ffaSHans Petter Selasky 	for (set = 0; set < maxsets; set++) {
514*d6b92ffaSHans Petter Selasky 		memset(mdb, 0, sizeof(mdb));
515*d6b92ffaSHans Petter Selasky 		if (!smp_query_via(mdb, portid, IB_ATTR_MULTICASTFORWTBL,
516*d6b92ffaSHans Petter Selasky 				   block | (set << 28), timeout, srcport))
517*d6b92ffaSHans Petter Selasky 			return -1;
518*d6b92ffaSHans Petter Selasky 
519*d6b92ffaSHans Petter Selasky 		for (i = 0; i < 16; i++, map++) {
520*d6b92ffaSHans Petter Selasky 			uint16_t mask = ntohs(msets[mlid % 32]);
521*d6b92ffaSHans Petter Selasky 			if (mask & (1 << i))
522*d6b92ffaSHans Petter Selasky 				*map = 1;
523*d6b92ffaSHans Petter Selasky 			else
524*d6b92ffaSHans Petter Selasky 				continue;
525*d6b92ffaSHans Petter Selasky 			VERBOSE("Switch guid 0x%" PRIx64
526*d6b92ffaSHans Petter Selasky 				": mlid 0x%x is forwarded to port %d",
527*d6b92ffaSHans Petter Selasky 				node->nodeguid, mlid + 0xc000, i + set * 16);
528*d6b92ffaSHans Petter Selasky 		}
529*d6b92ffaSHans Petter Selasky 	}
530*d6b92ffaSHans Petter Selasky 
531*d6b92ffaSHans Petter Selasky 	return 0;
532*d6b92ffaSHans Petter Selasky }
533*d6b92ffaSHans Petter Selasky 
534*d6b92ffaSHans Petter Selasky /*
535*d6b92ffaSHans Petter Selasky  * Return 1 if found, 0 if not, -1 on errors.
536*d6b92ffaSHans Petter Selasky  */
find_mcpath(ib_portid_t * from,int mlid)537*d6b92ffaSHans Petter Selasky static Node *find_mcpath(ib_portid_t * from, int mlid)
538*d6b92ffaSHans Petter Selasky {
539*d6b92ffaSHans Petter Selasky 	Node *node, *remotenode;
540*d6b92ffaSHans Petter Selasky 	Port *port, *remoteport;
541*d6b92ffaSHans Petter Selasky 	char map[256];
542*d6b92ffaSHans Petter Selasky 	int r, i;
543*d6b92ffaSHans Petter Selasky 	int dist = 0, leafport = 0;
544*d6b92ffaSHans Petter Selasky 	ib_portid_t *path;
545*d6b92ffaSHans Petter Selasky 
546*d6b92ffaSHans Petter Selasky 	DEBUG("from %s", portid2str(from));
547*d6b92ffaSHans Petter Selasky 
548*d6b92ffaSHans Petter Selasky 	if (!(node = calloc(1, sizeof(Node))))
549*d6b92ffaSHans Petter Selasky 		IBEXIT("out of memory");
550*d6b92ffaSHans Petter Selasky 
551*d6b92ffaSHans Petter Selasky 	if (!(port = calloc(1, sizeof(Port))))
552*d6b92ffaSHans Petter Selasky 		IBEXIT("out of memory");
553*d6b92ffaSHans Petter Selasky 
554*d6b92ffaSHans Petter Selasky 	if (get_node(node, port, from) < 0) {
555*d6b92ffaSHans Petter Selasky 		IBWARN("can't reach node %s", portid2str(from));
556*d6b92ffaSHans Petter Selasky 		return 0;
557*d6b92ffaSHans Petter Selasky 	}
558*d6b92ffaSHans Petter Selasky 
559*d6b92ffaSHans Petter Selasky 	node->upnode = 0;	/* root */
560*d6b92ffaSHans Petter Selasky 	if ((r = new_node(node, port, from, 0)) > 0) {
561*d6b92ffaSHans Petter Selasky 		if (node->type != IB_NODE_SWITCH) {
562*d6b92ffaSHans Petter Selasky 			IBWARN("ibtracert from CA to CA is unsupported");
563*d6b92ffaSHans Petter Selasky 			return 0;	/* ibtracert from host to itself is unsupported */
564*d6b92ffaSHans Petter Selasky 		}
565*d6b92ffaSHans Petter Selasky 
566*d6b92ffaSHans Petter Selasky 		if (switch_mclookup(node, from, mlid, map) < 0 || !map[0])
567*d6b92ffaSHans Petter Selasky 			return 0;
568*d6b92ffaSHans Petter Selasky 		return node;
569*d6b92ffaSHans Petter Selasky 	}
570*d6b92ffaSHans Petter Selasky 
571*d6b92ffaSHans Petter Selasky 	for (dist = 0; dist < MAXHOPS; dist++) {
572*d6b92ffaSHans Petter Selasky 
573*d6b92ffaSHans Petter Selasky 		for (node = nodesdist[dist]; node; node = node->dnext) {
574*d6b92ffaSHans Petter Selasky 
575*d6b92ffaSHans Petter Selasky 			path = &node->path;
576*d6b92ffaSHans Petter Selasky 
577*d6b92ffaSHans Petter Selasky 			VERBOSE("dist %d node %p", dist, node);
578*d6b92ffaSHans Petter Selasky 			dump_endnode(ibverbose, "processing", node,
579*d6b92ffaSHans Petter Selasky 				     node->ports);
580*d6b92ffaSHans Petter Selasky 
581*d6b92ffaSHans Petter Selasky 			memset(map, 0, sizeof(map));
582*d6b92ffaSHans Petter Selasky 
583*d6b92ffaSHans Petter Selasky 			if (node->type != IB_NODE_SWITCH) {
584*d6b92ffaSHans Petter Selasky 				if (dist)
585*d6b92ffaSHans Petter Selasky 					continue;
586*d6b92ffaSHans Petter Selasky 				leafport = path->drpath.p[path->drpath.cnt];
587*d6b92ffaSHans Petter Selasky 				map[port->portnum] = 1;
588*d6b92ffaSHans Petter Selasky 				node->upport = 0;	/* starting here */
589*d6b92ffaSHans Petter Selasky 				DEBUG("Starting from CA 0x%" PRIx64
590*d6b92ffaSHans Petter Selasky 				      " lid %d port %d (leafport %d)",
591*d6b92ffaSHans Petter Selasky 				      node->nodeguid, port->lid, port->portnum,
592*d6b92ffaSHans Petter Selasky 				      leafport);
593*d6b92ffaSHans Petter Selasky 			} else {	/* switch */
594*d6b92ffaSHans Petter Selasky 
595*d6b92ffaSHans Petter Selasky 				/* if starting from a leaf port fix up port (up port) */
596*d6b92ffaSHans Petter Selasky 				if (dist == 1 && leafport)
597*d6b92ffaSHans Petter Selasky 					node->upport = leafport;
598*d6b92ffaSHans Petter Selasky 
599*d6b92ffaSHans Petter Selasky 				if (switch_mclookup(node, path, mlid, map) < 0) {
600*d6b92ffaSHans Petter Selasky 					IBWARN("skipping bad Switch 0x%" PRIx64
601*d6b92ffaSHans Petter Selasky 					       "", node->nodeguid);
602*d6b92ffaSHans Petter Selasky 					continue;
603*d6b92ffaSHans Petter Selasky 				}
604*d6b92ffaSHans Petter Selasky 			}
605*d6b92ffaSHans Petter Selasky 
606*d6b92ffaSHans Petter Selasky 			for (i = 1; i <= node->numports; i++) {
607*d6b92ffaSHans Petter Selasky 				if (!map[i] || i == node->upport)
608*d6b92ffaSHans Petter Selasky 					continue;
609*d6b92ffaSHans Petter Selasky 
610*d6b92ffaSHans Petter Selasky 				if (dist == 0 && leafport) {
611*d6b92ffaSHans Petter Selasky 					if (from->drpath.cnt > 0)
612*d6b92ffaSHans Petter Selasky 						path->drpath.cnt--;
613*d6b92ffaSHans Petter Selasky 				} else {
614*d6b92ffaSHans Petter Selasky 					if (!(port = calloc(1, sizeof(Port))))
615*d6b92ffaSHans Petter Selasky 						IBEXIT("out of memory");
616*d6b92ffaSHans Petter Selasky 
617*d6b92ffaSHans Petter Selasky 					if (get_port(port, i, path) < 0) {
618*d6b92ffaSHans Petter Selasky 						IBWARN
619*d6b92ffaSHans Petter Selasky 						    ("can't reach node %s port %d",
620*d6b92ffaSHans Petter Selasky 						     portid2str(path), i);
621*d6b92ffaSHans Petter Selasky 						free(port);
622*d6b92ffaSHans Petter Selasky 						return 0;
623*d6b92ffaSHans Petter Selasky 					}
624*d6b92ffaSHans Petter Selasky 
625*d6b92ffaSHans Petter Selasky 					if (port->physstate != 5) {	/* LinkUP */
626*d6b92ffaSHans Petter Selasky 						free(port);
627*d6b92ffaSHans Petter Selasky 						continue;
628*d6b92ffaSHans Petter Selasky 					}
629*d6b92ffaSHans Petter Selasky #if 0
630*d6b92ffaSHans Petter Selasky 					link_port(port, node);
631*d6b92ffaSHans Petter Selasky #endif
632*d6b92ffaSHans Petter Selasky 
633*d6b92ffaSHans Petter Selasky 					if (extend_dpath(&path->drpath, i) < 0) {
634*d6b92ffaSHans Petter Selasky 						free(port);
635*d6b92ffaSHans Petter Selasky 						return 0;
636*d6b92ffaSHans Petter Selasky 					}
637*d6b92ffaSHans Petter Selasky 				}
638*d6b92ffaSHans Petter Selasky 
639*d6b92ffaSHans Petter Selasky 				if (!(remotenode = calloc(1, sizeof(Node))))
640*d6b92ffaSHans Petter Selasky 					IBEXIT("out of memory");
641*d6b92ffaSHans Petter Selasky 
642*d6b92ffaSHans Petter Selasky 				if (!(remoteport = calloc(1, sizeof(Port))))
643*d6b92ffaSHans Petter Selasky 					IBEXIT("out of memory");
644*d6b92ffaSHans Petter Selasky 
645*d6b92ffaSHans Petter Selasky 				if (get_node(remotenode, remoteport, path) < 0) {
646*d6b92ffaSHans Petter Selasky 					IBWARN
647*d6b92ffaSHans Petter Selasky 					    ("NodeInfo on %s port %d failed, skipping port",
648*d6b92ffaSHans Petter Selasky 					     portid2str(path), i);
649*d6b92ffaSHans Petter Selasky 					path->drpath.cnt--;	/* restore path */
650*d6b92ffaSHans Petter Selasky 					free(remotenode);
651*d6b92ffaSHans Petter Selasky 					free(remoteport);
652*d6b92ffaSHans Petter Selasky 					continue;
653*d6b92ffaSHans Petter Selasky 				}
654*d6b92ffaSHans Petter Selasky 
655*d6b92ffaSHans Petter Selasky 				remotenode->upnode = node;
656*d6b92ffaSHans Petter Selasky 				remotenode->upport = remoteport->portnum;
657*d6b92ffaSHans Petter Selasky 				remoteport->remoteport = port;
658*d6b92ffaSHans Petter Selasky 
659*d6b92ffaSHans Petter Selasky 				if ((r = new_node(remotenode, remoteport, path,
660*d6b92ffaSHans Petter Selasky 						  dist + 1)) > 0)
661*d6b92ffaSHans Petter Selasky 					return remotenode;
662*d6b92ffaSHans Petter Selasky 
663*d6b92ffaSHans Petter Selasky 				if (r == 0)
664*d6b92ffaSHans Petter Selasky 					dump_endnode(ibverbose, "new remote",
665*d6b92ffaSHans Petter Selasky 						     remotenode, remoteport);
666*d6b92ffaSHans Petter Selasky 				else if (remotenode->type == IB_NODE_SWITCH)
667*d6b92ffaSHans Petter Selasky 					dump_endnode(2,
668*d6b92ffaSHans Petter Selasky 						     "ERR: circle discovered at",
669*d6b92ffaSHans Petter Selasky 						     remotenode, remoteport);
670*d6b92ffaSHans Petter Selasky 
671*d6b92ffaSHans Petter Selasky 				path->drpath.cnt--;	/* restore path */
672*d6b92ffaSHans Petter Selasky 			}
673*d6b92ffaSHans Petter Selasky 		}
674*d6b92ffaSHans Petter Selasky 	}
675*d6b92ffaSHans Petter Selasky 
676*d6b92ffaSHans Petter Selasky 	return 0;		/* not found */
677*d6b92ffaSHans Petter Selasky }
678*d6b92ffaSHans Petter Selasky 
find_target_portguid(ib_portid_t * to)679*d6b92ffaSHans Petter Selasky static uint64_t find_target_portguid(ib_portid_t * to)
680*d6b92ffaSHans Petter Selasky {
681*d6b92ffaSHans Petter Selasky 	Node tonode;
682*d6b92ffaSHans Petter Selasky 	Port toport;
683*d6b92ffaSHans Petter Selasky 
684*d6b92ffaSHans Petter Selasky 	if (get_node(&tonode, &toport, to) < 0) {
685*d6b92ffaSHans Petter Selasky 		IBWARN("can't find to port\n");
686*d6b92ffaSHans Petter Selasky 		return -1;
687*d6b92ffaSHans Petter Selasky 	}
688*d6b92ffaSHans Petter Selasky 
689*d6b92ffaSHans Petter Selasky 	return toport.portguid;
690*d6b92ffaSHans Petter Selasky }
691*d6b92ffaSHans Petter Selasky 
dump_mcpath(Node * node,int dumplevel)692*d6b92ffaSHans Petter Selasky static void dump_mcpath(Node * node, int dumplevel)
693*d6b92ffaSHans Petter Selasky {
694*d6b92ffaSHans Petter Selasky 	char *nodename = NULL;
695*d6b92ffaSHans Petter Selasky 
696*d6b92ffaSHans Petter Selasky 	if (node->upnode)
697*d6b92ffaSHans Petter Selasky 		dump_mcpath(node->upnode, dumplevel);
698*d6b92ffaSHans Petter Selasky 
699*d6b92ffaSHans Petter Selasky 	nodename =
700*d6b92ffaSHans Petter Selasky 	    remap_node_name(node_name_map, node->nodeguid, node->nodedesc);
701*d6b92ffaSHans Petter Selasky 
702*d6b92ffaSHans Petter Selasky 	if (!node->dist) {
703*d6b92ffaSHans Petter Selasky 		printf("From %s 0x%" PRIx64 " port %d lid %u-%u \"%s\"\n",
704*d6b92ffaSHans Petter Selasky 		       (node->type <=
705*d6b92ffaSHans Petter Selasky 			IB_NODE_MAX ? node_type_str[node->type] : "???"),
706*d6b92ffaSHans Petter Selasky 		       node->nodeguid, node->ports->portnum, node->ports->lid,
707*d6b92ffaSHans Petter Selasky 		       node->ports->lid + (1 << node->ports->lmc) - 1,
708*d6b92ffaSHans Petter Selasky 		       nodename);
709*d6b92ffaSHans Petter Selasky 		goto free_name;
710*d6b92ffaSHans Petter Selasky 	}
711*d6b92ffaSHans Petter Selasky 
712*d6b92ffaSHans Petter Selasky 	if (node->dist) {
713*d6b92ffaSHans Petter Selasky 		if (dumplevel == 1)
714*d6b92ffaSHans Petter Selasky 			printf("[%d] -> %s {0x%016" PRIx64 "}[%d]\n",
715*d6b92ffaSHans Petter Selasky 			       node->ports->remoteport->portnum,
716*d6b92ffaSHans Petter Selasky 			       (node->type <=
717*d6b92ffaSHans Petter Selasky 				IB_NODE_MAX ? node_type_str[node->type] :
718*d6b92ffaSHans Petter Selasky 				"???"), node->nodeguid, node->upport);
719*d6b92ffaSHans Petter Selasky 		else
720*d6b92ffaSHans Petter Selasky 			printf("[%d] -> %s 0x%" PRIx64 "[%d] lid %u \"%s\"\n",
721*d6b92ffaSHans Petter Selasky 			       node->ports->remoteport->portnum,
722*d6b92ffaSHans Petter Selasky 			       (node->type <=
723*d6b92ffaSHans Petter Selasky 				IB_NODE_MAX ? node_type_str[node->type] :
724*d6b92ffaSHans Petter Selasky 				"???"), node->nodeguid, node->upport,
725*d6b92ffaSHans Petter Selasky 			       node->ports->lid, nodename);
726*d6b92ffaSHans Petter Selasky 	}
727*d6b92ffaSHans Petter Selasky 
728*d6b92ffaSHans Petter Selasky 	if (node->dist < 0)
729*d6b92ffaSHans Petter Selasky 		/* target node */
730*d6b92ffaSHans Petter Selasky 		printf("To %s 0x%" PRIx64 " port %d lid %u-%u \"%s\"\n",
731*d6b92ffaSHans Petter Selasky 		       (node->type <=
732*d6b92ffaSHans Petter Selasky 			IB_NODE_MAX ? node_type_str[node->type] : "???"),
733*d6b92ffaSHans Petter Selasky 		       node->nodeguid, node->ports->portnum, node->ports->lid,
734*d6b92ffaSHans Petter Selasky 		       node->ports->lid + (1 << node->ports->lmc) - 1,
735*d6b92ffaSHans Petter Selasky 		       nodename);
736*d6b92ffaSHans Petter Selasky 
737*d6b92ffaSHans Petter Selasky free_name:
738*d6b92ffaSHans Petter Selasky 	free(nodename);
739*d6b92ffaSHans Petter Selasky }
740*d6b92ffaSHans Petter Selasky 
resolve_lid(ib_portid_t * portid,const void * srcport)741*d6b92ffaSHans Petter Selasky static int resolve_lid(ib_portid_t * portid, const void *srcport)
742*d6b92ffaSHans Petter Selasky {
743*d6b92ffaSHans Petter Selasky 	uint8_t portinfo[64] = { 0 };
744*d6b92ffaSHans Petter Selasky 	uint16_t lid;
745*d6b92ffaSHans Petter Selasky 
746*d6b92ffaSHans Petter Selasky 	if (!smp_query_via(portinfo, portid, IB_ATTR_PORT_INFO, 0, 0, srcport))
747*d6b92ffaSHans Petter Selasky 		return -1;
748*d6b92ffaSHans Petter Selasky 	mad_decode_field(portinfo, IB_PORT_LID_F, &lid);
749*d6b92ffaSHans Petter Selasky 
750*d6b92ffaSHans Petter Selasky 	ib_portid_set(portid, lid, 0, 0);
751*d6b92ffaSHans Petter Selasky 
752*d6b92ffaSHans Petter Selasky 	return 0;
753*d6b92ffaSHans Petter Selasky }
754*d6b92ffaSHans Petter Selasky 
755*d6b92ffaSHans Petter Selasky static int dumplevel = 2, multicast, mlid;
756*d6b92ffaSHans Petter Selasky 
process_opt(void * context,int ch,char * optarg)757*d6b92ffaSHans Petter Selasky static int process_opt(void *context, int ch, char *optarg)
758*d6b92ffaSHans Petter Selasky {
759*d6b92ffaSHans Petter Selasky 	switch (ch) {
760*d6b92ffaSHans Petter Selasky 	case 1:
761*d6b92ffaSHans Petter Selasky 		node_name_map_file = strdup(optarg);
762*d6b92ffaSHans Petter Selasky 		break;
763*d6b92ffaSHans Petter Selasky 	case 'm':
764*d6b92ffaSHans Petter Selasky 		multicast++;
765*d6b92ffaSHans Petter Selasky 		mlid = strtoul(optarg, 0, 0);
766*d6b92ffaSHans Petter Selasky 		break;
767*d6b92ffaSHans Petter Selasky 	case 'f':
768*d6b92ffaSHans Petter Selasky 		force++;
769*d6b92ffaSHans Petter Selasky 		break;
770*d6b92ffaSHans Petter Selasky 	case 'n':
771*d6b92ffaSHans Petter Selasky 		dumplevel = 1;
772*d6b92ffaSHans Petter Selasky 		break;
773*d6b92ffaSHans Petter Selasky 	default:
774*d6b92ffaSHans Petter Selasky 		return -1;
775*d6b92ffaSHans Petter Selasky 	}
776*d6b92ffaSHans Petter Selasky 	return 0;
777*d6b92ffaSHans Petter Selasky }
778*d6b92ffaSHans Petter Selasky 
main(int argc,char ** argv)779*d6b92ffaSHans Petter Selasky int main(int argc, char **argv)
780*d6b92ffaSHans Petter Selasky {
781*d6b92ffaSHans Petter Selasky 	int mgmt_classes[3] =
782*d6b92ffaSHans Petter Selasky 	    { IB_SMI_CLASS, IB_SMI_DIRECT_CLASS, IB_SA_CLASS };
783*d6b92ffaSHans Petter Selasky 	ib_portid_t my_portid = { 0 };
784*d6b92ffaSHans Petter Selasky 	ib_portid_t src_portid = { 0 };
785*d6b92ffaSHans Petter Selasky 	ib_portid_t dest_portid = { 0 };
786*d6b92ffaSHans Petter Selasky 	Node *endnode;
787*d6b92ffaSHans Petter Selasky 
788*d6b92ffaSHans Petter Selasky 	const struct ibdiag_opt opts[] = {
789*d6b92ffaSHans Petter Selasky 		{"force", 'f', 0, NULL, "force"},
790*d6b92ffaSHans Petter Selasky 		{"no_info", 'n', 0, NULL, "simple format"},
791*d6b92ffaSHans Petter Selasky 		{"mlid", 'm', 1, "<mlid>", "multicast trace of the mlid"},
792*d6b92ffaSHans Petter Selasky 		{"node-name-map", 1, 1, "<file>", "node name map file"},
793*d6b92ffaSHans Petter Selasky 		{0}
794*d6b92ffaSHans Petter Selasky 	};
795*d6b92ffaSHans Petter Selasky 	char usage_args[] = "<src-addr> <dest-addr>";
796*d6b92ffaSHans Petter Selasky 	const char *usage_examples[] = {
797*d6b92ffaSHans Petter Selasky 		"- Unicast examples:",
798*d6b92ffaSHans Petter Selasky 		"4 16\t\t\t# show path between lids 4 and 16",
799*d6b92ffaSHans Petter Selasky 		"-n 4 16\t\t# same, but using simple output format",
800*d6b92ffaSHans Petter Selasky 		"-G 0x8f1040396522d 0x002c9000100d051\t# use guid addresses",
801*d6b92ffaSHans Petter Selasky 
802*d6b92ffaSHans Petter Selasky 		" - Multicast examples:",
803*d6b92ffaSHans Petter Selasky 		"-m 0xc000 4 16\t# show multicast path of mlid 0xc000 between lids 4 and 16",
804*d6b92ffaSHans Petter Selasky 		NULL,
805*d6b92ffaSHans Petter Selasky 	};
806*d6b92ffaSHans Petter Selasky 
807*d6b92ffaSHans Petter Selasky 	ibdiag_process_opts(argc, argv, NULL, "DK", opts, process_opt,
808*d6b92ffaSHans Petter Selasky 			    usage_args, usage_examples);
809*d6b92ffaSHans Petter Selasky 
810*d6b92ffaSHans Petter Selasky 	f = stdout;
811*d6b92ffaSHans Petter Selasky 	argc -= optind;
812*d6b92ffaSHans Petter Selasky 	argv += optind;
813*d6b92ffaSHans Petter Selasky 
814*d6b92ffaSHans Petter Selasky 	if (argc < 2)
815*d6b92ffaSHans Petter Selasky 		ibdiag_show_usage();
816*d6b92ffaSHans Petter Selasky 
817*d6b92ffaSHans Petter Selasky 	if (ibd_timeout)
818*d6b92ffaSHans Petter Selasky 		timeout = ibd_timeout;
819*d6b92ffaSHans Petter Selasky 
820*d6b92ffaSHans Petter Selasky 	srcport = mad_rpc_open_port(ibd_ca, ibd_ca_port, mgmt_classes, 3);
821*d6b92ffaSHans Petter Selasky 	if (!srcport)
822*d6b92ffaSHans Petter Selasky 		IBEXIT("Failed to open '%s' port '%d'", ibd_ca, ibd_ca_port);
823*d6b92ffaSHans Petter Selasky 
824*d6b92ffaSHans Petter Selasky 	smp_mkey_set(srcport, ibd_mkey);
825*d6b92ffaSHans Petter Selasky 
826*d6b92ffaSHans Petter Selasky 	node_name_map = open_node_name_map(node_name_map_file);
827*d6b92ffaSHans Petter Selasky 
828*d6b92ffaSHans Petter Selasky 	if (resolve_portid_str(ibd_ca, ibd_ca_port, &src_portid, argv[0],
829*d6b92ffaSHans Petter Selasky 			       ibd_dest_type, ibd_sm_id, srcport) < 0)
830*d6b92ffaSHans Petter Selasky 		IBEXIT("can't resolve source port %s", argv[0]);
831*d6b92ffaSHans Petter Selasky 
832*d6b92ffaSHans Petter Selasky 	if (resolve_portid_str(ibd_ca, ibd_ca_port, &dest_portid, argv[1],
833*d6b92ffaSHans Petter Selasky 			       ibd_dest_type, ibd_sm_id, srcport) < 0)
834*d6b92ffaSHans Petter Selasky 		IBEXIT("can't resolve destination port %s", argv[1]);
835*d6b92ffaSHans Petter Selasky 
836*d6b92ffaSHans Petter Selasky 	if (ibd_dest_type == IB_DEST_DRPATH) {
837*d6b92ffaSHans Petter Selasky 		if (resolve_lid(&src_portid, NULL) < 0)
838*d6b92ffaSHans Petter Selasky 			IBEXIT("cannot resolve lid for port \'%s\'",
839*d6b92ffaSHans Petter Selasky 				portid2str(&src_portid));
840*d6b92ffaSHans Petter Selasky 		if (resolve_lid(&dest_portid, NULL) < 0)
841*d6b92ffaSHans Petter Selasky 			IBEXIT("cannot resolve lid for port \'%s\'",
842*d6b92ffaSHans Petter Selasky 				portid2str(&dest_portid));
843*d6b92ffaSHans Petter Selasky 	}
844*d6b92ffaSHans Petter Selasky 
845*d6b92ffaSHans Petter Selasky 	if (dest_portid.lid == 0 || src_portid.lid == 0) {
846*d6b92ffaSHans Petter Selasky 		IBWARN("bad src/dest lid");
847*d6b92ffaSHans Petter Selasky 		ibdiag_show_usage();
848*d6b92ffaSHans Petter Selasky 	}
849*d6b92ffaSHans Petter Selasky 
850*d6b92ffaSHans Petter Selasky 	if (ibd_dest_type != IB_DEST_DRPATH) {
851*d6b92ffaSHans Petter Selasky 		/* first find a direct path to the src port */
852*d6b92ffaSHans Petter Selasky 		if (find_route(&my_portid, &src_portid, 0) < 0)
853*d6b92ffaSHans Petter Selasky 			IBEXIT("can't find a route to the src port");
854*d6b92ffaSHans Petter Selasky 
855*d6b92ffaSHans Petter Selasky 		src_portid = my_portid;
856*d6b92ffaSHans Petter Selasky 	}
857*d6b92ffaSHans Petter Selasky 
858*d6b92ffaSHans Petter Selasky 	if (!multicast) {
859*d6b92ffaSHans Petter Selasky 		if (find_route(&src_portid, &dest_portid, dumplevel) < 0)
860*d6b92ffaSHans Petter Selasky 			IBEXIT("can't find a route from src to dest");
861*d6b92ffaSHans Petter Selasky 		exit(0);
862*d6b92ffaSHans Petter Selasky 	} else {
863*d6b92ffaSHans Petter Selasky 		if (mlid < 0xc000)
864*d6b92ffaSHans Petter Selasky 			IBWARN("invalid MLID; must be 0xc000 or larger");
865*d6b92ffaSHans Petter Selasky 	}
866*d6b92ffaSHans Petter Selasky 
867*d6b92ffaSHans Petter Selasky 	if (!(target_portguid = find_target_portguid(&dest_portid)))
868*d6b92ffaSHans Petter Selasky 		IBEXIT("can't reach target lid %d", dest_portid.lid);
869*d6b92ffaSHans Petter Selasky 
870*d6b92ffaSHans Petter Selasky 	if (!(endnode = find_mcpath(&src_portid, mlid)))
871*d6b92ffaSHans Petter Selasky 		IBEXIT("can't find a multicast route from src to dest");
872*d6b92ffaSHans Petter Selasky 
873*d6b92ffaSHans Petter Selasky 	/* dump multicast path */
874*d6b92ffaSHans Petter Selasky 	dump_mcpath(endnode, dumplevel);
875*d6b92ffaSHans Petter Selasky 
876*d6b92ffaSHans Petter Selasky 	close_node_name_map(node_name_map);
877*d6b92ffaSHans Petter Selasky 
878*d6b92ffaSHans Petter Selasky 	mad_rpc_close_port(srcport);
879*d6b92ffaSHans Petter Selasky 
880*d6b92ffaSHans Petter Selasky 	exit(0);
881*d6b92ffaSHans Petter Selasky }
882