1 /*
2  * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved.
3  * Copyright (c) 2002-2015 Mellanox Technologies LTD. All rights reserved.
4  * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
5  *
6  * This software is available to you under a choice of one of two
7  * licenses.  You may choose to be licensed under the terms of the GNU
8  * General Public License (GPL) Version 2, available from the file
9  * COPYING in the main directory of this source tree, or the
10  * OpenIB.org BSD license below:
11  *
12  *     Redistribution and use in source and binary forms, with or
13  *     without modification, are permitted provided that the following
14  *     conditions are met:
15  *
16  *      - Redistributions of source code must retain the above
17  *        copyright notice, this list of conditions and the following
18  *        disclaimer.
19  *
20  *      - Redistributions in binary form must reproduce the above
21  *        copyright notice, this list of conditions and the following
22  *        disclaimer in the documentation and/or other materials
23  *        provided with the distribution.
24  *
25  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32  * SOFTWARE.
33  *
34  */
35 
36 /*
37  * Abstract:
38  *    Implementation of osm_ucast_mgr_t.
39  * This file implements the Unicast Manager object.
40  */
41 
42 #if HAVE_CONFIG_H
43 #  include <config.h>
44 #endif				/* HAVE_CONFIG_H */
45 
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <ctype.h>
50 #include <iba/ib_types.h>
51 #include <complib/cl_qmap.h>
52 #include <complib/cl_debug.h>
53 #include <complib/cl_qlist.h>
54 #include <opensm/osm_file_ids.h>
55 #define FILE_ID OSM_FILE_UCAST_MGR_C
56 #include <opensm/osm_ucast_mgr.h>
57 #include <opensm/osm_sm.h>
58 #include <opensm/osm_log.h>
59 #include <opensm/osm_node.h>
60 #include <opensm/osm_switch.h>
61 #include <opensm/osm_helper.h>
62 #include <opensm/osm_msgdef.h>
63 #include <opensm/osm_opensm.h>
64 
osm_ucast_mgr_construct(IN osm_ucast_mgr_t * p_mgr)65 void osm_ucast_mgr_construct(IN osm_ucast_mgr_t * p_mgr)
66 {
67 	memset(p_mgr, 0, sizeof(*p_mgr));
68 }
69 
osm_ucast_mgr_destroy(IN osm_ucast_mgr_t * p_mgr)70 void osm_ucast_mgr_destroy(IN osm_ucast_mgr_t * p_mgr)
71 {
72 	CL_ASSERT(p_mgr);
73 
74 	OSM_LOG_ENTER(p_mgr->p_log);
75 
76 	if (p_mgr->cache_valid)
77 		osm_ucast_cache_invalidate(p_mgr);
78 
79 	OSM_LOG_EXIT(p_mgr->p_log);
80 }
81 
osm_ucast_mgr_init(IN osm_ucast_mgr_t * p_mgr,IN osm_sm_t * sm)82 ib_api_status_t osm_ucast_mgr_init(IN osm_ucast_mgr_t * p_mgr, IN osm_sm_t * sm)
83 {
84 	ib_api_status_t status = IB_SUCCESS;
85 
86 	OSM_LOG_ENTER(sm->p_log);
87 
88 	osm_ucast_mgr_construct(p_mgr);
89 
90 	p_mgr->sm = sm;
91 	p_mgr->p_log = sm->p_log;
92 	p_mgr->p_subn = sm->p_subn;
93 	p_mgr->p_lock = sm->p_lock;
94 
95 	if (sm->p_subn->opt.use_ucast_cache)
96 		cl_qmap_init(&p_mgr->cache_sw_tbl);
97 
98 	OSM_LOG_EXIT(p_mgr->p_log);
99 	return status;
100 }
101 
102 /**********************************************************************
103  Add each switch's own and neighbor LIDs to its LID matrix
104 **********************************************************************/
ucast_mgr_process_hop_0_1(IN cl_map_item_t * p_map_item,IN void * context)105 static void ucast_mgr_process_hop_0_1(IN cl_map_item_t * p_map_item,
106 				      IN void *context)
107 {
108 	osm_switch_t * p_sw = (osm_switch_t *) p_map_item;
109 	osm_node_t *p_remote_node;
110 	uint16_t lid, remote_lid;
111 	uint8_t i;
112 
113 	lid = cl_ntoh16(osm_node_get_base_lid(p_sw->p_node, 0));
114 	osm_switch_set_hops(p_sw, lid, 0, 0);
115 
116 	for (i = 1; i < p_sw->num_ports; i++) {
117 		osm_physp_t *p = osm_node_get_physp_ptr(p_sw->p_node, i);
118 		p_remote_node = (p && p->p_remote_physp) ?
119 		    p->p_remote_physp->p_node : NULL;
120 
121 		if (p_remote_node && p_remote_node->sw &&
122 		    p_remote_node != p_sw->p_node) {
123 			remote_lid = osm_node_get_base_lid(p_remote_node, 0);
124 			remote_lid = cl_ntoh16(remote_lid);
125 			osm_switch_set_hops(p_sw, remote_lid, i, p->hop_wf);
126 		}
127 	}
128 }
129 
ucast_mgr_process_neighbor(IN osm_ucast_mgr_t * p_mgr,IN osm_switch_t * p_this_sw,IN osm_switch_t * p_remote_sw,IN uint8_t port_num,IN uint8_t remote_port_num)130 static void ucast_mgr_process_neighbor(IN osm_ucast_mgr_t * p_mgr,
131 				       IN osm_switch_t * p_this_sw,
132 				       IN osm_switch_t * p_remote_sw,
133 				       IN uint8_t port_num,
134 				       IN uint8_t remote_port_num)
135 {
136 	osm_switch_t *p_sw;
137 	cl_map_item_t *item;
138 	uint16_t lid_ho;
139 	uint16_t hops;
140 	osm_physp_t *p;
141 
142 	OSM_LOG_ENTER(p_mgr->p_log);
143 
144 	OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
145 		"Node 0x%" PRIx64 ", remote node 0x%" PRIx64
146 		", port %u, remote port %u\n",
147 		cl_ntoh64(osm_node_get_node_guid(p_this_sw->p_node)),
148 		cl_ntoh64(osm_node_get_node_guid(p_remote_sw->p_node)),
149 		port_num, remote_port_num);
150 
151 	p = osm_node_get_physp_ptr(p_this_sw->p_node, port_num);
152 
153 	for (item = cl_qmap_head(&p_mgr->p_subn->sw_guid_tbl);
154 	     item != cl_qmap_end(&p_mgr->p_subn->sw_guid_tbl);
155 	     item = cl_qmap_next(item)) {
156 		p_sw = (osm_switch_t *) item;
157 		lid_ho = cl_ntoh16(osm_node_get_base_lid(p_sw->p_node, 0));
158 		hops = osm_switch_get_least_hops(p_remote_sw, lid_ho);
159 		if (hops == OSM_NO_PATH)
160 			continue;
161 		hops += p->hop_wf;
162 		if (hops <
163 		    osm_switch_get_hop_count(p_this_sw, lid_ho, port_num)) {
164 			if (osm_switch_set_hops
165 			    (p_this_sw, lid_ho, port_num, (uint8_t) hops) != 0)
166 				OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR, "ERR 3A03: "
167 					"cannot set hops for lid %u at switch 0x%"
168 					PRIx64 "\n", lid_ho,
169 					cl_ntoh64(osm_node_get_node_guid
170 						  (p_this_sw->p_node)));
171 			p_mgr->some_hop_count_set = TRUE;
172 		}
173 	}
174 
175 	OSM_LOG_EXIT(p_mgr->p_log);
176 }
177 
find_and_add_remote_sys(osm_switch_t * sw,uint8_t port,boolean_t dor,struct osm_remote_guids_count * r)178 static struct osm_remote_node *find_and_add_remote_sys(osm_switch_t * sw,
179 						       uint8_t port,
180 						       boolean_t dor, struct
181 						       osm_remote_guids_count
182 						       *r)
183 {
184 	unsigned i;
185 	osm_physp_t *p = osm_node_get_physp_ptr(sw->p_node, port);
186 	osm_node_t *node = p->p_remote_physp->p_node;
187 	uint8_t rem_port = osm_physp_get_port_num(p->p_remote_physp);
188 
189 	for (i = 0; i < r->count; i++)
190 		if (r->guids[i].node == node)
191 			if (!dor || (r->guids[i].port == rem_port))
192 				return &r->guids[i];
193 
194 	r->guids[i].node = node;
195 	r->guids[i].forwarded_to = 0;
196 	r->guids[i].port = rem_port;
197 	r->count++;
198 	return &r->guids[i];
199 }
200 
ucast_mgr_process_port(IN osm_ucast_mgr_t * p_mgr,IN osm_switch_t * p_sw,IN osm_port_t * p_port,IN unsigned lid_offset)201 static void ucast_mgr_process_port(IN osm_ucast_mgr_t * p_mgr,
202 				   IN osm_switch_t * p_sw,
203 				   IN osm_port_t * p_port,
204 				   IN unsigned lid_offset)
205 {
206 	uint16_t min_lid_ho;
207 	uint16_t max_lid_ho;
208 	uint16_t lid_ho;
209 	uint8_t port;
210 	boolean_t is_ignored_by_port_prof;
211 	ib_net64_t node_guid;
212 	unsigned start_from = 1;
213 
214 	OSM_LOG_ENTER(p_mgr->p_log);
215 
216 	osm_port_get_lid_range_ho(p_port, &min_lid_ho, &max_lid_ho);
217 
218 	/* If the lids are zero - then there was some problem with
219 	 * the initialization. Don't handle this port. */
220 	if (min_lid_ho == 0 || max_lid_ho == 0) {
221 		OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR, "ERR 3A04: "
222 			"Port 0x%" PRIx64 " (%s port %d) has LID 0. An "
223 			"initialization error occurred. Ignoring port\n",
224 			cl_ntoh64(osm_port_get_guid(p_port)),
225 			p_port->p_node->print_desc,
226 			p_port->p_physp->port_num);
227 		goto Exit;
228 	}
229 
230 	lid_ho = min_lid_ho + lid_offset;
231 
232 	if (lid_ho > max_lid_ho)
233 		goto Exit;
234 
235 	if (lid_offset && !p_mgr->is_dor)
236 		/* ignore potential overflow - it is handled in osm_switch.c */
237 		start_from =
238 		    osm_switch_get_port_by_lid(p_sw, lid_ho - 1, OSM_NEW_LFT) + 1;
239 
240 	OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
241 		"Processing port 0x%" PRIx64
242 		" (\'%s\' port %u), LID %u [%u,%u]\n",
243 		cl_ntoh64(osm_port_get_guid(p_port)),
244 		p_port->p_node->print_desc, p_port->p_physp->port_num, lid_ho,
245 		min_lid_ho, max_lid_ho);
246 
247 	/* TODO - This should be runtime error, not a CL_ASSERT() */
248 	CL_ASSERT(max_lid_ho <= IB_LID_UCAST_END_HO);
249 
250 	node_guid = osm_node_get_node_guid(p_sw->p_node);
251 
252 	/*
253 	   The lid matrix contains the number of hops to each
254 	   lid from each port.  From this information we determine
255 	   how best to distribute the LID range across the ports
256 	   that can reach those LIDs.
257 	 */
258 	port = osm_switch_recommend_path(p_sw, p_port, lid_ho, start_from,
259 					 p_mgr->p_subn->ignore_existing_lfts,
260 					 p_mgr->p_subn->opt.lmc,
261 					 p_mgr->is_dor,
262 					 p_mgr->p_subn->opt.port_shifting,
263 					 !lid_offset && p_port->use_scatter,
264 					 OSM_LFT);
265 
266 	if (port == OSM_NO_PATH) {
267 		/* do not try to overwrite the ppro of non existing port ... */
268 		is_ignored_by_port_prof = TRUE;
269 
270 		OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
271 			"No path to get to LID %u from switch 0x%" PRIx64 "\n",
272 			lid_ho, cl_ntoh64(node_guid));
273 	} else {
274 		osm_physp_t *p = osm_node_get_physp_ptr(p_sw->p_node, port);
275 		if (!p)
276 			goto Exit;
277 
278 		OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
279 			"Routing LID %u to port %u for switch 0x%" PRIx64 "\n",
280 			lid_ho, port, cl_ntoh64(node_guid));
281 
282 		/*
283 		   we would like to optionally ignore this port in equalization
284 		   as in the case of the Mellanox Anafa Internal PCI TCA port
285 		 */
286 		is_ignored_by_port_prof = p->is_prof_ignored;
287 
288 		/*
289 		   We also would ignore this route if the target lid is of
290 		   a switch and the port_profile_switch_node is not TRUE
291 		 */
292 		if (!p_mgr->p_subn->opt.port_profile_switch_nodes)
293 			is_ignored_by_port_prof |=
294 			    (osm_node_get_type(p_port->p_node) ==
295 			     IB_NODE_TYPE_SWITCH);
296 	}
297 
298 	/*
299 	   We have selected the port for this LID.
300 	   Write it to the forwarding tables.
301 	 */
302 	p_sw->new_lft[lid_ho] = port;
303 	if (!is_ignored_by_port_prof) {
304 		struct osm_remote_node *rem_node_used;
305 		osm_switch_count_path(p_sw, port);
306 		if (port > 0 && p_port->priv &&
307 		    (rem_node_used = find_and_add_remote_sys(p_sw, port,
308 							     p_mgr->is_dor,
309 							     p_port->priv)))
310 			rem_node_used->forwarded_to++;
311 	}
312 
313 Exit:
314 	OSM_LOG_EXIT(p_mgr->p_log);
315 }
316 
alloc_ports_priv(osm_ucast_mgr_t * mgr)317 static void alloc_ports_priv(osm_ucast_mgr_t * mgr)
318 {
319 	cl_qmap_t *port_tbl = &mgr->p_subn->port_guid_tbl;
320 	struct osm_remote_guids_count *r;
321 	osm_port_t *port;
322 	cl_map_item_t *item;
323 	unsigned lmc;
324 
325 	for (item = cl_qmap_head(port_tbl); item != cl_qmap_end(port_tbl);
326 	     item = cl_qmap_next(item)) {
327 		port = (osm_port_t *) item;
328 		lmc = ib_port_info_get_lmc(&port->p_physp->port_info);
329 		r = malloc(sizeof(*r) + sizeof(r->guids[0]) * (1 << lmc));
330 		if (!r) {
331 			OSM_LOG(mgr->p_log, OSM_LOG_ERROR, "ERR 3A09: "
332 				"cannot allocate memory to track remote"
333 				" systems for lmc > 0\n");
334 			port->priv = NULL;
335 			continue;
336 		}
337 		memset(r, 0, sizeof(*r) + sizeof(r->guids[0]) * (1 << lmc));
338 		port->priv = r;
339 	}
340 }
341 
free_ports_priv(osm_ucast_mgr_t * mgr)342 static void free_ports_priv(osm_ucast_mgr_t * mgr)
343 {
344 	cl_qmap_t *port_tbl = &mgr->p_subn->port_guid_tbl;
345 	osm_port_t *port;
346 	cl_map_item_t *item;
347 	for (item = cl_qmap_head(port_tbl); item != cl_qmap_end(port_tbl);
348 	     item = cl_qmap_next(item)) {
349 		port = (osm_port_t *) item;
350 		if (port->priv) {
351 			free(port->priv);
352 			port->priv = NULL;
353 		}
354 	}
355 }
356 
ucast_mgr_process_tbl(IN cl_map_item_t * p_map_item,IN void * context)357 static void ucast_mgr_process_tbl(IN cl_map_item_t * p_map_item,
358 				  IN void *context)
359 {
360 	osm_ucast_mgr_t *p_mgr = context;
361 	osm_switch_t * p_sw = (osm_switch_t *) p_map_item;
362 	unsigned i, lids_per_port;
363 
364 	OSM_LOG_ENTER(p_mgr->p_log);
365 
366 	CL_ASSERT(p_sw && p_sw->p_node);
367 
368 	OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
369 		"Processing switch 0x%" PRIx64 "\n",
370 		cl_ntoh64(osm_node_get_node_guid(p_sw->p_node)));
371 
372 	/* Initialize LIDs in buffer to invalid port number. */
373 	memset(p_sw->new_lft, OSM_NO_PATH, p_sw->max_lid_ho + 1);
374 
375 	alloc_ports_priv(p_mgr);
376 
377 	/*
378 	   Iterate through every port setting LID routes for each
379 	   port based on base LID and LMC value.
380 	 */
381 	lids_per_port = 1 << p_mgr->p_subn->opt.lmc;
382 	for (i = 0; i < lids_per_port; i++) {
383 		cl_qlist_t *list = &p_mgr->port_order_list;
384 		cl_list_item_t *item;
385 		for (item = cl_qlist_head(list); item != cl_qlist_end(list);
386 		     item = cl_qlist_next(item)) {
387 			osm_port_t *port = cl_item_obj(item, port, list_item);
388 			ucast_mgr_process_port(p_mgr, p_sw, port, i);
389 		}
390 	}
391 
392 	free_ports_priv(p_mgr);
393 
394 	OSM_LOG_EXIT(p_mgr->p_log);
395 }
396 
ucast_mgr_process_neighbors(IN cl_map_item_t * p_map_item,IN void * context)397 static void ucast_mgr_process_neighbors(IN cl_map_item_t * p_map_item,
398 					IN void *context)
399 {
400 	osm_switch_t * p_sw = (osm_switch_t *) p_map_item;
401 	osm_ucast_mgr_t * p_mgr = context;
402 	osm_node_t *p_node;
403 	osm_node_t *p_remote_node;
404 	uint32_t port_num;
405 	uint8_t remote_port_num;
406 	uint32_t num_ports;
407 	osm_physp_t *p_physp;
408 
409 	OSM_LOG_ENTER(p_mgr->p_log);
410 
411 	p_node = p_sw->p_node;
412 
413 	CL_ASSERT(p_node);
414 	CL_ASSERT(osm_node_get_type(p_node) == IB_NODE_TYPE_SWITCH);
415 
416 	OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
417 		"Processing switch with GUID 0x%" PRIx64 "\n",
418 		cl_ntoh64(osm_node_get_node_guid(p_node)));
419 
420 	num_ports = osm_node_get_num_physp(p_node);
421 
422 	/*
423 	   Start with port 1 to skip the switch's management port.
424 	 */
425 	for (port_num = 1; port_num < num_ports; port_num++) {
426 		p_remote_node = osm_node_get_remote_node(p_node,
427 							 (uint8_t) port_num,
428 							 &remote_port_num);
429 		if (p_remote_node && p_remote_node->sw
430 		    && (p_remote_node != p_node)) {
431 			/* make sure the link is healthy. If it is not - don't
432 			   propagate through it. */
433 			p_physp = osm_node_get_physp_ptr(p_node, port_num);
434 			if (!p_physp || !osm_link_is_healthy(p_physp))
435 				continue;
436 
437 			ucast_mgr_process_neighbor(p_mgr, p_sw,
438 						   p_remote_node->sw,
439 						   (uint8_t) port_num,
440 						   remote_port_num);
441 		}
442 	}
443 
444 	OSM_LOG_EXIT(p_mgr->p_log);
445 }
446 
set_hop_wf(void * ctx,uint64_t guid,char * p)447 static int set_hop_wf(void *ctx, uint64_t guid, char *p)
448 {
449 	osm_ucast_mgr_t *m = ctx;
450 	osm_node_t *node = osm_get_node_by_guid(m->p_subn, cl_hton64(guid));
451 	osm_physp_t *physp;
452 	unsigned port, hop_wf;
453 	char *e;
454 
455 	if (!node || !node->sw) {
456 		OSM_LOG(m->p_log, OSM_LOG_DEBUG,
457 			"switch with guid 0x%016" PRIx64 " is not found\n",
458 			guid);
459 		return 0;
460 	}
461 
462 	if (!p || !*p || !(port = strtoul(p, &e, 0)) || (p == e) ||
463 	    port >= node->sw->num_ports) {
464 		OSM_LOG(m->p_log, OSM_LOG_DEBUG,
465 			"bad port specified for guid 0x%016" PRIx64 "\n", guid);
466 		return 0;
467 	}
468 
469 	p = e + 1;
470 
471 	if (!*p || !(hop_wf = strtoul(p, &e, 0)) || p == e || hop_wf >= 0x100) {
472 		OSM_LOG(m->p_log, OSM_LOG_DEBUG,
473 			"bad hop weight factor specified for guid 0x%016" PRIx64
474 			"port %u\n", guid, port);
475 		return 0;
476 	}
477 
478 	physp = osm_node_get_physp_ptr(node, port);
479 	if (!physp)
480 		return 0;
481 
482 	physp->hop_wf = hop_wf;
483 
484 	return 0;
485 }
486 
set_default_hop_wf(cl_map_item_t * p_map_item,void * ctx)487 static void set_default_hop_wf(cl_map_item_t * p_map_item, void *ctx)
488 {
489 	osm_switch_t *sw = (osm_switch_t *) p_map_item;
490 	int i;
491 
492 	for (i = 1; i < sw->num_ports; i++) {
493 		osm_physp_t *p = osm_node_get_physp_ptr(sw->p_node, i);
494 		if (p)
495 			p->hop_wf = 1;
496 	}
497 }
498 
set_search_ordering_ports(void * ctx,uint64_t guid,char * p)499 static int set_search_ordering_ports(void *ctx, uint64_t guid, char *p)
500 {
501 	osm_subn_t *p_subn = ctx;
502 	osm_node_t *node = osm_get_node_by_guid(p_subn, cl_hton64(guid));
503 	osm_switch_t *sw;
504 	uint8_t *search_ordering_ports = NULL;
505 	uint8_t port;
506 	unsigned int *ports = NULL;
507 	const int bpw = sizeof(*ports)*8;
508 	int words;
509 	int i = 1; /* port 0 maps to port 0 */
510 
511 	if (!node || !(sw = node->sw)) {
512 		OSM_LOG(&p_subn->p_osm->log, OSM_LOG_VERBOSE,
513 			"switch with guid 0x%016" PRIx64 " is not found\n",
514 			guid);
515 		return 0;
516 	}
517 
518 	if (sw->search_ordering_ports) {
519 		OSM_LOG(&p_subn->p_osm->log, OSM_LOG_VERBOSE,
520 			"switch with guid 0x%016" PRIx64 " already listed\n",
521 			guid);
522 		return 0;
523 	}
524 
525 	search_ordering_ports = malloc(sizeof(*search_ordering_ports)*sw->num_ports);
526 	if (!search_ordering_ports) {
527 		OSM_LOG(&p_subn->p_osm->log, OSM_LOG_ERROR,
528 			"ERR 3A07: cannot allocate memory for search_ordering_ports\n");
529 		return -1;
530 	}
531 	memset(search_ordering_ports, 0, sizeof(*search_ordering_ports)*sw->num_ports);
532 
533 	/* the ports array is for record keeping of which ports have
534 	 * been seen */
535 	words = (sw->num_ports + bpw - 1)/bpw;
536 	ports = malloc(words*sizeof(*ports));
537 	if (!ports) {
538 		OSM_LOG(&p_subn->p_osm->log, OSM_LOG_ERROR,
539 			"ERR 3A08: cannot allocate memory for ports\n");
540 		free(search_ordering_ports);
541 		return -1;
542 	}
543 	memset(ports, 0, words*sizeof(*ports));
544 
545 	while ((*p != '\0') && (*p != '#')) {
546 		char *e;
547 
548 		port = strtoul(p, &e, 0);
549 		if ((p == e) || (port == 0) || (port >= sw->num_ports) ||
550 		    !osm_node_get_physp_ptr(node, port)) {
551 			OSM_LOG(&p_subn->p_osm->log, OSM_LOG_VERBOSE,
552 				"bad port %d specified for guid 0x%016" PRIx64 "\n",
553 				port, guid);
554 			free(search_ordering_ports);
555 			free(ports);
556 			return 0;
557 		}
558 
559 		if (ports[port/bpw] & (1u << (port%bpw))) {
560 			OSM_LOG(&p_subn->p_osm->log, OSM_LOG_VERBOSE,
561 				"port %d already specified for guid 0x%016" PRIx64 "\n",
562 				port, guid);
563 			free(search_ordering_ports);
564 			free(ports);
565 			return 0;
566 		}
567 
568 		ports[port/bpw] |= (1u << (port%bpw));
569 		search_ordering_ports[i++] = port;
570 
571 		p = e;
572 		while (isspace(*p)) {
573 			p++;
574 		}
575 	}
576 
577 	if (i > 1) {
578 		for (port = 1; port < sw->num_ports; port++) {
579 			/* fill out the rest of the search_ordering_ports array
580 			 * in sequence using the remaining unspecified
581 			 * ports.
582 			 */
583 			if (!(ports[port/bpw] & (1u << (port%bpw)))) {
584 				search_ordering_ports[i++] = port;
585 			}
586 		}
587 		sw->search_ordering_ports = search_ordering_ports;
588 	} else {
589 		free(search_ordering_ports);
590 	}
591 
592 	free(ports);
593 	return 0;
594 }
595 
osm_ucast_mgr_build_lid_matrices(IN osm_ucast_mgr_t * p_mgr)596 int osm_ucast_mgr_build_lid_matrices(IN osm_ucast_mgr_t * p_mgr)
597 {
598 	uint32_t i;
599 	uint32_t iteration_max;
600 	cl_qmap_t *p_sw_guid_tbl;
601 
602 	p_sw_guid_tbl = &p_mgr->p_subn->sw_guid_tbl;
603 
604 	OSM_LOG(p_mgr->p_log, OSM_LOG_VERBOSE,
605 		"Starting switches' Min Hop Table Assignment\n");
606 
607 	/*
608 	   Set up the weighting factors for the routing.
609 	 */
610 	cl_qmap_apply_func(p_sw_guid_tbl, set_default_hop_wf, NULL);
611 	if (p_mgr->p_subn->opt.hop_weights_file) {
612 		OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
613 			"Fetching hop weight factor file \'%s\'\n",
614 			p_mgr->p_subn->opt.hop_weights_file);
615 		if (parse_node_map(p_mgr->p_subn->opt.hop_weights_file,
616 				   set_hop_wf, p_mgr)) {
617 			OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR, "ERR 3A05: "
618 				"cannot parse hop_weights_file \'%s\'\n",
619 				p_mgr->p_subn->opt.hop_weights_file);
620 		}
621 	}
622 
623 	/*
624 	   Set the switch matrices for each switch's own port 0 LID(s)
625 	   then set the lid matrices for the each switch's leaf nodes.
626 	 */
627 	cl_qmap_apply_func(p_sw_guid_tbl, ucast_mgr_process_hop_0_1, p_mgr);
628 
629 	/*
630 	   Get the switch matrices for each switch's neighbors.
631 	   This process requires a number of iterations equal to
632 	   the number of switches in the subnet minus 1.
633 
634 	   In each iteration, a switch learns the lid/port/hop
635 	   information (as contained by a switch's lid matrix) from
636 	   its immediate neighbors.  After each iteration, a switch
637 	   (and it's neighbors) know more routing information than
638 	   it did on the previous iteration.
639 	   Thus, by repeatedly absorbing the routing information of
640 	   neighbor switches, every switch eventually learns how to
641 	   route all LIDs on the subnet.
642 
643 	   Note that there may not be any switches in the subnet if
644 	   we are in simple p2p configuration.
645 	 */
646 	iteration_max = cl_qmap_count(p_sw_guid_tbl);
647 
648 	/*
649 	   If there are switches in the subnet, iterate until the lid
650 	   matrix has been constructed.  Otherwise, just immediately
651 	   indicate we're done if no switches exist.
652 	 */
653 	if (iteration_max) {
654 		iteration_max--;
655 
656 		/*
657 		   we need to find out when the propagation of
658 		   hop counts has relaxed. So this global variable
659 		   is preset to 0 on each iteration and if
660 		   if non of the switches was set will exit the
661 		   while loop
662 		 */
663 		p_mgr->some_hop_count_set = TRUE;
664 		for (i = 0; (i < iteration_max) && p_mgr->some_hop_count_set;
665 		     i++) {
666 			p_mgr->some_hop_count_set = FALSE;
667 			cl_qmap_apply_func(p_sw_guid_tbl,
668 					   ucast_mgr_process_neighbors, p_mgr);
669 		}
670 		OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
671 			"Min-hop propagated in %d steps\n", i);
672 	}
673 
674 	return 0;
675 }
676 
ucast_mgr_setup_all_switches(osm_subn_t * p_subn)677 static int ucast_mgr_setup_all_switches(osm_subn_t * p_subn)
678 {
679 	osm_switch_t *p_sw;
680 	uint16_t lids;
681 
682 	lids = (uint16_t) cl_ptr_vector_get_size(&p_subn->port_lid_tbl);
683 	lids = lids ? lids - 1 : 0;
684 
685 	for (p_sw = (osm_switch_t *) cl_qmap_head(&p_subn->sw_guid_tbl);
686 	     p_sw != (osm_switch_t *) cl_qmap_end(&p_subn->sw_guid_tbl);
687 	     p_sw = (osm_switch_t *) cl_qmap_next(&p_sw->map_item)) {
688 		if (osm_switch_prepare_path_rebuild(p_sw, lids)) {
689 			OSM_LOG(&p_subn->p_osm->log, OSM_LOG_ERROR, "ERR 3A0B: "
690 				"cannot setup switch 0x%016" PRIx64 "\n",
691 				cl_ntoh64(osm_node_get_node_guid
692 					  (p_sw->p_node)));
693 			return -1;
694 		}
695 		if (p_sw->search_ordering_ports) {
696 			free(p_sw->search_ordering_ports);
697 			p_sw->search_ordering_ports = NULL;
698 		}
699 	}
700 
701 	if (p_subn->opt.port_search_ordering_file) {
702 		OSM_LOG(&p_subn->p_osm->log, OSM_LOG_DEBUG,
703 			"Fetching dimension ports file \'%s\'\n",
704 			p_subn->opt.port_search_ordering_file);
705 		if (parse_node_map(p_subn->opt.port_search_ordering_file,
706 				   set_search_ordering_ports, p_subn)) {
707 			OSM_LOG(&p_subn->p_osm->log, OSM_LOG_ERROR, "ERR 3A0F: "
708 				"cannot parse port_search_ordering_file \'%s\'\n",
709 				p_subn->opt.port_search_ordering_file);
710 		}
711 	}
712 
713 	return 0;
714 }
715 
add_guid_to_order_list(void * ctx,uint64_t guid,char * p)716 static int add_guid_to_order_list(void *ctx, uint64_t guid, char *p)
717 {
718 	osm_ucast_mgr_t *m = ctx;
719 	osm_port_t *port = osm_get_port_by_guid(m->p_subn, cl_hton64(guid));
720 
721 	if (!port) {
722 		OSM_LOG(m->p_log, OSM_LOG_DEBUG,
723 			"port guid not found: 0x%016" PRIx64 "\n", guid);
724 		return 0;
725 	}
726 
727 	if (port->flag) {
728 		OSM_LOG(m->p_log, OSM_LOG_DEBUG,
729 			"port guid specified multiple times 0x%016" PRIx64 "\n",
730 			guid);
731 		return 0;
732 	}
733 
734 	cl_qlist_insert_tail(&m->port_order_list, &port->list_item);
735 	port->flag = 1;
736 	port->use_scatter =  (m->p_subn->opt.guid_routing_order_no_scatter == TRUE) ? 0 : m->p_subn->opt.scatter_ports;
737 
738 	return 0;
739 }
740 
add_port_to_order_list(cl_map_item_t * p_map_item,void * ctx)741 static void add_port_to_order_list(cl_map_item_t * p_map_item, void *ctx)
742 {
743 	osm_port_t *port = (osm_port_t *) p_map_item;
744 	osm_ucast_mgr_t *m = ctx;
745 
746 	if (!port->flag) {
747 		port->use_scatter = m->p_subn->opt.scatter_ports;
748 		cl_qlist_insert_tail(&m->port_order_list, &port->list_item);
749 	} else
750 		port->flag = 0;
751 }
752 
mark_ignored_port(void * ctx,uint64_t guid,char * p)753 static int mark_ignored_port(void *ctx, uint64_t guid, char *p)
754 {
755 	osm_ucast_mgr_t *m = ctx;
756 	osm_node_t *node = osm_get_node_by_guid(m->p_subn, cl_hton64(guid));
757 	osm_physp_t *physp;
758 	unsigned port;
759 
760 	if (!node || !node->sw) {
761 		OSM_LOG(m->p_log, OSM_LOG_DEBUG,
762 			"switch with guid 0x%016" PRIx64 " is not found\n",
763 			guid);
764 		return 0;
765 	}
766 
767 	if (!p || !*p || !(port = strtoul(p, NULL, 0)) ||
768 	    port >= node->sw->num_ports) {
769 		OSM_LOG(m->p_log, OSM_LOG_DEBUG,
770 			"bad port specified for guid 0x%016" PRIx64 "\n", guid);
771 		return 0;
772 	}
773 
774 	physp = osm_node_get_physp_ptr(node, port);
775 	if (!physp)
776 		return 0;
777 
778 	physp->is_prof_ignored = 1;
779 
780 	return 0;
781 }
782 
clear_prof_ignore_flag(cl_map_item_t * p_map_item,void * ctx)783 static void clear_prof_ignore_flag(cl_map_item_t * p_map_item, void *ctx)
784 {
785 	osm_switch_t *sw = (osm_switch_t *) p_map_item;
786 	int i;
787 
788 	for (i = 1; i < sw->num_ports; i++) {
789 		osm_physp_t *p = osm_node_get_physp_ptr(sw->p_node, i);
790 		if (p)
791 			p->is_prof_ignored = 0;
792 	}
793 }
794 
add_sw_endports_to_order_list(osm_switch_t * sw,osm_ucast_mgr_t * m)795 static void add_sw_endports_to_order_list(osm_switch_t * sw,
796 					  osm_ucast_mgr_t * m)
797 {
798 	osm_port_t *port;
799 	osm_physp_t *p;
800 	int i;
801 
802 	for (i = 1; i < sw->num_ports; i++) {
803 		p = osm_node_get_physp_ptr(sw->p_node, i);
804 		if (p && p->p_remote_physp && !p->p_remote_physp->p_node->sw) {
805 			port = osm_get_port_by_guid(m->p_subn,
806 						    p->p_remote_physp->
807 						    port_guid);
808 			if (!port || port->flag)
809 				continue;
810 			cl_qlist_insert_tail(&m->port_order_list,
811 					     &port->list_item);
812 			port->flag = 1;
813 			port->use_scatter = m->p_subn->opt.scatter_ports;
814 		}
815 	}
816 }
817 
sw_count_endport_links(osm_switch_t * sw)818 static void sw_count_endport_links(osm_switch_t * sw)
819 {
820 	osm_physp_t *p;
821 	int i;
822 
823 	sw->endport_links = 0;
824 	for (i = 1; i < sw->num_ports; i++) {
825 		p = osm_node_get_physp_ptr(sw->p_node, i);
826 		if (p && p->p_remote_physp && !p->p_remote_physp->p_node->sw)
827 			sw->endport_links++;
828 	}
829 }
830 
compar_sw_load(const void * s1,const void * s2)831 static int compar_sw_load(const void *s1, const void *s2)
832 {
833 #define get_sw_endport_links(s) (*(osm_switch_t **)s)->endport_links
834 	return get_sw_endport_links(s2) - get_sw_endport_links(s1);
835 }
836 
sort_ports_by_switch_load(osm_ucast_mgr_t * m)837 static void sort_ports_by_switch_load(osm_ucast_mgr_t * m)
838 {
839 	int i, num = cl_qmap_count(&m->p_subn->sw_guid_tbl);
840 	void **s = malloc(num * sizeof(*s));
841 	if (!s) {
842 		OSM_LOG(m->p_log, OSM_LOG_ERROR, "ERR 3A0C: "
843 			"No memory, skip by switch load sorting.\n");
844 		return;
845 	}
846 	s[0] = cl_qmap_head(&m->p_subn->sw_guid_tbl);
847 	for (i = 1; i < num; i++)
848 		s[i] = cl_qmap_next(s[i - 1]);
849 
850 	for (i = 0; i < num; i++)
851 		sw_count_endport_links(s[i]);
852 
853 	qsort(s, num, sizeof(*s), compar_sw_load);
854 
855 	for (i = 0; i < num; i++)
856 		add_sw_endports_to_order_list(s[i], m);
857 	free(s);
858 }
859 
ucast_mgr_build_lfts(osm_ucast_mgr_t * p_mgr)860 static int ucast_mgr_build_lfts(osm_ucast_mgr_t * p_mgr)
861 {
862 	cl_qlist_init(&p_mgr->port_order_list);
863 
864 	if (p_mgr->p_subn->opt.guid_routing_order_file) {
865 		OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
866 			"Fetching guid routing order file \'%s\'\n",
867 			p_mgr->p_subn->opt.guid_routing_order_file);
868 
869 		if (parse_node_map(p_mgr->p_subn->opt.guid_routing_order_file,
870 				   add_guid_to_order_list, p_mgr))
871 			OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR, "ERR 3A0D: "
872 				"cannot parse guid routing order file \'%s\'\n",
873 				p_mgr->p_subn->opt.guid_routing_order_file);
874 	}
875 	sort_ports_by_switch_load(p_mgr);
876 
877 	if (p_mgr->p_subn->opt.port_prof_ignore_file) {
878 		cl_qmap_apply_func(&p_mgr->p_subn->sw_guid_tbl,
879 				   clear_prof_ignore_flag, NULL);
880 		if (parse_node_map(p_mgr->p_subn->opt.port_prof_ignore_file,
881 				   mark_ignored_port, p_mgr)) {
882 			OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR, "ERR 3A0E: "
883 				"cannot parse port prof ignore file \'%s\'\n",
884 				p_mgr->p_subn->opt.port_prof_ignore_file);
885 		}
886 	}
887 
888 	cl_qmap_apply_func(&p_mgr->p_subn->port_guid_tbl,
889 			   add_port_to_order_list, p_mgr);
890 
891 	cl_qmap_apply_func(&p_mgr->p_subn->sw_guid_tbl, ucast_mgr_process_tbl,
892 			   p_mgr);
893 
894 	cl_qlist_remove_all(&p_mgr->port_order_list);
895 
896 	return 0;
897 }
898 
ucast_mgr_set_fwd_top(IN cl_map_item_t * p_map_item,IN void * cxt)899 static void ucast_mgr_set_fwd_top(IN cl_map_item_t * p_map_item,
900 				  IN void *cxt)
901 {
902 	osm_ucast_mgr_t *p_mgr = cxt;
903 	osm_switch_t * p_sw = (osm_switch_t *) p_map_item;
904 	osm_node_t *p_node;
905 	osm_physp_t *p_physp;
906 	osm_dr_path_t *p_path;
907 	osm_madw_context_t context;
908 	ib_api_status_t status;
909 	ib_switch_info_t si;
910 	boolean_t set_swinfo_require = FALSE;
911 	uint16_t lin_top;
912 	uint8_t life_state;
913 
914 	CL_ASSERT(p_mgr);
915 
916 	OSM_LOG_ENTER(p_mgr->p_log);
917 
918 	CL_ASSERT(p_sw && p_sw->max_lid_ho);
919 
920 	p_node = p_sw->p_node;
921 
922 	CL_ASSERT(p_node);
923 
924 	if (p_mgr->max_lid < p_sw->max_lid_ho)
925 		p_mgr->max_lid = p_sw->max_lid_ho;
926 
927 	p_physp = osm_node_get_physp_ptr(p_node, 0);
928 
929 	CL_ASSERT(p_physp);
930 
931 	p_path = osm_physp_get_dr_path_ptr(p_physp);
932 
933 	/*
934 	   Set the top of the unicast forwarding table.
935 	 */
936 	si = p_sw->switch_info;
937 	lin_top = cl_hton16(p_sw->max_lid_ho);
938 	if (lin_top != si.lin_top) {
939 		set_swinfo_require = TRUE;
940 		si.lin_top = lin_top;
941 		context.si_context.lft_top_change = TRUE;
942 	} else
943 		context.si_context.lft_top_change = FALSE;
944 
945 	life_state = si.life_state;
946 	ib_switch_info_set_life_time(&si, p_mgr->p_subn->opt.packet_life_time);
947 
948 	if (life_state != si.life_state)
949 		set_swinfo_require = TRUE;
950 
951 	if (set_swinfo_require) {
952 		OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
953 			"Setting switch FT top to LID %u\n", p_sw->max_lid_ho);
954 
955 		context.si_context.light_sweep = FALSE;
956 		context.si_context.node_guid = osm_node_get_node_guid(p_node);
957 		context.si_context.set_method = TRUE;
958 
959 		status = osm_req_set(p_mgr->sm, p_path, (uint8_t *) & si,
960 				     sizeof(si), IB_MAD_ATTR_SWITCH_INFO,
961 				     0, FALSE,
962 				     ib_port_info_get_m_key(&p_physp->port_info),
963 				     CL_DISP_MSGID_NONE, &context);
964 
965 		if (status != IB_SUCCESS)
966 			OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR, "ERR 3A06: "
967 				"Sending SwitchInfo attribute failed (%s)\n",
968 				ib_get_err_str(status));
969 	}
970 
971 	OSM_LOG_EXIT(p_mgr->p_log);
972 }
973 
set_lft_block(IN osm_switch_t * p_sw,IN osm_ucast_mgr_t * p_mgr,IN uint16_t block_id_ho)974 static int set_lft_block(IN osm_switch_t *p_sw, IN osm_ucast_mgr_t *p_mgr,
975 			 IN uint16_t block_id_ho)
976 {
977 	osm_madw_context_t context;
978 	osm_dr_path_t *p_path;
979 	osm_physp_t *p_physp;
980 	ib_api_status_t status;
981 
982 	/*
983 	   Send linear forwarding table blocks to the switch
984 	   as long as the switch indicates it has blocks needing
985 	   configuration.
986 	 */
987 	if (!p_sw->new_lft) {
988 		/* any routing should provide the new_lft */
989 		CL_ASSERT(p_mgr->p_subn->opt.use_ucast_cache &&
990 			  p_mgr->cache_valid && !p_sw->need_update);
991 		return -1;
992 	}
993 
994 	p_physp = osm_node_get_physp_ptr(p_sw->p_node, 0);
995 	if (!p_physp)
996 		return -1;
997 
998 	p_path = osm_physp_get_dr_path_ptr(p_physp);
999 
1000 	context.lft_context.node_guid = osm_node_get_node_guid(p_sw->p_node);
1001 	context.lft_context.set_method = TRUE;
1002 
1003 	if (!p_sw->need_update && !p_mgr->p_subn->need_update &&
1004 	    !memcmp(p_sw->new_lft + block_id_ho * IB_SMP_DATA_SIZE,
1005 		    p_sw->lft + block_id_ho * IB_SMP_DATA_SIZE,
1006 		    IB_SMP_DATA_SIZE))
1007 		return 0;
1008 
1009 	/*
1010 	 * Zero the stored LFT block, so in case the MAD will end up
1011 	 * with error, we will resend it in the next sweep.
1012 	 */
1013 	memset(p_sw->lft + block_id_ho * IB_SMP_DATA_SIZE, 0,
1014 	       IB_SMP_DATA_SIZE);
1015 
1016 	OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
1017 		"Writing FT block %u to switch 0x%" PRIx64 "\n", block_id_ho,
1018 		cl_ntoh64(context.lft_context.node_guid));
1019 
1020 	status = osm_req_set(p_mgr->sm, p_path,
1021 			     p_sw->new_lft + block_id_ho * IB_SMP_DATA_SIZE,
1022 			     IB_SMP_DATA_SIZE, IB_MAD_ATTR_LIN_FWD_TBL,
1023 			     cl_hton32(block_id_ho), FALSE,
1024 			     ib_port_info_get_m_key(&p_physp->port_info),
1025 			     CL_DISP_MSGID_NONE, &context);
1026 
1027 	if (status != IB_SUCCESS) {
1028 		OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR, "ERR 3A10: "
1029 			"Sending linear fwd. tbl. block failed (%s)\n",
1030 			ib_get_err_str(status));
1031 		return -1;
1032 	}
1033 
1034 	return 0;
1035 }
1036 
ucast_mgr_pipeline_fwd_tbl(osm_ucast_mgr_t * p_mgr)1037 static void ucast_mgr_pipeline_fwd_tbl(osm_ucast_mgr_t * p_mgr)
1038 {
1039 	cl_qmap_t *tbl;
1040 	cl_map_item_t *item;
1041 	unsigned i, max_block = p_mgr->max_lid / IB_SMP_DATA_SIZE + 1;
1042 
1043 	tbl = &p_mgr->p_subn->sw_guid_tbl;
1044 	for (i = 0; i < max_block; i++)
1045 		for (item = cl_qmap_head(tbl); item != cl_qmap_end(tbl);
1046 		     item = cl_qmap_next(item))
1047 			set_lft_block((osm_switch_t *)item, p_mgr, i);
1048 }
1049 
osm_ucast_mgr_set_fwd_tables(osm_ucast_mgr_t * p_mgr)1050 void osm_ucast_mgr_set_fwd_tables(osm_ucast_mgr_t * p_mgr)
1051 {
1052 	p_mgr->max_lid = 0;
1053 
1054 	cl_qmap_apply_func(&p_mgr->p_subn->sw_guid_tbl, ucast_mgr_set_fwd_top,
1055 			   p_mgr);
1056 
1057 	ucast_mgr_pipeline_fwd_tbl(p_mgr);
1058 }
1059 
ucast_mgr_route(struct osm_routing_engine * r,osm_opensm_t * osm)1060 static int ucast_mgr_route(struct osm_routing_engine *r, osm_opensm_t * osm)
1061 {
1062 	int ret;
1063 
1064 	OSM_LOG(&osm->log, OSM_LOG_VERBOSE,
1065 		"building routing with \'%s\' routing algorithm...\n", r->name);
1066 
1067 	/* Set the before each lft build to keep the routes in place between sweeps */
1068 	if (osm->subn.opt.scatter_ports)
1069 		srandom(osm->subn.opt.scatter_ports);
1070 
1071 	if (!r->build_lid_matrices ||
1072 	    (ret = r->build_lid_matrices(r->context)) > 0)
1073 		ret = osm_ucast_mgr_build_lid_matrices(&osm->sm.ucast_mgr);
1074 
1075 	if (ret < 0) {
1076 		OSM_LOG(&osm->log, OSM_LOG_ERROR,
1077 			"%s: cannot build lid matrices\n", r->name);
1078 		return ret;
1079 	}
1080 
1081 	if (!r->ucast_build_fwd_tables ||
1082 	    (ret = r->ucast_build_fwd_tables(r->context)) > 0)
1083 		ret = ucast_mgr_build_lfts(&osm->sm.ucast_mgr);
1084 
1085 	if (ret < 0) {
1086 		OSM_LOG(&osm->log, OSM_LOG_ERROR,
1087 			"%s: cannot build fwd tables\n", r->name);
1088 		return ret;
1089 	}
1090 
1091 	osm->routing_engine_used = r;
1092 
1093 	osm_ucast_mgr_set_fwd_tables(&osm->sm.ucast_mgr);
1094 
1095 	return 0;
1096 }
1097 
osm_ucast_mgr_process(IN osm_ucast_mgr_t * p_mgr)1098 int osm_ucast_mgr_process(IN osm_ucast_mgr_t * p_mgr)
1099 {
1100 	osm_opensm_t *p_osm;
1101 	struct osm_routing_engine *p_routing_eng;
1102 	cl_qmap_t *p_sw_guid_tbl;
1103 	int failed = 0;
1104 
1105 	OSM_LOG_ENTER(p_mgr->p_log);
1106 
1107 	p_sw_guid_tbl = &p_mgr->p_subn->sw_guid_tbl;
1108 	p_osm = p_mgr->p_subn->p_osm;
1109 	p_routing_eng = p_osm->routing_engine_list;
1110 
1111 	CL_PLOCK_EXCL_ACQUIRE(p_mgr->p_lock);
1112 
1113 	/*
1114 	   If there are no switches in the subnet, we are done.
1115 	 */
1116 	if (cl_qmap_count(p_sw_guid_tbl) == 0 ||
1117 	    ucast_mgr_setup_all_switches(p_mgr->p_subn) < 0)
1118 		goto Exit;
1119 
1120 	failed = -1;
1121 	p_osm->routing_engine_used = NULL;
1122 	while (p_routing_eng) {
1123 		failed = ucast_mgr_route(p_routing_eng, p_osm);
1124 		if (!failed)
1125 			break;
1126 		p_routing_eng = p_routing_eng->next;
1127 	}
1128 
1129 	if (!p_osm->routing_engine_used &&
1130 	    p_osm->no_fallback_routing_engine != TRUE) {
1131 		/* If configured routing algorithm failed, use default MinHop */
1132 		failed = ucast_mgr_route(p_osm->default_routing_engine, p_osm);
1133 	}
1134 
1135 	if (p_osm->routing_engine_used) {
1136 		OSM_LOG(p_mgr->p_log, OSM_LOG_INFO,
1137 			"%s tables configured on all switches\n",
1138 			osm_routing_engine_type_str(p_osm->
1139 						    routing_engine_used->type));
1140 
1141 		if (p_mgr->p_subn->opt.use_ucast_cache)
1142 			p_mgr->cache_valid = TRUE;
1143 	} else {
1144 		p_mgr->p_subn->subnet_initialization_error = TRUE;
1145 		OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
1146 			"No routing engine able to successfully configure "
1147 			" switch tables on current fabric\n");
1148 	}
1149 Exit:
1150 	CL_PLOCK_RELEASE(p_mgr->p_lock);
1151 	OSM_LOG_EXIT(p_mgr->p_log);
1152 	return failed;
1153 }
1154 
ucast_build_lid_matrices(void * context)1155 static int ucast_build_lid_matrices(void *context)
1156 {
1157 	return osm_ucast_mgr_build_lid_matrices(context);
1158 }
1159 
ucast_build_lfts(void * context)1160 static int ucast_build_lfts(void *context)
1161 {
1162 	return ucast_mgr_build_lfts(context);
1163 }
1164 
osm_ucast_minhop_setup(struct osm_routing_engine * r,osm_opensm_t * osm)1165 int osm_ucast_minhop_setup(struct osm_routing_engine *r, osm_opensm_t * osm)
1166 {
1167 	r->context = &osm->sm.ucast_mgr;
1168 	r->build_lid_matrices = ucast_build_lid_matrices;
1169 	r->ucast_build_fwd_tables = ucast_build_lfts;
1170 	return 0;
1171 }
1172 
ucast_dor_build_lfts(void * context)1173 static int ucast_dor_build_lfts(void *context)
1174 {
1175 	osm_ucast_mgr_t *mgr = context;
1176 	int ret;
1177 
1178 	mgr->is_dor = 1;
1179 	ret = ucast_mgr_build_lfts(mgr);
1180 	mgr->is_dor = 0;
1181 
1182 	return ret;
1183 }
1184 
osm_ucast_dor_setup(struct osm_routing_engine * r,osm_opensm_t * osm)1185 int osm_ucast_dor_setup(struct osm_routing_engine *r, osm_opensm_t * osm)
1186 {
1187 	r->context = &osm->sm.ucast_mgr;
1188 	r->build_lid_matrices = ucast_build_lid_matrices;
1189 	r->ucast_build_fwd_tables = ucast_dor_build_lfts;
1190 	return 0;
1191 }
1192 
ucast_dummy_build_lid_matrices(void * context)1193 int ucast_dummy_build_lid_matrices(void *context)
1194 {
1195 	return 0;
1196 }
1197