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 */
59typedef enum updn_switch_dir {
60	UP = 0,
61	DOWN
62} updn_switch_dir_t;
63
64/* updn structure */
65typedef struct updn {
66	unsigned num_roots;
67	osm_opensm_t *p_osm;
68} updn_t;
69
70struct 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 */
83static 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 **********************************************************************/
110static 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 */
210static 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 */
288static 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 **********************************************************************/
307static 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 **********************************************************************/
355static 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 **********************************************************************/
393static 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
407static 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 */
416static 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 **********************************************************************/
520static 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
528static 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
557static 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 */
579static 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 **********************************************************************/
665static void updn_delete(void *context)
666{
667	free(context);
668}
669
670int 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}
687