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  * Copyright (c) 2007      Simula Research Laboratory. All rights reserved.
6  * Copyright (c) 2007      Silicon Graphics Inc. All rights reserved.
7  * Copyright (c) 2008,2009 System Fabric Works, Inc. All rights reserved.
8  * Copyright (c) 2009      HNR Consulting. All rights reserved.
9  * Copyright (c) 2009-2011 ZIH, TU Dresden, Federal Republic of Germany. All rights reserved.
10  *
11  * This software is available to you under a choice of one of two
12  * licenses.  You may choose to be licensed under the terms of the GNU
13  * General Public License (GPL) Version 2, available from the file
14  * COPYING in the main directory of this source tree, or the
15  * OpenIB.org BSD license below:
16  *
17  *     Redistribution and use in source and binary forms, with or
18  *     without modification, are permitted provided that the following
19  *     conditions are met:
20  *
21  *      - Redistributions of source code must retain the above
22  *        copyright notice, this list of conditions and the following
23  *        disclaimer.
24  *
25  *      - Redistributions in binary form must reproduce the above
26  *        copyright notice, this list of conditions and the following
27  *        disclaimer in the documentation and/or other materials
28  *        provided with the distribution.
29  *
30  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
31  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
32  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
33  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
34  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
35  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
36  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
37  * SOFTWARE.
38  *
39  */
40 
41 /*
42  * Abstract:
43  *      Implementation of LASH algorithm Calculation functions
44  */
45 
46 #if HAVE_CONFIG_H
47 #  include <config.h>
48 #endif				/* HAVE_CONFIG_H */
49 
50 #include <stdlib.h>
51 #include <stdio.h>
52 #include <errno.h>
53 #include <complib/cl_debug.h>
54 #include <complib/cl_qmap.h>
55 #include <opensm/osm_file_ids.h>
56 #define FILE_ID OSM_FILE_UCAST_LASH_C
57 #include <opensm/osm_switch.h>
58 #include <opensm/osm_opensm.h>
59 #include <opensm/osm_log.h>
60 #include <opensm/osm_mesh.h>
61 #include <opensm/osm_ucast_lash.h>
62 
63 typedef struct _reachable_dest {
64 	int switch_id;
65 	struct _reachable_dest *next;
66 } reachable_dest_t;
67 
68 static void connect_switches(lash_t * p_lash, int sw1, int sw2, int phy_port_1)
69 {
70 	osm_log_t *p_log = &p_lash->p_osm->log;
71 	unsigned num = p_lash->switches[sw1]->node->num_links;
72 	switch_t *s1 = p_lash->switches[sw1];
73 	mesh_node_t *node = s1->node;
74 	switch_t *s2;
75 	link_t *l;
76 	unsigned int i;
77 
78 	/*
79 	 * if doing mesh analysis:
80 	 *  - do not consider connections to self
81 	 *  - collapse multiple connections between
82 	 *    pair of switches to a single locical link
83 	 */
84 	if (p_lash->p_osm->subn.opt.do_mesh_analysis) {
85 		if (sw1 == sw2)
86 			return;
87 
88 		/* see if we are already linked to sw2 */
89 		for (i = 0; i < num; i++) {
90 			l = node->links[i];
91 
92 			if (node->links[i]->switch_id == sw2) {
93 				l->ports[l->num_ports++] = phy_port_1;
94 				return;
95 			}
96 		}
97 	}
98 
99 	l = node->links[num];
100 	l->switch_id = sw2;
101 	l->link_id = -1;
102 	l->ports[l->num_ports++] = phy_port_1;
103 
104 	s2 = p_lash->switches[sw2];
105 	for (i = 0; i < s2->node->num_links; i++) {
106 		if (s2->node->links[i]->switch_id == sw1) {
107 			s2->node->links[i]->link_id = num;
108 			l->link_id = i;
109 			break;
110 		}
111 	}
112 
113 	node->num_links++;
114 
115 	OSM_LOG(p_log, OSM_LOG_VERBOSE,
116 		"LASH connect: %d, %d, %d\n", sw1, sw2, phy_port_1);
117 }
118 
119 static osm_switch_t *get_osm_switch_from_port(const osm_port_t * port)
120 {
121 	osm_physp_t *p = port->p_physp;
122 	if (p->p_node->sw)
123 		return p->p_node->sw;
124 	else if (p->p_remote_physp && p->p_remote_physp->p_node->sw)
125 		return p->p_remote_physp->p_node->sw;
126 	return NULL;
127 }
128 
129 static int cycle_exists(cdg_vertex_t * start, cdg_vertex_t * current,
130 			cdg_vertex_t * prev, int visit_num)
131 {
132 	int i, new_visit_num;
133 	int cycle_found = 0;
134 
135 	if (current != NULL && current->visiting_number > 0) {
136 		if (visit_num > current->visiting_number && current->seen == 0) {
137 			cycle_found = 1;
138 		}
139 	} else {
140 		if (current == NULL) {
141 			current = start;
142 			CL_ASSERT(prev == NULL);
143 		}
144 
145 		current->visiting_number = visit_num;
146 
147 		if (prev != NULL) {
148 			prev->next = current;
149 			CL_ASSERT(prev->to == current->from);
150 			CL_ASSERT(prev->visiting_number > 0);
151 		}
152 
153 		new_visit_num = visit_num + 1;
154 
155 		for (i = 0; i < current->num_deps; i++) {
156 			cycle_found =
157 			    cycle_exists(start, current->deps[i].v, current,
158 					 new_visit_num);
159 			if (cycle_found == 1)
160 				i = current->num_deps;
161 		}
162 
163 		current->seen = 1;
164 		if (prev != NULL)
165 			prev->next = NULL;
166 	}
167 
168 	return cycle_found;
169 }
170 
171 static inline int get_next_switch(lash_t *p_lash, int sw, int link)
172 {
173 	return p_lash->switches[sw]->node->links[link]->switch_id;
174 }
175 
176 static void remove_semipermanent_depend_for_sp(lash_t * p_lash, int sw,
177 					       int dest_switch, int lane)
178 {
179 	switch_t **switches = p_lash->switches;
180 	cdg_vertex_t ****cdg_vertex_matrix = p_lash->cdg_vertex_matrix;
181 	int i_next_switch, output_link, i, next_link, i_next_next_switch,
182 	    depend = 0;
183 	cdg_vertex_t *v;
184 	int __attribute__((unused)) found;
185 
186 	output_link = switches[sw]->routing_table[dest_switch].out_link;
187 	i_next_switch = get_next_switch(p_lash, sw, output_link);
188 
189 	while (sw != dest_switch) {
190 		v = cdg_vertex_matrix[lane][sw][i_next_switch];
191 		CL_ASSERT(v != NULL);
192 
193 		if (v->num_using_vertex == 1) {
194 
195 			cdg_vertex_matrix[lane][sw][i_next_switch] = NULL;
196 
197 			free(v);
198 		} else {
199 			v->num_using_vertex--;
200 			if (i_next_switch != dest_switch) {
201 				next_link =
202 				    switches[i_next_switch]->routing_table[dest_switch].out_link;
203 				i_next_next_switch = get_next_switch(p_lash, i_next_switch, next_link);
204 				found = 0;
205 
206 				for (i = 0; i < v->num_deps; i++)
207 					if (v->deps[i].v ==
208 					    cdg_vertex_matrix[lane][i_next_switch]
209 					    [i_next_next_switch]) {
210 						found = 1;
211 						depend = i;
212 					}
213 
214 				CL_ASSERT(found);
215 
216 				if (v->deps[depend].num_used == 1) {
217 					for (i = depend;
218 					     i < v->num_deps - 1; i++) {
219 						v->deps[i].v = v->deps[i + 1].v;
220 						v->deps[i].num_used =
221 						    v->deps[i + 1].num_used;
222 					}
223 
224 					v->num_deps--;
225 				} else
226 					v->deps[depend].num_used--;
227 			}
228 		}
229 
230 		sw = i_next_switch;
231 		output_link = switches[sw]->routing_table[dest_switch].out_link;
232 
233 		if (sw != dest_switch)
234 			i_next_switch = get_next_switch(p_lash, sw, output_link);
235 	}
236 }
237 
238 inline static void enqueue(cl_list_t * bfsq, switch_t * sw)
239 {
240 	CL_ASSERT(sw->q_state == UNQUEUED);
241 	sw->q_state = Q_MEMBER;
242 	cl_list_insert_tail(bfsq, sw);
243 }
244 
245 inline static void dequeue(cl_list_t * bfsq, switch_t ** sw)
246 {
247 	*sw = (switch_t *) cl_list_remove_head(bfsq);
248 	CL_ASSERT((*sw)->q_state == Q_MEMBER);
249 	(*sw)->q_state = MST_MEMBER;
250 }
251 
252 static int get_phys_connection(switch_t *sw, int switch_to)
253 {
254 	unsigned int i;
255 
256 	for (i = 0; i < sw->node->num_links; i++)
257 		if (sw->node->links[i]->switch_id == switch_to)
258 			return i;
259 	return i;
260 }
261 
262 static void shortest_path(lash_t * p_lash, int ir)
263 {
264 	switch_t **switches = p_lash->switches, *sw, *swi;
265 	unsigned int i;
266 	cl_list_t bfsq;
267 
268 	cl_list_construct(&bfsq);
269 	cl_list_init(&bfsq, 20);
270 
271 	enqueue(&bfsq, switches[ir]);
272 
273 	while (!cl_is_list_empty(&bfsq)) {
274 		dequeue(&bfsq, &sw);
275 		for (i = 0; i < sw->node->num_links; i++) {
276 			swi = switches[sw->node->links[i]->switch_id];
277 			if (swi->q_state == UNQUEUED) {
278 				enqueue(&bfsq, swi);
279 				sw->dij_channels[sw->used_channels++] = swi->id;
280 			}
281 		}
282 	}
283 
284 	cl_list_destroy(&bfsq);
285 }
286 
287 static int generate_routing_func_for_mst(lash_t * p_lash, int sw_id,
288 					 reachable_dest_t ** destinations)
289 {
290 	int i, next_switch;
291 	switch_t *sw = p_lash->switches[sw_id];
292 	int num_channels = sw->used_channels;
293 	reachable_dest_t *dest, *i_dest, *concat_dest = NULL, *prev;
294 
295 	for (i = 0; i < num_channels; i++) {
296 		next_switch = sw->dij_channels[i];
297 		if (generate_routing_func_for_mst(p_lash, next_switch, &dest))
298 			return -1;
299 
300 		i_dest = dest;
301 		prev = i_dest;
302 
303 		while (i_dest != NULL) {
304 			if (sw->routing_table[i_dest->switch_id].out_link ==
305 			    NONE)
306 				sw->routing_table[i_dest->switch_id].out_link =
307 				    get_phys_connection(sw, next_switch);
308 
309 			prev = i_dest;
310 			i_dest = i_dest->next;
311 		}
312 
313 		CL_ASSERT(prev->next == NULL);
314 		prev->next = concat_dest;
315 		concat_dest = dest;
316 	}
317 
318 	i_dest = (reachable_dest_t *) malloc(sizeof(reachable_dest_t));
319 	if (!i_dest)
320 		return -1;
321 	i_dest->switch_id = sw->id;
322 	i_dest->next = concat_dest;
323 	*destinations = i_dest;
324 	return 0;
325 }
326 
327 static int generate_cdg_for_sp(lash_t * p_lash, int sw, int dest_switch,
328 			       int lane)
329 {
330 	unsigned num_switches = p_lash->num_switches;
331 	switch_t **switches = p_lash->switches;
332 	cdg_vertex_t ****cdg_vertex_matrix = p_lash->cdg_vertex_matrix;
333 	int next_switch, output_link, j, exists;
334 	cdg_vertex_t *v, *prev = NULL;
335 
336 	output_link = switches[sw]->routing_table[dest_switch].out_link;
337 	next_switch = get_next_switch(p_lash, sw, output_link);
338 
339 	while (sw != dest_switch) {
340 
341 		if (cdg_vertex_matrix[lane][sw][next_switch] == NULL) {
342 			v = calloc(1, sizeof(*v) + (num_switches - 1) * sizeof(v->deps[0]));
343 			if (!v)
344 				return -1;
345 			v->from = sw;
346 			v->to = next_switch;
347 			v->temp = 1;
348 			cdg_vertex_matrix[lane][sw][next_switch] = v;
349 		} else
350 			v = cdg_vertex_matrix[lane][sw][next_switch];
351 
352 		v->num_using_vertex++;
353 
354 		if (prev != NULL) {
355 			exists = 0;
356 
357 			for (j = 0; j < prev->num_deps; j++)
358 				if (prev->deps[j].v == v) {
359 					exists = 1;
360 					prev->deps[j].num_used++;
361 				}
362 
363 			if (exists == 0) {
364 				prev->deps[prev->num_deps].v = v;
365 				prev->deps[prev->num_deps].num_used++;
366 				prev->num_deps++;
367 
368 				CL_ASSERT(prev->num_deps < (int)num_switches);
369 
370 				if (prev->temp == 0)
371 					prev->num_temp_depend++;
372 
373 			}
374 		}
375 
376 		sw = next_switch;
377 		output_link = switches[sw]->routing_table[dest_switch].out_link;
378 
379 		if (sw != dest_switch) {
380 			CL_ASSERT(output_link != NONE);
381 			next_switch = get_next_switch(p_lash, sw, output_link);
382 		}
383 
384 		prev = v;
385 	}
386 	return 0;
387 }
388 
389 static void set_temp_depend_to_permanent_for_sp(lash_t * p_lash, int sw,
390 						int dest_switch, int lane)
391 {
392 	switch_t **switches = p_lash->switches;
393 	cdg_vertex_t ****cdg_vertex_matrix = p_lash->cdg_vertex_matrix;
394 	int next_switch, output_link;
395 	cdg_vertex_t *v;
396 
397 	output_link = switches[sw]->routing_table[dest_switch].out_link;
398 	next_switch = get_next_switch(p_lash, sw, output_link);
399 
400 	while (sw != dest_switch) {
401 		v = cdg_vertex_matrix[lane][sw][next_switch];
402 		CL_ASSERT(v != NULL);
403 
404 		if (v->temp == 1)
405 			v->temp = 0;
406 		else
407 			v->num_temp_depend = 0;
408 
409 		sw = next_switch;
410 		output_link = switches[sw]->routing_table[dest_switch].out_link;
411 
412 		if (sw != dest_switch)
413 			next_switch = get_next_switch(p_lash, sw, output_link);
414 	}
415 
416 }
417 
418 static void remove_temp_depend_for_sp(lash_t * p_lash, int sw, int dest_switch,
419 				      int lane)
420 {
421 	switch_t **switches = p_lash->switches;
422 	cdg_vertex_t ****cdg_vertex_matrix = p_lash->cdg_vertex_matrix;
423 	int next_switch, output_link, i;
424 	cdg_vertex_t *v;
425 
426 	output_link = switches[sw]->routing_table[dest_switch].out_link;
427 	next_switch = get_next_switch(p_lash, sw, output_link);
428 
429 	while (sw != dest_switch) {
430 		v = cdg_vertex_matrix[lane][sw][next_switch];
431 		CL_ASSERT(v != NULL);
432 
433 		if (v->temp == 1) {
434 			cdg_vertex_matrix[lane][sw][next_switch] = NULL;
435 			free(v);
436 		} else {
437 			CL_ASSERT(v->num_temp_depend <= v->num_deps);
438 			v->num_deps = v->num_deps - v->num_temp_depend;
439 			v->num_temp_depend = 0;
440 			v->num_using_vertex--;
441 
442 			for (i = v->num_deps; i < p_lash->num_switches - 1; i++)
443 				v->deps[i].num_used = 0;
444 		}
445 
446 		sw = next_switch;
447 		output_link = switches[sw]->routing_table[dest_switch].out_link;
448 
449 		if (sw != dest_switch)
450 			next_switch = get_next_switch(p_lash, sw, output_link);
451 
452 	}
453 }
454 
455 static int balance_virtual_lanes(lash_t * p_lash, unsigned lanes_needed)
456 {
457 	unsigned num_switches = p_lash->num_switches;
458 	cdg_vertex_t ****cdg_vertex_matrix = p_lash->cdg_vertex_matrix;
459 	int *num_mst_in_lane = p_lash->num_mst_in_lane;
460 	int ***virtual_location = p_lash->virtual_location;
461 	int min_filled_lane, max_filled_lane, trials;
462 	int old_min_filled_lane, old_max_filled_lane, new_num_min_lane,
463 	    new_num_max_lane;
464 	unsigned int i, j;
465 	int src, dest, start, next_switch, output_link;
466 	int next_switch2, output_link2;
467 	int stop = 0, cycle_found;
468 	int cycle_found2;
469 	unsigned start_vl = p_lash->p_osm->subn.opt.lash_start_vl;
470 
471 	max_filled_lane = 0;
472 	min_filled_lane = lanes_needed - 1;
473 
474 	trials = num_mst_in_lane[max_filled_lane];
475 	if (lanes_needed == 1)
476 		stop = 1;
477 
478 	while (stop == 0) {
479 		src = abs(rand()) % (num_switches);
480 		dest = abs(rand()) % (num_switches);
481 
482 		while (virtual_location[src][dest][max_filled_lane] != 1) {
483 			start = dest;
484 			if (dest == num_switches - 1)
485 				dest = 0;
486 			else
487 				dest++;
488 
489 			while (dest != start
490 			       && virtual_location[src][dest][max_filled_lane]
491 			       != 1) {
492 				if (dest == num_switches - 1)
493 					dest = 0;
494 				else
495 					dest++;
496 			}
497 
498 			if (virtual_location[src][dest][max_filled_lane] != 1) {
499 				if (src == num_switches - 1)
500 					src = 0;
501 				else
502 					src++;
503 			}
504 		}
505 
506 		if (generate_cdg_for_sp(p_lash, src, dest, min_filled_lane) ||
507 		    generate_cdg_for_sp(p_lash, dest, src, min_filled_lane))
508 			return -1;
509 
510 		output_link = p_lash->switches[src]->routing_table[dest].out_link;
511 		next_switch = get_next_switch(p_lash, src, output_link);
512 
513 		output_link2 = p_lash->switches[dest]->routing_table[src].out_link;
514 		next_switch2 = get_next_switch(p_lash, dest, output_link2);
515 
516 		CL_ASSERT(cdg_vertex_matrix[min_filled_lane][src][next_switch] != NULL);
517 		CL_ASSERT(cdg_vertex_matrix[min_filled_lane][dest][next_switch2] != NULL);
518 
519 		cycle_found =
520 		    cycle_exists(cdg_vertex_matrix[min_filled_lane][src][next_switch], NULL, NULL,
521 				 1);
522 		cycle_found2 =
523 		    cycle_exists(cdg_vertex_matrix[min_filled_lane][dest][next_switch2], NULL, NULL,
524 				 1);
525 
526 		for (i = 0; i < num_switches; i++)
527 			for (j = 0; j < num_switches; j++)
528 				if (cdg_vertex_matrix[min_filled_lane][i][j] != NULL) {
529 					cdg_vertex_matrix[min_filled_lane][i][j]->visiting_number =
530 					    0;
531 					cdg_vertex_matrix[min_filled_lane][i][j]->seen = 0;
532 				}
533 
534 		if (cycle_found == 1 || cycle_found2 == 1) {
535 			remove_temp_depend_for_sp(p_lash, src, dest, min_filled_lane);
536 			remove_temp_depend_for_sp(p_lash, dest, src, min_filled_lane);
537 
538 			virtual_location[src][dest][max_filled_lane] = 2;
539 			virtual_location[dest][src][max_filled_lane] = 2;
540 			trials--;
541 			trials--;
542 		} else {
543 			set_temp_depend_to_permanent_for_sp(p_lash, src, dest, min_filled_lane);
544 			set_temp_depend_to_permanent_for_sp(p_lash, dest, src, min_filled_lane);
545 
546 			num_mst_in_lane[max_filled_lane]--;
547 			num_mst_in_lane[max_filled_lane]--;
548 			num_mst_in_lane[min_filled_lane]++;
549 			num_mst_in_lane[min_filled_lane]++;
550 
551 			remove_semipermanent_depend_for_sp(p_lash, src, dest, max_filled_lane);
552 			remove_semipermanent_depend_for_sp(p_lash, dest, src, max_filled_lane);
553 			virtual_location[src][dest][max_filled_lane] = 0;
554 			virtual_location[dest][src][max_filled_lane] = 0;
555 			virtual_location[src][dest][min_filled_lane] = 1;
556 			virtual_location[dest][src][min_filled_lane] = 1;
557 			p_lash->switches[src]->routing_table[dest].lane = min_filled_lane + start_vl;
558 			p_lash->switches[dest]->routing_table[src].lane = min_filled_lane + start_vl;
559 		}
560 
561 		if (trials == 0)
562 			stop = 1;
563 		else {
564 			if (num_mst_in_lane[max_filled_lane] - num_mst_in_lane[min_filled_lane] <
565 			    p_lash->balance_limit)
566 				stop = 1;
567 		}
568 
569 		old_min_filled_lane = min_filled_lane;
570 		old_max_filled_lane = max_filled_lane;
571 
572 		new_num_min_lane = MAX_INT;
573 		new_num_max_lane = 0;
574 
575 		for (i = 0; i < lanes_needed; i++) {
576 
577 			if (num_mst_in_lane[i] < new_num_min_lane) {
578 				new_num_min_lane = num_mst_in_lane[i];
579 				min_filled_lane = i;
580 			}
581 
582 			if (num_mst_in_lane[i] > new_num_max_lane) {
583 				new_num_max_lane = num_mst_in_lane[i];
584 				max_filled_lane = i;
585 			}
586 		}
587 
588 		if (old_min_filled_lane != min_filled_lane) {
589 			trials = num_mst_in_lane[max_filled_lane];
590 			for (i = 0; i < num_switches; i++)
591 				for (j = 0; j < num_switches; j++)
592 					if (virtual_location[i][j][max_filled_lane] == 2)
593 						virtual_location[i][j][max_filled_lane] = 1;
594 		}
595 
596 		if (old_max_filled_lane != max_filled_lane) {
597 			trials = num_mst_in_lane[max_filled_lane];
598 			for (i = 0; i < num_switches; i++)
599 				for (j = 0; j < num_switches; j++)
600 					if (virtual_location[i][j][old_max_filled_lane] == 2)
601 						virtual_location[i][j][old_max_filled_lane] = 1;
602 		}
603 	}
604 	return 0;
605 }
606 
607 static switch_t *switch_create(lash_t * p_lash, unsigned id, osm_switch_t * p_sw)
608 {
609 	unsigned num_switches = p_lash->num_switches;
610 	unsigned num_ports = p_sw->num_ports;
611 	switch_t *sw;
612 	unsigned int i;
613 
614 	sw = malloc(sizeof(*sw) + num_switches * sizeof(sw->routing_table[0]));
615 	if (!sw)
616 		return NULL;
617 
618 	memset(sw, 0, sizeof(*sw));
619 	for (i = 0; i < num_switches; i++) {
620 		sw->routing_table[i].out_link = NONE;
621 		sw->routing_table[i].lane = NONE;
622 	}
623 
624 	sw->id = id;
625 	sw->dij_channels = malloc(num_ports * sizeof(int));
626 	if (!sw->dij_channels) {
627 		free(sw);
628 		return NULL;
629 	}
630 
631 	sw->p_sw = p_sw;
632 	p_sw->priv = sw;
633 
634 	if (osm_mesh_node_create(p_lash, sw)) {
635 		free(sw->dij_channels);
636 		free(sw);
637 		return NULL;
638 	}
639 
640 	return sw;
641 }
642 
643 static void switch_delete(lash_t *p_lash, switch_t * sw)
644 {
645 	if (sw->dij_channels)
646 		free(sw->dij_channels);
647 	free(sw);
648 }
649 
650 static void delete_mesh_switches(lash_t *p_lash)
651 {
652 	if (p_lash->switches) {
653 		unsigned id;
654 		for (id = 0; ((int)id) < p_lash->num_switches; id++)
655 			if (p_lash->switches[id])
656 				osm_mesh_node_delete(p_lash,
657 						     p_lash->switches[id]);
658 	}
659 }
660 
661 static void free_lash_structures(lash_t * p_lash)
662 {
663 	unsigned int i, j, k;
664 	unsigned num_switches = p_lash->num_switches;
665 	osm_log_t *p_log = &p_lash->p_osm->log;
666 
667 	OSM_LOG_ENTER(p_log);
668 
669 	delete_mesh_switches(p_lash);
670 
671 	/* free cdg_vertex_matrix */
672 	for (i = 0; i < p_lash->vl_min; i++) {
673 		for (j = 0; j < num_switches; j++) {
674 			for (k = 0; k < num_switches; k++)
675 				if (p_lash->cdg_vertex_matrix[i][j][k])
676 					free(p_lash->cdg_vertex_matrix[i][j][k]);
677 			if (p_lash->cdg_vertex_matrix[i][j])
678 				free(p_lash->cdg_vertex_matrix[i][j]);
679 		}
680 		if (p_lash->cdg_vertex_matrix[i])
681 			free(p_lash->cdg_vertex_matrix[i]);
682 	}
683 
684 	if (p_lash->cdg_vertex_matrix)
685 		free(p_lash->cdg_vertex_matrix);
686 
687 	/* free virtual_location */
688 	for (i = 0; i < num_switches; i++) {
689 		for (j = 0; j < num_switches; j++) {
690 			if (p_lash->virtual_location[i][j])
691 				free(p_lash->virtual_location[i][j]);
692 		}
693 		if (p_lash->virtual_location[i])
694 			free(p_lash->virtual_location[i]);
695 	}
696 	if (p_lash->virtual_location)
697 		free(p_lash->virtual_location);
698 
699 	OSM_LOG_EXIT(p_log);
700 }
701 
702 static int init_lash_structures(lash_t * p_lash)
703 {
704 	unsigned vl_min = p_lash->vl_min;
705 	unsigned num_switches = p_lash->num_switches;
706 	osm_log_t *p_log = &p_lash->p_osm->log;
707 	int status = 0;
708 	unsigned int i, j, k;
709 
710 	OSM_LOG_ENTER(p_log);
711 
712 	/* initialise cdg_vertex_matrix[num_switches][num_switches][num_switches] */
713 	p_lash->cdg_vertex_matrix =
714 	    (cdg_vertex_t ****) malloc(vl_min * sizeof(cdg_vertex_t ***));
715 	if (p_lash->cdg_vertex_matrix == NULL)
716 		goto Exit_Mem_Error;
717 	for (i = 0; i < vl_min; i++) {
718 		p_lash->cdg_vertex_matrix[i] =
719 		    (cdg_vertex_t ***) malloc(num_switches *
720 					      sizeof(cdg_vertex_t **));
721 
722 		if (p_lash->cdg_vertex_matrix[i] == NULL)
723 			goto Exit_Mem_Error;
724 	}
725 
726 	for (i = 0; i < vl_min; i++) {
727 		for (j = 0; j < num_switches; j++) {
728 			p_lash->cdg_vertex_matrix[i][j] =
729 			    (cdg_vertex_t **) malloc(num_switches *
730 						     sizeof(cdg_vertex_t *));
731 			if (p_lash->cdg_vertex_matrix[i][j] == NULL)
732 				goto Exit_Mem_Error;
733 
734 			for (k = 0; k < num_switches; k++)
735 				p_lash->cdg_vertex_matrix[i][j][k] = NULL;
736 		}
737 	}
738 
739 	/*
740 	 * initialise virtual_location[num_switches][num_switches][num_layers],
741 	 * default value = 0
742 	 */
743 	p_lash->virtual_location =
744 	    (int ***)malloc(num_switches * sizeof(int ***));
745 	if (p_lash->virtual_location == NULL)
746 		goto Exit_Mem_Error;
747 
748 	for (i = 0; i < num_switches; i++) {
749 		p_lash->virtual_location[i] =
750 		    (int **)malloc(num_switches * sizeof(int **));
751 		if (p_lash->virtual_location[i] == NULL)
752 			goto Exit_Mem_Error;
753 	}
754 
755 	for (i = 0; i < num_switches; i++) {
756 		for (j = 0; j < num_switches; j++) {
757 			p_lash->virtual_location[i][j] =
758 			    (int *)malloc(vl_min * sizeof(int *));
759 			if (p_lash->virtual_location[i][j] == NULL)
760 				goto Exit_Mem_Error;
761 			for (k = 0; k < vl_min; k++)
762 				p_lash->virtual_location[i][j][k] = 0;
763 		}
764 	}
765 
766 	/* initialise num_mst_in_lane[num_switches], default 0 */
767 	memset(p_lash->num_mst_in_lane, 0,
768 	       IB_MAX_NUM_VLS * sizeof(p_lash->num_mst_in_lane[0]));
769 
770 	goto Exit;
771 
772 Exit_Mem_Error:
773 	status = -1;
774 	OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 4D01: "
775 		"Could not allocate required memory for LASH errno %d, errno %d for lack of memory\n",
776 		errno, ENOMEM);
777 
778 Exit:
779 	OSM_LOG_EXIT(p_log);
780 	return status;
781 }
782 
783 static int lash_core(lash_t * p_lash)
784 {
785 	osm_log_t *p_log = &p_lash->p_osm->log;
786 	unsigned num_switches = p_lash->num_switches;
787 	switch_t **switches = p_lash->switches;
788 	unsigned lanes_needed = 1;
789 	unsigned int i, j, k, dest_switch = 0;
790 	reachable_dest_t *dests, *idest;
791 	int cycle_found = 0;
792 	unsigned v_lane;
793 	int stop = 0, output_link, i_next_switch;
794 	int output_link2, i_next_switch2;
795 	int cycle_found2 = 0;
796 	int status = -1;
797 	int *switch_bitmap = NULL;	/* Bitmap to check if we have processed this pair */
798 	unsigned start_vl = p_lash->p_osm->subn.opt.lash_start_vl;
799 
800 	OSM_LOG_ENTER(p_log);
801 
802 	if (p_lash->p_osm->subn.opt.do_mesh_analysis && osm_do_mesh_analysis(p_lash)) {
803 		OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 4D05: Mesh analysis failed\n");
804 		goto Exit;
805 	}
806 
807 	for (i = 0; i < num_switches; i++) {
808 
809 		shortest_path(p_lash, i);
810 		if (generate_routing_func_for_mst(p_lash, i, &dests)) {
811 			OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 4D06: "
812 				"generate_routing_func_for_mst failed\n");
813 			goto Exit;
814 		}
815 
816 		idest = dests;
817 		while (idest != NULL) {
818 			dests = dests->next;
819 			free(idest);
820 			idest = dests;
821 		}
822 
823 		for (j = 0; j < num_switches; j++) {
824 			switches[j]->used_channels = 0;
825 			switches[j]->q_state = UNQUEUED;
826 		}
827 	}
828 
829 	switch_bitmap = calloc(num_switches * num_switches, sizeof(int));
830 	if (!switch_bitmap) {
831 		OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 4D04: "
832 			"Failed allocating switch_bitmap - out of memory\n");
833 		goto Exit;
834 	}
835 
836 	for (i = 0; i < num_switches; i++) {
837 		for (dest_switch = 0; dest_switch < num_switches; dest_switch++)
838 			if (dest_switch != i && switch_bitmap[i * num_switches + dest_switch] == 0) {
839 				v_lane = 0;
840 				stop = 0;
841 				while (v_lane < lanes_needed && stop == 0) {
842 					if (generate_cdg_for_sp(p_lash, i, dest_switch, v_lane) ||
843 					    generate_cdg_for_sp(p_lash, dest_switch, i, v_lane)) {
844 						OSM_LOG(p_log, OSM_LOG_ERROR,
845 							"ERR 4D07: generate_cdg_for_sp failed\n");
846 						goto Exit;
847 					}
848 
849 					output_link =
850 					    switches[i]->routing_table[dest_switch].out_link;
851 					output_link2 =
852 					    switches[dest_switch]->routing_table[i].out_link;
853 
854 					i_next_switch = get_next_switch(p_lash, i, output_link);
855 					i_next_switch2 = get_next_switch(p_lash, dest_switch, output_link2);
856 
857 					CL_ASSERT(p_lash->
858 						  cdg_vertex_matrix[v_lane][i][i_next_switch] !=
859 						  NULL);
860 					CL_ASSERT(p_lash->
861 						  cdg_vertex_matrix[v_lane][dest_switch]
862 						  [i_next_switch2] != NULL);
863 
864 					cycle_found =
865 					    cycle_exists(p_lash->
866 							 cdg_vertex_matrix[v_lane][i]
867 							 [i_next_switch], NULL, NULL, 1);
868 					cycle_found2 =
869 					    cycle_exists(p_lash->
870 							 cdg_vertex_matrix[v_lane][dest_switch]
871 							 [i_next_switch2], NULL, NULL, 1);
872 
873 					for (j = 0; j < num_switches; j++)
874 						for (k = 0; k < num_switches; k++)
875 							if (p_lash->
876 							    cdg_vertex_matrix[v_lane][j][k] !=
877 							    NULL) {
878 								p_lash->
879 								    cdg_vertex_matrix[v_lane][j]
880 								    [k]->visiting_number = 0;
881 								p_lash->
882 								    cdg_vertex_matrix[v_lane][j]
883 								    [k]->seen = 0;
884 							}
885 
886 					if (cycle_found == 1 || cycle_found2 == 1) {
887 						remove_temp_depend_for_sp(p_lash, i, dest_switch,
888 									  v_lane);
889 						remove_temp_depend_for_sp(p_lash, dest_switch, i,
890 									  v_lane);
891 						v_lane++;
892 					} else {
893 						set_temp_depend_to_permanent_for_sp(p_lash, i,
894 										    dest_switch,
895 										    v_lane);
896 						set_temp_depend_to_permanent_for_sp(p_lash,
897 										    dest_switch, i,
898 										    v_lane);
899 						stop = 1;
900 						p_lash->num_mst_in_lane[v_lane]++;
901 						p_lash->num_mst_in_lane[v_lane]++;
902 					}
903 				}
904 
905 				switches[i]->routing_table[dest_switch].lane = v_lane + start_vl;
906 				switches[dest_switch]->routing_table[i].lane = v_lane + start_vl;
907 
908 				if (cycle_found == 1 || cycle_found2 == 1) {
909 					if (++lanes_needed > p_lash->vl_min)
910 						goto Error_Not_Enough_Lanes;
911 
912 					if (generate_cdg_for_sp(p_lash, i, dest_switch, v_lane) ||
913 					    generate_cdg_for_sp(p_lash, dest_switch, i, v_lane)) {
914 						OSM_LOG(p_log, OSM_LOG_ERROR,
915 							"ERR 4D08: generate_cdg_for_sp failed\n");
916 						goto Exit;
917 					}
918 
919 					set_temp_depend_to_permanent_for_sp(p_lash, i, dest_switch,
920 									    v_lane);
921 					set_temp_depend_to_permanent_for_sp(p_lash, dest_switch, i,
922 									    v_lane);
923 
924 					p_lash->num_mst_in_lane[v_lane]++;
925 					p_lash->num_mst_in_lane[v_lane]++;
926 				}
927 				p_lash->virtual_location[i][dest_switch][v_lane] = 1;
928 				p_lash->virtual_location[dest_switch][i][v_lane] = 1;
929 
930 				switch_bitmap[i * num_switches + dest_switch] = 1;
931 				switch_bitmap[dest_switch * num_switches + i] = 1;
932 			}
933 	}
934 
935 	for (i = 0; i < lanes_needed; i++)
936 		OSM_LOG(p_log, OSM_LOG_INFO, "Lanes in layer %d: %d\n",
937 			i, p_lash->num_mst_in_lane[i]);
938 
939 	OSM_LOG(p_log, OSM_LOG_INFO,
940 		"Lanes needed: %d, Balancing\n", lanes_needed);
941 
942 	if (balance_virtual_lanes(p_lash, lanes_needed)) {
943 		OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 4D09: Balancing failed\n");
944 		goto Exit;
945 	}
946 
947 	for (i = 0; i < lanes_needed; i++)
948 		OSM_LOG(p_log, OSM_LOG_INFO, "Lanes in layer %d: %d\n",
949 			i, p_lash->num_mst_in_lane[i]);
950 
951 	status = 0;
952 	goto Exit;
953 
954 Error_Not_Enough_Lanes:
955 	OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 4D02: "
956 		"Lane requirements (%d) exceed available lanes (%d)"
957 		" with starting lane (%d)\n",
958 		lanes_needed, p_lash->vl_min, start_vl);
959 Exit:
960 	if (switch_bitmap)
961 		free(switch_bitmap);
962 	OSM_LOG_EXIT(p_log);
963 	return status;
964 }
965 
966 static unsigned get_lash_id(osm_switch_t * p_sw)
967 {
968 	return ((switch_t *) p_sw->priv)->id;
969 }
970 
971 static int get_next_port(switch_t *sw, int link)
972 {
973 	link_t *l = sw->node->links[link];
974 	int port = l->next_port++;
975 
976 	/*
977 	 * note if not doing mesh analysis
978 	 * then num_ports is always 1
979 	 */
980 	if (l->next_port >= l->num_ports)
981 		l->next_port = 0;
982 
983 	return l->ports[port];
984 }
985 
986 static void populate_fwd_tbls(lash_t * p_lash)
987 {
988 	osm_log_t *p_log = &p_lash->p_osm->log;
989 	osm_subn_t *p_subn = &p_lash->p_osm->subn;
990 	osm_switch_t *p_sw, *p_next_sw, *p_dst_sw;
991 	osm_port_t *port;
992 	uint16_t max_lid_ho, lid;
993 
994 	OSM_LOG_ENTER(p_log);
995 
996 	p_next_sw = (osm_switch_t *) cl_qmap_head(&p_subn->sw_guid_tbl);
997 
998 	/* Go through each switch individually */
999 	while (p_next_sw != (osm_switch_t *) cl_qmap_end(&p_subn->sw_guid_tbl)) {
1000 		uint64_t current_guid;
1001 		switch_t *sw;
1002 		p_sw = p_next_sw;
1003 		p_next_sw = (osm_switch_t *) cl_qmap_next(&p_sw->map_item);
1004 
1005 		max_lid_ho = p_sw->max_lid_ho;
1006 		current_guid = p_sw->p_node->node_info.port_guid;
1007 		sw = p_sw->priv;
1008 
1009 		memset(p_sw->new_lft, OSM_NO_PATH, p_sw->lft_size);
1010 
1011 		for (lid = 1; lid <= max_lid_ho; lid++) {
1012 			port = osm_get_port_by_lid_ho(p_subn, lid);
1013 			if (!port)
1014 				continue;
1015 
1016 			p_dst_sw = get_osm_switch_from_port(port);
1017 			if (p_dst_sw == p_sw) {
1018 				uint8_t egress_port = port->p_node->sw ? 0 :
1019 					port->p_physp->p_remote_physp->port_num;
1020 				p_sw->new_lft[lid] = egress_port;
1021 				OSM_LOG(p_log, OSM_LOG_VERBOSE,
1022 					"LASH fwd MY SRC SRC GUID 0x%016" PRIx64
1023 					" src lash id (%d), src lid no (%u) src lash port (%d) "
1024 					"DST GUID 0x%016" PRIx64
1025 					" src lash id (%d), src lash port (%d)\n",
1026 					cl_ntoh64(current_guid), -1, lid,
1027 					egress_port, cl_ntoh64(current_guid),
1028 					-1, egress_port);
1029 			} else if (p_dst_sw) {
1030 				unsigned dst_lash_switch_id =
1031 				    get_lash_id(p_dst_sw);
1032 				uint8_t lash_egress_port =
1033 				    (uint8_t) sw->
1034 				    routing_table[dst_lash_switch_id].out_link;
1035 				uint8_t physical_egress_port =
1036 					get_next_port(sw, lash_egress_port);
1037 
1038 				p_sw->new_lft[lid] = physical_egress_port;
1039 				OSM_LOG(p_log, OSM_LOG_VERBOSE,
1040 					"LASH fwd SRC GUID 0x%016" PRIx64
1041 					" src lash id (%d), "
1042 					"src lid no (%u) src lash port (%d) "
1043 					"DST GUID 0x%016" PRIx64
1044 					" src lash id (%d), src lash port (%d)\n",
1045 					cl_ntoh64(current_guid), sw->id, lid,
1046 					lash_egress_port,
1047 					cl_ntoh64(p_dst_sw->p_node->node_info.
1048 						  port_guid),
1049 					dst_lash_switch_id,
1050 					physical_egress_port);
1051 			}
1052 		}		/* for */
1053 	}
1054 	OSM_LOG_EXIT(p_log);
1055 }
1056 
1057 static void osm_lash_process_switch(lash_t * p_lash, osm_switch_t * p_sw)
1058 {
1059 	osm_log_t *p_log = &p_lash->p_osm->log;
1060 	int i, port_count;
1061 	osm_physp_t *p_current_physp, *p_remote_physp;
1062 	unsigned switch_a_lash_id, switch_b_lash_id;
1063 
1064 	OSM_LOG_ENTER(p_log);
1065 
1066 	switch_a_lash_id = get_lash_id(p_sw);
1067 	port_count = osm_node_get_num_physp(p_sw->p_node);
1068 
1069 	/* starting at port 1, ignoring management port on switch */
1070 	for (i = 1; i < port_count; i++) {
1071 
1072 		p_current_physp = osm_node_get_physp_ptr(p_sw->p_node, i);
1073 		if (p_current_physp) {
1074 			p_remote_physp = p_current_physp->p_remote_physp;
1075 			if (p_remote_physp && p_remote_physp->p_node->sw) {
1076 				int physical_port_a_num =
1077 				    osm_physp_get_port_num(p_current_physp);
1078 				int physical_port_b_num =
1079 				    osm_physp_get_port_num(p_remote_physp);
1080 				switch_b_lash_id =
1081 				    get_lash_id(p_remote_physp->p_node->sw);
1082 
1083 				connect_switches(p_lash, switch_a_lash_id,
1084 						 switch_b_lash_id,
1085 						 physical_port_a_num);
1086 				OSM_LOG(p_log, OSM_LOG_VERBOSE,
1087 					"LASH SUCCESS connected G 0x%016" PRIx64
1088 					" , lash_id(%u), P(%u) " " to G 0x%016"
1089 					PRIx64 " , lash_id(%u) , P(%u)\n",
1090 					cl_ntoh64(osm_physp_get_port_guid
1091 						  (p_current_physp)),
1092 					switch_a_lash_id, physical_port_a_num,
1093 					cl_ntoh64(osm_physp_get_port_guid
1094 						  (p_remote_physp)),
1095 					switch_b_lash_id, physical_port_b_num);
1096 			}
1097 		}
1098 	}
1099 
1100 	OSM_LOG_EXIT(p_log);
1101 }
1102 
1103 static void lash_cleanup(lash_t * p_lash)
1104 {
1105 	osm_subn_t *p_subn = &p_lash->p_osm->subn;
1106 	osm_switch_t *p_next_sw, *p_sw;
1107 
1108 	/* drop any existing references to old lash switches */
1109 	p_next_sw = (osm_switch_t *) cl_qmap_head(&p_subn->sw_guid_tbl);
1110 	while (p_next_sw != (osm_switch_t *) cl_qmap_end(&p_subn->sw_guid_tbl)) {
1111 		p_sw = p_next_sw;
1112 		p_next_sw = (osm_switch_t *) cl_qmap_next(&p_sw->map_item);
1113 		p_sw->priv = NULL;
1114 	}
1115 
1116 	if (p_lash->switches) {
1117 		unsigned id;
1118 		for (id = 0; ((int)id) < p_lash->num_switches; id++)
1119 			if (p_lash->switches[id])
1120 				switch_delete(p_lash, p_lash->switches[id]);
1121 		free(p_lash->switches);
1122 	}
1123 	p_lash->switches = NULL;
1124 }
1125 
1126 /*
1127   static int  discover_network_properties()
1128   Traverse the topology of the network in order to determine
1129    - the maximum number of switches,
1130    - the minimum number of virtual layers
1131 */
1132 
1133 static int discover_network_properties(lash_t * p_lash)
1134 {
1135 	int i, id = 0;
1136 	uint8_t vl_min;
1137 	osm_subn_t *p_subn = &p_lash->p_osm->subn;
1138 	osm_switch_t *p_next_sw, *p_sw;
1139 	osm_log_t *p_log = &p_lash->p_osm->log;
1140 
1141 	p_lash->num_switches = cl_qmap_count(&p_subn->sw_guid_tbl);
1142 
1143 	p_lash->switches = calloc(p_lash->num_switches, sizeof(switch_t *));
1144 	if (!p_lash->switches)
1145 		return -1;
1146 
1147 	vl_min = 5;		/* set to a high value */
1148 
1149 	p_next_sw = (osm_switch_t *) cl_qmap_head(&p_subn->sw_guid_tbl);
1150 	while (p_next_sw != (osm_switch_t *) cl_qmap_end(&p_subn->sw_guid_tbl)) {
1151 		uint16_t port_count;
1152 		p_sw = p_next_sw;
1153 		p_next_sw = (osm_switch_t *) cl_qmap_next(&p_sw->map_item);
1154 
1155 		p_lash->switches[id] = switch_create(p_lash, id, p_sw);
1156 		if (!p_lash->switches[id])
1157 			return -1;
1158 		id++;
1159 
1160 		port_count = osm_node_get_num_physp(p_sw->p_node);
1161 
1162 		/* Note, ignoring port 0. management port */
1163 		for (i = 1; i < port_count; i++) {
1164 			osm_physp_t *p_current_physp =
1165 			    osm_node_get_physp_ptr(p_sw->p_node, i);
1166 
1167 			if (p_current_physp
1168 			    && p_current_physp->p_remote_physp) {
1169 
1170 				ib_port_info_t *p_port_info =
1171 				    &p_current_physp->port_info;
1172 				uint8_t port_vl_min =
1173 				    ib_port_info_get_op_vls(p_port_info);
1174 				if (port_vl_min && port_vl_min < vl_min)
1175 					vl_min = port_vl_min;
1176 			}
1177 		}		/* for */
1178 	}			/* while */
1179 
1180 	vl_min = 1 << (vl_min - 1);
1181 	if (vl_min > 15)
1182 		vl_min = 15;
1183 
1184 	if (p_lash->p_osm->subn.opt.lash_start_vl >= vl_min) {
1185 		OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 4D03: "
1186 			"Start VL(%d) too high for min operational vl(%d)\n",
1187 			p_lash->p_osm->subn.opt.lash_start_vl, vl_min);
1188 		return -1;
1189 	}
1190 
1191 	p_lash->vl_min = vl_min - p_lash->p_osm->subn.opt.lash_start_vl;
1192 
1193 	OSM_LOG(p_log, OSM_LOG_INFO,
1194 		"min operational vl(%d) start vl(%d) max_switches(%d)\n",
1195 		p_lash->vl_min, p_lash->p_osm->subn.opt.lash_start_vl,
1196 		p_lash->num_switches);
1197 	return 0;
1198 }
1199 
1200 static void process_switches(lash_t * p_lash)
1201 {
1202 	osm_switch_t *p_sw, *p_next_sw;
1203 	osm_subn_t *p_subn = &p_lash->p_osm->subn;
1204 
1205 	/* Go through each switch and process it. i.e build the connection
1206 	   structure required by LASH */
1207 	p_next_sw = (osm_switch_t *) cl_qmap_head(&p_subn->sw_guid_tbl);
1208 	while (p_next_sw != (osm_switch_t *) cl_qmap_end(&p_subn->sw_guid_tbl)) {
1209 		p_sw = p_next_sw;
1210 		p_next_sw = (osm_switch_t *) cl_qmap_next(&p_sw->map_item);
1211 
1212 		osm_lash_process_switch(p_lash, p_sw);
1213 	}
1214 }
1215 
1216 static int lash_process(void *context)
1217 {
1218 	lash_t *p_lash = context;
1219 	osm_log_t *p_log = &p_lash->p_osm->log;
1220 	int status = 0;
1221 
1222 	OSM_LOG_ENTER(p_log);
1223 
1224 	p_lash->balance_limit = 6;
1225 
1226 	/* everything starts here */
1227 	lash_cleanup(p_lash);
1228 
1229 	status = discover_network_properties(p_lash);
1230 	if (status)
1231 		goto Exit;
1232 
1233 	status = init_lash_structures(p_lash);
1234 	if (status)
1235 		goto Exit;
1236 
1237 	process_switches(p_lash);
1238 
1239 	status = lash_core(p_lash);
1240 	if (status)
1241 		goto Exit;
1242 
1243 	populate_fwd_tbls(p_lash);
1244 
1245 Exit:
1246 	if (p_lash->vl_min)
1247 		free_lash_structures(p_lash);
1248 	OSM_LOG_EXIT(p_log);
1249 
1250 	return status;
1251 }
1252 
1253 static lash_t *lash_create(osm_opensm_t * p_osm)
1254 {
1255 	lash_t *p_lash;
1256 
1257 	p_lash = calloc(1, sizeof(lash_t));
1258 	if (!p_lash)
1259 		return NULL;
1260 
1261 	p_lash->p_osm = p_osm;
1262 
1263 	return p_lash;
1264 }
1265 
1266 static void lash_delete(void *context)
1267 {
1268 	lash_t *p_lash = context;
1269 
1270 	if (p_lash->switches) {
1271 		unsigned id;
1272 		for (id = 0; ((int)id) < p_lash->num_switches; id++)
1273 			if (p_lash->switches[id])
1274 				switch_delete(p_lash, p_lash->switches[id]);
1275 		free(p_lash->switches);
1276 	}
1277 
1278 	free(p_lash);
1279 }
1280 
1281 static uint8_t get_lash_sl(void *context, uint8_t path_sl_hint,
1282 			   const ib_net16_t slid, const ib_net16_t dlid)
1283 {
1284 	unsigned dst_id;
1285 	unsigned src_id;
1286 	osm_port_t *p_src_port, *p_dst_port;
1287 	osm_switch_t *p_sw;
1288 	lash_t *p_lash = context;
1289 	osm_opensm_t *p_osm = p_lash->p_osm;
1290 
1291 	if (!(p_osm->routing_engine_used &&
1292 	      p_osm->routing_engine_used->type == OSM_ROUTING_ENGINE_TYPE_LASH))
1293 		return OSM_DEFAULT_SL;
1294 
1295 	p_src_port = osm_get_port_by_lid(&p_osm->subn, slid);
1296 	if (!p_src_port)
1297 		return OSM_DEFAULT_SL;
1298 
1299 	p_dst_port = osm_get_port_by_lid(&p_osm->subn, dlid);
1300 	if (!p_dst_port)
1301 		return OSM_DEFAULT_SL;
1302 
1303 	p_sw = get_osm_switch_from_port(p_dst_port);
1304 	if (!p_sw || !p_sw->priv)
1305 		return OSM_DEFAULT_SL;
1306 	dst_id = get_lash_id(p_sw);
1307 
1308 	p_sw = get_osm_switch_from_port(p_src_port);
1309 	if (!p_sw || !p_sw->priv)
1310 		return OSM_DEFAULT_SL;
1311 
1312 	src_id = get_lash_id(p_sw);
1313 	if (src_id == dst_id)
1314 		return p_osm->subn.opt.lash_start_vl;
1315 
1316 	return (uint8_t) ((switch_t *) p_sw->priv)->routing_table[dst_id].lane;
1317 }
1318 
1319 int osm_ucast_lash_setup(struct osm_routing_engine *r, osm_opensm_t *p_osm)
1320 {
1321 	lash_t *p_lash = lash_create(p_osm);
1322 	if (!p_lash)
1323 		return -1;
1324 
1325 	r->context = p_lash;
1326 	r->ucast_build_fwd_tables = lash_process;
1327 	r->path_sl = get_lash_sl;
1328 	r->destroy = lash_delete;
1329 
1330 	return 0;
1331 }
1332