1/* 2 * Copyright (c) 2006-2008 Voltaire, Inc. All rights reserved. 3 * Copyright (c) 2006,2008-2009 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_file_ids.h> 53#define FILE_ID OSM_FILE_UCAST_FILE_C 54#include <opensm/osm_opensm.h> 55#include <opensm/osm_switch.h> 56#include <opensm/osm_log.h> 57 58static uint16_t remap_lid(osm_opensm_t * p_osm, uint16_t lid, ib_net64_t guid) 59{ 60 osm_port_t *p_port; 61 uint16_t min_lid, max_lid; 62 uint8_t lmc; 63 64 p_port = osm_get_port_by_guid(&p_osm->subn, guid); 65 if (!p_port) { 66 OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE, 67 "cannot find port guid 0x%016" PRIx64 68 " , will use the same lid\n", cl_ntoh64(guid)); 69 return lid; 70 } 71 72 osm_port_get_lid_range_ho(p_port, &min_lid, &max_lid); 73 if (min_lid <= lid && lid <= max_lid) 74 return lid; 75 76 lmc = osm_port_get_lmc(p_port); 77 return min_lid + (lid & ((1 << lmc) - 1)); 78} 79 80static void add_path(osm_opensm_t * p_osm, 81 osm_switch_t * p_sw, uint16_t lid, uint8_t port_num, 82 ib_net64_t port_guid) 83{ 84 uint16_t new_lid; 85 uint8_t old_port; 86 87 new_lid = port_guid ? remap_lid(p_osm, lid, port_guid) : lid; 88 old_port = osm_switch_get_port_by_lid(p_sw, new_lid, OSM_LFT); 89 if (old_port != OSM_NO_PATH && old_port != port_num) { 90 OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE, 91 "LID collision is detected on switch " 92 "0x016%" PRIx64 ", will overwrite LID %u entry\n", 93 cl_ntoh64(osm_node_get_node_guid(p_sw->p_node)), 94 new_lid); 95 } 96 97 p_sw->new_lft[new_lid] = port_num; 98 if (!(p_osm->subn.opt.port_profile_switch_nodes && port_guid && 99 osm_get_switch_by_guid(&p_osm->subn, port_guid))) 100 osm_switch_count_path(p_sw, port_num); 101 102 OSM_LOG(&p_osm->log, OSM_LOG_DEBUG, 103 "route 0x%04x(was 0x%04x) %u 0x%016" PRIx64 104 " is added to switch 0x%016" PRIx64 "\n", 105 new_lid, lid, port_num, cl_ntoh64(port_guid), 106 cl_ntoh64(osm_node_get_node_guid(p_sw->p_node))); 107} 108 109static void add_lid_hops(osm_opensm_t * p_osm, osm_switch_t * p_sw, 110 uint16_t lid, ib_net64_t guid, 111 uint8_t hops[], unsigned len) 112{ 113 uint8_t i; 114 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 int status = -1; 134 135 file_name = p_osm->subn.opt.lfts_file; 136 if (!file_name) { 137 OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE, 138 "LFTs file name is not given; " 139 "using default routing algorithm\n"); 140 return 1; 141 } 142 143 file = fopen(file_name, "r"); 144 if (!file) { 145 OSM_LOG(&p_osm->log, OSM_LOG_ERROR | OSM_LOG_SYS, "ERR 6302: " 146 "Can't open ucast dump file \'%s\': %m\n", file_name); 147 goto Exit; 148 } 149 150 lineno = 0; 151 p_sw = NULL; 152 153 while (fgets(line, sizeof(line) - 1, file) != NULL) { 154 char *p, *q; 155 lineno++; 156 157 p = line; 158 while (isspace(*p)) 159 p++; 160 161 if (*p == '#') 162 continue; 163 164 if (!strncmp(p, "Multicast mlids", 15)) { 165 OSM_LOG(&p_osm->log, OSM_LOG_ERROR | OSM_LOG_SYS, 166 "ERR 6303: " 167 "Multicast dump file detected; " 168 "skipping parsing. Using default " 169 "routing algorithm\n"); 170 } else if (!strncmp(p, "Unicast lids", 12)) { 171 q = strstr(p, " guid 0x"); 172 if (!q) { 173 OSM_LOG(&p_osm->log, OSM_LOG_ERROR, 174 "PARSE ERROR: %s:%u: " 175 "cannot parse switch definition\n", 176 file_name, lineno); 177 goto Exit; 178 } 179 p = q + 8; 180 sw_guid = strtoull(p, &q, 16); 181 if (q == p || !isspace(*q)) { 182 OSM_LOG(&p_osm->log, OSM_LOG_ERROR, 183 "PARSE ERROR: %s:%u: " 184 "cannot parse switch guid: \'%s\'\n", 185 file_name, lineno, p); 186 goto Exit; 187 } 188 sw_guid = cl_hton64(sw_guid); 189 190 p_sw = osm_get_switch_by_guid(&p_osm->subn, sw_guid); 191 if (!p_sw) { 192 OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE, 193 "cannot find switch %016" PRIx64 "\n", 194 cl_ntoh64(sw_guid)); 195 continue; 196 } 197 memset(p_sw->new_lft, OSM_NO_PATH, p_sw->lft_size); 198 } else if (p_sw && !strncmp(p, "0x", 2)) { 199 p += 2; 200 lid = (uint16_t) strtoul(p, &q, 16); 201 if (q == p || !isspace(*q)) { 202 OSM_LOG(&p_osm->log, OSM_LOG_ERROR, 203 "PARSE ERROR: %s:%u: " 204 "cannot parse lid: \'%s\'\n", 205 file_name, lineno, p); 206 goto Exit; 207 } 208 p = q; 209 while (isspace(*p)) 210 p++; 211 port_num = (uint8_t) strtoul(p, &q, 10); 212 if (q == p || !isspace(*q)) { 213 OSM_LOG(&p_osm->log, OSM_LOG_ERROR, 214 "PARSE ERROR: %s:%u: " 215 "cannot parse port: \'%s\'\n", 216 file_name, lineno, p); 217 goto Exit; 218 } 219 if (port_num >= 220 osm_node_get_num_physp(p_sw->p_node)) { 221 OSM_LOG(&p_osm->log, OSM_LOG_ERROR, 222 "Invalid port %d found " 223 "for switch %016" PRIx64 "\n", 224 port_num, 225 cl_ntoh64(osm_node_get_node_guid 226 (p_sw->p_node))); 227 goto Exit; 228 } 229 230 p = q; 231 /* additionally try to extract guid */ 232 q = strstr(p, " portguid 0x"); 233 if (!q) { 234 OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE, 235 "PARSE WARNING: %s:%u: " 236 "cannot find port guid " 237 "(maybe broken dump): \'%s\'\n", 238 file_name, lineno, p); 239 port_guid = 0; 240 } else { 241 p = q + 12; 242 port_guid = strtoull(p, &q, 16); 243 if (q == p || (!isspace(*q) && *q != ':')) { 244 OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE, 245 "PARSE WARNING: %s:%u: " 246 "cannot parse port guid " 247 "(maybe broken dump): \'%s\'\n", 248 file_name, lineno, p); 249 port_guid = 0; 250 } 251 } 252 port_guid = cl_hton64(port_guid); 253 add_path(p_osm, p_sw, lid, port_num, port_guid); 254 } 255 } 256 status = 0; 257Exit: 258 if (file) 259 fclose(file); 260 return status; 261} 262 263static int do_lid_matrix_file_load(void *context) 264{ 265 char line[1024]; 266 uint8_t hops[256]; 267 char *file_name; 268 FILE *file; 269 ib_net64_t guid; 270 osm_opensm_t *p_osm = context; 271 osm_switch_t *p_sw; 272 unsigned lineno; 273 uint16_t lid; 274 int status = -1; 275 276 file_name = p_osm->subn.opt.lid_matrix_dump_file; 277 if (!file_name) { 278 OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE, 279 "lid matrix file name is not given; " 280 "using default lid matrix generation algorithm\n"); 281 return 1; 282 } 283 284 file = fopen(file_name, "r"); 285 if (!file) { 286 OSM_LOG(&p_osm->log, OSM_LOG_ERROR | OSM_LOG_SYS, "ERR 6305: " 287 "Can't open lid matrix file \'%s\': %m\n", file_name); 288 goto Exit; 289 } 290 291 lineno = 0; 292 p_sw = NULL; 293 294 while (fgets(line, sizeof(line) - 1, file) != NULL) { 295 char *p, *q; 296 lineno++; 297 298 p = line; 299 while (isspace(*p)) 300 p++; 301 302 if (*p == '#') 303 continue; 304 305 if (!strncmp(p, "Switch", 6)) { 306 q = strstr(p, " guid 0x"); 307 if (!q) { 308 OSM_LOG(&p_osm->log, OSM_LOG_ERROR, 309 "PARSE ERROR: %s:%u: " 310 "cannot parse switch definition\n", 311 file_name, lineno); 312 goto Exit; 313 } 314 p = q + 8; 315 guid = strtoull(p, &q, 16); 316 if (q == p || !isspace(*q)) { 317 OSM_LOG(&p_osm->log, OSM_LOG_ERROR, 318 "PARSE ERROR: %s:%u: " 319 "cannot parse switch guid: \'%s\'\n", 320 file_name, lineno, p); 321 goto Exit; 322 } 323 guid = cl_hton64(guid); 324 325 p_sw = osm_get_switch_by_guid(&p_osm->subn, guid); 326 if (!p_sw) { 327 OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE, 328 "cannot find switch %016" PRIx64 "\n", 329 cl_ntoh64(guid)); 330 continue; 331 } 332 } else if (p_sw && !strncmp(p, "0x", 2)) { 333 unsigned long num; 334 unsigned len = 0; 335 336 memset(hops, 0xff, sizeof(hops)); 337 338 p += 2; 339 num = strtoul(p, &q, 16); 340 if (num > 0xffff || q == p || 341 (*q != ':' && !isspace(*q))) { 342 OSM_LOG(&p_osm->log, OSM_LOG_ERROR, 343 "PARSE ERROR: %s:%u: " 344 "cannot parse lid: \'%s\'\n", 345 file_name, lineno, p); 346 goto Exit; 347 } 348 /* Just checked the range, so casting is safe */ 349 lid = (uint16_t) num; 350 p = q; 351 while (isspace(*p) || *p == ':') 352 p++; 353 while (len < 256 && *p && *p != '#') { 354 num = strtoul(p, &q, 16); 355 if (num > 0xff || q == p) { 356 OSM_LOG(&p_osm->log, OSM_LOG_ERROR, 357 "PARSE ERROR: %s:%u: " 358 "cannot parse hops number: \'%s\'\n", 359 file_name, lineno, p); 360 goto Exit; 361 } 362 /* Just checked the range, so casting is safe */ 363 hops[len++] = (uint8_t) num; 364 p = q; 365 while (isspace(*p)) 366 p++; 367 } 368 /* additionally try to extract guid */ 369 q = strstr(p, " portguid 0x"); 370 if (!q) { 371 OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE, 372 "PARSE WARNING: %s:%u: " 373 "cannot find port guid " 374 "(maybe broken dump): \'%s\'\n", 375 file_name, lineno, p); 376 guid = 0; 377 } else { 378 p = q + 12; 379 guid = strtoull(p, &q, 16); 380 if (q == p || !isspace(*q)) { 381 OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE, 382 "PARSE WARNING: %s:%u: " 383 "cannot parse port guid " 384 "(maybe broken dump): \'%s\'\n", 385 file_name, lineno, p); 386 guid = 0; 387 } 388 } 389 guid = cl_hton64(guid); 390 add_lid_hops(p_osm, p_sw, lid, guid, hops, len); 391 } 392 } 393 status = 0; 394Exit: 395 if (file) 396 fclose(file); 397 return status; 398} 399 400int osm_ucast_file_setup(struct osm_routing_engine *r, osm_opensm_t *osm) 401{ 402 r->context = osm; 403 r->build_lid_matrices = do_lid_matrix_file_load; 404 r->ucast_build_fwd_tables = do_ucast_file_load; 405 return 0; 406} 407