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 DEBUG("Switch top is 0x%x\n", top); 358 359 printf(" Lid Out Destination\n"); 360 printf(" Port Info \n"); 361 startblock = startlid / IB_SMP_DATA_SIZE; 362 endblock = ALIGN(endlid, IB_SMP_DATA_SIZE) / IB_SMP_DATA_SIZE; 363 for (block = startblock; block < endblock; block++) { 364 int status; 365 DEBUG("reading block %d", block); 366 if (!smp_query_status_via(lft, portid, IB_ATTR_LINEARFORWTBL, block, 367 0, &status, srcport)) { 368 fprintf(stderr, "SubnGet() failed" 369 "; MAD status 0x%x AM 0x%x\n", 370 status, block); 371 return NULL; 372 } 373 i = block * IB_SMP_DATA_SIZE; 374 e = i + IB_SMP_DATA_SIZE; 375 if (i < startlid) 376 i = startlid; 377 if (e > endlid + 1) 378 e = endlid + 1; 379 380 for (; i < e; i++) { 381 unsigned outport = lft[i % IB_SMP_DATA_SIZE]; 382 unsigned valid = (outport <= nports); 383 384 if (!valid && !dump_all) 385 continue; 386 dump_lid(str, sizeof str, i, valid); 387 printf("0x%04x %03u %s\n", i, outport & 0xff, str); 388 n++; 389 } 390 } 391 392 printf("%d %slids dumped \n", n, dump_all ? "" : "valid "); 393 free(mapnd); 394 return 0; 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 mgmt_classes[3] = 421 { IB_SMI_CLASS, IB_SMI_DIRECT_CLASS, IB_SA_CLASS }; 422 ib_portid_t portid = { 0 }; 423 unsigned startlid = 0, endlid = 0; 424 char *err; 425 426 const struct ibdiag_opt opts[] = { 427 {"all", 'a', 0, NULL, "show all lids, even invalid entries"}, 428 {"no_dests", 'n', 0, NULL, 429 "do not try to resolve destinations"}, 430 {"Multicast", 'M', 0, NULL, "show multicast forwarding tables"}, 431 {"node-name-map", 1, 1, "<file>", "node name map file"}, 432 {0} 433 }; 434 char usage_args[] = "[<dest dr_path|lid|guid> [<startlid> [<endlid>]]]"; 435 const char *usage_examples[] = { 436 " -- Unicast examples:", 437 "4\t# dump all lids with valid out ports of switch with lid 4", 438 "-a 4\t# same, but dump all lids, even with invalid out ports", 439 "-n 4\t# simple dump format - no destination resolving", 440 "4 10\t# dump lids starting from 10", 441 "4 0x10 0x20\t# dump lid range", 442 "-G 0x08f1040023\t# resolve switch by GUID", 443 "-D 0,1\t# resolve switch by direct path", 444 " -- Multicast examples:", 445 "-M 4\t# dump all non empty mlids of switch with lid 4", 446 "-M 4 0xc010 0xc020\t# same, but with range", 447 "-M -n 4\t# simple dump format", 448 NULL, 449 }; 450 451 ibdiag_process_opts(argc, argv, NULL, "K", opts, process_opt, 452 usage_args, usage_examples); 453 454 argc -= optind; 455 argv += optind; 456 457 if (!argc) 458 ibdiag_show_usage(); 459 460 if (argc > 1) 461 startlid = strtoul(argv[1], 0, 0); 462 if (argc > 2) 463 endlid = strtoul(argv[2], 0, 0); 464 465 node_name_map = open_node_name_map(node_name_map_file); 466 467 srcport = mad_rpc_open_port(ibd_ca, ibd_ca_port, mgmt_classes, 3); 468 if (!srcport) 469 IBEXIT("Failed to open '%s' port '%d'", ibd_ca, ibd_ca_port); 470 471 smp_mkey_set(srcport, ibd_mkey); 472 473 if (resolve_portid_str(ibd_ca, ibd_ca_port, &portid, argv[0], 474 ibd_dest_type, ibd_sm_id, srcport) < 0) 475 IBEXIT("can't resolve destination port %s", argv[0]); 476 477 if (multicast) 478 err = dump_multicast_tables(&portid, startlid, endlid); 479 else 480 err = dump_unicast_tables(&portid, startlid, endlid); 481 482 if (err) 483 IBEXIT("dump tables: %s", err); 484 485 mad_rpc_close_port(srcport); 486 close_node_name_map(node_name_map); 487 exit(0); 488 } 489