xref: /freebsd/contrib/ofed/opensm/opensm/osm_ucast_updn.c (revision 87181516ef48be852d5e5fee53c6e0dbfc62f21e)
1*d6b92ffaSHans Petter Selasky /*
2*d6b92ffaSHans Petter Selasky  * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved.
3*d6b92ffaSHans Petter Selasky  * Copyright (c) 2002-2007,2009 Mellanox Technologies LTD. All rights reserved.
4*d6b92ffaSHans Petter Selasky  * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
5*d6b92ffaSHans Petter Selasky  * Copyright (c) 2009 HNR Consulting. All rights reserved.
6*d6b92ffaSHans Petter Selasky  *
7*d6b92ffaSHans Petter Selasky  * This software is available to you under a choice of one of two
8*d6b92ffaSHans Petter Selasky  * licenses.  You may choose to be licensed under the terms of the GNU
9*d6b92ffaSHans Petter Selasky  * General Public License (GPL) Version 2, available from the file
10*d6b92ffaSHans Petter Selasky  * COPYING in the main directory of this source tree, or the
11*d6b92ffaSHans Petter Selasky  * OpenIB.org BSD license below:
12*d6b92ffaSHans Petter Selasky  *
13*d6b92ffaSHans Petter Selasky  *     Redistribution and use in source and binary forms, with or
14*d6b92ffaSHans Petter Selasky  *     without modification, are permitted provided that the following
15*d6b92ffaSHans Petter Selasky  *     conditions are met:
16*d6b92ffaSHans Petter Selasky  *
17*d6b92ffaSHans Petter Selasky  *      - Redistributions of source code must retain the above
18*d6b92ffaSHans Petter Selasky  *        copyright notice, this list of conditions and the following
19*d6b92ffaSHans Petter Selasky  *        disclaimer.
20*d6b92ffaSHans Petter Selasky  *
21*d6b92ffaSHans Petter Selasky  *      - Redistributions in binary form must reproduce the above
22*d6b92ffaSHans Petter Selasky  *        copyright notice, this list of conditions and the following
23*d6b92ffaSHans Petter Selasky  *        disclaimer in the documentation and/or other materials
24*d6b92ffaSHans Petter Selasky  *        provided with the distribution.
25*d6b92ffaSHans Petter Selasky  *
26*d6b92ffaSHans Petter Selasky  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27*d6b92ffaSHans Petter Selasky  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28*d6b92ffaSHans Petter Selasky  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29*d6b92ffaSHans Petter Selasky  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
30*d6b92ffaSHans Petter Selasky  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
31*d6b92ffaSHans Petter Selasky  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
32*d6b92ffaSHans Petter Selasky  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
33*d6b92ffaSHans Petter Selasky  * SOFTWARE.
34*d6b92ffaSHans Petter Selasky  *
35*d6b92ffaSHans Petter Selasky  */
36*d6b92ffaSHans Petter Selasky 
37*d6b92ffaSHans Petter Selasky /*
38*d6b92ffaSHans Petter Selasky  * Abstract:
39*d6b92ffaSHans Petter Selasky  *      Implementation of Up Down Algorithm using ranking & Min Hop
40*d6b92ffaSHans Petter Selasky  *      Calculation functions
41*d6b92ffaSHans Petter Selasky  */
42*d6b92ffaSHans Petter Selasky 
43*d6b92ffaSHans Petter Selasky #if HAVE_CONFIG_H
44*d6b92ffaSHans Petter Selasky #  include <config.h>
45*d6b92ffaSHans Petter Selasky #endif				/* HAVE_CONFIG_H */
46*d6b92ffaSHans Petter Selasky 
47*d6b92ffaSHans Petter Selasky #include <stdlib.h>
48*d6b92ffaSHans Petter Selasky #include <ctype.h>
49*d6b92ffaSHans Petter Selasky #include <complib/cl_debug.h>
50*d6b92ffaSHans Petter Selasky #include <complib/cl_qmap.h>
51*d6b92ffaSHans Petter Selasky #include <opensm/osm_file_ids.h>
52*d6b92ffaSHans Petter Selasky #define FILE_ID OSM_FILE_UCAST_UPDN_C
53*d6b92ffaSHans Petter Selasky #include <opensm/osm_switch.h>
54*d6b92ffaSHans Petter Selasky #include <opensm/osm_opensm.h>
55*d6b92ffaSHans Petter Selasky #include <opensm/osm_ucast_mgr.h>
56*d6b92ffaSHans Petter Selasky 
57*d6b92ffaSHans Petter Selasky /* //////////////////////////// */
58*d6b92ffaSHans Petter Selasky /*  Local types                 */
59*d6b92ffaSHans Petter Selasky /* //////////////////////////// */
60*d6b92ffaSHans Petter Selasky 
61*d6b92ffaSHans Petter Selasky /* direction */
62*d6b92ffaSHans Petter Selasky typedef enum updn_switch_dir {
63*d6b92ffaSHans Petter Selasky 	UP = 0,
64*d6b92ffaSHans Petter Selasky 	DOWN
65*d6b92ffaSHans Petter Selasky } updn_switch_dir_t;
66*d6b92ffaSHans Petter Selasky 
67*d6b92ffaSHans Petter Selasky /* updn structure */
68*d6b92ffaSHans Petter Selasky typedef struct updn {
69*d6b92ffaSHans Petter Selasky 	unsigned num_roots;
70*d6b92ffaSHans Petter Selasky 	osm_opensm_t *p_osm;
71*d6b92ffaSHans Petter Selasky } updn_t;
72*d6b92ffaSHans Petter Selasky 
73*d6b92ffaSHans Petter Selasky struct updn_node {
74*d6b92ffaSHans Petter Selasky 	cl_list_item_t list;
75*d6b92ffaSHans Petter Selasky 	osm_switch_t *sw;
76*d6b92ffaSHans Petter Selasky 	uint64_t id;
77*d6b92ffaSHans Petter Selasky 	updn_switch_dir_t dir;
78*d6b92ffaSHans Petter Selasky 	unsigned rank;
79*d6b92ffaSHans Petter Selasky 	unsigned visited;
80*d6b92ffaSHans Petter Selasky };
81*d6b92ffaSHans Petter Selasky 
82*d6b92ffaSHans Petter Selasky /* This function returns direction based on rank and guid info of current &
83*d6b92ffaSHans Petter Selasky    remote ports */
updn_get_dir(unsigned cur_rank,unsigned rem_rank,uint64_t cur_id,uint64_t rem_id)84*d6b92ffaSHans Petter Selasky static updn_switch_dir_t updn_get_dir(unsigned cur_rank, unsigned rem_rank,
85*d6b92ffaSHans Petter Selasky 				      uint64_t cur_id, uint64_t rem_id)
86*d6b92ffaSHans Petter Selasky {
87*d6b92ffaSHans Petter Selasky 	/* HACK: comes to solve root nodes connection, in a classic subnet root nodes do not connect
88*d6b92ffaSHans Petter Selasky 	   directly, but in case they are we assign to root node an UP direction to allow UPDN to discover
89*d6b92ffaSHans Petter Selasky 	   the subnet correctly (and not from the point of view of the last root node).
90*d6b92ffaSHans Petter Selasky 	 */
91*d6b92ffaSHans Petter Selasky 	if (!cur_rank && !rem_rank)
92*d6b92ffaSHans Petter Selasky 		return UP;
93*d6b92ffaSHans Petter Selasky 
94*d6b92ffaSHans Petter Selasky 	if (cur_rank < rem_rank)
95*d6b92ffaSHans Petter Selasky 		return DOWN;
96*d6b92ffaSHans Petter Selasky 	else if (cur_rank > rem_rank)
97*d6b92ffaSHans Petter Selasky 		return UP;
98*d6b92ffaSHans Petter Selasky 	else {
99*d6b92ffaSHans Petter Selasky 		/* Equal rank, decide by id number, bigger == UP direction */
100*d6b92ffaSHans Petter Selasky 		if (cur_id > rem_id)
101*d6b92ffaSHans Petter Selasky 			return UP;
102*d6b92ffaSHans Petter Selasky 		else
103*d6b92ffaSHans Petter Selasky 			return DOWN;
104*d6b92ffaSHans Petter Selasky 	}
105*d6b92ffaSHans Petter Selasky }
106*d6b92ffaSHans Petter Selasky 
107*d6b92ffaSHans Petter Selasky /**********************************************************************
108*d6b92ffaSHans Petter Selasky  * This function does the bfs of min hop table calculation by guid index
109*d6b92ffaSHans Petter Selasky  * as a starting point.
110*d6b92ffaSHans Petter Selasky  **********************************************************************/
updn_bfs_by_node(IN osm_log_t * p_log,IN osm_subn_t * p_subn,IN osm_switch_t * p_sw)111*d6b92ffaSHans Petter Selasky static int updn_bfs_by_node(IN osm_log_t * p_log, IN osm_subn_t * p_subn,
112*d6b92ffaSHans Petter Selasky 			    IN osm_switch_t * p_sw)
113*d6b92ffaSHans Petter Selasky {
114*d6b92ffaSHans Petter Selasky 	uint8_t pn, pn_rem;
115*d6b92ffaSHans Petter Selasky 	cl_qlist_t list;
116*d6b92ffaSHans Petter Selasky 	uint16_t lid;
117*d6b92ffaSHans Petter Selasky 	struct updn_node *u;
118*d6b92ffaSHans Petter Selasky 	updn_switch_dir_t next_dir, current_dir;
119*d6b92ffaSHans Petter Selasky 
120*d6b92ffaSHans Petter Selasky 	OSM_LOG_ENTER(p_log);
121*d6b92ffaSHans Petter Selasky 
122*d6b92ffaSHans Petter Selasky 	lid = osm_node_get_base_lid(p_sw->p_node, 0);
123*d6b92ffaSHans Petter Selasky 	lid = cl_ntoh16(lid);
124*d6b92ffaSHans Petter Selasky 	osm_switch_set_hops(p_sw, lid, 0, 0);
125*d6b92ffaSHans Petter Selasky 
126*d6b92ffaSHans Petter Selasky 	OSM_LOG(p_log, OSM_LOG_DEBUG,
127*d6b92ffaSHans Petter Selasky 		"Starting from switch - port GUID 0x%" PRIx64 " lid %u\n",
128*d6b92ffaSHans Petter Selasky 		cl_ntoh64(p_sw->p_node->node_info.port_guid), lid);
129*d6b92ffaSHans Petter Selasky 
130*d6b92ffaSHans Petter Selasky 	u = p_sw->priv;
131*d6b92ffaSHans Petter Selasky 	u->dir = UP;
132*d6b92ffaSHans Petter Selasky 
133*d6b92ffaSHans Petter Selasky 	/* Update list with the new element */
134*d6b92ffaSHans Petter Selasky 	cl_qlist_init(&list);
135*d6b92ffaSHans Petter Selasky 	cl_qlist_insert_tail(&list, &u->list);
136*d6b92ffaSHans Petter Selasky 
137*d6b92ffaSHans Petter Selasky 	/* BFS the list till no next element */
138*d6b92ffaSHans Petter Selasky 	while (!cl_is_qlist_empty(&list)) {
139*d6b92ffaSHans Petter Selasky 		u = (struct updn_node *)cl_qlist_remove_head(&list);
140*d6b92ffaSHans Petter Selasky 		u->visited = 0;	/* cleanup */
141*d6b92ffaSHans Petter Selasky 		current_dir = u->dir;
142*d6b92ffaSHans Petter Selasky 		/* Go over all ports of the switch and find unvisited remote nodes */
143*d6b92ffaSHans Petter Selasky 		for (pn = 1; pn < u->sw->num_ports; pn++) {
144*d6b92ffaSHans Petter Selasky 			osm_node_t *p_remote_node;
145*d6b92ffaSHans Petter Selasky 			struct updn_node *rem_u;
146*d6b92ffaSHans Petter Selasky 			uint8_t current_min_hop, remote_min_hop,
147*d6b92ffaSHans Petter Selasky 			    set_hop_return_value;
148*d6b92ffaSHans Petter Selasky 			osm_switch_t *p_remote_sw;
149*d6b92ffaSHans Petter Selasky 
150*d6b92ffaSHans Petter Selasky 			p_remote_node =
151*d6b92ffaSHans Petter Selasky 			    osm_node_get_remote_node(u->sw->p_node, pn,
152*d6b92ffaSHans Petter Selasky 						     &pn_rem);
153*d6b92ffaSHans Petter Selasky 			/* If no remote node OR remote node is not a SWITCH
154*d6b92ffaSHans Petter Selasky 			   continue to next pn */
155*d6b92ffaSHans Petter Selasky 			if (!p_remote_node || !p_remote_node->sw)
156*d6b92ffaSHans Petter Selasky 				continue;
157*d6b92ffaSHans Petter Selasky 			/* Fetch remote guid only after validation of remote node */
158*d6b92ffaSHans Petter Selasky 			p_remote_sw = p_remote_node->sw;
159*d6b92ffaSHans Petter Selasky 			rem_u = p_remote_sw->priv;
160*d6b92ffaSHans Petter Selasky 			/* Decide which direction to mark it (UP/DOWN) */
161*d6b92ffaSHans Petter Selasky 			next_dir = updn_get_dir(u->rank, rem_u->rank,
162*d6b92ffaSHans Petter Selasky 						u->id, rem_u->id);
163*d6b92ffaSHans Petter Selasky 
164*d6b92ffaSHans Petter Selasky 			/* Check if this is a legal step : the only illegal step is going
165*d6b92ffaSHans Petter Selasky 			   from DOWN to UP */
166*d6b92ffaSHans Petter Selasky 			if ((current_dir == DOWN) && (next_dir == UP)) {
167*d6b92ffaSHans Petter Selasky 				OSM_LOG(p_log, OSM_LOG_DEBUG,
168*d6b92ffaSHans Petter Selasky 					"Avoiding move from 0x%016" PRIx64
169*d6b92ffaSHans Petter Selasky 					" to 0x%016" PRIx64 "\n",
170*d6b92ffaSHans Petter Selasky 					cl_ntoh64(osm_node_get_node_guid(u->sw->p_node)),
171*d6b92ffaSHans Petter Selasky 					cl_ntoh64(osm_node_get_node_guid(p_remote_node)));
172*d6b92ffaSHans Petter Selasky 				/* Illegal step */
173*d6b92ffaSHans Petter Selasky 				continue;
174*d6b92ffaSHans Petter Selasky 			}
175*d6b92ffaSHans Petter Selasky 			/* Set MinHop value for the current lid */
176*d6b92ffaSHans Petter Selasky 			current_min_hop = osm_switch_get_least_hops(u->sw, lid);
177*d6b92ffaSHans Petter Selasky 			/* Check hop count if better insert into list && update
178*d6b92ffaSHans Petter Selasky 			   the remote node Min Hop Table */
179*d6b92ffaSHans Petter Selasky 			remote_min_hop =
180*d6b92ffaSHans Petter Selasky 			    osm_switch_get_hop_count(p_remote_sw, lid, pn_rem);
181*d6b92ffaSHans Petter Selasky 			if (current_min_hop + 1 < remote_min_hop) {
182*d6b92ffaSHans Petter Selasky 				set_hop_return_value =
183*d6b92ffaSHans Petter Selasky 				    osm_switch_set_hops(p_remote_sw, lid,
184*d6b92ffaSHans Petter Selasky 							pn_rem,
185*d6b92ffaSHans Petter Selasky 							current_min_hop + 1);
186*d6b92ffaSHans Petter Selasky 				if (set_hop_return_value) {
187*d6b92ffaSHans Petter Selasky 					OSM_LOG(p_log, OSM_LOG_ERROR, "ERR AA01: "
188*d6b92ffaSHans Petter Selasky 						"Invalid value returned from set min hop is: %d\n",
189*d6b92ffaSHans Petter Selasky 						set_hop_return_value);
190*d6b92ffaSHans Petter Selasky 				}
191*d6b92ffaSHans Petter Selasky 				/* Check if remote port has already been visited */
192*d6b92ffaSHans Petter Selasky 				if (!rem_u->visited) {
193*d6b92ffaSHans Petter Selasky 					/* Insert updn_switch item into the list */
194*d6b92ffaSHans Petter Selasky 					rem_u->dir = next_dir;
195*d6b92ffaSHans Petter Selasky 					rem_u->visited = 1;
196*d6b92ffaSHans Petter Selasky 					cl_qlist_insert_tail(&list,
197*d6b92ffaSHans Petter Selasky 							     &rem_u->list);
198*d6b92ffaSHans Petter Selasky 				}
199*d6b92ffaSHans Petter Selasky 			}
200*d6b92ffaSHans Petter Selasky 		}
201*d6b92ffaSHans Petter Selasky 	}
202*d6b92ffaSHans Petter Selasky 
203*d6b92ffaSHans Petter Selasky 	OSM_LOG_EXIT(p_log);
204*d6b92ffaSHans Petter Selasky 	return 0;
205*d6b92ffaSHans Petter Selasky }
206*d6b92ffaSHans Petter Selasky 
207*d6b92ffaSHans Petter Selasky /* NOTE : PLS check if we need to decide that the first */
208*d6b92ffaSHans Petter Selasky /*        rank is a SWITCH for BFS purpose */
updn_subn_rank(IN updn_t * p_updn)209*d6b92ffaSHans Petter Selasky static int updn_subn_rank(IN updn_t * p_updn)
210*d6b92ffaSHans Petter Selasky {
211*d6b92ffaSHans Petter Selasky 	osm_switch_t *p_sw;
212*d6b92ffaSHans Petter Selasky 	osm_physp_t *p_physp, *p_remote_physp;
213*d6b92ffaSHans Petter Selasky 	cl_qlist_t list;
214*d6b92ffaSHans Petter Selasky 	cl_map_item_t *item;
215*d6b92ffaSHans Petter Selasky 	struct updn_node *u, *remote_u;
216*d6b92ffaSHans Petter Selasky 	uint8_t num_ports, port_num;
217*d6b92ffaSHans Petter Selasky 	osm_log_t *p_log = &p_updn->p_osm->log;
218*d6b92ffaSHans Petter Selasky 	unsigned max_rank = 0;
219*d6b92ffaSHans Petter Selasky 
220*d6b92ffaSHans Petter Selasky 	OSM_LOG_ENTER(p_log);
221*d6b92ffaSHans Petter Selasky 	cl_qlist_init(&list);
222*d6b92ffaSHans Petter Selasky 
223*d6b92ffaSHans Petter Selasky 	/* add all roots to the list */
224*d6b92ffaSHans Petter Selasky 	for (item = cl_qmap_head(&p_updn->p_osm->subn.sw_guid_tbl);
225*d6b92ffaSHans Petter Selasky 	     item != cl_qmap_end(&p_updn->p_osm->subn.sw_guid_tbl);
226*d6b92ffaSHans Petter Selasky 	     item = cl_qmap_next(item)) {
227*d6b92ffaSHans Petter Selasky 		p_sw = (osm_switch_t *)item;
228*d6b92ffaSHans Petter Selasky 		u = p_sw->priv;
229*d6b92ffaSHans Petter Selasky 		if (!u->rank)
230*d6b92ffaSHans Petter Selasky 			cl_qlist_insert_tail(&list, &u->list);
231*d6b92ffaSHans Petter Selasky 	}
232*d6b92ffaSHans Petter Selasky 
233*d6b92ffaSHans Petter Selasky 	/* BFS the list till it's empty */
234*d6b92ffaSHans Petter Selasky 	while (!cl_is_qlist_empty(&list)) {
235*d6b92ffaSHans Petter Selasky 		u = (struct updn_node *)cl_qlist_remove_head(&list);
236*d6b92ffaSHans Petter Selasky 		/* Go over all remote nodes and rank them (if not already visited) */
237*d6b92ffaSHans Petter Selasky 		p_sw = u->sw;
238*d6b92ffaSHans Petter Selasky 		num_ports = p_sw->num_ports;
239*d6b92ffaSHans Petter Selasky 		OSM_LOG(p_log, OSM_LOG_DEBUG,
240*d6b92ffaSHans Petter Selasky 			"Handling switch GUID 0x%" PRIx64 "\n",
241*d6b92ffaSHans Petter Selasky 			cl_ntoh64(osm_node_get_node_guid(p_sw->p_node)));
242*d6b92ffaSHans Petter Selasky 		for (port_num = 1; port_num < num_ports; port_num++) {
243*d6b92ffaSHans Petter Selasky 			ib_net64_t port_guid;
244*d6b92ffaSHans Petter Selasky 
245*d6b92ffaSHans Petter Selasky 			/* Current port fetched in order to get remote side */
246*d6b92ffaSHans Petter Selasky 			p_physp =
247*d6b92ffaSHans Petter Selasky 			    osm_node_get_physp_ptr(p_sw->p_node, port_num);
248*d6b92ffaSHans Petter Selasky 
249*d6b92ffaSHans Petter Selasky 			if (!p_physp)
250*d6b92ffaSHans Petter Selasky 				continue;
251*d6b92ffaSHans Petter Selasky 
252*d6b92ffaSHans Petter Selasky 			p_remote_physp = p_physp->p_remote_physp;
253*d6b92ffaSHans Petter Selasky 
254*d6b92ffaSHans Petter Selasky 			/*
255*d6b92ffaSHans Petter Selasky 			   make sure that all the following occur on p_remote_physp:
256*d6b92ffaSHans Petter Selasky 			   1. The port isn't NULL
257*d6b92ffaSHans Petter Selasky 			   2. It is a switch
258*d6b92ffaSHans Petter Selasky 			 */
259*d6b92ffaSHans Petter Selasky 			if (p_remote_physp && p_remote_physp->p_node->sw) {
260*d6b92ffaSHans Petter Selasky 				remote_u = p_remote_physp->p_node->sw->priv;
261*d6b92ffaSHans Petter Selasky 				port_guid = p_remote_physp->port_guid;
262*d6b92ffaSHans Petter Selasky 
263*d6b92ffaSHans Petter Selasky 				if (remote_u->rank > u->rank + 1) {
264*d6b92ffaSHans Petter Selasky 					remote_u->rank = u->rank + 1;
265*d6b92ffaSHans Petter Selasky 					max_rank = remote_u->rank;
266*d6b92ffaSHans Petter Selasky 					cl_qlist_insert_tail(&list,
267*d6b92ffaSHans Petter Selasky 							     &remote_u->list);
268*d6b92ffaSHans Petter Selasky 					OSM_LOG(p_log, OSM_LOG_DEBUG,
269*d6b92ffaSHans Petter Selasky 						"Rank of port GUID 0x%" PRIx64
270*d6b92ffaSHans Petter Selasky 						" = %u\n", cl_ntoh64(port_guid),
271*d6b92ffaSHans Petter Selasky 						remote_u->rank);
272*d6b92ffaSHans Petter Selasky 				}
273*d6b92ffaSHans Petter Selasky 			}
274*d6b92ffaSHans Petter Selasky 		}
275*d6b92ffaSHans Petter Selasky 	}
276*d6b92ffaSHans Petter Selasky 
277*d6b92ffaSHans Petter Selasky 	/* Print Summary of ranking */
278*d6b92ffaSHans Petter Selasky 	OSM_LOG(p_log, OSM_LOG_VERBOSE,
279*d6b92ffaSHans Petter Selasky 		"Subnet ranking completed. Max Node Rank = %d\n", max_rank);
280*d6b92ffaSHans Petter Selasky 	OSM_LOG_EXIT(p_log);
281*d6b92ffaSHans Petter Selasky 	return 0;
282*d6b92ffaSHans Petter Selasky }
283*d6b92ffaSHans Petter Selasky 
284*d6b92ffaSHans Petter Selasky /* hack: preserve min hops entries to any other root switches */
updn_clear_non_root_hops(updn_t * updn,osm_switch_t * sw)285*d6b92ffaSHans Petter Selasky static void updn_clear_non_root_hops(updn_t * updn, osm_switch_t * sw)
286*d6b92ffaSHans Petter Selasky {
287*d6b92ffaSHans Petter Selasky 	osm_port_t *port;
288*d6b92ffaSHans Petter Selasky 	unsigned i;
289*d6b92ffaSHans Petter Selasky 
290*d6b92ffaSHans Petter Selasky 	for (i = 0; i < sw->num_hops; i++)
291*d6b92ffaSHans Petter Selasky 		if (sw->hops[i]) {
292*d6b92ffaSHans Petter Selasky 			port = osm_get_port_by_lid_ho(&updn->p_osm->subn, i);
293*d6b92ffaSHans Petter Selasky 			if (!port || !port->p_node->sw
294*d6b92ffaSHans Petter Selasky 			    || ((struct updn_node *)port->p_node->sw->priv)->
295*d6b92ffaSHans Petter Selasky 			    rank != 0)
296*d6b92ffaSHans Petter Selasky 				memset(sw->hops[i], 0xff, sw->num_ports);
297*d6b92ffaSHans Petter Selasky 		}
298*d6b92ffaSHans Petter Selasky }
299*d6b92ffaSHans Petter Selasky 
updn_set_min_hop_table(IN updn_t * p_updn)300*d6b92ffaSHans Petter Selasky static int updn_set_min_hop_table(IN updn_t * p_updn)
301*d6b92ffaSHans Petter Selasky {
302*d6b92ffaSHans Petter Selasky 	osm_subn_t *p_subn = &p_updn->p_osm->subn;
303*d6b92ffaSHans Petter Selasky 	osm_log_t *p_log = &p_updn->p_osm->log;
304*d6b92ffaSHans Petter Selasky 	osm_switch_t *p_sw;
305*d6b92ffaSHans Petter Selasky 	cl_map_item_t *item;
306*d6b92ffaSHans Petter Selasky 
307*d6b92ffaSHans Petter Selasky 	OSM_LOG_ENTER(p_log);
308*d6b92ffaSHans Petter Selasky 
309*d6b92ffaSHans Petter Selasky 	/* Go over all the switches in the subnet - for each init their Min Hop
310*d6b92ffaSHans Petter Selasky 	   Table */
311*d6b92ffaSHans Petter Selasky 	OSM_LOG(p_log, OSM_LOG_VERBOSE,
312*d6b92ffaSHans Petter Selasky 		"Init Min Hop Table of all switches [\n");
313*d6b92ffaSHans Petter Selasky 
314*d6b92ffaSHans Petter Selasky 	for (item = cl_qmap_head(&p_updn->p_osm->subn.sw_guid_tbl);
315*d6b92ffaSHans Petter Selasky 	     item != cl_qmap_end(&p_updn->p_osm->subn.sw_guid_tbl);
316*d6b92ffaSHans Petter Selasky 	     item = cl_qmap_next(item)) {
317*d6b92ffaSHans Petter Selasky 		p_sw = (osm_switch_t *)item;
318*d6b92ffaSHans Petter Selasky 		/* Clear Min Hop Table */
319*d6b92ffaSHans Petter Selasky 		if (p_subn->opt.connect_roots)
320*d6b92ffaSHans Petter Selasky 			updn_clear_non_root_hops(p_updn, p_sw);
321*d6b92ffaSHans Petter Selasky 		else
322*d6b92ffaSHans Petter Selasky 			osm_switch_clear_hops(p_sw);
323*d6b92ffaSHans Petter Selasky 	}
324*d6b92ffaSHans Petter Selasky 
325*d6b92ffaSHans Petter Selasky 	OSM_LOG(p_log, OSM_LOG_VERBOSE,
326*d6b92ffaSHans Petter Selasky 		"Init Min Hop Table of all switches ]\n");
327*d6b92ffaSHans Petter Selasky 
328*d6b92ffaSHans Petter Selasky 	/* Now do the BFS for each port  in the subnet */
329*d6b92ffaSHans Petter Selasky 	OSM_LOG(p_log, OSM_LOG_VERBOSE,
330*d6b92ffaSHans Petter Selasky 		"BFS through all port guids in the subnet [\n");
331*d6b92ffaSHans Petter Selasky 
332*d6b92ffaSHans Petter Selasky 	for (item = cl_qmap_head(&p_updn->p_osm->subn.sw_guid_tbl);
333*d6b92ffaSHans Petter Selasky 	     item != cl_qmap_end(&p_updn->p_osm->subn.sw_guid_tbl);
334*d6b92ffaSHans Petter Selasky 	     item = cl_qmap_next(item)) {
335*d6b92ffaSHans Petter Selasky 		p_sw = (osm_switch_t *)item;
336*d6b92ffaSHans Petter Selasky 		updn_bfs_by_node(p_log, p_subn, p_sw);
337*d6b92ffaSHans Petter Selasky 	}
338*d6b92ffaSHans Petter Selasky 
339*d6b92ffaSHans Petter Selasky 	OSM_LOG(p_log, OSM_LOG_VERBOSE,
340*d6b92ffaSHans Petter Selasky 		"BFS through all port guids in the subnet ]\n");
341*d6b92ffaSHans Petter Selasky 	/* Cleanup */
342*d6b92ffaSHans Petter Selasky 	OSM_LOG_EXIT(p_log);
343*d6b92ffaSHans Petter Selasky 	return 0;
344*d6b92ffaSHans Petter Selasky }
345*d6b92ffaSHans Petter Selasky 
updn_build_lid_matrices(IN updn_t * p_updn)346*d6b92ffaSHans Petter Selasky static int updn_build_lid_matrices(IN updn_t * p_updn)
347*d6b92ffaSHans Petter Selasky {
348*d6b92ffaSHans Petter Selasky 	int status;
349*d6b92ffaSHans Petter Selasky 
350*d6b92ffaSHans Petter Selasky 	OSM_LOG_ENTER(&p_updn->p_osm->log);
351*d6b92ffaSHans Petter Selasky 
352*d6b92ffaSHans Petter Selasky 	OSM_LOG(&p_updn->p_osm->log, OSM_LOG_VERBOSE,
353*d6b92ffaSHans Petter Selasky 		"Ranking all port guids in the list\n");
354*d6b92ffaSHans Petter Selasky 	if (!p_updn->num_roots) {
355*d6b92ffaSHans Petter Selasky 		OSM_LOG(&p_updn->p_osm->log, OSM_LOG_ERROR, "ERR AA0A: "
356*d6b92ffaSHans Petter Selasky 			"No guids were provided or number of guids is 0\n");
357*d6b92ffaSHans Petter Selasky 		status = -1;
358*d6b92ffaSHans Petter Selasky 		goto _exit;
359*d6b92ffaSHans Petter Selasky 	}
360*d6b92ffaSHans Petter Selasky 
361*d6b92ffaSHans Petter Selasky 	/* Check if it's not a switched subnet */
362*d6b92ffaSHans Petter Selasky 	if (cl_is_qmap_empty(&p_updn->p_osm->subn.sw_guid_tbl)) {
363*d6b92ffaSHans Petter Selasky 		OSM_LOG(&p_updn->p_osm->log, OSM_LOG_ERROR, "ERR AA0B: "
364*d6b92ffaSHans Petter Selasky 			"This is not a switched subnet, cannot perform UPDN algorithm\n");
365*d6b92ffaSHans Petter Selasky 		status = -1;
366*d6b92ffaSHans Petter Selasky 		goto _exit;
367*d6b92ffaSHans Petter Selasky 	}
368*d6b92ffaSHans Petter Selasky 
369*d6b92ffaSHans Petter Selasky 	/* Rank the subnet switches */
370*d6b92ffaSHans Petter Selasky 	if (updn_subn_rank(p_updn)) {
371*d6b92ffaSHans Petter Selasky 		OSM_LOG(&p_updn->p_osm->log, OSM_LOG_ERROR, "ERR AA0E: "
372*d6b92ffaSHans Petter Selasky 			"Failed to assign ranks\n");
373*d6b92ffaSHans Petter Selasky 		status = -1;
374*d6b92ffaSHans Petter Selasky 		goto _exit;
375*d6b92ffaSHans Petter Selasky 	}
376*d6b92ffaSHans Petter Selasky 
377*d6b92ffaSHans Petter Selasky 	/* After multiple ranking need to set Min Hop Table by UpDn algorithm  */
378*d6b92ffaSHans Petter Selasky 	OSM_LOG(&p_updn->p_osm->log, OSM_LOG_VERBOSE,
379*d6b92ffaSHans Petter Selasky 		"Setting all switches' Min Hop Table\n");
380*d6b92ffaSHans Petter Selasky 	status = updn_set_min_hop_table(p_updn);
381*d6b92ffaSHans Petter Selasky 
382*d6b92ffaSHans Petter Selasky _exit:
383*d6b92ffaSHans Petter Selasky 	OSM_LOG_EXIT(&p_updn->p_osm->log);
384*d6b92ffaSHans Petter Selasky 	return status;
385*d6b92ffaSHans Petter Selasky }
386*d6b92ffaSHans Petter Selasky 
create_updn_node(osm_switch_t * sw)387*d6b92ffaSHans Petter Selasky static struct updn_node *create_updn_node(osm_switch_t * sw)
388*d6b92ffaSHans Petter Selasky {
389*d6b92ffaSHans Petter Selasky 	struct updn_node *u;
390*d6b92ffaSHans Petter Selasky 
391*d6b92ffaSHans Petter Selasky 	u = malloc(sizeof(*u));
392*d6b92ffaSHans Petter Selasky 	if (!u)
393*d6b92ffaSHans Petter Selasky 		return NULL;
394*d6b92ffaSHans Petter Selasky 	memset(u, 0, sizeof(*u));
395*d6b92ffaSHans Petter Selasky 	u->sw = sw;
396*d6b92ffaSHans Petter Selasky 	u->id = cl_ntoh64(osm_node_get_node_guid(sw->p_node));
397*d6b92ffaSHans Petter Selasky 	u->rank = 0xffffffff;
398*d6b92ffaSHans Petter Selasky 	return u;
399*d6b92ffaSHans Petter Selasky }
400*d6b92ffaSHans Petter Selasky 
delete_updn_node(struct updn_node * u)401*d6b92ffaSHans Petter Selasky static void delete_updn_node(struct updn_node *u)
402*d6b92ffaSHans Petter Selasky {
403*d6b92ffaSHans Petter Selasky 	u->sw->priv = NULL;
404*d6b92ffaSHans Petter Selasky 	free(u);
405*d6b92ffaSHans Petter Selasky }
406*d6b92ffaSHans Petter Selasky 
407*d6b92ffaSHans Petter Selasky /* Find Root nodes automatically by Min Hop Table info */
updn_find_root_nodes_by_min_hop(OUT updn_t * p_updn)408*d6b92ffaSHans Petter Selasky static void updn_find_root_nodes_by_min_hop(OUT updn_t * p_updn)
409*d6b92ffaSHans Petter Selasky {
410*d6b92ffaSHans Petter Selasky 	osm_opensm_t *p_osm = p_updn->p_osm;
411*d6b92ffaSHans Petter Selasky 	osm_switch_t *p_sw;
412*d6b92ffaSHans Petter Selasky 	osm_port_t *p_port;
413*d6b92ffaSHans Petter Selasky 	osm_physp_t *p_physp;
414*d6b92ffaSHans Petter Selasky 	cl_map_item_t *item;
415*d6b92ffaSHans Petter Selasky 	double thd1, thd2;
416*d6b92ffaSHans Petter Selasky 	unsigned i, cas_num = 0;
417*d6b92ffaSHans Petter Selasky 	unsigned *cas_per_sw;
418*d6b92ffaSHans Petter Selasky 	uint16_t lid_ho;
419*d6b92ffaSHans Petter Selasky 
420*d6b92ffaSHans Petter Selasky 	OSM_LOG_ENTER(&p_osm->log);
421*d6b92ffaSHans Petter Selasky 
422*d6b92ffaSHans Petter Selasky 	OSM_LOG(&p_osm->log, OSM_LOG_DEBUG,
423*d6b92ffaSHans Petter Selasky 		"Current number of ports in the subnet is %d\n",
424*d6b92ffaSHans Petter Selasky 		cl_qmap_count(&p_osm->subn.port_guid_tbl));
425*d6b92ffaSHans Petter Selasky 
426*d6b92ffaSHans Petter Selasky 	lid_ho = (uint16_t) cl_ptr_vector_get_size(&p_updn->p_osm->subn.port_lid_tbl) + 1;
427*d6b92ffaSHans Petter Selasky 	cas_per_sw = malloc(lid_ho * sizeof(*cas_per_sw));
428*d6b92ffaSHans Petter Selasky 	if (!cas_per_sw) {
429*d6b92ffaSHans Petter Selasky 		OSM_LOG(&p_osm->log, OSM_LOG_ERROR, "ERR AA14: "
430*d6b92ffaSHans Petter Selasky 			"cannot alloc mem for CAs per switch counter array\n");
431*d6b92ffaSHans Petter Selasky 		goto _exit;
432*d6b92ffaSHans Petter Selasky 	}
433*d6b92ffaSHans Petter Selasky 	memset(cas_per_sw, 0, lid_ho * sizeof(*cas_per_sw));
434*d6b92ffaSHans Petter Selasky 
435*d6b92ffaSHans Petter Selasky 	/* Find the Maximum number of CAs (and routers) for histogram normalization */
436*d6b92ffaSHans Petter Selasky 	OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE,
437*d6b92ffaSHans Petter Selasky 		"Finding the number of CAs and storing them in cl_map\n");
438*d6b92ffaSHans Petter Selasky 	for (item = cl_qmap_head(&p_updn->p_osm->subn.port_guid_tbl);
439*d6b92ffaSHans Petter Selasky 	     item != cl_qmap_end(&p_updn->p_osm->subn.port_guid_tbl);
440*d6b92ffaSHans Petter Selasky 	     item = cl_qmap_next(item)) {
441*d6b92ffaSHans Petter Selasky 		p_port = (osm_port_t *)item;
442*d6b92ffaSHans Petter Selasky 		if (!p_port->p_node->sw) {
443*d6b92ffaSHans Petter Selasky 			p_physp = p_port->p_physp->p_remote_physp;
444*d6b92ffaSHans Petter Selasky 			if (!p_physp || !p_physp->p_node->sw)
445*d6b92ffaSHans Petter Selasky 				continue;
446*d6b92ffaSHans Petter Selasky 			lid_ho = osm_node_get_base_lid(p_physp->p_node, 0);
447*d6b92ffaSHans Petter Selasky 			lid_ho = cl_ntoh16(lid_ho);
448*d6b92ffaSHans Petter Selasky 			cas_per_sw[lid_ho]++;
449*d6b92ffaSHans Petter Selasky 			cas_num++;
450*d6b92ffaSHans Petter Selasky 		}
451*d6b92ffaSHans Petter Selasky 	}
452*d6b92ffaSHans Petter Selasky 
453*d6b92ffaSHans Petter Selasky 	thd1 = cas_num * 0.9;
454*d6b92ffaSHans Petter Selasky 	thd2 = cas_num * 0.05;
455*d6b92ffaSHans Petter Selasky 	OSM_LOG(&p_osm->log, OSM_LOG_DEBUG,
456*d6b92ffaSHans Petter Selasky 		"Found %u CAs and RTRs, %u SWs in the subnet. "
457*d6b92ffaSHans Petter Selasky 		"Thresholds are thd1 = %f && thd2 = %f\n",
458*d6b92ffaSHans Petter Selasky 		cas_num, cl_qmap_count(&p_osm->subn.sw_guid_tbl), thd1, thd2);
459*d6b92ffaSHans Petter Selasky 
460*d6b92ffaSHans Petter Selasky 	OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE,
461*d6b92ffaSHans Petter Selasky 		"Passing through all switches to collect Min Hop info\n");
462*d6b92ffaSHans Petter Selasky 	for (item = cl_qmap_head(&p_updn->p_osm->subn.sw_guid_tbl);
463*d6b92ffaSHans Petter Selasky 	     item != cl_qmap_end(&p_updn->p_osm->subn.sw_guid_tbl);
464*d6b92ffaSHans Petter Selasky 	     item = cl_qmap_next(item)) {
465*d6b92ffaSHans Petter Selasky 		unsigned hop_hist[IB_SUBNET_PATH_HOPS_MAX];
466*d6b92ffaSHans Petter Selasky 		uint16_t max_lid_ho;
467*d6b92ffaSHans Petter Selasky 		uint8_t hop_val;
468*d6b92ffaSHans Petter Selasky 		uint16_t numHopBarsOverThd1 = 0;
469*d6b92ffaSHans Petter Selasky 		uint16_t numHopBarsOverThd2 = 0;
470*d6b92ffaSHans Petter Selasky 
471*d6b92ffaSHans Petter Selasky 		p_sw = (osm_switch_t *) item;
472*d6b92ffaSHans Petter Selasky 
473*d6b92ffaSHans Petter Selasky 		memset(hop_hist, 0, sizeof(hop_hist));
474*d6b92ffaSHans Petter Selasky 
475*d6b92ffaSHans Petter Selasky 		max_lid_ho = p_sw->max_lid_ho;
476*d6b92ffaSHans Petter Selasky 		for (lid_ho = 1; lid_ho <= max_lid_ho; lid_ho++)
477*d6b92ffaSHans Petter Selasky 			if (cas_per_sw[lid_ho]) {
478*d6b92ffaSHans Petter Selasky 				hop_val =
479*d6b92ffaSHans Petter Selasky 				    osm_switch_get_least_hops(p_sw, lid_ho);
480*d6b92ffaSHans Petter Selasky 				if (hop_val >= IB_SUBNET_PATH_HOPS_MAX)
481*d6b92ffaSHans Petter Selasky 					continue;
482*d6b92ffaSHans Petter Selasky 
483*d6b92ffaSHans Petter Selasky 				hop_hist[hop_val] += cas_per_sw[lid_ho];
484*d6b92ffaSHans Petter Selasky 			}
485*d6b92ffaSHans Petter Selasky 
486*d6b92ffaSHans Petter Selasky 		/* Now recognize the spines by requiring one bar to be
487*d6b92ffaSHans Petter Selasky 		   above 90% of the number of CAs and RTRs */
488*d6b92ffaSHans Petter Selasky 		for (i = 0; i < IB_SUBNET_PATH_HOPS_MAX; i++) {
489*d6b92ffaSHans Petter Selasky 			if (hop_hist[i] > thd1)
490*d6b92ffaSHans Petter Selasky 				numHopBarsOverThd1++;
491*d6b92ffaSHans Petter Selasky 			if (hop_hist[i] > thd2)
492*d6b92ffaSHans Petter Selasky 				numHopBarsOverThd2++;
493*d6b92ffaSHans Petter Selasky 		}
494*d6b92ffaSHans Petter Selasky 
495*d6b92ffaSHans Petter Selasky 		/* If thd conditions are valid - rank the root node */
496*d6b92ffaSHans Petter Selasky 		if (numHopBarsOverThd1 == 1 && numHopBarsOverThd2 == 1) {
497*d6b92ffaSHans Petter Selasky 			OSM_LOG(&p_osm->log, OSM_LOG_DEBUG,
498*d6b92ffaSHans Petter Selasky 				"Ranking GUID 0x%" PRIx64 " as root node\n",
499*d6b92ffaSHans Petter Selasky 				cl_ntoh64(osm_node_get_node_guid(p_sw->p_node)));
500*d6b92ffaSHans Petter Selasky 			((struct updn_node *)p_sw->priv)->rank = 0;
501*d6b92ffaSHans Petter Selasky 			p_updn->num_roots++;
502*d6b92ffaSHans Petter Selasky 		}
503*d6b92ffaSHans Petter Selasky 	}
504*d6b92ffaSHans Petter Selasky 
505*d6b92ffaSHans Petter Selasky 	free(cas_per_sw);
506*d6b92ffaSHans Petter Selasky _exit:
507*d6b92ffaSHans Petter Selasky 	OSM_LOG_EXIT(&p_osm->log);
508*d6b92ffaSHans Petter Selasky 	return;
509*d6b92ffaSHans Petter Selasky }
510*d6b92ffaSHans Petter Selasky 
dump_roots(cl_map_item_t * item,FILE * file,void * cxt)511*d6b92ffaSHans Petter Selasky static void dump_roots(cl_map_item_t *item, FILE *file, void *cxt)
512*d6b92ffaSHans Petter Selasky {
513*d6b92ffaSHans Petter Selasky 	osm_switch_t *sw = (osm_switch_t *)item;
514*d6b92ffaSHans Petter Selasky 	if (!((struct updn_node *)sw->priv)->rank)
515*d6b92ffaSHans Petter Selasky 		fprintf(file, "0x%" PRIx64 "\n",
516*d6b92ffaSHans Petter Selasky 			cl_ntoh64(osm_node_get_node_guid(sw->p_node)));
517*d6b92ffaSHans Petter Selasky }
518*d6b92ffaSHans Petter Selasky 
update_id(void * cxt,uint64_t guid,char * p)519*d6b92ffaSHans Petter Selasky static int update_id(void *cxt, uint64_t guid, char *p)
520*d6b92ffaSHans Petter Selasky {
521*d6b92ffaSHans Petter Selasky 	osm_opensm_t *osm = cxt;
522*d6b92ffaSHans Petter Selasky 	osm_switch_t *sw;
523*d6b92ffaSHans Petter Selasky 	uint64_t id;
524*d6b92ffaSHans Petter Selasky 	char *e;
525*d6b92ffaSHans Petter Selasky 
526*d6b92ffaSHans Petter Selasky 	sw = osm_get_switch_by_guid(&osm->subn, cl_hton64(guid));
527*d6b92ffaSHans Petter Selasky 	if (!sw) {
528*d6b92ffaSHans Petter Selasky 		OSM_LOG(&osm->log, OSM_LOG_VERBOSE,
529*d6b92ffaSHans Petter Selasky 			"switch with guid 0x%" PRIx64 " is not found\n", guid);
530*d6b92ffaSHans Petter Selasky 		return 0;
531*d6b92ffaSHans Petter Selasky 	}
532*d6b92ffaSHans Petter Selasky 
533*d6b92ffaSHans Petter Selasky 	id = strtoull(p, &e, 0);
534*d6b92ffaSHans Petter Selasky 	if (*e && !isspace(*e)) {
535*d6b92ffaSHans Petter Selasky 		OSM_LOG(&osm->log, OSM_LOG_ERROR,
536*d6b92ffaSHans Petter Selasky 			"ERR AA05: cannot parse node id \'%s\'", p);
537*d6b92ffaSHans Petter Selasky 		return -1;
538*d6b92ffaSHans Petter Selasky 	}
539*d6b92ffaSHans Petter Selasky 
540*d6b92ffaSHans Petter Selasky 	OSM_LOG(&osm->log, OSM_LOG_DEBUG,
541*d6b92ffaSHans Petter Selasky 		"update node 0x%" PRIx64 " id to 0x%" PRIx64 "\n", guid, id);
542*d6b92ffaSHans Petter Selasky 
543*d6b92ffaSHans Petter Selasky 	((struct updn_node *)sw->priv)->id = id;
544*d6b92ffaSHans Petter Selasky 
545*d6b92ffaSHans Petter Selasky 	return 0;
546*d6b92ffaSHans Petter Selasky }
547*d6b92ffaSHans Petter Selasky 
rank_root_node(void * cxt,uint64_t guid,char * p)548*d6b92ffaSHans Petter Selasky static int rank_root_node(void *cxt, uint64_t guid, char *p)
549*d6b92ffaSHans Petter Selasky {
550*d6b92ffaSHans Petter Selasky 	updn_t *updn = cxt;
551*d6b92ffaSHans Petter Selasky 	osm_switch_t *sw;
552*d6b92ffaSHans Petter Selasky 
553*d6b92ffaSHans Petter Selasky 	sw = osm_get_switch_by_guid(&updn->p_osm->subn, cl_hton64(guid));
554*d6b92ffaSHans Petter Selasky 	if (!sw) {
555*d6b92ffaSHans Petter Selasky 		OSM_LOG(&updn->p_osm->log, OSM_LOG_VERBOSE,
556*d6b92ffaSHans Petter Selasky 			"switch with guid 0x%" PRIx64 " is not found\n", guid);
557*d6b92ffaSHans Petter Selasky 		return 0;
558*d6b92ffaSHans Petter Selasky 	}
559*d6b92ffaSHans Petter Selasky 
560*d6b92ffaSHans Petter Selasky 	OSM_LOG(&updn->p_osm->log, OSM_LOG_DEBUG,
561*d6b92ffaSHans Petter Selasky 		"Ranking root port GUID 0x%" PRIx64 "\n", guid);
562*d6b92ffaSHans Petter Selasky 
563*d6b92ffaSHans Petter Selasky 	((struct updn_node *)sw->priv)->rank = 0;
564*d6b92ffaSHans Petter Selasky 	updn->num_roots++;
565*d6b92ffaSHans Petter Selasky 
566*d6b92ffaSHans Petter Selasky 	return 0;
567*d6b92ffaSHans Petter Selasky }
568*d6b92ffaSHans Petter Selasky 
569*d6b92ffaSHans Petter Selasky /* UPDN callback function */
updn_lid_matrices(void * ctx)570*d6b92ffaSHans Petter Selasky static int updn_lid_matrices(void *ctx)
571*d6b92ffaSHans Petter Selasky {
572*d6b92ffaSHans Petter Selasky 	updn_t *p_updn = ctx;
573*d6b92ffaSHans Petter Selasky 	cl_map_item_t *item;
574*d6b92ffaSHans Petter Selasky 	osm_switch_t *p_sw;
575*d6b92ffaSHans Petter Selasky 	int ret = 0;
576*d6b92ffaSHans Petter Selasky 
577*d6b92ffaSHans Petter Selasky 	OSM_LOG_ENTER(&p_updn->p_osm->log);
578*d6b92ffaSHans Petter Selasky 
579*d6b92ffaSHans Petter Selasky 	for (item = cl_qmap_head(&p_updn->p_osm->subn.sw_guid_tbl);
580*d6b92ffaSHans Petter Selasky 	     item != cl_qmap_end(&p_updn->p_osm->subn.sw_guid_tbl);
581*d6b92ffaSHans Petter Selasky 	     item = cl_qmap_next(item)) {
582*d6b92ffaSHans Petter Selasky 		p_sw = (osm_switch_t *)item;
583*d6b92ffaSHans Petter Selasky 		p_sw->priv = create_updn_node(p_sw);
584*d6b92ffaSHans Petter Selasky 		if (!p_sw->priv) {
585*d6b92ffaSHans Petter Selasky 			OSM_LOG(&(p_updn->p_osm->log), OSM_LOG_ERROR, "ERR AA0C: "
586*d6b92ffaSHans Petter Selasky 				"cannot create updn node\n");
587*d6b92ffaSHans Petter Selasky 			OSM_LOG_EXIT(&p_updn->p_osm->log);
588*d6b92ffaSHans Petter Selasky 			return -1;
589*d6b92ffaSHans Petter Selasky 		}
590*d6b92ffaSHans Petter Selasky 	}
591*d6b92ffaSHans Petter Selasky 
592*d6b92ffaSHans Petter Selasky 	/* First setup root nodes */
593*d6b92ffaSHans Petter Selasky 	p_updn->num_roots = 0;
594*d6b92ffaSHans Petter Selasky 
595*d6b92ffaSHans Petter Selasky 	if (p_updn->p_osm->subn.opt.root_guid_file) {
596*d6b92ffaSHans Petter Selasky 		OSM_LOG(&p_updn->p_osm->log, OSM_LOG_DEBUG,
597*d6b92ffaSHans Petter Selasky 			"UPDN - Fetching root nodes from file \'%s\'\n",
598*d6b92ffaSHans Petter Selasky 			p_updn->p_osm->subn.opt.root_guid_file);
599*d6b92ffaSHans Petter Selasky 
600*d6b92ffaSHans Petter Selasky 		ret = parse_node_map(p_updn->p_osm->subn.opt.root_guid_file,
601*d6b92ffaSHans Petter Selasky 				     rank_root_node, p_updn);
602*d6b92ffaSHans Petter Selasky 		if (ret) {
603*d6b92ffaSHans Petter Selasky 			OSM_LOG(&p_updn->p_osm->log, OSM_LOG_ERROR, "ERR AA02: "
604*d6b92ffaSHans Petter Selasky 				"cannot parse root guids file \'%s\'\n",
605*d6b92ffaSHans Petter Selasky 				p_updn->p_osm->subn.opt.root_guid_file);
606*d6b92ffaSHans Petter Selasky 			osm_ucast_mgr_build_lid_matrices(&p_updn->p_osm->sm.ucast_mgr);
607*d6b92ffaSHans Petter Selasky 			updn_find_root_nodes_by_min_hop(p_updn);
608*d6b92ffaSHans Petter Selasky 		} else if (p_updn->p_osm->subn.opt.connect_roots &&
609*d6b92ffaSHans Petter Selasky 			   p_updn->num_roots > 1)
610*d6b92ffaSHans Petter Selasky 			osm_ucast_mgr_build_lid_matrices(&p_updn->p_osm->sm.ucast_mgr);
611*d6b92ffaSHans Petter Selasky 	} else {
612*d6b92ffaSHans Petter Selasky 		osm_ucast_mgr_build_lid_matrices(&p_updn->p_osm->sm.ucast_mgr);
613*d6b92ffaSHans Petter Selasky 		updn_find_root_nodes_by_min_hop(p_updn);
614*d6b92ffaSHans Petter Selasky 	}
615*d6b92ffaSHans Petter Selasky 
616*d6b92ffaSHans Petter Selasky 	if (p_updn->p_osm->subn.opt.ids_guid_file) {
617*d6b92ffaSHans Petter Selasky 		OSM_LOG(&p_updn->p_osm->log, OSM_LOG_DEBUG,
618*d6b92ffaSHans Petter Selasky 			"UPDN - update node ids from file \'%s\'\n",
619*d6b92ffaSHans Petter Selasky 			p_updn->p_osm->subn.opt.ids_guid_file);
620*d6b92ffaSHans Petter Selasky 
621*d6b92ffaSHans Petter Selasky 		ret = parse_node_map(p_updn->p_osm->subn.opt.ids_guid_file,
622*d6b92ffaSHans Petter Selasky 				     update_id, p_updn->p_osm);
623*d6b92ffaSHans Petter Selasky 		if (ret)
624*d6b92ffaSHans Petter Selasky 			OSM_LOG(&p_updn->p_osm->log, OSM_LOG_ERROR, "ERR AA03: "
625*d6b92ffaSHans Petter Selasky 				"cannot parse node ids file \'%s\'\n",
626*d6b92ffaSHans Petter Selasky 				p_updn->p_osm->subn.opt.ids_guid_file);
627*d6b92ffaSHans Petter Selasky 	}
628*d6b92ffaSHans Petter Selasky 
629*d6b92ffaSHans Petter Selasky 	/* Only if there are assigned root nodes do the algorithm, otherwise perform do nothing */
630*d6b92ffaSHans Petter Selasky 	if (p_updn->num_roots) {
631*d6b92ffaSHans Petter Selasky 		OSM_LOG(&p_updn->p_osm->log, OSM_LOG_DEBUG,
632*d6b92ffaSHans Petter Selasky 			"activating UPDN algorithm\n");
633*d6b92ffaSHans Petter Selasky 		ret = updn_build_lid_matrices(p_updn);
634*d6b92ffaSHans Petter Selasky 	} else {
635*d6b92ffaSHans Petter Selasky 		OSM_LOG(&p_updn->p_osm->log, OSM_LOG_INFO,
636*d6b92ffaSHans Petter Selasky 			"disabling UPDN algorithm, no root nodes were found\n");
637*d6b92ffaSHans Petter Selasky 		ret = -1;
638*d6b92ffaSHans Petter Selasky 	}
639*d6b92ffaSHans Petter Selasky 
640*d6b92ffaSHans Petter Selasky 	if (OSM_LOG_IS_ACTIVE_V2(&p_updn->p_osm->log, OSM_LOG_ROUTING))
641*d6b92ffaSHans Petter Selasky 		osm_dump_qmap_to_file(p_updn->p_osm, "opensm-updn-roots.dump",
642*d6b92ffaSHans Petter Selasky 				      &p_updn->p_osm->subn.sw_guid_tbl,
643*d6b92ffaSHans Petter Selasky 				      dump_roots, NULL);
644*d6b92ffaSHans Petter Selasky 
645*d6b92ffaSHans Petter Selasky 	for (item = cl_qmap_head(&p_updn->p_osm->subn.sw_guid_tbl);
646*d6b92ffaSHans Petter Selasky 	     item != cl_qmap_end(&p_updn->p_osm->subn.sw_guid_tbl);
647*d6b92ffaSHans Petter Selasky 	     item = cl_qmap_next(item)) {
648*d6b92ffaSHans Petter Selasky 		p_sw = (osm_switch_t *) item;
649*d6b92ffaSHans Petter Selasky 		delete_updn_node(p_sw->priv);
650*d6b92ffaSHans Petter Selasky 	}
651*d6b92ffaSHans Petter Selasky 
652*d6b92ffaSHans Petter Selasky 	OSM_LOG_EXIT(&p_updn->p_osm->log);
653*d6b92ffaSHans Petter Selasky 	return ret;
654*d6b92ffaSHans Petter Selasky }
655*d6b92ffaSHans Petter Selasky 
updn_delete(void * context)656*d6b92ffaSHans Petter Selasky static void updn_delete(void *context)
657*d6b92ffaSHans Petter Selasky {
658*d6b92ffaSHans Petter Selasky 	free(context);
659*d6b92ffaSHans Petter Selasky }
660*d6b92ffaSHans Petter Selasky 
osm_ucast_updn_setup(struct osm_routing_engine * r,osm_opensm_t * osm)661*d6b92ffaSHans Petter Selasky int osm_ucast_updn_setup(struct osm_routing_engine *r, osm_opensm_t *osm)
662*d6b92ffaSHans Petter Selasky {
663*d6b92ffaSHans Petter Selasky 	updn_t *updn;
664*d6b92ffaSHans Petter Selasky 
665*d6b92ffaSHans Petter Selasky 	updn = malloc(sizeof(updn_t));
666*d6b92ffaSHans Petter Selasky 	if (!updn)
667*d6b92ffaSHans Petter Selasky 		return -1;
668*d6b92ffaSHans Petter Selasky 	memset(updn, 0, sizeof(updn_t));
669*d6b92ffaSHans Petter Selasky 
670*d6b92ffaSHans Petter Selasky 	updn->p_osm = osm;
671*d6b92ffaSHans Petter Selasky 
672*d6b92ffaSHans Petter Selasky 	r->context = updn;
673*d6b92ffaSHans Petter Selasky 	r->destroy = updn_delete;
674*d6b92ffaSHans Petter Selasky 	r->build_lid_matrices = updn_lid_matrices;
675*d6b92ffaSHans Petter Selasky 
676*d6b92ffaSHans Petter Selasky 	return 0;
677*d6b92ffaSHans Petter Selasky }
678