1/* 2 * Copyright (c) 2006,2007 Voltaire, Inc. All rights reserved. 3 * Copyright (c) 2008 Mellanox Technologies LTD. All rights reserved. 4 * 5 * This software is available to you under a choice of one of two 6 * licenses. You may choose to be licensed under the terms of the GNU 7 * General Public License (GPL) Version 2, available from the file 8 * COPYING in the main directory of this source tree, or the 9 * OpenIB.org BSD license below: 10 * 11 * Redistribution and use in source and binary forms, with or 12 * without modification, are permitted provided that the following 13 * conditions are met: 14 * 15 * - Redistributions of source code must retain the above 16 * copyright notice, this list of conditions and the following 17 * disclaimer. 18 * 19 * - Redistributions in binary form must reproduce the above 20 * copyright notice, this list of conditions and the following 21 * disclaimer in the documentation and/or other materials 22 * provided with the distribution. 23 * 24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 28 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 29 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 30 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31 * SOFTWARE. 32 * 33 */ 34 35/* 36 * Abstract: 37 * Implementation of OpenSM unicast routing module which loads 38 * routes from the dump file 39 */ 40 41#if HAVE_CONFIG_H 42# include <config.h> 43#endif /* HAVE_CONFIG_H */ 44 45#include <stdlib.h> 46#include <string.h> 47#include <ctype.h> 48 49#include <iba/ib_types.h> 50#include <complib/cl_qmap.h> 51#include <complib/cl_debug.h> 52#include <opensm/osm_opensm.h> 53#include <opensm/osm_switch.h> 54#include <opensm/osm_log.h> 55 56static uint16_t remap_lid(osm_opensm_t * p_osm, uint16_t lid, ib_net64_t guid) 57{ 58 osm_port_t *p_port; 59 uint16_t min_lid, max_lid; 60 uint8_t lmc; 61 62 p_port = osm_get_port_by_guid(&p_osm->subn, guid); 63 if (!p_port) { 64 OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE, 65 "cannot find port guid 0x%016" PRIx64 66 " , will use the same lid\n", cl_ntoh64(guid)); 67 return lid; 68 } 69 70 osm_port_get_lid_range_ho(p_port, &min_lid, &max_lid); 71 if (min_lid <= lid && lid <= max_lid) 72 return lid; 73 74 lmc = osm_port_get_lmc(p_port); 75 return min_lid + (lid & ((1 << lmc) - 1)); 76} 77 78static void add_path(osm_opensm_t * p_osm, 79 osm_switch_t * p_sw, uint16_t lid, uint8_t port_num, 80 ib_net64_t port_guid) 81{ 82 uint16_t new_lid; 83 uint8_t old_port; 84 85 new_lid = port_guid ? remap_lid(p_osm, lid, port_guid) : lid; 86 old_port = osm_switch_get_port_by_lid(p_sw, new_lid); 87 if (old_port != OSM_NO_PATH && old_port != port_num) { 88 OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE, 89 "LID collision is detected on switch " 90 "0x016%" PRIx64 ", will overwrite LID %u entry\n", 91 cl_ntoh64(osm_node_get_node_guid(p_sw->p_node)), 92 new_lid); 93 } 94 95 p_sw->new_lft[new_lid] = port_num; 96 if (!(p_osm->subn.opt.port_profile_switch_nodes && port_guid && 97 osm_get_switch_by_guid(&p_osm->subn, port_guid))) 98 osm_switch_count_path(p_sw, port_num); 99 100 OSM_LOG(&p_osm->log, OSM_LOG_DEBUG, 101 "route 0x%04x(was 0x%04x) %u 0x%016" PRIx64 102 " is added to switch 0x%016" PRIx64 "\n", 103 new_lid, lid, port_num, cl_ntoh64(port_guid), 104 cl_ntoh64(osm_node_get_node_guid(p_sw->p_node))); 105} 106 107static void add_lid_hops(osm_opensm_t * p_osm, osm_switch_t * p_sw, 108 uint16_t lid, ib_net64_t guid, 109 uint8_t hops[], unsigned len) 110{ 111 uint16_t new_lid; 112 uint8_t i; 113 114 new_lid = guid ? remap_lid(p_osm, lid, guid) : lid; 115 if (len > p_sw->num_ports) 116 len = p_sw->num_ports; 117 118 for (i = 0; i < len; i++) 119 osm_switch_set_hops(p_sw, lid, i, hops[i]); 120} 121 122static int do_ucast_file_load(void *context) 123{ 124 char line[1024]; 125 char *file_name; 126 FILE *file; 127 ib_net64_t sw_guid, port_guid; 128 osm_opensm_t *p_osm = context; 129 osm_switch_t *p_sw; 130 uint16_t lid; 131 uint8_t port_num; 132 unsigned lineno; 133 134 file_name = p_osm->subn.opt.lfts_file; 135 if (!file_name) { 136 OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE, 137 "LFTs file name is not given; " 138 "using default routing algorithm\n"); 139 return 1; 140 } 141 142 file = fopen(file_name, "r"); 143 if (!file) { 144 OSM_LOG(&p_osm->log, OSM_LOG_ERROR | OSM_LOG_SYS, "ERR 6302: " 145 "cannot open ucast dump file \'%s\': %m\n", file_name); 146 return -1; 147 } 148 149 lineno = 0; 150 p_sw = NULL; 151 152 while (fgets(line, sizeof(line) - 1, file) != NULL) { 153 char *p, *q; 154 lineno++; 155 156 p = line; 157 while (isspace(*p)) 158 p++; 159 160 if (*p == '#') 161 continue; 162 163 if (!strncmp(p, "Multicast mlids", 15)) { 164 OSM_LOG(&p_osm->log, OSM_LOG_ERROR | OSM_LOG_SYS, 165 "ERR 6303: " 166 "Multicast dump file detected; " 167 "skipping parsing. Using default " 168 "routing algorithm\n"); 169 } else if (!strncmp(p, "Unicast lids", 12)) { 170 if (p_sw) 171 osm_ucast_mgr_set_fwd_table(&p_osm->sm. 172 ucast_mgr, p_sw); 173 q = strstr(p, " guid 0x"); 174 if (!q) { 175 OSM_LOG(&p_osm->log, OSM_LOG_ERROR, 176 "PARSE ERROR: %s:%u: " 177 "cannot parse switch definition\n", 178 file_name, lineno); 179 return -1; 180 } 181 p = q + 8; 182 sw_guid = strtoull(p, &q, 16); 183 if (q == p || !isspace(*q)) { 184 OSM_LOG(&p_osm->log, OSM_LOG_ERROR, 185 "PARSE ERROR: %s:%u: " 186 "cannot parse switch guid: \'%s\'\n", 187 file_name, lineno, p); 188 return -1; 189 } 190 sw_guid = cl_hton64(sw_guid); 191 192 p_sw = osm_get_switch_by_guid(&p_osm->subn, sw_guid); 193 if (!p_sw) { 194 OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE, 195 "cannot find switch %016" PRIx64 "\n", 196 cl_ntoh64(sw_guid)); 197 continue; 198 } 199 memset(p_sw->new_lft, OSM_NO_PATH, 200 IB_LID_UCAST_END_HO + 1); 201 } else if (p_sw && !strncmp(p, "0x", 2)) { 202 p += 2; 203 lid = (uint16_t) strtoul(p, &q, 16); 204 if (q == p || !isspace(*q)) { 205 OSM_LOG(&p_osm->log, OSM_LOG_ERROR, 206 "PARSE ERROR: %s:%u: " 207 "cannot parse lid: \'%s\'\n", 208 file_name, lineno, p); 209 return -1; 210 } 211 p = q; 212 while (isspace(*p)) 213 p++; 214 port_num = (uint8_t) strtoul(p, &q, 10); 215 if (q == p || !isspace(*q)) { 216 OSM_LOG(&p_osm->log, OSM_LOG_ERROR, 217 "PARSE ERROR: %s:%u: " 218 "cannot parse port: \'%s\'\n", 219 file_name, lineno, p); 220 return -1; 221 } 222 p = q; 223 /* additionally try to exract guid */ 224 q = strstr(p, " portguid 0x"); 225 if (!q) { 226 OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE, 227 "PARSE WARNING: %s:%u: " 228 "cannot find port guid " 229 "(maybe broken dump): \'%s\'\n", 230 file_name, lineno, p); 231 port_guid = 0; 232 } else { 233 p = q + 12; 234 port_guid = strtoull(p, &q, 16); 235 if (q == p || (!isspace(*q) && *q != ':')) { 236 OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE, 237 "PARSE WARNING: %s:%u: " 238 "cannot parse port guid " 239 "(maybe broken dump): \'%s\'\n", 240 file_name, lineno, p); 241 port_guid = 0; 242 } 243 } 244 port_guid = cl_hton64(port_guid); 245 add_path(p_osm, p_sw, lid, port_num, port_guid); 246 } 247 } 248 249 if (p_sw) 250 osm_ucast_mgr_set_fwd_table(&p_osm->sm.ucast_mgr, p_sw); 251 252 fclose(file); 253 return 0; 254} 255 256static int do_lid_matrix_file_load(void *context) 257{ 258 char line[1024]; 259 uint8_t hops[256]; 260 char *file_name; 261 FILE *file; 262 ib_net64_t guid; 263 osm_opensm_t *p_osm = context; 264 osm_switch_t *p_sw; 265 unsigned lineno; 266 uint16_t lid; 267 268 file_name = p_osm->subn.opt.lid_matrix_dump_file; 269 if (!file_name) { 270 OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE, 271 "lid matrix file name is not given; " 272 "using default lid matrix generation algorithm\n"); 273 return 1; 274 } 275 276 file = fopen(file_name, "r"); 277 if (!file) { 278 OSM_LOG(&p_osm->log, OSM_LOG_ERROR | OSM_LOG_SYS, "ERR 6305: " 279 "cannot open lid matrix file \'%s\': %m\n", file_name); 280 return -1; 281 } 282 283 lineno = 0; 284 p_sw = NULL; 285 286 while (fgets(line, sizeof(line) - 1, file) != NULL) { 287 char *p, *q; 288 lineno++; 289 290 p = line; 291 while (isspace(*p)) 292 p++; 293 294 if (*p == '#') 295 continue; 296 297 if (!strncmp(p, "Switch", 6)) { 298 q = strstr(p, " guid 0x"); 299 if (!q) { 300 OSM_LOG(&p_osm->log, OSM_LOG_ERROR, 301 "PARSE ERROR: %s:%u: " 302 "cannot parse switch definition\n", 303 file_name, lineno); 304 return -1; 305 } 306 p = q + 8; 307 guid = strtoull(p, &q, 16); 308 if (q == p || !isspace(*q)) { 309 OSM_LOG(&p_osm->log, OSM_LOG_ERROR, 310 "PARSE ERROR: %s:%u: " 311 "cannot parse switch guid: \'%s\'\n", 312 file_name, lineno, p); 313 return -1; 314 } 315 guid = cl_hton64(guid); 316 317 p_sw = osm_get_switch_by_guid(&p_osm->subn, guid); 318 if (!p_sw) { 319 OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE, 320 "cannot find switch %016" PRIx64 "\n", 321 cl_ntoh64(guid)); 322 continue; 323 } 324 } else if (p_sw && !strncmp(p, "0x", 2)) { 325 unsigned long num; 326 unsigned len = 0; 327 328 memset(hops, 0xff, sizeof(hops)); 329 330 p += 2; 331 num = strtoul(p, &q, 16); 332 if (num > 0xffff || q == p || 333 (*q != ':' && !isspace(*q))) { 334 OSM_LOG(&p_osm->log, OSM_LOG_ERROR, 335 "PARSE ERROR: %s:%u: " 336 "cannot parse lid: \'%s\'\n", 337 file_name, lineno, p); 338 return -1; 339 } 340 /* Just checked the range, so casting is safe */ 341 lid = (uint16_t) num; 342 p = q; 343 while (isspace(*p) || *p == ':') 344 p++; 345 while (len < 256 && *p && *p != '#') { 346 num = strtoul(p, &q, 16); 347 if (num > 0xff || q == p) { 348 OSM_LOG(&p_osm->log, OSM_LOG_ERROR, 349 "PARSE ERROR: %s:%u: " 350 "cannot parse hops number: \'%s\'\n", 351 file_name, lineno, p); 352 return -1; 353 } 354 /* Just checked the range, so casting is safe */ 355 hops[len++] = (uint8_t) num; 356 p = q; 357 while (isspace(*p)) 358 p++; 359 } 360 /* additionally try to extract guid */ 361 q = strstr(p, " portguid 0x"); 362 if (!q) { 363 OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE, 364 "PARSE WARNING: %s:%u: " 365 "cannot find port guid " 366 "(maybe broken dump): \'%s\'\n", 367 file_name, lineno, p); 368 guid = 0; 369 } else { 370 p = q + 12; 371 guid = strtoull(p, &q, 16); 372 if (q == p || !isspace(*q)) { 373 OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE, 374 "PARSE WARNING: %s:%u: " 375 "cannot parse port guid " 376 "(maybe broken dump): \'%s\'\n", 377 file_name, lineno, p); 378 guid = 0; 379 } 380 } 381 guid = cl_hton64(guid); 382 add_lid_hops(p_osm, p_sw, lid, guid, hops, len); 383 } 384 } 385 386 fclose(file); 387 return 0; 388} 389 390int osm_ucast_file_setup(struct osm_routing_engine *r, osm_opensm_t *osm) 391{ 392 r->context = osm; 393 r->build_lid_matrices = do_lid_matrix_file_load; 394 r->ucast_build_fwd_tables = do_ucast_file_load; 395 return 0; 396} 397