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