1219820Sjeff/* 2219820Sjeff * Copyright (c) 2004-2008 Voltaire Inc. All rights reserved. 3219820Sjeff * 4219820Sjeff * This software is available to you under a choice of one of two 5219820Sjeff * licenses. You may choose to be licensed under the terms of the GNU 6219820Sjeff * General Public License (GPL) Version 2, available from the file 7219820Sjeff * COPYING in the main directory of this source tree, or the 8219820Sjeff * OpenIB.org BSD license below: 9219820Sjeff * 10219820Sjeff * Redistribution and use in source and binary forms, with or 11219820Sjeff * without modification, are permitted provided that the following 12219820Sjeff * conditions are met: 13219820Sjeff * 14219820Sjeff * - Redistributions of source code must retain the above 15219820Sjeff * copyright notice, this list of conditions and the following 16219820Sjeff * disclaimer. 17219820Sjeff * 18219820Sjeff * - Redistributions in binary form must reproduce the above 19219820Sjeff * copyright notice, this list of conditions and the following 20219820Sjeff * disclaimer in the documentation and/or other materials 21219820Sjeff * provided with the distribution. 22219820Sjeff * 23219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30219820Sjeff * SOFTWARE. 31219820Sjeff * 32219820Sjeff */ 33219820Sjeff 34219820Sjeff#if HAVE_CONFIG_H 35219820Sjeff# include <config.h> 36219820Sjeff#endif /* HAVE_CONFIG_H */ 37219820Sjeff 38219820Sjeff#define _GNU_SOURCE 39219820Sjeff#include <stdio.h> 40219820Sjeff#include <stdlib.h> 41219820Sjeff#include <unistd.h> 42219820Sjeff#include <stdarg.h> 43219820Sjeff#include <ctype.h> 44219820Sjeff#include <getopt.h> 45219820Sjeff#include <netinet/in.h> 46219820Sjeff#include <inttypes.h> 47219820Sjeff#include <errno.h> 48219820Sjeff 49219820Sjeff#include <infiniband/common.h> 50219820Sjeff#include <infiniband/umad.h> 51219820Sjeff#include <infiniband/mad.h> 52219820Sjeff#include <infiniband/complib/cl_nodenamemap.h> 53219820Sjeff 54219820Sjeff#include "ibdiag_common.h" 55219820Sjeff 56219820Sjeff#define MAXHOPS 63 57219820Sjeff 58219820Sjeffstatic char *node_type_str[] = { 59219820Sjeff "???", 60219820Sjeff "ca", 61219820Sjeff "switch", 62219820Sjeff "router", 63219820Sjeff "iwarp rnic" 64219820Sjeff}; 65219820Sjeff 66219820Sjeffstatic int timeout = 0; /* ms */ 67219820Sjeffstatic int verbose; 68219820Sjeffstatic int force; 69219820Sjeffstatic FILE *f; 70219820Sjeff 71219820Sjeffchar *argv0 = "ibtracert"; 72219820Sjeff 73219820Sjeffstatic char *node_name_map_file = NULL; 74219820Sjeffstatic nn_map_t *node_name_map = NULL; 75219820Sjeff 76219820Sjefftypedef struct Port Port; 77219820Sjefftypedef struct Switch Switch; 78219820Sjefftypedef struct Node Node; 79219820Sjeff 80219820Sjeffstruct Port { 81219820Sjeff Port *next; 82219820Sjeff Port *remoteport; 83219820Sjeff uint64_t portguid; 84219820Sjeff int portnum; 85219820Sjeff int lid; 86219820Sjeff int lmc; 87219820Sjeff int state; 88219820Sjeff int physstate; 89219820Sjeff char portinfo[64]; 90219820Sjeff}; 91219820Sjeff 92219820Sjeffstruct Switch { 93219820Sjeff int linearcap; 94219820Sjeff int mccap; 95219820Sjeff int linearFDBtop; 96219820Sjeff int fdb_base; 97219820Sjeff int8_t fdb[64]; 98219820Sjeff char switchinfo[64]; 99219820Sjeff}; 100219820Sjeff 101219820Sjeffstruct Node { 102219820Sjeff Node *htnext; 103219820Sjeff Node *dnext; 104219820Sjeff Port *ports; 105219820Sjeff ib_portid_t path; 106219820Sjeff int type; 107219820Sjeff int dist; 108219820Sjeff int numports; 109219820Sjeff int upport; 110219820Sjeff Node *upnode; 111219820Sjeff uint64_t nodeguid; /* also portguid */ 112219820Sjeff char nodedesc[64]; 113219820Sjeff char nodeinfo[64]; 114219820Sjeff}; 115219820Sjeff 116219820SjeffNode *nodesdist[MAXHOPS]; 117219820Sjeffuint64_t target_portguid; 118219820Sjeff 119219820Sjeffstatic int 120219820Sjeffget_node(Node *node, Port *port, ib_portid_t *portid) 121219820Sjeff{ 122219820Sjeff void *pi = port->portinfo, *ni = node->nodeinfo, *nd = node->nodedesc; 123219820Sjeff char *s, *e; 124219820Sjeff 125219820Sjeff if (!smp_query(ni, portid, IB_ATTR_NODE_INFO, 0, timeout)) 126219820Sjeff return -1; 127219820Sjeff 128219820Sjeff if (!smp_query(nd, portid, IB_ATTR_NODE_DESC, 0, timeout)) 129219820Sjeff return -1; 130219820Sjeff 131219820Sjeff for (s = nd, e = s + 64; s < e; s++) { 132219820Sjeff if (!*s) 133219820Sjeff break; 134219820Sjeff if (!isprint(*s)) 135219820Sjeff *s = ' '; 136219820Sjeff } 137219820Sjeff 138219820Sjeff if (!smp_query(pi, portid, IB_ATTR_PORT_INFO, 0, timeout)) 139219820Sjeff return -1; 140219820Sjeff 141219820Sjeff mad_decode_field(ni, IB_NODE_GUID_F, &node->nodeguid); 142219820Sjeff mad_decode_field(ni, IB_NODE_TYPE_F, &node->type); 143219820Sjeff mad_decode_field(ni, IB_NODE_NPORTS_F, &node->numports); 144219820Sjeff 145219820Sjeff mad_decode_field(ni, IB_NODE_PORT_GUID_F, &port->portguid); 146219820Sjeff mad_decode_field(ni, IB_NODE_LOCAL_PORT_F, &port->portnum); 147219820Sjeff mad_decode_field(pi, IB_PORT_LID_F, &port->lid); 148219820Sjeff mad_decode_field(pi, IB_PORT_LMC_F, &port->lmc); 149219820Sjeff mad_decode_field(pi, IB_PORT_STATE_F, &port->state); 150219820Sjeff 151219820Sjeff DEBUG("portid %s: got node %" PRIx64 " '%s'", portid2str(portid), node->nodeguid, node->nodedesc); 152219820Sjeff return 0; 153219820Sjeff} 154219820Sjeff 155219820Sjeffstatic int 156219820Sjeffswitch_lookup(Switch *sw, ib_portid_t *portid, int lid) 157219820Sjeff{ 158219820Sjeff void *si = sw->switchinfo, *fdb = sw->fdb; 159219820Sjeff 160219820Sjeff if (!smp_query(si, portid, IB_ATTR_SWITCH_INFO, 0, timeout)) 161219820Sjeff return -1; 162219820Sjeff 163219820Sjeff mad_decode_field(si, IB_SW_LINEAR_FDB_CAP_F, &sw->linearcap); 164219820Sjeff mad_decode_field(si, IB_SW_LINEAR_FDB_TOP_F, &sw->linearFDBtop); 165219820Sjeff 166219820Sjeff if (lid > sw->linearcap && lid > sw->linearFDBtop) 167219820Sjeff return -1; 168219820Sjeff 169219820Sjeff if (!smp_query(fdb, portid, IB_ATTR_LINEARFORWTBL, lid / 64, timeout)) 170219820Sjeff return -1; 171219820Sjeff 172219820Sjeff DEBUG("portid %s: forward lid %d to port %d", 173219820Sjeff portid2str(portid), lid, sw->fdb[lid % 64]); 174219820Sjeff return sw->fdb[lid % 64]; 175219820Sjeff} 176219820Sjeff 177219820Sjeffstatic int 178219820Sjeffsameport(Port *a, Port *b) 179219820Sjeff{ 180219820Sjeff return a->portguid == b->portguid || (force && a->lid == b->lid); 181219820Sjeff} 182219820Sjeff 183219820Sjeffstatic int 184219820Sjeffextend_dpath(ib_dr_path_t *path, int nextport) 185219820Sjeff{ 186219820Sjeff if (path->cnt+2 >= sizeof(path->p)) 187219820Sjeff return -1; 188219820Sjeff ++path->cnt; 189219820Sjeff path->p[path->cnt] = nextport; 190219820Sjeff return path->cnt; 191219820Sjeff} 192219820Sjeff 193219820Sjeffstatic void 194219820Sjeffdump_endnode(int dump, char *prompt, Node *node, Port *port) 195219820Sjeff{ 196219820Sjeff char *nodename = NULL; 197219820Sjeff 198219820Sjeff if (!dump) 199219820Sjeff return; 200219820Sjeff if (dump == 1) { 201219820Sjeff fprintf(f, "%s {0x%016" PRIx64 "}[%d]\n", 202219820Sjeff prompt, node->nodeguid, 203219820Sjeff node->type == IB_NODE_SWITCH ? 0 : port->portnum); 204219820Sjeff return; 205219820Sjeff } 206219820Sjeff 207219820Sjeff nodename = remap_node_name(node_name_map, node->nodeguid, node->nodedesc); 208219820Sjeff 209219820Sjeff fprintf(f, "%s %s {0x%016" PRIx64 "} portnum %d lid %u-%u \"%s\"\n", 210219820Sjeff prompt, 211219820Sjeff (node->type <= IB_NODE_MAX ? node_type_str[node->type] : "???"), 212219820Sjeff node->nodeguid, node->type == IB_NODE_SWITCH ? 0 : port->portnum, 213219820Sjeff port->lid, port->lid + (1 << port->lmc) - 1, 214219820Sjeff nodename); 215219820Sjeff 216219820Sjeff free(nodename); 217219820Sjeff} 218219820Sjeff 219219820Sjeffstatic void 220219820Sjeffdump_route(int dump, Node *node, int outport, Port *port) 221219820Sjeff{ 222219820Sjeff char *nodename = NULL; 223219820Sjeff 224219820Sjeff if (!dump && !verbose) 225219820Sjeff return; 226219820Sjeff 227219820Sjeff nodename = remap_node_name(node_name_map, node->nodeguid, node->nodedesc); 228219820Sjeff 229219820Sjeff if (dump == 1) 230219820Sjeff fprintf(f, "[%d] -> {0x%016" PRIx64 "}[%d]\n", 231219820Sjeff outport, port->portguid, port->portnum); 232219820Sjeff else 233219820Sjeff fprintf(f, "[%d] -> %s port {0x%016" PRIx64 "}[%d] lid %u-%u \"%s\"\n", 234219820Sjeff outport, 235219820Sjeff (node->type <= IB_NODE_MAX ? node_type_str[node->type] : "???"), 236219820Sjeff port->portguid, port->portnum, 237219820Sjeff port->lid, port->lid + (1 << port->lmc) - 1, 238219820Sjeff nodename); 239219820Sjeff 240219820Sjeff free(nodename); 241219820Sjeff} 242219820Sjeff 243219820Sjeffstatic int 244219820Sjefffind_route(ib_portid_t *from, ib_portid_t *to, int dump) 245219820Sjeff{ 246219820Sjeff Node *node, fromnode, tonode, nextnode; 247219820Sjeff Port *port, fromport, toport, nextport; 248219820Sjeff Switch sw; 249219820Sjeff int maxhops = MAXHOPS; 250219820Sjeff int portnum, outport; 251219820Sjeff 252219820Sjeff DEBUG("from %s", portid2str(from)); 253219820Sjeff 254219820Sjeff if (get_node(&fromnode, &fromport, from) < 0 || 255219820Sjeff get_node(&tonode, &toport, to) < 0) { 256219820Sjeff IBWARN("can't reach to/from ports"); 257219820Sjeff if (!force) 258219820Sjeff return -1; 259219820Sjeff if (to->lid > 0) 260219820Sjeff toport.lid = to->lid; 261219820Sjeff IBWARN("Force: look for lid %d", to->lid); 262219820Sjeff } 263219820Sjeff 264219820Sjeff node = &fromnode; 265219820Sjeff port = &fromport; 266219820Sjeff portnum = port->portnum; 267219820Sjeff 268219820Sjeff dump_endnode(dump, "From", node, port); 269219820Sjeff 270219820Sjeff while (maxhops--) { 271219820Sjeff if (port->state != 4) 272219820Sjeff goto badport; 273219820Sjeff 274219820Sjeff if (sameport(port, &toport)) 275219820Sjeff break; /* found */ 276219820Sjeff 277219820Sjeff outport = portnum; 278219820Sjeff if (node->type == IB_NODE_SWITCH) { 279219820Sjeff DEBUG("switch node"); 280219820Sjeff if ((outport = switch_lookup(&sw, from, to->lid)) < 0 || 281219820Sjeff outport > node->numports) 282219820Sjeff goto badtbl; 283219820Sjeff 284219820Sjeff if (extend_dpath(&from->drpath, outport) < 0) 285219820Sjeff goto badpath; 286219820Sjeff 287219820Sjeff if (get_node(&nextnode, &nextport, from) < 0) { 288219820Sjeff IBWARN("can't reach port at %s", portid2str(from)); 289219820Sjeff return -1; 290219820Sjeff } 291219820Sjeff if (outport == 0) { 292219820Sjeff if (!sameport(&nextport, &toport)) 293219820Sjeff goto badtbl; 294219820Sjeff else 295219820Sjeff break; /* found SMA port */ 296219820Sjeff } 297219820Sjeff } else if ((node->type == IB_NODE_CA) || 298219820Sjeff (node->type == IB_NODE_ROUTER)) { 299219820Sjeff int ca_src = 0; 300219820Sjeff 301219820Sjeff DEBUG("ca or router node"); 302219820Sjeff if (!sameport(port, &fromport)) { 303219820Sjeff IBWARN("can't continue: reached CA or router port %" PRIx64 ", lid %d", 304219820Sjeff port->portguid, port->lid); 305219820Sjeff return -1; 306219820Sjeff } 307219820Sjeff /* we are at CA or router "from" - go one hop back to (hopefully) a switch */ 308219820Sjeff if (from->drpath.cnt > 0) { 309219820Sjeff DEBUG("ca or router node - return back 1 hop"); 310219820Sjeff from->drpath.cnt--; 311219820Sjeff } else { 312219820Sjeff ca_src = 1; 313219820Sjeff if (portnum && extend_dpath(&from->drpath, portnum) < 0) 314219820Sjeff goto badpath; 315219820Sjeff } 316219820Sjeff if (get_node(&nextnode, &nextport, from) < 0) { 317219820Sjeff IBWARN("can't reach port at %s", portid2str(from)); 318219820Sjeff return -1; 319219820Sjeff } 320219820Sjeff /* fix port num to be seen from the CA or router side */ 321219820Sjeff if (!ca_src) 322219820Sjeff nextport.portnum = from->drpath.p[from->drpath.cnt+1]; 323219820Sjeff } 324219820Sjeff port = &nextport; 325219820Sjeff if (port->state != 4) 326219820Sjeff goto badoutport; 327219820Sjeff node = &nextnode; 328219820Sjeff portnum = port->portnum; 329219820Sjeff dump_route(dump, node, outport, port); 330219820Sjeff } 331219820Sjeff 332219820Sjeff if (maxhops <= 0) { 333219820Sjeff IBWARN("no route found after %d hops", MAXHOPS); 334219820Sjeff return -1; 335219820Sjeff } 336219820Sjeff dump_endnode(dump, "To", node, port); 337219820Sjeff return 0; 338219820Sjeff 339219820Sjeffbadport: 340219820Sjeff IBWARN("Bad port state found: node \"%s\" port %d state %d", 341219820Sjeff clean_nodedesc(node->nodedesc), portnum, port->state); 342219820Sjeff return -1; 343219820Sjeffbadoutport: 344219820Sjeff IBWARN("Bad out port state found: node \"%s\" outport %d state %d", 345219820Sjeff clean_nodedesc(node->nodedesc), outport, port->state); 346219820Sjeff return -1; 347219820Sjeffbadtbl: 348219820Sjeff IBWARN("Bad forwarding table entry found at: node \"%s\" lid entry %d is %d (top %d)", 349219820Sjeff clean_nodedesc(node->nodedesc), to->lid, outport, sw.linearFDBtop); 350219820Sjeff return -1; 351219820Sjeffbadpath: 352219820Sjeff IBWARN("Direct path too long!"); 353219820Sjeff return -1; 354219820Sjeff} 355219820Sjeff 356219820Sjeff 357219820Sjeff/************************** 358219820Sjeff * MC span part 359219820Sjeff */ 360219820Sjeff 361219820Sjeff#define HASHGUID(guid) ((uint32_t)(((uint32_t)(guid) * 101) ^ ((uint32_t)((guid) >> 32) * 103))) 362219820Sjeff#define HTSZ 137 363219820Sjeff 364219820Sjeffstatic int 365219820Sjeffinsert_node(Node *new) 366219820Sjeff{ 367219820Sjeff static Node *nodestbl[HTSZ]; 368219820Sjeff int hash = HASHGUID(new->nodeguid) % HTSZ; 369219820Sjeff Node *node ; 370219820Sjeff 371219820Sjeff for (node = nodestbl[hash]; node; node = node->htnext) 372219820Sjeff if (node->nodeguid == new->nodeguid) { 373219820Sjeff DEBUG("node %" PRIx64 " already exists", new->nodeguid); 374219820Sjeff return -1; 375219820Sjeff } 376219820Sjeff 377219820Sjeff new->htnext = nodestbl[hash]; 378219820Sjeff nodestbl[hash] = new; 379219820Sjeff 380219820Sjeff return 0; 381219820Sjeff} 382219820Sjeff 383219820Sjeffstatic int 384219820Sjeffget_port(Port *port, int portnum, ib_portid_t *portid) 385219820Sjeff{ 386219820Sjeff char portinfo[64]; 387219820Sjeff void *pi = portinfo; 388219820Sjeff 389219820Sjeff port->portnum = portnum; 390219820Sjeff 391219820Sjeff if (!smp_query(pi, portid, IB_ATTR_PORT_INFO, portnum, timeout)) 392219820Sjeff return -1; 393219820Sjeff 394219820Sjeff mad_decode_field(pi, IB_PORT_LID_F, &port->lid); 395219820Sjeff mad_decode_field(pi, IB_PORT_LMC_F, &port->lmc); 396219820Sjeff mad_decode_field(pi, IB_PORT_STATE_F, &port->state); 397219820Sjeff mad_decode_field(pi, IB_PORT_PHYS_STATE_F, &port->physstate); 398219820Sjeff 399219820Sjeff VERBOSE("portid %s portnum %d: lid %d state %d physstate %d", 400219820Sjeff portid2str(portid), portnum, port->lid, port->state, port->physstate); 401219820Sjeff return 1; 402219820Sjeff} 403219820Sjeff 404219820Sjeffstatic void 405219820Sjefflink_port(Port *port, Node *node) 406219820Sjeff{ 407219820Sjeff port->next = node->ports; 408219820Sjeff node->ports = port; 409219820Sjeff} 410219820Sjeff 411219820Sjeffstatic int 412219820Sjeffnew_node(Node *node, Port *port, ib_portid_t *path, int dist) 413219820Sjeff{ 414219820Sjeff if (port->portguid == target_portguid) { 415219820Sjeff node->dist = -1; /* tag as target */ 416219820Sjeff link_port(port, node); 417219820Sjeff dump_endnode(verbose, "found target", node, port); 418219820Sjeff return 1; /* found; */ 419219820Sjeff } 420219820Sjeff 421219820Sjeff /* BFS search start with my self */ 422219820Sjeff if (insert_node(node) < 0) 423219820Sjeff return -1; /* known switch */ 424219820Sjeff 425219820Sjeff VERBOSE("insert dist %d node %p port %d lid %d", dist, node, port->portnum, port->lid); 426219820Sjeff 427219820Sjeff link_port(port, node); 428219820Sjeff 429219820Sjeff node->dist = dist; 430219820Sjeff node->path = *path; 431219820Sjeff node->dnext = nodesdist[dist]; 432219820Sjeff nodesdist[dist] = node; 433219820Sjeff 434219820Sjeff return 0; 435219820Sjeff} 436219820Sjeff 437219820Sjeffstatic int 438219820Sjeffswitch_mclookup(Node *node, ib_portid_t *portid, int mlid, char *map) 439219820Sjeff{ 440219820Sjeff Switch sw; 441219820Sjeff char mdb[64]; 442219820Sjeff void *si = sw.switchinfo; 443219820Sjeff uint16_t *msets = (uint16_t *)mdb; 444219820Sjeff int maxsets, block, i, set; 445219820Sjeff 446219820Sjeff memset(map, 0, 256); 447219820Sjeff 448219820Sjeff if (!smp_query(si, portid, IB_ATTR_SWITCH_INFO, 0, timeout)) 449219820Sjeff return -1; 450219820Sjeff 451219820Sjeff mlid -= 0xc000; 452219820Sjeff 453219820Sjeff mad_decode_field(si, IB_SW_MCAST_FDB_CAP_F, &sw.mccap); 454219820Sjeff 455219820Sjeff if (mlid > sw.mccap) 456219820Sjeff return -1; 457219820Sjeff 458219820Sjeff block = mlid / 32; 459219820Sjeff maxsets = (node->numports + 15) / 16; /* round up */ 460219820Sjeff 461219820Sjeff for (set = 0; set < maxsets; set++) { 462219820Sjeff if (!smp_query(mdb, portid, IB_ATTR_MULTICASTFORWTBL, 463219820Sjeff block | (set << 28), timeout)) 464219820Sjeff return -1; 465219820Sjeff 466219820Sjeff for (i = 0; i < 16; i++, map++) { 467219820Sjeff uint16_t mask = ntohs(msets[mlid % 32]); 468219820Sjeff if (mask & (1 << i)) 469219820Sjeff *map = 1; 470219820Sjeff else 471219820Sjeff continue; 472219820Sjeff VERBOSE("Switch guid 0x%" PRIx64 ": mlid 0x%x is forwarded to port %d", 473219820Sjeff node->nodeguid, mlid + 0xc000, i + set * 16); 474219820Sjeff } 475219820Sjeff } 476219820Sjeff 477219820Sjeff return 0; 478219820Sjeff} 479219820Sjeff 480219820Sjeff/* 481219820Sjeff * Return 1 if found, 0 if not, -1 on errors. 482219820Sjeff */ 483219820Sjeffstatic Node * 484219820Sjefffind_mcpath(ib_portid_t *from, int mlid) 485219820Sjeff{ 486219820Sjeff Node *node, *remotenode; 487219820Sjeff Port *port, *remoteport; 488219820Sjeff char map[256]; 489219820Sjeff int r, i; 490219820Sjeff int dist = 0, leafport = 0; 491219820Sjeff ib_portid_t *path; 492219820Sjeff 493219820Sjeff DEBUG("from %s", portid2str(from)); 494219820Sjeff 495219820Sjeff if (!(node = calloc(1, sizeof(Node)))) 496219820Sjeff IBERROR("out of memory"); 497219820Sjeff 498219820Sjeff if (!(port = calloc(1, sizeof(Port)))) 499219820Sjeff IBERROR("out of memory"); 500219820Sjeff 501219820Sjeff if (get_node(node, port, from) < 0) { 502219820Sjeff IBWARN("can't reach node %s", portid2str(from)); 503219820Sjeff return 0; 504219820Sjeff } 505219820Sjeff 506219820Sjeff node->upnode = 0; /* root */ 507219820Sjeff if ((r = new_node(node, port, from, 0)) > 0) { 508219820Sjeff if (node->type != IB_NODE_SWITCH) { 509219820Sjeff IBWARN("ibtracert from CA to CA is unsupported"); 510219820Sjeff return 0; /* ibtracert from host to itself is unsupported */ 511219820Sjeff } 512219820Sjeff 513219820Sjeff if (switch_mclookup(node, from, mlid, map) < 0 || 514219820Sjeff !map[0]) 515219820Sjeff return 0; 516219820Sjeff return node; 517219820Sjeff } 518219820Sjeff 519219820Sjeff for (dist = 0; dist < MAXHOPS; dist++) { 520219820Sjeff 521219820Sjeff for (node = nodesdist[dist]; node; node = node->dnext) { 522219820Sjeff 523219820Sjeff path = &node->path; 524219820Sjeff 525219820Sjeff VERBOSE("dist %d node %p", dist, node); 526219820Sjeff dump_endnode(verbose, "processing", node, node->ports); 527219820Sjeff 528219820Sjeff memset(map, 0, sizeof(map)); 529219820Sjeff 530219820Sjeff if (node->type != IB_NODE_SWITCH) { 531219820Sjeff if (dist) 532219820Sjeff continue; 533219820Sjeff leafport = path->drpath.p[path->drpath.cnt]; 534219820Sjeff map[port->portnum] = 1; 535219820Sjeff node->upport = 0; /* starting here */ 536219820Sjeff DEBUG("Starting from CA 0x%" PRIx64 " lid %d port %d (leafport %d)", 537219820Sjeff node->nodeguid, port->lid, port->portnum, leafport); 538219820Sjeff } else { /* switch */ 539219820Sjeff 540219820Sjeff /* if starting from a leaf port fix up port (up port) */ 541219820Sjeff if (dist == 1 && leafport) 542219820Sjeff node->upport = leafport; 543219820Sjeff 544219820Sjeff if (switch_mclookup(node, path, mlid, map) < 0) { 545219820Sjeff IBWARN("skipping bad Switch 0x%" PRIx64 "", 546219820Sjeff node->nodeguid); 547219820Sjeff continue; 548219820Sjeff } 549219820Sjeff } 550219820Sjeff 551219820Sjeff for (i = 1; i <= node->numports; i++) { 552219820Sjeff if (!map[i] || i == node->upport) 553219820Sjeff continue; 554219820Sjeff 555219820Sjeff if (dist == 0 && leafport) { 556219820Sjeff if (from->drpath.cnt > 0) 557219820Sjeff path->drpath.cnt--; 558219820Sjeff } else { 559219820Sjeff if (!(port = calloc(1, sizeof(Port)))) 560219820Sjeff IBERROR("out of memory"); 561219820Sjeff 562219820Sjeff if (get_port(port, i, path) < 0) { 563219820Sjeff IBWARN("can't reach node %s port %d", portid2str(path), i); 564219820Sjeff return 0; 565219820Sjeff } 566219820Sjeff 567219820Sjeff if (port->physstate != 5) { /* LinkUP */ 568219820Sjeff free(port); 569219820Sjeff continue; 570219820Sjeff } 571219820Sjeff 572219820Sjeff#if 0 573219820Sjeff link_port(port, node); 574219820Sjeff#endif 575219820Sjeff 576219820Sjeff if (extend_dpath(&path->drpath, i) < 0) 577219820Sjeff return 0; 578219820Sjeff } 579219820Sjeff 580219820Sjeff if (!(remotenode = calloc(1, sizeof(Node)))) 581219820Sjeff IBERROR("out of memory"); 582219820Sjeff 583219820Sjeff if (!(remoteport = calloc(1, sizeof(Port)))) 584219820Sjeff IBERROR("out of memory"); 585219820Sjeff 586219820Sjeff if (get_node(remotenode, remoteport, path) < 0) { 587219820Sjeff IBWARN("NodeInfo on %s port %d failed, skipping port", 588219820Sjeff portid2str(path), i); 589219820Sjeff path->drpath.cnt--; /* restore path */ 590219820Sjeff free(remotenode); 591219820Sjeff free(remoteport); 592219820Sjeff continue; 593219820Sjeff } 594219820Sjeff 595219820Sjeff remotenode->upnode = node; 596219820Sjeff remotenode->upport = remoteport->portnum; 597219820Sjeff remoteport->remoteport = port; 598219820Sjeff 599219820Sjeff if ((r = new_node(remotenode, remoteport, path, dist+1)) > 0) 600219820Sjeff return remotenode; 601219820Sjeff 602219820Sjeff if (r == 0) 603219820Sjeff dump_endnode(verbose, "new remote", 604219820Sjeff remotenode, remoteport); 605219820Sjeff else if (remotenode->type == IB_NODE_SWITCH) 606219820Sjeff dump_endnode(2, "ERR: circle discovered at", 607219820Sjeff remotenode, remoteport); 608219820Sjeff 609219820Sjeff path->drpath.cnt--; /* restore path */ 610219820Sjeff } 611219820Sjeff } 612219820Sjeff } 613219820Sjeff 614219820Sjeff return 0; /* not found */ 615219820Sjeff} 616219820Sjeff 617219820Sjeffstatic uint64_t 618219820Sjefffind_target_portguid(ib_portid_t *to) 619219820Sjeff{ 620219820Sjeff Node tonode; 621219820Sjeff Port toport; 622219820Sjeff 623219820Sjeff if (get_node(&tonode, &toport, to) < 0) { 624219820Sjeff IBWARN("can't find to port\n"); 625219820Sjeff return -1; 626219820Sjeff } 627219820Sjeff 628219820Sjeff return toport.portguid; 629219820Sjeff} 630219820Sjeff 631219820Sjeffstatic void 632219820Sjeffdump_mcpath(Node *node, int dumplevel) 633219820Sjeff{ 634219820Sjeff char *nodename = NULL; 635219820Sjeff 636219820Sjeff if (node->upnode) 637219820Sjeff dump_mcpath(node->upnode, dumplevel); 638219820Sjeff 639219820Sjeff nodename = remap_node_name(node_name_map, node->nodeguid, node->nodedesc); 640219820Sjeff 641219820Sjeff if (!node->dist) { 642219820Sjeff printf("From %s 0x%" PRIx64 " port %d lid %u-%u \"%s\"\n", 643219820Sjeff (node->type <= IB_NODE_MAX ? node_type_str[node->type] : "???"), 644219820Sjeff node->nodeguid, node->ports->portnum, node->ports->lid, 645219820Sjeff node->ports->lid + (1 << node->ports->lmc) - 1, 646219820Sjeff nodename); 647219820Sjeff goto free_name; 648219820Sjeff } 649219820Sjeff 650219820Sjeff if (node->dist) { 651219820Sjeff if (dumplevel == 1) 652219820Sjeff printf("[%d] -> %s {0x%016" PRIx64 "}[%d]\n", 653219820Sjeff node->ports->remoteport->portnum, 654219820Sjeff (node->type <= IB_NODE_MAX ? node_type_str[node->type] : "???"), 655219820Sjeff node->nodeguid, node->upport); 656219820Sjeff else 657219820Sjeff printf("[%d] -> %s 0x%" PRIx64 "[%d] lid %u \"%s\"\n", 658219820Sjeff node->ports->remoteport->portnum, 659219820Sjeff (node->type <= IB_NODE_MAX ? node_type_str[node->type] : "???"), 660219820Sjeff node->nodeguid, node->upport, 661219820Sjeff node->ports->lid, nodename); 662219820Sjeff } 663219820Sjeff 664219820Sjeff if (node->dist < 0) 665219820Sjeff /* target node */ 666219820Sjeff printf("To %s 0x%" PRIx64 " port %d lid %u-%u \"%s\"\n", 667219820Sjeff (node->type <= IB_NODE_MAX ? node_type_str[node->type] : "???"), 668219820Sjeff node->nodeguid, node->ports->portnum, node->ports->lid, 669219820Sjeff node->ports->lid + (1 << node->ports->lmc) - 1, 670219820Sjeff nodename); 671219820Sjeff 672219820Sjefffree_name: 673219820Sjeff free(nodename); 674219820Sjeff} 675219820Sjeff 676219820Sjeffstatic int resolve_lid(ib_portid_t *portid, const void *srcport) 677219820Sjeff{ 678219820Sjeff uint8_t portinfo[64]; 679219820Sjeff uint16_t lid; 680219820Sjeff 681219820Sjeff if (!smp_query_via(portinfo, portid, IB_ATTR_PORT_INFO, 0, 0, srcport)) 682219820Sjeff return -1; 683219820Sjeff mad_decode_field(portinfo, IB_PORT_LID_F, &lid); 684219820Sjeff 685219820Sjeff ib_portid_set(portid, lid, 0, 0); 686219820Sjeff 687219820Sjeff return 0; 688219820Sjeff} 689219820Sjeff 690219820Sjeffstatic void 691219820Sjeffusage(void) 692219820Sjeff{ 693219820Sjeff char *basename; 694219820Sjeff 695219820Sjeff if (!(basename = strrchr(argv0, '/'))) 696219820Sjeff basename = argv0; 697219820Sjeff else 698219820Sjeff basename++; 699219820Sjeff 700219820Sjeff fprintf(stderr, "Usage: %s [-d(ebug) -v(erbose) -D(irect) -G(uids) -n(o_info) -C ca_name -P ca_port " 701219820Sjeff "-s smlid -t(imeout) timeout_ms -m mlid --node-name-map node-name-map ] <src-addr> <dest-addr>\n", 702219820Sjeff basename); 703219820Sjeff fprintf(stderr, "\n\tUnicast examples:\n"); 704219820Sjeff fprintf(stderr, "\t\t%s 4 16\t\t\t# show path between lids 4 and 16\n", basename); 705219820Sjeff fprintf(stderr, "\t\t%s -n 4 16\t\t# same, but using simple output format\n", basename); 706219820Sjeff fprintf(stderr, "\t\t%s -G 0x8f1040396522d 0x002c9000100d051\t# use guid addresses\n", basename); 707219820Sjeff 708219820Sjeff fprintf(stderr, "\n\tMulticast example:\n"); 709219820Sjeff fprintf(stderr, "\t\t%s -m 0xc000 4 16\t# show multicast path of mlid 0xc000 between lids 4 and 16\n", basename); 710219820Sjeff exit(-1); 711219820Sjeff} 712219820Sjeff 713219820Sjeffint 714219820Sjeffmain(int argc, char **argv) 715219820Sjeff{ 716219820Sjeff int mgmt_classes[3] = {IB_SMI_CLASS, IB_SMI_DIRECT_CLASS, IB_SA_CLASS}; 717219820Sjeff ib_portid_t my_portid = {0}; 718219820Sjeff ib_portid_t src_portid = {0}; 719219820Sjeff ib_portid_t dest_portid = {0}; 720219820Sjeff ib_portid_t *sm_id = 0, sm_portid = {0}; 721219820Sjeff int dumplevel = 2, dest_type = IB_DEST_LID, multicast = 0, mlid = 0; 722219820Sjeff Node *endnode; 723219820Sjeff int udebug = 0; 724219820Sjeff char *ca = 0; 725219820Sjeff int ca_port = 0; 726219820Sjeff 727219820Sjeff static char const str_opts[] = "C:P:t:s:m:dvfDGnVhu"; 728219820Sjeff static const struct option long_opts[] = { 729219820Sjeff { "C", 1, 0, 'C'}, 730219820Sjeff { "P", 1, 0, 'P'}, 731219820Sjeff { "debug", 0, 0, 'd'}, 732219820Sjeff { "verbose", 0, 0, 'v'}, 733219820Sjeff { "force", 0, 0, 'f'}, 734219820Sjeff { "Direct", 0, 0, 'D'}, 735219820Sjeff { "Guids", 0, 0, 'G'}, 736219820Sjeff { "no_info", 0, 0, 'n'}, 737219820Sjeff { "timeout", 1, 0, 't'}, 738219820Sjeff { "s", 1, 0, 's'}, 739219820Sjeff { "m", 1, 0, 'm'}, 740219820Sjeff { "Version", 0, 0, 'V'}, 741219820Sjeff { "help", 0, 0, 'h'}, 742219820Sjeff { "usage", 0, 0, 'u'}, 743219820Sjeff { "node-name-map", 1, 0, 1}, 744219820Sjeff { } 745219820Sjeff }; 746219820Sjeff 747219820Sjeff argv0 = argv[0]; 748219820Sjeff 749219820Sjeff f = stdout; 750219820Sjeff 751219820Sjeff while (1) { 752219820Sjeff int ch = getopt_long(argc, argv, str_opts, long_opts, NULL); 753219820Sjeff if ( ch == -1 ) 754219820Sjeff break; 755219820Sjeff switch(ch) { 756219820Sjeff case 1: 757219820Sjeff node_name_map_file = strdup(optarg); 758219820Sjeff break; 759219820Sjeff case 'C': 760219820Sjeff ca = optarg; 761219820Sjeff break; 762219820Sjeff case 'P': 763219820Sjeff ca_port = strtoul(optarg, 0, 0); 764219820Sjeff break; 765219820Sjeff case 'd': 766219820Sjeff ibdebug++; 767219820Sjeff madrpc_show_errors(1); 768219820Sjeff umad_debug(udebug); 769219820Sjeff udebug++; 770219820Sjeff break; 771219820Sjeff case 'D': 772219820Sjeff dest_type = IB_DEST_DRPATH; 773219820Sjeff break; 774219820Sjeff case 'G': 775219820Sjeff dest_type = IB_DEST_GUID; 776219820Sjeff break; 777219820Sjeff case 'm': 778219820Sjeff multicast++; 779219820Sjeff mlid = strtoul(optarg, 0, 0); 780219820Sjeff break; 781219820Sjeff case 'f': 782219820Sjeff force++; 783219820Sjeff break; 784219820Sjeff case 'n': 785219820Sjeff dumplevel = 1; 786219820Sjeff break; 787219820Sjeff case 's': 788219820Sjeff if (ib_resolve_portid_str(&sm_portid, optarg, IB_DEST_LID, 0) < 0) 789219820Sjeff IBERROR("can't resolve SM destination port %s", optarg); 790219820Sjeff sm_id = &sm_portid; 791219820Sjeff break; 792219820Sjeff case 't': 793219820Sjeff timeout = strtoul(optarg, 0, 0); 794219820Sjeff madrpc_set_timeout(timeout); 795219820Sjeff break; 796219820Sjeff case 'v': 797219820Sjeff madrpc_show_errors(1); 798219820Sjeff verbose++; 799219820Sjeff break; 800219820Sjeff case 'V': 801219820Sjeff fprintf(stderr, "%s %s\n", argv0, get_build_version() ); 802219820Sjeff exit(-1); 803219820Sjeff default: 804219820Sjeff usage(); 805219820Sjeff break; 806219820Sjeff } 807219820Sjeff } 808219820Sjeff argc -= optind; 809219820Sjeff argv += optind; 810219820Sjeff 811219820Sjeff if (argc < 2) 812219820Sjeff usage(); 813219820Sjeff 814219820Sjeff madrpc_init(ca, ca_port, mgmt_classes, 3); 815219820Sjeff node_name_map = open_node_name_map(node_name_map_file); 816219820Sjeff 817219820Sjeff if (ib_resolve_portid_str(&src_portid, argv[0], dest_type, sm_id) < 0) 818219820Sjeff IBERROR("can't resolve source port %s", argv[0]); 819219820Sjeff 820219820Sjeff if (ib_resolve_portid_str(&dest_portid, argv[1], dest_type, sm_id) < 0) 821219820Sjeff IBERROR("can't resolve destination port %s", argv[1]); 822219820Sjeff 823219820Sjeff if (dest_type == IB_DEST_DRPATH) { 824219820Sjeff if (resolve_lid(&src_portid, NULL) < 0) 825219820Sjeff IBERROR("cannot resolve lid for port \'%s\'", 826219820Sjeff portid2str(&src_portid)); 827219820Sjeff if (resolve_lid(&dest_portid, NULL) < 0) 828219820Sjeff IBERROR("cannot resolve lid for port \'%s\'", 829219820Sjeff portid2str(&dest_portid)); 830219820Sjeff } 831219820Sjeff 832219820Sjeff if (dest_portid.lid == 0 || src_portid.lid == 0) { 833219820Sjeff IBWARN("bad src/dest lid"); 834219820Sjeff usage(); 835219820Sjeff } 836219820Sjeff 837219820Sjeff if (dest_type != IB_DEST_DRPATH) { 838219820Sjeff /* first find a direct path to the src port */ 839219820Sjeff if (find_route(&my_portid, &src_portid, 0) < 0) 840219820Sjeff IBERROR("can't find a route to the src port"); 841219820Sjeff 842219820Sjeff src_portid = my_portid; 843219820Sjeff } 844219820Sjeff 845219820Sjeff if (!multicast) { 846219820Sjeff if (find_route(&src_portid, &dest_portid, dumplevel) < 0) 847219820Sjeff IBERROR("can't find a route from src to dest"); 848219820Sjeff exit(0); 849219820Sjeff } else { 850219820Sjeff if (mlid < 0xc000) 851219820Sjeff IBWARN("invalid MLID; must be 0xc000 or larger"); 852219820Sjeff } 853219820Sjeff 854219820Sjeff if (!(target_portguid = find_target_portguid(&dest_portid))) 855219820Sjeff IBERROR("can't reach target lid %d", dest_portid.lid); 856219820Sjeff 857219820Sjeff if (!(endnode = find_mcpath(&src_portid, mlid))) 858219820Sjeff IBERROR("can't find a multicast route from src to dest"); 859219820Sjeff 860219820Sjeff /* dump multicast path */ 861219820Sjeff dump_mcpath(endnode, dumplevel); 862219820Sjeff 863219820Sjeff close_node_name_map(node_name_map); 864219820Sjeff exit(0); 865219820Sjeff} 866