1 /* 2 * Copyright (c) 2004-2009 Voltaire Inc. All rights reserved. 3 * Copyright (c) 2011 Mellanox Technologies LTD. All rights reserved. 4 * Copyright (c) 2011 Lawrence Livermore National Lab. All rights reserved. 5 * 6 * This software is available to you under a choice of one of two 7 * licenses. You may choose to be licensed under the terms of the GNU 8 * General Public License (GPL) Version 2, available from the file 9 * COPYING in the main directory of this source tree, or the 10 * OpenIB.org BSD license below: 11 * 12 * Redistribution and use in source and binary forms, with or 13 * without modification, are permitted provided that the following 14 * conditions are met: 15 * 16 * - Redistributions of source code must retain the above 17 * copyright notice, this list of conditions and the following 18 * disclaimer. 19 * 20 * - Redistributions in binary form must reproduce the above 21 * copyright notice, this list of conditions and the following 22 * disclaimer in the documentation and/or other materials 23 * provided with the distribution. 24 * 25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 29 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 30 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 31 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 32 * SOFTWARE. 33 * 34 */ 35 36 #if HAVE_CONFIG_H 37 # include <config.h> 38 #endif /* HAVE_CONFIG_H */ 39 40 #include <stdio.h> 41 #include <stdlib.h> 42 #include <unistd.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/mad.h> 51 52 #include "ibdiag_common.h" 53 54 struct ibmad_port *srcport; 55 56 static ibmad_gid_t dgid; 57 static int with_grh; 58 59 static op_fn_t class_port_info; 60 static op_fn_t congestion_info; 61 static op_fn_t congestion_key_info; 62 static op_fn_t congestion_log; 63 static op_fn_t switch_congestion_setting; 64 static op_fn_t switch_port_congestion_setting; 65 static op_fn_t ca_congestion_setting; 66 static op_fn_t congestion_control_table; 67 static op_fn_t timestamp_dump; 68 69 static const match_rec_t match_tbl[] = { 70 {"ClassPortInfo", "CP", class_port_info, 0, ""}, 71 {"CongestionInfo", "CI", congestion_info, 0, ""}, 72 {"CongestionKeyInfo", "CK", congestion_key_info, 0, ""}, 73 {"CongestionLog", "CL", congestion_log, 0, ""}, 74 {"SwitchCongestionSetting", "SS", switch_congestion_setting, 0, ""}, 75 {"SwitchPortCongestionSetting", "SP", switch_port_congestion_setting, 1, ""}, 76 {"CACongestionSetting", "CS", ca_congestion_setting, 0, ""}, 77 {"CongestionControlTable", "CT", congestion_control_table, 0, ""}, 78 {"Timestamp", "TI", timestamp_dump, 0, ""}, 79 {0} 80 }; 81 82 uint64_t cckey = 0; 83 84 /*******************************************/ 85 static char *class_port_info(ib_portid_t * dest, char **argv, int argc) 86 { 87 char buf[2048]; 88 char data[IB_CC_DATA_SZ] = { 0 }; 89 90 if (!cc_query_status_via(data, dest, CLASS_PORT_INFO, 91 0, 0, NULL, srcport, cckey)) 92 return "class port info query failed"; 93 94 mad_dump_classportinfo(buf, sizeof buf, data, sizeof data); 95 96 printf("# ClassPortInfo: %s\n%s", portid2str(dest), buf); 97 return NULL; 98 } 99 100 static char *congestion_info(ib_portid_t * dest, char **argv, int argc) 101 { 102 char buf[2048]; 103 char data[IB_CC_DATA_SZ] = { 0 }; 104 105 if (!cc_query_status_via(data, dest, IB_CC_ATTR_CONGESTION_INFO, 106 0, 0, NULL, srcport, cckey)) 107 return "congestion info query failed"; 108 109 mad_dump_cc_congestioninfo(buf, sizeof buf, data, sizeof data); 110 111 printf("# CongestionInfo: %s\n%s", portid2str(dest), buf); 112 return NULL; 113 } 114 115 static char *congestion_key_info(ib_portid_t * dest, char **argv, int argc) 116 { 117 char buf[2048]; 118 char data[IB_CC_DATA_SZ] = { 0 }; 119 120 if (!cc_query_status_via(data, dest, IB_CC_ATTR_CONGESTION_KEY_INFO, 121 0, 0, NULL, srcport, cckey)) 122 return "congestion key info query failed"; 123 124 mad_dump_cc_congestionkeyinfo(buf, sizeof buf, data, sizeof data); 125 126 printf("# CongestionKeyInfo: %s\n%s", portid2str(dest), buf); 127 return NULL; 128 } 129 130 static char *congestion_log(ib_portid_t * dest, char **argv, int argc) 131 { 132 char buf[2048]; 133 char data[IB_CC_LOG_DATA_SZ] = { 0 }; 134 char emptybuf[16] = { 0 }; 135 int i, type; 136 137 if (!cc_query_status_via(data, dest, IB_CC_ATTR_CONGESTION_LOG, 138 0, 0, NULL, srcport, cckey)) 139 return "congestion log query failed"; 140 141 mad_decode_field((uint8_t *)data, IB_CC_CONGESTION_LOG_LOGTYPE_F, &type); 142 143 if (type != 1 && type != 2) 144 return "unrecognized log type"; 145 146 mad_dump_cc_congestionlog(buf, sizeof buf, data, sizeof data); 147 148 printf("# CongestionLog: %s\n%s", portid2str(dest), buf); 149 150 if (type == 1) { 151 mad_dump_cc_congestionlogswitch(buf, sizeof buf, data, sizeof data); 152 printf("%s\n", buf); 153 for (i = 0; i < 15; i++) { 154 /* output only if entry not 0 */ 155 if (memcmp(data + 40 + i * 12, emptybuf, 12)) { 156 mad_dump_cc_congestionlogentryswitch(buf, sizeof buf, 157 data + 40 + i * 12, 158 12); 159 printf("%s\n", buf); 160 } 161 } 162 } 163 else { 164 /* XXX: Q3/2010 errata lists first entry offset at 80, but we assume 165 * will be updated to 96 once CurrentTimeStamp field is word aligned. 166 * In addition, assume max 13 log events instead of 16. Due to 167 * errata changes increasing size of CA log event, 16 log events is 168 * no longer possible to fit in max MAD size. 169 */ 170 mad_dump_cc_congestionlogca(buf, sizeof buf, data, sizeof data); 171 printf("%s\n", buf); 172 for (i = 0; i < 13; i++) { 173 /* output only if entry not 0 */ 174 if (memcmp(data + 12 + i * 16, emptybuf, 16)) { 175 mad_dump_cc_congestionlogentryca(buf, sizeof buf, 176 data + 12 + i * 16, 177 16); 178 printf("%s\n", buf); 179 } 180 } 181 } 182 183 return NULL; 184 } 185 186 static char *switch_congestion_setting(ib_portid_t * dest, char **argv, int argc) 187 { 188 char buf[2048]; 189 char data[IB_CC_DATA_SZ] = { 0 }; 190 191 if (!cc_query_status_via(data, dest, IB_CC_ATTR_SWITCH_CONGESTION_SETTING, 192 0, 0, NULL, srcport, cckey)) 193 return "switch congestion setting query failed"; 194 195 mad_dump_cc_switchcongestionsetting(buf, sizeof buf, data, sizeof data); 196 197 printf("# SwitchCongestionSetting: %s\n%s", portid2str(dest), buf); 198 return NULL; 199 } 200 201 static char *switch_port_congestion_setting(ib_portid_t * dest, char **argv, int argc) 202 { 203 char buf[2048]; 204 char data[IB_CC_DATA_SZ] = { 0 }; 205 int type, numports, maxblocks, i, j; 206 int portnum = 0; 207 int outputcount = 0; 208 209 if (argc > 0) 210 portnum = strtol(argv[0], 0, 0); 211 212 /* Figure out number of ports first */ 213 if (!smp_query_via(data, dest, IB_ATTR_NODE_INFO, 0, 0, srcport)) 214 return "node info query failed"; 215 216 mad_decode_field((uint8_t *)data, IB_NODE_TYPE_F, &type); 217 mad_decode_field((uint8_t *)data, IB_NODE_NPORTS_F, &numports); 218 219 if (type != IB_NODE_SWITCH) 220 return "destination not a switch"; 221 222 printf("# SwitchPortCongestionSetting: %s\n", portid2str(dest)); 223 224 if (portnum) { 225 if (portnum > numports) 226 return "invalid port number specified"; 227 228 memset(data, '\0', sizeof data); 229 if (!cc_query_status_via(data, dest, IB_CC_ATTR_SWITCH_PORT_CONGESTION_SETTING, 230 portnum / 32, 0, NULL, srcport, cckey)) 231 return "switch port congestion setting query failed"; 232 233 mad_dump_cc_switchportcongestionsettingelement(buf, sizeof buf, 234 data + ((portnum % 32) * 4), 235 4); 236 printf("%s", buf); 237 return NULL; 238 } 239 240 /* else get all port info */ 241 242 maxblocks = numports / 32 + 1; 243 244 for (i = 0; i < maxblocks; i++) { 245 memset(data, '\0', sizeof data); 246 if (!cc_query_status_via(data, dest, IB_CC_ATTR_SWITCH_PORT_CONGESTION_SETTING, 247 i, 0, NULL, srcport, cckey)) 248 return "switch port congestion setting query failed"; 249 250 for (j = 0; j < 32 && outputcount <= numports; j++) { 251 printf("Port:............................%u\n", i * 32 + j); 252 mad_dump_cc_switchportcongestionsettingelement(buf, sizeof buf, 253 data + j * 4, 254 4); 255 printf("%s\n", buf); 256 outputcount++; 257 } 258 } 259 260 return NULL; 261 } 262 263 static char *ca_congestion_setting(ib_portid_t * dest, char **argv, int argc) 264 { 265 char buf[2048]; 266 char data[IB_CC_DATA_SZ] = { 0 }; 267 int i; 268 269 if (!cc_query_status_via(data, dest, IB_CC_ATTR_CA_CONGESTION_SETTING, 270 0, 0, NULL, srcport, cckey)) 271 return "ca congestion setting query failed"; 272 273 mad_dump_cc_cacongestionsetting(buf, sizeof buf, data, sizeof data); 274 275 printf("# CACongestionSetting: %s\n%s\n", portid2str(dest), buf); 276 277 for (i = 0; i < 16; i++) { 278 printf("SL:..............................%u\n", i); 279 mad_dump_cc_cacongestionentry(buf, sizeof buf, 280 data + 4 + i * 8, 281 8); 282 printf("%s\n", buf); 283 } 284 return NULL; 285 } 286 287 static char *congestion_control_table(ib_portid_t * dest, char **argv, int argc) 288 { 289 char buf[2048]; 290 char data[IB_CC_DATA_SZ] = { 0 }; 291 int limit, outputcount = 0; 292 int i, j; 293 294 if (!cc_query_status_via(data, dest, IB_CC_ATTR_CONGESTION_CONTROL_TABLE, 295 0, 0, NULL, srcport, cckey)) 296 return "congestion control table query failed"; 297 298 mad_decode_field((uint8_t *)data, IB_CC_CONGESTION_CONTROL_TABLE_CCTI_LIMIT_F, &limit); 299 300 mad_dump_cc_congestioncontroltable(buf, sizeof buf, data, sizeof data); 301 302 printf("# CongestionControlTable: %s\n%s\n", portid2str(dest), buf); 303 304 if (!limit) 305 return NULL; 306 307 for (i = 0; i < (limit/64) + 1; i++) { 308 309 /* first query done */ 310 if (i) 311 if (!cc_query_status_via(data, dest, IB_CC_ATTR_CONGESTION_CONTROL_TABLE, 312 i, 0, NULL, srcport, cckey)) 313 return "congestion control table query failed"; 314 315 for (j = 0; j < 64 && outputcount <= limit; j++) { 316 printf("Entry:...........................%u\n", i*64 + j); 317 mad_dump_cc_congestioncontroltableentry(buf, sizeof buf, 318 data + 4 + j * 2, 319 sizeof data - 4 - j * 2); 320 printf("%s\n", buf); 321 outputcount++; 322 } 323 } 324 return NULL; 325 } 326 327 static char *timestamp_dump(ib_portid_t * dest, char **argv, int argc) 328 { 329 char buf[2048]; 330 char data[IB_CC_DATA_SZ] = { 0 }; 331 332 if (!cc_query_status_via(data, dest, IB_CC_ATTR_TIMESTAMP, 333 0, 0, NULL, srcport, cckey)) 334 return "timestamp query failed"; 335 336 mad_dump_cc_timestamp(buf, sizeof buf, data, sizeof data); 337 338 printf("# Timestamp: %s\n%s", portid2str(dest), buf); 339 return NULL; 340 } 341 342 static int process_opt(void *context, int ch, char *optarg) 343 { 344 switch (ch) { 345 case 'c': 346 cckey = (uint64_t) strtoull(optarg, 0, 0); 347 break; 348 case 25: 349 if (!inet_pton(AF_INET6, optarg, &dgid)) { 350 fprintf(stderr, "dgid format is wrong!\n"); 351 ibdiag_show_usage(); 352 return 1; 353 } 354 with_grh = 1; 355 break; 356 default: 357 return -1; 358 } 359 return 0; 360 } 361 362 int main(int argc, char **argv) 363 { 364 char usage_args[1024]; 365 int mgmt_classes[3] = { IB_SMI_CLASS, IB_SA_CLASS, IB_CC_CLASS }; 366 ib_portid_t portid = { 0 }; 367 char *err; 368 op_fn_t *fn; 369 const match_rec_t *r; 370 int n; 371 372 const struct ibdiag_opt opts[] = { 373 {"cckey", 'c', 1, "<key>", "CC key"}, 374 {"dgid", 25, 1, NULL, "remote gid (IPv6 format)"}, 375 {0} 376 }; 377 const char *usage_examples[] = { 378 "CongestionInfo 3\t\t\t# Congestion Info by lid", 379 "SwitchPortCongestionSetting 3\t# Query all Switch Port Congestion Settings", 380 "SwitchPortCongestionSetting 3 1\t# Query Switch Port Congestion Setting for port 1", 381 NULL 382 }; 383 384 n = sprintf(usage_args, "[-c key] <op> <lid|guid>\n" 385 "\nSupported ops (and aliases, case insensitive):\n"); 386 for (r = match_tbl; r->name; r++) { 387 n += snprintf(usage_args + n, sizeof(usage_args) - n, 388 " %s (%s) <lid|guid>%s\n", r->name, 389 r->alias ? r->alias : "", 390 r->opt_portnum ? " [<portnum>]" : ""); 391 if (n >= sizeof(usage_args)) 392 exit(-1); 393 } 394 395 ibdiag_process_opts(argc, argv, NULL, "DK", opts, process_opt, 396 usage_args, usage_examples); 397 398 argc -= optind; 399 argv += optind; 400 401 if (argc < 2) 402 ibdiag_show_usage(); 403 404 if (!(fn = match_op(match_tbl, argv[0]))) 405 IBEXIT("operation '%s' not supported", argv[0]); 406 407 srcport = mad_rpc_open_port(ibd_ca, ibd_ca_port, mgmt_classes, 3); 408 if (!srcport) 409 IBEXIT("Failed to open '%s' port '%d'", ibd_ca, ibd_ca_port); 410 411 smp_mkey_set(srcport, ibd_mkey); 412 413 if (with_grh && ibd_dest_type != IB_DEST_LID) 414 IBEXIT("When using GRH, LID should be provided"); 415 if (resolve_portid_str(ibd_ca, ibd_ca_port, &portid, argv[1], 416 ibd_dest_type, ibd_sm_id, srcport) < 0) 417 IBEXIT("can't resolve destination %s", argv[1]); 418 if (with_grh) { 419 portid.grh_present = 1; 420 memcpy(&portid.gid, &dgid, sizeof(portid.gid)); 421 } 422 if ((err = fn(&portid, argv + 2, argc - 2))) 423 IBEXIT("operation %s: %s", argv[0], err); 424 425 mad_rpc_close_port(srcport); 426 exit(0); 427 } 428