1d6b92ffaSHans Petter Selasky /*
2d6b92ffaSHans Petter Selasky  * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved.
3d6b92ffaSHans Petter Selasky  * Copyright (c) 2002-2015 Mellanox Technologies LTD. All rights reserved.
4d6b92ffaSHans Petter Selasky  * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
5d6b92ffaSHans Petter Selasky  * Copyright (c) 2009-2015 ZIH, TU Dresden, Federal Republic of Germany. All rights reserved.
6d6b92ffaSHans Petter Selasky  * Copyright (C) 2012-2017 Tokyo Institute of Technology. All rights reserved.
7d6b92ffaSHans Petter Selasky  *
8d6b92ffaSHans Petter Selasky  * This software is available to you under a choice of one of two
9d6b92ffaSHans Petter Selasky  * licenses.  You may choose to be licensed under the terms of the GNU
10d6b92ffaSHans Petter Selasky  * General Public License (GPL) Version 2, available from the file
11d6b92ffaSHans Petter Selasky  * COPYING in the main directory of this source tree, or the
12d6b92ffaSHans Petter Selasky  * OpenIB.org BSD license below:
13d6b92ffaSHans Petter Selasky  *
14d6b92ffaSHans Petter Selasky  *     Redistribution and use in source and binary forms, with or
15d6b92ffaSHans Petter Selasky  *     without modification, are permitted provided that the following
16d6b92ffaSHans Petter Selasky  *     conditions are met:
17d6b92ffaSHans Petter Selasky  *
18d6b92ffaSHans Petter Selasky  *      - Redistributions of source code must retain the above
19d6b92ffaSHans Petter Selasky  *        copyright notice, this list of conditions and the following
20d6b92ffaSHans Petter Selasky  *        disclaimer.
21d6b92ffaSHans Petter Selasky  *
22d6b92ffaSHans Petter Selasky  *      - Redistributions in binary form must reproduce the above
23d6b92ffaSHans Petter Selasky  *        copyright notice, this list of conditions and the following
24d6b92ffaSHans Petter Selasky  *        disclaimer in the documentation and/or other materials
25d6b92ffaSHans Petter Selasky  *        provided with the distribution.
26d6b92ffaSHans Petter Selasky  *
27d6b92ffaSHans Petter Selasky  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28d6b92ffaSHans Petter Selasky  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29d6b92ffaSHans Petter Selasky  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30d6b92ffaSHans Petter Selasky  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
31d6b92ffaSHans Petter Selasky  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
32d6b92ffaSHans Petter Selasky  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
33d6b92ffaSHans Petter Selasky  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
34d6b92ffaSHans Petter Selasky  * SOFTWARE.
35d6b92ffaSHans Petter Selasky  *
36d6b92ffaSHans Petter Selasky  */
37d6b92ffaSHans Petter Selasky 
38d6b92ffaSHans Petter Selasky /*
39d6b92ffaSHans Petter Selasky  * Abstract:
40d6b92ffaSHans Petter Selasky  *    Implementation of OpenSM (deadlock-free) single-source-shortest-path routing
41d6b92ffaSHans Petter Selasky  *    (with dijkstra algorithm)
42d6b92ffaSHans Petter Selasky  */
43d6b92ffaSHans Petter Selasky 
44d6b92ffaSHans Petter Selasky #if HAVE_CONFIG_H
45d6b92ffaSHans Petter Selasky #  include <config.h>
46d6b92ffaSHans Petter Selasky #endif				/* HAVE_CONFIG_H */
47d6b92ffaSHans Petter Selasky 
48d6b92ffaSHans Petter Selasky #include <stdio.h>
49d6b92ffaSHans Petter Selasky #include <stdlib.h>
50d6b92ffaSHans Petter Selasky #include <string.h>
51d6b92ffaSHans Petter Selasky #include <opensm/osm_file_ids.h>
52d6b92ffaSHans Petter Selasky #define FILE_ID OSM_FILE_UCAST_DFSSSP_C
53d6b92ffaSHans Petter Selasky #include <opensm/osm_ucast_mgr.h>
54d6b92ffaSHans Petter Selasky #include <opensm/osm_opensm.h>
55d6b92ffaSHans Petter Selasky #include <opensm/osm_node.h>
56d6b92ffaSHans Petter Selasky #include <opensm/osm_multicast.h>
57d6b92ffaSHans Petter Selasky #include <opensm/osm_mcast_mgr.h>
58d6b92ffaSHans Petter Selasky 
59d6b92ffaSHans Petter Selasky /* "infinity" for dijkstra */
60d6b92ffaSHans Petter Selasky #define INF      0x7FFFFFFF
61d6b92ffaSHans Petter Selasky 
62d6b92ffaSHans Petter Selasky enum {
63d6b92ffaSHans Petter Selasky 	UNDISCOVERED = 0,
64d6b92ffaSHans Petter Selasky 	DISCOVERED
65d6b92ffaSHans Petter Selasky };
66d6b92ffaSHans Petter Selasky 
67d6b92ffaSHans Petter Selasky enum {
68d6b92ffaSHans Petter Selasky 	UNKNOWN = 0,
69d6b92ffaSHans Petter Selasky 	GRAY,
70d6b92ffaSHans Petter Selasky 	BLACK,
71d6b92ffaSHans Petter Selasky };
72d6b92ffaSHans Petter Selasky 
73d6b92ffaSHans Petter Selasky typedef struct link {
74d6b92ffaSHans Petter Selasky 	uint64_t guid;		/* guid of the neighbor behind the link */
75d6b92ffaSHans Petter Selasky 	uint32_t from;		/* base_index in the adjazenz list (start of the link) */
76d6b92ffaSHans Petter Selasky 	uint8_t from_port;	/* port on the base_side (needed for weight update to identify the correct link for multigraphs) */
77d6b92ffaSHans Petter Selasky 	uint32_t to;		/* index of the neighbor in the adjazenz list (end of the link) */
78d6b92ffaSHans Petter Selasky 	uint8_t to_port;	/* port on the side of the neighbor (needed for the LFT) */
79d6b92ffaSHans Petter Selasky 	uint64_t weight;	/* link weight */
80d6b92ffaSHans Petter Selasky 	struct link *next;
81d6b92ffaSHans Petter Selasky } link_t;
82d6b92ffaSHans Petter Selasky 
83d6b92ffaSHans Petter Selasky typedef struct vertex {
84d6b92ffaSHans Petter Selasky 	/* informations of the fabric */
85d6b92ffaSHans Petter Selasky 	uint64_t guid;
86d6b92ffaSHans Petter Selasky 	uint16_t lid;		/* for lft filling */
87d6b92ffaSHans Petter Selasky 	uint32_t num_hca;	/* numbers of Hca/LIDs on the switch, for weight calculation */
88d6b92ffaSHans Petter Selasky 	link_t *links;
89d6b92ffaSHans Petter Selasky 	uint8_t hops;
90d6b92ffaSHans Petter Selasky 	/* for dijkstra routing */
91d6b92ffaSHans Petter Selasky 	link_t *used_link;	/* link between the vertex discovered before and this vertex */
92d6b92ffaSHans Petter Selasky 	uint64_t distance;	/* distance from source to this vertex */
93d6b92ffaSHans Petter Selasky 	uint8_t state;
94d6b92ffaSHans Petter Selasky 	/* for the binary heap */
95d6b92ffaSHans Petter Selasky 	uint32_t heap_id;
96d6b92ffaSHans Petter Selasky 	/* for LFT writing and debug */
97d6b92ffaSHans Petter Selasky 	osm_switch_t *sw;	/* selfpointer */
98d6b92ffaSHans Petter Selasky 	boolean_t dropped;	/* indicate dropped switches (w/ ucast cache) */
99d6b92ffaSHans Petter Selasky } vertex_t;
100d6b92ffaSHans Petter Selasky 
101d6b92ffaSHans Petter Selasky typedef struct binary_heap {
102d6b92ffaSHans Petter Selasky 	uint32_t size;		/* size of the heap */
103d6b92ffaSHans Petter Selasky 	vertex_t **nodes;	/* array with pointers to elements of the adj_list */
104d6b92ffaSHans Petter Selasky } binary_heap_t;
105d6b92ffaSHans Petter Selasky 
106d6b92ffaSHans Petter Selasky typedef struct vltable {
107d6b92ffaSHans Petter Selasky 	uint64_t num_lids;	/* size of the lids array */
108d6b92ffaSHans Petter Selasky 	uint16_t *lids;		/* sorted array of all lids in the subnet */
109d6b92ffaSHans Petter Selasky 	uint8_t *vls;		/* matrix form assignment lid X lid -> virtual lane */
110d6b92ffaSHans Petter Selasky } vltable_t;
111d6b92ffaSHans Petter Selasky 
112d6b92ffaSHans Petter Selasky typedef struct cdg_link {
113d6b92ffaSHans Petter Selasky 	struct cdg_node *node;
114d6b92ffaSHans Petter Selasky 	uint32_t num_pairs;	/* number of src->dest pairs incremented in path adding step */
115d6b92ffaSHans Petter Selasky 	uint32_t max_len;	/* length of the srcdest array */
116d6b92ffaSHans Petter Selasky 	uint32_t removed;	/* number of pairs removed in path deletion step */
117d6b92ffaSHans Petter Selasky 	uint32_t *srcdest_pairs;
118d6b92ffaSHans Petter Selasky 	struct cdg_link *next;
119d6b92ffaSHans Petter Selasky } cdg_link_t;
120d6b92ffaSHans Petter Selasky 
121d6b92ffaSHans Petter Selasky /* struct for a node of a binary tree with additional parent pointer */
122d6b92ffaSHans Petter Selasky typedef struct cdg_node {
123d6b92ffaSHans Petter Selasky 	uint64_t channelID;	/* unique key consist of src lid + port + dest lid + port */
124d6b92ffaSHans Petter Selasky 	cdg_link_t *linklist;	/* edges to adjazent nodes */
125d6b92ffaSHans Petter Selasky 	uint8_t status;		/* node status in cycle search to avoid recursive function */
126d6b92ffaSHans Petter Selasky 	uint8_t visited;	/* needed to traverse the binary tree */
127d6b92ffaSHans Petter Selasky 	struct cdg_node *pre;	/* to save the path in cycle detection algorithm */
128d6b92ffaSHans Petter Selasky 	struct cdg_node *left, *right, *parent;
129d6b92ffaSHans Petter Selasky } cdg_node_t;
130d6b92ffaSHans Petter Selasky 
131d6b92ffaSHans Petter Selasky typedef struct dfsssp_context {
132d6b92ffaSHans Petter Selasky 	osm_routing_engine_type_t routing_type;
133d6b92ffaSHans Petter Selasky 	osm_ucast_mgr_t *p_mgr;
134d6b92ffaSHans Petter Selasky 	vertex_t *adj_list;
135d6b92ffaSHans Petter Selasky 	uint32_t adj_list_size;
136d6b92ffaSHans Petter Selasky 	vltable_t *srcdest2vl_table;
137d6b92ffaSHans Petter Selasky 	uint8_t *vl_split_count;
138d6b92ffaSHans Petter Selasky } dfsssp_context_t;
139d6b92ffaSHans Petter Selasky 
140d6b92ffaSHans Petter Selasky /**************** set initial values for structs **********************
141d6b92ffaSHans Petter Selasky  **********************************************************************/
set_default_link(link_t * link)142d6b92ffaSHans Petter Selasky static inline void set_default_link(link_t * link)
143d6b92ffaSHans Petter Selasky {
144d6b92ffaSHans Petter Selasky 	link->guid = 0;
145d6b92ffaSHans Petter Selasky 	link->from = 0;
146d6b92ffaSHans Petter Selasky 	link->from_port = 0;
147d6b92ffaSHans Petter Selasky 	link->to = 0;
148d6b92ffaSHans Petter Selasky 	link->to_port = 0;
149d6b92ffaSHans Petter Selasky 	link->weight = 0;
150d6b92ffaSHans Petter Selasky 	link->next = NULL;
151d6b92ffaSHans Petter Selasky }
152d6b92ffaSHans Petter Selasky 
set_default_vertex(vertex_t * vertex)153d6b92ffaSHans Petter Selasky static inline void set_default_vertex(vertex_t * vertex)
154d6b92ffaSHans Petter Selasky {
155d6b92ffaSHans Petter Selasky 	vertex->guid = 0;
156d6b92ffaSHans Petter Selasky 	vertex->lid = 0;
157d6b92ffaSHans Petter Selasky 	vertex->num_hca = 0;
158d6b92ffaSHans Petter Selasky 	vertex->links = NULL;
159d6b92ffaSHans Petter Selasky 	vertex->hops = 0;
160d6b92ffaSHans Petter Selasky 	vertex->used_link = NULL;
161d6b92ffaSHans Petter Selasky 	vertex->distance = 0;
162d6b92ffaSHans Petter Selasky 	vertex->state = UNDISCOVERED;
163d6b92ffaSHans Petter Selasky 	vertex->heap_id = 0;
164d6b92ffaSHans Petter Selasky 	vertex->sw = NULL;
165d6b92ffaSHans Petter Selasky 	vertex->dropped = FALSE;
166d6b92ffaSHans Petter Selasky }
167d6b92ffaSHans Petter Selasky 
set_default_cdg_node(cdg_node_t * node)168d6b92ffaSHans Petter Selasky static inline void set_default_cdg_node(cdg_node_t * node)
169d6b92ffaSHans Petter Selasky {
170d6b92ffaSHans Petter Selasky 	node->channelID = 0;
171d6b92ffaSHans Petter Selasky 	node->linklist = NULL;
172d6b92ffaSHans Petter Selasky 	node->status = UNKNOWN;
173d6b92ffaSHans Petter Selasky 	node->visited = 0;
174d6b92ffaSHans Petter Selasky 	node->pre = NULL;
175d6b92ffaSHans Petter Selasky 	node->left = NULL;
176d6b92ffaSHans Petter Selasky 	node->right = NULL;
177d6b92ffaSHans Petter Selasky 	node->parent = NULL;
178d6b92ffaSHans Petter Selasky }
179d6b92ffaSHans Petter Selasky 
180d6b92ffaSHans Petter Selasky /**********************************************************************
181d6b92ffaSHans Petter Selasky  **********************************************************************/
182d6b92ffaSHans Petter Selasky 
183d6b92ffaSHans Petter Selasky /************ helper functions for heap in dijkstra *******************
184d6b92ffaSHans Petter Selasky  **********************************************************************/
185d6b92ffaSHans Petter Selasky /* returns true if element 1 is smaller than element 2 */
heap_smaller(binary_heap_t * heap,uint32_t i,uint32_t j)186d6b92ffaSHans Petter Selasky static inline uint32_t heap_smaller(binary_heap_t * heap, uint32_t i,
187d6b92ffaSHans Petter Selasky 				    uint32_t j)
188d6b92ffaSHans Petter Selasky {
189d6b92ffaSHans Petter Selasky 	return (heap->nodes[i]->distance < heap->nodes[j]->distance) ? 1 : 0;
190d6b92ffaSHans Petter Selasky }
191d6b92ffaSHans Petter Selasky 
192d6b92ffaSHans Petter Selasky /* swap two elements */
heap_exchange(binary_heap_t * heap,uint32_t i,uint32_t j)193d6b92ffaSHans Petter Selasky static void heap_exchange(binary_heap_t * heap, uint32_t i, uint32_t j)
194d6b92ffaSHans Petter Selasky {
195d6b92ffaSHans Petter Selasky 	uint32_t tmp_heap_id = 0;
196d6b92ffaSHans Petter Selasky 	vertex_t *tmp_node = NULL;
197d6b92ffaSHans Petter Selasky 
198d6b92ffaSHans Petter Selasky 	/* 1. swap the heap_id */
199d6b92ffaSHans Petter Selasky 	tmp_heap_id = heap->nodes[i]->heap_id;
200d6b92ffaSHans Petter Selasky 	heap->nodes[i]->heap_id = heap->nodes[j]->heap_id;
201d6b92ffaSHans Petter Selasky 	heap->nodes[j]->heap_id = tmp_heap_id;
202d6b92ffaSHans Petter Selasky 	/* 2. swap pointers */
203d6b92ffaSHans Petter Selasky 	tmp_node = heap->nodes[i];
204d6b92ffaSHans Petter Selasky 	heap->nodes[i] = heap->nodes[j];
205d6b92ffaSHans Petter Selasky 	heap->nodes[j] = tmp_node;
206d6b92ffaSHans Petter Selasky }
207d6b92ffaSHans Petter Selasky 
208d6b92ffaSHans Petter Selasky /* changes position of element with parent until children are bigger */
heap_up(binary_heap_t * heap,uint32_t i)209d6b92ffaSHans Petter Selasky static uint32_t heap_up(binary_heap_t * heap, uint32_t i)
210d6b92ffaSHans Petter Selasky {
211d6b92ffaSHans Petter Selasky 	uint32_t curr = i, father = 0;
212d6b92ffaSHans Petter Selasky 
213d6b92ffaSHans Petter Selasky 	if (curr > 0) {
214d6b92ffaSHans Petter Selasky 		father = (curr - 1) >> 1;
215d6b92ffaSHans Petter Selasky 		while (heap_smaller(heap, curr, father)) {
216d6b92ffaSHans Petter Selasky 			heap_exchange(heap, curr, father);
217d6b92ffaSHans Petter Selasky 			/* try to go up when we arent already root */
218d6b92ffaSHans Petter Selasky 			curr = father;
219d6b92ffaSHans Petter Selasky 			if (curr > 0)
220d6b92ffaSHans Petter Selasky 				father = (curr - 1) >> 1;
221d6b92ffaSHans Petter Selasky 		}
222d6b92ffaSHans Petter Selasky 	}
223d6b92ffaSHans Petter Selasky 
224d6b92ffaSHans Petter Selasky 	return curr;
225d6b92ffaSHans Petter Selasky }
226d6b92ffaSHans Petter Selasky 
227d6b92ffaSHans Petter Selasky /* changes position of element with children until parent is smaller */
heap_down(binary_heap_t * heap,uint32_t i)228d6b92ffaSHans Petter Selasky static uint32_t heap_down(binary_heap_t * heap, uint32_t i)
229d6b92ffaSHans Petter Selasky {
230d6b92ffaSHans Petter Selasky 	uint32_t curr = i;
231d6b92ffaSHans Petter Selasky 	uint32_t son1 = 0, son2 = 0, smaller_son = 0;
232d6b92ffaSHans Petter Selasky 	uint32_t exchanged = 0;
233d6b92ffaSHans Petter Selasky 
234d6b92ffaSHans Petter Selasky 	do {
235d6b92ffaSHans Petter Selasky 		son1 = ((curr + 1) << 1) - 1;
236d6b92ffaSHans Petter Selasky 		son2 = (curr + 1) << 1;
237d6b92ffaSHans Petter Selasky 		exchanged = 0;
238d6b92ffaSHans Petter Selasky 
239d6b92ffaSHans Petter Selasky 		/* exchange with smaller son */
240d6b92ffaSHans Petter Selasky 		if (son1 < heap->size && son2 < heap->size) {
241d6b92ffaSHans Petter Selasky 			if (heap_smaller(heap, son1, son2))
242d6b92ffaSHans Petter Selasky 				smaller_son = son1;
243d6b92ffaSHans Petter Selasky 			else
244d6b92ffaSHans Petter Selasky 				smaller_son = son2;
245d6b92ffaSHans Petter Selasky 		} else if (son1 < heap->size) {
246d6b92ffaSHans Petter Selasky 			/* only one son */
247d6b92ffaSHans Petter Selasky 			smaller_son = son1;
248d6b92ffaSHans Petter Selasky 		} else {
249d6b92ffaSHans Petter Selasky 			/* finished */
250d6b92ffaSHans Petter Selasky 			break;
251d6b92ffaSHans Petter Selasky 		}
252d6b92ffaSHans Petter Selasky 
253d6b92ffaSHans Petter Selasky 		/* only exchange when smaller */
254d6b92ffaSHans Petter Selasky 		if (heap_smaller(heap, smaller_son, curr)) {
255d6b92ffaSHans Petter Selasky 			heap_exchange(heap, curr, smaller_son);
256d6b92ffaSHans Petter Selasky 			exchanged = 1;
257d6b92ffaSHans Petter Selasky 			curr = smaller_son;
258d6b92ffaSHans Petter Selasky 		}
259d6b92ffaSHans Petter Selasky 	} while (exchanged);
260d6b92ffaSHans Petter Selasky 
261d6b92ffaSHans Petter Selasky 	return curr;
262d6b92ffaSHans Petter Selasky }
263d6b92ffaSHans Petter Selasky 
264d6b92ffaSHans Petter Selasky /* reheapify element */
heap_heapify(binary_heap_t * heap,uint32_t i)265d6b92ffaSHans Petter Selasky static inline void heap_heapify(binary_heap_t * heap, uint32_t i)
266d6b92ffaSHans Petter Selasky {
267d6b92ffaSHans Petter Selasky 	heap_down(heap, heap_up(heap, i));
268d6b92ffaSHans Petter Selasky }
269d6b92ffaSHans Petter Selasky 
270d6b92ffaSHans Petter Selasky /* creates heap for graph */
heap_create(vertex_t * adj_list,uint32_t adj_list_size,binary_heap_t ** binheap)271d6b92ffaSHans Petter Selasky static int heap_create(vertex_t * adj_list, uint32_t adj_list_size,
272d6b92ffaSHans Petter Selasky 		       binary_heap_t ** binheap)
273d6b92ffaSHans Petter Selasky {
274d6b92ffaSHans Petter Selasky 	binary_heap_t *heap = NULL;
275d6b92ffaSHans Petter Selasky 	uint32_t i = 0;
276d6b92ffaSHans Petter Selasky 
277d6b92ffaSHans Petter Selasky 	/* allocate the memory for the heap object */
278d6b92ffaSHans Petter Selasky 	heap = (binary_heap_t *) malloc(sizeof(binary_heap_t));
279d6b92ffaSHans Petter Selasky 	if (!heap)
280d6b92ffaSHans Petter Selasky 		return 1;
281d6b92ffaSHans Petter Selasky 
282d6b92ffaSHans Petter Selasky 	/* the heap size is equivalent to the size of the adj_list */
283d6b92ffaSHans Petter Selasky 	heap->size = adj_list_size;
284d6b92ffaSHans Petter Selasky 
285d6b92ffaSHans Petter Selasky 	/* allocate the pointer array, fill with the pointers to the elements of the adj_list and set the initial heap_id */
286d6b92ffaSHans Petter Selasky 	heap->nodes = (vertex_t **) malloc(heap->size * sizeof(vertex_t *));
287d6b92ffaSHans Petter Selasky 	if (!heap->nodes) {
288d6b92ffaSHans Petter Selasky 		free(heap);
289d6b92ffaSHans Petter Selasky 		return 1;
290d6b92ffaSHans Petter Selasky 	}
291d6b92ffaSHans Petter Selasky 	for (i = 0; i < heap->size; i++) {
292d6b92ffaSHans Petter Selasky 		heap->nodes[i] = &adj_list[i];
293d6b92ffaSHans Petter Selasky 		heap->nodes[i]->heap_id = i;
294d6b92ffaSHans Petter Selasky 	}
295d6b92ffaSHans Petter Selasky 
296d6b92ffaSHans Petter Selasky 	/* sort elements */
297d6b92ffaSHans Petter Selasky 	for (i = heap->size; i > 0; i--)
298d6b92ffaSHans Petter Selasky 		heap_down(heap, i - 1);
299d6b92ffaSHans Petter Selasky 
300d6b92ffaSHans Petter Selasky 	*binheap = heap;
301d6b92ffaSHans Petter Selasky 	return 0;
302d6b92ffaSHans Petter Selasky }
303d6b92ffaSHans Petter Selasky 
304d6b92ffaSHans Petter Selasky /* returns current minimum and removes it from heap */
heap_getmin(binary_heap_t * heap)305d6b92ffaSHans Petter Selasky static vertex_t *heap_getmin(binary_heap_t * heap)
306d6b92ffaSHans Petter Selasky {
307d6b92ffaSHans Petter Selasky 	vertex_t *min = NULL;
308d6b92ffaSHans Petter Selasky 
309d6b92ffaSHans Petter Selasky 	if (heap->size > 0)
310d6b92ffaSHans Petter Selasky 		min = heap->nodes[0];
311d6b92ffaSHans Petter Selasky 
312d6b92ffaSHans Petter Selasky 	if (min == NULL)
313d6b92ffaSHans Petter Selasky 		return min;
314d6b92ffaSHans Petter Selasky 
315d6b92ffaSHans Petter Selasky 	if (heap->size > 0) {
316d6b92ffaSHans Petter Selasky 		if (heap->size > 1) {
317d6b92ffaSHans Petter Selasky 			heap_exchange(heap, 0, heap->size - 1);
318d6b92ffaSHans Petter Selasky 			heap->size--;
319d6b92ffaSHans Petter Selasky 			heap_down(heap, 0);
320d6b92ffaSHans Petter Selasky 		} else {
321d6b92ffaSHans Petter Selasky 			heap->size--;
322d6b92ffaSHans Petter Selasky 		}
323d6b92ffaSHans Petter Selasky 	}
324d6b92ffaSHans Petter Selasky 
325d6b92ffaSHans Petter Selasky 	return min;
326d6b92ffaSHans Petter Selasky }
327d6b92ffaSHans Petter Selasky 
328d6b92ffaSHans Petter Selasky /* cleanup heap */
heap_free(binary_heap_t * heap)329d6b92ffaSHans Petter Selasky static void heap_free(binary_heap_t * heap)
330d6b92ffaSHans Petter Selasky {
331d6b92ffaSHans Petter Selasky 	if (heap) {
332d6b92ffaSHans Petter Selasky 		if (heap->nodes) {
333d6b92ffaSHans Petter Selasky 			free(heap->nodes);
334d6b92ffaSHans Petter Selasky 			heap->nodes = NULL;
335d6b92ffaSHans Petter Selasky 		}
336d6b92ffaSHans Petter Selasky 		free(heap);
337d6b92ffaSHans Petter Selasky 	}
338d6b92ffaSHans Petter Selasky }
339d6b92ffaSHans Petter Selasky 
340d6b92ffaSHans Petter Selasky /**********************************************************************
341d6b92ffaSHans Petter Selasky  **********************************************************************/
342d6b92ffaSHans Petter Selasky 
343d6b92ffaSHans Petter Selasky /************ helper functions to save src/dest X vl combination ******
344d6b92ffaSHans Petter Selasky  **********************************************************************/
345d6b92ffaSHans Petter Selasky /* compare function of two lids for stdlib qsort */
cmp_lids(const void * l1,const void * l2)346d6b92ffaSHans Petter Selasky static int cmp_lids(const void *l1, const void *l2)
347d6b92ffaSHans Petter Selasky {
348d6b92ffaSHans Petter Selasky 	ib_net16_t lid1 = *((ib_net16_t *) l1), lid2 = *((ib_net16_t *) l2);
349d6b92ffaSHans Petter Selasky 
350d6b92ffaSHans Petter Selasky 	if (lid1 < lid2)
351d6b92ffaSHans Petter Selasky 		return -1;
352d6b92ffaSHans Petter Selasky 	else if (lid1 > lid2)
353d6b92ffaSHans Petter Selasky 		return 1;
354d6b92ffaSHans Petter Selasky 	else
355d6b92ffaSHans Petter Selasky 		return 0;
356d6b92ffaSHans Petter Selasky }
357d6b92ffaSHans Petter Selasky 
358d6b92ffaSHans Petter Selasky /* use stdlib to sort the lid array */
vltable_sort_lids(vltable_t * vltable)359d6b92ffaSHans Petter Selasky static inline void vltable_sort_lids(vltable_t * vltable)
360d6b92ffaSHans Petter Selasky {
361d6b92ffaSHans Petter Selasky 	qsort(vltable->lids, vltable->num_lids, sizeof(ib_net16_t), cmp_lids);
362d6b92ffaSHans Petter Selasky }
363d6b92ffaSHans Petter Selasky 
364d6b92ffaSHans Petter Selasky /* use stdlib to get index of key in lid array;
365d6b92ffaSHans Petter Selasky    return -1 if lid isn't found in lids array
366d6b92ffaSHans Petter Selasky */
vltable_get_lidindex(ib_net16_t * key,vltable_t * vltable)367d6b92ffaSHans Petter Selasky static inline int64_t vltable_get_lidindex(ib_net16_t * key, vltable_t * vltable)
368d6b92ffaSHans Petter Selasky {
369d6b92ffaSHans Petter Selasky 	ib_net16_t *found_lid = NULL;
370d6b92ffaSHans Petter Selasky 
371d6b92ffaSHans Petter Selasky 	found_lid =
372d6b92ffaSHans Petter Selasky 	    (ib_net16_t *) bsearch(key, vltable->lids, vltable->num_lids,
373d6b92ffaSHans Petter Selasky 				   sizeof(ib_net16_t), cmp_lids);
374d6b92ffaSHans Petter Selasky 	if (found_lid)
375d6b92ffaSHans Petter Selasky 		return found_lid - vltable->lids;
376d6b92ffaSHans Petter Selasky 	else
377d6b92ffaSHans Petter Selasky 		return -1;
378d6b92ffaSHans Petter Selasky }
379d6b92ffaSHans Petter Selasky 
380d6b92ffaSHans Petter Selasky /* get virtual lane from src lid X dest lid combination;
381d6b92ffaSHans Petter Selasky    return -1 for invalid lids
382d6b92ffaSHans Petter Selasky */
vltable_get_vl(vltable_t * vltable,ib_net16_t slid,ib_net16_t dlid)383d6b92ffaSHans Petter Selasky static int32_t vltable_get_vl(vltable_t * vltable, ib_net16_t slid, ib_net16_t dlid)
384d6b92ffaSHans Petter Selasky {
385d6b92ffaSHans Petter Selasky 	int64_t ind1 = vltable_get_lidindex(&slid, vltable);
386d6b92ffaSHans Petter Selasky 	int64_t ind2 = vltable_get_lidindex(&dlid, vltable);
387d6b92ffaSHans Petter Selasky 
388d6b92ffaSHans Petter Selasky 	if (ind1 > -1 && ind2 > -1)
389d6b92ffaSHans Petter Selasky 		return (int32_t) (vltable->
390d6b92ffaSHans Petter Selasky 				  vls[ind1 + ind2 * vltable->num_lids]);
391d6b92ffaSHans Petter Selasky 	else
392d6b92ffaSHans Petter Selasky 		return -1;
393d6b92ffaSHans Petter Selasky }
394d6b92ffaSHans Petter Selasky 
395d6b92ffaSHans Petter Selasky /* set a virtual lane in the matrix */
vltable_insert(vltable_t * vltable,ib_net16_t slid,ib_net16_t dlid,uint8_t vl)396d6b92ffaSHans Petter Selasky static inline void vltable_insert(vltable_t * vltable, ib_net16_t slid,
397d6b92ffaSHans Petter Selasky 				  ib_net16_t dlid, uint8_t vl)
398d6b92ffaSHans Petter Selasky {
399d6b92ffaSHans Petter Selasky 	int64_t ind1 = vltable_get_lidindex(&slid, vltable);
400d6b92ffaSHans Petter Selasky 	int64_t ind2 = vltable_get_lidindex(&dlid, vltable);
401d6b92ffaSHans Petter Selasky 
402d6b92ffaSHans Petter Selasky 	if (ind1 > -1 && ind2 > -1)
403d6b92ffaSHans Petter Selasky 		vltable->vls[ind1 + ind2 * vltable->num_lids] = vl;
404d6b92ffaSHans Petter Selasky }
405d6b92ffaSHans Petter Selasky 
406d6b92ffaSHans Petter Selasky /* change a number of lanes from lane xy to lane yz */
vltable_change_vl(vltable_t * vltable,uint8_t from,uint8_t to,uint64_t count)407d6b92ffaSHans Petter Selasky static void vltable_change_vl(vltable_t * vltable, uint8_t from, uint8_t to,
408d6b92ffaSHans Petter Selasky 			      uint64_t count)
409d6b92ffaSHans Petter Selasky {
410d6b92ffaSHans Petter Selasky 	uint64_t set = 0, stop = 0;
411d6b92ffaSHans Petter Selasky 	uint64_t ind1 = 0, ind2 = 0;
412d6b92ffaSHans Petter Selasky 
413d6b92ffaSHans Petter Selasky 	for (ind1 = 0; ind1 < vltable->num_lids; ind1++) {
414d6b92ffaSHans Petter Selasky 		for (ind2 = 0; ind2 < vltable->num_lids; ind2++) {
415d6b92ffaSHans Petter Selasky 			if (set == count) {
416d6b92ffaSHans Petter Selasky 				stop = 1;
417d6b92ffaSHans Petter Selasky 				break;
418d6b92ffaSHans Petter Selasky 			}
419d6b92ffaSHans Petter Selasky 			if (ind1 != ind2) {
420d6b92ffaSHans Petter Selasky 				if (vltable->
421d6b92ffaSHans Petter Selasky 				    vls[ind1 + ind2 * vltable->num_lids] ==
422d6b92ffaSHans Petter Selasky 				    from) {
423d6b92ffaSHans Petter Selasky 					vltable->vls[ind1 +
424d6b92ffaSHans Petter Selasky 						     ind2 * vltable->num_lids] =
425d6b92ffaSHans Petter Selasky 					    to;
426d6b92ffaSHans Petter Selasky 					set++;
427d6b92ffaSHans Petter Selasky 				}
428d6b92ffaSHans Petter Selasky 			}
429d6b92ffaSHans Petter Selasky 		}
430d6b92ffaSHans Petter Selasky 		if (stop)
431d6b92ffaSHans Petter Selasky 			break;
432d6b92ffaSHans Petter Selasky 	}
433d6b92ffaSHans Petter Selasky }
434d6b92ffaSHans Petter Selasky 
vltable_print(osm_ucast_mgr_t * p_mgr,vltable_t * vltable)435d6b92ffaSHans Petter Selasky static void vltable_print(osm_ucast_mgr_t * p_mgr, vltable_t * vltable)
436d6b92ffaSHans Petter Selasky {
437d6b92ffaSHans Petter Selasky 	uint64_t ind1 = 0, ind2 = 0;
438d6b92ffaSHans Petter Selasky 
439d6b92ffaSHans Petter Selasky 	for (ind1 = 0; ind1 < vltable->num_lids; ind1++) {
440d6b92ffaSHans Petter Selasky 		for (ind2 = 0; ind2 < vltable->num_lids; ind2++) {
441d6b92ffaSHans Petter Selasky 			if (ind1 != ind2) {
442d6b92ffaSHans Petter Selasky 				OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
443d6b92ffaSHans Petter Selasky 					"   route from src_lid=%" PRIu16
444d6b92ffaSHans Petter Selasky 					" to dest_lid=%" PRIu16 " on vl=%" PRIu8
445d6b92ffaSHans Petter Selasky 					"\n", cl_ntoh16(vltable->lids[ind1]),
446d6b92ffaSHans Petter Selasky 					cl_ntoh16(vltable->lids[ind2]),
447d6b92ffaSHans Petter Selasky 					vltable->vls[ind1 +
448d6b92ffaSHans Petter Selasky 						     ind2 * vltable->num_lids]);
449d6b92ffaSHans Petter Selasky 			}
450d6b92ffaSHans Petter Selasky 		}
451d6b92ffaSHans Petter Selasky 	}
452d6b92ffaSHans Petter Selasky }
453d6b92ffaSHans Petter Selasky 
vltable_dealloc(vltable_t ** vltable)454d6b92ffaSHans Petter Selasky static void vltable_dealloc(vltable_t ** vltable)
455d6b92ffaSHans Petter Selasky {
456d6b92ffaSHans Petter Selasky 	if (*vltable) {
457d6b92ffaSHans Petter Selasky 		if ((*vltable)->lids)
458d6b92ffaSHans Petter Selasky 			free((*vltable)->lids);
459d6b92ffaSHans Petter Selasky 		if ((*vltable)->vls)
460d6b92ffaSHans Petter Selasky 			free((*vltable)->vls);
461d6b92ffaSHans Petter Selasky 		free(*vltable);
462d6b92ffaSHans Petter Selasky 		*vltable = NULL;
463d6b92ffaSHans Petter Selasky 	}
464d6b92ffaSHans Petter Selasky }
465d6b92ffaSHans Petter Selasky 
vltable_alloc(vltable_t ** vltable,uint64_t size)466d6b92ffaSHans Petter Selasky static int vltable_alloc(vltable_t ** vltable, uint64_t size)
467d6b92ffaSHans Petter Selasky {
468d6b92ffaSHans Petter Selasky 	/* allocate VL table and indexing array */
469d6b92ffaSHans Petter Selasky 	*vltable = (vltable_t *) malloc(sizeof(vltable_t));
470d6b92ffaSHans Petter Selasky 	if (!(*vltable))
471d6b92ffaSHans Petter Selasky 		goto ERROR;
472d6b92ffaSHans Petter Selasky 	(*vltable)->num_lids = size;
473d6b92ffaSHans Petter Selasky 	(*vltable)->lids = (ib_net16_t *) malloc(size * sizeof(ib_net16_t));
474d6b92ffaSHans Petter Selasky 	if (!((*vltable)->lids))
475d6b92ffaSHans Petter Selasky 		goto ERROR;
476d6b92ffaSHans Petter Selasky 	(*vltable)->vls = (uint8_t *) malloc(size * size * sizeof(uint8_t));
477d6b92ffaSHans Petter Selasky 	if (!((*vltable)->vls))
478d6b92ffaSHans Petter Selasky 		goto ERROR;
479d6b92ffaSHans Petter Selasky 	memset((*vltable)->vls, OSM_DEFAULT_SL, size * size);
480d6b92ffaSHans Petter Selasky 
481d6b92ffaSHans Petter Selasky 	return 0;
482d6b92ffaSHans Petter Selasky 
483d6b92ffaSHans Petter Selasky ERROR:
484d6b92ffaSHans Petter Selasky 	vltable_dealloc(vltable);
485d6b92ffaSHans Petter Selasky 
486d6b92ffaSHans Petter Selasky 	return 1;
487d6b92ffaSHans Petter Selasky }
488d6b92ffaSHans Petter Selasky 
489d6b92ffaSHans Petter Selasky /**********************************************************************
490d6b92ffaSHans Petter Selasky  **********************************************************************/
491d6b92ffaSHans Petter Selasky 
492d6b92ffaSHans Petter Selasky /************ helper functions to save/manage the channel dep. graph **
493d6b92ffaSHans Petter Selasky  **********************************************************************/
494d6b92ffaSHans Petter Selasky /* update the srcdest array;
495d6b92ffaSHans Petter Selasky    realloc array (double the size) if size is not large enough
496d6b92ffaSHans Petter Selasky */
set_next_srcdest_pair(cdg_link_t * link,uint32_t srcdest)497d6b92ffaSHans Petter Selasky static void set_next_srcdest_pair(cdg_link_t * link, uint32_t srcdest)
498d6b92ffaSHans Petter Selasky {
499d6b92ffaSHans Petter Selasky 	uint32_t new_size = 0, start_size = 2;
500d6b92ffaSHans Petter Selasky 	uint32_t *tmp = NULL, *tmp2 = NULL;
501d6b92ffaSHans Petter Selasky 
502d6b92ffaSHans Petter Selasky 	if (link->num_pairs == 0) {
503d6b92ffaSHans Petter Selasky 		link->srcdest_pairs =
504d6b92ffaSHans Petter Selasky 		    (uint32_t *) malloc(start_size * sizeof(uint32_t));
505d6b92ffaSHans Petter Selasky 		link->srcdest_pairs[link->num_pairs] = srcdest;
506d6b92ffaSHans Petter Selasky 		link->max_len = start_size;
507d6b92ffaSHans Petter Selasky 		link->removed = 0;
508d6b92ffaSHans Petter Selasky 	} else if (link->num_pairs == link->max_len) {
509d6b92ffaSHans Petter Selasky 		new_size = link->max_len << 1;
510d6b92ffaSHans Petter Selasky 		tmp = (uint32_t *) malloc(new_size * sizeof(uint32_t));
511d6b92ffaSHans Petter Selasky 		tmp =
512d6b92ffaSHans Petter Selasky 		    memcpy(tmp, link->srcdest_pairs,
513d6b92ffaSHans Petter Selasky 			   link->max_len * sizeof(uint32_t));
514d6b92ffaSHans Petter Selasky 		tmp2 = link->srcdest_pairs;
515d6b92ffaSHans Petter Selasky 		link->srcdest_pairs = tmp;
516d6b92ffaSHans Petter Selasky 		link->srcdest_pairs[link->num_pairs] = srcdest;
517d6b92ffaSHans Petter Selasky 		free(tmp2);
518d6b92ffaSHans Petter Selasky 		link->max_len = new_size;
519d6b92ffaSHans Petter Selasky 	} else {
520d6b92ffaSHans Petter Selasky 		link->srcdest_pairs[link->num_pairs] = srcdest;
521d6b92ffaSHans Petter Selasky 	}
522d6b92ffaSHans Petter Selasky 	link->num_pairs++;
523d6b92ffaSHans Petter Selasky }
524d6b92ffaSHans Petter Selasky 
get_next_srcdest_pair(cdg_link_t * link,uint32_t index)525d6b92ffaSHans Petter Selasky static inline uint32_t get_next_srcdest_pair(cdg_link_t * link, uint32_t index)
526d6b92ffaSHans Petter Selasky {
527d6b92ffaSHans Petter Selasky 	return link->srcdest_pairs[index];
528d6b92ffaSHans Petter Selasky }
529d6b92ffaSHans Petter Selasky 
530d6b92ffaSHans Petter Selasky /* traverse binary tree to find a node */
cdg_search(cdg_node_t * root,uint64_t channelID)531d6b92ffaSHans Petter Selasky static cdg_node_t *cdg_search(cdg_node_t * root, uint64_t channelID)
532d6b92ffaSHans Petter Selasky {
533d6b92ffaSHans Petter Selasky 	while (root) {
534d6b92ffaSHans Petter Selasky 		if (channelID < root->channelID)
535d6b92ffaSHans Petter Selasky 			root = root->left;
536d6b92ffaSHans Petter Selasky 		else if (channelID > root->channelID)
537d6b92ffaSHans Petter Selasky 			root = root->right;
538d6b92ffaSHans Petter Selasky 		else if (channelID == root->channelID)
539d6b92ffaSHans Petter Selasky 			return root;
540d6b92ffaSHans Petter Selasky 	}
541d6b92ffaSHans Petter Selasky 	return NULL;
542d6b92ffaSHans Petter Selasky }
543d6b92ffaSHans Petter Selasky 
544d6b92ffaSHans Petter Selasky /* insert new node into the binary tree */
cdg_insert(cdg_node_t ** root,cdg_node_t * new_node)545d6b92ffaSHans Petter Selasky static void cdg_insert(cdg_node_t ** root, cdg_node_t * new_node)
546d6b92ffaSHans Petter Selasky {
547d6b92ffaSHans Petter Selasky 	cdg_node_t *current = *root;
548d6b92ffaSHans Petter Selasky 
549d6b92ffaSHans Petter Selasky 	if (!current) {
550d6b92ffaSHans Petter Selasky 		current = new_node;
551d6b92ffaSHans Petter Selasky 		*root = current;
552d6b92ffaSHans Petter Selasky 		return;
553d6b92ffaSHans Petter Selasky 	}
554d6b92ffaSHans Petter Selasky 
555d6b92ffaSHans Petter Selasky 	while (current) {
556d6b92ffaSHans Petter Selasky 		if (new_node->channelID < current->channelID) {
557d6b92ffaSHans Petter Selasky 			if (current->left) {
558d6b92ffaSHans Petter Selasky 				current = current->left;
559d6b92ffaSHans Petter Selasky 			} else {
560d6b92ffaSHans Petter Selasky 				current->left = new_node;
561d6b92ffaSHans Petter Selasky 				new_node->parent = current;
562d6b92ffaSHans Petter Selasky 				break;
563d6b92ffaSHans Petter Selasky 			}
564d6b92ffaSHans Petter Selasky 		} else if (new_node->channelID > current->channelID) {
565d6b92ffaSHans Petter Selasky 			if (current->right) {
566d6b92ffaSHans Petter Selasky 				current = current->right;
567d6b92ffaSHans Petter Selasky 			} else {
568d6b92ffaSHans Petter Selasky 				current->right = new_node;
569d6b92ffaSHans Petter Selasky 				new_node->parent = current;
570d6b92ffaSHans Petter Selasky 				break;
571d6b92ffaSHans Petter Selasky 			}
572d6b92ffaSHans Petter Selasky 		} else if (new_node->channelID == current->channelID) {
573d6b92ffaSHans Petter Selasky 			/* not really possible, maybe programming error */
574d6b92ffaSHans Petter Selasky 			break;
575d6b92ffaSHans Petter Selasky 		}
576d6b92ffaSHans Petter Selasky 	}
577d6b92ffaSHans Petter Selasky }
578d6b92ffaSHans Petter Selasky 
cdg_node_dealloc(cdg_node_t * node)579d6b92ffaSHans Petter Selasky static void cdg_node_dealloc(cdg_node_t * node)
580d6b92ffaSHans Petter Selasky {
581d6b92ffaSHans Petter Selasky 	cdg_link_t *link = node->linklist, *tmp = NULL;
582d6b92ffaSHans Petter Selasky 
583d6b92ffaSHans Petter Selasky 	/* dealloc linklist */
584d6b92ffaSHans Petter Selasky 	while (link) {
585d6b92ffaSHans Petter Selasky 		tmp = link;
586d6b92ffaSHans Petter Selasky 		link = link->next;
587d6b92ffaSHans Petter Selasky 
588d6b92ffaSHans Petter Selasky 		if (tmp->num_pairs)
589d6b92ffaSHans Petter Selasky 			free(tmp->srcdest_pairs);
590d6b92ffaSHans Petter Selasky 		free(tmp);
591d6b92ffaSHans Petter Selasky 	}
592d6b92ffaSHans Petter Selasky 	/* dealloc node */
593d6b92ffaSHans Petter Selasky 	free(node);
594d6b92ffaSHans Petter Selasky }
595d6b92ffaSHans Petter Selasky 
cdg_dealloc(cdg_node_t ** root)596d6b92ffaSHans Petter Selasky static void cdg_dealloc(cdg_node_t ** root)
597d6b92ffaSHans Petter Selasky {
598d6b92ffaSHans Petter Selasky 	cdg_node_t *current = *root;
599d6b92ffaSHans Petter Selasky 
600d6b92ffaSHans Petter Selasky 	while (current) {
601d6b92ffaSHans Petter Selasky 		if (current->left) {
602d6b92ffaSHans Petter Selasky 			current = current->left;
603d6b92ffaSHans Petter Selasky 		} else if (current->right) {
604d6b92ffaSHans Petter Selasky 			current = current->right;
605d6b92ffaSHans Petter Selasky 		} else {
606d6b92ffaSHans Petter Selasky 			if (current->parent == NULL) {
607d6b92ffaSHans Petter Selasky 				cdg_node_dealloc(current);
608d6b92ffaSHans Petter Selasky 				*root = NULL;
609d6b92ffaSHans Petter Selasky 				break;
610d6b92ffaSHans Petter Selasky 			}
611d6b92ffaSHans Petter Selasky 			if (current->parent->left == current) {
612d6b92ffaSHans Petter Selasky 				current = current->parent;
613d6b92ffaSHans Petter Selasky 				cdg_node_dealloc(current->left);
614d6b92ffaSHans Petter Selasky 				current->left = NULL;
615d6b92ffaSHans Petter Selasky 			} else if (current->parent->right == current) {
616d6b92ffaSHans Petter Selasky 				current = current->parent;
617d6b92ffaSHans Petter Selasky 				cdg_node_dealloc(current->right);
618d6b92ffaSHans Petter Selasky 				current->right = NULL;
619d6b92ffaSHans Petter Selasky 			}
620d6b92ffaSHans Petter Selasky 		}
621d6b92ffaSHans Petter Selasky 	}
622d6b92ffaSHans Petter Selasky }
623d6b92ffaSHans Petter Selasky 
624d6b92ffaSHans Petter Selasky /* search for a edge in the cdg which should be removed to break a cycle */
get_weakest_link_in_cycle(cdg_node_t * cycle)625d6b92ffaSHans Petter Selasky static cdg_link_t *get_weakest_link_in_cycle(cdg_node_t * cycle)
626d6b92ffaSHans Petter Selasky {
627d6b92ffaSHans Petter Selasky 	cdg_node_t *current = cycle, *node_with_weakest_link = NULL;
628d6b92ffaSHans Petter Selasky 	cdg_link_t *link = NULL, *weakest_link = NULL;
629d6b92ffaSHans Petter Selasky 
630d6b92ffaSHans Petter Selasky 	link = current->linklist;
631d6b92ffaSHans Petter Selasky 	while (link) {
632d6b92ffaSHans Petter Selasky 		if (link->node->status == GRAY) {
633d6b92ffaSHans Petter Selasky 			weakest_link = link;
634d6b92ffaSHans Petter Selasky 			node_with_weakest_link = current;
635d6b92ffaSHans Petter Selasky 			current = link->node;
636d6b92ffaSHans Petter Selasky 			break;
637d6b92ffaSHans Petter Selasky 		}
638d6b92ffaSHans Petter Selasky 		link = link->next;
639d6b92ffaSHans Petter Selasky 	}
640d6b92ffaSHans Petter Selasky 
641d6b92ffaSHans Petter Selasky 	while (1) {
642d6b92ffaSHans Petter Selasky 		current->status = UNKNOWN;
643d6b92ffaSHans Petter Selasky 		link = current->linklist;
644d6b92ffaSHans Petter Selasky 		while (link) {
645d6b92ffaSHans Petter Selasky 			if (link->node->status == GRAY) {
646d6b92ffaSHans Petter Selasky 				if ((link->num_pairs - link->removed) <
647d6b92ffaSHans Petter Selasky 				    (weakest_link->num_pairs -
648d6b92ffaSHans Petter Selasky 				     weakest_link->removed)) {
649d6b92ffaSHans Petter Selasky 					weakest_link = link;
650d6b92ffaSHans Petter Selasky 					node_with_weakest_link = current;
651d6b92ffaSHans Petter Selasky 				}
652d6b92ffaSHans Petter Selasky 				current = link->node;
653d6b92ffaSHans Petter Selasky 				break;
654d6b92ffaSHans Petter Selasky 			}
655d6b92ffaSHans Petter Selasky 			link = link->next;
656d6b92ffaSHans Petter Selasky 		}
657d6b92ffaSHans Petter Selasky 		/* if complete cycle is traversed */
658d6b92ffaSHans Petter Selasky 		if (current == cycle) {
659d6b92ffaSHans Petter Selasky 			current->status = UNKNOWN;
660d6b92ffaSHans Petter Selasky 			break;
661d6b92ffaSHans Petter Selasky 		}
662d6b92ffaSHans Petter Selasky 	}
663d6b92ffaSHans Petter Selasky 
664d6b92ffaSHans Petter Selasky 	if (node_with_weakest_link->linklist == weakest_link) {
665d6b92ffaSHans Petter Selasky 		node_with_weakest_link->linklist = weakest_link->next;
666d6b92ffaSHans Petter Selasky 	} else {
667d6b92ffaSHans Petter Selasky 		link = node_with_weakest_link->linklist;
668d6b92ffaSHans Petter Selasky 		while (link) {
669d6b92ffaSHans Petter Selasky 			if (link->next == weakest_link) {
670d6b92ffaSHans Petter Selasky 				link->next = weakest_link->next;
671d6b92ffaSHans Petter Selasky 				break;
672d6b92ffaSHans Petter Selasky 			}
673d6b92ffaSHans Petter Selasky 			link = link->next;
674d6b92ffaSHans Petter Selasky 		}
675d6b92ffaSHans Petter Selasky 	}
676d6b92ffaSHans Petter Selasky 
677d6b92ffaSHans Petter Selasky 	return weakest_link;
678d6b92ffaSHans Petter Selasky }
679d6b92ffaSHans Petter Selasky 
680d6b92ffaSHans Petter Selasky /* search for nodes in the cdg not yet reached in the cycle search process;
681d6b92ffaSHans Petter Selasky    (some nodes are unreachable, e.g. a node is a source or the cdg has not connected parts)
682d6b92ffaSHans Petter Selasky */
get_next_cdg_node(cdg_node_t * root)683d6b92ffaSHans Petter Selasky static cdg_node_t *get_next_cdg_node(cdg_node_t * root)
684d6b92ffaSHans Petter Selasky {
685d6b92ffaSHans Petter Selasky 	cdg_node_t *current = root, *res = NULL;
686d6b92ffaSHans Petter Selasky 
687d6b92ffaSHans Petter Selasky 	while (current) {
688d6b92ffaSHans Petter Selasky 		current->visited = 1;
689d6b92ffaSHans Petter Selasky 		if (current->status == UNKNOWN) {
690d6b92ffaSHans Petter Selasky 			res = current;
691d6b92ffaSHans Petter Selasky 			break;
692d6b92ffaSHans Petter Selasky 		}
693d6b92ffaSHans Petter Selasky 		if (current->left && !current->left->visited) {
694d6b92ffaSHans Petter Selasky 			current = current->left;
695d6b92ffaSHans Petter Selasky 		} else if (current->right && !current->right->visited) {
696d6b92ffaSHans Petter Selasky 			current = current->right;
697d6b92ffaSHans Petter Selasky 		} else {
698d6b92ffaSHans Petter Selasky 			if (current->left)
699d6b92ffaSHans Petter Selasky 				current->left->visited = 0;
700d6b92ffaSHans Petter Selasky 			if (current->right)
701d6b92ffaSHans Petter Selasky 				current->right->visited = 0;
702d6b92ffaSHans Petter Selasky 			if (current->parent == NULL)
703d6b92ffaSHans Petter Selasky 				break;
704d6b92ffaSHans Petter Selasky 			else
705d6b92ffaSHans Petter Selasky 				current = current->parent;
706d6b92ffaSHans Petter Selasky 		}
707d6b92ffaSHans Petter Selasky 	}
708d6b92ffaSHans Petter Selasky 
709d6b92ffaSHans Petter Selasky 	/* Clean up */
710d6b92ffaSHans Petter Selasky 	while (current) {
711d6b92ffaSHans Petter Selasky 		current->visited = 0;
712d6b92ffaSHans Petter Selasky 		if (current->left)
713d6b92ffaSHans Petter Selasky 			current->left->visited = 0;
714d6b92ffaSHans Petter Selasky 		if (current->right)
715d6b92ffaSHans Petter Selasky 			current->right->visited = 0;
716d6b92ffaSHans Petter Selasky 		current = current->parent;
717d6b92ffaSHans Petter Selasky 	}
718d6b92ffaSHans Petter Selasky 
719d6b92ffaSHans Petter Selasky 	return res;
720d6b92ffaSHans Petter Selasky }
721d6b92ffaSHans Petter Selasky 
722d6b92ffaSHans Petter Selasky /* make a DFS on the cdg to check for a cycle */
search_cycle_in_channel_dep_graph(cdg_node_t * cdg,cdg_node_t * start_node)723d6b92ffaSHans Petter Selasky static cdg_node_t *search_cycle_in_channel_dep_graph(cdg_node_t * cdg,
724d6b92ffaSHans Petter Selasky 						     cdg_node_t * start_node)
725d6b92ffaSHans Petter Selasky {
726d6b92ffaSHans Petter Selasky 	cdg_node_t *cycle = NULL;
727d6b92ffaSHans Petter Selasky 	cdg_node_t *current = start_node, *next_node = NULL, *tmp = NULL;
728d6b92ffaSHans Petter Selasky 	cdg_link_t *link = NULL;
729d6b92ffaSHans Petter Selasky 
730d6b92ffaSHans Petter Selasky 	while (current) {
731d6b92ffaSHans Petter Selasky 		current->status = GRAY;
732d6b92ffaSHans Petter Selasky 		link = current->linklist;
733d6b92ffaSHans Petter Selasky 		next_node = NULL;
734d6b92ffaSHans Petter Selasky 		while (link) {
735d6b92ffaSHans Petter Selasky 			if (link->node->status == UNKNOWN) {
736d6b92ffaSHans Petter Selasky 				next_node = link->node;
737d6b92ffaSHans Petter Selasky 				break;
738d6b92ffaSHans Petter Selasky 			}
739d6b92ffaSHans Petter Selasky 			if (link->node->status == GRAY) {
740d6b92ffaSHans Petter Selasky 				cycle = link->node;
741d6b92ffaSHans Petter Selasky 				goto Exit;
742d6b92ffaSHans Petter Selasky 			}
743d6b92ffaSHans Petter Selasky 			link = link->next;
744d6b92ffaSHans Petter Selasky 		}
745d6b92ffaSHans Petter Selasky 		if (next_node) {
746d6b92ffaSHans Petter Selasky 			next_node->pre = current;
747d6b92ffaSHans Petter Selasky 			current = next_node;
748d6b92ffaSHans Petter Selasky 		} else {
749d6b92ffaSHans Petter Selasky 			/* found a sink in the graph, go to last node */
750d6b92ffaSHans Petter Selasky 			current->status = BLACK;
751d6b92ffaSHans Petter Selasky 
752d6b92ffaSHans Petter Selasky 			/* srcdest_pairs of this node aren't relevant, free the allocated memory */
753d6b92ffaSHans Petter Selasky 			link = current->linklist;
754d6b92ffaSHans Petter Selasky 			while (link) {
755d6b92ffaSHans Petter Selasky 				if (link->num_pairs)
756d6b92ffaSHans Petter Selasky 					free(link->srcdest_pairs);
757d6b92ffaSHans Petter Selasky 				link->srcdest_pairs = NULL;
758d6b92ffaSHans Petter Selasky 				link->num_pairs = 0;
759d6b92ffaSHans Petter Selasky 				link->removed = 0;
760d6b92ffaSHans Petter Selasky 				link = link->next;
761d6b92ffaSHans Petter Selasky 			}
762d6b92ffaSHans Petter Selasky 
763d6b92ffaSHans Petter Selasky 			if (current->pre) {
764d6b92ffaSHans Petter Selasky 				tmp = current;
765d6b92ffaSHans Petter Selasky 				current = current->pre;
766d6b92ffaSHans Petter Selasky 				tmp->pre = NULL;
767d6b92ffaSHans Petter Selasky 			} else {
768d6b92ffaSHans Petter Selasky 				/* search for other subgraphs in cdg */
769d6b92ffaSHans Petter Selasky 				current = get_next_cdg_node(cdg);
770d6b92ffaSHans Petter Selasky 				if (!current)
771d6b92ffaSHans Petter Selasky 					break;	/* all relevant nodes traversed, no more cycles found */
772d6b92ffaSHans Petter Selasky 			}
773d6b92ffaSHans Petter Selasky 		}
774d6b92ffaSHans Petter Selasky 	}
775d6b92ffaSHans Petter Selasky 
776d6b92ffaSHans Petter Selasky Exit:
777d6b92ffaSHans Petter Selasky 	return cycle;
778d6b92ffaSHans Petter Selasky }
779d6b92ffaSHans Petter Selasky 
780d6b92ffaSHans Petter Selasky /* calculate the path from source to destination port;
781d6b92ffaSHans Petter Selasky    new channels are added directly to the cdg
782d6b92ffaSHans Petter Selasky */
update_channel_dep_graph(cdg_node_t ** cdg_root,osm_port_t * src_port,uint16_t slid,osm_port_t * dest_port,uint16_t dlid)783d6b92ffaSHans Petter Selasky static int update_channel_dep_graph(cdg_node_t ** cdg_root,
784d6b92ffaSHans Petter Selasky 				    osm_port_t * src_port, uint16_t slid,
785d6b92ffaSHans Petter Selasky 				    osm_port_t * dest_port, uint16_t dlid)
786d6b92ffaSHans Petter Selasky {
787d6b92ffaSHans Petter Selasky 	osm_node_t *local_node = NULL, *remote_node = NULL;
788d6b92ffaSHans Petter Selasky 	uint16_t local_lid = 0, remote_lid = 0;
789d6b92ffaSHans Petter Selasky 	uint32_t srcdest = 0;
790d6b92ffaSHans Petter Selasky 	uint8_t local_port = 0, remote_port = 0;
791d6b92ffaSHans Petter Selasky 	uint64_t channelID = 0;
792d6b92ffaSHans Petter Selasky 
793d6b92ffaSHans Petter Selasky 	cdg_node_t *channel_head = NULL, *channel = NULL, *last_channel = NULL;
794d6b92ffaSHans Petter Selasky 	cdg_link_t *linklist = NULL;
795d6b92ffaSHans Petter Selasky 
796d6b92ffaSHans Petter Selasky 	/* set the identifier for the src/dest pair to save this on each edge of the cdg */
797d6b92ffaSHans Petter Selasky 	srcdest = (((uint32_t) slid) << 16) + ((uint32_t) dlid);
798d6b92ffaSHans Petter Selasky 
799d6b92ffaSHans Petter Selasky 	channel_head = (cdg_node_t *) malloc(sizeof(cdg_node_t));
800d6b92ffaSHans Petter Selasky 	if (!channel_head)
801d6b92ffaSHans Petter Selasky 		goto ERROR;
802d6b92ffaSHans Petter Selasky 	set_default_cdg_node(channel_head);
803d6b92ffaSHans Petter Selasky 	last_channel = channel_head;
804d6b92ffaSHans Petter Selasky 
805d6b92ffaSHans Petter Selasky 	/* if src is a Hca, then the channel from Hca to switch would be a source in the graph
806d6b92ffaSHans Petter Selasky 	   sources can't be part of a cycle -> skip this channel
807d6b92ffaSHans Petter Selasky 	 */
808d6b92ffaSHans Petter Selasky 	remote_node =
809d6b92ffaSHans Petter Selasky 	    osm_node_get_remote_node(src_port->p_node,
810d6b92ffaSHans Petter Selasky 				     src_port->p_physp->port_num, &remote_port);
811d6b92ffaSHans Petter Selasky 
812d6b92ffaSHans Petter Selasky 	while (remote_node && remote_node->sw) {
813d6b92ffaSHans Petter Selasky 		local_node = remote_node;
814d6b92ffaSHans Petter Selasky 		local_port = local_node->sw->new_lft[dlid];
815d6b92ffaSHans Petter Selasky 		/* sanity check: local_port must be set or routing is broken */
816d6b92ffaSHans Petter Selasky 		if (local_port == OSM_NO_PATH)
817d6b92ffaSHans Petter Selasky 			goto ERROR;
818d6b92ffaSHans Petter Selasky 		local_lid = cl_ntoh16(osm_node_get_base_lid(local_node, 0));
819d6b92ffaSHans Petter Selasky 		/* each port belonging to a switch has lmc==0 -> get_base_lid is fine
820d6b92ffaSHans Petter Selasky 		   (local/remote port in this function are always part of a switch)
821d6b92ffaSHans Petter Selasky 		 */
822d6b92ffaSHans Petter Selasky 
823d6b92ffaSHans Petter Selasky 		remote_node =
824d6b92ffaSHans Petter Selasky 		    osm_node_get_remote_node(local_node, local_port,
825d6b92ffaSHans Petter Selasky 					     &remote_port);
826d6b92ffaSHans Petter Selasky 		/* if remote_node is a Hca, then the last channel from switch to Hca would be a sink in the cdg -> skip */
827d6b92ffaSHans Petter Selasky 		if (!remote_node || !remote_node->sw)
828d6b92ffaSHans Petter Selasky 			break;
829d6b92ffaSHans Petter Selasky 		remote_lid = cl_ntoh16(osm_node_get_base_lid(remote_node, 0));
830d6b92ffaSHans Petter Selasky 
831d6b92ffaSHans Petter Selasky 		channelID =
832d6b92ffaSHans Petter Selasky 		    (((uint64_t) local_lid) << 48) +
833d6b92ffaSHans Petter Selasky 		    (((uint64_t) local_port) << 32) +
834d6b92ffaSHans Petter Selasky 		    (((uint64_t) remote_lid) << 16) + ((uint64_t) remote_port);
835d6b92ffaSHans Petter Selasky 		channel = cdg_search(*cdg_root, channelID);
836d6b92ffaSHans Petter Selasky 		if (channel) {
837d6b92ffaSHans Petter Selasky 			/* check whether last channel has connection to this channel, i.e. subpath already exists in cdg */
838d6b92ffaSHans Petter Selasky 			linklist = last_channel->linklist;
839d6b92ffaSHans Petter Selasky 			while (linklist && linklist->node != channel
840d6b92ffaSHans Petter Selasky 			       && linklist->next)
841d6b92ffaSHans Petter Selasky 				linklist = linklist->next;
842d6b92ffaSHans Petter Selasky 			/* if there is no connection, add one */
843d6b92ffaSHans Petter Selasky 			if (linklist) {
844d6b92ffaSHans Petter Selasky 				if (linklist->node == channel) {
845d6b92ffaSHans Petter Selasky 					set_next_srcdest_pair(linklist,
846d6b92ffaSHans Petter Selasky 							      srcdest);
847d6b92ffaSHans Petter Selasky 				} else {
848d6b92ffaSHans Petter Selasky 					linklist->next =
849d6b92ffaSHans Petter Selasky 					    (cdg_link_t *)
850d6b92ffaSHans Petter Selasky 					    malloc(sizeof(cdg_link_t));
851d6b92ffaSHans Petter Selasky 					if (!linklist->next)
852d6b92ffaSHans Petter Selasky 						goto ERROR;
853d6b92ffaSHans Petter Selasky 					linklist = linklist->next;
854d6b92ffaSHans Petter Selasky 					linklist->node = channel;
855d6b92ffaSHans Petter Selasky 					linklist->num_pairs = 0;
856d6b92ffaSHans Petter Selasky 					linklist->srcdest_pairs = NULL;
857d6b92ffaSHans Petter Selasky 					set_next_srcdest_pair(linklist,
858d6b92ffaSHans Petter Selasky 							      srcdest);
859d6b92ffaSHans Petter Selasky 					linklist->next = NULL;
860d6b92ffaSHans Petter Selasky 				}
861d6b92ffaSHans Petter Selasky 			} else {
862d6b92ffaSHans Petter Selasky 				/* either this is the first channel of the path, or the last channel was a new channel, or last channel was a sink */
863d6b92ffaSHans Petter Selasky 				last_channel->linklist =
864d6b92ffaSHans Petter Selasky 				    (cdg_link_t *) malloc(sizeof(cdg_link_t));
865d6b92ffaSHans Petter Selasky 				if (!last_channel->linklist)
866d6b92ffaSHans Petter Selasky 					goto ERROR;
867d6b92ffaSHans Petter Selasky 				last_channel->linklist->node = channel;
868d6b92ffaSHans Petter Selasky 				last_channel->linklist->num_pairs = 0;
869d6b92ffaSHans Petter Selasky 				last_channel->linklist->srcdest_pairs = NULL;
870d6b92ffaSHans Petter Selasky 				set_next_srcdest_pair(last_channel->linklist,
871d6b92ffaSHans Petter Selasky 						      srcdest);
872d6b92ffaSHans Petter Selasky 				last_channel->linklist->next = NULL;
873d6b92ffaSHans Petter Selasky 			}
874d6b92ffaSHans Petter Selasky 		} else {
875d6b92ffaSHans Petter Selasky 			/* create new channel */
876d6b92ffaSHans Petter Selasky 			channel = (cdg_node_t *) malloc(sizeof(cdg_node_t));
877d6b92ffaSHans Petter Selasky 			if (!channel)
878d6b92ffaSHans Petter Selasky 				goto ERROR;
879d6b92ffaSHans Petter Selasky 			set_default_cdg_node(channel);
880d6b92ffaSHans Petter Selasky 			channel->channelID = channelID;
881d6b92ffaSHans Petter Selasky 			cdg_insert(cdg_root, channel);
882d6b92ffaSHans Petter Selasky 
883d6b92ffaSHans Petter Selasky 			/* go to end of link list of last channel */
884d6b92ffaSHans Petter Selasky 			linklist = last_channel->linklist;
885d6b92ffaSHans Petter Selasky 			while (linklist && linklist->next)
886d6b92ffaSHans Petter Selasky 				linklist = linklist->next;
887d6b92ffaSHans Petter Selasky 			if (linklist) {
888d6b92ffaSHans Petter Selasky 				/* update last link of an existing channel */
889d6b92ffaSHans Petter Selasky 				linklist->next =
890d6b92ffaSHans Petter Selasky 				    (cdg_link_t *) malloc(sizeof(cdg_link_t));
891d6b92ffaSHans Petter Selasky 				if (!linklist->next)
892d6b92ffaSHans Petter Selasky 					goto ERROR;
893d6b92ffaSHans Petter Selasky 				linklist = linklist->next;
894d6b92ffaSHans Petter Selasky 				linklist->node = channel;
895d6b92ffaSHans Petter Selasky 				linklist->num_pairs = 0;
896d6b92ffaSHans Petter Selasky 				linklist->srcdest_pairs = NULL;
897d6b92ffaSHans Petter Selasky 				set_next_srcdest_pair(linklist, srcdest);
898d6b92ffaSHans Petter Selasky 				linklist->next = NULL;
899d6b92ffaSHans Petter Selasky 			} else {
900d6b92ffaSHans Petter Selasky 				/* either this is the first channel of the path, or the last channel was a new channel, or last channel was a sink */
901d6b92ffaSHans Petter Selasky 				last_channel->linklist =
902d6b92ffaSHans Petter Selasky 				    (cdg_link_t *) malloc(sizeof(cdg_link_t));
903d6b92ffaSHans Petter Selasky 				if (!last_channel->linklist)
904d6b92ffaSHans Petter Selasky 					goto ERROR;
905d6b92ffaSHans Petter Selasky 				last_channel->linklist->node = channel;
906d6b92ffaSHans Petter Selasky 				last_channel->linklist->num_pairs = 0;
907d6b92ffaSHans Petter Selasky 				last_channel->linklist->srcdest_pairs = NULL;
908d6b92ffaSHans Petter Selasky 				set_next_srcdest_pair(last_channel->linklist,
909d6b92ffaSHans Petter Selasky 						      srcdest);
910d6b92ffaSHans Petter Selasky 				last_channel->linklist->next = NULL;
911d6b92ffaSHans Petter Selasky 			}
912d6b92ffaSHans Petter Selasky 		}
913d6b92ffaSHans Petter Selasky 		last_channel = channel;
914d6b92ffaSHans Petter Selasky 	}
915d6b92ffaSHans Petter Selasky 
916d6b92ffaSHans Petter Selasky 	if (channel_head->linklist) {
917d6b92ffaSHans Petter Selasky 		if (channel_head->linklist->srcdest_pairs)
918d6b92ffaSHans Petter Selasky 			free(channel_head->linklist->srcdest_pairs);
919d6b92ffaSHans Petter Selasky 		free(channel_head->linklist);
920d6b92ffaSHans Petter Selasky 	}
921d6b92ffaSHans Petter Selasky 	free(channel_head);
922d6b92ffaSHans Petter Selasky 
923d6b92ffaSHans Petter Selasky 	return 0;
924d6b92ffaSHans Petter Selasky 
925d6b92ffaSHans Petter Selasky ERROR:
926d6b92ffaSHans Petter Selasky 	/* cleanup data and exit */
927d6b92ffaSHans Petter Selasky 	if (channel_head) {
928d6b92ffaSHans Petter Selasky 		if (channel_head->linklist)
929d6b92ffaSHans Petter Selasky 			free(channel_head->linklist);
930d6b92ffaSHans Petter Selasky 		free(channel_head);
931d6b92ffaSHans Petter Selasky 	}
932d6b92ffaSHans Petter Selasky 
933d6b92ffaSHans Petter Selasky 	return 1;
934d6b92ffaSHans Petter Selasky }
935d6b92ffaSHans Petter Selasky 
936d6b92ffaSHans Petter Selasky /* calculate the path from source to destination port;
937d6b92ffaSHans Petter Selasky    the links in the cdg representing this path are decremented to simulate the removal
938d6b92ffaSHans Petter Selasky */
remove_path_from_cdg(cdg_node_t ** cdg_root,osm_port_t * src_port,uint16_t slid,osm_port_t * dest_port,uint16_t dlid)939d6b92ffaSHans Petter Selasky static int remove_path_from_cdg(cdg_node_t ** cdg_root, osm_port_t * src_port,
940d6b92ffaSHans Petter Selasky 				uint16_t slid, osm_port_t * dest_port,
941d6b92ffaSHans Petter Selasky 				uint16_t dlid)
942d6b92ffaSHans Petter Selasky {
943d6b92ffaSHans Petter Selasky 	osm_node_t *local_node = NULL, *remote_node = NULL;
944d6b92ffaSHans Petter Selasky 	uint16_t local_lid = 0, remote_lid = 0;
945d6b92ffaSHans Petter Selasky 	uint8_t local_port = 0, remote_port = 0;
946d6b92ffaSHans Petter Selasky 	uint64_t channelID = 0;
947d6b92ffaSHans Petter Selasky 
948d6b92ffaSHans Petter Selasky 	cdg_node_t *channel_head = NULL, *channel = NULL, *last_channel = NULL;
949d6b92ffaSHans Petter Selasky 	cdg_link_t *linklist = NULL;
950d6b92ffaSHans Petter Selasky 
951d6b92ffaSHans Petter Selasky 	channel_head = (cdg_node_t *) malloc(sizeof(cdg_node_t));
952d6b92ffaSHans Petter Selasky 	if (!channel_head)
953d6b92ffaSHans Petter Selasky 		goto ERROR;
954d6b92ffaSHans Petter Selasky 	set_default_cdg_node(channel_head);
955d6b92ffaSHans Petter Selasky 	last_channel = channel_head;
956d6b92ffaSHans Petter Selasky 
957d6b92ffaSHans Petter Selasky 	/* if src is a Hca, then the channel from Hca to switch would be a source in the graph
958d6b92ffaSHans Petter Selasky 	   sources can't be part of a cycle -> skip this channel
959d6b92ffaSHans Petter Selasky 	 */
960d6b92ffaSHans Petter Selasky 	remote_node =
961d6b92ffaSHans Petter Selasky 	    osm_node_get_remote_node(src_port->p_node,
962d6b92ffaSHans Petter Selasky 				     src_port->p_physp->port_num, &remote_port);
963d6b92ffaSHans Petter Selasky 
964d6b92ffaSHans Petter Selasky 	while (remote_node && remote_node->sw) {
965d6b92ffaSHans Petter Selasky 		local_node = remote_node;
966d6b92ffaSHans Petter Selasky 		local_port = local_node->sw->new_lft[dlid];
967d6b92ffaSHans Petter Selasky 		/* sanity check: local_port must be set or routing is broken */
968d6b92ffaSHans Petter Selasky 		if (local_port == OSM_NO_PATH)
969d6b92ffaSHans Petter Selasky 			goto ERROR;
970d6b92ffaSHans Petter Selasky 		local_lid = cl_ntoh16(osm_node_get_base_lid(local_node, 0));
971d6b92ffaSHans Petter Selasky 
972d6b92ffaSHans Petter Selasky 		remote_node =
973d6b92ffaSHans Petter Selasky 		    osm_node_get_remote_node(local_node, local_port,
974d6b92ffaSHans Petter Selasky 					     &remote_port);
975d6b92ffaSHans Petter Selasky 		/* if remote_node is a Hca, then the last channel from switch to Hca would be a sink in the cdg -> skip */
976d6b92ffaSHans Petter Selasky 		if (!remote_node || !remote_node->sw)
977d6b92ffaSHans Petter Selasky 			break;
978d6b92ffaSHans Petter Selasky 		remote_lid = cl_ntoh16(osm_node_get_base_lid(remote_node, 0));
979d6b92ffaSHans Petter Selasky 
980d6b92ffaSHans Petter Selasky 		channelID =
981d6b92ffaSHans Petter Selasky 		    (((uint64_t) local_lid) << 48) +
982d6b92ffaSHans Petter Selasky 		    (((uint64_t) local_port) << 32) +
983d6b92ffaSHans Petter Selasky 		    (((uint64_t) remote_lid) << 16) + ((uint64_t) remote_port);
984d6b92ffaSHans Petter Selasky 		channel = cdg_search(*cdg_root, channelID);
985d6b92ffaSHans Petter Selasky 		if (channel) {
986d6b92ffaSHans Petter Selasky 			/* check whether last channel has connection to this channel, i.e. subpath already exists in cdg */
987d6b92ffaSHans Petter Selasky 			linklist = last_channel->linklist;
988d6b92ffaSHans Petter Selasky 			while (linklist && linklist->node != channel
989d6b92ffaSHans Petter Selasky 			       && linklist->next)
990d6b92ffaSHans Petter Selasky 				linklist = linklist->next;
991d6b92ffaSHans Petter Selasky 			/* remove the srcdest from the link */
992d6b92ffaSHans Petter Selasky 			if (linklist) {
993d6b92ffaSHans Petter Selasky 				if (linklist->node == channel) {
994d6b92ffaSHans Petter Selasky 					linklist->removed++;
995d6b92ffaSHans Petter Selasky 				} else {
996d6b92ffaSHans Petter Selasky 					/* may happen if the link is missing (thru cycle detect algorithm) */
997d6b92ffaSHans Petter Selasky 				}
998d6b92ffaSHans Petter Selasky 			} else {
999d6b92ffaSHans Petter Selasky 				/* may happen if the link is missing (thru cycle detect algorithm or last_channel==channel_head (dummy channel)) */
1000d6b92ffaSHans Petter Selasky 			}
1001d6b92ffaSHans Petter Selasky 		} else {
1002d6b92ffaSHans Petter Selasky 			/* must be an error, channels for the path are added before, so a missing channel would be a corrupt data structure */
1003d6b92ffaSHans Petter Selasky 			goto ERROR;
1004d6b92ffaSHans Petter Selasky 		}
1005d6b92ffaSHans Petter Selasky 		last_channel = channel;
1006d6b92ffaSHans Petter Selasky 	}
1007d6b92ffaSHans Petter Selasky 
1008d6b92ffaSHans Petter Selasky 	if (channel_head->linklist)
1009d6b92ffaSHans Petter Selasky 		free(channel_head->linklist);
1010d6b92ffaSHans Petter Selasky 	free(channel_head);
1011d6b92ffaSHans Petter Selasky 
1012d6b92ffaSHans Petter Selasky 	return 0;
1013d6b92ffaSHans Petter Selasky 
1014d6b92ffaSHans Petter Selasky ERROR:
1015d6b92ffaSHans Petter Selasky 	/* cleanup data and exit */
1016d6b92ffaSHans Petter Selasky 	if (channel_head) {
1017d6b92ffaSHans Petter Selasky 		if (channel_head->linklist)
1018d6b92ffaSHans Petter Selasky 			free(channel_head->linklist);
1019d6b92ffaSHans Petter Selasky 		free(channel_head);
1020d6b92ffaSHans Petter Selasky 	}
1021d6b92ffaSHans Petter Selasky 
1022d6b92ffaSHans Petter Selasky 	return 1;
1023d6b92ffaSHans Petter Selasky }
1024d6b92ffaSHans Petter Selasky 
1025d6b92ffaSHans Petter Selasky /**********************************************************************
1026d6b92ffaSHans Petter Selasky  **********************************************************************/
1027d6b92ffaSHans Petter Selasky 
1028d6b92ffaSHans Petter Selasky /************ helper functions to generate an ordered list of ports ***
1029d6b92ffaSHans Petter Selasky  ************ (functions copied from osm_ucast_mgr.c and modified) ****
1030d6b92ffaSHans Petter Selasky  **********************************************************************/
add_sw_endports_to_order_list(osm_switch_t * sw,osm_ucast_mgr_t * m,cl_qmap_t * guid_tbl,boolean_t add_guids)1031d6b92ffaSHans Petter Selasky static void add_sw_endports_to_order_list(osm_switch_t * sw,
1032d6b92ffaSHans Petter Selasky 					  osm_ucast_mgr_t * m,
1033d6b92ffaSHans Petter Selasky 					  cl_qmap_t * guid_tbl,
1034d6b92ffaSHans Petter Selasky 					  boolean_t add_guids)
1035d6b92ffaSHans Petter Selasky {
1036d6b92ffaSHans Petter Selasky 	osm_port_t *port;
1037d6b92ffaSHans Petter Selasky 	ib_net64_t port_guid;
1038d6b92ffaSHans Petter Selasky 	uint64_t sw_guid;
1039d6b92ffaSHans Petter Selasky 	osm_physp_t *p;
1040d6b92ffaSHans Petter Selasky 	int i;
1041d6b92ffaSHans Petter Selasky 	boolean_t found;
1042d6b92ffaSHans Petter Selasky 
1043d6b92ffaSHans Petter Selasky 	for (i = 1; i < sw->num_ports; i++) {
1044d6b92ffaSHans Petter Selasky 		p = osm_node_get_physp_ptr(sw->p_node, i);
1045d6b92ffaSHans Petter Selasky 		if (p && p->p_remote_physp && !p->p_remote_physp->p_node->sw) {
1046d6b92ffaSHans Petter Selasky 			port_guid = p->p_remote_physp->port_guid;
1047d6b92ffaSHans Petter Selasky 			/* check if link is healthy, otherwise ignore CA */
1048d6b92ffaSHans Petter Selasky 			if (!osm_link_is_healthy(p)) {
1049d6b92ffaSHans Petter Selasky 				sw_guid =
1050d6b92ffaSHans Petter Selasky 				    cl_ntoh64(osm_node_get_node_guid
1051d6b92ffaSHans Petter Selasky 					      (sw->p_node));
1052d6b92ffaSHans Petter Selasky 				OSM_LOG(m->p_log, OSM_LOG_INFO,
1053d6b92ffaSHans Petter Selasky 					"WRN AD40: ignoring CA due to unhealthy"
1054d6b92ffaSHans Petter Selasky 					" link from switch 0x%016" PRIx64
1055d6b92ffaSHans Petter Selasky 					" port %" PRIu8 " to CA 0x%016" PRIx64
1056d6b92ffaSHans Petter Selasky 					"\n", sw_guid, i, cl_ntoh64(port_guid));
1057d6b92ffaSHans Petter Selasky 			}
1058d6b92ffaSHans Petter Selasky 			port = osm_get_port_by_guid(m->p_subn, port_guid);
1059d6b92ffaSHans Petter Selasky 			if (!port)
1060d6b92ffaSHans Petter Selasky 				continue;
1061d6b92ffaSHans Petter Selasky 			if (!cl_is_qmap_empty(guid_tbl)) {
1062d6b92ffaSHans Petter Selasky 				found = (cl_qmap_get(guid_tbl, port_guid)
1063d6b92ffaSHans Petter Selasky 					 != cl_qmap_end(guid_tbl));
1064d6b92ffaSHans Petter Selasky 				if ((add_guids && !found)
1065d6b92ffaSHans Petter Selasky 				    || (!add_guids && found))
1066d6b92ffaSHans Petter Selasky 					continue;
1067d6b92ffaSHans Petter Selasky 			}
1068d6b92ffaSHans Petter Selasky 			if (!cl_is_item_in_qlist(&m->port_order_list,
1069d6b92ffaSHans Petter Selasky 						 &port->list_item))
1070d6b92ffaSHans Petter Selasky 				cl_qlist_insert_tail(&m->port_order_list,
1071d6b92ffaSHans Petter Selasky 						     &port->list_item);
1072d6b92ffaSHans Petter Selasky 			else
1073d6b92ffaSHans Petter Selasky 				OSM_LOG(m->p_log, OSM_LOG_INFO,
1074d6b92ffaSHans Petter Selasky 					"WRN AD37: guid 0x%016" PRIx64
1075d6b92ffaSHans Petter Selasky 					" already in list\n", port_guid);
1076d6b92ffaSHans Petter Selasky 		}
1077d6b92ffaSHans Petter Selasky 	}
1078d6b92ffaSHans Petter Selasky }
1079d6b92ffaSHans Petter Selasky 
add_guid_to_order_list(uint64_t guid,osm_ucast_mgr_t * m)1080d6b92ffaSHans Petter Selasky static void add_guid_to_order_list(uint64_t guid, osm_ucast_mgr_t * m)
1081d6b92ffaSHans Petter Selasky {
1082d6b92ffaSHans Petter Selasky 	osm_port_t *port = osm_get_port_by_guid(m->p_subn, cl_hton64(guid));
1083d6b92ffaSHans Petter Selasky 
1084d6b92ffaSHans Petter Selasky 	if (!port) {
1085d6b92ffaSHans Petter Selasky 		 OSM_LOG(m->p_log, OSM_LOG_DEBUG,
1086d6b92ffaSHans Petter Selasky 			 "port guid not found: 0x%016" PRIx64 "\n", guid);
1087d6b92ffaSHans Petter Selasky 	}
1088d6b92ffaSHans Petter Selasky 
1089d6b92ffaSHans Petter Selasky 	if (!cl_is_item_in_qlist(&m->port_order_list, &port->list_item))
1090d6b92ffaSHans Petter Selasky 		cl_qlist_insert_tail(&m->port_order_list, &port->list_item);
1091d6b92ffaSHans Petter Selasky 	else
1092d6b92ffaSHans Petter Selasky 		OSM_LOG(m->p_log, OSM_LOG_INFO,
1093d6b92ffaSHans Petter Selasky 			"WRN AD38: guid 0x%016" PRIx64 " already in list\n",
1094d6b92ffaSHans Petter Selasky 			guid);
1095d6b92ffaSHans Petter Selasky }
1096d6b92ffaSHans Petter Selasky 
1097d6b92ffaSHans Petter Selasky /* compare function of #Hca attached to a switch for stdlib qsort */
cmp_num_hca(const void * l1,const void * l2)1098d6b92ffaSHans Petter Selasky static int cmp_num_hca(const void * l1, const void * l2)
1099d6b92ffaSHans Petter Selasky {
1100d6b92ffaSHans Petter Selasky 	vertex_t *sw1 = *((vertex_t **) l1);
1101d6b92ffaSHans Petter Selasky 	vertex_t *sw2 = *((vertex_t **) l2);
1102d6b92ffaSHans Petter Selasky 	uint32_t num_hca1 = 0, num_hca2 = 0;
1103d6b92ffaSHans Petter Selasky 
1104d6b92ffaSHans Petter Selasky 	if (sw1)
1105d6b92ffaSHans Petter Selasky 		num_hca1 = sw1->num_hca;
1106d6b92ffaSHans Petter Selasky 	if (sw2)
1107d6b92ffaSHans Petter Selasky 		num_hca2 = sw2->num_hca;
1108d6b92ffaSHans Petter Selasky 
1109d6b92ffaSHans Petter Selasky 	if (num_hca1 > num_hca2)
1110d6b92ffaSHans Petter Selasky 		return -1;
1111d6b92ffaSHans Petter Selasky 	else if (num_hca1 < num_hca2)
1112d6b92ffaSHans Petter Selasky 		return 1;
1113d6b92ffaSHans Petter Selasky 	else
1114d6b92ffaSHans Petter Selasky 		return 0;
1115d6b92ffaSHans Petter Selasky }
1116d6b92ffaSHans Petter Selasky 
1117d6b92ffaSHans Petter Selasky /* use stdlib to sort the switch array depending on num_hca */
sw_list_sort_by_num_hca(vertex_t ** sw_list,uint32_t sw_list_size)1118d6b92ffaSHans Petter Selasky static inline void sw_list_sort_by_num_hca(vertex_t ** sw_list,
1119d6b92ffaSHans Petter Selasky 					   uint32_t sw_list_size)
1120d6b92ffaSHans Petter Selasky {
1121d6b92ffaSHans Petter Selasky 	qsort(sw_list, sw_list_size, sizeof(vertex_t *), cmp_num_hca);
1122d6b92ffaSHans Petter Selasky }
1123d6b92ffaSHans Petter Selasky 
1124d6b92ffaSHans Petter Selasky /**********************************************************************
1125d6b92ffaSHans Petter Selasky  **********************************************************************/
1126d6b92ffaSHans Petter Selasky 
1127d6b92ffaSHans Petter Selasky /************ helper functions to manage a map of CN and I/O guids ****
1128d6b92ffaSHans Petter Selasky  **********************************************************************/
add_guid_to_map(void * cxt,uint64_t guid,char * p)1129d6b92ffaSHans Petter Selasky static int add_guid_to_map(void * cxt, uint64_t guid, char * p)
1130d6b92ffaSHans Petter Selasky {
1131d6b92ffaSHans Petter Selasky 	cl_qmap_t *map = cxt;
1132d6b92ffaSHans Petter Selasky 	name_map_item_t *item;
1133d6b92ffaSHans Petter Selasky 	name_map_item_t *inserted_item;
1134d6b92ffaSHans Petter Selasky 
1135d6b92ffaSHans Petter Selasky 	item = malloc(sizeof(*item));
1136d6b92ffaSHans Petter Selasky 	if (!item)
1137d6b92ffaSHans Petter Selasky 		return -1;
1138d6b92ffaSHans Petter Selasky 
1139d6b92ffaSHans Petter Selasky 	item->guid = cl_hton64(guid);	/* internal: network byte order */
1140d6b92ffaSHans Petter Selasky 	item->name = NULL;		/* name isn't needed */
1141d6b92ffaSHans Petter Selasky 	inserted_item = (name_map_item_t *) cl_qmap_insert(map, item->guid, &item->item);
1142d6b92ffaSHans Petter Selasky 	if (inserted_item != item)
1143d6b92ffaSHans Petter Selasky                 free(item);
1144d6b92ffaSHans Petter Selasky 
1145d6b92ffaSHans Petter Selasky 	return 0;
1146d6b92ffaSHans Petter Selasky }
1147d6b92ffaSHans Petter Selasky 
destroy_guid_map(cl_qmap_t * guid_tbl)1148d6b92ffaSHans Petter Selasky static void destroy_guid_map(cl_qmap_t * guid_tbl)
1149d6b92ffaSHans Petter Selasky {
1150d6b92ffaSHans Petter Selasky 	name_map_item_t *p_guid = NULL, *p_next_guid = NULL;
1151d6b92ffaSHans Petter Selasky 
1152d6b92ffaSHans Petter Selasky 	p_next_guid = (name_map_item_t *) cl_qmap_head(guid_tbl);
1153d6b92ffaSHans Petter Selasky 	while (p_next_guid != (name_map_item_t *) cl_qmap_end(guid_tbl)) {
1154d6b92ffaSHans Petter Selasky 		p_guid = p_next_guid;
1155d6b92ffaSHans Petter Selasky 		p_next_guid = (name_map_item_t *) cl_qmap_next(&p_guid->item);
1156d6b92ffaSHans Petter Selasky 		free(p_guid);
1157d6b92ffaSHans Petter Selasky 	}
1158d6b92ffaSHans Petter Selasky 	cl_qmap_remove_all(guid_tbl);
1159d6b92ffaSHans Petter Selasky }
1160d6b92ffaSHans Petter Selasky 
1161d6b92ffaSHans Petter Selasky /**********************************************************************
1162d6b92ffaSHans Petter Selasky  **********************************************************************/
1163d6b92ffaSHans Petter Selasky 
dfsssp_print_graph(osm_ucast_mgr_t * p_mgr,vertex_t * adj_list,uint32_t size)1164d6b92ffaSHans Petter Selasky static void dfsssp_print_graph(osm_ucast_mgr_t * p_mgr, vertex_t * adj_list,
1165d6b92ffaSHans Petter Selasky 			       uint32_t size)
1166d6b92ffaSHans Petter Selasky {
1167d6b92ffaSHans Petter Selasky 	uint32_t i = 0, c = 0;
1168d6b92ffaSHans Petter Selasky 	link_t *link = NULL;
1169d6b92ffaSHans Petter Selasky 
1170d6b92ffaSHans Petter Selasky 	/* index 0 is for the source in dijkstra -> ignore */
1171d6b92ffaSHans Petter Selasky 	for (i = 1; i < size; i++) {
1172d6b92ffaSHans Petter Selasky 		OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, "adj_list[%" PRIu32 "]:\n",
1173d6b92ffaSHans Petter Selasky 			i);
1174d6b92ffaSHans Petter Selasky 		OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
1175d6b92ffaSHans Petter Selasky 			"   guid = 0x%" PRIx64 " lid = %" PRIu16 " (%s)\n",
1176d6b92ffaSHans Petter Selasky 			adj_list[i].guid, adj_list[i].lid,
1177d6b92ffaSHans Petter Selasky 			adj_list[i].sw->p_node->print_desc);
1178d6b92ffaSHans Petter Selasky 		OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
1179d6b92ffaSHans Petter Selasky 			"   num_hca = %" PRIu32 "\n", adj_list[i].num_hca);
1180d6b92ffaSHans Petter Selasky 
1181d6b92ffaSHans Petter Selasky 		c = 1;
1182d6b92ffaSHans Petter Selasky 		for (link = adj_list[i].links; link != NULL;
1183d6b92ffaSHans Petter Selasky 		     link = link->next, c++) {
1184d6b92ffaSHans Petter Selasky 			OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
1185d6b92ffaSHans Petter Selasky 				"   link[%" PRIu32 "]:\n", c);
1186d6b92ffaSHans Petter Selasky 			OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
1187d6b92ffaSHans Petter Selasky 				"      to guid = 0x%" PRIx64 " (%s) port %"
1188d6b92ffaSHans Petter Selasky 				PRIu8 "\n", link->guid,
1189d6b92ffaSHans Petter Selasky 				adj_list[link->to].sw->p_node->print_desc,
1190d6b92ffaSHans Petter Selasky 				link->to_port);
1191d6b92ffaSHans Petter Selasky 			OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
1192d6b92ffaSHans Petter Selasky 				"      weight on this link = %" PRIu64 "\n",
1193d6b92ffaSHans Petter Selasky 				link->weight);
1194d6b92ffaSHans Petter Selasky 		}
1195d6b92ffaSHans Petter Selasky 	}
1196d6b92ffaSHans Petter Selasky }
1197d6b92ffaSHans Petter Selasky 
1198d6b92ffaSHans Petter Selasky /* predefine, to use this in next function */
1199d6b92ffaSHans Petter Selasky static void dfsssp_context_destroy(void *context);
1200d6b92ffaSHans Petter Selasky static int dijkstra(osm_ucast_mgr_t * p_mgr, vertex_t * adj_list,
1201d6b92ffaSHans Petter Selasky 		    uint32_t adj_list_size, osm_port_t * port, uint16_t lid);
1202d6b92ffaSHans Petter Selasky 
1203d6b92ffaSHans Petter Selasky /* traverse subnet to gather information about the connected switches */
dfsssp_build_graph(void * context)1204d6b92ffaSHans Petter Selasky static int dfsssp_build_graph(void *context)
1205d6b92ffaSHans Petter Selasky {
1206d6b92ffaSHans Petter Selasky 	dfsssp_context_t *dfsssp_ctx = (dfsssp_context_t *) context;
1207d6b92ffaSHans Petter Selasky 	osm_ucast_mgr_t *p_mgr = (osm_ucast_mgr_t *) (dfsssp_ctx->p_mgr);
1208d6b92ffaSHans Petter Selasky 
1209d6b92ffaSHans Petter Selasky 	cl_qmap_t *port_tbl = &p_mgr->p_subn->port_guid_tbl;	/* 1 management port per switch + 1 or 2 ports for each Hca */
1210d6b92ffaSHans Petter Selasky 	osm_port_t *p_port = NULL;
1211d6b92ffaSHans Petter Selasky 	cl_qmap_t *sw_tbl = &p_mgr->p_subn->sw_guid_tbl;
1212d6b92ffaSHans Petter Selasky 	cl_map_item_t *item = NULL;
1213d6b92ffaSHans Petter Selasky 	osm_switch_t *sw = NULL;
1214d6b92ffaSHans Petter Selasky 	osm_node_t *remote_node = NULL;
1215d6b92ffaSHans Petter Selasky 	uint8_t port = 0, remote_port = 0;
1216d6b92ffaSHans Petter Selasky 	uint32_t i = 0, j = 0, err = 0, undiscov = 0, max_num_undiscov = 0;
1217d6b92ffaSHans Petter Selasky 	uint64_t total_num_hca = 0;
1218d6b92ffaSHans Petter Selasky 	vertex_t *adj_list = NULL;
1219d6b92ffaSHans Petter Selasky 	osm_physp_t *p_physp = NULL;
1220d6b92ffaSHans Petter Selasky 	link_t *link = NULL, *head = NULL;
1221d6b92ffaSHans Petter Selasky 	uint32_t num_sw = 0, adj_list_size = 0;
1222d6b92ffaSHans Petter Selasky 	uint8_t lmc = 0;
1223d6b92ffaSHans Petter Selasky 	uint16_t sm_lid = 0;
1224d6b92ffaSHans Petter Selasky 
1225d6b92ffaSHans Petter Selasky 	OSM_LOG_ENTER(p_mgr->p_log);
1226d6b92ffaSHans Petter Selasky 	OSM_LOG(p_mgr->p_log, OSM_LOG_VERBOSE,
1227d6b92ffaSHans Petter Selasky 		"Building graph for df-/sssp routing\n");
1228d6b92ffaSHans Petter Selasky 
1229d6b92ffaSHans Petter Selasky 	/* if this pointer isn't NULL, this is a reroute step;
1230d6b92ffaSHans Petter Selasky 	   old context will be destroyed (adj_list and srcdest2vl_table)
1231d6b92ffaSHans Petter Selasky 	 */
1232d6b92ffaSHans Petter Selasky 	if (dfsssp_ctx->adj_list)
1233d6b92ffaSHans Petter Selasky 		dfsssp_context_destroy(context);
1234d6b92ffaSHans Petter Selasky 
1235d6b92ffaSHans Petter Selasky 	num_sw = cl_qmap_count(sw_tbl);
1236d6b92ffaSHans Petter Selasky 	adj_list_size = num_sw + 1;
1237d6b92ffaSHans Petter Selasky 	/* allocate an adjazenz list (array), 0. element is reserved for the source (Hca) in the routing algo, others are switches */
1238d6b92ffaSHans Petter Selasky 	adj_list = (vertex_t *) malloc(adj_list_size * sizeof(vertex_t));
1239d6b92ffaSHans Petter Selasky 	if (!adj_list) {
1240d6b92ffaSHans Petter Selasky 		OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
1241d6b92ffaSHans Petter Selasky 			"ERR AD02: cannot allocate memory for adj_list\n");
1242d6b92ffaSHans Petter Selasky 		goto ERROR;
1243d6b92ffaSHans Petter Selasky 	}
1244d6b92ffaSHans Petter Selasky 	for (i = 0; i < adj_list_size; i++)
1245d6b92ffaSHans Petter Selasky 		set_default_vertex(&adj_list[i]);
1246d6b92ffaSHans Petter Selasky 
1247d6b92ffaSHans Petter Selasky 	dfsssp_ctx->adj_list = adj_list;
1248d6b92ffaSHans Petter Selasky 	dfsssp_ctx->adj_list_size = adj_list_size;
1249d6b92ffaSHans Petter Selasky 
1250d6b92ffaSHans Petter Selasky 	/* count the total number of Hca / LIDs (for lmc>0) in the fabric;
1251d6b92ffaSHans Petter Selasky 	   even include base/enhanced switch port 0; base SP0 will have lmc=0
1252d6b92ffaSHans Petter Selasky 	 */
1253d6b92ffaSHans Petter Selasky 	for (item = cl_qmap_head(port_tbl); item != cl_qmap_end(port_tbl);
1254d6b92ffaSHans Petter Selasky 	     item = cl_qmap_next(item)) {
1255d6b92ffaSHans Petter Selasky 		p_port = (osm_port_t *) item;
1256d6b92ffaSHans Petter Selasky 		if (osm_node_get_type(p_port->p_node) == IB_NODE_TYPE_CA ||
1257d6b92ffaSHans Petter Selasky 		    osm_node_get_type(p_port->p_node) == IB_NODE_TYPE_SWITCH) {
1258d6b92ffaSHans Petter Selasky 			lmc = osm_port_get_lmc(p_port);
1259d6b92ffaSHans Petter Selasky 			total_num_hca += (1 << lmc);
1260d6b92ffaSHans Petter Selasky 		}
1261d6b92ffaSHans Petter Selasky 	}
1262d6b92ffaSHans Petter Selasky 
1263d6b92ffaSHans Petter Selasky 	i = 1;			/* fill adj_list -> start with index 1 */
1264d6b92ffaSHans Petter Selasky 	for (item = cl_qmap_head(sw_tbl); item != cl_qmap_end(sw_tbl);
1265d6b92ffaSHans Petter Selasky 	     item = cl_qmap_next(item), i++) {
1266d6b92ffaSHans Petter Selasky 		sw = (osm_switch_t *) item;
1267d6b92ffaSHans Petter Selasky 		OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
1268d6b92ffaSHans Petter Selasky 			"Processing switch with GUID 0x%" PRIx64 "\n",
1269d6b92ffaSHans Petter Selasky 			cl_ntoh64(osm_node_get_node_guid(sw->p_node)));
1270d6b92ffaSHans Petter Selasky 
1271d6b92ffaSHans Petter Selasky 		adj_list[i].guid =
1272d6b92ffaSHans Petter Selasky 		    cl_ntoh64(osm_node_get_node_guid(sw->p_node));
1273d6b92ffaSHans Petter Selasky 		adj_list[i].lid =
1274d6b92ffaSHans Petter Selasky 		    cl_ntoh16(osm_node_get_base_lid(sw->p_node, 0));
1275d6b92ffaSHans Petter Selasky 		adj_list[i].sw = sw;
1276d6b92ffaSHans Petter Selasky 
1277d6b92ffaSHans Petter Selasky 		link = (link_t *) malloc(sizeof(link_t));
1278d6b92ffaSHans Petter Selasky 		if (!link) {
1279d6b92ffaSHans Petter Selasky 			OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
1280d6b92ffaSHans Petter Selasky 				"ERR AD03: cannot allocate memory for a link\n");
1281d6b92ffaSHans Petter Selasky 			goto ERROR;
1282d6b92ffaSHans Petter Selasky 		}
1283d6b92ffaSHans Petter Selasky 		head = link;
1284d6b92ffaSHans Petter Selasky 		head->next = NULL;
1285d6b92ffaSHans Petter Selasky 
1286d6b92ffaSHans Petter Selasky 		/* add SP0 to number of CA connected to a switch */
1287d6b92ffaSHans Petter Selasky 		lmc = osm_node_get_lmc(sw->p_node, 0);
1288d6b92ffaSHans Petter Selasky 		adj_list[i].num_hca += (1 << lmc);
1289d6b92ffaSHans Petter Selasky 
1290d6b92ffaSHans Petter Selasky 		/* iterate over all ports in the switch, start with port 1 (port 0 is a management port) */
1291d6b92ffaSHans Petter Selasky 		for (port = 1; port < sw->num_ports; port++) {
1292d6b92ffaSHans Petter Selasky 			/* get the node behind the port */
1293d6b92ffaSHans Petter Selasky 			remote_node =
1294d6b92ffaSHans Petter Selasky 			    osm_node_get_remote_node(sw->p_node, port,
1295d6b92ffaSHans Petter Selasky 						     &remote_port);
1296d6b92ffaSHans Petter Selasky 			/* if there is no remote node on this port or it's the same switch -> try next port */
1297d6b92ffaSHans Petter Selasky 			if (!remote_node || remote_node->sw == sw)
1298d6b92ffaSHans Petter Selasky 				continue;
1299d6b92ffaSHans Petter Selasky 			/* make sure the link is healthy */
1300d6b92ffaSHans Petter Selasky 			p_physp = osm_node_get_physp_ptr(sw->p_node, port);
1301d6b92ffaSHans Petter Selasky 			if (!p_physp || !osm_link_is_healthy(p_physp))
1302d6b92ffaSHans Petter Selasky 				continue;
1303d6b92ffaSHans Petter Selasky 			/* if there is a Hca connected -> count and cycle */
1304d6b92ffaSHans Petter Selasky 			if (!remote_node->sw) {
1305d6b92ffaSHans Petter Selasky 				lmc = osm_node_get_lmc(remote_node, (uint32_t)remote_port);
1306d6b92ffaSHans Petter Selasky 				adj_list[i].num_hca += (1 << lmc);
1307d6b92ffaSHans Petter Selasky 				continue;
1308d6b92ffaSHans Petter Selasky 			}
1309d6b92ffaSHans Petter Selasky 			OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
1310d6b92ffaSHans Petter Selasky 				"Node 0x%" PRIx64 ", remote node 0x%" PRIx64
1311d6b92ffaSHans Petter Selasky 				", port %" PRIu8 ", remote port %" PRIu8 "\n",
1312d6b92ffaSHans Petter Selasky 				cl_ntoh64(osm_node_get_node_guid(sw->p_node)),
1313d6b92ffaSHans Petter Selasky 				cl_ntoh64(osm_node_get_node_guid(remote_node)),
1314d6b92ffaSHans Petter Selasky 				port, remote_port);
1315d6b92ffaSHans Petter Selasky 
1316d6b92ffaSHans Petter Selasky 			link->next = (link_t *) malloc(sizeof(link_t));
1317d6b92ffaSHans Petter Selasky 			if (!link->next) {
1318d6b92ffaSHans Petter Selasky 				OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
1319d6b92ffaSHans Petter Selasky 					"ERR AD08: cannot allocate memory for a link\n");
1320d6b92ffaSHans Petter Selasky 				while (head) {
1321d6b92ffaSHans Petter Selasky 					link = head;
1322d6b92ffaSHans Petter Selasky 					head = head->next;
1323d6b92ffaSHans Petter Selasky 					free(link);
1324d6b92ffaSHans Petter Selasky 				}
1325d6b92ffaSHans Petter Selasky 				goto ERROR;
1326d6b92ffaSHans Petter Selasky 			}
1327d6b92ffaSHans Petter Selasky 			link = link->next;
1328d6b92ffaSHans Petter Selasky 			set_default_link(link);
1329d6b92ffaSHans Petter Selasky 			link->guid =
1330d6b92ffaSHans Petter Selasky 			    cl_ntoh64(osm_node_get_node_guid(remote_node));
1331d6b92ffaSHans Petter Selasky 			link->from = i;
1332d6b92ffaSHans Petter Selasky 			link->from_port = port;
1333d6b92ffaSHans Petter Selasky 			link->to_port = remote_port;
1334d6b92ffaSHans Petter Selasky 			link->weight = total_num_hca * total_num_hca;	/* initialize with P^2 to force shortest paths */
1335d6b92ffaSHans Petter Selasky 		}
1336d6b92ffaSHans Petter Selasky 
1337d6b92ffaSHans Petter Selasky 		adj_list[i].links = head->next;
1338d6b92ffaSHans Petter Selasky 		free(head);
1339d6b92ffaSHans Petter Selasky 	}
1340d6b92ffaSHans Petter Selasky 	/* connect the links with it's second adjacent node in the list */
1341d6b92ffaSHans Petter Selasky 	for (i = 1; i < adj_list_size; i++) {
1342d6b92ffaSHans Petter Selasky 		link = adj_list[i].links;
1343d6b92ffaSHans Petter Selasky 		while (link) {
1344d6b92ffaSHans Petter Selasky 			for (j = 1; j < adj_list_size; j++) {
1345d6b92ffaSHans Petter Selasky 				if (link->guid == adj_list[j].guid) {
1346d6b92ffaSHans Petter Selasky 					link->to = j;
1347d6b92ffaSHans Petter Selasky 					break;
1348d6b92ffaSHans Petter Selasky 				}
1349d6b92ffaSHans Petter Selasky 			}
1350d6b92ffaSHans Petter Selasky 			link = link->next;
1351d6b92ffaSHans Petter Selasky 		}
1352d6b92ffaSHans Petter Selasky 	}
1353d6b92ffaSHans Petter Selasky 	/* do one dry run to determine connectivity issues */
1354d6b92ffaSHans Petter Selasky 	sm_lid = p_mgr->p_subn->master_sm_base_lid;
1355d6b92ffaSHans Petter Selasky 	p_port = osm_get_port_by_lid(p_mgr->p_subn, sm_lid);
1356d6b92ffaSHans Petter Selasky 	err = dijkstra(p_mgr, adj_list, adj_list_size, p_port, sm_lid);
1357d6b92ffaSHans Petter Selasky 	if (err) {
1358d6b92ffaSHans Petter Selasky 		goto ERROR;
1359d6b92ffaSHans Petter Selasky 	} else {
1360d6b92ffaSHans Petter Selasky 		/* if sm is running on a switch, then dijkstra doesn't
1361d6b92ffaSHans Petter Selasky 		   initialize the used_link for this switch
1362d6b92ffaSHans Petter Selasky 		 */
1363d6b92ffaSHans Petter Selasky 		if (osm_node_get_type(p_port->p_node) != IB_NODE_TYPE_CA)
1364d6b92ffaSHans Petter Selasky 			max_num_undiscov = 1;
1365d6b92ffaSHans Petter Selasky 		for (i = 1; i < adj_list_size; i++)
1366d6b92ffaSHans Petter Selasky 			undiscov += (adj_list[i].used_link) ? 0 : 1;
1367d6b92ffaSHans Petter Selasky 		if (max_num_undiscov < undiscov) {
1368d6b92ffaSHans Petter Selasky 			OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
1369d6b92ffaSHans Petter Selasky 				"ERR AD0C: unsupported network state (detached"
1370d6b92ffaSHans Petter Selasky 				" and inaccessible switches found; gracefully"
1371d6b92ffaSHans Petter Selasky 				" shutdown this routing engine)\n");
1372d6b92ffaSHans Petter Selasky 			goto ERROR;
1373d6b92ffaSHans Petter Selasky 		}
1374d6b92ffaSHans Petter Selasky 	}
1375d6b92ffaSHans Petter Selasky 	/* print the discovered graph */
1376d6b92ffaSHans Petter Selasky 	if (OSM_LOG_IS_ACTIVE_V2(p_mgr->p_log, OSM_LOG_DEBUG))
1377d6b92ffaSHans Petter Selasky 		dfsssp_print_graph(p_mgr, adj_list, adj_list_size);
1378d6b92ffaSHans Petter Selasky 
1379d6b92ffaSHans Petter Selasky 	OSM_LOG_EXIT(p_mgr->p_log);
1380d6b92ffaSHans Petter Selasky 	return 0;
1381d6b92ffaSHans Petter Selasky 
1382d6b92ffaSHans Petter Selasky ERROR:
1383d6b92ffaSHans Petter Selasky 	dfsssp_context_destroy(context);
1384d6b92ffaSHans Petter Selasky 	return -1;
1385d6b92ffaSHans Petter Selasky }
1386d6b92ffaSHans Petter Selasky 
print_routes(osm_ucast_mgr_t * p_mgr,vertex_t * adj_list,uint32_t adj_list_size,osm_port_t * port)1387d6b92ffaSHans Petter Selasky static void print_routes(osm_ucast_mgr_t * p_mgr, vertex_t * adj_list,
1388d6b92ffaSHans Petter Selasky 			 uint32_t adj_list_size, osm_port_t * port)
1389d6b92ffaSHans Petter Selasky {
1390d6b92ffaSHans Petter Selasky 	uint32_t i = 0, j = 0;
1391d6b92ffaSHans Petter Selasky 
1392d6b92ffaSHans Petter Selasky 	for (i = 1; i < adj_list_size; i++) {
1393d6b92ffaSHans Petter Selasky 		if (adj_list[i].state == DISCOVERED) {
1394d6b92ffaSHans Petter Selasky 			OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
1395d6b92ffaSHans Petter Selasky 				"Route from 0x%" PRIx64 " (%s) to 0x%" PRIx64
1396d6b92ffaSHans Petter Selasky 				" (%s):\n", adj_list[i].guid,
1397d6b92ffaSHans Petter Selasky 				adj_list[i].sw->p_node->print_desc,
1398d6b92ffaSHans Petter Selasky 				cl_ntoh64(osm_node_get_node_guid(port->p_node)),
1399d6b92ffaSHans Petter Selasky 				port->p_node->print_desc);
1400d6b92ffaSHans Petter Selasky 			j = i;
1401d6b92ffaSHans Petter Selasky 			while (adj_list[j].used_link) {
1402d6b92ffaSHans Petter Selasky 				if (j > 0) {
1403d6b92ffaSHans Petter Selasky 					OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
1404d6b92ffaSHans Petter Selasky 						"   0x%" PRIx64
1405d6b92ffaSHans Petter Selasky 						" (%s) routes thru port %" PRIu8
1406d6b92ffaSHans Petter Selasky 						"\n", adj_list[j].guid,
1407d6b92ffaSHans Petter Selasky 						adj_list[j].sw->p_node->
1408d6b92ffaSHans Petter Selasky 						print_desc,
1409d6b92ffaSHans Petter Selasky 						adj_list[j].used_link->to_port);
1410d6b92ffaSHans Petter Selasky 				} else {
1411d6b92ffaSHans Petter Selasky 					OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
1412d6b92ffaSHans Petter Selasky 						"   0x%" PRIx64
1413d6b92ffaSHans Petter Selasky 						" (%s) routes thru port %" PRIu8
1414d6b92ffaSHans Petter Selasky 						"\n", adj_list[j].guid,
1415d6b92ffaSHans Petter Selasky 						port->p_node->print_desc,
1416d6b92ffaSHans Petter Selasky 						adj_list[j].used_link->to_port);
1417d6b92ffaSHans Petter Selasky 				}
1418d6b92ffaSHans Petter Selasky 				j = adj_list[j].used_link->from;
1419d6b92ffaSHans Petter Selasky 			}
1420d6b92ffaSHans Petter Selasky 		}
1421d6b92ffaSHans Petter Selasky 	}
1422d6b92ffaSHans Petter Selasky }
1423d6b92ffaSHans Petter Selasky 
1424d6b92ffaSHans Petter Selasky /* dijkstra step from one source to all switches in the df-/sssp graph */
dijkstra(osm_ucast_mgr_t * p_mgr,vertex_t * adj_list,uint32_t adj_list_size,osm_port_t * port,uint16_t lid)1425d6b92ffaSHans Petter Selasky static int dijkstra(osm_ucast_mgr_t * p_mgr, vertex_t * adj_list,
1426d6b92ffaSHans Petter Selasky 		    uint32_t adj_list_size, osm_port_t * port, uint16_t lid)
1427d6b92ffaSHans Petter Selasky {
1428d6b92ffaSHans Petter Selasky 	uint32_t i = 0, j = 0, index = 0;
1429d6b92ffaSHans Petter Selasky 	osm_node_t *remote_node = NULL;
1430d6b92ffaSHans Petter Selasky 	uint8_t remote_port = 0;
1431d6b92ffaSHans Petter Selasky 	vertex_t *current = NULL;
1432d6b92ffaSHans Petter Selasky 	link_t *link = NULL;
1433d6b92ffaSHans Petter Selasky 	uint64_t guid = 0;
1434d6b92ffaSHans Petter Selasky 	binary_heap_t *heap = NULL;
1435d6b92ffaSHans Petter Selasky 	int err = 0;
1436d6b92ffaSHans Petter Selasky 
1437d6b92ffaSHans Petter Selasky 	OSM_LOG_ENTER(p_mgr->p_log);
1438d6b92ffaSHans Petter Selasky 
1439d6b92ffaSHans Petter Selasky 	/* reset all switches for new round with a new source for dijkstra */
1440d6b92ffaSHans Petter Selasky 	for (i = 1; i < adj_list_size; i++) {
1441d6b92ffaSHans Petter Selasky 		adj_list[i].hops = 0;
1442d6b92ffaSHans Petter Selasky 		adj_list[i].used_link = NULL;
1443d6b92ffaSHans Petter Selasky 		adj_list[i].distance = INF;
1444d6b92ffaSHans Petter Selasky 		adj_list[i].state = UNDISCOVERED;
1445d6b92ffaSHans Petter Selasky 	}
1446d6b92ffaSHans Petter Selasky 
1447d6b92ffaSHans Petter Selasky 	/* if behind port is a Hca -> set adj_list[0] */
1448d6b92ffaSHans Petter Selasky 	if (osm_node_get_type(port->p_node) == IB_NODE_TYPE_CA) {
1449d6b92ffaSHans Petter Selasky 		/* save old link to prevent many mallocs after set_default_... */
1450d6b92ffaSHans Petter Selasky 		link = adj_list[0].links;
1451d6b92ffaSHans Petter Selasky 		/* initialize adj_list[0] (the source for the routing, a Hca) */
1452d6b92ffaSHans Petter Selasky 		set_default_vertex(&adj_list[0]);
1453d6b92ffaSHans Petter Selasky 		adj_list[0].guid =
1454d6b92ffaSHans Petter Selasky 		    cl_ntoh64(osm_node_get_node_guid(port->p_node));
1455d6b92ffaSHans Petter Selasky 		adj_list[0].lid = lid;
1456d6b92ffaSHans Petter Selasky 		index = 0;
1457d6b92ffaSHans Petter Selasky 		/* write saved link back to new adj_list[0] */
1458d6b92ffaSHans Petter Selasky 		adj_list[0].links = link;
1459d6b92ffaSHans Petter Selasky 
1460d6b92ffaSHans Petter Selasky 		/* initialize link to neighbor for adj_list[0];
1461d6b92ffaSHans Petter Selasky 		   make sure the link is healthy
1462d6b92ffaSHans Petter Selasky 		 */
1463d6b92ffaSHans Petter Selasky 		if (port->p_physp && osm_link_is_healthy(port->p_physp)) {
1464d6b92ffaSHans Petter Selasky 			remote_node =
1465d6b92ffaSHans Petter Selasky 			    osm_node_get_remote_node(port->p_node,
1466d6b92ffaSHans Petter Selasky 						     port->p_physp->port_num,
1467d6b92ffaSHans Petter Selasky 						     &remote_port);
1468d6b92ffaSHans Petter Selasky 			/* if there is no remote node on this port or it's the same Hca -> ignore */
1469d6b92ffaSHans Petter Selasky 			if (remote_node
1470d6b92ffaSHans Petter Selasky 			    && (osm_node_get_type(remote_node) ==
1471d6b92ffaSHans Petter Selasky 				IB_NODE_TYPE_SWITCH)) {
1472d6b92ffaSHans Petter Selasky 				if (!(adj_list[0].links)) {
1473d6b92ffaSHans Petter Selasky 					adj_list[0].links =
1474d6b92ffaSHans Petter Selasky 					    (link_t *) malloc(sizeof(link_t));
1475d6b92ffaSHans Petter Selasky 					if (!(adj_list[0].links)) {
1476d6b92ffaSHans Petter Selasky 						OSM_LOG(p_mgr->p_log,
1477d6b92ffaSHans Petter Selasky 							OSM_LOG_ERROR,
1478d6b92ffaSHans Petter Selasky 							"ERR AD07: cannot allocate memory for a link\n");
1479d6b92ffaSHans Petter Selasky 						return 1;
1480d6b92ffaSHans Petter Selasky 					}
1481d6b92ffaSHans Petter Selasky 				}
1482d6b92ffaSHans Petter Selasky 				set_default_link(adj_list[0].links);
1483d6b92ffaSHans Petter Selasky 				adj_list[0].links->guid =
1484d6b92ffaSHans Petter Selasky 				    cl_ntoh64(osm_node_get_node_guid
1485d6b92ffaSHans Petter Selasky 					      (remote_node));
1486d6b92ffaSHans Petter Selasky 				adj_list[0].links->from_port =
1487d6b92ffaSHans Petter Selasky 				    port->p_physp->port_num;
1488d6b92ffaSHans Petter Selasky 				adj_list[0].links->to_port = remote_port;
1489d6b92ffaSHans Petter Selasky 				adj_list[0].links->weight = 1;
1490d6b92ffaSHans Petter Selasky 				for (j = 1; j < adj_list_size; j++) {
1491d6b92ffaSHans Petter Selasky 					if (adj_list[0].links->guid ==
1492d6b92ffaSHans Petter Selasky 					    adj_list[j].guid) {
1493d6b92ffaSHans Petter Selasky 						adj_list[0].links->to = j;
1494d6b92ffaSHans Petter Selasky 						break;
1495d6b92ffaSHans Petter Selasky 					}
1496d6b92ffaSHans Petter Selasky 				}
1497d6b92ffaSHans Petter Selasky 			}
1498d6b92ffaSHans Petter Selasky 		} else {
1499d6b92ffaSHans Petter Selasky 			/* if link is unhealthy then there's a severe issue */
1500d6b92ffaSHans Petter Selasky 			OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
1501d6b92ffaSHans Petter Selasky 				"ERR AD0B: unsupported network state (CA with"
1502d6b92ffaSHans Petter Selasky 				" unhealthy link state discovered; should have"
1503d6b92ffaSHans Petter Selasky 				" been filtered out before already; gracefully"
1504d6b92ffaSHans Petter Selasky 				" shutdown this routing engine)\n");
1505d6b92ffaSHans Petter Selasky 			return 1;
1506d6b92ffaSHans Petter Selasky 		}
1507d6b92ffaSHans Petter Selasky 		/* if behind port is a switch -> search switch in adj_list */
1508d6b92ffaSHans Petter Selasky 	} else {
1509d6b92ffaSHans Petter Selasky 		/* reset adj_list[0], if links=NULL reset was done before, then skip */
1510d6b92ffaSHans Petter Selasky 		if (adj_list[0].links) {
1511d6b92ffaSHans Petter Selasky 			free(adj_list[0].links);
1512d6b92ffaSHans Petter Selasky 			set_default_vertex(&adj_list[0]);
1513d6b92ffaSHans Petter Selasky 		}
1514d6b92ffaSHans Petter Selasky 		/* search for the switch which is the source in this round */
1515d6b92ffaSHans Petter Selasky 		guid = cl_ntoh64(osm_node_get_node_guid(port->p_node));
1516d6b92ffaSHans Petter Selasky 		for (i = 1; i < adj_list_size; i++) {
1517d6b92ffaSHans Petter Selasky 			if (guid == adj_list[i].guid) {
1518d6b92ffaSHans Petter Selasky 				index = i;
1519d6b92ffaSHans Petter Selasky 				break;
1520d6b92ffaSHans Petter Selasky 			}
1521d6b92ffaSHans Petter Selasky 		}
1522d6b92ffaSHans Petter Selasky 	}
1523d6b92ffaSHans Petter Selasky 
1524d6b92ffaSHans Petter Selasky 	/* source in dijkstra */
1525d6b92ffaSHans Petter Selasky 	adj_list[index].distance = 0;
1526d6b92ffaSHans Petter Selasky 	adj_list[index].state = DISCOVERED;
1527d6b92ffaSHans Petter Selasky 	adj_list[index].hops = 0;	/* the source has hop count = 0 */
1528d6b92ffaSHans Petter Selasky 
1529d6b92ffaSHans Petter Selasky 	/* create a heap to find (efficient) the node with the smallest distance */
1530d6b92ffaSHans Petter Selasky 	if (osm_node_get_type(port->p_node) == IB_NODE_TYPE_CA)
1531d6b92ffaSHans Petter Selasky 		err = heap_create(adj_list, adj_list_size, &heap);
1532d6b92ffaSHans Petter Selasky 	else
1533d6b92ffaSHans Petter Selasky 		err = heap_create(&adj_list[1], adj_list_size - 1, &heap);
1534d6b92ffaSHans Petter Selasky 	if (err) {
1535d6b92ffaSHans Petter Selasky 		OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
1536d6b92ffaSHans Petter Selasky 			"ERR AD09: cannot allocate memory for heap or heap->node in heap_create(...)\n");
1537d6b92ffaSHans Petter Selasky 		return err;
1538d6b92ffaSHans Petter Selasky 	}
1539d6b92ffaSHans Petter Selasky 
1540d6b92ffaSHans Petter Selasky 	current = heap_getmin(heap);
1541d6b92ffaSHans Petter Selasky 	while (current) {
1542d6b92ffaSHans Petter Selasky 		current->state = DISCOVERED;
1543d6b92ffaSHans Petter Selasky 		if (current->used_link)	/* increment the number of hops to the source for each new node */
1544d6b92ffaSHans Petter Selasky 			current->hops =
1545d6b92ffaSHans Petter Selasky 			    adj_list[current->used_link->from].hops + 1;
1546d6b92ffaSHans Petter Selasky 
1547d6b92ffaSHans Petter Selasky 		/* add/update nodes which aren't discovered but accessible */
1548d6b92ffaSHans Petter Selasky 		for (link = current->links; link != NULL; link = link->next) {
1549d6b92ffaSHans Petter Selasky 			if ((adj_list[link->to].state != DISCOVERED)
1550d6b92ffaSHans Petter Selasky 			    && (current->distance + link->weight <
1551d6b92ffaSHans Petter Selasky 				adj_list[link->to].distance)) {
1552d6b92ffaSHans Petter Selasky 				adj_list[link->to].used_link = link;
1553d6b92ffaSHans Petter Selasky 				adj_list[link->to].distance =
1554d6b92ffaSHans Petter Selasky 				    current->distance + link->weight;
1555d6b92ffaSHans Petter Selasky 				heap_heapify(heap, adj_list[link->to].heap_id);
1556d6b92ffaSHans Petter Selasky 			}
1557d6b92ffaSHans Petter Selasky 		}
1558d6b92ffaSHans Petter Selasky 
1559d6b92ffaSHans Petter Selasky 		current = heap_getmin(heap);
1560d6b92ffaSHans Petter Selasky 	}
1561d6b92ffaSHans Petter Selasky 
1562d6b92ffaSHans Petter Selasky 	/* destroy the heap */
1563d6b92ffaSHans Petter Selasky 	heap_free(heap);
1564d6b92ffaSHans Petter Selasky 	heap = NULL;
1565d6b92ffaSHans Petter Selasky 
1566d6b92ffaSHans Petter Selasky 	OSM_LOG_EXIT(p_mgr->p_log);
1567d6b92ffaSHans Petter Selasky 	return 0;
1568d6b92ffaSHans Petter Selasky }
1569d6b92ffaSHans Petter Selasky 
1570d6b92ffaSHans Petter Selasky /* update the linear forwarding tables of all switches with the informations
1571d6b92ffaSHans Petter Selasky    from the last dijsktra step
1572d6b92ffaSHans Petter Selasky */
update_lft(osm_ucast_mgr_t * p_mgr,vertex_t * adj_list,uint32_t adj_list_size,osm_port_t * p_port,uint16_t lid)1573d6b92ffaSHans Petter Selasky static int update_lft(osm_ucast_mgr_t * p_mgr, vertex_t * adj_list,
1574d6b92ffaSHans Petter Selasky 		      uint32_t adj_list_size, osm_port_t * p_port, uint16_t lid)
1575d6b92ffaSHans Petter Selasky {
1576d6b92ffaSHans Petter Selasky 	uint32_t i = 0;
1577d6b92ffaSHans Petter Selasky 	uint8_t port = 0;
1578d6b92ffaSHans Petter Selasky 	uint8_t hops = 0;
1579d6b92ffaSHans Petter Selasky 	osm_switch_t *p_sw = NULL;
1580d6b92ffaSHans Petter Selasky 	boolean_t is_ignored_by_port_prof = FALSE;
1581d6b92ffaSHans Petter Selasky 	osm_physp_t *p = NULL;
1582d6b92ffaSHans Petter Selasky 	cl_status_t ret;
1583d6b92ffaSHans Petter Selasky 
1584d6b92ffaSHans Petter Selasky 	OSM_LOG_ENTER(p_mgr->p_log);
1585d6b92ffaSHans Petter Selasky 
1586d6b92ffaSHans Petter Selasky 	for (i = 1; i < adj_list_size; i++) {
1587d6b92ffaSHans Petter Selasky 		/* if no route goes thru this switch -> cycle */
1588d6b92ffaSHans Petter Selasky 		if (!(adj_list[i].used_link))
1589d6b92ffaSHans Petter Selasky 			continue;
1590d6b92ffaSHans Petter Selasky 
1591d6b92ffaSHans Petter Selasky 		p_sw = adj_list[i].sw;
1592d6b92ffaSHans Petter Selasky 		hops = adj_list[i].hops;
1593d6b92ffaSHans Petter Selasky 		port = adj_list[i].used_link->to_port;
1594d6b92ffaSHans Petter Selasky 		/* the used_link is the link that was used in dijkstra to reach this node,
1595d6b92ffaSHans Petter Selasky 		   so the to_port is the local port on this node
1596d6b92ffaSHans Petter Selasky 		 */
1597d6b92ffaSHans Petter Selasky 
1598d6b92ffaSHans Petter Selasky 		if (port == OSM_NO_PATH) {	/* if clause shouldn't be possible in this routing, but who cares */
1599d6b92ffaSHans Petter Selasky 			OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
1600d6b92ffaSHans Petter Selasky 				"ERR AD06: No path to get to LID %" PRIu16
1601d6b92ffaSHans Petter Selasky 				" from switch 0x%" PRIx64 "\n", lid,
1602d6b92ffaSHans Petter Selasky 				cl_ntoh64(osm_node_get_node_guid
1603d6b92ffaSHans Petter Selasky 					  (p_sw->p_node)));
1604d6b92ffaSHans Petter Selasky 
1605d6b92ffaSHans Petter Selasky 			/* do not try to overwrite the ppro of non existing port ... */
1606d6b92ffaSHans Petter Selasky 			is_ignored_by_port_prof = TRUE;
1607d6b92ffaSHans Petter Selasky 			return 1;
1608d6b92ffaSHans Petter Selasky 		} else {
1609d6b92ffaSHans Petter Selasky 			OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
1610d6b92ffaSHans Petter Selasky 				"Routing LID %" PRIu16 " to port %" PRIu8
1611d6b92ffaSHans Petter Selasky 				" for switch 0x%" PRIx64 "\n", lid, port,
1612d6b92ffaSHans Petter Selasky 				cl_ntoh64(osm_node_get_node_guid
1613d6b92ffaSHans Petter Selasky 					  (p_sw->p_node)));
1614d6b92ffaSHans Petter Selasky 
1615d6b92ffaSHans Petter Selasky 			p = osm_node_get_physp_ptr(p_sw->p_node, port);
1616d6b92ffaSHans Petter Selasky 			if (!p) {
1617d6b92ffaSHans Petter Selasky 				OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
1618d6b92ffaSHans Petter Selasky 					"ERR AD0A: Physical port %d of Node GUID 0x%"
1619d6b92ffaSHans Petter Selasky 					PRIx64 "not found\n", port,
1620d6b92ffaSHans Petter Selasky 					cl_ntoh64(osm_node_get_node_guid(p_sw->p_node)));
1621d6b92ffaSHans Petter Selasky 				return 1;
1622d6b92ffaSHans Petter Selasky 			}
1623d6b92ffaSHans Petter Selasky 
1624d6b92ffaSHans Petter Selasky 			/* we would like to optionally ignore this port in equalization
1625d6b92ffaSHans Petter Selasky 			   as in the case of the Mellanox Anafa Internal PCI TCA port
1626d6b92ffaSHans Petter Selasky 			 */
1627d6b92ffaSHans Petter Selasky 			is_ignored_by_port_prof = p->is_prof_ignored;
1628d6b92ffaSHans Petter Selasky 
1629d6b92ffaSHans Petter Selasky 			/* We also would ignore this route if the target lid is of
1630d6b92ffaSHans Petter Selasky 			   a switch and the port_profile_switch_node is not TRUE
1631d6b92ffaSHans Petter Selasky 			 */
1632d6b92ffaSHans Petter Selasky 			if (!p_mgr->p_subn->opt.port_profile_switch_nodes)
1633d6b92ffaSHans Petter Selasky 				is_ignored_by_port_prof |=
1634d6b92ffaSHans Petter Selasky 				    (osm_node_get_type(p_port->p_node) ==
1635d6b92ffaSHans Petter Selasky 				     IB_NODE_TYPE_SWITCH);
1636d6b92ffaSHans Petter Selasky 		}
1637d6b92ffaSHans Petter Selasky 
1638d6b92ffaSHans Petter Selasky 		/* to support lmc > 0 the functions alloc_ports_priv, free_ports_priv, find_and_add_remote_sys
1639d6b92ffaSHans Petter Selasky 		   from minhop aren't needed cause osm_switch_recommend_path is implicitly calculated
1640d6b92ffaSHans Petter Selasky 		   for each LID pair thru dijkstra;
1641d6b92ffaSHans Petter Selasky 		   for each port the dijkstra algorithm calculates (max_lid_ho - min_lid_ho)-times maybe
1642d6b92ffaSHans Petter Selasky 		   disjoint routes to spread the bandwidth -> diffent routes for one port and lmc>0
1643d6b92ffaSHans Petter Selasky 		 */
1644d6b92ffaSHans Petter Selasky 
1645d6b92ffaSHans Petter Selasky 		/* set port in LFT */
1646d6b92ffaSHans Petter Selasky 		p_sw->new_lft[lid] = port;
1647d6b92ffaSHans Petter Selasky 		if (!is_ignored_by_port_prof) {
1648d6b92ffaSHans Petter Selasky 			/* update the number of path routing thru this port */
1649d6b92ffaSHans Petter Selasky 			osm_switch_count_path(p_sw, port);
1650d6b92ffaSHans Petter Selasky 		}
1651d6b92ffaSHans Petter Selasky 		/* set the hop count from this switch to the lid */
1652d6b92ffaSHans Petter Selasky 		ret = osm_switch_set_hops(p_sw, lid, port, hops);
1653d6b92ffaSHans Petter Selasky 		if (ret != CL_SUCCESS)
1654d6b92ffaSHans Petter Selasky 			OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
1655d6b92ffaSHans Petter Selasky 				"ERR AD05: cannot set hops for LID %" PRIu16
1656d6b92ffaSHans Petter Selasky 				" at switch 0x%" PRIx64 "\n", lid,
1657d6b92ffaSHans Petter Selasky 				cl_ntoh64(osm_node_get_node_guid
1658d6b92ffaSHans Petter Selasky 					  (p_sw->p_node)));
1659d6b92ffaSHans Petter Selasky 	}
1660d6b92ffaSHans Petter Selasky 
1661d6b92ffaSHans Petter Selasky 	OSM_LOG_EXIT(p_mgr->p_log);
1662d6b92ffaSHans Petter Selasky 	return 0;
1663d6b92ffaSHans Petter Selasky }
1664d6b92ffaSHans Petter Selasky 
1665d6b92ffaSHans Petter Selasky /* the function updates the multicast group membership information
1666d6b92ffaSHans Petter Selasky    similar to create_mgrp_switch_map (osm_mcast_mgr.c)
1667d6b92ffaSHans Petter Selasky    => with it we can identify if a switch needs to be processed
1668d6b92ffaSHans Petter Selasky    or not in update_mcft
1669d6b92ffaSHans Petter Selasky */
update_mgrp_membership(cl_qlist_t * port_list)1670d6b92ffaSHans Petter Selasky static void update_mgrp_membership(cl_qlist_t * port_list)
1671d6b92ffaSHans Petter Selasky {
1672d6b92ffaSHans Petter Selasky 	osm_mcast_work_obj_t *wobj = NULL;
1673d6b92ffaSHans Petter Selasky 	osm_port_t *port = NULL;
1674d6b92ffaSHans Petter Selasky 	osm_switch_t *sw = NULL;
1675d6b92ffaSHans Petter Selasky 	cl_list_item_t *i = NULL;
1676d6b92ffaSHans Petter Selasky 
1677d6b92ffaSHans Petter Selasky 	for (i = cl_qlist_head(port_list); i != cl_qlist_end(port_list);
1678d6b92ffaSHans Petter Selasky 	     i = cl_qlist_next(i)) {
1679d6b92ffaSHans Petter Selasky 		wobj = cl_item_obj(i, wobj, list_item);
1680d6b92ffaSHans Petter Selasky 		port = wobj->p_port;
1681d6b92ffaSHans Petter Selasky 		if (port->p_node->sw) {
1682d6b92ffaSHans Petter Selasky 			sw = port->p_node->sw;
1683d6b92ffaSHans Petter Selasky 			sw->is_mc_member = 1;
1684d6b92ffaSHans Petter Selasky 		} else {
1685d6b92ffaSHans Petter Selasky 			sw = port->p_physp->p_remote_physp->p_node->sw;
1686d6b92ffaSHans Petter Selasky 			sw->num_of_mcm++;
1687d6b92ffaSHans Petter Selasky 		}
1688d6b92ffaSHans Petter Selasky 	}
1689d6b92ffaSHans Petter Selasky }
1690d6b92ffaSHans Petter Selasky 
1691d6b92ffaSHans Petter Selasky /* reset is_mc_member and num_of_mcm for future computations */
reset_mgrp_membership(vertex_t * adj_list,uint32_t adj_list_size)1692d6b92ffaSHans Petter Selasky static void reset_mgrp_membership(vertex_t * adj_list, uint32_t adj_list_size)
1693d6b92ffaSHans Petter Selasky {
1694d6b92ffaSHans Petter Selasky 	uint32_t i = 0;
1695d6b92ffaSHans Petter Selasky 
1696d6b92ffaSHans Petter Selasky 	for (i = 1; i < adj_list_size; i++) {
1697d6b92ffaSHans Petter Selasky 		if (adj_list[i].dropped)
1698d6b92ffaSHans Petter Selasky 			continue;
1699d6b92ffaSHans Petter Selasky 
1700d6b92ffaSHans Petter Selasky 		adj_list[i].sw->is_mc_member = 0;
1701d6b92ffaSHans Petter Selasky 		adj_list[i].sw->num_of_mcm = 0;
1702d6b92ffaSHans Petter Selasky 	}
1703d6b92ffaSHans Petter Selasky }
1704d6b92ffaSHans Petter Selasky 
1705d6b92ffaSHans Petter Selasky /* update the multicast forwarding tables of all switches with the informations
1706d6b92ffaSHans Petter Selasky    from the previous dijsktra step for the current mlid
1707d6b92ffaSHans Petter Selasky */
update_mcft(osm_sm_t * p_sm,vertex_t * adj_list,uint32_t adj_list_size,uint16_t mlid_ho,cl_qmap_t * port_map,osm_switch_t * root_sw)1708d6b92ffaSHans Petter Selasky static int update_mcft(osm_sm_t * p_sm, vertex_t * adj_list,
1709d6b92ffaSHans Petter Selasky 		       uint32_t adj_list_size, uint16_t mlid_ho,
1710d6b92ffaSHans Petter Selasky 		       cl_qmap_t * port_map, osm_switch_t * root_sw)
1711d6b92ffaSHans Petter Selasky {
1712d6b92ffaSHans Petter Selasky 	uint32_t i = 0;
1713d6b92ffaSHans Petter Selasky 	uint8_t port = 0, remote_port = 0;
1714d6b92ffaSHans Petter Selasky 	uint8_t upstream_port = 0, downstream_port = 0;
1715d6b92ffaSHans Petter Selasky 	ib_net64_t guid = 0;
1716d6b92ffaSHans Petter Selasky 	osm_switch_t *p_sw = NULL;
1717d6b92ffaSHans Petter Selasky 	osm_node_t *remote_node = NULL;
1718d6b92ffaSHans Petter Selasky 	osm_physp_t *p_physp = NULL;
1719d6b92ffaSHans Petter Selasky 	osm_mcast_tbl_t *p_tbl = NULL;
1720d6b92ffaSHans Petter Selasky 	vertex_t *curr_adj = NULL;
1721d6b92ffaSHans Petter Selasky 
1722d6b92ffaSHans Petter Selasky 	OSM_LOG_ENTER(p_sm->p_log);
1723d6b92ffaSHans Petter Selasky 
1724d6b92ffaSHans Petter Selasky 	for (i = 1; i < adj_list_size; i++) {
1725d6b92ffaSHans Petter Selasky 		if (adj_list[i].dropped)
1726d6b92ffaSHans Petter Selasky 			continue;
1727d6b92ffaSHans Petter Selasky 
1728d6b92ffaSHans Petter Selasky 		p_sw = adj_list[i].sw;
1729d6b92ffaSHans Petter Selasky 		OSM_LOG(p_sm->p_log, OSM_LOG_VERBOSE,
1730d6b92ffaSHans Petter Selasky 			"Processing switch 0x%016" PRIx64
1731d6b92ffaSHans Petter Selasky 			" (%s) for MLID 0x%X\n", cl_ntoh64(adj_list[i].guid),
1732d6b92ffaSHans Petter Selasky 			p_sw->p_node->print_desc, mlid_ho);
1733d6b92ffaSHans Petter Selasky 
1734d6b92ffaSHans Petter Selasky 		/* if a) the switch does not support mcast  or
1735d6b92ffaSHans Petter Selasky 		      b) no ports of this switch are part or the mcast group
1736d6b92ffaSHans Petter Selasky 		   then cycle
1737d6b92ffaSHans Petter Selasky 		 */
1738d6b92ffaSHans Petter Selasky 		if (osm_switch_supports_mcast(p_sw) == FALSE ||
1739d6b92ffaSHans Petter Selasky 		    (p_sw->num_of_mcm == 0 && !(p_sw->is_mc_member)))
1740d6b92ffaSHans Petter Selasky 			continue;
1741d6b92ffaSHans Petter Selasky 
1742d6b92ffaSHans Petter Selasky 		p_tbl = osm_switch_get_mcast_tbl_ptr(p_sw);
1743d6b92ffaSHans Petter Selasky 
1744d6b92ffaSHans Petter Selasky 		/* add all ports of this sw to the mcast table,
1745d6b92ffaSHans Petter Selasky 		   if they are part of the mcast grp
1746d6b92ffaSHans Petter Selasky 		 */
1747d6b92ffaSHans Petter Selasky 		if (p_sw->is_mc_member)
1748d6b92ffaSHans Petter Selasky 			osm_mcast_tbl_set(p_tbl, mlid_ho, 0);
1749d6b92ffaSHans Petter Selasky 		for (port = 1; port < p_sw->num_ports; port++) {
1750d6b92ffaSHans Petter Selasky 			/* get the node behind the port */
1751d6b92ffaSHans Petter Selasky 			remote_node =
1752d6b92ffaSHans Petter Selasky 				osm_node_get_remote_node(p_sw->p_node, port,
1753d6b92ffaSHans Petter Selasky 							 &remote_port);
1754d6b92ffaSHans Petter Selasky 			/* check if connected and its not the same switch */
1755d6b92ffaSHans Petter Selasky 			if (!remote_node || remote_node->sw == p_sw)
1756d6b92ffaSHans Petter Selasky 				continue;
1757d6b92ffaSHans Petter Selasky 			/* make sure the link is healthy */
1758d6b92ffaSHans Petter Selasky 			p_physp = osm_node_get_physp_ptr(p_sw->p_node, port);
1759d6b92ffaSHans Petter Selasky 			if (!p_physp || !osm_link_is_healthy(p_physp))
1760d6b92ffaSHans Petter Selasky 				continue;
1761d6b92ffaSHans Petter Selasky 			/* we don't add upstream ports in this step */
1762d6b92ffaSHans Petter Selasky 			if (osm_node_get_type(remote_node) != IB_NODE_TYPE_CA)
1763d6b92ffaSHans Petter Selasky 				continue;
1764d6b92ffaSHans Petter Selasky 
1765d6b92ffaSHans Petter Selasky 			guid = osm_physp_get_port_guid(osm_node_get_physp_ptr(
1766d6b92ffaSHans Petter Selasky 						       remote_node,
1767d6b92ffaSHans Petter Selasky 						       remote_port));
1768d6b92ffaSHans Petter Selasky 			if (cl_qmap_get(port_map, guid)
1769d6b92ffaSHans Petter Selasky 			    != cl_qmap_end(port_map))
1770d6b92ffaSHans Petter Selasky 				osm_mcast_tbl_set(p_tbl, mlid_ho, port);
1771d6b92ffaSHans Petter Selasky 		}
1772d6b92ffaSHans Petter Selasky 
1773d6b92ffaSHans Petter Selasky 		/* now we have to add the upstream port of 'this' switch and
1774d6b92ffaSHans Petter Selasky 		   the downstream port of the next switch to the mcast table
1775d6b92ffaSHans Petter Selasky 		   until we reach the root_sw
1776d6b92ffaSHans Petter Selasky 		 */
1777d6b92ffaSHans Petter Selasky 		curr_adj = &adj_list[i];
1778d6b92ffaSHans Petter Selasky 		while (curr_adj->sw != root_sw) {
1779d6b92ffaSHans Petter Selasky 			/* the used_link is the link that was used in dijkstra to reach this node,
1780d6b92ffaSHans Petter Selasky 			   so the to_port is the local (upstream) port on curr_adj->sw
1781d6b92ffaSHans Petter Selasky 			 */
1782d6b92ffaSHans Petter Selasky 			upstream_port = curr_adj->used_link->to_port;
1783d6b92ffaSHans Petter Selasky 			osm_mcast_tbl_set(p_tbl, mlid_ho, upstream_port);
1784d6b92ffaSHans Petter Selasky 
1785d6b92ffaSHans Petter Selasky 			/* now we go one step in direction root_sw and add the
1786d6b92ffaSHans Petter Selasky 			   downstream port for the spanning tree
1787d6b92ffaSHans Petter Selasky 			 */
1788d6b92ffaSHans Petter Selasky 			downstream_port = curr_adj->used_link->from_port;
1789d6b92ffaSHans Petter Selasky 			p_tbl = osm_switch_get_mcast_tbl_ptr(
1790d6b92ffaSHans Petter Selasky 				adj_list[curr_adj->used_link->from].sw);
1791d6b92ffaSHans Petter Selasky 			osm_mcast_tbl_set(p_tbl, mlid_ho, downstream_port);
1792d6b92ffaSHans Petter Selasky 
1793d6b92ffaSHans Petter Selasky 			curr_adj = &adj_list[curr_adj->used_link->from];
1794d6b92ffaSHans Petter Selasky 		}
1795d6b92ffaSHans Petter Selasky 	}
1796d6b92ffaSHans Petter Selasky 
1797d6b92ffaSHans Petter Selasky 	OSM_LOG_EXIT(p_sm->p_log);
1798d6b92ffaSHans Petter Selasky 	return 0;
1799d6b92ffaSHans Petter Selasky }
1800d6b92ffaSHans Petter Selasky 
1801d6b92ffaSHans Petter Selasky /* increment the edge weights of the df-/sssp graph which represent the number
1802d6b92ffaSHans Petter Selasky    of paths on this link
1803d6b92ffaSHans Petter Selasky */
update_weights(osm_ucast_mgr_t * p_mgr,vertex_t * adj_list,uint32_t adj_list_size)1804d6b92ffaSHans Petter Selasky static void update_weights(osm_ucast_mgr_t * p_mgr, vertex_t * adj_list,
1805d6b92ffaSHans Petter Selasky 			   uint32_t adj_list_size)
1806d6b92ffaSHans Petter Selasky {
1807d6b92ffaSHans Petter Selasky 	uint32_t i = 0, j = 0;
1808d6b92ffaSHans Petter Selasky 	uint32_t additional_weight = 0;
1809d6b92ffaSHans Petter Selasky 
1810d6b92ffaSHans Petter Selasky 	OSM_LOG_ENTER(p_mgr->p_log);
1811d6b92ffaSHans Petter Selasky 
1812d6b92ffaSHans Petter Selasky 	for (i = 1; i < adj_list_size; i++) {
1813d6b92ffaSHans Petter Selasky 		/* if no route goes thru this switch -> cycle */
1814d6b92ffaSHans Petter Selasky 		if (!(adj_list[i].used_link))
1815d6b92ffaSHans Petter Selasky 			continue;
1816d6b92ffaSHans Petter Selasky 		additional_weight = adj_list[i].num_hca;
1817d6b92ffaSHans Petter Selasky 
1818d6b92ffaSHans Petter Selasky 		j = i;
1819d6b92ffaSHans Petter Selasky 		while (adj_list[j].used_link) {
1820d6b92ffaSHans Petter Selasky 			/* update the link from pre to this node */
1821d6b92ffaSHans Petter Selasky 			adj_list[j].used_link->weight += additional_weight;
1822d6b92ffaSHans Petter Selasky 
1823d6b92ffaSHans Petter Selasky 			j = adj_list[j].used_link->from;
1824d6b92ffaSHans Petter Selasky 		}
1825d6b92ffaSHans Petter Selasky 	}
1826d6b92ffaSHans Petter Selasky 
1827d6b92ffaSHans Petter Selasky 	OSM_LOG_EXIT(p_mgr->p_log);
1828d6b92ffaSHans Petter Selasky }
1829d6b92ffaSHans Petter Selasky 
1830d6b92ffaSHans Petter Selasky /* get the largest number of virtual lanes which is supported by all switches
1831d6b92ffaSHans Petter Selasky    in the subnet
1832d6b92ffaSHans Petter Selasky */
get_avail_vl_in_subn(osm_ucast_mgr_t * p_mgr)1833d6b92ffaSHans Petter Selasky static uint8_t get_avail_vl_in_subn(osm_ucast_mgr_t * p_mgr)
1834d6b92ffaSHans Petter Selasky {
1835d6b92ffaSHans Petter Selasky 	uint32_t i = 0;
1836d6b92ffaSHans Petter Selasky 	uint8_t vls_avail = 0xFF, port_vls_avail = 0;
1837d6b92ffaSHans Petter Selasky 	cl_qmap_t *sw_tbl = &p_mgr->p_subn->sw_guid_tbl;
1838d6b92ffaSHans Petter Selasky 	cl_map_item_t *item = NULL;
1839d6b92ffaSHans Petter Selasky 	osm_switch_t *sw = NULL;
1840d6b92ffaSHans Petter Selasky 
1841d6b92ffaSHans Petter Selasky 	/* traverse all switches to get the number of available virtual lanes in the subnet */
1842d6b92ffaSHans Petter Selasky 	for (item = cl_qmap_head(sw_tbl); item != cl_qmap_end(sw_tbl);
1843d6b92ffaSHans Petter Selasky 	     item = cl_qmap_next(item)) {
1844d6b92ffaSHans Petter Selasky 		sw = (osm_switch_t *) item;
1845d6b92ffaSHans Petter Selasky 
1846d6b92ffaSHans Petter Selasky 		/* ignore management port 0 */
1847d6b92ffaSHans Petter Selasky 		for (i = 1; i < osm_node_get_num_physp(sw->p_node); i++) {
1848d6b92ffaSHans Petter Selasky 			osm_physp_t *p_physp =
1849d6b92ffaSHans Petter Selasky 			    osm_node_get_physp_ptr(sw->p_node, i);
1850d6b92ffaSHans Petter Selasky 
1851d6b92ffaSHans Petter Selasky 			if (p_physp && p_physp->p_remote_physp) {
1852d6b92ffaSHans Petter Selasky 				port_vls_avail =
1853d6b92ffaSHans Petter Selasky 				    ib_port_info_get_op_vls(&p_physp->
1854d6b92ffaSHans Petter Selasky 							    port_info);
1855d6b92ffaSHans Petter Selasky 				if (port_vls_avail
1856d6b92ffaSHans Petter Selasky 				    && port_vls_avail < vls_avail)
1857d6b92ffaSHans Petter Selasky 					vls_avail = port_vls_avail;
1858d6b92ffaSHans Petter Selasky 			}
1859d6b92ffaSHans Petter Selasky 		}
1860d6b92ffaSHans Petter Selasky 	}
1861d6b92ffaSHans Petter Selasky 
1862d6b92ffaSHans Petter Selasky 	/* ib_port_info_get_op_vls gives values 1 ... 5 (s. IBAS 14.2.5.6) */
1863d6b92ffaSHans Petter Selasky 	vls_avail = 1 << (vls_avail - 1);
1864d6b92ffaSHans Petter Selasky 
1865d6b92ffaSHans Petter Selasky 	/* set boundaries (s. IBAS 3.5.7) */
1866d6b92ffaSHans Petter Selasky 	if (vls_avail > 15)
1867d6b92ffaSHans Petter Selasky 		vls_avail = 15;
1868d6b92ffaSHans Petter Selasky 	if (vls_avail < 1)
1869d6b92ffaSHans Petter Selasky 		vls_avail = 1;
1870d6b92ffaSHans Petter Selasky 
1871d6b92ffaSHans Petter Selasky 	return vls_avail;
1872d6b92ffaSHans Petter Selasky }
1873d6b92ffaSHans Petter Selasky 
1874d6b92ffaSHans Petter Selasky /* search for cycles in the channel dependency graph to identify possible
1875d6b92ffaSHans Petter Selasky    deadlocks in the network;
1876d6b92ffaSHans Petter Selasky    assign new virtual lanes to some paths to break the deadlocks
1877d6b92ffaSHans Petter Selasky */
dfsssp_remove_deadlocks(dfsssp_context_t * dfsssp_ctx)1878d6b92ffaSHans Petter Selasky static int dfsssp_remove_deadlocks(dfsssp_context_t * dfsssp_ctx)
1879d6b92ffaSHans Petter Selasky {
1880d6b92ffaSHans Petter Selasky 	osm_ucast_mgr_t *p_mgr = (osm_ucast_mgr_t *) dfsssp_ctx->p_mgr;
1881d6b92ffaSHans Petter Selasky 
1882d6b92ffaSHans Petter Selasky 	cl_qlist_t *port_tbl = &p_mgr->port_order_list;	/* 1 management port per switch + 1 or 2 ports for each Hca */
1883d6b92ffaSHans Petter Selasky 	cl_list_item_t *item1 = NULL, *item2 = NULL;
1884d6b92ffaSHans Petter Selasky 	osm_port_t *src_port = NULL, *dest_port = NULL;
1885d6b92ffaSHans Petter Selasky 
1886d6b92ffaSHans Petter Selasky 	uint32_t i = 0, j = 0, err = 0;
1887d6b92ffaSHans Petter Selasky 	uint8_t vl = 0, test_vl = 0, vl_avail = 0, vl_needed = 1;
1888d6b92ffaSHans Petter Selasky 	double most_avg_paths = 0.0;
1889d6b92ffaSHans Petter Selasky 	cdg_node_t **cdg = NULL, *start_here = NULL, *cycle = NULL;
1890d6b92ffaSHans Petter Selasky 	cdg_link_t *weakest_link = NULL;
1891d6b92ffaSHans Petter Selasky 	uint32_t srcdest = 0;
1892d6b92ffaSHans Petter Selasky 
1893d6b92ffaSHans Petter Selasky 	vltable_t *srcdest2vl_table = NULL;
1894d6b92ffaSHans Petter Selasky 	uint8_t lmc = 0;
1895d6b92ffaSHans Petter Selasky 	uint16_t slid = 0, dlid = 0, min_lid_ho = 0, max_lid_ho =
1896d6b92ffaSHans Petter Selasky 	    0, min_lid_ho2 = 0, max_lid_ho2 = 0;;
1897d6b92ffaSHans Petter Selasky 	uint64_t *paths_per_vl = NULL;
1898d6b92ffaSHans Petter Selasky 	uint64_t from = 0, to = 0, count = 0;
1899d6b92ffaSHans Petter Selasky 	uint8_t *split_count = NULL;
1900d6b92ffaSHans Petter Selasky 	uint8_t ntype = 0;
1901d6b92ffaSHans Petter Selasky 
1902d6b92ffaSHans Petter Selasky 	OSM_LOG_ENTER(p_mgr->p_log);
1903d6b92ffaSHans Petter Selasky 	OSM_LOG(p_mgr->p_log, OSM_LOG_VERBOSE,
1904d6b92ffaSHans Petter Selasky 		"Assign each src/dest pair a Virtual Lanes, to remove deadlocks in the routing\n");
1905d6b92ffaSHans Petter Selasky 
1906d6b92ffaSHans Petter Selasky 	vl_avail = get_avail_vl_in_subn(p_mgr);
1907d6b92ffaSHans Petter Selasky 	OSM_LOG(p_mgr->p_log, OSM_LOG_INFO,
1908d6b92ffaSHans Petter Selasky 		"Virtual Lanes available: %" PRIu8 "\n", vl_avail);
1909d6b92ffaSHans Petter Selasky 
1910d6b92ffaSHans Petter Selasky 	paths_per_vl = (uint64_t *) malloc(vl_avail * sizeof(uint64_t));
1911d6b92ffaSHans Petter Selasky 	if (!paths_per_vl) {
1912d6b92ffaSHans Petter Selasky 		OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
1913d6b92ffaSHans Petter Selasky 			"ERR AD22: cannot allocate memory for paths_per_vl\n");
1914d6b92ffaSHans Petter Selasky 		return 1;
1915d6b92ffaSHans Petter Selasky 	}
1916d6b92ffaSHans Petter Selasky 	memset(paths_per_vl, 0, vl_avail * sizeof(uint64_t));
1917d6b92ffaSHans Petter Selasky 
1918d6b92ffaSHans Petter Selasky 	cdg = (cdg_node_t **) malloc(vl_avail * sizeof(cdg_node_t *));
1919d6b92ffaSHans Petter Selasky 	if (!cdg) {
1920d6b92ffaSHans Petter Selasky 		OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
1921d6b92ffaSHans Petter Selasky 			"ERR AD23: cannot allocate memory for cdg\n");
1922d6b92ffaSHans Petter Selasky 		free(paths_per_vl);
1923d6b92ffaSHans Petter Selasky 		return 1;
1924d6b92ffaSHans Petter Selasky 	}
1925d6b92ffaSHans Petter Selasky 	for (i = 0; i < vl_avail; i++)
1926d6b92ffaSHans Petter Selasky 		cdg[i] = NULL;
1927d6b92ffaSHans Petter Selasky 
1928d6b92ffaSHans Petter Selasky 	count = 0;
1929d6b92ffaSHans Petter Selasky 	/* count all ports (also multiple LIDs) of type CA or SP0 for size of VL table */
1930d6b92ffaSHans Petter Selasky 	for (item1 = cl_qlist_head(port_tbl); item1 != cl_qlist_end(port_tbl);
1931d6b92ffaSHans Petter Selasky 	     item1 = cl_qlist_next(item1)) {
1932d6b92ffaSHans Petter Selasky 		dest_port = (osm_port_t *)cl_item_obj(item1, dest_port,
1933d6b92ffaSHans Petter Selasky 						      list_item);
1934d6b92ffaSHans Petter Selasky 		ntype = osm_node_get_type(dest_port->p_node);
1935d6b92ffaSHans Petter Selasky 		if (ntype == IB_NODE_TYPE_CA || ntype == IB_NODE_TYPE_SWITCH) {
1936d6b92ffaSHans Petter Selasky 			/* only SP0 with SLtoVLMapping support will be processed */
1937d6b92ffaSHans Petter Selasky 			if (ntype == IB_NODE_TYPE_SWITCH
1938d6b92ffaSHans Petter Selasky 			    && !(dest_port->p_physp->port_info.capability_mask
1939d6b92ffaSHans Petter Selasky 			    & IB_PORT_CAP_HAS_SL_MAP))
1940d6b92ffaSHans Petter Selasky 				continue;
1941d6b92ffaSHans Petter Selasky 
1942d6b92ffaSHans Petter Selasky 			lmc = osm_port_get_lmc(dest_port);
1943d6b92ffaSHans Petter Selasky 			count += (1 << lmc);
1944d6b92ffaSHans Petter Selasky 		}
1945d6b92ffaSHans Petter Selasky 	}
1946d6b92ffaSHans Petter Selasky 	/* allocate VL table and indexing array */
1947d6b92ffaSHans Petter Selasky 	err = vltable_alloc(&srcdest2vl_table, count);
1948d6b92ffaSHans Petter Selasky 	if (err) {
1949d6b92ffaSHans Petter Selasky 		OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
1950d6b92ffaSHans Petter Selasky 			"ERR AD26: cannot allocate memory for srcdest2vl_table\n");
1951d6b92ffaSHans Petter Selasky 		goto ERROR;
1952d6b92ffaSHans Petter Selasky 	}
1953d6b92ffaSHans Petter Selasky 
1954d6b92ffaSHans Petter Selasky 	i = 0;
1955d6b92ffaSHans Petter Selasky 	/* fill lids into indexing array */
1956d6b92ffaSHans Petter Selasky 	for (item1 = cl_qlist_head(port_tbl); item1 != cl_qlist_end(port_tbl);
1957d6b92ffaSHans Petter Selasky 	     item1 = cl_qlist_next(item1)) {
1958d6b92ffaSHans Petter Selasky 		dest_port = (osm_port_t *)cl_item_obj(item1, dest_port,
1959d6b92ffaSHans Petter Selasky 						      list_item);
1960d6b92ffaSHans Petter Selasky 		ntype = osm_node_get_type(dest_port->p_node);
1961d6b92ffaSHans Petter Selasky 		if (ntype == IB_NODE_TYPE_CA || ntype == IB_NODE_TYPE_SWITCH) {
1962d6b92ffaSHans Petter Selasky 			/* only SP0 with SLtoVLMapping support will be processed */
1963d6b92ffaSHans Petter Selasky 			if (ntype == IB_NODE_TYPE_SWITCH
1964d6b92ffaSHans Petter Selasky 			    && !(dest_port->p_physp->port_info.capability_mask
1965d6b92ffaSHans Petter Selasky 			    & IB_PORT_CAP_HAS_SL_MAP))
1966d6b92ffaSHans Petter Selasky 				continue;
1967d6b92ffaSHans Petter Selasky 
1968d6b92ffaSHans Petter Selasky 			osm_port_get_lid_range_ho(dest_port, &min_lid_ho,
1969d6b92ffaSHans Petter Selasky 						  &max_lid_ho);
1970d6b92ffaSHans Petter Selasky 			for (dlid = min_lid_ho; dlid <= max_lid_ho; dlid++, i++)
1971d6b92ffaSHans Petter Selasky 				srcdest2vl_table->lids[i] = cl_hton16(dlid);
1972d6b92ffaSHans Petter Selasky 		}
1973d6b92ffaSHans Petter Selasky 	}
1974d6b92ffaSHans Petter Selasky 	/* sort lids */
1975d6b92ffaSHans Petter Selasky 	vltable_sort_lids(srcdest2vl_table);
1976d6b92ffaSHans Petter Selasky 
1977d6b92ffaSHans Petter Selasky 	test_vl = 0;
1978d6b92ffaSHans Petter Selasky 	/* fill cdg[0] with routes from each src/dest port combination for all Hca/SP0 in the subnet */
1979d6b92ffaSHans Petter Selasky 	for (item1 = cl_qlist_head(port_tbl); item1 != cl_qlist_end(port_tbl);
1980d6b92ffaSHans Petter Selasky 	     item1 = cl_qlist_next(item1)) {
1981d6b92ffaSHans Petter Selasky 		dest_port = (osm_port_t *)cl_item_obj(item1, dest_port,
1982d6b92ffaSHans Petter Selasky 						      list_item);
1983d6b92ffaSHans Petter Selasky 		ntype = osm_node_get_type(dest_port->p_node);
1984d6b92ffaSHans Petter Selasky 		if ((ntype != IB_NODE_TYPE_CA && ntype != IB_NODE_TYPE_SWITCH)
1985d6b92ffaSHans Petter Selasky 		    || !(dest_port->p_physp->port_info.capability_mask
1986d6b92ffaSHans Petter Selasky 		    & IB_PORT_CAP_HAS_SL_MAP))
1987d6b92ffaSHans Petter Selasky 			continue;
1988d6b92ffaSHans Petter Selasky 
1989d6b92ffaSHans Petter Selasky 		for (item2 = cl_qlist_head(port_tbl);
1990d6b92ffaSHans Petter Selasky 		     item2 != cl_qlist_end(port_tbl);
1991d6b92ffaSHans Petter Selasky 		     item2 = cl_qlist_next(item2)) {
1992d6b92ffaSHans Petter Selasky 			src_port = (osm_port_t *)cl_item_obj(item2, src_port,
1993d6b92ffaSHans Petter Selasky 							     list_item);
1994d6b92ffaSHans Petter Selasky 			ntype = osm_node_get_type(src_port->p_node);
1995d6b92ffaSHans Petter Selasky 			if ((ntype != IB_NODE_TYPE_CA
1996d6b92ffaSHans Petter Selasky 			    && ntype != IB_NODE_TYPE_SWITCH)
1997d6b92ffaSHans Petter Selasky 			    || !(src_port->p_physp->port_info.capability_mask
1998d6b92ffaSHans Petter Selasky 			    & IB_PORT_CAP_HAS_SL_MAP))
1999d6b92ffaSHans Petter Selasky 				continue;
2000d6b92ffaSHans Petter Selasky 
2001d6b92ffaSHans Petter Selasky 			if (src_port != dest_port) {
2002d6b92ffaSHans Petter Selasky 				/* iterate over LIDs of src and dest port */
2003d6b92ffaSHans Petter Selasky 				osm_port_get_lid_range_ho(src_port, &min_lid_ho,
2004d6b92ffaSHans Petter Selasky 							  &max_lid_ho);
2005d6b92ffaSHans Petter Selasky 				for (slid = min_lid_ho; slid <= max_lid_ho;
2006d6b92ffaSHans Petter Selasky 				     slid++) {
2007d6b92ffaSHans Petter Selasky 					osm_port_get_lid_range_ho
2008d6b92ffaSHans Petter Selasky 					    (dest_port, &min_lid_ho2,
2009d6b92ffaSHans Petter Selasky 					     &max_lid_ho2);
2010d6b92ffaSHans Petter Selasky 					for (dlid = min_lid_ho2;
2011d6b92ffaSHans Petter Selasky 					     dlid <= max_lid_ho2;
2012d6b92ffaSHans Petter Selasky 					     dlid++) {
2013d6b92ffaSHans Petter Selasky 
2014d6b92ffaSHans Petter Selasky 						/* try to add the path to cdg[0] */
2015d6b92ffaSHans Petter Selasky 						err =
2016d6b92ffaSHans Petter Selasky 						    update_channel_dep_graph
2017d6b92ffaSHans Petter Selasky 						    (&(cdg[test_vl]),
2018d6b92ffaSHans Petter Selasky 						     src_port, slid,
2019d6b92ffaSHans Petter Selasky 						     dest_port, dlid);
2020d6b92ffaSHans Petter Selasky 						if (err) {
2021d6b92ffaSHans Petter Selasky 							OSM_LOG(p_mgr->
2022d6b92ffaSHans Petter Selasky 								p_log,
2023d6b92ffaSHans Petter Selasky 								OSM_LOG_ERROR,
2024d6b92ffaSHans Petter Selasky 								"ERR AD14: cannot allocate memory for cdg node or link in update_channel_dep_graph(...)\n");
2025d6b92ffaSHans Petter Selasky 							goto ERROR;
2026d6b92ffaSHans Petter Selasky 						}
2027d6b92ffaSHans Petter Selasky 						/* add the <s,d> combination / corresponding virtual lane to the VL table */
2028d6b92ffaSHans Petter Selasky 						vltable_insert
2029d6b92ffaSHans Petter Selasky 						    (srcdest2vl_table,
2030d6b92ffaSHans Petter Selasky 						     cl_hton16(slid),
2031d6b92ffaSHans Petter Selasky 						     cl_hton16(dlid),
2032d6b92ffaSHans Petter Selasky 						     test_vl);
2033d6b92ffaSHans Petter Selasky 						paths_per_vl[test_vl]++;
2034d6b92ffaSHans Petter Selasky 
2035d6b92ffaSHans Petter Selasky 					}
2036d6b92ffaSHans Petter Selasky 
2037d6b92ffaSHans Petter Selasky 				}
2038d6b92ffaSHans Petter Selasky 			}
2039d6b92ffaSHans Petter Selasky 
2040d6b92ffaSHans Petter Selasky 		}
2041d6b92ffaSHans Petter Selasky 	}
2042d6b92ffaSHans Petter Selasky 	dfsssp_ctx->srcdest2vl_table = srcdest2vl_table;
2043d6b92ffaSHans Petter Selasky 
2044d6b92ffaSHans Petter Selasky 	/* test all cdg for cycles and break the cycles by moving paths on the weakest link to the next cdg */
2045d6b92ffaSHans Petter Selasky 	for (test_vl = 0; test_vl < vl_avail - 1; test_vl++) {
2046d6b92ffaSHans Petter Selasky 		start_here = cdg[test_vl];
2047d6b92ffaSHans Petter Selasky 		while (start_here) {
2048d6b92ffaSHans Petter Selasky 			cycle =
2049d6b92ffaSHans Petter Selasky 			    search_cycle_in_channel_dep_graph(cdg[test_vl],
2050d6b92ffaSHans Petter Selasky 							      start_here);
2051d6b92ffaSHans Petter Selasky 
2052d6b92ffaSHans Petter Selasky 			if (cycle) {
2053d6b92ffaSHans Petter Selasky 				vl_needed = test_vl + 2;
2054d6b92ffaSHans Petter Selasky 
2055d6b92ffaSHans Petter Selasky 				/* calc weakest link n cycle */
2056d6b92ffaSHans Petter Selasky 				weakest_link = get_weakest_link_in_cycle(cycle);
2057d6b92ffaSHans Petter Selasky 				if (!weakest_link) {
2058d6b92ffaSHans Petter Selasky 					OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
2059d6b92ffaSHans Petter Selasky 						"ERR AD27: something went wrong in get_weakest_link_in_cycle(...)\n");
2060d6b92ffaSHans Petter Selasky 					err = 1;
2061d6b92ffaSHans Petter Selasky 					goto ERROR;
2062d6b92ffaSHans Petter Selasky 				}
2063d6b92ffaSHans Petter Selasky 
2064d6b92ffaSHans Petter Selasky 				paths_per_vl[test_vl] -=
2065d6b92ffaSHans Petter Selasky 				    weakest_link->num_pairs;
2066d6b92ffaSHans Petter Selasky 				paths_per_vl[test_vl + 1] +=
2067d6b92ffaSHans Petter Selasky 				    weakest_link->num_pairs;
2068d6b92ffaSHans Petter Selasky 
2069d6b92ffaSHans Petter Selasky 				/* move all <s,d> paths on this link to the next cdg */
2070d6b92ffaSHans Petter Selasky 				for (i = 0; i < weakest_link->num_pairs; i++) {
2071d6b92ffaSHans Petter Selasky 					srcdest =
2072d6b92ffaSHans Petter Selasky 					    get_next_srcdest_pair(weakest_link,
2073d6b92ffaSHans Petter Selasky 								  i);
2074d6b92ffaSHans Petter Selasky 					slid = (uint16_t) (srcdest >> 16);
2075d6b92ffaSHans Petter Selasky 					dlid =
2076d6b92ffaSHans Petter Selasky 					    (uint16_t) ((srcdest << 16) >> 16);
2077d6b92ffaSHans Petter Selasky 
2078d6b92ffaSHans Petter Selasky 					/* only move if not moved in a previous step */
2079d6b92ffaSHans Petter Selasky 					if (test_vl !=
2080d6b92ffaSHans Petter Selasky 					    (uint8_t)
2081d6b92ffaSHans Petter Selasky 					    vltable_get_vl(srcdest2vl_table,
2082d6b92ffaSHans Petter Selasky 							   cl_hton16(slid),
2083d6b92ffaSHans Petter Selasky 							   cl_hton16(dlid))) {
2084d6b92ffaSHans Petter Selasky 						/* this path has been moved
2085d6b92ffaSHans Petter Selasky 						   before -> don't count
2086d6b92ffaSHans Petter Selasky 						 */
2087d6b92ffaSHans Petter Selasky 						paths_per_vl[test_vl]++;
2088d6b92ffaSHans Petter Selasky 						paths_per_vl[test_vl + 1]--;
2089d6b92ffaSHans Petter Selasky 						continue;
2090d6b92ffaSHans Petter Selasky 					}
2091d6b92ffaSHans Petter Selasky 
2092d6b92ffaSHans Petter Selasky 					src_port =
2093d6b92ffaSHans Petter Selasky 					    osm_get_port_by_lid(p_mgr->p_subn,
2094d6b92ffaSHans Petter Selasky 								cl_hton16
2095d6b92ffaSHans Petter Selasky 								(slid));
2096d6b92ffaSHans Petter Selasky 					dest_port =
2097d6b92ffaSHans Petter Selasky 					    osm_get_port_by_lid(p_mgr->p_subn,
2098d6b92ffaSHans Petter Selasky 								cl_hton16
2099d6b92ffaSHans Petter Selasky 								(dlid));
2100d6b92ffaSHans Petter Selasky 
2101d6b92ffaSHans Petter Selasky 					/* remove path from current cdg / vl */
2102d6b92ffaSHans Petter Selasky 					err =
2103d6b92ffaSHans Petter Selasky 					    remove_path_from_cdg(&
2104d6b92ffaSHans Petter Selasky 								 (cdg[test_vl]),
2105d6b92ffaSHans Petter Selasky 								 src_port, slid,
2106d6b92ffaSHans Petter Selasky 								 dest_port,
2107d6b92ffaSHans Petter Selasky 								 dlid);
2108d6b92ffaSHans Petter Selasky 					if (err) {
2109d6b92ffaSHans Petter Selasky 						OSM_LOG(p_mgr->p_log,
2110d6b92ffaSHans Petter Selasky 							OSM_LOG_ERROR,
2111d6b92ffaSHans Petter Selasky 							"ERR AD44: something went wrong in remove_path_from_cdg(...)\n");
2112d6b92ffaSHans Petter Selasky 						goto ERROR;
2113d6b92ffaSHans Petter Selasky 					}
2114d6b92ffaSHans Petter Selasky 
2115d6b92ffaSHans Petter Selasky 					/* add path to next cdg / vl */
2116d6b92ffaSHans Petter Selasky 					err =
2117d6b92ffaSHans Petter Selasky 					    update_channel_dep_graph(&
2118d6b92ffaSHans Petter Selasky 								     (cdg
2119d6b92ffaSHans Petter Selasky 								      [test_vl +
2120d6b92ffaSHans Petter Selasky 								       1]),
2121d6b92ffaSHans Petter Selasky 								     src_port,
2122d6b92ffaSHans Petter Selasky 								     slid,
2123d6b92ffaSHans Petter Selasky 								     dest_port,
2124d6b92ffaSHans Petter Selasky 								     dlid);
2125d6b92ffaSHans Petter Selasky 					if (err) {
2126d6b92ffaSHans Petter Selasky 						OSM_LOG(p_mgr->p_log,
2127d6b92ffaSHans Petter Selasky 							OSM_LOG_ERROR,
2128d6b92ffaSHans Petter Selasky 							"ERR AD14: cannot allocate memory for cdg node or link in update_channel_dep_graph(...)\n");
2129d6b92ffaSHans Petter Selasky 						goto ERROR;
2130d6b92ffaSHans Petter Selasky 					}
2131d6b92ffaSHans Petter Selasky 					vltable_insert(srcdest2vl_table,
2132d6b92ffaSHans Petter Selasky 						       cl_hton16(slid),
2133d6b92ffaSHans Petter Selasky 						       cl_hton16(dlid),
2134d6b92ffaSHans Petter Selasky 						       test_vl + 1);
2135d6b92ffaSHans Petter Selasky 				}
2136d6b92ffaSHans Petter Selasky 
2137d6b92ffaSHans Petter Selasky 				if (weakest_link->num_pairs)
2138d6b92ffaSHans Petter Selasky 					free(weakest_link->srcdest_pairs);
2139d6b92ffaSHans Petter Selasky 				if (weakest_link)
2140d6b92ffaSHans Petter Selasky 					free(weakest_link);
2141d6b92ffaSHans Petter Selasky 			}
2142d6b92ffaSHans Petter Selasky 
2143d6b92ffaSHans Petter Selasky 			start_here = cycle;
2144d6b92ffaSHans Petter Selasky 		}
2145d6b92ffaSHans Petter Selasky 	}
2146d6b92ffaSHans Petter Selasky 
2147d6b92ffaSHans Petter Selasky 	/* test the last avail cdg for a cycle;
2148d6b92ffaSHans Petter Selasky 	   if there is one, than vl_needed > vl_avail
2149d6b92ffaSHans Petter Selasky 	 */
2150d6b92ffaSHans Petter Selasky 	start_here = cdg[vl_avail - 1];
2151d6b92ffaSHans Petter Selasky 	if (start_here) {
2152d6b92ffaSHans Petter Selasky 		cycle =
2153d6b92ffaSHans Petter Selasky 		    search_cycle_in_channel_dep_graph(cdg[vl_avail - 1],
2154d6b92ffaSHans Petter Selasky 						      start_here);
2155d6b92ffaSHans Petter Selasky 		if (cycle) {
2156d6b92ffaSHans Petter Selasky 			vl_needed = vl_avail + 1;
2157d6b92ffaSHans Petter Selasky 		}
2158d6b92ffaSHans Petter Selasky 	}
2159d6b92ffaSHans Petter Selasky 
2160d6b92ffaSHans Petter Selasky 	OSM_LOG(p_mgr->p_log, OSM_LOG_INFO,
2161d6b92ffaSHans Petter Selasky 		"Virtual Lanes needed: %" PRIu8 "\n", vl_needed);
2162d6b92ffaSHans Petter Selasky 	if (OSM_LOG_IS_ACTIVE_V2(p_mgr->p_log, OSM_LOG_INFO)) {
2163d6b92ffaSHans Petter Selasky 		OSM_LOG(p_mgr->p_log, OSM_LOG_INFO,
2164d6b92ffaSHans Petter Selasky 			"Paths per VL (before balancing):\n");
2165d6b92ffaSHans Petter Selasky 		for (i = 0; i < vl_avail; i++)
2166d6b92ffaSHans Petter Selasky 			OSM_LOG(p_mgr->p_log, OSM_LOG_INFO,
2167d6b92ffaSHans Petter Selasky 				"   %" PRIu32 ". lane: %" PRIu64 "\n", i,
2168d6b92ffaSHans Petter Selasky 				paths_per_vl[i]);
2169d6b92ffaSHans Petter Selasky 	}
2170d6b92ffaSHans Petter Selasky 
2171d6b92ffaSHans Petter Selasky 	OSM_LOG(p_mgr->p_log, OSM_LOG_VERBOSE,
2172d6b92ffaSHans Petter Selasky 		"Balancing the paths on the available Virtual Lanes\n");
2173d6b92ffaSHans Petter Selasky 
2174d6b92ffaSHans Petter Selasky 	/* optimal balancing virtual lanes, under condition: no additional cycle checks;
2175d6b92ffaSHans Petter Selasky 	   sl/vl != 0 might be assigned to loopback packets (i.e. slid/dlid on the
2176d6b92ffaSHans Petter Selasky 	   same port for lmc>0), but thats no problem, see IBAS 10.2.2.3
2177d6b92ffaSHans Petter Selasky 	 */
2178d6b92ffaSHans Petter Selasky 	split_count = (uint8_t *) calloc(vl_avail, sizeof(uint8_t));
2179d6b92ffaSHans Petter Selasky 	if (!split_count) {
2180d6b92ffaSHans Petter Selasky 		OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
2181d6b92ffaSHans Petter Selasky 			"ERR AD24: cannot allocate memory for split_count, skip balancing\n");
2182d6b92ffaSHans Petter Selasky 		err = 1;
2183d6b92ffaSHans Petter Selasky 		goto ERROR;
2184d6b92ffaSHans Petter Selasky 	}
2185d6b92ffaSHans Petter Selasky 	/* initial state: paths for VLs won't be separated */
2186d6b92ffaSHans Petter Selasky 	for (i = 0; i < ((vl_needed < vl_avail) ? vl_needed : vl_avail); i++)
2187d6b92ffaSHans Petter Selasky 		split_count[i] = 1;
2188d6b92ffaSHans Petter Selasky 	dfsssp_ctx->vl_split_count = split_count;
2189d6b92ffaSHans Petter Selasky 	/* balancing is necessary if we have empty VLs */
2190d6b92ffaSHans Petter Selasky 	if (vl_needed < vl_avail) {
2191d6b92ffaSHans Petter Selasky 		/* split paths of VLs until we find an equal distribution */
2192d6b92ffaSHans Petter Selasky 		for (i = vl_needed; i < vl_avail; i++) {
2193d6b92ffaSHans Petter Selasky 			/* find VL with most paths in it */
2194d6b92ffaSHans Petter Selasky 			vl = 0;
2195d6b92ffaSHans Petter Selasky 			most_avg_paths = 0.0;
2196d6b92ffaSHans Petter Selasky 			for (test_vl = 0; test_vl < vl_needed; test_vl++) {
2197d6b92ffaSHans Petter Selasky 				if (most_avg_paths <
2198d6b92ffaSHans Petter Selasky 				    ((double)paths_per_vl[test_vl] /
2199d6b92ffaSHans Petter Selasky 				    split_count[test_vl])) {
2200d6b92ffaSHans Petter Selasky 					vl = test_vl;
2201d6b92ffaSHans Petter Selasky 					most_avg_paths =
2202d6b92ffaSHans Petter Selasky 						(double)paths_per_vl[test_vl] /
2203d6b92ffaSHans Petter Selasky 						split_count[test_vl];
2204d6b92ffaSHans Petter Selasky 				}
2205d6b92ffaSHans Petter Selasky 			}
2206d6b92ffaSHans Petter Selasky 			split_count[vl]++;
2207d6b92ffaSHans Petter Selasky 		}
2208d6b92ffaSHans Petter Selasky 		/* change the VL assignment depending on split_count for
2209d6b92ffaSHans Petter Selasky 		   all VLs except VL 0
2210d6b92ffaSHans Petter Selasky 		 */
2211d6b92ffaSHans Petter Selasky 		for (from = vl_needed - 1; from > 0; from--) {
2212d6b92ffaSHans Petter Selasky 			/* how much space needed for others? */
2213d6b92ffaSHans Petter Selasky 			to = 0;
2214d6b92ffaSHans Petter Selasky 			for (i = 0; i < from; i++)
2215d6b92ffaSHans Petter Selasky 				to += split_count[i];
2216d6b92ffaSHans Petter Selasky 			count = paths_per_vl[from];
2217d6b92ffaSHans Petter Selasky 			vltable_change_vl(srcdest2vl_table, from, to, count);
2218d6b92ffaSHans Petter Selasky 			/* change also the information within the split_count
2219d6b92ffaSHans Petter Selasky 			   array; this is important for fast calculation later
2220d6b92ffaSHans Petter Selasky 			 */
2221d6b92ffaSHans Petter Selasky 			split_count[to] = split_count[from];
2222d6b92ffaSHans Petter Selasky 			split_count[from] = 0;
2223d6b92ffaSHans Petter Selasky 			paths_per_vl[to] = paths_per_vl[from];
2224d6b92ffaSHans Petter Selasky 			paths_per_vl[from] = 0;
2225d6b92ffaSHans Petter Selasky 		}
2226d6b92ffaSHans Petter Selasky 	} else if (vl_needed > vl_avail) {
2227d6b92ffaSHans Petter Selasky 		/* 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) */
2228d6b92ffaSHans Petter Selasky 		OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
2229d6b92ffaSHans Petter Selasky 			"ERR AD25: Not enough VLs available (avail=%d, needed=%d); Stopping dfsssp routing!\n",
2230d6b92ffaSHans Petter Selasky 			vl_avail, vl_needed);
2231d6b92ffaSHans Petter Selasky 		err = 1;
2232d6b92ffaSHans Petter Selasky 		goto ERROR;
2233d6b92ffaSHans Petter Selasky 	}
2234d6b92ffaSHans Petter Selasky 	/* else { no balancing } */
2235d6b92ffaSHans Petter Selasky 
2236d6b92ffaSHans Petter Selasky 	if (OSM_LOG_IS_ACTIVE_V2(p_mgr->p_log, OSM_LOG_DEBUG)) {
2237d6b92ffaSHans Petter Selasky 		OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
2238d6b92ffaSHans Petter Selasky 			"Virtual Lanes per src/dest combination after balancing:\n");
2239d6b92ffaSHans Petter Selasky 		vltable_print(p_mgr, srcdest2vl_table);
2240d6b92ffaSHans Petter Selasky 	}
2241d6b92ffaSHans Petter Selasky 	if (OSM_LOG_IS_ACTIVE_V2(p_mgr->p_log, OSM_LOG_INFO)) {
2242d6b92ffaSHans Petter Selasky 		OSM_LOG(p_mgr->p_log, OSM_LOG_INFO,
2243d6b92ffaSHans Petter Selasky 			"Approx. #paths per VL (after balancing):\n");
2244d6b92ffaSHans Petter Selasky 		j = 0;
2245d6b92ffaSHans Petter Selasky 		count = 1; /* to prevent div. by 0 */
2246d6b92ffaSHans Petter Selasky 		for (i = 0; i < vl_avail; i++) {
2247d6b92ffaSHans Petter Selasky 			if (split_count[i] > 0) {
2248d6b92ffaSHans Petter Selasky 				j = i;
2249d6b92ffaSHans Petter Selasky 				count = split_count[i];
2250d6b92ffaSHans Petter Selasky 			}
2251d6b92ffaSHans Petter Selasky 			OSM_LOG(p_mgr->p_log, OSM_LOG_INFO,
2252d6b92ffaSHans Petter Selasky 				"   %" PRIu32 ". lane: %" PRIu64 "\n", i,
2253d6b92ffaSHans Petter Selasky 				paths_per_vl[j] / count);
2254d6b92ffaSHans Petter Selasky 		}
2255d6b92ffaSHans Petter Selasky 	}
2256d6b92ffaSHans Petter Selasky 
2257d6b92ffaSHans Petter Selasky 	free(paths_per_vl);
2258d6b92ffaSHans Petter Selasky 
2259d6b92ffaSHans Petter Selasky 	/* deallocate channel dependency graphs */
2260d6b92ffaSHans Petter Selasky 	for (i = 0; i < vl_avail; i++)
2261d6b92ffaSHans Petter Selasky 		cdg_dealloc(&cdg[i]);
2262d6b92ffaSHans Petter Selasky 	free(cdg);
2263d6b92ffaSHans Petter Selasky 
2264d6b92ffaSHans Petter Selasky 	OSM_LOG_EXIT(p_mgr->p_log);
2265d6b92ffaSHans Petter Selasky 	return 0;
2266d6b92ffaSHans Petter Selasky 
2267d6b92ffaSHans Petter Selasky ERROR:
2268d6b92ffaSHans Petter Selasky 	free(paths_per_vl);
2269d6b92ffaSHans Petter Selasky 
2270d6b92ffaSHans Petter Selasky 	for (i = 0; i < vl_avail; i++)
2271d6b92ffaSHans Petter Selasky 		cdg_dealloc(&cdg[i]);
2272d6b92ffaSHans Petter Selasky 	free(cdg);
2273d6b92ffaSHans Petter Selasky 
2274d6b92ffaSHans Petter Selasky 	vltable_dealloc(&srcdest2vl_table);
2275d6b92ffaSHans Petter Selasky 	dfsssp_ctx->srcdest2vl_table = NULL;
2276d6b92ffaSHans Petter Selasky 
2277d6b92ffaSHans Petter Selasky 	return err;
2278d6b92ffaSHans Petter Selasky }
2279d6b92ffaSHans Petter Selasky 
2280d6b92ffaSHans Petter Selasky /* meta function which calls subfunctions for dijkstra, update lft and weights,
2281d6b92ffaSHans Petter Selasky    (and remove deadlocks) to calculate the routing for the subnet
2282d6b92ffaSHans Petter Selasky */
dfsssp_do_dijkstra_routing(void * context)2283d6b92ffaSHans Petter Selasky static int dfsssp_do_dijkstra_routing(void *context)
2284d6b92ffaSHans Petter Selasky {
2285d6b92ffaSHans Petter Selasky 	dfsssp_context_t *dfsssp_ctx = (dfsssp_context_t *) context;
2286d6b92ffaSHans Petter Selasky 	osm_ucast_mgr_t *p_mgr = (osm_ucast_mgr_t *) dfsssp_ctx->p_mgr;
2287d6b92ffaSHans Petter Selasky 	vertex_t *adj_list = (vertex_t *) dfsssp_ctx->adj_list;
2288d6b92ffaSHans Petter Selasky 	uint32_t adj_list_size = dfsssp_ctx->adj_list_size;
2289d6b92ffaSHans Petter Selasky 
2290d6b92ffaSHans Petter Selasky 	vertex_t **sw_list = NULL;
2291d6b92ffaSHans Petter Selasky 	uint32_t sw_list_size = 0;
2292d6b92ffaSHans Petter Selasky 	uint64_t guid = 0;
2293d6b92ffaSHans Petter Selasky 	cl_qlist_t *qlist = NULL;
2294d6b92ffaSHans Petter Selasky 	cl_list_item_t *qlist_item = NULL;
2295d6b92ffaSHans Petter Selasky 
2296d6b92ffaSHans Petter Selasky 	cl_qmap_t *sw_tbl = &p_mgr->p_subn->sw_guid_tbl;
2297d6b92ffaSHans Petter Selasky 	cl_qmap_t cn_tbl, io_tbl, *p_mixed_tbl = NULL;
2298d6b92ffaSHans Petter Selasky 	cl_map_item_t *item = NULL;
2299d6b92ffaSHans Petter Selasky 	osm_switch_t *sw = NULL;
2300d6b92ffaSHans Petter Selasky 	osm_port_t *port = NULL;
2301d6b92ffaSHans Petter Selasky 	uint32_t i = 0, err = 0;
2302d6b92ffaSHans Petter Selasky 	uint16_t lid = 0, min_lid_ho = 0, max_lid_ho = 0;
2303d6b92ffaSHans Petter Selasky 	uint8_t lmc = 0;
2304d6b92ffaSHans Petter Selasky 	boolean_t cn_nodes_provided = FALSE, io_nodes_provided = FALSE;
2305d6b92ffaSHans Petter Selasky 
2306d6b92ffaSHans Petter Selasky 	OSM_LOG_ENTER(p_mgr->p_log);
2307d6b92ffaSHans Petter Selasky 	OSM_LOG(p_mgr->p_log, OSM_LOG_VERBOSE,
2308d6b92ffaSHans Petter Selasky 		"Calculating shortest path from all Hca/switches to all\n");
2309d6b92ffaSHans Petter Selasky 
2310d6b92ffaSHans Petter Selasky 	cl_qmap_init(&cn_tbl);
2311d6b92ffaSHans Petter Selasky 	cl_qmap_init(&io_tbl);
2312d6b92ffaSHans Petter Selasky 	p_mixed_tbl = &cn_tbl;
2313d6b92ffaSHans Petter Selasky 
2314d6b92ffaSHans Petter Selasky 	cl_qlist_init(&p_mgr->port_order_list);
2315d6b92ffaSHans Petter Selasky 
2316d6b92ffaSHans Petter Selasky 	/* reset the new_lft for each switch */
2317d6b92ffaSHans Petter Selasky 	for (item = cl_qmap_head(sw_tbl); item != cl_qmap_end(sw_tbl);
2318d6b92ffaSHans Petter Selasky 	     item = cl_qmap_next(item)) {
2319d6b92ffaSHans Petter Selasky 		sw = (osm_switch_t *) item;
2320d6b92ffaSHans Petter Selasky 		/* initialize LIDs in buffer to invalid port number */
2321d6b92ffaSHans Petter Selasky 		memset(sw->new_lft, OSM_NO_PATH, sw->max_lid_ho + 1);
2322d6b92ffaSHans Petter Selasky 		/* initialize LFT and hop count for bsp0/esp0 of the switch */
2323d6b92ffaSHans Petter Selasky 		min_lid_ho = cl_ntoh16(osm_node_get_base_lid(sw->p_node, 0));
2324d6b92ffaSHans Petter Selasky 		lmc = osm_node_get_lmc(sw->p_node, 0);
2325d6b92ffaSHans Petter Selasky 		for (i = min_lid_ho; i < min_lid_ho + (1 << lmc); i++) {
2326d6b92ffaSHans Petter Selasky 			/* for each switch the port to the 'self'lid is the management port 0 */
2327d6b92ffaSHans Petter Selasky 			sw->new_lft[i] = 0;
2328d6b92ffaSHans Petter Selasky 			/* the hop count to the 'self'lid is 0 for each switch */
2329d6b92ffaSHans Petter Selasky 			osm_switch_set_hops(sw, i, 0, 0);
2330d6b92ffaSHans Petter Selasky 		}
2331d6b92ffaSHans Petter Selasky 	}
2332d6b92ffaSHans Petter Selasky 
2333d6b92ffaSHans Petter Selasky 	/* we need an intermediate array of pointers to switches in adj_list;
2334d6b92ffaSHans Petter Selasky 	   this array will be sorted in respect to num_hca (descending)
2335d6b92ffaSHans Petter Selasky 	 */
2336d6b92ffaSHans Petter Selasky 	sw_list_size = adj_list_size - 1;
2337d6b92ffaSHans Petter Selasky 	sw_list = (vertex_t **)malloc(sw_list_size * sizeof(vertex_t *));
2338d6b92ffaSHans Petter Selasky 	if (!sw_list) {
2339d6b92ffaSHans Petter Selasky 		OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
2340d6b92ffaSHans Petter Selasky 			"ERR AD29: cannot allocate memory for sw_list in dfsssp_do_dijkstra_routing\n");
2341d6b92ffaSHans Petter Selasky 		goto ERROR;
2342d6b92ffaSHans Petter Selasky 	}
2343d6b92ffaSHans Petter Selasky 	memset(sw_list, 0, sw_list_size * sizeof(vertex_t *));
2344d6b92ffaSHans Petter Selasky 
2345d6b92ffaSHans Petter Selasky 	/* fill the array with references to the 'real' sw in adj_list */
2346d6b92ffaSHans Petter Selasky 	for (i = 0; i < sw_list_size; i++)
2347d6b92ffaSHans Petter Selasky 		sw_list[i] = &(adj_list[i + 1]);
2348d6b92ffaSHans Petter Selasky 
2349d6b92ffaSHans Petter Selasky 	/* sort the sw_list in descending order */
2350d6b92ffaSHans Petter Selasky 	sw_list_sort_by_num_hca(sw_list, sw_list_size);
2351d6b92ffaSHans Petter Selasky 
2352d6b92ffaSHans Petter Selasky 	/* parse compute node guid file, if provided by the user */
2353d6b92ffaSHans Petter Selasky 	if (p_mgr->p_subn->opt.cn_guid_file) {
2354d6b92ffaSHans Petter Selasky 		OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
2355d6b92ffaSHans Petter Selasky 			"Parsing compute nodes from file %s\n",
2356d6b92ffaSHans Petter Selasky 			p_mgr->p_subn->opt.cn_guid_file);
2357d6b92ffaSHans Petter Selasky 
2358d6b92ffaSHans Petter Selasky 		if (parse_node_map(p_mgr->p_subn->opt.cn_guid_file,
2359d6b92ffaSHans Petter Selasky 				   add_guid_to_map, &cn_tbl)) {
2360d6b92ffaSHans Petter Selasky 			OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
2361d6b92ffaSHans Petter Selasky 				"ERR AD33: Problem parsing compute node guid file\n");
2362d6b92ffaSHans Petter Selasky 			goto ERROR;
2363d6b92ffaSHans Petter Selasky 		}
2364d6b92ffaSHans Petter Selasky 
2365d6b92ffaSHans Petter Selasky 		if (cl_is_qmap_empty(&cn_tbl))
2366d6b92ffaSHans Petter Selasky 			OSM_LOG(p_mgr->p_log, OSM_LOG_INFO,
2367d6b92ffaSHans Petter Selasky 				"WRN AD34: compute node guids file contains no valid guids\n");
2368d6b92ffaSHans Petter Selasky 		else
2369d6b92ffaSHans Petter Selasky 			cn_nodes_provided = TRUE;
2370d6b92ffaSHans Petter Selasky 	}
2371d6b92ffaSHans Petter Selasky 
2372d6b92ffaSHans Petter Selasky 	/* parse I/O guid file, if provided by the user */
2373d6b92ffaSHans Petter Selasky 	if (p_mgr->p_subn->opt.io_guid_file) {
2374d6b92ffaSHans Petter Selasky 		OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
2375d6b92ffaSHans Petter Selasky 			"Parsing I/O nodes from file %s\n",
2376d6b92ffaSHans Petter Selasky 			p_mgr->p_subn->opt.io_guid_file);
2377d6b92ffaSHans Petter Selasky 
2378d6b92ffaSHans Petter Selasky 		if (parse_node_map(p_mgr->p_subn->opt.io_guid_file,
2379d6b92ffaSHans Petter Selasky 				   add_guid_to_map, &io_tbl)) {
2380d6b92ffaSHans Petter Selasky 			OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
2381d6b92ffaSHans Petter Selasky 				"ERR AD35: Problem parsing I/O guid file\n");
2382d6b92ffaSHans Petter Selasky 			goto ERROR;
2383d6b92ffaSHans Petter Selasky 		}
2384d6b92ffaSHans Petter Selasky 
2385d6b92ffaSHans Petter Selasky 		if (cl_is_qmap_empty(&io_tbl))
2386d6b92ffaSHans Petter Selasky 			OSM_LOG(p_mgr->p_log, OSM_LOG_INFO,
2387d6b92ffaSHans Petter Selasky 				"WRN AD36: I/O node guids file contains no valid guids\n");
2388d6b92ffaSHans Petter Selasky 		else
2389d6b92ffaSHans Petter Selasky 			io_nodes_provided = TRUE;
2390d6b92ffaSHans Petter Selasky 	}
2391d6b92ffaSHans Petter Selasky 
2392d6b92ffaSHans Petter Selasky 	/* if we mix Hca/Tca/SP0 during the dijkstra routing, we might end up
2393d6b92ffaSHans Petter Selasky 	   in rare cases with a bad balancing for Hca<->Hca connections, i.e.
2394d6b92ffaSHans Petter Selasky 	   some inter-switch links get oversubscribed with paths;
2395d6b92ffaSHans Petter Selasky 	   therefore: add Hca ports first to ensure good Hca<->Hca balancing
2396d6b92ffaSHans Petter Selasky 	 */
2397d6b92ffaSHans Petter Selasky 	if (cn_nodes_provided) {
2398d6b92ffaSHans Petter Selasky 		for (i = 0; i < adj_list_size - 1; i++) {
2399d6b92ffaSHans Petter Selasky 			if (sw_list[i] && sw_list[i]->sw) {
2400d6b92ffaSHans Petter Selasky 				sw = (osm_switch_t *)(sw_list[i]->sw);
2401d6b92ffaSHans Petter Selasky 				add_sw_endports_to_order_list(sw, p_mgr,
2402d6b92ffaSHans Petter Selasky 							      &cn_tbl, TRUE);
2403d6b92ffaSHans Petter Selasky 			} else {
2404d6b92ffaSHans Petter Selasky 				OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
2405d6b92ffaSHans Petter Selasky 					"ERR AD30: corrupted sw_list array in dfsssp_do_dijkstra_routing\n");
2406d6b92ffaSHans Petter Selasky 				goto ERROR;
2407d6b92ffaSHans Petter Selasky 			}
2408d6b92ffaSHans Petter Selasky 		}
2409d6b92ffaSHans Petter Selasky 	}
2410d6b92ffaSHans Petter Selasky 	/* then: add Tca ports to ensure good Hca->Tca balancing and separate
2411d6b92ffaSHans Petter Selasky 	   paths towards I/O nodes on the same switch (if possible)
2412d6b92ffaSHans Petter Selasky 	 */
2413d6b92ffaSHans Petter Selasky 	if (io_nodes_provided) {
2414d6b92ffaSHans Petter Selasky 		for (i = 0; i < adj_list_size - 1; i++) {
2415d6b92ffaSHans Petter Selasky 			if (sw_list[i] && sw_list[i]->sw) {
2416d6b92ffaSHans Petter Selasky 				sw = (osm_switch_t *)(sw_list[i]->sw);
2417d6b92ffaSHans Petter Selasky 				add_sw_endports_to_order_list(sw, p_mgr,
2418d6b92ffaSHans Petter Selasky 							      &io_tbl, TRUE);
2419d6b92ffaSHans Petter Selasky 			} else {
2420d6b92ffaSHans Petter Selasky 				OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
2421d6b92ffaSHans Petter Selasky 					"ERR AD32: corrupted sw_list array in dfsssp_do_dijkstra_routing\n");
2422d6b92ffaSHans Petter Selasky 				goto ERROR;
2423d6b92ffaSHans Petter Selasky 			}
2424d6b92ffaSHans Petter Selasky 		}
2425d6b92ffaSHans Petter Selasky 	}
2426d6b92ffaSHans Petter Selasky 	/* then: add anything else, such as administration nodes, ... */
2427d6b92ffaSHans Petter Selasky 	if (cn_nodes_provided && io_nodes_provided) {
2428d6b92ffaSHans Petter Selasky 		cl_qmap_merge(&cn_tbl, &io_tbl);
2429d6b92ffaSHans Petter Selasky 	} else if (io_nodes_provided) {
2430d6b92ffaSHans Petter Selasky 		p_mixed_tbl = &io_tbl;
2431d6b92ffaSHans Petter Selasky 	}
2432d6b92ffaSHans Petter Selasky 	for (i = 0; i < adj_list_size - 1; i++) {
2433d6b92ffaSHans Petter Selasky 		if (sw_list[i] && sw_list[i]->sw) {
2434d6b92ffaSHans Petter Selasky 			sw = (osm_switch_t *)(sw_list[i]->sw);
2435d6b92ffaSHans Petter Selasky 			add_sw_endports_to_order_list(sw, p_mgr, p_mixed_tbl,
2436d6b92ffaSHans Petter Selasky 						      FALSE);
2437d6b92ffaSHans Petter Selasky 		} else {
2438d6b92ffaSHans Petter Selasky 			OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
2439d6b92ffaSHans Petter Selasky 				"ERR AD39: corrupted sw_list array in dfsssp_do_dijkstra_routing\n");
2440d6b92ffaSHans Petter Selasky 			goto ERROR;
2441d6b92ffaSHans Petter Selasky 		}
2442d6b92ffaSHans Petter Selasky 	}
2443d6b92ffaSHans Petter Selasky 	/* last: add SP0 afterwards which have lower priority for balancing */
2444d6b92ffaSHans Petter Selasky 	for (i = 0; i < sw_list_size; i++) {
2445d6b92ffaSHans Petter Selasky 		if (sw_list[i] && sw_list[i]->sw) {
2446d6b92ffaSHans Petter Selasky 			sw = (osm_switch_t *)(sw_list[i]->sw);
2447d6b92ffaSHans Petter Selasky 			guid = cl_ntoh64(osm_node_get_node_guid(sw->p_node));
2448d6b92ffaSHans Petter Selasky 			add_guid_to_order_list(guid, p_mgr);
2449d6b92ffaSHans Petter Selasky 		} else {
2450d6b92ffaSHans Petter Selasky 			OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
2451d6b92ffaSHans Petter Selasky 				"ERR AD31: corrupted sw_list array in dfsssp_do_dijkstra_routing\n");
2452d6b92ffaSHans Petter Selasky 			goto ERROR;
2453d6b92ffaSHans Petter Selasky 		}
2454d6b92ffaSHans Petter Selasky 	}
2455d6b92ffaSHans Petter Selasky 
2456d6b92ffaSHans Petter Selasky 	/* the intermediate array lived long enough */
2457d6b92ffaSHans Petter Selasky 	free(sw_list);
2458d6b92ffaSHans Petter Selasky 	sw_list = NULL;
2459d6b92ffaSHans Petter Selasky 	/* same is true for the compute node and I/O guid map */
2460d6b92ffaSHans Petter Selasky 	destroy_guid_map(&cn_tbl);
2461d6b92ffaSHans Petter Selasky 	cn_nodes_provided = FALSE;
2462d6b92ffaSHans Petter Selasky 	destroy_guid_map(&io_tbl);
2463d6b92ffaSHans Petter Selasky 	io_nodes_provided = FALSE;
2464d6b92ffaSHans Petter Selasky 
2465d6b92ffaSHans Petter Selasky 	/* do the routing for the each Hca in the subnet and each switch
2466d6b92ffaSHans Petter Selasky 	   in the subnet (to add the routes to base/enhanced SP0)
2467d6b92ffaSHans Petter Selasky 	 */
2468d6b92ffaSHans Petter Selasky 	qlist = &p_mgr->port_order_list;
2469d6b92ffaSHans Petter Selasky 	for (qlist_item = cl_qlist_head(qlist);
2470d6b92ffaSHans Petter Selasky 	     qlist_item != cl_qlist_end(qlist);
2471d6b92ffaSHans Petter Selasky 	     qlist_item = cl_qlist_next(qlist_item)) {
2472d6b92ffaSHans Petter Selasky 		port = (osm_port_t *)cl_item_obj(qlist_item, port, list_item);
2473d6b92ffaSHans Petter Selasky 
2474d6b92ffaSHans Petter Selasky 		/* calculate shortest path with dijkstra from node to all switches/Hca */
2475d6b92ffaSHans Petter Selasky 		if (osm_node_get_type(port->p_node) == IB_NODE_TYPE_CA) {
2476d6b92ffaSHans Petter Selasky 			OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
2477d6b92ffaSHans Petter Selasky 				"Processing Hca with GUID 0x%" PRIx64 "\n",
2478d6b92ffaSHans Petter Selasky 				cl_ntoh64(osm_node_get_node_guid
2479d6b92ffaSHans Petter Selasky 					  (port->p_node)));
2480d6b92ffaSHans Petter Selasky 		} else if (osm_node_get_type(port->p_node) == IB_NODE_TYPE_SWITCH) {
2481d6b92ffaSHans Petter Selasky 			OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
2482d6b92ffaSHans Petter Selasky 				"Processing switch with GUID 0x%" PRIx64 "\n",
2483d6b92ffaSHans Petter Selasky 				cl_ntoh64(osm_node_get_node_guid
2484d6b92ffaSHans Petter Selasky 					  (port->p_node)));
2485d6b92ffaSHans Petter Selasky 		} else {
2486d6b92ffaSHans Petter Selasky 			/* we don't handle routers, in case they show up */
2487d6b92ffaSHans Petter Selasky 			continue;
2488d6b92ffaSHans Petter Selasky 		}
2489d6b92ffaSHans Petter Selasky 
2490d6b92ffaSHans Petter Selasky 		/* distribute the LID range across the ports that can reach those LIDs
2491d6b92ffaSHans Petter Selasky 		   to have disjoint paths for one destination port with lmc>0;
2492d6b92ffaSHans Petter Selasky 		   for switches with bsp0: min=max; with esp0: max>min if lmc>0
2493d6b92ffaSHans Petter Selasky 		 */
2494d6b92ffaSHans Petter Selasky 		osm_port_get_lid_range_ho(port, &min_lid_ho,
2495d6b92ffaSHans Petter Selasky 					  &max_lid_ho);
2496d6b92ffaSHans Petter Selasky 		for (lid = min_lid_ho; lid <= max_lid_ho; lid++) {
2497d6b92ffaSHans Petter Selasky 			/* do dijkstra from this Hca/LID/SP0 to each switch */
2498d6b92ffaSHans Petter Selasky 			err =
2499d6b92ffaSHans Petter Selasky 			    dijkstra(p_mgr, adj_list, adj_list_size, port, lid);
2500d6b92ffaSHans Petter Selasky 			if (err)
2501d6b92ffaSHans Petter Selasky 				goto ERROR;
2502d6b92ffaSHans Petter Selasky 			if (OSM_LOG_IS_ACTIVE_V2(p_mgr->p_log, OSM_LOG_DEBUG))
2503d6b92ffaSHans Petter Selasky 				print_routes(p_mgr, adj_list, adj_list_size,
2504d6b92ffaSHans Petter Selasky 					     port);
2505d6b92ffaSHans Petter Selasky 
2506d6b92ffaSHans Petter Selasky 			/* make an update for the linear forwarding tables of the switches */
2507d6b92ffaSHans Petter Selasky 			err =
2508d6b92ffaSHans Petter Selasky 			    update_lft(p_mgr, adj_list, adj_list_size, port, lid);
2509d6b92ffaSHans Petter Selasky 			if (err)
2510d6b92ffaSHans Petter Selasky 				goto ERROR;
2511d6b92ffaSHans Petter Selasky 
2512d6b92ffaSHans Petter Selasky 			/* add weights for calculated routes to adjust the weights for the next cycle */
2513d6b92ffaSHans Petter Selasky 			update_weights(p_mgr, adj_list, adj_list_size);
2514d6b92ffaSHans Petter Selasky 
2515d6b92ffaSHans Petter Selasky 			if (OSM_LOG_IS_ACTIVE_V2(p_mgr->p_log, OSM_LOG_DEBUG))
2516d6b92ffaSHans Petter Selasky 				dfsssp_print_graph(p_mgr, adj_list,
2517d6b92ffaSHans Petter Selasky 						   adj_list_size);
2518d6b92ffaSHans Petter Selasky 		}
2519d6b92ffaSHans Petter Selasky 	}
2520d6b92ffaSHans Petter Selasky 
2521d6b92ffaSHans Petter Selasky 	/* try deadlock removal only for the dfsssp routing (not for the sssp case, which is a subset of the dfsssp algorithm) */
2522d6b92ffaSHans Petter Selasky 	if (dfsssp_ctx->routing_type == OSM_ROUTING_ENGINE_TYPE_DFSSSP) {
2523d6b92ffaSHans Petter Selasky 		/* remove potential deadlocks by assigning different virtual lanes to src/dest paths and balance the lanes */
2524d6b92ffaSHans Petter Selasky 		err = dfsssp_remove_deadlocks(dfsssp_ctx);
2525d6b92ffaSHans Petter Selasky 		if (err)
2526d6b92ffaSHans Petter Selasky 			goto ERROR;
2527d6b92ffaSHans Petter Selasky 	} else if (dfsssp_ctx->routing_type == OSM_ROUTING_ENGINE_TYPE_SSSP) {
2528d6b92ffaSHans Petter Selasky 		OSM_LOG(p_mgr->p_log, OSM_LOG_INFO,
2529d6b92ffaSHans Petter Selasky 			"SSSP routing specified -> skipping deadlock removal thru dfsssp_remove_deadlocks(...)\n");
2530d6b92ffaSHans Petter Selasky 	} else {
2531d6b92ffaSHans Petter Selasky 		OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
2532d6b92ffaSHans Petter Selasky 			"ERR AD28: wrong routing engine specified in dfsssp_ctx\n");
2533d6b92ffaSHans Petter Selasky 		goto ERROR;
2534d6b92ffaSHans Petter Selasky 	}
2535d6b92ffaSHans Petter Selasky 
2536d6b92ffaSHans Petter Selasky 	/* list not needed after the dijkstra steps and deadlock removal */
2537d6b92ffaSHans Petter Selasky 	cl_qlist_remove_all(&p_mgr->port_order_list);
2538d6b92ffaSHans Petter Selasky 
2539d6b92ffaSHans Petter Selasky 	/* print the new_lft for each switch after routing is done */
2540d6b92ffaSHans Petter Selasky 	if (OSM_LOG_IS_ACTIVE_V2(p_mgr->p_log, OSM_LOG_DEBUG)) {
2541d6b92ffaSHans Petter Selasky 		for (item = cl_qmap_head(sw_tbl); item != cl_qmap_end(sw_tbl);
2542d6b92ffaSHans Petter Selasky 		     item = cl_qmap_next(item)) {
2543d6b92ffaSHans Petter Selasky 			sw = (osm_switch_t *) item;
2544d6b92ffaSHans Petter Selasky 			OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
2545d6b92ffaSHans Petter Selasky 				"Summary of the (new) LFT for switch 0x%" PRIx64
2546d6b92ffaSHans Petter Selasky 				" (%s):\n",
2547d6b92ffaSHans Petter Selasky 				cl_ntoh64(osm_node_get_node_guid(sw->p_node)),
2548d6b92ffaSHans Petter Selasky 				sw->p_node->print_desc);
2549d6b92ffaSHans Petter Selasky 			for (i = 0; i < sw->max_lid_ho + 1; i++)
2550d6b92ffaSHans Petter Selasky 				if (sw->new_lft[i] != OSM_NO_PATH) {
2551d6b92ffaSHans Petter Selasky 					OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
2552d6b92ffaSHans Petter Selasky 						"   for LID=%" PRIu32
2553d6b92ffaSHans Petter Selasky 						" use port=%" PRIu8 "\n", i,
2554d6b92ffaSHans Petter Selasky 						sw->new_lft[i]);
2555d6b92ffaSHans Petter Selasky 				}
2556d6b92ffaSHans Petter Selasky 		}
2557d6b92ffaSHans Petter Selasky 	}
2558d6b92ffaSHans Petter Selasky 
2559d6b92ffaSHans Petter Selasky 	OSM_LOG_EXIT(p_mgr->p_log);
2560d6b92ffaSHans Petter Selasky 	return 0;
2561d6b92ffaSHans Petter Selasky 
2562d6b92ffaSHans Petter Selasky ERROR:
2563d6b92ffaSHans Petter Selasky 	if (!cl_is_qlist_empty(&p_mgr->port_order_list))
2564d6b92ffaSHans Petter Selasky 		cl_qlist_remove_all(&p_mgr->port_order_list);
2565d6b92ffaSHans Petter Selasky 	if (cn_nodes_provided)
2566d6b92ffaSHans Petter Selasky 		destroy_guid_map(&cn_tbl);
2567d6b92ffaSHans Petter Selasky 	if (io_nodes_provided)
2568d6b92ffaSHans Petter Selasky 		destroy_guid_map(&io_tbl);
2569d6b92ffaSHans Petter Selasky 	if (sw_list)
2570d6b92ffaSHans Petter Selasky 		free(sw_list);
2571d6b92ffaSHans Petter Selasky 	return -1;
2572d6b92ffaSHans Petter Selasky }
2573d6b92ffaSHans Petter Selasky 
2574d6b92ffaSHans Petter Selasky /* meta function which calls subfunctions for finding the optimal switch
2575d6b92ffaSHans Petter Selasky    for the spanning tree, performing a dijkstra step with this sw as root,
2576d6b92ffaSHans Petter Selasky    and calculating the mcast table for MLID
2577d6b92ffaSHans Petter Selasky */
dfsssp_do_mcast_routing(void * context,osm_mgrp_box_t * mbox)2578d6b92ffaSHans Petter Selasky static ib_api_status_t dfsssp_do_mcast_routing(void * context,
2579d6b92ffaSHans Petter Selasky 					       osm_mgrp_box_t * mbox)
2580d6b92ffaSHans Petter Selasky {
2581d6b92ffaSHans Petter Selasky 	dfsssp_context_t *dfsssp_ctx = (dfsssp_context_t *) context;
2582d6b92ffaSHans Petter Selasky 	osm_ucast_mgr_t *p_mgr = (osm_ucast_mgr_t *) dfsssp_ctx->p_mgr;
2583d6b92ffaSHans Petter Selasky 	osm_sm_t *sm = (osm_sm_t *) p_mgr->sm;
2584d6b92ffaSHans Petter Selasky 	vertex_t *adj_list = (vertex_t *) dfsssp_ctx->adj_list;
2585d6b92ffaSHans Petter Selasky 	uint32_t adj_list_size = dfsssp_ctx->adj_list_size;
2586d6b92ffaSHans Petter Selasky 	cl_qlist_t mcastgrp_port_list;
2587d6b92ffaSHans Petter Selasky 	cl_qmap_t mcastgrp_port_map;
2588d6b92ffaSHans Petter Selasky 	osm_switch_t *root_sw = NULL, *p_sw = NULL;
2589d6b92ffaSHans Petter Selasky 	osm_port_t *port = NULL;
2590d6b92ffaSHans Petter Selasky 	ib_net16_t lid = 0;
2591d6b92ffaSHans Petter Selasky 	uint32_t err = 0, num_ports = 0, i = 0;
2592d6b92ffaSHans Petter Selasky 	ib_net64_t guid = 0;
2593d6b92ffaSHans Petter Selasky 	ib_api_status_t status = IB_SUCCESS;
2594d6b92ffaSHans Petter Selasky 
2595d6b92ffaSHans Petter Selasky 	OSM_LOG_ENTER(sm->p_log);
2596d6b92ffaSHans Petter Selasky 
2597d6b92ffaSHans Petter Selasky 	/* using the ucast cache feature with dfsssp might mean that a leaf sw
2598d6b92ffaSHans Petter Selasky 	   got removed (and got back) without calling dfsssp_build_graph
2599d6b92ffaSHans Petter Selasky 	   and therefore the adj_list (and pointers to osm's internal switches)
2600d6b92ffaSHans Petter Selasky 	   could be outdated (here we have no knowledge if it has happened, so
2601d6b92ffaSHans Petter Selasky 	   unfortunately a check is necessary... still better than rebuilding
2602d6b92ffaSHans Petter Selasky 	   adj_list every time we arrive here)
2603d6b92ffaSHans Petter Selasky 	 */
2604d6b92ffaSHans Petter Selasky 	if (p_mgr->p_subn->opt.use_ucast_cache && p_mgr->cache_valid) {
2605d6b92ffaSHans Petter Selasky 		for (i = 1; i < adj_list_size; i++) {
2606d6b92ffaSHans Petter Selasky 			guid = cl_hton64(adj_list[i].guid);
2607d6b92ffaSHans Petter Selasky 			p_sw = osm_get_switch_by_guid(p_mgr->p_subn, guid);
2608d6b92ffaSHans Petter Selasky 			if (p_sw) {
2609d6b92ffaSHans Petter Selasky 				/* check if switch came back from the dead */
2610d6b92ffaSHans Petter Selasky 				if (adj_list[i].dropped)
2611d6b92ffaSHans Petter Selasky 					adj_list[i].dropped = FALSE;
2612d6b92ffaSHans Petter Selasky 
2613d6b92ffaSHans Petter Selasky 				/* verify that sw object has not been moved
2614d6b92ffaSHans Petter Selasky 				   (this can happen for a leaf switch, if it
2615d6b92ffaSHans Petter Selasky 				   was dropped and came back later without a
2616d6b92ffaSHans Petter Selasky 				   rerouting), otherwise we have to update
2617d6b92ffaSHans Petter Selasky 				   dfsssp's internal switch list with the new
2618d6b92ffaSHans Petter Selasky 				   sw pointer
2619d6b92ffaSHans Petter Selasky 				 */
2620d6b92ffaSHans Petter Selasky 				if (p_sw == adj_list[i].sw)
2621d6b92ffaSHans Petter Selasky 					continue;
2622d6b92ffaSHans Petter Selasky 				else
2623d6b92ffaSHans Petter Selasky 					adj_list[i].sw = p_sw;
2624d6b92ffaSHans Petter Selasky 			} else {
2625d6b92ffaSHans Petter Selasky 				/* if a switch from adj_list is not in the
2626d6b92ffaSHans Petter Selasky 				   sw_guid_tbl anymore, then the only reason is
2627d6b92ffaSHans Petter Selasky 				   that it was a leaf switch and opensm dropped
2628d6b92ffaSHans Petter Selasky 				   it without calling a rerouting
2629d6b92ffaSHans Petter Selasky 				   -> calling dijkstra is no problem, since it
2630d6b92ffaSHans Petter Selasky 				      is a leaf and different from root_sw
2631d6b92ffaSHans Petter Selasky 				   -> only update_mcft and reset_mgrp_membership
2632d6b92ffaSHans Petter Selasky 				      need to be aware of these dropped switches
2633d6b92ffaSHans Petter Selasky 				 */
2634d6b92ffaSHans Petter Selasky 				if (!adj_list[i].dropped)
2635d6b92ffaSHans Petter Selasky 					adj_list[i].dropped = TRUE;
2636d6b92ffaSHans Petter Selasky 			}
2637d6b92ffaSHans Petter Selasky 		}
2638d6b92ffaSHans Petter Selasky 	}
2639d6b92ffaSHans Petter Selasky 
2640d6b92ffaSHans Petter Selasky 	/* create a map and a list of all ports which are member in the mcast
2641d6b92ffaSHans Petter Selasky 	   group; map for searching elements and list for iteration
2642d6b92ffaSHans Petter Selasky 	 */
2643d6b92ffaSHans Petter Selasky 	if (osm_mcast_make_port_list_and_map(&mcastgrp_port_list,
2644d6b92ffaSHans Petter Selasky 					     &mcastgrp_port_map, mbox)) {
2645d6b92ffaSHans Petter Selasky 		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR AD50: "
2646d6b92ffaSHans Petter Selasky 			"Insufficient memory to make port list\n");
2647d6b92ffaSHans Petter Selasky 		status = IB_ERROR;
2648d6b92ffaSHans Petter Selasky 		goto Exit;
2649d6b92ffaSHans Petter Selasky 	}
2650d6b92ffaSHans Petter Selasky 
2651d6b92ffaSHans Petter Selasky 	num_ports = cl_qlist_count(&mcastgrp_port_list);
2652d6b92ffaSHans Petter Selasky 	if (num_ports < 2) {
2653d6b92ffaSHans Petter Selasky 		OSM_LOG(sm->p_log, OSM_LOG_VERBOSE,
2654d6b92ffaSHans Petter Selasky 			"MLID 0x%X has %u members - nothing to do\n",
2655d6b92ffaSHans Petter Selasky 			mbox->mlid, num_ports);
2656d6b92ffaSHans Petter Selasky 		goto Exit;
2657d6b92ffaSHans Petter Selasky 	}
2658d6b92ffaSHans Petter Selasky 
2659d6b92ffaSHans Petter Selasky 	/* find the root switch for the spanning tree, which has the smallest
2660d6b92ffaSHans Petter Selasky 	   hops count to all LIDs in the mcast group
2661d6b92ffaSHans Petter Selasky 	 */
2662d6b92ffaSHans Petter Selasky 	root_sw = osm_mcast_mgr_find_root_switch(sm, &mcastgrp_port_list);
2663d6b92ffaSHans Petter Selasky 	if (!root_sw) {
2664d6b92ffaSHans Petter Selasky 		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR AD51: "
2665d6b92ffaSHans Petter Selasky 			"Unable to locate a suitable switch for group 0x%X\n",
2666d6b92ffaSHans Petter Selasky 			mbox->mlid);
2667d6b92ffaSHans Petter Selasky 		status = IB_ERROR;
2668d6b92ffaSHans Petter Selasky 		goto Exit;
2669d6b92ffaSHans Petter Selasky 	}
2670d6b92ffaSHans Petter Selasky 
2671d6b92ffaSHans Petter Selasky 	/* a) start one dijkstra step from the root switch to generate a
2672d6b92ffaSHans Petter Selasky 	   spanning tree
2673d6b92ffaSHans Petter Selasky 	   b) this might be a bit of an overkill to span the whole
2674d6b92ffaSHans Petter Selasky 	   network, if there are only a few ports in the mcast group, but
2675d6b92ffaSHans Petter Selasky 	   its only one dijkstra step for each mcast group and we did many
2676d6b92ffaSHans Petter Selasky 	   steps before in the ucast routing for each LID in the subnet;
2677d6b92ffaSHans Petter Selasky 	   c) we can use the subnet structure from the ucast routing, and
2678d6b92ffaSHans Petter Selasky 	   don't even have to reset the link weights (=> therefore the mcast
2679d6b92ffaSHans Petter Selasky 	   spanning tree will use less 'growded' links in the network)
2680d6b92ffaSHans Petter Selasky 	   d) the mcast dfsssp algorithm will not change the link weights
2681d6b92ffaSHans Petter Selasky 	 */
2682d6b92ffaSHans Petter Selasky 	lid = osm_node_get_base_lid(root_sw->p_node, 0);
2683d6b92ffaSHans Petter Selasky 	port = osm_get_port_by_lid(sm->p_subn, lid);
2684d6b92ffaSHans Petter Selasky 	err = dijkstra(p_mgr, adj_list, adj_list_size, port, lid);
2685d6b92ffaSHans Petter Selasky 	if (err) {
2686d6b92ffaSHans Petter Selasky 		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR AD52: "
2687d6b92ffaSHans Petter Selasky 			"Dijkstra step for mcast failed for group 0x%X\n",
2688d6b92ffaSHans Petter Selasky 			mbox->mlid);
2689d6b92ffaSHans Petter Selasky 		status = IB_ERROR;
2690d6b92ffaSHans Petter Selasky 		goto Exit;
2691d6b92ffaSHans Petter Selasky 	}
2692d6b92ffaSHans Petter Selasky 
2693d6b92ffaSHans Petter Selasky 	/* set mcast group membership again for update_mcft
2694d6b92ffaSHans Petter Selasky 	   (unfortunately: osm_mcast_mgr_find_root_switch resets it)
2695d6b92ffaSHans Petter Selasky 	 */
2696d6b92ffaSHans Petter Selasky 	update_mgrp_membership(&mcastgrp_port_list);
2697d6b92ffaSHans Petter Selasky 
2698d6b92ffaSHans Petter Selasky 	/* update the mcast forwarding tables of the switches */
2699d6b92ffaSHans Petter Selasky 	err = update_mcft(sm, adj_list, adj_list_size, mbox->mlid,
2700d6b92ffaSHans Petter Selasky 			  &mcastgrp_port_map, root_sw);
2701d6b92ffaSHans Petter Selasky 	if (err) {
2702d6b92ffaSHans Petter Selasky 		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR AD53: "
2703d6b92ffaSHans Petter Selasky 			"Update of mcast forwarding tables failed for group 0x%X\n",
2704d6b92ffaSHans Petter Selasky 			mbox->mlid);
2705d6b92ffaSHans Petter Selasky 		status = IB_ERROR;
2706d6b92ffaSHans Petter Selasky 		goto Exit;
2707d6b92ffaSHans Petter Selasky 	}
2708d6b92ffaSHans Petter Selasky 
2709d6b92ffaSHans Petter Selasky Exit:
2710d6b92ffaSHans Petter Selasky 	reset_mgrp_membership(adj_list, adj_list_size);
2711d6b92ffaSHans Petter Selasky 	osm_mcast_drop_port_list(&mcastgrp_port_list);
2712d6b92ffaSHans Petter Selasky 	OSM_LOG_EXIT(sm->p_log);
2713d6b92ffaSHans Petter Selasky 	return status;
2714d6b92ffaSHans Petter Selasky }
2715d6b92ffaSHans Petter Selasky 
2716d6b92ffaSHans Petter Selasky /* called from extern in QP creation process to gain the the service level and
2717d6b92ffaSHans Petter Selasky    the virtual lane respectively for a <s,d> pair
2718d6b92ffaSHans Petter Selasky */
get_dfsssp_sl(void * context,uint8_t hint_for_default_sl,const ib_net16_t slid,const ib_net16_t dlid)2719d6b92ffaSHans Petter Selasky static uint8_t get_dfsssp_sl(void *context, uint8_t hint_for_default_sl,
2720d6b92ffaSHans Petter Selasky 			     const ib_net16_t slid, const ib_net16_t dlid)
2721d6b92ffaSHans Petter Selasky {
2722d6b92ffaSHans Petter Selasky 	dfsssp_context_t *dfsssp_ctx = (dfsssp_context_t *) context;
2723d6b92ffaSHans Petter Selasky 	osm_port_t *src_port, *dest_port;
2724d6b92ffaSHans Petter Selasky 	vltable_t *srcdest2vl_table = NULL;
2725d6b92ffaSHans Petter Selasky 	uint8_t *vl_split_count = NULL;
2726d6b92ffaSHans Petter Selasky 	osm_ucast_mgr_t *p_mgr = NULL;
2727d6b92ffaSHans Petter Selasky 	int32_t res = 0;
2728d6b92ffaSHans Petter Selasky 
2729d6b92ffaSHans Petter Selasky 	if (dfsssp_ctx
2730d6b92ffaSHans Petter Selasky 	    && dfsssp_ctx->routing_type == OSM_ROUTING_ENGINE_TYPE_DFSSSP) {
2731d6b92ffaSHans Petter Selasky 		p_mgr = (osm_ucast_mgr_t *) dfsssp_ctx->p_mgr;
2732d6b92ffaSHans Petter Selasky 		srcdest2vl_table = (vltable_t *) (dfsssp_ctx->srcdest2vl_table);
2733d6b92ffaSHans Petter Selasky 		vl_split_count = (uint8_t *) (dfsssp_ctx->vl_split_count);
2734d6b92ffaSHans Petter Selasky 	}
2735d6b92ffaSHans Petter Selasky 	else
2736d6b92ffaSHans Petter Selasky 		return hint_for_default_sl;
2737d6b92ffaSHans Petter Selasky 
2738d6b92ffaSHans Petter Selasky 	src_port = osm_get_port_by_lid(p_mgr->p_subn, slid);
2739d6b92ffaSHans Petter Selasky 	if (!src_port)
2740d6b92ffaSHans Petter Selasky 		return hint_for_default_sl;
2741d6b92ffaSHans Petter Selasky 
2742d6b92ffaSHans Petter Selasky 	dest_port = osm_get_port_by_lid(p_mgr->p_subn, dlid);
2743d6b92ffaSHans Petter Selasky 	if (!dest_port)
2744d6b92ffaSHans Petter Selasky 		return hint_for_default_sl;
2745d6b92ffaSHans Petter Selasky 
2746d6b92ffaSHans Petter Selasky 	if (!srcdest2vl_table)
2747d6b92ffaSHans Petter Selasky 		return hint_for_default_sl;
2748d6b92ffaSHans Petter Selasky 
2749d6b92ffaSHans Petter Selasky 	res = vltable_get_vl(srcdest2vl_table, slid, dlid);
2750d6b92ffaSHans Petter Selasky 
2751d6b92ffaSHans Petter Selasky 	/* we will randomly distribute the traffic over multiple VLs if
2752d6b92ffaSHans Petter Selasky 	   necessary for good balancing; therefore vl_split_count provides
2753d6b92ffaSHans Petter Selasky 	   the number of VLs to use for certain traffic
2754d6b92ffaSHans Petter Selasky 	 */
2755d6b92ffaSHans Petter Selasky 	if (res > -1) {
2756d6b92ffaSHans Petter Selasky 		if (vl_split_count[res] > 1)
2757d6b92ffaSHans Petter Selasky 			return (uint8_t) (res + rand()%(vl_split_count[res]));
2758d6b92ffaSHans Petter Selasky 		else
2759d6b92ffaSHans Petter Selasky 			return (uint8_t) res;
2760d6b92ffaSHans Petter Selasky 	} else
2761d6b92ffaSHans Petter Selasky 		return hint_for_default_sl;
2762d6b92ffaSHans Petter Selasky }
2763d6b92ffaSHans Petter Selasky 
dfsssp_context_create(osm_opensm_t * p_osm,osm_routing_engine_type_t routing_type)2764d6b92ffaSHans Petter Selasky static dfsssp_context_t *dfsssp_context_create(osm_opensm_t * p_osm,
2765d6b92ffaSHans Petter Selasky 					       osm_routing_engine_type_t
2766d6b92ffaSHans Petter Selasky 					       routing_type)
2767d6b92ffaSHans Petter Selasky {
2768d6b92ffaSHans Petter Selasky 	dfsssp_context_t *dfsssp_ctx = NULL;
2769d6b92ffaSHans Petter Selasky 
2770d6b92ffaSHans Petter Selasky 	/* allocate memory */
2771d6b92ffaSHans Petter Selasky 	dfsssp_ctx = (dfsssp_context_t *) malloc(sizeof(dfsssp_context_t));
2772d6b92ffaSHans Petter Selasky 	if (dfsssp_ctx) {
2773d6b92ffaSHans Petter Selasky 		/* set initial values */
2774d6b92ffaSHans Petter Selasky 		dfsssp_ctx->routing_type = routing_type;
2775d6b92ffaSHans Petter Selasky 		dfsssp_ctx->p_mgr = (osm_ucast_mgr_t *) & (p_osm->sm.ucast_mgr);
2776d6b92ffaSHans Petter Selasky 		dfsssp_ctx->adj_list = NULL;
2777d6b92ffaSHans Petter Selasky 		dfsssp_ctx->adj_list_size = 0;
2778d6b92ffaSHans Petter Selasky 		dfsssp_ctx->srcdest2vl_table = NULL;
2779d6b92ffaSHans Petter Selasky 		dfsssp_ctx->vl_split_count = NULL;
2780d6b92ffaSHans Petter Selasky 	} else {
2781d6b92ffaSHans Petter Selasky 		OSM_LOG(p_osm->sm.ucast_mgr.p_log, OSM_LOG_ERROR,
2782d6b92ffaSHans Petter Selasky 			"ERR AD04: cannot allocate memory for dfsssp_ctx in dfsssp_context_create\n");
2783d6b92ffaSHans Petter Selasky 		return NULL;
2784d6b92ffaSHans Petter Selasky 	}
2785d6b92ffaSHans Petter Selasky 
2786d6b92ffaSHans Petter Selasky 	return dfsssp_ctx;
2787d6b92ffaSHans Petter Selasky }
2788d6b92ffaSHans Petter Selasky 
dfsssp_context_destroy(void * context)2789d6b92ffaSHans Petter Selasky static void dfsssp_context_destroy(void *context)
2790d6b92ffaSHans Petter Selasky {
2791d6b92ffaSHans Petter Selasky 	dfsssp_context_t *dfsssp_ctx = (dfsssp_context_t *) context;
2792d6b92ffaSHans Petter Selasky 	vertex_t *adj_list = (vertex_t *) (dfsssp_ctx->adj_list);
2793d6b92ffaSHans Petter Selasky 	uint32_t i = 0;
2794d6b92ffaSHans Petter Selasky 	link_t *link = NULL, *tmp = NULL;
2795d6b92ffaSHans Petter Selasky 
2796d6b92ffaSHans Petter Selasky 	/* free adj_list */
2797d6b92ffaSHans Petter Selasky 	for (i = 0; i < dfsssp_ctx->adj_list_size; i++) {
2798d6b92ffaSHans Petter Selasky 		link = adj_list[i].links;
2799d6b92ffaSHans Petter Selasky 		while (link) {
2800d6b92ffaSHans Petter Selasky 			tmp = link;
2801d6b92ffaSHans Petter Selasky 			link = link->next;
2802d6b92ffaSHans Petter Selasky 			free(tmp);
2803d6b92ffaSHans Petter Selasky 		}
2804d6b92ffaSHans Petter Selasky 	}
2805d6b92ffaSHans Petter Selasky 	free(adj_list);
2806d6b92ffaSHans Petter Selasky 	dfsssp_ctx->adj_list = NULL;
2807d6b92ffaSHans Petter Selasky 	dfsssp_ctx->adj_list_size = 0;
2808d6b92ffaSHans Petter Selasky 
2809d6b92ffaSHans Petter Selasky 	/* free srcdest2vl table and the split count information table
2810d6b92ffaSHans Petter Selasky 	   (can be done, because dfsssp_context_destroy is called after
2811d6b92ffaSHans Petter Selasky 	    osm_get_dfsssp_sl)
2812d6b92ffaSHans Petter Selasky 	 */
2813d6b92ffaSHans Petter Selasky 	vltable_dealloc(&(dfsssp_ctx->srcdest2vl_table));
2814d6b92ffaSHans Petter Selasky 	dfsssp_ctx->srcdest2vl_table = NULL;
2815d6b92ffaSHans Petter Selasky 
2816d6b92ffaSHans Petter Selasky 	if (dfsssp_ctx->vl_split_count) {
2817d6b92ffaSHans Petter Selasky 		free(dfsssp_ctx->vl_split_count);
2818d6b92ffaSHans Petter Selasky 		dfsssp_ctx->vl_split_count = NULL;
2819d6b92ffaSHans Petter Selasky 	}
2820d6b92ffaSHans Petter Selasky }
2821d6b92ffaSHans Petter Selasky 
delete(void * context)2822d6b92ffaSHans Petter Selasky static void delete(void *context)
2823d6b92ffaSHans Petter Selasky {
2824d6b92ffaSHans Petter Selasky 	if (!context)
2825d6b92ffaSHans Petter Selasky 		return;
2826d6b92ffaSHans Petter Selasky 	dfsssp_context_destroy(context);
2827d6b92ffaSHans Petter Selasky 
2828d6b92ffaSHans Petter Selasky 	free(context);
2829d6b92ffaSHans Petter Selasky }
2830d6b92ffaSHans Petter Selasky 
osm_ucast_dfsssp_setup(struct osm_routing_engine * r,osm_opensm_t * p_osm)2831d6b92ffaSHans Petter Selasky int osm_ucast_dfsssp_setup(struct osm_routing_engine *r, osm_opensm_t * p_osm)
2832d6b92ffaSHans Petter Selasky {
2833d6b92ffaSHans Petter Selasky 	/* create context container and add ucast management object */
2834d6b92ffaSHans Petter Selasky 	dfsssp_context_t *dfsssp_context =
2835d6b92ffaSHans Petter Selasky 	    dfsssp_context_create(p_osm, OSM_ROUTING_ENGINE_TYPE_DFSSSP);
2836d6b92ffaSHans Petter Selasky 	if (!dfsssp_context) {
2837d6b92ffaSHans Petter Selasky 		return 1;	/* alloc failed -> skip this routing */
2838d6b92ffaSHans Petter Selasky 	}
2839d6b92ffaSHans Petter Selasky 
2840d6b92ffaSHans Petter Selasky 	/* reset function pointers to dfsssp routines */
2841d6b92ffaSHans Petter Selasky 	r->context = (void *)dfsssp_context;
2842d6b92ffaSHans Petter Selasky 	r->build_lid_matrices = dfsssp_build_graph;
2843d6b92ffaSHans Petter Selasky 	r->ucast_build_fwd_tables = dfsssp_do_dijkstra_routing;
2844d6b92ffaSHans Petter Selasky 	r->mcast_build_stree = dfsssp_do_mcast_routing;
2845d6b92ffaSHans Petter Selasky 	r->path_sl = get_dfsssp_sl;
2846d6b92ffaSHans Petter Selasky 	r->destroy = delete;
2847d6b92ffaSHans Petter Selasky 
2848d6b92ffaSHans Petter Selasky 	/* we initialize with the current time to achieve a 'good' randomized
2849d6b92ffaSHans Petter Selasky 	   assignment in get_dfsssp_sl(...)
2850d6b92ffaSHans Petter Selasky 	 */
2851d6b92ffaSHans Petter Selasky 	srand(time(NULL));
2852d6b92ffaSHans Petter Selasky 
2853d6b92ffaSHans Petter Selasky 	return 0;
2854d6b92ffaSHans Petter Selasky }
2855d6b92ffaSHans Petter Selasky 
osm_ucast_sssp_setup(struct osm_routing_engine * r,osm_opensm_t * p_osm)2856d6b92ffaSHans Petter Selasky int osm_ucast_sssp_setup(struct osm_routing_engine *r, osm_opensm_t * p_osm)
2857d6b92ffaSHans Petter Selasky {
2858d6b92ffaSHans Petter Selasky 	/* create context container and add ucast management object */
2859d6b92ffaSHans Petter Selasky 	dfsssp_context_t *dfsssp_context =
2860d6b92ffaSHans Petter Selasky 	    dfsssp_context_create(p_osm, OSM_ROUTING_ENGINE_TYPE_SSSP);
2861d6b92ffaSHans Petter Selasky 	if (!dfsssp_context) {
2862d6b92ffaSHans Petter Selasky 		return 1;	/* alloc failed -> skip this routing */
2863d6b92ffaSHans Petter Selasky 	}
2864d6b92ffaSHans Petter Selasky 
2865d6b92ffaSHans Petter Selasky 	/* reset function pointers to sssp routines */
2866d6b92ffaSHans Petter Selasky 	r->context = (void *)dfsssp_context;
2867d6b92ffaSHans Petter Selasky 	r->build_lid_matrices = dfsssp_build_graph;
2868d6b92ffaSHans Petter Selasky 	r->ucast_build_fwd_tables = dfsssp_do_dijkstra_routing;
2869d6b92ffaSHans Petter Selasky 	r->mcast_build_stree = dfsssp_do_mcast_routing;
2870d6b92ffaSHans Petter Selasky 	r->destroy = delete;
2871d6b92ffaSHans Petter Selasky 
2872d6b92ffaSHans Petter Selasky 	return 0;
2873d6b92ffaSHans Petter Selasky }
2874