1219820Sjeff/* 2219820Sjeff * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. 3219820Sjeff * Copyright (c) 2002-2008 Mellanox Technologies LTD. All rights reserved. 4219820Sjeff * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. 5219820Sjeff * Copyright (c) 2007 Simula Research Laboratory. All rights reserved. 6219820Sjeff * Copyright (c) 2007 Silicon Graphics Inc. All rights reserved. 7219820Sjeff * 8219820Sjeff * This software is available to you under a choice of one of two 9219820Sjeff * licenses. You may choose to be licensed under the terms of the GNU 10219820Sjeff * General Public License (GPL) Version 2, available from the file 11219820Sjeff * COPYING in the main directory of this source tree, or the 12219820Sjeff * OpenIB.org BSD license below: 13219820Sjeff * 14219820Sjeff * Redistribution and use in source and binary forms, with or 15219820Sjeff * without modification, are permitted provided that the following 16219820Sjeff * conditions are met: 17219820Sjeff * 18219820Sjeff * - Redistributions of source code must retain the above 19219820Sjeff * copyright notice, this list of conditions and the following 20219820Sjeff * disclaimer. 21219820Sjeff * 22219820Sjeff * - Redistributions in binary form must reproduce the above 23219820Sjeff * copyright notice, this list of conditions and the following 24219820Sjeff * disclaimer in the documentation and/or other materials 25219820Sjeff * provided with the distribution. 26219820Sjeff * 27219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 28219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 29219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 30219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 31219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 32219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 33219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 34219820Sjeff * SOFTWARE. 35219820Sjeff * 36219820Sjeff */ 37219820Sjeff 38219820Sjeff/* 39219820Sjeff * Abstract: 40219820Sjeff * Implementation of LASH algorithm Calculation functions 41219820Sjeff */ 42219820Sjeff 43219820Sjeff#if HAVE_CONFIG_H 44219820Sjeff# include <config.h> 45219820Sjeff#endif /* HAVE_CONFIG_H */ 46219820Sjeff 47219820Sjeff#include <stdlib.h> 48219820Sjeff#include <stdio.h> 49219820Sjeff#include <errno.h> 50219820Sjeff#include <complib/cl_debug.h> 51219820Sjeff#include <complib/cl_qmap.h> 52219820Sjeff#include <opensm/osm_switch.h> 53219820Sjeff#include <opensm/osm_opensm.h> 54219820Sjeff#include <opensm/osm_log.h> 55219820Sjeff 56219820Sjeff/* //////////////////////////// */ 57219820Sjeff/* Local types */ 58219820Sjeff/* //////////////////////////// */ 59219820Sjeff 60219820Sjeffenum { 61219820Sjeff UNQUEUED, 62219820Sjeff Q_MEMBER, 63219820Sjeff MST_MEMBER, 64219820Sjeff MAX_INT = 9999, 65219820Sjeff NONE = MAX_INT 66219820Sjeff}; 67219820Sjeff 68219820Sjefftypedef struct _cdg_vertex { 69219820Sjeff int num_dependencies; 70219820Sjeff struct _cdg_vertex **dependency; 71219820Sjeff int from; 72219820Sjeff int to; 73219820Sjeff int seen; 74219820Sjeff int temp; 75219820Sjeff int visiting_number; 76219820Sjeff struct _cdg_vertex *next; 77219820Sjeff int num_temp_depend; 78219820Sjeff int num_using_vertex; 79219820Sjeff int *num_using_this_depend; 80219820Sjeff} cdg_vertex_t; 81219820Sjeff 82219820Sjefftypedef struct _reachable_dest { 83219820Sjeff int switch_id; 84219820Sjeff struct _reachable_dest *next; 85219820Sjeff} reachable_dest_t; 86219820Sjeff 87219820Sjefftypedef struct _switch { 88219820Sjeff osm_switch_t *p_sw; 89219820Sjeff int *dij_channels; 90219820Sjeff int id; 91219820Sjeff int used_channels; 92219820Sjeff int q_state; 93219820Sjeff struct routing_table { 94219820Sjeff unsigned out_link; 95219820Sjeff unsigned lane; 96219820Sjeff } *routing_table; 97219820Sjeff unsigned int num_connections; 98219820Sjeff int *virtual_physical_port_table; 99219820Sjeff int *phys_connections; 100219820Sjeff} switch_t; 101219820Sjeff 102219820Sjefftypedef struct _lash { 103219820Sjeff osm_opensm_t *p_osm; 104219820Sjeff int num_switches; 105219820Sjeff uint8_t vl_min; 106219820Sjeff int balance_limit; 107219820Sjeff switch_t **switches; 108219820Sjeff cdg_vertex_t ****cdg_vertex_matrix; 109219820Sjeff int *num_mst_in_lane; 110219820Sjeff int ***virtual_location; 111219820Sjeff} lash_t; 112219820Sjeff 113219820Sjeffstatic cdg_vertex_t *create_cdg_vertex(unsigned num_switches) 114219820Sjeff{ 115219820Sjeff cdg_vertex_t *cdg_vertex = (cdg_vertex_t *) malloc(sizeof(cdg_vertex_t)); 116219820Sjeff 117219820Sjeff cdg_vertex->dependency = malloc((num_switches - 1) * sizeof(cdg_vertex_t *)); 118219820Sjeff cdg_vertex->num_using_this_depend = (int *)malloc((num_switches - 1) * sizeof(int)); 119219820Sjeff return cdg_vertex; 120219820Sjeff} 121219820Sjeff 122219820Sjeffstatic void connect_switches(lash_t * p_lash, int sw1, int sw2, int phy_port_1) 123219820Sjeff{ 124219820Sjeff osm_log_t *p_log = &p_lash->p_osm->log; 125219820Sjeff unsigned num = p_lash->switches[sw1]->num_connections; 126219820Sjeff 127219820Sjeff p_lash->switches[sw1]->phys_connections[num] = sw2; 128219820Sjeff p_lash->switches[sw1]->virtual_physical_port_table[num] = phy_port_1; 129219820Sjeff p_lash->switches[sw1]->num_connections++; 130219820Sjeff 131219820Sjeff OSM_LOG(p_log, OSM_LOG_VERBOSE, 132219820Sjeff "LASH connect: %d, %d, %d\n", sw1, sw2, 133219820Sjeff phy_port_1); 134219820Sjeff 135219820Sjeff} 136219820Sjeff 137219820Sjeffstatic osm_switch_t *get_osm_switch_from_port(osm_port_t * port) 138219820Sjeff{ 139219820Sjeff osm_physp_t *p = port->p_physp; 140219820Sjeff if (p->p_node->sw) 141219820Sjeff return p->p_node->sw; 142219820Sjeff else if (p->p_remote_physp->p_node->sw) 143219820Sjeff return p->p_remote_physp->p_node->sw; 144219820Sjeff return NULL; 145219820Sjeff} 146219820Sjeff 147219820Sjeff#if 0 148219820Sjeffstatic int randint(int high) 149219820Sjeff{ 150219820Sjeff int r; 151219820Sjeff 152219820Sjeff if (high == 0) 153219820Sjeff return 0; 154219820Sjeff r = rand(); 155219820Sjeff high++; 156219820Sjeff return (r % high); 157219820Sjeff} 158219820Sjeff#endif 159219820Sjeff 160219820Sjeffstatic int cycle_exists(cdg_vertex_t * start, cdg_vertex_t * current, 161219820Sjeff cdg_vertex_t * prev, int visit_num) 162219820Sjeff{ 163219820Sjeff cdg_vertex_t *h; 164219820Sjeff int i, new_visit_num; 165219820Sjeff int cycle_found = 0; 166219820Sjeff 167219820Sjeff if (current != NULL && current->visiting_number > 0) { 168219820Sjeff if (visit_num > current->visiting_number && current->seen == 0) { 169219820Sjeff h = start; 170219820Sjeff cycle_found = 1; 171219820Sjeff } 172219820Sjeff } else { 173219820Sjeff if (current == NULL) { 174219820Sjeff current = start; 175219820Sjeff CL_ASSERT(prev == NULL); 176219820Sjeff } 177219820Sjeff 178219820Sjeff current->visiting_number = visit_num; 179219820Sjeff 180219820Sjeff if (prev != NULL) { 181219820Sjeff prev->next = current; 182219820Sjeff CL_ASSERT(prev->to == current->from); 183219820Sjeff CL_ASSERT(prev->visiting_number > 0); 184219820Sjeff } 185219820Sjeff 186219820Sjeff new_visit_num = visit_num + 1; 187219820Sjeff 188219820Sjeff for (i = 0; i < current->num_dependencies; i++) { 189219820Sjeff cycle_found = 190219820Sjeff cycle_exists(start, current->dependency[i], current, 191219820Sjeff new_visit_num); 192219820Sjeff if (cycle_found == 1) 193219820Sjeff i = current->num_dependencies; 194219820Sjeff } 195219820Sjeff 196219820Sjeff current->seen = 1; 197219820Sjeff if (prev != NULL) 198219820Sjeff prev->next = NULL; 199219820Sjeff } 200219820Sjeff 201219820Sjeff return cycle_found; 202219820Sjeff} 203219820Sjeff 204219820Sjeffstatic void remove_semipermanent_depend_for_sp(lash_t * p_lash, int sw, 205219820Sjeff int dest_switch, int lane) 206219820Sjeff{ 207219820Sjeff switch_t **switches = p_lash->switches; 208219820Sjeff cdg_vertex_t ****cdg_vertex_matrix = p_lash->cdg_vertex_matrix; 209219820Sjeff int i_next_switch, output_link, i, next_link, i_next_next_switch, 210219820Sjeff depend = 0; 211219820Sjeff cdg_vertex_t *v; 212219820Sjeff int found; 213219820Sjeff 214219820Sjeff output_link = switches[sw]->routing_table[dest_switch].out_link; 215219820Sjeff i_next_switch = switches[sw]->phys_connections[output_link]; 216219820Sjeff 217219820Sjeff while (sw != dest_switch) { 218219820Sjeff v = cdg_vertex_matrix[lane][sw][i_next_switch]; 219219820Sjeff CL_ASSERT(v != NULL); 220219820Sjeff 221219820Sjeff if (v->num_using_vertex == 1) { 222219820Sjeff 223219820Sjeff cdg_vertex_matrix[lane][sw][i_next_switch] = NULL; 224219820Sjeff 225219820Sjeff free(v); 226219820Sjeff } else { 227219820Sjeff v->num_using_vertex--; 228219820Sjeff if (i_next_switch != dest_switch) { 229219820Sjeff next_link = 230219820Sjeff switches[i_next_switch]->routing_table[dest_switch].out_link; 231219820Sjeff i_next_next_switch = 232219820Sjeff switches[i_next_switch]->phys_connections[next_link]; 233219820Sjeff found = 0; 234219820Sjeff 235219820Sjeff for (i = 0; i < v->num_dependencies; i++) 236219820Sjeff if (v->dependency[i] == 237219820Sjeff cdg_vertex_matrix[lane][i_next_switch] 238219820Sjeff [i_next_next_switch]) { 239219820Sjeff found = 1; 240219820Sjeff depend = i; 241219820Sjeff } 242219820Sjeff 243219820Sjeff CL_ASSERT(found); 244219820Sjeff 245219820Sjeff if (v->num_using_this_depend[depend] == 1) { 246219820Sjeff for (i = depend; 247219820Sjeff i < v->num_dependencies - 1; i++) { 248219820Sjeff v->dependency[i] = 249219820Sjeff v->dependency[i + 1]; 250219820Sjeff v->num_using_this_depend[i] = 251219820Sjeff v->num_using_this_depend[i + 252219820Sjeff 1]; 253219820Sjeff } 254219820Sjeff 255219820Sjeff v->num_dependencies--; 256219820Sjeff } else 257219820Sjeff v->num_using_this_depend[depend]--; 258219820Sjeff } 259219820Sjeff } 260219820Sjeff 261219820Sjeff sw = i_next_switch; 262219820Sjeff output_link = switches[sw]->routing_table[dest_switch].out_link; 263219820Sjeff 264219820Sjeff if (sw != dest_switch) 265219820Sjeff i_next_switch = 266219820Sjeff switches[sw]->phys_connections[output_link]; 267219820Sjeff } 268219820Sjeff} 269219820Sjeff 270219820Sjeffinline static void enqueue(cl_list_t * bfsq, switch_t * sw) 271219820Sjeff{ 272219820Sjeff CL_ASSERT(sw->q_state == UNQUEUED); 273219820Sjeff sw->q_state = Q_MEMBER; 274219820Sjeff cl_list_insert_tail(bfsq, sw); 275219820Sjeff} 276219820Sjeff 277219820Sjeffinline static void dequeue(cl_list_t * bfsq, switch_t ** sw) 278219820Sjeff{ 279219820Sjeff *sw = (switch_t *) cl_list_remove_head(bfsq); 280219820Sjeff CL_ASSERT((*sw)->q_state == Q_MEMBER); 281219820Sjeff (*sw)->q_state = MST_MEMBER; 282219820Sjeff} 283219820Sjeff 284219820Sjeffstatic int get_phys_connection(switch_t *sw, int switch_to) 285219820Sjeff{ 286219820Sjeff unsigned int i = 0; 287219820Sjeff 288219820Sjeff for (i = 0; i < sw->num_connections; i++) 289219820Sjeff if (sw->phys_connections[i] == switch_to) 290219820Sjeff return i; 291219820Sjeff return i; 292219820Sjeff} 293219820Sjeff 294219820Sjeffstatic void shortest_path(lash_t * p_lash, int ir) 295219820Sjeff{ 296219820Sjeff switch_t **switches = p_lash->switches, *sw, *swi; 297219820Sjeff unsigned int i; 298219820Sjeff cl_list_t bfsq; 299219820Sjeff 300219820Sjeff cl_list_construct(&bfsq); 301219820Sjeff cl_list_init(&bfsq, 20); 302219820Sjeff 303219820Sjeff enqueue(&bfsq, switches[ir]); 304219820Sjeff 305219820Sjeff while (!cl_is_list_empty(&bfsq)) { 306219820Sjeff dequeue(&bfsq, &sw); 307219820Sjeff for (i = 0; i < sw->num_connections; i++) { 308219820Sjeff swi = switches[sw->phys_connections[i]]; 309219820Sjeff if (swi->q_state == UNQUEUED) { 310219820Sjeff enqueue(&bfsq, swi); 311219820Sjeff sw->dij_channels[sw->used_channels++] = swi->id; 312219820Sjeff } 313219820Sjeff } 314219820Sjeff } 315219820Sjeff 316219820Sjeff cl_list_destroy(&bfsq); 317219820Sjeff} 318219820Sjeff 319219820Sjeffstatic void generate_routing_func_for_mst(lash_t * p_lash, int sw_id, 320219820Sjeff reachable_dest_t ** destinations) 321219820Sjeff{ 322219820Sjeff int i, next_switch; 323219820Sjeff switch_t *sw = p_lash->switches[sw_id]; 324219820Sjeff int num_channels = sw->used_channels; 325219820Sjeff reachable_dest_t *dest, *i_dest, *concat_dest = NULL, *prev; 326219820Sjeff 327219820Sjeff for (i = 0; i < num_channels; i++) { 328219820Sjeff next_switch = sw->dij_channels[i]; 329219820Sjeff generate_routing_func_for_mst(p_lash, next_switch, &dest); 330219820Sjeff 331219820Sjeff i_dest = dest; 332219820Sjeff prev = i_dest; 333219820Sjeff 334219820Sjeff while (i_dest != NULL) { 335219820Sjeff if (sw->routing_table[i_dest->switch_id].out_link == 336219820Sjeff NONE) { 337219820Sjeff sw->routing_table[i_dest->switch_id].out_link = 338219820Sjeff get_phys_connection(sw, next_switch); 339219820Sjeff } 340219820Sjeff 341219820Sjeff prev = i_dest; 342219820Sjeff i_dest = i_dest->next; 343219820Sjeff } 344219820Sjeff 345219820Sjeff CL_ASSERT(prev->next == NULL); 346219820Sjeff prev->next = concat_dest; 347219820Sjeff concat_dest = dest; 348219820Sjeff } 349219820Sjeff 350219820Sjeff i_dest = (reachable_dest_t *) malloc(sizeof(reachable_dest_t)); 351219820Sjeff i_dest->switch_id = sw->id; 352219820Sjeff i_dest->next = concat_dest; 353219820Sjeff *destinations = i_dest; 354219820Sjeff} 355219820Sjeff 356219820Sjeffstatic void generate_cdg_for_sp(lash_t * p_lash, int sw, int dest_switch, 357219820Sjeff int lane) 358219820Sjeff{ 359219820Sjeff unsigned num_switches = p_lash->num_switches; 360219820Sjeff switch_t **switches = p_lash->switches; 361219820Sjeff cdg_vertex_t ****cdg_vertex_matrix = p_lash->cdg_vertex_matrix; 362219820Sjeff int next_switch, output_link, j, exists; 363219820Sjeff cdg_vertex_t *v, *prev = NULL; 364219820Sjeff 365219820Sjeff output_link = switches[sw]->routing_table[dest_switch].out_link; 366219820Sjeff next_switch = switches[sw]->phys_connections[output_link]; 367219820Sjeff 368219820Sjeff while (sw != dest_switch) { 369219820Sjeff 370219820Sjeff if (cdg_vertex_matrix[lane][sw][next_switch] == NULL) { 371219820Sjeff unsigned i; 372219820Sjeff v = create_cdg_vertex(num_switches); 373219820Sjeff 374219820Sjeff for (i = 0; i < num_switches - 1; i++) { 375219820Sjeff v->dependency[i] = NULL; 376219820Sjeff v->num_using_this_depend[i] = 0; 377219820Sjeff } 378219820Sjeff 379219820Sjeff v->num_using_vertex = 0; 380219820Sjeff v->num_dependencies = 0; 381219820Sjeff v->from = sw; 382219820Sjeff v->to = next_switch; 383219820Sjeff v->seen = 0; 384219820Sjeff v->visiting_number = 0; 385219820Sjeff v->next = NULL; 386219820Sjeff v->temp = 1; 387219820Sjeff v->num_temp_depend = 0; 388219820Sjeff 389219820Sjeff cdg_vertex_matrix[lane][sw][next_switch] = v; 390219820Sjeff } else 391219820Sjeff v = cdg_vertex_matrix[lane][sw][next_switch]; 392219820Sjeff 393219820Sjeff v->num_using_vertex++; 394219820Sjeff 395219820Sjeff if (prev != NULL) { 396219820Sjeff exists = 0; 397219820Sjeff 398219820Sjeff for (j = 0; j < prev->num_dependencies; j++) 399219820Sjeff if (prev->dependency[j] == v) { 400219820Sjeff exists = 1; 401219820Sjeff prev->num_using_this_depend[j]++; 402219820Sjeff } 403219820Sjeff 404219820Sjeff if (exists == 0) { 405219820Sjeff prev->dependency[prev->num_dependencies] = v; 406219820Sjeff prev->num_using_this_depend[prev->num_dependencies]++; 407219820Sjeff prev->num_dependencies++; 408219820Sjeff 409219820Sjeff CL_ASSERT(prev->num_dependencies < (int)num_switches); 410219820Sjeff 411219820Sjeff if (prev->temp == 0) 412219820Sjeff prev->num_temp_depend++; 413219820Sjeff 414219820Sjeff } 415219820Sjeff } 416219820Sjeff 417219820Sjeff sw = next_switch; 418219820Sjeff output_link = switches[sw]->routing_table[dest_switch].out_link; 419219820Sjeff 420219820Sjeff if (sw != dest_switch) { 421219820Sjeff CL_ASSERT(output_link != NONE); 422219820Sjeff next_switch = switches[sw]->phys_connections[output_link]; 423219820Sjeff } 424219820Sjeff 425219820Sjeff prev = v; 426219820Sjeff } 427219820Sjeff} 428219820Sjeff 429219820Sjeffstatic void set_temp_depend_to_permanent_for_sp(lash_t * p_lash, int sw, 430219820Sjeff int dest_switch, int lane) 431219820Sjeff{ 432219820Sjeff switch_t **switches = p_lash->switches; 433219820Sjeff cdg_vertex_t ****cdg_vertex_matrix = p_lash->cdg_vertex_matrix; 434219820Sjeff int next_switch, output_link; 435219820Sjeff cdg_vertex_t *v; 436219820Sjeff 437219820Sjeff output_link = switches[sw]->routing_table[dest_switch].out_link; 438219820Sjeff next_switch = switches[sw]->phys_connections[output_link]; 439219820Sjeff 440219820Sjeff while (sw != dest_switch) { 441219820Sjeff v = cdg_vertex_matrix[lane][sw][next_switch]; 442219820Sjeff CL_ASSERT(v != NULL); 443219820Sjeff 444219820Sjeff if (v->temp == 1) 445219820Sjeff v->temp = 0; 446219820Sjeff else 447219820Sjeff v->num_temp_depend = 0; 448219820Sjeff 449219820Sjeff sw = next_switch; 450219820Sjeff output_link = switches[sw]->routing_table[dest_switch].out_link; 451219820Sjeff 452219820Sjeff if (sw != dest_switch) 453219820Sjeff next_switch = 454219820Sjeff switches[sw]->phys_connections[output_link]; 455219820Sjeff } 456219820Sjeff 457219820Sjeff} 458219820Sjeff 459219820Sjeffstatic void remove_temp_depend_for_sp(lash_t * p_lash, int sw, int dest_switch, 460219820Sjeff int lane) 461219820Sjeff{ 462219820Sjeff switch_t **switches = p_lash->switches; 463219820Sjeff cdg_vertex_t ****cdg_vertex_matrix = p_lash->cdg_vertex_matrix; 464219820Sjeff int next_switch, output_link, i; 465219820Sjeff cdg_vertex_t *v; 466219820Sjeff 467219820Sjeff output_link = switches[sw]->routing_table[dest_switch].out_link; 468219820Sjeff next_switch = switches[sw]->phys_connections[output_link]; 469219820Sjeff 470219820Sjeff while (sw != dest_switch) { 471219820Sjeff v = cdg_vertex_matrix[lane][sw][next_switch]; 472219820Sjeff CL_ASSERT(v != NULL); 473219820Sjeff 474219820Sjeff if (v->temp == 1) { 475219820Sjeff cdg_vertex_matrix[lane][sw][next_switch] = NULL; 476219820Sjeff free(v); 477219820Sjeff } else { 478219820Sjeff CL_ASSERT(v->num_temp_depend <= v->num_dependencies); 479219820Sjeff v->num_dependencies = 480219820Sjeff v->num_dependencies - v->num_temp_depend; 481219820Sjeff v->num_temp_depend = 0; 482219820Sjeff v->num_using_vertex--; 483219820Sjeff 484219820Sjeff for (i = v->num_dependencies; 485219820Sjeff i < p_lash->num_switches - 1; i++) 486219820Sjeff v->num_using_this_depend[i] = 0; 487219820Sjeff } 488219820Sjeff 489219820Sjeff sw = next_switch; 490219820Sjeff output_link = switches[sw]->routing_table[dest_switch].out_link; 491219820Sjeff 492219820Sjeff if (sw != dest_switch) 493219820Sjeff next_switch = 494219820Sjeff switches[sw]->phys_connections[output_link]; 495219820Sjeff 496219820Sjeff } 497219820Sjeff} 498219820Sjeff 499219820Sjeffstatic void balance_virtual_lanes(lash_t * p_lash, unsigned lanes_needed) 500219820Sjeff{ 501219820Sjeff unsigned num_switches = p_lash->num_switches; 502219820Sjeff cdg_vertex_t ****cdg_vertex_matrix = p_lash->cdg_vertex_matrix; 503219820Sjeff int *num_mst_in_lane = p_lash->num_mst_in_lane; 504219820Sjeff int ***virtual_location = p_lash->virtual_location; 505219820Sjeff int min_filled_lane, max_filled_lane, medium_filled_lane, trials; 506219820Sjeff int old_min_filled_lane, old_max_filled_lane, new_num_min_lane, 507219820Sjeff new_num_max_lane; 508219820Sjeff unsigned int i, j; 509219820Sjeff int src, dest, start, next_switch, output_link; 510219820Sjeff int next_switch2, output_link2; 511219820Sjeff int stop = 0, cycle_found; 512219820Sjeff int cycle_found2; 513219820Sjeff 514219820Sjeff max_filled_lane = 0; 515219820Sjeff min_filled_lane = lanes_needed - 1; 516219820Sjeff 517219820Sjeff if (max_filled_lane > 1) 518219820Sjeff medium_filled_lane = max_filled_lane - 1; 519219820Sjeff 520219820Sjeff trials = num_mst_in_lane[max_filled_lane]; 521219820Sjeff if (lanes_needed == 1) 522219820Sjeff stop = 1; 523219820Sjeff 524219820Sjeff while (stop == 0) { 525219820Sjeff src = abs(rand()) % (num_switches); 526219820Sjeff dest = abs(rand()) % (num_switches); 527219820Sjeff 528219820Sjeff while (virtual_location[src][dest][max_filled_lane] != 1) { 529219820Sjeff start = dest; 530219820Sjeff if (dest == num_switches - 1) 531219820Sjeff dest = 0; 532219820Sjeff else 533219820Sjeff dest++; 534219820Sjeff 535219820Sjeff while (dest != start 536219820Sjeff && virtual_location[src][dest][max_filled_lane] 537219820Sjeff != 1) { 538219820Sjeff if (dest == num_switches - 1) 539219820Sjeff dest = 0; 540219820Sjeff else 541219820Sjeff dest++; 542219820Sjeff } 543219820Sjeff 544219820Sjeff if (virtual_location[src][dest][max_filled_lane] != 1) { 545219820Sjeff if (src == num_switches - 1) 546219820Sjeff src = 0; 547219820Sjeff else 548219820Sjeff src++; 549219820Sjeff } 550219820Sjeff } 551219820Sjeff 552219820Sjeff generate_cdg_for_sp(p_lash, src, dest, min_filled_lane); 553219820Sjeff generate_cdg_for_sp(p_lash, dest, src, min_filled_lane); 554219820Sjeff 555219820Sjeff output_link = p_lash->switches[src]->routing_table[dest].out_link; 556219820Sjeff next_switch = p_lash->switches[src]->phys_connections[output_link]; 557219820Sjeff 558219820Sjeff output_link2 = p_lash->switches[dest]->routing_table[src].out_link; 559219820Sjeff next_switch2 = p_lash->switches[dest]->phys_connections[output_link2]; 560219820Sjeff 561219820Sjeff CL_ASSERT(cdg_vertex_matrix[min_filled_lane][src][next_switch] != NULL); 562219820Sjeff CL_ASSERT(cdg_vertex_matrix[min_filled_lane][dest][next_switch2] != NULL); 563219820Sjeff 564219820Sjeff cycle_found = 565219820Sjeff cycle_exists(cdg_vertex_matrix[min_filled_lane][src][next_switch], NULL, NULL, 566219820Sjeff 1); 567219820Sjeff cycle_found2 = 568219820Sjeff cycle_exists(cdg_vertex_matrix[min_filled_lane][dest][next_switch2], NULL, NULL, 569219820Sjeff 1); 570219820Sjeff 571219820Sjeff for (i = 0; i < num_switches; i++) 572219820Sjeff for (j = 0; j < num_switches; j++) 573219820Sjeff if (cdg_vertex_matrix[min_filled_lane][i][j] != NULL) { 574219820Sjeff cdg_vertex_matrix[min_filled_lane][i][j]->visiting_number = 575219820Sjeff 0; 576219820Sjeff cdg_vertex_matrix[min_filled_lane][i][j]->seen = 0; 577219820Sjeff } 578219820Sjeff 579219820Sjeff if (cycle_found == 1 || cycle_found2 == 1) { 580219820Sjeff remove_temp_depend_for_sp(p_lash, src, dest, min_filled_lane); 581219820Sjeff remove_temp_depend_for_sp(p_lash, dest, src, min_filled_lane); 582219820Sjeff 583219820Sjeff virtual_location[src][dest][max_filled_lane] = 2; 584219820Sjeff virtual_location[dest][src][max_filled_lane] = 2; 585219820Sjeff trials--; 586219820Sjeff trials--; 587219820Sjeff } else { 588219820Sjeff set_temp_depend_to_permanent_for_sp(p_lash, src, dest, min_filled_lane); 589219820Sjeff set_temp_depend_to_permanent_for_sp(p_lash, dest, src, min_filled_lane); 590219820Sjeff 591219820Sjeff num_mst_in_lane[max_filled_lane]--; 592219820Sjeff num_mst_in_lane[max_filled_lane]--; 593219820Sjeff num_mst_in_lane[min_filled_lane]++; 594219820Sjeff num_mst_in_lane[min_filled_lane]++; 595219820Sjeff 596219820Sjeff remove_semipermanent_depend_for_sp(p_lash, src, dest, max_filled_lane); 597219820Sjeff remove_semipermanent_depend_for_sp(p_lash, dest, src, max_filled_lane); 598219820Sjeff virtual_location[src][dest][max_filled_lane] = 0; 599219820Sjeff virtual_location[dest][src][max_filled_lane] = 0; 600219820Sjeff virtual_location[src][dest][min_filled_lane] = 1; 601219820Sjeff virtual_location[dest][src][min_filled_lane] = 1; 602219820Sjeff p_lash->switches[src]->routing_table[dest].lane = min_filled_lane; 603219820Sjeff p_lash->switches[dest]->routing_table[src].lane = min_filled_lane; 604219820Sjeff } 605219820Sjeff 606219820Sjeff if (trials == 0) 607219820Sjeff stop = 1; 608219820Sjeff else { 609219820Sjeff if (num_mst_in_lane[max_filled_lane] - num_mst_in_lane[min_filled_lane] < 610219820Sjeff p_lash->balance_limit) 611219820Sjeff stop = 1; 612219820Sjeff } 613219820Sjeff 614219820Sjeff old_min_filled_lane = min_filled_lane; 615219820Sjeff old_max_filled_lane = max_filled_lane; 616219820Sjeff 617219820Sjeff new_num_min_lane = MAX_INT; 618219820Sjeff new_num_max_lane = 0; 619219820Sjeff 620219820Sjeff for (i = 0; i < lanes_needed; i++) { 621219820Sjeff 622219820Sjeff if (num_mst_in_lane[i] < new_num_min_lane) { 623219820Sjeff new_num_min_lane = num_mst_in_lane[i]; 624219820Sjeff min_filled_lane = i; 625219820Sjeff } 626219820Sjeff 627219820Sjeff if (num_mst_in_lane[i] > new_num_max_lane) { 628219820Sjeff new_num_max_lane = num_mst_in_lane[i]; 629219820Sjeff max_filled_lane = i; 630219820Sjeff } 631219820Sjeff } 632219820Sjeff 633219820Sjeff if (old_min_filled_lane != min_filled_lane) { 634219820Sjeff trials = num_mst_in_lane[max_filled_lane]; 635219820Sjeff for (i = 0; i < num_switches; i++) 636219820Sjeff for (j = 0; j < num_switches; j++) 637219820Sjeff if (virtual_location[i][j][max_filled_lane] == 2) 638219820Sjeff virtual_location[i][j][max_filled_lane] = 1; 639219820Sjeff } 640219820Sjeff 641219820Sjeff if (old_max_filled_lane != max_filled_lane) { 642219820Sjeff trials = num_mst_in_lane[max_filled_lane]; 643219820Sjeff for (i = 0; i < num_switches; i++) 644219820Sjeff for (j = 0; j < num_switches; j++) 645219820Sjeff if (virtual_location[i][j][old_max_filled_lane] == 2) 646219820Sjeff virtual_location[i][j][old_max_filled_lane] = 1; 647219820Sjeff } 648219820Sjeff } 649219820Sjeff} 650219820Sjeff 651219820Sjeffstatic switch_t *switch_create(lash_t * p_lash, unsigned id, osm_switch_t * p_sw) 652219820Sjeff{ 653219820Sjeff unsigned num_switches = p_lash->num_switches; 654219820Sjeff unsigned num_ports = p_sw->num_ports; 655219820Sjeff switch_t *sw; 656219820Sjeff unsigned int i; 657219820Sjeff 658219820Sjeff sw = malloc(sizeof(*sw)); 659219820Sjeff if (!sw) 660219820Sjeff return NULL; 661219820Sjeff 662219820Sjeff memset(sw, 0, sizeof(*sw)); 663219820Sjeff 664219820Sjeff sw->id = id; 665219820Sjeff sw->dij_channels = malloc(num_ports * sizeof(int)); 666219820Sjeff if (!sw->dij_channels) { 667219820Sjeff free(sw); 668219820Sjeff return NULL; 669219820Sjeff } 670219820Sjeff 671219820Sjeff sw->virtual_physical_port_table = malloc(num_ports * sizeof(int)); 672219820Sjeff if (!sw->virtual_physical_port_table) { 673219820Sjeff free(sw->dij_channels); 674219820Sjeff free(sw); 675219820Sjeff return NULL; 676219820Sjeff } 677219820Sjeff 678219820Sjeff sw->phys_connections = malloc(num_ports * sizeof(int)); 679219820Sjeff if (!sw->phys_connections) { 680219820Sjeff free(sw->virtual_physical_port_table); 681219820Sjeff free(sw->dij_channels); 682219820Sjeff free(sw); 683219820Sjeff return NULL; 684219820Sjeff } 685219820Sjeff 686219820Sjeff sw->routing_table = malloc(num_switches * sizeof(sw->routing_table[0])); 687219820Sjeff if (!sw->routing_table) { 688219820Sjeff free(sw->phys_connections); 689219820Sjeff free(sw->virtual_physical_port_table); 690219820Sjeff free(sw->dij_channels); 691219820Sjeff free(sw); 692219820Sjeff return NULL; 693219820Sjeff } 694219820Sjeff 695219820Sjeff for (i = 0; i < num_switches; i++) { 696219820Sjeff sw->routing_table[i].out_link = NONE; 697219820Sjeff sw->routing_table[i].lane = NONE; 698219820Sjeff } 699219820Sjeff 700219820Sjeff for (i = 0; i < num_ports; i++) { 701219820Sjeff sw->virtual_physical_port_table[i] = -1; 702219820Sjeff sw->phys_connections[i] = NONE; 703219820Sjeff } 704219820Sjeff 705219820Sjeff sw->p_sw = p_sw; 706219820Sjeff if (p_sw) 707219820Sjeff p_sw->priv = sw; 708219820Sjeff 709219820Sjeff return sw; 710219820Sjeff} 711219820Sjeff 712219820Sjeffstatic void switch_delete(switch_t * sw) 713219820Sjeff{ 714219820Sjeff if (sw->dij_channels) 715219820Sjeff free(sw->dij_channels); 716219820Sjeff if (sw->virtual_physical_port_table) 717219820Sjeff free(sw->virtual_physical_port_table); 718219820Sjeff if (sw->phys_connections) 719219820Sjeff free(sw->phys_connections); 720219820Sjeff if (sw->routing_table) 721219820Sjeff free(sw->routing_table); 722219820Sjeff free(sw); 723219820Sjeff} 724219820Sjeff 725219820Sjeffstatic void free_lash_structures(lash_t * p_lash) 726219820Sjeff{ 727219820Sjeff unsigned int i, j, k; 728219820Sjeff unsigned num_switches = p_lash->num_switches; 729219820Sjeff osm_log_t *p_log = &p_lash->p_osm->log; 730219820Sjeff 731219820Sjeff OSM_LOG_ENTER(p_log); 732219820Sjeff 733219820Sjeff // free cdg_vertex_matrix 734219820Sjeff for (i = 0; i < p_lash->vl_min; i++) { 735219820Sjeff for (j = 0; j < num_switches; j++) { 736219820Sjeff for (k = 0; k < num_switches; k++) { 737219820Sjeff if (p_lash->cdg_vertex_matrix[i][j][k]) { 738219820Sjeff 739219820Sjeff if (p_lash->cdg_vertex_matrix[i][j][k]->dependency) 740219820Sjeff free(p_lash->cdg_vertex_matrix[i][j][k]-> 741219820Sjeff dependency); 742219820Sjeff 743219820Sjeff if (p_lash->cdg_vertex_matrix[i][j][k]-> 744219820Sjeff num_using_this_depend) 745219820Sjeff free(p_lash->cdg_vertex_matrix[i][j][k]-> 746219820Sjeff num_using_this_depend); 747219820Sjeff 748219820Sjeff free(p_lash->cdg_vertex_matrix[i][j][k]); 749219820Sjeff } 750219820Sjeff } 751219820Sjeff if (p_lash->cdg_vertex_matrix[i][j]) 752219820Sjeff free(p_lash->cdg_vertex_matrix[i][j]); 753219820Sjeff } 754219820Sjeff if (p_lash->cdg_vertex_matrix[i]) 755219820Sjeff free(p_lash->cdg_vertex_matrix[i]); 756219820Sjeff } 757219820Sjeff 758219820Sjeff if (p_lash->cdg_vertex_matrix) 759219820Sjeff free(p_lash->cdg_vertex_matrix); 760219820Sjeff 761219820Sjeff // free virtual_location 762219820Sjeff for (i = 0; i < num_switches; i++) { 763219820Sjeff for (j = 0; j < num_switches; j++) { 764219820Sjeff if (p_lash->virtual_location[i][j]) 765219820Sjeff free(p_lash->virtual_location[i][j]); 766219820Sjeff } 767219820Sjeff if (p_lash->virtual_location[i]) 768219820Sjeff free(p_lash->virtual_location[i]); 769219820Sjeff } 770219820Sjeff if (p_lash->virtual_location) 771219820Sjeff free(p_lash->virtual_location); 772219820Sjeff 773219820Sjeff if (p_lash->num_mst_in_lane) 774219820Sjeff free(p_lash->num_mst_in_lane); 775219820Sjeff 776219820Sjeff OSM_LOG_EXIT(p_log); 777219820Sjeff} 778219820Sjeff 779219820Sjeffstatic int init_lash_structures(lash_t * p_lash) 780219820Sjeff{ 781219820Sjeff unsigned vl_min = p_lash->vl_min; 782219820Sjeff unsigned num_switches = p_lash->num_switches; 783219820Sjeff osm_log_t *p_log = &p_lash->p_osm->log; 784219820Sjeff int status = 0; 785219820Sjeff unsigned int i, j, k; 786219820Sjeff 787219820Sjeff OSM_LOG_ENTER(p_log); 788219820Sjeff 789219820Sjeff // initialise cdg_vertex_matrix[num_switches][num_switches][num_switches] 790219820Sjeff p_lash->cdg_vertex_matrix = 791219820Sjeff (cdg_vertex_t ****) malloc(vl_min * sizeof(cdg_vertex_t ****)); 792219820Sjeff for (i = 0; i < vl_min; i++) { 793219820Sjeff p_lash->cdg_vertex_matrix[i] = 794219820Sjeff (cdg_vertex_t ***) malloc(num_switches * 795219820Sjeff sizeof(cdg_vertex_t ***)); 796219820Sjeff 797219820Sjeff if (p_lash->cdg_vertex_matrix[i] == NULL) 798219820Sjeff goto Exit_Mem_Error; 799219820Sjeff } 800219820Sjeff 801219820Sjeff for (i = 0; i < vl_min; i++) { 802219820Sjeff for (j = 0; j < num_switches; j++) { 803219820Sjeff p_lash->cdg_vertex_matrix[i][j] = 804219820Sjeff (cdg_vertex_t **) malloc(num_switches * 805219820Sjeff sizeof(cdg_vertex_t **)); 806219820Sjeff if (p_lash->cdg_vertex_matrix[i][j] == NULL) 807219820Sjeff goto Exit_Mem_Error; 808219820Sjeff 809219820Sjeff for (k = 0; k < num_switches; k++) { 810219820Sjeff p_lash->cdg_vertex_matrix[i][j][k] = NULL; 811219820Sjeff } 812219820Sjeff } 813219820Sjeff } 814219820Sjeff 815219820Sjeff // initialise virtual_location[num_switches][num_switches][num_layers], 816219820Sjeff // default value = 0 817219820Sjeff p_lash->virtual_location = 818219820Sjeff (int ***)malloc(num_switches * sizeof(int ***)); 819219820Sjeff if (p_lash->virtual_location == NULL) 820219820Sjeff goto Exit_Mem_Error; 821219820Sjeff 822219820Sjeff for (i = 0; i < num_switches; i++) { 823219820Sjeff p_lash->virtual_location[i] = 824219820Sjeff (int **)malloc(num_switches * sizeof(int **)); 825219820Sjeff if (p_lash->virtual_location[i] == NULL) 826219820Sjeff goto Exit_Mem_Error; 827219820Sjeff } 828219820Sjeff 829219820Sjeff for (i = 0; i < num_switches; i++) { 830219820Sjeff for (j = 0; j < num_switches; j++) { 831219820Sjeff p_lash->virtual_location[i][j] = 832219820Sjeff (int *)malloc(vl_min * sizeof(int *)); 833219820Sjeff if (p_lash->virtual_location[i][j] == NULL) 834219820Sjeff goto Exit_Mem_Error; 835219820Sjeff for (k = 0; k < vl_min; k++) { 836219820Sjeff p_lash->virtual_location[i][j][k] = 0; 837219820Sjeff } 838219820Sjeff } 839219820Sjeff } 840219820Sjeff 841219820Sjeff // initialise num_mst_in_lane[num_switches], default 0 842219820Sjeff p_lash->num_mst_in_lane = (int *)malloc(num_switches * sizeof(int)); 843219820Sjeff if (p_lash->num_mst_in_lane == NULL) 844219820Sjeff goto Exit_Mem_Error; 845219820Sjeff memset(p_lash->num_mst_in_lane, 0, 846219820Sjeff num_switches * sizeof(p_lash->num_mst_in_lane[0])); 847219820Sjeff 848219820Sjeff goto Exit; 849219820Sjeff 850219820SjeffExit_Mem_Error: 851219820Sjeff status = -1; 852219820Sjeff OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 4D01: " 853219820Sjeff "Could not allocate required memory for LASH errno %d, errno %d for lack of memory\n", 854219820Sjeff errno, ENOMEM); 855219820Sjeff 856219820SjeffExit: 857219820Sjeff OSM_LOG_EXIT(p_log); 858219820Sjeff return status; 859219820Sjeff} 860219820Sjeff 861219820Sjeffstatic int lash_core(lash_t * p_lash) 862219820Sjeff{ 863219820Sjeff osm_log_t *p_log = &p_lash->p_osm->log; 864219820Sjeff unsigned num_switches = p_lash->num_switches; 865219820Sjeff switch_t **switches = p_lash->switches; 866219820Sjeff unsigned lanes_needed = 1; 867219820Sjeff unsigned int i, j, k, dest_switch = 0; 868219820Sjeff reachable_dest_t *dests, *idest; 869219820Sjeff int cycle_found = 0; 870219820Sjeff unsigned v_lane; 871219820Sjeff int stop = 0, output_link, i_next_switch; 872219820Sjeff int output_link2, i_next_switch2; 873219820Sjeff int cycle_found2 = 0; 874219820Sjeff int status = 0; 875219820Sjeff int *switch_bitmap; /* Bitmap to check if we have processed this pair */ 876219820Sjeff 877219820Sjeff OSM_LOG_ENTER(p_log); 878219820Sjeff 879219820Sjeff for (i = 0; i < num_switches; i++) { 880219820Sjeff 881219820Sjeff shortest_path(p_lash, i); 882219820Sjeff generate_routing_func_for_mst(p_lash, i, &dests); 883219820Sjeff 884219820Sjeff idest = dests; 885219820Sjeff while (idest != NULL) { 886219820Sjeff dests = dests->next; 887219820Sjeff free(idest); 888219820Sjeff idest = dests; 889219820Sjeff } 890219820Sjeff 891219820Sjeff for (j = 0; j < num_switches; j++) { 892219820Sjeff switches[j]->used_channels = 0; 893219820Sjeff switches[j]->q_state = UNQUEUED; 894219820Sjeff } 895219820Sjeff } 896219820Sjeff 897219820Sjeff switch_bitmap = malloc(num_switches * num_switches * sizeof(int)); 898219820Sjeff if (!switch_bitmap) { 899219820Sjeff OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 4D04: " 900219820Sjeff "Failed allocating switch_bitmap - out of memory\n"); 901219820Sjeff goto Exit; 902219820Sjeff } 903219820Sjeff memset(switch_bitmap, 0, num_switches * num_switches * sizeof(int)); 904219820Sjeff 905219820Sjeff for (i = 0; i < num_switches; i++) { 906219820Sjeff for (dest_switch = 0; dest_switch < num_switches; dest_switch++) 907219820Sjeff if (dest_switch != i && switch_bitmap[i * num_switches + dest_switch] == 0) { 908219820Sjeff v_lane = 0; 909219820Sjeff stop = 0; 910219820Sjeff while (v_lane < lanes_needed && stop == 0) { 911219820Sjeff generate_cdg_for_sp(p_lash, i, dest_switch, v_lane); 912219820Sjeff generate_cdg_for_sp(p_lash, dest_switch, i, v_lane); 913219820Sjeff 914219820Sjeff output_link = 915219820Sjeff switches[i]->routing_table[dest_switch].out_link; 916219820Sjeff output_link2 = 917219820Sjeff switches[dest_switch]->routing_table[i].out_link; 918219820Sjeff 919219820Sjeff i_next_switch = switches[i]->phys_connections[output_link]; 920219820Sjeff i_next_switch2 = 921219820Sjeff switches[dest_switch]->phys_connections[output_link2]; 922219820Sjeff 923219820Sjeff CL_ASSERT(p_lash-> 924219820Sjeff cdg_vertex_matrix[v_lane][i][i_next_switch] != 925219820Sjeff NULL); 926219820Sjeff CL_ASSERT(p_lash-> 927219820Sjeff cdg_vertex_matrix[v_lane][dest_switch] 928219820Sjeff [i_next_switch2] != NULL); 929219820Sjeff 930219820Sjeff cycle_found = 931219820Sjeff cycle_exists(p_lash-> 932219820Sjeff cdg_vertex_matrix[v_lane][i] 933219820Sjeff [i_next_switch], NULL, NULL, 1); 934219820Sjeff cycle_found2 = 935219820Sjeff cycle_exists(p_lash-> 936219820Sjeff cdg_vertex_matrix[v_lane][dest_switch] 937219820Sjeff [i_next_switch2], NULL, NULL, 1); 938219820Sjeff 939219820Sjeff for (j = 0; j < num_switches; j++) 940219820Sjeff for (k = 0; k < num_switches; k++) 941219820Sjeff if (p_lash-> 942219820Sjeff cdg_vertex_matrix[v_lane][j][k] != 943219820Sjeff NULL) { 944219820Sjeff p_lash-> 945219820Sjeff cdg_vertex_matrix[v_lane][j] 946219820Sjeff [k]->visiting_number = 0; 947219820Sjeff p_lash-> 948219820Sjeff cdg_vertex_matrix[v_lane][j] 949219820Sjeff [k]->seen = 0; 950219820Sjeff } 951219820Sjeff 952219820Sjeff if (cycle_found == 1 || cycle_found2 == 1) { 953219820Sjeff remove_temp_depend_for_sp(p_lash, i, dest_switch, 954219820Sjeff v_lane); 955219820Sjeff remove_temp_depend_for_sp(p_lash, dest_switch, i, 956219820Sjeff v_lane); 957219820Sjeff v_lane++; 958219820Sjeff } else { 959219820Sjeff set_temp_depend_to_permanent_for_sp(p_lash, i, 960219820Sjeff dest_switch, 961219820Sjeff v_lane); 962219820Sjeff set_temp_depend_to_permanent_for_sp(p_lash, 963219820Sjeff dest_switch, i, 964219820Sjeff v_lane); 965219820Sjeff stop = 1; 966219820Sjeff p_lash->num_mst_in_lane[v_lane]++; 967219820Sjeff p_lash->num_mst_in_lane[v_lane]++; 968219820Sjeff } 969219820Sjeff } 970219820Sjeff 971219820Sjeff switches[i]->routing_table[dest_switch].lane = v_lane; 972219820Sjeff switches[dest_switch]->routing_table[i].lane = v_lane; 973219820Sjeff 974219820Sjeff if (cycle_found == 1 || cycle_found2 == 1) { 975219820Sjeff if (++lanes_needed > p_lash->vl_min) 976219820Sjeff goto Error_Not_Enough_Lanes; 977219820Sjeff 978219820Sjeff generate_cdg_for_sp(p_lash, i, dest_switch, v_lane); 979219820Sjeff generate_cdg_for_sp(p_lash, dest_switch, i, v_lane); 980219820Sjeff 981219820Sjeff set_temp_depend_to_permanent_for_sp(p_lash, i, dest_switch, 982219820Sjeff v_lane); 983219820Sjeff set_temp_depend_to_permanent_for_sp(p_lash, dest_switch, i, 984219820Sjeff v_lane); 985219820Sjeff 986219820Sjeff p_lash->num_mst_in_lane[v_lane]++; 987219820Sjeff p_lash->num_mst_in_lane[v_lane]++; 988219820Sjeff } 989219820Sjeff p_lash->virtual_location[i][dest_switch][v_lane] = 1; 990219820Sjeff p_lash->virtual_location[dest_switch][i][v_lane] = 1; 991219820Sjeff 992219820Sjeff switch_bitmap[i * num_switches + dest_switch] = 1; 993219820Sjeff switch_bitmap[dest_switch * num_switches + i] = 1; 994219820Sjeff } 995219820Sjeff } 996219820Sjeff 997219820Sjeff OSM_LOG(p_log, OSM_LOG_INFO, 998219820Sjeff "Lanes needed: %d, Balancing\n", lanes_needed); 999219820Sjeff 1000219820Sjeff for (i = 0; i < lanes_needed; i++) { 1001219820Sjeff OSM_LOG(p_log, OSM_LOG_INFO, "Lanes in layer %d: %d\n", 1002219820Sjeff i, p_lash->num_mst_in_lane[i]); 1003219820Sjeff } 1004219820Sjeff 1005219820Sjeff balance_virtual_lanes(p_lash, lanes_needed); 1006219820Sjeff 1007219820Sjeff for (i = 0; i < lanes_needed; i++) { 1008219820Sjeff OSM_LOG(p_log, OSM_LOG_INFO, "Lanes in layer %d: %d\n", 1009219820Sjeff i, p_lash->num_mst_in_lane[i]); 1010219820Sjeff } 1011219820Sjeff 1012219820Sjeff goto Exit; 1013219820Sjeff 1014219820SjeffError_Not_Enough_Lanes: 1015219820Sjeff status = -1; 1016219820Sjeff OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 4D02: " 1017219820Sjeff "Lane requirements (%d) exceed available lanes (%d)\n", 1018219820Sjeff p_lash->vl_min, lanes_needed); 1019219820SjeffExit: 1020219820Sjeff if (switch_bitmap) 1021219820Sjeff free(switch_bitmap); 1022219820Sjeff OSM_LOG_EXIT(p_log); 1023219820Sjeff return status; 1024219820Sjeff} 1025219820Sjeff 1026219820Sjeffstatic unsigned get_lash_id(osm_switch_t * p_sw) 1027219820Sjeff{ 1028219820Sjeff return ((switch_t *) p_sw->priv)->id; 1029219820Sjeff} 1030219820Sjeff 1031219820Sjeffstatic void populate_fwd_tbls(lash_t * p_lash) 1032219820Sjeff{ 1033219820Sjeff osm_log_t *p_log = &p_lash->p_osm->log; 1034219820Sjeff osm_subn_t *p_subn = &p_lash->p_osm->subn; 1035219820Sjeff osm_opensm_t *p_osm = p_lash->p_osm; 1036219820Sjeff osm_switch_t *p_sw, *p_next_sw, *p_dst_sw; 1037219820Sjeff osm_port_t *port; 1038219820Sjeff uint16_t max_lid_ho, lid; 1039219820Sjeff 1040219820Sjeff OSM_LOG_ENTER(p_log); 1041219820Sjeff 1042219820Sjeff p_next_sw = (osm_switch_t *) cl_qmap_head(&p_subn->sw_guid_tbl); 1043219820Sjeff 1044219820Sjeff // Go through each swtich individually 1045219820Sjeff while (p_next_sw != (osm_switch_t *) cl_qmap_end(&p_subn->sw_guid_tbl)) { 1046219820Sjeff uint64_t current_guid; 1047219820Sjeff switch_t *sw; 1048219820Sjeff p_sw = p_next_sw; 1049219820Sjeff p_next_sw = (osm_switch_t *) cl_qmap_next(&p_sw->map_item); 1050219820Sjeff 1051219820Sjeff max_lid_ho = p_sw->max_lid_ho; 1052219820Sjeff current_guid = p_sw->p_node->node_info.port_guid; 1053219820Sjeff sw = p_sw->priv; 1054219820Sjeff 1055219820Sjeff memset(p_sw->new_lft, OSM_NO_PATH, IB_LID_UCAST_END_HO + 1); 1056219820Sjeff 1057219820Sjeff for (lid = 1; lid <= max_lid_ho; lid++) { 1058219820Sjeff port = cl_ptr_vector_get(&p_subn->port_lid_tbl, lid); 1059219820Sjeff if (!port) 1060219820Sjeff continue; 1061219820Sjeff 1062219820Sjeff p_dst_sw = get_osm_switch_from_port(port); 1063219820Sjeff if (p_dst_sw == p_sw) { 1064219820Sjeff uint8_t egress_port = port->p_node->sw ? 0 : 1065219820Sjeff port->p_physp->p_remote_physp->port_num; 1066219820Sjeff p_sw->new_lft[lid] = egress_port; 1067219820Sjeff OSM_LOG(p_log, OSM_LOG_VERBOSE, 1068219820Sjeff "LASH fwd MY SRC SRC GUID 0x%016" PRIx64 1069219820Sjeff " src lash id (%d), src lid no (%u) src lash port (%d) " 1070219820Sjeff "DST GUID 0x%016" PRIx64 1071219820Sjeff " src lash id (%d), src lash port (%d)\n", 1072219820Sjeff cl_ntoh64(current_guid), -1, lid, 1073219820Sjeff egress_port, cl_ntoh64(current_guid), 1074219820Sjeff -1, egress_port); 1075219820Sjeff } else if (p_dst_sw) { 1076219820Sjeff unsigned dst_lash_switch_id = 1077219820Sjeff get_lash_id(p_dst_sw); 1078219820Sjeff uint8_t lash_egress_port = 1079219820Sjeff (uint8_t) sw-> 1080219820Sjeff routing_table[dst_lash_switch_id].out_link; 1081219820Sjeff uint8_t physical_egress_port = 1082219820Sjeff (uint8_t) sw-> 1083219820Sjeff virtual_physical_port_table 1084219820Sjeff [lash_egress_port]; 1085219820Sjeff 1086219820Sjeff p_sw->new_lft[lid] = physical_egress_port; 1087219820Sjeff OSM_LOG(p_log, OSM_LOG_VERBOSE, 1088219820Sjeff "LASH fwd SRC GUID 0x%016" PRIx64 1089219820Sjeff " src lash id (%d), " 1090219820Sjeff "src lid no (%u) src lash port (%d) " 1091219820Sjeff "DST GUID 0x%016" PRIx64 1092219820Sjeff " src lash id (%d), src lash port (%d)\n", 1093219820Sjeff cl_ntoh64(current_guid), sw->id, lid, 1094219820Sjeff lash_egress_port, 1095219820Sjeff cl_ntoh64(p_dst_sw->p_node->node_info. 1096219820Sjeff port_guid), 1097219820Sjeff dst_lash_switch_id, 1098219820Sjeff physical_egress_port); 1099219820Sjeff } 1100219820Sjeff } // for 1101219820Sjeff osm_ucast_mgr_set_fwd_table(&p_osm->sm.ucast_mgr, p_sw); 1102219820Sjeff } 1103219820Sjeff OSM_LOG_EXIT(p_log); 1104219820Sjeff} 1105219820Sjeff 1106219820Sjeffstatic void osm_lash_process_switch(lash_t * p_lash, osm_switch_t * p_sw) 1107219820Sjeff{ 1108219820Sjeff osm_log_t *p_log = &p_lash->p_osm->log; 1109219820Sjeff int i, port_count; 1110219820Sjeff osm_physp_t *p_current_physp, *p_remote_physp; 1111219820Sjeff unsigned switch_a_lash_id, switch_b_lash_id; 1112219820Sjeff 1113219820Sjeff OSM_LOG_ENTER(p_log); 1114219820Sjeff 1115219820Sjeff switch_a_lash_id = get_lash_id(p_sw); 1116219820Sjeff port_count = osm_node_get_num_physp(p_sw->p_node); 1117219820Sjeff 1118219820Sjeff // starting at port 1, ignoring management port on switch 1119219820Sjeff for (i = 1; i < port_count; i++) { 1120219820Sjeff 1121219820Sjeff p_current_physp = osm_node_get_physp_ptr(p_sw->p_node, i); 1122219820Sjeff if (p_current_physp) { 1123219820Sjeff p_remote_physp = p_current_physp->p_remote_physp; 1124219820Sjeff if (p_remote_physp && p_remote_physp->p_node->sw) { 1125219820Sjeff int physical_port_a_num = 1126219820Sjeff osm_physp_get_port_num(p_current_physp); 1127219820Sjeff int physical_port_b_num = 1128219820Sjeff osm_physp_get_port_num(p_remote_physp); 1129219820Sjeff switch_b_lash_id = 1130219820Sjeff get_lash_id(p_remote_physp->p_node->sw); 1131219820Sjeff 1132219820Sjeff connect_switches(p_lash, switch_a_lash_id, 1133219820Sjeff switch_b_lash_id, 1134219820Sjeff physical_port_a_num); 1135219820Sjeff OSM_LOG(p_log, OSM_LOG_VERBOSE, 1136219820Sjeff "LASH SUCCESS connected G 0x%016" PRIx64 1137219820Sjeff " , lash_id(%u), P(%u) " " to G 0x%016" 1138219820Sjeff PRIx64 " , lash_id(%u) , P(%u)\n", 1139219820Sjeff cl_ntoh64(osm_physp_get_port_guid 1140219820Sjeff (p_current_physp)), 1141219820Sjeff switch_a_lash_id, physical_port_a_num, 1142219820Sjeff cl_ntoh64(osm_physp_get_port_guid 1143219820Sjeff (p_remote_physp)), 1144219820Sjeff switch_b_lash_id, physical_port_b_num); 1145219820Sjeff } 1146219820Sjeff } 1147219820Sjeff } 1148219820Sjeff 1149219820Sjeff OSM_LOG_EXIT(p_log); 1150219820Sjeff} 1151219820Sjeff 1152219820Sjeffstatic void lash_cleanup(lash_t * p_lash) 1153219820Sjeff{ 1154219820Sjeff osm_subn_t *p_subn = &p_lash->p_osm->subn; 1155219820Sjeff osm_switch_t *p_next_sw, *p_sw; 1156219820Sjeff 1157219820Sjeff /* drop any existing references to old lash switches */ 1158219820Sjeff p_next_sw = (osm_switch_t *) cl_qmap_head(&p_subn->sw_guid_tbl); 1159219820Sjeff while (p_next_sw != (osm_switch_t *) cl_qmap_end(&p_subn->sw_guid_tbl)) { 1160219820Sjeff p_sw = p_next_sw; 1161219820Sjeff p_next_sw = (osm_switch_t *) cl_qmap_next(&p_sw->map_item); 1162219820Sjeff p_sw->priv = NULL; 1163219820Sjeff } 1164219820Sjeff 1165219820Sjeff if (p_lash->switches) { 1166219820Sjeff unsigned id; 1167219820Sjeff for (id = 0; ((int)id) < p_lash->num_switches; id++) 1168219820Sjeff if (p_lash->switches[id]) 1169219820Sjeff switch_delete(p_lash->switches[id]); 1170219820Sjeff free(p_lash->switches); 1171219820Sjeff } 1172219820Sjeff p_lash->switches = NULL; 1173219820Sjeff} 1174219820Sjeff 1175219820Sjeff/* 1176219820Sjeff static int discover_network_properties() 1177219820Sjeff Traverse the topology of the network in order to determine 1178219820Sjeff - the maximum number of switches, 1179219820Sjeff - the minimum number of virtual layers 1180219820Sjeff*/ 1181219820Sjeff 1182219820Sjeffstatic int discover_network_properties(lash_t * p_lash) 1183219820Sjeff{ 1184219820Sjeff int i = 0, id = 0; 1185219820Sjeff uint8_t vl_min; 1186219820Sjeff osm_subn_t *p_subn = &p_lash->p_osm->subn; 1187219820Sjeff osm_switch_t *p_next_sw, *p_sw; 1188219820Sjeff osm_log_t *p_log = &p_lash->p_osm->log; 1189219820Sjeff 1190219820Sjeff p_lash->num_switches = cl_qmap_count(&p_subn->sw_guid_tbl); 1191219820Sjeff 1192219820Sjeff p_lash->switches = malloc(p_lash->num_switches * sizeof(switch_t *)); 1193219820Sjeff if (!p_lash->switches) 1194219820Sjeff return -1; 1195219820Sjeff memset(p_lash->switches, 0, p_lash->num_switches * sizeof(switch_t *)); 1196219820Sjeff 1197219820Sjeff vl_min = 5; // set to a high value 1198219820Sjeff 1199219820Sjeff p_next_sw = (osm_switch_t *) cl_qmap_head(&p_subn->sw_guid_tbl); 1200219820Sjeff while (p_next_sw != (osm_switch_t *) cl_qmap_end(&p_subn->sw_guid_tbl)) { 1201219820Sjeff uint16_t port_count; 1202219820Sjeff p_sw = p_next_sw; 1203219820Sjeff p_next_sw = (osm_switch_t *) cl_qmap_next(&p_sw->map_item); 1204219820Sjeff 1205219820Sjeff p_lash->switches[id] = switch_create(p_lash, id, p_sw); 1206219820Sjeff if (!p_lash->switches[id]) 1207219820Sjeff return -1; 1208219820Sjeff id++; 1209219820Sjeff 1210219820Sjeff port_count = osm_node_get_num_physp(p_sw->p_node); 1211219820Sjeff 1212219820Sjeff // Note, ignoring port 0. management port 1213219820Sjeff for (i = 1; i < port_count; i++) { 1214219820Sjeff osm_physp_t *p_current_physp = 1215219820Sjeff osm_node_get_physp_ptr(p_sw->p_node, i); 1216219820Sjeff 1217219820Sjeff if (p_current_physp 1218219820Sjeff && p_current_physp->p_remote_physp) { 1219219820Sjeff 1220219820Sjeff ib_port_info_t *p_port_info = 1221219820Sjeff &p_current_physp->port_info; 1222219820Sjeff uint8_t port_vl_min = 1223219820Sjeff ib_port_info_get_op_vls(p_port_info); 1224219820Sjeff if (port_vl_min && port_vl_min < vl_min) 1225219820Sjeff vl_min = port_vl_min; 1226219820Sjeff } 1227219820Sjeff } // for 1228219820Sjeff } // while 1229219820Sjeff 1230219820Sjeff vl_min = 1 << (vl_min - 1); 1231219820Sjeff if (vl_min > 15) 1232219820Sjeff vl_min = 15; 1233219820Sjeff 1234219820Sjeff p_lash->vl_min = vl_min; 1235219820Sjeff 1236219820Sjeff OSM_LOG(p_log, OSM_LOG_INFO, 1237219820Sjeff "min operational vl(%d) max_switches(%d)\n", p_lash->vl_min, 1238219820Sjeff p_lash->num_switches); 1239219820Sjeff return 0; 1240219820Sjeff} 1241219820Sjeff 1242219820Sjeffstatic void process_switches(lash_t * p_lash) 1243219820Sjeff{ 1244219820Sjeff osm_switch_t *p_sw, *p_next_sw; 1245219820Sjeff osm_subn_t *p_subn = &p_lash->p_osm->subn; 1246219820Sjeff 1247219820Sjeff /* Go through each swithc and process it. i.e build the connection 1248219820Sjeff structure required by LASH */ 1249219820Sjeff p_next_sw = (osm_switch_t *) cl_qmap_head(&p_subn->sw_guid_tbl); 1250219820Sjeff while (p_next_sw != (osm_switch_t *) cl_qmap_end(&p_subn->sw_guid_tbl)) { 1251219820Sjeff p_sw = p_next_sw; 1252219820Sjeff p_next_sw = (osm_switch_t *) cl_qmap_next(&p_sw->map_item); 1253219820Sjeff 1254219820Sjeff osm_lash_process_switch(p_lash, p_sw); 1255219820Sjeff } 1256219820Sjeff} 1257219820Sjeff 1258219820Sjeffstatic int lash_process(void *context) 1259219820Sjeff{ 1260219820Sjeff lash_t *p_lash = context; 1261219820Sjeff osm_log_t *p_log = &p_lash->p_osm->log; 1262219820Sjeff int return_status = IB_SUCCESS; 1263219820Sjeff 1264219820Sjeff OSM_LOG_ENTER(p_log); 1265219820Sjeff 1266219820Sjeff p_lash->balance_limit = 6; 1267219820Sjeff 1268219820Sjeff // everything starts here 1269219820Sjeff lash_cleanup(p_lash); 1270219820Sjeff 1271219820Sjeff discover_network_properties(p_lash); 1272219820Sjeff 1273219820Sjeff return_status = init_lash_structures(p_lash); 1274219820Sjeff if (return_status != IB_SUCCESS) 1275219820Sjeff goto Exit; 1276219820Sjeff 1277219820Sjeff process_switches(p_lash); 1278219820Sjeff 1279219820Sjeff return_status = lash_core(p_lash); 1280219820Sjeff if (return_status != IB_SUCCESS) 1281219820Sjeff goto Exit; 1282219820Sjeff 1283219820Sjeff populate_fwd_tbls(p_lash); 1284219820Sjeff 1285219820SjeffExit: 1286219820Sjeff free_lash_structures(p_lash); 1287219820Sjeff OSM_LOG_EXIT(p_log); 1288219820Sjeff 1289219820Sjeff return return_status; 1290219820Sjeff} 1291219820Sjeff 1292219820Sjeffstatic lash_t *lash_create(osm_opensm_t * p_osm) 1293219820Sjeff{ 1294219820Sjeff lash_t *p_lash; 1295219820Sjeff 1296219820Sjeff p_lash = malloc(sizeof(lash_t)); 1297219820Sjeff if (!p_lash) 1298219820Sjeff return NULL; 1299219820Sjeff 1300219820Sjeff memset(p_lash, 0, sizeof(lash_t)); 1301219820Sjeff p_lash->p_osm = p_osm; 1302219820Sjeff 1303219820Sjeff return (p_lash); 1304219820Sjeff} 1305219820Sjeff 1306219820Sjeffstatic void lash_delete(void *context) 1307219820Sjeff{ 1308219820Sjeff lash_t *p_lash = context; 1309219820Sjeff if (p_lash->switches) { 1310219820Sjeff unsigned id; 1311219820Sjeff for (id = 0; ((int)id) < p_lash->num_switches; id++) 1312219820Sjeff if (p_lash->switches[id]) 1313219820Sjeff switch_delete(p_lash->switches[id]); 1314219820Sjeff free(p_lash->switches); 1315219820Sjeff } 1316219820Sjeff free(p_lash); 1317219820Sjeff} 1318219820Sjeff 1319219820Sjeffuint8_t osm_get_lash_sl(osm_opensm_t * p_osm, osm_port_t * p_src_port, 1320219820Sjeff osm_port_t * p_dst_port) 1321219820Sjeff{ 1322219820Sjeff unsigned dst_id; 1323219820Sjeff unsigned src_id; 1324219820Sjeff osm_switch_t *p_sw; 1325219820Sjeff 1326219820Sjeff if (p_osm->routing_engine_used != OSM_ROUTING_ENGINE_TYPE_LASH) 1327219820Sjeff return OSM_DEFAULT_SL; 1328219820Sjeff 1329219820Sjeff p_sw = get_osm_switch_from_port(p_dst_port); 1330219820Sjeff if (!p_sw || !p_sw->priv) 1331219820Sjeff return OSM_DEFAULT_SL; 1332219820Sjeff dst_id = get_lash_id(p_sw); 1333219820Sjeff 1334219820Sjeff p_sw = get_osm_switch_from_port(p_src_port); 1335219820Sjeff if (!p_sw || !p_sw->priv) 1336219820Sjeff return OSM_DEFAULT_SL; 1337219820Sjeff 1338219820Sjeff src_id = get_lash_id(p_sw); 1339219820Sjeff if (src_id == dst_id) 1340219820Sjeff return OSM_DEFAULT_SL; 1341219820Sjeff 1342219820Sjeff return (uint8_t) ((switch_t *) p_sw->priv)->routing_table[dst_id].lane; 1343219820Sjeff} 1344219820Sjeff 1345219820Sjeffint osm_ucast_lash_setup(struct osm_routing_engine *r, osm_opensm_t *p_osm) 1346219820Sjeff{ 1347219820Sjeff lash_t *p_lash = lash_create(p_osm); 1348219820Sjeff if (!p_lash) 1349219820Sjeff return -1; 1350219820Sjeff 1351219820Sjeff r->context = p_lash; 1352219820Sjeff r->ucast_build_fwd_tables = lash_process; 1353219820Sjeff r->delete = lash_delete; 1354219820Sjeff 1355219820Sjeff return 0; 1356219820Sjeff} 1357