1219820Sjeff/* 2219820Sjeff * Copyright (c) 2008 Mellanox Technologies LTD. All rights reserved. 3219820Sjeff * 4219820Sjeff * This software is available to you under a choice of one of two 5219820Sjeff * licenses. You may choose to be licensed under the terms of the GNU 6219820Sjeff * General Public License (GPL) Version 2, available from the file 7219820Sjeff * COPYING in the main directory of this source tree, or the 8219820Sjeff * OpenIB.org BSD license below: 9219820Sjeff * 10219820Sjeff * Redistribution and use in source and binary forms, with or 11219820Sjeff * without modification, are permitted provided that the following 12219820Sjeff * conditions are met: 13219820Sjeff * 14219820Sjeff * - Redistributions of source code must retain the above 15219820Sjeff * copyright notice, this list of conditions and the following 16219820Sjeff * disclaimer. 17219820Sjeff * 18219820Sjeff * - Redistributions in binary form must reproduce the above 19219820Sjeff * copyright notice, this list of conditions and the following 20219820Sjeff * disclaimer in the documentation and/or other materials 21219820Sjeff * provided with the distribution. 22219820Sjeff * 23219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30219820Sjeff * SOFTWARE. 31219820Sjeff * 32219820Sjeff */ 33219820Sjeff 34219820Sjeff/* 35219820Sjeff * Abstract: 36219820Sjeff * Implementation of OpenSM Cached Unicast Routing 37219820Sjeff * 38219820Sjeff * Environment: 39219820Sjeff * Linux User Mode 40219820Sjeff * 41219820Sjeff */ 42219820Sjeff 43219820Sjeff#if HAVE_CONFIG_H 44219820Sjeff# include <config.h> 45219820Sjeff#endif 46219820Sjeff 47219820Sjeff#include <stdlib.h> 48219820Sjeff#include <string.h> 49219820Sjeff#include <ctype.h> 50219820Sjeff#include <errno.h> 51219820Sjeff#include <iba/ib_types.h> 52219820Sjeff#include <complib/cl_qmap.h> 53219820Sjeff#include <complib/cl_pool.h> 54219820Sjeff#include <complib/cl_debug.h> 55219820Sjeff#include <opensm/osm_opensm.h> 56219820Sjeff#include <opensm/osm_ucast_mgr.h> 57219820Sjeff#include <opensm/osm_ucast_cache.h> 58219820Sjeff#include <opensm/osm_switch.h> 59219820Sjeff#include <opensm/osm_node.h> 60219820Sjeff#include <opensm/osm_port.h> 61219820Sjeff 62219820Sjeff#define CACHE_SW_PORTS 36 63219820Sjeff 64219820Sjefftypedef struct cache_port { 65219820Sjeff boolean_t is_leaf; 66219820Sjeff uint16_t remote_lid_ho; 67219820Sjeff} cache_port_t; 68219820Sjeff 69219820Sjefftypedef struct cache_switch { 70219820Sjeff cl_map_item_t map_item; 71219820Sjeff boolean_t dropped; 72219820Sjeff uint16_t max_lid_ho; 73219820Sjeff uint16_t num_hops; 74219820Sjeff uint8_t **hops; 75219820Sjeff uint8_t *lft; 76219820Sjeff uint8_t num_ports; 77219820Sjeff cache_port_t ports[0]; 78219820Sjeff} cache_switch_t; 79219820Sjeff 80219820Sjeff/********************************************************************** 81219820Sjeff **********************************************************************/ 82219820Sjeff 83219820Sjeffstatic uint16_t __cache_sw_get_base_lid_ho(cache_switch_t * p_sw) 84219820Sjeff{ 85219820Sjeff return p_sw->ports[0].remote_lid_ho; 86219820Sjeff} 87219820Sjeff 88219820Sjeff/********************************************************************** 89219820Sjeff **********************************************************************/ 90219820Sjeff 91219820Sjeffstatic boolean_t __cache_sw_is_leaf(cache_switch_t * p_sw) 92219820Sjeff{ 93219820Sjeff return p_sw->ports[0].is_leaf; 94219820Sjeff} 95219820Sjeff 96219820Sjeff/********************************************************************** 97219820Sjeff **********************************************************************/ 98219820Sjeff 99219820Sjeffstatic void __cache_sw_set_leaf(cache_switch_t * p_sw) 100219820Sjeff{ 101219820Sjeff p_sw->ports[0].is_leaf = TRUE; 102219820Sjeff} 103219820Sjeff 104219820Sjeff/********************************************************************** 105219820Sjeff **********************************************************************/ 106219820Sjeff 107219820Sjeffstatic cache_switch_t *__cache_sw_new(uint16_t lid_ho, unsigned num_ports) 108219820Sjeff{ 109219820Sjeff cache_switch_t *p_cache_sw = malloc(sizeof(cache_switch_t) + 110219820Sjeff num_ports * sizeof(cache_port_t)); 111219820Sjeff if (!p_cache_sw) 112219820Sjeff return NULL; 113219820Sjeff 114219820Sjeff memset(p_cache_sw, 0, 115219820Sjeff sizeof(*p_cache_sw) + num_ports * sizeof(cache_port_t)); 116219820Sjeff 117219820Sjeff p_cache_sw->num_ports = num_ports; 118219820Sjeff 119219820Sjeff /* port[0] fields represent this switch details - lid and type */ 120219820Sjeff p_cache_sw->ports[0].remote_lid_ho = lid_ho; 121219820Sjeff p_cache_sw->ports[0].is_leaf = FALSE; 122219820Sjeff 123219820Sjeff return p_cache_sw; 124219820Sjeff} 125219820Sjeff 126219820Sjeff/********************************************************************** 127219820Sjeff **********************************************************************/ 128219820Sjeff 129219820Sjeffstatic void __cache_sw_destroy(cache_switch_t * p_sw) 130219820Sjeff{ 131219820Sjeff if (!p_sw) 132219820Sjeff return; 133219820Sjeff 134219820Sjeff if (p_sw->lft) 135219820Sjeff free(p_sw->lft); 136219820Sjeff if (p_sw->hops) 137219820Sjeff free(p_sw->hops); 138219820Sjeff free(p_sw); 139219820Sjeff} 140219820Sjeff 141219820Sjeff/********************************************************************** 142219820Sjeff **********************************************************************/ 143219820Sjeff 144219820Sjeffstatic cache_switch_t *__cache_get_sw(osm_ucast_mgr_t * p_mgr, uint16_t lid_ho) 145219820Sjeff{ 146219820Sjeff cache_switch_t *p_cache_sw = (cache_switch_t *) 147219820Sjeff cl_qmap_get(&p_mgr->cache_sw_tbl, lid_ho); 148219820Sjeff if (p_cache_sw == (cache_switch_t *) 149219820Sjeff cl_qmap_end(&p_mgr->cache_sw_tbl)) 150219820Sjeff p_cache_sw = NULL; 151219820Sjeff 152219820Sjeff return p_cache_sw; 153219820Sjeff} 154219820Sjeff 155219820Sjeff/********************************************************************** 156219820Sjeff **********************************************************************/ 157219820Sjeffstatic void __cache_add_sw_link(osm_ucast_mgr_t * p_mgr, osm_physp_t *p, 158219820Sjeff uint16_t remote_lid_ho, boolean_t is_ca) 159219820Sjeff{ 160219820Sjeff cache_switch_t *p_cache_sw; 161219820Sjeff uint16_t lid_ho = cl_ntoh16(osm_node_get_base_lid(p->p_node, 0)); 162219820Sjeff 163219820Sjeff OSM_LOG_ENTER(p_mgr->p_log); 164219820Sjeff 165219820Sjeff if (!lid_ho || !remote_lid_ho || !p->port_num) 166219820Sjeff goto Exit; 167219820Sjeff 168219820Sjeff OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, 169219820Sjeff "Caching switch port: lid %u [port %u] -> lid %u (%s)\n", 170219820Sjeff lid_ho, p->port_num, remote_lid_ho, (is_ca) ? "CA/RTR" : "SW"); 171219820Sjeff 172219820Sjeff p_cache_sw = __cache_get_sw(p_mgr, lid_ho); 173219820Sjeff if (!p_cache_sw) { 174219820Sjeff p_cache_sw = __cache_sw_new(lid_ho, p->p_node->sw->num_ports); 175219820Sjeff if (!p_cache_sw) { 176219820Sjeff OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR, 177219820Sjeff "ERR AD01: Out of memory - cache is invalid\n"); 178219820Sjeff osm_ucast_cache_invalidate(p_mgr); 179219820Sjeff goto Exit; 180219820Sjeff } 181219820Sjeff cl_qmap_insert(&p_mgr->cache_sw_tbl, lid_ho, 182219820Sjeff &p_cache_sw->map_item); 183219820Sjeff } 184219820Sjeff 185219820Sjeff if (p->port_num >= p_cache_sw->num_ports) { 186219820Sjeff OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR, 187219820Sjeff "ERR AD02: Wrong switch? - cache is invalid\n"); 188219820Sjeff osm_ucast_cache_invalidate(p_mgr); 189219820Sjeff goto Exit; 190219820Sjeff } 191219820Sjeff 192219820Sjeff if (is_ca) 193219820Sjeff __cache_sw_set_leaf(p_cache_sw); 194219820Sjeff 195219820Sjeff if (p_cache_sw->ports[p->port_num].remote_lid_ho == 0) { 196219820Sjeff /* cache this link only if it hasn't been already cached */ 197219820Sjeff p_cache_sw->ports[p->port_num].remote_lid_ho = remote_lid_ho; 198219820Sjeff p_cache_sw->ports[p->port_num].is_leaf = is_ca; 199219820Sjeff } 200219820SjeffExit: 201219820Sjeff OSM_LOG_EXIT(p_mgr->p_log); 202219820Sjeff} 203219820Sjeff 204219820Sjeff/********************************************************************** 205219820Sjeff **********************************************************************/ 206219820Sjeff 207219820Sjeffstatic void __cache_cleanup_switches(osm_ucast_mgr_t * p_mgr) 208219820Sjeff{ 209219820Sjeff cache_switch_t *p_sw; 210219820Sjeff cache_switch_t *p_next_sw; 211219820Sjeff unsigned port_num; 212219820Sjeff boolean_t found_port; 213219820Sjeff 214219820Sjeff if (!p_mgr->cache_valid) 215219820Sjeff return; 216219820Sjeff 217219820Sjeff p_next_sw = (cache_switch_t *) cl_qmap_head(&p_mgr->cache_sw_tbl); 218219820Sjeff while (p_next_sw != 219219820Sjeff (cache_switch_t *) cl_qmap_end(&p_mgr->cache_sw_tbl)) { 220219820Sjeff p_sw = p_next_sw; 221219820Sjeff p_next_sw = (cache_switch_t *) cl_qmap_next(&p_sw->map_item); 222219820Sjeff 223219820Sjeff found_port = FALSE; 224219820Sjeff for (port_num = 1; port_num < p_sw->num_ports; port_num++) 225219820Sjeff if (p_sw->ports[port_num].remote_lid_ho) 226219820Sjeff found_port = TRUE; 227219820Sjeff 228219820Sjeff if (!found_port) { 229219820Sjeff cl_qmap_remove_item(&p_mgr->cache_sw_tbl, 230219820Sjeff &p_sw->map_item); 231219820Sjeff __cache_sw_destroy(p_sw); 232219820Sjeff } 233219820Sjeff } 234219820Sjeff} 235219820Sjeff 236219820Sjeff/********************************************************************** 237219820Sjeff **********************************************************************/ 238219820Sjeff 239219820Sjeffstatic void 240219820Sjeff__cache_check_link_change(osm_ucast_mgr_t * p_mgr, 241219820Sjeff osm_physp_t * p_physp_1, osm_physp_t * p_physp_2) 242219820Sjeff{ 243219820Sjeff OSM_LOG_ENTER(p_mgr->p_log); 244219820Sjeff CL_ASSERT(p_physp_1 && p_physp_2); 245219820Sjeff 246219820Sjeff if (!p_mgr->cache_valid) 247219820Sjeff goto Exit; 248219820Sjeff 249219820Sjeff if (!p_physp_1->p_remote_physp && !p_physp_2->p_remote_physp) 250219820Sjeff /* both ports were down - new link */ 251219820Sjeff goto Exit; 252219820Sjeff 253219820Sjeff /* unicast cache cannot tolerate any link location change */ 254219820Sjeff 255219820Sjeff if ((p_physp_1->p_remote_physp && 256219820Sjeff p_physp_1->p_remote_physp->p_remote_physp) || 257219820Sjeff (p_physp_2->p_remote_physp && 258219820Sjeff p_physp_2->p_remote_physp->p_remote_physp)) { 259219820Sjeff OSM_LOG(p_mgr->p_log, OSM_LOG_INFO, 260219820Sjeff "Link location change discovered - cache is invalid\n"); 261219820Sjeff osm_ucast_cache_invalidate(p_mgr); 262219820Sjeff goto Exit; 263219820Sjeff } 264219820SjeffExit: 265219820Sjeff OSM_LOG_EXIT(p_mgr->p_log); 266219820Sjeff} 267219820Sjeff 268219820Sjeff/********************************************************************** 269219820Sjeff **********************************************************************/ 270219820Sjeff 271219820Sjeffstatic void __cache_remove_port(osm_ucast_mgr_t * p_mgr, uint16_t lid_ho, 272219820Sjeff uint8_t port_num, uint16_t remote_lid_ho, 273219820Sjeff boolean_t is_ca) 274219820Sjeff{ 275219820Sjeff cache_switch_t *p_cache_sw; 276219820Sjeff 277219820Sjeff OSM_LOG_ENTER(p_mgr->p_log); 278219820Sjeff 279219820Sjeff if (!p_mgr->cache_valid) 280219820Sjeff goto Exit; 281219820Sjeff 282219820Sjeff p_cache_sw = __cache_get_sw(p_mgr, lid_ho); 283219820Sjeff if (!p_cache_sw) { 284219820Sjeff OSM_LOG(p_mgr->p_log, OSM_LOG_INFO, 285219820Sjeff "Found uncached switch/link (lid %u, port %u) - " 286219820Sjeff "cache is invalid\n", lid_ho, port_num); 287219820Sjeff osm_ucast_cache_invalidate(p_mgr); 288219820Sjeff goto Exit; 289219820Sjeff } 290219820Sjeff 291219820Sjeff if (port_num >= p_cache_sw->num_ports || 292219820Sjeff !p_cache_sw->ports[port_num].remote_lid_ho) { 293219820Sjeff OSM_LOG(p_mgr->p_log, OSM_LOG_INFO, 294219820Sjeff "Found uncached switch link (lid %u, port %u) - " 295219820Sjeff "cache is invalid\n", lid_ho, port_num); 296219820Sjeff osm_ucast_cache_invalidate(p_mgr); 297219820Sjeff goto Exit; 298219820Sjeff } 299219820Sjeff 300219820Sjeff if (p_cache_sw->ports[port_num].remote_lid_ho != remote_lid_ho) { 301219820Sjeff OSM_LOG(p_mgr->p_log, OSM_LOG_INFO, 302219820Sjeff "Remote lid change on switch lid %u, port %u " 303219820Sjeff "(was %u, now %u) - cache is invalid\n", 304219820Sjeff lid_ho, port_num, 305219820Sjeff p_cache_sw->ports[port_num].remote_lid_ho, 306219820Sjeff remote_lid_ho); 307219820Sjeff osm_ucast_cache_invalidate(p_mgr); 308219820Sjeff goto Exit; 309219820Sjeff } 310219820Sjeff 311219820Sjeff if ((p_cache_sw->ports[port_num].is_leaf && !is_ca) || 312219820Sjeff (!p_cache_sw->ports[port_num].is_leaf && is_ca)) { 313219820Sjeff OSM_LOG(p_mgr->p_log, OSM_LOG_INFO, 314219820Sjeff "Remote node type change on switch lid %u, port %u - " 315219820Sjeff "cache is invalid\n", lid_ho, port_num); 316219820Sjeff osm_ucast_cache_invalidate(p_mgr); 317219820Sjeff goto Exit; 318219820Sjeff } 319219820Sjeff 320219820Sjeff OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, 321219820Sjeff "New link from lid %u, port %u to lid %u - " 322219820Sjeff "found in cache\n", lid_ho, port_num, remote_lid_ho); 323219820Sjeff 324219820Sjeff /* the new link was cached - clean it from the cache */ 325219820Sjeff 326219820Sjeff p_cache_sw->ports[port_num].remote_lid_ho = 0; 327219820Sjeff p_cache_sw->ports[port_num].is_leaf = FALSE; 328219820SjeffExit: 329219820Sjeff OSM_LOG_EXIT(p_mgr->p_log); 330219820Sjeff} /* __cache_remove_port() */ 331219820Sjeff 332219820Sjeff/********************************************************************** 333219820Sjeff **********************************************************************/ 334219820Sjeff 335219820Sjeffstatic void 336219820Sjeff__cache_restore_ucast_info(osm_ucast_mgr_t * p_mgr, 337219820Sjeff cache_switch_t * p_cache_sw, osm_switch_t * p_sw) 338219820Sjeff{ 339219820Sjeff if (!p_mgr->cache_valid) 340219820Sjeff return; 341219820Sjeff 342219820Sjeff /* when seting unicast info, the cached port 343219820Sjeff should have all the required info */ 344219820Sjeff CL_ASSERT(p_cache_sw->max_lid_ho && p_cache_sw->lft && 345219820Sjeff p_cache_sw->num_hops && p_cache_sw->hops); 346219820Sjeff 347219820Sjeff p_sw->max_lid_ho = p_cache_sw->max_lid_ho; 348219820Sjeff 349219820Sjeff if (p_sw->new_lft) 350219820Sjeff free(p_sw->new_lft); 351219820Sjeff p_sw->new_lft = p_cache_sw->lft; 352219820Sjeff p_cache_sw->lft = NULL; 353219820Sjeff 354219820Sjeff p_sw->num_hops = p_cache_sw->num_hops; 355219820Sjeff p_cache_sw->num_hops = 0; 356219820Sjeff if (p_sw->hops) 357219820Sjeff free(p_sw->hops); 358219820Sjeff p_sw->hops = p_cache_sw->hops; 359219820Sjeff p_cache_sw->hops = NULL; 360219820Sjeff} 361219820Sjeff 362219820Sjeff/********************************************************************** 363219820Sjeff **********************************************************************/ 364219820Sjeff 365219820Sjeffstatic void __ucast_cache_dump(osm_ucast_mgr_t * p_mgr) 366219820Sjeff{ 367219820Sjeff cache_switch_t *p_sw; 368219820Sjeff unsigned i; 369219820Sjeff 370219820Sjeff OSM_LOG_ENTER(p_mgr->p_log); 371219820Sjeff 372219820Sjeff if (!osm_log_is_active(p_mgr->p_log, OSM_LOG_DEBUG)) 373219820Sjeff goto Exit; 374219820Sjeff 375219820Sjeff OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, 376219820Sjeff "Dumping missing nodes/links as logged by unicast cache:\n"); 377219820Sjeff for (p_sw = (cache_switch_t *) cl_qmap_head(&p_mgr->cache_sw_tbl); 378219820Sjeff p_sw != (cache_switch_t *) cl_qmap_end(&p_mgr->cache_sw_tbl); 379219820Sjeff p_sw = (cache_switch_t *) cl_qmap_next(&p_sw->map_item)) { 380219820Sjeff 381219820Sjeff OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, 382219820Sjeff "\t Switch lid %u %s%s\n", 383219820Sjeff __cache_sw_get_base_lid_ho(p_sw), 384219820Sjeff (__cache_sw_is_leaf(p_sw)) ? "[leaf switch] " : "", 385219820Sjeff (p_sw->dropped) ? "[whole switch missing]" : ""); 386219820Sjeff 387219820Sjeff for (i = 1; i < p_sw->num_ports; i++) 388219820Sjeff if (p_sw->ports[i].remote_lid_ho > 0) 389219820Sjeff OSM_LOG(p_mgr->p_log, 390219820Sjeff OSM_LOG_DEBUG, 391219820Sjeff "\t - port %u -> lid %u %s\n", 392219820Sjeff i, p_sw->ports[i].remote_lid_ho, 393219820Sjeff (p_sw->ports[i].is_leaf) ? 394219820Sjeff "[remote node is leaf]" : ""); 395219820Sjeff } 396219820SjeffExit: 397219820Sjeff OSM_LOG_EXIT(p_mgr->p_log); 398219820Sjeff} 399219820Sjeff 400219820Sjeff/********************************************************************** 401219820Sjeff **********************************************************************/ 402219820Sjeff 403219820Sjeffvoid osm_ucast_cache_invalidate(osm_ucast_mgr_t * p_mgr) 404219820Sjeff{ 405219820Sjeff cache_switch_t *p_sw; 406219820Sjeff cache_switch_t *p_next_sw; 407219820Sjeff 408219820Sjeff OSM_LOG_ENTER(p_mgr->p_log); 409219820Sjeff OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, "Invalidating unicast cache\n"); 410219820Sjeff 411219820Sjeff if (!p_mgr->cache_valid) 412219820Sjeff goto Exit; 413219820Sjeff 414219820Sjeff p_mgr->cache_valid = FALSE; 415219820Sjeff 416219820Sjeff p_next_sw = (cache_switch_t *) cl_qmap_head(&p_mgr->cache_sw_tbl); 417219820Sjeff while (p_next_sw != 418219820Sjeff (cache_switch_t *) cl_qmap_end(&p_mgr->cache_sw_tbl)) { 419219820Sjeff p_sw = p_next_sw; 420219820Sjeff p_next_sw = (cache_switch_t *) cl_qmap_next(&p_sw->map_item); 421219820Sjeff __cache_sw_destroy(p_sw); 422219820Sjeff } 423219820Sjeff cl_qmap_remove_all(&p_mgr->cache_sw_tbl); 424219820SjeffExit: 425219820Sjeff OSM_LOG_EXIT(p_mgr->p_log); 426219820Sjeff} 427219820Sjeff 428219820Sjeff/********************************************************************** 429219820Sjeff **********************************************************************/ 430219820Sjeff 431219820Sjeffstatic void ucast_cache_validate(osm_ucast_mgr_t * p_mgr) 432219820Sjeff{ 433219820Sjeff cache_switch_t *p_cache_sw; 434219820Sjeff cache_switch_t *p_remote_cache_sw; 435219820Sjeff unsigned port_num; 436219820Sjeff unsigned max_ports; 437219820Sjeff uint8_t remote_node_type; 438219820Sjeff uint16_t lid_ho; 439219820Sjeff uint16_t remote_lid_ho; 440219820Sjeff osm_switch_t *p_sw; 441219820Sjeff osm_switch_t *p_remote_sw; 442219820Sjeff osm_node_t *p_node; 443219820Sjeff osm_physp_t *p_physp; 444219820Sjeff osm_physp_t *p_remote_physp; 445219820Sjeff osm_port_t *p_remote_port; 446219820Sjeff cl_qmap_t *p_sw_tbl; 447219820Sjeff 448219820Sjeff OSM_LOG_ENTER(p_mgr->p_log); 449219820Sjeff if (!p_mgr->cache_valid) 450219820Sjeff goto Exit; 451219820Sjeff 452219820Sjeff /* If there are no switches in the subnet, we are done */ 453219820Sjeff p_sw_tbl = &p_mgr->p_subn->sw_guid_tbl; 454219820Sjeff if (cl_qmap_count(p_sw_tbl) == 0) { 455219820Sjeff osm_ucast_cache_invalidate(p_mgr); 456219820Sjeff goto Exit; 457219820Sjeff } 458219820Sjeff 459219820Sjeff /* 460219820Sjeff * Scan all the physical switch ports in the subnet. 461219820Sjeff * If the port need_update flag is on, check whether 462219820Sjeff * it's just some node/port reset or a cached topology 463219820Sjeff * change. Otherwise the cache is invalid. 464219820Sjeff */ 465219820Sjeff for (p_sw = (osm_switch_t *) cl_qmap_head(p_sw_tbl); 466219820Sjeff p_sw != (osm_switch_t *) cl_qmap_end(p_sw_tbl); 467219820Sjeff p_sw = (osm_switch_t *) cl_qmap_next(&p_sw->map_item)) { 468219820Sjeff 469219820Sjeff p_node = p_sw->p_node; 470219820Sjeff 471219820Sjeff lid_ho = cl_ntoh16(osm_node_get_base_lid(p_node, 0)); 472219820Sjeff p_cache_sw = __cache_get_sw(p_mgr, lid_ho); 473219820Sjeff 474219820Sjeff max_ports = osm_node_get_num_physp(p_node); 475219820Sjeff 476219820Sjeff /* skip port 0 */ 477219820Sjeff for (port_num = 1; port_num < max_ports; port_num++) { 478219820Sjeff 479219820Sjeff p_physp = osm_node_get_physp_ptr(p_node, port_num); 480219820Sjeff 481219820Sjeff if (!p_physp || !p_physp->p_remote_physp || 482219820Sjeff !osm_physp_link_exists(p_physp, 483219820Sjeff p_physp->p_remote_physp)) 484219820Sjeff /* no valid link */ 485219820Sjeff continue; 486219820Sjeff 487219820Sjeff /* 488219820Sjeff * While scanning all the physical ports in the subnet, 489219820Sjeff * mark corresponding leaf switches in the cache. 490219820Sjeff */ 491219820Sjeff if (p_cache_sw && 492219820Sjeff !p_cache_sw->dropped && 493219820Sjeff !__cache_sw_is_leaf(p_cache_sw) && 494219820Sjeff p_physp->p_remote_physp->p_node && 495219820Sjeff osm_node_get_type(p_physp->p_remote_physp-> 496219820Sjeff p_node) != IB_NODE_TYPE_SWITCH) 497219820Sjeff __cache_sw_set_leaf(p_cache_sw); 498219820Sjeff 499219820Sjeff if (!p_physp->need_update) 500219820Sjeff continue; 501219820Sjeff 502219820Sjeff OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, 503219820Sjeff "Checking switch lid %u, port %u\n", 504219820Sjeff lid_ho, port_num); 505219820Sjeff 506219820Sjeff p_remote_physp = osm_physp_get_remote(p_physp); 507219820Sjeff remote_node_type = 508219820Sjeff osm_node_get_type(p_remote_physp->p_node); 509219820Sjeff 510219820Sjeff if (remote_node_type == IB_NODE_TYPE_SWITCH) 511219820Sjeff remote_lid_ho = 512219820Sjeff cl_ntoh16(osm_node_get_base_lid 513219820Sjeff (p_remote_physp->p_node, 0)); 514219820Sjeff else 515219820Sjeff remote_lid_ho = 516219820Sjeff cl_ntoh16(osm_node_get_base_lid 517219820Sjeff (p_remote_physp->p_node, 518219820Sjeff osm_physp_get_port_num 519219820Sjeff (p_remote_physp))); 520219820Sjeff 521219820Sjeff if (!p_cache_sw || 522219820Sjeff port_num >= p_cache_sw->num_ports || 523219820Sjeff !p_cache_sw->ports[port_num].remote_lid_ho) { 524219820Sjeff /* 525219820Sjeff * There is some uncached change on the port. 526219820Sjeff * In general, the reasons might be as follows: 527219820Sjeff * - switch reset 528219820Sjeff * - port reset (or port down/up) 529219820Sjeff * - quick connection location change 530219820Sjeff * - new link (or new switch) 531219820Sjeff * 532219820Sjeff * First two reasons allow cache usage, while 533219820Sjeff * the last two reasons should invalidate cache. 534219820Sjeff * 535219820Sjeff * In case of quick connection location change, 536219820Sjeff * cache would have been invalidated by 537219820Sjeff * osm_ucast_cache_check_new_link() function. 538219820Sjeff * 539219820Sjeff * In case of new link between two known nodes, 540219820Sjeff * cache also would have been invalidated by 541219820Sjeff * osm_ucast_cache_check_new_link() function. 542219820Sjeff * 543219820Sjeff * Another reason is cached link between two 544219820Sjeff * known switches went back. In this case the 545219820Sjeff * osm_ucast_cache_check_new_link() function would 546219820Sjeff * clear both sides of the link from the cache 547219820Sjeff * during the discovery process, so effectively 548219820Sjeff * this would be equivalent to port reset. 549219820Sjeff * 550219820Sjeff * So three possible reasons remain: 551219820Sjeff * - switch reset 552219820Sjeff * - port reset (or port down/up) 553219820Sjeff * - link of a new switch 554219820Sjeff * 555219820Sjeff * To validate cache, we need to check only the 556219820Sjeff * third reason - link of a new node/switch: 557219820Sjeff * - If this is the local switch that is new, 558219820Sjeff * then it should have (p_sw->need_update == 2). 559219820Sjeff * - If the remote node is switch and it's new, 560219820Sjeff * then it also should have 561219820Sjeff * (p_sw->need_update == 2). 562219820Sjeff * - If the remote node is CA/RTR and it's new, 563219820Sjeff * then its port should have is_new flag on. 564219820Sjeff */ 565219820Sjeff if (p_sw->need_update == 2) { 566219820Sjeff OSM_LOG(p_mgr->p_log, OSM_LOG_INFO, 567219820Sjeff "New switch found (lid %u) - " 568219820Sjeff "cache is invalid\n", lid_ho); 569219820Sjeff osm_ucast_cache_invalidate(p_mgr); 570219820Sjeff goto Exit; 571219820Sjeff } 572219820Sjeff 573219820Sjeff if (remote_node_type == IB_NODE_TYPE_SWITCH) { 574219820Sjeff 575219820Sjeff p_remote_sw = 576219820Sjeff p_remote_physp->p_node->sw; 577219820Sjeff if (p_remote_sw->need_update == 2) { 578219820Sjeff /* this could also be case of 579219820Sjeff switch coming back with an 580219820Sjeff additional link that it 581219820Sjeff didn't have before */ 582219820Sjeff OSM_LOG(p_mgr->p_log, 583219820Sjeff OSM_LOG_INFO, 584219820Sjeff "New switch/link found (lid %u) - " 585219820Sjeff "cache is invalid\n", 586219820Sjeff remote_lid_ho); 587219820Sjeff osm_ucast_cache_invalidate 588219820Sjeff (p_mgr); 589219820Sjeff goto Exit; 590219820Sjeff } 591219820Sjeff } else { 592219820Sjeff /* 593219820Sjeff * Remote node is CA/RTR. 594219820Sjeff * Get p_port of the remote node and 595219820Sjeff * check its p_port->is_new flag. 596219820Sjeff */ 597219820Sjeff p_remote_port = 598219820Sjeff osm_get_port_by_guid(p_mgr->p_subn, 599219820Sjeff osm_physp_get_port_guid 600219820Sjeff (p_remote_physp)); 601219820Sjeff if (p_remote_port->is_new) { 602219820Sjeff OSM_LOG(p_mgr->p_log, 603219820Sjeff OSM_LOG_INFO, 604219820Sjeff "New CA/RTR found (lid %u) - " 605219820Sjeff "cache is invalid\n", 606219820Sjeff remote_lid_ho); 607219820Sjeff osm_ucast_cache_invalidate 608219820Sjeff (p_mgr); 609219820Sjeff goto Exit; 610219820Sjeff } 611219820Sjeff } 612219820Sjeff } else { 613219820Sjeff /* 614219820Sjeff * The change on the port is cached. 615219820Sjeff * In general, the reasons might be as follows: 616219820Sjeff * - link between two known nodes went back 617219820Sjeff * - one or more nodes went back, causing all 618219820Sjeff * the links to reappear 619219820Sjeff * 620219820Sjeff * If it was link that went back, then this case 621219820Sjeff * would have been taken care of during the 622219820Sjeff * discovery by osm_ucast_cache_check_new_link(), 623219820Sjeff * so it's some node that went back. 624219820Sjeff */ 625219820Sjeff if ((p_cache_sw->ports[port_num].is_leaf && 626219820Sjeff remote_node_type == IB_NODE_TYPE_SWITCH) || 627219820Sjeff (!p_cache_sw->ports[port_num].is_leaf && 628219820Sjeff remote_node_type != IB_NODE_TYPE_SWITCH)) { 629219820Sjeff OSM_LOG(p_mgr->p_log, OSM_LOG_INFO, 630219820Sjeff "Remote node type change on switch lid %u, port %u - " 631219820Sjeff "cache is invalid\n", 632219820Sjeff lid_ho, port_num); 633219820Sjeff osm_ucast_cache_invalidate(p_mgr); 634219820Sjeff goto Exit; 635219820Sjeff } 636219820Sjeff 637219820Sjeff if (p_cache_sw->ports[port_num].remote_lid_ho != 638219820Sjeff remote_lid_ho) { 639219820Sjeff OSM_LOG(p_mgr->p_log, OSM_LOG_INFO, 640219820Sjeff "Remote lid change on switch lid %u, port %u" 641219820Sjeff "(was %u, now %u) - cache is invalid\n", 642219820Sjeff lid_ho, port_num, 643219820Sjeff p_cache_sw->ports[port_num]. 644219820Sjeff remote_lid_ho, remote_lid_ho); 645219820Sjeff osm_ucast_cache_invalidate(p_mgr); 646219820Sjeff goto Exit; 647219820Sjeff } 648219820Sjeff 649219820Sjeff /* 650219820Sjeff * We don't care who is the node that has 651219820Sjeff * reappeared in the subnet (local or remote). 652219820Sjeff * What's important that the cached link matches 653219820Sjeff * the real fabrics link. 654219820Sjeff * Just clean it from cache. 655219820Sjeff */ 656219820Sjeff 657219820Sjeff p_cache_sw->ports[port_num].remote_lid_ho = 0; 658219820Sjeff p_cache_sw->ports[port_num].is_leaf = FALSE; 659219820Sjeff if (p_cache_sw->dropped) { 660219820Sjeff __cache_restore_ucast_info(p_mgr, 661219820Sjeff p_cache_sw, 662219820Sjeff p_sw); 663219820Sjeff p_cache_sw->dropped = FALSE; 664219820Sjeff } 665219820Sjeff 666219820Sjeff OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, 667219820Sjeff "Restored link from cache: lid %u, port %u to lid %u\n", 668219820Sjeff lid_ho, port_num, remote_lid_ho); 669219820Sjeff } 670219820Sjeff } 671219820Sjeff } 672219820Sjeff 673219820Sjeff /* Remove all the cached switches that 674219820Sjeff have all their ports restored */ 675219820Sjeff __cache_cleanup_switches(p_mgr); 676219820Sjeff 677219820Sjeff /* 678219820Sjeff * Done scanning all the physical switch ports in the subnet. 679219820Sjeff * Now we need to check the other side: 680219820Sjeff * Scan all the cached switches and their ports: 681219820Sjeff * - If the cached switch is missing in the subnet 682219820Sjeff * (dropped flag is on), check that it's a leaf switch. 683219820Sjeff * If it's not a leaf, the cache is invalid, because 684219820Sjeff * cache can tolerate only leaf switch removal. 685219820Sjeff * - If the cached switch exists in fabric, check all 686219820Sjeff * its cached ports. These cached ports represent 687219820Sjeff * missing link in the fabric. 688219820Sjeff * The missing links that can be tolerated are: 689219820Sjeff * + link to missing CA/RTR 690219820Sjeff * + link to missing leaf switch 691219820Sjeff */ 692219820Sjeff for (p_cache_sw = (cache_switch_t *) cl_qmap_head(&p_mgr->cache_sw_tbl); 693219820Sjeff p_cache_sw != (cache_switch_t *) cl_qmap_end(&p_mgr->cache_sw_tbl); 694219820Sjeff p_cache_sw = 695219820Sjeff (cache_switch_t *) cl_qmap_next(&p_cache_sw->map_item)) { 696219820Sjeff 697219820Sjeff if (p_cache_sw->dropped) { 698219820Sjeff if (!__cache_sw_is_leaf(p_cache_sw)) { 699219820Sjeff OSM_LOG(p_mgr->p_log, OSM_LOG_INFO, 700219820Sjeff "Missing non-leaf switch (lid %u) - " 701219820Sjeff "cache is invalid\n", 702219820Sjeff __cache_sw_get_base_lid_ho(p_cache_sw)); 703219820Sjeff osm_ucast_cache_invalidate(p_mgr); 704219820Sjeff goto Exit; 705219820Sjeff } 706219820Sjeff 707219820Sjeff OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, 708219820Sjeff "Missing leaf switch (lid %u) - " 709219820Sjeff "continuing validation\n", 710219820Sjeff __cache_sw_get_base_lid_ho(p_cache_sw)); 711219820Sjeff continue; 712219820Sjeff } 713219820Sjeff 714219820Sjeff for (port_num = 1; port_num < p_cache_sw->num_ports; port_num++) { 715219820Sjeff if (!p_cache_sw->ports[port_num].remote_lid_ho) 716219820Sjeff continue; 717219820Sjeff 718219820Sjeff if (p_cache_sw->ports[port_num].is_leaf) { 719219820Sjeff CL_ASSERT(__cache_sw_is_leaf(p_cache_sw)); 720219820Sjeff OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, 721219820Sjeff "Switch lid %u, port %u: missing link to CA/RTR - " 722219820Sjeff "continuing validation\n", 723219820Sjeff __cache_sw_get_base_lid_ho(p_cache_sw), 724219820Sjeff port_num); 725219820Sjeff continue; 726219820Sjeff } 727219820Sjeff 728219820Sjeff p_remote_cache_sw = __cache_get_sw(p_mgr, 729219820Sjeff p_cache_sw-> 730219820Sjeff ports[port_num]. 731219820Sjeff remote_lid_ho); 732219820Sjeff 733219820Sjeff if (!p_remote_cache_sw || !p_remote_cache_sw->dropped) { 734219820Sjeff OSM_LOG(p_mgr->p_log, OSM_LOG_INFO, 735219820Sjeff "Switch lid %u, port %u: missing link to existing switch - " 736219820Sjeff "cache is invalid\n", 737219820Sjeff __cache_sw_get_base_lid_ho(p_cache_sw), 738219820Sjeff port_num); 739219820Sjeff osm_ucast_cache_invalidate(p_mgr); 740219820Sjeff goto Exit; 741219820Sjeff } 742219820Sjeff 743219820Sjeff if (!__cache_sw_is_leaf(p_remote_cache_sw)) { 744219820Sjeff OSM_LOG(p_mgr->p_log, OSM_LOG_INFO, 745219820Sjeff "Switch lid %u, port %u: missing link to non-leaf switch - " 746219820Sjeff "cache is invalid\n", 747219820Sjeff __cache_sw_get_base_lid_ho(p_cache_sw), 748219820Sjeff port_num); 749219820Sjeff osm_ucast_cache_invalidate(p_mgr); 750219820Sjeff goto Exit; 751219820Sjeff } 752219820Sjeff 753219820Sjeff /* 754219820Sjeff * At this point we know that the missing link is to 755219820Sjeff * a leaf switch. However, one case deserves a special 756219820Sjeff * treatment. If there was a link between two leaf 757219820Sjeff * switches, then missing leaf switch might break 758219820Sjeff * routing. It is possible that there are routes 759219820Sjeff * that use leaf switches to get from switch to switch 760219820Sjeff * and not just to get to the CAs behind the leaf switch. 761219820Sjeff */ 762219820Sjeff if (__cache_sw_is_leaf(p_cache_sw) && 763219820Sjeff __cache_sw_is_leaf(p_remote_cache_sw)) { 764219820Sjeff OSM_LOG(p_mgr->p_log, OSM_LOG_INFO, 765219820Sjeff "Switch lid %u, port %u: missing leaf-2-leaf link - " 766219820Sjeff "cache is invalid\n", 767219820Sjeff __cache_sw_get_base_lid_ho(p_cache_sw), 768219820Sjeff port_num); 769219820Sjeff osm_ucast_cache_invalidate(p_mgr); 770219820Sjeff goto Exit; 771219820Sjeff } 772219820Sjeff 773219820Sjeff OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, 774219820Sjeff "Switch lid %u, port %u: missing remote leaf switch - " 775219820Sjeff "continuing validation\n", 776219820Sjeff __cache_sw_get_base_lid_ho(p_cache_sw), 777219820Sjeff port_num); 778219820Sjeff } 779219820Sjeff } 780219820Sjeff 781219820Sjeff OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, "Unicast cache is valid\n"); 782219820Sjeff __ucast_cache_dump(p_mgr); 783219820SjeffExit: 784219820Sjeff OSM_LOG_EXIT(p_mgr->p_log); 785219820Sjeff} /* osm_ucast_cache_validate() */ 786219820Sjeff 787219820Sjeff/********************************************************************** 788219820Sjeff **********************************************************************/ 789219820Sjeff 790219820Sjeffvoid osm_ucast_cache_check_new_link(osm_ucast_mgr_t * p_mgr, 791219820Sjeff osm_node_t * p_node_1, uint8_t port_num_1, 792219820Sjeff osm_node_t * p_node_2, uint8_t port_num_2) 793219820Sjeff{ 794219820Sjeff uint16_t lid_ho_1; 795219820Sjeff uint16_t lid_ho_2; 796219820Sjeff 797219820Sjeff OSM_LOG_ENTER(p_mgr->p_log); 798219820Sjeff 799219820Sjeff if (!p_mgr->cache_valid) 800219820Sjeff goto Exit; 801219820Sjeff 802219820Sjeff __cache_check_link_change(p_mgr, 803219820Sjeff osm_node_get_physp_ptr(p_node_1, port_num_1), 804219820Sjeff osm_node_get_physp_ptr(p_node_2, port_num_2)); 805219820Sjeff 806219820Sjeff if (!p_mgr->cache_valid) 807219820Sjeff goto Exit; 808219820Sjeff 809219820Sjeff if (osm_node_get_type(p_node_1) != IB_NODE_TYPE_SWITCH && 810219820Sjeff osm_node_get_type(p_node_2) != IB_NODE_TYPE_SWITCH) { 811219820Sjeff OSM_LOG(p_mgr->p_log, OSM_LOG_INFO, 812219820Sjeff "Found CA/RTR-2-CA/RTR link - cache is invalid\n"); 813219820Sjeff osm_ucast_cache_invalidate(p_mgr); 814219820Sjeff goto Exit; 815219820Sjeff } 816219820Sjeff 817219820Sjeff /* for code simplicity, we want the first node to be switch */ 818219820Sjeff if (osm_node_get_type(p_node_1) != IB_NODE_TYPE_SWITCH) { 819219820Sjeff osm_node_t *tmp_node = p_node_1; 820219820Sjeff uint8_t tmp_port_num = port_num_1; 821219820Sjeff p_node_1 = p_node_2; 822219820Sjeff port_num_1 = port_num_2; 823219820Sjeff p_node_2 = tmp_node; 824219820Sjeff port_num_2 = tmp_port_num; 825219820Sjeff } 826219820Sjeff 827219820Sjeff lid_ho_1 = cl_ntoh16(osm_node_get_base_lid(p_node_1, 0)); 828219820Sjeff 829219820Sjeff if (osm_node_get_type(p_node_2) == IB_NODE_TYPE_SWITCH) 830219820Sjeff lid_ho_2 = cl_ntoh16(osm_node_get_base_lid(p_node_2, 0)); 831219820Sjeff else 832219820Sjeff lid_ho_2 = 833219820Sjeff cl_ntoh16(osm_node_get_base_lid(p_node_2, port_num_2)); 834219820Sjeff 835219820Sjeff if (!lid_ho_1 || !lid_ho_2) { 836219820Sjeff /* 837219820Sjeff * No lid assigned, which means that one of the nodes is new. 838219820Sjeff * Need to wait for lid manager to process this node. 839219820Sjeff * The switches and their links will be checked later when 840219820Sjeff * the whole cache validity will be verified. 841219820Sjeff */ 842219820Sjeff OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, 843219820Sjeff "Link port %u <-> %u reveals new node - cache will " 844219820Sjeff "be validated later\n", port_num_1, port_num_2); 845219820Sjeff goto Exit; 846219820Sjeff } 847219820Sjeff 848219820Sjeff __cache_remove_port(p_mgr, lid_ho_1, port_num_1, lid_ho_2, 849219820Sjeff (osm_node_get_type(p_node_2) != 850219820Sjeff IB_NODE_TYPE_SWITCH)); 851219820Sjeff 852219820Sjeff /* if node_2 is a switch, the link should be cleaned from its cache */ 853219820Sjeff 854219820Sjeff if (osm_node_get_type(p_node_2) == IB_NODE_TYPE_SWITCH) 855219820Sjeff __cache_remove_port(p_mgr, lid_ho_2, 856219820Sjeff port_num_2, lid_ho_1, FALSE); 857219820Sjeff 858219820SjeffExit: 859219820Sjeff OSM_LOG_EXIT(p_mgr->p_log); 860219820Sjeff} /* osm_ucast_cache_check_new_link() */ 861219820Sjeff 862219820Sjeff/********************************************************************** 863219820Sjeff **********************************************************************/ 864219820Sjeff 865219820Sjeffvoid osm_ucast_cache_add_link(osm_ucast_mgr_t * p_mgr, 866219820Sjeff osm_physp_t * p_physp1, osm_physp_t * p_physp2) 867219820Sjeff{ 868219820Sjeff osm_node_t *p_node_1 = p_physp1->p_node, *p_node_2 = p_physp2->p_node; 869219820Sjeff uint16_t lid_ho_1, lid_ho_2; 870219820Sjeff 871219820Sjeff OSM_LOG_ENTER(p_mgr->p_log); 872219820Sjeff 873219820Sjeff if (!p_mgr->cache_valid) 874219820Sjeff goto Exit; 875219820Sjeff 876219820Sjeff if (osm_node_get_type(p_node_1) != IB_NODE_TYPE_SWITCH && 877219820Sjeff osm_node_get_type(p_node_2) != IB_NODE_TYPE_SWITCH) { 878219820Sjeff OSM_LOG(p_mgr->p_log, OSM_LOG_INFO, 879219820Sjeff "Dropping CA-2-CA link - cache invalid\n"); 880219820Sjeff osm_ucast_cache_invalidate(p_mgr); 881219820Sjeff goto Exit; 882219820Sjeff } 883219820Sjeff 884219820Sjeff if ((osm_node_get_type(p_node_1) == IB_NODE_TYPE_SWITCH && 885219820Sjeff !osm_node_get_physp_ptr(p_node_1, 0)) || 886219820Sjeff (osm_node_get_type(p_node_2) == IB_NODE_TYPE_SWITCH && 887219820Sjeff !osm_node_get_physp_ptr(p_node_2, 0))) { 888219820Sjeff /* we're caching a link when one of the nodes 889219820Sjeff has already been dropped and cached */ 890219820Sjeff OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, 891219820Sjeff "Port %u <-> port %u: port0 on one of the nodes " 892219820Sjeff "has already been dropped and cached\n", 893219820Sjeff p_physp1->port_num, p_physp2->port_num); 894219820Sjeff goto Exit; 895219820Sjeff } 896219820Sjeff 897219820Sjeff /* One of the nodes is switch. Just for code 898219820Sjeff simplicity, make sure that it's the first node. */ 899219820Sjeff 900219820Sjeff if (osm_node_get_type(p_node_1) != IB_NODE_TYPE_SWITCH) { 901219820Sjeff osm_physp_t *tmp = p_physp1; 902219820Sjeff p_physp1 = p_physp2; 903219820Sjeff p_physp2 = tmp; 904219820Sjeff p_node_1 = p_physp1->p_node; 905219820Sjeff p_node_2 = p_physp2->p_node; 906219820Sjeff } 907219820Sjeff 908219820Sjeff if (!p_node_1->sw) { 909219820Sjeff /* something is wrong - we'd better not use cache */ 910219820Sjeff osm_ucast_cache_invalidate(p_mgr); 911219820Sjeff goto Exit; 912219820Sjeff } 913219820Sjeff 914219820Sjeff lid_ho_1 = cl_ntoh16(osm_node_get_base_lid(p_node_1, 0)); 915219820Sjeff 916219820Sjeff if (osm_node_get_type(p_node_2) == IB_NODE_TYPE_SWITCH) { 917219820Sjeff 918219820Sjeff if (!p_node_2->sw) { 919219820Sjeff /* something is wrong - we'd better not use cache */ 920219820Sjeff osm_ucast_cache_invalidate(p_mgr); 921219820Sjeff goto Exit; 922219820Sjeff } 923219820Sjeff 924219820Sjeff lid_ho_2 = cl_ntoh16(osm_node_get_base_lid(p_node_2, 0)); 925219820Sjeff 926219820Sjeff /* lost switch-2-switch link - cache both sides */ 927219820Sjeff __cache_add_sw_link(p_mgr, p_physp1, lid_ho_2, FALSE); 928219820Sjeff __cache_add_sw_link(p_mgr, p_physp2, lid_ho_1, FALSE); 929219820Sjeff } else { 930219820Sjeff lid_ho_2 = cl_ntoh16(osm_physp_get_base_lid(p_physp2)); 931219820Sjeff 932219820Sjeff /* lost link to CA/RTR - cache only switch side */ 933219820Sjeff __cache_add_sw_link(p_mgr, p_physp1, lid_ho_2, TRUE); 934219820Sjeff } 935219820Sjeff 936219820SjeffExit: 937219820Sjeff OSM_LOG_EXIT(p_mgr->p_log); 938219820Sjeff} /* osm_ucast_cache_add_link() */ 939219820Sjeff 940219820Sjeff/********************************************************************** 941219820Sjeff **********************************************************************/ 942219820Sjeff 943219820Sjeffvoid osm_ucast_cache_add_node(osm_ucast_mgr_t * p_mgr, osm_node_t * p_node) 944219820Sjeff{ 945219820Sjeff uint16_t lid_ho; 946219820Sjeff uint8_t max_ports; 947219820Sjeff uint8_t port_num; 948219820Sjeff osm_physp_t *p_physp; 949219820Sjeff cache_switch_t *p_cache_sw; 950219820Sjeff 951219820Sjeff OSM_LOG_ENTER(p_mgr->p_log); 952219820Sjeff 953219820Sjeff if (!p_mgr->cache_valid) 954219820Sjeff goto Exit; 955219820Sjeff 956219820Sjeff if (osm_node_get_type(p_node) == IB_NODE_TYPE_SWITCH) { 957219820Sjeff 958219820Sjeff lid_ho = cl_ntoh16(osm_node_get_base_lid(p_node, 0)); 959219820Sjeff 960219820Sjeff OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, 961219820Sjeff "Caching dropped switch lid %u\n", lid_ho); 962219820Sjeff 963219820Sjeff if (!p_node->sw) { 964219820Sjeff /* something is wrong - forget about cache */ 965219820Sjeff OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR, 966219820Sjeff "ERR AD03: no switch info for node lid %u - " 967219820Sjeff "clearing cache\n", lid_ho); 968219820Sjeff osm_ucast_cache_invalidate(p_mgr); 969219820Sjeff goto Exit; 970219820Sjeff } 971219820Sjeff 972219820Sjeff /* unlink (add to cache) all the ports of this switch */ 973219820Sjeff max_ports = osm_node_get_num_physp(p_node); 974219820Sjeff for (port_num = 1; port_num < max_ports; port_num++) { 975219820Sjeff 976219820Sjeff p_physp = osm_node_get_physp_ptr(p_node, port_num); 977219820Sjeff if (!p_physp || !p_physp->p_remote_physp) 978219820Sjeff continue; 979219820Sjeff 980219820Sjeff osm_ucast_cache_add_link(p_mgr, p_physp, 981219820Sjeff p_physp->p_remote_physp); 982219820Sjeff } 983219820Sjeff 984219820Sjeff /* 985219820Sjeff * All the ports have been dropped (cached). 986219820Sjeff * If one of the ports was connected to CA/RTR, 987219820Sjeff * then the cached switch would be marked as leaf. 988219820Sjeff * If it isn't, then the dropped switch isn't a leaf, 989219820Sjeff * and cache can't handle it. 990219820Sjeff */ 991219820Sjeff 992219820Sjeff p_cache_sw = __cache_get_sw(p_mgr, lid_ho); 993219820Sjeff CL_ASSERT(p_cache_sw); 994219820Sjeff 995219820Sjeff if (!__cache_sw_is_leaf(p_cache_sw)) { 996219820Sjeff OSM_LOG(p_mgr->p_log, OSM_LOG_INFO, 997219820Sjeff "Dropped non-leaf switch (lid %u) - " 998219820Sjeff "cache is invalid\n", lid_ho); 999219820Sjeff osm_ucast_cache_invalidate(p_mgr); 1000219820Sjeff goto Exit; 1001219820Sjeff } 1002219820Sjeff 1003219820Sjeff p_cache_sw->dropped = TRUE; 1004219820Sjeff 1005219820Sjeff if (!p_node->sw->num_hops || !p_node->sw->hops) { 1006219820Sjeff OSM_LOG(p_mgr->p_log, OSM_LOG_INFO, 1007219820Sjeff "No LID matrices for switch lid %u - " 1008219820Sjeff "cache is invalid\n", lid_ho); 1009219820Sjeff osm_ucast_cache_invalidate(p_mgr); 1010219820Sjeff goto Exit; 1011219820Sjeff } 1012219820Sjeff 1013219820Sjeff /* lid matrices */ 1014219820Sjeff 1015219820Sjeff p_cache_sw->num_hops = p_node->sw->num_hops; 1016219820Sjeff p_node->sw->num_hops = 0; 1017219820Sjeff p_cache_sw->hops = p_node->sw->hops; 1018219820Sjeff p_node->sw->hops = NULL; 1019219820Sjeff 1020219820Sjeff /* linear forwarding table */ 1021219820Sjeff 1022219820Sjeff if (p_node->sw->new_lft) { 1023219820Sjeff /* LFT buffer exists - we use it, because 1024219820Sjeff it is more updated than the switch's LFT */ 1025219820Sjeff p_cache_sw->lft = p_node->sw->new_lft; 1026219820Sjeff p_node->sw->new_lft = NULL; 1027219820Sjeff } else { 1028219820Sjeff /* no LFT buffer, so we use the switch's LFT */ 1029219820Sjeff p_cache_sw->lft = p_node->sw->lft; 1030219820Sjeff p_node->sw->lft = NULL; 1031219820Sjeff } 1032219820Sjeff p_cache_sw->max_lid_ho = p_node->sw->max_lid_ho; 1033219820Sjeff } else { 1034219820Sjeff /* dropping CA/RTR: add to cache all the ports of this node */ 1035219820Sjeff max_ports = osm_node_get_num_physp(p_node); 1036219820Sjeff for (port_num = 1; port_num < max_ports; port_num++) { 1037219820Sjeff 1038219820Sjeff p_physp = osm_node_get_physp_ptr(p_node, port_num); 1039219820Sjeff if (!p_physp || !p_physp->p_remote_physp) 1040219820Sjeff continue; 1041219820Sjeff 1042219820Sjeff CL_ASSERT(osm_node_get_type 1043219820Sjeff (p_physp->p_remote_physp->p_node) == 1044219820Sjeff IB_NODE_TYPE_SWITCH); 1045219820Sjeff 1046219820Sjeff osm_ucast_cache_add_link(p_mgr, 1047219820Sjeff p_physp->p_remote_physp, 1048219820Sjeff p_physp); 1049219820Sjeff } 1050219820Sjeff } 1051219820SjeffExit: 1052219820Sjeff OSM_LOG_EXIT(p_mgr->p_log); 1053219820Sjeff} /* osm_ucast_cache_add_node() */ 1054219820Sjeff 1055219820Sjeff/********************************************************************** 1056219820Sjeff **********************************************************************/ 1057219820Sjeff 1058219820Sjeffint osm_ucast_cache_process(osm_ucast_mgr_t * p_mgr) 1059219820Sjeff{ 1060219820Sjeff cl_qmap_t *tbl = &p_mgr->p_subn->sw_guid_tbl; 1061219820Sjeff cl_map_item_t *item; 1062219820Sjeff osm_switch_t *p_sw; 1063219820Sjeff 1064219820Sjeff if (!p_mgr->p_subn->opt.use_ucast_cache) 1065219820Sjeff return 1; 1066219820Sjeff 1067219820Sjeff ucast_cache_validate(p_mgr); 1068219820Sjeff if (!p_mgr->cache_valid) 1069219820Sjeff return 1; 1070219820Sjeff 1071219820Sjeff OSM_LOG(p_mgr->p_log, OSM_LOG_INFO, 1072219820Sjeff "Configuring switch tables using cached routing\n"); 1073219820Sjeff 1074219820Sjeff for (item = cl_qmap_head(tbl); item != cl_qmap_end(tbl); 1075219820Sjeff item = cl_qmap_next(item)) { 1076219820Sjeff p_sw = (osm_switch_t *) item; 1077219820Sjeff 1078219820Sjeff if (p_sw->need_update && !p_sw->new_lft) { 1079219820Sjeff /* no new routing was recently calculated for this 1080219820Sjeff switch, but the LFT needs to be updated anyway */ 1081219820Sjeff p_sw->new_lft = p_sw->lft; 1082219820Sjeff p_sw->lft = malloc(IB_LID_UCAST_END_HO + 1); 1083219820Sjeff if (!p_sw->lft) 1084219820Sjeff return IB_INSUFFICIENT_MEMORY; 1085219820Sjeff memset(p_sw->lft, OSM_NO_PATH, IB_LID_UCAST_END_HO + 1); 1086219820Sjeff } 1087219820Sjeff 1088219820Sjeff osm_ucast_mgr_set_fwd_table(p_mgr, p_sw); 1089219820Sjeff } 1090219820Sjeff 1091219820Sjeff return 0; 1092219820Sjeff} 1093219820Sjeff 1094219820Sjeff/********************************************************************** 1095219820Sjeff **********************************************************************/ 1096