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
remap_lid(osm_opensm_t * p_osm,uint16_t lid,ib_net64_t guid)58 static 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
add_path(osm_opensm_t * p_osm,osm_switch_t * p_sw,uint16_t lid,uint8_t port_num,ib_net64_t port_guid)80 static 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
add_lid_hops(osm_opensm_t * p_osm,osm_switch_t * p_sw,uint16_t lid,ib_net64_t guid,uint8_t hops[],unsigned len)109 static 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
do_ucast_file_load(void * context)122 static 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;
257 Exit:
258 if (file)
259 fclose(file);
260 return status;
261 }
262
do_lid_matrix_file_load(void * context)263 static 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;
394 Exit:
395 if (file)
396 fclose(file);
397 return status;
398 }
399
osm_ucast_file_setup(struct osm_routing_engine * r,osm_opensm_t * osm)400 int 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