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