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