]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/ofed/infiniband-diags/src/ibtracert.c
Adjust ENA driver to the new HAL
[FreeBSD/FreeBSD.git] / contrib / ofed / infiniband-diags / src / ibtracert.c
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  */
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
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
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
201 static int sameport(Port * a, Port * b)
202 {
203         return a->portguid == b->portguid || (force && a->lid == b->lid);
204 }
205
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
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
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
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
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
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
455 static void link_port(Port * port, Node * node)
456 {
457         port->next = node->ports;
458         node->ports = port;
459 }
460
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
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  */
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
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
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
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
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
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 }