Blame opensm/osm_ucast_dnup.c

Packit 13e616
/*
Packit 13e616
 * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved.
Packit 13e616
 * Copyright (c) 2002-2007,2009 Mellanox Technologies LTD. All rights reserved.
Packit 13e616
 * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
Packit 13e616
 * Copyright (c) 2009 HNR Consulting. All rights reserved.
Packit 13e616
 * Copyright (c) 2009 Battelle Memorial Institue. All rights reserved.
Packit 13e616
 *
Packit 13e616
 * This software is available to you under a choice of one of two
Packit 13e616
 * licenses.  You may choose to be licensed under the terms of the GNU
Packit 13e616
 * General Public License (GPL) Version 2, available from the file
Packit 13e616
 * COPYING in the main directory of this source tree, or the
Packit 13e616
 * OpenIB.org BSD license below:
Packit 13e616
 *
Packit 13e616
 *     Redistribution and use in source and binary forms, with or
Packit 13e616
 *     without modification, are permitted provided that the following
Packit 13e616
 *     conditions are met:
Packit 13e616
 *
Packit 13e616
 *      - Redistributions of source code must retain the above
Packit 13e616
 *        copyright notice, this list of conditions and the following
Packit 13e616
 *        disclaimer.
Packit 13e616
 *
Packit 13e616
 *      - Redistributions in binary form must reproduce the above
Packit 13e616
 *        copyright notice, this list of conditions and the following
Packit 13e616
 *        disclaimer in the documentation and/or other materials
Packit 13e616
 *        provided with the distribution.
Packit 13e616
 *
Packit 13e616
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
Packit 13e616
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
Packit 13e616
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
Packit 13e616
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
Packit 13e616
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
Packit 13e616
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
Packit 13e616
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
Packit 13e616
 * SOFTWARE.
Packit 13e616
 *
Packit 13e616
 */
Packit 13e616
Packit 13e616
/*
Packit 13e616
 * Abstract:
Packit 13e616
 *      Implementation of Up Down Algorithm using ranking & Min Hop
Packit 13e616
 *      Calculation functions
Packit 13e616
 */
Packit 13e616
Packit 13e616
#if HAVE_CONFIG_H
Packit 13e616
#  include <config.h>
Packit 13e616
#endif				/* HAVE_CONFIG_H */
Packit 13e616
Packit 13e616
#include <stdlib.h>
Packit 13e616
#include <ctype.h>
Packit 13e616
#include <complib/cl_debug.h>
Packit 13e616
#include <complib/cl_qmap.h>
Packit 13e616
#include <opensm/osm_file_ids.h>
Packit 13e616
#define FILE_ID OSM_FILE_UCAST_DNUP_C
Packit 13e616
#include <opensm/osm_switch.h>
Packit 13e616
#include <opensm/osm_opensm.h>
Packit 13e616
#include <opensm/osm_ucast_mgr.h>
Packit 13e616
Packit 13e616
/* //////////////////////////// */
Packit 13e616
/*  Local types                 */
Packit 13e616
/* //////////////////////////// */
Packit 13e616
Packit 13e616
/* direction */
Packit 13e616
typedef enum dnup_switch_dir {
Packit 13e616
	UP = 0,
Packit 13e616
	DOWN,
Packit 13e616
	EQUAL
Packit 13e616
} dnup_switch_dir_t;
Packit 13e616
Packit 13e616
/* dnup structure */
Packit 13e616
typedef struct dnup {
Packit 13e616
	osm_opensm_t *p_osm;
Packit 13e616
} dnup_t;
Packit 13e616
Packit 13e616
struct dnup_node {
Packit 13e616
	cl_list_item_t list;
Packit 13e616
	osm_switch_t *sw;
Packit 13e616
	dnup_switch_dir_t dir;
Packit 13e616
	unsigned rank;
Packit 13e616
	unsigned visited;
Packit 13e616
};
Packit 13e616
Packit 13e616
/* This function returns direction based on rank and guid info of current &
Packit 13e616
   remote ports */
Packit 13e616
static dnup_switch_dir_t dnup_get_dir(unsigned cur_rank, unsigned rem_rank)
Packit 13e616
{
Packit 13e616
	/* HACK: comes to solve root nodes connection, in a classic subnet root nodes do not connect
Packit 13e616
	   directly, but in case they are we assign to root node an UP direction to allow DNUP to discover
Packit 13e616
	   the subnet correctly (and not from the point of view of the last root node).
Packit 13e616
	 */
Packit 13e616
	if (!cur_rank && !rem_rank)
Packit 13e616
		return EQUAL;
Packit 13e616
Packit 13e616
	if (cur_rank < rem_rank)
Packit 13e616
		return DOWN;
Packit 13e616
	else if (cur_rank > rem_rank)
Packit 13e616
		return UP;
Packit 13e616
	else
Packit 13e616
		return EQUAL;
Packit 13e616
}
Packit 13e616
Packit 13e616
/**********************************************************************
Packit 13e616
 * This function does the bfs of min hop table calculation by guid index
Packit 13e616
 * as a starting point.
Packit 13e616
 **********************************************************************/
Packit 13e616
static int dnup_bfs_by_node(IN osm_log_t * p_log, IN osm_subn_t * p_subn,
Packit 13e616
			    IN osm_switch_t * p_sw, IN uint8_t prune_weight,
Packit 13e616
			    OUT uint8_t * max_hops)
Packit 13e616
{
Packit 13e616
	uint8_t pn, pn_rem;
Packit 13e616
	cl_qlist_t list;
Packit 13e616
	uint16_t lid;
Packit 13e616
	struct dnup_node *u;
Packit 13e616
	dnup_switch_dir_t next_dir, current_dir;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(p_log);
Packit 13e616
Packit 13e616
	lid = osm_node_get_base_lid(p_sw->p_node, 0);
Packit 13e616
	lid = cl_ntoh16(lid);
Packit 13e616
	osm_switch_set_hops(p_sw, lid, 0, 0);
Packit 13e616
Packit 13e616
	OSM_LOG(p_log, OSM_LOG_DEBUG,
Packit 13e616
		"Starting from switch - port GUID 0x%" PRIx64 " lid %u\n",
Packit 13e616
		cl_ntoh64(p_sw->p_node->node_info.port_guid), lid);
Packit 13e616
Packit 13e616
	u = p_sw->priv;
Packit 13e616
	u->dir = DOWN;
Packit 13e616
Packit 13e616
	/* Update list with the new element */
Packit 13e616
	cl_qlist_init(&list);
Packit 13e616
	cl_qlist_insert_tail(&list, &u->list);
Packit 13e616
Packit 13e616
	/* BFS the list till no next element */
Packit 13e616
	while (!cl_is_qlist_empty(&list)) {
Packit 13e616
		u = (struct dnup_node *)cl_qlist_remove_head(&list);
Packit 13e616
		u->visited = 0;	/* cleanup */
Packit 13e616
		current_dir = u->dir;
Packit 13e616
		/* Go over all ports of the switch and find unvisited remote nodes */
Packit 13e616
		for (pn = 1; pn < u->sw->num_ports; pn++) {
Packit 13e616
			osm_node_t *p_remote_node;
Packit 13e616
			struct dnup_node *rem_u;
Packit 13e616
			uint8_t current_min_hop, remote_min_hop,
Packit 13e616
			    set_hop_return_value;
Packit 13e616
			osm_switch_t *p_remote_sw;
Packit 13e616
Packit 13e616
			p_remote_node =
Packit 13e616
			    osm_node_get_remote_node(u->sw->p_node, pn,
Packit 13e616
						     &pn_rem);
Packit 13e616
			/* If no remote node OR remote node is not a SWITCH
Packit 13e616
			   continue to next pn */
Packit 13e616
			if (!p_remote_node || !p_remote_node->sw)
Packit 13e616
				continue;
Packit 13e616
			/* Fetch remote guid only after validation of remote node */
Packit 13e616
			p_remote_sw = p_remote_node->sw;
Packit 13e616
			rem_u = p_remote_sw->priv;
Packit 13e616
			/* Decide which direction to mark it (UP/DOWN) */
Packit 13e616
			next_dir = dnup_get_dir(u->rank, rem_u->rank);
Packit 13e616
Packit 13e616
			/* Set MinHop value for the current lid */
Packit 13e616
			current_min_hop = osm_switch_get_least_hops(u->sw, lid);
Packit 13e616
			/* Check hop count if better insert into list && update
Packit 13e616
			   the remote node Min Hop Table */
Packit 13e616
			remote_min_hop =
Packit 13e616
			    osm_switch_get_hop_count(p_remote_sw, lid, pn_rem);
Packit 13e616
Packit 13e616
			/* Check if this is a legal step : the only illegal step is going
Packit 13e616
			   from UP to DOWN */
Packit 13e616
			if ((current_dir == UP) && (next_dir == DOWN)) {
Packit 13e616
				OSM_LOG(p_log, OSM_LOG_DEBUG,
Packit 13e616
					"Avoiding move from 0x%016" PRIx64
Packit 13e616
					" to 0x%016" PRIx64 "\n",
Packit 13e616
					cl_ntoh64(osm_node_get_node_guid(u->sw->p_node)),
Packit 13e616
					cl_ntoh64(osm_node_get_node_guid(p_remote_node)));
Packit 13e616
				/* Illegal step. If prune_weight is set, allow it with an
Packit 13e616
				 * additional weight
Packit 13e616
				 */
Packit 13e616
				if(prune_weight) {
Packit 13e616
					current_min_hop+=prune_weight;
Packit 13e616
					if(current_min_hop >= 64) {
Packit 13e616
						OSM_LOG(p_log, OSM_LOG_ERROR,
Packit 13e616
							"ERR AE02: Too many hops on subnet,"
Packit 13e616
							" can't relax illegal Dn/Up transition.");
Packit 13e616
						osm_switch_set_hops(p_remote_sw, lid,
Packit 13e616
								    pn_rem, OSM_NO_PATH);
Packit 13e616
					}
Packit 13e616
				} else {
Packit 13e616
					continue;
Packit 13e616
				}
Packit 13e616
			}
Packit 13e616
			if (current_min_hop + 1 < remote_min_hop) {
Packit 13e616
				set_hop_return_value =
Packit 13e616
				    osm_switch_set_hops(p_remote_sw, lid,
Packit 13e616
							pn_rem,
Packit 13e616
							current_min_hop + 1);
Packit 13e616
				if(max_hops && current_min_hop + 1 > *max_hops) {
Packit 13e616
					*max_hops = current_min_hop + 1;
Packit 13e616
				}
Packit 13e616
				if (set_hop_return_value) {
Packit 13e616
					OSM_LOG(p_log, OSM_LOG_ERROR, "ERR AE01: "
Packit 13e616
						"Invalid value returned from set min hop is: %d\n",
Packit 13e616
						set_hop_return_value);
Packit 13e616
				}
Packit 13e616
				/* Check if remote port has already been visited */
Packit 13e616
				if (!rem_u->visited) {
Packit 13e616
					/* Insert dnup_switch item into the list */
Packit 13e616
					rem_u->dir = next_dir;
Packit 13e616
					rem_u->visited = 1;
Packit 13e616
					cl_qlist_insert_tail(&list,
Packit 13e616
							     &rem_u->list);
Packit 13e616
				}
Packit 13e616
			}
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
	OSM_LOG_EXIT(p_log);
Packit 13e616
	return 0;
Packit 13e616
}
Packit 13e616
Packit 13e616
/* NOTE : PLS check if we need to decide that the first */
Packit 13e616
/*        rank is a SWITCH for BFS purpose */
Packit 13e616
static int dnup_subn_rank(IN dnup_t * p_dnup)
Packit 13e616
{
Packit 13e616
	osm_switch_t *p_sw;
Packit 13e616
	osm_physp_t *p_physp, *p_remote_physp;
Packit 13e616
	cl_qlist_t list;
Packit 13e616
	cl_map_item_t *item;
Packit 13e616
	struct dnup_node *u, *remote_u;
Packit 13e616
	uint8_t num_ports, port_num;
Packit 13e616
	osm_log_t *p_log = &p_dnup->p_osm->log;
Packit 13e616
	unsigned max_rank = 0;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(p_log);
Packit 13e616
	cl_qlist_init(&list);
Packit 13e616
Packit 13e616
	/* add all node level switches to the list */
Packit 13e616
	for (item = cl_qmap_head(&p_dnup->p_osm->subn.sw_guid_tbl);
Packit 13e616
	     item != cl_qmap_end(&p_dnup->p_osm->subn.sw_guid_tbl);
Packit 13e616
	     item = cl_qmap_next(item)) {
Packit 13e616
		p_sw = (osm_switch_t *)item;
Packit 13e616
		u = p_sw->priv;
Packit 13e616
		if (u->rank == 0)
Packit 13e616
			cl_qlist_insert_tail(&list, &u->list);
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/* BFS the list till it's empty */
Packit 13e616
	while (!cl_is_qlist_empty(&list)) {
Packit 13e616
		u = (struct dnup_node *)cl_qlist_remove_head(&list);
Packit 13e616
		/* Go over all remote nodes and rank them (if not already visited) */
Packit 13e616
		p_sw = u->sw;
Packit 13e616
		num_ports = p_sw->num_ports;
Packit 13e616
		OSM_LOG(p_log, OSM_LOG_DEBUG,
Packit 13e616
			"Handling switch GUID 0x%" PRIx64 "\n",
Packit 13e616
			cl_ntoh64(osm_node_get_node_guid(p_sw->p_node)));
Packit 13e616
		for (port_num = 1; port_num < num_ports; port_num++) {
Packit 13e616
			ib_net64_t port_guid;
Packit 13e616
Packit 13e616
			/* Current port fetched in order to get remote side */
Packit 13e616
			p_physp =
Packit 13e616
			    osm_node_get_physp_ptr(p_sw->p_node, port_num);
Packit 13e616
Packit 13e616
			if (!p_physp)
Packit 13e616
				continue;
Packit 13e616
Packit 13e616
			p_remote_physp = p_physp->p_remote_physp;
Packit 13e616
Packit 13e616
			/*
Packit 13e616
			   make sure that all the following occur on p_remote_physp:
Packit 13e616
			   1. The port isn't NULL
Packit 13e616
			   2. It is a switch
Packit 13e616
			 */
Packit 13e616
			if (p_remote_physp && p_remote_physp->p_node->sw) {
Packit 13e616
				remote_u = p_remote_physp->p_node->sw->priv;
Packit 13e616
				port_guid = p_remote_physp->port_guid;
Packit 13e616
Packit 13e616
				if (remote_u->rank > u->rank + 1) {
Packit 13e616
					remote_u->rank = u->rank + 1;
Packit 13e616
					max_rank = remote_u->rank;
Packit 13e616
					cl_qlist_insert_tail(&list,
Packit 13e616
							     &remote_u->list);
Packit 13e616
					OSM_LOG(p_log, OSM_LOG_DEBUG,
Packit 13e616
						"Rank of port GUID 0x%" PRIx64
Packit 13e616
						" = %u\n", cl_ntoh64(port_guid),
Packit 13e616
						remote_u->rank);
Packit 13e616
				}
Packit 13e616
			}
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/* Print Summary of ranking */
Packit 13e616
	OSM_LOG(p_log, OSM_LOG_VERBOSE,
Packit 13e616
		"Subnet ranking completed. Max Node Rank = %d\n", max_rank);
Packit 13e616
	OSM_LOG_EXIT(p_log);
Packit 13e616
	return 0;
Packit 13e616
}
Packit 13e616
Packit 13e616
static int dnup_set_min_hop_table(IN dnup_t * p_dnup)
Packit 13e616
{
Packit 13e616
	osm_subn_t *p_subn = &p_dnup->p_osm->subn;
Packit 13e616
	osm_log_t *p_log = &p_dnup->p_osm->log;
Packit 13e616
	osm_switch_t *p_sw;
Packit 13e616
	struct dnup_node *u;
Packit 13e616
	cl_map_item_t *item;
Packit 13e616
	uint8_t max_hops = 0;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(p_log);
Packit 13e616
Packit 13e616
	/* Go over all the switches in the subnet - for each init their Min Hop
Packit 13e616
	   Table */
Packit 13e616
	OSM_LOG(p_log, OSM_LOG_VERBOSE,
Packit 13e616
		"Init Min Hop Table of all switches [\n");
Packit 13e616
Packit 13e616
	for (item = cl_qmap_head(&p_dnup->p_osm->subn.sw_guid_tbl);
Packit 13e616
	     item != cl_qmap_end(&p_dnup->p_osm->subn.sw_guid_tbl);
Packit 13e616
	     item = cl_qmap_next(item)) {
Packit 13e616
		p_sw = (osm_switch_t *)item;
Packit 13e616
		/* Clear Min Hop Table */
Packit 13e616
		osm_switch_clear_hops(p_sw);
Packit 13e616
	}
Packit 13e616
Packit 13e616
	OSM_LOG(p_log, OSM_LOG_VERBOSE,
Packit 13e616
		"Init Min Hop Table of all switches ]\n");
Packit 13e616
Packit 13e616
	/* Now do the BFS for each port  in the subnet */
Packit 13e616
	OSM_LOG(p_log, OSM_LOG_VERBOSE,
Packit 13e616
		"BFS through all port guids in the subnet [\n");
Packit 13e616
Packit 13e616
	for (item = cl_qmap_head(&p_dnup->p_osm->subn.sw_guid_tbl);
Packit 13e616
	     item != cl_qmap_end(&p_dnup->p_osm->subn.sw_guid_tbl);
Packit 13e616
	     item = cl_qmap_next(item)) {
Packit 13e616
		p_sw = (osm_switch_t *)item;
Packit 13e616
		dnup_bfs_by_node(p_log, p_subn, p_sw, 0, &max_hops);
Packit 13e616
	}
Packit 13e616
	if(p_subn->opt.connect_roots) {
Packit 13e616
		/*This is probably not necessary, by I am more comfortable
Packit 13e616
		 * clearing any possible side effects from the previous
Packit 13e616
		 * dnup routing pass
Packit 13e616
		 */
Packit 13e616
		for (item = cl_qmap_head(&p_dnup->p_osm->subn.sw_guid_tbl);
Packit 13e616
		     item != cl_qmap_end(&p_dnup->p_osm->subn.sw_guid_tbl);
Packit 13e616
		     item = cl_qmap_next(item)) {
Packit 13e616
			p_sw = (osm_switch_t *)item;
Packit 13e616
			osm_switch_clear_hops(p_sw);
Packit 13e616
			u = (struct dnup_node *) p_sw->priv;
Packit 13e616
			u->visited = 0;
Packit 13e616
		}
Packit 13e616
		for (item = cl_qmap_head(&p_dnup->p_osm->subn.sw_guid_tbl);
Packit 13e616
		     item != cl_qmap_end(&p_dnup->p_osm->subn.sw_guid_tbl);
Packit 13e616
		     item = cl_qmap_next(item)) {
Packit 13e616
			p_sw = (osm_switch_t *)item;
Packit 13e616
			dnup_bfs_by_node(p_log, p_subn, p_sw, max_hops + 1, NULL);
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
	OSM_LOG(p_log, OSM_LOG_VERBOSE,
Packit 13e616
		"BFS through all port guids in the subnet ]\n");
Packit 13e616
	/* Cleanup */
Packit 13e616
	OSM_LOG_EXIT(p_log);
Packit 13e616
	return 0;
Packit 13e616
}
Packit 13e616
Packit 13e616
static int dnup_build_lid_matrices(IN dnup_t * p_dnup)
Packit 13e616
{
Packit 13e616
	int status;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(&p_dnup->p_osm->log);
Packit 13e616
Packit 13e616
	OSM_LOG(&p_dnup->p_osm->log, OSM_LOG_VERBOSE,
Packit 13e616
		"Ranking all port guids in the list\n");
Packit 13e616
	/* Check if it's not a switched subnet */
Packit 13e616
	if (cl_is_qmap_empty(&p_dnup->p_osm->subn.sw_guid_tbl)) {
Packit 13e616
		OSM_LOG(&p_dnup->p_osm->log, OSM_LOG_ERROR, "ERR AEOB: "
Packit 13e616
			"This is not a switched subnet, cannot perform DNUP algorithm\n");
Packit 13e616
		status = -1;
Packit 13e616
		goto _exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/* Rank the subnet switches */
Packit 13e616
	dnup_subn_rank(p_dnup);
Packit 13e616
Packit 13e616
	/* After multiple ranking need to set Min Hop Table by DnUp algorithm  */
Packit 13e616
	OSM_LOG(&p_dnup->p_osm->log, OSM_LOG_VERBOSE,
Packit 13e616
		"Setting all switches' Min Hop Table\n");
Packit 13e616
	status = dnup_set_min_hop_table(p_dnup);
Packit 13e616
Packit 13e616
_exit:
Packit 13e616
	OSM_LOG_EXIT(&p_dnup->p_osm->log);
Packit 13e616
	return status;
Packit 13e616
}
Packit 13e616
Packit 13e616
static struct dnup_node *create_dnup_node(osm_switch_t * sw)
Packit 13e616
{
Packit 13e616
	struct dnup_node *u;
Packit 13e616
Packit 13e616
	u = malloc(sizeof(*u));
Packit 13e616
	if (!u)
Packit 13e616
		return NULL;
Packit 13e616
	memset(u, 0, sizeof(*u));
Packit 13e616
	u->sw = sw;
Packit 13e616
	u->rank = 0xffffffff;
Packit 13e616
	return u;
Packit 13e616
}
Packit 13e616
Packit 13e616
static void delete_dnup_node(struct dnup_node *u)
Packit 13e616
{
Packit 13e616
	u->sw->priv = NULL;
Packit 13e616
	free(u);
Packit 13e616
}
Packit 13e616
Packit 13e616
/* DNUP callback function */
Packit 13e616
static int dnup_lid_matrices(void *ctx)
Packit 13e616
{
Packit 13e616
	dnup_t *p_dnup = ctx;
Packit 13e616
	cl_map_item_t *item;
Packit 13e616
	osm_switch_t *p_sw;
Packit 13e616
	int ret = 0;
Packit 13e616
	int num_leafs = 0;
Packit 13e616
	uint8_t pn, pn_rem;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(&p_dnup->p_osm->log);
Packit 13e616
Packit 13e616
	for (item = cl_qmap_head(&p_dnup->p_osm->subn.sw_guid_tbl);
Packit 13e616
	     item != cl_qmap_end(&p_dnup->p_osm->subn.sw_guid_tbl);
Packit 13e616
	     item = cl_qmap_next(item)) {
Packit 13e616
		p_sw = (osm_switch_t *)item;
Packit 13e616
		p_sw->priv = create_dnup_node(p_sw);
Packit 13e616
		if (!p_sw->priv) {
Packit 13e616
			OSM_LOG(&(p_dnup->p_osm->log), OSM_LOG_ERROR, "ERR AE0C: "
Packit 13e616
				"cannot create dnup node\n");
Packit 13e616
			OSM_LOG_EXIT(&p_dnup->p_osm->log);
Packit 13e616
			return -1;
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
Packit 13e616
	/* First setup node level nodes */
Packit 13e616
	for (item = cl_qmap_head(&p_dnup->p_osm->subn.sw_guid_tbl);
Packit 13e616
	     item != cl_qmap_end(&p_dnup->p_osm->subn.sw_guid_tbl);
Packit 13e616
	     item = cl_qmap_next(item)) {
Packit 13e616
		p_sw = (osm_switch_t *)item;
Packit 13e616
Packit 13e616
		for (pn = 0; pn < p_sw->num_ports; pn++) {
Packit 13e616
			osm_node_t *p_remote_node;
Packit 13e616
			p_remote_node = osm_node_get_remote_node(p_sw->p_node, pn, &pn_rem);
Packit 13e616
			if(p_remote_node && !p_remote_node->sw) {
Packit 13e616
				struct dnup_node *u = p_sw->priv;
Packit 13e616
				u->rank = 0;
Packit 13e616
				OSM_LOG(&(p_dnup->p_osm->log),
Packit 13e616
					OSM_LOG_VERBOSE, "(%s) rank 0 leaf switch\n",
Packit 13e616
					p_sw->p_node->print_desc);
Packit 13e616
				num_leafs++;
Packit 13e616
				break;
Packit 13e616
			}
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
	if(num_leafs == 0) {
Packit 13e616
		OSM_LOG(&(p_dnup->p_osm->log),
Packit 13e616
			OSM_LOG_ERROR, "ERR AE0D: No leaf switches found, DnUp routing failed\n");
Packit 13e616
		OSM_LOG_EXIT(&p_dnup->p_osm->log);
Packit 13e616
		return -1;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	ret = dnup_build_lid_matrices(p_dnup);
Packit 13e616
Packit 13e616
	for (item = cl_qmap_head(&p_dnup->p_osm->subn.sw_guid_tbl);
Packit 13e616
	     item != cl_qmap_end(&p_dnup->p_osm->subn.sw_guid_tbl);
Packit 13e616
	     item = cl_qmap_next(item)) {
Packit 13e616
		p_sw = (osm_switch_t *) item;
Packit 13e616
		delete_dnup_node(p_sw->priv);
Packit 13e616
	}
Packit 13e616
Packit 13e616
	OSM_LOG_EXIT(&p_dnup->p_osm->log);
Packit 13e616
	return ret;
Packit 13e616
}
Packit 13e616
Packit 13e616
static void dnup_delete(void *context)
Packit 13e616
{
Packit 13e616
	free(context);
Packit 13e616
}
Packit 13e616
Packit 13e616
int osm_ucast_dnup_setup(struct osm_routing_engine *r, osm_opensm_t *osm)
Packit 13e616
{
Packit 13e616
	dnup_t *dnup;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(&osm->log);
Packit 13e616
Packit 13e616
	dnup = malloc(sizeof(dnup_t));
Packit 13e616
	if (!dnup)
Packit 13e616
		return -1;
Packit 13e616
	memset(dnup, 0, sizeof(dnup_t));
Packit 13e616
Packit 13e616
	dnup->p_osm = osm;
Packit 13e616
Packit 13e616
	r->context = dnup;
Packit 13e616
	r->destroy = dnup_delete;
Packit 13e616
	r->build_lid_matrices = dnup_lid_matrices;
Packit 13e616
Packit 13e616
	OSM_LOG_EXIT(&osm->log);
Packit 13e616
	return 0;
Packit 13e616
}