Blame opensm/osm_ucast_dnup.c

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