1321936Shselasky/* 2321936Shselasky * Copyright (c) 2006-2008 Voltaire, Inc. All rights reserved. 3321936Shselasky * Copyright (c) 2006,2008-2009 Mellanox Technologies LTD. All rights reserved. 4321936Shselasky * 5321936Shselasky * This software is available to you under a choice of one of two 6321936Shselasky * licenses. You may choose to be licensed under the terms of the GNU 7321936Shselasky * General Public License (GPL) Version 2, available from the file 8321936Shselasky * COPYING in the main directory of this source tree, or the 9321936Shselasky * OpenIB.org BSD license below: 10321936Shselasky * 11321936Shselasky * Redistribution and use in source and binary forms, with or 12321936Shselasky * without modification, are permitted provided that the following 13321936Shselasky * conditions are met: 14321936Shselasky * 15321936Shselasky * - Redistributions of source code must retain the above 16321936Shselasky * copyright notice, this list of conditions and the following 17321936Shselasky * disclaimer. 18321936Shselasky * 19321936Shselasky * - Redistributions in binary form must reproduce the above 20321936Shselasky * copyright notice, this list of conditions and the following 21321936Shselasky * disclaimer in the documentation and/or other materials 22321936Shselasky * provided with the distribution. 23321936Shselasky * 24321936Shselasky * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 25321936Shselasky * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26321936Shselasky * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 27321936Shselasky * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 28321936Shselasky * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 29321936Shselasky * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 30321936Shselasky * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31321936Shselasky * SOFTWARE. 32321936Shselasky * 33321936Shselasky */ 34321936Shselasky 35321936Shselasky/* 36321936Shselasky * Abstract: 37321936Shselasky * Implementation of OpenSM unicast routing module which loads 38321936Shselasky * routes from the dump file 39321936Shselasky */ 40321936Shselasky 41321936Shselasky#if HAVE_CONFIG_H 42321936Shselasky# include <config.h> 43321936Shselasky#endif /* HAVE_CONFIG_H */ 44321936Shselasky 45321936Shselasky#include <stdlib.h> 46321936Shselasky#include <string.h> 47321936Shselasky#include <ctype.h> 48321936Shselasky 49321936Shselasky#include <iba/ib_types.h> 50321936Shselasky#include <complib/cl_qmap.h> 51321936Shselasky#include <complib/cl_debug.h> 52321936Shselasky#include <opensm/osm_file_ids.h> 53321936Shselasky#define FILE_ID OSM_FILE_UCAST_FILE_C 54321936Shselasky#include <opensm/osm_opensm.h> 55321936Shselasky#include <opensm/osm_switch.h> 56321936Shselasky#include <opensm/osm_log.h> 57321936Shselasky 58321936Shselaskystatic uint16_t remap_lid(osm_opensm_t * p_osm, uint16_t lid, ib_net64_t guid) 59321936Shselasky{ 60321936Shselasky osm_port_t *p_port; 61321936Shselasky uint16_t min_lid, max_lid; 62321936Shselasky uint8_t lmc; 63321936Shselasky 64321936Shselasky p_port = osm_get_port_by_guid(&p_osm->subn, guid); 65321936Shselasky if (!p_port) { 66321936Shselasky OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE, 67321936Shselasky "cannot find port guid 0x%016" PRIx64 68321936Shselasky " , will use the same lid\n", cl_ntoh64(guid)); 69321936Shselasky return lid; 70321936Shselasky } 71321936Shselasky 72321936Shselasky osm_port_get_lid_range_ho(p_port, &min_lid, &max_lid); 73321936Shselasky if (min_lid <= lid && lid <= max_lid) 74321936Shselasky return lid; 75321936Shselasky 76321936Shselasky lmc = osm_port_get_lmc(p_port); 77321936Shselasky return min_lid + (lid & ((1 << lmc) - 1)); 78321936Shselasky} 79321936Shselasky 80321936Shselaskystatic void add_path(osm_opensm_t * p_osm, 81321936Shselasky osm_switch_t * p_sw, uint16_t lid, uint8_t port_num, 82321936Shselasky ib_net64_t port_guid) 83321936Shselasky{ 84321936Shselasky uint16_t new_lid; 85321936Shselasky uint8_t old_port; 86321936Shselasky 87321936Shselasky new_lid = port_guid ? remap_lid(p_osm, lid, port_guid) : lid; 88321936Shselasky old_port = osm_switch_get_port_by_lid(p_sw, new_lid, OSM_LFT); 89321936Shselasky if (old_port != OSM_NO_PATH && old_port != port_num) { 90321936Shselasky OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE, 91321936Shselasky "LID collision is detected on switch " 92321936Shselasky "0x016%" PRIx64 ", will overwrite LID %u entry\n", 93321936Shselasky cl_ntoh64(osm_node_get_node_guid(p_sw->p_node)), 94321936Shselasky new_lid); 95321936Shselasky } 96321936Shselasky 97321936Shselasky p_sw->new_lft[new_lid] = port_num; 98321936Shselasky if (!(p_osm->subn.opt.port_profile_switch_nodes && port_guid && 99321936Shselasky osm_get_switch_by_guid(&p_osm->subn, port_guid))) 100321936Shselasky osm_switch_count_path(p_sw, port_num); 101321936Shselasky 102321936Shselasky OSM_LOG(&p_osm->log, OSM_LOG_DEBUG, 103321936Shselasky "route 0x%04x(was 0x%04x) %u 0x%016" PRIx64 104321936Shselasky " is added to switch 0x%016" PRIx64 "\n", 105321936Shselasky new_lid, lid, port_num, cl_ntoh64(port_guid), 106321936Shselasky cl_ntoh64(osm_node_get_node_guid(p_sw->p_node))); 107321936Shselasky} 108321936Shselasky 109321936Shselaskystatic void add_lid_hops(osm_opensm_t * p_osm, osm_switch_t * p_sw, 110321936Shselasky uint16_t lid, ib_net64_t guid, 111321936Shselasky uint8_t hops[], unsigned len) 112321936Shselasky{ 113321936Shselasky uint8_t i; 114321936Shselasky 115321936Shselasky if (len > p_sw->num_ports) 116321936Shselasky len = p_sw->num_ports; 117321936Shselasky 118321936Shselasky for (i = 0; i < len; i++) 119321936Shselasky osm_switch_set_hops(p_sw, lid, i, hops[i]); 120321936Shselasky} 121321936Shselasky 122321936Shselaskystatic int do_ucast_file_load(void *context) 123321936Shselasky{ 124321936Shselasky char line[1024]; 125321936Shselasky char *file_name; 126321936Shselasky FILE *file; 127321936Shselasky ib_net64_t sw_guid, port_guid; 128321936Shselasky osm_opensm_t *p_osm = context; 129321936Shselasky osm_switch_t *p_sw; 130321936Shselasky uint16_t lid; 131321936Shselasky uint8_t port_num; 132321936Shselasky unsigned lineno; 133321936Shselasky int status = -1; 134321936Shselasky 135321936Shselasky file_name = p_osm->subn.opt.lfts_file; 136321936Shselasky if (!file_name) { 137321936Shselasky OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE, 138321936Shselasky "LFTs file name is not given; " 139321936Shselasky "using default routing algorithm\n"); 140321936Shselasky return 1; 141321936Shselasky } 142321936Shselasky 143321936Shselasky file = fopen(file_name, "r"); 144321936Shselasky if (!file) { 145321936Shselasky OSM_LOG(&p_osm->log, OSM_LOG_ERROR | OSM_LOG_SYS, "ERR 6302: " 146321936Shselasky "Can't open ucast dump file \'%s\': %m\n", file_name); 147321936Shselasky goto Exit; 148321936Shselasky } 149321936Shselasky 150321936Shselasky lineno = 0; 151321936Shselasky p_sw = NULL; 152321936Shselasky 153321936Shselasky while (fgets(line, sizeof(line) - 1, file) != NULL) { 154321936Shselasky char *p, *q; 155321936Shselasky lineno++; 156321936Shselasky 157321936Shselasky p = line; 158321936Shselasky while (isspace(*p)) 159321936Shselasky p++; 160321936Shselasky 161321936Shselasky if (*p == '#') 162321936Shselasky continue; 163321936Shselasky 164321936Shselasky if (!strncmp(p, "Multicast mlids", 15)) { 165321936Shselasky OSM_LOG(&p_osm->log, OSM_LOG_ERROR | OSM_LOG_SYS, 166321936Shselasky "ERR 6303: " 167321936Shselasky "Multicast dump file detected; " 168321936Shselasky "skipping parsing. Using default " 169321936Shselasky "routing algorithm\n"); 170321936Shselasky } else if (!strncmp(p, "Unicast lids", 12)) { 171321936Shselasky q = strstr(p, " guid 0x"); 172321936Shselasky if (!q) { 173321936Shselasky OSM_LOG(&p_osm->log, OSM_LOG_ERROR, 174321936Shselasky "PARSE ERROR: %s:%u: " 175321936Shselasky "cannot parse switch definition\n", 176321936Shselasky file_name, lineno); 177321936Shselasky goto Exit; 178321936Shselasky } 179321936Shselasky p = q + 8; 180321936Shselasky sw_guid = strtoull(p, &q, 16); 181321936Shselasky if (q == p || !isspace(*q)) { 182321936Shselasky OSM_LOG(&p_osm->log, OSM_LOG_ERROR, 183321936Shselasky "PARSE ERROR: %s:%u: " 184321936Shselasky "cannot parse switch guid: \'%s\'\n", 185321936Shselasky file_name, lineno, p); 186321936Shselasky goto Exit; 187321936Shselasky } 188321936Shselasky sw_guid = cl_hton64(sw_guid); 189321936Shselasky 190321936Shselasky p_sw = osm_get_switch_by_guid(&p_osm->subn, sw_guid); 191321936Shselasky if (!p_sw) { 192321936Shselasky OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE, 193321936Shselasky "cannot find switch %016" PRIx64 "\n", 194321936Shselasky cl_ntoh64(sw_guid)); 195321936Shselasky continue; 196321936Shselasky } 197321936Shselasky memset(p_sw->new_lft, OSM_NO_PATH, p_sw->lft_size); 198321936Shselasky } else if (p_sw && !strncmp(p, "0x", 2)) { 199321936Shselasky p += 2; 200321936Shselasky lid = (uint16_t) strtoul(p, &q, 16); 201321936Shselasky if (q == p || !isspace(*q)) { 202321936Shselasky OSM_LOG(&p_osm->log, OSM_LOG_ERROR, 203321936Shselasky "PARSE ERROR: %s:%u: " 204321936Shselasky "cannot parse lid: \'%s\'\n", 205321936Shselasky file_name, lineno, p); 206321936Shselasky goto Exit; 207321936Shselasky } 208321936Shselasky p = q; 209321936Shselasky while (isspace(*p)) 210321936Shselasky p++; 211321936Shselasky port_num = (uint8_t) strtoul(p, &q, 10); 212321936Shselasky if (q == p || !isspace(*q)) { 213321936Shselasky OSM_LOG(&p_osm->log, OSM_LOG_ERROR, 214321936Shselasky "PARSE ERROR: %s:%u: " 215321936Shselasky "cannot parse port: \'%s\'\n", 216321936Shselasky file_name, lineno, p); 217321936Shselasky goto Exit; 218321936Shselasky } 219321936Shselasky if (port_num >= 220321936Shselasky osm_node_get_num_physp(p_sw->p_node)) { 221321936Shselasky OSM_LOG(&p_osm->log, OSM_LOG_ERROR, 222321936Shselasky "Invalid port %d found " 223321936Shselasky "for switch %016" PRIx64 "\n", 224321936Shselasky port_num, 225321936Shselasky cl_ntoh64(osm_node_get_node_guid 226321936Shselasky (p_sw->p_node))); 227321936Shselasky goto Exit; 228321936Shselasky } 229321936Shselasky 230321936Shselasky p = q; 231321936Shselasky /* additionally try to extract guid */ 232321936Shselasky q = strstr(p, " portguid 0x"); 233321936Shselasky if (!q) { 234321936Shselasky OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE, 235321936Shselasky "PARSE WARNING: %s:%u: " 236321936Shselasky "cannot find port guid " 237321936Shselasky "(maybe broken dump): \'%s\'\n", 238321936Shselasky file_name, lineno, p); 239321936Shselasky port_guid = 0; 240321936Shselasky } else { 241321936Shselasky p = q + 12; 242321936Shselasky port_guid = strtoull(p, &q, 16); 243321936Shselasky if (q == p || (!isspace(*q) && *q != ':')) { 244321936Shselasky OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE, 245321936Shselasky "PARSE WARNING: %s:%u: " 246321936Shselasky "cannot parse port guid " 247321936Shselasky "(maybe broken dump): \'%s\'\n", 248321936Shselasky file_name, lineno, p); 249321936Shselasky port_guid = 0; 250321936Shselasky } 251321936Shselasky } 252321936Shselasky port_guid = cl_hton64(port_guid); 253321936Shselasky add_path(p_osm, p_sw, lid, port_num, port_guid); 254321936Shselasky } 255321936Shselasky } 256321936Shselasky status = 0; 257321936ShselaskyExit: 258321936Shselasky if (file) 259321936Shselasky fclose(file); 260321936Shselasky return status; 261321936Shselasky} 262321936Shselasky 263321936Shselaskystatic int do_lid_matrix_file_load(void *context) 264321936Shselasky{ 265321936Shselasky char line[1024]; 266321936Shselasky uint8_t hops[256]; 267321936Shselasky char *file_name; 268321936Shselasky FILE *file; 269321936Shselasky ib_net64_t guid; 270321936Shselasky osm_opensm_t *p_osm = context; 271321936Shselasky osm_switch_t *p_sw; 272321936Shselasky unsigned lineno; 273321936Shselasky uint16_t lid; 274321936Shselasky int status = -1; 275321936Shselasky 276321936Shselasky file_name = p_osm->subn.opt.lid_matrix_dump_file; 277321936Shselasky if (!file_name) { 278321936Shselasky OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE, 279321936Shselasky "lid matrix file name is not given; " 280321936Shselasky "using default lid matrix generation algorithm\n"); 281321936Shselasky return 1; 282321936Shselasky } 283321936Shselasky 284321936Shselasky file = fopen(file_name, "r"); 285321936Shselasky if (!file) { 286321936Shselasky OSM_LOG(&p_osm->log, OSM_LOG_ERROR | OSM_LOG_SYS, "ERR 6305: " 287321936Shselasky "Can't open lid matrix file \'%s\': %m\n", file_name); 288321936Shselasky goto Exit; 289321936Shselasky } 290321936Shselasky 291321936Shselasky lineno = 0; 292321936Shselasky p_sw = NULL; 293321936Shselasky 294321936Shselasky while (fgets(line, sizeof(line) - 1, file) != NULL) { 295321936Shselasky char *p, *q; 296321936Shselasky lineno++; 297321936Shselasky 298321936Shselasky p = line; 299321936Shselasky while (isspace(*p)) 300321936Shselasky p++; 301321936Shselasky 302321936Shselasky if (*p == '#') 303321936Shselasky continue; 304321936Shselasky 305321936Shselasky if (!strncmp(p, "Switch", 6)) { 306321936Shselasky q = strstr(p, " guid 0x"); 307321936Shselasky if (!q) { 308321936Shselasky OSM_LOG(&p_osm->log, OSM_LOG_ERROR, 309321936Shselasky "PARSE ERROR: %s:%u: " 310321936Shselasky "cannot parse switch definition\n", 311321936Shselasky file_name, lineno); 312321936Shselasky goto Exit; 313321936Shselasky } 314321936Shselasky p = q + 8; 315321936Shselasky guid = strtoull(p, &q, 16); 316321936Shselasky if (q == p || !isspace(*q)) { 317321936Shselasky OSM_LOG(&p_osm->log, OSM_LOG_ERROR, 318321936Shselasky "PARSE ERROR: %s:%u: " 319321936Shselasky "cannot parse switch guid: \'%s\'\n", 320321936Shselasky file_name, lineno, p); 321321936Shselasky goto Exit; 322321936Shselasky } 323321936Shselasky guid = cl_hton64(guid); 324321936Shselasky 325321936Shselasky p_sw = osm_get_switch_by_guid(&p_osm->subn, guid); 326321936Shselasky if (!p_sw) { 327321936Shselasky OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE, 328321936Shselasky "cannot find switch %016" PRIx64 "\n", 329321936Shselasky cl_ntoh64(guid)); 330321936Shselasky continue; 331321936Shselasky } 332321936Shselasky } else if (p_sw && !strncmp(p, "0x", 2)) { 333321936Shselasky unsigned long num; 334321936Shselasky unsigned len = 0; 335321936Shselasky 336321936Shselasky memset(hops, 0xff, sizeof(hops)); 337321936Shselasky 338321936Shselasky p += 2; 339321936Shselasky num = strtoul(p, &q, 16); 340321936Shselasky if (num > 0xffff || q == p || 341321936Shselasky (*q != ':' && !isspace(*q))) { 342321936Shselasky OSM_LOG(&p_osm->log, OSM_LOG_ERROR, 343321936Shselasky "PARSE ERROR: %s:%u: " 344321936Shselasky "cannot parse lid: \'%s\'\n", 345321936Shselasky file_name, lineno, p); 346321936Shselasky goto Exit; 347321936Shselasky } 348321936Shselasky /* Just checked the range, so casting is safe */ 349321936Shselasky lid = (uint16_t) num; 350321936Shselasky p = q; 351321936Shselasky while (isspace(*p) || *p == ':') 352321936Shselasky p++; 353321936Shselasky while (len < 256 && *p && *p != '#') { 354321936Shselasky num = strtoul(p, &q, 16); 355321936Shselasky if (num > 0xff || q == p) { 356321936Shselasky OSM_LOG(&p_osm->log, OSM_LOG_ERROR, 357321936Shselasky "PARSE ERROR: %s:%u: " 358321936Shselasky "cannot parse hops number: \'%s\'\n", 359321936Shselasky file_name, lineno, p); 360321936Shselasky goto Exit; 361321936Shselasky } 362321936Shselasky /* Just checked the range, so casting is safe */ 363321936Shselasky hops[len++] = (uint8_t) num; 364321936Shselasky p = q; 365321936Shselasky while (isspace(*p)) 366321936Shselasky p++; 367321936Shselasky } 368321936Shselasky /* additionally try to extract guid */ 369321936Shselasky q = strstr(p, " portguid 0x"); 370321936Shselasky if (!q) { 371321936Shselasky OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE, 372321936Shselasky "PARSE WARNING: %s:%u: " 373321936Shselasky "cannot find port guid " 374321936Shselasky "(maybe broken dump): \'%s\'\n", 375321936Shselasky file_name, lineno, p); 376321936Shselasky guid = 0; 377321936Shselasky } else { 378321936Shselasky p = q + 12; 379321936Shselasky guid = strtoull(p, &q, 16); 380321936Shselasky if (q == p || !isspace(*q)) { 381321936Shselasky OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE, 382321936Shselasky "PARSE WARNING: %s:%u: " 383321936Shselasky "cannot parse port guid " 384321936Shselasky "(maybe broken dump): \'%s\'\n", 385321936Shselasky file_name, lineno, p); 386321936Shselasky guid = 0; 387321936Shselasky } 388321936Shselasky } 389321936Shselasky guid = cl_hton64(guid); 390321936Shselasky add_lid_hops(p_osm, p_sw, lid, guid, hops, len); 391321936Shselasky } 392321936Shselasky } 393321936Shselasky status = 0; 394321936ShselaskyExit: 395321936Shselasky if (file) 396321936Shselasky fclose(file); 397321936Shselasky return status; 398321936Shselasky} 399321936Shselasky 400321936Shselaskyint osm_ucast_file_setup(struct osm_routing_engine *r, osm_opensm_t *osm) 401321936Shselasky{ 402321936Shselasky r->context = osm; 403321936Shselasky r->build_lid_matrices = do_lid_matrix_file_load; 404321936Shselasky r->ucast_build_fwd_tables = do_ucast_file_load; 405321936Shselasky return 0; 406321936Shselasky} 407