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