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 return NULL; 226 } 227 } 228 229 i = block * IB_MLIDS_IN_BLOCK; 230 e = i + IB_MLIDS_IN_BLOCK; 231 if (i < startlid) 232 i = startlid; 233 if (e > endlid + 1) 234 e = endlid + 1; 235 236 for (; i < e; i++) { 237 if (dump_mlid(str, sizeof str, i, nports, mft) == 0) 238 continue; 239 printf("0x%04x %s\n", i, str); 240 n++; 241 } 242 } 243 244 printf("%d %smlids dumped \n", n, dump_all ? "" : "valid "); 245 246 free(mapnd); 247 return 0; 248 } 249 250 int dump_lid(char *str, int strlen, int lid, int valid) 251 { 252 char nd[IB_SMP_DATA_SIZE] = { 0 }; 253 uint8_t ni[IB_SMP_DATA_SIZE] = { 0 }; 254 uint8_t pi[IB_SMP_DATA_SIZE] = { 0 }; 255 ib_portid_t lidport = { 0 }; 256 static int last_port_lid, base_port_lid; 257 char ntype[50], sguid[30]; 258 static uint64_t portguid; 259 uint64_t nodeguid; 260 int baselid, lmc, type; 261 char *mapnd = NULL; 262 int rc; 263 264 if (brief) { 265 str[0] = 0; 266 return 0; 267 } 268 269 if (lid <= last_port_lid) { 270 if (!valid) 271 return snprintf(str, strlen, 272 ": (path #%d - illegal port)", 273 lid - base_port_lid); 274 else if (!portguid) 275 return snprintf(str, strlen, 276 ": (path #%d out of %d)", 277 lid - base_port_lid + 1, 278 last_port_lid - base_port_lid + 1); 279 else { 280 return snprintf(str, strlen, 281 ": (path #%d out of %d: portguid %s)", 282 lid - base_port_lid + 1, 283 last_port_lid - base_port_lid + 1, 284 mad_dump_val(IB_NODE_PORT_GUID_F, sguid, 285 sizeof sguid, &portguid)); 286 } 287 } 288 289 if (!valid) 290 return snprintf(str, strlen, ": (illegal port)"); 291 292 portguid = 0; 293 lidport.lid = lid; 294 295 if (!smp_query_via(nd, &lidport, IB_ATTR_NODE_DESC, 0, 100, srcport) || 296 !smp_query_via(pi, &lidport, IB_ATTR_PORT_INFO, 0, 100, srcport) || 297 !smp_query_via(ni, &lidport, IB_ATTR_NODE_INFO, 0, 100, srcport)) 298 return snprintf(str, strlen, ": (unknown node and type)"); 299 300 mad_decode_field(ni, IB_NODE_GUID_F, &nodeguid); 301 mad_decode_field(ni, IB_NODE_PORT_GUID_F, &portguid); 302 mad_decode_field(ni, IB_NODE_TYPE_F, &type); 303 304 mad_decode_field(pi, IB_PORT_LID_F, &baselid); 305 mad_decode_field(pi, IB_PORT_LMC_F, &lmc); 306 307 if (lmc > 0) { 308 base_port_lid = baselid; 309 last_port_lid = baselid + (1 << lmc) - 1; 310 } 311 312 mapnd = remap_node_name(node_name_map, nodeguid, nd); 313 314 rc = snprintf(str, strlen, ": (%s portguid %s: '%s')", 315 mad_dump_val(IB_NODE_TYPE_F, ntype, sizeof ntype, 316 &type), mad_dump_val(IB_NODE_PORT_GUID_F, 317 sguid, sizeof sguid, 318 &portguid), 319 mapnd); 320 321 free(mapnd); 322 return rc; 323 } 324 325 char *dump_unicast_tables(ib_portid_t * portid, int startlid, int endlid) 326 { 327 char lft[IB_SMP_DATA_SIZE] = { 0 }; 328 char nd[IB_SMP_DATA_SIZE] = { 0 }; 329 uint8_t sw[IB_SMP_DATA_SIZE] = { 0 }; 330 char str[200], *s; 331 uint64_t nodeguid; 332 int block, i, e, top; 333 unsigned nports; 334 int n = 0, startblock, endblock; 335 char *mapnd = NULL; 336 337 if ((s = check_switch(portid, &nports, &nodeguid, sw, nd))) 338 return s; 339 340 mad_decode_field(sw, IB_SW_LINEAR_FDB_TOP_F, &top); 341 342 if (!endlid || endlid > top) 343 endlid = top; 344 345 if (endlid > IB_MAX_UCAST_LID) { 346 IBWARN("illegal lft top %d, truncate to %d", endlid, 347 IB_MAX_UCAST_LID); 348 endlid = IB_MAX_UCAST_LID; 349 } 350 351 mapnd = remap_node_name(node_name_map, nodeguid, nd); 352 353 printf("Unicast lids [0x%x-0x%x] of switch %s guid 0x%016" PRIx64 354 " (%s):\n", startlid, endlid, portid2str(portid), nodeguid, 355 mapnd); 356 357 free(mapnd); 358 359 DEBUG("Switch top is 0x%x\n", top); 360 361 printf(" Lid Out Destination\n"); 362 printf(" Port Info \n"); 363 startblock = startlid / IB_SMP_DATA_SIZE; 364 endblock = ALIGN(endlid, IB_SMP_DATA_SIZE) / IB_SMP_DATA_SIZE; 365 for (block = startblock; block < endblock; block++) { 366 int status; 367 DEBUG("reading block %d", block); 368 if (!smp_query_status_via(lft, portid, IB_ATTR_LINEARFORWTBL, block, 369 0, &status, srcport)) { 370 fprintf(stderr, "SubnGet() failed" 371 "; MAD status 0x%x AM 0x%x\n", 372 status, block); 373 return NULL; 374 } 375 i = block * IB_SMP_DATA_SIZE; 376 e = i + IB_SMP_DATA_SIZE; 377 if (i < startlid) 378 i = startlid; 379 if (e > endlid + 1) 380 e = endlid + 1; 381 382 for (; i < e; i++) { 383 unsigned outport = lft[i % IB_SMP_DATA_SIZE]; 384 unsigned valid = (outport <= nports); 385 386 if (!valid && !dump_all) 387 continue; 388 dump_lid(str, sizeof str, i, valid); 389 printf("0x%04x %03u %s\n", i, outport & 0xff, str); 390 n++; 391 } 392 } 393 394 printf("%d %slids dumped \n", n, dump_all ? "" : "valid "); 395 return 0; 396 } 397 398 static int process_opt(void *context, int ch, char *optarg) 399 { 400 switch (ch) { 401 case 'a': 402 dump_all++; 403 break; 404 case 'M': 405 multicast++; 406 break; 407 case 'n': 408 brief++; 409 break; 410 case 1: 411 node_name_map_file = strdup(optarg); 412 break; 413 default: 414 return -1; 415 } 416 return 0; 417 } 418 419 int main(int argc, char **argv) 420 { 421 int mgmt_classes[3] = 422 { IB_SMI_CLASS, IB_SMI_DIRECT_CLASS, IB_SA_CLASS }; 423 ib_portid_t portid = { 0 }; 424 unsigned startlid = 0, endlid = 0; 425 char *err; 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 "4\t# dump all lids with valid out ports of switch with lid 4", 439 "-a 4\t# same, but dump all lids, even with invalid out ports", 440 "-n 4\t# simple dump format - no destination resolving", 441 "4 10\t# dump lids starting from 10", 442 "4 0x10 0x20\t# dump lid range", 443 "-G 0x08f1040023\t# resolve switch by GUID", 444 "-D 0,1\t# resolve switch by direct path", 445 " -- Multicast examples:", 446 "-M 4\t# dump all non empty mlids of switch with lid 4", 447 "-M 4 0xc010 0xc020\t# same, but with range", 448 "-M -n 4\t# simple dump format", 449 NULL, 450 }; 451 452 ibdiag_process_opts(argc, argv, NULL, "K", opts, process_opt, 453 usage_args, usage_examples); 454 455 argc -= optind; 456 argv += optind; 457 458 if (!argc) 459 ibdiag_show_usage(); 460 461 if (argc > 1) 462 startlid = strtoul(argv[1], 0, 0); 463 if (argc > 2) 464 endlid = strtoul(argv[2], 0, 0); 465 466 node_name_map = open_node_name_map(node_name_map_file); 467 468 srcport = mad_rpc_open_port(ibd_ca, ibd_ca_port, mgmt_classes, 3); 469 if (!srcport) 470 IBEXIT("Failed to open '%s' port '%d'", ibd_ca, ibd_ca_port); 471 472 smp_mkey_set(srcport, ibd_mkey); 473 474 if (resolve_portid_str(ibd_ca, ibd_ca_port, &portid, argv[0], 475 ibd_dest_type, ibd_sm_id, srcport) < 0) 476 IBEXIT("can't resolve destination port %s", argv[0]); 477 478 if (multicast) 479 err = dump_multicast_tables(&portid, startlid, endlid); 480 else 481 err = dump_unicast_tables(&portid, startlid, endlid); 482 483 if (err) 484 IBEXIT("dump tables: %s", err); 485 486 mad_rpc_close_port(srcport); 487 close_node_name_map(node_name_map); 488 exit(0); 489 } 490