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