osm_ucast_dnup.c revision 321936
1193240Ssam/*
2193240Ssam * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved.
3193240Ssam * Copyright (c) 2002-2007,2009 Mellanox Technologies LTD. All rights reserved.
4193240Ssam * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
5193240Ssam * Copyright (c) 2009 HNR Consulting. All rights reserved.
6193240Ssam * Copyright (c) 2009 Battelle Memorial Institue. All rights reserved.
7193240Ssam *
8193240Ssam * This software is available to you under a choice of one of two
9193240Ssam * licenses.  You may choose to be licensed under the terms of the GNU
10193240Ssam * General Public License (GPL) Version 2, available from the file
11193240Ssam * COPYING in the main directory of this source tree, or the
12193240Ssam * OpenIB.org BSD license below:
13193240Ssam *
14193240Ssam *     Redistribution and use in source and binary forms, with or
15193240Ssam *     without modification, are permitted provided that the following
16193240Ssam *     conditions are met:
17193240Ssam *
18193240Ssam *      - Redistributions of source code must retain the above
19193240Ssam *        copyright notice, this list of conditions and the following
20193240Ssam *        disclaimer.
21193240Ssam *
22193240Ssam *      - Redistributions in binary form must reproduce the above
23193240Ssam *        copyright notice, this list of conditions and the following
24193240Ssam *        disclaimer in the documentation and/or other materials
25193240Ssam *        provided with the distribution.
26193240Ssam *
27193240Ssam * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28193240Ssam * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29193240Ssam * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30193240Ssam * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
31193240Ssam * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
32193240Ssam * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
33193240Ssam * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
34193240Ssam * SOFTWARE.
35193240Ssam *
36193240Ssam */
37193240Ssam
38193240Ssam/*
39193240Ssam * Abstract:
40193240Ssam *      Implementation of Up Down Algorithm using ranking & Min Hop
41193240Ssam *      Calculation functions
42193240Ssam */
43193240Ssam
44193240Ssam#if HAVE_CONFIG_H
45193240Ssam#  include <config.h>
46193240Ssam#endif				/* HAVE_CONFIG_H */
47193240Ssam
48193240Ssam#include <stdlib.h>
49193240Ssam#include <ctype.h>
50193240Ssam#include <complib/cl_debug.h>
51193240Ssam#include <complib/cl_qmap.h>
52193240Ssam#include <opensm/osm_file_ids.h>
53193240Ssam#define FILE_ID OSM_FILE_UCAST_DNUP_C
54193240Ssam#include <opensm/osm_switch.h>
55193240Ssam#include <opensm/osm_opensm.h>
56193240Ssam#include <opensm/osm_ucast_mgr.h>
57193240Ssam
58193240Ssam/* //////////////////////////// */
59193240Ssam/*  Local types                 */
60193240Ssam/* //////////////////////////// */
61193240Ssam
62193240Ssam/* direction */
63193240Ssamtypedef enum dnup_switch_dir {
64193240Ssam	UP = 0,
65193240Ssam	DOWN,
66193240Ssam	EQUAL
67193240Ssam} dnup_switch_dir_t;
68193240Ssam
69193240Ssam/* dnup structure */
70193240Ssamtypedef struct dnup {
71193240Ssam	osm_opensm_t *p_osm;
72193240Ssam} dnup_t;
73193240Ssam
74193240Ssamstruct dnup_node {
75193240Ssam	cl_list_item_t list;
76193240Ssam	osm_switch_t *sw;
77193240Ssam	dnup_switch_dir_t dir;
78193240Ssam	unsigned rank;
79193240Ssam	unsigned visited;
80193240Ssam};
81193240Ssam
82193240Ssam/* This function returns direction based on rank and guid info of current &
83193240Ssam   remote ports */
84193240Ssamstatic dnup_switch_dir_t dnup_get_dir(unsigned cur_rank, unsigned rem_rank)
85193240Ssam{
86193240Ssam	/* HACK: comes to solve root nodes connection, in a classic subnet root nodes do not connect
87193240Ssam	   directly, but in case they are we assign to root node an UP direction to allow DNUP to discover
88193240Ssam	   the subnet correctly (and not from the point of view of the last root node).
89193240Ssam	 */
90193240Ssam	if (!cur_rank && !rem_rank)
91193240Ssam		return EQUAL;
92193240Ssam
93193240Ssam	if (cur_rank < rem_rank)
94193240Ssam		return DOWN;
95193240Ssam	else if (cur_rank > rem_rank)
96193240Ssam		return UP;
97193240Ssam	else
98193240Ssam		return EQUAL;
99193240Ssam}
100193240Ssam
101193240Ssam/**********************************************************************
102193240Ssam * This function does the bfs of min hop table calculation by guid index
103193240Ssam * as a starting point.
104193240Ssam **********************************************************************/
105193240Ssamstatic int dnup_bfs_by_node(IN osm_log_t * p_log, IN osm_subn_t * p_subn,
106193240Ssam			    IN osm_switch_t * p_sw, IN uint8_t prune_weight,
107193240Ssam			    OUT uint8_t * max_hops)
108193240Ssam{
109193240Ssam	uint8_t pn, pn_rem;
110193240Ssam	cl_qlist_t list;
111193240Ssam	uint16_t lid;
112193240Ssam	struct dnup_node *u;
113193240Ssam	dnup_switch_dir_t next_dir, current_dir;
114193240Ssam
115193240Ssam	OSM_LOG_ENTER(p_log);
116193240Ssam
117193240Ssam	lid = osm_node_get_base_lid(p_sw->p_node, 0);
118193240Ssam	lid = cl_ntoh16(lid);
119193240Ssam	osm_switch_set_hops(p_sw, lid, 0, 0);
120193240Ssam
121193240Ssam	OSM_LOG(p_log, OSM_LOG_DEBUG,
122193240Ssam		"Starting from switch - port GUID 0x%" PRIx64 " lid %u\n",
123193240Ssam		cl_ntoh64(p_sw->p_node->node_info.port_guid), lid);
124193240Ssam
125193240Ssam	u = p_sw->priv;
126193240Ssam	u->dir = DOWN;
127193240Ssam
128193240Ssam	/* Update list with the new element */
129193240Ssam	cl_qlist_init(&list);
130193240Ssam	cl_qlist_insert_tail(&list, &u->list);
131193240Ssam
132193240Ssam	/* BFS the list till no next element */
133193240Ssam	while (!cl_is_qlist_empty(&list)) {
134193240Ssam		u = (struct dnup_node *)cl_qlist_remove_head(&list);
135193240Ssam		u->visited = 0;	/* cleanup */
136193240Ssam		current_dir = u->dir;
137193240Ssam		/* Go over all ports of the switch and find unvisited remote nodes */
138193240Ssam		for (pn = 1; pn < u->sw->num_ports; pn++) {
139193240Ssam			osm_node_t *p_remote_node;
140193240Ssam			struct dnup_node *rem_u;
141193240Ssam			uint8_t current_min_hop, remote_min_hop,
142193240Ssam			    set_hop_return_value;
143193240Ssam			osm_switch_t *p_remote_sw;
144193240Ssam
145193240Ssam			p_remote_node =
146193240Ssam			    osm_node_get_remote_node(u->sw->p_node, pn,
147195377Ssam						     &pn_rem);
148195377Ssam			/* If no remote node OR remote node is not a SWITCH
149193240Ssam			   continue to next pn */
150193240Ssam			if (!p_remote_node || !p_remote_node->sw)
151193240Ssam				continue;
152193240Ssam			/* Fetch remote guid only after validation of remote node */
153193240Ssam			p_remote_sw = p_remote_node->sw;
154193240Ssam			rem_u = p_remote_sw->priv;
155193240Ssam			/* Decide which direction to mark it (UP/DOWN) */
156193240Ssam			next_dir = dnup_get_dir(u->rank, rem_u->rank);
157193240Ssam
158193240Ssam			/* Set MinHop value for the current lid */
159193240Ssam			current_min_hop = osm_switch_get_least_hops(u->sw, lid);
160193240Ssam			/* Check hop count if better insert into list && update
161193240Ssam			   the remote node Min Hop Table */
162193240Ssam			remote_min_hop =
163193240Ssam			    osm_switch_get_hop_count(p_remote_sw, lid, pn_rem);
164193240Ssam
165193240Ssam			/* Check if this is a legal step : the only illegal step is going
166193240Ssam			   from UP to DOWN */
167193240Ssam			if ((current_dir == UP) && (next_dir == DOWN)) {
168193240Ssam				OSM_LOG(p_log, OSM_LOG_DEBUG,
169193240Ssam					"Avoiding move from 0x%016" PRIx64
170193240Ssam					" to 0x%016" PRIx64 "\n",
171193240Ssam					cl_ntoh64(osm_node_get_node_guid(u->sw->p_node)),
172193240Ssam					cl_ntoh64(osm_node_get_node_guid(p_remote_node)));
173193240Ssam				/* Illegal step. If prune_weight is set, allow it with an
174193240Ssam				 * additional weight
175193240Ssam				 */
176193240Ssam				if(prune_weight) {
177193240Ssam					current_min_hop+=prune_weight;
178193240Ssam					if(current_min_hop >= 64) {
179193240Ssam						OSM_LOG(p_log, OSM_LOG_ERROR,
180193240Ssam							"ERR AE02: Too many hops on subnet,"
181193240Ssam							" can't relax illegal Dn/Up transition.");
182193240Ssam						osm_switch_set_hops(p_remote_sw, lid,
183193240Ssam								    pn_rem, OSM_NO_PATH);
184193240Ssam					}
185193240Ssam				} else {
186193240Ssam					continue;
187193240Ssam				}
188193240Ssam			}
189193240Ssam			if (current_min_hop + 1 < remote_min_hop) {
190193240Ssam				set_hop_return_value =
191193240Ssam				    osm_switch_set_hops(p_remote_sw, lid,
192193240Ssam							pn_rem,
193193240Ssam							current_min_hop + 1);
194193240Ssam				if(max_hops && current_min_hop + 1 > *max_hops) {
195193240Ssam					*max_hops = current_min_hop + 1;
196193240Ssam				}
197193240Ssam				if (set_hop_return_value) {
198193240Ssam					OSM_LOG(p_log, OSM_LOG_ERROR, "ERR AE01: "
199193240Ssam						"Invalid value returned from set min hop is: %d\n",
200193240Ssam						set_hop_return_value);
201193240Ssam				}
202193240Ssam				/* Check if remote port has already been visited */
203193240Ssam				if (!rem_u->visited) {
204193240Ssam					/* Insert dnup_switch item into the list */
205193240Ssam					rem_u->dir = next_dir;
206193240Ssam					rem_u->visited = 1;
207193240Ssam					cl_qlist_insert_tail(&list,
208193240Ssam							     &rem_u->list);
209193240Ssam				}
210193240Ssam			}
211193240Ssam		}
212193240Ssam	}
213193240Ssam
214193240Ssam	OSM_LOG_EXIT(p_log);
215193240Ssam	return 0;
216193240Ssam}
217193240Ssam
218193240Ssam/* NOTE : PLS check if we need to decide that the first */
219193240Ssam/*        rank is a SWITCH for BFS purpose */
220193240Ssamstatic int dnup_subn_rank(IN dnup_t * p_dnup)
221193240Ssam{
222193240Ssam	osm_switch_t *p_sw;
223193240Ssam	osm_physp_t *p_physp, *p_remote_physp;
224193240Ssam	cl_qlist_t list;
225193240Ssam	cl_map_item_t *item;
226193240Ssam	struct dnup_node *u, *remote_u;
227193240Ssam	uint8_t num_ports, port_num;
228193240Ssam	osm_log_t *p_log = &p_dnup->p_osm->log;
229193240Ssam	unsigned max_rank = 0;
230193240Ssam
231193240Ssam	OSM_LOG_ENTER(p_log);
232193240Ssam	cl_qlist_init(&list);
233193240Ssam
234193240Ssam	/* add all node level switches to the list */
235193240Ssam	for (item = cl_qmap_head(&p_dnup->p_osm->subn.sw_guid_tbl);
236193240Ssam	     item != cl_qmap_end(&p_dnup->p_osm->subn.sw_guid_tbl);
237193240Ssam	     item = cl_qmap_next(item)) {
238193240Ssam		p_sw = (osm_switch_t *)item;
239193240Ssam		u = p_sw->priv;
240193240Ssam		if (u->rank == 0)
241193240Ssam			cl_qlist_insert_tail(&list, &u->list);
242193240Ssam	}
243193240Ssam
244193240Ssam	/* BFS the list till it's empty */
245193240Ssam	while (!cl_is_qlist_empty(&list)) {
246193240Ssam		u = (struct dnup_node *)cl_qlist_remove_head(&list);
247193240Ssam		/* Go over all remote nodes and rank them (if not already visited) */
248193240Ssam		p_sw = u->sw;
249193240Ssam		num_ports = p_sw->num_ports;
250193240Ssam		OSM_LOG(p_log, OSM_LOG_DEBUG,
251193240Ssam			"Handling switch GUID 0x%" PRIx64 "\n",
252193240Ssam			cl_ntoh64(osm_node_get_node_guid(p_sw->p_node)));
253193240Ssam		for (port_num = 1; port_num < num_ports; port_num++) {
254193240Ssam			ib_net64_t port_guid;
255193240Ssam
256193240Ssam			/* Current port fetched in order to get remote side */
257193240Ssam			p_physp =
258193240Ssam			    osm_node_get_physp_ptr(p_sw->p_node, port_num);
259193240Ssam
260193240Ssam			if (!p_physp)
261193240Ssam				continue;
262193240Ssam
263193240Ssam			p_remote_physp = p_physp->p_remote_physp;
264193240Ssam
265193240Ssam			/*
266193240Ssam			   make sure that all the following occur on p_remote_physp:
267193240Ssam			   1. The port isn't NULL
268193240Ssam			   2. It is a switch
269193240Ssam			 */
270193240Ssam			if (p_remote_physp && p_remote_physp->p_node->sw) {
271193240Ssam				remote_u = p_remote_physp->p_node->sw->priv;
272193240Ssam				port_guid = p_remote_physp->port_guid;
273193240Ssam
274193240Ssam				if (remote_u->rank > u->rank + 1) {
275193240Ssam					remote_u->rank = u->rank + 1;
276193240Ssam					max_rank = remote_u->rank;
277193240Ssam					cl_qlist_insert_tail(&list,
278193240Ssam							     &remote_u->list);
279193240Ssam					OSM_LOG(p_log, OSM_LOG_DEBUG,
280193240Ssam						"Rank of port GUID 0x%" PRIx64
281193240Ssam						" = %u\n", cl_ntoh64(port_guid),
282193240Ssam						remote_u->rank);
283193240Ssam				}
284193240Ssam			}
285193240Ssam		}
286193240Ssam	}
287193240Ssam
288193240Ssam	/* Print Summary of ranking */
289193240Ssam	OSM_LOG(p_log, OSM_LOG_VERBOSE,
290193240Ssam		"Subnet ranking completed. Max Node Rank = %d\n", max_rank);
291193240Ssam	OSM_LOG_EXIT(p_log);
292193240Ssam	return 0;
293193240Ssam}
294193240Ssam
295193240Ssamstatic int dnup_set_min_hop_table(IN dnup_t * p_dnup)
296193240Ssam{
297193240Ssam	osm_subn_t *p_subn = &p_dnup->p_osm->subn;
298193240Ssam	osm_log_t *p_log = &p_dnup->p_osm->log;
299193240Ssam	osm_switch_t *p_sw;
300193240Ssam	struct dnup_node *u;
301193240Ssam	cl_map_item_t *item;
302193240Ssam	uint8_t max_hops = 0;
303193240Ssam
304193240Ssam	OSM_LOG_ENTER(p_log);
305193240Ssam
306193240Ssam	/* Go over all the switches in the subnet - for each init their Min Hop
307193240Ssam	   Table */
308193240Ssam	OSM_LOG(p_log, OSM_LOG_VERBOSE,
309193240Ssam		"Init Min Hop Table of all switches [\n");
310193240Ssam
311193240Ssam	for (item = cl_qmap_head(&p_dnup->p_osm->subn.sw_guid_tbl);
312193240Ssam	     item != cl_qmap_end(&p_dnup->p_osm->subn.sw_guid_tbl);
313193240Ssam	     item = cl_qmap_next(item)) {
314193240Ssam		p_sw = (osm_switch_t *)item;
315193240Ssam		/* Clear Min Hop Table */
316193240Ssam		osm_switch_clear_hops(p_sw);
317193240Ssam	}
318193240Ssam
319193240Ssam	OSM_LOG(p_log, OSM_LOG_VERBOSE,
320193240Ssam		"Init Min Hop Table of all switches ]\n");
321193240Ssam
322193240Ssam	/* Now do the BFS for each port  in the subnet */
323193240Ssam	OSM_LOG(p_log, OSM_LOG_VERBOSE,
324193240Ssam		"BFS through all port guids in the subnet [\n");
325193240Ssam
326193240Ssam	for (item = cl_qmap_head(&p_dnup->p_osm->subn.sw_guid_tbl);
327193240Ssam	     item != cl_qmap_end(&p_dnup->p_osm->subn.sw_guid_tbl);
328193240Ssam	     item = cl_qmap_next(item)) {
329193240Ssam		p_sw = (osm_switch_t *)item;
330193240Ssam		dnup_bfs_by_node(p_log, p_subn, p_sw, 0, &max_hops);
331193240Ssam	}
332193240Ssam	if(p_subn->opt.connect_roots) {
333193240Ssam		/*This is probably not necessary, by I am more comfortable
334193240Ssam		 * clearing any possible side effects from the previous
335193240Ssam		 * dnup routing pass
336193240Ssam		 */
337193240Ssam		for (item = cl_qmap_head(&p_dnup->p_osm->subn.sw_guid_tbl);
338193240Ssam		     item != cl_qmap_end(&p_dnup->p_osm->subn.sw_guid_tbl);
339193240Ssam		     item = cl_qmap_next(item)) {
340193240Ssam			p_sw = (osm_switch_t *)item;
341193240Ssam			osm_switch_clear_hops(p_sw);
342193240Ssam			u = (struct dnup_node *) p_sw->priv;
343193240Ssam			u->visited = 0;
344193240Ssam		}
345193240Ssam		for (item = cl_qmap_head(&p_dnup->p_osm->subn.sw_guid_tbl);
346193240Ssam		     item != cl_qmap_end(&p_dnup->p_osm->subn.sw_guid_tbl);
347193240Ssam		     item = cl_qmap_next(item)) {
348193240Ssam			p_sw = (osm_switch_t *)item;
349193240Ssam			dnup_bfs_by_node(p_log, p_subn, p_sw, max_hops + 1, NULL);
350193240Ssam		}
351193240Ssam	}
352193240Ssam
353193240Ssam	OSM_LOG(p_log, OSM_LOG_VERBOSE,
354193240Ssam		"BFS through all port guids in the subnet ]\n");
355193240Ssam	/* Cleanup */
356193240Ssam	OSM_LOG_EXIT(p_log);
357193240Ssam	return 0;
358193240Ssam}
359193240Ssam
360193240Ssamstatic int dnup_build_lid_matrices(IN dnup_t * p_dnup)
361193240Ssam{
362193240Ssam	int status;
363193240Ssam
364193240Ssam	OSM_LOG_ENTER(&p_dnup->p_osm->log);
365193240Ssam
366193240Ssam	OSM_LOG(&p_dnup->p_osm->log, OSM_LOG_VERBOSE,
367193240Ssam		"Ranking all port guids in the list\n");
368193240Ssam	/* Check if it's not a switched subnet */
369193240Ssam	if (cl_is_qmap_empty(&p_dnup->p_osm->subn.sw_guid_tbl)) {
370193240Ssam		OSM_LOG(&p_dnup->p_osm->log, OSM_LOG_ERROR, "ERR AEOB: "
371193240Ssam			"This is not a switched subnet, cannot perform DNUP algorithm\n");
372193240Ssam		status = -1;
373193240Ssam		goto _exit;
374193240Ssam	}
375193240Ssam
376193240Ssam	/* Rank the subnet switches */
377193240Ssam	dnup_subn_rank(p_dnup);
378193240Ssam
379193240Ssam	/* After multiple ranking need to set Min Hop Table by DnUp algorithm  */
380193240Ssam	OSM_LOG(&p_dnup->p_osm->log, OSM_LOG_VERBOSE,
381193240Ssam		"Setting all switches' Min Hop Table\n");
382193240Ssam	status = dnup_set_min_hop_table(p_dnup);
383193240Ssam
384193240Ssam_exit:
385193240Ssam	OSM_LOG_EXIT(&p_dnup->p_osm->log);
386193240Ssam	return status;
387193240Ssam}
388193240Ssam
389193240Ssamstatic struct dnup_node *create_dnup_node(osm_switch_t * sw)
390193240Ssam{
391193240Ssam	struct dnup_node *u;
392193240Ssam
393193240Ssam	u = malloc(sizeof(*u));
394193240Ssam	if (!u)
395193240Ssam		return NULL;
396193240Ssam	memset(u, 0, sizeof(*u));
397193240Ssam	u->sw = sw;
398193240Ssam	u->rank = 0xffffffff;
399193240Ssam	return u;
400193240Ssam}
401193240Ssam
402193240Ssamstatic void delete_dnup_node(struct dnup_node *u)
403193240Ssam{
404193240Ssam	u->sw->priv = NULL;
405193240Ssam	free(u);
406193240Ssam}
407193240Ssam
408193240Ssam/* DNUP callback function */
409193240Ssamstatic int dnup_lid_matrices(void *ctx)
410193240Ssam{
411193240Ssam	dnup_t *p_dnup = ctx;
412193240Ssam	cl_map_item_t *item;
413193240Ssam	osm_switch_t *p_sw;
414193240Ssam	int ret = 0;
415193240Ssam	int num_leafs = 0;
416193240Ssam	uint8_t pn, pn_rem;
417193240Ssam
418193240Ssam	OSM_LOG_ENTER(&p_dnup->p_osm->log);
419193240Ssam
420193240Ssam	for (item = cl_qmap_head(&p_dnup->p_osm->subn.sw_guid_tbl);
421193240Ssam	     item != cl_qmap_end(&p_dnup->p_osm->subn.sw_guid_tbl);
422193240Ssam	     item = cl_qmap_next(item)) {
423195618Srpaulo		p_sw = (osm_switch_t *)item;
424193240Ssam		p_sw->priv = create_dnup_node(p_sw);
425193240Ssam		if (!p_sw->priv) {
426193240Ssam			OSM_LOG(&(p_dnup->p_osm->log), OSM_LOG_ERROR, "ERR AE0C: "
427193240Ssam				"cannot create dnup node\n");
428193240Ssam			OSM_LOG_EXIT(&p_dnup->p_osm->log);
429193240Ssam			return -1;
430193240Ssam		}
431193240Ssam	}
432193240Ssam
433193240Ssam
434193240Ssam	/* First setup node level nodes */
435193240Ssam	for (item = cl_qmap_head(&p_dnup->p_osm->subn.sw_guid_tbl);
436193240Ssam	     item != cl_qmap_end(&p_dnup->p_osm->subn.sw_guid_tbl);
437193240Ssam	     item = cl_qmap_next(item)) {
438193240Ssam		p_sw = (osm_switch_t *)item;
439193240Ssam
440193240Ssam		for (pn = 0; pn < p_sw->num_ports; pn++) {
441193240Ssam			osm_node_t *p_remote_node;
442193240Ssam			p_remote_node = osm_node_get_remote_node(p_sw->p_node, pn, &pn_rem);
443193240Ssam			if(p_remote_node && !p_remote_node->sw) {
444193240Ssam				struct dnup_node *u = p_sw->priv;
445193240Ssam				u->rank = 0;
446193240Ssam				OSM_LOG(&(p_dnup->p_osm->log),
447193240Ssam					OSM_LOG_VERBOSE, "(%s) rank 0 leaf switch\n",
448193240Ssam					p_sw->p_node->print_desc);
449193240Ssam				num_leafs++;
450193240Ssam				break;
451193240Ssam			}
452193240Ssam		}
453193240Ssam	}
454193240Ssam
455193240Ssam	if(num_leafs == 0) {
456193240Ssam		OSM_LOG(&(p_dnup->p_osm->log),
457193240Ssam			OSM_LOG_ERROR, "ERR AE0D: No leaf switches found, DnUp routing failed\n");
458193240Ssam		OSM_LOG_EXIT(&p_dnup->p_osm->log);
459193240Ssam		return -1;
460193240Ssam	}
461193240Ssam
462193240Ssam	ret = dnup_build_lid_matrices(p_dnup);
463193240Ssam
464193240Ssam	for (item = cl_qmap_head(&p_dnup->p_osm->subn.sw_guid_tbl);
465193240Ssam	     item != cl_qmap_end(&p_dnup->p_osm->subn.sw_guid_tbl);
466193240Ssam	     item = cl_qmap_next(item)) {
467193240Ssam		p_sw = (osm_switch_t *) item;
468193240Ssam		delete_dnup_node(p_sw->priv);
469193240Ssam	}
470193240Ssam
471193240Ssam	OSM_LOG_EXIT(&p_dnup->p_osm->log);
472193240Ssam	return ret;
473193240Ssam}
474193240Ssam
475193240Ssamstatic void dnup_delete(void *context)
476193240Ssam{
477193240Ssam	free(context);
478193240Ssam}
479193240Ssam
480193240Ssamint osm_ucast_dnup_setup(struct osm_routing_engine *r, osm_opensm_t *osm)
481193240Ssam{
482193240Ssam	dnup_t *dnup;
483193240Ssam
484193240Ssam	OSM_LOG_ENTER(&osm->log);
485193240Ssam
486193240Ssam	dnup = malloc(sizeof(dnup_t));
487193240Ssam	if (!dnup)
488193240Ssam		return -1;
489193240Ssam	memset(dnup, 0, sizeof(dnup_t));
490193240Ssam
491193240Ssam	dnup->p_osm = osm;
492193240Ssam
493193240Ssam	r->context = dnup;
494193240Ssam	r->destroy = dnup_delete;
495193240Ssam	r->build_lid_matrices = dnup_lid_matrices;
496193240Ssam
497193240Ssam	OSM_LOG_EXIT(&osm->log);
498193240Ssam	return 0;
499193240Ssam}
500193240Ssam