1218792Snp/* 2218792Snp * Copyright (c) 2004-2009 Voltaire Inc. All rights reserved. 3218792Snp * Copyright (c) 2009-2011 Mellanox Technologies LTD. All rights reserved. 4218792Snp * 5218792Snp * This software is available to you under a choice of one of two 6218792Snp * licenses. You may choose to be licensed under the terms of the GNU 7218792Snp * General Public License (GPL) Version 2, available from the file 8218792Snp * COPYING in the main directory of this source tree, or the 9218792Snp * OpenIB.org BSD license below: 10218792Snp * 11218792Snp * Redistribution and use in source and binary forms, with or 12218792Snp * without modification, are permitted provided that the following 13218792Snp * conditions are met: 14218792Snp * 15218792Snp * - Redistributions of source code must retain the above 16218792Snp * copyright notice, this list of conditions and the following 17218792Snp * disclaimer. 18218792Snp * 19218792Snp * - Redistributions in binary form must reproduce the above 20218792Snp * copyright notice, this list of conditions and the following 21218792Snp * disclaimer in the documentation and/or other materials 22218792Snp * provided with the distribution. 23218792Snp * 24218792Snp * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 25218792Snp * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26218792Snp * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 27218792Snp * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 28218792Snp * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 29218792Snp * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 30218792Snp * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31218792Snp * SOFTWARE. 32218792Snp * 33218792Snp */ 34218792Snp 35218792Snp#if HAVE_CONFIG_H 36218792Snp# include <config.h> 37218792Snp#endif /* HAVE_CONFIG_H */ 38218792Snp 39219286Snp#include <stdio.h> 40219286Snp#include <stdlib.h> 41219286Snp#include <unistd.h> 42218792Snp#include <string.h> 43218792Snp#include <inttypes.h> 44218792Snp#include <getopt.h> 45218792Snp#include <netinet/in.h> 46218792Snp 47219436Snp#include <infiniband/umad.h> 48218792Snp#include <infiniband/mad.h> 49218792Snp#include <complib/cl_nodenamemap.h> 50218792Snp 51218792Snp#include "ibdiag_common.h" 52218792Snp 53218792Snpstruct ibmad_port *srcport; 54218792Snp 55218792Snpstatic int brief, dump_all, multicast; 56222003Snp 57218792Snpstatic char *node_name_map_file = NULL; 58218792Snpstatic nn_map_t *node_name_map = NULL; 59221474Snp 60218792Snp/*******************************************/ 61218792Snp 62218792Snpchar *check_switch(ib_portid_t * portid, unsigned int *nports, uint64_t * guid, 63222509Snp uint8_t * sw, char *nd) 64218792Snp{ 65218792Snp uint8_t ni[IB_SMP_DATA_SIZE] = { 0 }; 66218792Snp int type; 67218792Snp 68218792Snp DEBUG("checking node type"); 69218792Snp if (!smp_query_via(ni, portid, IB_ATTR_NODE_INFO, 0, 0, srcport)) { 70218792Snp xdump(stderr, "nodeinfo\n", ni, sizeof ni); 71218792Snp return "node info failed: valid addr?"; 72218792Snp } 73218792Snp 74227843Smarius if (!smp_query_via(nd, portid, IB_ATTR_NODE_DESC, 0, 0, srcport)) 75218792Snp return "node desc failed"; 76218792Snp 77218792Snp mad_decode_field(ni, IB_NODE_TYPE_F, &type); 78218792Snp if (type != IB_NODE_SWITCH) 79218792Snp return "not a switch"; 80218792Snp 81218792Snp DEBUG("Gathering information about switch"); 82218792Snp mad_decode_field(ni, IB_NODE_NPORTS_F, nports); 83218792Snp mad_decode_field(ni, IB_NODE_GUID_F, guid); 84218792Snp 85218792Snp if (!smp_query_via(sw, portid, IB_ATTR_SWITCH_INFO, 0, 0, srcport)) 86218792Snp return "switch info failed: is a switch node?"; 87218792Snp 88218792Snp return 0; 89218792Snp} 90218792Snp 91218792Snp#define IB_MLIDS_IN_BLOCK (IB_SMP_DATA_SIZE/2) 92218792Snp 93218792Snpint dump_mlid(char *str, int strlen, unsigned mlid, unsigned nports, 94218792Snp uint16_t mft[16][IB_MLIDS_IN_BLOCK]) 95218792Snp{ 96218792Snp uint16_t mask; 97218792Snp unsigned i, chunk, bit, nonzero = 0; 98218792Snp 99218792Snp if (brief) { 100218792Snp int n = 0; 101218792Snp unsigned chunks = ALIGN(nports + 1, 16) / 16; 102218792Snp for (i = 0; i < chunks; i++) { 103218792Snp mask = ntohs(mft[i][mlid % IB_MLIDS_IN_BLOCK]); 104218792Snp if (mask) 105218792Snp nonzero++; 106218792Snp n += snprintf(str + n, strlen - n, "%04hx", mask); 107218792Snp if (n >= strlen) { 108218792Snp n = strlen; 109218792Snp break; 110218792Snp } 111218792Snp } 112218792Snp if (!nonzero && !dump_all) { 113218792Snp str[0] = 0; 114218792Snp return 0; 115218792Snp } 116218792Snp return n; 117218792Snp } 118218792Snp for (i = 0; i <= nports; i++) { 119218792Snp chunk = i / 16; 120218792Snp bit = i % 16; 121218792Snp 122218792Snp mask = ntohs(mft[chunk][mlid % IB_MLIDS_IN_BLOCK]); 123228561Snp if (mask) 124228561Snp nonzero++; 125228561Snp str[i * 2] = (mask & (1 << bit)) ? 'x' : ' '; 126228561Snp str[i * 2 + 1] = ' '; 127228561Snp } 128228561Snp if (!nonzero && !dump_all) { 129218792Snp str[0] = 0; 130218792Snp return 0; 131228561Snp } 132218792Snp str[i * 2] = 0; 133218792Snp return i * 2; 134218792Snp} 135228561Snp 136218792Snpuint16_t mft[16][IB_MLIDS_IN_BLOCK] = { { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0}, { 0 }, { 0 } }; 137228561Snp 138228561Snpchar *dump_multicast_tables(ib_portid_t * portid, unsigned startlid, 139228561Snp unsigned endlid) 140218792Snp{ 141228561Snp char nd[IB_SMP_DATA_SIZE] = { 0 }; 142228561Snp uint8_t sw[IB_SMP_DATA_SIZE] = { 0 }; 143228561Snp char str[512]; 144218792Snp char *s; 145228561Snp uint64_t nodeguid; 146228561Snp uint32_t mod; 147228561Snp unsigned block, i, j, e, nports, cap, chunks, startblock, lastblock, 148218792Snp top; 149228561Snp char *mapnd = NULL; 150228561Snp int n = 0; 151228561Snp 152218792Snp if ((s = check_switch(portid, &nports, &nodeguid, sw, nd))) 153228561Snp return s; 154228561Snp 155228561Snp mad_decode_field(sw, IB_SW_MCAST_FDB_CAP_F, &cap); 156228561Snp mad_decode_field(sw, IB_SW_MCAST_FDB_TOP_F, &top); 157228561Snp 158228561Snp if (!endlid || endlid > IB_MIN_MCAST_LID + cap - 1) 159228561Snp endlid = IB_MIN_MCAST_LID + cap - 1; 160228561Snp if (!dump_all && top && top < endlid) { 161228561Snp if (top < IB_MIN_MCAST_LID - 1) 162228561Snp IBWARN("illegal top mlid %x", top); 163228561Snp else 164228561Snp endlid = top; 165228561Snp } 166228561Snp 167228561Snp if (!startlid) 168228561Snp startlid = IB_MIN_MCAST_LID; 169228561Snp else if (startlid < IB_MIN_MCAST_LID) { 170228561Snp IBWARN("illegal start mlid %x, set to %x", startlid, 171218792Snp IB_MIN_MCAST_LID); 172218792Snp startlid = IB_MIN_MCAST_LID; 173218792Snp } 174228561Snp 175228561Snp if (endlid > IB_MAX_MCAST_LID) { 176228561Snp IBWARN("illegal end mlid %x, truncate to %x", endlid, 177218792Snp IB_MAX_MCAST_LID); 178228561Snp endlid = IB_MAX_MCAST_LID; 179228561Snp } 180228561Snp 181218792Snp mapnd = remap_node_name(node_name_map, nodeguid, nd); 182228561Snp 183228561Snp printf("Multicast mlids [0x%x-0x%x] of switch %s guid 0x%016" PRIx64 184228561Snp " (%s):\n", startlid, endlid, portid2str(portid), nodeguid, 185218792Snp mapnd); 186228561Snp 187228561Snp if (brief) 188228561Snp printf(" MLid Port Mask\n"); 189218792Snp else { 190218792Snp if (nports > 9) { 191218792Snp for (i = 0, s = str; i <= nports; i++) { 192218792Snp *s++ = (i % 10) ? ' ' : '0' + i / 10; 193228561Snp *s++ = ' '; 194228561Snp } 195218792Snp *s = 0; 196228561Snp printf(" %s\n", str); 197228561Snp } 198218792Snp for (i = 0, s = str; i <= nports; i++) 199218792Snp s += sprintf(s, "%d ", i % 10); 200228561Snp printf(" Ports: %s\n", str); 201218792Snp printf(" MLid\n"); 202228561Snp } 203228561Snp if (ibverbose) 204218792Snp printf("Switch multicast mlid capability is %d top is 0x%x\n", 205218792Snp cap, top); 206228561Snp 207218792Snp chunks = ALIGN(nports + 1, 16) / 16; 208228561Snp 209228561Snp startblock = startlid / IB_MLIDS_IN_BLOCK; 210218792Snp lastblock = endlid / IB_MLIDS_IN_BLOCK; 211228561Snp for (block = startblock; block <= lastblock; block++) { 212228561Snp for (j = 0; j < chunks; j++) { 213228561Snp int status; 214228561Snp mod = (block - IB_MIN_MCAST_LID / IB_MLIDS_IN_BLOCK) 215228561Snp | (j << 28); 216228561Snp 217221474Snp DEBUG("reading block %x chunk %d mod %x", block, j, 218228561Snp mod); 219228561Snp if (!smp_query_status_via 220228561Snp (mft + j, portid, IB_ATTR_MULTICASTFORWTBL, mod, 0, 221228561Snp &status, srcport)) { 222228561Snp fprintf(stderr, "SubnGet() failed" 223228561Snp "; MAD status 0x%x AM 0x%x\n", 224228561Snp status, mod); 225228561Snp free(mapnd); 226228561Snp return NULL; 227228561Snp } 228228561Snp } 229228561Snp 230228561Snp i = block * IB_MLIDS_IN_BLOCK; 231228561Snp e = i + IB_MLIDS_IN_BLOCK; 232228561Snp if (i < startlid) 233218792Snp i = startlid; 234219944Snp if (e > endlid + 1) 235218792Snp e = endlid + 1; 236228561Snp 237218792Snp for (; i < e; i++) { 238218792Snp if (dump_mlid(str, sizeof str, i, nports, mft) == 0) 239218792Snp continue; 240218792Snp printf("0x%04x %s\n", i, str); 241228561Snp n++; 242228561Snp } 243228561Snp } 244228561Snp 245228561Snp printf("%d %smlids dumped \n", n, dump_all ? "" : "valid "); 246228561Snp 247218792Snp free(mapnd); 248218792Snp return 0; 249221474Snp} 250221474Snp 251221474Snpint dump_lid(char *str, int strlen, int lid, int valid) 252221474Snp{ 253221474Snp char nd[IB_SMP_DATA_SIZE] = { 0 }; 254222509Snp uint8_t ni[IB_SMP_DATA_SIZE] = { 0 }; 255221474Snp uint8_t pi[IB_SMP_DATA_SIZE] = { 0 }; 256221474Snp ib_portid_t lidport = { 0 }; 257221474Snp static int last_port_lid, base_port_lid; 258221474Snp char ntype[50], sguid[30]; 259218792Snp static uint64_t portguid; 260218792Snp uint64_t nodeguid; 261218792Snp int baselid, lmc, type; 262218792Snp char *mapnd = NULL; 263218792Snp int rc; 264218792Snp 265218792Snp if (brief) { 266218792Snp str[0] = 0; 267218792Snp return 0; 268218792Snp } 269218792Snp 270218792Snp if (lid <= last_port_lid) { 271218792Snp if (!valid) 272218792Snp return snprintf(str, strlen, 273218792Snp ": (path #%d - illegal port)", 274218792Snp lid - base_port_lid); 275228561Snp else if (!portguid) 276228561Snp return snprintf(str, strlen, 277228561Snp ": (path #%d out of %d)", 278228561Snp lid - base_port_lid + 1, 279228561Snp last_port_lid - base_port_lid + 1); 280218792Snp else { 281218792Snp return snprintf(str, strlen, 282218792Snp ": (path #%d out of %d: portguid %s)", 283218792Snp lid - base_port_lid + 1, 284218792Snp last_port_lid - base_port_lid + 1, 285218792Snp mad_dump_val(IB_NODE_PORT_GUID_F, sguid, 286218792Snp sizeof sguid, &portguid)); 287228561Snp } 288228561Snp } 289228561Snp 290228561Snp if (!valid) 291228561Snp return snprintf(str, strlen, ": (illegal port)"); 292228561Snp 293228561Snp portguid = 0; 294218792Snp lidport.lid = lid; 295228561Snp 296218792Snp if (!smp_query_via(nd, &lidport, IB_ATTR_NODE_DESC, 0, 100, srcport) || 297218792Snp !smp_query_via(pi, &lidport, IB_ATTR_PORT_INFO, 0, 100, srcport) || 298218792Snp !smp_query_via(ni, &lidport, IB_ATTR_NODE_INFO, 0, 100, srcport)) 299218792Snp return snprintf(str, strlen, ": (unknown node and type)"); 300218792Snp 301228561Snp mad_decode_field(ni, IB_NODE_GUID_F, &nodeguid); 302228561Snp mad_decode_field(ni, IB_NODE_PORT_GUID_F, &portguid); 303218792Snp mad_decode_field(ni, IB_NODE_TYPE_F, &type); 304218792Snp 305219436Snp mad_decode_field(pi, IB_PORT_LID_F, &baselid); 306228561Snp mad_decode_field(pi, IB_PORT_LMC_F, &lmc); 307218792Snp 308218792Snp if (lmc > 0) { 309218792Snp base_port_lid = baselid; 310218792Snp last_port_lid = baselid + (1 << lmc) - 1; 311218792Snp } 312228561Snp 313228561Snp mapnd = remap_node_name(node_name_map, nodeguid, nd); 314228561Snp 315222551Snp rc = snprintf(str, strlen, ": (%s portguid %s: '%s')", 316228561Snp mad_dump_val(IB_NODE_TYPE_F, ntype, sizeof ntype, 317228561Snp &type), mad_dump_val(IB_NODE_PORT_GUID_F, 318228561Snp sguid, sizeof sguid, 319228561Snp &portguid), 320228561Snp mapnd); 321228561Snp 322228561Snp free(mapnd); 323228561Snp return rc; 324228561Snp} 325228561Snp 326228561Snpchar *dump_unicast_tables(ib_portid_t * portid, int startlid, int endlid) 327219286Snp{ 328221474Snp char lft[IB_SMP_DATA_SIZE] = { 0 }; 329221474Snp char nd[IB_SMP_DATA_SIZE] = { 0 }; 330221474Snp uint8_t sw[IB_SMP_DATA_SIZE] = { 0 }; 331221474Snp char str[200], *s; 332221474Snp uint64_t nodeguid; 333222552Snp int block, i, e, top; 334221474Snp unsigned nports; 335221474Snp int n = 0, startblock, endblock; 336221474Snp char *mapnd = NULL; 337222509Snp 338221474Snp if ((s = check_switch(portid, &nports, &nodeguid, sw, nd))) 339221474Snp return s; 340228561Snp 341228561Snp mad_decode_field(sw, IB_SW_LINEAR_FDB_TOP_F, &top); 342222973Snp 343228561Snp if (!endlid || endlid > top) 344228561Snp endlid = top; 345228561Snp 346228561Snp if (endlid > IB_MAX_UCAST_LID) { 347228561Snp IBWARN("illegal lft top %d, truncate to %d", endlid, 348228561Snp IB_MAX_UCAST_LID); 349219392Snp endlid = IB_MAX_UCAST_LID; 350218792Snp } 351218792Snp 352218792Snp mapnd = remap_node_name(node_name_map, nodeguid, nd); 353218792Snp 354218792Snp printf("Unicast lids [0x%x-0x%x] of switch %s guid 0x%016" PRIx64 355218792Snp " (%s):\n", startlid, endlid, portid2str(portid), nodeguid, 356218792Snp mapnd); 357218792Snp 358218792Snp free(mapnd); 359218792Snp 360218792Snp DEBUG("Switch top is 0x%x\n", top); 361218792Snp 362218792Snp printf(" Lid Out Destination\n"); 363218792Snp printf(" Port Info \n"); 364218792Snp startblock = startlid / IB_SMP_DATA_SIZE; 365218792Snp endblock = ALIGN(endlid, IB_SMP_DATA_SIZE) / IB_SMP_DATA_SIZE; 366218792Snp for (block = startblock; block < endblock; block++) { 367218792Snp int status; 368218792Snp DEBUG("reading block %d", block); 369218792Snp if (!smp_query_status_via(lft, portid, IB_ATTR_LINEARFORWTBL, block, 370228561Snp 0, &status, srcport)) { 371228561Snp fprintf(stderr, "SubnGet() failed" 372228561Snp "; MAD status 0x%x AM 0x%x\n", 373228561Snp status, block); 374228561Snp return NULL; 375218792Snp } 376218792Snp i = block * IB_SMP_DATA_SIZE; 377218792Snp e = i + IB_SMP_DATA_SIZE; 378218792Snp if (i < startlid) 379218792Snp i = startlid; 380218792Snp if (e > endlid + 1) 381218792Snp e = endlid + 1; 382218792Snp 383218792Snp for (; i < e; i++) { 384218792Snp unsigned outport = lft[i % IB_SMP_DATA_SIZE]; 385218792Snp unsigned valid = (outport <= nports); 386218792Snp 387218792Snp if (!valid && !dump_all) 388218792Snp continue; 389218792Snp dump_lid(str, sizeof str, i, valid); 390218792Snp printf("0x%04x %03u %s\n", i, outport & 0xff, str); 391218792Snp n++; 392218792Snp } 393218792Snp } 394218792Snp 395218792Snp printf("%d %slids dumped \n", n, dump_all ? "" : "valid "); 396218792Snp return 0; 397218792Snp} 398218792Snp 399218792Snpstatic int process_opt(void *context, int ch, char *optarg) 400218792Snp{ 401218792Snp switch (ch) { 402218792Snp case 'a': 403228561Snp dump_all++; 404228561Snp break; 405228561Snp case 'M': 406218792Snp multicast++; 407218792Snp break; 408218792Snp case 'n': 409218792Snp brief++; 410218792Snp break; 411218792Snp case 1: 412218792Snp node_name_map_file = strdup(optarg); 413222085Snp break; 414228561Snp default: 415228561Snp return -1; 416222085Snp } 417222085Snp return 0; 418222085Snp} 419222085Snp 420222085Snpint main(int argc, char **argv) 421222085Snp{ 422218792Snp int mgmt_classes[3] = 423218792Snp { IB_SMI_CLASS, IB_SMI_DIRECT_CLASS, IB_SA_CLASS }; 424218792Snp ib_portid_t portid = { 0 }; 425228561Snp unsigned startlid = 0, endlid = 0; 426228561Snp char *err; 427228561Snp 428218792Snp const struct ibdiag_opt opts[] = { 429228561Snp {"all", 'a', 0, NULL, "show all lids, even invalid entries"}, 430228561Snp {"no_dests", 'n', 0, NULL, 431228561Snp "do not try to resolve destinations"}, 432228561Snp {"Multicast", 'M', 0, NULL, "show multicast forwarding tables"}, 433218792Snp {"node-name-map", 1, 1, "<file>", "node name map file"}, 434218792Snp {0} 435218792Snp }; 436218792Snp char usage_args[] = "[<dest dr_path|lid|guid> [<startlid> [<endlid>]]]"; 437218792Snp const char *usage_examples[] = { 438228561Snp " -- Unicast examples:", 439228561Snp "4\t# dump all lids with valid out ports of switch with lid 4", 440228561Snp "-a 4\t# same, but dump all lids, even with invalid out ports", 441218792Snp "-n 4\t# simple dump format - no destination resolving", 442218792Snp "4 10\t# dump lids starting from 10", 443218792Snp "4 0x10 0x20\t# dump lid range", 444218792Snp "-G 0x08f1040023\t# resolve switch by GUID", 445218792Snp "-D 0,1\t# resolve switch by direct path", 446218792Snp " -- Multicast examples:", 447218792Snp "-M 4\t# dump all non empty mlids of switch with lid 4", 448218792Snp "-M 4 0xc010 0xc020\t# same, but with range", 449228561Snp "-M -n 4\t# simple dump format", 450228561Snp NULL, 451228561Snp }; 452228561Snp 453228561Snp ibdiag_process_opts(argc, argv, NULL, "K", opts, process_opt, 454228561Snp usage_args, usage_examples); 455218792Snp 456218792Snp argc -= optind; 457218792Snp argv += optind; 458218792Snp 459228561Snp if (!argc) 460228561Snp ibdiag_show_usage(); 461228561Snp 462228561Snp if (argc > 1) 463228561Snp startlid = strtoul(argv[1], 0, 0); 464228561Snp if (argc > 2) 465218792Snp endlid = strtoul(argv[2], 0, 0); 466218792Snp 467218792Snp node_name_map = open_node_name_map(node_name_map_file); 468218792Snp 469218792Snp srcport = mad_rpc_open_port(ibd_ca, ibd_ca_port, mgmt_classes, 3); 470228561Snp if (!srcport) 471228561Snp IBEXIT("Failed to open '%s' port '%d'", ibd_ca, ibd_ca_port); 472228561Snp 473222551Snp smp_mkey_set(srcport, ibd_mkey); 474228561Snp 475228561Snp if (resolve_portid_str(ibd_ca, ibd_ca_port, &portid, argv[0], 476228561Snp ibd_dest_type, ibd_sm_id, srcport) < 0) 477218792Snp IBEXIT("can't resolve destination port %s", argv[0]); 478228561Snp 479228561Snp if (multicast) 480228561Snp err = dump_multicast_tables(&portid, startlid, endlid); 481228561Snp else 482228561Snp err = dump_unicast_tables(&portid, startlid, endlid); 483228561Snp 484228561Snp if (err) 485218792Snp IBEXIT("dump tables: %s", err); 486218792Snp 487228561Snp mad_rpc_close_port(srcport); 488228561Snp close_node_name_map(node_name_map); 489228561Snp exit(0); 490218792Snp} 491228561Snp