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