Blame opensm/osm_ucast_mgr.c

Packit 13e616
/*
Packit 13e616
 * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved.
Packit 13e616
 * Copyright (c) 2002-2015 Mellanox Technologies LTD. All rights reserved.
Packit 13e616
 * Copyright (c) 1996-2003 Intel Corporation. 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 osm_ucast_mgr_t.
Packit 13e616
 * This file implements the Unicast Manager object.
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 <stdio.h>
Packit 13e616
#include <stdlib.h>
Packit 13e616
#include <string.h>
Packit 13e616
#include <ctype.h>
Packit 13e616
#include <iba/ib_types.h>
Packit 13e616
#include <complib/cl_qmap.h>
Packit 13e616
#include <complib/cl_debug.h>
Packit 13e616
#include <complib/cl_qlist.h>
Packit 13e616
#include <opensm/osm_file_ids.h>
Packit 13e616
#define FILE_ID OSM_FILE_UCAST_MGR_C
Packit 13e616
#include <opensm/osm_ucast_mgr.h>
Packit 13e616
#include <opensm/osm_sm.h>
Packit 13e616
#include <opensm/osm_log.h>
Packit 13e616
#include <opensm/osm_node.h>
Packit 13e616
#include <opensm/osm_switch.h>
Packit 13e616
#include <opensm/osm_helper.h>
Packit 13e616
#include <opensm/osm_msgdef.h>
Packit 13e616
#include <opensm/osm_opensm.h>
Packit 13e616
Packit 13e616
void osm_ucast_mgr_construct(IN osm_ucast_mgr_t * p_mgr)
Packit 13e616
{
Packit 13e616
	memset(p_mgr, 0, sizeof(*p_mgr));
Packit 13e616
}
Packit 13e616
Packit 13e616
void osm_ucast_mgr_destroy(IN osm_ucast_mgr_t * p_mgr)
Packit 13e616
{
Packit 13e616
	CL_ASSERT(p_mgr);
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(p_mgr->p_log);
Packit 13e616
Packit 13e616
	if (p_mgr->cache_valid)
Packit 13e616
		osm_ucast_cache_invalidate(p_mgr);
Packit 13e616
Packit 13e616
	OSM_LOG_EXIT(p_mgr->p_log);
Packit 13e616
}
Packit 13e616
Packit 13e616
ib_api_status_t osm_ucast_mgr_init(IN osm_ucast_mgr_t * p_mgr, IN osm_sm_t * sm)
Packit 13e616
{
Packit 13e616
	ib_api_status_t status = IB_SUCCESS;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(sm->p_log);
Packit 13e616
Packit 13e616
	osm_ucast_mgr_construct(p_mgr);
Packit 13e616
Packit 13e616
	p_mgr->sm = sm;
Packit 13e616
	p_mgr->p_log = sm->p_log;
Packit 13e616
	p_mgr->p_subn = sm->p_subn;
Packit 13e616
	p_mgr->p_lock = sm->p_lock;
Packit 13e616
Packit 13e616
	if (sm->p_subn->opt.use_ucast_cache)
Packit 13e616
		cl_qmap_init(&p_mgr->cache_sw_tbl);
Packit 13e616
Packit 13e616
	OSM_LOG_EXIT(p_mgr->p_log);
Packit 13e616
	return status;
Packit 13e616
}
Packit 13e616
Packit 13e616
/**********************************************************************
Packit 13e616
 Add each switch's own and neighbor LIDs to its LID matrix
Packit 13e616
**********************************************************************/
Packit 13e616
static void ucast_mgr_process_hop_0_1(IN cl_map_item_t * p_map_item,
Packit 13e616
				      IN void *context)
Packit 13e616
{
Packit 13e616
	osm_switch_t * p_sw = (osm_switch_t *) p_map_item;
Packit 13e616
	osm_node_t *p_remote_node;
Packit 13e616
	uint16_t lid, remote_lid;
Packit 13e616
	uint8_t i;
Packit 13e616
Packit 13e616
	lid = cl_ntoh16(osm_node_get_base_lid(p_sw->p_node, 0));
Packit 13e616
	osm_switch_set_hops(p_sw, lid, 0, 0);
Packit 13e616
Packit 13e616
	for (i = 1; i < p_sw->num_ports; i++) {
Packit 13e616
		osm_physp_t *p = osm_node_get_physp_ptr(p_sw->p_node, i);
Packit 13e616
		p_remote_node = (p && p->p_remote_physp) ?
Packit 13e616
		    p->p_remote_physp->p_node : NULL;
Packit 13e616
Packit 13e616
		if (p_remote_node && p_remote_node->sw &&
Packit 13e616
		    p_remote_node != p_sw->p_node) {
Packit 13e616
			remote_lid = osm_node_get_base_lid(p_remote_node, 0);
Packit 13e616
			remote_lid = cl_ntoh16(remote_lid);
Packit 13e616
			osm_switch_set_hops(p_sw, remote_lid, i, p->hop_wf);
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
}
Packit 13e616
Packit 13e616
static void ucast_mgr_process_neighbor(IN osm_ucast_mgr_t * p_mgr,
Packit 13e616
				       IN osm_switch_t * p_this_sw,
Packit 13e616
				       IN osm_switch_t * p_remote_sw,
Packit 13e616
				       IN uint8_t port_num,
Packit 13e616
				       IN uint8_t remote_port_num)
Packit 13e616
{
Packit 13e616
	osm_switch_t *p_sw;
Packit 13e616
	cl_map_item_t *item;
Packit 13e616
	uint16_t lid_ho;
Packit 13e616
	uint16_t hops;
Packit 13e616
	osm_physp_t *p;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(p_mgr->p_log);
Packit 13e616
Packit 13e616
	OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
Packit 13e616
		"Node 0x%" PRIx64 ", remote node 0x%" PRIx64
Packit 13e616
		", port %u, remote port %u\n",
Packit 13e616
		cl_ntoh64(osm_node_get_node_guid(p_this_sw->p_node)),
Packit 13e616
		cl_ntoh64(osm_node_get_node_guid(p_remote_sw->p_node)),
Packit 13e616
		port_num, remote_port_num);
Packit 13e616
Packit 13e616
	p = osm_node_get_physp_ptr(p_this_sw->p_node, port_num);
Packit 13e616
Packit 13e616
	for (item = cl_qmap_head(&p_mgr->p_subn->sw_guid_tbl);
Packit 13e616
	     item != cl_qmap_end(&p_mgr->p_subn->sw_guid_tbl);
Packit 13e616
	     item = cl_qmap_next(item)) {
Packit 13e616
		p_sw = (osm_switch_t *) item;
Packit 13e616
		lid_ho = cl_ntoh16(osm_node_get_base_lid(p_sw->p_node, 0));
Packit 13e616
		hops = osm_switch_get_least_hops(p_remote_sw, lid_ho);
Packit 13e616
		if (hops == OSM_NO_PATH)
Packit 13e616
			continue;
Packit 13e616
		hops += p->hop_wf;
Packit 13e616
		if (hops <
Packit 13e616
		    osm_switch_get_hop_count(p_this_sw, lid_ho, port_num)) {
Packit 13e616
			if (osm_switch_set_hops
Packit 13e616
			    (p_this_sw, lid_ho, port_num, (uint8_t) hops) != 0)
Packit 13e616
				OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR, "ERR 3A03: "
Packit 13e616
					"cannot set hops for lid %u at switch 0x%"
Packit 13e616
					PRIx64 "\n", lid_ho,
Packit 13e616
					cl_ntoh64(osm_node_get_node_guid
Packit 13e616
						  (p_this_sw->p_node)));
Packit 13e616
			p_mgr->some_hop_count_set = TRUE;
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
	OSM_LOG_EXIT(p_mgr->p_log);
Packit 13e616
}
Packit 13e616
Packit 13e616
static struct osm_remote_node *find_and_add_remote_sys(osm_switch_t * sw,
Packit 13e616
						       uint8_t port,
Packit 13e616
						       boolean_t dor, struct
Packit 13e616
						       osm_remote_guids_count
Packit 13e616
						       *r)
Packit 13e616
{
Packit 13e616
	unsigned i;
Packit 13e616
	osm_physp_t *p = osm_node_get_physp_ptr(sw->p_node, port);
Packit 13e616
	osm_node_t *node = p->p_remote_physp->p_node;
Packit 13e616
	uint8_t rem_port = osm_physp_get_port_num(p->p_remote_physp);
Packit 13e616
Packit 13e616
	for (i = 0; i < r->count; i++)
Packit 13e616
		if (r->guids[i].node == node)
Packit 13e616
			if (!dor || (r->guids[i].port == rem_port))
Packit 13e616
				return &r->guids[i];
Packit 13e616
Packit 13e616
	r->guids[i].node = node;
Packit 13e616
	r->guids[i].forwarded_to = 0;
Packit 13e616
	r->guids[i].port = rem_port;
Packit 13e616
	r->count++;
Packit 13e616
	return &r->guids[i];
Packit 13e616
}
Packit 13e616
Packit 13e616
static void ucast_mgr_process_port(IN osm_ucast_mgr_t * p_mgr,
Packit 13e616
				   IN osm_switch_t * p_sw,
Packit 13e616
				   IN osm_port_t * p_port,
Packit 13e616
				   IN unsigned lid_offset)
Packit 13e616
{
Packit 13e616
	uint16_t min_lid_ho;
Packit 13e616
	uint16_t max_lid_ho;
Packit 13e616
	uint16_t lid_ho;
Packit 13e616
	uint8_t port;
Packit 13e616
	boolean_t is_ignored_by_port_prof;
Packit 13e616
	ib_net64_t node_guid;
Packit 13e616
	unsigned start_from = 1;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(p_mgr->p_log);
Packit 13e616
Packit 13e616
	osm_port_get_lid_range_ho(p_port, &min_lid_ho, &max_lid_ho);
Packit 13e616
Packit 13e616
	/* If the lids are zero - then there was some problem with
Packit 13e616
	 * the initialization. Don't handle this port. */
Packit 13e616
	if (min_lid_ho == 0 || max_lid_ho == 0) {
Packit 13e616
		OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR, "ERR 3A04: "
Packit 13e616
			"Port 0x%" PRIx64 " (%s port %d) has LID 0. An "
Packit 13e616
			"initialization error occurred. Ignoring port\n",
Packit 13e616
			cl_ntoh64(osm_port_get_guid(p_port)),
Packit 13e616
			p_port->p_node->print_desc,
Packit 13e616
			p_port->p_physp->port_num);
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	lid_ho = min_lid_ho + lid_offset;
Packit 13e616
Packit 13e616
	if (lid_ho > max_lid_ho)
Packit 13e616
		goto Exit;
Packit 13e616
Packit 13e616
	if (lid_offset && !p_mgr->is_dor)
Packit 13e616
		/* ignore potential overflow - it is handled in osm_switch.c */
Packit 13e616
		start_from =
Packit 13e616
		    osm_switch_get_port_by_lid(p_sw, lid_ho - 1, OSM_NEW_LFT) + 1;
Packit 13e616
Packit 13e616
	OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
Packit 13e616
		"Processing port 0x%" PRIx64
Packit 13e616
		" (\'%s\' port %u), LID %u [%u,%u]\n",
Packit 13e616
		cl_ntoh64(osm_port_get_guid(p_port)),
Packit 13e616
		p_port->p_node->print_desc, p_port->p_physp->port_num, lid_ho,
Packit 13e616
		min_lid_ho, max_lid_ho);
Packit 13e616
Packit 13e616
	/* TODO - This should be runtime error, not a CL_ASSERT() */
Packit 13e616
	CL_ASSERT(max_lid_ho <= IB_LID_UCAST_END_HO);
Packit 13e616
Packit 13e616
	node_guid = osm_node_get_node_guid(p_sw->p_node);
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   The lid matrix contains the number of hops to each
Packit 13e616
	   lid from each port.  From this information we determine
Packit 13e616
	   how best to distribute the LID range across the ports
Packit 13e616
	   that can reach those LIDs.
Packit 13e616
	 */
Packit 13e616
	port = osm_switch_recommend_path(p_sw, p_port, lid_ho, start_from,
Packit 13e616
					 p_mgr->p_subn->ignore_existing_lfts,
Packit 13e616
					 p_mgr->p_subn->opt.lmc,
Packit 13e616
					 p_mgr->is_dor,
Packit 13e616
					 p_mgr->p_subn->opt.port_shifting,
Packit 13e616
					 !lid_offset && p_port->use_scatter,
Packit 13e616
					 OSM_LFT);
Packit 13e616
Packit 13e616
	if (port == OSM_NO_PATH) {
Packit 13e616
		/* do not try to overwrite the ppro of non existing port ... */
Packit 13e616
		is_ignored_by_port_prof = TRUE;
Packit 13e616
Packit 13e616
		OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
Packit 13e616
			"No path to get to LID %u from switch 0x%" PRIx64 "\n",
Packit 13e616
			lid_ho, cl_ntoh64(node_guid));
Packit 13e616
	} else {
Packit 13e616
		osm_physp_t *p = osm_node_get_physp_ptr(p_sw->p_node, port);
Packit 13e616
		if (!p)
Packit 13e616
			goto Exit;
Packit 13e616
Packit 13e616
		OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
Packit 13e616
			"Routing LID %u to port %u for switch 0x%" PRIx64 "\n",
Packit 13e616
			lid_ho, port, cl_ntoh64(node_guid));
Packit 13e616
Packit 13e616
		/*
Packit 13e616
		   we would like to optionally ignore this port in equalization
Packit 13e616
		   as in the case of the Mellanox Anafa Internal PCI TCA port
Packit 13e616
		 */
Packit 13e616
		is_ignored_by_port_prof = p->is_prof_ignored;
Packit 13e616
Packit 13e616
		/*
Packit 13e616
		   We also would ignore this route if the target lid is of
Packit 13e616
		   a switch and the port_profile_switch_node is not TRUE
Packit 13e616
		 */
Packit 13e616
		if (!p_mgr->p_subn->opt.port_profile_switch_nodes)
Packit 13e616
			is_ignored_by_port_prof |=
Packit 13e616
			    (osm_node_get_type(p_port->p_node) ==
Packit 13e616
			     IB_NODE_TYPE_SWITCH);
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   We have selected the port for this LID.
Packit 13e616
	   Write it to the forwarding tables.
Packit 13e616
	 */
Packit 13e616
	p_sw->new_lft[lid_ho] = port;
Packit 13e616
	if (!is_ignored_by_port_prof) {
Packit 13e616
		struct osm_remote_node *rem_node_used;
Packit 13e616
		osm_switch_count_path(p_sw, port);
Packit 13e616
		if (port > 0 && p_port->priv &&
Packit 13e616
		    (rem_node_used = find_and_add_remote_sys(p_sw, port,
Packit 13e616
							     p_mgr->is_dor,
Packit 13e616
							     p_port->priv)))
Packit 13e616
			rem_node_used->forwarded_to++;
Packit 13e616
	}
Packit 13e616
Packit 13e616
Exit:
Packit 13e616
	OSM_LOG_EXIT(p_mgr->p_log);
Packit 13e616
}
Packit 13e616
Packit 13e616
static void alloc_ports_priv(osm_ucast_mgr_t * mgr)
Packit 13e616
{
Packit 13e616
	cl_qmap_t *port_tbl = &mgr->p_subn->port_guid_tbl;
Packit 13e616
	struct osm_remote_guids_count *r;
Packit 13e616
	osm_port_t *port;
Packit 13e616
	cl_map_item_t *item;
Packit 13e616
	unsigned lmc;
Packit 13e616
Packit 13e616
	for (item = cl_qmap_head(port_tbl); item != cl_qmap_end(port_tbl);
Packit 13e616
	     item = cl_qmap_next(item)) {
Packit 13e616
		port = (osm_port_t *) item;
Packit 13e616
		lmc = ib_port_info_get_lmc(&port->p_physp->port_info);
Packit 13e616
		r = malloc(sizeof(*r) + sizeof(r->guids[0]) * (1 << lmc));
Packit 13e616
		if (!r) {
Packit 13e616
			OSM_LOG(mgr->p_log, OSM_LOG_ERROR, "ERR 3A09: "
Packit 13e616
				"cannot allocate memory to track remote"
Packit 13e616
				" systems for lmc > 0\n");
Packit 13e616
			port->priv = NULL;
Packit 13e616
			continue;
Packit 13e616
		}
Packit 13e616
		memset(r, 0, sizeof(*r) + sizeof(r->guids[0]) * (1 << lmc));
Packit 13e616
		port->priv = r;
Packit 13e616
	}
Packit 13e616
}
Packit 13e616
Packit 13e616
static void free_ports_priv(osm_ucast_mgr_t * mgr)
Packit 13e616
{
Packit 13e616
	cl_qmap_t *port_tbl = &mgr->p_subn->port_guid_tbl;
Packit 13e616
	osm_port_t *port;
Packit 13e616
	cl_map_item_t *item;
Packit 13e616
	for (item = cl_qmap_head(port_tbl); item != cl_qmap_end(port_tbl);
Packit 13e616
	     item = cl_qmap_next(item)) {
Packit 13e616
		port = (osm_port_t *) item;
Packit 13e616
		if (port->priv) {
Packit 13e616
			free(port->priv);
Packit 13e616
			port->priv = NULL;
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
}
Packit 13e616
Packit 13e616
static void ucast_mgr_process_tbl(IN cl_map_item_t * p_map_item,
Packit 13e616
				  IN void *context)
Packit 13e616
{
Packit 13e616
	osm_ucast_mgr_t *p_mgr = context;
Packit 13e616
	osm_switch_t * p_sw = (osm_switch_t *) p_map_item;
Packit 13e616
	unsigned i, lids_per_port;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(p_mgr->p_log);
Packit 13e616
Packit 13e616
	CL_ASSERT(p_sw && p_sw->p_node);
Packit 13e616
Packit 13e616
	OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
Packit 13e616
		"Processing switch 0x%" PRIx64 "\n",
Packit 13e616
		cl_ntoh64(osm_node_get_node_guid(p_sw->p_node)));
Packit 13e616
Packit 13e616
	/* Initialize LIDs in buffer to invalid port number. */
Packit 13e616
	memset(p_sw->new_lft, OSM_NO_PATH, p_sw->max_lid_ho + 1);
Packit 13e616
Packit 13e616
	alloc_ports_priv(p_mgr);
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   Iterate through every port setting LID routes for each
Packit 13e616
	   port based on base LID and LMC value.
Packit 13e616
	 */
Packit 13e616
	lids_per_port = 1 << p_mgr->p_subn->opt.lmc;
Packit 13e616
	for (i = 0; i < lids_per_port; i++) {
Packit 13e616
		cl_qlist_t *list = &p_mgr->port_order_list;
Packit 13e616
		cl_list_item_t *item;
Packit 13e616
		for (item = cl_qlist_head(list); item != cl_qlist_end(list);
Packit 13e616
		     item = cl_qlist_next(item)) {
Packit 13e616
			osm_port_t *port = cl_item_obj(item, port, list_item);
Packit 13e616
			ucast_mgr_process_port(p_mgr, p_sw, port, i);
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
	free_ports_priv(p_mgr);
Packit 13e616
Packit 13e616
	OSM_LOG_EXIT(p_mgr->p_log);
Packit 13e616
}
Packit 13e616
Packit 13e616
static void ucast_mgr_process_neighbors(IN cl_map_item_t * p_map_item,
Packit 13e616
					IN void *context)
Packit 13e616
{
Packit 13e616
	osm_switch_t * p_sw = (osm_switch_t *) p_map_item;
Packit 13e616
	osm_ucast_mgr_t * p_mgr = context;
Packit 13e616
	osm_node_t *p_node;
Packit 13e616
	osm_node_t *p_remote_node;
Packit 13e616
	uint32_t port_num;
Packit 13e616
	uint8_t remote_port_num;
Packit 13e616
	uint32_t num_ports;
Packit 13e616
	osm_physp_t *p_physp;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(p_mgr->p_log);
Packit 13e616
Packit 13e616
	p_node = p_sw->p_node;
Packit 13e616
Packit 13e616
	CL_ASSERT(p_node);
Packit 13e616
	CL_ASSERT(osm_node_get_type(p_node) == IB_NODE_TYPE_SWITCH);
Packit 13e616
Packit 13e616
	OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
Packit 13e616
		"Processing switch with GUID 0x%" PRIx64 "\n",
Packit 13e616
		cl_ntoh64(osm_node_get_node_guid(p_node)));
Packit 13e616
Packit 13e616
	num_ports = osm_node_get_num_physp(p_node);
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   Start with port 1 to skip the switch's management port.
Packit 13e616
	 */
Packit 13e616
	for (port_num = 1; port_num < num_ports; port_num++) {
Packit 13e616
		p_remote_node = osm_node_get_remote_node(p_node,
Packit 13e616
							 (uint8_t) port_num,
Packit 13e616
							 &remote_port_num);
Packit 13e616
		if (p_remote_node && p_remote_node->sw
Packit 13e616
		    && (p_remote_node != p_node)) {
Packit 13e616
			/* make sure the link is healthy. If it is not - don't
Packit 13e616
			   propagate through it. */
Packit 13e616
			p_physp = osm_node_get_physp_ptr(p_node, port_num);
Packit 13e616
			if (!p_physp || !osm_link_is_healthy(p_physp))
Packit 13e616
				continue;
Packit 13e616
Packit 13e616
			ucast_mgr_process_neighbor(p_mgr, p_sw,
Packit 13e616
						   p_remote_node->sw,
Packit 13e616
						   (uint8_t) port_num,
Packit 13e616
						   remote_port_num);
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
	OSM_LOG_EXIT(p_mgr->p_log);
Packit 13e616
}
Packit 13e616
Packit 13e616
static int set_hop_wf(void *ctx, uint64_t guid, char *p)
Packit 13e616
{
Packit 13e616
	osm_ucast_mgr_t *m = ctx;
Packit 13e616
	osm_node_t *node = osm_get_node_by_guid(m->p_subn, cl_hton64(guid));
Packit 13e616
	osm_physp_t *physp;
Packit 13e616
	unsigned port, hop_wf;
Packit 13e616
	char *e;
Packit 13e616
Packit 13e616
	if (!node || !node->sw) {
Packit 13e616
		OSM_LOG(m->p_log, OSM_LOG_DEBUG,
Packit 13e616
			"switch with guid 0x%016" PRIx64 " is not found\n",
Packit 13e616
			guid);
Packit 13e616
		return 0;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	if (!p || !*p || !(port = strtoul(p, &e, 0)) || (p == e) ||
Packit 13e616
	    port >= node->sw->num_ports) {
Packit 13e616
		OSM_LOG(m->p_log, OSM_LOG_DEBUG,
Packit 13e616
			"bad port specified for guid 0x%016" PRIx64 "\n", guid);
Packit 13e616
		return 0;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	p = e + 1;
Packit 13e616
Packit 13e616
	if (!*p || !(hop_wf = strtoul(p, &e, 0)) || p == e || hop_wf >= 0x100) {
Packit 13e616
		OSM_LOG(m->p_log, OSM_LOG_DEBUG,
Packit 13e616
			"bad hop weight factor specified for guid 0x%016" PRIx64
Packit 13e616
			"port %u\n", guid, port);
Packit 13e616
		return 0;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	physp = osm_node_get_physp_ptr(node, port);
Packit 13e616
	if (!physp)
Packit 13e616
		return 0;
Packit 13e616
Packit 13e616
	physp->hop_wf = hop_wf;
Packit 13e616
Packit 13e616
	return 0;
Packit 13e616
}
Packit 13e616
Packit 13e616
static void set_default_hop_wf(cl_map_item_t * p_map_item, void *ctx)
Packit 13e616
{
Packit 13e616
	osm_switch_t *sw = (osm_switch_t *) p_map_item;
Packit 13e616
	int i;
Packit 13e616
Packit 13e616
	for (i = 1; i < sw->num_ports; i++) {
Packit 13e616
		osm_physp_t *p = osm_node_get_physp_ptr(sw->p_node, i);
Packit 13e616
		if (p)
Packit 13e616
			p->hop_wf = 1;
Packit 13e616
	}
Packit 13e616
}
Packit 13e616
Packit 13e616
static int set_search_ordering_ports(void *ctx, uint64_t guid, char *p)
Packit 13e616
{
Packit 13e616
	osm_subn_t *p_subn = ctx;
Packit 13e616
	osm_node_t *node = osm_get_node_by_guid(p_subn, cl_hton64(guid));
Packit 13e616
	osm_switch_t *sw;
Packit 13e616
	uint8_t *search_ordering_ports = NULL;
Packit 13e616
	uint8_t port;
Packit 13e616
	unsigned int *ports = NULL;
Packit 13e616
	const int bpw = sizeof(*ports)*8;
Packit 13e616
	int words;
Packit 13e616
	int i = 1; /* port 0 maps to port 0 */
Packit 13e616
Packit 13e616
	if (!node || !(sw = node->sw)) {
Packit 13e616
		OSM_LOG(&p_subn->p_osm->log, OSM_LOG_VERBOSE,
Packit 13e616
			"switch with guid 0x%016" PRIx64 " is not found\n",
Packit 13e616
			guid);
Packit 13e616
		return 0;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	if (sw->search_ordering_ports) {
Packit 13e616
		OSM_LOG(&p_subn->p_osm->log, OSM_LOG_VERBOSE,
Packit 13e616
			"switch with guid 0x%016" PRIx64 " already listed\n",
Packit 13e616
			guid);
Packit 13e616
		return 0;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	search_ordering_ports = malloc(sizeof(*search_ordering_ports)*sw->num_ports);
Packit 13e616
	if (!search_ordering_ports) {
Packit 13e616
		OSM_LOG(&p_subn->p_osm->log, OSM_LOG_ERROR,
Packit 13e616
			"ERR 3A07: cannot allocate memory for search_ordering_ports\n");
Packit 13e616
		return -1;
Packit 13e616
	}
Packit 13e616
	memset(search_ordering_ports, 0, sizeof(*search_ordering_ports)*sw->num_ports);
Packit 13e616
Packit 13e616
	/* the ports array is for record keeping of which ports have
Packit 13e616
	 * been seen */
Packit 13e616
	words = (sw->num_ports + bpw - 1)/bpw;
Packit 13e616
	ports = malloc(words*sizeof(*ports));
Packit 13e616
	if (!ports) {
Packit 13e616
		OSM_LOG(&p_subn->p_osm->log, OSM_LOG_ERROR,
Packit 13e616
			"ERR 3A08: cannot allocate memory for ports\n");
Packit 13e616
		free(search_ordering_ports);
Packit 13e616
		return -1;
Packit 13e616
	}
Packit 13e616
	memset(ports, 0, words*sizeof(*ports));
Packit 13e616
Packit 13e616
	while ((*p != '\0') && (*p != '#')) {
Packit 13e616
		char *e;
Packit 13e616
Packit 13e616
		port = strtoul(p, &e, 0);
Packit 13e616
		if ((p == e) || (port == 0) || (port >= sw->num_ports) ||
Packit 13e616
		    !osm_node_get_physp_ptr(node, port)) {
Packit 13e616
			OSM_LOG(&p_subn->p_osm->log, OSM_LOG_VERBOSE,
Packit 13e616
				"bad port %d specified for guid 0x%016" PRIx64 "\n",
Packit 13e616
				port, guid);
Packit 13e616
			free(search_ordering_ports);
Packit 13e616
			free(ports);
Packit 13e616
			return 0;
Packit 13e616
		}
Packit 13e616
Packit 13e616
		if (ports[port/bpw] & (1u << (port%bpw))) {
Packit 13e616
			OSM_LOG(&p_subn->p_osm->log, OSM_LOG_VERBOSE,
Packit 13e616
				"port %d already specified for guid 0x%016" PRIx64 "\n",
Packit 13e616
				port, guid);
Packit 13e616
			free(search_ordering_ports);
Packit 13e616
			free(ports);
Packit 13e616
			return 0;
Packit 13e616
		}
Packit 13e616
Packit 13e616
		ports[port/bpw] |= (1u << (port%bpw));
Packit 13e616
		search_ordering_ports[i++] = port;
Packit 13e616
Packit 13e616
		p = e;
Packit 13e616
		while (isspace(*p)) {
Packit 13e616
			p++;
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
	if (i > 1) {
Packit 13e616
		for (port = 1; port < sw->num_ports; port++) {
Packit 13e616
			/* fill out the rest of the search_ordering_ports array
Packit 13e616
			 * in sequence using the remaining unspecified
Packit 13e616
			 * ports.
Packit 13e616
			 */
Packit 13e616
			if (!(ports[port/bpw] & (1u << (port%bpw)))) {
Packit 13e616
				search_ordering_ports[i++] = port;
Packit 13e616
			}
Packit 13e616
		}
Packit 13e616
		sw->search_ordering_ports = search_ordering_ports;
Packit 13e616
	} else {
Packit 13e616
		free(search_ordering_ports);
Packit 13e616
	}
Packit 13e616
Packit 13e616
	free(ports);
Packit 13e616
	return 0;
Packit 13e616
}
Packit 13e616
Packit 13e616
int osm_ucast_mgr_build_lid_matrices(IN osm_ucast_mgr_t * p_mgr)
Packit 13e616
{
Packit 13e616
	uint32_t i;
Packit 13e616
	uint32_t iteration_max;
Packit 13e616
	cl_qmap_t *p_sw_guid_tbl;
Packit 13e616
Packit 13e616
	p_sw_guid_tbl = &p_mgr->p_subn->sw_guid_tbl;
Packit 13e616
Packit 13e616
	OSM_LOG(p_mgr->p_log, OSM_LOG_VERBOSE,
Packit 13e616
		"Starting switches' Min Hop Table Assignment\n");
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   Set up the weighting factors for the routing.
Packit 13e616
	 */
Packit 13e616
	cl_qmap_apply_func(p_sw_guid_tbl, set_default_hop_wf, NULL);
Packit 13e616
	if (p_mgr->p_subn->opt.hop_weights_file) {
Packit 13e616
		OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
Packit 13e616
			"Fetching hop weight factor file \'%s\'\n",
Packit 13e616
			p_mgr->p_subn->opt.hop_weights_file);
Packit 13e616
		if (parse_node_map(p_mgr->p_subn->opt.hop_weights_file,
Packit 13e616
				   set_hop_wf, p_mgr)) {
Packit 13e616
			OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR, "ERR 3A05: "
Packit 13e616
				"cannot parse hop_weights_file \'%s\'\n",
Packit 13e616
				p_mgr->p_subn->opt.hop_weights_file);
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   Set the switch matrices for each switch's own port 0 LID(s)
Packit 13e616
	   then set the lid matrices for the each switch's leaf nodes.
Packit 13e616
	 */
Packit 13e616
	cl_qmap_apply_func(p_sw_guid_tbl, ucast_mgr_process_hop_0_1, p_mgr);
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   Get the switch matrices for each switch's neighbors.
Packit 13e616
	   This process requires a number of iterations equal to
Packit 13e616
	   the number of switches in the subnet minus 1.
Packit 13e616
Packit 13e616
	   In each iteration, a switch learns the lid/port/hop
Packit 13e616
	   information (as contained by a switch's lid matrix) from
Packit 13e616
	   its immediate neighbors.  After each iteration, a switch
Packit 13e616
	   (and it's neighbors) know more routing information than
Packit 13e616
	   it did on the previous iteration.
Packit 13e616
	   Thus, by repeatedly absorbing the routing information of
Packit 13e616
	   neighbor switches, every switch eventually learns how to
Packit 13e616
	   route all LIDs on the subnet.
Packit 13e616
Packit 13e616
	   Note that there may not be any switches in the subnet if
Packit 13e616
	   we are in simple p2p configuration.
Packit 13e616
	 */
Packit 13e616
	iteration_max = cl_qmap_count(p_sw_guid_tbl);
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   If there are switches in the subnet, iterate until the lid
Packit 13e616
	   matrix has been constructed.  Otherwise, just immediately
Packit 13e616
	   indicate we're done if no switches exist.
Packit 13e616
	 */
Packit 13e616
	if (iteration_max) {
Packit 13e616
		iteration_max--;
Packit 13e616
Packit 13e616
		/*
Packit 13e616
		   we need to find out when the propagation of
Packit 13e616
		   hop counts has relaxed. So this global variable
Packit 13e616
		   is preset to 0 on each iteration and if
Packit 13e616
		   if non of the switches was set will exit the
Packit 13e616
		   while loop
Packit 13e616
		 */
Packit 13e616
		p_mgr->some_hop_count_set = TRUE;
Packit 13e616
		for (i = 0; (i < iteration_max) && p_mgr->some_hop_count_set;
Packit 13e616
		     i++) {
Packit 13e616
			p_mgr->some_hop_count_set = FALSE;
Packit 13e616
			cl_qmap_apply_func(p_sw_guid_tbl,
Packit 13e616
					   ucast_mgr_process_neighbors, p_mgr);
Packit 13e616
		}
Packit 13e616
		OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
Packit 13e616
			"Min-hop propagated in %d steps\n", i);
Packit 13e616
	}
Packit 13e616
Packit 13e616
	return 0;
Packit 13e616
}
Packit 13e616
Packit 13e616
static int ucast_mgr_setup_all_switches(osm_subn_t * p_subn)
Packit 13e616
{
Packit 13e616
	osm_switch_t *p_sw;
Packit 13e616
	uint16_t lids;
Packit 13e616
Packit 13e616
	lids = (uint16_t) cl_ptr_vector_get_size(&p_subn->port_lid_tbl);
Packit 13e616
	lids = lids ? lids - 1 : 0;
Packit 13e616
Packit 13e616
	for (p_sw = (osm_switch_t *) cl_qmap_head(&p_subn->sw_guid_tbl);
Packit 13e616
	     p_sw != (osm_switch_t *) cl_qmap_end(&p_subn->sw_guid_tbl);
Packit 13e616
	     p_sw = (osm_switch_t *) cl_qmap_next(&p_sw->map_item)) {
Packit 13e616
		if (osm_switch_prepare_path_rebuild(p_sw, lids)) {
Packit 13e616
			OSM_LOG(&p_subn->p_osm->log, OSM_LOG_ERROR, "ERR 3A0B: "
Packit 13e616
				"cannot setup switch 0x%016" PRIx64 "\n",
Packit 13e616
				cl_ntoh64(osm_node_get_node_guid
Packit 13e616
					  (p_sw->p_node)));
Packit 13e616
			return -1;
Packit 13e616
		}
Packit 13e616
		if (p_sw->search_ordering_ports) {
Packit 13e616
			free(p_sw->search_ordering_ports);
Packit 13e616
			p_sw->search_ordering_ports = NULL;
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
	if (p_subn->opt.port_search_ordering_file) {
Packit 13e616
		OSM_LOG(&p_subn->p_osm->log, OSM_LOG_DEBUG,
Packit 13e616
			"Fetching dimension ports file \'%s\'\n",
Packit 13e616
			p_subn->opt.port_search_ordering_file);
Packit 13e616
		if (parse_node_map(p_subn->opt.port_search_ordering_file,
Packit 13e616
				   set_search_ordering_ports, p_subn)) {
Packit 13e616
			OSM_LOG(&p_subn->p_osm->log, OSM_LOG_ERROR, "ERR 3A0F: "
Packit 13e616
				"cannot parse port_search_ordering_file \'%s\'\n",
Packit 13e616
				p_subn->opt.port_search_ordering_file);
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
	return 0;
Packit 13e616
}
Packit 13e616
Packit 13e616
static int add_guid_to_order_list(void *ctx, uint64_t guid, char *p)
Packit 13e616
{
Packit 13e616
	osm_ucast_mgr_t *m = ctx;
Packit 13e616
	osm_port_t *port = osm_get_port_by_guid(m->p_subn, cl_hton64(guid));
Packit 13e616
Packit 13e616
	if (!port) {
Packit 13e616
		OSM_LOG(m->p_log, OSM_LOG_DEBUG,
Packit 13e616
			"port guid not found: 0x%016" PRIx64 "\n", guid);
Packit 13e616
		return 0;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	if (port->flag) {
Packit 13e616
		OSM_LOG(m->p_log, OSM_LOG_DEBUG,
Packit 13e616
			"port guid specified multiple times 0x%016" PRIx64 "\n",
Packit 13e616
			guid);
Packit 13e616
		return 0;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	cl_qlist_insert_tail(&m->port_order_list, &port->list_item);
Packit 13e616
	port->flag = 1;
Packit 13e616
	port->use_scatter =  (m->p_subn->opt.guid_routing_order_no_scatter == TRUE) ? 0 : m->p_subn->opt.scatter_ports;
Packit 13e616
Packit 13e616
	return 0;
Packit 13e616
}
Packit 13e616
Packit 13e616
static void add_port_to_order_list(cl_map_item_t * p_map_item, void *ctx)
Packit 13e616
{
Packit 13e616
	osm_port_t *port = (osm_port_t *) p_map_item;
Packit 13e616
	osm_ucast_mgr_t *m = ctx;
Packit 13e616
Packit 13e616
	if (!port->flag) {
Packit 13e616
		port->use_scatter = m->p_subn->opt.scatter_ports;
Packit 13e616
		cl_qlist_insert_tail(&m->port_order_list, &port->list_item);
Packit 13e616
	} else
Packit 13e616
		port->flag = 0;
Packit 13e616
}
Packit 13e616
Packit 13e616
static int mark_ignored_port(void *ctx, uint64_t guid, char *p)
Packit 13e616
{
Packit 13e616
	osm_ucast_mgr_t *m = ctx;
Packit 13e616
	osm_node_t *node = osm_get_node_by_guid(m->p_subn, cl_hton64(guid));
Packit 13e616
	osm_physp_t *physp;
Packit 13e616
	unsigned port;
Packit 13e616
Packit 13e616
	if (!node || !node->sw) {
Packit 13e616
		OSM_LOG(m->p_log, OSM_LOG_DEBUG,
Packit 13e616
			"switch with guid 0x%016" PRIx64 " is not found\n",
Packit 13e616
			guid);
Packit 13e616
		return 0;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	if (!p || !*p || !(port = strtoul(p, NULL, 0)) ||
Packit 13e616
	    port >= node->sw->num_ports) {
Packit 13e616
		OSM_LOG(m->p_log, OSM_LOG_DEBUG,
Packit 13e616
			"bad port specified for guid 0x%016" PRIx64 "\n", guid);
Packit 13e616
		return 0;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	physp = osm_node_get_physp_ptr(node, port);
Packit 13e616
	if (!physp)
Packit 13e616
		return 0;
Packit 13e616
Packit 13e616
	physp->is_prof_ignored = 1;
Packit 13e616
Packit 13e616
	return 0;
Packit 13e616
}
Packit 13e616
Packit 13e616
static void clear_prof_ignore_flag(cl_map_item_t * p_map_item, void *ctx)
Packit 13e616
{
Packit 13e616
	osm_switch_t *sw = (osm_switch_t *) p_map_item;
Packit 13e616
	int i;
Packit 13e616
Packit 13e616
	for (i = 1; i < sw->num_ports; i++) {
Packit 13e616
		osm_physp_t *p = osm_node_get_physp_ptr(sw->p_node, i);
Packit 13e616
		if (p)
Packit 13e616
			p->is_prof_ignored = 0;
Packit 13e616
	}
Packit 13e616
}
Packit 13e616
Packit 13e616
static void add_sw_endports_to_order_list(osm_switch_t * sw,
Packit 13e616
					  osm_ucast_mgr_t * m)
Packit 13e616
{
Packit 13e616
	osm_port_t *port;
Packit 13e616
	osm_physp_t *p;
Packit 13e616
	int i;
Packit 13e616
Packit 13e616
	for (i = 1; i < sw->num_ports; i++) {
Packit 13e616
		p = osm_node_get_physp_ptr(sw->p_node, i);
Packit 13e616
		if (p && p->p_remote_physp && !p->p_remote_physp->p_node->sw) {
Packit 13e616
			port = osm_get_port_by_guid(m->p_subn,
Packit 13e616
						    p->p_remote_physp->
Packit 13e616
						    port_guid);
Packit 13e616
			if (!port || port->flag)
Packit 13e616
				continue;
Packit 13e616
			cl_qlist_insert_tail(&m->port_order_list,
Packit 13e616
					     &port->list_item);
Packit 13e616
			port->flag = 1;
Packit 13e616
			port->use_scatter = m->p_subn->opt.scatter_ports;
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
}
Packit 13e616
Packit 13e616
static void sw_count_endport_links(osm_switch_t * sw)
Packit 13e616
{
Packit 13e616
	osm_physp_t *p;
Packit 13e616
	int i;
Packit 13e616
Packit 13e616
	sw->endport_links = 0;
Packit 13e616
	for (i = 1; i < sw->num_ports; i++) {
Packit 13e616
		p = osm_node_get_physp_ptr(sw->p_node, i);
Packit 13e616
		if (p && p->p_remote_physp && !p->p_remote_physp->p_node->sw)
Packit 13e616
			sw->endport_links++;
Packit 13e616
	}
Packit 13e616
}
Packit 13e616
Packit 13e616
static int compar_sw_load(const void *s1, const void *s2)
Packit 13e616
{
Packit 13e616
#define get_sw_endport_links(s) (*(osm_switch_t **)s)->endport_links
Packit 13e616
	return get_sw_endport_links(s2) - get_sw_endport_links(s1);
Packit 13e616
}
Packit 13e616
Packit 13e616
static void sort_ports_by_switch_load(osm_ucast_mgr_t * m)
Packit 13e616
{
Packit 13e616
	int i, num = cl_qmap_count(&m->p_subn->sw_guid_tbl);
Packit 13e616
	void **s = malloc(num * sizeof(*s));
Packit 13e616
	if (!s) {
Packit 13e616
		OSM_LOG(m->p_log, OSM_LOG_ERROR, "ERR 3A0C: "
Packit 13e616
			"No memory, skip by switch load sorting.\n");
Packit 13e616
		return;
Packit 13e616
	}
Packit 13e616
	s[0] = cl_qmap_head(&m->p_subn->sw_guid_tbl);
Packit 13e616
	for (i = 1; i < num; i++)
Packit 13e616
		s[i] = cl_qmap_next(s[i - 1]);
Packit 13e616
Packit 13e616
	for (i = 0; i < num; i++)
Packit 13e616
		sw_count_endport_links(s[i]);
Packit 13e616
Packit 13e616
	qsort(s, num, sizeof(*s), compar_sw_load);
Packit 13e616
Packit 13e616
	for (i = 0; i < num; i++)
Packit 13e616
		add_sw_endports_to_order_list(s[i], m);
Packit 13e616
	free(s);
Packit 13e616
}
Packit 13e616
Packit 13e616
static int ucast_mgr_build_lfts(osm_ucast_mgr_t * p_mgr)
Packit 13e616
{
Packit 13e616
	cl_qlist_init(&p_mgr->port_order_list);
Packit 13e616
Packit 13e616
	if (p_mgr->p_subn->opt.guid_routing_order_file) {
Packit 13e616
		OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
Packit 13e616
			"Fetching guid routing order file \'%s\'\n",
Packit 13e616
			p_mgr->p_subn->opt.guid_routing_order_file);
Packit 13e616
Packit 13e616
		if (parse_node_map(p_mgr->p_subn->opt.guid_routing_order_file,
Packit 13e616
				   add_guid_to_order_list, p_mgr))
Packit 13e616
			OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR, "ERR 3A0D: "
Packit 13e616
				"cannot parse guid routing order file \'%s\'\n",
Packit 13e616
				p_mgr->p_subn->opt.guid_routing_order_file);
Packit 13e616
	}
Packit 13e616
	sort_ports_by_switch_load(p_mgr);
Packit 13e616
Packit 13e616
	if (p_mgr->p_subn->opt.port_prof_ignore_file) {
Packit 13e616
		cl_qmap_apply_func(&p_mgr->p_subn->sw_guid_tbl,
Packit 13e616
				   clear_prof_ignore_flag, NULL);
Packit 13e616
		if (parse_node_map(p_mgr->p_subn->opt.port_prof_ignore_file,
Packit 13e616
				   mark_ignored_port, p_mgr)) {
Packit 13e616
			OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR, "ERR 3A0E: "
Packit 13e616
				"cannot parse port prof ignore file \'%s\'\n",
Packit 13e616
				p_mgr->p_subn->opt.port_prof_ignore_file);
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
	cl_qmap_apply_func(&p_mgr->p_subn->port_guid_tbl,
Packit 13e616
			   add_port_to_order_list, p_mgr);
Packit 13e616
Packit 13e616
	cl_qmap_apply_func(&p_mgr->p_subn->sw_guid_tbl, ucast_mgr_process_tbl,
Packit 13e616
			   p_mgr);
Packit 13e616
Packit 13e616
	cl_qlist_remove_all(&p_mgr->port_order_list);
Packit 13e616
Packit 13e616
	return 0;
Packit 13e616
}
Packit 13e616
Packit 13e616
static void ucast_mgr_set_fwd_top(IN cl_map_item_t * p_map_item,
Packit 13e616
				  IN void *cxt)
Packit 13e616
{
Packit 13e616
	osm_ucast_mgr_t *p_mgr = cxt;
Packit 13e616
	osm_switch_t * p_sw = (osm_switch_t *) p_map_item;
Packit 13e616
	osm_node_t *p_node;
Packit 13e616
	osm_physp_t *p_physp;
Packit 13e616
	osm_dr_path_t *p_path;
Packit 13e616
	osm_madw_context_t context;
Packit 13e616
	ib_api_status_t status;
Packit 13e616
	ib_switch_info_t si;
Packit 13e616
	boolean_t set_swinfo_require = FALSE;
Packit 13e616
	uint16_t lin_top;
Packit 13e616
	uint8_t life_state;
Packit 13e616
Packit 13e616
	CL_ASSERT(p_mgr);
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(p_mgr->p_log);
Packit 13e616
Packit 13e616
	CL_ASSERT(p_sw && p_sw->max_lid_ho);
Packit 13e616
Packit 13e616
	p_node = p_sw->p_node;
Packit 13e616
Packit 13e616
	CL_ASSERT(p_node);
Packit 13e616
Packit 13e616
	if (p_mgr->max_lid < p_sw->max_lid_ho)
Packit 13e616
		p_mgr->max_lid = p_sw->max_lid_ho;
Packit 13e616
Packit 13e616
	p_physp = osm_node_get_physp_ptr(p_node, 0);
Packit 13e616
Packit 13e616
	CL_ASSERT(p_physp);
Packit 13e616
Packit 13e616
	p_path = osm_physp_get_dr_path_ptr(p_physp);
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   Set the top of the unicast forwarding table.
Packit 13e616
	 */
Packit 13e616
	si = p_sw->switch_info;
Packit 13e616
	lin_top = cl_hton16(p_sw->max_lid_ho);
Packit 13e616
	if (lin_top != si.lin_top) {
Packit 13e616
		set_swinfo_require = TRUE;
Packit 13e616
		si.lin_top = lin_top;
Packit 13e616
		context.si_context.lft_top_change = TRUE;
Packit 13e616
	} else
Packit 13e616
		context.si_context.lft_top_change = FALSE;
Packit 13e616
Packit 13e616
	life_state = si.life_state;
Packit 13e616
	ib_switch_info_set_life_time(&si, p_mgr->p_subn->opt.packet_life_time);
Packit 13e616
Packit 13e616
	if (life_state != si.life_state)
Packit 13e616
		set_swinfo_require = TRUE;
Packit 13e616
Packit 13e616
	if (set_swinfo_require) {
Packit 13e616
		OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
Packit 13e616
			"Setting switch FT top to LID %u\n", p_sw->max_lid_ho);
Packit 13e616
Packit 13e616
		context.si_context.light_sweep = FALSE;
Packit 13e616
		context.si_context.node_guid = osm_node_get_node_guid(p_node);
Packit 13e616
		context.si_context.set_method = TRUE;
Packit 13e616
Packit 13e616
		status = osm_req_set(p_mgr->sm, p_path, (uint8_t *) & si,
Packit 13e616
				     sizeof(si), IB_MAD_ATTR_SWITCH_INFO,
Packit 13e616
				     0, FALSE,
Packit 13e616
				     ib_port_info_get_m_key(&p_physp->port_info),
Packit 13e616
				     0, CL_DISP_MSGID_NONE, &context);
Packit 13e616
Packit 13e616
		if (status != IB_SUCCESS)
Packit 13e616
			OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR, "ERR 3A06: "
Packit 13e616
				"Sending SwitchInfo attribute failed (%s)\n",
Packit 13e616
				ib_get_err_str(status));
Packit 13e616
	}
Packit 13e616
Packit 13e616
	OSM_LOG_EXIT(p_mgr->p_log);
Packit 13e616
}
Packit 13e616
Packit 13e616
static int set_lft_block(IN osm_switch_t *p_sw, IN osm_ucast_mgr_t *p_mgr,
Packit 13e616
			 IN uint16_t block_id_ho)
Packit 13e616
{
Packit 13e616
	osm_madw_context_t context;
Packit 13e616
	osm_dr_path_t *p_path;
Packit 13e616
	osm_physp_t *p_physp;
Packit 13e616
	ib_api_status_t status;
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   Send linear forwarding table blocks to the switch
Packit 13e616
	   as long as the switch indicates it has blocks needing
Packit 13e616
	   configuration.
Packit 13e616
	 */
Packit 13e616
	if (!p_sw->new_lft) {
Packit 13e616
		/* any routing should provide the new_lft */
Packit 13e616
		CL_ASSERT(p_mgr->p_subn->opt.use_ucast_cache &&
Packit 13e616
			  p_mgr->cache_valid && !p_sw->need_update);
Packit 13e616
		return -1;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	p_physp = osm_node_get_physp_ptr(p_sw->p_node, 0);
Packit 13e616
	if (!p_physp)
Packit 13e616
		return -1;
Packit 13e616
Packit 13e616
	p_path = osm_physp_get_dr_path_ptr(p_physp);
Packit 13e616
Packit 13e616
	context.lft_context.node_guid = osm_node_get_node_guid(p_sw->p_node);
Packit 13e616
	context.lft_context.set_method = TRUE;
Packit 13e616
Packit 13e616
	if (!p_sw->need_update && !p_mgr->p_subn->need_update &&
Packit 13e616
	    !memcmp(p_sw->new_lft + block_id_ho * IB_SMP_DATA_SIZE,
Packit 13e616
		    p_sw->lft + block_id_ho * IB_SMP_DATA_SIZE,
Packit 13e616
		    IB_SMP_DATA_SIZE))
Packit 13e616
		return 0;
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	 * Zero the stored LFT block, so in case the MAD will end up
Packit 13e616
	 * with error, we will resend it in the next sweep.
Packit 13e616
	 */
Packit 13e616
	memset(p_sw->lft + block_id_ho * IB_SMP_DATA_SIZE, 0,
Packit 13e616
	       IB_SMP_DATA_SIZE);
Packit 13e616
Packit 13e616
	OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
Packit 13e616
		"Writing FT block %u to switch 0x%" PRIx64 "\n", block_id_ho,
Packit 13e616
		cl_ntoh64(context.lft_context.node_guid));
Packit 13e616
Packit 13e616
	status = osm_req_set(p_mgr->sm, p_path,
Packit 13e616
			     p_sw->new_lft + block_id_ho * IB_SMP_DATA_SIZE,
Packit 13e616
			     IB_SMP_DATA_SIZE, IB_MAD_ATTR_LIN_FWD_TBL,
Packit 13e616
			     cl_hton32(block_id_ho), FALSE,
Packit 13e616
			     ib_port_info_get_m_key(&p_physp->port_info),
Packit 13e616
			     0, CL_DISP_MSGID_NONE, &context);
Packit 13e616
Packit 13e616
	if (status != IB_SUCCESS) {
Packit 13e616
		OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR, "ERR 3A10: "
Packit 13e616
			"Sending linear fwd. tbl. block failed (%s)\n",
Packit 13e616
			ib_get_err_str(status));
Packit 13e616
		return -1;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	return 0;
Packit 13e616
}
Packit 13e616
Packit 13e616
static void ucast_mgr_pipeline_fwd_tbl(osm_ucast_mgr_t * p_mgr)
Packit 13e616
{
Packit 13e616
	cl_qmap_t *tbl;
Packit 13e616
	cl_map_item_t *item;
Packit 13e616
	unsigned i, max_block = p_mgr->max_lid / IB_SMP_DATA_SIZE + 1;
Packit 13e616
Packit 13e616
	tbl = &p_mgr->p_subn->sw_guid_tbl;
Packit 13e616
	for (i = 0; i < max_block; i++)
Packit 13e616
		for (item = cl_qmap_head(tbl); item != cl_qmap_end(tbl);
Packit 13e616
		     item = cl_qmap_next(item))
Packit 13e616
			set_lft_block((osm_switch_t *)item, p_mgr, i);
Packit 13e616
}
Packit 13e616
Packit 13e616
void osm_ucast_mgr_set_fwd_tables(osm_ucast_mgr_t * p_mgr)
Packit 13e616
{
Packit 13e616
	p_mgr->max_lid = 0;
Packit 13e616
Packit 13e616
	cl_qmap_apply_func(&p_mgr->p_subn->sw_guid_tbl, ucast_mgr_set_fwd_top,
Packit 13e616
			   p_mgr);
Packit 13e616
Packit 13e616
	ucast_mgr_pipeline_fwd_tbl(p_mgr);
Packit 13e616
}
Packit 13e616
Packit 13e616
static int ucast_mgr_route(struct osm_routing_engine *r, osm_opensm_t * osm)
Packit 13e616
{
Packit 13e616
	int ret;
Packit 13e616
Packit 13e616
	OSM_LOG(&osm->log, OSM_LOG_VERBOSE,
Packit 13e616
		"building routing with \'%s\' routing algorithm...\n", r->name);
Packit 13e616
Packit 13e616
	/* Set the before each lft build to keep the routes in place between sweeps */
Packit 13e616
	if (osm->subn.opt.scatter_ports)
Packit 13e616
		srandom(osm->subn.opt.scatter_ports);
Packit 13e616
Packit 13e616
	if (!r->build_lid_matrices ||
Packit 13e616
	    (ret = r->build_lid_matrices(r->context)) > 0)
Packit 13e616
		ret = osm_ucast_mgr_build_lid_matrices(&osm->sm.ucast_mgr);
Packit 13e616
Packit 13e616
	if (ret < 0) {
Packit 13e616
		OSM_LOG(&osm->log, OSM_LOG_ERROR,
Packit 13e616
			"%s: cannot build lid matrices\n", r->name);
Packit 13e616
		return ret;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	if (!r->ucast_build_fwd_tables ||
Packit 13e616
	    (ret = r->ucast_build_fwd_tables(r->context)) > 0)
Packit 13e616
		ret = ucast_mgr_build_lfts(&osm->sm.ucast_mgr);
Packit 13e616
Packit 13e616
	if (ret < 0) {
Packit 13e616
		OSM_LOG(&osm->log, OSM_LOG_ERROR,
Packit 13e616
			"%s: cannot build fwd tables\n", r->name);
Packit 13e616
		return ret;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	osm->routing_engine_used = r;
Packit 13e616
Packit 13e616
	osm_ucast_mgr_set_fwd_tables(&osm->sm.ucast_mgr);
Packit 13e616
Packit 13e616
	return 0;
Packit 13e616
}
Packit 13e616
Packit 13e616
int osm_ucast_mgr_process(IN osm_ucast_mgr_t * p_mgr)
Packit 13e616
{
Packit 13e616
	osm_opensm_t *p_osm;
Packit 13e616
	struct osm_routing_engine *p_routing_eng;
Packit 13e616
	cl_qmap_t *p_sw_guid_tbl;
Packit 13e616
	int failed = 0;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(p_mgr->p_log);
Packit 13e616
Packit 13e616
	p_sw_guid_tbl = &p_mgr->p_subn->sw_guid_tbl;
Packit 13e616
	p_osm = p_mgr->p_subn->p_osm;
Packit 13e616
	p_routing_eng = p_osm->routing_engine_list;
Packit 13e616
Packit 13e616
	CL_PLOCK_EXCL_ACQUIRE(p_mgr->p_lock);
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   If there are no switches in the subnet, we are done.
Packit 13e616
	 */
Packit 13e616
	if (cl_qmap_count(p_sw_guid_tbl) == 0 ||
Packit 13e616
	    ucast_mgr_setup_all_switches(p_mgr->p_subn) < 0)
Packit 13e616
		goto Exit;
Packit 13e616
Packit 13e616
	failed = -1;
Packit 13e616
	p_osm->routing_engine_used = NULL;
Packit 13e616
	while (p_routing_eng) {
Packit 13e616
		failed = ucast_mgr_route(p_routing_eng, p_osm);
Packit 13e616
		if (!failed)
Packit 13e616
			break;
Packit 13e616
		p_routing_eng = p_routing_eng->next;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	if (!p_osm->routing_engine_used &&
Packit 13e616
	    p_osm->no_fallback_routing_engine != TRUE) {
Packit 13e616
		/* If configured routing algorithm failed, use default MinHop */
Packit 13e616
		failed = ucast_mgr_route(p_osm->default_routing_engine, p_osm);
Packit 13e616
	}
Packit 13e616
Packit 13e616
	if (p_osm->routing_engine_used) {
Packit 13e616
		OSM_LOG(p_mgr->p_log, OSM_LOG_INFO,
Packit 13e616
			"%s tables configured on all switches\n",
Packit 13e616
			osm_routing_engine_type_str(p_osm->
Packit 13e616
						    routing_engine_used->type));
Packit 13e616
Packit 13e616
		if (p_mgr->p_subn->opt.use_ucast_cache)
Packit 13e616
			p_mgr->cache_valid = TRUE;
Packit 13e616
	} else {
Packit 13e616
		p_mgr->p_subn->subnet_initialization_error = TRUE;
Packit 13e616
		OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
Packit 13e616
			"No routing engine able to successfully configure "
Packit 13e616
			" switch tables on current fabric\n");
Packit 13e616
	}
Packit 13e616
Exit:
Packit 13e616
	CL_PLOCK_RELEASE(p_mgr->p_lock);
Packit 13e616
	OSM_LOG_EXIT(p_mgr->p_log);
Packit 13e616
	return failed;
Packit 13e616
}
Packit 13e616
Packit 13e616
static int ucast_build_lid_matrices(void *context)
Packit 13e616
{
Packit 13e616
	return osm_ucast_mgr_build_lid_matrices(context);
Packit 13e616
}
Packit 13e616
Packit 13e616
static int ucast_build_lfts(void *context)
Packit 13e616
{
Packit 13e616
	return ucast_mgr_build_lfts(context);
Packit 13e616
}
Packit 13e616
Packit 13e616
int osm_ucast_minhop_setup(struct osm_routing_engine *r, osm_opensm_t * osm)
Packit 13e616
{
Packit 13e616
	r->context = &osm->sm.ucast_mgr;
Packit 13e616
	r->build_lid_matrices = ucast_build_lid_matrices;
Packit 13e616
	r->ucast_build_fwd_tables = ucast_build_lfts;
Packit 13e616
	return 0;
Packit 13e616
}
Packit 13e616
Packit 13e616
static int ucast_dor_build_lfts(void *context)
Packit 13e616
{
Packit 13e616
	osm_ucast_mgr_t *mgr = context;
Packit 13e616
	int ret;
Packit 13e616
Packit 13e616
	mgr->is_dor = 1;
Packit 13e616
	ret = ucast_mgr_build_lfts(mgr);
Packit 13e616
	mgr->is_dor = 0;
Packit 13e616
Packit 13e616
	return ret;
Packit 13e616
}
Packit 13e616
Packit 13e616
int osm_ucast_dor_setup(struct osm_routing_engine *r, osm_opensm_t * osm)
Packit 13e616
{
Packit 13e616
	r->context = &osm->sm.ucast_mgr;
Packit 13e616
	r->build_lid_matrices = ucast_build_lid_matrices;
Packit 13e616
	r->ucast_build_fwd_tables = ucast_dor_build_lfts;
Packit 13e616
	return 0;
Packit 13e616
}
Packit 13e616
Packit 13e616
int ucast_dummy_build_lid_matrices(void *context)
Packit 13e616
{
Packit 13e616
	return 0;
Packit 13e616
}