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