ibnetdiscover.c revision 275448
1/* 2 * Copyright (c) 2004-2008 Voltaire Inc. All rights reserved. 3 * Copyright (c) 2007 Xsigo Systems Inc. All rights reserved. 4 * 5 * This software is available to you under a choice of one of two 6 * licenses. You may choose to be licensed under the terms of the GNU 7 * General Public License (GPL) Version 2, available from the file 8 * COPYING in the main directory of this source tree, or the 9 * OpenIB.org BSD license below: 10 * 11 * Redistribution and use in source and binary forms, with or 12 * without modification, are permitted provided that the following 13 * conditions are met: 14 * 15 * - Redistributions of source code must retain the above 16 * copyright notice, this list of conditions and the following 17 * disclaimer. 18 * 19 * - Redistributions in binary form must reproduce the above 20 * copyright notice, this list of conditions and the following 21 * disclaimer in the documentation and/or other materials 22 * provided with the distribution. 23 * 24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 28 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 29 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 30 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31 * SOFTWARE. 32 * 33 */ 34 35#if HAVE_CONFIG_H 36# include <config.h> 37#endif /* HAVE_CONFIG_H */ 38 39#define _GNU_SOURCE 40#include <stdio.h> 41#include <stdlib.h> 42#include <unistd.h> 43#include <stdarg.h> 44#include <time.h> 45#include <string.h> 46#include <getopt.h> 47#include <errno.h> 48#include <inttypes.h> 49 50#include <infiniband/common.h> 51#include <infiniband/umad.h> 52#include <infiniband/mad.h> 53#include <complib/cl_nodenamemap.h> 54 55#include "ibnetdiscover.h" 56#include "grouping.h" 57#include "ibdiag_common.h" 58 59static char *node_type_str[] = { 60 "???", 61 "ca", 62 "switch", 63 "router", 64 "iwarp rnic" 65}; 66 67static char *linkwidth_str[] = { 68 "??", 69 "1x", 70 "4x", 71 "??", 72 "8x", 73 "??", 74 "??", 75 "??", 76 "12x" 77}; 78 79static char *linkspeed_str[] = { 80 "???", 81 "SDR", 82 "DDR", 83 "???", 84 "QDR" 85}; 86 87static int timeout = 2000; /* ms */ 88static int dumplevel = 0; 89static int verbose; 90static FILE *f; 91 92char *argv0 = "ibnetdiscover"; 93 94static char *node_name_map_file = NULL; 95static nn_map_t *node_name_map = NULL; 96 97Node *nodesdist[MAXHOPS+1]; /* last is Ca list */ 98Node *mynode; 99int maxhops_discovered = 0; 100 101struct ChassisList *chassis = NULL; 102 103static char * 104get_linkwidth_str(int linkwidth) 105{ 106 if (linkwidth > 8) 107 return linkwidth_str[0]; 108 else 109 return linkwidth_str[linkwidth]; 110} 111 112static char * 113get_linkspeed_str(int linkspeed) 114{ 115 if (linkspeed > 4) 116 return linkspeed_str[0]; 117 else 118 return linkspeed_str[linkspeed]; 119} 120 121static inline const char* 122node_type_str2(Node *node) 123{ 124 switch(node->type) { 125 case SWITCH_NODE: return "SW"; 126 case CA_NODE: return "CA"; 127 case ROUTER_NODE: return "RT"; 128 } 129 return "??"; 130} 131 132void 133decode_port_info(void *pi, Port *port) 134{ 135 mad_decode_field(pi, IB_PORT_LID_F, &port->lid); 136 mad_decode_field(pi, IB_PORT_LMC_F, &port->lmc); 137 mad_decode_field(pi, IB_PORT_STATE_F, &port->state); 138 mad_decode_field(pi, IB_PORT_PHYS_STATE_F, &port->physstate); 139 mad_decode_field(pi, IB_PORT_LINK_WIDTH_ACTIVE_F, &port->linkwidth); 140 mad_decode_field(pi, IB_PORT_LINK_SPEED_ACTIVE_F, &port->linkspeed); 141} 142 143 144int 145get_port(Port *port, int portnum, ib_portid_t *portid) 146{ 147 char portinfo[64]; 148 void *pi = portinfo; 149 150 port->portnum = portnum; 151 152 if (!smp_query(pi, portid, IB_ATTR_PORT_INFO, portnum, timeout)) 153 return -1; 154 decode_port_info(pi, port); 155 156 DEBUG("portid %s portnum %d: lid %d state %d physstate %d %s %s", 157 portid2str(portid), portnum, port->lid, port->state, port->physstate, get_linkwidth_str(port->linkwidth), get_linkspeed_str(port->linkspeed)); 158 return 1; 159} 160/* 161 * Returns 0 if non switch node is found, 1 if switch is found, -1 if error. 162 */ 163int 164get_node(Node *node, Port *port, ib_portid_t *portid) 165{ 166 char portinfo[64]; 167 char switchinfo[64]; 168 void *pi = portinfo, *ni = node->nodeinfo, *nd = node->nodedesc; 169 void *si = switchinfo; 170 171 if (!smp_query(ni, portid, IB_ATTR_NODE_INFO, 0, timeout)) 172 return -1; 173 174 mad_decode_field(ni, IB_NODE_GUID_F, &node->nodeguid); 175 mad_decode_field(ni, IB_NODE_TYPE_F, &node->type); 176 mad_decode_field(ni, IB_NODE_NPORTS_F, &node->numports); 177 mad_decode_field(ni, IB_NODE_DEVID_F, &node->devid); 178 mad_decode_field(ni, IB_NODE_VENDORID_F, &node->vendid); 179 mad_decode_field(ni, IB_NODE_SYSTEM_GUID_F, &node->sysimgguid); 180 mad_decode_field(ni, IB_NODE_PORT_GUID_F, &node->portguid); 181 mad_decode_field(ni, IB_NODE_LOCAL_PORT_F, &node->localport); 182 port->portnum = node->localport; 183 port->portguid = node->portguid; 184 185 if (!smp_query(nd, portid, IB_ATTR_NODE_DESC, 0, timeout)) 186 return -1; 187 188 if (!smp_query(pi, portid, IB_ATTR_PORT_INFO, 0, timeout)) 189 return -1; 190 decode_port_info(pi, port); 191 192 if (node->type != SWITCH_NODE) 193 return 0; 194 195 node->smalid = port->lid; 196 node->smalmc = port->lmc; 197 198 /* after we have the sma information find out the real PortInfo for this port */ 199 if (!smp_query(pi, portid, IB_ATTR_PORT_INFO, node->localport, timeout)) 200 return -1; 201 decode_port_info(pi, port); 202 203 if (!smp_query(si, portid, IB_ATTR_SWITCH_INFO, 0, timeout)) 204 node->smaenhsp0 = 0; /* assume base SP0 */ 205 else 206 mad_decode_field(si, IB_SW_ENHANCED_PORT0_F, &node->smaenhsp0); 207 208 DEBUG("portid %s: got switch node %" PRIx64 " '%s'", 209 portid2str(portid), node->nodeguid, node->nodedesc); 210 return 1; 211} 212 213static int 214extend_dpath(ib_dr_path_t *path, int nextport) 215{ 216 if (path->cnt+2 >= sizeof(path->p)) 217 return -1; 218 ++path->cnt; 219 if (path->cnt > maxhops_discovered) 220 maxhops_discovered = path->cnt; 221 path->p[path->cnt] = nextport; 222 return path->cnt; 223} 224 225static void 226dump_endnode(ib_portid_t *path, char *prompt, Node *node, Port *port) 227{ 228 if (!dumplevel) 229 return; 230 231 fprintf(f, "%s -> %s %s {%016" PRIx64 "} portnum %d lid %d-%d\"%s\"\n", 232 portid2str(path), prompt, 233 (node->type <= IB_NODE_MAX ? node_type_str[node->type] : "???"), 234 node->nodeguid, node->type == SWITCH_NODE ? 0 : port->portnum, 235 port->lid, port->lid + (1 << port->lmc) - 1, 236 clean_nodedesc(node->nodedesc)); 237} 238 239#define HASHGUID(guid) ((uint32_t)(((uint32_t)(guid) * 101) ^ ((uint32_t)((guid) >> 32) * 103))) 240#define HTSZ 137 241 242static Node *nodestbl[HTSZ]; 243 244static Node * 245find_node(Node *new) 246{ 247 int hash = HASHGUID(new->nodeguid) % HTSZ; 248 Node *node; 249 250 for (node = nodestbl[hash]; node; node = node->htnext) 251 if (node->nodeguid == new->nodeguid) 252 return node; 253 254 return NULL; 255} 256 257static Node * 258create_node(Node *temp, ib_portid_t *path, int dist) 259{ 260 Node *node; 261 int hash = HASHGUID(temp->nodeguid) % HTSZ; 262 263 node = malloc(sizeof(*node)); 264 if (!node) 265 return NULL; 266 267 memcpy(node, temp, sizeof(*node)); 268 node->dist = dist; 269 node->path = *path; 270 271 node->htnext = nodestbl[hash]; 272 nodestbl[hash] = node; 273 274 if (node->type != SWITCH_NODE) 275 dist = MAXHOPS; /* special Ca list */ 276 277 node->dnext = nodesdist[dist]; 278 nodesdist[dist] = node; 279 280 return node; 281} 282 283static Port * 284find_port(Node *node, Port *port) 285{ 286 Port *old; 287 288 for (old = node->ports; old; old = old->next) 289 if (old->portnum == port->portnum) 290 return old; 291 292 return NULL; 293} 294 295static Port * 296create_port(Node *node, Port *temp) 297{ 298 Port *port; 299 300 port = malloc(sizeof(*port)); 301 if (!port) 302 return NULL; 303 304 memcpy(port, temp, sizeof(*port)); 305 port->node = node; 306 port->next = node->ports; 307 node->ports = port; 308 309 return port; 310} 311 312static void 313link_ports(Node *node, Port *port, Node *remotenode, Port *remoteport) 314{ 315 DEBUG("linking: 0x%" PRIx64 " %p->%p:%u and 0x%" PRIx64 " %p->%p:%u", 316 node->nodeguid, node, port, port->portnum, 317 remotenode->nodeguid, remotenode, remoteport, remoteport->portnum); 318 if (port->remoteport) 319 port->remoteport->remoteport = NULL; 320 if (remoteport->remoteport) 321 remoteport->remoteport->remoteport = NULL; 322 port->remoteport = remoteport; 323 remoteport->remoteport = port; 324} 325 326static int 327handle_port(Node *node, Port *port, ib_portid_t *path, int portnum, int dist) 328{ 329 Node node_buf; 330 Port port_buf; 331 Node *remotenode, *oldnode; 332 Port *remoteport, *oldport; 333 334 memset(&node_buf, 0, sizeof(node_buf)); 335 memset(&port_buf, 0, sizeof(port_buf)); 336 337 DEBUG("handle node %p port %p:%d dist %d", node, port, portnum, dist); 338 if (port->physstate != 5) /* LinkUp */ 339 return -1; 340 341 if (extend_dpath(&path->drpath, portnum) < 0) 342 return -1; 343 344 if (get_node(&node_buf, &port_buf, path) < 0) { 345 IBWARN("NodeInfo on %s failed, skipping port", 346 portid2str(path)); 347 path->drpath.cnt--; /* restore path */ 348 return -1; 349 } 350 351 oldnode = find_node(&node_buf); 352 if (oldnode) 353 remotenode = oldnode; 354 else if (!(remotenode = create_node(&node_buf, path, dist + 1))) 355 IBERROR("no memory"); 356 357 oldport = find_port(remotenode, &port_buf); 358 if (oldport) { 359 remoteport = oldport; 360 if (node != remotenode || port != remoteport) 361 IBWARN("port moving..."); 362 } else if (!(remoteport = create_port(remotenode, &port_buf))) 363 IBERROR("no memory"); 364 365 dump_endnode(path, oldnode ? "known remote" : "new remote", 366 remotenode, remoteport); 367 368 link_ports(node, port, remotenode, remoteport); 369 370 path->drpath.cnt--; /* restore path */ 371 return 0; 372} 373 374/* 375 * Return 1 if found, 0 if not, -1 on errors. 376 */ 377static int 378discover(ib_portid_t *from) 379{ 380 Node node_buf; 381 Port port_buf; 382 Node *node; 383 Port *port; 384 int i; 385 int dist = 0; 386 ib_portid_t *path; 387 388 DEBUG("from %s", portid2str(from)); 389 390 memset(&node_buf, 0, sizeof(node_buf)); 391 memset(&port_buf, 0, sizeof(port_buf)); 392 393 if (get_node(&node_buf, &port_buf, from) < 0) { 394 IBWARN("can't reach node %s", portid2str(from)); 395 return -1; 396 } 397 398 node = create_node(&node_buf, from, 0); 399 if (!node) 400 IBERROR("out of memory"); 401 402 mynode = node; 403 404 port = create_port(node, &port_buf); 405 if (!port) 406 IBERROR("out of memory"); 407 408 if (node->type != SWITCH_NODE && 409 handle_port(node, port, from, node->localport, 0) < 0) 410 return 0; 411 412 for (dist = 0; dist < MAXHOPS; dist++) { 413 414 for (node = nodesdist[dist]; node; node = node->dnext) { 415 416 path = &node->path; 417 418 DEBUG("dist %d node %p", dist, node); 419 dump_endnode(path, "processing", node, port); 420 421 for (i = 1; i <= node->numports; i++) { 422 if (i == node->localport) 423 continue; 424 425 if (get_port(&port_buf, i, path) < 0) { 426 IBWARN("can't reach node %s port %d", portid2str(path), i); 427 continue; 428 } 429 430 port = find_port(node, &port_buf); 431 if (port) 432 continue; 433 434 port = create_port(node, &port_buf); 435 if (!port) 436 IBERROR("out of memory"); 437 438 /* If switch, set port GUID to node GUID */ 439 if (node->type == SWITCH_NODE) 440 port->portguid = node->portguid; 441 442 handle_port(node, port, path, i, dist); 443 } 444 } 445 } 446 447 return 0; 448} 449 450char * 451node_name(Node *node) 452{ 453 static char buf[256]; 454 455 switch(node->type) { 456 case SWITCH_NODE: 457 sprintf(buf, "\"%s", "S"); 458 break; 459 case CA_NODE: 460 sprintf(buf, "\"%s", "H"); 461 break; 462 case ROUTER_NODE: 463 sprintf(buf, "\"%s", "R"); 464 break; 465 default: 466 sprintf(buf, "\"%s", "?"); 467 break; 468 } 469 sprintf(buf+2, "-%016" PRIx64 "\"", node->nodeguid); 470 471 return buf; 472} 473 474void 475list_node(Node *node) 476{ 477 char *node_type; 478 char *nodename = remap_node_name(node_name_map, node->nodeguid, 479 node->nodedesc); 480 481 switch(node->type) { 482 case SWITCH_NODE: 483 node_type = "Switch"; 484 break; 485 case CA_NODE: 486 node_type = "Ca"; 487 break; 488 case ROUTER_NODE: 489 node_type = "Router"; 490 break; 491 default: 492 node_type = "???"; 493 break; 494 } 495 fprintf(f, "%s\t : 0x%016" PRIx64 " ports %d devid 0x%x vendid 0x%x \"%s\"\n", 496 node_type, 497 node->nodeguid, node->numports, node->devid, node->vendid, 498 nodename); 499 500 free(nodename); 501} 502 503void 504out_ids(Node *node, int group, char *chname) 505{ 506 fprintf(f, "\nvendid=0x%x\ndevid=0x%x\n", node->vendid, node->devid); 507 if (node->sysimgguid) 508 fprintf(f, "sysimgguid=0x%" PRIx64, node->sysimgguid); 509 if (group 510 && node->chrecord && node->chrecord->chassisnum) { 511 fprintf(f, "\t\t# Chassis %d", node->chrecord->chassisnum); 512 if (chname) 513 fprintf(f, " (%s)", chname); 514 if (is_xsigo_tca(node->nodeguid) && node->ports->remoteport) 515 fprintf(f, " slot %d", node->ports->remoteport->portnum); 516 } 517 fprintf(f, "\n"); 518} 519 520uint64_t 521out_chassis(int chassisnum) 522{ 523 uint64_t guid; 524 525 fprintf(f, "\nChassis %d", chassisnum); 526 guid = get_chassis_guid(chassisnum); 527 if (guid) 528 fprintf(f, " (guid 0x%" PRIx64 ")", guid); 529 fprintf(f, "\n"); 530 return guid; 531} 532 533void 534out_switch(Node *node, int group, char *chname) 535{ 536 char *str; 537 char *nodename = NULL; 538 539 out_ids(node, group, chname); 540 fprintf(f, "switchguid=0x%" PRIx64, node->nodeguid); 541 fprintf(f, "(%" PRIx64 ")", node->portguid); 542 /* Currently, only if Voltaire chassis */ 543 if (group 544 && node->chrecord && node->chrecord->chassisnum 545 && node->vendid == VTR_VENDOR_ID) { 546 str = get_chassis_type(node->chrecord->chassistype); 547 if (str) 548 fprintf(f, "%s ", str); 549 str = get_chassis_slot(node->chrecord->chassisslot); 550 if (str) 551 fprintf(f, "%s ", str); 552 fprintf(f, "%d Chip %d", node->chrecord->slotnum, node->chrecord->anafanum); 553 } 554 555 nodename = remap_node_name(node_name_map, node->nodeguid, 556 node->nodedesc); 557 558 fprintf(f, "\nSwitch\t%d %s\t\t# \"%s\" %s port 0 lid %d lmc %d\n", 559 node->numports, node_name(node), 560 nodename, 561 node->smaenhsp0 ? "enhanced" : "base", 562 node->smalid, node->smalmc); 563 564 free(nodename); 565} 566 567void 568out_ca(Node *node, int group, char *chname) 569{ 570 char *node_type; 571 char *node_type2; 572 char *nodename = remap_node_name(node_name_map, node->nodeguid, 573 node->nodedesc); 574 575 out_ids(node, group, chname); 576 switch(node->type) { 577 case CA_NODE: 578 node_type = "ca"; 579 node_type2 = "Ca"; 580 break; 581 case ROUTER_NODE: 582 node_type = "rt"; 583 node_type2 = "Rt"; 584 break; 585 default: 586 node_type = "???"; 587 node_type2 = "???"; 588 break; 589 } 590 591 fprintf(f, "%sguid=0x%" PRIx64 "\n", node_type, node->nodeguid); 592 fprintf(f, "%s\t%d %s\t\t# \"%s\"", 593 node_type2, node->numports, node_name(node), 594 nodename); 595 if (group && is_xsigo_hca(node->nodeguid)) 596 fprintf(f, " (scp)"); 597 fprintf(f, "\n"); 598 599 free(nodename); 600} 601 602static char * 603out_ext_port(Port *port, int group) 604{ 605 char *str = NULL; 606 607 /* Currently, only if Voltaire chassis */ 608 if (group 609 && port->node->chrecord && port->node->vendid == VTR_VENDOR_ID) 610 str = portmapstring(port); 611 612 return (str); 613} 614 615void 616out_switch_port(Port *port, int group) 617{ 618 char *ext_port_str = NULL; 619 char *rem_nodename = NULL; 620 621 DEBUG("port %p:%d remoteport %p", port, port->portnum, port->remoteport); 622 fprintf(f, "[%d]", port->portnum); 623 624 ext_port_str = out_ext_port(port, group); 625 if (ext_port_str) 626 fprintf(f, "%s", ext_port_str); 627 628 rem_nodename = remap_node_name(node_name_map, 629 port->remoteport->node->nodeguid, 630 port->remoteport->node->nodedesc); 631 632 ext_port_str = out_ext_port(port->remoteport, group); 633 fprintf(f, "\t%s[%d]%s", 634 node_name(port->remoteport->node), 635 port->remoteport->portnum, 636 ext_port_str ? ext_port_str : ""); 637 if (port->remoteport->node->type != SWITCH_NODE) 638 fprintf(f, "(%" PRIx64 ") ", port->remoteport->portguid); 639 fprintf(f, "\t\t# \"%s\" lid %d %s%s", 640 rem_nodename, 641 port->remoteport->node->type == SWITCH_NODE ? port->remoteport->node->smalid : port->remoteport->lid, 642 get_linkwidth_str(port->linkwidth), 643 get_linkspeed_str(port->linkspeed)); 644 645 if (is_xsigo_tca(port->remoteport->portguid)) 646 fprintf(f, " slot %d", port->portnum); 647 else if (is_xsigo_hca(port->remoteport->portguid)) 648 fprintf(f, " (scp)"); 649 fprintf(f, "\n"); 650 651 free(rem_nodename); 652} 653 654void 655out_ca_port(Port *port, int group) 656{ 657 char *str = NULL; 658 char *rem_nodename = NULL; 659 660 fprintf(f, "[%d]", port->portnum); 661 if (port->node->type != SWITCH_NODE) 662 fprintf(f, "(%" PRIx64 ") ", port->portguid); 663 fprintf(f, "\t%s[%d]", 664 node_name(port->remoteport->node), 665 port->remoteport->portnum); 666 str = out_ext_port(port->remoteport, group); 667 if (str) 668 fprintf(f, "%s", str); 669 if (port->remoteport->node->type != SWITCH_NODE) 670 fprintf(f, " (%" PRIx64 ") ", port->remoteport->portguid); 671 672 rem_nodename = remap_node_name(node_name_map, 673 port->remoteport->node->nodeguid, 674 port->remoteport->node->nodedesc); 675 676 fprintf(f, "\t\t# lid %d lmc %d \"%s\" lid %d %s%s\n", 677 port->lid, port->lmc, rem_nodename, 678 port->remoteport->node->type == SWITCH_NODE ? port->remoteport->node->smalid : port->remoteport->lid, 679 get_linkwidth_str(port->linkwidth), 680 get_linkspeed_str(port->linkspeed)); 681 682 free(rem_nodename); 683} 684 685int 686dump_topology(int listtype, int group) 687{ 688 Node *node; 689 Port *port; 690 int i = 0, dist = 0; 691 time_t t = time(0); 692 uint64_t chguid; 693 char *chname = NULL; 694 695 if (!listtype) { 696 fprintf(f, "#\n# Topology file: generated on %s#\n", ctime(&t)); 697 fprintf(f, "# Max of %d hops discovered\n", maxhops_discovered); 698 fprintf(f, "# Initiated from node %016" PRIx64 " port %016" PRIx64 "\n", mynode->nodeguid, mynode->portguid); 699 } 700 701 /* Make pass on switches */ 702 if (group && !listtype) { 703 ChassisList *ch = NULL; 704 705 /* Chassis based switches first */ 706 for (ch = chassis; ch; ch = ch->next) { 707 int n = 0; 708 709 if (!ch->chassisnum) 710 continue; 711 chguid = out_chassis(ch->chassisnum); 712 if (chname) 713 free(chname); 714 chname = NULL; 715 if (is_xsigo_guid(chguid)) { 716 for (node = nodesdist[MAXHOPS]; node; node = node->dnext) { 717 if (!node->chrecord || 718 !node->chrecord->chassisnum) 719 continue; 720 721 if (node->chrecord->chassisnum != ch->chassisnum) 722 continue; 723 724 if (is_xsigo_hca(node->nodeguid)) { 725 chname = remap_node_name(node_name_map, 726 node->nodeguid, 727 node->nodedesc); 728 fprintf(f, "Hostname: %s\n", chname); 729 } 730 } 731 } 732 733 fprintf(f, "\n# Spine Nodes"); 734 for (n = 1; n <= (SPINES_MAX_NUM+1); n++) { 735 if (ch->spinenode[n]) { 736 out_switch(ch->spinenode[n], group, chname); 737 for (port = ch->spinenode[n]->ports; port; port = port->next, i++) 738 if (port->remoteport) 739 out_switch_port(port, group); 740 } 741 } 742 fprintf(f, "\n# Line Nodes"); 743 for (n = 1; n <= (LINES_MAX_NUM+1); n++) { 744 if (ch->linenode[n]) { 745 out_switch(ch->linenode[n], group, chname); 746 for (port = ch->linenode[n]->ports; port; port = port->next, i++) 747 if (port->remoteport) 748 out_switch_port(port, group); 749 } 750 } 751 752 fprintf(f, "\n# Chassis Switches"); 753 for (dist = 0; dist <= maxhops_discovered; dist++) { 754 755 for (node = nodesdist[dist]; node; node = node->dnext) { 756 757 /* Non Voltaire chassis */ 758 if (node->vendid == VTR_VENDOR_ID) 759 continue; 760 if (!node->chrecord || 761 !node->chrecord->chassisnum) 762 continue; 763 764 if (node->chrecord->chassisnum != ch->chassisnum) 765 continue; 766 767 out_switch(node, group, chname); 768 for (port = node->ports; port; port = port->next, i++) 769 if (port->remoteport) 770 out_switch_port(port, group); 771 772 } 773 774 } 775 776 fprintf(f, "\n# Chassis CAs"); 777 for (node = nodesdist[MAXHOPS]; node; node = node->dnext) { 778 if (!node->chrecord || 779 !node->chrecord->chassisnum) 780 continue; 781 782 if (node->chrecord->chassisnum != ch->chassisnum) 783 continue; 784 785 out_ca(node, group, chname); 786 for (port = node->ports; port; port = port->next, i++) 787 if (port->remoteport) 788 out_ca_port(port, group); 789 790 } 791 792 } 793 794 } else { 795 for (dist = 0; dist <= maxhops_discovered; dist++) { 796 797 for (node = nodesdist[dist]; node; node = node->dnext) { 798 799 DEBUG("SWITCH: dist %d node %p", dist, node); 800 if (!listtype) 801 out_switch(node, group, chname); 802 else { 803 if (listtype & LIST_SWITCH_NODE) 804 list_node(node); 805 continue; 806 } 807 808 for (port = node->ports; port; port = port->next, i++) 809 if (port->remoteport) 810 out_switch_port(port, group); 811 } 812 } 813 } 814 815 if (chname) 816 free(chname); 817 chname = NULL; 818 if (group && !listtype) { 819 820 fprintf(f, "\nNon-Chassis Nodes\n"); 821 822 for (dist = 0; dist <= maxhops_discovered; dist++) { 823 824 for (node = nodesdist[dist]; node; node = node->dnext) { 825 826 DEBUG("SWITCH: dist %d node %p", dist, node); 827 /* Now, skip chassis based switches */ 828 if (node->chrecord && 829 node->chrecord->chassisnum) 830 continue; 831 out_switch(node, group, chname); 832 833 for (port = node->ports; port; port = port->next, i++) 834 if (port->remoteport) 835 out_switch_port(port, group); 836 } 837 838 } 839 840 } 841 842 /* Make pass on CAs */ 843 for (node = nodesdist[MAXHOPS]; node; node = node->dnext) { 844 845 DEBUG("CA: dist %d node %p", dist, node); 846 if (!listtype) { 847 /* Now, skip chassis based CAs */ 848 if (group && node->chrecord && 849 node->chrecord->chassisnum) 850 continue; 851 out_ca(node, group, chname); 852 } else { 853 if (((listtype & LIST_CA_NODE) && (node->type == CA_NODE)) || 854 ((listtype & LIST_ROUTER_NODE) && (node->type == ROUTER_NODE))) 855 list_node(node); 856 continue; 857 } 858 859 for (port = node->ports; port; port = port->next, i++) 860 if (port->remoteport) 861 out_ca_port(port, group); 862 } 863 864 if (chname) 865 free(chname); 866 867 return i; 868} 869 870void dump_ports_report () 871{ 872 int b, n = 0, p; 873 Node *node; 874 Port *port; 875 876 // If switch and LID == 0, search of other switch ports with 877 // valid LID and assign it to all ports of that switch 878 for (b = 0; b <= MAXHOPS; b++) 879 for (node = nodesdist[b]; node; node = node->dnext) 880 if (node->type == SWITCH_NODE) { 881 int swlid = 0; 882 for (p = 0, port = node->ports; 883 p < node->numports && port && !swlid; 884 port = port->next) 885 if (port->lid != 0) 886 swlid = port->lid; 887 for (p = 0, port = node->ports; 888 p < node->numports && port; 889 port = port->next) 890 port->lid = swlid; 891 } 892 893 for (b = 0; b <= MAXHOPS; b++) 894 for (node = nodesdist[b]; node; node = node->dnext) { 895 for (p = 0, port = node->ports; 896 p < node->numports && port; 897 p++, port = port->next) { 898 fprintf(stdout, 899 "%2s %5d %2d 0x%016" PRIx64 " %s %s", 900 node_type_str2(port->node), port->lid, 901 port->portnum, 902 port->portguid, 903 get_linkwidth_str(port->linkwidth), 904 get_linkspeed_str(port->linkspeed)); 905 if (port->remoteport) 906 fprintf(stdout, 907 " - %2s %5d %2d 0x%016" PRIx64 908 " ( '%s' - '%s' )\n", 909 node_type_str2(port->remoteport->node), 910 port->remoteport->lid, 911 port->remoteport->portnum, 912 port->remoteport->portguid, 913 port->node->nodedesc, 914 port->remoteport->node->nodedesc); 915 else 916 fprintf(stdout, "%36s'%s'\n", "", 917 port->node->nodedesc); 918 } 919 n++; 920 } 921} 922 923void 924usage(void) 925{ 926 fprintf(stderr, "Usage: %s [-d(ebug)] -e(rr_show) -v(erbose) -s(how) -l(ist) -g(rouping) -H(ca_list) -S(witch_list) -R(outer_list) -V(ersion) -C ca_name -P ca_port " 927 "-t(imeout) timeout_ms --node-name-map node-name-map] -p(orts) [<topology-file>]\n", 928 argv0); 929 fprintf(stderr, " --node-name-map <node-name-map> specify a node name map file\n"); 930 exit(-1); 931} 932 933int 934main(int argc, char **argv) 935{ 936 int mgmt_classes[2] = {IB_SMI_CLASS, IB_SMI_DIRECT_CLASS}; 937 ib_portid_t my_portid = {0}; 938 int udebug = 0, list = 0; 939 char *ca = 0; 940 int ca_port = 0; 941 int group = 0; 942 int ports_report = 0; 943 944 static char const str_opts[] = "C:P:t:devslgHSRpVhu"; 945 static const struct option long_opts[] = { 946 { "C", 1, 0, 'C'}, 947 { "P", 1, 0, 'P'}, 948 { "debug", 0, 0, 'd'}, 949 { "err_show", 0, 0, 'e'}, 950 { "verbose", 0, 0, 'v'}, 951 { "show", 0, 0, 's'}, 952 { "list", 0, 0, 'l'}, 953 { "grouping", 0, 0, 'g'}, 954 { "Hca_list", 0, 0, 'H'}, 955 { "Switch_list", 0, 0, 'S'}, 956 { "Router_list", 0, 0, 'R'}, 957 { "timeout", 1, 0, 't'}, 958 { "node-name-map", 1, 0, 1}, 959 { "ports", 0, 0, 'p'}, 960 { "Version", 0, 0, 'V'}, 961 { "help", 0, 0, 'h'}, 962 { "usage", 0, 0, 'u'}, 963 { } 964 }; 965 966 f = stdout; 967 968 argv0 = argv[0]; 969 970 while (1) { 971 int ch = getopt_long(argc, argv, str_opts, long_opts, NULL); 972 if ( ch == -1 ) 973 break; 974 switch(ch) { 975 case 1: 976 node_name_map_file = strdup(optarg); 977 break; 978 case 'C': 979 ca = optarg; 980 break; 981 case 'P': 982 ca_port = strtoul(optarg, 0, 0); 983 break; 984 case 'd': 985 ibdebug++; 986 madrpc_show_errors(1); 987 umad_debug(udebug); 988 udebug++; 989 break; 990 case 't': 991 timeout = strtoul(optarg, 0, 0); 992 break; 993 case 'v': 994 verbose++; 995 dumplevel++; 996 break; 997 case 's': 998 dumplevel = 1; 999 break; 1000 case 'e': 1001 madrpc_show_errors(1); 1002 break; 1003 case 'l': 1004 list = LIST_CA_NODE | LIST_SWITCH_NODE | LIST_ROUTER_NODE; 1005 break; 1006 case 'g': 1007 group = 1; 1008 break; 1009 case 'S': 1010 list = LIST_SWITCH_NODE; 1011 break; 1012 case 'H': 1013 list = LIST_CA_NODE; 1014 break; 1015 case 'R': 1016 list = LIST_ROUTER_NODE; 1017 break; 1018 case 'V': 1019 fprintf(stderr, "%s %s\n", argv0, get_build_version() ); 1020 exit(-1); 1021 case 'p': 1022 ports_report = 1; 1023 break; 1024 default: 1025 usage(); 1026 break; 1027 } 1028 } 1029 argc -= optind; 1030 argv += optind; 1031 1032 if (argc && !(f = fopen(argv[0], "w"))) 1033 IBERROR("can't open file %s for writing", argv[0]); 1034 1035 madrpc_init(ca, ca_port, mgmt_classes, 2); 1036 node_name_map = open_node_name_map(node_name_map_file); 1037 1038 if (discover(&my_portid) < 0) 1039 IBERROR("discover"); 1040 1041 if (group) 1042 chassis = group_nodes(); 1043 1044 if (ports_report) 1045 dump_ports_report(); 1046 else 1047 dump_topology(list, group); 1048 1049 close_node_name_map(node_name_map); 1050 exit(0); 1051} 1052