xref: /freebsd/contrib/ofed/opensm/opensm/osm_ucast_dnup.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  * Copyright (c) 2009 Battelle Memorial Institue. All rights reserved.
7*d6b92ffaSHans Petter Selasky  *
8*d6b92ffaSHans Petter Selasky  * This software is available to you under a choice of one of two
9*d6b92ffaSHans Petter Selasky  * licenses.  You may choose to be licensed under the terms of the GNU
10*d6b92ffaSHans Petter Selasky  * General Public License (GPL) Version 2, available from the file
11*d6b92ffaSHans Petter Selasky  * COPYING in the main directory of this source tree, or the
12*d6b92ffaSHans Petter Selasky  * OpenIB.org BSD license below:
13*d6b92ffaSHans Petter Selasky  *
14*d6b92ffaSHans Petter Selasky  *     Redistribution and use in source and binary forms, with or
15*d6b92ffaSHans Petter Selasky  *     without modification, are permitted provided that the following
16*d6b92ffaSHans Petter Selasky  *     conditions are met:
17*d6b92ffaSHans Petter Selasky  *
18*d6b92ffaSHans Petter Selasky  *      - Redistributions of source code must retain the above
19*d6b92ffaSHans Petter Selasky  *        copyright notice, this list of conditions and the following
20*d6b92ffaSHans Petter Selasky  *        disclaimer.
21*d6b92ffaSHans Petter Selasky  *
22*d6b92ffaSHans Petter Selasky  *      - Redistributions in binary form must reproduce the above
23*d6b92ffaSHans Petter Selasky  *        copyright notice, this list of conditions and the following
24*d6b92ffaSHans Petter Selasky  *        disclaimer in the documentation and/or other materials
25*d6b92ffaSHans Petter Selasky  *        provided with the distribution.
26*d6b92ffaSHans Petter Selasky  *
27*d6b92ffaSHans Petter Selasky  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28*d6b92ffaSHans Petter Selasky  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29*d6b92ffaSHans Petter Selasky  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30*d6b92ffaSHans Petter Selasky  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
31*d6b92ffaSHans Petter Selasky  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
32*d6b92ffaSHans Petter Selasky  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
33*d6b92ffaSHans Petter Selasky  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
34*d6b92ffaSHans Petter Selasky  * SOFTWARE.
35*d6b92ffaSHans Petter Selasky  *
36*d6b92ffaSHans Petter Selasky  */
37*d6b92ffaSHans Petter Selasky 
38*d6b92ffaSHans Petter Selasky /*
39*d6b92ffaSHans Petter Selasky  * Abstract:
40*d6b92ffaSHans Petter Selasky  *      Implementation of Up Down Algorithm using ranking & Min Hop
41*d6b92ffaSHans Petter Selasky  *      Calculation functions
42*d6b92ffaSHans Petter Selasky  */
43*d6b92ffaSHans Petter Selasky 
44*d6b92ffaSHans Petter Selasky #if HAVE_CONFIG_H
45*d6b92ffaSHans Petter Selasky #  include <config.h>
46*d6b92ffaSHans Petter Selasky #endif				/* HAVE_CONFIG_H */
47*d6b92ffaSHans Petter Selasky 
48*d6b92ffaSHans Petter Selasky #include <stdlib.h>
49*d6b92ffaSHans Petter Selasky #include <ctype.h>
50*d6b92ffaSHans Petter Selasky #include <complib/cl_debug.h>
51*d6b92ffaSHans Petter Selasky #include <complib/cl_qmap.h>
52*d6b92ffaSHans Petter Selasky #include <opensm/osm_file_ids.h>
53*d6b92ffaSHans Petter Selasky #define FILE_ID OSM_FILE_UCAST_DNUP_C
54*d6b92ffaSHans Petter Selasky #include <opensm/osm_switch.h>
55*d6b92ffaSHans Petter Selasky #include <opensm/osm_opensm.h>
56*d6b92ffaSHans Petter Selasky #include <opensm/osm_ucast_mgr.h>
57*d6b92ffaSHans Petter Selasky 
58*d6b92ffaSHans Petter Selasky /* //////////////////////////// */
59*d6b92ffaSHans Petter Selasky /*  Local types                 */
60*d6b92ffaSHans Petter Selasky /* //////////////////////////// */
61*d6b92ffaSHans Petter Selasky 
62*d6b92ffaSHans Petter Selasky /* direction */
63*d6b92ffaSHans Petter Selasky typedef enum dnup_switch_dir {
64*d6b92ffaSHans Petter Selasky 	UP = 0,
65*d6b92ffaSHans Petter Selasky 	DOWN,
66*d6b92ffaSHans Petter Selasky 	EQUAL
67*d6b92ffaSHans Petter Selasky } dnup_switch_dir_t;
68*d6b92ffaSHans Petter Selasky 
69*d6b92ffaSHans Petter Selasky /* dnup structure */
70*d6b92ffaSHans Petter Selasky typedef struct dnup {
71*d6b92ffaSHans Petter Selasky 	osm_opensm_t *p_osm;
72*d6b92ffaSHans Petter Selasky } dnup_t;
73*d6b92ffaSHans Petter Selasky 
74*d6b92ffaSHans Petter Selasky struct dnup_node {
75*d6b92ffaSHans Petter Selasky 	cl_list_item_t list;
76*d6b92ffaSHans Petter Selasky 	osm_switch_t *sw;
77*d6b92ffaSHans Petter Selasky 	dnup_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 */
dnup_get_dir(unsigned cur_rank,unsigned rem_rank)84*d6b92ffaSHans Petter Selasky static dnup_switch_dir_t dnup_get_dir(unsigned cur_rank, unsigned rem_rank)
85*d6b92ffaSHans Petter Selasky {
86*d6b92ffaSHans Petter Selasky 	/* HACK: comes to solve root nodes connection, in a classic subnet root nodes do not connect
87*d6b92ffaSHans Petter Selasky 	   directly, but in case they are we assign to root node an UP direction to allow DNUP to discover
88*d6b92ffaSHans Petter Selasky 	   the subnet correctly (and not from the point of view of the last root node).
89*d6b92ffaSHans Petter Selasky 	 */
90*d6b92ffaSHans Petter Selasky 	if (!cur_rank && !rem_rank)
91*d6b92ffaSHans Petter Selasky 		return EQUAL;
92*d6b92ffaSHans Petter Selasky 
93*d6b92ffaSHans Petter Selasky 	if (cur_rank < rem_rank)
94*d6b92ffaSHans Petter Selasky 		return DOWN;
95*d6b92ffaSHans Petter Selasky 	else if (cur_rank > rem_rank)
96*d6b92ffaSHans Petter Selasky 		return UP;
97*d6b92ffaSHans Petter Selasky 	else
98*d6b92ffaSHans Petter Selasky 		return EQUAL;
99*d6b92ffaSHans Petter Selasky }
100*d6b92ffaSHans Petter Selasky 
101*d6b92ffaSHans Petter Selasky /**********************************************************************
102*d6b92ffaSHans Petter Selasky  * This function does the bfs of min hop table calculation by guid index
103*d6b92ffaSHans Petter Selasky  * as a starting point.
104*d6b92ffaSHans Petter Selasky  **********************************************************************/
dnup_bfs_by_node(IN osm_log_t * p_log,IN osm_subn_t * p_subn,IN osm_switch_t * p_sw,IN uint8_t prune_weight,OUT uint8_t * max_hops)105*d6b92ffaSHans Petter Selasky static int dnup_bfs_by_node(IN osm_log_t * p_log, IN osm_subn_t * p_subn,
106*d6b92ffaSHans Petter Selasky 			    IN osm_switch_t * p_sw, IN uint8_t prune_weight,
107*d6b92ffaSHans Petter Selasky 			    OUT uint8_t * max_hops)
108*d6b92ffaSHans Petter Selasky {
109*d6b92ffaSHans Petter Selasky 	uint8_t pn, pn_rem;
110*d6b92ffaSHans Petter Selasky 	cl_qlist_t list;
111*d6b92ffaSHans Petter Selasky 	uint16_t lid;
112*d6b92ffaSHans Petter Selasky 	struct dnup_node *u;
113*d6b92ffaSHans Petter Selasky 	dnup_switch_dir_t next_dir, current_dir;
114*d6b92ffaSHans Petter Selasky 
115*d6b92ffaSHans Petter Selasky 	OSM_LOG_ENTER(p_log);
116*d6b92ffaSHans Petter Selasky 
117*d6b92ffaSHans Petter Selasky 	lid = osm_node_get_base_lid(p_sw->p_node, 0);
118*d6b92ffaSHans Petter Selasky 	lid = cl_ntoh16(lid);
119*d6b92ffaSHans Petter Selasky 	osm_switch_set_hops(p_sw, lid, 0, 0);
120*d6b92ffaSHans Petter Selasky 
121*d6b92ffaSHans Petter Selasky 	OSM_LOG(p_log, OSM_LOG_DEBUG,
122*d6b92ffaSHans Petter Selasky 		"Starting from switch - port GUID 0x%" PRIx64 " lid %u\n",
123*d6b92ffaSHans Petter Selasky 		cl_ntoh64(p_sw->p_node->node_info.port_guid), lid);
124*d6b92ffaSHans Petter Selasky 
125*d6b92ffaSHans Petter Selasky 	u = p_sw->priv;
126*d6b92ffaSHans Petter Selasky 	u->dir = DOWN;
127*d6b92ffaSHans Petter Selasky 
128*d6b92ffaSHans Petter Selasky 	/* Update list with the new element */
129*d6b92ffaSHans Petter Selasky 	cl_qlist_init(&list);
130*d6b92ffaSHans Petter Selasky 	cl_qlist_insert_tail(&list, &u->list);
131*d6b92ffaSHans Petter Selasky 
132*d6b92ffaSHans Petter Selasky 	/* BFS the list till no next element */
133*d6b92ffaSHans Petter Selasky 	while (!cl_is_qlist_empty(&list)) {
134*d6b92ffaSHans Petter Selasky 		u = (struct dnup_node *)cl_qlist_remove_head(&list);
135*d6b92ffaSHans Petter Selasky 		u->visited = 0;	/* cleanup */
136*d6b92ffaSHans Petter Selasky 		current_dir = u->dir;
137*d6b92ffaSHans Petter Selasky 		/* Go over all ports of the switch and find unvisited remote nodes */
138*d6b92ffaSHans Petter Selasky 		for (pn = 1; pn < u->sw->num_ports; pn++) {
139*d6b92ffaSHans Petter Selasky 			osm_node_t *p_remote_node;
140*d6b92ffaSHans Petter Selasky 			struct dnup_node *rem_u;
141*d6b92ffaSHans Petter Selasky 			uint8_t current_min_hop, remote_min_hop,
142*d6b92ffaSHans Petter Selasky 			    set_hop_return_value;
143*d6b92ffaSHans Petter Selasky 			osm_switch_t *p_remote_sw;
144*d6b92ffaSHans Petter Selasky 
145*d6b92ffaSHans Petter Selasky 			p_remote_node =
146*d6b92ffaSHans Petter Selasky 			    osm_node_get_remote_node(u->sw->p_node, pn,
147*d6b92ffaSHans Petter Selasky 						     &pn_rem);
148*d6b92ffaSHans Petter Selasky 			/* If no remote node OR remote node is not a SWITCH
149*d6b92ffaSHans Petter Selasky 			   continue to next pn */
150*d6b92ffaSHans Petter Selasky 			if (!p_remote_node || !p_remote_node->sw)
151*d6b92ffaSHans Petter Selasky 				continue;
152*d6b92ffaSHans Petter Selasky 			/* Fetch remote guid only after validation of remote node */
153*d6b92ffaSHans Petter Selasky 			p_remote_sw = p_remote_node->sw;
154*d6b92ffaSHans Petter Selasky 			rem_u = p_remote_sw->priv;
155*d6b92ffaSHans Petter Selasky 			/* Decide which direction to mark it (UP/DOWN) */
156*d6b92ffaSHans Petter Selasky 			next_dir = dnup_get_dir(u->rank, rem_u->rank);
157*d6b92ffaSHans Petter Selasky 
158*d6b92ffaSHans Petter Selasky 			/* Set MinHop value for the current lid */
159*d6b92ffaSHans Petter Selasky 			current_min_hop = osm_switch_get_least_hops(u->sw, lid);
160*d6b92ffaSHans Petter Selasky 			/* Check hop count if better insert into list && update
161*d6b92ffaSHans Petter Selasky 			   the remote node Min Hop Table */
162*d6b92ffaSHans Petter Selasky 			remote_min_hop =
163*d6b92ffaSHans Petter Selasky 			    osm_switch_get_hop_count(p_remote_sw, lid, pn_rem);
164*d6b92ffaSHans Petter Selasky 
165*d6b92ffaSHans Petter Selasky 			/* Check if this is a legal step : the only illegal step is going
166*d6b92ffaSHans Petter Selasky 			   from UP to DOWN */
167*d6b92ffaSHans Petter Selasky 			if ((current_dir == UP) && (next_dir == DOWN)) {
168*d6b92ffaSHans Petter Selasky 				OSM_LOG(p_log, OSM_LOG_DEBUG,
169*d6b92ffaSHans Petter Selasky 					"Avoiding move from 0x%016" PRIx64
170*d6b92ffaSHans Petter Selasky 					" to 0x%016" PRIx64 "\n",
171*d6b92ffaSHans Petter Selasky 					cl_ntoh64(osm_node_get_node_guid(u->sw->p_node)),
172*d6b92ffaSHans Petter Selasky 					cl_ntoh64(osm_node_get_node_guid(p_remote_node)));
173*d6b92ffaSHans Petter Selasky 				/* Illegal step. If prune_weight is set, allow it with an
174*d6b92ffaSHans Petter Selasky 				 * additional weight
175*d6b92ffaSHans Petter Selasky 				 */
176*d6b92ffaSHans Petter Selasky 				if(prune_weight) {
177*d6b92ffaSHans Petter Selasky 					current_min_hop+=prune_weight;
178*d6b92ffaSHans Petter Selasky 					if(current_min_hop >= 64) {
179*d6b92ffaSHans Petter Selasky 						OSM_LOG(p_log, OSM_LOG_ERROR,
180*d6b92ffaSHans Petter Selasky 							"ERR AE02: Too many hops on subnet,"
181*d6b92ffaSHans Petter Selasky 							" can't relax illegal Dn/Up transition.");
182*d6b92ffaSHans Petter Selasky 						osm_switch_set_hops(p_remote_sw, lid,
183*d6b92ffaSHans Petter Selasky 								    pn_rem, OSM_NO_PATH);
184*d6b92ffaSHans Petter Selasky 					}
185*d6b92ffaSHans Petter Selasky 				} else {
186*d6b92ffaSHans Petter Selasky 					continue;
187*d6b92ffaSHans Petter Selasky 				}
188*d6b92ffaSHans Petter Selasky 			}
189*d6b92ffaSHans Petter Selasky 			if (current_min_hop + 1 < remote_min_hop) {
190*d6b92ffaSHans Petter Selasky 				set_hop_return_value =
191*d6b92ffaSHans Petter Selasky 				    osm_switch_set_hops(p_remote_sw, lid,
192*d6b92ffaSHans Petter Selasky 							pn_rem,
193*d6b92ffaSHans Petter Selasky 							current_min_hop + 1);
194*d6b92ffaSHans Petter Selasky 				if(max_hops && current_min_hop + 1 > *max_hops) {
195*d6b92ffaSHans Petter Selasky 					*max_hops = current_min_hop + 1;
196*d6b92ffaSHans Petter Selasky 				}
197*d6b92ffaSHans Petter Selasky 				if (set_hop_return_value) {
198*d6b92ffaSHans Petter Selasky 					OSM_LOG(p_log, OSM_LOG_ERROR, "ERR AE01: "
199*d6b92ffaSHans Petter Selasky 						"Invalid value returned from set min hop is: %d\n",
200*d6b92ffaSHans Petter Selasky 						set_hop_return_value);
201*d6b92ffaSHans Petter Selasky 				}
202*d6b92ffaSHans Petter Selasky 				/* Check if remote port has already been visited */
203*d6b92ffaSHans Petter Selasky 				if (!rem_u->visited) {
204*d6b92ffaSHans Petter Selasky 					/* Insert dnup_switch item into the list */
205*d6b92ffaSHans Petter Selasky 					rem_u->dir = next_dir;
206*d6b92ffaSHans Petter Selasky 					rem_u->visited = 1;
207*d6b92ffaSHans Petter Selasky 					cl_qlist_insert_tail(&list,
208*d6b92ffaSHans Petter Selasky 							     &rem_u->list);
209*d6b92ffaSHans Petter Selasky 				}
210*d6b92ffaSHans Petter Selasky 			}
211*d6b92ffaSHans Petter Selasky 		}
212*d6b92ffaSHans Petter Selasky 	}
213*d6b92ffaSHans Petter Selasky 
214*d6b92ffaSHans Petter Selasky 	OSM_LOG_EXIT(p_log);
215*d6b92ffaSHans Petter Selasky 	return 0;
216*d6b92ffaSHans Petter Selasky }
217*d6b92ffaSHans Petter Selasky 
218*d6b92ffaSHans Petter Selasky /* NOTE : PLS check if we need to decide that the first */
219*d6b92ffaSHans Petter Selasky /*        rank is a SWITCH for BFS purpose */
dnup_subn_rank(IN dnup_t * p_dnup)220*d6b92ffaSHans Petter Selasky static int dnup_subn_rank(IN dnup_t * p_dnup)
221*d6b92ffaSHans Petter Selasky {
222*d6b92ffaSHans Petter Selasky 	osm_switch_t *p_sw;
223*d6b92ffaSHans Petter Selasky 	osm_physp_t *p_physp, *p_remote_physp;
224*d6b92ffaSHans Petter Selasky 	cl_qlist_t list;
225*d6b92ffaSHans Petter Selasky 	cl_map_item_t *item;
226*d6b92ffaSHans Petter Selasky 	struct dnup_node *u, *remote_u;
227*d6b92ffaSHans Petter Selasky 	uint8_t num_ports, port_num;
228*d6b92ffaSHans Petter Selasky 	osm_log_t *p_log = &p_dnup->p_osm->log;
229*d6b92ffaSHans Petter Selasky 	unsigned max_rank = 0;
230*d6b92ffaSHans Petter Selasky 
231*d6b92ffaSHans Petter Selasky 	OSM_LOG_ENTER(p_log);
232*d6b92ffaSHans Petter Selasky 	cl_qlist_init(&list);
233*d6b92ffaSHans Petter Selasky 
234*d6b92ffaSHans Petter Selasky 	/* add all node level switches to the list */
235*d6b92ffaSHans Petter Selasky 	for (item = cl_qmap_head(&p_dnup->p_osm->subn.sw_guid_tbl);
236*d6b92ffaSHans Petter Selasky 	     item != cl_qmap_end(&p_dnup->p_osm->subn.sw_guid_tbl);
237*d6b92ffaSHans Petter Selasky 	     item = cl_qmap_next(item)) {
238*d6b92ffaSHans Petter Selasky 		p_sw = (osm_switch_t *)item;
239*d6b92ffaSHans Petter Selasky 		u = p_sw->priv;
240*d6b92ffaSHans Petter Selasky 		if (u->rank == 0)
241*d6b92ffaSHans Petter Selasky 			cl_qlist_insert_tail(&list, &u->list);
242*d6b92ffaSHans Petter Selasky 	}
243*d6b92ffaSHans Petter Selasky 
244*d6b92ffaSHans Petter Selasky 	/* BFS the list till it's empty */
245*d6b92ffaSHans Petter Selasky 	while (!cl_is_qlist_empty(&list)) {
246*d6b92ffaSHans Petter Selasky 		u = (struct dnup_node *)cl_qlist_remove_head(&list);
247*d6b92ffaSHans Petter Selasky 		/* Go over all remote nodes and rank them (if not already visited) */
248*d6b92ffaSHans Petter Selasky 		p_sw = u->sw;
249*d6b92ffaSHans Petter Selasky 		num_ports = p_sw->num_ports;
250*d6b92ffaSHans Petter Selasky 		OSM_LOG(p_log, OSM_LOG_DEBUG,
251*d6b92ffaSHans Petter Selasky 			"Handling switch GUID 0x%" PRIx64 "\n",
252*d6b92ffaSHans Petter Selasky 			cl_ntoh64(osm_node_get_node_guid(p_sw->p_node)));
253*d6b92ffaSHans Petter Selasky 		for (port_num = 1; port_num < num_ports; port_num++) {
254*d6b92ffaSHans Petter Selasky 			ib_net64_t port_guid;
255*d6b92ffaSHans Petter Selasky 
256*d6b92ffaSHans Petter Selasky 			/* Current port fetched in order to get remote side */
257*d6b92ffaSHans Petter Selasky 			p_physp =
258*d6b92ffaSHans Petter Selasky 			    osm_node_get_physp_ptr(p_sw->p_node, port_num);
259*d6b92ffaSHans Petter Selasky 
260*d6b92ffaSHans Petter Selasky 			if (!p_physp)
261*d6b92ffaSHans Petter Selasky 				continue;
262*d6b92ffaSHans Petter Selasky 
263*d6b92ffaSHans Petter Selasky 			p_remote_physp = p_physp->p_remote_physp;
264*d6b92ffaSHans Petter Selasky 
265*d6b92ffaSHans Petter Selasky 			/*
266*d6b92ffaSHans Petter Selasky 			   make sure that all the following occur on p_remote_physp:
267*d6b92ffaSHans Petter Selasky 			   1. The port isn't NULL
268*d6b92ffaSHans Petter Selasky 			   2. It is a switch
269*d6b92ffaSHans Petter Selasky 			 */
270*d6b92ffaSHans Petter Selasky 			if (p_remote_physp && p_remote_physp->p_node->sw) {
271*d6b92ffaSHans Petter Selasky 				remote_u = p_remote_physp->p_node->sw->priv;
272*d6b92ffaSHans Petter Selasky 				port_guid = p_remote_physp->port_guid;
273*d6b92ffaSHans Petter Selasky 
274*d6b92ffaSHans Petter Selasky 				if (remote_u->rank > u->rank + 1) {
275*d6b92ffaSHans Petter Selasky 					remote_u->rank = u->rank + 1;
276*d6b92ffaSHans Petter Selasky 					max_rank = remote_u->rank;
277*d6b92ffaSHans Petter Selasky 					cl_qlist_insert_tail(&list,
278*d6b92ffaSHans Petter Selasky 							     &remote_u->list);
279*d6b92ffaSHans Petter Selasky 					OSM_LOG(p_log, OSM_LOG_DEBUG,
280*d6b92ffaSHans Petter Selasky 						"Rank of port GUID 0x%" PRIx64
281*d6b92ffaSHans Petter Selasky 						" = %u\n", cl_ntoh64(port_guid),
282*d6b92ffaSHans Petter Selasky 						remote_u->rank);
283*d6b92ffaSHans Petter Selasky 				}
284*d6b92ffaSHans Petter Selasky 			}
285*d6b92ffaSHans Petter Selasky 		}
286*d6b92ffaSHans Petter Selasky 	}
287*d6b92ffaSHans Petter Selasky 
288*d6b92ffaSHans Petter Selasky 	/* Print Summary of ranking */
289*d6b92ffaSHans Petter Selasky 	OSM_LOG(p_log, OSM_LOG_VERBOSE,
290*d6b92ffaSHans Petter Selasky 		"Subnet ranking completed. Max Node Rank = %d\n", max_rank);
291*d6b92ffaSHans Petter Selasky 	OSM_LOG_EXIT(p_log);
292*d6b92ffaSHans Petter Selasky 	return 0;
293*d6b92ffaSHans Petter Selasky }
294*d6b92ffaSHans Petter Selasky 
dnup_set_min_hop_table(IN dnup_t * p_dnup)295*d6b92ffaSHans Petter Selasky static int dnup_set_min_hop_table(IN dnup_t * p_dnup)
296*d6b92ffaSHans Petter Selasky {
297*d6b92ffaSHans Petter Selasky 	osm_subn_t *p_subn = &p_dnup->p_osm->subn;
298*d6b92ffaSHans Petter Selasky 	osm_log_t *p_log = &p_dnup->p_osm->log;
299*d6b92ffaSHans Petter Selasky 	osm_switch_t *p_sw;
300*d6b92ffaSHans Petter Selasky 	struct dnup_node *u;
301*d6b92ffaSHans Petter Selasky 	cl_map_item_t *item;
302*d6b92ffaSHans Petter Selasky 	uint8_t max_hops = 0;
303*d6b92ffaSHans Petter Selasky 
304*d6b92ffaSHans Petter Selasky 	OSM_LOG_ENTER(p_log);
305*d6b92ffaSHans Petter Selasky 
306*d6b92ffaSHans Petter Selasky 	/* Go over all the switches in the subnet - for each init their Min Hop
307*d6b92ffaSHans Petter Selasky 	   Table */
308*d6b92ffaSHans Petter Selasky 	OSM_LOG(p_log, OSM_LOG_VERBOSE,
309*d6b92ffaSHans Petter Selasky 		"Init Min Hop Table of all switches [\n");
310*d6b92ffaSHans Petter Selasky 
311*d6b92ffaSHans Petter Selasky 	for (item = cl_qmap_head(&p_dnup->p_osm->subn.sw_guid_tbl);
312*d6b92ffaSHans Petter Selasky 	     item != cl_qmap_end(&p_dnup->p_osm->subn.sw_guid_tbl);
313*d6b92ffaSHans Petter Selasky 	     item = cl_qmap_next(item)) {
314*d6b92ffaSHans Petter Selasky 		p_sw = (osm_switch_t *)item;
315*d6b92ffaSHans Petter Selasky 		/* Clear Min Hop Table */
316*d6b92ffaSHans Petter Selasky 		osm_switch_clear_hops(p_sw);
317*d6b92ffaSHans Petter Selasky 	}
318*d6b92ffaSHans Petter Selasky 
319*d6b92ffaSHans Petter Selasky 	OSM_LOG(p_log, OSM_LOG_VERBOSE,
320*d6b92ffaSHans Petter Selasky 		"Init Min Hop Table of all switches ]\n");
321*d6b92ffaSHans Petter Selasky 
322*d6b92ffaSHans Petter Selasky 	/* Now do the BFS for each port  in the subnet */
323*d6b92ffaSHans Petter Selasky 	OSM_LOG(p_log, OSM_LOG_VERBOSE,
324*d6b92ffaSHans Petter Selasky 		"BFS through all port guids in the subnet [\n");
325*d6b92ffaSHans Petter Selasky 
326*d6b92ffaSHans Petter Selasky 	for (item = cl_qmap_head(&p_dnup->p_osm->subn.sw_guid_tbl);
327*d6b92ffaSHans Petter Selasky 	     item != cl_qmap_end(&p_dnup->p_osm->subn.sw_guid_tbl);
328*d6b92ffaSHans Petter Selasky 	     item = cl_qmap_next(item)) {
329*d6b92ffaSHans Petter Selasky 		p_sw = (osm_switch_t *)item;
330*d6b92ffaSHans Petter Selasky 		dnup_bfs_by_node(p_log, p_subn, p_sw, 0, &max_hops);
331*d6b92ffaSHans Petter Selasky 	}
332*d6b92ffaSHans Petter Selasky 	if(p_subn->opt.connect_roots) {
333*d6b92ffaSHans Petter Selasky 		/*This is probably not necessary, by I am more comfortable
334*d6b92ffaSHans Petter Selasky 		 * clearing any possible side effects from the previous
335*d6b92ffaSHans Petter Selasky 		 * dnup routing pass
336*d6b92ffaSHans Petter Selasky 		 */
337*d6b92ffaSHans Petter Selasky 		for (item = cl_qmap_head(&p_dnup->p_osm->subn.sw_guid_tbl);
338*d6b92ffaSHans Petter Selasky 		     item != cl_qmap_end(&p_dnup->p_osm->subn.sw_guid_tbl);
339*d6b92ffaSHans Petter Selasky 		     item = cl_qmap_next(item)) {
340*d6b92ffaSHans Petter Selasky 			p_sw = (osm_switch_t *)item;
341*d6b92ffaSHans Petter Selasky 			osm_switch_clear_hops(p_sw);
342*d6b92ffaSHans Petter Selasky 			u = (struct dnup_node *) p_sw->priv;
343*d6b92ffaSHans Petter Selasky 			u->visited = 0;
344*d6b92ffaSHans Petter Selasky 		}
345*d6b92ffaSHans Petter Selasky 		for (item = cl_qmap_head(&p_dnup->p_osm->subn.sw_guid_tbl);
346*d6b92ffaSHans Petter Selasky 		     item != cl_qmap_end(&p_dnup->p_osm->subn.sw_guid_tbl);
347*d6b92ffaSHans Petter Selasky 		     item = cl_qmap_next(item)) {
348*d6b92ffaSHans Petter Selasky 			p_sw = (osm_switch_t *)item;
349*d6b92ffaSHans Petter Selasky 			dnup_bfs_by_node(p_log, p_subn, p_sw, max_hops + 1, NULL);
350*d6b92ffaSHans Petter Selasky 		}
351*d6b92ffaSHans Petter Selasky 	}
352*d6b92ffaSHans Petter Selasky 
353*d6b92ffaSHans Petter Selasky 	OSM_LOG(p_log, OSM_LOG_VERBOSE,
354*d6b92ffaSHans Petter Selasky 		"BFS through all port guids in the subnet ]\n");
355*d6b92ffaSHans Petter Selasky 	/* Cleanup */
356*d6b92ffaSHans Petter Selasky 	OSM_LOG_EXIT(p_log);
357*d6b92ffaSHans Petter Selasky 	return 0;
358*d6b92ffaSHans Petter Selasky }
359*d6b92ffaSHans Petter Selasky 
dnup_build_lid_matrices(IN dnup_t * p_dnup)360*d6b92ffaSHans Petter Selasky static int dnup_build_lid_matrices(IN dnup_t * p_dnup)
361*d6b92ffaSHans Petter Selasky {
362*d6b92ffaSHans Petter Selasky 	int status;
363*d6b92ffaSHans Petter Selasky 
364*d6b92ffaSHans Petter Selasky 	OSM_LOG_ENTER(&p_dnup->p_osm->log);
365*d6b92ffaSHans Petter Selasky 
366*d6b92ffaSHans Petter Selasky 	OSM_LOG(&p_dnup->p_osm->log, OSM_LOG_VERBOSE,
367*d6b92ffaSHans Petter Selasky 		"Ranking all port guids in the list\n");
368*d6b92ffaSHans Petter Selasky 	/* Check if it's not a switched subnet */
369*d6b92ffaSHans Petter Selasky 	if (cl_is_qmap_empty(&p_dnup->p_osm->subn.sw_guid_tbl)) {
370*d6b92ffaSHans Petter Selasky 		OSM_LOG(&p_dnup->p_osm->log, OSM_LOG_ERROR, "ERR AEOB: "
371*d6b92ffaSHans Petter Selasky 			"This is not a switched subnet, cannot perform DNUP algorithm\n");
372*d6b92ffaSHans Petter Selasky 		status = -1;
373*d6b92ffaSHans Petter Selasky 		goto _exit;
374*d6b92ffaSHans Petter Selasky 	}
375*d6b92ffaSHans Petter Selasky 
376*d6b92ffaSHans Petter Selasky 	/* Rank the subnet switches */
377*d6b92ffaSHans Petter Selasky 	dnup_subn_rank(p_dnup);
378*d6b92ffaSHans Petter Selasky 
379*d6b92ffaSHans Petter Selasky 	/* After multiple ranking need to set Min Hop Table by DnUp algorithm  */
380*d6b92ffaSHans Petter Selasky 	OSM_LOG(&p_dnup->p_osm->log, OSM_LOG_VERBOSE,
381*d6b92ffaSHans Petter Selasky 		"Setting all switches' Min Hop Table\n");
382*d6b92ffaSHans Petter Selasky 	status = dnup_set_min_hop_table(p_dnup);
383*d6b92ffaSHans Petter Selasky 
384*d6b92ffaSHans Petter Selasky _exit:
385*d6b92ffaSHans Petter Selasky 	OSM_LOG_EXIT(&p_dnup->p_osm->log);
386*d6b92ffaSHans Petter Selasky 	return status;
387*d6b92ffaSHans Petter Selasky }
388*d6b92ffaSHans Petter Selasky 
create_dnup_node(osm_switch_t * sw)389*d6b92ffaSHans Petter Selasky static struct dnup_node *create_dnup_node(osm_switch_t * sw)
390*d6b92ffaSHans Petter Selasky {
391*d6b92ffaSHans Petter Selasky 	struct dnup_node *u;
392*d6b92ffaSHans Petter Selasky 
393*d6b92ffaSHans Petter Selasky 	u = malloc(sizeof(*u));
394*d6b92ffaSHans Petter Selasky 	if (!u)
395*d6b92ffaSHans Petter Selasky 		return NULL;
396*d6b92ffaSHans Petter Selasky 	memset(u, 0, sizeof(*u));
397*d6b92ffaSHans Petter Selasky 	u->sw = sw;
398*d6b92ffaSHans Petter Selasky 	u->rank = 0xffffffff;
399*d6b92ffaSHans Petter Selasky 	return u;
400*d6b92ffaSHans Petter Selasky }
401*d6b92ffaSHans Petter Selasky 
delete_dnup_node(struct dnup_node * u)402*d6b92ffaSHans Petter Selasky static void delete_dnup_node(struct dnup_node *u)
403*d6b92ffaSHans Petter Selasky {
404*d6b92ffaSHans Petter Selasky 	u->sw->priv = NULL;
405*d6b92ffaSHans Petter Selasky 	free(u);
406*d6b92ffaSHans Petter Selasky }
407*d6b92ffaSHans Petter Selasky 
408*d6b92ffaSHans Petter Selasky /* DNUP callback function */
dnup_lid_matrices(void * ctx)409*d6b92ffaSHans Petter Selasky static int dnup_lid_matrices(void *ctx)
410*d6b92ffaSHans Petter Selasky {
411*d6b92ffaSHans Petter Selasky 	dnup_t *p_dnup = ctx;
412*d6b92ffaSHans Petter Selasky 	cl_map_item_t *item;
413*d6b92ffaSHans Petter Selasky 	osm_switch_t *p_sw;
414*d6b92ffaSHans Petter Selasky 	int ret = 0;
415*d6b92ffaSHans Petter Selasky 	int num_leafs = 0;
416*d6b92ffaSHans Petter Selasky 	uint8_t pn, pn_rem;
417*d6b92ffaSHans Petter Selasky 
418*d6b92ffaSHans Petter Selasky 	OSM_LOG_ENTER(&p_dnup->p_osm->log);
419*d6b92ffaSHans Petter Selasky 
420*d6b92ffaSHans Petter Selasky 	for (item = cl_qmap_head(&p_dnup->p_osm->subn.sw_guid_tbl);
421*d6b92ffaSHans Petter Selasky 	     item != cl_qmap_end(&p_dnup->p_osm->subn.sw_guid_tbl);
422*d6b92ffaSHans Petter Selasky 	     item = cl_qmap_next(item)) {
423*d6b92ffaSHans Petter Selasky 		p_sw = (osm_switch_t *)item;
424*d6b92ffaSHans Petter Selasky 		p_sw->priv = create_dnup_node(p_sw);
425*d6b92ffaSHans Petter Selasky 		if (!p_sw->priv) {
426*d6b92ffaSHans Petter Selasky 			OSM_LOG(&(p_dnup->p_osm->log), OSM_LOG_ERROR, "ERR AE0C: "
427*d6b92ffaSHans Petter Selasky 				"cannot create dnup node\n");
428*d6b92ffaSHans Petter Selasky 			OSM_LOG_EXIT(&p_dnup->p_osm->log);
429*d6b92ffaSHans Petter Selasky 			return -1;
430*d6b92ffaSHans Petter Selasky 		}
431*d6b92ffaSHans Petter Selasky 	}
432*d6b92ffaSHans Petter Selasky 
433*d6b92ffaSHans Petter Selasky 
434*d6b92ffaSHans Petter Selasky 	/* First setup node level nodes */
435*d6b92ffaSHans Petter Selasky 	for (item = cl_qmap_head(&p_dnup->p_osm->subn.sw_guid_tbl);
436*d6b92ffaSHans Petter Selasky 	     item != cl_qmap_end(&p_dnup->p_osm->subn.sw_guid_tbl);
437*d6b92ffaSHans Petter Selasky 	     item = cl_qmap_next(item)) {
438*d6b92ffaSHans Petter Selasky 		p_sw = (osm_switch_t *)item;
439*d6b92ffaSHans Petter Selasky 
440*d6b92ffaSHans Petter Selasky 		for (pn = 0; pn < p_sw->num_ports; pn++) {
441*d6b92ffaSHans Petter Selasky 			osm_node_t *p_remote_node;
442*d6b92ffaSHans Petter Selasky 			p_remote_node = osm_node_get_remote_node(p_sw->p_node, pn, &pn_rem);
443*d6b92ffaSHans Petter Selasky 			if(p_remote_node && !p_remote_node->sw) {
444*d6b92ffaSHans Petter Selasky 				struct dnup_node *u = p_sw->priv;
445*d6b92ffaSHans Petter Selasky 				u->rank = 0;
446*d6b92ffaSHans Petter Selasky 				OSM_LOG(&(p_dnup->p_osm->log),
447*d6b92ffaSHans Petter Selasky 					OSM_LOG_VERBOSE, "(%s) rank 0 leaf switch\n",
448*d6b92ffaSHans Petter Selasky 					p_sw->p_node->print_desc);
449*d6b92ffaSHans Petter Selasky 				num_leafs++;
450*d6b92ffaSHans Petter Selasky 				break;
451*d6b92ffaSHans Petter Selasky 			}
452*d6b92ffaSHans Petter Selasky 		}
453*d6b92ffaSHans Petter Selasky 	}
454*d6b92ffaSHans Petter Selasky 
455*d6b92ffaSHans Petter Selasky 	if(num_leafs == 0) {
456*d6b92ffaSHans Petter Selasky 		OSM_LOG(&(p_dnup->p_osm->log),
457*d6b92ffaSHans Petter Selasky 			OSM_LOG_ERROR, "ERR AE0D: No leaf switches found, DnUp routing failed\n");
458*d6b92ffaSHans Petter Selasky 		OSM_LOG_EXIT(&p_dnup->p_osm->log);
459*d6b92ffaSHans Petter Selasky 		return -1;
460*d6b92ffaSHans Petter Selasky 	}
461*d6b92ffaSHans Petter Selasky 
462*d6b92ffaSHans Petter Selasky 	ret = dnup_build_lid_matrices(p_dnup);
463*d6b92ffaSHans Petter Selasky 
464*d6b92ffaSHans Petter Selasky 	for (item = cl_qmap_head(&p_dnup->p_osm->subn.sw_guid_tbl);
465*d6b92ffaSHans Petter Selasky 	     item != cl_qmap_end(&p_dnup->p_osm->subn.sw_guid_tbl);
466*d6b92ffaSHans Petter Selasky 	     item = cl_qmap_next(item)) {
467*d6b92ffaSHans Petter Selasky 		p_sw = (osm_switch_t *) item;
468*d6b92ffaSHans Petter Selasky 		delete_dnup_node(p_sw->priv);
469*d6b92ffaSHans Petter Selasky 	}
470*d6b92ffaSHans Petter Selasky 
471*d6b92ffaSHans Petter Selasky 	OSM_LOG_EXIT(&p_dnup->p_osm->log);
472*d6b92ffaSHans Petter Selasky 	return ret;
473*d6b92ffaSHans Petter Selasky }
474*d6b92ffaSHans Petter Selasky 
dnup_delete(void * context)475*d6b92ffaSHans Petter Selasky static void dnup_delete(void *context)
476*d6b92ffaSHans Petter Selasky {
477*d6b92ffaSHans Petter Selasky 	free(context);
478*d6b92ffaSHans Petter Selasky }
479*d6b92ffaSHans Petter Selasky 
osm_ucast_dnup_setup(struct osm_routing_engine * r,osm_opensm_t * osm)480*d6b92ffaSHans Petter Selasky int osm_ucast_dnup_setup(struct osm_routing_engine *r, osm_opensm_t *osm)
481*d6b92ffaSHans Petter Selasky {
482*d6b92ffaSHans Petter Selasky 	dnup_t *dnup;
483*d6b92ffaSHans Petter Selasky 
484*d6b92ffaSHans Petter Selasky 	OSM_LOG_ENTER(&osm->log);
485*d6b92ffaSHans Petter Selasky 
486*d6b92ffaSHans Petter Selasky 	dnup = malloc(sizeof(dnup_t));
487*d6b92ffaSHans Petter Selasky 	if (!dnup)
488*d6b92ffaSHans Petter Selasky 		return -1;
489*d6b92ffaSHans Petter Selasky 	memset(dnup, 0, sizeof(dnup_t));
490*d6b92ffaSHans Petter Selasky 
491*d6b92ffaSHans Petter Selasky 	dnup->p_osm = osm;
492*d6b92ffaSHans Petter Selasky 
493*d6b92ffaSHans Petter Selasky 	r->context = dnup;
494*d6b92ffaSHans Petter Selasky 	r->destroy = dnup_delete;
495*d6b92ffaSHans Petter Selasky 	r->build_lid_matrices = dnup_lid_matrices;
496*d6b92ffaSHans Petter Selasky 
497*d6b92ffaSHans Petter Selasky 	OSM_LOG_EXIT(&osm->log);
498*d6b92ffaSHans Petter Selasky 	return 0;
499*d6b92ffaSHans Petter Selasky }
500