1/* 2 * Copyright (c) 2004-2008 Voltaire Inc. All rights reserved. 3 * 4 * This software is available to you under a choice of one of two 5 * licenses. You may choose to be licensed under the terms of the GNU 6 * General Public License (GPL) Version 2, available from the file 7 * COPYING in the main directory of this source tree, or the 8 * OpenIB.org BSD license below: 9 * 10 * Redistribution and use in source and binary forms, with or 11 * without modification, are permitted provided that the following 12 * conditions are met: 13 * 14 * - Redistributions of source code must retain the above 15 * copyright notice, this list of conditions and the following 16 * disclaimer. 17 * 18 * - Redistributions in binary form must reproduce the above 19 * copyright notice, this list of conditions and the following 20 * disclaimer in the documentation and/or other materials 21 * provided with the distribution. 22 * 23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 * SOFTWARE. 31 * 32 */ 33 34#if HAVE_CONFIG_H 35# include <config.h> 36#endif /* HAVE_CONFIG_H */ 37 38#include <stdio.h> 39#include <stdlib.h> 40#include <unistd.h> 41#include <stdarg.h> 42#include <time.h> 43#include <string.h> 44#include <getopt.h> 45#include <netinet/in.h> 46 47#define __STDC_FORMAT_MACROS 48#include <inttypes.h> 49 50#include <infiniband/common.h> 51#include <infiniband/umad.h> 52#include <infiniband/mad.h> 53#include <infiniband/complib/cl_nodenamemap.h> 54 55#include "ibdiag_common.h" 56 57#undef DEBUG 58#define DEBUG if (verbose>1) IBWARN 59 60static int dest_type = IB_DEST_LID; 61static int verbose; 62 63typedef char *(op_fn_t)(ib_portid_t *dest, char **argv, int argc); 64 65typedef struct match_rec { 66 char *name; 67 op_fn_t *fn; 68 unsigned opt_portnum; 69} match_rec_t; 70 71static op_fn_t node_desc, node_info, port_info, switch_info, pkey_table, 72 sl2vl_table, vlarb_table, guid_info; 73 74static const match_rec_t match_tbl[] = { 75 { "nodeinfo", node_info }, 76 { "nodedesc", node_desc }, 77 { "portinfo", port_info, 1 }, 78 { "switchinfo", switch_info }, 79 { "pkeys", pkey_table, 1 }, 80 { "sl2vl", sl2vl_table, 1 }, 81 { "vlarb", vlarb_table, 1 }, 82 { "guids", guid_info }, 83 {0} 84}; 85 86char *argv0 = "smpquery"; 87static char *node_name_map_file = NULL; 88static nn_map_t *node_name_map = NULL; 89 90/*******************************************/ 91static char * 92node_desc(ib_portid_t *dest, char **argv, int argc) 93{ 94 int node_type, l; 95 uint64_t node_guid; 96 char nd[IB_SMP_DATA_SIZE]; 97 uint8_t data[IB_SMP_DATA_SIZE]; 98 char dots[128]; 99 char *nodename = NULL; 100 101 if (!smp_query(data, dest, IB_ATTR_NODE_INFO, 0, 0)) 102 return "node info query failed"; 103 104 mad_decode_field(data, IB_NODE_TYPE_F, &node_type); 105 mad_decode_field(data, IB_NODE_GUID_F, &node_guid); 106 107 if (!smp_query(nd, dest, IB_ATTR_NODE_DESC, 0, 0)) 108 return "node desc query failed"; 109 110 nodename = remap_node_name(node_name_map, node_guid, nd); 111 112 l = strlen(nodename); 113 if (l < 32) { 114 memset(dots, '.', 32 - l); 115 dots[32 - l] = '\0'; 116 } else { 117 dots[0] = '.'; 118 dots[1] = '\0'; 119 } 120 121 printf("Node Description:%s%s\n", dots, nodename); 122 free(nodename); 123 return 0; 124} 125 126static char * 127node_info(ib_portid_t *dest, char **argv, int argc) 128{ 129 char buf[2048]; 130 char data[IB_SMP_DATA_SIZE]; 131 132 if (!smp_query(data, dest, IB_ATTR_NODE_INFO, 0, 0)) 133 return "node info query failed"; 134 135 mad_dump_nodeinfo(buf, sizeof buf, data, sizeof data); 136 137 printf("# Node info: %s\n%s", portid2str(dest), buf); 138 return 0; 139} 140 141static char * 142port_info(ib_portid_t *dest, char **argv, int argc) 143{ 144 char buf[2048]; 145 char data[IB_SMP_DATA_SIZE]; 146 int portnum = 0; 147 148 if (argc > 0) 149 portnum = strtol(argv[0], 0, 0); 150 151 if (!smp_query(data, dest, IB_ATTR_PORT_INFO, portnum, 0)) 152 return "port info query failed"; 153 154 mad_dump_portinfo(buf, sizeof buf, data, sizeof data); 155 156 printf("# Port info: %s port %d\n%s", portid2str(dest), portnum, buf); 157 return 0; 158} 159 160static char * 161switch_info(ib_portid_t *dest, char **argv, int argc) 162{ 163 char buf[2048]; 164 char data[IB_SMP_DATA_SIZE]; 165 166 if (!smp_query(data, dest, IB_ATTR_SWITCH_INFO, 0, 0)) 167 return "switch info query failed"; 168 169 mad_dump_switchinfo(buf, sizeof buf, data, sizeof data); 170 171 printf("# Switch info: %s\n%s", portid2str(dest), buf); 172 return 0; 173} 174 175static char * 176pkey_table(ib_portid_t *dest, char **argv, int argc) 177{ 178 uint8_t data[IB_SMP_DATA_SIZE]; 179 uint32_t i, j, k; 180 uint16_t *p; 181 unsigned mod; 182 int n, t, phy_ports; 183 int portnum = 0; 184 185 if (argc > 0) 186 portnum = strtol(argv[0], 0, 0); 187 188 /* Get the partition capacity */ 189 if (!smp_query(data, dest, IB_ATTR_NODE_INFO, 0, 0)) 190 return "node info query failed"; 191 192 mad_decode_field(data, IB_NODE_TYPE_F, &t); 193 mad_decode_field(data, IB_NODE_NPORTS_F, &phy_ports); 194 if (portnum > phy_ports) 195 return "invalid port number"; 196 197 if ((t == IB_NODE_SWITCH) && (portnum != 0)) { 198 if (!smp_query(data, dest, IB_ATTR_SWITCH_INFO, 0, 0)) 199 return "switch info failed"; 200 mad_decode_field(data, IB_SW_PARTITION_ENFORCE_CAP_F, &n); 201 } else 202 mad_decode_field(data, IB_NODE_PARTITION_CAP_F, &n); 203 204 for (i = 0; i < (n + 31) / 32; i++) { 205 mod = i | (portnum << 16); 206 if (!smp_query(data, dest, IB_ATTR_PKEY_TBL, mod, 0)) 207 return "pkey table query failed"; 208 if (i + 1 == (n + 31) / 32) 209 k = ((n + 7 - i * 32) / 8) * 8; 210 else 211 k = 32; 212 p = (uint16_t *) data; 213 for (j = 0; j < k; j += 8, p += 8) { 214 printf("%4u: 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x\n", 215 (i * 32) + j, 216 ntohs(p[0]), ntohs(p[1]), 217 ntohs(p[2]), ntohs(p[3]), 218 ntohs(p[4]), ntohs(p[5]), 219 ntohs(p[6]), ntohs(p[7])); 220 } 221 } 222 printf("%d pkeys capacity for this port\n", n); 223 224 return 0; 225} 226 227static char *sl2vl_dump_table_entry(ib_portid_t *dest, int in, int out) 228{ 229 char buf[2048]; 230 char data[IB_SMP_DATA_SIZE]; 231 int portnum = (in << 8) | out; 232 233 if (!smp_query(data, dest, IB_ATTR_SLVL_TABLE, portnum, 0)) 234 return "slvl query failed"; 235 236 mad_dump_sltovl(buf, sizeof buf, data, sizeof data); 237 printf("ports: in %2d, out %2d: ", in, out); 238 printf("%s", buf); 239 return 0; 240} 241 242static char * 243sl2vl_table(ib_portid_t *dest, char **argv, int argc) 244{ 245 uint8_t data[IB_SMP_DATA_SIZE]; 246 int type, num_ports, portnum = 0; 247 int i; 248 char *ret; 249 250 if (argc > 0) 251 portnum = strtol(argv[0], 0, 0); 252 253 if (!smp_query(data, dest, IB_ATTR_NODE_INFO, 0, 0)) 254 return "node info query failed"; 255 256 mad_decode_field(data, IB_NODE_TYPE_F, &type); 257 mad_decode_field(data, IB_NODE_NPORTS_F, &num_ports); 258 if (portnum > num_ports) 259 return "invalid port number"; 260 261 printf("# SL2VL table: %s\n", portid2str(dest)); 262 printf("# SL: |"); 263 for (i = 0 ; i < 16 ; i++) 264 printf("%2d|", i); 265 printf("\n"); 266 267 if (type != IB_NODE_SWITCH) 268 return sl2vl_dump_table_entry(dest, 0, 0); 269 270 for (i = 0 ; i <= num_ports ; i++) { 271 ret = sl2vl_dump_table_entry(dest, i, portnum); 272 if (ret) 273 return ret; 274 } 275 return 0; 276} 277 278static char *vlarb_dump_table_entry(ib_portid_t *dest, int portnum, int offset, unsigned cap) 279{ 280 char buf[2048]; 281 char data[IB_SMP_DATA_SIZE]; 282 283 if (!smp_query(data, dest, IB_ATTR_VL_ARBITRATION, 284 (offset << 16) | portnum, 0)) 285 return "vl arb query failed"; 286 mad_dump_vlarbitration(buf, sizeof(buf), data, cap * 2); 287 printf("%s", buf); 288 return 0; 289} 290 291static char *vlarb_dump_table(ib_portid_t *dest, int portnum, 292 char *name, int offset, int cap) 293{ 294 char *ret; 295 296 printf("# %s priority VL Arbitration Table:", name); 297 ret = vlarb_dump_table_entry(dest, portnum, offset, 298 cap < 32 ? cap : 32); 299 if (!ret && cap > 32) 300 ret = vlarb_dump_table_entry(dest, portnum, offset + 1, 301 cap - 32); 302 return ret; 303} 304 305static char * 306vlarb_table(ib_portid_t *dest, char **argv, int argc) 307{ 308 uint8_t data[IB_SMP_DATA_SIZE]; 309 int portnum = 0; 310 int type, enhsp0, lowcap, highcap; 311 char *ret = 0; 312 313 if (argc > 0) 314 portnum = strtol(argv[0], 0, 0); 315 316 /* port number of 0 could mean SP0 or port MAD arrives on */ 317 if (portnum == 0) { 318 if (!smp_query(data, dest, IB_ATTR_NODE_INFO, 0, 0)) 319 return "node info query failed"; 320 321 mad_decode_field(data, IB_NODE_TYPE_F, &type); 322 if (type == IB_NODE_SWITCH) { 323 if (!smp_query(data, dest, IB_ATTR_SWITCH_INFO, 0, 0)) 324 return "switch info query failed"; 325 mad_decode_field(data, IB_SW_ENHANCED_PORT0_F, &enhsp0); 326 if (!enhsp0) { 327 printf("# No VLArbitration tables (BSP0): %s port %d\n", 328 portid2str(dest), 0); 329 return 0; 330 } 331 } 332 } 333 334 if (!smp_query(data, dest, IB_ATTR_PORT_INFO, portnum, 0)) 335 return "port info query failed"; 336 337 mad_decode_field(data, IB_PORT_VL_ARBITRATION_LOW_CAP_F, &lowcap); 338 mad_decode_field(data, IB_PORT_VL_ARBITRATION_HIGH_CAP_F,&highcap); 339 340 printf("# VLArbitration tables: %s port %d LowCap %d HighCap %d\n", 341 portid2str(dest), portnum, lowcap, highcap); 342 343 if (lowcap > 0) 344 ret = vlarb_dump_table(dest, portnum, "Low", 1, lowcap); 345 346 if (!ret && highcap > 0) 347 ret = vlarb_dump_table(dest, portnum, "High", 3, highcap); 348 349 return ret; 350} 351 352static char * 353guid_info(ib_portid_t *dest, char **argv, int argc) 354{ 355 uint8_t data[IB_SMP_DATA_SIZE]; 356 uint32_t i, j, k; 357 uint64_t *p; 358 unsigned mod; 359 int n; 360 361 /* Get the guid capacity */ 362 if (!smp_query(data, dest, IB_ATTR_PORT_INFO, 0, 0)) 363 return "port info failed"; 364 mad_decode_field(data, IB_PORT_GUID_CAP_F, &n); 365 366 for (i = 0; i < (n + 7) / 8; i++) { 367 mod = i; 368 if (!smp_query(data, dest, IB_ATTR_GUID_INFO, mod, 0)) 369 return "guid info query failed"; 370 if (i + 1 == (n + 7) / 8) 371 k = ((n + 1 - i * 8) / 2) * 2; 372 else 373 k = 8; 374 p = (uint64_t *) data; 375 for (j = 0; j < k; j += 2, p += 2) { 376 printf("%4u: 0x%016"PRIx64" 0x%016"PRIx64"\n", 377 (i * 8) + j, 378 ntohll(p[0]), ntohll(p[1])); 379 } 380 } 381 printf("%d guids capacity for this port\n", n); 382 383 return 0; 384} 385 386static op_fn_t * 387match_op(char *name) 388{ 389 const match_rec_t *r; 390 for (r = match_tbl; r->name; r++) 391 if (!strcmp(r->name, name)) 392 return r->fn; 393 return 0; 394} 395 396static void 397usage(void) 398{ 399 char *basename; 400 const match_rec_t *r; 401 402 if (!(basename = strrchr(argv0, '/'))) 403 basename = argv0; 404 else 405 basename++; 406 407 fprintf(stderr, "Usage: %s [-d(ebug) -e(rr_show) -v(erbose) -D(irect) -G(uid) -s smlid -V(ersion) -C ca_name -P ca_port " 408 "-t(imeout) timeout_ms --node-name-map node-name-map] <op> <dest dr_path|lid|guid> [op params]\n", 409 basename); 410 fprintf(stderr, "\tsupported ops:\n"); 411 for (r = match_tbl ; r->name ; r++) { 412 fprintf(stderr, "\t\t%s <addr>%s\n", r->name, 413 r->opt_portnum ? " [<portnum>]" : ""); 414 } 415 fprintf(stderr, "\n\texamples:\n"); 416 fprintf(stderr, "\t\t%s portinfo 3 1\t\t\t\t# portinfo by lid, with port modifier\n", basename); 417 fprintf(stderr, "\t\t%s -G switchinfo 0x2C9000100D051 1\t# switchinfo by guid\n", basename); 418 fprintf(stderr, "\t\t%s -D nodeinfo 0\t\t\t\t# nodeinfo by direct route\n", basename); 419 fprintf(stderr, "\t\t%s -c nodeinfo 6 0,12\t\t\t# nodeinfo by combined route\n", basename); 420 exit(-1); 421} 422 423int 424main(int argc, char **argv) 425{ 426 int mgmt_classes[3] = {IB_SMI_CLASS, IB_SMI_DIRECT_CLASS, IB_SA_CLASS}; 427 ib_portid_t portid = {0}; 428 ib_portid_t *sm_id = 0, sm_portid = {0}; 429 extern int ibdebug; 430 int timeout = 0, udebug = 0; 431 char *ca = 0; 432 int ca_port = 0; 433 char *err; 434 op_fn_t *fn; 435 436 static char const str_opts[] = "C:P:t:s:devDcGVhu"; 437 static const struct option long_opts[] = { 438 { "C", 1, 0, 'C'}, 439 { "P", 1, 0, 'P'}, 440 { "debug", 0, 0, 'd'}, 441 { "err_show", 0, 0, 'e'}, 442 { "verbose", 0, 0, 'v'}, 443 { "Direct", 0, 0, 'D'}, 444 { "combined", 0, 0, 'c'}, 445 { "Guid", 0, 0, 'G'}, 446 { "smlid", 1, 0, 's'}, 447 { "timeout", 1, 0, 't'}, 448 { "node-name-map", 1, 0, 1}, 449 { "Version", 0, 0, 'V'}, 450 { "help", 0, 0, 'h'}, 451 { "usage", 0, 0, 'u'}, 452 { } 453 }; 454 455 argv0 = argv[0]; 456 457 while (1) { 458 int ch = getopt_long(argc, argv, str_opts, long_opts, NULL); 459 if ( ch == -1 ) 460 break; 461 switch(ch) { 462 case 1: 463 node_name_map_file = strdup(optarg); 464 break; 465 case 'd': 466 ibdebug++; 467 madrpc_show_errors(1); 468 umad_debug(udebug); 469 udebug++; 470 break; 471 case 'e': 472 madrpc_show_errors(1); 473 break; 474 case 'D': 475 dest_type = IB_DEST_DRPATH; 476 break; 477 case 'c': 478 dest_type = IB_DEST_DRSLID; 479 break; 480 case 'G': 481 dest_type = IB_DEST_GUID; 482 break; 483 case 'C': 484 ca = optarg; 485 break; 486 case 'P': 487 ca_port = strtoul(optarg, 0, 0); 488 break; 489 case 's': 490 if (ib_resolve_portid_str(&sm_portid, optarg, IB_DEST_LID, 0) < 0) 491 IBERROR("can't resolve SM destination port %s", optarg); 492 sm_id = &sm_portid; 493 break; 494 case 't': 495 timeout = strtoul(optarg, 0, 0); 496 madrpc_set_timeout(timeout); 497 break; 498 case 'v': 499 verbose++; 500 break; 501 case 'V': 502 fprintf(stderr, "%s %s\n", argv0, get_build_version() ); 503 exit(-1); 504 default: 505 usage(); 506 break; 507 } 508 } 509 argc -= optind; 510 argv += optind; 511 512 if (argc < 2) 513 usage(); 514 515 if (!(fn = match_op(argv[0]))) 516 IBERROR("operation '%s' not supported", argv[0]); 517 518 madrpc_init(ca, ca_port, mgmt_classes, 3); 519 node_name_map = open_node_name_map(node_name_map_file); 520 521 if (dest_type != IB_DEST_DRSLID) { 522 if (ib_resolve_portid_str(&portid, argv[1], dest_type, sm_id) < 0) 523 IBERROR("can't resolve destination port %s", argv[1]); 524 if ((err = fn(&portid, argv+2, argc-2))) 525 IBERROR("operation %s: %s", argv[0], err); 526 } else { 527 char concat[64]; 528 529 memset(concat, 0, 64); 530 snprintf(concat, sizeof(concat), "%s %s", argv[1], argv[2]); 531 if (ib_resolve_portid_str(&portid, concat, dest_type, sm_id) < 0) 532 IBERROR("can't resolve destination port %s", concat); 533 if ((err = fn(&portid, argv+3, argc-3))) 534 IBERROR("operation %s: %s", argv[0], err); 535 } 536 close_node_name_map(node_name_map); 537 exit(0); 538} 539