]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/ofed/management/infiniband-diags/src/ibroute.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / ofed / management / infiniband-diags / src / ibroute.c
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 <inttypes.h>
45 #include <getopt.h>
46 #include <netinet/in.h>
47 #include <ctype.h>
48
49 #include <infiniband/common.h>
50 #include <infiniband/umad.h>
51 #include <infiniband/mad.h>
52 #include <infiniband/complib/cl_nodenamemap.h>
53
54 #include "ibdiag_common.h"
55
56 static int dest_type = IB_DEST_LID;
57 static int brief;
58 static int verbose;
59 static int dump_all;
60
61 char *argv0 = "ibroute";
62
63 /*******************************************/
64
65 char *
66 check_switch(ib_portid_t *portid, int *nports, uint64_t *guid,
67              uint8_t *sw, char *nd)
68 {
69         uint8_t ni[IB_SMP_DATA_SIZE] = {0};
70         int type;
71
72         DEBUG("checking node type");
73         if (!smp_query(ni, portid, IB_ATTR_NODE_INFO, 0, 0)) {
74                 xdump(stderr, "nodeinfo\n", ni, sizeof ni);
75                 return "node info failed: valid addr?";
76         }
77
78         if (!smp_query(nd, portid, IB_ATTR_NODE_DESC, 0, 0))
79                 return "node desc failed";
80
81         mad_decode_field(ni, IB_NODE_TYPE_F, &type);
82         if (type != IB_NODE_SWITCH)
83                 return "not a switch";
84
85         DEBUG("Gathering information about switch");
86         mad_decode_field(ni, IB_NODE_NPORTS_F, nports);
87         mad_decode_field(ni, IB_NODE_GUID_F, guid);
88
89         if (!smp_query(sw, portid, IB_ATTR_SWITCH_INFO, 0, 0))
90                 return "switch info failed: is a switch node?";
91
92         return 0;
93 }
94
95 #define IB_MLIDS_IN_BLOCK       (IB_SMP_DATA_SIZE/2)
96
97 int
98 dump_mlid(char *str, int strlen, int mlid, int nports,
99           uint16_t mft[16][IB_MLIDS_IN_BLOCK])
100 {
101         uint16_t mask;
102         int i, chunk, bit;
103         int nonzero = 0;
104
105         if (brief) {
106                 int n = 0, chunks = ALIGN(nports + 1, 16) / 16;
107                 for (i = 0; i < chunks; i++) {
108                         mask = ntohs(mft[i][mlid%IB_MLIDS_IN_BLOCK]);
109                         if (mask)
110                                 nonzero++;
111                         n += snprintf(str + n, strlen - n, "%04hx", mask);
112                         if (n >= strlen) {
113                                 n = strlen;
114                                 break;
115                         }
116                 }
117                 if (!nonzero && !dump_all) {
118                         str[0] = 0;
119                         return 0;
120                 }
121                 return n;
122         }
123         for (i = 0; i <= nports; i++) {
124                 chunk = i / 16;
125                 bit = i % 16;
126
127                 mask = ntohs(mft[chunk][mlid%IB_MLIDS_IN_BLOCK]);
128                 if (mask)
129                         nonzero++;
130                 str[i*2] = (mask & (1 << bit)) ? 'x' : ' ';
131                 str[i*2+1] = ' ';
132         }
133         if (!nonzero && !dump_all) {
134                 str[0] = 0;
135                 return 0;
136         }
137         str[i*2] = 0;
138         return i * 2;
139 }
140
141 uint16_t mft[16][IB_MLIDS_IN_BLOCK];
142
143 char *
144 dump_multicast_tables(ib_portid_t *portid, int startlid, int endlid)
145 {
146         char nd[IB_SMP_DATA_SIZE] = {0};
147         uint8_t sw[IB_SMP_DATA_SIZE] = {0};
148         char str[512];
149         char *s;
150         uint64_t nodeguid;
151         uint32_t mod;
152         int block, i, j, e, nports, cap, chunks;
153         int n = 0, startblock, lastblock;
154
155         if ((s = check_switch(portid, &nports, &nodeguid, sw, nd)))
156                 return s;
157
158         mad_decode_field(sw, IB_SW_MCAST_FDB_CAP_F, &cap);
159
160         if (!endlid || endlid > IB_MIN_MCAST_LID + cap - 1)
161                 endlid = IB_MIN_MCAST_LID + cap - 1;
162
163         if (!startlid)
164                 startlid = IB_MIN_MCAST_LID;
165
166         if (startlid < IB_MIN_MCAST_LID) {
167                 IBWARN("illegal start mlid %x, set to %x", startlid, IB_MIN_MCAST_LID);
168                 startlid = IB_MIN_MCAST_LID;
169         }
170
171         if (endlid > IB_MAX_MCAST_LID) {
172                 IBWARN("illegal end mlid %x, truncate to %x", endlid, IB_MAX_MCAST_LID);
173                 endlid = IB_MAX_MCAST_LID;
174         }
175
176         printf("Multicast mlids [0x%x-0x%x] of switch %s guid 0x%016" PRIx64 " (%s):\n",
177                 startlid, endlid, portid2str(portid), nodeguid, clean_nodedesc(nd));
178
179         if (brief)
180                 printf(" MLid       Port Mask\n");
181         else {
182                 if (nports > 9) {
183                         for (i = 0, s = str; i <= nports; i++) {
184                                 *s++ = (i%10) ? ' ' : '0' + i/10;
185                                 *s++ = ' ';
186                         }
187                         *s = 0;
188                         printf("            %s\n", str);
189                 }
190                 for (i = 0, s = str; i <= nports; i++)
191                         s += sprintf(s, "%d ", i%10);
192                 printf("     Ports: %s\n", str);
193                 printf(" MLid\n");
194         }
195         if (verbose)
196                 printf("Switch muticast mlids capability is 0x%d\n", cap);
197
198         chunks = ALIGN(nports + 1, 16) / 16;
199
200         startblock = startlid / IB_MLIDS_IN_BLOCK;
201         lastblock = endlid / IB_MLIDS_IN_BLOCK;
202         for (block = startblock; block <= lastblock; block++) {
203                 for (j = 0; j < chunks; j++) {
204                         mod = (block - IB_MIN_MCAST_LID/IB_MLIDS_IN_BLOCK) | (j << 28);
205
206                         DEBUG("reading block %x chunk %d mod %x", block, j, mod);
207                         if (!smp_query(mft + j, portid, IB_ATTR_MULTICASTFORWTBL, mod, 0))
208                                 return "multicast forwarding table get failed";
209                 }
210
211                 i = block * IB_MLIDS_IN_BLOCK;
212                 e = i + IB_MLIDS_IN_BLOCK;
213                 if (i < startlid)
214                         i = startlid;
215                 if (e > endlid + 1)
216                         e = endlid + 1;
217
218                 for (; i < e; i++) {
219                         if (dump_mlid(str, sizeof str, i, nports, mft) == 0)
220                                 continue;
221                         printf("0x%04x      %s\n", i, str);
222                         n++;
223                 }
224         }
225
226         printf("%d %smlids dumped \n", n, dump_all ? "" : "valid ");
227         return 0;
228 }
229
230 int
231 dump_lid(char *str, int strlen, int lid, int valid)
232 {
233         char nd[IB_SMP_DATA_SIZE] = {0};
234         uint8_t ni[IB_SMP_DATA_SIZE] = {0};
235         uint8_t pi[IB_SMP_DATA_SIZE] = {0};
236         ib_portid_t lidport = {0};
237         static int last_port_lid, base_port_lid;
238         char ntype[50], sguid[30], desc[64];
239         static uint64_t portguid;
240         int baselid, lmc, type;
241
242         if (brief) {
243                 str[0] = 0;
244                 return 0;
245         }
246
247         if (lid <= last_port_lid) {
248                 if (!valid)
249                         return snprintf(str, strlen, ": (path #%d - illegal port)",
250                                         lid - base_port_lid);
251                 else if (!portguid)
252                         return snprintf(str, strlen,
253                                         ": (path #%d out of %d)",
254                                         lid - base_port_lid + 1,
255                                         last_port_lid - base_port_lid + 1);
256                 else {
257                         return snprintf(str, strlen,
258                                         ": (path #%d out of %d: portguid %s)",
259                                         lid - base_port_lid + 1,
260                                         last_port_lid - base_port_lid + 1,
261                                         mad_dump_val(IB_NODE_PORT_GUID_F, sguid, sizeof sguid, &portguid));
262                 }
263         }
264
265         if (!valid)
266                 return snprintf(str, strlen, ": (illegal port)");
267
268         portguid = 0;
269         lidport.lid = lid;
270
271         if (!smp_query(nd, &lidport, IB_ATTR_NODE_DESC, 0, 100) ||
272             !smp_query(pi, &lidport, IB_ATTR_PORT_INFO, 0, 100) ||
273             !smp_query(ni, &lidport, IB_ATTR_NODE_INFO, 0, 100))
274                 return snprintf(str, strlen, ": (unknown node and type)");
275
276         mad_decode_field(ni, IB_NODE_PORT_GUID_F, &portguid);
277         mad_decode_field(ni, IB_NODE_TYPE_F, &type);
278
279         mad_decode_field(pi, IB_PORT_LID_F, &baselid);
280         mad_decode_field(pi, IB_PORT_LMC_F, &lmc);
281
282         if (lmc > 0) {
283                 base_port_lid = baselid;
284                 last_port_lid = baselid + (1 << lmc) - 1;
285         }
286
287         return snprintf(str, strlen, ": (%s portguid %s: %s)",
288                 mad_dump_val(IB_NODE_TYPE_F, ntype, sizeof ntype, &type),
289                 mad_dump_val(IB_NODE_PORT_GUID_F, sguid, sizeof sguid, &portguid),
290                 mad_dump_val(IB_NODE_DESC_F, desc, sizeof desc, clean_nodedesc(nd)));
291 }
292
293 char *
294 dump_unicast_tables(ib_portid_t *portid, int startlid, int endlid)
295 {
296         char lft[IB_SMP_DATA_SIZE];
297         char nd[IB_SMP_DATA_SIZE];
298         uint8_t sw[IB_SMP_DATA_SIZE];
299         char str[200], *s;
300         uint64_t nodeguid;
301         int block, i, e, nports, top;
302         int n = 0, startblock, endblock;
303
304         if ((s = check_switch(portid, &nports, &nodeguid, sw, nd)))
305                 return s;
306
307         mad_decode_field(sw, IB_SW_LINEAR_FDB_TOP_F, &top);
308
309         if (!endlid || endlid > top)
310                 endlid = top;
311
312         if (endlid > IB_MAX_UCAST_LID) {
313                 IBWARN("ilegal lft top %d, truncate to %d", endlid, IB_MAX_UCAST_LID);
314                 endlid = IB_MAX_UCAST_LID;
315         }
316
317         printf("Unicast lids [0x%x-0x%x] of switch %s guid 0x%016" PRIx64 " (%s):\n",
318                 startlid, endlid, portid2str(portid), nodeguid, clean_nodedesc(nd));
319
320         DEBUG("Switch top is 0x%x\n", top);
321
322         printf("  Lid  Out   Destination\n");
323         printf("       Port     Info \n");
324         startblock = startlid / IB_SMP_DATA_SIZE;
325         endblock = ALIGN(endlid, IB_SMP_DATA_SIZE) / IB_SMP_DATA_SIZE;
326         for (block = startblock; block <= endblock; block++) {
327                 DEBUG("reading block %d", block);
328                 if (!smp_query(lft, portid, IB_ATTR_LINEARFORWTBL, block, 0))
329                         return "linear forwarding table get failed";
330                 i = block * IB_SMP_DATA_SIZE;
331                 e = i + IB_SMP_DATA_SIZE;
332                 if (i < startlid)
333                         i = startlid;
334                 if (e > endlid + 1)
335                         e = endlid + 1;
336
337                 for (;i < e; i++) {
338                         unsigned outport = lft[i % IB_SMP_DATA_SIZE];
339                         unsigned valid = (outport <= nports);
340
341                         if (!valid && !dump_all)
342                                 continue;
343                         dump_lid(str, sizeof str, i, valid);
344                         printf("0x%04x %03u %s\n", i, outport & 0xff, str);
345                         n++;
346                 }
347         }
348
349         printf("%d %slids dumped \n", n, dump_all ? "" : "valid ");
350         return 0;
351 }
352
353 void
354 usage(void)
355 {
356         char *basename;
357
358         if (!(basename = strrchr(argv0, '/')))
359                 basename = argv0;
360         else
361                 basename++;
362
363         fprintf(stderr, "Usage: %s [-d(ebug)] -a(ll) -n(o_dests) -v(erbose) -D(irect) -G(uid) -M(ulticast) -s smlid -V(ersion) -C ca_name -P ca_port "
364                         "-t(imeout) timeout_ms] [<dest dr_path|lid|guid> [<startlid> [<endlid>]]]\n",
365                         basename);
366         fprintf(stderr, "\n\tUnicast examples:\n");
367         fprintf(stderr, "\t\t%s 4\t# dump all lids with valid out ports of switch with lid 4\n", basename);
368         fprintf(stderr, "\t\t%s -a 4\t# same, but dump all lids, even with invalid out ports\n", basename);
369         fprintf(stderr, "\t\t%s -n 4\t# simple dump format - no destination resolving\n", basename);
370         fprintf(stderr, "\t\t%s 4 10\t# dump lids starting from 10\n", basename);
371         fprintf(stderr, "\t\t%s 4 0x10 0x20\t# dump lid range\n", basename);
372         fprintf(stderr, "\t\t%s -G 0x08f1040023\t# resolve switch by GUID\n", basename);
373         fprintf(stderr, "\t\t%s -D 0,1\t# resolve switch by direct path\n", basename);
374
375         fprintf(stderr, "\n\tMulticast examples:\n");
376         fprintf(stderr, "\t\t%s -M 4\t# dump all non empty mlids of switch with lid 4\n", basename);
377         fprintf(stderr, "\t\t%s -M 4 0xc010 0xc020\t# same, but with range\n", basename);
378         fprintf(stderr, "\t\t%s -M -n 4\t# simple dump format\n", basename);
379         exit(-1);
380 }
381
382 int
383 main(int argc, char **argv)
384 {
385         int mgmt_classes[3] = {IB_SMI_CLASS, IB_SMI_DIRECT_CLASS, IB_SA_CLASS};
386         ib_portid_t portid = {0};
387         ib_portid_t *sm_id = 0, sm_portid = {0};
388         int timeout;
389         int multicast = 0, startlid = 0, endlid = 0;
390         char *err;
391         char *ca = 0;
392         int ca_port = 0;
393
394         static char const str_opts[] = "C:P:t:s:danvDGMVhu";
395         static const struct option long_opts[] = {
396                 { "C", 1, 0, 'C'},
397                 { "P", 1, 0, 'P'},
398                 { "debug", 0, 0, 'd'},
399                 { "all", 0, 0, 'a'},
400                 { "no_dests", 0, 0, 'n'},
401                 { "verbose", 0, 0, 'v'},
402                 { "Direct", 0, 0, 'D'},
403                 { "Guid", 0, 0, 'G'},
404                 { "Multicast", 0, 0, 'M'},
405                 { "timeout", 1, 0, 't'},
406                 { "s", 1, 0, 's'},
407                 { "Version", 0, 0, 'V'},
408                 { "help", 0, 0, 'h'},
409                 { "usage", 0, 0, 'u'},
410                 { }
411         };
412
413         argv0 = argv[0];
414
415         while (1) {
416                 int ch = getopt_long(argc, argv, str_opts, long_opts, NULL);
417                 if ( ch == -1 )
418                         break;
419                 switch(ch) {
420                 case 'C':
421                         ca = optarg;
422                         break;
423                 case 'P':
424                         ca_port = strtoul(optarg, 0, 0);
425                         break;
426                 case 'a':
427                         dump_all++;
428                         break;
429                 case 'd':
430                         ibdebug++;
431                         break;
432                 case 'D':
433                         dest_type = IB_DEST_DRPATH;
434                         break;
435                 case 'G':
436                         dest_type = IB_DEST_GUID;
437                         break;
438                 case 'M':
439                         multicast++;
440                         break;
441                 case 'n':
442                         brief++;
443                         break;
444                 case 's':
445                         if (ib_resolve_portid_str(&sm_portid, optarg, IB_DEST_LID, 0) < 0)
446                                 IBERROR("can't resolve SM destination port %s", optarg);
447                         sm_id = &sm_portid;
448                         break;
449                 case 't':
450                         timeout = strtoul(optarg, 0, 0);
451                         madrpc_set_timeout(timeout);
452                         break;
453                 case 'v':
454                         madrpc_show_errors(1);
455                         verbose++;
456                         break;
457                 case 'V':
458                         fprintf(stderr, "%s %s\n", argv0, get_build_version() );
459                         exit(-1);
460                 default:
461                         usage();
462                         break;
463                 }
464         }
465         argc -= optind;
466         argv += optind;
467
468         if (!argc)
469                 usage();
470
471         if (argc > 1)
472                 startlid = strtoul(argv[1], 0, 0);
473         if (argc > 2)
474                 endlid = strtoul(argv[2], 0, 0);
475
476         madrpc_init(ca, ca_port, mgmt_classes, 3);
477
478         if (!argc) {
479                 if (ib_resolve_self(&portid, 0, 0) < 0)
480                         IBERROR("can't resolve self addr");
481         } else {
482                 if (ib_resolve_portid_str(&portid, argv[0], dest_type, sm_id) < 0)
483                         IBERROR("can't resolve destination port %s", argv[1]);
484         }
485
486         if (multicast)
487                 err = dump_multicast_tables(&portid, startlid, endlid);
488         else
489                 err = dump_unicast_tables(&portid, startlid, endlid);
490
491         if (err)
492                 IBERROR("dump tables: %s", err);
493
494         exit(0);
495 }