]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/ofed/infiniband-diags/src/dump_fts.c
Upgrade Unbound to 1.6.0. More to follow.
[FreeBSD/FreeBSD.git] / contrib / ofed / infiniband-diags / src / dump_fts.c
1 /*
2  * Copyright (c) 2004-2009 Voltaire Inc.  All rights reserved.
3  * Copyright (c) 2009-2011 Mellanox Technologies LTD.  All rights reserved.
4  * Copyright (c) 2013 Lawrence Livermore National Security.  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 <inttypes.h>
45 #include <getopt.h>
46 #include <netinet/in.h>
47 #include <assert.h>
48
49 #include <infiniband/umad.h>
50 #include <infiniband/mad.h>
51 #include <complib/cl_nodenamemap.h>
52
53 #include <infiniband/ibnetdisc.h>
54
55 #include "ibdiag_common.h"
56
57 struct ibmad_port *srcport;
58
59 unsigned startlid = 0, endlid = 0;
60
61 static int brief, dump_all, multicast;
62
63 static char *node_name_map_file = NULL;
64 static nn_map_t *node_name_map = NULL;
65
66 #define IB_MLIDS_IN_BLOCK       (IB_SMP_DATA_SIZE/2)
67
68 int dump_mlid(char *str, int strlen, unsigned mlid, unsigned nports,
69               uint16_t mft[16][IB_MLIDS_IN_BLOCK])
70 {
71         uint16_t mask;
72         unsigned i, chunk, bit, nonzero = 0;
73
74         if (brief) {
75                 int n = 0;
76                 unsigned chunks = ALIGN(nports + 1, 16) / 16;
77                 for (i = 0; i < chunks; i++) {
78                         mask = ntohs(mft[i][mlid % IB_MLIDS_IN_BLOCK]);
79                         if (mask)
80                                 nonzero++;
81                         n += snprintf(str + n, strlen - n, "%04hx", mask);
82                         if (n >= strlen) {
83                                 n = strlen;
84                                 break;
85                         }
86                 }
87                 if (!nonzero && !dump_all) {
88                         str[0] = 0;
89                         return 0;
90                 }
91                 return n;
92         }
93         for (i = 0; i <= nports; i++) {
94                 chunk = i / 16;
95                 bit = i % 16;
96
97                 mask = ntohs(mft[chunk][mlid % IB_MLIDS_IN_BLOCK]);
98                 if (mask)
99                         nonzero++;
100                 str[i * 2] = (mask & (1 << bit)) ? 'x' : ' ';
101                 str[i * 2 + 1] = ' ';
102         }
103         if (!nonzero && !dump_all) {
104                 str[0] = 0;
105                 return 0;
106         }
107         str[i * 2] = 0;
108         return i * 2;
109 }
110
111 uint16_t mft[16][IB_MLIDS_IN_BLOCK] = { { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0}, { 0 }, { 0 } };
112
113 void dump_multicast_tables(ibnd_node_t * node, unsigned startlid,
114                             unsigned endlid, struct ibmad_port * mad_port)
115 {
116         ib_portid_t *portid = &node->path_portid;
117         char nd[IB_SMP_DATA_SIZE] = { 0 };
118         char str[512];
119         char *s;
120         uint64_t nodeguid;
121         uint32_t mod;
122         unsigned block, i, j, e, nports, cap, chunks, startblock, lastblock,
123             top;
124         char *mapnd = NULL;
125         int n = 0;
126
127         memcpy(nd, node->nodedesc, strlen(node->nodedesc));
128         nports = node->numports;
129         nodeguid = node->guid;
130
131         mad_decode_field(node->switchinfo, IB_SW_MCAST_FDB_CAP_F, &cap);
132         mad_decode_field(node->switchinfo, IB_SW_MCAST_FDB_TOP_F, &top);
133
134         if (!endlid || endlid > IB_MIN_MCAST_LID + cap - 1)
135                 endlid = IB_MIN_MCAST_LID + cap - 1;
136         if (!dump_all && top && top < endlid) {
137                 if (top < IB_MIN_MCAST_LID - 1)
138                         IBWARN("illegal top mlid %x", top);
139                 else
140                         endlid = top;
141         }
142
143         if (!startlid)
144                 startlid = IB_MIN_MCAST_LID;
145         else if (startlid < IB_MIN_MCAST_LID) {
146                 IBWARN("illegal start mlid %x, set to %x", startlid,
147                        IB_MIN_MCAST_LID);
148                 startlid = IB_MIN_MCAST_LID;
149         }
150
151         if (endlid > IB_MAX_MCAST_LID) {
152                 IBWARN("illegal end mlid %x, truncate to %x", endlid,
153                        IB_MAX_MCAST_LID);
154                 endlid = IB_MAX_MCAST_LID;
155         }
156
157         mapnd = remap_node_name(node_name_map, nodeguid, nd);
158
159         printf("Multicast mlids [0x%x-0x%x] of switch %s guid 0x%016" PRIx64
160                " (%s):\n", startlid, endlid, portid2str(portid), nodeguid,
161                mapnd);
162
163         if (brief)
164                 printf(" MLid       Port Mask\n");
165         else {
166                 if (nports > 9) {
167                         for (i = 0, s = str; i <= nports; i++) {
168                                 *s++ = (i % 10) ? ' ' : '0' + i / 10;
169                                 *s++ = ' ';
170                         }
171                         *s = 0;
172                         printf("            %s\n", str);
173                 }
174                 for (i = 0, s = str; i <= nports; i++)
175                         s += sprintf(s, "%d ", i % 10);
176                 printf("     Ports: %s\n", str);
177                 printf(" MLid\n");
178         }
179         if (ibverbose)
180                 printf("Switch multicast mlid capability is %d top is 0x%x\n",
181                        cap, top);
182
183         chunks = ALIGN(nports + 1, 16) / 16;
184
185         startblock = startlid / IB_MLIDS_IN_BLOCK;
186         lastblock = endlid / IB_MLIDS_IN_BLOCK;
187         for (block = startblock; block <= lastblock; block++) {
188                 for (j = 0; j < chunks; j++) {
189                         int status;
190                         mod = (block - IB_MIN_MCAST_LID / IB_MLIDS_IN_BLOCK)
191                             | (j << 28);
192
193                         DEBUG("reading block %x chunk %d mod %x", block, j,
194                               mod);
195                         if (!smp_query_status_via
196                             (mft + j, portid, IB_ATTR_MULTICASTFORWTBL, mod, 0,
197                              &status, mad_port)) {
198                                 fprintf(stderr, "SubnGet(MFT) failed on switch "
199                                                 "'%s' %s Node GUID 0x%"PRIx64
200                                                 " SMA LID %d; MAD status 0x%x "
201                                                 "AM 0x%x\n",
202                                                 mapnd, portid2str(portid),
203                                                 node->guid, node->smalid,
204                                                 status, mod);
205                         }
206                 }
207
208                 i = block * IB_MLIDS_IN_BLOCK;
209                 e = i + IB_MLIDS_IN_BLOCK;
210                 if (i < startlid)
211                         i = startlid;
212                 if (e > endlid + 1)
213                         e = endlid + 1;
214
215                 for (; i < e; i++) {
216                         if (dump_mlid(str, sizeof str, i, nports, mft) == 0)
217                                 continue;
218                         printf("0x%04x      %s\n", i, str);
219                         n++;
220                 }
221         }
222
223         printf("%d %smlids dumped \n", n, dump_all ? "" : "valid ");
224
225         free(mapnd);
226 }
227
228 int dump_lid(char *str, int str_len, int lid, int valid,
229                 ibnd_fabric_t *fabric,
230                 int * last_port_lid, int * base_port_lid,
231                 uint64_t * portguid)
232 {
233         char nd[IB_SMP_DATA_SIZE] = { 0 };
234
235         ibnd_port_t *port = NULL;
236
237         char ntype[50], sguid[30];
238         uint64_t nodeguid;
239         int baselid, lmc, type;
240         char *mapnd = NULL;
241         int rc;
242
243         if (brief) {
244                 str[0] = 0;
245                 return 0;
246         }
247
248         if (lid <= *last_port_lid) {
249                 if (!valid)
250                         return snprintf(str, str_len,
251                                         ": (path #%d - illegal port)",
252                                         lid - *base_port_lid);
253                 else if (!*portguid)
254                         return snprintf(str, str_len,
255                                         ": (path #%d out of %d)",
256                                         lid - *base_port_lid + 1,
257                                         *last_port_lid - *base_port_lid + 1);
258                 else {
259                         return snprintf(str, str_len,
260                                         ": (path #%d out of %d: portguid %s)",
261                                         lid - *base_port_lid + 1,
262                                         *last_port_lid - *base_port_lid + 1,
263                                         mad_dump_val(IB_NODE_PORT_GUID_F, sguid,
264                                                      sizeof sguid, portguid));
265                 }
266         }
267
268         if (!valid)
269                 return snprintf(str, str_len, ": (illegal port)");
270
271         *portguid = 0;
272
273         port = ibnd_find_port_lid(fabric, lid);
274         if (!port) {
275                 return snprintf(str, str_len, ": (node info not available fabric scan)");
276         }
277
278         nodeguid = port->node->guid;
279         *portguid = port->guid;
280         type = port->node->type;
281
282         baselid = port->base_lid;
283         lmc = port->lmc;
284
285         memcpy(nd, port->node->nodedesc, strlen(port->node->nodedesc));
286
287         if (lmc > 0) {
288                 *base_port_lid = baselid;
289                 *last_port_lid = baselid + (1 << lmc) - 1;
290         }
291
292         mapnd = remap_node_name(node_name_map, nodeguid, nd);
293  
294         rc = snprintf(str, str_len, ": (%s portguid %s: '%s')",
295                       mad_dump_val(IB_NODE_TYPE_F, ntype, sizeof ntype,
296                                    &type), mad_dump_val(IB_NODE_PORT_GUID_F,
297                                                         sguid, sizeof sguid,
298                                                         portguid),
299                       mapnd);
300
301         free(mapnd);
302         return rc;
303 }
304
305 void dump_unicast_tables(ibnd_node_t * node, int startlid, int endlid,
306                         struct ibmad_port *mad_port, ibnd_fabric_t *fabric)
307 {
308         ib_portid_t * portid = &node->path_portid;
309         char lft[IB_SMP_DATA_SIZE] = { 0 };
310         char nd[IB_SMP_DATA_SIZE] = { 0 };
311         char str[200];
312         uint64_t nodeguid;
313         int block, i, e, top;
314         unsigned nports;
315         int n = 0, startblock, endblock;
316         char *mapnd = NULL;
317         int last_port_lid = 0, base_port_lid = 0;
318         uint64_t portguid = 0;
319
320         mad_decode_field(node->switchinfo, IB_SW_LINEAR_FDB_TOP_F, &top);
321         nodeguid = node->guid;
322         nports = node->numports;
323         memcpy(nd, node->nodedesc, strlen(node->nodedesc));
324
325         if (!endlid || endlid > top)
326                 endlid = top;
327
328         if (endlid > IB_MAX_UCAST_LID) {
329                 IBWARN("illegal lft top %d, truncate to %d", endlid,
330                        IB_MAX_UCAST_LID);
331                 endlid = IB_MAX_UCAST_LID;
332         }
333
334         mapnd = remap_node_name(node_name_map, nodeguid, nd);
335
336         printf("Unicast lids [0x%x-0x%x] of switch %s guid 0x%016" PRIx64
337                " (%s):\n", startlid, endlid, portid2str(portid), nodeguid,
338                mapnd);
339
340         DEBUG("Switch top is 0x%x\n", top);
341
342         printf("  Lid  Out   Destination\n");
343         printf("       Port     Info \n");
344         startblock = startlid / IB_SMP_DATA_SIZE;
345         endblock = ALIGN(endlid, IB_SMP_DATA_SIZE) / IB_SMP_DATA_SIZE;
346         for (block = startblock; block < endblock; block++) {
347                 int status;
348                 DEBUG("reading block %d", block);
349                 if (!smp_query_status_via(lft, portid, IB_ATTR_LINEARFORWTBL, block,
350                                    0, &status, mad_port)) {
351                         fprintf(stderr, "SubnGet(LFT) failed on switch "
352                                         "'%s' %s Node GUID 0x%"PRIx64
353                                         " SMA LID %d; MAD status 0x%x AM 0x%x\n",
354                                         mapnd, portid2str(portid),
355                                         node->guid, node->smalid,
356                                         status, block);
357                 }
358                 i = block * IB_SMP_DATA_SIZE;
359                 e = i + IB_SMP_DATA_SIZE;
360                 if (i < startlid)
361                         i = startlid;
362                 if (e > endlid + 1)
363                         e = endlid + 1;
364
365                 for (; i < e; i++) {
366                         unsigned outport = lft[i % IB_SMP_DATA_SIZE];
367                         unsigned valid = (outport <= nports);
368
369                         if (!valid && !dump_all)
370                                 continue;
371                         dump_lid(str, sizeof str, i, valid, fabric,
372                                 &last_port_lid, &base_port_lid, &portguid);
373                         printf("0x%04x %03u %s\n", i, outport & 0xff, str);
374                         n++;
375                 }
376         }
377
378         printf("%d %slids dumped \n", n, dump_all ? "" : "valid ");
379         free(mapnd);
380 }
381
382 void dump_node(ibnd_node_t *node, struct ibmad_port *mad_port,
383                 ibnd_fabric_t *fabric)
384 {
385         if (multicast)
386                 dump_multicast_tables(node, startlid, endlid, mad_port);
387         else
388                 dump_unicast_tables(node, startlid, endlid,
389                                                 mad_port, fabric);
390 }
391
392 void process_switch(ibnd_node_t * node, void *fabric)
393 {
394         dump_node(node, srcport, (ibnd_fabric_t *)fabric);
395 }
396
397 static int process_opt(void *context, int ch, char *optarg)
398 {
399         switch (ch) {
400         case 'a':
401                 dump_all++;
402                 break;
403         case 'M':
404                 multicast++;
405                 break;
406         case 'n':
407                 brief++;
408                 break;
409         case 1:
410                 node_name_map_file = strdup(optarg);
411                 break;
412         default:
413                 return -1;
414         }
415         return 0;
416 }
417
418 int main(int argc, char **argv)
419 {
420         int rc = 0;
421         int mgmt_classes[3] =
422             { IB_SMI_CLASS, IB_SMI_DIRECT_CLASS, IB_SA_CLASS };
423
424         struct ibnd_config config = { 0 };
425         ibnd_fabric_t *fabric = NULL;
426
427         const struct ibdiag_opt opts[] = {
428                 {"all", 'a', 0, NULL, "show all lids, even invalid entries"},
429                 {"no_dests", 'n', 0, NULL,
430                  "do not try to resolve destinations"},
431                 {"Multicast", 'M', 0, NULL, "show multicast forwarding tables"},
432                 {"node-name-map", 1, 1, "<file>", "node name map file"},
433                 {0}
434         };
435         char usage_args[] = "[<dest dr_path|lid|guid> [<startlid> [<endlid>]]]";
436         const char *usage_examples[] = {
437                 " -- Unicast examples:",
438                 "-a\t# same, but dump all lids, even with invalid out ports",
439                 "-n\t# simple dump format - no destination resolving",
440                 "10\t# dump lids starting from 10",
441                 "0x10 0x20\t# dump lid range",
442                 " -- Multicast examples:",
443                 "-M\t# dump all non empty mlids of switch with lid 4",
444                 "-M 0xc010 0xc020\t# same, but with range",
445                 "-M -n\t# simple dump format",
446                 NULL,
447         };
448
449         ibdiag_process_opts(argc, argv, &config, "KGDLs", opts, process_opt,
450                             usage_args, usage_examples);
451
452         argc -= optind;
453         argv += optind;
454
455         if (argc > 0)
456                 startlid = strtoul(argv[0], 0, 0);
457         if (argc > 1)
458                 endlid = strtoul(argv[1], 0, 0);
459
460         node_name_map = open_node_name_map(node_name_map_file);
461
462         if (ibd_timeout)
463                 config.timeout_ms = ibd_timeout;
464
465         config.flags = ibd_ibnetdisc_flags;
466         config.mkey = ibd_mkey;
467
468         if ((fabric = ibnd_discover_fabric(ibd_ca, ibd_ca_port, NULL,
469                                                 &config)) != NULL) {
470
471                 srcport = mad_rpc_open_port(ibd_ca, ibd_ca_port, mgmt_classes, 3);
472                 if (!srcport) {
473                         fprintf(stderr,
474                                 "Failed to open '%s' port '%d'\n", ibd_ca, ibd_ca_port);
475                         rc = -1;
476                         goto Exit;
477                 }
478                 smp_mkey_set(srcport, ibd_mkey);
479
480                 if (ibd_timeout) {
481                         mad_rpc_set_timeout(srcport, ibd_timeout);
482                 }
483
484                 ibnd_iter_nodes_type(fabric, process_switch, IB_NODE_SWITCH, fabric);
485
486                 mad_rpc_close_port(srcport);
487
488         } else {
489                 fprintf(stderr, "Failed to discover fabric\n");
490                 rc = -1;
491         }
492 Exit:
493         ibnd_destroy_fabric(fabric);
494
495         close_node_name_map(node_name_map);
496         exit(rc);
497 }