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