]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/ofed/management/opensm/opensm/osm_ucast_updn.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / ofed / management / opensm / opensm / osm_ucast_updn.c
1 /*
2  * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved.
3  * Copyright (c) 2002-2006 Mellanox Technologies LTD. All rights reserved.
4  * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
5  *
6  * This software is available to you under a choice of one of two
7  * licenses.  You may choose to be licensed under the terms of the GNU
8  * General Public License (GPL) Version 2, available from the file
9  * COPYING in the main directory of this source tree, or the
10  * OpenIB.org BSD license below:
11  *
12  *     Redistribution and use in source and binary forms, with or
13  *     without modification, are permitted provided that the following
14  *     conditions are met:
15  *
16  *      - Redistributions of source code must retain the above
17  *        copyright notice, this list of conditions and the following
18  *        disclaimer.
19  *
20  *      - Redistributions in binary form must reproduce the above
21  *        copyright notice, this list of conditions and the following
22  *        disclaimer in the documentation and/or other materials
23  *        provided with the distribution.
24  *
25  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32  * SOFTWARE.
33  *
34  */
35
36 /*
37  * Abstract:
38  *      Implementation of Up Down Algorithm using ranking & Min Hop
39  *      Calculation functions
40  */
41
42 #if HAVE_CONFIG_H
43 #  include <config.h>
44 #endif                          /* HAVE_CONFIG_H */
45
46 #include <stdlib.h>
47 #include <ctype.h>
48 #include <complib/cl_debug.h>
49 #include <complib/cl_qmap.h>
50 #include <opensm/osm_switch.h>
51 #include <opensm/osm_opensm.h>
52 #include <opensm/osm_ucast_mgr.h>
53
54 /* //////////////////////////// */
55 /*  Local types                 */
56 /* //////////////////////////// */
57
58 /* direction */
59 typedef enum updn_switch_dir {
60         UP = 0,
61         DOWN
62 } updn_switch_dir_t;
63
64 /* updn structure */
65 typedef struct updn {
66         unsigned num_roots;
67         osm_opensm_t *p_osm;
68 } updn_t;
69
70 struct updn_node {
71         cl_list_item_t list;
72         osm_switch_t *sw;
73         uint64_t id;
74         updn_switch_dir_t dir;
75         unsigned rank;
76         unsigned visited;
77 };
78
79 /**********************************************************************
80  **********************************************************************/
81 /* This function returns direction based on rank and guid info of current &
82    remote ports */
83 static updn_switch_dir_t updn_get_dir(unsigned cur_rank, unsigned rem_rank,
84                                       uint64_t cur_id, uint64_t rem_id)
85 {
86         /* HACK: comes to solve root nodes connection, in a classic subnet root nodes do not connect
87            directly, but in case they are we assign to root node an UP direction to allow UPDN to discover
88            the subnet correctly (and not from the point of view of the last root node).
89          */
90         if (!cur_rank && !rem_rank)
91                 return UP;
92
93         if (cur_rank < rem_rank)
94                 return DOWN;
95         else if (cur_rank > rem_rank)
96                 return UP;
97         else {
98                 /* Equal rank, decide by id number, bigger == UP direction */
99                 if (cur_id > rem_id)
100                         return UP;
101                 else
102                         return DOWN;
103         }
104 }
105
106 /**********************************************************************
107  * This function does the bfs of min hop table calculation by guid index
108  * as a starting point.
109  **********************************************************************/
110 static int updn_bfs_by_node(IN osm_log_t * p_log, IN osm_subn_t * p_subn,
111                             IN osm_switch_t * p_sw)
112 {
113         uint8_t pn, pn_rem;
114         cl_qlist_t list;
115         uint16_t lid;
116         struct updn_node *u;
117         updn_switch_dir_t next_dir, current_dir;
118
119         OSM_LOG_ENTER(p_log);
120
121         lid = osm_node_get_base_lid(p_sw->p_node, 0);
122         lid = cl_ntoh16(lid);
123         osm_switch_set_hops(p_sw, lid, 0, 0);
124
125         OSM_LOG(p_log, OSM_LOG_DEBUG,
126                 "Starting from switch - port GUID 0x%" PRIx64 " lid %u\n",
127                 cl_ntoh64(p_sw->p_node->node_info.port_guid), lid);
128
129         u = p_sw->priv;
130         u->dir = UP;
131
132         /* Update list with the new element */
133         cl_qlist_init(&list);
134         cl_qlist_insert_tail(&list, &u->list);
135
136         /* BFS the list till no next element */
137         while (!cl_is_qlist_empty(&list)) {
138                 u = (struct updn_node *)cl_qlist_remove_head(&list);
139                 u->visited = 0; /* cleanup */
140                 current_dir = u->dir;
141                 /* Go over all ports of the switch and find unvisited remote nodes */
142                 for (pn = 1; pn < u->sw->num_ports; pn++) {
143                         osm_node_t *p_remote_node;
144                         struct updn_node *rem_u;
145                         uint8_t current_min_hop, remote_min_hop,
146                             set_hop_return_value;
147                         osm_switch_t *p_remote_sw;
148
149                         p_remote_node =
150                             osm_node_get_remote_node(u->sw->p_node, pn,
151                                                      &pn_rem);
152                         /* If no remote node OR remote node is not a SWITCH
153                            continue to next pn */
154                         if (!p_remote_node || !p_remote_node->sw)
155                                 continue;
156                         /* Fetch remote guid only after validation of remote node */
157                         p_remote_sw = p_remote_node->sw;
158                         rem_u = p_remote_sw->priv;
159                         /* Decide which direction to mark it (UP/DOWN) */
160                         next_dir = updn_get_dir(u->rank, rem_u->rank,
161                                                 u->id, rem_u->id);
162
163                         /* Check if this is a legal step : the only illegal step is going
164                            from DOWN to UP */
165                         if ((current_dir == DOWN) && (next_dir == UP)) {
166                                 OSM_LOG(p_log, OSM_LOG_DEBUG,
167                                         "Avoiding move from 0x%016" PRIx64
168                                         " to 0x%016" PRIx64 "\n",
169                                         cl_ntoh64(osm_node_get_node_guid(u->sw->p_node)),
170                                         cl_ntoh64(osm_node_get_node_guid(p_remote_node)));
171                                 /* Illegal step */
172                                 continue;
173                         }
174                         /* Set MinHop value for the current lid */
175                         current_min_hop = osm_switch_get_least_hops(u->sw, lid);
176                         /* Check hop count if better insert into list && update
177                            the remote node Min Hop Table */
178                         remote_min_hop =
179                             osm_switch_get_hop_count(p_remote_sw, lid, pn_rem);
180                         if (current_min_hop + 1 < remote_min_hop) {
181                                 set_hop_return_value =
182                                     osm_switch_set_hops(p_remote_sw, lid,
183                                                         pn_rem,
184                                                         current_min_hop + 1);
185                                 if (set_hop_return_value) {
186                                         OSM_LOG(p_log, OSM_LOG_ERROR, "ERR AA01: "
187                                                 "Invalid value returned from set min hop is: %d\n",
188                                                 set_hop_return_value);
189                                 }
190                                 /* Check if remote port has already been visited */
191                                 if (!rem_u->visited) {
192                                         /* Insert updn_switch item into the list */
193                                         rem_u->dir = next_dir;
194                                         rem_u->visited = 1;
195                                         cl_qlist_insert_tail(&list,
196                                                              &rem_u->list);
197                                 }
198                         }
199                 }
200         }
201
202         OSM_LOG_EXIT(p_log);
203         return 0;
204 }
205
206 /**********************************************************************
207  **********************************************************************/
208 /* NOTE : PLS check if we need to decide that the first */
209 /*        rank is a SWITCH for BFS purpose */
210 static int updn_subn_rank(IN updn_t * p_updn)
211 {
212         osm_switch_t *p_sw;
213         osm_physp_t *p_physp, *p_remote_physp;
214         cl_qlist_t list;
215         cl_map_item_t *item;
216         struct updn_node *u, *remote_u;
217         uint8_t num_ports, port_num;
218         osm_log_t *p_log = &p_updn->p_osm->log;
219         unsigned max_rank = 0;
220
221         OSM_LOG_ENTER(p_log);
222         cl_qlist_init(&list);
223
224         /* add all roots to the list */
225         for (item = cl_qmap_head(&p_updn->p_osm->subn.sw_guid_tbl);
226              item != cl_qmap_end(&p_updn->p_osm->subn.sw_guid_tbl);
227              item = cl_qmap_next(item)) {
228                 p_sw = (osm_switch_t *)item;
229                 u = p_sw->priv;
230                 if (!u->rank)
231                         cl_qlist_insert_tail(&list, &u->list);
232         }
233
234         /* BFS the list till it's empty */
235         while (!cl_is_qlist_empty(&list)) {
236                 u = (struct updn_node *)cl_qlist_remove_head(&list);
237                 /* Go over all remote nodes and rank them (if not already visited) */
238                 p_sw = u->sw;
239                 num_ports = p_sw->num_ports;
240                 OSM_LOG(p_log, OSM_LOG_DEBUG,
241                         "Handling switch GUID 0x%" PRIx64 "\n",
242                         cl_ntoh64(osm_node_get_node_guid(p_sw->p_node)));
243                 for (port_num = 1; port_num < num_ports; port_num++) {
244                         ib_net64_t port_guid;
245
246                         /* Current port fetched in order to get remote side */
247                         p_physp =
248                             osm_node_get_physp_ptr(p_sw->p_node, port_num);
249
250                         if (!p_physp)
251                                 continue;
252
253                         p_remote_physp = p_physp->p_remote_physp;
254
255                         /*
256                            make sure that all the following occur on p_remote_physp:
257                            1. The port isn't NULL
258                            2. It is a switch
259                          */
260                         if (p_remote_physp && p_remote_physp->p_node->sw) {
261                                 remote_u = p_remote_physp->p_node->sw->priv;
262                                 port_guid = p_remote_physp->port_guid;
263
264                                 if (remote_u->rank > u->rank + 1) {
265                                         remote_u->rank = u->rank + 1;
266                                         max_rank = remote_u->rank;
267                                         cl_qlist_insert_tail(&list,
268                                                              &remote_u->list);
269                                         OSM_LOG(p_log, OSM_LOG_DEBUG,
270                                                 "Rank of port GUID 0x%" PRIx64
271                                                 " = %u\n", cl_ntoh64(port_guid),
272                                                 remote_u->rank);
273                                 }
274                         }
275                 }
276         }
277
278         /* Print Summary of ranking */
279         OSM_LOG(p_log, OSM_LOG_VERBOSE,
280                 "Subnet ranking completed. Max Node Rank = %d\n", max_rank);
281         OSM_LOG_EXIT(p_log);
282         return 0;
283 }
284
285 /**********************************************************************
286  **********************************************************************/
287 /* hack: preserve min hops entries to any other root switches */
288 static void updn_clear_root_hops(updn_t * p_updn, osm_switch_t * p_sw)
289 {
290         osm_port_t *p_port;
291         unsigned i;
292
293         for (i = 0; i < p_sw->num_hops; i++)
294                 if (p_sw->hops[i]) {
295                         p_port =
296                             cl_ptr_vector_get(&p_updn->p_osm->subn.port_lid_tbl,
297                                               i);
298                         if (!p_port || !p_port->p_node->sw
299                             || ((struct updn_node *)p_port->p_node->sw->priv)->
300                             rank != 0)
301                                 memset(p_sw->hops[i], 0xff, p_sw->num_ports);
302                 }
303 }
304
305 /**********************************************************************
306  **********************************************************************/
307 static int updn_set_min_hop_table(IN updn_t * p_updn)
308 {
309         osm_subn_t *p_subn = &p_updn->p_osm->subn;
310         osm_log_t *p_log = &p_updn->p_osm->log;
311         osm_switch_t *p_sw;
312         cl_map_item_t *item;
313
314         OSM_LOG_ENTER(p_log);
315
316         /* Go over all the switches in the subnet - for each init their Min Hop
317            Table */
318         OSM_LOG(p_log, OSM_LOG_VERBOSE,
319                 "Init Min Hop Table of all switches [\n");
320
321         for (item = cl_qmap_head(&p_updn->p_osm->subn.sw_guid_tbl);
322              item != cl_qmap_end(&p_updn->p_osm->subn.sw_guid_tbl);
323              item = cl_qmap_next(item)) {
324                 p_sw = (osm_switch_t *)item;
325                 /* Clear Min Hop Table */
326                 if (p_subn->opt.connect_roots)
327                         updn_clear_root_hops(p_updn, p_sw);
328                 else
329                         osm_switch_clear_hops(p_sw);
330         }
331
332         OSM_LOG(p_log, OSM_LOG_VERBOSE,
333                 "Init Min Hop Table of all switches ]\n");
334
335         /* Now do the BFS for each port  in the subnet */
336         OSM_LOG(p_log, OSM_LOG_VERBOSE,
337                 "BFS through all port guids in the subnet [\n");
338
339         for (item = cl_qmap_head(&p_updn->p_osm->subn.sw_guid_tbl);
340              item != cl_qmap_end(&p_updn->p_osm->subn.sw_guid_tbl);
341              item = cl_qmap_next(item)) {
342                 p_sw = (osm_switch_t *)item;
343                 updn_bfs_by_node(p_log, p_subn, p_sw);
344         }
345
346         OSM_LOG(p_log, OSM_LOG_VERBOSE,
347                 "BFS through all port guids in the subnet ]\n");
348         /* Cleanup */
349         OSM_LOG_EXIT(p_log);
350         return 0;
351 }
352
353 /**********************************************************************
354  **********************************************************************/
355 static int updn_build_lid_matrices(IN updn_t * p_updn)
356 {
357         int status;
358
359         OSM_LOG_ENTER(&p_updn->p_osm->log);
360
361         OSM_LOG(&p_updn->p_osm->log, OSM_LOG_VERBOSE,
362                 "Ranking all port guids in the list\n");
363         if (!p_updn->num_roots) {
364                 OSM_LOG(&p_updn->p_osm->log, OSM_LOG_ERROR, "ERR AA0A: "
365                         "No guids were provided or number of guids is 0\n");
366                 status = -1;
367                 goto _exit;
368         }
369
370         /* Check if it's not a switched subnet */
371         if (cl_is_qmap_empty(&p_updn->p_osm->subn.sw_guid_tbl)) {
372                 OSM_LOG(&p_updn->p_osm->log, OSM_LOG_ERROR, "ERR AAOB: "
373                         "This is not a switched subnet, cannot perform UPDN algorithm\n");
374                 status = -1;
375                 goto _exit;
376         }
377
378         /* Rank the subnet switches */
379         updn_subn_rank(p_updn);
380
381         /* After multiple ranking need to set Min Hop Table by UpDn algorithm  */
382         OSM_LOG(&p_updn->p_osm->log, OSM_LOG_VERBOSE,
383                 "Setting all switches' Min Hop Table\n");
384         status = updn_set_min_hop_table(p_updn);
385
386 _exit:
387         OSM_LOG_EXIT(&p_updn->p_osm->log);
388         return status;
389 }
390
391 /**********************************************************************
392  **********************************************************************/
393 static struct updn_node *create_updn_node(osm_switch_t * sw)
394 {
395         struct updn_node *u;
396
397         u = malloc(sizeof(*u));
398         if (!u)
399                 return NULL;
400         memset(u, 0, sizeof(*u));
401         u->sw = sw;
402         u->id = cl_ntoh64(osm_node_get_node_guid(sw->p_node));
403         u->rank = 0xffffffff;
404         return u;
405 }
406
407 static void delete_updn_node(struct updn_node *u)
408 {
409         u->sw->priv = NULL;
410         free(u);
411 }
412
413 /**********************************************************************
414  **********************************************************************/
415 /* Find Root nodes automatically by Min Hop Table info */
416 static void updn_find_root_nodes_by_min_hop(OUT updn_t * p_updn)
417 {
418         osm_opensm_t *p_osm = p_updn->p_osm;
419         osm_switch_t *p_sw;
420         osm_port_t *p_port;
421         osm_physp_t *p_physp;
422         cl_map_item_t *item;
423         double thd1, thd2;
424         unsigned i, cas_num = 0;
425         unsigned *cas_per_sw;
426         uint16_t lid_ho;
427
428         OSM_LOG_ENTER(&p_osm->log);
429
430         OSM_LOG(&p_osm->log, OSM_LOG_DEBUG,
431                 "Current number of ports in the subnet is %d\n",
432                 cl_qmap_count(&p_osm->subn.port_guid_tbl));
433
434         cas_per_sw = malloc((IB_LID_UCAST_END_HO + 1) * sizeof(*cas_per_sw));
435         if (!cas_per_sw) {
436                 OSM_LOG(&p_osm->log, OSM_LOG_ERROR, "ERR AA14: "
437                         "cannot alloc mem for CAs per switch counter array\n");
438                 goto _exit;
439         }
440         memset(cas_per_sw, 0, (IB_LID_UCAST_END_HO + 1) * sizeof(*cas_per_sw));
441
442         /* Find the Maximum number of CAs (and routers) for histogram normalization */
443         OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE,
444                 "Finding the number of CAs and storing them in cl_map\n");
445         for (item = cl_qmap_head(&p_updn->p_osm->subn.port_guid_tbl);
446              item != cl_qmap_end(&p_updn->p_osm->subn.port_guid_tbl);
447              item = cl_qmap_next(item)) {
448                 p_port = (osm_port_t *)item;
449                 if (!p_port->p_node->sw) {
450                         p_physp = p_port->p_physp->p_remote_physp;
451                         if (!p_physp || !p_physp->p_node->sw)
452                                 continue;
453                         lid_ho = osm_node_get_base_lid(p_physp->p_node, 0);
454                         lid_ho = cl_ntoh16(lid_ho);
455                         cas_per_sw[lid_ho]++;
456                         cas_num++;
457                 }
458         }
459
460         thd1 = cas_num * 0.9;
461         thd2 = cas_num * 0.05;
462         OSM_LOG(&p_osm->log, OSM_LOG_DEBUG,
463                 "Found %u CAs and RTRs, %u SWs in the subnet. "
464                 "Thresholds are thd1 = %f && thd2 = %f\n",
465                 cas_num, cl_qmap_count(&p_osm->subn.sw_guid_tbl), thd1, thd2);
466
467         OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE,
468                 "Passing through all switches to collect Min Hop info\n");
469         for (item = cl_qmap_head(&p_updn->p_osm->subn.sw_guid_tbl);
470              item != cl_qmap_end(&p_updn->p_osm->subn.sw_guid_tbl);
471              item = cl_qmap_next(item)) {
472                 unsigned hop_hist[IB_SUBNET_PATH_HOPS_MAX];
473                 uint16_t max_lid_ho;
474                 uint8_t hop_val;
475                 uint16_t numHopBarsOverThd1 = 0;
476                 uint16_t numHopBarsOverThd2 = 0;
477
478                 p_sw = (osm_switch_t *) item;
479
480                 memset(hop_hist, 0, sizeof(hop_hist));
481
482                 max_lid_ho = p_sw->max_lid_ho;
483                 for (lid_ho = 1; lid_ho <= max_lid_ho; lid_ho++)
484                         if (cas_per_sw[lid_ho]) {
485                                 hop_val =
486                                     osm_switch_get_least_hops(p_sw, lid_ho);
487                                 if (hop_val >= IB_SUBNET_PATH_HOPS_MAX)
488                                         continue;
489
490                                 hop_hist[hop_val] += cas_per_sw[lid_ho];
491                         }
492
493                 /* Now recognize the spines by requiring one bar to be
494                    above 90% of the number of CAs and RTRs */
495                 for (i = 0; i < IB_SUBNET_PATH_HOPS_MAX; i++) {
496                         if (hop_hist[i] > thd1)
497                                 numHopBarsOverThd1++;
498                         if (hop_hist[i] > thd2)
499                                 numHopBarsOverThd2++;
500                 }
501
502                 /* If thd conditions are valid - rank the root node */
503                 if (numHopBarsOverThd1 == 1 && numHopBarsOverThd2 == 1) {
504                         OSM_LOG(&p_osm->log, OSM_LOG_DEBUG,
505                                 "Ranking GUID 0x%" PRIx64 " as root node\n",
506                                 cl_ntoh64(osm_node_get_node_guid(p_sw->p_node)));
507                         ((struct updn_node *)p_sw->priv)->rank = 0;
508                         p_updn->num_roots++;
509                 }
510         }
511
512         free(cas_per_sw);
513 _exit:
514         OSM_LOG_EXIT(&p_osm->log);
515         return;
516 }
517
518 /**********************************************************************
519  **********************************************************************/
520 static void dump_roots(cl_map_item_t *item, FILE *file, void *cxt)
521 {
522         osm_switch_t *sw = (osm_switch_t *)item;
523         if (!((struct updn_node *)sw->priv)->rank)
524                 fprintf(file, "0x%" PRIx64 "\n",
525                         cl_ntoh64(osm_node_get_node_guid(sw->p_node)));
526 }
527
528 static int update_id(void *cxt, uint64_t guid, char *p)
529 {
530         osm_opensm_t *osm = cxt;
531         osm_switch_t *sw;
532         uint64_t id;
533         char *e;
534
535         sw = osm_get_switch_by_guid(&osm->subn, cl_hton64(guid));
536         if (!sw) {
537                 OSM_LOG(&osm->log, OSM_LOG_VERBOSE,
538                         "switch with guid 0x%" PRIx64 " is not found\n", guid);
539                 return 0;
540         }
541
542         id = strtoull(p, &e, 0);
543         if (*e && !isspace(*e)) {
544                 OSM_LOG(&osm->log, OSM_LOG_ERROR,
545                         "ERR: cannot parse node id \'%s\'", p);
546                 return -1;
547         }
548
549         OSM_LOG(&osm->log, OSM_LOG_DEBUG,
550                 "update node 0x%" PRIx64 " id to 0x%" PRIx64 "\n", guid, id);
551
552         ((struct updn_node *)sw->priv)->id = id;
553
554         return 0;
555 }
556
557 static int rank_root_node(void *cxt, uint64_t guid, char *p)
558 {
559         updn_t *updn = cxt;
560         osm_switch_t *sw;
561
562         sw = osm_get_switch_by_guid(&updn->p_osm->subn, cl_hton64(guid));
563         if (!sw) {
564                 OSM_LOG(&updn->p_osm->log, OSM_LOG_VERBOSE,
565                         "switch with guid 0x%" PRIx64 " is not found\n", guid);
566                 return 0;
567         }
568
569         OSM_LOG(&updn->p_osm->log, OSM_LOG_DEBUG,
570                 "Ranking root port GUID 0x%" PRIx64 "\n", guid);
571
572         ((struct updn_node *)sw->priv)->rank = 0;
573         updn->num_roots++;
574
575         return 0;
576 }
577
578 /* UPDN callback function */
579 static int updn_lid_matrices(void *ctx)
580 {
581         updn_t *p_updn = ctx;
582         cl_map_item_t *item;
583         osm_switch_t *p_sw;
584         int ret = 0;
585
586         OSM_LOG_ENTER(&p_updn->p_osm->log);
587
588         for (item = cl_qmap_head(&p_updn->p_osm->subn.sw_guid_tbl);
589              item != cl_qmap_end(&p_updn->p_osm->subn.sw_guid_tbl);
590              item = cl_qmap_next(item)) {
591                 p_sw = (osm_switch_t *)item;
592                 p_sw->priv = create_updn_node(p_sw);
593                 if (!p_sw->priv) {
594                         OSM_LOG(&(p_updn->p_osm->log), OSM_LOG_ERROR, "ERR AA0C: "
595                                 "cannot create updn node\n");
596                         OSM_LOG_EXIT(&p_updn->p_osm->log);
597                         return -1;
598                 }
599         }
600
601         /* First setup root nodes */
602         p_updn->num_roots = 0;
603
604         if (p_updn->p_osm->subn.opt.root_guid_file) {
605                 OSM_LOG(&p_updn->p_osm->log, OSM_LOG_DEBUG,
606                         "UPDN - Fetching root nodes from file \'%s\'\n",
607                         p_updn->p_osm->subn.opt.root_guid_file);
608
609                 ret = parse_node_map(p_updn->p_osm->subn.opt.root_guid_file,
610                                      rank_root_node, p_updn);
611                 if (ret)
612                         OSM_LOG(&p_updn->p_osm->log, OSM_LOG_ERROR, "ERR : "
613                                 "cannot parse root guids file \'%s\'\n",
614                                 p_updn->p_osm->subn.opt.root_guid_file);
615                 if (p_updn->p_osm->subn.opt.connect_roots &&
616                     p_updn->num_roots > 1)
617                         osm_ucast_mgr_build_lid_matrices(&p_updn->p_osm->sm.ucast_mgr);
618         } else {
619                 osm_ucast_mgr_build_lid_matrices(&p_updn->p_osm->sm.ucast_mgr);
620                 updn_find_root_nodes_by_min_hop(p_updn);
621         }
622
623         if (p_updn->p_osm->subn.opt.ids_guid_file) {
624                 OSM_LOG(&p_updn->p_osm->log, OSM_LOG_DEBUG,
625                         "UPDN - update node ids from file \'%s\'\n",
626                         p_updn->p_osm->subn.opt.ids_guid_file);
627
628                 ret = parse_node_map(p_updn->p_osm->subn.opt.ids_guid_file,
629                                      update_id, p_updn->p_osm);
630                 if (ret)
631                         OSM_LOG(&p_updn->p_osm->log, OSM_LOG_ERROR, "ERR : "
632                                 "cannot parse node ids file \'%s\'\n",
633                                 p_updn->p_osm->subn.opt.ids_guid_file);
634         }
635
636         /* Only if there are assigned root nodes do the algorithm, otherwise perform do nothing */
637         if (p_updn->num_roots) {
638                 OSM_LOG(&p_updn->p_osm->log, OSM_LOG_DEBUG,
639                         "activating UPDN algorithm\n");
640                 ret = updn_build_lid_matrices(p_updn);
641         } else {
642                 OSM_LOG(&p_updn->p_osm->log, OSM_LOG_INFO,
643                         "disabling UPDN algorithm, no root nodes were found\n");
644                 ret = -1;
645         }
646
647         if (osm_log_is_active(&p_updn->p_osm->log, OSM_LOG_ROUTING))
648                 osm_dump_qmap_to_file(p_updn->p_osm, "opensm-updn-roots.dump",
649                                       &p_updn->p_osm->subn.sw_guid_tbl,
650                                       dump_roots, NULL);
651
652         for (item = cl_qmap_head(&p_updn->p_osm->subn.sw_guid_tbl);
653              item != cl_qmap_end(&p_updn->p_osm->subn.sw_guid_tbl);
654              item = cl_qmap_next(item)) {
655                 p_sw = (osm_switch_t *) item;
656                 delete_updn_node(p_sw->priv);
657         }
658
659         OSM_LOG_EXIT(&p_updn->p_osm->log);
660         return ret;
661 }
662
663 /**********************************************************************
664  **********************************************************************/
665 static void updn_delete(void *context)
666 {
667         free(context);
668 }
669
670 int osm_ucast_updn_setup(struct osm_routing_engine *r, osm_opensm_t *osm)
671 {
672         updn_t *updn;
673
674         updn = malloc(sizeof(updn_t));
675         if (!updn)
676                 return -1;
677         memset(updn, 0, sizeof(updn_t));
678
679         updn->p_osm = osm;
680
681         r->context = updn;
682         r->delete = updn_delete;
683         r->build_lid_matrices = updn_lid_matrices;
684
685         return 0;
686 }