1 /* 2 * Copyright (c) 2004-2009 Voltaire Inc. All rights reserved. 3 * Copyright (c) 2009-2011 Mellanox Technologies LTD. All rights reserved. 4 * Copyright (c) 2013 Lawrence Livermore National Security. 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 #include <stdio.h> 41 #include <stdlib.h> 42 #include <unistd.h> 43 #include <string.h> 44 #include <inttypes.h> 45 #include <getopt.h> 46 #include <netinet/in.h> 47 #include <assert.h> 48 49 #include <infiniband/umad.h> 50 #include <infiniband/mad.h> 51 #include <complib/cl_nodenamemap.h> 52 53 #include <infiniband/ibnetdisc.h> 54 55 #include "ibdiag_common.h" 56 57 struct ibmad_port *srcport; 58 59 unsigned startlid = 0, endlid = 0; 60 61 static int brief, dump_all, multicast; 62 63 static char *node_name_map_file = NULL; 64 static nn_map_t *node_name_map = NULL; 65 66 #define IB_MLIDS_IN_BLOCK (IB_SMP_DATA_SIZE/2) 67 68 int dump_mlid(char *str, int strlen, unsigned mlid, unsigned nports, 69 uint16_t mft[16][IB_MLIDS_IN_BLOCK]) 70 { 71 uint16_t mask; 72 unsigned i, chunk, bit, nonzero = 0; 73 74 if (brief) { 75 int n = 0; 76 unsigned chunks = ALIGN(nports + 1, 16) / 16; 77 for (i = 0; i < chunks; i++) { 78 mask = ntohs(mft[i][mlid % IB_MLIDS_IN_BLOCK]); 79 if (mask) 80 nonzero++; 81 n += snprintf(str + n, strlen - n, "%04hx", mask); 82 if (n >= strlen) { 83 n = strlen; 84 break; 85 } 86 } 87 if (!nonzero && !dump_all) { 88 str[0] = 0; 89 return 0; 90 } 91 return n; 92 } 93 for (i = 0; i <= nports; i++) { 94 chunk = i / 16; 95 bit = i % 16; 96 97 mask = ntohs(mft[chunk][mlid % IB_MLIDS_IN_BLOCK]); 98 if (mask) 99 nonzero++; 100 str[i * 2] = (mask & (1 << bit)) ? 'x' : ' '; 101 str[i * 2 + 1] = ' '; 102 } 103 if (!nonzero && !dump_all) { 104 str[0] = 0; 105 return 0; 106 } 107 str[i * 2] = 0; 108 return i * 2; 109 } 110 111 uint16_t mft[16][IB_MLIDS_IN_BLOCK] = { { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0}, { 0 }, { 0 } }; 112 113 void dump_multicast_tables(ibnd_node_t * node, unsigned startlid, 114 unsigned endlid, struct ibmad_port * mad_port) 115 { 116 ib_portid_t *portid = &node->path_portid; 117 char nd[IB_SMP_DATA_SIZE] = { 0 }; 118 char str[512]; 119 char *s; 120 uint64_t nodeguid; 121 uint32_t mod; 122 unsigned block, i, j, e, nports, cap, chunks, startblock, lastblock, 123 top; 124 char *mapnd = NULL; 125 int n = 0; 126 127 memcpy(nd, node->nodedesc, strlen(node->nodedesc)); 128 nports = node->numports; 129 nodeguid = node->guid; 130 131 mad_decode_field(node->switchinfo, IB_SW_MCAST_FDB_CAP_F, &cap); 132 mad_decode_field(node->switchinfo, IB_SW_MCAST_FDB_TOP_F, &top); 133 134 if (!endlid || endlid > IB_MIN_MCAST_LID + cap - 1) 135 endlid = IB_MIN_MCAST_LID + cap - 1; 136 if (!dump_all && top && top < endlid) { 137 if (top < IB_MIN_MCAST_LID - 1) 138 IBWARN("illegal top mlid %x", top); 139 else 140 endlid = top; 141 } 142 143 if (!startlid) 144 startlid = IB_MIN_MCAST_LID; 145 else if (startlid < IB_MIN_MCAST_LID) { 146 IBWARN("illegal start mlid %x, set to %x", startlid, 147 IB_MIN_MCAST_LID); 148 startlid = IB_MIN_MCAST_LID; 149 } 150 151 if (endlid > IB_MAX_MCAST_LID) { 152 IBWARN("illegal end mlid %x, truncate to %x", endlid, 153 IB_MAX_MCAST_LID); 154 endlid = IB_MAX_MCAST_LID; 155 } 156 157 mapnd = remap_node_name(node_name_map, nodeguid, nd); 158 159 printf("Multicast mlids [0x%x-0x%x] of switch %s guid 0x%016" PRIx64 160 " (%s):\n", startlid, endlid, portid2str(portid), nodeguid, 161 mapnd); 162 163 if (brief) 164 printf(" MLid Port Mask\n"); 165 else { 166 if (nports > 9) { 167 for (i = 0, s = str; i <= nports; i++) { 168 *s++ = (i % 10) ? ' ' : '0' + i / 10; 169 *s++ = ' '; 170 } 171 *s = 0; 172 printf(" %s\n", str); 173 } 174 for (i = 0, s = str; i <= nports; i++) 175 s += sprintf(s, "%d ", i % 10); 176 printf(" Ports: %s\n", str); 177 printf(" MLid\n"); 178 } 179 if (ibverbose) 180 printf("Switch multicast mlid capability is %d top is 0x%x\n", 181 cap, top); 182 183 chunks = ALIGN(nports + 1, 16) / 16; 184 185 startblock = startlid / IB_MLIDS_IN_BLOCK; 186 lastblock = endlid / IB_MLIDS_IN_BLOCK; 187 for (block = startblock; block <= lastblock; block++) { 188 for (j = 0; j < chunks; j++) { 189 int status; 190 mod = (block - IB_MIN_MCAST_LID / IB_MLIDS_IN_BLOCK) 191 | (j << 28); 192 193 DEBUG("reading block %x chunk %d mod %x", block, j, 194 mod); 195 if (!smp_query_status_via 196 (mft + j, portid, IB_ATTR_MULTICASTFORWTBL, mod, 0, 197 &status, mad_port)) { 198 fprintf(stderr, "SubnGet(MFT) failed on switch " 199 "'%s' %s Node GUID 0x%"PRIx64 200 " SMA LID %d; MAD status 0x%x " 201 "AM 0x%x\n", 202 mapnd, portid2str(portid), 203 node->guid, node->smalid, 204 status, mod); 205 } 206 } 207 208 i = block * IB_MLIDS_IN_BLOCK; 209 e = i + IB_MLIDS_IN_BLOCK; 210 if (i < startlid) 211 i = startlid; 212 if (e > endlid + 1) 213 e = endlid + 1; 214 215 for (; i < e; i++) { 216 if (dump_mlid(str, sizeof str, i, nports, mft) == 0) 217 continue; 218 printf("0x%04x %s\n", i, str); 219 n++; 220 } 221 } 222 223 printf("%d %smlids dumped \n", n, dump_all ? "" : "valid "); 224 225 free(mapnd); 226 } 227 228 int dump_lid(char *str, int str_len, int lid, int valid, 229 ibnd_fabric_t *fabric, 230 int * last_port_lid, int * base_port_lid, 231 uint64_t * portguid) 232 { 233 char nd[IB_SMP_DATA_SIZE] = { 0 }; 234 235 ibnd_port_t *port = NULL; 236 237 char ntype[50], sguid[30]; 238 uint64_t nodeguid; 239 int baselid, lmc, type; 240 char *mapnd = NULL; 241 int rc; 242 243 if (brief) { 244 str[0] = 0; 245 return 0; 246 } 247 248 if (lid <= *last_port_lid) { 249 if (!valid) 250 return snprintf(str, str_len, 251 ": (path #%d - illegal port)", 252 lid - *base_port_lid); 253 else if (!*portguid) 254 return snprintf(str, str_len, 255 ": (path #%d out of %d)", 256 lid - *base_port_lid + 1, 257 *last_port_lid - *base_port_lid + 1); 258 else { 259 return snprintf(str, str_len, 260 ": (path #%d out of %d: portguid %s)", 261 lid - *base_port_lid + 1, 262 *last_port_lid - *base_port_lid + 1, 263 mad_dump_val(IB_NODE_PORT_GUID_F, sguid, 264 sizeof sguid, portguid)); 265 } 266 } 267 268 if (!valid) 269 return snprintf(str, str_len, ": (illegal port)"); 270 271 *portguid = 0; 272 273 port = ibnd_find_port_lid(fabric, lid); 274 if (!port) { 275 return snprintf(str, str_len, ": (node info not available fabric scan)"); 276 } 277 278 nodeguid = port->node->guid; 279 *portguid = port->guid; 280 type = port->node->type; 281 282 baselid = port->base_lid; 283 lmc = port->lmc; 284 285 memcpy(nd, port->node->nodedesc, strlen(port->node->nodedesc)); 286 287 if (lmc > 0) { 288 *base_port_lid = baselid; 289 *last_port_lid = baselid + (1 << lmc) - 1; 290 } 291 292 mapnd = remap_node_name(node_name_map, nodeguid, nd); 293 294 rc = snprintf(str, str_len, ": (%s portguid %s: '%s')", 295 mad_dump_val(IB_NODE_TYPE_F, ntype, sizeof ntype, 296 &type), mad_dump_val(IB_NODE_PORT_GUID_F, 297 sguid, sizeof sguid, 298 portguid), 299 mapnd); 300 301 free(mapnd); 302 return rc; 303 } 304 305 void dump_unicast_tables(ibnd_node_t * node, int startlid, int endlid, 306 struct ibmad_port *mad_port, ibnd_fabric_t *fabric) 307 { 308 ib_portid_t * portid = &node->path_portid; 309 char lft[IB_SMP_DATA_SIZE] = { 0 }; 310 char nd[IB_SMP_DATA_SIZE] = { 0 }; 311 char str[200]; 312 uint64_t nodeguid; 313 int block, i, e, top; 314 unsigned nports; 315 int n = 0, startblock, endblock; 316 char *mapnd = NULL; 317 int last_port_lid = 0, base_port_lid = 0; 318 uint64_t portguid = 0; 319 320 mad_decode_field(node->switchinfo, IB_SW_LINEAR_FDB_TOP_F, &top); 321 nodeguid = node->guid; 322 nports = node->numports; 323 memcpy(nd, node->nodedesc, strlen(node->nodedesc)); 324 325 if (!endlid || endlid > top) 326 endlid = top; 327 328 if (endlid > IB_MAX_UCAST_LID) { 329 IBWARN("illegal lft top %d, truncate to %d", endlid, 330 IB_MAX_UCAST_LID); 331 endlid = IB_MAX_UCAST_LID; 332 } 333 334 mapnd = remap_node_name(node_name_map, nodeguid, nd); 335 336 printf("Unicast lids [0x%x-0x%x] of switch %s guid 0x%016" PRIx64 337 " (%s):\n", startlid, endlid, portid2str(portid), nodeguid, 338 mapnd); 339 340 DEBUG("Switch top is 0x%x\n", top); 341 342 printf(" Lid Out Destination\n"); 343 printf(" Port Info \n"); 344 startblock = startlid / IB_SMP_DATA_SIZE; 345 endblock = ALIGN(endlid, IB_SMP_DATA_SIZE) / IB_SMP_DATA_SIZE; 346 for (block = startblock; block < endblock; block++) { 347 int status; 348 DEBUG("reading block %d", block); 349 if (!smp_query_status_via(lft, portid, IB_ATTR_LINEARFORWTBL, block, 350 0, &status, mad_port)) { 351 fprintf(stderr, "SubnGet(LFT) failed on switch " 352 "'%s' %s Node GUID 0x%"PRIx64 353 " SMA LID %d; MAD status 0x%x AM 0x%x\n", 354 mapnd, portid2str(portid), 355 node->guid, node->smalid, 356 status, block); 357 } 358 i = block * IB_SMP_DATA_SIZE; 359 e = i + IB_SMP_DATA_SIZE; 360 if (i < startlid) 361 i = startlid; 362 if (e > endlid + 1) 363 e = endlid + 1; 364 365 for (; i < e; i++) { 366 unsigned outport = lft[i % IB_SMP_DATA_SIZE]; 367 unsigned valid = (outport <= nports); 368 369 if (!valid && !dump_all) 370 continue; 371 dump_lid(str, sizeof str, i, valid, fabric, 372 &last_port_lid, &base_port_lid, &portguid); 373 printf("0x%04x %03u %s\n", i, outport & 0xff, str); 374 n++; 375 } 376 } 377 378 printf("%d %slids dumped \n", n, dump_all ? "" : "valid "); 379 free(mapnd); 380 } 381 382 void dump_node(ibnd_node_t *node, struct ibmad_port *mad_port, 383 ibnd_fabric_t *fabric) 384 { 385 if (multicast) 386 dump_multicast_tables(node, startlid, endlid, mad_port); 387 else 388 dump_unicast_tables(node, startlid, endlid, 389 mad_port, fabric); 390 } 391 392 void process_switch(ibnd_node_t * node, void *fabric) 393 { 394 dump_node(node, srcport, (ibnd_fabric_t *)fabric); 395 } 396 397 static int process_opt(void *context, int ch, char *optarg) 398 { 399 switch (ch) { 400 case 'a': 401 dump_all++; 402 break; 403 case 'M': 404 multicast++; 405 break; 406 case 'n': 407 brief++; 408 break; 409 case 1: 410 node_name_map_file = strdup(optarg); 411 break; 412 default: 413 return -1; 414 } 415 return 0; 416 } 417 418 int main(int argc, char **argv) 419 { 420 int rc = 0; 421 int mgmt_classes[3] = 422 { IB_SMI_CLASS, IB_SMI_DIRECT_CLASS, IB_SA_CLASS }; 423 424 struct ibnd_config config = { 0 }; 425 ibnd_fabric_t *fabric = NULL; 426 427 const struct ibdiag_opt opts[] = { 428 {"all", 'a', 0, NULL, "show all lids, even invalid entries"}, 429 {"no_dests", 'n', 0, NULL, 430 "do not try to resolve destinations"}, 431 {"Multicast", 'M', 0, NULL, "show multicast forwarding tables"}, 432 {"node-name-map", 1, 1, "<file>", "node name map file"}, 433 {0} 434 }; 435 char usage_args[] = "[<dest dr_path|lid|guid> [<startlid> [<endlid>]]]"; 436 const char *usage_examples[] = { 437 " -- Unicast examples:", 438 "-a\t# same, but dump all lids, even with invalid out ports", 439 "-n\t# simple dump format - no destination resolving", 440 "10\t# dump lids starting from 10", 441 "0x10 0x20\t# dump lid range", 442 " -- Multicast examples:", 443 "-M\t# dump all non empty mlids of switch with lid 4", 444 "-M 0xc010 0xc020\t# same, but with range", 445 "-M -n\t# simple dump format", 446 NULL, 447 }; 448 449 ibdiag_process_opts(argc, argv, &config, "KGDLs", opts, process_opt, 450 usage_args, usage_examples); 451 452 argc -= optind; 453 argv += optind; 454 455 if (argc > 0) 456 startlid = strtoul(argv[0], 0, 0); 457 if (argc > 1) 458 endlid = strtoul(argv[1], 0, 0); 459 460 node_name_map = open_node_name_map(node_name_map_file); 461 462 if (ibd_timeout) 463 config.timeout_ms = ibd_timeout; 464 465 config.flags = ibd_ibnetdisc_flags; 466 config.mkey = ibd_mkey; 467 468 if ((fabric = ibnd_discover_fabric(ibd_ca, ibd_ca_port, NULL, 469 &config)) != NULL) { 470 471 srcport = mad_rpc_open_port(ibd_ca, ibd_ca_port, mgmt_classes, 3); 472 if (!srcport) { 473 fprintf(stderr, 474 "Failed to open '%s' port '%d'\n", ibd_ca, ibd_ca_port); 475 rc = -1; 476 goto Exit; 477 } 478 smp_mkey_set(srcport, ibd_mkey); 479 480 if (ibd_timeout) { 481 mad_rpc_set_timeout(srcport, ibd_timeout); 482 } 483 484 ibnd_iter_nodes_type(fabric, process_switch, IB_NODE_SWITCH, fabric); 485 486 mad_rpc_close_port(srcport); 487 488 } else { 489 fprintf(stderr, "Failed to discover fabric\n"); 490 rc = -1; 491 } 492 Exit: 493 ibnd_destroy_fabric(fabric); 494 495 close_node_name_map(node_name_map); 496 exit(rc); 497 } 498