1 /* 2 * Copyright (c) 2004-2009 Voltaire Inc. All rights reserved. 3 * Copyright (c) 2007 Xsigo Systems Inc. All rights reserved. 4 * Copyright (c) 2008 Lawrence Livermore National Lab. All rights reserved. 5 * Copyright (c) 2010,2011 Mellanox Technologies LTD. All rights reserved. 6 * 7 * This software is available to you under a choice of one of two 8 * licenses. You may choose to be licensed under the terms of the GNU 9 * General Public License (GPL) Version 2, available from the file 10 * COPYING in the main directory of this source tree, or the 11 * OpenIB.org BSD license below: 12 * 13 * Redistribution and use in source and binary forms, with or 14 * without modification, are permitted provided that the following 15 * conditions are met: 16 * 17 * - Redistributions of source code must retain the above 18 * copyright notice, this list of conditions and the following 19 * disclaimer. 20 * 21 * - Redistributions in binary form must reproduce the above 22 * copyright notice, this list of conditions and the following 23 * disclaimer in the documentation and/or other materials 24 * provided with the distribution. 25 * 26 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 27 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 28 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 29 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 30 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 31 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 32 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 33 * SOFTWARE. 34 * 35 */ 36 37 #if HAVE_CONFIG_H 38 #include <config.h> 39 #endif /* HAVE_CONFIG_H */ 40 41 #define _GNU_SOURCE 42 #include <stdio.h> 43 #include <stdlib.h> 44 #include <unistd.h> 45 #include <time.h> 46 #include <string.h> 47 #include <getopt.h> 48 #include <inttypes.h> 49 50 #include <infiniband/umad.h> 51 #include <infiniband/mad.h> 52 #include <complib/cl_nodenamemap.h> 53 #include <infiniband/ibnetdisc.h> 54 55 #include "ibdiag_common.h" 56 57 #define LIST_CA_NODE (1 << IB_NODE_CA) 58 #define LIST_SWITCH_NODE (1 << IB_NODE_SWITCH) 59 #define LIST_ROUTER_NODE (1 << IB_NODE_ROUTER) 60 61 #define DIFF_FLAG_SWITCH 0x01 62 #define DIFF_FLAG_CA 0x02 63 #define DIFF_FLAG_ROUTER 0x04 64 #define DIFF_FLAG_PORT_CONNECTION 0x08 65 #define DIFF_FLAG_LID 0x10 66 #define DIFF_FLAG_NODE_DESCRIPTION 0x20 67 68 #define DIFF_FLAG_DEFAULT (DIFF_FLAG_SWITCH | DIFF_FLAG_CA | DIFF_FLAG_ROUTER \ 69 | DIFF_FLAG_PORT_CONNECTION) 70 71 static FILE *f; 72 73 static char *node_name_map_file = NULL; 74 static nn_map_t *node_name_map = NULL; 75 static char *cache_file = NULL; 76 static char *load_cache_file = NULL; 77 static char *diff_cache_file = NULL; 78 static unsigned diffcheck_flags = DIFF_FLAG_DEFAULT; 79 80 static int report_max_hops = 0; 81 static int full_info; 82 83 /** 84 * Define our own conversion functions to maintain compatibility with the old 85 * ibnetdiscover which did not use the ibmad conversion functions. 86 */ 87 char *dump_linkspeed_compat(uint32_t speed) 88 { 89 switch (speed) { 90 case 1: 91 return ("SDR"); 92 break; 93 case 2: 94 return ("DDR"); 95 break; 96 case 4: 97 return ("QDR"); 98 break; 99 } 100 return ("???"); 101 } 102 103 char *dump_linkspeedext_compat(uint32_t espeed, uint32_t speed, uint32_t fdr10) 104 { 105 switch (espeed) { 106 case 0: 107 if (fdr10 & FDR10) 108 return ("FDR10"); 109 else 110 return dump_linkspeed_compat(speed); 111 break; 112 case 1: 113 return ("FDR"); 114 break; 115 case 2: 116 return ("EDR"); 117 break; 118 } 119 return ("???"); 120 } 121 122 char *dump_linkwidth_compat(uint32_t width) 123 { 124 switch (width) { 125 case 1: 126 return ("1x"); 127 break; 128 case 2: 129 return ("4x"); 130 break; 131 case 4: 132 return ("8x"); 133 break; 134 case 8: 135 return ("12x"); 136 break; 137 case 16: 138 return ("2x"); 139 break; 140 } 141 return ("??"); 142 } 143 144 static inline const char *ports_nt_str_compat(ibnd_node_t * node) 145 { 146 switch (node->type) { 147 case IB_NODE_SWITCH: 148 return "SW"; 149 case IB_NODE_CA: 150 return "CA"; 151 case IB_NODE_ROUTER: 152 return "RT"; 153 } 154 return "??"; 155 } 156 157 char *node_name(ibnd_node_t * node) 158 { 159 static char buf[256]; 160 161 switch (node->type) { 162 case IB_NODE_SWITCH: 163 sprintf(buf, "\"%s", "S"); 164 break; 165 case IB_NODE_CA: 166 sprintf(buf, "\"%s", "H"); 167 break; 168 case IB_NODE_ROUTER: 169 sprintf(buf, "\"%s", "R"); 170 break; 171 default: 172 sprintf(buf, "\"%s", "?"); 173 break; 174 } 175 sprintf(buf + 2, "-%016" PRIx64 "\"", node->guid); 176 177 return buf; 178 } 179 180 void list_node(ibnd_node_t * node, void *user_data) 181 { 182 char *node_type; 183 char *nodename = remap_node_name(node_name_map, node->guid, 184 node->nodedesc); 185 186 switch (node->type) { 187 case IB_NODE_SWITCH: 188 node_type = "Switch"; 189 break; 190 case IB_NODE_CA: 191 node_type = "Ca"; 192 break; 193 case IB_NODE_ROUTER: 194 node_type = "Router"; 195 break; 196 default: 197 node_type = "???"; 198 break; 199 } 200 fprintf(f, 201 "%s\t : 0x%016" PRIx64 202 " ports %d devid 0x%x vendid 0x%x \"%s\"\n", node_type, 203 node->guid, node->numports, mad_get_field(node->info, 0, 204 IB_NODE_DEVID_F), 205 mad_get_field(node->info, 0, IB_NODE_VENDORID_F), nodename); 206 207 free(nodename); 208 } 209 210 void list_nodes(ibnd_fabric_t * fabric, int list) 211 { 212 if (list & LIST_CA_NODE) 213 ibnd_iter_nodes_type(fabric, list_node, IB_NODE_CA, NULL); 214 if (list & LIST_SWITCH_NODE) 215 ibnd_iter_nodes_type(fabric, list_node, IB_NODE_SWITCH, NULL); 216 if (list & LIST_ROUTER_NODE) 217 ibnd_iter_nodes_type(fabric, list_node, IB_NODE_ROUTER, NULL); 218 } 219 220 void out_ids(ibnd_node_t * node, int group, char *chname, char *out_prefix) 221 { 222 uint64_t sysimgguid = 223 mad_get_field64(node->info, 0, IB_NODE_SYSTEM_GUID_F); 224 225 fprintf(f, "\n%svendid=0x%x\n", out_prefix ? out_prefix : "", 226 mad_get_field(node->info, 0, IB_NODE_VENDORID_F)); 227 fprintf(f, "%sdevid=0x%x\n", out_prefix ? out_prefix : "", 228 mad_get_field(node->info, 0, IB_NODE_DEVID_F)); 229 if (sysimgguid) 230 fprintf(f, "%ssysimgguid=0x%" PRIx64, 231 out_prefix ? out_prefix : "", sysimgguid); 232 if (group && node->chassis && node->chassis->chassisnum) { 233 fprintf(f, "\t\t# Chassis %d", node->chassis->chassisnum); 234 if (chname) 235 fprintf(f, " (%s)", clean_nodedesc(chname)); 236 if (ibnd_is_xsigo_tca(node->guid) && node->ports[1] && 237 node->ports[1]->remoteport) 238 fprintf(f, " slot %d", 239 node->ports[1]->remoteport->portnum); 240 } 241 if (sysimgguid || 242 (group && node->chassis && node->chassis->chassisnum)) 243 fprintf(f, "\n"); 244 } 245 246 uint64_t out_chassis(ibnd_fabric_t * fabric, unsigned char chassisnum) 247 { 248 uint64_t guid; 249 250 fprintf(f, "\nChassis %u", chassisnum); 251 guid = ibnd_get_chassis_guid(fabric, chassisnum); 252 if (guid) 253 fprintf(f, " (guid 0x%" PRIx64 ")", guid); 254 fprintf(f, "\n"); 255 return guid; 256 } 257 258 void out_switch_detail(ibnd_node_t * node, char *sw_prefix) 259 { 260 char *nodename = NULL; 261 262 nodename = remap_node_name(node_name_map, node->guid, node->nodedesc); 263 264 fprintf(f, "%sSwitch\t%d %s\t\t# \"%s\" %s port 0 lid %d lmc %d", 265 sw_prefix ? sw_prefix : "", node->numports, node_name(node), 266 nodename, node->smaenhsp0 ? "enhanced" : "base", 267 node->smalid, node->smalmc); 268 269 free(nodename); 270 } 271 272 void out_switch(ibnd_node_t * node, int group, char *chname, char *id_prefix, 273 char *sw_prefix) 274 { 275 char *str; 276 char str2[256]; 277 278 out_ids(node, group, chname, id_prefix); 279 fprintf(f, "%sswitchguid=0x%" PRIx64, 280 id_prefix ? id_prefix : "", node->guid); 281 fprintf(f, "(%" PRIx64 ")", 282 mad_get_field64(node->info, 0, IB_NODE_PORT_GUID_F)); 283 if (group) { 284 fprintf(f, "\t# "); 285 str = ibnd_get_chassis_type(node); 286 if (str) 287 fprintf(f, "%s ", str); 288 str = ibnd_get_chassis_slot_str(node, str2, 256); 289 if (str) 290 fprintf(f, "%s", str); 291 } 292 fprintf(f, "\n"); 293 294 out_switch_detail(node, sw_prefix); 295 fprintf(f, "\n"); 296 } 297 298 void out_ca_detail(ibnd_node_t * node, char *ca_prefix) 299 { 300 char *node_type; 301 302 switch (node->type) { 303 case IB_NODE_CA: 304 node_type = "Ca"; 305 break; 306 case IB_NODE_ROUTER: 307 node_type = "Rt"; 308 break; 309 default: 310 node_type = "???"; 311 break; 312 } 313 314 fprintf(f, "%s%s\t%d %s\t\t# \"%s\"", ca_prefix ? ca_prefix : "", 315 node_type, node->numports, node_name(node), 316 clean_nodedesc(node->nodedesc)); 317 } 318 319 void out_ca(ibnd_node_t * node, int group, char *chname, char *id_prefix, 320 char *ca_prefix) 321 { 322 char *node_type; 323 324 out_ids(node, group, chname, id_prefix); 325 switch (node->type) { 326 case IB_NODE_CA: 327 node_type = "ca"; 328 break; 329 case IB_NODE_ROUTER: 330 node_type = "rt"; 331 break; 332 default: 333 node_type = "???"; 334 break; 335 } 336 337 fprintf(f, "%s%sguid=0x%" PRIx64 "\n", 338 id_prefix ? id_prefix : "", node_type, node->guid); 339 out_ca_detail(node, ca_prefix); 340 if (group && ibnd_is_xsigo_hca(node->guid)) 341 fprintf(f, " (scp)"); 342 fprintf(f, "\n"); 343 } 344 345 #define OUT_BUFFER_SIZE 16 346 static char *out_ext_port(ibnd_port_t * port, int group) 347 { 348 static char mapping[OUT_BUFFER_SIZE]; 349 350 if (group && port->ext_portnum != 0) { 351 snprintf(mapping, OUT_BUFFER_SIZE, 352 "[ext %d]", port->ext_portnum); 353 return (mapping); 354 } 355 356 return (NULL); 357 } 358 359 void out_switch_port(ibnd_port_t * port, int group, char *out_prefix) 360 { 361 char *ext_port_str = NULL; 362 char *rem_nodename = NULL; 363 uint32_t iwidth = mad_get_field(port->info, 0, 364 IB_PORT_LINK_WIDTH_ACTIVE_F); 365 uint32_t ispeed = mad_get_field(port->info, 0, 366 IB_PORT_LINK_SPEED_ACTIVE_F); 367 uint32_t vlcap = mad_get_field(port->info, 0, 368 IB_PORT_VL_CAP_F); 369 uint32_t fdr10 = mad_get_field(port->ext_info, 0, 370 IB_MLNX_EXT_PORT_LINK_SPEED_ACTIVE_F); 371 uint32_t cap_mask, espeed; 372 373 DEBUG("port %p:%d remoteport %p\n", port, port->portnum, 374 port->remoteport); 375 fprintf(f, "%s[%d]", out_prefix ? out_prefix : "", port->portnum); 376 377 ext_port_str = out_ext_port(port, group); 378 if (ext_port_str) 379 fprintf(f, "%s", ext_port_str); 380 381 rem_nodename = remap_node_name(node_name_map, 382 port->remoteport->node->guid, 383 port->remoteport->node->nodedesc); 384 385 ext_port_str = out_ext_port(port->remoteport, group); 386 387 if (!port->node->ports[0]) { 388 cap_mask = 0; 389 ispeed = 0; 390 espeed = 0; 391 } else { 392 cap_mask = mad_get_field(port->node->ports[0]->info, 0, 393 IB_PORT_CAPMASK_F); 394 if (cap_mask & CL_NTOH32(IB_PORT_CAP_HAS_EXT_SPEEDS)) 395 espeed = mad_get_field(port->info, 0, 396 IB_PORT_LINK_SPEED_EXT_ACTIVE_F); 397 else 398 espeed = 0; 399 } 400 fprintf(f, "\t%s[%d]%s", 401 node_name(port->remoteport->node), port->remoteport->portnum, 402 ext_port_str ? ext_port_str : ""); 403 if (port->remoteport->node->type != IB_NODE_SWITCH) 404 fprintf(f, "(%" PRIx64 ") ", port->remoteport->guid); 405 fprintf(f, "\t\t# \"%s\" lid %d %s%s", 406 rem_nodename, 407 port->remoteport->node->type == IB_NODE_SWITCH ? 408 port->remoteport->node->smalid : 409 port->remoteport->base_lid, 410 dump_linkwidth_compat(iwidth), 411 (ispeed != 4 && !espeed) ? 412 dump_linkspeed_compat(ispeed) : 413 dump_linkspeedext_compat(espeed, ispeed, fdr10)); 414 415 if (full_info) { 416 fprintf(f, " s=%d w=%d v=%d", ispeed, iwidth, vlcap); 417 if (espeed) 418 fprintf(f, " e=%d", espeed); 419 } 420 421 if (ibnd_is_xsigo_tca(port->remoteport->guid)) 422 fprintf(f, " slot %d", port->portnum); 423 else if (ibnd_is_xsigo_hca(port->remoteport->guid)) 424 fprintf(f, " (scp)"); 425 fprintf(f, "\n"); 426 427 free(rem_nodename); 428 } 429 430 void out_ca_port(ibnd_port_t * port, int group, char *out_prefix) 431 { 432 char *str = NULL; 433 char *rem_nodename = NULL; 434 uint32_t iwidth = mad_get_field(port->info, 0, 435 IB_PORT_LINK_WIDTH_ACTIVE_F); 436 uint32_t ispeed = mad_get_field(port->info, 0, 437 IB_PORT_LINK_SPEED_ACTIVE_F); 438 uint32_t vlcap = mad_get_field(port->info, 0, 439 IB_PORT_VL_CAP_F); 440 uint32_t fdr10 = mad_get_field(port->ext_info, 0, 441 IB_MLNX_EXT_PORT_LINK_SPEED_ACTIVE_F); 442 uint32_t cap_mask, espeed; 443 444 fprintf(f, "%s[%d]", out_prefix ? out_prefix : "", port->portnum); 445 if (port->node->type != IB_NODE_SWITCH) 446 fprintf(f, "(%" PRIx64 ") ", port->guid); 447 fprintf(f, "\t%s[%d]", 448 node_name(port->remoteport->node), port->remoteport->portnum); 449 str = out_ext_port(port->remoteport, group); 450 if (str) 451 fprintf(f, "%s", str); 452 if (port->remoteport->node->type != IB_NODE_SWITCH) 453 fprintf(f, " (%" PRIx64 ") ", port->remoteport->guid); 454 455 rem_nodename = remap_node_name(node_name_map, 456 port->remoteport->node->guid, 457 port->remoteport->node->nodedesc); 458 459 cap_mask = mad_get_field(port->info, 0, IB_PORT_CAPMASK_F); 460 if (cap_mask & CL_NTOH32(IB_PORT_CAP_HAS_EXT_SPEEDS)) 461 espeed = mad_get_field(port->info, 0, 462 IB_PORT_LINK_SPEED_EXT_ACTIVE_F); 463 else 464 espeed = 0; 465 466 fprintf(f, "\t\t# lid %d lmc %d \"%s\" lid %d %s%s", 467 port->base_lid, port->lmc, rem_nodename, 468 port->remoteport->node->type == IB_NODE_SWITCH ? 469 port->remoteport->node->smalid : 470 port->remoteport->base_lid, 471 dump_linkwidth_compat(iwidth), 472 (ispeed != 4 && !espeed) ? 473 dump_linkspeed_compat(ispeed) : 474 dump_linkspeedext_compat(espeed, ispeed, fdr10)); 475 476 if (full_info) { 477 fprintf(f, " s=%d w=%d v=%d", ispeed, iwidth, vlcap); 478 if (espeed) 479 fprintf(f, " e=%d", espeed); 480 } 481 482 fprintf(f, "\n"); 483 484 free(rem_nodename); 485 } 486 487 struct iter_user_data { 488 int group; 489 int skip_chassis_nodes; 490 }; 491 492 static void switch_iter_func(ibnd_node_t * node, void *iter_user_data) 493 { 494 ibnd_port_t *port; 495 int p = 0; 496 struct iter_user_data *data = (struct iter_user_data *)iter_user_data; 497 498 DEBUG("SWITCH: node %p\n", node); 499 500 /* skip chassis based switches if flagged */ 501 if (data->skip_chassis_nodes && node->chassis 502 && node->chassis->chassisnum) 503 return; 504 505 out_switch(node, data->group, NULL, NULL, NULL); 506 for (p = 1; p <= node->numports; p++) { 507 port = node->ports[p]; 508 if (port && port->remoteport) 509 out_switch_port(port, data->group, NULL); 510 } 511 } 512 513 static void ca_iter_func(ibnd_node_t * node, void *iter_user_data) 514 { 515 ibnd_port_t *port; 516 int p = 0; 517 struct iter_user_data *data = (struct iter_user_data *)iter_user_data; 518 519 DEBUG("CA: node %p\n", node); 520 /* Now, skip chassis based CAs */ 521 if (data->group && node->chassis && node->chassis->chassisnum) 522 return; 523 out_ca(node, data->group, NULL, NULL, NULL); 524 525 for (p = 1; p <= node->numports; p++) { 526 port = node->ports[p]; 527 if (port && port->remoteport) 528 out_ca_port(port, data->group, NULL); 529 } 530 } 531 532 static void router_iter_func(ibnd_node_t * node, void *iter_user_data) 533 { 534 ibnd_port_t *port; 535 int p = 0; 536 struct iter_user_data *data = (struct iter_user_data *)iter_user_data; 537 538 DEBUG("RT: node %p\n", node); 539 /* Now, skip chassis based RTs */ 540 if (data->group && node->chassis && node->chassis->chassisnum) 541 return; 542 out_ca(node, data->group, NULL, NULL, NULL); 543 for (p = 1; p <= node->numports; p++) { 544 port = node->ports[p]; 545 if (port && port->remoteport) 546 out_ca_port(port, data->group, NULL); 547 } 548 } 549 550 int dump_topology(int group, ibnd_fabric_t * fabric) 551 { 552 ibnd_node_t *node; 553 ibnd_port_t *port; 554 int i = 0, p = 0; 555 time_t t = time(0); 556 uint64_t chguid; 557 char *chname = NULL; 558 struct iter_user_data iter_user_data; 559 560 fprintf(f, "#\n# Topology file: generated on %s#\n", ctime(&t)); 561 if (report_max_hops) 562 fprintf(f, "# Reported max hops discovered: %u\n" 563 "# Total MADs used: %u\n", 564 fabric->maxhops_discovered, fabric->total_mads_used); 565 fprintf(f, "# Initiated from node %016" PRIx64 " port %016" PRIx64 "\n", 566 fabric->from_node->guid, 567 mad_get_field64(fabric->from_node->info, 0, 568 IB_NODE_PORT_GUID_F)); 569 570 /* Make pass on switches */ 571 if (group) { 572 ibnd_chassis_t *ch = NULL; 573 574 /* Chassis based switches first */ 575 for (ch = fabric->chassis; ch; ch = ch->next) { 576 int n = 0; 577 578 if (!ch->chassisnum) 579 continue; 580 chguid = out_chassis(fabric, ch->chassisnum); 581 chname = NULL; 582 if (ibnd_is_xsigo_guid(chguid)) { 583 for (node = ch->nodes; node; 584 node = node->next_chassis_node) { 585 if (ibnd_is_xsigo_hca(node->guid)) { 586 chname = node->nodedesc; 587 fprintf(f, "Hostname: %s\n", 588 clean_nodedesc 589 (node->nodedesc)); 590 } 591 } 592 } 593 594 fprintf(f, "\n# Spine Nodes"); 595 for (n = 1; n <= SPINES_MAX_NUM; n++) { 596 if (ch->spinenode[n]) { 597 out_switch(ch->spinenode[n], group, 598 chname, NULL, NULL); 599 for (p = 1; 600 p <= ch->spinenode[n]->numports; 601 p++) { 602 port = 603 ch->spinenode[n]->ports[p]; 604 if (port && port->remoteport) 605 out_switch_port(port, 606 group, 607 NULL); 608 } 609 } 610 } 611 fprintf(f, "\n# Line Nodes"); 612 for (n = 1; n <= LINES_MAX_NUM; n++) { 613 if (ch->linenode[n]) { 614 out_switch(ch->linenode[n], group, 615 chname, NULL, NULL); 616 for (p = 1; 617 p <= ch->linenode[n]->numports; 618 p++) { 619 port = 620 ch->linenode[n]->ports[p]; 621 if (port && port->remoteport) 622 out_switch_port(port, 623 group, 624 NULL); 625 } 626 } 627 } 628 629 fprintf(f, "\n# Chassis Switches"); 630 for (node = ch->nodes; node; 631 node = node->next_chassis_node) { 632 if (node->type == IB_NODE_SWITCH) { 633 out_switch(node, group, chname, NULL, 634 NULL); 635 for (p = 1; p <= node->numports; p++) { 636 port = node->ports[p]; 637 if (port && port->remoteport) 638 out_switch_port(port, 639 group, 640 NULL); 641 } 642 } 643 644 } 645 646 fprintf(f, "\n# Chassis CAs"); 647 for (node = ch->nodes; node; 648 node = node->next_chassis_node) { 649 if (node->type == IB_NODE_CA) { 650 out_ca(node, group, chname, NULL, NULL); 651 for (p = 1; p <= node->numports; p++) { 652 port = node->ports[p]; 653 if (port && port->remoteport) 654 out_ca_port(port, group, 655 NULL); 656 } 657 } 658 } 659 660 } 661 662 } else { /* !group */ 663 iter_user_data.group = group; 664 iter_user_data.skip_chassis_nodes = 0; 665 ibnd_iter_nodes_type(fabric, switch_iter_func, IB_NODE_SWITCH, 666 &iter_user_data); 667 } 668 669 chname = NULL; 670 if (group) { 671 iter_user_data.group = group; 672 iter_user_data.skip_chassis_nodes = 1; 673 674 fprintf(f, "\nNon-Chassis Nodes\n"); 675 676 ibnd_iter_nodes_type(fabric, switch_iter_func, IB_NODE_SWITCH, 677 &iter_user_data); 678 } 679 680 iter_user_data.group = group; 681 iter_user_data.skip_chassis_nodes = 0; 682 /* Make pass on CAs */ 683 ibnd_iter_nodes_type(fabric, ca_iter_func, IB_NODE_CA, &iter_user_data); 684 685 /* Make pass on routers */ 686 ibnd_iter_nodes_type(fabric, router_iter_func, IB_NODE_ROUTER, 687 &iter_user_data); 688 689 return i; 690 } 691 692 void dump_ports_report(ibnd_node_t * node, void *user_data) 693 { 694 int p = 0; 695 ibnd_port_t *port = NULL; 696 char *nodename = NULL; 697 char *rem_nodename = NULL; 698 699 /* for each port */ 700 for (p = node->numports, port = node->ports[p]; p > 0; 701 port = node->ports[--p]) { 702 uint32_t iwidth, ispeed, fdr10, espeed, cap_mask; 703 uint8_t *info = NULL; 704 if (port == NULL) 705 continue; 706 iwidth = 707 mad_get_field(port->info, 0, IB_PORT_LINK_WIDTH_ACTIVE_F); 708 ispeed = 709 mad_get_field(port->info, 0, IB_PORT_LINK_SPEED_ACTIVE_F); 710 if (port->node->type == IB_NODE_SWITCH) { 711 if (port->node->ports[0]) 712 info = (uint8_t *)&port->node->ports[0]->info; 713 } 714 else 715 info = (uint8_t *)&port->info; 716 if (info) { 717 cap_mask = mad_get_field(info, 0, IB_PORT_CAPMASK_F); 718 if (cap_mask & CL_NTOH32(IB_PORT_CAP_HAS_EXT_SPEEDS)) 719 espeed = mad_get_field(port->info, 0, 720 IB_PORT_LINK_SPEED_EXT_ACTIVE_F); 721 else 722 espeed = 0; 723 } else { 724 ispeed = 0; 725 iwidth = 0; 726 espeed = 0; 727 } 728 fdr10 = mad_get_field(port->ext_info, 0, 729 IB_MLNX_EXT_PORT_LINK_SPEED_ACTIVE_F); 730 nodename = remap_node_name(node_name_map, 731 port->node->guid, 732 port->node->nodedesc); 733 fprintf(stdout, "%2s %5d %2d 0x%016" PRIx64 " %s %s", 734 ports_nt_str_compat(node), 735 node->type == 736 IB_NODE_SWITCH ? node->smalid : port->base_lid, 737 port->portnum, port->guid, 738 dump_linkwidth_compat(iwidth), 739 (ispeed != 4 && !espeed) ? 740 dump_linkspeed_compat(ispeed) : 741 dump_linkspeedext_compat(espeed, ispeed, fdr10)); 742 if (port->remoteport) { 743 rem_nodename = remap_node_name(node_name_map, 744 port->remoteport->node->guid, 745 port->remoteport->node->nodedesc); 746 fprintf(stdout, 747 " - %2s %5d %2d 0x%016" PRIx64 748 " ( '%s' - '%s' )\n", 749 ports_nt_str_compat(port->remoteport->node), 750 port->remoteport->node->type == IB_NODE_SWITCH ? 751 port->remoteport->node->smalid : 752 port->remoteport->base_lid, 753 port->remoteport->portnum, 754 port->remoteport->guid, nodename, rem_nodename); 755 free(rem_nodename); 756 } else 757 fprintf(stdout, "%36s'%s'\n", "", nodename); 758 759 free(nodename); 760 } 761 } 762 763 struct iter_diff_data { 764 uint32_t diff_flags; 765 ibnd_fabric_t *fabric1; 766 ibnd_fabric_t *fabric2; 767 char *fabric1_prefix; 768 char *fabric2_prefix; 769 void (*out_header) (ibnd_node_t *, int, char *, char *, char *); 770 void (*out_header_detail) (ibnd_node_t *, char *); 771 void (*out_port) (ibnd_port_t *, int, char *); 772 }; 773 774 static void diff_iter_out_header(ibnd_node_t * node, 775 struct iter_diff_data *data, 776 int *out_header_flag) 777 { 778 if (!(*out_header_flag)) { 779 (*data->out_header) (node, 0, NULL, NULL, NULL); 780 (*out_header_flag)++; 781 } 782 } 783 784 static void diff_ports(ibnd_node_t * fabric1_node, ibnd_node_t * fabric2_node, 785 int *out_header_flag, struct iter_diff_data *data) 786 { 787 ibnd_port_t *fabric1_port; 788 ibnd_port_t *fabric2_port; 789 int p; 790 791 for (p = 1; p <= fabric1_node->numports; p++) { 792 int fabric1_out = 0, fabric2_out = 0; 793 794 fabric1_port = fabric1_node->ports[p]; 795 fabric2_port = fabric2_node->ports[p]; 796 797 if (data->diff_flags & DIFF_FLAG_PORT_CONNECTION) { 798 if ((fabric1_port && !fabric2_port) 799 || ((fabric1_port && fabric2_port) 800 && (fabric1_port->remoteport 801 && !fabric2_port->remoteport))) 802 fabric1_out++; 803 else if ((!fabric1_port && fabric2_port) 804 || ((fabric1_port && fabric2_port) 805 && (!fabric1_port->remoteport 806 && fabric2_port->remoteport))) 807 fabric2_out++; 808 else if ((fabric1_port && fabric2_port) 809 && ((fabric1_port->guid != fabric2_port->guid) 810 || 811 ((fabric1_port->remoteport 812 && fabric2_port->remoteport) 813 && (fabric1_port->remoteport->guid != 814 fabric2_port->remoteport->guid)))) { 815 fabric1_out++; 816 fabric2_out++; 817 } 818 } 819 820 if ((data->diff_flags & DIFF_FLAG_LID) 821 && fabric1_port && fabric2_port 822 && fabric1_port->base_lid != fabric2_port->base_lid) { 823 fabric1_out++; 824 fabric2_out++; 825 } 826 827 if (data->diff_flags & DIFF_FLAG_PORT_CONNECTION 828 && data->diff_flags & DIFF_FLAG_NODE_DESCRIPTION 829 && fabric1_port && fabric2_port 830 && fabric1_port->remoteport && fabric2_port->remoteport 831 && memcmp(fabric1_port->remoteport->node->nodedesc, 832 fabric2_port->remoteport->node->nodedesc, 833 IB_SMP_DATA_SIZE)) { 834 fabric1_out++; 835 fabric2_out++; 836 } 837 838 if (data->diff_flags & DIFF_FLAG_PORT_CONNECTION 839 && data->diff_flags & DIFF_FLAG_NODE_DESCRIPTION 840 && fabric1_port && fabric2_port 841 && fabric1_port->remoteport && fabric2_port->remoteport 842 && memcmp(fabric1_port->remoteport->node->nodedesc, 843 fabric2_port->remoteport->node->nodedesc, 844 IB_SMP_DATA_SIZE)) { 845 fabric1_out++; 846 fabric2_out++; 847 } 848 849 if (data->diff_flags & DIFF_FLAG_PORT_CONNECTION 850 && data->diff_flags & DIFF_FLAG_LID 851 && fabric1_port && fabric2_port 852 && fabric1_port->remoteport && fabric2_port->remoteport 853 && fabric1_port->remoteport->base_lid != fabric2_port->remoteport->base_lid) { 854 fabric1_out++; 855 fabric2_out++; 856 } 857 858 if (fabric1_out) { 859 diff_iter_out_header(fabric1_node, data, 860 out_header_flag); 861 (*data->out_port) (fabric1_port, 0, 862 data->fabric1_prefix); 863 } 864 if (fabric2_out) { 865 diff_iter_out_header(fabric1_node, data, 866 out_header_flag); 867 (*data->out_port) (fabric2_port, 0, 868 data->fabric2_prefix); 869 } 870 } 871 } 872 873 static void diff_iter_func(ibnd_node_t * fabric1_node, void *iter_user_data) 874 { 875 struct iter_diff_data *data = iter_user_data; 876 ibnd_node_t *fabric2_node; 877 ibnd_port_t *fabric1_port; 878 int p; 879 880 DEBUG("DEBUG: fabric1_node %p\n", fabric1_node); 881 882 fabric2_node = ibnd_find_node_guid(data->fabric2, fabric1_node->guid); 883 if (!fabric2_node) { 884 (*data->out_header) (fabric1_node, 0, NULL, 885 data->fabric1_prefix, 886 data->fabric1_prefix); 887 for (p = 1; p <= fabric1_node->numports; p++) { 888 fabric1_port = fabric1_node->ports[p]; 889 if (fabric1_port && fabric1_port->remoteport) 890 (*data->out_port) (fabric1_port, 0, 891 data->fabric1_prefix); 892 } 893 } else if (data->diff_flags & 894 (DIFF_FLAG_PORT_CONNECTION | DIFF_FLAG_LID 895 | DIFF_FLAG_NODE_DESCRIPTION)) { 896 int out_header_flag = 0; 897 898 if ((data->diff_flags & DIFF_FLAG_LID 899 && fabric1_node->smalid != fabric2_node->smalid) || 900 (data->diff_flags & DIFF_FLAG_NODE_DESCRIPTION 901 && memcmp(fabric1_node->nodedesc, fabric2_node->nodedesc, 902 IB_SMP_DATA_SIZE))) { 903 (*data->out_header) (fabric1_node, 0, NULL, NULL, 904 data->fabric1_prefix); 905 (*data->out_header_detail) (fabric2_node, 906 data->fabric2_prefix); 907 fprintf(f, "\n"); 908 out_header_flag++; 909 } 910 911 if (fabric1_node->numports != fabric2_node->numports) { 912 diff_iter_out_header(fabric1_node, data, 913 &out_header_flag); 914 fprintf(f, "%snumports = %d\n", data->fabric1_prefix, 915 fabric1_node->numports); 916 fprintf(f, "%snumports = %d\n", data->fabric2_prefix, 917 fabric2_node->numports); 918 return; 919 } 920 921 if (data->diff_flags & DIFF_FLAG_PORT_CONNECTION 922 || data->diff_flags & DIFF_FLAG_LID) 923 diff_ports(fabric1_node, fabric2_node, &out_header_flag, 924 data); 925 } 926 } 927 928 static int diff_common(ibnd_fabric_t * orig_fabric, ibnd_fabric_t * new_fabric, 929 int node_type, uint32_t diff_flags, 930 void (*out_header) (ibnd_node_t *, int, char *, char *, 931 char *), 932 void (*out_header_detail) (ibnd_node_t *, char *), 933 void (*out_port) (ibnd_port_t *, int, char *)) 934 { 935 struct iter_diff_data iter_diff_data; 936 937 iter_diff_data.diff_flags = diff_flags; 938 iter_diff_data.fabric1 = orig_fabric; 939 iter_diff_data.fabric2 = new_fabric; 940 iter_diff_data.fabric1_prefix = "< "; 941 iter_diff_data.fabric2_prefix = "> "; 942 iter_diff_data.out_header = out_header; 943 iter_diff_data.out_header_detail = out_header_detail; 944 iter_diff_data.out_port = out_port; 945 ibnd_iter_nodes_type(orig_fabric, diff_iter_func, node_type, 946 &iter_diff_data); 947 948 /* Do opposite diff to find existence of node types 949 * in new_fabric but not in orig_fabric. 950 * 951 * In this diff, we don't need to check port connections, 952 * lids, or node descriptions since it has already been 953 * done (i.e. checks are only done when guid exists on both 954 * orig and new). 955 */ 956 iter_diff_data.diff_flags = diff_flags & ~DIFF_FLAG_PORT_CONNECTION; 957 iter_diff_data.diff_flags &= ~DIFF_FLAG_LID; 958 iter_diff_data.diff_flags &= ~DIFF_FLAG_NODE_DESCRIPTION; 959 iter_diff_data.fabric1 = new_fabric; 960 iter_diff_data.fabric2 = orig_fabric; 961 iter_diff_data.fabric1_prefix = "> "; 962 iter_diff_data.fabric2_prefix = "< "; 963 iter_diff_data.out_header = out_header; 964 iter_diff_data.out_header_detail = out_header_detail; 965 iter_diff_data.out_port = out_port; 966 ibnd_iter_nodes_type(new_fabric, diff_iter_func, node_type, 967 &iter_diff_data); 968 969 return 0; 970 } 971 972 int diff(ibnd_fabric_t * orig_fabric, ibnd_fabric_t * new_fabric) 973 { 974 if (diffcheck_flags & DIFF_FLAG_SWITCH) 975 diff_common(orig_fabric, new_fabric, IB_NODE_SWITCH, 976 diffcheck_flags, out_switch, out_switch_detail, 977 out_switch_port); 978 979 if (diffcheck_flags & DIFF_FLAG_CA) 980 diff_common(orig_fabric, new_fabric, IB_NODE_CA, 981 diffcheck_flags, out_ca, out_ca_detail, 982 out_ca_port); 983 984 if (diffcheck_flags & DIFF_FLAG_ROUTER) 985 diff_common(orig_fabric, new_fabric, IB_NODE_ROUTER, 986 diffcheck_flags, out_ca, out_ca_detail, 987 out_ca_port); 988 989 return 0; 990 } 991 992 static int list, group, ports_report; 993 994 static int process_opt(void *context, int ch, char *optarg) 995 { 996 struct ibnd_config *cfg = context; 997 char *p; 998 999 switch (ch) { 1000 case 1: 1001 node_name_map_file = strdup(optarg); 1002 break; 1003 case 2: 1004 cache_file = strdup(optarg); 1005 break; 1006 case 3: 1007 load_cache_file = strdup(optarg); 1008 break; 1009 case 4: 1010 diff_cache_file = strdup(optarg); 1011 break; 1012 case 5: 1013 diffcheck_flags = 0; 1014 p = strtok(optarg, ","); 1015 while (p) { 1016 if (!strcasecmp(p, "sw")) 1017 diffcheck_flags |= DIFF_FLAG_SWITCH; 1018 else if (!strcasecmp(p, "ca")) 1019 diffcheck_flags |= DIFF_FLAG_CA; 1020 else if (!strcasecmp(p, "router")) 1021 diffcheck_flags |= DIFF_FLAG_ROUTER; 1022 else if (!strcasecmp(p, "port")) 1023 diffcheck_flags |= DIFF_FLAG_PORT_CONNECTION; 1024 else if (!strcasecmp(p, "lid")) 1025 diffcheck_flags |= DIFF_FLAG_LID; 1026 else if (!strcasecmp(p, "nodedesc")) 1027 diffcheck_flags |= DIFF_FLAG_NODE_DESCRIPTION; 1028 else { 1029 fprintf(stderr, "invalid diff check key: %s\n", 1030 p); 1031 return -1; 1032 } 1033 p = strtok(NULL, ","); 1034 } 1035 break; 1036 case 's': 1037 cfg->show_progress = 1; 1038 break; 1039 case 'f': 1040 full_info = 1; 1041 break; 1042 case 'l': 1043 list = LIST_CA_NODE | LIST_SWITCH_NODE | LIST_ROUTER_NODE; 1044 break; 1045 case 'g': 1046 group = 1; 1047 break; 1048 case 'S': 1049 list = LIST_SWITCH_NODE; 1050 break; 1051 case 'H': 1052 list = LIST_CA_NODE; 1053 break; 1054 case 'R': 1055 list = LIST_ROUTER_NODE; 1056 break; 1057 case 'p': 1058 ports_report = 1; 1059 break; 1060 case 'm': 1061 report_max_hops = 1; 1062 break; 1063 case 'o': 1064 cfg->max_smps = strtoul(optarg, NULL, 0); 1065 break; 1066 default: 1067 return -1; 1068 } 1069 1070 return 0; 1071 } 1072 1073 int main(int argc, char **argv) 1074 { 1075 struct ibnd_config config = { 0 }; 1076 ibnd_fabric_t *fabric = NULL; 1077 ibnd_fabric_t *diff_fabric = NULL; 1078 1079 const struct ibdiag_opt opts[] = { 1080 {"full", 'f', 0, NULL, "show full information (ports' speed and width, vlcap)"}, 1081 {"show", 's', 0, NULL, "show more information"}, 1082 {"list", 'l', 0, NULL, "list of connected nodes"}, 1083 {"grouping", 'g', 0, NULL, "show grouping"}, 1084 {"Hca_list", 'H', 0, NULL, "list of connected CAs"}, 1085 {"Switch_list", 'S', 0, NULL, "list of connected switches"}, 1086 {"Router_list", 'R', 0, NULL, "list of connected routers"}, 1087 {"node-name-map", 1, 1, "<file>", "node name map file"}, 1088 {"cache", 2, 1, "<file>", 1089 "filename to cache ibnetdiscover data to"}, 1090 {"load-cache", 3, 1, "<file>", 1091 "filename of ibnetdiscover cache to load"}, 1092 {"diff", 4, 1, "<file>", 1093 "filename of ibnetdiscover cache to diff"}, 1094 {"diffcheck", 5, 1, "<key(s)>", 1095 "specify checks to execute for --diff"}, 1096 {"ports", 'p', 0, NULL, "obtain a ports report"}, 1097 {"max_hops", 'm', 0, NULL, 1098 "report max hops discovered by the library"}, 1099 {"outstanding_smps", 'o', 1, NULL, 1100 "specify the number of outstanding SMP's which should be " 1101 "issued during the scan"}, 1102 {0} 1103 }; 1104 char usage_args[] = "[topology-file]"; 1105 1106 ibdiag_process_opts(argc, argv, &config, "DGKLs", opts, process_opt, 1107 usage_args, NULL); 1108 1109 f = stdout; 1110 1111 argc -= optind; 1112 argv += optind; 1113 1114 if (ibd_timeout) 1115 config.timeout_ms = ibd_timeout; 1116 1117 config.flags = ibd_ibnetdisc_flags; 1118 1119 if (argc && !(f = fopen(argv[0], "w"))) 1120 IBEXIT("can't open file %s for writing", argv[0]); 1121 1122 config.mkey = ibd_mkey; 1123 1124 node_name_map = open_node_name_map(node_name_map_file); 1125 1126 if (diff_cache_file && 1127 !(diff_fabric = ibnd_load_fabric(diff_cache_file, 0))) 1128 IBEXIT("loading cached fabric for diff failed\n"); 1129 1130 if (load_cache_file) { 1131 if ((fabric = ibnd_load_fabric(load_cache_file, 0)) == NULL) 1132 IBEXIT("loading cached fabric failed\n"); 1133 } else { 1134 if ((fabric = 1135 ibnd_discover_fabric(ibd_ca, ibd_ca_port, NULL, &config)) == NULL) 1136 IBEXIT("discover failed\n"); 1137 } 1138 1139 if (ports_report) 1140 ibnd_iter_nodes(fabric, dump_ports_report, NULL); 1141 else if (list) 1142 list_nodes(fabric, list); 1143 else if (diff_fabric) 1144 diff(diff_fabric, fabric); 1145 else 1146 dump_topology(group, fabric); 1147 1148 if (cache_file) 1149 if (ibnd_cache_fabric(fabric, cache_file, 0) < 0) 1150 IBEXIT("caching ibnetdiscover data failed\n"); 1151 1152 ibnd_destroy_fabric(fabric); 1153 if (diff_fabric) 1154 ibnd_destroy_fabric(diff_fabric); 1155 close_node_name_map(node_name_map); 1156 exit(0); 1157 } 1158