1 /*
2 * Copyright (c) 2006-2007 The Regents of the University of California.
3 * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved.
4 * Copyright (c) 2002-2010 Mellanox Technologies LTD. All rights reserved.
5 * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
6 * Copyright (c) 2009 HNR Consulting. All rights reserved.
7 * Copyright (c) 2011 Lawrence Livermore National Security. All rights reserved.
8 *
9 * This software is available to you under a choice of one of two
10 * licenses. You may choose to be licensed under the terms of the GNU
11 * General Public License (GPL) Version 2, available from the file
12 * COPYING in the main directory of this source tree, or the
13 * OpenIB.org BSD license below:
14 *
15 * Redistribution and use in source and binary forms, with or
16 * without modification, are permitted provided that the following
17 * conditions are met:
18 *
19 * - Redistributions of source code must retain the above
20 * copyright notice, this list of conditions and the following
21 * disclaimer.
22 *
23 * - Redistributions in binary form must reproduce the above
24 * copyright notice, this list of conditions and the following
25 * disclaimer in the documentation and/or other materials
26 * provided with the distribution.
27 *
28 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
29 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
30 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
31 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
32 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
33 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
34 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
35 * SOFTWARE.
36 *
37 */
38
39 /**
40 * Define common functions which can be included in the various C based diags.
41 */
42
43 #define _GNU_SOURCE
44 #include <stdio.h>
45 #include <errno.h>
46 #include <string.h>
47 #include <stdlib.h>
48 #include <stdarg.h>
49 #include <sys/types.h>
50 #include <unistd.h>
51 #include <ctype.h>
52 #include <config.h>
53 #include <getopt.h>
54 #include <limits.h>
55 #include <sys/stat.h>
56 #include <stdarg.h>
57
58 #include <infiniband/umad.h>
59 #include <infiniband/mad.h>
60 #include <ibdiag_common.h>
61 #include <ibdiag_version.h>
62
63 int ibverbose;
64 enum MAD_DEST ibd_dest_type = IB_DEST_LID;
65 ib_portid_t *ibd_sm_id;
66 static ib_portid_t sm_portid = { 0 };
67
68 /* general config options */
69 #define IBDIAG_CONFIG_GENERAL IBDIAG_CONFIG_PATH"/ibdiag.conf"
70 char *ibd_ca = NULL;
71 int ibd_ca_port = 0;
72 int ibd_timeout = 0;
73 uint32_t ibd_ibnetdisc_flags = IBND_CONFIG_MLX_EPI;
74 uint64_t ibd_mkey;
75 uint64_t ibd_sakey = 0;
76 int show_keys = 0;
77 char *ibd_nd_format = NULL;
78
79 static const char *prog_name;
80 static const char *prog_args;
81 static const char **prog_examples;
82 static struct option *long_opts = NULL;
83 static const struct ibdiag_opt *opts_map[256];
84
get_build_version(void)85 static const char *get_build_version(void)
86 {
87 return "BUILD VERSION: " IBDIAG_VERSION;
88 }
89
pretty_print(int start,int width,const char * str)90 static void pretty_print(int start, int width, const char *str)
91 {
92 int len = width - start;
93 const char *p, *e;
94
95 while (1) {
96 while (isspace(*str))
97 str++;
98 p = str;
99 do {
100 e = p + 1;
101 p = strchr(e, ' ');
102 } while (p && p - str < len);
103 if (!p) {
104 fprintf(stderr, "%s", str);
105 break;
106 }
107 if (e - str == 1)
108 e = p;
109 fprintf(stderr, "%.*s\n%*s", (int)(e - str), str, start, "");
110 str = e;
111 }
112 }
113
val_str_true(const char * val_str)114 static inline int val_str_true(const char *val_str)
115 {
116 return ((strncmp(val_str, "TRUE", strlen("TRUE")) == 0) ||
117 (strncmp(val_str, "true", strlen("true")) == 0));
118 }
119
read_ibdiag_config(const char * file)120 void read_ibdiag_config(const char *file)
121 {
122 char buf[1024];
123 FILE *config_fd = NULL;
124 char *p_prefix, *p_last;
125 char *name;
126 char *val_str;
127 struct stat statbuf;
128
129 /* silently ignore missing config file */
130 if (stat(file, &statbuf))
131 return;
132
133 config_fd = fopen(file, "r");
134 if (!config_fd)
135 return;
136
137 while (fgets(buf, sizeof buf, config_fd) != NULL) {
138 p_prefix = strtok_r(buf, "\n", &p_last);
139 if (!p_prefix)
140 continue; /* ignore blank lines */
141
142 if (*p_prefix == '#')
143 continue; /* ignore comment lines */
144
145 name = strtok_r(p_prefix, "=", &p_last);
146 val_str = strtok_r(NULL, "\n", &p_last);
147
148 if (strncmp(name, "CA", strlen("CA")) == 0) {
149 free(ibd_ca);
150 ibd_ca = strdup(val_str);
151 } else if (strncmp(name, "Port", strlen("Port")) == 0) {
152 ibd_ca_port = strtoul(val_str, NULL, 0);
153 } else if (strncmp(name, "timeout", strlen("timeout")) == 0) {
154 ibd_timeout = strtoul(val_str, NULL, 0);
155 } else if (strncmp(name, "MLX_EPI", strlen("MLX_EPI")) == 0) {
156 if (val_str_true(val_str)) {
157 ibd_ibnetdisc_flags |= IBND_CONFIG_MLX_EPI;
158 } else {
159 ibd_ibnetdisc_flags &= ~IBND_CONFIG_MLX_EPI;
160 }
161 } else if (strncmp(name, "m_key", strlen("m_key")) == 0) {
162 ibd_mkey = strtoull(val_str, 0, 0);
163 } else if (strncmp(name, "sa_key",
164 strlen("sa_key")) == 0) {
165 ibd_sakey = strtoull(val_str, 0, 0);
166 } else if (strncmp(name, "nd_format",
167 strlen("nd_format")) == 0) {
168 ibd_nd_format = strdup(val_str);
169 }
170 }
171
172 fclose(config_fd);
173 }
174
175
ibdiag_show_usage()176 void ibdiag_show_usage()
177 {
178 struct option *o = long_opts;
179 int n;
180
181 fprintf(stderr, "\nUsage: %s [options] %s\n\n", prog_name,
182 prog_args ? prog_args : "");
183
184 if (long_opts[0].name)
185 fprintf(stderr, "Options:\n");
186 for (o = long_opts; o->name; o++) {
187 const struct ibdiag_opt *io = opts_map[o->val];
188 n = fprintf(stderr, " --%s", io->name);
189 if (isprint(io->letter))
190 n += fprintf(stderr, ", -%c", io->letter);
191 if (io->has_arg)
192 n += fprintf(stderr, " %s",
193 io->arg_tmpl ? io->arg_tmpl : "<val>");
194 if (io->description && *io->description) {
195 n += fprintf(stderr, "%*s ", 24 - n > 0 ? 24 - n : 0,
196 "");
197 pretty_print(n, 74, io->description);
198 }
199 fprintf(stderr, "\n");
200 }
201
202 if (prog_examples) {
203 const char **p;
204 fprintf(stderr, "\nExamples:\n");
205 for (p = prog_examples; *p && **p; p++)
206 fprintf(stderr, " %s %s\n", prog_name, *p);
207 }
208
209 fprintf(stderr, "\n");
210
211 exit(2);
212 }
213
process_opt(int ch,char * optarg)214 static int process_opt(int ch, char *optarg)
215 {
216 char *endp;
217 long val;
218
219 switch (ch) {
220 case 'z':
221 read_ibdiag_config(optarg);
222 break;
223 case 'h':
224 ibdiag_show_usage();
225 break;
226 case 'V':
227 fprintf(stderr, "%s %s\n", prog_name, get_build_version());
228 exit(0);
229 case 'e':
230 madrpc_show_errors(1);
231 break;
232 case 'v':
233 ibverbose++;
234 break;
235 case 'd':
236 ibdebug++;
237 madrpc_show_errors(1);
238 umad_debug(ibdebug - 1);
239 break;
240 case 'C':
241 ibd_ca = optarg;
242 break;
243 case 'P':
244 ibd_ca_port = strtoul(optarg, 0, 0);
245 if (ibd_ca_port < 0)
246 IBEXIT("cannot resolve CA port %d", ibd_ca_port);
247 break;
248 case 'D':
249 ibd_dest_type = IB_DEST_DRPATH;
250 break;
251 case 'L':
252 ibd_dest_type = IB_DEST_LID;
253 break;
254 case 'G':
255 ibd_dest_type = IB_DEST_GUID;
256 break;
257 case 't':
258 errno = 0;
259 val = strtol(optarg, &endp, 0);
260 if (errno || (endp && *endp != '\0') || val <= 0 ||
261 val > INT_MAX)
262 IBEXIT("Invalid timeout \"%s\". Timeout requires a "
263 "positive integer value < %d.", optarg, INT_MAX);
264 else {
265 madrpc_set_timeout((int)val);
266 ibd_timeout = (int)val;
267 }
268 break;
269 case 's':
270 /* srcport is not required when resolving via IB_DEST_LID */
271 if (resolve_portid_str(ibd_ca, ibd_ca_port, &sm_portid, optarg,
272 IB_DEST_LID, 0, NULL) < 0)
273 IBEXIT("cannot resolve SM destination port %s",
274 optarg);
275 ibd_sm_id = &sm_portid;
276 break;
277 case 'K':
278 show_keys = 1;
279 break;
280 case 'y':
281 errno = 0;
282 ibd_mkey = strtoull(optarg, &endp, 0);
283 if (errno || *endp != '\0') {
284 errno = 0;
285 ibd_mkey = strtoull(getpass("M_Key: "), &endp, 0);
286 if (errno || *endp != '\0') {
287 IBEXIT("Bad M_Key");
288 }
289 }
290 break;
291 default:
292 return -1;
293 }
294
295 return 0;
296 }
297
298 static const struct ibdiag_opt common_opts[] = {
299 {"config", 'z', 1, "<config>", "use config file, default: " IBDIAG_CONFIG_GENERAL},
300 {"Ca", 'C', 1, "<ca>", "Ca name to use"},
301 {"Port", 'P', 1, "<port>", "Ca port number to use"},
302 {"Direct", 'D', 0, NULL, "use Direct address argument"},
303 {"Lid", 'L', 0, NULL, "use LID address argument"},
304 {"Guid", 'G', 0, NULL, "use GUID address argument"},
305 {"timeout", 't', 1, "<ms>", "timeout in ms"},
306 {"sm_port", 's', 1, "<lid>", "SM port lid"},
307 {"show_keys", 'K', 0, NULL, "display security keys in output"},
308 {"m_key", 'y', 1, "<key>", "M_Key to use in request"},
309 {"errors", 'e', 0, NULL, "show send and receive errors"},
310 {"verbose", 'v', 0, NULL, "increase verbosity level"},
311 {"debug", 'd', 0, NULL, "raise debug level"},
312 {"help", 'h', 0, NULL, "help message"},
313 {"version", 'V', 0, NULL, "show version"},
314 {0}
315 };
316
make_opt(struct option * l,const struct ibdiag_opt * o,const struct ibdiag_opt * map[])317 static void make_opt(struct option *l, const struct ibdiag_opt *o,
318 const struct ibdiag_opt *map[])
319 {
320 l->name = o->name;
321 l->has_arg = o->has_arg;
322 l->flag = NULL;
323 l->val = o->letter;
324 if (!map[l->val])
325 map[l->val] = o;
326 }
327
make_long_opts(const char * exclude_str,const struct ibdiag_opt * custom_opts,const struct ibdiag_opt * map[])328 static struct option *make_long_opts(const char *exclude_str,
329 const struct ibdiag_opt *custom_opts,
330 const struct ibdiag_opt *map[])
331 {
332 struct option *long_opts, *l;
333 const struct ibdiag_opt *o;
334 unsigned n = 0;
335
336 if (custom_opts)
337 for (o = custom_opts; o->name; o++)
338 n++;
339
340 long_opts = malloc((sizeof(common_opts) / sizeof(common_opts[0]) + n) *
341 sizeof(*long_opts));
342 if (!long_opts)
343 return NULL;
344
345 l = long_opts;
346
347 if (custom_opts)
348 for (o = custom_opts; o->name; o++)
349 make_opt(l++, o, map);
350
351 for (o = common_opts; o->name; o++) {
352 if (exclude_str && strchr(exclude_str, o->letter))
353 continue;
354 make_opt(l++, o, map);
355 }
356
357 memset(l, 0, sizeof(*l));
358
359 return long_opts;
360 }
361
make_str_opts(const struct option * o,char * p,unsigned size)362 static void make_str_opts(const struct option *o, char *p, unsigned size)
363 {
364 unsigned i, n = 0;
365
366 for (n = 0; o->name && n + 2 + o->has_arg < size; o++) {
367 p[n++] = (char)o->val;
368 for (i = 0; i < (unsigned)o->has_arg; i++)
369 p[n++] = ':';
370 }
371 p[n] = '\0';
372 }
373
ibdiag_process_opts(int argc,char * const argv[],void * cxt,const char * exclude_common_str,const struct ibdiag_opt custom_opts[],int (* custom_handler)(void * cxt,int val,char * optarg),const char * usage_args,const char * usage_examples[])374 int ibdiag_process_opts(int argc, char *const argv[], void *cxt,
375 const char *exclude_common_str,
376 const struct ibdiag_opt custom_opts[],
377 int (*custom_handler) (void *cxt, int val,
378 char *optarg),
379 const char *usage_args, const char *usage_examples[])
380 {
381 char str_opts[1024];
382 const struct ibdiag_opt *o;
383
384 prog_name = argv[0];
385 prog_args = usage_args;
386 prog_examples = usage_examples;
387
388 if (long_opts)
389 free(long_opts);
390
391 long_opts = make_long_opts(exclude_common_str, custom_opts, opts_map);
392 if (!long_opts)
393 return -1;
394
395 read_ibdiag_config(IBDIAG_CONFIG_GENERAL);
396
397 make_str_opts(long_opts, str_opts, sizeof(str_opts));
398
399 while (1) {
400 int ch = getopt_long(argc, argv, str_opts, long_opts, NULL);
401 if (ch == -1)
402 break;
403 o = opts_map[ch];
404 if (!o)
405 ibdiag_show_usage();
406 if (custom_handler) {
407 if (custom_handler(cxt, ch, optarg) &&
408 process_opt(ch, optarg))
409 ibdiag_show_usage();
410 } else if (process_opt(ch, optarg))
411 ibdiag_show_usage();
412 }
413
414 return 0;
415 }
416
ibexit(const char * fn,char * msg,...)417 void ibexit(const char *fn, char *msg, ...)
418 {
419 char buf[512];
420 va_list va;
421 int n;
422
423 va_start(va, msg);
424 n = vsprintf(buf, msg, va);
425 va_end(va);
426 buf[n] = 0;
427
428 if (ibdebug)
429 printf("%s: iberror: [pid %d] %s: failed: %s\n",
430 prog_name ? prog_name : "", getpid(), fn, buf);
431 else
432 printf("%s: iberror: failed: %s\n",
433 prog_name ? prog_name : "", buf);
434
435 exit(-1);
436 }
437
438 char *
conv_cnt_human_readable(uint64_t val64,float * val,int data)439 conv_cnt_human_readable(uint64_t val64, float *val, int data)
440 {
441 uint64_t tmp = val64;
442 int ui = 0;
443 int div = 1;
444
445 tmp /= 1024;
446 while (tmp) {
447 ui++;
448 tmp /= 1024;
449 div *= 1024;
450 }
451
452 *val = (float)(val64);
453 if (data) {
454 *val *= 4;
455 if (*val/div > 1024) {
456 ui++;
457 div *= 1024;
458 }
459 }
460 *val /= div;
461
462 if (data) {
463 switch (ui) {
464 case 0:
465 return ("B");
466 case 1:
467 return ("KB");
468 case 2:
469 return ("MB");
470 case 3:
471 return ("GB");
472 case 4:
473 return ("TB");
474 case 5:
475 return ("PB");
476 case 6:
477 return ("EB");
478 default:
479 return ("");
480 }
481 } else {
482 switch (ui) {
483 case 0:
484 return ("");
485 case 1:
486 return ("K");
487 case 2:
488 return ("M");
489 case 3:
490 return ("G");
491 case 4:
492 return ("T");
493 case 5:
494 return ("P");
495 case 6:
496 return ("E");
497 default:
498 return ("");
499 }
500 }
501 return ("");
502 }
503
is_port_info_extended_supported(ib_portid_t * dest,int port,struct ibmad_port * srcport)504 int is_port_info_extended_supported(ib_portid_t * dest, int port,
505 struct ibmad_port *srcport)
506 {
507 uint8_t data[IB_SMP_DATA_SIZE] = { 0 };
508 uint32_t cap_mask;
509 uint16_t cap_mask2;
510
511 if (!smp_query_via(data, dest, IB_ATTR_PORT_INFO, port, 0, srcport))
512 IBEXIT("port info query failed");
513
514 mad_decode_field(data, IB_PORT_CAPMASK_F, &cap_mask);
515 if (cap_mask & CL_NTOH32(IB_PORT_CAP_HAS_CAP_MASK2)) {
516 mad_decode_field(data, IB_PORT_CAPMASK2_F, &cap_mask2);
517 if (!(cap_mask2 &
518 CL_NTOH16(IB_PORT_CAP2_IS_PORT_INFO_EXT_SUPPORTED))) {
519 IBWARN("port info capability mask2 = 0x%x doesn't"
520 " indicate PortInfoExtended support", cap_mask2);
521 return 0;
522 }
523 } else {
524 IBWARN("port info capability mask2 not supported");
525 return 0;
526 }
527
528 return 1;
529 }
530
is_mlnx_ext_port_info_supported(uint32_t vendorid,uint16_t devid)531 int is_mlnx_ext_port_info_supported(uint32_t vendorid,
532 uint16_t devid)
533 {
534 if (ibd_ibnetdisc_flags & IBND_CONFIG_MLX_EPI) {
535
536 if ((devid >= 0xc738 && devid <= 0xc73b) || devid == 0xcb20 || devid == 0xcf08 ||
537 ((vendorid == 0x119f) &&
538 /* Bull SwitchX */
539 (devid == 0x1b02 || devid == 0x1b50 ||
540 /* Bull SwitchIB and SwitchIB2 */
541 devid == 0x1ba0 ||
542 (devid >= 0x1bd0 && devid <= 0x1bd5))))
543 return 1;
544 if ((devid >= 0x1003 && devid <= 0x1017) ||
545 ((vendorid == 0x119f) &&
546 /* Bull ConnectX3 */
547 (devid == 0x1b33 || devid == 0x1b73 ||
548 devid == 0x1b40 || devid == 0x1b41 ||
549 devid == 0x1b60 || devid == 0x1b61 ||
550 /* Bull ConnectIB */
551 devid == 0x1b83 ||
552 devid == 0x1b93 || devid == 0x1b94 ||
553 /* Bull ConnectX4 */
554 devid == 0x1bb4 || devid == 0x1bb5 ||
555 devid == 0x1bc4)))
556 return 1;
557 }
558
559 return 0;
560 }
561
562 /** =========================================================================
563 * Resolve the SM portid using the umad layer rather than using
564 * ib_resolve_smlid_via which requires a PortInfo query on the local port.
565 */
resolve_sm_portid(char * ca_name,uint8_t portnum,ib_portid_t * sm_id)566 int resolve_sm_portid(char *ca_name, uint8_t portnum, ib_portid_t *sm_id)
567 {
568 umad_port_t port;
569 int rc;
570
571 if (!sm_id)
572 return (-1);
573
574 if ((rc = umad_get_port(ca_name, portnum, &port)) < 0)
575 return rc;
576
577 memset(sm_id, 0, sizeof(*sm_id));
578 sm_id->lid = port.sm_lid;
579 sm_id->sl = port.sm_sl;
580
581 umad_release_port(&port);
582
583 return 0;
584 }
585
586 /** =========================================================================
587 * Resolve local CA characteristics using the umad layer rather than using
588 * ib_resolve_self_via which requires SMP queries on the local port.
589 */
resolve_self(char * ca_name,uint8_t ca_port,ib_portid_t * portid,int * portnum,ibmad_gid_t * gid)590 int resolve_self(char *ca_name, uint8_t ca_port, ib_portid_t *portid,
591 int *portnum, ibmad_gid_t *gid)
592 {
593 umad_port_t port;
594 uint64_t prefix, guid;
595 int rc;
596
597 if (!(portid || portnum || gid))
598 return (-1);
599
600 if ((rc = umad_get_port(ca_name, ca_port, &port)) < 0)
601 return rc;
602
603 if (portid) {
604 memset(portid, 0, sizeof(*portid));
605 portid->lid = port.base_lid;
606 portid->sl = port.sm_sl;
607 }
608 if (portnum)
609 *portnum = port.portnum;
610 if (gid) {
611 memset(gid, 0, sizeof(*gid));
612 prefix = cl_ntoh64(port.gid_prefix);
613 guid = cl_ntoh64(port.port_guid);
614 mad_encode_field(*gid, IB_GID_PREFIX_F, &prefix);
615 mad_encode_field(*gid, IB_GID_GUID_F, &guid);
616 }
617
618 umad_release_port(&port);
619
620 return 0;
621 }
622
resolve_gid(char * ca_name,uint8_t ca_port,ib_portid_t * portid,ibmad_gid_t gid,ib_portid_t * sm_id,const struct ibmad_port * srcport)623 int resolve_gid(char *ca_name, uint8_t ca_port, ib_portid_t * portid,
624 ibmad_gid_t gid, ib_portid_t * sm_id,
625 const struct ibmad_port *srcport)
626 {
627 ib_portid_t sm_portid;
628 char buf[IB_SA_DATA_SIZE] = { 0 };
629
630 if (!sm_id) {
631 sm_id = &sm_portid;
632 if (resolve_sm_portid(ca_name, ca_port, sm_id) < 0)
633 return -1;
634 }
635
636 if ((portid->lid =
637 ib_path_query_via(srcport, gid, gid, sm_id, buf)) < 0)
638 return -1;
639
640 return 0;
641 }
642
resolve_guid(char * ca_name,uint8_t ca_port,ib_portid_t * portid,uint64_t * guid,ib_portid_t * sm_id,const struct ibmad_port * srcport)643 int resolve_guid(char *ca_name, uint8_t ca_port, ib_portid_t *portid,
644 uint64_t *guid, ib_portid_t *sm_id,
645 const struct ibmad_port *srcport)
646 {
647 ib_portid_t sm_portid;
648 uint8_t buf[IB_SA_DATA_SIZE] = { 0 };
649 uint64_t prefix;
650 ibmad_gid_t selfgid;
651
652 if (!sm_id) {
653 sm_id = &sm_portid;
654 if (resolve_sm_portid(ca_name, ca_port, sm_id) < 0)
655 return -1;
656 }
657
658 if (resolve_self(ca_name, ca_port, NULL, NULL, &selfgid) < 0)
659 return -1;
660
661 memcpy(&prefix, portid->gid, sizeof(prefix));
662 if (!prefix)
663 mad_set_field64(portid->gid, 0, IB_GID_PREFIX_F,
664 IB_DEFAULT_SUBN_PREFIX);
665 if (guid)
666 mad_set_field64(portid->gid, 0, IB_GID_GUID_F, *guid);
667
668 if ((portid->lid =
669 ib_path_query_via(srcport, selfgid, portid->gid, sm_id, buf)) < 0)
670 return -1;
671
672 mad_decode_field(buf, IB_SA_PR_SL_F, &portid->sl);
673 return 0;
674 }
675
676 /*
677 * Callers of this function should ensure their ibmad_port has been opened with
678 * IB_SA_CLASS as this function may require the SA to resolve addresses.
679 */
resolve_portid_str(char * ca_name,uint8_t ca_port,ib_portid_t * portid,char * addr_str,enum MAD_DEST dest_type,ib_portid_t * sm_id,const struct ibmad_port * srcport)680 int resolve_portid_str(char *ca_name, uint8_t ca_port, ib_portid_t * portid,
681 char *addr_str, enum MAD_DEST dest_type,
682 ib_portid_t *sm_id, const struct ibmad_port *srcport)
683 {
684 ibmad_gid_t gid;
685 uint64_t guid;
686 int lid;
687 char *routepath;
688 ib_portid_t selfportid = { 0 };
689 int selfport = 0;
690
691 memset(portid, 0, sizeof *portid);
692
693 switch (dest_type) {
694 case IB_DEST_LID:
695 lid = strtol(addr_str, 0, 0);
696 if (!IB_LID_VALID(lid))
697 return -1;
698 return ib_portid_set(portid, lid, 0, 0);
699
700 case IB_DEST_DRPATH:
701 if (str2drpath(&portid->drpath, addr_str, 0, 0) < 0)
702 return -1;
703 return 0;
704
705 case IB_DEST_GUID:
706 if (!(guid = strtoull(addr_str, 0, 0)))
707 return -1;
708
709 /* keep guid in portid? */
710 return resolve_guid(ca_name, ca_port, portid, &guid, sm_id,
711 srcport);
712
713 case IB_DEST_DRSLID:
714 lid = strtol(addr_str, &routepath, 0);
715 routepath++;
716 if (!IB_LID_VALID(lid))
717 return -1;
718 ib_portid_set(portid, lid, 0, 0);
719
720 /* handle DR parsing and set DrSLID to local lid */
721 if (resolve_self(ca_name, ca_port, &selfportid, &selfport,
722 NULL) < 0)
723 return -1;
724 if (str2drpath(&portid->drpath, routepath, selfportid.lid, 0) <
725 0)
726 return -1;
727 return 0;
728
729 case IB_DEST_GID:
730 if (inet_pton(AF_INET6, addr_str, &gid) <= 0)
731 return -1;
732 return resolve_gid(ca_name, ca_port, portid, gid, sm_id,
733 srcport);
734 default:
735 IBWARN("bad dest_type %d", dest_type);
736 }
737
738 return -1;
739 }
740
get_max_width(unsigned int num)741 static unsigned int get_max_width(unsigned int num)
742 {
743 unsigned r = 0; /* 1x */
744
745 if (num & 8)
746 r = 3; /* 12x */
747 else {
748 if (num & 4)
749 r = 2; /* 8x */
750 else if (num & 2)
751 r = 1; /* 4x */
752 else if (num & 0x10)
753 r = 4; /* 2x */
754 }
755
756 return (1 << r);
757 }
758
get_max(unsigned int num)759 static unsigned int get_max(unsigned int num)
760 {
761 unsigned r = 0; // r will be lg(num)
762
763 while (num >>= 1) // unroll for more speed...
764 r++;
765
766 return (1 << r);
767 }
768
get_max_msg(char * width_msg,char * speed_msg,int msg_size,ibnd_port_t * port)769 void get_max_msg(char *width_msg, char *speed_msg, int msg_size, ibnd_port_t * port)
770 {
771 char buf[64];
772 uint32_t max_speed = 0;
773 uint32_t cap_mask, rem_cap_mask, fdr10;
774 uint8_t *info = NULL;
775
776 uint32_t max_width = get_max_width(mad_get_field(port->info, 0,
777 IB_PORT_LINK_WIDTH_SUPPORTED_F)
778 & mad_get_field(port->remoteport->info, 0,
779 IB_PORT_LINK_WIDTH_SUPPORTED_F));
780 if ((max_width & mad_get_field(port->info, 0,
781 IB_PORT_LINK_WIDTH_ACTIVE_F)) == 0)
782 // we are not at the max supported width
783 // print what we could be at.
784 snprintf(width_msg, msg_size, "Could be %s",
785 mad_dump_val(IB_PORT_LINK_WIDTH_ACTIVE_F,
786 buf, 64, &max_width));
787
788 if (port->node->type == IB_NODE_SWITCH) {
789 if (port->node->ports[0])
790 info = (uint8_t *)&port->node->ports[0]->info;
791 }
792 else
793 info = (uint8_t *)&port->info;
794
795 if (info)
796 cap_mask = mad_get_field(info, 0, IB_PORT_CAPMASK_F);
797 else
798 cap_mask = 0;
799
800 info = NULL;
801 if (port->remoteport->node->type == IB_NODE_SWITCH) {
802 if (port->remoteport->node->ports[0])
803 info = (uint8_t *)&port->remoteport->node->ports[0]->info;
804 } else
805 info = (uint8_t *)&port->remoteport->info;
806
807 if (info)
808 rem_cap_mask = mad_get_field(info, 0, IB_PORT_CAPMASK_F);
809 else
810 rem_cap_mask = 0;
811 if (cap_mask & CL_NTOH32(IB_PORT_CAP_HAS_EXT_SPEEDS) &&
812 rem_cap_mask & CL_NTOH32(IB_PORT_CAP_HAS_EXT_SPEEDS))
813 goto check_ext_speed;
814 check_fdr10_supp:
815 fdr10 = (mad_get_field(port->ext_info, 0,
816 IB_MLNX_EXT_PORT_LINK_SPEED_SUPPORTED_F) & FDR10)
817 && (mad_get_field(port->remoteport->ext_info, 0,
818 IB_MLNX_EXT_PORT_LINK_SPEED_SUPPORTED_F) & FDR10);
819 if (fdr10)
820 goto check_fdr10_active;
821
822 max_speed = get_max(mad_get_field(port->info, 0,
823 IB_PORT_LINK_SPEED_SUPPORTED_F)
824 & mad_get_field(port->remoteport->info, 0,
825 IB_PORT_LINK_SPEED_SUPPORTED_F));
826 if ((max_speed & mad_get_field(port->info, 0,
827 IB_PORT_LINK_SPEED_ACTIVE_F)) == 0)
828 // we are not at the max supported speed
829 // print what we could be at.
830 snprintf(speed_msg, msg_size, "Could be %s",
831 mad_dump_val(IB_PORT_LINK_SPEED_ACTIVE_F,
832 buf, 64, &max_speed));
833 return;
834
835 check_ext_speed:
836 if (mad_get_field(port->info, 0,
837 IB_PORT_LINK_SPEED_EXT_SUPPORTED_F) == 0 ||
838 mad_get_field(port->remoteport->info, 0,
839 IB_PORT_LINK_SPEED_EXT_SUPPORTED_F) == 0)
840 goto check_fdr10_supp;
841 max_speed = get_max(mad_get_field(port->info, 0,
842 IB_PORT_LINK_SPEED_EXT_SUPPORTED_F)
843 & mad_get_field(port->remoteport->info, 0,
844 IB_PORT_LINK_SPEED_EXT_SUPPORTED_F));
845 if ((max_speed & mad_get_field(port->info, 0,
846 IB_PORT_LINK_SPEED_EXT_ACTIVE_F)) == 0)
847 // we are not at the max supported extended speed
848 // print what we could be at.
849 snprintf(speed_msg, msg_size, "Could be %s",
850 mad_dump_val(IB_PORT_LINK_SPEED_EXT_ACTIVE_F,
851 buf, 64, &max_speed));
852 return;
853
854 check_fdr10_active:
855 if ((mad_get_field(port->ext_info, 0,
856 IB_MLNX_EXT_PORT_LINK_SPEED_ACTIVE_F) & FDR10) == 0) {
857 /* Special case QDR to try to avoid confusion with FDR10 */
858 if (mad_get_field(port->info, 0, IB_PORT_LINK_SPEED_ACTIVE_F) == 4) /* QDR (10.0 Gbps) */
859 snprintf(speed_msg, msg_size,
860 "Could be FDR10 (Found link at QDR but expected speed is FDR10)");
861 else
862 snprintf(speed_msg, msg_size, "Could be FDR10");
863 }
864 }
865
vsnprint_field(char * buf,size_t n,enum MAD_FIELDS f,int spacing,const char * format,va_list va_args)866 int vsnprint_field(char *buf, size_t n, enum MAD_FIELDS f, int spacing,
867 const char *format, va_list va_args)
868 {
869 int len, i, ret;
870
871 len = strlen(mad_field_name(f));
872 if (len + 2 > n || spacing + 1 > n)
873 return 0;
874
875 strncpy(buf, mad_field_name(f), n);
876 buf[len] = ':';
877 for (i = len+1; i < spacing+1; i++) {
878 buf[i] = '.';
879 }
880
881 ret = vsnprintf(&buf[spacing+1], n - spacing, format, va_args);
882 if (ret >= n - spacing)
883 buf[n] = '\0';
884
885 return ret + spacing;
886 }
887
snprint_field(char * buf,size_t n,enum MAD_FIELDS f,int spacing,const char * format,...)888 int snprint_field(char *buf, size_t n, enum MAD_FIELDS f, int spacing,
889 const char *format, ...)
890 {
891 va_list val;
892 int ret;
893
894 va_start(val, format);
895 ret = vsnprint_field(buf, n, f, spacing, format, val);
896 va_end(val);
897
898 return ret;
899 }
900
dump_portinfo(void * pi,int tabs)901 void dump_portinfo(void *pi, int tabs)
902 {
903 int field, i;
904 char val[64];
905 char buf[1024];
906
907 for (field = IB_PORT_FIRST_F; field < IB_PORT_LAST_F; field++) {
908 for (i=0;i<tabs;i++)
909 printf("\t");
910 if (field == IB_PORT_MKEY_F && show_keys == 0) {
911 snprint_field(buf, 1024, field, 32, NOT_DISPLAYED_STR);
912 } else {
913 mad_decode_field(pi, field, val);
914 if (!mad_dump_field(field, buf, 1024, val))
915 return;
916 }
917 printf("%s\n", buf);
918 }
919
920 for (field = IB_PORT_CAPMASK2_F;
921 field < IB_PORT_LINK_SPEED_EXT_LAST_F; field++) {
922 for (i=0;i<tabs;i++)
923 printf("\t");
924 mad_decode_field(pi, field, val);
925 if (!mad_dump_field(field, buf, 1024, val))
926 return;
927 printf("%s\n", buf);
928 }
929 }
930
match_op(const match_rec_t match_tbl[],char * name)931 op_fn_t *match_op(const match_rec_t match_tbl[], char *name)
932 {
933 const match_rec_t *r;
934 for (r = match_tbl; r->name; r++)
935 if (!strcasecmp(r->name, name) ||
936 (r->alias && !strcasecmp(r->alias, name)))
937 return r->fn;
938 return NULL;
939 }
940