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