1219820Sjeff/* 2219820Sjeff * Copyright (c) 2006,2007 Voltaire, Inc. All rights reserved. 3219820Sjeff * Copyright (c) 2008 Mellanox Technologies LTD. All rights reserved. 4219820Sjeff * 5219820Sjeff * This software is available to you under a choice of one of two 6219820Sjeff * licenses. You may choose to be licensed under the terms of the GNU 7219820Sjeff * General Public License (GPL) Version 2, available from the file 8219820Sjeff * COPYING in the main directory of this source tree, or the 9219820Sjeff * OpenIB.org BSD license below: 10219820Sjeff * 11219820Sjeff * Redistribution and use in source and binary forms, with or 12219820Sjeff * without modification, are permitted provided that the following 13219820Sjeff * conditions are met: 14219820Sjeff * 15219820Sjeff * - Redistributions of source code must retain the above 16219820Sjeff * copyright notice, this list of conditions and the following 17219820Sjeff * disclaimer. 18219820Sjeff * 19219820Sjeff * - Redistributions in binary form must reproduce the above 20219820Sjeff * copyright notice, this list of conditions and the following 21219820Sjeff * disclaimer in the documentation and/or other materials 22219820Sjeff * provided with the distribution. 23219820Sjeff * 24219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 25219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 27219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 28219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 29219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 30219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31219820Sjeff * SOFTWARE. 32219820Sjeff * 33219820Sjeff */ 34219820Sjeff 35219820Sjeff/* 36219820Sjeff * Abstract: 37219820Sjeff * Implementation of OpenSM unicast routing module which loads 38219820Sjeff * routes from the dump file 39219820Sjeff */ 40219820Sjeff 41219820Sjeff#if HAVE_CONFIG_H 42219820Sjeff# include <config.h> 43219820Sjeff#endif /* HAVE_CONFIG_H */ 44219820Sjeff 45219820Sjeff#include <stdlib.h> 46219820Sjeff#include <string.h> 47219820Sjeff#include <ctype.h> 48219820Sjeff 49219820Sjeff#include <iba/ib_types.h> 50219820Sjeff#include <complib/cl_qmap.h> 51219820Sjeff#include <complib/cl_debug.h> 52219820Sjeff#include <opensm/osm_opensm.h> 53219820Sjeff#include <opensm/osm_switch.h> 54219820Sjeff#include <opensm/osm_log.h> 55219820Sjeff 56219820Sjeffstatic uint16_t remap_lid(osm_opensm_t * p_osm, uint16_t lid, ib_net64_t guid) 57219820Sjeff{ 58219820Sjeff osm_port_t *p_port; 59219820Sjeff uint16_t min_lid, max_lid; 60219820Sjeff uint8_t lmc; 61219820Sjeff 62219820Sjeff p_port = osm_get_port_by_guid(&p_osm->subn, guid); 63219820Sjeff if (!p_port) { 64219820Sjeff OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE, 65219820Sjeff "cannot find port guid 0x%016" PRIx64 66219820Sjeff " , will use the same lid\n", cl_ntoh64(guid)); 67219820Sjeff return lid; 68219820Sjeff } 69219820Sjeff 70219820Sjeff osm_port_get_lid_range_ho(p_port, &min_lid, &max_lid); 71219820Sjeff if (min_lid <= lid && lid <= max_lid) 72219820Sjeff return lid; 73219820Sjeff 74219820Sjeff lmc = osm_port_get_lmc(p_port); 75219820Sjeff return min_lid + (lid & ((1 << lmc) - 1)); 76219820Sjeff} 77219820Sjeff 78219820Sjeffstatic void add_path(osm_opensm_t * p_osm, 79219820Sjeff osm_switch_t * p_sw, uint16_t lid, uint8_t port_num, 80219820Sjeff ib_net64_t port_guid) 81219820Sjeff{ 82219820Sjeff uint16_t new_lid; 83219820Sjeff uint8_t old_port; 84219820Sjeff 85219820Sjeff new_lid = port_guid ? remap_lid(p_osm, lid, port_guid) : lid; 86219820Sjeff old_port = osm_switch_get_port_by_lid(p_sw, new_lid); 87219820Sjeff if (old_port != OSM_NO_PATH && old_port != port_num) { 88219820Sjeff OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE, 89219820Sjeff "LID collision is detected on switch " 90219820Sjeff "0x016%" PRIx64 ", will overwrite LID %u entry\n", 91219820Sjeff cl_ntoh64(osm_node_get_node_guid(p_sw->p_node)), 92219820Sjeff new_lid); 93219820Sjeff } 94219820Sjeff 95219820Sjeff p_sw->new_lft[new_lid] = port_num; 96219820Sjeff if (!(p_osm->subn.opt.port_profile_switch_nodes && port_guid && 97219820Sjeff osm_get_switch_by_guid(&p_osm->subn, port_guid))) 98219820Sjeff osm_switch_count_path(p_sw, port_num); 99219820Sjeff 100219820Sjeff OSM_LOG(&p_osm->log, OSM_LOG_DEBUG, 101219820Sjeff "route 0x%04x(was 0x%04x) %u 0x%016" PRIx64 102219820Sjeff " is added to switch 0x%016" PRIx64 "\n", 103219820Sjeff new_lid, lid, port_num, cl_ntoh64(port_guid), 104219820Sjeff cl_ntoh64(osm_node_get_node_guid(p_sw->p_node))); 105219820Sjeff} 106219820Sjeff 107219820Sjeffstatic void add_lid_hops(osm_opensm_t * p_osm, osm_switch_t * p_sw, 108219820Sjeff uint16_t lid, ib_net64_t guid, 109219820Sjeff uint8_t hops[], unsigned len) 110219820Sjeff{ 111219820Sjeff uint16_t new_lid; 112219820Sjeff uint8_t i; 113219820Sjeff 114219820Sjeff new_lid = guid ? remap_lid(p_osm, lid, guid) : lid; 115219820Sjeff if (len > p_sw->num_ports) 116219820Sjeff len = p_sw->num_ports; 117219820Sjeff 118219820Sjeff for (i = 0; i < len; i++) 119219820Sjeff osm_switch_set_hops(p_sw, lid, i, hops[i]); 120219820Sjeff} 121219820Sjeff 122219820Sjeffstatic int do_ucast_file_load(void *context) 123219820Sjeff{ 124219820Sjeff char line[1024]; 125219820Sjeff char *file_name; 126219820Sjeff FILE *file; 127219820Sjeff ib_net64_t sw_guid, port_guid; 128219820Sjeff osm_opensm_t *p_osm = context; 129219820Sjeff osm_switch_t *p_sw; 130219820Sjeff uint16_t lid; 131219820Sjeff uint8_t port_num; 132219820Sjeff unsigned lineno; 133219820Sjeff 134219820Sjeff file_name = p_osm->subn.opt.lfts_file; 135219820Sjeff if (!file_name) { 136219820Sjeff OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE, 137219820Sjeff "LFTs file name is not given; " 138219820Sjeff "using default routing algorithm\n"); 139219820Sjeff return 1; 140219820Sjeff } 141219820Sjeff 142219820Sjeff file = fopen(file_name, "r"); 143219820Sjeff if (!file) { 144219820Sjeff OSM_LOG(&p_osm->log, OSM_LOG_ERROR | OSM_LOG_SYS, "ERR 6302: " 145219820Sjeff "cannot open ucast dump file \'%s\': %m\n", file_name); 146219820Sjeff return -1; 147219820Sjeff } 148219820Sjeff 149219820Sjeff lineno = 0; 150219820Sjeff p_sw = NULL; 151219820Sjeff 152219820Sjeff while (fgets(line, sizeof(line) - 1, file) != NULL) { 153219820Sjeff char *p, *q; 154219820Sjeff lineno++; 155219820Sjeff 156219820Sjeff p = line; 157219820Sjeff while (isspace(*p)) 158219820Sjeff p++; 159219820Sjeff 160219820Sjeff if (*p == '#') 161219820Sjeff continue; 162219820Sjeff 163219820Sjeff if (!strncmp(p, "Multicast mlids", 15)) { 164219820Sjeff OSM_LOG(&p_osm->log, OSM_LOG_ERROR | OSM_LOG_SYS, 165219820Sjeff "ERR 6303: " 166219820Sjeff "Multicast dump file detected; " 167219820Sjeff "skipping parsing. Using default " 168219820Sjeff "routing algorithm\n"); 169219820Sjeff } else if (!strncmp(p, "Unicast lids", 12)) { 170219820Sjeff if (p_sw) 171219820Sjeff osm_ucast_mgr_set_fwd_table(&p_osm->sm. 172219820Sjeff ucast_mgr, p_sw); 173219820Sjeff q = strstr(p, " guid 0x"); 174219820Sjeff if (!q) { 175219820Sjeff OSM_LOG(&p_osm->log, OSM_LOG_ERROR, 176219820Sjeff "PARSE ERROR: %s:%u: " 177219820Sjeff "cannot parse switch definition\n", 178219820Sjeff file_name, lineno); 179219820Sjeff return -1; 180219820Sjeff } 181219820Sjeff p = q + 8; 182219820Sjeff sw_guid = strtoull(p, &q, 16); 183219820Sjeff if (q == p || !isspace(*q)) { 184219820Sjeff OSM_LOG(&p_osm->log, OSM_LOG_ERROR, 185219820Sjeff "PARSE ERROR: %s:%u: " 186219820Sjeff "cannot parse switch guid: \'%s\'\n", 187219820Sjeff file_name, lineno, p); 188219820Sjeff return -1; 189219820Sjeff } 190219820Sjeff sw_guid = cl_hton64(sw_guid); 191219820Sjeff 192219820Sjeff p_sw = osm_get_switch_by_guid(&p_osm->subn, sw_guid); 193219820Sjeff if (!p_sw) { 194219820Sjeff OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE, 195219820Sjeff "cannot find switch %016" PRIx64 "\n", 196219820Sjeff cl_ntoh64(sw_guid)); 197219820Sjeff continue; 198219820Sjeff } 199219820Sjeff memset(p_sw->new_lft, OSM_NO_PATH, 200219820Sjeff IB_LID_UCAST_END_HO + 1); 201219820Sjeff } else if (p_sw && !strncmp(p, "0x", 2)) { 202219820Sjeff p += 2; 203219820Sjeff lid = (uint16_t) strtoul(p, &q, 16); 204219820Sjeff if (q == p || !isspace(*q)) { 205219820Sjeff OSM_LOG(&p_osm->log, OSM_LOG_ERROR, 206219820Sjeff "PARSE ERROR: %s:%u: " 207219820Sjeff "cannot parse lid: \'%s\'\n", 208219820Sjeff file_name, lineno, p); 209219820Sjeff return -1; 210219820Sjeff } 211219820Sjeff p = q; 212219820Sjeff while (isspace(*p)) 213219820Sjeff p++; 214219820Sjeff port_num = (uint8_t) strtoul(p, &q, 10); 215219820Sjeff if (q == p || !isspace(*q)) { 216219820Sjeff OSM_LOG(&p_osm->log, OSM_LOG_ERROR, 217219820Sjeff "PARSE ERROR: %s:%u: " 218219820Sjeff "cannot parse port: \'%s\'\n", 219219820Sjeff file_name, lineno, p); 220219820Sjeff return -1; 221219820Sjeff } 222219820Sjeff p = q; 223219820Sjeff /* additionally try to exract guid */ 224219820Sjeff q = strstr(p, " portguid 0x"); 225219820Sjeff if (!q) { 226219820Sjeff OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE, 227219820Sjeff "PARSE WARNING: %s:%u: " 228219820Sjeff "cannot find port guid " 229219820Sjeff "(maybe broken dump): \'%s\'\n", 230219820Sjeff file_name, lineno, p); 231219820Sjeff port_guid = 0; 232219820Sjeff } else { 233219820Sjeff p = q + 12; 234219820Sjeff port_guid = strtoull(p, &q, 16); 235219820Sjeff if (q == p || (!isspace(*q) && *q != ':')) { 236219820Sjeff OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE, 237219820Sjeff "PARSE WARNING: %s:%u: " 238219820Sjeff "cannot parse port guid " 239219820Sjeff "(maybe broken dump): \'%s\'\n", 240219820Sjeff file_name, lineno, p); 241219820Sjeff port_guid = 0; 242219820Sjeff } 243219820Sjeff } 244219820Sjeff port_guid = cl_hton64(port_guid); 245219820Sjeff add_path(p_osm, p_sw, lid, port_num, port_guid); 246219820Sjeff } 247219820Sjeff } 248219820Sjeff 249219820Sjeff if (p_sw) 250219820Sjeff osm_ucast_mgr_set_fwd_table(&p_osm->sm.ucast_mgr, p_sw); 251219820Sjeff 252219820Sjeff fclose(file); 253219820Sjeff return 0; 254219820Sjeff} 255219820Sjeff 256219820Sjeffstatic int do_lid_matrix_file_load(void *context) 257219820Sjeff{ 258219820Sjeff char line[1024]; 259219820Sjeff uint8_t hops[256]; 260219820Sjeff char *file_name; 261219820Sjeff FILE *file; 262219820Sjeff ib_net64_t guid; 263219820Sjeff osm_opensm_t *p_osm = context; 264219820Sjeff osm_switch_t *p_sw; 265219820Sjeff unsigned lineno; 266219820Sjeff uint16_t lid; 267219820Sjeff 268219820Sjeff file_name = p_osm->subn.opt.lid_matrix_dump_file; 269219820Sjeff if (!file_name) { 270219820Sjeff OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE, 271219820Sjeff "lid matrix file name is not given; " 272219820Sjeff "using default lid matrix generation algorithm\n"); 273219820Sjeff return 1; 274219820Sjeff } 275219820Sjeff 276219820Sjeff file = fopen(file_name, "r"); 277219820Sjeff if (!file) { 278219820Sjeff OSM_LOG(&p_osm->log, OSM_LOG_ERROR | OSM_LOG_SYS, "ERR 6305: " 279219820Sjeff "cannot open lid matrix file \'%s\': %m\n", file_name); 280219820Sjeff return -1; 281219820Sjeff } 282219820Sjeff 283219820Sjeff lineno = 0; 284219820Sjeff p_sw = NULL; 285219820Sjeff 286219820Sjeff while (fgets(line, sizeof(line) - 1, file) != NULL) { 287219820Sjeff char *p, *q; 288219820Sjeff lineno++; 289219820Sjeff 290219820Sjeff p = line; 291219820Sjeff while (isspace(*p)) 292219820Sjeff p++; 293219820Sjeff 294219820Sjeff if (*p == '#') 295219820Sjeff continue; 296219820Sjeff 297219820Sjeff if (!strncmp(p, "Switch", 6)) { 298219820Sjeff q = strstr(p, " guid 0x"); 299219820Sjeff if (!q) { 300219820Sjeff OSM_LOG(&p_osm->log, OSM_LOG_ERROR, 301219820Sjeff "PARSE ERROR: %s:%u: " 302219820Sjeff "cannot parse switch definition\n", 303219820Sjeff file_name, lineno); 304219820Sjeff return -1; 305219820Sjeff } 306219820Sjeff p = q + 8; 307219820Sjeff guid = strtoull(p, &q, 16); 308219820Sjeff if (q == p || !isspace(*q)) { 309219820Sjeff OSM_LOG(&p_osm->log, OSM_LOG_ERROR, 310219820Sjeff "PARSE ERROR: %s:%u: " 311219820Sjeff "cannot parse switch guid: \'%s\'\n", 312219820Sjeff file_name, lineno, p); 313219820Sjeff return -1; 314219820Sjeff } 315219820Sjeff guid = cl_hton64(guid); 316219820Sjeff 317219820Sjeff p_sw = osm_get_switch_by_guid(&p_osm->subn, guid); 318219820Sjeff if (!p_sw) { 319219820Sjeff OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE, 320219820Sjeff "cannot find switch %016" PRIx64 "\n", 321219820Sjeff cl_ntoh64(guid)); 322219820Sjeff continue; 323219820Sjeff } 324219820Sjeff } else if (p_sw && !strncmp(p, "0x", 2)) { 325219820Sjeff unsigned long num; 326219820Sjeff unsigned len = 0; 327219820Sjeff 328219820Sjeff memset(hops, 0xff, sizeof(hops)); 329219820Sjeff 330219820Sjeff p += 2; 331219820Sjeff num = strtoul(p, &q, 16); 332219820Sjeff if (num > 0xffff || q == p || 333219820Sjeff (*q != ':' && !isspace(*q))) { 334219820Sjeff OSM_LOG(&p_osm->log, OSM_LOG_ERROR, 335219820Sjeff "PARSE ERROR: %s:%u: " 336219820Sjeff "cannot parse lid: \'%s\'\n", 337219820Sjeff file_name, lineno, p); 338219820Sjeff return -1; 339219820Sjeff } 340219820Sjeff /* Just checked the range, so casting is safe */ 341219820Sjeff lid = (uint16_t) num; 342219820Sjeff p = q; 343219820Sjeff while (isspace(*p) || *p == ':') 344219820Sjeff p++; 345219820Sjeff while (len < 256 && *p && *p != '#') { 346219820Sjeff num = strtoul(p, &q, 16); 347219820Sjeff if (num > 0xff || q == p) { 348219820Sjeff OSM_LOG(&p_osm->log, OSM_LOG_ERROR, 349219820Sjeff "PARSE ERROR: %s:%u: " 350219820Sjeff "cannot parse hops number: \'%s\'\n", 351219820Sjeff file_name, lineno, p); 352219820Sjeff return -1; 353219820Sjeff } 354219820Sjeff /* Just checked the range, so casting is safe */ 355219820Sjeff hops[len++] = (uint8_t) num; 356219820Sjeff p = q; 357219820Sjeff while (isspace(*p)) 358219820Sjeff p++; 359219820Sjeff } 360219820Sjeff /* additionally try to extract guid */ 361219820Sjeff q = strstr(p, " portguid 0x"); 362219820Sjeff if (!q) { 363219820Sjeff OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE, 364219820Sjeff "PARSE WARNING: %s:%u: " 365219820Sjeff "cannot find port guid " 366219820Sjeff "(maybe broken dump): \'%s\'\n", 367219820Sjeff file_name, lineno, p); 368219820Sjeff guid = 0; 369219820Sjeff } else { 370219820Sjeff p = q + 12; 371219820Sjeff guid = strtoull(p, &q, 16); 372219820Sjeff if (q == p || !isspace(*q)) { 373219820Sjeff OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE, 374219820Sjeff "PARSE WARNING: %s:%u: " 375219820Sjeff "cannot parse port guid " 376219820Sjeff "(maybe broken dump): \'%s\'\n", 377219820Sjeff file_name, lineno, p); 378219820Sjeff guid = 0; 379219820Sjeff } 380219820Sjeff } 381219820Sjeff guid = cl_hton64(guid); 382219820Sjeff add_lid_hops(p_osm, p_sw, lid, guid, hops, len); 383219820Sjeff } 384219820Sjeff } 385219820Sjeff 386219820Sjeff fclose(file); 387219820Sjeff return 0; 388219820Sjeff} 389219820Sjeff 390219820Sjeffint osm_ucast_file_setup(struct osm_routing_engine *r, osm_opensm_t *osm) 391219820Sjeff{ 392219820Sjeff r->context = osm; 393219820Sjeff r->build_lid_matrices = do_lid_matrix_file_load; 394219820Sjeff r->ucast_build_fwd_tables = do_ucast_file_load; 395219820Sjeff return 0; 396219820Sjeff} 397