Blame opensm/osm_ucast_updn.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
 *
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_UPDN_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 updn_switch_dir {
Packit 13e616
	UP = 0,
Packit 13e616
	DOWN
Packit 13e616
} updn_switch_dir_t;
Packit 13e616
Packit 13e616
/* updn structure */
Packit 13e616
typedef struct updn {
Packit 13e616
	unsigned num_roots;
Packit 13e616
	osm_opensm_t *p_osm;
Packit 13e616
} updn_t;
Packit 13e616
Packit 13e616
struct updn_node {
Packit 13e616
	cl_list_item_t list;
Packit 13e616
	osm_switch_t *sw;
Packit 13e616
	uint64_t id;
Packit 13e616
	updn_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 updn_switch_dir_t updn_get_dir(unsigned cur_rank, unsigned rem_rank,
Packit 13e616
				      uint64_t cur_id, uint64_t rem_id)
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 UPDN 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 UP;
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
		/* Equal rank, decide by id number, bigger == UP direction */
Packit 13e616
		if (cur_id > rem_id)
Packit 13e616
			return UP;
Packit 13e616
		else
Packit 13e616
			return DOWN;
Packit 13e616
	}
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 updn_bfs_by_node(IN osm_log_t * p_log, IN osm_subn_t * p_subn,
Packit 13e616
			    IN osm_switch_t * p_sw)
Packit 13e616
{
Packit 13e616
	uint8_t pn, pn_rem;
Packit 13e616
	cl_qlist_t list;
Packit 13e616
	uint16_t lid;
Packit 13e616
	struct updn_node *u;
Packit 13e616
	updn_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 = UP;
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 updn_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 updn_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 = updn_get_dir(u->rank, rem_u->rank,
Packit 13e616
						u->id, rem_u->id);
Packit 13e616
Packit 13e616
			/* Check if this is a legal step : the only illegal step is going
Packit 13e616
			   from DOWN to UP */
Packit 13e616
			if ((current_dir == DOWN) && (next_dir == UP)) {
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 */
Packit 13e616
				continue;
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
			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 (set_hop_return_value) {
Packit 13e616
					OSM_LOG(p_log, OSM_LOG_ERROR, "ERR AA01: "
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 updn_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 updn_subn_rank(IN updn_t * p_updn)
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 updn_node *u, *remote_u;
Packit 13e616
	uint8_t num_ports, port_num;
Packit 13e616
	osm_log_t *p_log = &p_updn->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 roots to the list */
Packit 13e616
	for (item = cl_qmap_head(&p_updn->p_osm->subn.sw_guid_tbl);
Packit 13e616
	     item != cl_qmap_end(&p_updn->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)
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 updn_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
/* hack: preserve min hops entries to any other root switches */
Packit 13e616
static void updn_clear_non_root_hops(updn_t * updn, osm_switch_t * sw)
Packit 13e616
{
Packit 13e616
	osm_port_t *port;
Packit 13e616
	unsigned i;
Packit 13e616
Packit 13e616
	for (i = 0; i < sw->num_hops; i++)
Packit 13e616
		if (sw->hops[i]) {
Packit 13e616
			port = osm_get_port_by_lid_ho(&updn->p_osm->subn, i);
Packit 13e616
			if (!port || !port->p_node->sw
Packit 13e616
			    || ((struct updn_node *)port->p_node->sw->priv)->
Packit 13e616
			    rank != 0)
Packit 13e616
				memset(sw->hops[i], 0xff, sw->num_ports);
Packit 13e616
		}
Packit 13e616
}
Packit 13e616
Packit 13e616
static int updn_set_min_hop_table(IN updn_t * p_updn)
Packit 13e616
{
Packit 13e616
	osm_subn_t *p_subn = &p_updn->p_osm->subn;
Packit 13e616
	osm_log_t *p_log = &p_updn->p_osm->log;
Packit 13e616
	osm_switch_t *p_sw;
Packit 13e616
	cl_map_item_t *item;
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_updn->p_osm->subn.sw_guid_tbl);
Packit 13e616
	     item != cl_qmap_end(&p_updn->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
		if (p_subn->opt.connect_roots)
Packit 13e616
			updn_clear_non_root_hops(p_updn, p_sw);
Packit 13e616
		else
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_updn->p_osm->subn.sw_guid_tbl);
Packit 13e616
	     item != cl_qmap_end(&p_updn->p_osm->subn.sw_guid_tbl);
Packit 13e616
	     item = cl_qmap_next(item)) {
Packit 13e616
		p_sw = (osm_switch_t *)item;
Packit 13e616
		updn_bfs_by_node(p_log, p_subn, p_sw);
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 updn_build_lid_matrices(IN updn_t * p_updn)
Packit 13e616
{
Packit 13e616
	int status;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(&p_updn->p_osm->log);
Packit 13e616
Packit 13e616
	OSM_LOG(&p_updn->p_osm->log, OSM_LOG_VERBOSE,
Packit 13e616
		"Ranking all port guids in the list\n");
Packit 13e616
	if (!p_updn->num_roots) {
Packit 13e616
		OSM_LOG(&p_updn->p_osm->log, OSM_LOG_ERROR, "ERR AA0A: "
Packit 13e616
			"No guids were provided or number of guids is 0\n");
Packit 13e616
		status = -1;
Packit 13e616
		goto _exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/* Check if it's not a switched subnet */
Packit 13e616
	if (cl_is_qmap_empty(&p_updn->p_osm->subn.sw_guid_tbl)) {
Packit 13e616
		OSM_LOG(&p_updn->p_osm->log, OSM_LOG_ERROR, "ERR AA0B: "
Packit 13e616
			"This is not a switched subnet, cannot perform UPDN algorithm\n");
Packit 13e616
		status = -1;
Packit 13e616
		goto _exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/* Rank the subnet switches */
Packit 13e616
	if (updn_subn_rank(p_updn)) {
Packit 13e616
		OSM_LOG(&p_updn->p_osm->log, OSM_LOG_ERROR, "ERR AA0E: "
Packit 13e616
			"Failed to assign ranks\n");
Packit 13e616
		status = -1;
Packit 13e616
		goto _exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/* After multiple ranking need to set Min Hop Table by UpDn algorithm  */
Packit 13e616
	OSM_LOG(&p_updn->p_osm->log, OSM_LOG_VERBOSE,
Packit 13e616
		"Setting all switches' Min Hop Table\n");
Packit 13e616
	status = updn_set_min_hop_table(p_updn);
Packit 13e616
Packit 13e616
_exit:
Packit 13e616
	OSM_LOG_EXIT(&p_updn->p_osm->log);
Packit 13e616
	return status;
Packit 13e616
}
Packit 13e616
Packit 13e616
static struct updn_node *create_updn_node(osm_switch_t * sw)
Packit 13e616
{
Packit 13e616
	struct updn_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->id = cl_ntoh64(osm_node_get_node_guid(sw->p_node));
Packit 13e616
	u->rank = 0xffffffff;
Packit 13e616
	return u;
Packit 13e616
}
Packit 13e616
Packit 13e616
static void delete_updn_node(struct updn_node *u)
Packit 13e616
{
Packit 13e616
	u->sw->priv = NULL;
Packit 13e616
	free(u);
Packit 13e616
}
Packit 13e616
Packit 13e616
/* Find Root nodes automatically by Min Hop Table info */
Packit 13e616
static void updn_find_root_nodes_by_min_hop(OUT updn_t * p_updn)
Packit 13e616
{
Packit 13e616
	osm_opensm_t *p_osm = p_updn->p_osm;
Packit 13e616
	osm_switch_t *p_sw;
Packit 13e616
	osm_port_t *p_port;
Packit 13e616
	osm_physp_t *p_physp;
Packit 13e616
	cl_map_item_t *item;
Packit 13e616
	double thd1, thd2;
Packit 13e616
	unsigned i, cas_num = 0;
Packit 13e616
	unsigned *cas_per_sw;
Packit 13e616
	uint16_t lid_ho;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(&p_osm->log);
Packit 13e616
Packit 13e616
	OSM_LOG(&p_osm->log, OSM_LOG_DEBUG,
Packit 13e616
		"Current number of ports in the subnet is %d\n",
Packit 13e616
		cl_qmap_count(&p_osm->subn.port_guid_tbl));
Packit 13e616
Packit 13e616
	lid_ho = (uint16_t) cl_ptr_vector_get_size(&p_updn->p_osm->subn.port_lid_tbl) + 1;
Packit 13e616
	cas_per_sw = malloc(lid_ho * sizeof(*cas_per_sw));
Packit 13e616
	if (!cas_per_sw) {
Packit 13e616
		OSM_LOG(&p_osm->log, OSM_LOG_ERROR, "ERR AA14: "
Packit 13e616
			"cannot alloc mem for CAs per switch counter array\n");
Packit 13e616
		goto _exit;
Packit 13e616
	}
Packit 13e616
	memset(cas_per_sw, 0, lid_ho * sizeof(*cas_per_sw));
Packit 13e616
Packit 13e616
	/* Find the Maximum number of CAs (and routers) for histogram normalization */
Packit 13e616
	OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE,
Packit 13e616
		"Finding the number of CAs and storing them in cl_map\n");
Packit 13e616
	for (item = cl_qmap_head(&p_updn->p_osm->subn.port_guid_tbl);
Packit 13e616
	     item != cl_qmap_end(&p_updn->p_osm->subn.port_guid_tbl);
Packit 13e616
	     item = cl_qmap_next(item)) {
Packit 13e616
		p_port = (osm_port_t *)item;
Packit 13e616
		if (!p_port->p_node->sw) {
Packit 13e616
			p_physp = p_port->p_physp->p_remote_physp;
Packit 13e616
			if (!p_physp || !p_physp->p_node->sw)
Packit 13e616
				continue;
Packit 13e616
			lid_ho = osm_node_get_base_lid(p_physp->p_node, 0);
Packit 13e616
			lid_ho = cl_ntoh16(lid_ho);
Packit 13e616
			cas_per_sw[lid_ho]++;
Packit 13e616
			cas_num++;
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
	thd1 = cas_num * 0.9;
Packit 13e616
	thd2 = cas_num * 0.05;
Packit 13e616
	OSM_LOG(&p_osm->log, OSM_LOG_DEBUG,
Packit 13e616
		"Found %u CAs and RTRs, %u SWs in the subnet. "
Packit 13e616
		"Thresholds are thd1 = %f && thd2 = %f\n",
Packit 13e616
		cas_num, cl_qmap_count(&p_osm->subn.sw_guid_tbl), thd1, thd2);
Packit 13e616
Packit 13e616
	OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE,
Packit 13e616
		"Passing through all switches to collect Min Hop info\n");
Packit 13e616
	for (item = cl_qmap_head(&p_updn->p_osm->subn.sw_guid_tbl);
Packit 13e616
	     item != cl_qmap_end(&p_updn->p_osm->subn.sw_guid_tbl);
Packit 13e616
	     item = cl_qmap_next(item)) {
Packit 13e616
		unsigned hop_hist[IB_SUBNET_PATH_HOPS_MAX];
Packit 13e616
		uint16_t max_lid_ho;
Packit 13e616
		uint8_t hop_val;
Packit 13e616
		uint16_t numHopBarsOverThd1 = 0;
Packit 13e616
		uint16_t numHopBarsOverThd2 = 0;
Packit 13e616
Packit 13e616
		p_sw = (osm_switch_t *) item;
Packit 13e616
Packit 13e616
		memset(hop_hist, 0, sizeof(hop_hist));
Packit 13e616
Packit 13e616
		max_lid_ho = p_sw->max_lid_ho;
Packit 13e616
		for (lid_ho = 1; lid_ho <= max_lid_ho; lid_ho++)
Packit 13e616
			if (cas_per_sw[lid_ho]) {
Packit 13e616
				hop_val =
Packit 13e616
				    osm_switch_get_least_hops(p_sw, lid_ho);
Packit 13e616
				if (hop_val >= IB_SUBNET_PATH_HOPS_MAX)
Packit 13e616
					continue;
Packit 13e616
Packit 13e616
				hop_hist[hop_val] += cas_per_sw[lid_ho];
Packit 13e616
			}
Packit 13e616
Packit 13e616
		/* Now recognize the spines by requiring one bar to be
Packit 13e616
		   above 90% of the number of CAs and RTRs */
Packit 13e616
		for (i = 0; i < IB_SUBNET_PATH_HOPS_MAX; i++) {
Packit 13e616
			if (hop_hist[i] > thd1)
Packit 13e616
				numHopBarsOverThd1++;
Packit 13e616
			if (hop_hist[i] > thd2)
Packit 13e616
				numHopBarsOverThd2++;
Packit 13e616
		}
Packit 13e616
Packit 13e616
		/* If thd conditions are valid - rank the root node */
Packit 13e616
		if (numHopBarsOverThd1 == 1 && numHopBarsOverThd2 == 1) {
Packit 13e616
			OSM_LOG(&p_osm->log, OSM_LOG_DEBUG,
Packit 13e616
				"Ranking GUID 0x%" PRIx64 " as root node\n",
Packit 13e616
				cl_ntoh64(osm_node_get_node_guid(p_sw->p_node)));
Packit 13e616
			((struct updn_node *)p_sw->priv)->rank = 0;
Packit 13e616
			p_updn->num_roots++;
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
	free(cas_per_sw);
Packit 13e616
_exit:
Packit 13e616
	OSM_LOG_EXIT(&p_osm->log);
Packit 13e616
	return;
Packit 13e616
}
Packit 13e616
Packit 13e616
static void dump_roots(cl_map_item_t *item, FILE *file, void *cxt)
Packit 13e616
{
Packit 13e616
	osm_switch_t *sw = (osm_switch_t *)item;
Packit 13e616
	if (!((struct updn_node *)sw->priv)->rank)
Packit 13e616
		fprintf(file, "0x%" PRIx64 "\n",
Packit 13e616
			cl_ntoh64(osm_node_get_node_guid(sw->p_node)));
Packit 13e616
}
Packit 13e616
Packit 13e616
static int update_id(void *cxt, uint64_t guid, char *p)
Packit 13e616
{
Packit 13e616
	osm_opensm_t *osm = cxt;
Packit 13e616
	osm_switch_t *sw;
Packit 13e616
	uint64_t id;
Packit 13e616
	char *e;
Packit 13e616
Packit 13e616
	sw = osm_get_switch_by_guid(&osm->subn, cl_hton64(guid));
Packit 13e616
	if (!sw) {
Packit 13e616
		OSM_LOG(&osm->log, OSM_LOG_VERBOSE,
Packit 13e616
			"switch with guid 0x%" PRIx64 " is not found\n", guid);
Packit 13e616
		return 0;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	id = strtoull(p, &e, 0);
Packit 13e616
	if (*e && !isspace(*e)) {
Packit 13e616
		OSM_LOG(&osm->log, OSM_LOG_ERROR,
Packit 13e616
			"ERR AA05: cannot parse node id \'%s\'", p);
Packit 13e616
		return -1;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	OSM_LOG(&osm->log, OSM_LOG_DEBUG,
Packit 13e616
		"update node 0x%" PRIx64 " id to 0x%" PRIx64 "\n", guid, id);
Packit 13e616
Packit 13e616
	((struct updn_node *)sw->priv)->id = id;
Packit 13e616
Packit 13e616
	return 0;
Packit 13e616
}
Packit 13e616
Packit 13e616
static int rank_root_node(void *cxt, uint64_t guid, char *p)
Packit 13e616
{
Packit 13e616
	updn_t *updn = cxt;
Packit 13e616
	osm_switch_t *sw;
Packit 13e616
Packit 13e616
	sw = osm_get_switch_by_guid(&updn->p_osm->subn, cl_hton64(guid));
Packit 13e616
	if (!sw) {
Packit 13e616
		OSM_LOG(&updn->p_osm->log, OSM_LOG_VERBOSE,
Packit 13e616
			"switch with guid 0x%" PRIx64 " is not found\n", guid);
Packit 13e616
		return 0;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	OSM_LOG(&updn->p_osm->log, OSM_LOG_DEBUG,
Packit 13e616
		"Ranking root port GUID 0x%" PRIx64 "\n", guid);
Packit 13e616
Packit 13e616
	((struct updn_node *)sw->priv)->rank = 0;
Packit 13e616
	updn->num_roots++;
Packit 13e616
Packit 13e616
	return 0;
Packit 13e616
}
Packit 13e616
Packit 13e616
/* UPDN callback function */
Packit 13e616
static int updn_lid_matrices(void *ctx)
Packit 13e616
{
Packit 13e616
	updn_t *p_updn = ctx;
Packit 13e616
	cl_map_item_t *item;
Packit 13e616
	osm_switch_t *p_sw;
Packit 13e616
	int ret = 0;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(&p_updn->p_osm->log);
Packit 13e616
Packit 13e616
	for (item = cl_qmap_head(&p_updn->p_osm->subn.sw_guid_tbl);
Packit 13e616
	     item != cl_qmap_end(&p_updn->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_updn_node(p_sw);
Packit 13e616
		if (!p_sw->priv) {
Packit 13e616
			OSM_LOG(&(p_updn->p_osm->log), OSM_LOG_ERROR, "ERR AA0C: "
Packit 13e616
				"cannot create updn node\n");
Packit 13e616
			OSM_LOG_EXIT(&p_updn->p_osm->log);
Packit 13e616
			return -1;
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/* First setup root nodes */
Packit 13e616
	p_updn->num_roots = 0;
Packit 13e616
Packit 13e616
	if (p_updn->p_osm->subn.opt.root_guid_file) {
Packit 13e616
		OSM_LOG(&p_updn->p_osm->log, OSM_LOG_DEBUG,
Packit 13e616
			"UPDN - Fetching root nodes from file \'%s\'\n",
Packit 13e616
			p_updn->p_osm->subn.opt.root_guid_file);
Packit 13e616
Packit 13e616
		ret = parse_node_map(p_updn->p_osm->subn.opt.root_guid_file,
Packit 13e616
				     rank_root_node, p_updn);
Packit 13e616
		if (ret) {
Packit 13e616
			OSM_LOG(&p_updn->p_osm->log, OSM_LOG_ERROR, "ERR AA02: "
Packit 13e616
				"cannot parse root guids file \'%s\'\n",
Packit 13e616
				p_updn->p_osm->subn.opt.root_guid_file);
Packit 13e616
			osm_ucast_mgr_build_lid_matrices(&p_updn->p_osm->sm.ucast_mgr);
Packit 13e616
			updn_find_root_nodes_by_min_hop(p_updn);
Packit 13e616
		} else if (p_updn->p_osm->subn.opt.connect_roots &&
Packit 13e616
			   p_updn->num_roots > 1)
Packit 13e616
			osm_ucast_mgr_build_lid_matrices(&p_updn->p_osm->sm.ucast_mgr);
Packit 13e616
	} else {
Packit 13e616
		osm_ucast_mgr_build_lid_matrices(&p_updn->p_osm->sm.ucast_mgr);
Packit 13e616
		updn_find_root_nodes_by_min_hop(p_updn);
Packit 13e616
	}
Packit 13e616
Packit 13e616
	if (p_updn->p_osm->subn.opt.ids_guid_file) {
Packit 13e616
		OSM_LOG(&p_updn->p_osm->log, OSM_LOG_DEBUG,
Packit 13e616
			"UPDN - update node ids from file \'%s\'\n",
Packit 13e616
			p_updn->p_osm->subn.opt.ids_guid_file);
Packit 13e616
Packit 13e616
		ret = parse_node_map(p_updn->p_osm->subn.opt.ids_guid_file,
Packit 13e616
				     update_id, p_updn->p_osm);
Packit 13e616
		if (ret)
Packit 13e616
			OSM_LOG(&p_updn->p_osm->log, OSM_LOG_ERROR, "ERR AA03: "
Packit 13e616
				"cannot parse node ids file \'%s\'\n",
Packit 13e616
				p_updn->p_osm->subn.opt.ids_guid_file);
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/* Only if there are assigned root nodes do the algorithm, otherwise perform do nothing */
Packit 13e616
	if (p_updn->num_roots) {
Packit 13e616
		OSM_LOG(&p_updn->p_osm->log, OSM_LOG_DEBUG,
Packit 13e616
			"activating UPDN algorithm\n");
Packit 13e616
		ret = updn_build_lid_matrices(p_updn);
Packit 13e616
	} else {
Packit 13e616
		OSM_LOG(&p_updn->p_osm->log, OSM_LOG_INFO,
Packit 13e616
			"disabling UPDN algorithm, no root nodes were found\n");
Packit 13e616
		ret = -1;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	if (OSM_LOG_IS_ACTIVE_V2(&p_updn->p_osm->log, OSM_LOG_ROUTING))
Packit 13e616
		osm_dump_qmap_to_file(p_updn->p_osm, "opensm-updn-roots.dump",
Packit 13e616
				      &p_updn->p_osm->subn.sw_guid_tbl,
Packit 13e616
				      dump_roots, NULL);
Packit 13e616
Packit 13e616
	for (item = cl_qmap_head(&p_updn->p_osm->subn.sw_guid_tbl);
Packit 13e616
	     item != cl_qmap_end(&p_updn->p_osm->subn.sw_guid_tbl);
Packit 13e616
	     item = cl_qmap_next(item)) {
Packit 13e616
		p_sw = (osm_switch_t *) item;
Packit 13e616
		delete_updn_node(p_sw->priv);
Packit 13e616
	}
Packit 13e616
Packit 13e616
	OSM_LOG_EXIT(&p_updn->p_osm->log);
Packit 13e616
	return ret;
Packit 13e616
}
Packit 13e616
Packit 13e616
static void updn_delete(void *context)
Packit 13e616
{
Packit 13e616
	free(context);
Packit 13e616
}
Packit 13e616
Packit 13e616
int osm_ucast_updn_setup(struct osm_routing_engine *r, osm_opensm_t *osm)
Packit 13e616
{
Packit 13e616
	updn_t *updn;
Packit 13e616
Packit 13e616
	updn = malloc(sizeof(updn_t));
Packit 13e616
	if (!updn)
Packit 13e616
		return -1;
Packit 13e616
	memset(updn, 0, sizeof(updn_t));
Packit 13e616
Packit 13e616
	updn->p_osm = osm;
Packit 13e616
Packit 13e616
	r->context = updn;
Packit 13e616
	r->destroy = updn_delete;
Packit 13e616
	r->build_lid_matrices = updn_lid_matrices;
Packit 13e616
Packit 13e616
	return 0;
Packit 13e616
}