Blame opensm/osm_ucast_file.c

Packit 13e616
/*
Packit 13e616
 * Copyright (c) 2006-2008 Voltaire, Inc. All rights reserved.
Packit 13e616
 * Copyright (c) 2006,2008-2009 Mellanox Technologies LTD. All rights reserved.
Packit 13e616
 *
Packit 13e616
 * This software is available to you under a choice of one of two
Packit 13e616
 * licenses.  You may choose to be licensed under the terms of the GNU
Packit 13e616
 * General Public License (GPL) Version 2, available from the file
Packit 13e616
 * COPYING in the main directory of this source tree, or the
Packit 13e616
 * OpenIB.org BSD license below:
Packit 13e616
 *
Packit 13e616
 *     Redistribution and use in source and binary forms, with or
Packit 13e616
 *     without modification, are permitted provided that the following
Packit 13e616
 *     conditions are met:
Packit 13e616
 *
Packit 13e616
 *      - Redistributions of source code must retain the above
Packit 13e616
 *        copyright notice, this list of conditions and the following
Packit 13e616
 *        disclaimer.
Packit 13e616
 *
Packit 13e616
 *      - Redistributions in binary form must reproduce the above
Packit 13e616
 *        copyright notice, this list of conditions and the following
Packit 13e616
 *        disclaimer in the documentation and/or other materials
Packit 13e616
 *        provided with the distribution.
Packit 13e616
 *
Packit 13e616
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
Packit 13e616
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
Packit 13e616
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
Packit 13e616
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
Packit 13e616
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
Packit 13e616
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
Packit 13e616
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
Packit 13e616
 * SOFTWARE.
Packit 13e616
 *
Packit 13e616
 */
Packit 13e616
Packit 13e616
/*
Packit 13e616
 * Abstract:
Packit 13e616
 *    Implementation of OpenSM unicast routing module which loads
Packit 13e616
 *    routes from the dump file
Packit 13e616
 */
Packit 13e616
Packit 13e616
#if HAVE_CONFIG_H
Packit 13e616
#  include <config.h>
Packit 13e616
#endif				/* HAVE_CONFIG_H */
Packit 13e616
Packit 13e616
#include <stdlib.h>
Packit 13e616
#include <string.h>
Packit 13e616
#include <ctype.h>
Packit 13e616
Packit 13e616
#include <iba/ib_types.h>
Packit 13e616
#include <complib/cl_qmap.h>
Packit 13e616
#include <complib/cl_debug.h>
Packit 13e616
#include <opensm/osm_file_ids.h>
Packit 13e616
#define FILE_ID OSM_FILE_UCAST_FILE_C
Packit 13e616
#include <opensm/osm_opensm.h>
Packit 13e616
#include <opensm/osm_switch.h>
Packit 13e616
#include <opensm/osm_log.h>
Packit 13e616
Packit 13e616
static uint16_t remap_lid(osm_opensm_t * p_osm, uint16_t lid, ib_net64_t guid)
Packit 13e616
{
Packit 13e616
	osm_port_t *p_port;
Packit 13e616
	uint16_t min_lid, max_lid;
Packit 13e616
	uint8_t lmc;
Packit 13e616
Packit 13e616
	p_port = osm_get_port_by_guid(&p_osm->subn, guid);
Packit 13e616
	if (!p_port) {
Packit 13e616
		OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE,
Packit 13e616
			"cannot find port guid 0x%016" PRIx64
Packit 13e616
			" , will use the same lid\n", cl_ntoh64(guid));
Packit 13e616
		return lid;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	osm_port_get_lid_range_ho(p_port, &min_lid, &max_lid);
Packit 13e616
	if (min_lid <= lid && lid <= max_lid)
Packit 13e616
		return lid;
Packit 13e616
Packit 13e616
	lmc = osm_port_get_lmc(p_port);
Packit 13e616
	return min_lid + (lid & ((1 << lmc) - 1));
Packit 13e616
}
Packit 13e616
Packit 13e616
static void add_path(osm_opensm_t * p_osm,
Packit 13e616
		     osm_switch_t * p_sw, uint16_t lid, uint8_t port_num,
Packit 13e616
		     ib_net64_t port_guid)
Packit 13e616
{
Packit 13e616
	uint16_t new_lid;
Packit 13e616
	uint8_t old_port;
Packit 13e616
Packit 13e616
	new_lid = port_guid ? remap_lid(p_osm, lid, port_guid) : lid;
Packit 13e616
	old_port = osm_switch_get_port_by_lid(p_sw, new_lid, OSM_LFT);
Packit 13e616
	if (old_port != OSM_NO_PATH && old_port != port_num) {
Packit 13e616
		OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE,
Packit 13e616
			"LID collision is detected on switch "
Packit 13e616
			"0x016%" PRIx64 ", will overwrite LID %u entry\n",
Packit 13e616
			cl_ntoh64(osm_node_get_node_guid(p_sw->p_node)),
Packit 13e616
			new_lid);
Packit 13e616
	}
Packit 13e616
Packit 13e616
	p_sw->new_lft[new_lid] = port_num;
Packit 13e616
	if (!(p_osm->subn.opt.port_profile_switch_nodes && port_guid &&
Packit 13e616
	      osm_get_switch_by_guid(&p_osm->subn, port_guid)))
Packit 13e616
		osm_switch_count_path(p_sw, port_num);
Packit 13e616
Packit 13e616
	OSM_LOG(&p_osm->log, OSM_LOG_DEBUG,
Packit 13e616
		"route 0x%04x(was 0x%04x) %u 0x%016" PRIx64
Packit 13e616
		" is added to switch 0x%016" PRIx64 "\n",
Packit 13e616
		new_lid, lid, port_num, cl_ntoh64(port_guid),
Packit 13e616
		cl_ntoh64(osm_node_get_node_guid(p_sw->p_node)));
Packit 13e616
}
Packit 13e616
Packit 13e616
static void add_lid_hops(osm_opensm_t * p_osm, osm_switch_t * p_sw,
Packit 13e616
			 uint16_t lid, ib_net64_t guid,
Packit 13e616
			 uint8_t hops[], unsigned len)
Packit 13e616
{
Packit 13e616
	uint8_t i;
Packit 13e616
Packit 13e616
	if (len > p_sw->num_ports)
Packit 13e616
		len = p_sw->num_ports;
Packit 13e616
Packit 13e616
	for (i = 0; i < len; i++)
Packit 13e616
		osm_switch_set_hops(p_sw, lid, i, hops[i]);
Packit 13e616
}
Packit 13e616
Packit 13e616
static int do_ucast_file_load(void *context)
Packit 13e616
{
Packit 13e616
	char line[1024];
Packit 13e616
	char *file_name;
Packit 13e616
	FILE *file;
Packit 13e616
	ib_net64_t sw_guid, port_guid;
Packit 13e616
	osm_opensm_t *p_osm = context;
Packit 13e616
	osm_switch_t *p_sw;
Packit 13e616
	uint16_t lid;
Packit 13e616
	uint8_t port_num;
Packit 13e616
	unsigned lineno;
Packit 13e616
	int status = -1;
Packit 13e616
Packit 13e616
	file_name = p_osm->subn.opt.lfts_file;
Packit 13e616
	if (!file_name) {
Packit 13e616
		OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE,
Packit 13e616
			"LFTs file name is not given; "
Packit 13e616
			"using default routing algorithm\n");
Packit 13e616
		return 1;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	file = fopen(file_name, "r");
Packit 13e616
	if (!file) {
Packit 13e616
		OSM_LOG(&p_osm->log, OSM_LOG_ERROR | OSM_LOG_SYS, "ERR 6302: "
Packit 13e616
			"Can't open ucast dump file \'%s\': %m\n", file_name);
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	lineno = 0;
Packit 13e616
	p_sw = NULL;
Packit 13e616
Packit 13e616
	while (fgets(line, sizeof(line) - 1, file) != NULL) {
Packit 13e616
		char *p, *q;
Packit 13e616
		lineno++;
Packit 13e616
Packit 13e616
		p = line;
Packit 13e616
		while (isspace(*p))
Packit 13e616
			p++;
Packit 13e616
Packit 13e616
		if (*p == '#')
Packit 13e616
			continue;
Packit 13e616
Packit 13e616
		if (!strncmp(p, "Multicast mlids", 15)) {
Packit 13e616
			OSM_LOG(&p_osm->log, OSM_LOG_ERROR | OSM_LOG_SYS,
Packit 13e616
				"ERR 6303: "
Packit 13e616
				"Multicast dump file detected; "
Packit 13e616
				"skipping parsing. Using default "
Packit 13e616
				"routing algorithm\n");
Packit 13e616
		} else if (!strncmp(p, "Unicast lids", 12)) {
Packit 13e616
			q = strstr(p, " guid 0x");
Packit 13e616
			if (!q) {
Packit 13e616
				OSM_LOG(&p_osm->log, OSM_LOG_ERROR,
Packit 13e616
					"PARSE ERROR: %s:%u: "
Packit 13e616
					"cannot parse switch definition\n",
Packit 13e616
					file_name, lineno);
Packit 13e616
				goto Exit;
Packit 13e616
			}
Packit 13e616
			p = q + 8;
Packit 13e616
			sw_guid = strtoull(p, &q, 16);
Packit 13e616
			if (q == p || !isspace(*q)) {
Packit 13e616
				OSM_LOG(&p_osm->log, OSM_LOG_ERROR,
Packit 13e616
					"PARSE ERROR: %s:%u: "
Packit 13e616
					"cannot parse switch guid: \'%s\'\n",
Packit 13e616
					file_name, lineno, p);
Packit 13e616
				goto Exit;
Packit 13e616
			}
Packit 13e616
			sw_guid = cl_hton64(sw_guid);
Packit 13e616
Packit 13e616
			p_sw = osm_get_switch_by_guid(&p_osm->subn, sw_guid);
Packit 13e616
			if (!p_sw) {
Packit 13e616
				OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE,
Packit 13e616
					"cannot find switch %016" PRIx64 "\n",
Packit 13e616
					cl_ntoh64(sw_guid));
Packit 13e616
				continue;
Packit 13e616
			}
Packit 13e616
			memset(p_sw->new_lft, OSM_NO_PATH, p_sw->lft_size);
Packit 13e616
		} else if (p_sw && !strncmp(p, "0x", 2)) {
Packit 13e616
			p += 2;
Packit 13e616
			lid = (uint16_t) strtoul(p, &q, 16);
Packit 13e616
			if (q == p || !isspace(*q)) {
Packit 13e616
				OSM_LOG(&p_osm->log, OSM_LOG_ERROR,
Packit 13e616
					"PARSE ERROR: %s:%u: "
Packit 13e616
					"cannot parse lid: \'%s\'\n",
Packit 13e616
					file_name, lineno, p);
Packit 13e616
				goto Exit;
Packit 13e616
			}
Packit 13e616
			p = q;
Packit 13e616
			while (isspace(*p))
Packit 13e616
				p++;
Packit 13e616
			port_num = (uint8_t) strtoul(p, &q, 10);
Packit 13e616
			if (q == p || !isspace(*q)) {
Packit 13e616
				OSM_LOG(&p_osm->log, OSM_LOG_ERROR,
Packit 13e616
					"PARSE ERROR: %s:%u: "
Packit 13e616
					"cannot parse port: \'%s\'\n",
Packit 13e616
					file_name, lineno, p);
Packit 13e616
				goto Exit;
Packit 13e616
			}
Packit 13e616
			if (port_num >=
Packit 13e616
				osm_node_get_num_physp(p_sw->p_node)) {
Packit 13e616
					OSM_LOG(&p_osm->log, OSM_LOG_ERROR,
Packit 13e616
						"Invalid port %d found "
Packit 13e616
						"for switch %016" PRIx64 "\n",
Packit 13e616
						port_num,
Packit 13e616
						cl_ntoh64(osm_node_get_node_guid
Packit 13e616
							(p_sw->p_node)));
Packit 13e616
					goto Exit;
Packit 13e616
			}
Packit 13e616
Packit 13e616
			p = q;
Packit 13e616
			/* additionally try to extract guid */
Packit 13e616
			q = strstr(p, " portguid 0x");
Packit 13e616
			if (!q) {
Packit 13e616
				OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE,
Packit 13e616
					"PARSE WARNING: %s:%u: "
Packit 13e616
					"cannot find port guid "
Packit 13e616
					"(maybe broken dump): \'%s\'\n",
Packit 13e616
					file_name, lineno, p);
Packit 13e616
				port_guid = 0;
Packit 13e616
			} else {
Packit 13e616
				p = q + 12;
Packit 13e616
				port_guid = strtoull(p, &q, 16);
Packit 13e616
				if (q == p || (!isspace(*q) && *q != ':')) {
Packit 13e616
					OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE,
Packit 13e616
						"PARSE WARNING: %s:%u: "
Packit 13e616
						"cannot parse port guid "
Packit 13e616
						"(maybe broken dump): \'%s\'\n",
Packit 13e616
						file_name, lineno, p);
Packit 13e616
					port_guid = 0;
Packit 13e616
				}
Packit 13e616
			}
Packit 13e616
			port_guid = cl_hton64(port_guid);
Packit 13e616
			add_path(p_osm, p_sw, lid, port_num, port_guid);
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
	status = 0;
Packit 13e616
Exit:
Packit 13e616
	if (file)
Packit 13e616
		fclose(file);
Packit 13e616
	return status;
Packit 13e616
}
Packit 13e616
Packit 13e616
static int do_lid_matrix_file_load(void *context)
Packit 13e616
{
Packit 13e616
	char line[1024];
Packit 13e616
	uint8_t hops[256];
Packit 13e616
	char *file_name;
Packit 13e616
	FILE *file;
Packit 13e616
	ib_net64_t guid;
Packit 13e616
	osm_opensm_t *p_osm = context;
Packit 13e616
	osm_switch_t *p_sw;
Packit 13e616
	unsigned lineno;
Packit 13e616
	uint16_t lid;
Packit 13e616
	int status = -1;
Packit 13e616
Packit 13e616
	file_name = p_osm->subn.opt.lid_matrix_dump_file;
Packit 13e616
	if (!file_name) {
Packit 13e616
		OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE,
Packit 13e616
			"lid matrix file name is not given; "
Packit 13e616
			"using default lid matrix generation algorithm\n");
Packit 13e616
		return 1;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	file = fopen(file_name, "r");
Packit 13e616
	if (!file) {
Packit 13e616
		OSM_LOG(&p_osm->log, OSM_LOG_ERROR | OSM_LOG_SYS, "ERR 6305: "
Packit 13e616
			"Can't open lid matrix file \'%s\': %m\n", file_name);
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	lineno = 0;
Packit 13e616
	p_sw = NULL;
Packit 13e616
Packit 13e616
	while (fgets(line, sizeof(line) - 1, file) != NULL) {
Packit 13e616
		char *p, *q;
Packit 13e616
		lineno++;
Packit 13e616
Packit 13e616
		p = line;
Packit 13e616
		while (isspace(*p))
Packit 13e616
			p++;
Packit 13e616
Packit 13e616
		if (*p == '#')
Packit 13e616
			continue;
Packit 13e616
Packit 13e616
		if (!strncmp(p, "Switch", 6)) {
Packit 13e616
			q = strstr(p, " guid 0x");
Packit 13e616
			if (!q) {
Packit 13e616
				OSM_LOG(&p_osm->log, OSM_LOG_ERROR,
Packit 13e616
					"PARSE ERROR: %s:%u: "
Packit 13e616
					"cannot parse switch definition\n",
Packit 13e616
					file_name, lineno);
Packit 13e616
				goto Exit;
Packit 13e616
			}
Packit 13e616
			p = q + 8;
Packit 13e616
			guid = strtoull(p, &q, 16);
Packit 13e616
			if (q == p || !isspace(*q)) {
Packit 13e616
				OSM_LOG(&p_osm->log, OSM_LOG_ERROR,
Packit 13e616
					"PARSE ERROR: %s:%u: "
Packit 13e616
					"cannot parse switch guid: \'%s\'\n",
Packit 13e616
					file_name, lineno, p);
Packit 13e616
				goto Exit;
Packit 13e616
			}
Packit 13e616
			guid = cl_hton64(guid);
Packit 13e616
Packit 13e616
			p_sw = osm_get_switch_by_guid(&p_osm->subn, guid);
Packit 13e616
			if (!p_sw) {
Packit 13e616
				OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE,
Packit 13e616
					"cannot find switch %016" PRIx64 "\n",
Packit 13e616
					cl_ntoh64(guid));
Packit 13e616
				continue;
Packit 13e616
			}
Packit 13e616
		} else if (p_sw && !strncmp(p, "0x", 2)) {
Packit 13e616
			unsigned long num;
Packit 13e616
			unsigned len = 0;
Packit 13e616
Packit 13e616
			memset(hops, 0xff, sizeof(hops));
Packit 13e616
Packit 13e616
			p += 2;
Packit 13e616
			num = strtoul(p, &q, 16);
Packit 13e616
			if (num > 0xffff || q == p ||
Packit 13e616
			    (*q != ':' && !isspace(*q))) {
Packit 13e616
				OSM_LOG(&p_osm->log, OSM_LOG_ERROR,
Packit 13e616
					"PARSE ERROR: %s:%u: "
Packit 13e616
					"cannot parse lid: \'%s\'\n",
Packit 13e616
					file_name, lineno, p);
Packit 13e616
				goto Exit;
Packit 13e616
			}
Packit 13e616
			/* Just checked the range, so casting is safe */
Packit 13e616
			lid = (uint16_t) num;
Packit 13e616
			p = q;
Packit 13e616
			while (isspace(*p) || *p == ':')
Packit 13e616
				p++;
Packit 13e616
			while (len < 256 && *p && *p != '#') {
Packit 13e616
				num = strtoul(p, &q, 16);
Packit 13e616
				if (num > 0xff || q == p) {
Packit 13e616
					OSM_LOG(&p_osm->log, OSM_LOG_ERROR,
Packit 13e616
						"PARSE ERROR: %s:%u: "
Packit 13e616
						"cannot parse hops number: \'%s\'\n",
Packit 13e616
						file_name, lineno, p);
Packit 13e616
					goto Exit;
Packit 13e616
				}
Packit 13e616
				/* Just checked the range, so casting is safe */
Packit 13e616
				hops[len++] = (uint8_t) num;
Packit 13e616
				p = q;
Packit 13e616
				while (isspace(*p))
Packit 13e616
					p++;
Packit 13e616
			}
Packit 13e616
			/* additionally try to extract guid */
Packit 13e616
			q = strstr(p, " portguid 0x");
Packit 13e616
			if (!q) {
Packit 13e616
				OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE,
Packit 13e616
					"PARSE WARNING: %s:%u: "
Packit 13e616
					"cannot find port guid "
Packit 13e616
					"(maybe broken dump): \'%s\'\n",
Packit 13e616
					file_name, lineno, p);
Packit 13e616
				guid = 0;
Packit 13e616
			} else {
Packit 13e616
				p = q + 12;
Packit 13e616
				guid = strtoull(p, &q, 16);
Packit 13e616
				if (q == p || !isspace(*q)) {
Packit 13e616
					OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE,
Packit 13e616
						"PARSE WARNING: %s:%u: "
Packit 13e616
						"cannot parse port guid "
Packit 13e616
						"(maybe broken dump): \'%s\'\n",
Packit 13e616
						file_name, lineno, p);
Packit 13e616
					guid = 0;
Packit 13e616
				}
Packit 13e616
			}
Packit 13e616
			guid = cl_hton64(guid);
Packit 13e616
			add_lid_hops(p_osm, p_sw, lid, guid, hops, len);
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
	status = 0;
Packit 13e616
Exit:
Packit 13e616
	if (file)
Packit 13e616
		fclose(file);
Packit 13e616
	return status;
Packit 13e616
}
Packit 13e616
Packit 13e616
int osm_ucast_file_setup(struct osm_routing_engine *r, osm_opensm_t *osm)
Packit 13e616
{
Packit 13e616
	r->context = osm;
Packit 13e616
	r->build_lid_matrices = do_lid_matrix_file_load;
Packit 13e616
	r->ucast_build_fwd_tables = do_ucast_file_load;
Packit 13e616
	return 0;
Packit 13e616
}