[OPENSM] set opensm cache & config folder as %ProgramFiles%\WinOF\OpenSM; integrated...
[mirror/winof/.git] / ulp / libibnetdisc / src / ibnetdisc.c
1 /*
2  * Copyright (c) 2004-2007 Voltaire Inc.  All rights reserved.
3  * Copyright (c) 2007 Xsigo Systems Inc.  All rights reserved.
4  * Copyright (c) 2008 Lawrence Livermore National Laboratory
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 #define _GNU_SOURCE
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <unistd.h>
44 #include <stdarg.h>
45 #include <time.h>
46 #include <string.h>
47 #include <getopt.h>
48 #include <errno.h>
49 #include <inttypes.h>
50
51 #include <infiniband/umad.h>
52 #include <infiniband/mad.h>
53
54 #include <infiniband/ibnetdisc.h>
55 #include <complib/cl_nodenamemap.h>
56
57 #include "internal.h"
58 #include "chassis.h"
59
60 static int show_progress = 0;
61 int ibdebug;
62
63 void decode_port_info(ibnd_port_t * port)
64 {
65         port->base_lid = (uint16_t) mad_get_field(port->info, 0, IB_PORT_LID_F);
66         port->lmc = (uint8_t) mad_get_field(port->info, 0, IB_PORT_LMC_F);
67 }
68
69 static int get_port_info(struct ibmad_port *ibmad_port,
70                          ibnd_fabric_t * fabric, ibnd_port_t * port,
71                          int portnum, ib_portid_t * portid)
72 {
73         char width[64], speed[64];
74         int iwidth;
75         int ispeed;
76
77         port->portnum = portnum;
78         iwidth = mad_get_field(port->info, 0, IB_PORT_LINK_WIDTH_ACTIVE_F);
79         ispeed = mad_get_field(port->info, 0, IB_PORT_LINK_SPEED_ACTIVE_F);
80
81         if (!smp_query_via(port->info, portid, IB_ATTR_PORT_INFO,
82                            portnum, 0, ibmad_port))
83                 return -1;
84
85         decode_port_info(port);
86
87         IBND_DEBUG
88             ("portid %s portnum %d: base lid %d state %d physstate %d %s %s\n",
89              portid2str(portid), portnum, port->base_lid,
90              mad_get_field(port->info, 0, IB_PORT_STATE_F),
91              mad_get_field(port->info, 0, IB_PORT_PHYS_STATE_F),
92              mad_dump_val(IB_PORT_LINK_WIDTH_ACTIVE_F, width, 64, &iwidth),
93              mad_dump_val(IB_PORT_LINK_SPEED_ACTIVE_F, speed, 64, &ispeed));
94         return 0;
95 }
96
97 /*
98  * Returns -1 if error.
99  */
100 static int query_node_info(struct ibmad_port *ibmad_port,
101                            ibnd_fabric_t * fabric, ibnd_node_t * node,
102                            ib_portid_t * portid)
103 {
104         if (!smp_query_via(&(node->info), portid, IB_ATTR_NODE_INFO, 0, 0,
105                            ibmad_port))
106                 return -1;
107
108         /* decode just a couple of fields for quicker reference. */
109         mad_decode_field(node->info, IB_NODE_GUID_F, &(node->guid));
110         mad_decode_field(node->info, IB_NODE_TYPE_F, &(node->type));
111         mad_decode_field(node->info, IB_NODE_NPORTS_F, &(node->numports));
112
113         return (0);
114 }
115
116 /*
117  * Returns 0 if non switch node is found, 1 if switch is found, -1 if error.
118  */
119 static int query_node(struct ibmad_port *ibmad_port, ibnd_fabric_t * fabric,
120                       ibnd_node_t * node, ibnd_port_t * port,
121                       ib_portid_t * portid)
122 {
123         int rc = 0;
124         void *nd = node->nodedesc;
125
126         if ((rc = query_node_info(ibmad_port, fabric, node, portid)) != 0)
127                 return rc;
128
129         port->portnum = mad_get_field(node->info, 0, IB_NODE_LOCAL_PORT_F);
130         port->guid = mad_get_field64(node->info, 0, IB_NODE_PORT_GUID_F);
131
132         if (!smp_query_via(nd, portid, IB_ATTR_NODE_DESC, 0, 0, ibmad_port))
133                 return -1;
134
135         if (!smp_query_via(port->info, portid, IB_ATTR_PORT_INFO, 0, 0,
136                            ibmad_port))
137                 return -1;
138         decode_port_info(port);
139
140         if (node->type != IB_NODE_SWITCH)
141                 return 0;
142
143         node->smalid = port->base_lid;
144         node->smalmc = port->lmc;
145
146         /* after we have the sma information find out the real PortInfo for this port */
147         if (!smp_query_via(port->info, portid, IB_ATTR_PORT_INFO,
148                            port->portnum, 0, ibmad_port))
149                 return -1;
150         decode_port_info(port);
151
152         port->base_lid = (uint16_t) node->smalid;       /* LID is still defined by port 0 */
153         port->lmc = (uint8_t) node->smalmc;
154
155         if (!smp_query_via(node->switchinfo, portid, IB_ATTR_SWITCH_INFO, 0, 0,
156                            ibmad_port))
157                 node->smaenhsp0 = 0;    /* assume base SP0 */
158         else
159                 mad_decode_field(node->switchinfo, IB_SW_ENHANCED_PORT0_F,
160                                  &node->smaenhsp0);
161
162         IBND_DEBUG("portid %s: got switch node %" PRIx64 " '%s'\n",
163                    portid2str(portid), node->guid, node->nodedesc);
164         return 0;
165 }
166
167 static int add_port_to_dpath(ib_dr_path_t * path, int nextport)
168 {
169         if (path->cnt + 2 >= sizeof(path->p)) {
170                 IBND_ERROR("DR path has grown too long\n");
171                 return -1;
172         }
173         ++path->cnt;
174         path->p[path->cnt] = (uint8_t) nextport;
175         return path->cnt;
176 }
177
178 static void retract_dpath(ib_portid_t * path)
179 {
180         path->drpath.cnt--;     /* restore path */
181         if (path->drpath.cnt == 0 && path->lid) {
182                 /* return to lid based routing on this path */
183                 path->drpath.drslid = 0;
184                 path->drpath.drdlid = 0;
185         }
186 }
187
188 static int extend_dpath(struct ibmad_port *ibmad_port, ibnd_fabric_t * fabric,
189                         ib_portid_t * portid, int nextport)
190 {
191         int rc = 0;
192
193         if (portid->lid) {
194                 /* If we were LID routed we need to set up the drslid */
195                 if (!fabric->selfportid.lid)
196                         if (ib_resolve_self_via(&fabric->selfportid, NULL, NULL,
197                                                 ibmad_port) < 0) {
198                                 IBND_ERROR("Failed to resolve self\n");
199                                 return -1;
200                         }
201
202                 portid->drpath.drslid = (uint16_t) fabric->selfportid.lid;
203                 portid->drpath.drdlid = 0xFFFF;
204         }
205
206         rc = add_port_to_dpath(&portid->drpath, nextport);
207
208         if ((rc != -1) && (portid->drpath.cnt > fabric->maxhops_discovered))
209                 fabric->maxhops_discovered = portid->drpath.cnt;
210         return (rc);
211 }
212
213 static void dump_endnode(ib_portid_t * path, char *prompt,
214                          ibnd_node_t * node, ibnd_port_t * port)
215 {
216         char type[64];
217         if (!show_progress)
218                 return;
219
220         mad_dump_node_type(type, 64, &(node->type), sizeof(int));
221         printf("%s -> %s %s {%016" PRIx64 "} portnum %d base lid %d-%d\"%s\"\n",
222                portid2str(path), prompt, type, node->guid,
223                node->type == IB_NODE_SWITCH ? 0 : port->portnum,
224                port->base_lid,
225                port->base_lid + (1 << port->lmc) - 1, node->nodedesc);
226 }
227
228 static ibnd_node_t *find_existing_node(ibnd_fabric_t * fabric,
229                                        ibnd_node_t * new)
230 {
231         int hash = HASHGUID(new->guid) % HTSZ;
232         ibnd_node_t *node;
233
234         for (node = fabric->nodestbl[hash]; node; node = node->htnext)
235                 if (node->guid == new->guid)
236                         return node;
237
238         return NULL;
239 }
240
241 ibnd_node_t *ibnd_find_node_guid(ibnd_fabric_t * fabric, uint64_t guid)
242 {
243         int hash = HASHGUID(guid) % HTSZ;
244         ibnd_node_t *node;
245
246         if (!fabric) {
247                 IBND_DEBUG("fabric parameter NULL\n");
248                 return (NULL);
249         }
250
251         for (node = fabric->nodestbl[hash]; node; node = node->htnext)
252                 if (node->guid == guid)
253                         return (ibnd_node_t *) node;
254
255         return NULL;
256 }
257
258 static int _check_ibmad_port(struct ibmad_port *ibmad_port)
259 {
260         if (!ibmad_port) {
261                 IBND_DEBUG("ibmad_port must be specified\n");
262                 return (-1);
263         }
264         if (mad_rpc_class_agent(ibmad_port, IB_SMI_CLASS) == -1
265             || mad_rpc_class_agent(ibmad_port, IB_SMI_DIRECT_CLASS) == -1) {
266                 IBND_DEBUG("ibmad_port must be opened with "
267                            "IB_SMI_CLASS && IB_SMI_DIRECT_CLASS\n");
268                 return (-1);
269         }
270         return (0);
271 }
272
273 ibnd_node_t *ibnd_update_node(struct ibmad_port * ibmad_port,
274                               ibnd_fabric_t * fabric, ibnd_node_t * node)
275 {
276         char portinfo_port0[IB_SMP_DATA_SIZE];
277         void *nd = node->nodedesc;
278         int p = 0;
279
280         if (_check_ibmad_port(ibmad_port) < 0)
281                 return (NULL);
282
283         if (!fabric) {
284                 IBND_DEBUG("fabric parameter NULL\n");
285                 return (NULL);
286         }
287
288         if (!node) {
289                 IBND_DEBUG("node parameter NULL\n");
290                 return (NULL);
291         }
292
293         if (query_node_info(ibmad_port, fabric, node, &(node->path_portid)))
294                 return (NULL);
295
296         if (!smp_query_via(nd, &(node->path_portid), IB_ATTR_NODE_DESC, 0, 0,
297                            ibmad_port))
298                 return (NULL);
299
300         /* update all the port info's */
301         for (p = 1; p >= node->numports; p++) {
302                 get_port_info(ibmad_port, fabric, node->ports[p],
303                               p, &(node->path_portid));
304         }
305
306         if (node->type != IB_NODE_SWITCH)
307                 goto done;
308
309         if (!smp_query_via
310             (portinfo_port0, &(node->path_portid), IB_ATTR_PORT_INFO, 0, 0,
311              ibmad_port))
312                 return (NULL);
313
314         node->smalid = mad_get_field(portinfo_port0, 0, IB_PORT_LID_F);
315         node->smalmc = mad_get_field(portinfo_port0, 0, IB_PORT_LMC_F);
316
317         if (!smp_query_via(node->switchinfo, &(node->path_portid),
318                            IB_ATTR_SWITCH_INFO, 0, 0, ibmad_port))
319                 node->smaenhsp0 = 0;    /* assume base SP0 */
320         else
321                 mad_decode_field(node->switchinfo, IB_SW_ENHANCED_PORT0_F,
322                                  &node->smaenhsp0);
323
324 done:
325         return (node);
326 }
327
328 ibnd_node_t *ibnd_find_node_dr(ibnd_fabric_t * fabric, char *dr_str)
329 {
330         int i = 0;
331         ibnd_node_t *rc;
332         ib_dr_path_t path;
333
334         if (!fabric) {
335                 IBND_DEBUG("fabric parameter NULL\n");
336                 return (NULL);
337         }
338
339         rc = fabric->from_node;
340
341         if (str2drpath(&path, dr_str, 0, 0) == -1) {
342                 return (NULL);
343         }
344
345         for (i = 0; i <= path.cnt; i++) {
346                 ibnd_port_t *remote_port = NULL;
347                 if (path.p[i] == 0)
348                         continue;
349                 if (!rc->ports)
350                         return (NULL);
351
352                 remote_port = rc->ports[path.p[i]]->remoteport;
353                 if (!remote_port)
354                         return (NULL);
355
356                 rc = remote_port->node;
357         }
358
359         return (rc);
360 }
361
362 static void add_to_nodeguid_hash(ibnd_node_t * node, ibnd_node_t * hash[])
363 {
364         int hash_idx = HASHGUID(node->guid) % HTSZ;
365
366         node->htnext = hash[hash_idx];
367         hash[hash_idx] = node;
368 }
369
370 static void add_to_portguid_hash(ibnd_port_t * port, ibnd_port_t * hash[])
371 {
372         int hash_idx = HASHGUID(port->guid) % HTSZ;
373
374         port->htnext = hash[hash_idx];
375         hash[hash_idx] = port;
376 }
377
378 static void add_to_type_list(ibnd_node_t * node, ibnd_fabric_t * fabric)
379 {
380         switch (node->type) {
381         case IB_NODE_CA:
382                 node->type_next = fabric->ch_adapters;
383                 fabric->ch_adapters = node;
384                 break;
385         case IB_NODE_SWITCH:
386                 node->type_next = fabric->switches;
387                 fabric->switches = node;
388                 break;
389         case IB_NODE_ROUTER:
390                 node->type_next = fabric->routers;
391                 fabric->routers = node;
392                 break;
393         }
394 }
395
396 static void add_to_nodedist(ibnd_node_t * node, ibnd_fabric_t * fabric)
397 {
398         int dist = node->dist;
399         if (node->type != IB_NODE_SWITCH)
400                 dist = MAXHOPS; /* special Ca list */
401
402         node->dnext = fabric->nodesdist[dist];
403         fabric->nodesdist[dist] = node;
404 }
405
406 static ibnd_node_t *create_node(ibnd_fabric_t * fabric,
407                                 ibnd_node_t * temp, ib_portid_t * path,
408                                 int dist)
409 {
410         ibnd_node_t *node;
411
412         node = malloc(sizeof(*node));
413         if (!node) {
414                 IBND_ERROR("OOM: node creation failed\n");
415                 return (NULL);
416         }
417
418         memcpy(node, temp, sizeof(*node));
419         node->dist = dist;
420         node->path_portid = *path;
421
422         add_to_nodeguid_hash(node, fabric->nodestbl);
423
424         /* add this to the all nodes list */
425         node->next = fabric->nodes;
426         fabric->nodes = (ibnd_node_t *) node;
427
428         add_to_type_list(node, fabric);
429         add_to_nodedist(node, fabric);
430
431         return node;
432 }
433
434 static struct ibnd_port *find_existing_port_node(ibnd_node_t * node,
435                                                  ibnd_port_t * port)
436 {
437         if (port->portnum > node->numports || node->ports == NULL)
438                 return (NULL);
439
440         return (node->ports[port->portnum]);
441 }
442
443 static struct ibnd_port *add_port_to_node(ibnd_fabric_t * fabric,
444                                           ibnd_node_t * node,
445                                           ibnd_port_t * temp)
446 {
447         ibnd_port_t *port;
448
449         if (node->ports == NULL) {
450                 node->ports = calloc(sizeof(*node->ports), node->numports + 1);
451                 if (!node->ports) {
452                         IBND_ERROR("Failed to allocate the ports array\n");
453                         return (NULL);
454                 }
455         }
456
457         port = malloc(sizeof(*port));
458         if (!port) {
459                 IBND_ERROR("Failed to allocate port\n");
460                 return NULL;
461         }
462
463         memcpy(port, temp, sizeof(*port));
464         port->node = (ibnd_node_t *) node;
465         port->ext_portnum = 0;
466
467         node->ports[temp->portnum] = (ibnd_port_t *) port;
468
469         add_to_portguid_hash(port, fabric->portstbl);
470         return port;
471 }
472
473 static void link_ports(ibnd_node_t * node, ibnd_port_t * port,
474                        ibnd_node_t * remotenode, ibnd_port_t * remoteport)
475 {
476         IBND_DEBUG("linking: 0x%" PRIx64 " %p->%p:%u and 0x%" PRIx64
477                    " %p->%p:%u\n", node->guid, node, port, port->portnum,
478                    remotenode->guid, remotenode, remoteport,
479                    remoteport->portnum);
480         if (port->remoteport)
481                 port->remoteport->remoteport = NULL;
482         if (remoteport->remoteport)
483                 remoteport->remoteport->remoteport = NULL;
484         port->remoteport = (ibnd_port_t *) remoteport;
485         remoteport->remoteport = (ibnd_port_t *) port;
486 }
487
488 static int get_remote_node(struct ibmad_port *ibmad_port,
489                            ibnd_fabric_t * fabric, ibnd_node_t * node,
490                            ibnd_port_t * port, ib_portid_t * path,
491                            int portnum, int dist)
492 {
493         int rc = 0;
494         ibnd_node_t node_buf;
495         ibnd_port_t port_buf;
496         ibnd_node_t *remotenode, *oldnode;
497         ibnd_port_t *remoteport, *oldport;
498
499         memset(&node_buf, 0, sizeof(node_buf));
500         memset(&port_buf, 0, sizeof(port_buf));
501
502         IBND_DEBUG("handle node %p port %p:%d dist %d\n", node, port, portnum,
503                    dist);
504
505         if (mad_get_field(port->info, 0, IB_PORT_PHYS_STATE_F)
506             != IB_PORT_PHYS_STATE_LINKUP)
507                 return 1;       /* positive == non-fatal error */
508
509         if (extend_dpath(ibmad_port, fabric, path, portnum) < 0)
510                 return -1;
511
512         if (query_node(ibmad_port, fabric, &node_buf, &port_buf, path)) {
513                 IBND_ERROR("Query remote node (%s) failed, skipping port\n",
514                            portid2str(path));
515                 retract_dpath(path);
516                 return 1;       /* positive == non-fatal error */
517         }
518
519         oldnode = find_existing_node(fabric, &node_buf);
520         if (oldnode)
521                 remotenode = oldnode;
522         else if (!(remotenode = create_node(fabric, &node_buf, path, dist + 1))) {
523                 rc = -1;
524                 goto error;
525         }
526
527         oldport = find_existing_port_node(remotenode, &port_buf);
528         if (oldport) {
529                 remoteport = oldport;
530         } else if (!(remoteport = add_port_to_node(fabric, remotenode,
531                                                    &port_buf))) {
532                 IBND_ERROR("OOM failed to add port to node\n");
533                 rc = -1;
534                 goto error;
535         }
536
537         dump_endnode(path, oldnode ? "known remote" : "new remote",
538                      remotenode, remoteport);
539
540         link_ports(node, port, remotenode, remoteport);
541
542 error:
543         retract_dpath(path);
544         return (rc);
545 }
546
547 ibnd_fabric_t *ibnd_discover_fabric(struct ibmad_port * ibmad_port,
548                                     ib_portid_t * from, int hops)
549 {
550         int rc = 0;
551         ibnd_fabric_t *fabric = NULL;
552         ib_portid_t my_portid = { 0 };
553         ibnd_node_t node_buf;
554         ibnd_port_t port_buf;
555         ibnd_node_t *node;
556         ibnd_port_t *port;
557         int i;
558         int dist = 0;
559         ib_portid_t *path;
560         int max_hops = MAXHOPS - 1;     /* default find everything */
561
562         if (_check_ibmad_port(ibmad_port) < 0)
563                 return (NULL);
564
565         /* if not everything how much? */
566         if (hops >= 0) {
567                 max_hops = hops;
568         }
569
570         /* If not specified start from "my" port */
571         if (!from)
572                 from = &my_portid;
573
574         fabric = malloc(sizeof(*fabric));
575
576         if (!fabric) {
577                 IBND_ERROR("OOM: failed to malloc ibnd_fabric_t\n");
578                 return (NULL);
579         }
580
581         memset(fabric, 0, sizeof(*fabric));
582
583         IBND_DEBUG("from %s\n", portid2str(from));
584
585         memset(&node_buf, 0, sizeof(node_buf));
586         memset(&port_buf, 0, sizeof(port_buf));
587
588         if (query_node(ibmad_port, fabric, &node_buf, &port_buf, from)) {
589                 IBND_DEBUG("can't reach node %s\n", portid2str(from));
590                 goto error;
591         }
592
593         node = create_node(fabric, &node_buf, from, 0);
594         if (!node)
595                 goto error;
596
597         fabric->from_node = (ibnd_node_t *) node;
598
599         port = add_port_to_node(fabric, node, &port_buf);
600         if (!port)
601                 goto error;
602
603         if (node->type != IB_NODE_SWITCH) {
604                 rc = get_remote_node(ibmad_port, fabric, node, port, from,
605                                      mad_get_field(node->info, 0,
606                                                    IB_NODE_LOCAL_PORT_F), 0);
607                 if (rc < 0)
608                         goto error;
609                 if (rc > 0)             /* non-fatal error, nothing more to be done */
610                         return ((ibnd_fabric_t *) fabric);
611         }
612
613         for (dist = 0; dist <= max_hops; dist++) {
614
615                 for (node = fabric->nodesdist[dist]; node; node = node->dnext) {
616
617                         path = &node->path_portid;
618
619                         IBND_DEBUG("dist %d node %p\n", dist, node);
620                         dump_endnode(path, "processing", node, port);
621
622                         for (i = 1; i <= node->numports; i++) {
623                                 if (i == mad_get_field(node->info, 0,
624                                                        IB_NODE_LOCAL_PORT_F))
625                                         continue;
626
627                                 if (get_port_info(ibmad_port, fabric,
628                                                   &port_buf, i, path)) {
629                                         IBND_ERROR
630                                             ("can't reach node %s port %d\n",
631                                              portid2str(path), i);
632                                         continue;
633                                 }
634
635                                 port = find_existing_port_node(node, &port_buf);
636                                 if (port)
637                                         continue;
638
639                                 port =
640                                     add_port_to_node(fabric, node, &port_buf);
641                                 if (!port)
642                                         goto error;
643
644                                 /* If switch, set port GUID to node port GUID */
645                                 if (node->type == IB_NODE_SWITCH) {
646                                         port->guid =
647                                             mad_get_field64(node->info, 0,
648                                                             IB_NODE_PORT_GUID_F);
649                                 }
650
651                                 if (get_remote_node(ibmad_port, fabric, node,
652                                                     port, path, i, dist) < 0)
653                                         goto error;
654                         }
655                 }
656         }
657
658         if (group_nodes(fabric))
659                 goto error;
660
661         return ((ibnd_fabric_t *) fabric);
662 error:
663         ibnd_destroy_fabric((ibnd_fabric_t *) fabric);
664         return (NULL);
665 }
666
667 static void destroy_node(ibnd_node_t * node)
668 {
669         int p = 0;
670
671         for (p = 0; p <= node->numports; p++) {
672                 free(node->ports[p]);
673         }
674         free(node->ports);
675         free(node);
676 }
677
678 void ibnd_destroy_fabric(ibnd_fabric_t * fabric)
679 {
680         int dist = 0;
681         ibnd_node_t *node = NULL;
682         ibnd_node_t *next = NULL;
683         ibnd_chassis_t *ch, *ch_next;
684
685         if (!fabric)
686                 return;
687
688         ch = fabric->first_chassis;
689         while (ch) {
690                 ch_next = ch->next;
691                 free(ch);
692                 ch = ch_next;
693         }
694         for (dist = 0; dist <= MAXHOPS; dist++) {
695                 node = fabric->nodesdist[dist];
696                 while (node) {
697                         next = node->dnext;
698                         destroy_node(node);
699                         node = next;
700                 }
701         }
702         free(fabric);
703 }
704
705 void ibnd_debug(int i)
706 {
707         if (i) {
708                 ibdebug++;
709                 madrpc_show_errors(1);
710                 umad_debug(i);
711         } else {
712                 ibdebug = 0;
713                 madrpc_show_errors(0);
714                 umad_debug(0);
715         }
716 }
717
718 void ibnd_show_progress(int i)
719 {
720         show_progress = i;
721 }
722
723 void ibnd_iter_nodes(ibnd_fabric_t * fabric, ibnd_iter_node_func_t func,
724                      void *user_data)
725 {
726         ibnd_node_t *cur = NULL;
727
728         if (!fabric) {
729                 IBND_DEBUG("fabric parameter NULL\n");
730                 return;
731         }
732
733         if (!func) {
734                 IBND_DEBUG("func parameter NULL\n");
735                 return;
736         }
737
738         for (cur = fabric->nodes; cur; cur = cur->next) {
739                 func(cur, user_data);
740         }
741 }
742
743 void ibnd_iter_nodes_type(ibnd_fabric_t * fabric, ibnd_iter_node_func_t func,
744                           int node_type, void *user_data)
745 {
746         ibnd_node_t *list = NULL;
747         ibnd_node_t *cur = NULL;
748
749         if (!fabric) {
750                 IBND_DEBUG("fabric parameter NULL\n");
751                 return;
752         }
753
754         if (!func) {
755                 IBND_DEBUG("func parameter NULL\n");
756                 return;
757         }
758
759         switch (node_type) {
760         case IB_NODE_SWITCH:
761                 list = fabric->switches;
762                 break;
763         case IB_NODE_CA:
764                 list = fabric->ch_adapters;
765                 break;
766         case IB_NODE_ROUTER:
767                 list = fabric->routers;
768                 break;
769         default:
770                 IBND_DEBUG("Invalid node_type specified %d\n", node_type);
771                 break;
772         }
773
774         for (cur = list; cur; cur = cur->type_next) {
775                 func((ibnd_node_t *) cur, user_data);
776         }
777 }