Blame opensm/osm_ucast_dfsssp.c

Packit Service 54dbc3
/*
Packit Service 54dbc3
 * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved.
Packit Service 54dbc3
 * Copyright (c) 2002-2015 Mellanox Technologies LTD. All rights reserved.
Packit Service 54dbc3
 * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
Packit Service 54dbc3
 * Copyright (c) 2009-2015 ZIH, TU Dresden, Federal Republic of Germany. All rights reserved.
Packit Service 54dbc3
 * Copyright (C) 2012-2017 Tokyo Institute of Technology. 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 OpenSM (deadlock-free) single-source-shortest-path routing
Packit Service 54dbc3
 *    (with dijkstra algorithm)
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 <stdio.h>
Packit Service 54dbc3
#include <stdlib.h>
Packit Service 54dbc3
#include <string.h>
Packit Service 54dbc3
#include <complib/cl_heap.h>
Packit Service 54dbc3
#include <opensm/osm_file_ids.h>
Packit Service 54dbc3
#define FILE_ID OSM_FILE_UCAST_DFSSSP_C
Packit Service 54dbc3
#include <opensm/osm_ucast_mgr.h>
Packit Service 54dbc3
#include <opensm/osm_opensm.h>
Packit Service 54dbc3
#include <opensm/osm_node.h>
Packit Service 54dbc3
#include <opensm/osm_multicast.h>
Packit Service 54dbc3
#include <opensm/osm_mcast_mgr.h>
Packit Service 54dbc3
Packit Service 54dbc3
/* "infinity" for dijkstra */
Packit Service 54dbc3
#define INF      0x7FFFFFFF
Packit Service 54dbc3
Packit Service 54dbc3
enum {
Packit Service 54dbc3
	UNDISCOVERED = 0,
Packit Service 54dbc3
	DISCOVERED
Packit Service 54dbc3
};
Packit Service 54dbc3
Packit Service 54dbc3
enum {
Packit Service 54dbc3
	UNKNOWN = 0,
Packit Service 54dbc3
	GRAY,
Packit Service 54dbc3
	BLACK,
Packit Service 54dbc3
};
Packit Service 54dbc3
Packit Service 54dbc3
typedef struct link {
Packit Service 54dbc3
	uint64_t guid;		/* guid of the neighbor behind the link */
Packit Service 54dbc3
	uint32_t from;		/* base_index in the adjazenz list (start of the link) */
Packit Service 54dbc3
	uint8_t from_port;	/* port on the base_side (needed for weight update to identify the correct link for multigraphs) */
Packit Service 54dbc3
	uint32_t to;		/* index of the neighbor in the adjazenz list (end of the link) */
Packit Service 54dbc3
	uint8_t to_port;	/* port on the side of the neighbor (needed for the LFT) */
Packit Service 54dbc3
	uint64_t weight;	/* link weight */
Packit Service 54dbc3
	struct link *next;
Packit Service 54dbc3
} link_t;
Packit Service 54dbc3
Packit Service 54dbc3
typedef struct vertex {
Packit Service 54dbc3
	/* informations of the fabric */
Packit Service 54dbc3
	uint64_t guid;
Packit Service 54dbc3
	uint16_t lid;		/* for lft filling */
Packit Service 54dbc3
	uint32_t num_hca;	/* numbers of Hca/LIDs on the switch, for weight calculation */
Packit Service 54dbc3
	link_t *links;
Packit Service 54dbc3
	uint8_t hops;
Packit Service 54dbc3
	/* for dijkstra routing */
Packit Service 54dbc3
	link_t *used_link;	/* link between the vertex discovered before and this vertex */
Packit Service 54dbc3
	uint64_t distance;	/* distance from source to this vertex */
Packit Service 54dbc3
	uint8_t state;
Packit Service 54dbc3
	/* for the d-ary heap */
Packit Service 54dbc3
	size_t heap_index;
Packit Service 54dbc3
	/* for LFT writing and debug */
Packit Service 54dbc3
	osm_switch_t *sw;	/* selfpointer */
Packit Service 54dbc3
	boolean_t dropped;	/* indicate dropped switches (w/ ucast cache) */
Packit Service 54dbc3
} vertex_t;
Packit Service 54dbc3
Packit Service 54dbc3
typedef struct vltable {
Packit Service 54dbc3
	uint64_t num_lids;	/* size of the lids array */
Packit Service 54dbc3
	uint16_t *lids;		/* sorted array of all lids in the subnet */
Packit Service 54dbc3
	uint8_t *vls;		/* matrix form assignment lid X lid -> virtual lane */
Packit Service 54dbc3
} vltable_t;
Packit Service 54dbc3
Packit Service 54dbc3
typedef struct cdg_link {
Packit Service 54dbc3
	struct cdg_node *node;
Packit Service 54dbc3
	uint32_t num_pairs;	/* number of src->dest pairs incremented in path adding step */
Packit Service 54dbc3
	uint32_t max_len;	/* length of the srcdest array */
Packit Service 54dbc3
	uint32_t removed;	/* number of pairs removed in path deletion step */
Packit Service 54dbc3
	uint32_t *srcdest_pairs;
Packit Service 54dbc3
	struct cdg_link *next;
Packit Service 54dbc3
} cdg_link_t;
Packit Service 54dbc3
Packit Service 54dbc3
/* struct for a node of a binary tree with additional parent pointer */
Packit Service 54dbc3
typedef struct cdg_node {
Packit Service 54dbc3
	uint64_t channelID;	/* unique key consist of src lid + port + dest lid + port */
Packit Service 54dbc3
	cdg_link_t *linklist;	/* edges to adjazent nodes */
Packit Service 54dbc3
	uint8_t status;		/* node status in cycle search to avoid recursive function */
Packit Service 54dbc3
	uint8_t visited;	/* needed to traverse the binary tree */
Packit Service 54dbc3
	struct cdg_node *pre;	/* to save the path in cycle detection algorithm */
Packit Service 54dbc3
	struct cdg_node *left, *right, *parent;
Packit Service 54dbc3
} cdg_node_t;
Packit Service 54dbc3
Packit Service 54dbc3
typedef struct dfsssp_context {
Packit Service 54dbc3
	osm_routing_engine_type_t routing_type;
Packit Service 54dbc3
	osm_ucast_mgr_t *p_mgr;
Packit Service 54dbc3
	vertex_t *adj_list;
Packit Service 54dbc3
	uint32_t adj_list_size;
Packit Service 54dbc3
	vltable_t *srcdest2vl_table;
Packit Service 54dbc3
	uint8_t *vl_split_count;
Packit Service 54dbc3
} dfsssp_context_t;
Packit Service 54dbc3
Packit Service 54dbc3
/**************** set initial values for structs **********************
Packit Service 54dbc3
 **********************************************************************/
Packit Service 54dbc3
static inline void set_default_link(link_t * link)
Packit Service 54dbc3
{
Packit Service 54dbc3
	link->guid = 0;
Packit Service 54dbc3
	link->from = 0;
Packit Service 54dbc3
	link->from_port = 0;
Packit Service 54dbc3
	link->to = 0;
Packit Service 54dbc3
	link->to_port = 0;
Packit Service 54dbc3
	link->weight = 0;
Packit Service 54dbc3
	link->next = NULL;
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
static inline void set_default_vertex(vertex_t * vertex)
Packit Service 54dbc3
{
Packit Service 54dbc3
	vertex->guid = 0;
Packit Service 54dbc3
	vertex->lid = 0;
Packit Service 54dbc3
	vertex->num_hca = 0;
Packit Service 54dbc3
	vertex->links = NULL;
Packit Service 54dbc3
	vertex->hops = 0;
Packit Service 54dbc3
	vertex->used_link = NULL;
Packit Service 54dbc3
	vertex->distance = 0;
Packit Service 54dbc3
	vertex->state = UNDISCOVERED;
Packit Service 54dbc3
	vertex->heap_index = 0;
Packit Service 54dbc3
	vertex->sw = NULL;
Packit Service 54dbc3
	vertex->dropped = FALSE;
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
static inline void set_default_cdg_node(cdg_node_t * node)
Packit Service 54dbc3
{
Packit Service 54dbc3
	node->channelID = 0;
Packit Service 54dbc3
	node->linklist = NULL;
Packit Service 54dbc3
	node->status = UNKNOWN;
Packit Service 54dbc3
	node->visited = 0;
Packit Service 54dbc3
	node->pre = NULL;
Packit Service 54dbc3
	node->left = NULL;
Packit Service 54dbc3
	node->right = NULL;
Packit Service 54dbc3
	node->parent = NULL;
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
/**********************************************************************
Packit Service 54dbc3
 **********************************************************************/
Packit Service 54dbc3
Packit Service 54dbc3
/************ helper functions to save src/dest X vl combination ******
Packit Service 54dbc3
 **********************************************************************/
Packit Service 54dbc3
/* compare function of two lids for stdlib qsort */
Packit Service 54dbc3
static int cmp_lids(const void *l1, const void *l2)
Packit Service 54dbc3
{
Packit Service 54dbc3
	ib_net16_t lid1 = *((ib_net16_t *) l1), lid2 = *((ib_net16_t *) l2);
Packit Service 54dbc3
Packit Service 54dbc3
	if (lid1 < lid2)
Packit Service 54dbc3
		return -1;
Packit Service 54dbc3
	else if (lid1 > lid2)
Packit Service 54dbc3
		return 1;
Packit Service 54dbc3
	else
Packit Service 54dbc3
		return 0;
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
/* use stdlib to sort the lid array */
Packit Service 54dbc3
static inline void vltable_sort_lids(vltable_t * vltable)
Packit Service 54dbc3
{
Packit Service 54dbc3
	qsort(vltable->lids, vltable->num_lids, sizeof(ib_net16_t), cmp_lids);
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
/* use stdlib to get index of key in lid array;
Packit Service 54dbc3
   return -1 if lid isn't found in lids array
Packit Service 54dbc3
*/
Packit Service 54dbc3
static inline int64_t vltable_get_lidindex(ib_net16_t * key, vltable_t * vltable)
Packit Service 54dbc3
{
Packit Service 54dbc3
	ib_net16_t *found_lid = NULL;
Packit Service 54dbc3
Packit Service 54dbc3
	found_lid =
Packit Service 54dbc3
	    (ib_net16_t *) bsearch(key, vltable->lids, vltable->num_lids,
Packit Service 54dbc3
				   sizeof(ib_net16_t), cmp_lids);
Packit Service 54dbc3
	if (found_lid)
Packit Service 54dbc3
		return found_lid - vltable->lids;
Packit Service 54dbc3
	else
Packit Service 54dbc3
		return -1;
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
/* get virtual lane from src lid X dest lid combination;
Packit Service 54dbc3
   return -1 for invalid lids
Packit Service 54dbc3
*/
Packit Service 54dbc3
static int32_t vltable_get_vl(vltable_t * vltable, ib_net16_t slid, ib_net16_t dlid)
Packit Service 54dbc3
{
Packit Service 54dbc3
	int64_t ind1 = vltable_get_lidindex(&slid, vltable);
Packit Service 54dbc3
	int64_t ind2 = vltable_get_lidindex(&dlid, vltable);
Packit Service 54dbc3
Packit Service 54dbc3
	if (ind1 > -1 && ind2 > -1)
Packit Service 54dbc3
		return (int32_t) (vltable->
Packit Service 54dbc3
				  vls[ind1 + ind2 * vltable->num_lids]);
Packit Service 54dbc3
	else
Packit Service 54dbc3
		return -1;
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
/* set a virtual lane in the matrix */
Packit Service 54dbc3
static inline void vltable_insert(vltable_t * vltable, ib_net16_t slid,
Packit Service 54dbc3
				  ib_net16_t dlid, uint8_t vl)
Packit Service 54dbc3
{
Packit Service 54dbc3
	int64_t ind1 = vltable_get_lidindex(&slid, vltable);
Packit Service 54dbc3
	int64_t ind2 = vltable_get_lidindex(&dlid, vltable);
Packit Service 54dbc3
Packit Service 54dbc3
	if (ind1 > -1 && ind2 > -1)
Packit Service 54dbc3
		vltable->vls[ind1 + ind2 * vltable->num_lids] = vl;
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
/* change a number of lanes from lane xy to lane yz */
Packit Service 54dbc3
static void vltable_change_vl(vltable_t * vltable, uint8_t from, uint8_t to,
Packit Service 54dbc3
			      uint64_t count)
Packit Service 54dbc3
{
Packit Service 54dbc3
	uint64_t set = 0, stop = 0;
Packit Service 54dbc3
	uint64_t ind1 = 0, ind2 = 0;
Packit Service 54dbc3
Packit Service 54dbc3
	for (ind1 = 0; ind1 < vltable->num_lids; ind1++) {
Packit Service 54dbc3
		for (ind2 = 0; ind2 < vltable->num_lids; ind2++) {
Packit Service 54dbc3
			if (set == count) {
Packit Service 54dbc3
				stop = 1;
Packit Service 54dbc3
				break;
Packit Service 54dbc3
			}
Packit Service 54dbc3
			if (ind1 != ind2) {
Packit Service 54dbc3
				if (vltable->
Packit Service 54dbc3
				    vls[ind1 + ind2 * vltable->num_lids] ==
Packit Service 54dbc3
				    from) {
Packit Service 54dbc3
					vltable->vls[ind1 +
Packit Service 54dbc3
						     ind2 * vltable->num_lids] =
Packit Service 54dbc3
					    to;
Packit Service 54dbc3
					set++;
Packit Service 54dbc3
				}
Packit Service 54dbc3
			}
Packit Service 54dbc3
		}
Packit Service 54dbc3
		if (stop)
Packit Service 54dbc3
			break;
Packit Service 54dbc3
	}
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
static void vltable_print(osm_ucast_mgr_t * p_mgr, vltable_t * vltable)
Packit Service 54dbc3
{
Packit Service 54dbc3
	uint64_t ind1 = 0, ind2 = 0;
Packit Service 54dbc3
Packit Service 54dbc3
	for (ind1 = 0; ind1 < vltable->num_lids; ind1++) {
Packit Service 54dbc3
		for (ind2 = 0; ind2 < vltable->num_lids; ind2++) {
Packit Service 54dbc3
			if (ind1 != ind2) {
Packit Service 54dbc3
				OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
Packit Service 54dbc3
					"   route from src_lid=%" PRIu16
Packit Service 54dbc3
					" to dest_lid=%" PRIu16 " on vl=%" PRIu8
Packit Service 54dbc3
					"\n", cl_ntoh16(vltable->lids[ind1]),
Packit Service 54dbc3
					cl_ntoh16(vltable->lids[ind2]),
Packit Service 54dbc3
					vltable->vls[ind1 +
Packit Service 54dbc3
						     ind2 * vltable->num_lids]);
Packit Service 54dbc3
			}
Packit Service 54dbc3
		}
Packit Service 54dbc3
	}
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
static void vltable_dealloc(vltable_t ** vltable)
Packit Service 54dbc3
{
Packit Service 54dbc3
	if (*vltable) {
Packit Service 54dbc3
		if ((*vltable)->lids)
Packit Service 54dbc3
			free((*vltable)->lids);
Packit Service 54dbc3
		if ((*vltable)->vls)
Packit Service 54dbc3
			free((*vltable)->vls);
Packit Service 54dbc3
		free(*vltable);
Packit Service 54dbc3
		*vltable = NULL;
Packit Service 54dbc3
	}
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
static int vltable_alloc(vltable_t ** vltable, uint64_t size)
Packit Service 54dbc3
{
Packit Service 54dbc3
	/* allocate VL table and indexing array */
Packit Service 54dbc3
	*vltable = (vltable_t *) malloc(sizeof(vltable_t));
Packit Service 54dbc3
	if (!(*vltable))
Packit Service 54dbc3
		goto ERROR;
Packit Service 54dbc3
	(*vltable)->num_lids = size;
Packit Service 54dbc3
	(*vltable)->lids = (ib_net16_t *) malloc(size * sizeof(ib_net16_t));
Packit Service 54dbc3
	if (!((*vltable)->lids))
Packit Service 54dbc3
		goto ERROR;
Packit Service 54dbc3
	(*vltable)->vls = (uint8_t *) malloc(size * size * sizeof(uint8_t));
Packit Service 54dbc3
	if (!((*vltable)->vls))
Packit Service 54dbc3
		goto ERROR;
Packit Service 54dbc3
	memset((*vltable)->vls, OSM_DEFAULT_SL, size * size);
Packit Service 54dbc3
Packit Service 54dbc3
	return 0;
Packit Service 54dbc3
Packit Service 54dbc3
ERROR:
Packit Service 54dbc3
	vltable_dealloc(vltable);
Packit Service 54dbc3
Packit Service 54dbc3
	return 1;
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
/**********************************************************************
Packit Service 54dbc3
 **********************************************************************/
Packit Service 54dbc3
Packit Service 54dbc3
/************ helper functions to save/manage the channel dep. graph **
Packit Service 54dbc3
 **********************************************************************/
Packit Service 54dbc3
/* update the srcdest array;
Packit Service 54dbc3
   realloc array (double the size) if size is not large enough
Packit Service 54dbc3
*/
Packit Service 54dbc3
static void set_next_srcdest_pair(cdg_link_t * link, uint32_t srcdest)
Packit Service 54dbc3
{
Packit Service 54dbc3
	uint32_t new_size = 0, start_size = 2;
Packit Service 54dbc3
	uint32_t *tmp = NULL, *tmp2 = NULL;
Packit Service 54dbc3
Packit Service 54dbc3
	if (link->num_pairs == 0) {
Packit Service 54dbc3
		link->srcdest_pairs =
Packit Service 54dbc3
		    (uint32_t *) malloc(start_size * sizeof(uint32_t));
Packit Service 54dbc3
		link->srcdest_pairs[link->num_pairs] = srcdest;
Packit Service 54dbc3
		link->max_len = start_size;
Packit Service 54dbc3
		link->removed = 0;
Packit Service 54dbc3
	} else if (link->num_pairs == link->max_len) {
Packit Service 54dbc3
		new_size = link->max_len << 1;
Packit Service 54dbc3
		tmp = (uint32_t *) malloc(new_size * sizeof(uint32_t));
Packit Service 54dbc3
		tmp =
Packit Service 54dbc3
		    memcpy(tmp, link->srcdest_pairs,
Packit Service 54dbc3
			   link->max_len * sizeof(uint32_t));
Packit Service 54dbc3
		tmp2 = link->srcdest_pairs;
Packit Service 54dbc3
		link->srcdest_pairs = tmp;
Packit Service 54dbc3
		link->srcdest_pairs[link->num_pairs] = srcdest;
Packit Service 54dbc3
		free(tmp2);
Packit Service 54dbc3
		link->max_len = new_size;
Packit Service 54dbc3
	} else {
Packit Service 54dbc3
		link->srcdest_pairs[link->num_pairs] = srcdest;
Packit Service 54dbc3
	}
Packit Service 54dbc3
	link->num_pairs++;
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
static inline uint32_t get_next_srcdest_pair(cdg_link_t * link, uint32_t index)
Packit Service 54dbc3
{
Packit Service 54dbc3
	return link->srcdest_pairs[index];
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
/* traverse binary tree to find a node */
Packit Service 54dbc3
static cdg_node_t *cdg_search(cdg_node_t * root, uint64_t channelID)
Packit Service 54dbc3
{
Packit Service 54dbc3
	while (root) {
Packit Service 54dbc3
		if (channelID < root->channelID)
Packit Service 54dbc3
			root = root->left;
Packit Service 54dbc3
		else if (channelID > root->channelID)
Packit Service 54dbc3
			root = root->right;
Packit Service 54dbc3
		else if (channelID == root->channelID)
Packit Service 54dbc3
			return root;
Packit Service 54dbc3
	}
Packit Service 54dbc3
	return NULL;
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
/* insert new node into the binary tree */
Packit Service 54dbc3
static void cdg_insert(cdg_node_t ** root, cdg_node_t * new_node)
Packit Service 54dbc3
{
Packit Service 54dbc3
	cdg_node_t *current = *root;
Packit Service 54dbc3
Packit Service 54dbc3
	if (!current) {
Packit Service 54dbc3
		current = new_node;
Packit Service 54dbc3
		*root = current;
Packit Service 54dbc3
		return;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	while (current) {
Packit Service 54dbc3
		if (new_node->channelID < current->channelID) {
Packit Service 54dbc3
			if (current->left) {
Packit Service 54dbc3
				current = current->left;
Packit Service 54dbc3
			} else {
Packit Service 54dbc3
				current->left = new_node;
Packit Service 54dbc3
				new_node->parent = current;
Packit Service 54dbc3
				break;
Packit Service 54dbc3
			}
Packit Service 54dbc3
		} else if (new_node->channelID > current->channelID) {
Packit Service 54dbc3
			if (current->right) {
Packit Service 54dbc3
				current = current->right;
Packit Service 54dbc3
			} else {
Packit Service 54dbc3
				current->right = new_node;
Packit Service 54dbc3
				new_node->parent = current;
Packit Service 54dbc3
				break;
Packit Service 54dbc3
			}
Packit Service 54dbc3
		} else if (new_node->channelID == current->channelID) {
Packit Service 54dbc3
			/* not really possible, maybe programming error */
Packit Service 54dbc3
			break;
Packit Service 54dbc3
		}
Packit Service 54dbc3
	}
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
static void cdg_node_dealloc(cdg_node_t * node)
Packit Service 54dbc3
{
Packit Service 54dbc3
	cdg_link_t *link = node->linklist, *tmp = NULL;
Packit Service 54dbc3
Packit Service 54dbc3
	/* dealloc linklist */
Packit Service 54dbc3
	while (link) {
Packit Service 54dbc3
		tmp = link;
Packit Service 54dbc3
		link = link->next;
Packit Service 54dbc3
Packit Service 54dbc3
		if (tmp->num_pairs)
Packit Service 54dbc3
			free(tmp->srcdest_pairs);
Packit Service 54dbc3
		free(tmp);
Packit Service 54dbc3
	}
Packit Service 54dbc3
	/* dealloc node */
Packit Service 54dbc3
	free(node);
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
static void cdg_dealloc(cdg_node_t ** root)
Packit Service 54dbc3
{
Packit Service 54dbc3
	cdg_node_t *current = *root;
Packit Service 54dbc3
Packit Service 54dbc3
	while (current) {
Packit Service 54dbc3
		if (current->left) {
Packit Service 54dbc3
			current = current->left;
Packit Service 54dbc3
		} else if (current->right) {
Packit Service 54dbc3
			current = current->right;
Packit Service 54dbc3
		} else {
Packit Service 54dbc3
			if (current->parent == NULL) {
Packit Service 54dbc3
				cdg_node_dealloc(current);
Packit Service 54dbc3
				*root = NULL;
Packit Service 54dbc3
				break;
Packit Service 54dbc3
			}
Packit Service 54dbc3
			if (current->parent->left == current) {
Packit Service 54dbc3
				current = current->parent;
Packit Service 54dbc3
				cdg_node_dealloc(current->left);
Packit Service 54dbc3
				current->left = NULL;
Packit Service 54dbc3
			} else if (current->parent->right == current) {
Packit Service 54dbc3
				current = current->parent;
Packit Service 54dbc3
				cdg_node_dealloc(current->right);
Packit Service 54dbc3
				current->right = NULL;
Packit Service 54dbc3
			}
Packit Service 54dbc3
		}
Packit Service 54dbc3
	}
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
/* search for a edge in the cdg which should be removed to break a cycle */
Packit Service 54dbc3
static cdg_link_t *get_weakest_link_in_cycle(cdg_node_t * cycle)
Packit Service 54dbc3
{
Packit Service 54dbc3
	cdg_node_t *current = cycle, *node_with_weakest_link = NULL;
Packit Service 54dbc3
	cdg_link_t *link = NULL, *weakest_link = NULL;
Packit Service 54dbc3
Packit Service 54dbc3
	link = current->linklist;
Packit Service 54dbc3
	while (link) {
Packit Service 54dbc3
		if (link->node->status == GRAY) {
Packit Service 54dbc3
			weakest_link = link;
Packit Service 54dbc3
			node_with_weakest_link = current;
Packit Service 54dbc3
			current = link->node;
Packit Service 54dbc3
			break;
Packit Service 54dbc3
		}
Packit Service 54dbc3
		link = link->next;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	while (1) {
Packit Service 54dbc3
		current->status = UNKNOWN;
Packit Service 54dbc3
		link = current->linklist;
Packit Service 54dbc3
		while (link) {
Packit Service 54dbc3
			if (link->node->status == GRAY) {
Packit Service 54dbc3
				if ((link->num_pairs - link->removed) <
Packit Service 54dbc3
				    (weakest_link->num_pairs -
Packit Service 54dbc3
				     weakest_link->removed)) {
Packit Service 54dbc3
					weakest_link = link;
Packit Service 54dbc3
					node_with_weakest_link = current;
Packit Service 54dbc3
				}
Packit Service 54dbc3
				current = link->node;
Packit Service 54dbc3
				break;
Packit Service 54dbc3
			}
Packit Service 54dbc3
			link = link->next;
Packit Service 54dbc3
		}
Packit Service 54dbc3
		/* if complete cycle is traversed */
Packit Service 54dbc3
		if (current == cycle) {
Packit Service 54dbc3
			current->status = UNKNOWN;
Packit Service 54dbc3
			break;
Packit Service 54dbc3
		}
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	if (node_with_weakest_link->linklist == weakest_link) {
Packit Service 54dbc3
		node_with_weakest_link->linklist = weakest_link->next;
Packit Service 54dbc3
	} else {
Packit Service 54dbc3
		link = node_with_weakest_link->linklist;
Packit Service 54dbc3
		while (link) {
Packit Service 54dbc3
			if (link->next == weakest_link) {
Packit Service 54dbc3
				link->next = weakest_link->next;
Packit Service 54dbc3
				break;
Packit Service 54dbc3
			}
Packit Service 54dbc3
			link = link->next;
Packit Service 54dbc3
		}
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	return weakest_link;
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
/* search for nodes in the cdg not yet reached in the cycle search process;
Packit Service 54dbc3
   (some nodes are unreachable, e.g. a node is a source or the cdg has not connected parts)
Packit Service 54dbc3
*/
Packit Service 54dbc3
static cdg_node_t *get_next_cdg_node(cdg_node_t * root)
Packit Service 54dbc3
{
Packit Service 54dbc3
	cdg_node_t *current = root, *res = NULL;
Packit Service 54dbc3
Packit Service 54dbc3
	while (current) {
Packit Service 54dbc3
		current->visited = 1;
Packit Service 54dbc3
		if (current->status == UNKNOWN) {
Packit Service 54dbc3
			res = current;
Packit Service 54dbc3
			break;
Packit Service 54dbc3
		}
Packit Service 54dbc3
		if (current->left && !current->left->visited) {
Packit Service 54dbc3
			current = current->left;
Packit Service 54dbc3
		} else if (current->right && !current->right->visited) {
Packit Service 54dbc3
			current = current->right;
Packit Service 54dbc3
		} else {
Packit Service 54dbc3
			if (current->left)
Packit Service 54dbc3
				current->left->visited = 0;
Packit Service 54dbc3
			if (current->right)
Packit Service 54dbc3
				current->right->visited = 0;
Packit Service 54dbc3
			if (current->parent == NULL)
Packit Service 54dbc3
				break;
Packit Service 54dbc3
			else
Packit Service 54dbc3
				current = current->parent;
Packit Service 54dbc3
		}
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	/* Clean up */
Packit Service 54dbc3
	while (current) {
Packit Service 54dbc3
		current->visited = 0;
Packit Service 54dbc3
		if (current->left)
Packit Service 54dbc3
			current->left->visited = 0;
Packit Service 54dbc3
		if (current->right)
Packit Service 54dbc3
			current->right->visited = 0;
Packit Service 54dbc3
		current = current->parent;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	return res;
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
/* make a DFS on the cdg to check for a cycle */
Packit Service 54dbc3
static cdg_node_t *search_cycle_in_channel_dep_graph(cdg_node_t * cdg,
Packit Service 54dbc3
						     cdg_node_t * start_node)
Packit Service 54dbc3
{
Packit Service 54dbc3
	cdg_node_t *cycle = NULL;
Packit Service 54dbc3
	cdg_node_t *current = start_node, *next_node = NULL, *tmp = NULL;
Packit Service 54dbc3
	cdg_link_t *link = NULL;
Packit Service 54dbc3
Packit Service 54dbc3
	while (current) {
Packit Service 54dbc3
		current->status = GRAY;
Packit Service 54dbc3
		link = current->linklist;
Packit Service 54dbc3
		next_node = NULL;
Packit Service 54dbc3
		while (link) {
Packit Service 54dbc3
			if (link->node->status == UNKNOWN) {
Packit Service 54dbc3
				next_node = link->node;
Packit Service 54dbc3
				break;
Packit Service 54dbc3
			}
Packit Service 54dbc3
			if (link->node->status == GRAY) {
Packit Service 54dbc3
				cycle = link->node;
Packit Service 54dbc3
				goto Exit;
Packit Service 54dbc3
			}
Packit Service 54dbc3
			link = link->next;
Packit Service 54dbc3
		}
Packit Service 54dbc3
		if (next_node) {
Packit Service 54dbc3
			next_node->pre = current;
Packit Service 54dbc3
			current = next_node;
Packit Service 54dbc3
		} else {
Packit Service 54dbc3
			/* found a sink in the graph, go to last node */
Packit Service 54dbc3
			current->status = BLACK;
Packit Service 54dbc3
Packit Service 54dbc3
			/* srcdest_pairs of this node aren't relevant, free the allocated memory */
Packit Service 54dbc3
			link = current->linklist;
Packit Service 54dbc3
			while (link) {
Packit Service 54dbc3
				if (link->num_pairs)
Packit Service 54dbc3
					free(link->srcdest_pairs);
Packit Service 54dbc3
				link->srcdest_pairs = NULL;
Packit Service 54dbc3
				link->num_pairs = 0;
Packit Service 54dbc3
				link->removed = 0;
Packit Service 54dbc3
				link = link->next;
Packit Service 54dbc3
			}
Packit Service 54dbc3
Packit Service 54dbc3
			if (current->pre) {
Packit Service 54dbc3
				tmp = current;
Packit Service 54dbc3
				current = current->pre;
Packit Service 54dbc3
				tmp->pre = NULL;
Packit Service 54dbc3
			} else {
Packit Service 54dbc3
				/* search for other subgraphs in cdg */
Packit Service 54dbc3
				current = get_next_cdg_node(cdg);
Packit Service 54dbc3
				if (!current)
Packit Service 54dbc3
					break;	/* all relevant nodes traversed, no more cycles found */
Packit Service 54dbc3
			}
Packit Service 54dbc3
		}
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
Exit:
Packit Service 54dbc3
	return cycle;
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
/* calculate the path from source to destination port;
Packit Service 54dbc3
   new channels are added directly to the cdg
Packit Service 54dbc3
*/
Packit Service 54dbc3
static int update_channel_dep_graph(cdg_node_t ** cdg_root,
Packit Service 54dbc3
				    osm_port_t * src_port, uint16_t slid,
Packit Service 54dbc3
				    osm_port_t * dest_port, uint16_t dlid)
Packit Service 54dbc3
{
Packit Service 54dbc3
	osm_node_t *local_node = NULL, *remote_node = NULL;
Packit Service 54dbc3
	uint16_t local_lid = 0, remote_lid = 0;
Packit Service 54dbc3
	uint32_t srcdest = 0;
Packit Service 54dbc3
	uint8_t local_port = 0, remote_port = 0;
Packit Service 54dbc3
	uint64_t channelID = 0;
Packit Service 54dbc3
Packit Service 54dbc3
	cdg_node_t *channel_head = NULL, *channel = NULL, *last_channel = NULL;
Packit Service 54dbc3
	cdg_link_t *linklist = NULL;
Packit Service 54dbc3
Packit Service 54dbc3
	/* set the identifier for the src/dest pair to save this on each edge of the cdg */
Packit Service 54dbc3
	srcdest = (((uint32_t) slid) << 16) + ((uint32_t) dlid);
Packit Service 54dbc3
Packit Service 54dbc3
	channel_head = (cdg_node_t *) malloc(sizeof(cdg_node_t));
Packit Service 54dbc3
	if (!channel_head)
Packit Service 54dbc3
		goto ERROR;
Packit Service 54dbc3
	set_default_cdg_node(channel_head);
Packit Service 54dbc3
	last_channel = channel_head;
Packit Service 54dbc3
Packit Service 54dbc3
	/* if src is a Hca, then the channel from Hca to switch would be a source in the graph
Packit Service 54dbc3
	   sources can't be part of a cycle -> skip this channel
Packit Service 54dbc3
	 */
Packit Service 54dbc3
	remote_node =
Packit Service 54dbc3
	    osm_node_get_remote_node(src_port->p_node,
Packit Service 54dbc3
				     src_port->p_physp->port_num, &remote_port);
Packit Service 54dbc3
Packit Service 54dbc3
	while (remote_node && remote_node->sw) {
Packit Service 54dbc3
		local_node = remote_node;
Packit Service 54dbc3
		local_port = local_node->sw->new_lft[dlid];
Packit Service 54dbc3
		/* sanity check: local_port must be set or routing is broken */
Packit Service 54dbc3
		if (local_port == OSM_NO_PATH)
Packit Service 54dbc3
			goto ERROR;
Packit Service 54dbc3
		local_lid = cl_ntoh16(osm_node_get_base_lid(local_node, 0));
Packit Service 54dbc3
		/* each port belonging to a switch has lmc==0 -> get_base_lid is fine
Packit Service 54dbc3
		   (local/remote port in this function are always part of a switch)
Packit Service 54dbc3
		 */
Packit Service 54dbc3
Packit Service 54dbc3
		remote_node =
Packit Service 54dbc3
		    osm_node_get_remote_node(local_node, local_port,
Packit Service 54dbc3
					     &remote_port);
Packit Service 54dbc3
		/* if remote_node is a Hca, then the last channel from switch to Hca would be a sink in the cdg -> skip */
Packit Service 54dbc3
		if (!remote_node || !remote_node->sw)
Packit Service 54dbc3
			break;
Packit Service 54dbc3
		remote_lid = cl_ntoh16(osm_node_get_base_lid(remote_node, 0));
Packit Service 54dbc3
Packit Service 54dbc3
		channelID =
Packit Service 54dbc3
		    (((uint64_t) local_lid) << 48) +
Packit Service 54dbc3
		    (((uint64_t) local_port) << 32) +
Packit Service 54dbc3
		    (((uint64_t) remote_lid) << 16) + ((uint64_t) remote_port);
Packit Service 54dbc3
		channel = cdg_search(*cdg_root, channelID);
Packit Service 54dbc3
		if (channel) {
Packit Service 54dbc3
			/* check whether last channel has connection to this channel, i.e. subpath already exists in cdg */
Packit Service 54dbc3
			linklist = last_channel->linklist;
Packit Service 54dbc3
			while (linklist && linklist->node != channel
Packit Service 54dbc3
			       && linklist->next)
Packit Service 54dbc3
				linklist = linklist->next;
Packit Service 54dbc3
			/* if there is no connection, add one */
Packit Service 54dbc3
			if (linklist) {
Packit Service 54dbc3
				if (linklist->node == channel) {
Packit Service 54dbc3
					set_next_srcdest_pair(linklist,
Packit Service 54dbc3
							      srcdest);
Packit Service 54dbc3
				} else {
Packit Service 54dbc3
					linklist->next =
Packit Service 54dbc3
					    (cdg_link_t *)
Packit Service 54dbc3
					    malloc(sizeof(cdg_link_t));
Packit Service 54dbc3
					if (!linklist->next)
Packit Service 54dbc3
						goto ERROR;
Packit Service 54dbc3
					linklist = linklist->next;
Packit Service 54dbc3
					linklist->node = channel;
Packit Service 54dbc3
					linklist->num_pairs = 0;
Packit Service 54dbc3
					linklist->srcdest_pairs = NULL;
Packit Service 54dbc3
					set_next_srcdest_pair(linklist,
Packit Service 54dbc3
							      srcdest);
Packit Service 54dbc3
					linklist->next = NULL;
Packit Service 54dbc3
				}
Packit Service 54dbc3
			} else {
Packit Service 54dbc3
				/* either this is the first channel of the path, or the last channel was a new channel, or last channel was a sink */
Packit Service 54dbc3
				last_channel->linklist =
Packit Service 54dbc3
				    (cdg_link_t *) malloc(sizeof(cdg_link_t));
Packit Service 54dbc3
				if (!last_channel->linklist)
Packit Service 54dbc3
					goto ERROR;
Packit Service 54dbc3
				last_channel->linklist->node = channel;
Packit Service 54dbc3
				last_channel->linklist->num_pairs = 0;
Packit Service 54dbc3
				last_channel->linklist->srcdest_pairs = NULL;
Packit Service 54dbc3
				set_next_srcdest_pair(last_channel->linklist,
Packit Service 54dbc3
						      srcdest);
Packit Service 54dbc3
				last_channel->linklist->next = NULL;
Packit Service 54dbc3
			}
Packit Service 54dbc3
		} else {
Packit Service 54dbc3
			/* create new channel */
Packit Service 54dbc3
			channel = (cdg_node_t *) malloc(sizeof(cdg_node_t));
Packit Service 54dbc3
			if (!channel)
Packit Service 54dbc3
				goto ERROR;
Packit Service 54dbc3
			set_default_cdg_node(channel);
Packit Service 54dbc3
			channel->channelID = channelID;
Packit Service 54dbc3
			cdg_insert(cdg_root, channel);
Packit Service 54dbc3
Packit Service 54dbc3
			/* go to end of link list of last channel */
Packit Service 54dbc3
			linklist = last_channel->linklist;
Packit Service 54dbc3
			while (linklist && linklist->next)
Packit Service 54dbc3
				linklist = linklist->next;
Packit Service 54dbc3
			if (linklist) {
Packit Service 54dbc3
				/* update last link of an existing channel */
Packit Service 54dbc3
				linklist->next =
Packit Service 54dbc3
				    (cdg_link_t *) malloc(sizeof(cdg_link_t));
Packit Service 54dbc3
				if (!linklist->next)
Packit Service 54dbc3
					goto ERROR;
Packit Service 54dbc3
				linklist = linklist->next;
Packit Service 54dbc3
				linklist->node = channel;
Packit Service 54dbc3
				linklist->num_pairs = 0;
Packit Service 54dbc3
				linklist->srcdest_pairs = NULL;
Packit Service 54dbc3
				set_next_srcdest_pair(linklist, srcdest);
Packit Service 54dbc3
				linklist->next = NULL;
Packit Service 54dbc3
			} else {
Packit Service 54dbc3
				/* either this is the first channel of the path, or the last channel was a new channel, or last channel was a sink */
Packit Service 54dbc3
				last_channel->linklist =
Packit Service 54dbc3
				    (cdg_link_t *) malloc(sizeof(cdg_link_t));
Packit Service 54dbc3
				if (!last_channel->linklist)
Packit Service 54dbc3
					goto ERROR;
Packit Service 54dbc3
				last_channel->linklist->node = channel;
Packit Service 54dbc3
				last_channel->linklist->num_pairs = 0;
Packit Service 54dbc3
				last_channel->linklist->srcdest_pairs = NULL;
Packit Service 54dbc3
				set_next_srcdest_pair(last_channel->linklist,
Packit Service 54dbc3
						      srcdest);
Packit Service 54dbc3
				last_channel->linklist->next = NULL;
Packit Service 54dbc3
			}
Packit Service 54dbc3
		}
Packit Service 54dbc3
		last_channel = channel;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	if (channel_head->linklist) {
Packit Service 54dbc3
		if (channel_head->linklist->srcdest_pairs)
Packit Service 54dbc3
			free(channel_head->linklist->srcdest_pairs);
Packit Service 54dbc3
		free(channel_head->linklist);
Packit Service 54dbc3
	}
Packit Service 54dbc3
	free(channel_head);
Packit Service 54dbc3
Packit Service 54dbc3
	return 0;
Packit Service 54dbc3
Packit Service 54dbc3
ERROR:
Packit Service 54dbc3
	/* cleanup data and exit */
Packit Service 54dbc3
	if (channel_head) {
Packit Service 54dbc3
		if (channel_head->linklist)
Packit Service 54dbc3
			free(channel_head->linklist);
Packit Service 54dbc3
		free(channel_head);
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	return 1;
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
/* calculate the path from source to destination port;
Packit Service 54dbc3
   the links in the cdg representing this path are decremented to simulate the removal
Packit Service 54dbc3
*/
Packit Service 54dbc3
static int remove_path_from_cdg(cdg_node_t ** cdg_root, osm_port_t * src_port,
Packit Service 54dbc3
				uint16_t slid, osm_port_t * dest_port,
Packit Service 54dbc3
				uint16_t dlid)
Packit Service 54dbc3
{
Packit Service 54dbc3
	osm_node_t *local_node = NULL, *remote_node = NULL;
Packit Service 54dbc3
	uint16_t local_lid = 0, remote_lid = 0;
Packit Service 54dbc3
	uint8_t local_port = 0, remote_port = 0;
Packit Service 54dbc3
	uint64_t channelID = 0;
Packit Service 54dbc3
Packit Service 54dbc3
	cdg_node_t *channel_head = NULL, *channel = NULL, *last_channel = NULL;
Packit Service 54dbc3
	cdg_link_t *linklist = NULL;
Packit Service 54dbc3
Packit Service 54dbc3
	channel_head = (cdg_node_t *) malloc(sizeof(cdg_node_t));
Packit Service 54dbc3
	if (!channel_head)
Packit Service 54dbc3
		goto ERROR;
Packit Service 54dbc3
	set_default_cdg_node(channel_head);
Packit Service 54dbc3
	last_channel = channel_head;
Packit Service 54dbc3
Packit Service 54dbc3
	/* if src is a Hca, then the channel from Hca to switch would be a source in the graph
Packit Service 54dbc3
	   sources can't be part of a cycle -> skip this channel
Packit Service 54dbc3
	 */
Packit Service 54dbc3
	remote_node =
Packit Service 54dbc3
	    osm_node_get_remote_node(src_port->p_node,
Packit Service 54dbc3
				     src_port->p_physp->port_num, &remote_port);
Packit Service 54dbc3
Packit Service 54dbc3
	while (remote_node && remote_node->sw) {
Packit Service 54dbc3
		local_node = remote_node;
Packit Service 54dbc3
		local_port = local_node->sw->new_lft[dlid];
Packit Service 54dbc3
		/* sanity check: local_port must be set or routing is broken */
Packit Service 54dbc3
		if (local_port == OSM_NO_PATH)
Packit Service 54dbc3
			goto ERROR;
Packit Service 54dbc3
		local_lid = cl_ntoh16(osm_node_get_base_lid(local_node, 0));
Packit Service 54dbc3
Packit Service 54dbc3
		remote_node =
Packit Service 54dbc3
		    osm_node_get_remote_node(local_node, local_port,
Packit Service 54dbc3
					     &remote_port);
Packit Service 54dbc3
		/* if remote_node is a Hca, then the last channel from switch to Hca would be a sink in the cdg -> skip */
Packit Service 54dbc3
		if (!remote_node || !remote_node->sw)
Packit Service 54dbc3
			break;
Packit Service 54dbc3
		remote_lid = cl_ntoh16(osm_node_get_base_lid(remote_node, 0));
Packit Service 54dbc3
Packit Service 54dbc3
		channelID =
Packit Service 54dbc3
		    (((uint64_t) local_lid) << 48) +
Packit Service 54dbc3
		    (((uint64_t) local_port) << 32) +
Packit Service 54dbc3
		    (((uint64_t) remote_lid) << 16) + ((uint64_t) remote_port);
Packit Service 54dbc3
		channel = cdg_search(*cdg_root, channelID);
Packit Service 54dbc3
		if (channel) {
Packit Service 54dbc3
			/* check whether last channel has connection to this channel, i.e. subpath already exists in cdg */
Packit Service 54dbc3
			linklist = last_channel->linklist;
Packit Service 54dbc3
			while (linklist && linklist->node != channel
Packit Service 54dbc3
			       && linklist->next)
Packit Service 54dbc3
				linklist = linklist->next;
Packit Service 54dbc3
			/* remove the srcdest from the link */
Packit Service 54dbc3
			if (linklist) {
Packit Service 54dbc3
				if (linklist->node == channel) {
Packit Service 54dbc3
					linklist->removed++;
Packit Service 54dbc3
				} else {
Packit Service 54dbc3
					/* may happen if the link is missing (thru cycle detect algorithm) */
Packit Service 54dbc3
				}
Packit Service 54dbc3
			} else {
Packit Service 54dbc3
				/* may happen if the link is missing (thru cycle detect algorithm or last_channel==channel_head (dummy channel)) */
Packit Service 54dbc3
			}
Packit Service 54dbc3
		} else {
Packit Service 54dbc3
			/* must be an error, channels for the path are added before, so a missing channel would be a corrupt data structure */
Packit Service 54dbc3
			goto ERROR;
Packit Service 54dbc3
		}
Packit Service 54dbc3
		last_channel = channel;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	if (channel_head->linklist)
Packit Service 54dbc3
		free(channel_head->linklist);
Packit Service 54dbc3
	free(channel_head);
Packit Service 54dbc3
Packit Service 54dbc3
	return 0;
Packit Service 54dbc3
Packit Service 54dbc3
ERROR:
Packit Service 54dbc3
	/* cleanup data and exit */
Packit Service 54dbc3
	if (channel_head) {
Packit Service 54dbc3
		if (channel_head->linklist)
Packit Service 54dbc3
			free(channel_head->linklist);
Packit Service 54dbc3
		free(channel_head);
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	return 1;
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
/**********************************************************************
Packit Service 54dbc3
 **********************************************************************/
Packit Service 54dbc3
Packit Service 54dbc3
/************ helper functions to generate an ordered list of ports ***
Packit Service 54dbc3
 ************ (functions copied from osm_ucast_mgr.c and modified) ****
Packit Service 54dbc3
 **********************************************************************/
Packit Service 54dbc3
static void add_sw_endports_to_order_list(osm_switch_t * sw,
Packit Service 54dbc3
					  osm_ucast_mgr_t * m,
Packit Service 54dbc3
					  cl_qmap_t * guid_tbl,
Packit Service 54dbc3
					  boolean_t add_guids)
Packit Service 54dbc3
{
Packit Service 54dbc3
	osm_port_t *port;
Packit Service 54dbc3
	ib_net64_t port_guid;
Packit Service 54dbc3
	uint64_t sw_guid;
Packit Service 54dbc3
	osm_physp_t *p;
Packit Service 54dbc3
	int i;
Packit Service 54dbc3
	boolean_t found;
Packit Service 54dbc3
Packit Service 54dbc3
	for (i = 1; i < sw->num_ports; i++) {
Packit Service 54dbc3
		p = osm_node_get_physp_ptr(sw->p_node, i);
Packit Service 54dbc3
		if (p && p->p_remote_physp && !p->p_remote_physp->p_node->sw) {
Packit Service 54dbc3
			port_guid = p->p_remote_physp->port_guid;
Packit Service 54dbc3
			/* check if link is healthy, otherwise ignore CA */
Packit Service 54dbc3
			if (!osm_link_is_healthy(p)) {
Packit Service 54dbc3
				sw_guid =
Packit Service 54dbc3
				    cl_ntoh64(osm_node_get_node_guid
Packit Service 54dbc3
					      (sw->p_node));
Packit Service 54dbc3
				OSM_LOG(m->p_log, OSM_LOG_INFO,
Packit Service 54dbc3
					"WRN AD40: ignoring CA due to unhealthy"
Packit Service 54dbc3
					" link from switch 0x%016" PRIx64
Packit Service 54dbc3
					" port %" PRIu8 " to CA 0x%016" PRIx64
Packit Service 54dbc3
					"\n", sw_guid, i, cl_ntoh64(port_guid));
Packit Service 54dbc3
			}
Packit Service 54dbc3
			port = osm_get_port_by_guid(m->p_subn, port_guid);
Packit Service 54dbc3
			if (!port)
Packit Service 54dbc3
				continue;
Packit Service 54dbc3
			if (!cl_is_qmap_empty(guid_tbl)) {
Packit Service 54dbc3
				found = (cl_qmap_get(guid_tbl, port_guid)
Packit Service 54dbc3
					 != cl_qmap_end(guid_tbl));
Packit Service 54dbc3
				if ((add_guids && !found)
Packit Service 54dbc3
				    || (!add_guids && found))
Packit Service 54dbc3
					continue;
Packit Service 54dbc3
			}
Packit Service 54dbc3
			if (!cl_is_item_in_qlist(&m->port_order_list,
Packit Service 54dbc3
						 &port->list_item))
Packit Service 54dbc3
				cl_qlist_insert_tail(&m->port_order_list,
Packit Service 54dbc3
						     &port->list_item);
Packit Service 54dbc3
			else
Packit Service 54dbc3
				OSM_LOG(m->p_log, OSM_LOG_INFO,
Packit Service 54dbc3
					"WRN AD37: guid 0x%016" PRIx64
Packit Service 54dbc3
					" already in list\n", port_guid);
Packit Service 54dbc3
		}
Packit Service 54dbc3
	}
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
static void add_guid_to_order_list(uint64_t guid, osm_ucast_mgr_t * m)
Packit Service 54dbc3
{
Packit Service 54dbc3
	osm_port_t *port = osm_get_port_by_guid(m->p_subn, cl_hton64(guid));
Packit Service 54dbc3
Packit Service 54dbc3
	if (!port) {
Packit Service 54dbc3
		 OSM_LOG(m->p_log, OSM_LOG_DEBUG,
Packit Service 54dbc3
			 "port guid not found: 0x%016" PRIx64 "\n", guid);
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	if (!cl_is_item_in_qlist(&m->port_order_list, &port->list_item))
Packit Service 54dbc3
		cl_qlist_insert_tail(&m->port_order_list, &port->list_item);
Packit Service 54dbc3
	else
Packit Service 54dbc3
		OSM_LOG(m->p_log, OSM_LOG_INFO,
Packit Service 54dbc3
			"WRN AD38: guid 0x%016" PRIx64 " already in list\n",
Packit Service 54dbc3
			guid);
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
/* compare function of #Hca attached to a switch for stdlib qsort */
Packit Service 54dbc3
static int cmp_num_hca(const void * l1, const void * l2)
Packit Service 54dbc3
{
Packit Service 54dbc3
	vertex_t *sw1 = *((vertex_t **) l1);
Packit Service 54dbc3
	vertex_t *sw2 = *((vertex_t **) l2);
Packit Service 54dbc3
	uint32_t num_hca1 = 0, num_hca2 = 0;
Packit Service 54dbc3
Packit Service 54dbc3
	if (sw1)
Packit Service 54dbc3
		num_hca1 = sw1->num_hca;
Packit Service 54dbc3
	if (sw2)
Packit Service 54dbc3
		num_hca2 = sw2->num_hca;
Packit Service 54dbc3
Packit Service 54dbc3
	if (num_hca1 > num_hca2)
Packit Service 54dbc3
		return -1;
Packit Service 54dbc3
	else if (num_hca1 < num_hca2)
Packit Service 54dbc3
		return 1;
Packit Service 54dbc3
	else
Packit Service 54dbc3
		return 0;
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
/* use stdlib to sort the switch array depending on num_hca */
Packit Service 54dbc3
static inline void sw_list_sort_by_num_hca(vertex_t ** sw_list,
Packit Service 54dbc3
					   uint32_t sw_list_size)
Packit Service 54dbc3
{
Packit Service 54dbc3
	qsort(sw_list, sw_list_size, sizeof(vertex_t *), cmp_num_hca);
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
/**********************************************************************
Packit Service 54dbc3
 **********************************************************************/
Packit Service 54dbc3
Packit Service 54dbc3
/************ helper functions to manage a map of CN and I/O guids ****
Packit Service 54dbc3
 **********************************************************************/
Packit Service 54dbc3
static int add_guid_to_map(void * cxt, uint64_t guid, char * p)
Packit Service 54dbc3
{
Packit Service 54dbc3
	cl_qmap_t *map = cxt;
Packit Service 54dbc3
	name_map_item_t *item;
Packit Service 54dbc3
	name_map_item_t *inserted_item;
Packit Service 54dbc3
Packit Service 54dbc3
	item = malloc(sizeof(*item));
Packit Service 54dbc3
	if (!item)
Packit Service 54dbc3
		return -1;
Packit Service 54dbc3
Packit Service 54dbc3
	item->guid = cl_hton64(guid);	/* internal: network byte order */
Packit Service 54dbc3
	item->name = NULL;		/* name isn't needed */
Packit Service 54dbc3
	inserted_item = (name_map_item_t *) cl_qmap_insert(map, item->guid, &item->item);
Packit Service 54dbc3
	if (inserted_item != item)
Packit Service 54dbc3
                free(item);
Packit Service 54dbc3
Packit Service 54dbc3
	return 0;
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
static void destroy_guid_map(cl_qmap_t * guid_tbl)
Packit Service 54dbc3
{
Packit Service 54dbc3
	name_map_item_t *p_guid = NULL, *p_next_guid = NULL;
Packit Service 54dbc3
Packit Service 54dbc3
	p_next_guid = (name_map_item_t *) cl_qmap_head(guid_tbl);
Packit Service 54dbc3
	while (p_next_guid != (name_map_item_t *) cl_qmap_end(guid_tbl)) {
Packit Service 54dbc3
		p_guid = p_next_guid;
Packit Service 54dbc3
		p_next_guid = (name_map_item_t *) cl_qmap_next(&p_guid->item);
Packit Service 54dbc3
		free(p_guid);
Packit Service 54dbc3
	}
Packit Service 54dbc3
	cl_qmap_remove_all(guid_tbl);
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
/**********************************************************************
Packit Service 54dbc3
 **********************************************************************/
Packit Service 54dbc3
Packit Service 54dbc3
static void dfsssp_print_graph(osm_ucast_mgr_t * p_mgr, vertex_t * adj_list,
Packit Service 54dbc3
			       uint32_t size)
Packit Service 54dbc3
{
Packit Service 54dbc3
	uint32_t i = 0, c = 0;
Packit Service 54dbc3
	link_t *link = NULL;
Packit Service 54dbc3
Packit Service 54dbc3
	/* index 0 is for the source in dijkstra -> ignore */
Packit Service 54dbc3
	for (i = 1; i < size; i++) {
Packit Service 54dbc3
		OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, "adj_list[%" PRIu32 "]:\n",
Packit Service 54dbc3
			i);
Packit Service 54dbc3
		OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
Packit Service 54dbc3
			"   guid = 0x%" PRIx64 " lid = %" PRIu16 " (%s)\n",
Packit Service 54dbc3
			adj_list[i].guid, adj_list[i].lid,
Packit Service 54dbc3
			adj_list[i].sw->p_node->print_desc);
Packit Service 54dbc3
		OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
Packit Service 54dbc3
			"   num_hca = %" PRIu32 "\n", adj_list[i].num_hca);
Packit Service 54dbc3
Packit Service 54dbc3
		c = 1;
Packit Service 54dbc3
		for (link = adj_list[i].links; link != NULL;
Packit Service 54dbc3
		     link = link->next, c++) {
Packit Service 54dbc3
			OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
Packit Service 54dbc3
				"   link[%" PRIu32 "]:\n", c);
Packit Service 54dbc3
			OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
Packit Service 54dbc3
				"      to guid = 0x%" PRIx64 " (%s) port %"
Packit Service 54dbc3
				PRIu8 "\n", link->guid,
Packit Service 54dbc3
				adj_list[link->to].sw->p_node->print_desc,
Packit Service 54dbc3
				link->to_port);
Packit Service 54dbc3
			OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
Packit Service 54dbc3
				"      weight on this link = %" PRIu64 "\n",
Packit Service 54dbc3
				link->weight);
Packit Service 54dbc3
		}
Packit Service 54dbc3
	}
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
/* predefine, to use this in next function */
Packit Service 54dbc3
static void dfsssp_context_destroy(void *context);
Packit Service 54dbc3
static int dijkstra(osm_ucast_mgr_t * p_mgr, cl_heap_t * p_heap,
Packit Service 54dbc3
		    vertex_t * adj_list, uint32_t adj_list_size,
Packit Service 54dbc3
		    osm_port_t * port, uint16_t lid);
Packit Service 54dbc3
Packit Service 54dbc3
/* traverse subnet to gather information about the connected switches */
Packit Service 54dbc3
static int dfsssp_build_graph(void *context)
Packit Service 54dbc3
{
Packit Service 54dbc3
	dfsssp_context_t *dfsssp_ctx = (dfsssp_context_t *) context;
Packit Service 54dbc3
	osm_ucast_mgr_t *p_mgr = (osm_ucast_mgr_t *) (dfsssp_ctx->p_mgr);
Packit Service 54dbc3
	boolean_t has_fdr10 = (1 == p_mgr->p_subn->opt.fdr10) ? TRUE : FALSE;
Packit Service 54dbc3
	cl_qmap_t *port_tbl = &p_mgr->p_subn->port_guid_tbl;	/* 1 management port per switch + 1 or 2 ports for each Hca */
Packit Service 54dbc3
	osm_port_t *p_port = NULL;
Packit Service 54dbc3
	cl_qmap_t *sw_tbl = &p_mgr->p_subn->sw_guid_tbl;
Packit Service 54dbc3
	cl_map_item_t *item = NULL;
Packit Service 54dbc3
	osm_switch_t *sw = NULL;
Packit Service 54dbc3
	osm_node_t *remote_node = NULL;
Packit Service 54dbc3
	uint8_t port = 0, remote_port = 0;
Packit Service 54dbc3
	uint32_t i = 0, j = 0, err = 0, undiscov = 0, max_num_undiscov = 0;
Packit Service 54dbc3
	uint64_t total_num_hca = 0;
Packit Service 54dbc3
	vertex_t *adj_list = NULL;
Packit Service 54dbc3
	osm_physp_t *p_physp = NULL;
Packit Service 54dbc3
	link_t *link = NULL, *head = NULL;
Packit Service 54dbc3
	uint32_t num_sw = 0, adj_list_size = 0;
Packit Service 54dbc3
	uint8_t lmc = 0;
Packit Service 54dbc3
	uint16_t sm_lid = 0;
Packit Service 54dbc3
	cl_heap_t heap;
Packit Service 54dbc3
Packit Service 54dbc3
	OSM_LOG_ENTER(p_mgr->p_log);
Packit Service 54dbc3
	OSM_LOG(p_mgr->p_log, OSM_LOG_VERBOSE,
Packit Service 54dbc3
		"Building graph for df-/sssp routing\n");
Packit Service 54dbc3
Packit Service 54dbc3
	/* if this pointer isn't NULL, this is a reroute step;
Packit Service 54dbc3
	   old context will be destroyed (adj_list and srcdest2vl_table)
Packit Service 54dbc3
	 */
Packit Service 54dbc3
	if (dfsssp_ctx->adj_list)
Packit Service 54dbc3
		dfsssp_context_destroy(context);
Packit Service 54dbc3
Packit Service 54dbc3
	/* construct the generic heap opject to use it in dijkstra */
Packit Service 54dbc3
	cl_heap_construct(&heap;;
Packit Service 54dbc3
Packit Service 54dbc3
	num_sw = cl_qmap_count(sw_tbl);
Packit Service 54dbc3
	adj_list_size = num_sw + 1;
Packit Service 54dbc3
	/* allocate an adjazenz list (array), 0. element is reserved for the source (Hca) in the routing algo, others are switches */
Packit Service 54dbc3
	adj_list = (vertex_t *) malloc(adj_list_size * sizeof(vertex_t));
Packit Service 54dbc3
	if (!adj_list) {
Packit Service 54dbc3
		OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
Packit Service 54dbc3
			"ERR AD02: cannot allocate memory for adj_list\n");
Packit Service 54dbc3
		goto ERROR;
Packit Service 54dbc3
	}
Packit Service 54dbc3
	for (i = 0; i < adj_list_size; i++)
Packit Service 54dbc3
		set_default_vertex(&adj_list[i]);
Packit Service 54dbc3
Packit Service 54dbc3
	dfsssp_ctx->adj_list = adj_list;
Packit Service 54dbc3
	dfsssp_ctx->adj_list_size = adj_list_size;
Packit Service 54dbc3
Packit Service 54dbc3
	/* count the total number of Hca / LIDs (for lmc>0) in the fabric;
Packit Service 54dbc3
	   even include base/enhanced switch port 0; base SP0 will have lmc=0
Packit Service 54dbc3
	 */
Packit Service 54dbc3
	for (item = cl_qmap_head(port_tbl); item != cl_qmap_end(port_tbl);
Packit Service 54dbc3
	     item = cl_qmap_next(item)) {
Packit Service 54dbc3
		p_port = (osm_port_t *) item;
Packit Service 54dbc3
		if (osm_node_get_type(p_port->p_node) == IB_NODE_TYPE_CA ||
Packit Service 54dbc3
		    osm_node_get_type(p_port->p_node) == IB_NODE_TYPE_SWITCH) {
Packit Service 54dbc3
			lmc = osm_port_get_lmc(p_port);
Packit Service 54dbc3
			total_num_hca += (1 << lmc);
Packit Service 54dbc3
		}
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	i = 1;			/* fill adj_list -> start with index 1 */
Packit Service 54dbc3
	for (item = cl_qmap_head(sw_tbl); item != cl_qmap_end(sw_tbl);
Packit Service 54dbc3
	     item = cl_qmap_next(item), i++) {
Packit Service 54dbc3
		sw = (osm_switch_t *) item;
Packit Service 54dbc3
		OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
Packit Service 54dbc3
			"Processing switch with GUID 0x%" PRIx64 "\n",
Packit Service 54dbc3
			cl_ntoh64(osm_node_get_node_guid(sw->p_node)));
Packit Service 54dbc3
Packit Service 54dbc3
		adj_list[i].guid =
Packit Service 54dbc3
		    cl_ntoh64(osm_node_get_node_guid(sw->p_node));
Packit Service 54dbc3
		adj_list[i].lid =
Packit Service 54dbc3
		    cl_ntoh16(osm_node_get_base_lid(sw->p_node, 0));
Packit Service 54dbc3
		adj_list[i].sw = sw;
Packit Service 54dbc3
Packit Service 54dbc3
		link = (link_t *) malloc(sizeof(link_t));
Packit Service 54dbc3
		if (!link) {
Packit Service 54dbc3
			OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
Packit Service 54dbc3
				"ERR AD03: cannot allocate memory for a link\n");
Packit Service 54dbc3
			goto ERROR;
Packit Service 54dbc3
		}
Packit Service 54dbc3
		head = link;
Packit Service 54dbc3
		head->next = NULL;
Packit Service 54dbc3
Packit Service 54dbc3
		/* add SP0 to number of CA connected to a switch */
Packit Service 54dbc3
		lmc = osm_node_get_lmc(sw->p_node, 0);
Packit Service 54dbc3
		adj_list[i].num_hca += (1 << lmc);
Packit Service 54dbc3
Packit Service 54dbc3
		/* iterate over all ports in the switch, start with port 1 (port 0 is a management port) */
Packit Service 54dbc3
		for (port = 1; port < sw->num_ports; port++) {
Packit Service 54dbc3
			/* get the node behind the port */
Packit Service 54dbc3
			remote_node =
Packit Service 54dbc3
			    osm_node_get_remote_node(sw->p_node, port,
Packit Service 54dbc3
						     &remote_port);
Packit Service 54dbc3
			/* if there is no remote node on this port or it's the same switch -> try next port */
Packit Service 54dbc3
			if (!remote_node || remote_node->sw == sw)
Packit Service 54dbc3
				continue;
Packit Service 54dbc3
			/* make sure the link is healthy */
Packit Service 54dbc3
			p_physp = osm_node_get_physp_ptr(sw->p_node, port);
Packit Service 54dbc3
			if (!p_physp || !osm_link_is_healthy(p_physp))
Packit Service 54dbc3
				continue;
Packit Service 54dbc3
			/* if there is a Hca connected -> count and cycle */
Packit Service 54dbc3
			if (!remote_node->sw) {
Packit Service 54dbc3
				lmc = osm_node_get_lmc(remote_node, (uint32_t)remote_port);
Packit Service 54dbc3
				adj_list[i].num_hca += (1 << lmc);
Packit Service 54dbc3
				continue;
Packit Service 54dbc3
			}
Packit Service 54dbc3
			/* filter out throttled links to improve performance */
Packit Service 54dbc3
			if (p_mgr->p_subn->opt.avoid_throttled_links &&
Packit Service 54dbc3
			    osm_link_is_throttled(p_physp, has_fdr10)) {
Packit Service 54dbc3
				OSM_LOG(p_mgr->p_log, OSM_LOG_INFO,
Packit Service 54dbc3
					"Detected and ignoring throttled link:"
Packit Service 54dbc3
					" 0x%" PRIx64 "/P%" PRIu8
Packit Service 54dbc3
					" <--> 0x%" PRIx64 "/P%" PRIu8 "\n",
Packit Service 54dbc3
					cl_ntoh64(osm_node_get_node_guid(sw->p_node)),
Packit Service 54dbc3
					port,
Packit Service 54dbc3
					cl_ntoh64(osm_node_get_node_guid(remote_node)),
Packit Service 54dbc3
					remote_port);
Packit Service 54dbc3
				continue;
Packit Service 54dbc3
			}
Packit Service 54dbc3
			OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
Packit Service 54dbc3
				"Node 0x%" PRIx64 ", remote node 0x%" PRIx64
Packit Service 54dbc3
				", port %" PRIu8 ", remote port %" PRIu8 "\n",
Packit Service 54dbc3
				cl_ntoh64(osm_node_get_node_guid(sw->p_node)),
Packit Service 54dbc3
				cl_ntoh64(osm_node_get_node_guid(remote_node)),
Packit Service 54dbc3
				port, remote_port);
Packit Service 54dbc3
Packit Service 54dbc3
			link->next = (link_t *) malloc(sizeof(link_t));
Packit Service 54dbc3
			if (!link->next) {
Packit Service 54dbc3
				OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
Packit Service 54dbc3
					"ERR AD08: cannot allocate memory for a link\n");
Packit Service 54dbc3
				while (head) {
Packit Service 54dbc3
					link = head;
Packit Service 54dbc3
					head = head->next;
Packit Service 54dbc3
					free(link);
Packit Service 54dbc3
				}
Packit Service 54dbc3
				goto ERROR;
Packit Service 54dbc3
			}
Packit Service 54dbc3
			link = link->next;
Packit Service 54dbc3
			set_default_link(link);
Packit Service 54dbc3
			link->guid =
Packit Service 54dbc3
			    cl_ntoh64(osm_node_get_node_guid(remote_node));
Packit Service 54dbc3
			link->from = i;
Packit Service 54dbc3
			link->from_port = port;
Packit Service 54dbc3
			link->to_port = remote_port;
Packit Service 54dbc3
			link->weight = total_num_hca * total_num_hca;	/* initialize with P^2 to force shortest paths */
Packit Service 54dbc3
		}
Packit Service 54dbc3
Packit Service 54dbc3
		adj_list[i].links = head->next;
Packit Service 54dbc3
		free(head);
Packit Service 54dbc3
	}
Packit Service 54dbc3
	/* connect the links with it's second adjacent node in the list */
Packit Service 54dbc3
	for (i = 1; i < adj_list_size; i++) {
Packit Service 54dbc3
		link = adj_list[i].links;
Packit Service 54dbc3
		while (link) {
Packit Service 54dbc3
			for (j = 1; j < adj_list_size; j++) {
Packit Service 54dbc3
				if (link->guid == adj_list[j].guid) {
Packit Service 54dbc3
					link->to = j;
Packit Service 54dbc3
					break;
Packit Service 54dbc3
				}
Packit Service 54dbc3
			}
Packit Service 54dbc3
			link = link->next;
Packit Service 54dbc3
		}
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	/* do one dry run to determine connectivity issues */
Packit Service 54dbc3
	sm_lid = p_mgr->p_subn->master_sm_base_lid;
Packit Service 54dbc3
	p_port = osm_get_port_by_lid(p_mgr->p_subn, sm_lid);
Packit Service 54dbc3
	err = dijkstra(p_mgr, &heap, adj_list, adj_list_size, p_port, sm_lid);
Packit Service 54dbc3
	if (err) {
Packit Service 54dbc3
		goto ERROR;
Packit Service 54dbc3
	} else {
Packit Service 54dbc3
		/* if sm is running on a switch, then dijkstra doesn't
Packit Service 54dbc3
		   initialize the used_link for this switch
Packit Service 54dbc3
		 */
Packit Service 54dbc3
		if (osm_node_get_type(p_port->p_node) != IB_NODE_TYPE_CA)
Packit Service 54dbc3
			max_num_undiscov = 1;
Packit Service 54dbc3
		for (i = 1; i < adj_list_size; i++)
Packit Service 54dbc3
			undiscov += (adj_list[i].used_link) ? 0 : 1;
Packit Service 54dbc3
		if (max_num_undiscov < undiscov) {
Packit Service 54dbc3
			OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
Packit Service 54dbc3
				"ERR AD0C: unsupported network state (detached"
Packit Service 54dbc3
				" and inaccessible switches found; gracefully"
Packit Service 54dbc3
				" shutdown this routing engine)\n");
Packit Service 54dbc3
			goto ERROR;
Packit Service 54dbc3
		}
Packit Service 54dbc3
	}
Packit Service 54dbc3
	/* delete the heap which is not needed anymore */
Packit Service 54dbc3
	cl_heap_destroy(&heap;;
Packit Service 54dbc3
Packit Service 54dbc3
	/* print the discovered graph */
Packit Service 54dbc3
	if (OSM_LOG_IS_ACTIVE_V2(p_mgr->p_log, OSM_LOG_DEBUG))
Packit Service 54dbc3
		dfsssp_print_graph(p_mgr, adj_list, adj_list_size);
Packit Service 54dbc3
Packit Service 54dbc3
	OSM_LOG_EXIT(p_mgr->p_log);
Packit Service 54dbc3
	return 0;
Packit Service 54dbc3
Packit Service 54dbc3
ERROR:
Packit Service 54dbc3
	if (cl_is_heap_inited(&heap))
Packit Service 54dbc3
		cl_heap_destroy(&heap;;
Packit Service 54dbc3
	dfsssp_context_destroy(context);
Packit Service 54dbc3
	return -1;
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
static void print_routes(osm_ucast_mgr_t * p_mgr, vertex_t * adj_list,
Packit Service 54dbc3
			 uint32_t adj_list_size, osm_port_t * port)
Packit Service 54dbc3
{
Packit Service 54dbc3
	uint32_t i = 0, j = 0;
Packit Service 54dbc3
Packit Service 54dbc3
	for (i = 1; i < adj_list_size; i++) {
Packit Service 54dbc3
		if (adj_list[i].state == DISCOVERED) {
Packit Service 54dbc3
			OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
Packit Service 54dbc3
				"Route from 0x%" PRIx64 " (%s) to 0x%" PRIx64
Packit Service 54dbc3
				" (%s):\n", adj_list[i].guid,
Packit Service 54dbc3
				adj_list[i].sw->p_node->print_desc,
Packit Service 54dbc3
				cl_ntoh64(osm_node_get_node_guid(port->p_node)),
Packit Service 54dbc3
				port->p_node->print_desc);
Packit Service 54dbc3
			j = i;
Packit Service 54dbc3
			while (adj_list[j].used_link) {
Packit Service 54dbc3
				if (j > 0) {
Packit Service 54dbc3
					OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
Packit Service 54dbc3
						"   0x%" PRIx64
Packit Service 54dbc3
						" (%s) routes thru port %" PRIu8
Packit Service 54dbc3
						"\n", adj_list[j].guid,
Packit Service 54dbc3
						adj_list[j].sw->p_node->
Packit Service 54dbc3
						print_desc,
Packit Service 54dbc3
						adj_list[j].used_link->to_port);
Packit Service 54dbc3
				} else {
Packit Service 54dbc3
					OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
Packit Service 54dbc3
						"   0x%" PRIx64
Packit Service 54dbc3
						" (%s) routes thru port %" PRIu8
Packit Service 54dbc3
						"\n", adj_list[j].guid,
Packit Service 54dbc3
						port->p_node->print_desc,
Packit Service 54dbc3
						adj_list[j].used_link->to_port);
Packit Service 54dbc3
				}
Packit Service 54dbc3
				j = adj_list[j].used_link->from;
Packit Service 54dbc3
			}
Packit Service 54dbc3
		}
Packit Service 54dbc3
	}
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
/* callback function for the cl_heap to update the index */
Packit Service 54dbc3
static void apply_index_update(const void * context, const size_t new_index)
Packit Service 54dbc3
{
Packit Service 54dbc3
	vertex_t *heap_elem = (vertex_t *) context;
Packit Service 54dbc3
	if (heap_elem)
Packit Service 54dbc3
		heap_elem->heap_index = new_index;
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
/* dijkstra step from one source to all switches in the df-/sssp graph */
Packit Service 54dbc3
static int dijkstra(osm_ucast_mgr_t * p_mgr, cl_heap_t * p_heap,
Packit Service 54dbc3
		    vertex_t * adj_list, uint32_t adj_list_size,
Packit Service 54dbc3
		    osm_port_t * port, uint16_t lid)
Packit Service 54dbc3
{
Packit Service 54dbc3
	uint32_t i = 0, j = 0, index = 0;
Packit Service 54dbc3
	osm_node_t *remote_node = NULL;
Packit Service 54dbc3
	uint8_t remote_port = 0;
Packit Service 54dbc3
	vertex_t *current = NULL;
Packit Service 54dbc3
	link_t *link = NULL;
Packit Service 54dbc3
	uint64_t guid = 0;
Packit Service 54dbc3
	cl_status_t ret = CL_SUCCESS;
Packit Service 54dbc3
Packit Service 54dbc3
	OSM_LOG_ENTER(p_mgr->p_log);
Packit Service 54dbc3
Packit Service 54dbc3
	/* build an 4-ary heap to find the node with minimum distance */
Packit Service 54dbc3
	if (!cl_is_heap_inited(p_heap))
Packit Service 54dbc3
		ret = cl_heap_init(p_heap, adj_list_size, 4,
Packit Service 54dbc3
				   &apply_index_update, NULL);
Packit Service 54dbc3
	else
Packit Service 54dbc3
		ret = cl_heap_resize(p_heap, adj_list_size);
Packit Service 54dbc3
	if (ret != CL_SUCCESS) {
Packit Service 54dbc3
		OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
Packit Service 54dbc3
			"ERR AD09: cannot allocate memory or resize heap\n");
Packit Service 54dbc3
		return ret;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	/* reset all switches for new round with a new source for dijkstra */
Packit Service 54dbc3
	for (i = 1; i < adj_list_size; i++) {
Packit Service 54dbc3
		adj_list[i].hops = 0;
Packit Service 54dbc3
		adj_list[i].used_link = NULL;
Packit Service 54dbc3
		adj_list[i].distance = INF;
Packit Service 54dbc3
		adj_list[i].state = UNDISCOVERED;
Packit Service 54dbc3
		ret = cl_heap_insert(p_heap, INF, &adj_list[i]);
Packit Service 54dbc3
		if (ret != CL_SUCCESS) {
Packit Service 54dbc3
			OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
Packit Service 54dbc3
				"ERR AD11: cl_heap_insert failed\n");
Packit Service 54dbc3
			return ret;
Packit Service 54dbc3
		}
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	/* if behind port is a Hca -> set adj_list[0] */
Packit Service 54dbc3
	if (osm_node_get_type(port->p_node) == IB_NODE_TYPE_CA) {
Packit Service 54dbc3
		/* save old link to prevent many mallocs after set_default_... */
Packit Service 54dbc3
		link = adj_list[0].links;
Packit Service 54dbc3
		/* initialize adj_list[0] (the source for the routing, a Hca) */
Packit Service 54dbc3
		set_default_vertex(&adj_list[0]);
Packit Service 54dbc3
		adj_list[0].guid =
Packit Service 54dbc3
		    cl_ntoh64(osm_node_get_node_guid(port->p_node));
Packit Service 54dbc3
		adj_list[0].lid = lid;
Packit Service 54dbc3
		index = 0;
Packit Service 54dbc3
		/* write saved link back to new adj_list[0] */
Packit Service 54dbc3
		adj_list[0].links = link;
Packit Service 54dbc3
Packit Service 54dbc3
		/* initialize link to neighbor for adj_list[0];
Packit Service 54dbc3
		   make sure the link is healthy
Packit Service 54dbc3
		 */
Packit Service 54dbc3
		if (port->p_physp && osm_link_is_healthy(port->p_physp)) {
Packit Service 54dbc3
			remote_node =
Packit Service 54dbc3
			    osm_node_get_remote_node(port->p_node,
Packit Service 54dbc3
						     port->p_physp->port_num,
Packit Service 54dbc3
						     &remote_port);
Packit Service 54dbc3
			/* if there is no remote node on this port or it's the same Hca -> ignore */
Packit Service 54dbc3
			if (remote_node
Packit Service 54dbc3
			    && (osm_node_get_type(remote_node) ==
Packit Service 54dbc3
				IB_NODE_TYPE_SWITCH)) {
Packit Service 54dbc3
				if (!(adj_list[0].links)) {
Packit Service 54dbc3
					adj_list[0].links =
Packit Service 54dbc3
					    (link_t *) malloc(sizeof(link_t));
Packit Service 54dbc3
					if (!(adj_list[0].links)) {
Packit Service 54dbc3
						OSM_LOG(p_mgr->p_log,
Packit Service 54dbc3
							OSM_LOG_ERROR,
Packit Service 54dbc3
							"ERR AD07: cannot allocate memory for a link\n");
Packit Service 54dbc3
						return 1;
Packit Service 54dbc3
					}
Packit Service 54dbc3
				}
Packit Service 54dbc3
				set_default_link(adj_list[0].links);
Packit Service 54dbc3
				adj_list[0].links->guid =
Packit Service 54dbc3
				    cl_ntoh64(osm_node_get_node_guid
Packit Service 54dbc3
					      (remote_node));
Packit Service 54dbc3
				adj_list[0].links->from_port =
Packit Service 54dbc3
				    port->p_physp->port_num;
Packit Service 54dbc3
				adj_list[0].links->to_port = remote_port;
Packit Service 54dbc3
				adj_list[0].links->weight = 1;
Packit Service 54dbc3
				for (j = 1; j < adj_list_size; j++) {
Packit Service 54dbc3
					if (adj_list[0].links->guid ==
Packit Service 54dbc3
					    adj_list[j].guid) {
Packit Service 54dbc3
						adj_list[0].links->to = j;
Packit Service 54dbc3
						break;
Packit Service 54dbc3
					}
Packit Service 54dbc3
				}
Packit Service 54dbc3
			}
Packit Service 54dbc3
		} else {
Packit Service 54dbc3
			/* if link is unhealthy then there's a severe issue */
Packit Service 54dbc3
			OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
Packit Service 54dbc3
				"ERR AD0B: unsupported network state (CA with"
Packit Service 54dbc3
				" unhealthy link state discovered; should have"
Packit Service 54dbc3
				" been filtered out before already; gracefully"
Packit Service 54dbc3
				" shutdown this routing engine)\n");
Packit Service 54dbc3
			return 1;
Packit Service 54dbc3
		}
Packit Service 54dbc3
		ret = cl_heap_insert(p_heap, INF, &adj_list[0]);
Packit Service 54dbc3
		if (ret != CL_SUCCESS) {
Packit Service 54dbc3
			OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
Packit Service 54dbc3
				"ERR AD13: cl_heap_insert failed\n");
Packit Service 54dbc3
			return ret;
Packit Service 54dbc3
		}
Packit Service 54dbc3
		/* if behind port is a switch -> search switch in adj_list */
Packit Service 54dbc3
	} else {
Packit Service 54dbc3
		/* reset adj_list[0], if links=NULL reset was done before, then skip */
Packit Service 54dbc3
		if (adj_list[0].links) {
Packit Service 54dbc3
			free(adj_list[0].links);
Packit Service 54dbc3
			set_default_vertex(&adj_list[0]);
Packit Service 54dbc3
		}
Packit Service 54dbc3
		/* search for the switch which is the source in this round */
Packit Service 54dbc3
		guid = cl_ntoh64(osm_node_get_node_guid(port->p_node));
Packit Service 54dbc3
		for (i = 1; i < adj_list_size; i++) {
Packit Service 54dbc3
			if (guid == adj_list[i].guid) {
Packit Service 54dbc3
				index = i;
Packit Service 54dbc3
				break;
Packit Service 54dbc3
			}
Packit Service 54dbc3
		}
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	/* source in dijkstra */
Packit Service 54dbc3
	adj_list[index].distance = 0;
Packit Service 54dbc3
	adj_list[index].state = DISCOVERED;
Packit Service 54dbc3
	adj_list[index].hops = 0;	/* the source has hop count = 0 */
Packit Service 54dbc3
	ret = cl_heap_modify_key(p_heap, adj_list[index].distance,
Packit Service 54dbc3
				 adj_list[index].heap_index);
Packit Service 54dbc3
	if (ret != CL_SUCCESS) {
Packit Service 54dbc3
		OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
Packit Service 54dbc3
			"ERR AD10: index out of bounds in cl_heap_modify_key\n");
Packit Service 54dbc3
		return ret;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	current = (vertex_t *) cl_heap_extract_root(p_heap);
Packit Service 54dbc3
	while (current) {
Packit Service 54dbc3
		current->state = DISCOVERED;
Packit Service 54dbc3
		if (current->used_link)	/* increment the number of hops to the source for each new node */
Packit Service 54dbc3
			current->hops =
Packit Service 54dbc3
			    adj_list[current->used_link->from].hops + 1;
Packit Service 54dbc3
Packit Service 54dbc3
		/* add/update nodes which aren't discovered but accessible */
Packit Service 54dbc3
		for (link = current->links; link != NULL; link = link->next) {
Packit Service 54dbc3
			if ((adj_list[link->to].state != DISCOVERED)
Packit Service 54dbc3
			    && (current->distance + link->weight <
Packit Service 54dbc3
				adj_list[link->to].distance)) {
Packit Service 54dbc3
				adj_list[link->to].used_link = link;
Packit Service 54dbc3
				adj_list[link->to].distance =
Packit Service 54dbc3
				    current->distance + link->weight;
Packit Service 54dbc3
				ret = cl_heap_modify_key(p_heap,
Packit Service 54dbc3
							 adj_list[link->to].distance,
Packit Service 54dbc3
							 adj_list[link->to].heap_index);
Packit Service 54dbc3
				if (ret != CL_SUCCESS) {
Packit Service 54dbc3
					OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
Packit Service 54dbc3
						"ERR AD12: index out of bounds in cl_heap_modify_key\n");
Packit Service 54dbc3
					return ret;
Packit Service 54dbc3
				}
Packit Service 54dbc3
			}
Packit Service 54dbc3
		}
Packit Service 54dbc3
Packit Service 54dbc3
		current = (vertex_t *) cl_heap_extract_root(p_heap);
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	OSM_LOG_EXIT(p_mgr->p_log);
Packit Service 54dbc3
	return 0;
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
/* update the linear forwarding tables of all switches with the informations
Packit Service 54dbc3
   from the last dijsktra step
Packit Service 54dbc3
*/
Packit Service 54dbc3
static int update_lft(osm_ucast_mgr_t * p_mgr, vertex_t * adj_list,
Packit Service 54dbc3
		      uint32_t adj_list_size, osm_port_t * p_port, uint16_t lid)
Packit Service 54dbc3
{
Packit Service 54dbc3
	uint32_t i = 0;
Packit Service 54dbc3
	uint8_t port = 0;
Packit Service 54dbc3
	uint8_t hops = 0;
Packit Service 54dbc3
	osm_switch_t *p_sw = NULL;
Packit Service 54dbc3
	boolean_t is_ignored_by_port_prof = FALSE;
Packit Service 54dbc3
	osm_physp_t *p = NULL;
Packit Service 54dbc3
	cl_status_t ret;
Packit Service 54dbc3
Packit Service 54dbc3
	OSM_LOG_ENTER(p_mgr->p_log);
Packit Service 54dbc3
Packit Service 54dbc3
	for (i = 1; i < adj_list_size; i++) {
Packit Service 54dbc3
		/* if no route goes thru this switch -> cycle */
Packit Service 54dbc3
		if (!(adj_list[i].used_link))
Packit Service 54dbc3
			continue;
Packit Service 54dbc3
Packit Service 54dbc3
		p_sw = adj_list[i].sw;
Packit Service 54dbc3
		hops = adj_list[i].hops;
Packit Service 54dbc3
		port = adj_list[i].used_link->to_port;
Packit Service 54dbc3
		/* the used_link is the link that was used in dijkstra to reach this node,
Packit Service 54dbc3
		   so the to_port is the local port on this node
Packit Service 54dbc3
		 */
Packit Service 54dbc3
Packit Service 54dbc3
		if (port == OSM_NO_PATH) {	/* if clause shouldn't be possible in this routing, but who cares */
Packit Service 54dbc3
			OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
Packit Service 54dbc3
				"ERR AD06: No path to get to LID %" PRIu16
Packit Service 54dbc3
				" from switch 0x%" PRIx64 "\n", lid,
Packit Service 54dbc3
				cl_ntoh64(osm_node_get_node_guid
Packit Service 54dbc3
					  (p_sw->p_node)));
Packit Service 54dbc3
Packit Service 54dbc3
			/* do not try to overwrite the ppro of non existing port ... */
Packit Service 54dbc3
			is_ignored_by_port_prof = TRUE;
Packit Service 54dbc3
			return 1;
Packit Service 54dbc3
		} else {
Packit Service 54dbc3
			OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
Packit Service 54dbc3
				"Routing LID %" PRIu16 " to port %" PRIu8
Packit Service 54dbc3
				" for switch 0x%" PRIx64 "\n", lid, port,
Packit Service 54dbc3
				cl_ntoh64(osm_node_get_node_guid
Packit Service 54dbc3
					  (p_sw->p_node)));
Packit Service 54dbc3
Packit Service 54dbc3
			p = osm_node_get_physp_ptr(p_sw->p_node, port);
Packit Service 54dbc3
			if (!p) {
Packit Service 54dbc3
				OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
Packit Service 54dbc3
					"ERR AD0A: Physical port %d of Node GUID 0x%"
Packit Service 54dbc3
					PRIx64 "not found\n", port,
Packit Service 54dbc3
					cl_ntoh64(osm_node_get_node_guid(p_sw->p_node)));
Packit Service 54dbc3
				return 1;
Packit Service 54dbc3
			}
Packit Service 54dbc3
Packit Service 54dbc3
			/* we would like to optionally ignore this port in equalization
Packit Service 54dbc3
			   as in the case of the Mellanox Anafa Internal PCI TCA port
Packit Service 54dbc3
			 */
Packit Service 54dbc3
			is_ignored_by_port_prof = p->is_prof_ignored;
Packit Service 54dbc3
Packit Service 54dbc3
			/* We also would ignore this route if the target lid is of
Packit Service 54dbc3
			   a switch and the port_profile_switch_node is not TRUE
Packit Service 54dbc3
			 */
Packit Service 54dbc3
			if (!p_mgr->p_subn->opt.port_profile_switch_nodes)
Packit Service 54dbc3
				is_ignored_by_port_prof |=
Packit Service 54dbc3
				    (osm_node_get_type(p_port->p_node) ==
Packit Service 54dbc3
				     IB_NODE_TYPE_SWITCH);
Packit Service 54dbc3
		}
Packit Service 54dbc3
Packit Service 54dbc3
		/* to support lmc > 0 the functions alloc_ports_priv, free_ports_priv, find_and_add_remote_sys
Packit Service 54dbc3
		   from minhop aren't needed cause osm_switch_recommend_path is implicitly calculated
Packit Service 54dbc3
		   for each LID pair thru dijkstra;
Packit Service 54dbc3
		   for each port the dijkstra algorithm calculates (max_lid_ho - min_lid_ho)-times maybe
Packit Service 54dbc3
		   disjoint routes to spread the bandwidth -> diffent routes for one port and lmc>0
Packit Service 54dbc3
		 */
Packit Service 54dbc3
Packit Service 54dbc3
		/* set port in LFT */
Packit Service 54dbc3
		p_sw->new_lft[lid] = port;
Packit Service 54dbc3
		if (!is_ignored_by_port_prof) {
Packit Service 54dbc3
			/* update the number of path routing thru this port */
Packit Service 54dbc3
			osm_switch_count_path(p_sw, port);
Packit Service 54dbc3
		}
Packit Service 54dbc3
		/* set the hop count from this switch to the lid */
Packit Service 54dbc3
		ret = osm_switch_set_hops(p_sw, lid, port, hops);
Packit Service 54dbc3
		if (ret != CL_SUCCESS)
Packit Service 54dbc3
			OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
Packit Service 54dbc3
				"ERR AD05: cannot set hops for LID %" PRIu16
Packit Service 54dbc3
				" at switch 0x%" PRIx64 "\n", lid,
Packit Service 54dbc3
				cl_ntoh64(osm_node_get_node_guid
Packit Service 54dbc3
					  (p_sw->p_node)));
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	OSM_LOG_EXIT(p_mgr->p_log);
Packit Service 54dbc3
	return 0;
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
/* the function updates the multicast group membership information
Packit Service 54dbc3
   similar to create_mgrp_switch_map (osm_mcast_mgr.c)
Packit Service 54dbc3
   => with it we can identify if a switch needs to be processed
Packit Service 54dbc3
   or not in update_mcft
Packit Service 54dbc3
*/
Packit Service 54dbc3
static void update_mgrp_membership(cl_qlist_t * port_list)
Packit Service 54dbc3
{
Packit Service 54dbc3
	osm_mcast_work_obj_t *wobj = NULL;
Packit Service 54dbc3
	osm_port_t *port = NULL;
Packit Service 54dbc3
	osm_switch_t *sw = NULL;
Packit Service 54dbc3
	cl_list_item_t *i = NULL;
Packit Service 54dbc3
Packit Service 54dbc3
	for (i = cl_qlist_head(port_list); i != cl_qlist_end(port_list);
Packit Service 54dbc3
	     i = cl_qlist_next(i)) {
Packit Service 54dbc3
		wobj = cl_item_obj(i, wobj, list_item);
Packit Service 54dbc3
		port = wobj->p_port;
Packit Service 54dbc3
		if (port->p_node->sw) {
Packit Service 54dbc3
			sw = port->p_node->sw;
Packit Service 54dbc3
			sw->is_mc_member = 1;
Packit Service 54dbc3
		} else {
Packit Service 54dbc3
			sw = port->p_physp->p_remote_physp->p_node->sw;
Packit Service 54dbc3
			sw->num_of_mcm++;
Packit Service 54dbc3
		}
Packit Service 54dbc3
	}
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
/* reset is_mc_member and num_of_mcm for future computations */
Packit Service 54dbc3
static void reset_mgrp_membership(vertex_t * adj_list, uint32_t adj_list_size)
Packit Service 54dbc3
{
Packit Service 54dbc3
	uint32_t i = 0;
Packit Service 54dbc3
Packit Service 54dbc3
	for (i = 1; i < adj_list_size; i++) {
Packit Service 54dbc3
		if (adj_list[i].dropped)
Packit Service 54dbc3
			continue;
Packit Service 54dbc3
Packit Service 54dbc3
		adj_list[i].sw->is_mc_member = 0;
Packit Service 54dbc3
		adj_list[i].sw->num_of_mcm = 0;
Packit Service 54dbc3
	}
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
/* update the multicast forwarding tables of all switches with the informations
Packit Service 54dbc3
   from the previous dijsktra step for the current mlid
Packit Service 54dbc3
*/
Packit Service 54dbc3
static int update_mcft(osm_sm_t * p_sm, vertex_t * adj_list,
Packit Service 54dbc3
		       uint32_t adj_list_size, uint16_t mlid_ho,
Packit Service 54dbc3
		       cl_qmap_t * port_map, osm_switch_t * root_sw)
Packit Service 54dbc3
{
Packit Service 54dbc3
	uint32_t i = 0;
Packit Service 54dbc3
	uint8_t port = 0, remote_port = 0;
Packit Service 54dbc3
	uint8_t upstream_port = 0, downstream_port = 0;
Packit Service 54dbc3
	ib_net64_t guid = 0;
Packit Service 54dbc3
	osm_switch_t *p_sw = NULL;
Packit Service 54dbc3
	osm_node_t *remote_node = NULL;
Packit Service 54dbc3
	osm_physp_t *p_physp = NULL;
Packit Service 54dbc3
	osm_mcast_tbl_t *p_tbl = NULL;
Packit Service 54dbc3
	vertex_t *curr_adj = NULL;
Packit Service 54dbc3
Packit Service 54dbc3
	OSM_LOG_ENTER(p_sm->p_log);
Packit Service 54dbc3
Packit Service 54dbc3
	for (i = 1; i < adj_list_size; i++) {
Packit Service 54dbc3
		if (adj_list[i].dropped)
Packit Service 54dbc3
			continue;
Packit Service 54dbc3
Packit Service 54dbc3
		p_sw = adj_list[i].sw;
Packit Service 54dbc3
		OSM_LOG(p_sm->p_log, OSM_LOG_VERBOSE,
Packit Service 54dbc3
			"Processing switch 0x%016" PRIx64
Packit Service 54dbc3
			" (%s) for MLID 0x%X\n", cl_ntoh64(adj_list[i].guid),
Packit Service 54dbc3
			p_sw->p_node->print_desc, mlid_ho);
Packit Service 54dbc3
Packit Service 54dbc3
		/* if a) the switch does not support mcast  or
Packit Service 54dbc3
		      b) no ports of this switch are part or the mcast group
Packit Service 54dbc3
		   then cycle
Packit Service 54dbc3
		 */
Packit Service 54dbc3
		if (osm_switch_supports_mcast(p_sw) == FALSE ||
Packit Service 54dbc3
		    (p_sw->num_of_mcm == 0 && !(p_sw->is_mc_member)))
Packit Service 54dbc3
			continue;
Packit Service 54dbc3
Packit Service 54dbc3
		p_tbl = osm_switch_get_mcast_tbl_ptr(p_sw);
Packit Service 54dbc3
Packit Service 54dbc3
		/* add all ports of this sw to the mcast table,
Packit Service 54dbc3
		   if they are part of the mcast grp
Packit Service 54dbc3
		 */
Packit Service 54dbc3
		if (p_sw->is_mc_member)
Packit Service 54dbc3
			osm_mcast_tbl_set(p_tbl, mlid_ho, 0);
Packit Service 54dbc3
		for (port = 1; port < p_sw->num_ports; port++) {
Packit Service 54dbc3
			/* get the node behind the port */
Packit Service 54dbc3
			remote_node =
Packit Service 54dbc3
				osm_node_get_remote_node(p_sw->p_node, port,
Packit Service 54dbc3
							 &remote_port);
Packit Service 54dbc3
			/* check if connected and its not the same switch */
Packit Service 54dbc3
			if (!remote_node || remote_node->sw == p_sw)
Packit Service 54dbc3
				continue;
Packit Service 54dbc3
			/* make sure the link is healthy */
Packit Service 54dbc3
			p_physp = osm_node_get_physp_ptr(p_sw->p_node, port);
Packit Service 54dbc3
			if (!p_physp || !osm_link_is_healthy(p_physp))
Packit Service 54dbc3
				continue;
Packit Service 54dbc3
			/* we don't add upstream ports in this step */
Packit Service 54dbc3
			if (osm_node_get_type(remote_node) != IB_NODE_TYPE_CA)
Packit Service 54dbc3
				continue;
Packit Service 54dbc3
Packit Service 54dbc3
			guid = osm_physp_get_port_guid(osm_node_get_physp_ptr(
Packit Service 54dbc3
						       remote_node,
Packit Service 54dbc3
						       remote_port));
Packit Service 54dbc3
			if (cl_qmap_get(port_map, guid)
Packit Service 54dbc3
			    != cl_qmap_end(port_map))
Packit Service 54dbc3
				osm_mcast_tbl_set(p_tbl, mlid_ho, port);
Packit Service 54dbc3
		}
Packit Service 54dbc3
Packit Service 54dbc3
		/* now we have to add the upstream port of 'this' switch and
Packit Service 54dbc3
		   the downstream port of the next switch to the mcast table
Packit Service 54dbc3
		   until we reach the root_sw
Packit Service 54dbc3
		 */
Packit Service 54dbc3
		curr_adj = &adj_list[i];
Packit Service 54dbc3
		while (curr_adj->sw != root_sw) {
Packit Service 54dbc3
			/* the used_link is the link that was used in dijkstra to reach this node,
Packit Service 54dbc3
			   so the to_port is the local (upstream) port on curr_adj->sw
Packit Service 54dbc3
			 */
Packit Service 54dbc3
			upstream_port = curr_adj->used_link->to_port;
Packit Service 54dbc3
			osm_mcast_tbl_set(p_tbl, mlid_ho, upstream_port);
Packit Service 54dbc3
Packit Service 54dbc3
			/* now we go one step in direction root_sw and add the
Packit Service 54dbc3
			   downstream port for the spanning tree
Packit Service 54dbc3
			 */
Packit Service 54dbc3
			downstream_port = curr_adj->used_link->from_port;
Packit Service 54dbc3
			p_tbl = osm_switch_get_mcast_tbl_ptr(
Packit Service 54dbc3
				adj_list[curr_adj->used_link->from].sw);
Packit Service 54dbc3
			osm_mcast_tbl_set(p_tbl, mlid_ho, downstream_port);
Packit Service 54dbc3
Packit Service 54dbc3
			curr_adj = &adj_list[curr_adj->used_link->from];
Packit Service 54dbc3
		}
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	OSM_LOG_EXIT(p_sm->p_log);
Packit Service 54dbc3
	return 0;
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
/* increment the edge weights of the df-/sssp graph which represent the number
Packit Service 54dbc3
   of paths on this link
Packit Service 54dbc3
*/
Packit Service 54dbc3
static void update_weights(osm_ucast_mgr_t * p_mgr, vertex_t * adj_list,
Packit Service 54dbc3
			   uint32_t adj_list_size)
Packit Service 54dbc3
{
Packit Service 54dbc3
	uint32_t i = 0, j = 0;
Packit Service 54dbc3
	uint32_t additional_weight = 0;
Packit Service 54dbc3
Packit Service 54dbc3
	OSM_LOG_ENTER(p_mgr->p_log);
Packit Service 54dbc3
Packit Service 54dbc3
	for (i = 1; i < adj_list_size; i++) {
Packit Service 54dbc3
		/* if no route goes thru this switch -> cycle */
Packit Service 54dbc3
		if (!(adj_list[i].used_link))
Packit Service 54dbc3
			continue;
Packit Service 54dbc3
		additional_weight = adj_list[i].num_hca;
Packit Service 54dbc3
Packit Service 54dbc3
		j = i;
Packit Service 54dbc3
		while (adj_list[j].used_link) {
Packit Service 54dbc3
			/* update the link from pre to this node */
Packit Service 54dbc3
			adj_list[j].used_link->weight += additional_weight;
Packit Service 54dbc3
Packit Service 54dbc3
			j = adj_list[j].used_link->from;
Packit Service 54dbc3
		}
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	OSM_LOG_EXIT(p_mgr->p_log);
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
/* get the largest number of virtual lanes which is supported by all switches
Packit Service 54dbc3
   in the subnet
Packit Service 54dbc3
*/
Packit Service 54dbc3
static uint8_t get_avail_vl_in_subn(osm_ucast_mgr_t * p_mgr)
Packit Service 54dbc3
{
Packit Service 54dbc3
	uint32_t i = 0;
Packit Service 54dbc3
	uint8_t vls_avail = 0xFF, port_vls_avail = 0;
Packit Service 54dbc3
	cl_qmap_t *sw_tbl = &p_mgr->p_subn->sw_guid_tbl;
Packit Service 54dbc3
	cl_map_item_t *item = NULL;
Packit Service 54dbc3
	osm_switch_t *sw = NULL;
Packit Service 54dbc3
Packit Service 54dbc3
	/* traverse all switches to get the number of available virtual lanes in the subnet */
Packit Service 54dbc3
	for (item = cl_qmap_head(sw_tbl); item != cl_qmap_end(sw_tbl);
Packit Service 54dbc3
	     item = cl_qmap_next(item)) {
Packit Service 54dbc3
		sw = (osm_switch_t *) item;
Packit Service 54dbc3
Packit Service 54dbc3
		/* ignore management port 0 */
Packit Service 54dbc3
		for (i = 1; i < osm_node_get_num_physp(sw->p_node); i++) {
Packit Service 54dbc3
			osm_physp_t *p_physp =
Packit Service 54dbc3
			    osm_node_get_physp_ptr(sw->p_node, i);
Packit Service 54dbc3
Packit Service 54dbc3
			if (p_physp && p_physp->p_remote_physp) {
Packit Service 54dbc3
				port_vls_avail =
Packit Service 54dbc3
				    ib_port_info_get_op_vls(&p_physp->
Packit Service 54dbc3
							    port_info);
Packit Service 54dbc3
				if (port_vls_avail
Packit Service 54dbc3
				    && port_vls_avail < vls_avail)
Packit Service 54dbc3
					vls_avail = port_vls_avail;
Packit Service 54dbc3
			}
Packit Service 54dbc3
		}
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	/* ib_port_info_get_op_vls gives values 1 ... 5 (s. IBAS 14.2.5.6) */
Packit Service 54dbc3
	vls_avail = 1 << (vls_avail - 1);
Packit Service 54dbc3
Packit Service 54dbc3
	/* set boundaries (s. IBAS 3.5.7) */
Packit Service 54dbc3
	if (vls_avail > 15)
Packit Service 54dbc3
		vls_avail = 15;
Packit Service 54dbc3
	if (vls_avail < 1)
Packit Service 54dbc3
		vls_avail = 1;
Packit Service 54dbc3
Packit Service 54dbc3
	return vls_avail;
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
/* search for cycles in the channel dependency graph to identify possible
Packit Service 54dbc3
   deadlocks in the network;
Packit Service 54dbc3
   assign new virtual lanes to some paths to break the deadlocks
Packit Service 54dbc3
*/
Packit Service 54dbc3
static int dfsssp_remove_deadlocks(dfsssp_context_t * dfsssp_ctx)
Packit Service 54dbc3
{
Packit Service 54dbc3
	osm_ucast_mgr_t *p_mgr = (osm_ucast_mgr_t *) dfsssp_ctx->p_mgr;
Packit Service 54dbc3
Packit Service 54dbc3
	cl_qlist_t *port_tbl = &p_mgr->port_order_list;	/* 1 management port per switch + 1 or 2 ports for each Hca */
Packit Service 54dbc3
	cl_list_item_t *item1 = NULL, *item2 = NULL;
Packit Service 54dbc3
	osm_port_t *src_port = NULL, *dest_port = NULL;
Packit Service 54dbc3
Packit Service 54dbc3
	uint32_t i = 0, j = 0, err = 0;
Packit Service 54dbc3
	uint8_t vl = 0, test_vl = 0, vl_avail = 0, vl_needed = 1;
Packit Service 54dbc3
	double most_avg_paths = 0.0;
Packit Service 54dbc3
	cdg_node_t **cdg = NULL, *start_here = NULL, *cycle = NULL;
Packit Service 54dbc3
	cdg_link_t *weakest_link = NULL;
Packit Service 54dbc3
	uint32_t srcdest = 0;
Packit Service 54dbc3
Packit Service 54dbc3
	vltable_t *srcdest2vl_table = NULL;
Packit Service 54dbc3
	uint8_t lmc = 0;
Packit Service 54dbc3
	uint16_t slid = 0, dlid = 0, min_lid_ho = 0, max_lid_ho =
Packit Service 54dbc3
	    0, min_lid_ho2 = 0, max_lid_ho2 = 0;;
Packit Service 54dbc3
	uint64_t *paths_per_vl = NULL;
Packit Service 54dbc3
	uint64_t from = 0, to = 0, count = 0;
Packit Service 54dbc3
	uint8_t *split_count = NULL;
Packit Service 54dbc3
	uint8_t ntype = 0;
Packit Service 54dbc3
Packit Service 54dbc3
	OSM_LOG_ENTER(p_mgr->p_log);
Packit Service 54dbc3
	OSM_LOG(p_mgr->p_log, OSM_LOG_VERBOSE,
Packit Service 54dbc3
		"Assign each src/dest pair a Virtual Lanes, to remove deadlocks in the routing\n");
Packit Service 54dbc3
Packit Service 54dbc3
	vl_avail = get_avail_vl_in_subn(p_mgr);
Packit Service 54dbc3
	OSM_LOG(p_mgr->p_log, OSM_LOG_INFO,
Packit Service 54dbc3
		"Virtual Lanes available: %" PRIu8 "\n", vl_avail);
Packit Service 54dbc3
Packit Service 54dbc3
	paths_per_vl = (uint64_t *) malloc(vl_avail * sizeof(uint64_t));
Packit Service 54dbc3
	if (!paths_per_vl) {
Packit Service 54dbc3
		OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
Packit Service 54dbc3
			"ERR AD22: cannot allocate memory for paths_per_vl\n");
Packit Service 54dbc3
		return 1;
Packit Service 54dbc3
	}
Packit Service 54dbc3
	memset(paths_per_vl, 0, vl_avail * sizeof(uint64_t));
Packit Service 54dbc3
Packit Service 54dbc3
	cdg = (cdg_node_t **) malloc(vl_avail * sizeof(cdg_node_t *));
Packit Service 54dbc3
	if (!cdg) {
Packit Service 54dbc3
		OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
Packit Service 54dbc3
			"ERR AD23: cannot allocate memory for cdg\n");
Packit Service 54dbc3
		free(paths_per_vl);
Packit Service 54dbc3
		return 1;
Packit Service 54dbc3
	}
Packit Service 54dbc3
	for (i = 0; i < vl_avail; i++)
Packit Service 54dbc3
		cdg[i] = NULL;
Packit Service 54dbc3
Packit Service 54dbc3
	count = 0;
Packit Service 54dbc3
	/* count all ports (also multiple LIDs) of type CA or SP0 for size of VL table */
Packit Service 54dbc3
	for (item1 = cl_qlist_head(port_tbl); item1 != cl_qlist_end(port_tbl);
Packit Service 54dbc3
	     item1 = cl_qlist_next(item1)) {
Packit Service 54dbc3
		dest_port = (osm_port_t *)cl_item_obj(item1, dest_port,
Packit Service 54dbc3
						      list_item);
Packit Service 54dbc3
		ntype = osm_node_get_type(dest_port->p_node);
Packit Service 54dbc3
		if (ntype == IB_NODE_TYPE_CA || ntype == IB_NODE_TYPE_SWITCH) {
Packit Service 54dbc3
			/* only SP0 with SLtoVLMapping support will be processed */
Packit Service 54dbc3
			if (ntype == IB_NODE_TYPE_SWITCH
Packit Service 54dbc3
			    && !(dest_port->p_physp->port_info.capability_mask
Packit Service 54dbc3
			    & IB_PORT_CAP_HAS_SL_MAP))
Packit Service 54dbc3
				continue;
Packit Service 54dbc3
Packit Service 54dbc3
			lmc = osm_port_get_lmc(dest_port);
Packit Service 54dbc3
			count += (1 << lmc);
Packit Service 54dbc3
		}
Packit Service 54dbc3
	}
Packit Service 54dbc3
	/* allocate VL table and indexing array */
Packit Service 54dbc3
	err = vltable_alloc(&srcdest2vl_table, count);
Packit Service 54dbc3
	if (err) {
Packit Service 54dbc3
		OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
Packit Service 54dbc3
			"ERR AD26: cannot allocate memory for srcdest2vl_table\n");
Packit Service 54dbc3
		goto ERROR;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	i = 0;
Packit Service 54dbc3
	/* fill lids into indexing array */
Packit Service 54dbc3
	for (item1 = cl_qlist_head(port_tbl); item1 != cl_qlist_end(port_tbl);
Packit Service 54dbc3
	     item1 = cl_qlist_next(item1)) {
Packit Service 54dbc3
		dest_port = (osm_port_t *)cl_item_obj(item1, dest_port,
Packit Service 54dbc3
						      list_item);
Packit Service 54dbc3
		ntype = osm_node_get_type(dest_port->p_node);
Packit Service 54dbc3
		if (ntype == IB_NODE_TYPE_CA || ntype == IB_NODE_TYPE_SWITCH) {
Packit Service 54dbc3
			/* only SP0 with SLtoVLMapping support will be processed */
Packit Service 54dbc3
			if (ntype == IB_NODE_TYPE_SWITCH
Packit Service 54dbc3
			    && !(dest_port->p_physp->port_info.capability_mask
Packit Service 54dbc3
			    & IB_PORT_CAP_HAS_SL_MAP))
Packit Service 54dbc3
				continue;
Packit Service 54dbc3
Packit Service 54dbc3
			osm_port_get_lid_range_ho(dest_port, &min_lid_ho,
Packit Service 54dbc3
						  &max_lid_ho);
Packit Service 54dbc3
			for (dlid = min_lid_ho; dlid <= max_lid_ho; dlid++, i++)
Packit Service 54dbc3
				srcdest2vl_table->lids[i] = cl_hton16(dlid);
Packit Service 54dbc3
		}
Packit Service 54dbc3
	}
Packit Service 54dbc3
	/* sort lids */
Packit Service 54dbc3
	vltable_sort_lids(srcdest2vl_table);
Packit Service 54dbc3
Packit Service 54dbc3
	test_vl = 0;
Packit Service 54dbc3
	/* fill cdg[0] with routes from each src/dest port combination for all Hca/SP0 in the subnet */
Packit Service 54dbc3
	for (item1 = cl_qlist_head(port_tbl); item1 != cl_qlist_end(port_tbl);
Packit Service 54dbc3
	     item1 = cl_qlist_next(item1)) {
Packit Service 54dbc3
		dest_port = (osm_port_t *)cl_item_obj(item1, dest_port,
Packit Service 54dbc3
						      list_item);
Packit Service 54dbc3
		ntype = osm_node_get_type(dest_port->p_node);
Packit Service 54dbc3
		if ((ntype != IB_NODE_TYPE_CA && ntype != IB_NODE_TYPE_SWITCH)
Packit Service 54dbc3
		    || !(dest_port->p_physp->port_info.capability_mask
Packit Service 54dbc3
		    & IB_PORT_CAP_HAS_SL_MAP))
Packit Service 54dbc3
			continue;
Packit Service 54dbc3
Packit Service 54dbc3
		for (item2 = cl_qlist_head(port_tbl);
Packit Service 54dbc3
		     item2 != cl_qlist_end(port_tbl);
Packit Service 54dbc3
		     item2 = cl_qlist_next(item2)) {
Packit Service 54dbc3
			src_port = (osm_port_t *)cl_item_obj(item2, src_port,
Packit Service 54dbc3
							     list_item);
Packit Service 54dbc3
			ntype = osm_node_get_type(src_port->p_node);
Packit Service 54dbc3
			if ((ntype != IB_NODE_TYPE_CA
Packit Service 54dbc3
			    && ntype != IB_NODE_TYPE_SWITCH)
Packit Service 54dbc3
			    || !(src_port->p_physp->port_info.capability_mask
Packit Service 54dbc3
			    & IB_PORT_CAP_HAS_SL_MAP))
Packit Service 54dbc3
				continue;
Packit Service 54dbc3
Packit Service 54dbc3
			if (src_port != dest_port) {
Packit Service 54dbc3
				/* iterate over LIDs of src and dest port */
Packit Service 54dbc3
				osm_port_get_lid_range_ho(src_port, &min_lid_ho,
Packit Service 54dbc3
							  &max_lid_ho);
Packit Service 54dbc3
				for (slid = min_lid_ho; slid <= max_lid_ho;
Packit Service 54dbc3
				     slid++) {
Packit Service 54dbc3
					osm_port_get_lid_range_ho
Packit Service 54dbc3
					    (dest_port, &min_lid_ho2,
Packit Service 54dbc3
					     &max_lid_ho2);
Packit Service 54dbc3
					for (dlid = min_lid_ho2;
Packit Service 54dbc3
					     dlid <= max_lid_ho2;
Packit Service 54dbc3
					     dlid++) {
Packit Service 54dbc3
Packit Service 54dbc3
						/* try to add the path to cdg[0] */
Packit Service 54dbc3
						err =
Packit Service 54dbc3
						    update_channel_dep_graph
Packit Service 54dbc3
						    (&(cdg[test_vl]),
Packit Service 54dbc3
						     src_port, slid,
Packit Service 54dbc3
						     dest_port, dlid);
Packit Service 54dbc3
						if (err) {
Packit Service 54dbc3
							OSM_LOG(p_mgr->
Packit Service 54dbc3
								p_log,
Packit Service 54dbc3
								OSM_LOG_ERROR,
Packit Service 54dbc3
								"ERR AD14: cannot allocate memory for cdg node or link in update_channel_dep_graph(...)\n");
Packit Service 54dbc3
							goto ERROR;
Packit Service 54dbc3
						}
Packit Service 54dbc3
						/* add the <s,d> combination / corresponding virtual lane to the VL table */
Packit Service 54dbc3
						vltable_insert
Packit Service 54dbc3
						    (srcdest2vl_table,
Packit Service 54dbc3
						     cl_hton16(slid),
Packit Service 54dbc3
						     cl_hton16(dlid),
Packit Service 54dbc3
						     test_vl);
Packit Service 54dbc3
						paths_per_vl[test_vl]++;
Packit Service 54dbc3
Packit Service 54dbc3
					}
Packit Service 54dbc3
Packit Service 54dbc3
				}
Packit Service 54dbc3
			}
Packit Service 54dbc3
Packit Service 54dbc3
		}
Packit Service 54dbc3
	}
Packit Service 54dbc3
	dfsssp_ctx->srcdest2vl_table = srcdest2vl_table;
Packit Service 54dbc3
Packit Service 54dbc3
	/* test all cdg for cycles and break the cycles by moving paths on the weakest link to the next cdg */
Packit Service 54dbc3
	for (test_vl = 0; test_vl < vl_avail - 1; test_vl++) {
Packit Service 54dbc3
		start_here = cdg[test_vl];
Packit Service 54dbc3
		while (start_here) {
Packit Service 54dbc3
			cycle =
Packit Service 54dbc3
			    search_cycle_in_channel_dep_graph(cdg[test_vl],
Packit Service 54dbc3
							      start_here);
Packit Service 54dbc3
Packit Service 54dbc3
			if (cycle) {
Packit Service 54dbc3
				vl_needed = test_vl + 2;
Packit Service 54dbc3
Packit Service 54dbc3
				/* calc weakest link n cycle */
Packit Service 54dbc3
				weakest_link = get_weakest_link_in_cycle(cycle);
Packit Service 54dbc3
				if (!weakest_link) {
Packit Service 54dbc3
					OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
Packit Service 54dbc3
						"ERR AD27: something went wrong in get_weakest_link_in_cycle(...)\n");
Packit Service 54dbc3
					err = 1;
Packit Service 54dbc3
					goto ERROR;
Packit Service 54dbc3
				}
Packit Service 54dbc3
Packit Service 54dbc3
				paths_per_vl[test_vl] -=
Packit Service 54dbc3
				    weakest_link->num_pairs;
Packit Service 54dbc3
				paths_per_vl[test_vl + 1] +=
Packit Service 54dbc3
				    weakest_link->num_pairs;
Packit Service 54dbc3
Packit Service 54dbc3
				/* move all <s,d> paths on this link to the next cdg */
Packit Service 54dbc3
				for (i = 0; i < weakest_link->num_pairs; i++) {
Packit Service 54dbc3
					srcdest =
Packit Service 54dbc3
					    get_next_srcdest_pair(weakest_link,
Packit Service 54dbc3
								  i);
Packit Service 54dbc3
					slid = (uint16_t) (srcdest >> 16);
Packit Service 54dbc3
					dlid =
Packit Service 54dbc3
					    (uint16_t) ((srcdest << 16) >> 16);
Packit Service 54dbc3
Packit Service 54dbc3
					/* only move if not moved in a previous step */
Packit Service 54dbc3
					if (test_vl !=
Packit Service 54dbc3
					    (uint8_t)
Packit Service 54dbc3
					    vltable_get_vl(srcdest2vl_table,
Packit Service 54dbc3
							   cl_hton16(slid),
Packit Service 54dbc3
							   cl_hton16(dlid))) {
Packit Service 54dbc3
						/* this path has been moved
Packit Service 54dbc3
						   before -> don't count
Packit Service 54dbc3
						 */
Packit Service 54dbc3
						paths_per_vl[test_vl]++;
Packit Service 54dbc3
						paths_per_vl[test_vl + 1]--;
Packit Service 54dbc3
						continue;
Packit Service 54dbc3
					}
Packit Service 54dbc3
Packit Service 54dbc3
					src_port =
Packit Service 54dbc3
					    osm_get_port_by_lid(p_mgr->p_subn,
Packit Service 54dbc3
								cl_hton16
Packit Service 54dbc3
								(slid));
Packit Service 54dbc3
					dest_port =
Packit Service 54dbc3
					    osm_get_port_by_lid(p_mgr->p_subn,
Packit Service 54dbc3
								cl_hton16
Packit Service 54dbc3
								(dlid));
Packit Service 54dbc3
Packit Service 54dbc3
					/* remove path from current cdg / vl */
Packit Service 54dbc3
					err =
Packit Service 54dbc3
					    remove_path_from_cdg(&
Packit Service 54dbc3
								 (cdg[test_vl]),
Packit Service 54dbc3
								 src_port, slid,
Packit Service 54dbc3
								 dest_port,
Packit Service 54dbc3
								 dlid);
Packit Service 54dbc3
					if (err) {
Packit Service 54dbc3
						OSM_LOG(p_mgr->p_log,
Packit Service 54dbc3
							OSM_LOG_ERROR,
Packit Service 54dbc3
							"ERR AD44: something went wrong in remove_path_from_cdg(...)\n");
Packit Service 54dbc3
						goto ERROR;
Packit Service 54dbc3
					}
Packit Service 54dbc3
Packit Service 54dbc3
					/* add path to next cdg / vl */
Packit Service 54dbc3
					err =
Packit Service 54dbc3
					    update_channel_dep_graph(&
Packit Service 54dbc3
								     (cdg
Packit Service 54dbc3
								      [test_vl +
Packit Service 54dbc3
								       1]),
Packit Service 54dbc3
								     src_port,
Packit Service 54dbc3
								     slid,
Packit Service 54dbc3
								     dest_port,
Packit Service 54dbc3
								     dlid);
Packit Service 54dbc3
					if (err) {
Packit Service 54dbc3
						OSM_LOG(p_mgr->p_log,
Packit Service 54dbc3
							OSM_LOG_ERROR,
Packit Service 54dbc3
							"ERR AD14: cannot allocate memory for cdg node or link in update_channel_dep_graph(...)\n");
Packit Service 54dbc3
						goto ERROR;
Packit Service 54dbc3
					}
Packit Service 54dbc3
					vltable_insert(srcdest2vl_table,
Packit Service 54dbc3
						       cl_hton16(slid),
Packit Service 54dbc3
						       cl_hton16(dlid),
Packit Service 54dbc3
						       test_vl + 1);
Packit Service 54dbc3
				}
Packit Service 54dbc3
Packit Service 54dbc3
				if (weakest_link->num_pairs)
Packit Service 54dbc3
					free(weakest_link->srcdest_pairs);
Packit Service 54dbc3
				if (weakest_link)
Packit Service 54dbc3
					free(weakest_link);
Packit Service 54dbc3
			}
Packit Service 54dbc3
Packit Service 54dbc3
			start_here = cycle;
Packit Service 54dbc3
		}
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	/* test the last avail cdg for a cycle;
Packit Service 54dbc3
	   if there is one, than vl_needed > vl_avail
Packit Service 54dbc3
	 */
Packit Service 54dbc3
	start_here = cdg[vl_avail - 1];
Packit Service 54dbc3
	if (start_here) {
Packit Service 54dbc3
		cycle =
Packit Service 54dbc3
		    search_cycle_in_channel_dep_graph(cdg[vl_avail - 1],
Packit Service 54dbc3
						      start_here);
Packit Service 54dbc3
		if (cycle) {
Packit Service 54dbc3
			vl_needed = vl_avail + 1;
Packit Service 54dbc3
		}
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	OSM_LOG(p_mgr->p_log, OSM_LOG_INFO,
Packit Service 54dbc3
		"Virtual Lanes needed: %" PRIu8 "\n", vl_needed);
Packit Service 54dbc3
	if (OSM_LOG_IS_ACTIVE_V2(p_mgr->p_log, OSM_LOG_INFO)) {
Packit Service 54dbc3
		OSM_LOG(p_mgr->p_log, OSM_LOG_INFO,
Packit Service 54dbc3
			"Paths per VL (before balancing):\n");
Packit Service 54dbc3
		for (i = 0; i < vl_avail; i++)
Packit Service 54dbc3
			OSM_LOG(p_mgr->p_log, OSM_LOG_INFO,
Packit Service 54dbc3
				"   %" PRIu32 ". lane: %" PRIu64 "\n", i,
Packit Service 54dbc3
				paths_per_vl[i]);
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	OSM_LOG(p_mgr->p_log, OSM_LOG_VERBOSE,
Packit Service 54dbc3
		"Balancing the paths on the available Virtual Lanes\n");
Packit Service 54dbc3
Packit Service 54dbc3
	/* optimal balancing virtual lanes, under condition: no additional cycle checks;
Packit Service 54dbc3
	   sl/vl != 0 might be assigned to loopback packets (i.e. slid/dlid on the
Packit Service 54dbc3
	   same port for lmc>0), but thats no problem, see IBAS 10.2.2.3
Packit Service 54dbc3
	 */
Packit Service 54dbc3
	split_count = (uint8_t *) calloc(vl_avail, sizeof(uint8_t));
Packit Service 54dbc3
	if (!split_count) {
Packit Service 54dbc3
		OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
Packit Service 54dbc3
			"ERR AD24: cannot allocate memory for split_count, skip balancing\n");
Packit Service 54dbc3
		err = 1;
Packit Service 54dbc3
		goto ERROR;
Packit Service 54dbc3
	}
Packit Service 54dbc3
	/* initial state: paths for VLs won't be separated */
Packit Service 54dbc3
	for (i = 0; i < ((vl_needed < vl_avail) ? vl_needed : vl_avail); i++)
Packit Service 54dbc3
		split_count[i] = 1;
Packit Service 54dbc3
	dfsssp_ctx->vl_split_count = split_count;
Packit Service 54dbc3
	/* balancing is necessary if we have empty VLs */
Packit Service 54dbc3
	if (vl_needed < vl_avail) {
Packit Service 54dbc3
		/* split paths of VLs until we find an equal distribution */
Packit Service 54dbc3
		for (i = vl_needed; i < vl_avail; i++) {
Packit Service 54dbc3
			/* find VL with most paths in it */
Packit Service 54dbc3
			vl = 0;
Packit Service 54dbc3
			most_avg_paths = 0.0;
Packit Service 54dbc3
			for (test_vl = 0; test_vl < vl_needed; test_vl++) {
Packit Service 54dbc3
				if (most_avg_paths <
Packit Service 54dbc3
				    ((double)paths_per_vl[test_vl] /
Packit Service 54dbc3
				    split_count[test_vl])) {
Packit Service 54dbc3
					vl = test_vl;
Packit Service 54dbc3
					most_avg_paths =
Packit Service 54dbc3
						(double)paths_per_vl[test_vl] /
Packit Service 54dbc3
						split_count[test_vl];
Packit Service 54dbc3
				}
Packit Service 54dbc3
			}
Packit Service 54dbc3
			split_count[vl]++;
Packit Service 54dbc3
		}
Packit Service 54dbc3
		/* change the VL assignment depending on split_count for
Packit Service 54dbc3
		   all VLs except VL 0
Packit Service 54dbc3
		 */
Packit Service 54dbc3
		for (from = vl_needed - 1; from > 0; from--) {
Packit Service 54dbc3
			/* how much space needed for others? */
Packit Service 54dbc3
			to = 0;
Packit Service 54dbc3
			for (i = 0; i < from; i++)
Packit Service 54dbc3
				to += split_count[i];
Packit Service 54dbc3
			count = paths_per_vl[from];
Packit Service 54dbc3
			vltable_change_vl(srcdest2vl_table, from, to, count);
Packit Service 54dbc3
			/* change also the information within the split_count
Packit Service 54dbc3
			   array; this is important for fast calculation later
Packit Service 54dbc3
			 */
Packit Service 54dbc3
			split_count[to] = split_count[from];
Packit Service 54dbc3
			split_count[from] = 0;
Packit Service 54dbc3
			paths_per_vl[to] = paths_per_vl[from];
Packit Service 54dbc3
			paths_per_vl[from] = 0;
Packit Service 54dbc3
		}
Packit Service 54dbc3
	} else if (vl_needed > vl_avail) {
Packit Service 54dbc3
		/* routing not possible, a further development would be the LASH-TOR approach (update: LASH-TOR isn't possible, there is a mistake in the theory) */
Packit Service 54dbc3
		OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
Packit Service 54dbc3
			"ERR AD25: Not enough VLs available (avail=%d, needed=%d); Stopping dfsssp routing!\n",
Packit Service 54dbc3
			vl_avail, vl_needed);
Packit Service 54dbc3
		err = 1;
Packit Service 54dbc3
		goto ERROR;
Packit Service 54dbc3
	}
Packit Service 54dbc3
	/* else { no balancing } */
Packit Service 54dbc3
Packit Service 54dbc3
	if (OSM_LOG_IS_ACTIVE_V2(p_mgr->p_log, OSM_LOG_DEBUG)) {
Packit Service 54dbc3
		OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
Packit Service 54dbc3
			"Virtual Lanes per src/dest combination after balancing:\n");
Packit Service 54dbc3
		vltable_print(p_mgr, srcdest2vl_table);
Packit Service 54dbc3
	}
Packit Service 54dbc3
	if (OSM_LOG_IS_ACTIVE_V2(p_mgr->p_log, OSM_LOG_INFO)) {
Packit Service 54dbc3
		OSM_LOG(p_mgr->p_log, OSM_LOG_INFO,
Packit Service 54dbc3
			"Approx. #paths per VL (after balancing):\n");
Packit Service 54dbc3
		j = 0;
Packit Service 54dbc3
		count = 1; /* to prevent div. by 0 */
Packit Service 54dbc3
		for (i = 0; i < vl_avail; i++) {
Packit Service 54dbc3
			if (split_count[i] > 0) {
Packit Service 54dbc3
				j = i;
Packit Service 54dbc3
				count = split_count[i];
Packit Service 54dbc3
			}
Packit Service 54dbc3
			OSM_LOG(p_mgr->p_log, OSM_LOG_INFO,
Packit Service 54dbc3
				"   %" PRIu32 ". lane: %" PRIu64 "\n", i,
Packit Service 54dbc3
				paths_per_vl[j] / count);
Packit Service 54dbc3
		}
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	free(paths_per_vl);
Packit Service 54dbc3
Packit Service 54dbc3
	/* deallocate channel dependency graphs */
Packit Service 54dbc3
	for (i = 0; i < vl_avail; i++)
Packit Service 54dbc3
		cdg_dealloc(&cdg[i]);
Packit Service 54dbc3
	free(cdg);
Packit Service 54dbc3
Packit Service 54dbc3
	OSM_LOG_EXIT(p_mgr->p_log);
Packit Service 54dbc3
	return 0;
Packit Service 54dbc3
Packit Service 54dbc3
ERROR:
Packit Service 54dbc3
	free(paths_per_vl);
Packit Service 54dbc3
Packit Service 54dbc3
	for (i = 0; i < vl_avail; i++)
Packit Service 54dbc3
		cdg_dealloc(&cdg[i]);
Packit Service 54dbc3
	free(cdg);
Packit Service 54dbc3
Packit Service 54dbc3
	vltable_dealloc(&srcdest2vl_table);
Packit Service 54dbc3
	dfsssp_ctx->srcdest2vl_table = NULL;
Packit Service 54dbc3
Packit Service 54dbc3
	return err;
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
/* meta function which calls subfunctions for dijkstra, update lft and weights,
Packit Service 54dbc3
   (and remove deadlocks) to calculate the routing for the subnet
Packit Service 54dbc3
*/
Packit Service 54dbc3
static int dfsssp_do_dijkstra_routing(void *context)
Packit Service 54dbc3
{
Packit Service 54dbc3
	dfsssp_context_t *dfsssp_ctx = (dfsssp_context_t *) context;
Packit Service 54dbc3
	osm_ucast_mgr_t *p_mgr = (osm_ucast_mgr_t *) dfsssp_ctx->p_mgr;
Packit Service 54dbc3
	vertex_t *adj_list = (vertex_t *) dfsssp_ctx->adj_list;
Packit Service 54dbc3
	uint32_t adj_list_size = dfsssp_ctx->adj_list_size;
Packit Service 54dbc3
	cl_heap_t heap;
Packit Service 54dbc3
Packit Service 54dbc3
	vertex_t **sw_list = NULL;
Packit Service 54dbc3
	uint32_t sw_list_size = 0;
Packit Service 54dbc3
	uint64_t guid = 0;
Packit Service 54dbc3
	cl_qlist_t *qlist = NULL;
Packit Service 54dbc3
	cl_list_item_t *qlist_item = NULL;
Packit Service 54dbc3
Packit Service 54dbc3
	cl_qmap_t *sw_tbl = &p_mgr->p_subn->sw_guid_tbl;
Packit Service 54dbc3
	cl_qmap_t cn_tbl, io_tbl, *p_mixed_tbl = NULL;
Packit Service 54dbc3
	cl_map_item_t *item = NULL;
Packit Service 54dbc3
	osm_switch_t *sw = NULL;
Packit Service 54dbc3
	osm_port_t *port = NULL;
Packit Service 54dbc3
	uint32_t i = 0, err = 0;
Packit Service 54dbc3
	uint16_t lid = 0, min_lid_ho = 0, max_lid_ho = 0;
Packit Service 54dbc3
	uint8_t lmc = 0;
Packit Service 54dbc3
	boolean_t cn_nodes_provided = FALSE, io_nodes_provided = FALSE;
Packit Service 54dbc3
Packit Service 54dbc3
	OSM_LOG_ENTER(p_mgr->p_log);
Packit Service 54dbc3
	OSM_LOG(p_mgr->p_log, OSM_LOG_VERBOSE,
Packit Service 54dbc3
		"Calculating shortest path from all Hca/switches to all\n");
Packit Service 54dbc3
Packit Service 54dbc3
	cl_qmap_init(&cn_tbl);
Packit Service 54dbc3
	cl_qmap_init(&io_tbl);
Packit Service 54dbc3
	p_mixed_tbl = &cn_tbl;
Packit Service 54dbc3
Packit Service 54dbc3
	cl_qlist_init(&p_mgr->port_order_list);
Packit Service 54dbc3
Packit Service 54dbc3
	/* reset the new_lft for each switch */
Packit Service 54dbc3
	for (item = cl_qmap_head(sw_tbl); item != cl_qmap_end(sw_tbl);
Packit Service 54dbc3
	     item = cl_qmap_next(item)) {
Packit Service 54dbc3
		sw = (osm_switch_t *) item;
Packit Service 54dbc3
		/* initialize LIDs in buffer to invalid port number */
Packit Service 54dbc3
		memset(sw->new_lft, OSM_NO_PATH, sw->max_lid_ho + 1);
Packit Service 54dbc3
		/* initialize LFT and hop count for bsp0/esp0 of the switch */
Packit Service 54dbc3
		min_lid_ho = cl_ntoh16(osm_node_get_base_lid(sw->p_node, 0));
Packit Service 54dbc3
		lmc = osm_node_get_lmc(sw->p_node, 0);
Packit Service 54dbc3
		for (i = min_lid_ho; i < min_lid_ho + (1 << lmc); i++) {
Packit Service 54dbc3
			/* for each switch the port to the 'self'lid is the management port 0 */
Packit Service 54dbc3
			sw->new_lft[i] = 0;
Packit Service 54dbc3
			/* the hop count to the 'self'lid is 0 for each switch */
Packit Service 54dbc3
			osm_switch_set_hops(sw, i, 0, 0);
Packit Service 54dbc3
		}
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	/* construct the generic heap opject to use it in dijkstra */
Packit Service 54dbc3
	cl_heap_construct(&heap;;
Packit Service 54dbc3
Packit Service 54dbc3
	/* we need an intermediate array of pointers to switches in adj_list;
Packit Service 54dbc3
	   this array will be sorted in respect to num_hca (descending)
Packit Service 54dbc3
	 */
Packit Service 54dbc3
	sw_list_size = adj_list_size - 1;
Packit Service 54dbc3
	sw_list = (vertex_t **)malloc(sw_list_size * sizeof(vertex_t *));
Packit Service 54dbc3
	if (!sw_list) {
Packit Service 54dbc3
		OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
Packit Service 54dbc3
			"ERR AD29: cannot allocate memory for sw_list in dfsssp_do_dijkstra_routing\n");
Packit Service 54dbc3
		goto ERROR;
Packit Service 54dbc3
	}
Packit Service 54dbc3
	memset(sw_list, 0, sw_list_size * sizeof(vertex_t *));
Packit Service 54dbc3
Packit Service 54dbc3
	/* fill the array with references to the 'real' sw in adj_list */
Packit Service 54dbc3
	for (i = 0; i < sw_list_size; i++)
Packit Service 54dbc3
		sw_list[i] = &(adj_list[i + 1]);
Packit Service 54dbc3
Packit Service 54dbc3
	/* sort the sw_list in descending order */
Packit Service 54dbc3
	sw_list_sort_by_num_hca(sw_list, sw_list_size);
Packit Service 54dbc3
Packit Service 54dbc3
	/* parse compute node guid file, if provided by the user */
Packit Service 54dbc3
	if (p_mgr->p_subn->opt.cn_guid_file) {
Packit Service 54dbc3
		OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
Packit Service 54dbc3
			"Parsing compute nodes from file %s\n",
Packit Service 54dbc3
			p_mgr->p_subn->opt.cn_guid_file);
Packit Service 54dbc3
Packit Service 54dbc3
		if (parse_node_map(p_mgr->p_subn->opt.cn_guid_file,
Packit Service 54dbc3
				   add_guid_to_map, &cn_tbl)) {
Packit Service 54dbc3
			OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
Packit Service 54dbc3
				"ERR AD33: Problem parsing compute node guid file\n");
Packit Service 54dbc3
			goto ERROR;
Packit Service 54dbc3
		}
Packit Service 54dbc3
Packit Service 54dbc3
		if (cl_is_qmap_empty(&cn_tbl))
Packit Service 54dbc3
			OSM_LOG(p_mgr->p_log, OSM_LOG_INFO,
Packit Service 54dbc3
				"WRN AD34: compute node guids file contains no valid guids\n");
Packit Service 54dbc3
		else
Packit Service 54dbc3
			cn_nodes_provided = TRUE;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	/* parse I/O guid file, if provided by the user */
Packit Service 54dbc3
	if (p_mgr->p_subn->opt.io_guid_file) {
Packit Service 54dbc3
		OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
Packit Service 54dbc3
			"Parsing I/O nodes from file %s\n",
Packit Service 54dbc3
			p_mgr->p_subn->opt.io_guid_file);
Packit Service 54dbc3
Packit Service 54dbc3
		if (parse_node_map(p_mgr->p_subn->opt.io_guid_file,
Packit Service 54dbc3
				   add_guid_to_map, &io_tbl)) {
Packit Service 54dbc3
			OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
Packit Service 54dbc3
				"ERR AD35: Problem parsing I/O guid file\n");
Packit Service 54dbc3
			goto ERROR;
Packit Service 54dbc3
		}
Packit Service 54dbc3
Packit Service 54dbc3
		if (cl_is_qmap_empty(&io_tbl))
Packit Service 54dbc3
			OSM_LOG(p_mgr->p_log, OSM_LOG_INFO,
Packit Service 54dbc3
				"WRN AD36: I/O node guids file contains no valid guids\n");
Packit Service 54dbc3
		else
Packit Service 54dbc3
			io_nodes_provided = TRUE;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	/* if we mix Hca/Tca/SP0 during the dijkstra routing, we might end up
Packit Service 54dbc3
	   in rare cases with a bad balancing for Hca<->Hca connections, i.e.
Packit Service 54dbc3
	   some inter-switch links get oversubscribed with paths;
Packit Service 54dbc3
	   therefore: add Hca ports first to ensure good Hca<->Hca balancing
Packit Service 54dbc3
	 */
Packit Service 54dbc3
	if (cn_nodes_provided) {
Packit Service 54dbc3
		for (i = 0; i < adj_list_size - 1; i++) {
Packit Service 54dbc3
			if (sw_list[i] && sw_list[i]->sw) {
Packit Service 54dbc3
				sw = (osm_switch_t *)(sw_list[i]->sw);
Packit Service 54dbc3
				add_sw_endports_to_order_list(sw, p_mgr,
Packit Service 54dbc3
							      &cn_tbl, TRUE);
Packit Service 54dbc3
			} else {
Packit Service 54dbc3
				OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
Packit Service 54dbc3
					"ERR AD30: corrupted sw_list array in dfsssp_do_dijkstra_routing\n");
Packit Service 54dbc3
				goto ERROR;
Packit Service 54dbc3
			}
Packit Service 54dbc3
		}
Packit Service 54dbc3
	}
Packit Service 54dbc3
	/* then: add Tca ports to ensure good Hca->Tca balancing and separate
Packit Service 54dbc3
	   paths towards I/O nodes on the same switch (if possible)
Packit Service 54dbc3
	 */
Packit Service 54dbc3
	if (io_nodes_provided) {
Packit Service 54dbc3
		for (i = 0; i < adj_list_size - 1; i++) {
Packit Service 54dbc3
			if (sw_list[i] && sw_list[i]->sw) {
Packit Service 54dbc3
				sw = (osm_switch_t *)(sw_list[i]->sw);
Packit Service 54dbc3
				add_sw_endports_to_order_list(sw, p_mgr,
Packit Service 54dbc3
							      &io_tbl, TRUE);
Packit Service 54dbc3
			} else {
Packit Service 54dbc3
				OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
Packit Service 54dbc3
					"ERR AD32: corrupted sw_list array in dfsssp_do_dijkstra_routing\n");
Packit Service 54dbc3
				goto ERROR;
Packit Service 54dbc3
			}
Packit Service 54dbc3
		}
Packit Service 54dbc3
	}
Packit Service 54dbc3
	/* then: add anything else, such as administration nodes, ... */
Packit Service 54dbc3
	if (cn_nodes_provided && io_nodes_provided) {
Packit Service 54dbc3
		cl_qmap_merge(&cn_tbl, &io_tbl);
Packit Service 54dbc3
	} else if (io_nodes_provided) {
Packit Service 54dbc3
		p_mixed_tbl = &io_tbl;
Packit Service 54dbc3
	}
Packit Service 54dbc3
	for (i = 0; i < adj_list_size - 1; i++) {
Packit Service 54dbc3
		if (sw_list[i] && sw_list[i]->sw) {
Packit Service 54dbc3
			sw = (osm_switch_t *)(sw_list[i]->sw);
Packit Service 54dbc3
			add_sw_endports_to_order_list(sw, p_mgr, p_mixed_tbl,
Packit Service 54dbc3
						      FALSE);
Packit Service 54dbc3
		} else {
Packit Service 54dbc3
			OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
Packit Service 54dbc3
				"ERR AD39: corrupted sw_list array in dfsssp_do_dijkstra_routing\n");
Packit Service 54dbc3
			goto ERROR;
Packit Service 54dbc3
		}
Packit Service 54dbc3
	}
Packit Service 54dbc3
	/* last: add SP0 afterwards which have lower priority for balancing */
Packit Service 54dbc3
	for (i = 0; i < sw_list_size; i++) {
Packit Service 54dbc3
		if (sw_list[i] && sw_list[i]->sw) {
Packit Service 54dbc3
			sw = (osm_switch_t *)(sw_list[i]->sw);
Packit Service 54dbc3
			guid = cl_ntoh64(osm_node_get_node_guid(sw->p_node));
Packit Service 54dbc3
			add_guid_to_order_list(guid, p_mgr);
Packit Service 54dbc3
		} else {
Packit Service 54dbc3
			OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
Packit Service 54dbc3
				"ERR AD31: corrupted sw_list array in dfsssp_do_dijkstra_routing\n");
Packit Service 54dbc3
			goto ERROR;
Packit Service 54dbc3
		}
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	/* the intermediate array lived long enough */
Packit Service 54dbc3
	free(sw_list);
Packit Service 54dbc3
	sw_list = NULL;
Packit Service 54dbc3
	/* same is true for the compute node and I/O guid map */
Packit Service 54dbc3
	destroy_guid_map(&cn_tbl);
Packit Service 54dbc3
	cn_nodes_provided = FALSE;
Packit Service 54dbc3
	destroy_guid_map(&io_tbl);
Packit Service 54dbc3
	io_nodes_provided = FALSE;
Packit Service 54dbc3
Packit Service 54dbc3
	/* do the routing for the each Hca in the subnet and each switch
Packit Service 54dbc3
	   in the subnet (to add the routes to base/enhanced SP0)
Packit Service 54dbc3
	 */
Packit Service 54dbc3
	qlist = &p_mgr->port_order_list;
Packit Service 54dbc3
	for (qlist_item = cl_qlist_head(qlist);
Packit Service 54dbc3
	     qlist_item != cl_qlist_end(qlist);
Packit Service 54dbc3
	     qlist_item = cl_qlist_next(qlist_item)) {
Packit Service 54dbc3
		port = (osm_port_t *)cl_item_obj(qlist_item, port, list_item);
Packit Service 54dbc3
Packit Service 54dbc3
		/* calculate shortest path with dijkstra from node to all switches/Hca */
Packit Service 54dbc3
		if (osm_node_get_type(port->p_node) == IB_NODE_TYPE_CA) {
Packit Service 54dbc3
			OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
Packit Service 54dbc3
				"Processing Hca with GUID 0x%" PRIx64 "\n",
Packit Service 54dbc3
				cl_ntoh64(osm_node_get_node_guid
Packit Service 54dbc3
					  (port->p_node)));
Packit Service 54dbc3
		} else if (osm_node_get_type(port->p_node) == IB_NODE_TYPE_SWITCH) {
Packit Service 54dbc3
			OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
Packit Service 54dbc3
				"Processing switch with GUID 0x%" PRIx64 "\n",
Packit Service 54dbc3
				cl_ntoh64(osm_node_get_node_guid
Packit Service 54dbc3
					  (port->p_node)));
Packit Service 54dbc3
		} else {
Packit Service 54dbc3
			/* we don't handle routers, in case they show up */
Packit Service 54dbc3
			continue;
Packit Service 54dbc3
		}
Packit Service 54dbc3
Packit Service 54dbc3
		/* distribute the LID range across the ports that can reach those LIDs
Packit Service 54dbc3
		   to have disjoint paths for one destination port with lmc>0;
Packit Service 54dbc3
		   for switches with bsp0: min=max; with esp0: max>min if lmc>0
Packit Service 54dbc3
		 */
Packit Service 54dbc3
		osm_port_get_lid_range_ho(port, &min_lid_ho,
Packit Service 54dbc3
					  &max_lid_ho);
Packit Service 54dbc3
		for (lid = min_lid_ho; lid <= max_lid_ho; lid++) {
Packit Service 54dbc3
			/* do dijkstra from this Hca/LID/SP0 to each switch */
Packit Service 54dbc3
			err =
Packit Service 54dbc3
			    dijkstra(p_mgr, &heap, adj_list, adj_list_size,
Packit Service 54dbc3
				     port, lid);
Packit Service 54dbc3
			if (err)
Packit Service 54dbc3
				goto ERROR;
Packit Service 54dbc3
			if (OSM_LOG_IS_ACTIVE_V2(p_mgr->p_log, OSM_LOG_DEBUG))
Packit Service 54dbc3
				print_routes(p_mgr, adj_list, adj_list_size,
Packit Service 54dbc3
					     port);
Packit Service 54dbc3
Packit Service 54dbc3
			/* make an update for the linear forwarding tables of the switches */
Packit Service 54dbc3
			err =
Packit Service 54dbc3
			    update_lft(p_mgr, adj_list, adj_list_size, port, lid);
Packit Service 54dbc3
			if (err)
Packit Service 54dbc3
				goto ERROR;
Packit Service 54dbc3
Packit Service 54dbc3
			/* add weights for calculated routes to adjust the weights for the next cycle */
Packit Service 54dbc3
			update_weights(p_mgr, adj_list, adj_list_size);
Packit Service 54dbc3
Packit Service 54dbc3
			if (OSM_LOG_IS_ACTIVE_V2(p_mgr->p_log, OSM_LOG_DEBUG))
Packit Service 54dbc3
				dfsssp_print_graph(p_mgr, adj_list,
Packit Service 54dbc3
						   adj_list_size);
Packit Service 54dbc3
		}
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	/* try deadlock removal only for the dfsssp routing (not for the sssp case, which is a subset of the dfsssp algorithm) */
Packit Service 54dbc3
	if (dfsssp_ctx->routing_type == OSM_ROUTING_ENGINE_TYPE_DFSSSP) {
Packit Service 54dbc3
		/* remove potential deadlocks by assigning different virtual lanes to src/dest paths and balance the lanes */
Packit Service 54dbc3
		err = dfsssp_remove_deadlocks(dfsssp_ctx);
Packit Service 54dbc3
		if (err)
Packit Service 54dbc3
			goto ERROR;
Packit Service 54dbc3
	} else if (dfsssp_ctx->routing_type == OSM_ROUTING_ENGINE_TYPE_SSSP) {
Packit Service 54dbc3
		OSM_LOG(p_mgr->p_log, OSM_LOG_INFO,
Packit Service 54dbc3
			"SSSP routing specified -> skipping deadlock removal thru dfsssp_remove_deadlocks(...)\n");
Packit Service 54dbc3
	} else {
Packit Service 54dbc3
		OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
Packit Service 54dbc3
			"ERR AD28: wrong routing engine specified in dfsssp_ctx\n");
Packit Service 54dbc3
		goto ERROR;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	/* list not needed after the dijkstra steps and deadlock removal */
Packit Service 54dbc3
	cl_qlist_remove_all(&p_mgr->port_order_list);
Packit Service 54dbc3
Packit Service 54dbc3
	/* delete the heap which is not needed anymore */
Packit Service 54dbc3
	cl_heap_destroy(&heap;;
Packit Service 54dbc3
Packit Service 54dbc3
	/* print the new_lft for each switch after routing is done */
Packit Service 54dbc3
	if (OSM_LOG_IS_ACTIVE_V2(p_mgr->p_log, OSM_LOG_DEBUG)) {
Packit Service 54dbc3
		for (item = cl_qmap_head(sw_tbl); item != cl_qmap_end(sw_tbl);
Packit Service 54dbc3
		     item = cl_qmap_next(item)) {
Packit Service 54dbc3
			sw = (osm_switch_t *) item;
Packit Service 54dbc3
			OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
Packit Service 54dbc3
				"Summary of the (new) LFT for switch 0x%" PRIx64
Packit Service 54dbc3
				" (%s):\n",
Packit Service 54dbc3
				cl_ntoh64(osm_node_get_node_guid(sw->p_node)),
Packit Service 54dbc3
				sw->p_node->print_desc);
Packit Service 54dbc3
			for (i = 0; i < sw->max_lid_ho + 1; i++)
Packit Service 54dbc3
				if (sw->new_lft[i] != OSM_NO_PATH) {
Packit Service 54dbc3
					OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
Packit Service 54dbc3
						"   for LID=%" PRIu32
Packit Service 54dbc3
						" use port=%" PRIu8 "\n", i,
Packit Service 54dbc3
						sw->new_lft[i]);
Packit Service 54dbc3
				}
Packit Service 54dbc3
		}
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	OSM_LOG_EXIT(p_mgr->p_log);
Packit Service 54dbc3
	return 0;
Packit Service 54dbc3
Packit Service 54dbc3
ERROR:
Packit Service 54dbc3
	if (!cl_is_qlist_empty(&p_mgr->port_order_list))
Packit Service 54dbc3
		cl_qlist_remove_all(&p_mgr->port_order_list);
Packit Service 54dbc3
	if (cn_nodes_provided)
Packit Service 54dbc3
		destroy_guid_map(&cn_tbl);
Packit Service 54dbc3
	if (io_nodes_provided)
Packit Service 54dbc3
		destroy_guid_map(&io_tbl);
Packit Service 54dbc3
	if (sw_list)
Packit Service 54dbc3
		free(sw_list);
Packit Service 54dbc3
	if (cl_is_heap_inited(&heap))
Packit Service 54dbc3
		cl_heap_destroy(&heap;;
Packit Service 54dbc3
	return -1;
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
/* meta function which calls subfunctions for finding the optimal switch
Packit Service 54dbc3
   for the spanning tree, performing a dijkstra step with this sw as root,
Packit Service 54dbc3
   and calculating the mcast table for MLID
Packit Service 54dbc3
*/
Packit Service 54dbc3
static ib_api_status_t dfsssp_do_mcast_routing(void * context,
Packit Service 54dbc3
					       osm_mgrp_box_t * mbox)
Packit Service 54dbc3
{
Packit Service 54dbc3
	dfsssp_context_t *dfsssp_ctx = (dfsssp_context_t *) context;
Packit Service 54dbc3
	osm_ucast_mgr_t *p_mgr = (osm_ucast_mgr_t *) dfsssp_ctx->p_mgr;
Packit Service 54dbc3
	osm_sm_t *sm = (osm_sm_t *) p_mgr->sm;
Packit Service 54dbc3
	vertex_t *adj_list = (vertex_t *) dfsssp_ctx->adj_list;
Packit Service 54dbc3
	uint32_t adj_list_size = dfsssp_ctx->adj_list_size;
Packit Service 54dbc3
	cl_qlist_t mcastgrp_port_list;
Packit Service 54dbc3
	cl_qmap_t mcastgrp_port_map;
Packit Service 54dbc3
	osm_switch_t *root_sw = NULL, *p_sw = NULL;
Packit Service 54dbc3
	osm_port_t *port = NULL;
Packit Service 54dbc3
	ib_net16_t lid = 0;
Packit Service 54dbc3
	uint32_t err = 0, num_ports = 0, i = 0;
Packit Service 54dbc3
	ib_net64_t guid = 0;
Packit Service 54dbc3
	ib_api_status_t status = IB_SUCCESS;
Packit Service 54dbc3
	cl_heap_t heap;
Packit Service 54dbc3
Packit Service 54dbc3
	OSM_LOG_ENTER(sm->p_log);
Packit Service 54dbc3
Packit Service 54dbc3
	/* using the ucast cache feature with dfsssp might mean that a leaf sw
Packit Service 54dbc3
	   got removed (and got back) without calling dfsssp_build_graph
Packit Service 54dbc3
	   and therefore the adj_list (and pointers to osm's internal switches)
Packit Service 54dbc3
	   could be outdated (here we have no knowledge if it has happened, so
Packit Service 54dbc3
	   unfortunately a check is necessary... still better than rebuilding
Packit Service 54dbc3
	   adj_list every time we arrive here)
Packit Service 54dbc3
	 */
Packit Service 54dbc3
	if (p_mgr->p_subn->opt.use_ucast_cache && p_mgr->cache_valid) {
Packit Service 54dbc3
		for (i = 1; i < adj_list_size; i++) {
Packit Service 54dbc3
			guid = cl_hton64(adj_list[i].guid);
Packit Service 54dbc3
			p_sw = osm_get_switch_by_guid(p_mgr->p_subn, guid);
Packit Service 54dbc3
			if (p_sw) {
Packit Service 54dbc3
				/* check if switch came back from the dead */
Packit Service 54dbc3
				if (adj_list[i].dropped)
Packit Service 54dbc3
					adj_list[i].dropped = FALSE;
Packit Service 54dbc3
Packit Service 54dbc3
				/* verify that sw object has not been moved
Packit Service 54dbc3
				   (this can happen for a leaf switch, if it
Packit Service 54dbc3
				   was dropped and came back later without a
Packit Service 54dbc3
				   rerouting), otherwise we have to update
Packit Service 54dbc3
				   dfsssp's internal switch list with the new
Packit Service 54dbc3
				   sw pointer
Packit Service 54dbc3
				 */
Packit Service 54dbc3
				if (p_sw == adj_list[i].sw)
Packit Service 54dbc3
					continue;
Packit Service 54dbc3
				else
Packit Service 54dbc3
					adj_list[i].sw = p_sw;
Packit Service 54dbc3
			} else {
Packit Service 54dbc3
				/* if a switch from adj_list is not in the
Packit Service 54dbc3
				   sw_guid_tbl anymore, then the only reason is
Packit Service 54dbc3
				   that it was a leaf switch and opensm dropped
Packit Service 54dbc3
				   it without calling a rerouting
Packit Service 54dbc3
				   -> calling dijkstra is no problem, since it
Packit Service 54dbc3
				      is a leaf and different from root_sw
Packit Service 54dbc3
				   -> only update_mcft and reset_mgrp_membership
Packit Service 54dbc3
				      need to be aware of these dropped switches
Packit Service 54dbc3
				 */
Packit Service 54dbc3
				if (!adj_list[i].dropped)
Packit Service 54dbc3
					adj_list[i].dropped = TRUE;
Packit Service 54dbc3
			}
Packit Service 54dbc3
		}
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	/* construct the generic heap opject to use it in dijkstra */
Packit Service 54dbc3
	cl_heap_construct(&heap;;
Packit Service 54dbc3
Packit Service 54dbc3
	/* create a map and a list of all ports which are member in the mcast
Packit Service 54dbc3
	   group; map for searching elements and list for iteration
Packit Service 54dbc3
	 */
Packit Service 54dbc3
	if (osm_mcast_make_port_list_and_map(&mcastgrp_port_list,
Packit Service 54dbc3
					     &mcastgrp_port_map, mbox)) {
Packit Service 54dbc3
		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR AD50: "
Packit Service 54dbc3
			"Insufficient memory to make port list\n");
Packit Service 54dbc3
		status = IB_ERROR;
Packit Service 54dbc3
		goto Exit;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	num_ports = cl_qlist_count(&mcastgrp_port_list);
Packit Service 54dbc3
	if (num_ports < 2) {
Packit Service 54dbc3
		OSM_LOG(sm->p_log, OSM_LOG_VERBOSE,
Packit Service 54dbc3
			"MLID 0x%X has %u members - nothing to do\n",
Packit Service 54dbc3
			mbox->mlid, num_ports);
Packit Service 54dbc3
		goto Exit;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	/* find the root switch for the spanning tree, which has the smallest
Packit Service 54dbc3
	   hops count to all LIDs in the mcast group
Packit Service 54dbc3
	 */
Packit Service 54dbc3
	root_sw = osm_mcast_mgr_find_root_switch(sm, &mcastgrp_port_list);
Packit Service 54dbc3
	if (!root_sw) {
Packit Service 54dbc3
		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR AD51: "
Packit Service 54dbc3
			"Unable to locate a suitable switch for group 0x%X\n",
Packit Service 54dbc3
			mbox->mlid);
Packit Service 54dbc3
		status = IB_ERROR;
Packit Service 54dbc3
		goto Exit;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	/* a) start one dijkstra step from the root switch to generate a
Packit Service 54dbc3
	   spanning tree
Packit Service 54dbc3
	   b) this might be a bit of an overkill to span the whole
Packit Service 54dbc3
	   network, if there are only a few ports in the mcast group, but
Packit Service 54dbc3
	   its only one dijkstra step for each mcast group and we did many
Packit Service 54dbc3
	   steps before in the ucast routing for each LID in the subnet;
Packit Service 54dbc3
	   c) we can use the subnet structure from the ucast routing, and
Packit Service 54dbc3
	   don't even have to reset the link weights (=> therefore the mcast
Packit Service 54dbc3
	   spanning tree will use less 'growded' links in the network)
Packit Service 54dbc3
	   d) the mcast dfsssp algorithm will not change the link weights
Packit Service 54dbc3
	 */
Packit Service 54dbc3
	lid = osm_node_get_base_lid(root_sw->p_node, 0);
Packit Service 54dbc3
	port = osm_get_port_by_lid(sm->p_subn, lid);
Packit Service 54dbc3
	err = dijkstra(p_mgr, &heap, adj_list, adj_list_size, port, lid);
Packit Service 54dbc3
	if (err) {
Packit Service 54dbc3
		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR AD52: "
Packit Service 54dbc3
			"Dijkstra step for mcast failed for group 0x%X\n",
Packit Service 54dbc3
			mbox->mlid);
Packit Service 54dbc3
		status = IB_ERROR;
Packit Service 54dbc3
		goto Exit;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	/* set mcast group membership again for update_mcft
Packit Service 54dbc3
	   (unfortunately: osm_mcast_mgr_find_root_switch resets it)
Packit Service 54dbc3
	 */
Packit Service 54dbc3
	update_mgrp_membership(&mcastgrp_port_list);
Packit Service 54dbc3
Packit Service 54dbc3
	/* update the mcast forwarding tables of the switches */
Packit Service 54dbc3
	err = update_mcft(sm, adj_list, adj_list_size, mbox->mlid,
Packit Service 54dbc3
			  &mcastgrp_port_map, root_sw);
Packit Service 54dbc3
	if (err) {
Packit Service 54dbc3
		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR AD53: "
Packit Service 54dbc3
			"Update of mcast forwarding tables failed for group 0x%X\n",
Packit Service 54dbc3
			mbox->mlid);
Packit Service 54dbc3
		status = IB_ERROR;
Packit Service 54dbc3
		goto Exit;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
Exit:
Packit Service 54dbc3
	if (cl_is_heap_inited(&heap))
Packit Service 54dbc3
		cl_heap_destroy(&heap;;
Packit Service 54dbc3
	reset_mgrp_membership(adj_list, adj_list_size);
Packit Service 54dbc3
	osm_mcast_drop_port_list(&mcastgrp_port_list);
Packit Service 54dbc3
	OSM_LOG_EXIT(sm->p_log);
Packit Service 54dbc3
	return status;
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
/* called from extern in QP creation process to gain the the service level and
Packit Service 54dbc3
   the virtual lane respectively for a <s,d> pair
Packit Service 54dbc3
*/
Packit Service 54dbc3
static uint8_t get_dfsssp_sl(void *context, uint8_t hint_for_default_sl,
Packit Service 54dbc3
			     const ib_net16_t slid, const ib_net16_t dlid)
Packit Service 54dbc3
{
Packit Service 54dbc3
	dfsssp_context_t *dfsssp_ctx = (dfsssp_context_t *) context;
Packit Service 54dbc3
	osm_port_t *src_port, *dest_port;
Packit Service 54dbc3
	vltable_t *srcdest2vl_table = NULL;
Packit Service 54dbc3
	uint8_t *vl_split_count = NULL;
Packit Service 54dbc3
	osm_ucast_mgr_t *p_mgr = NULL;
Packit Service 54dbc3
	int32_t res = 0;
Packit Service 54dbc3
Packit Service 54dbc3
	if (dfsssp_ctx
Packit Service 54dbc3
	    && dfsssp_ctx->routing_type == OSM_ROUTING_ENGINE_TYPE_DFSSSP) {
Packit Service 54dbc3
		p_mgr = (osm_ucast_mgr_t *) dfsssp_ctx->p_mgr;
Packit Service 54dbc3
		srcdest2vl_table = (vltable_t *) (dfsssp_ctx->srcdest2vl_table);
Packit Service 54dbc3
		vl_split_count = (uint8_t *) (dfsssp_ctx->vl_split_count);
Packit Service 54dbc3
	}
Packit Service 54dbc3
	else
Packit Service 54dbc3
		return hint_for_default_sl;
Packit Service 54dbc3
Packit Service 54dbc3
	src_port = osm_get_port_by_lid(p_mgr->p_subn, slid);
Packit Service 54dbc3
	if (!src_port)
Packit Service 54dbc3
		return hint_for_default_sl;
Packit Service 54dbc3
Packit Service 54dbc3
	dest_port = osm_get_port_by_lid(p_mgr->p_subn, dlid);
Packit Service 54dbc3
	if (!dest_port)
Packit Service 54dbc3
		return hint_for_default_sl;
Packit Service 54dbc3
Packit Service 54dbc3
	if (!srcdest2vl_table)
Packit Service 54dbc3
		return hint_for_default_sl;
Packit Service 54dbc3
Packit Service 54dbc3
	res = vltable_get_vl(srcdest2vl_table, slid, dlid);
Packit Service 54dbc3
Packit Service 54dbc3
	/* we will randomly distribute the traffic over multiple VLs if
Packit Service 54dbc3
	   necessary for good balancing; therefore vl_split_count provides
Packit Service 54dbc3
	   the number of VLs to use for certain traffic
Packit Service 54dbc3
	 */
Packit Service 54dbc3
	if (res > -1) {
Packit Service 54dbc3
		if (vl_split_count[res] > 1)
Packit Service 54dbc3
			return (uint8_t) (res + rand()%(vl_split_count[res]));
Packit Service 54dbc3
		else
Packit Service 54dbc3
			return (uint8_t) res;
Packit Service 54dbc3
	} else
Packit Service 54dbc3
		return hint_for_default_sl;
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
static dfsssp_context_t *dfsssp_context_create(osm_opensm_t * p_osm,
Packit Service 54dbc3
					       osm_routing_engine_type_t
Packit Service 54dbc3
					       routing_type)
Packit Service 54dbc3
{
Packit Service 54dbc3
	dfsssp_context_t *dfsssp_ctx = NULL;
Packit Service 54dbc3
Packit Service 54dbc3
	/* allocate memory */
Packit Service 54dbc3
	dfsssp_ctx = (dfsssp_context_t *) malloc(sizeof(dfsssp_context_t));
Packit Service 54dbc3
	if (dfsssp_ctx) {
Packit Service 54dbc3
		/* set initial values */
Packit Service 54dbc3
		dfsssp_ctx->routing_type = routing_type;
Packit Service 54dbc3
		dfsssp_ctx->p_mgr = (osm_ucast_mgr_t *) & (p_osm->sm.ucast_mgr);
Packit Service 54dbc3
		dfsssp_ctx->adj_list = NULL;
Packit Service 54dbc3
		dfsssp_ctx->adj_list_size = 0;
Packit Service 54dbc3
		dfsssp_ctx->srcdest2vl_table = NULL;
Packit Service 54dbc3
		dfsssp_ctx->vl_split_count = NULL;
Packit Service 54dbc3
	} else {
Packit Service 54dbc3
		OSM_LOG(p_osm->sm.ucast_mgr.p_log, OSM_LOG_ERROR,
Packit Service 54dbc3
			"ERR AD04: cannot allocate memory for dfsssp_ctx in dfsssp_context_create\n");
Packit Service 54dbc3
		return NULL;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	return dfsssp_ctx;
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
static void dfsssp_context_destroy(void *context)
Packit Service 54dbc3
{
Packit Service 54dbc3
	dfsssp_context_t *dfsssp_ctx = (dfsssp_context_t *) context;
Packit Service 54dbc3
	vertex_t *adj_list = (vertex_t *) (dfsssp_ctx->adj_list);
Packit Service 54dbc3
	uint32_t i = 0;
Packit Service 54dbc3
	link_t *link = NULL, *tmp = NULL;
Packit Service 54dbc3
Packit Service 54dbc3
	/* free adj_list */
Packit Service 54dbc3
	for (i = 0; i < dfsssp_ctx->adj_list_size; i++) {
Packit Service 54dbc3
		link = adj_list[i].links;
Packit Service 54dbc3
		while (link) {
Packit Service 54dbc3
			tmp = link;
Packit Service 54dbc3
			link = link->next;
Packit Service 54dbc3
			free(tmp);
Packit Service 54dbc3
		}
Packit Service 54dbc3
	}
Packit Service 54dbc3
	free(adj_list);
Packit Service 54dbc3
	dfsssp_ctx->adj_list = NULL;
Packit Service 54dbc3
	dfsssp_ctx->adj_list_size = 0;
Packit Service 54dbc3
Packit Service 54dbc3
	/* free srcdest2vl table and the split count information table
Packit Service 54dbc3
	   (can be done, because dfsssp_context_destroy is called after
Packit Service 54dbc3
	    osm_get_dfsssp_sl)
Packit Service 54dbc3
	 */
Packit Service 54dbc3
	vltable_dealloc(&(dfsssp_ctx->srcdest2vl_table));
Packit Service 54dbc3
	dfsssp_ctx->srcdest2vl_table = NULL;
Packit Service 54dbc3
Packit Service 54dbc3
	if (dfsssp_ctx->vl_split_count) {
Packit Service 54dbc3
		free(dfsssp_ctx->vl_split_count);
Packit Service 54dbc3
		dfsssp_ctx->vl_split_count = NULL;
Packit Service 54dbc3
	}
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
static void delete(void *context)
Packit Service 54dbc3
{
Packit Service 54dbc3
	if (!context)
Packit Service 54dbc3
		return;
Packit Service 54dbc3
	dfsssp_context_destroy(context);
Packit Service 54dbc3
Packit Service 54dbc3
	free(context);
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
int osm_ucast_dfsssp_setup(struct osm_routing_engine *r, osm_opensm_t * p_osm)
Packit Service 54dbc3
{
Packit Service 54dbc3
	/* create context container and add ucast management object */
Packit Service 54dbc3
	dfsssp_context_t *dfsssp_context =
Packit Service 54dbc3
	    dfsssp_context_create(p_osm, OSM_ROUTING_ENGINE_TYPE_DFSSSP);
Packit Service 54dbc3
	if (!dfsssp_context) {
Packit Service 54dbc3
		return 1;	/* alloc failed -> skip this routing */
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	/* reset function pointers to dfsssp routines */
Packit Service 54dbc3
	r->context = (void *)dfsssp_context;
Packit Service 54dbc3
	r->build_lid_matrices = dfsssp_build_graph;
Packit Service 54dbc3
	r->ucast_build_fwd_tables = dfsssp_do_dijkstra_routing;
Packit Service 54dbc3
	r->mcast_build_stree = dfsssp_do_mcast_routing;
Packit Service 54dbc3
	r->path_sl = get_dfsssp_sl;
Packit Service 54dbc3
	r->destroy = delete;
Packit Service 54dbc3
Packit Service 54dbc3
	/* we initialize with the current time to achieve a 'good' randomized
Packit Service 54dbc3
	   assignment in get_dfsssp_sl(...)
Packit Service 54dbc3
	 */
Packit Service 54dbc3
	srand(time(NULL));
Packit Service 54dbc3
Packit Service 54dbc3
	return 0;
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
int osm_ucast_sssp_setup(struct osm_routing_engine *r, osm_opensm_t * p_osm)
Packit Service 54dbc3
{
Packit Service 54dbc3
	/* create context container and add ucast management object */
Packit Service 54dbc3
	dfsssp_context_t *dfsssp_context =
Packit Service 54dbc3
	    dfsssp_context_create(p_osm, OSM_ROUTING_ENGINE_TYPE_SSSP);
Packit Service 54dbc3
	if (!dfsssp_context) {
Packit Service 54dbc3
		return 1;	/* alloc failed -> skip this routing */
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	/* reset function pointers to sssp routines */
Packit Service 54dbc3
	r->context = (void *)dfsssp_context;
Packit Service 54dbc3
	r->build_lid_matrices = dfsssp_build_graph;
Packit Service 54dbc3
	r->ucast_build_fwd_tables = dfsssp_do_dijkstra_routing;
Packit Service 54dbc3
	r->mcast_build_stree = dfsssp_do_mcast_routing;
Packit Service 54dbc3
	r->destroy = delete;
Packit Service 54dbc3
Packit Service 54dbc3
	return 0;
Packit Service 54dbc3
}