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