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 } 882