Blame opensm/osm_sa_path_record.c

Packit 13e616
/*
Packit 13e616
 * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved.
Packit 13e616
 * Copyright (c) 2002-2011 Mellanox Technologies LTD. All rights reserved.
Packit 13e616
 * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
Packit 13e616
 * Copyright (c) 2008 Xsigo Systems Inc. All rights reserved.
Packit 13e616
 * Copyright (c) 2009 HNR Consulting. All rights reserved.
Packit 13e616
 * Copyright (c) 2010 Sun Microsystems, Inc. All rights reserved.
Packit 13e616
 * Copyright (c) 2009-2011 ZIH, TU Dresden, Federal Republic of Germany. All rights reserved.
Packit 13e616
 * Copyright (c) 2013 Oracle and/or its affiliates. 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_pr_rcv_t.
Packit 13e616
 * This object represents the PathRecord Receiver object.
Packit 13e616
 * This object is part of the opensm family of objects.
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 <string.h>
Packit 13e616
#include <arpa/inet.h>
Packit 13e616
#include <iba/ib_types.h>
Packit 13e616
#include <complib/cl_qmap.h>
Packit 13e616
#include <complib/cl_passivelock.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_SA_PATH_RECORD_C
Packit 13e616
#include <vendor/osm_vendor_api.h>
Packit 13e616
#include <opensm/osm_base.h>
Packit 13e616
#include <opensm/osm_port.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_pkey.h>
Packit 13e616
#include <opensm/osm_multicast.h>
Packit 13e616
#include <opensm/osm_partition.h>
Packit 13e616
#include <opensm/osm_opensm.h>
Packit 13e616
#include <opensm/osm_qos_policy.h>
Packit 13e616
#include <opensm/osm_sa.h>
Packit 13e616
#include <opensm/osm_router.h>
Packit 13e616
#include <opensm/osm_prefix_route.h>
Packit 13e616
#include <opensm/osm_ucast_lash.h>
Packit 13e616
Packit 13e616
#define SA_PR_RESP_SIZE SA_ITEM_RESP_SIZE(path_rec)
Packit 13e616
Packit 13e616
#define MAX_HOPS 64
Packit 13e616
Packit 13e616
static inline boolean_t sa_path_rec_is_tavor_port(IN const osm_port_t * p_port)
Packit 13e616
{
Packit 13e616
	osm_node_t const *p_node;
Packit 13e616
	ib_net32_t vend_id;
Packit 13e616
Packit 13e616
	p_node = p_port->p_node;
Packit 13e616
	vend_id = ib_node_info_get_vendor_id(&p_node->node_info);
Packit 13e616
Packit 13e616
	return ((p_node->node_info.device_id == CL_HTON16(23108)) &&
Packit 13e616
		((vend_id == CL_HTON32(OSM_VENDOR_ID_MELLANOX)) ||
Packit 13e616
		 (vend_id == CL_HTON32(OSM_VENDOR_ID_TOPSPIN)) ||
Packit 13e616
		 (vend_id == CL_HTON32(OSM_VENDOR_ID_SILVERSTORM)) ||
Packit 13e616
		 (vend_id == CL_HTON32(OSM_VENDOR_ID_VOLTAIRE))));
Packit 13e616
}
Packit 13e616
Packit 13e616
static boolean_t
Packit 13e616
sa_path_rec_apply_tavor_mtu_limit(IN const ib_path_rec_t * p_pr,
Packit 13e616
				  IN const osm_port_t * p_src_port,
Packit 13e616
				  IN const osm_port_t * p_dest_port,
Packit 13e616
				  IN const ib_net64_t comp_mask)
Packit 13e616
{
Packit 13e616
	uint8_t required_mtu;
Packit 13e616
Packit 13e616
	/* only if at least one of the ports is a Tavor device */
Packit 13e616
	if (!sa_path_rec_is_tavor_port(p_src_port) &&
Packit 13e616
	    !sa_path_rec_is_tavor_port(p_dest_port))
Packit 13e616
		return FALSE;
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   we can apply the patch if either:
Packit 13e616
	   1. No MTU required
Packit 13e616
	   2. Required MTU <
Packit 13e616
	   3. Required MTU = 1K or 512 or 256
Packit 13e616
	   4. Required MTU > 256 or 512
Packit 13e616
	 */
Packit 13e616
	required_mtu = ib_path_rec_mtu(p_pr);
Packit 13e616
	if ((comp_mask & IB_PR_COMPMASK_MTUSELEC) &&
Packit 13e616
	    (comp_mask & IB_PR_COMPMASK_MTU)) {
Packit 13e616
		switch (ib_path_rec_mtu_sel(p_pr)) {
Packit 13e616
		case 0:	/* must be greater than */
Packit 13e616
		case 2:	/* exact match */
Packit 13e616
			if (IB_MTU_LEN_1024 < required_mtu)
Packit 13e616
				return FALSE;
Packit 13e616
			break;
Packit 13e616
Packit 13e616
		case 1:	/* must be less than */
Packit 13e616
			/* can't be disqualified by this one */
Packit 13e616
			break;
Packit 13e616
Packit 13e616
		case 3:	/* largest available */
Packit 13e616
			/* the ULP intentionally requested */
Packit 13e616
			/* the largest MTU possible */
Packit 13e616
			return FALSE;
Packit 13e616
Packit 13e616
		default:
Packit 13e616
			/* if we're here, there's a bug in ib_path_rec_mtu_sel() */
Packit 13e616
			CL_ASSERT(FALSE);
Packit 13e616
			break;
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
	return TRUE;
Packit 13e616
}
Packit 13e616
Packit 13e616
static ib_api_status_t pr_rcv_get_path_parms(IN osm_sa_t * sa,
Packit 13e616
					     IN const ib_path_rec_t * p_pr,
Packit 13e616
					     IN const osm_alias_guid_t * p_src_alias_guid,
Packit 13e616
					     IN const uint16_t src_lid_ho,
Packit 13e616
					     IN const osm_alias_guid_t * p_dest_alias_guid,
Packit 13e616
					     IN const uint16_t dest_lid_ho,
Packit 13e616
					     IN const ib_net64_t comp_mask,
Packit 13e616
					     OUT osm_path_parms_t * p_parms)
Packit 13e616
{
Packit 13e616
	const osm_node_t *p_node;
Packit 13e616
	const osm_physp_t *p_physp, *p_physp0;
Packit 13e616
	const osm_physp_t *p_src_physp;
Packit 13e616
	const osm_physp_t *p_dest_physp;
Packit 13e616
	const osm_prtn_t *p_prtn = NULL;
Packit 13e616
	osm_opensm_t *p_osm;
Packit 13e616
	struct osm_routing_engine *p_re;
Packit 13e616
	const ib_port_info_t *p_pi, *p_pi0;
Packit 13e616
	ib_api_status_t status = IB_SUCCESS;
Packit 13e616
	ib_net16_t pkey;
Packit 13e616
	uint8_t mtu;
Packit 13e616
	uint8_t rate, p0_extended_rate, dest_rate;
Packit 13e616
	uint8_t pkt_life;
Packit 13e616
	uint8_t required_mtu;
Packit 13e616
	uint8_t required_rate;
Packit 13e616
	uint8_t required_pkt_life;
Packit 13e616
	uint8_t sl;
Packit 13e616
	uint8_t in_port_num;
Packit 13e616
	ib_net16_t dest_lid;
Packit 13e616
	uint8_t i;
Packit 13e616
	ib_slvl_table_t *p_slvl_tbl = NULL;
Packit 13e616
	osm_qos_level_t *p_qos_level = NULL;
Packit 13e616
	uint16_t valid_sl_mask = 0xffff;
Packit 13e616
	int hops = 0;
Packit 13e616
	int extended, p0_extended;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(sa->p_log);
Packit 13e616
Packit 13e616
	dest_lid = cl_hton16(dest_lid_ho);
Packit 13e616
Packit 13e616
	p_dest_physp = p_dest_alias_guid->p_base_port->p_physp;
Packit 13e616
	p_physp = p_src_alias_guid->p_base_port->p_physp;
Packit 13e616
	p_src_physp = p_physp;
Packit 13e616
	p_pi = &p_physp->port_info;
Packit 13e616
	p_osm = sa->p_subn->p_osm;
Packit 13e616
	p_re = p_osm->routing_engine_used;
Packit 13e616
Packit 13e616
	mtu = ib_port_info_get_mtu_cap(p_pi);
Packit 13e616
	extended = p_pi->capability_mask & IB_PORT_CAP_HAS_EXT_SPEEDS;
Packit 13e616
	rate = ib_port_info_compute_rate(p_pi, extended);
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   Mellanox Tavor device performance is better using 1K MTU.
Packit 13e616
	   If required MTU and MTU selector are such that 1K is OK
Packit 13e616
	   and at least one end of the path is Tavor we override the
Packit 13e616
	   port MTU with 1K.
Packit 13e616
	 */
Packit 13e616
	if (sa->p_subn->opt.enable_quirks &&
Packit 13e616
	    sa_path_rec_apply_tavor_mtu_limit(p_pr,
Packit 13e616
					      p_src_alias_guid->p_base_port,
Packit 13e616
					      p_dest_alias_guid->p_base_port,
Packit 13e616
					      comp_mask))
Packit 13e616
		if (mtu > IB_MTU_LEN_1024) {
Packit 13e616
			mtu = IB_MTU_LEN_1024;
Packit 13e616
			OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit 13e616
				"Optimized Path MTU to 1K for Mellanox Tavor device\n");
Packit 13e616
		}
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   Walk the subnet object from source to destination,
Packit 13e616
	   tracking the most restrictive rate and mtu values along the way...
Packit 13e616
Packit 13e616
	   If source port node is a switch, then p_physp should
Packit 13e616
	   point to the port that routes the destination lid
Packit 13e616
	 */
Packit 13e616
Packit 13e616
	p_node = osm_physp_get_node_ptr(p_physp);
Packit 13e616
Packit 13e616
	if (p_node->sw) {
Packit 13e616
		/*
Packit 13e616
		 * Source node is a switch.
Packit 13e616
		 * Make sure that p_physp points to the out port of the
Packit 13e616
		 * switch that routes to the destination lid (dest_lid_ho)
Packit 13e616
		 */
Packit 13e616
		p_physp = osm_switch_get_route_by_lid(p_node->sw, dest_lid);
Packit 13e616
		if (p_physp == 0) {
Packit 13e616
			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F02: "
Packit 13e616
				"Cannot find routing from LID %u to LID %u on "
Packit 13e616
				"switch %s (GUID: 0x%016" PRIx64 ")\n",
Packit 13e616
				src_lid_ho, dest_lid_ho, p_node->print_desc,
Packit 13e616
				cl_ntoh64(osm_node_get_node_guid(p_node)));
Packit 13e616
			status = IB_NOT_FOUND;
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
	if (sa->p_subn->opt.qos) {
Packit 13e616
		/*
Packit 13e616
		 * Whether this node is switch or CA, the IN port for
Packit 13e616
		 * the sl2vl table is 0, because this is a source node.
Packit 13e616
		 */
Packit 13e616
		p_slvl_tbl = osm_physp_get_slvl_tbl(p_physp, 0);
Packit 13e616
Packit 13e616
		/* update valid SLs that still exist on this route */
Packit 13e616
		for (i = 0; i < IB_MAX_NUM_VLS; i++) {
Packit 13e616
			if (valid_sl_mask & (1 << i) &&
Packit 13e616
			    ib_slvl_table_get(p_slvl_tbl, i) == IB_DROP_VL)
Packit 13e616
				valid_sl_mask &= ~(1 << i);
Packit 13e616
		}
Packit 13e616
		if (!valid_sl_mask) {
Packit 13e616
			OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit 13e616
				"All the SLs lead to VL15 on this path\n");
Packit 13e616
			status = IB_NOT_FOUND;
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	 * Same as above
Packit 13e616
	 */
Packit 13e616
	p_node = osm_physp_get_node_ptr(p_dest_physp);
Packit 13e616
Packit 13e616
	if (p_node->sw) {
Packit 13e616
		/*
Packit 13e616
		 * if destination is switch, we want p_dest_physp to point to port 0
Packit 13e616
		 */
Packit 13e616
		p_dest_physp =
Packit 13e616
		    osm_switch_get_route_by_lid(p_node->sw, dest_lid);
Packit 13e616
Packit 13e616
		if (p_dest_physp == 0) {
Packit 13e616
			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F03: "
Packit 13e616
				"Can't find routing from LID %u to LID %u on "
Packit 13e616
				"switch %s (GUID: 0x%016" PRIx64 ")\n",
Packit 13e616
				src_lid_ho, dest_lid_ho, p_node->print_desc,
Packit 13e616
				cl_ntoh64(osm_node_get_node_guid(p_node)));
Packit 13e616
			status = IB_NOT_FOUND;
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	 * Now go through the path step by step
Packit 13e616
	 */
Packit 13e616
Packit 13e616
	while (p_physp != p_dest_physp) {
Packit 13e616
Packit 13e616
		int tmp_pnum = p_physp->port_num;
Packit 13e616
		p_node = osm_physp_get_node_ptr(p_physp);
Packit 13e616
		p_physp = osm_physp_get_remote(p_physp);
Packit 13e616
Packit 13e616
		if (p_physp == 0) {
Packit 13e616
			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F05: "
Packit 13e616
				"Can't find remote phys port of %s (GUID: "
Packit 13e616
				"0x%016"PRIx64") port %d "
Packit 13e616
				"while routing from LID %u to LID %u\n",
Packit 13e616
				p_node->print_desc,
Packit 13e616
				cl_ntoh64(osm_node_get_node_guid(p_node)),
Packit 13e616
				tmp_pnum, src_lid_ho, dest_lid_ho);
Packit 13e616
			status = IB_ERROR;
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
Packit 13e616
		in_port_num = osm_physp_get_port_num(p_physp);
Packit 13e616
Packit 13e616
		/*
Packit 13e616
		   This is point to point case (no switch in between)
Packit 13e616
		 */
Packit 13e616
		if (p_physp == p_dest_physp)
Packit 13e616
			break;
Packit 13e616
Packit 13e616
		p_node = osm_physp_get_node_ptr(p_physp);
Packit 13e616
Packit 13e616
		if (!p_node->sw) {
Packit 13e616
			/*
Packit 13e616
			   There is some sort of problem in the subnet object!
Packit 13e616
			   If this isn't a switch, we should have reached
Packit 13e616
			   the destination by now!
Packit 13e616
			 */
Packit 13e616
			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F06: "
Packit 13e616
				"Internal error, bad path while routing "
Packit 13e616
				"%s (GUID: 0x%016"PRIx64") port %d to "
Packit 13e616
				"%s (GUID: 0x%016"PRIx64") port %d; "
Packit 13e616
				"ended at %s port %d\n",
Packit 13e616
				p_src_alias_guid->p_base_port->p_node->print_desc,
Packit 13e616
				cl_ntoh64(p_src_alias_guid->p_base_port->p_node->node_info.node_guid),
Packit 13e616
				p_src_alias_guid->p_base_port->p_physp->port_num,
Packit 13e616
				p_dest_alias_guid->p_base_port->p_node->print_desc,
Packit 13e616
				cl_ntoh64(p_dest_alias_guid->p_base_port->p_node->node_info.node_guid),
Packit 13e616
				p_dest_alias_guid->p_base_port->p_physp->port_num,
Packit 13e616
				p_node->print_desc,
Packit 13e616
				p_physp->port_num);
Packit 13e616
			status = IB_ERROR;
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
Packit 13e616
		/*
Packit 13e616
		   Check parameters for the ingress port in this switch.
Packit 13e616
		 */
Packit 13e616
		p_pi = &p_physp->port_info;
Packit 13e616
Packit 13e616
		if (mtu > ib_port_info_get_mtu_cap(p_pi))
Packit 13e616
			mtu = ib_port_info_get_mtu_cap(p_pi);
Packit 13e616
Packit 13e616
		p_physp0 = osm_node_get_physp_ptr((osm_node_t *)p_node, 0);
Packit 13e616
		p_pi0 = &p_physp0->port_info;
Packit 13e616
		p0_extended = p_pi0->capability_mask & IB_PORT_CAP_HAS_EXT_SPEEDS;
Packit 13e616
		p0_extended_rate = ib_port_info_compute_rate(p_pi, p0_extended);
Packit 13e616
		if (ib_path_compare_rates(rate, p0_extended_rate) > 0)
Packit 13e616
			rate = p0_extended_rate;
Packit 13e616
Packit 13e616
		/*
Packit 13e616
		   Continue with the egress port on this switch.
Packit 13e616
		 */
Packit 13e616
		p_physp = osm_switch_get_route_by_lid(p_node->sw, dest_lid);
Packit 13e616
		if (p_physp == 0) {
Packit 13e616
			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F07: "
Packit 13e616
				"Dead end path on switch "
Packit 13e616
				"%s (GUID: 0x%016"PRIx64") to LID %u\n",
Packit 13e616
				p_node->print_desc,
Packit 13e616
				cl_ntoh64(osm_node_get_node_guid(p_node)),
Packit 13e616
				dest_lid_ho);
Packit 13e616
			status = IB_ERROR;
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
Packit 13e616
		p_pi = &p_physp->port_info;
Packit 13e616
Packit 13e616
		if (mtu > ib_port_info_get_mtu_cap(p_pi))
Packit 13e616
			mtu = ib_port_info_get_mtu_cap(p_pi);
Packit 13e616
Packit 13e616
		p0_extended_rate = ib_port_info_compute_rate(p_pi, p0_extended);
Packit 13e616
		if (ib_path_compare_rates(rate, p0_extended_rate) > 0)
Packit 13e616
			rate = p0_extended_rate;
Packit 13e616
Packit 13e616
		if (sa->p_subn->opt.qos) {
Packit 13e616
			/*
Packit 13e616
			 * Check SL2VL table of the switch and update valid SLs
Packit 13e616
			 */
Packit 13e616
			p_slvl_tbl =
Packit 13e616
			    osm_physp_get_slvl_tbl(p_physp, in_port_num);
Packit 13e616
			for (i = 0; i < IB_MAX_NUM_VLS; i++) {
Packit 13e616
				if (valid_sl_mask & (1 << i) &&
Packit 13e616
				    ib_slvl_table_get(p_slvl_tbl,
Packit 13e616
						      i) == IB_DROP_VL)
Packit 13e616
					valid_sl_mask &= ~(1 << i);
Packit 13e616
			}
Packit 13e616
			if (!valid_sl_mask) {
Packit 13e616
				OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "All the SLs "
Packit 13e616
					"lead to VL15 on this path\n");
Packit 13e616
				status = IB_NOT_FOUND;
Packit 13e616
				goto Exit;
Packit 13e616
			}
Packit 13e616
		}
Packit 13e616
Packit 13e616
		/* update number of hops traversed */
Packit 13e616
		hops++;
Packit 13e616
		if (hops > MAX_HOPS) {
Packit 13e616
			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F25: "
Packit 13e616
				"Path from GUID 0x%016" PRIx64 " (%s port %d) "
Packit 13e616
				"to lid %u GUID 0x%016" PRIx64 " (%s port %d) "
Packit 13e616
				"needs more than %d hops, max %d hops allowed\n",
Packit 13e616
				cl_ntoh64(osm_physp_get_port_guid(p_src_physp)),
Packit 13e616
				p_src_physp->p_node->print_desc,
Packit 13e616
				p_src_physp->port_num,
Packit 13e616
				dest_lid_ho,
Packit 13e616
				cl_ntoh64(osm_physp_get_port_guid
Packit 13e616
					  (p_dest_physp)),
Packit 13e616
				p_dest_physp->p_node->print_desc,
Packit 13e616
				p_dest_physp->port_num,
Packit 13e616
				hops,
Packit 13e616
				MAX_HOPS);
Packit 13e616
			status = IB_NOT_FOUND;
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   p_physp now points to the destination
Packit 13e616
	 */
Packit 13e616
	p_pi = &p_physp->port_info;
Packit 13e616
Packit 13e616
	if (mtu > ib_port_info_get_mtu_cap(p_pi))
Packit 13e616
		mtu = ib_port_info_get_mtu_cap(p_pi);
Packit 13e616
Packit 13e616
	extended = p_pi->capability_mask & IB_PORT_CAP_HAS_EXT_SPEEDS;
Packit 13e616
	dest_rate = ib_port_info_compute_rate(p_pi, extended);
Packit 13e616
	if (ib_path_compare_rates(rate, dest_rate) > 0)
Packit 13e616
		rate = dest_rate;
Packit 13e616
Packit 13e616
	OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit 13e616
		"Path min MTU = %u, min rate = %u\n", mtu, rate);
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	 * Get QoS Level object according to the path request
Packit 13e616
	 * and adjust path parameters according to QoS settings
Packit 13e616
	 */
Packit 13e616
	if (sa->p_subn->opt.qos &&
Packit 13e616
	    sa->p_subn->p_qos_policy &&
Packit 13e616
	    (p_qos_level =
Packit 13e616
	     osm_qos_policy_get_qos_level_by_pr(sa->p_subn->p_qos_policy,
Packit 13e616
						p_pr, p_src_physp, p_dest_physp,
Packit 13e616
						comp_mask))) {
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit 13e616
			"PathRecord request matches QoS Level '%s' (%s)\n",
Packit 13e616
			p_qos_level->name, p_qos_level->use ?
Packit 13e616
			p_qos_level->use : "no description");
Packit 13e616
Packit 13e616
		if (p_qos_level->mtu_limit_set
Packit 13e616
		    && (mtu > p_qos_level->mtu_limit))
Packit 13e616
			mtu = p_qos_level->mtu_limit;
Packit 13e616
Packit 13e616
		if (p_qos_level->rate_limit_set
Packit 13e616
		    && (ib_path_compare_rates(rate, p_qos_level->rate_limit) > 0))
Packit 13e616
			rate = p_qos_level->rate_limit;
Packit 13e616
Packit 13e616
		if (p_qos_level->sl_set) {
Packit 13e616
			sl = p_qos_level->sl;
Packit 13e616
			if (!(valid_sl_mask & (1 << sl))) {
Packit 13e616
				status = IB_NOT_FOUND;
Packit 13e616
				goto Exit;
Packit 13e616
			}
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	 * Set packet lifetime.
Packit 13e616
	 * According to spec definition IBA 1.2 Table 205
Packit 13e616
	 * PacketLifeTime description, for loopback paths,
Packit 13e616
	 * packetLifeTime shall be zero.
Packit 13e616
	 */
Packit 13e616
	if (p_src_alias_guid->p_base_port == p_dest_alias_guid->p_base_port)
Packit 13e616
		pkt_life = 0;
Packit 13e616
	else if (p_qos_level && p_qos_level->pkt_life_set)
Packit 13e616
		pkt_life = p_qos_level->pkt_life;
Packit 13e616
	else
Packit 13e616
		pkt_life = sa->p_subn->opt.subnet_timeout;
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   Determine if these values meet the user criteria
Packit 13e616
	   and adjust appropriately
Packit 13e616
	 */
Packit 13e616
Packit 13e616
	/* we silently ignore cases where only the MTU selector is defined */
Packit 13e616
	if ((comp_mask & IB_PR_COMPMASK_MTUSELEC) &&
Packit 13e616
	    (comp_mask & IB_PR_COMPMASK_MTU)) {
Packit 13e616
		required_mtu = ib_path_rec_mtu(p_pr);
Packit 13e616
		switch (ib_path_rec_mtu_sel(p_pr)) {
Packit 13e616
		case 0:	/* must be greater than */
Packit 13e616
			if (mtu <= required_mtu)
Packit 13e616
				status = IB_NOT_FOUND;
Packit 13e616
			break;
Packit 13e616
Packit 13e616
		case 1:	/* must be less than */
Packit 13e616
			if (mtu >= required_mtu) {
Packit 13e616
				/* adjust to use the highest mtu
Packit 13e616
				   lower than the required one */
Packit 13e616
				if (required_mtu > 1)
Packit 13e616
					mtu = required_mtu - 1;
Packit 13e616
				else
Packit 13e616
					status = IB_NOT_FOUND;
Packit 13e616
			}
Packit 13e616
			break;
Packit 13e616
Packit 13e616
		case 2:	/* exact match */
Packit 13e616
			if (mtu < required_mtu)
Packit 13e616
				status = IB_NOT_FOUND;
Packit 13e616
			else
Packit 13e616
				mtu = required_mtu;
Packit 13e616
			break;
Packit 13e616
Packit 13e616
		case 3:	/* largest available */
Packit 13e616
			/* can't be disqualified by this one */
Packit 13e616
			break;
Packit 13e616
Packit 13e616
		default:
Packit 13e616
			/* if we're here, there's a bug in ib_path_rec_mtu_sel() */
Packit 13e616
			CL_ASSERT(FALSE);
Packit 13e616
			status = IB_ERROR;
Packit 13e616
			break;
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
	if (status != IB_SUCCESS)
Packit 13e616
		goto Exit;
Packit 13e616
Packit 13e616
	/* we silently ignore cases where only the Rate selector is defined */
Packit 13e616
	if ((comp_mask & IB_PR_COMPMASK_RATESELEC) &&
Packit 13e616
	    (comp_mask & IB_PR_COMPMASK_RATE)) {
Packit 13e616
		required_rate = ib_path_rec_rate(p_pr);
Packit 13e616
		switch (ib_path_rec_rate_sel(p_pr)) {
Packit 13e616
		case 0:	/* must be greater than */
Packit 13e616
			if (ib_path_compare_rates(rate, required_rate) <= 0)
Packit 13e616
				status = IB_NOT_FOUND;
Packit 13e616
			break;
Packit 13e616
Packit 13e616
		case 1:	/* must be less than */
Packit 13e616
			if (ib_path_compare_rates(rate, required_rate) >= 0) {
Packit 13e616
				/* adjust the rate to use the highest rate
Packit 13e616
				   lower than the required one */
Packit 13e616
				rate = ib_path_rate_get_prev(required_rate);
Packit 13e616
				if (!rate)
Packit 13e616
					status = IB_NOT_FOUND;
Packit 13e616
			}
Packit 13e616
			break;
Packit 13e616
Packit 13e616
		case 2:	/* exact match */
Packit 13e616
			if (ib_path_compare_rates(rate, required_rate))
Packit 13e616
				status = IB_NOT_FOUND;
Packit 13e616
			else
Packit 13e616
				rate = required_rate;
Packit 13e616
			break;
Packit 13e616
Packit 13e616
		case 3:	/* largest available */
Packit 13e616
			/* can't be disqualified by this one */
Packit 13e616
			break;
Packit 13e616
Packit 13e616
		default:
Packit 13e616
			/* if we're here, there's a bug in ib_path_rec_mtu_sel() */
Packit 13e616
			CL_ASSERT(FALSE);
Packit 13e616
			status = IB_ERROR;
Packit 13e616
			break;
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
	if (status != IB_SUCCESS)
Packit 13e616
		goto Exit;
Packit 13e616
Packit 13e616
	/* we silently ignore cases where only the PktLife selector is defined */
Packit 13e616
	if ((comp_mask & IB_PR_COMPMASK_PKTLIFETIMESELEC) &&
Packit 13e616
	    (comp_mask & IB_PR_COMPMASK_PKTLIFETIME)) {
Packit 13e616
		required_pkt_life = ib_path_rec_pkt_life(p_pr);
Packit 13e616
		switch (ib_path_rec_pkt_life_sel(p_pr)) {
Packit 13e616
		case 0:	/* must be greater than */
Packit 13e616
			if (pkt_life <= required_pkt_life)
Packit 13e616
				status = IB_NOT_FOUND;
Packit 13e616
			break;
Packit 13e616
Packit 13e616
		case 1:	/* must be less than */
Packit 13e616
			if (pkt_life >= required_pkt_life) {
Packit 13e616
				/* adjust the lifetime to use the highest possible
Packit 13e616
				   lower than the required one */
Packit 13e616
				if (required_pkt_life > 1)
Packit 13e616
					pkt_life = required_pkt_life - 1;
Packit 13e616
				else
Packit 13e616
					status = IB_NOT_FOUND;
Packit 13e616
			}
Packit 13e616
			break;
Packit 13e616
Packit 13e616
		case 2:	/* exact match */
Packit 13e616
			if (pkt_life < required_pkt_life)
Packit 13e616
				status = IB_NOT_FOUND;
Packit 13e616
			else
Packit 13e616
				pkt_life = required_pkt_life;
Packit 13e616
			break;
Packit 13e616
Packit 13e616
		case 3:	/* smallest available */
Packit 13e616
			/* can't be disqualified by this one */
Packit 13e616
			break;
Packit 13e616
Packit 13e616
		default:
Packit 13e616
			/* if we're here, there's a bug in ib_path_rec_pkt_life_sel() */
Packit 13e616
			CL_ASSERT(FALSE);
Packit 13e616
			status = IB_ERROR;
Packit 13e616
			break;
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
	if (status != IB_SUCCESS)
Packit 13e616
		goto Exit;
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	 * set Pkey for this path record request
Packit 13e616
	 */
Packit 13e616
Packit 13e616
	if ((comp_mask & IB_PR_COMPMASK_RAWTRAFFIC) &&
Packit 13e616
	    (cl_ntoh32(p_pr->hop_flow_raw) & (1 << 31)))
Packit 13e616
		pkey = osm_physp_find_common_pkey(p_src_physp, p_dest_physp,
Packit 13e616
						  sa->p_subn->opt.allow_both_pkeys);
Packit 13e616
Packit 13e616
	else if (comp_mask & IB_PR_COMPMASK_PKEY) {
Packit 13e616
		/*
Packit 13e616
		 * PR request has a specific pkey:
Packit 13e616
		 * Check that source and destination share this pkey.
Packit 13e616
		 * If QoS level has pkeys, check that this pkey exists
Packit 13e616
		 * in the QoS level pkeys.
Packit 13e616
		 * PR returned pkey is the requested pkey.
Packit 13e616
		 */
Packit 13e616
		pkey = p_pr->pkey;
Packit 13e616
		if (!osm_physp_share_this_pkey(p_src_physp, p_dest_physp, pkey,
Packit 13e616
					       sa->p_subn->opt.allow_both_pkeys)) {
Packit 13e616
			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F1A: "
Packit 13e616
				"Ports 0x%016" PRIx64 " (%s port %d) and "
Packit 13e616
				"0x%016" PRIx64 " (%s port %d) "
Packit 13e616
				"do not share specified PKey 0x%04x\n",
Packit 13e616
				cl_ntoh64(osm_physp_get_port_guid(p_src_physp)),
Packit 13e616
				p_src_physp->p_node->print_desc,
Packit 13e616
				p_src_physp->port_num,
Packit 13e616
				cl_ntoh64(osm_physp_get_port_guid
Packit 13e616
					  (p_dest_physp)),
Packit 13e616
				p_dest_physp->p_node->print_desc,
Packit 13e616
				p_dest_physp->port_num,
Packit 13e616
				cl_ntoh16(pkey));
Packit 13e616
			status = IB_NOT_FOUND;
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
		if (p_qos_level && p_qos_level->pkey_range_len &&
Packit 13e616
		    !osm_qos_level_has_pkey(p_qos_level, pkey)) {
Packit 13e616
			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F1D: "
Packit 13e616
				"QoS level \"%s\" doesn't define specified PKey 0x%04x "
Packit 13e616
				"for ports 0x%016" PRIx64 " (%s port %d) and "
Packit 13e616
				"0x%016"PRIx64" (%s port %d)\n",
Packit 13e616
				p_qos_level->name,
Packit 13e616
				cl_ntoh16(pkey),
Packit 13e616
				cl_ntoh64(osm_physp_get_port_guid(p_src_physp)),
Packit 13e616
				p_src_physp->p_node->print_desc,
Packit 13e616
				p_src_alias_guid->p_base_port->p_physp->port_num,
Packit 13e616
				cl_ntoh64(osm_physp_get_port_guid
Packit 13e616
					  (p_dest_physp)),
Packit 13e616
				p_dest_physp->p_node->print_desc,
Packit 13e616
				p_dest_alias_guid->p_base_port->p_physp->port_num);
Packit 13e616
			status = IB_NOT_FOUND;
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
Packit 13e616
	} else if (p_qos_level && p_qos_level->pkey_range_len) {
Packit 13e616
		/*
Packit 13e616
		 * PR request doesn't have a specific pkey, but QoS level
Packit 13e616
		 * has pkeys - get shared pkey from QoS level pkeys
Packit 13e616
		 */
Packit 13e616
		pkey = osm_qos_level_get_shared_pkey(p_qos_level,
Packit 13e616
						     p_src_physp, p_dest_physp,
Packit 13e616
						     sa->p_subn->opt.allow_both_pkeys);
Packit 13e616
		if (!pkey) {
Packit 13e616
			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F1E: "
Packit 13e616
				"Ports 0x%016" PRIx64 " (%s) and "
Packit 13e616
				"0x%016" PRIx64 " (%s) do not share "
Packit 13e616
				"PKeys defined by QoS level \"%s\"\n",
Packit 13e616
				cl_ntoh64(osm_physp_get_port_guid(p_src_physp)),
Packit 13e616
				p_src_physp->p_node->print_desc,
Packit 13e616
				cl_ntoh64(osm_physp_get_port_guid
Packit 13e616
					  (p_dest_physp)),
Packit 13e616
				p_dest_physp->p_node->print_desc,
Packit 13e616
				p_qos_level->name);
Packit 13e616
			status = IB_NOT_FOUND;
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
	} else {
Packit 13e616
		/*
Packit 13e616
		 * Neither PR request nor QoS level have pkey.
Packit 13e616
		 * Just get any shared pkey.
Packit 13e616
		 */
Packit 13e616
		pkey = osm_physp_find_common_pkey(p_src_physp, p_dest_physp,
Packit 13e616
						  sa->p_subn->opt.allow_both_pkeys);
Packit 13e616
		if (!pkey) {
Packit 13e616
			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F1B: "
Packit 13e616
				"Ports src 0x%016"PRIx64" (%s port %d) and "
Packit 13e616
				"dst 0x%016"PRIx64" (%s port %d) do not have "
Packit 13e616
				"any shared PKeys\n",
Packit 13e616
				cl_ntoh64(osm_physp_get_port_guid(p_src_physp)),
Packit 13e616
				p_src_physp->p_node->print_desc,
Packit 13e616
				p_src_physp->port_num,
Packit 13e616
				cl_ntoh64(osm_physp_get_port_guid
Packit 13e616
					  (p_dest_physp)),
Packit 13e616
				p_dest_physp->p_node->print_desc,
Packit 13e616
				p_dest_physp->port_num);
Packit 13e616
			status = IB_NOT_FOUND;
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
	if (pkey) {
Packit 13e616
		p_prtn =
Packit 13e616
		    (osm_prtn_t *) cl_qmap_get(&sa->p_subn->prtn_pkey_tbl,
Packit 13e616
					       pkey & cl_hton16((uint16_t) ~
Packit 13e616
								0x8000));
Packit 13e616
		if (p_prtn ==
Packit 13e616
		    (osm_prtn_t *) cl_qmap_end(&sa->p_subn->prtn_pkey_tbl))
Packit 13e616
			p_prtn = NULL;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	 * Set PathRecord SL
Packit 13e616
	 */
Packit 13e616
Packit 13e616
	if (comp_mask & IB_PR_COMPMASK_SL) {
Packit 13e616
		/*
Packit 13e616
		 * Specific SL was requested
Packit 13e616
		 */
Packit 13e616
		sl = ib_path_rec_sl(p_pr);
Packit 13e616
Packit 13e616
		if (p_qos_level && p_qos_level->sl_set
Packit 13e616
		    && (p_qos_level->sl != sl)) {
Packit 13e616
			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F1F: "
Packit 13e616
				"QoS constraints: required PathRecord SL (%u) "
Packit 13e616
				"doesn't match QoS policy \"%s\" SL (%u) "
Packit 13e616
				"[%s port %d <-> %s port %d]\n", sl,
Packit 13e616
				p_qos_level->name,
Packit 13e616
				p_qos_level->sl,
Packit 13e616
				p_src_alias_guid->p_base_port->p_node->print_desc,
Packit 13e616
				p_src_alias_guid->p_base_port->p_physp->port_num,
Packit 13e616
				p_dest_alias_guid->p_base_port->p_node->print_desc,
Packit 13e616
				p_dest_alias_guid->p_base_port->p_physp->port_num);
Packit 13e616
			status = IB_NOT_FOUND;
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
Packit 13e616
	} else if (p_qos_level && p_qos_level->sl_set) {
Packit 13e616
		/*
Packit 13e616
		 * No specific SL was requested, but there is an SL in
Packit 13e616
		 * QoS level.
Packit 13e616
		 */
Packit 13e616
		sl = p_qos_level->sl;
Packit 13e616
Packit 13e616
		if (pkey && p_prtn && p_prtn->sl != p_qos_level->sl)
Packit 13e616
			OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit 13e616
				"QoS level SL (%u) overrides partition SL (%u)\n",
Packit 13e616
				p_qos_level->sl, p_prtn->sl);
Packit 13e616
Packit 13e616
	} else if (pkey) {
Packit 13e616
		/*
Packit 13e616
		 * No specific SL in request or in QoS level - use partition SL
Packit 13e616
		 */
Packit 13e616
		if (!p_prtn) {
Packit 13e616
			sl = OSM_DEFAULT_SL;
Packit 13e616
			/* this may be possible when pkey tables are created somehow in
Packit 13e616
			   previous runs or things are going wrong here */
Packit 13e616
			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F1C: "
Packit 13e616
				"No partition found for PKey 0x%04x - "
Packit 13e616
				"using default SL %d "
Packit 13e616
				"[%s port %d <-> %s port %d]\n",
Packit 13e616
				cl_ntoh16(pkey), sl,
Packit 13e616
				p_src_alias_guid->p_base_port->p_node->print_desc,
Packit 13e616
				p_src_alias_guid->p_base_port->p_physp->port_num,
Packit 13e616
				p_dest_alias_guid->p_base_port->p_node->print_desc,
Packit 13e616
				p_dest_alias_guid->p_base_port->p_physp->port_num);
Packit 13e616
		} else
Packit 13e616
			sl = p_prtn->sl;
Packit 13e616
	} else if (sa->p_subn->opt.qos) {
Packit 13e616
		if (valid_sl_mask & (1 << OSM_DEFAULT_SL))
Packit 13e616
			sl = OSM_DEFAULT_SL;
Packit 13e616
		else {
Packit 13e616
			for (i = 0; i < IB_MAX_NUM_VLS; i++)
Packit 13e616
				if (valid_sl_mask & (1 << i))
Packit 13e616
					break;
Packit 13e616
			sl = i;
Packit 13e616
		}
Packit 13e616
	} else
Packit 13e616
		sl = OSM_DEFAULT_SL;
Packit 13e616
Packit 13e616
	if (sa->p_subn->opt.qos && !(valid_sl_mask & (1 << sl))) {
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F24: "
Packit 13e616
			"Selected SL (%u) leads to VL15 "
Packit 13e616
			"[%s port %d <-> %s port %d]\n",
Packit 13e616
			sl,
Packit 13e616
			p_src_alias_guid->p_base_port->p_node->print_desc,
Packit 13e616
			p_src_alias_guid->p_base_port->p_physp->port_num,
Packit 13e616
			p_dest_alias_guid->p_base_port->p_node->print_desc,
Packit 13e616
			p_dest_alias_guid->p_base_port->p_physp->port_num);
Packit 13e616
		status = IB_NOT_FOUND;
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	 * If the routing engine wants to have a say in path SL selection,
Packit 13e616
	 * send the currently computed SL value as a hint and let the routing
Packit 13e616
	 * engine override it.
Packit 13e616
	 */
Packit 13e616
	if (p_re && p_re->path_sl) {
Packit 13e616
		uint8_t pr_sl;
Packit 13e616
		pr_sl = sl;
Packit 13e616
Packit 13e616
		sl = p_re->path_sl(p_re->context, sl,
Packit 13e616
				   cl_hton16(src_lid_ho), cl_hton16(dest_lid_ho));
Packit 13e616
Packit 13e616
		if ((comp_mask & IB_PR_COMPMASK_SL) && (sl != pr_sl)) {
Packit 13e616
			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F2A: "
Packit 13e616
				"Requested SL (%u) doesn't match SL calculated"
Packit 13e616
				"by routing engine (%u) "
Packit 13e616
				"[%s port %d <-> %s port %d]\n",
Packit 13e616
				pr_sl,
Packit 13e616
				sl,
Packit 13e616
				p_src_alias_guid->p_base_port->p_node->print_desc,
Packit 13e616
				p_src_alias_guid->p_base_port->p_physp->port_num,
Packit 13e616
				p_dest_alias_guid->p_base_port->p_node->print_desc,
Packit 13e616
				p_dest_alias_guid->p_base_port->p_physp->port_num);
Packit 13e616
			status = IB_NOT_FOUND;
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
	/* reset pkey when raw traffic */
Packit 13e616
	if (comp_mask & IB_PR_COMPMASK_RAWTRAFFIC &&
Packit 13e616
	    cl_ntoh32(p_pr->hop_flow_raw) & (1 << 31))
Packit 13e616
		pkey = 0;
Packit 13e616
Packit 13e616
	p_parms->mtu = mtu;
Packit 13e616
	p_parms->rate = rate;
Packit 13e616
	p_parms->pkt_life = pkt_life;
Packit 13e616
	p_parms->pkey = pkey;
Packit 13e616
	p_parms->sl = sl;
Packit 13e616
Packit 13e616
	OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Path params: mtu = %u, rate = %u,"
Packit 13e616
		" packet lifetime = %u, pkey = 0x%04X, sl = %u\n",
Packit 13e616
		mtu, rate, pkt_life, cl_ntoh16(pkey), sl);
Packit 13e616
Exit:
Packit 13e616
	OSM_LOG_EXIT(sa->p_log);
Packit 13e616
	return status;
Packit 13e616
}
Packit 13e616
Packit 13e616
ib_api_status_t osm_get_path_params(IN osm_sa_t * sa,
Packit 13e616
				    IN const osm_port_t * p_src_port,
Packit 13e616
				    IN const uint16_t slid_ho,
Packit 13e616
				    IN const osm_port_t * p_dest_port,
Packit 13e616
				    IN const uint16_t dlid_ho,
Packit 13e616
				    OUT osm_path_parms_t * p_parms)
Packit 13e616
{
Packit 13e616
	osm_alias_guid_t *p_src_alias_guid, *p_dest_alias_guid;
Packit 13e616
	ib_path_rec_t pr;
Packit 13e616
Packit 13e616
	if (!p_src_port || !slid_ho || !p_dest_port || !dlid_ho)
Packit 13e616
		return IB_INVALID_PARAMETER;
Packit 13e616
Packit 13e616
	memset(&pr, 0, sizeof(ib_path_rec_t));
Packit 13e616
Packit 13e616
	p_src_alias_guid = osm_get_alias_guid_by_guid(sa->p_subn,
Packit 13e616
						      osm_port_get_guid(p_src_port));
Packit 13e616
	p_dest_alias_guid = osm_get_alias_guid_by_guid(sa->p_subn,
Packit 13e616
						       osm_port_get_guid(p_dest_port));
Packit 13e616
	return pr_rcv_get_path_parms(sa, &pr,
Packit 13e616
				     p_src_alias_guid, slid_ho,
Packit 13e616
				     p_dest_alias_guid, dlid_ho, 0, p_parms);
Packit 13e616
}
Packit 13e616
Packit 13e616
static void pr_rcv_build_pr(IN osm_sa_t * sa,
Packit 13e616
			    IN const osm_alias_guid_t * p_src_alias_guid,
Packit 13e616
			    IN const osm_alias_guid_t * p_dest_alias_guid,
Packit 13e616
			    IN const ib_gid_t * p_sgid,
Packit 13e616
			    IN const ib_gid_t * p_dgid,
Packit 13e616
			    IN const uint16_t src_lid_ho,
Packit 13e616
			    IN const uint16_t dest_lid_ho,
Packit 13e616
			    IN const uint8_t preference,
Packit 13e616
			    IN const osm_path_parms_t * p_parms,
Packit 13e616
			    OUT ib_path_rec_t * p_pr)
Packit 13e616
{
Packit 13e616
	const osm_physp_t *p_src_physp = NULL, *p_dest_physp = NULL;
Packit 13e616
	osm_port_t *p_port;
Packit 13e616
	uint8_t rate, new_rate;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(sa->p_log);
Packit 13e616
Packit 13e616
	if (p_dgid)
Packit 13e616
		p_pr->dgid = *p_dgid;
Packit 13e616
	else {
Packit 13e616
		p_dest_physp = p_dest_alias_guid->p_base_port->p_physp;
Packit 13e616
Packit 13e616
		p_pr->dgid.unicast.prefix =
Packit 13e616
		    osm_physp_get_subnet_prefix(p_dest_physp);
Packit 13e616
		p_pr->dgid.unicast.interface_id = p_dest_alias_guid->alias_guid;
Packit 13e616
	}
Packit 13e616
	if (p_sgid)
Packit 13e616
		p_pr->sgid = *p_sgid;
Packit 13e616
	else {
Packit 13e616
		p_src_physp = p_src_alias_guid->p_base_port->p_physp;
Packit 13e616
Packit 13e616
		p_pr->sgid.unicast.prefix = osm_physp_get_subnet_prefix(p_src_physp);
Packit 13e616
		p_pr->sgid.unicast.interface_id = p_src_alias_guid->alias_guid;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	p_pr->dlid = cl_hton16(dest_lid_ho);
Packit 13e616
	p_pr->slid = cl_hton16(src_lid_ho);
Packit 13e616
Packit 13e616
	p_pr->hop_flow_raw &= cl_hton32(1 << 31);
Packit 13e616
Packit 13e616
	/* Only set HopLimit if going through a router */
Packit 13e616
	if (p_dgid)
Packit 13e616
		p_pr->hop_flow_raw |= cl_hton32(IB_HOPLIMIT_MAX);
Packit 13e616
Packit 13e616
	p_pr->pkey = p_parms->pkey;
Packit 13e616
	ib_path_rec_set_sl(p_pr, p_parms->sl);
Packit 13e616
	ib_path_rec_set_qos_class(p_pr, 0);
Packit 13e616
	p_pr->mtu = (uint8_t) (p_parms->mtu | 0x80);
Packit 13e616
	rate = p_parms->rate;
Packit 13e616
	if (sa->p_subn->opt.use_original_extended_sa_rates_only) {
Packit 13e616
		new_rate = ib_path_rate_max_12xedr(rate);
Packit 13e616
		if (new_rate != rate) {
Packit 13e616
			OSM_LOG(sa->p_log, OSM_LOG_VERBOSE,
Packit 13e616
				"Rate decreased from %u to %u\n",
Packit 13e616
				rate, new_rate);
Packit 13e616
			rate = new_rate;
Packit 13e616
		}
Packit 13e616
	} else if (rate >= IB_PATH_RECORD_RATE_28_GBS) {
Packit 13e616
		/*
Packit 13e616
		 * If one of the new 2x or HDR rates, make sure that
Packit 13e616
		 * src (and dest if reversible) ports support this
Packit 13e616
		 */
Packit 13e616
		if (p_src_physp == NULL) {
Packit 13e616
			p_port = osm_get_port_by_lid_ho(sa->p_subn, src_lid_ho);
Packit 13e616
			if (p_port)
Packit 13e616
				p_src_physp = p_port->p_physp;
Packit 13e616
		}
Packit 13e616
Packit 13e616
		if (p_src_physp)
Packit 13e616
			rate = ib_path_rate_2x_hdr_fixups(&p_src_physp->port_info, rate);
Packit 13e616
		if (p_parms->reversible) {
Packit 13e616
			if (p_dest_physp == NULL) {
Packit 13e616
				p_port = osm_get_port_by_lid_ho(sa->p_subn,
Packit 13e616
								dest_lid_ho);
Packit 13e616
				if (p_port)
Packit 13e616
					p_dest_physp = p_port->p_physp;
Packit 13e616
			}
Packit 13e616
			if (p_dest_physp)
Packit 13e616
				rate = ib_path_rate_2x_hdr_fixups(&p_dest_physp->port_info, rate);
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
	p_pr->rate = (uint8_t) (rate | 0x80);
Packit 13e616
Packit 13e616
	/* According to 1.2 spec definition Table 205 PacketLifeTime description,
Packit 13e616
	   for loopback paths, packetLifeTime shall be zero. */
Packit 13e616
	if (p_src_alias_guid->p_base_port == p_dest_alias_guid->p_base_port)
Packit 13e616
		p_pr->pkt_life = 0x80;	/* loopback */
Packit 13e616
	else
Packit 13e616
		p_pr->pkt_life = (uint8_t) (p_parms->pkt_life | 0x80);
Packit 13e616
Packit 13e616
	p_pr->preference = preference;
Packit 13e616
Packit 13e616
	/* always return num_path = 0 so this is only the reversible component */
Packit 13e616
	if (p_parms->reversible)
Packit 13e616
		p_pr->num_path = 0x80;
Packit 13e616
Packit 13e616
	OSM_LOG_EXIT(sa->p_log);
Packit 13e616
}
Packit 13e616
Packit 13e616
static osm_sa_item_t *pr_rcv_get_lid_pair_path(IN osm_sa_t * sa,
Packit 13e616
					       IN const ib_path_rec_t * p_pr,
Packit 13e616
					       IN const osm_alias_guid_t * p_src_alias_guid,
Packit 13e616
					       IN const osm_alias_guid_t * p_dest_alias_guid,
Packit 13e616
					       IN const ib_gid_t * p_sgid,
Packit 13e616
					       IN const ib_gid_t * p_dgid,
Packit 13e616
					       IN const uint16_t src_lid_ho,
Packit 13e616
					       IN const uint16_t dest_lid_ho,
Packit 13e616
					       IN const ib_net64_t comp_mask,
Packit 13e616
					       IN const uint8_t preference)
Packit 13e616
{
Packit 13e616
	osm_path_parms_t path_parms;
Packit 13e616
	osm_path_parms_t rev_path_parms;
Packit 13e616
	osm_sa_item_t *p_pr_item;
Packit 13e616
	ib_api_status_t status, rev_path_status;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(sa->p_log);
Packit 13e616
Packit 13e616
	OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Src LID %u, Dest LID %u\n",
Packit 13e616
		src_lid_ho, dest_lid_ho);
Packit 13e616
Packit 13e616
	p_pr_item = malloc(SA_PR_RESP_SIZE);
Packit 13e616
	if (p_pr_item == NULL) {
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F01: "
Packit 13e616
			"Unable to allocate path record\n");
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
	memset(p_pr_item, 0, SA_PR_RESP_SIZE);
Packit 13e616
Packit 13e616
	status = pr_rcv_get_path_parms(sa, p_pr, p_src_alias_guid, src_lid_ho,
Packit 13e616
				       p_dest_alias_guid, dest_lid_ho,
Packit 13e616
				       comp_mask, &path_parms);
Packit 13e616
Packit 13e616
	if (status != IB_SUCCESS) {
Packit 13e616
		free(p_pr_item);
Packit 13e616
		p_pr_item = NULL;
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/* now try the reversible path */
Packit 13e616
	rev_path_status = pr_rcv_get_path_parms(sa, p_pr, p_dest_alias_guid,
Packit 13e616
						dest_lid_ho, p_src_alias_guid,
Packit 13e616
						src_lid_ho, comp_mask,
Packit 13e616
						&rev_path_parms);
Packit 13e616
Packit 13e616
	path_parms.reversible = (rev_path_status == IB_SUCCESS);
Packit 13e616
Packit 13e616
	/* did we get a Reversible Path compmask ? */
Packit 13e616
	/*
Packit 13e616
	   NOTE that if the reversible component = 0, it is a don't care
Packit 13e616
	   rather than requiring non-reversible paths ...
Packit 13e616
	   see Vol1 Ver1.2 p900 l16
Packit 13e616
	 */
Packit 13e616
	if ((comp_mask & IB_PR_COMPMASK_REVERSIBLE) &&
Packit 13e616
	    !path_parms.reversible && (p_pr->num_path & 0x80)) {
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit 13e616
			"Requested reversible path but failed to get one\n");
Packit 13e616
		free(p_pr_item);
Packit 13e616
		p_pr_item = NULL;
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	pr_rcv_build_pr(sa, p_src_alias_guid, p_dest_alias_guid, p_sgid, p_dgid,
Packit 13e616
			src_lid_ho, dest_lid_ho, preference, &path_parms,
Packit 13e616
			&p_pr_item->resp.path_rec);
Packit 13e616
Packit 13e616
Exit:
Packit 13e616
	OSM_LOG_EXIT(sa->p_log);
Packit 13e616
	return p_pr_item;
Packit 13e616
}
Packit 13e616
Packit 13e616
static void pr_rcv_get_port_pair_paths(IN osm_sa_t * sa,
Packit 13e616
				       IN const ib_sa_mad_t *sa_mad,
Packit 13e616
				       IN const osm_port_t * p_req_port,
Packit 13e616
				       IN const osm_alias_guid_t * p_src_alias_guid,
Packit 13e616
				       IN const osm_alias_guid_t * p_dest_alias_guid,
Packit 13e616
				       IN const ib_gid_t * p_sgid,
Packit 13e616
				       IN const ib_gid_t * p_dgid,
Packit 13e616
				       IN cl_qlist_t * p_list)
Packit 13e616
{
Packit 13e616
	const ib_path_rec_t *p_pr = ib_sa_mad_get_payload_ptr(sa_mad);
Packit 13e616
	ib_net64_t comp_mask = sa_mad->comp_mask;
Packit 13e616
	osm_sa_item_t *p_pr_item;
Packit 13e616
	uint16_t src_lid_min_ho;
Packit 13e616
	uint16_t src_lid_max_ho;
Packit 13e616
	uint16_t dest_lid_min_ho;
Packit 13e616
	uint16_t dest_lid_max_ho;
Packit 13e616
	uint16_t src_lid_ho;
Packit 13e616
	uint16_t dest_lid_ho;
Packit 13e616
	uint32_t path_num;
Packit 13e616
	uint8_t preference;
Packit 13e616
	unsigned iterations, src_offset, dest_offset;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(sa->p_log);
Packit 13e616
Packit 13e616
	OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit 13e616
		"Src port 0x%016" PRIx64 ", Dst port 0x%016" PRIx64 "\n",
Packit 13e616
		cl_ntoh64(p_src_alias_guid->alias_guid),
Packit 13e616
		cl_ntoh64(p_dest_alias_guid->alias_guid));
Packit 13e616
Packit 13e616
	/* Check that the req_port, src_port and dest_port all share a
Packit 13e616
	   pkey. The check is done on the default physical port of the ports. */
Packit 13e616
	if (osm_port_share_pkey(sa->p_log, p_req_port,
Packit 13e616
				p_src_alias_guid->p_base_port,
Packit 13e616
				sa->p_subn->opt.allow_both_pkeys) == FALSE
Packit 13e616
	    || osm_port_share_pkey(sa->p_log, p_req_port,
Packit 13e616
				   p_dest_alias_guid->p_base_port,
Packit 13e616
				   sa->p_subn->opt.allow_both_pkeys) == FALSE
Packit 13e616
	    || osm_port_share_pkey(sa->p_log, p_src_alias_guid->p_base_port,
Packit 13e616
				   p_dest_alias_guid->p_base_port,
Packit 13e616
				   sa->p_subn->opt.allow_both_pkeys) == FALSE)
Packit 13e616
		/* One of the pairs doesn't share a pkey so the path is disqualified. */
Packit 13e616
		goto Exit;
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   We shouldn't be here if the paths are disqualified in some way...
Packit 13e616
	   Thus, we assume every possible connection is valid.
Packit 13e616
Packit 13e616
	   We desire to return high-quality paths first.
Packit 13e616
	   In OpenSM, higher quality means least overlap with other paths.
Packit 13e616
	   This is acheived in practice by returning paths with
Packit 13e616
	   different LID value on each end, which means these
Packit 13e616
	   paths are more redundant that paths with the same LID repeated
Packit 13e616
	   on one side.  For example, in OpenSM the paths between two
Packit 13e616
	   endpoints with LMC = 1 might be as follows:
Packit 13e616
Packit 13e616
	   Port A, LID 1 <-> Port B, LID 3
Packit 13e616
	   Port A, LID 1 <-> Port B, LID 4
Packit 13e616
	   Port A, LID 2 <-> Port B, LID 3
Packit 13e616
	   Port A, LID 2 <-> Port B, LID 4
Packit 13e616
Packit 13e616
	   The OpenSM unicast routing algorithms attempt to disperse each path
Packit 13e616
	   to as varied a physical path as is reasonable.  1<->3 and 1<->4 have
Packit 13e616
	   more physical overlap (hence less redundancy) than 1<->3 and 2<->4.
Packit 13e616
Packit 13e616
	   OpenSM ranks paths in three preference groups:
Packit 13e616
Packit 13e616
	   Preference Value    Description
Packit 13e616
	   ----------------    -------------------------------------------
Packit 13e616
	   0             Redundant in both directions with other
Packit 13e616
	   pref value = 0 paths
Packit 13e616
Packit 13e616
	   1             Redundant in one direction with other
Packit 13e616
	   pref value = 0 and pref value = 1 paths
Packit 13e616
Packit 13e616
	   2             Not redundant in either direction with
Packit 13e616
	   other paths
Packit 13e616
Packit 13e616
	   3-FF          Unused
Packit 13e616
Packit 13e616
	   SA clients don't need to know these details, only that the lower
Packit 13e616
	   preference paths are preferred, as stated in the spec.  The paths
Packit 13e616
	   may not actually be physically redundant depending on the topology
Packit 13e616
	   of the subnet, but the point of LMC > 0 is to offer redundancy,
Packit 13e616
	   so it is assumed that the subnet is physically appropriate for the
Packit 13e616
	   specified LMC value.  A more advanced implementation would inspect for
Packit 13e616
	   physical redundancy, but I'm not going to bother with that now.
Packit 13e616
	 */
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   Refine our search if the client specified end-point LIDs
Packit 13e616
	 */
Packit 13e616
	if (comp_mask & IB_PR_COMPMASK_DLID)
Packit 13e616
		dest_lid_max_ho = dest_lid_min_ho = cl_ntoh16(p_pr->dlid);
Packit 13e616
	else
Packit 13e616
		osm_port_get_lid_range_ho(p_dest_alias_guid->p_base_port,
Packit 13e616
					  &dest_lid_min_ho, &dest_lid_max_ho);
Packit 13e616
Packit 13e616
	if (comp_mask & IB_PR_COMPMASK_SLID)
Packit 13e616
		src_lid_max_ho = src_lid_min_ho = cl_ntoh16(p_pr->slid);
Packit 13e616
	else
Packit 13e616
		osm_port_get_lid_range_ho(p_src_alias_guid->p_base_port,
Packit 13e616
					  &src_lid_min_ho, &src_lid_max_ho);
Packit 13e616
Packit 13e616
	if (src_lid_min_ho == 0) {
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit 13e616
			"Obtained source LID of 0. No such LID possible "
Packit 13e616
			"(%s port %d)\n",
Packit 13e616
			p_src_alias_guid->p_base_port->p_node->print_desc,
Packit 13e616
			p_src_alias_guid->p_base_port->p_physp->port_num);
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	if (dest_lid_min_ho == 0) {
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit 13e616
			"Obtained destination LID of 0. No such LID possible "
Packit 13e616
			"(%s port %d)\n",
Packit 13e616
			p_dest_alias_guid->p_base_port->p_node->print_desc,
Packit 13e616
			p_dest_alias_guid->p_base_port->p_physp->port_num);
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit 13e616
		"Src LIDs [%u-%u], Dest LIDs [%u-%u]\n",
Packit 13e616
		src_lid_min_ho, src_lid_max_ho,
Packit 13e616
		dest_lid_min_ho, dest_lid_max_ho);
Packit 13e616
Packit 13e616
	src_lid_ho = src_lid_min_ho;
Packit 13e616
	dest_lid_ho = dest_lid_min_ho;
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   Preferred paths come first in OpenSM
Packit 13e616
	 */
Packit 13e616
	preference = 0;
Packit 13e616
	path_num = 0;
Packit 13e616
Packit 13e616
	/* If SubnAdmGet, assume NumbPaths 1 (1.2 erratum) */
Packit 13e616
	if (sa_mad->method == IB_MAD_METHOD_GET)
Packit 13e616
		iterations = 1;
Packit 13e616
	else if (comp_mask & IB_PR_COMPMASK_NUMBPATH)
Packit 13e616
		iterations = ib_path_rec_num_path(p_pr);
Packit 13e616
	else
Packit 13e616
		iterations = (unsigned) (-1);
Packit 13e616
Packit 13e616
	while (path_num < iterations) {
Packit 13e616
		/*
Packit 13e616
		   These paths are "fully redundant"
Packit 13e616
		 */
Packit 13e616
Packit 13e616
		p_pr_item = pr_rcv_get_lid_pair_path(sa, p_pr, p_src_alias_guid,
Packit 13e616
						     p_dest_alias_guid,
Packit 13e616
						     p_sgid, p_dgid,
Packit 13e616
						     src_lid_ho, dest_lid_ho,
Packit 13e616
						     comp_mask, preference);
Packit 13e616
Packit 13e616
		if (p_pr_item) {
Packit 13e616
			cl_qlist_insert_tail(p_list, &p_pr_item->list_item);
Packit 13e616
			++path_num;
Packit 13e616
		}
Packit 13e616
Packit 13e616
		if (++src_lid_ho > src_lid_max_ho)
Packit 13e616
			break;
Packit 13e616
Packit 13e616
		if (++dest_lid_ho > dest_lid_max_ho)
Packit 13e616
			break;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   Check if we've accumulated all the paths that the user cares to see
Packit 13e616
	 */
Packit 13e616
	if (path_num == iterations)
Packit 13e616
		goto Exit;
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   Don't bother reporting preference 1 paths for now.
Packit 13e616
	   It's more trouble than it's worth and can only occur
Packit 13e616
	   if ports have different LMC values, which isn't supported
Packit 13e616
	   by OpenSM right now anyway.
Packit 13e616
	 */
Packit 13e616
	preference = 2;
Packit 13e616
	src_lid_ho = src_lid_min_ho;
Packit 13e616
	dest_lid_ho = dest_lid_min_ho;
Packit 13e616
	src_offset = 0;
Packit 13e616
	dest_offset = 0;
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   Iterate over the remaining paths
Packit 13e616
	 */
Packit 13e616
	while (path_num < iterations) {
Packit 13e616
		dest_offset++;
Packit 13e616
		dest_lid_ho++;
Packit 13e616
Packit 13e616
		if (dest_lid_ho > dest_lid_max_ho) {
Packit 13e616
			src_offset++;
Packit 13e616
			src_lid_ho++;
Packit 13e616
Packit 13e616
			if (src_lid_ho > src_lid_max_ho)
Packit 13e616
				break;	/* done */
Packit 13e616
Packit 13e616
			dest_offset = 0;
Packit 13e616
			dest_lid_ho = dest_lid_min_ho;
Packit 13e616
		}
Packit 13e616
Packit 13e616
		/*
Packit 13e616
		   These paths are "fully non-redundant" with paths already
Packit 13e616
		   identified above and consequently not of much value.
Packit 13e616
Packit 13e616
		   Don't return paths we already identified above, as indicated
Packit 13e616
		   by the offset values being equal.
Packit 13e616
		 */
Packit 13e616
		if (src_offset == dest_offset)
Packit 13e616
			continue;	/* already reported */
Packit 13e616
Packit 13e616
		p_pr_item = pr_rcv_get_lid_pair_path(sa, p_pr, p_src_alias_guid,
Packit 13e616
						     p_dest_alias_guid, p_sgid,
Packit 13e616
						     p_dgid, src_lid_ho,
Packit 13e616
						     dest_lid_ho, comp_mask,
Packit 13e616
						     preference);
Packit 13e616
Packit 13e616
		if (p_pr_item) {
Packit 13e616
			cl_qlist_insert_tail(p_list, &p_pr_item->list_item);
Packit 13e616
			++path_num;
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
Exit:
Packit 13e616
	OSM_LOG_EXIT(sa->p_log);
Packit 13e616
}
Packit 13e616
Packit 13e616
/* Find the router port that is configured to handle this prefix, if any */
Packit 13e616
static ib_net64_t find_router(const osm_sa_t *sa, ib_net64_t prefix)
Packit 13e616
{
Packit 13e616
	osm_prefix_route_t *route = NULL;
Packit 13e616
	osm_router_t *rtr;
Packit 13e616
	cl_qlist_t *l = &sa->p_subn->prefix_routes_list;
Packit 13e616
	cl_list_item_t *i;
Packit 13e616
Packit 13e616
	OSM_LOG(sa->p_log, OSM_LOG_VERBOSE, "Non local DGID subnet prefix "
Packit 13e616
		"0x%016" PRIx64 "\n", cl_ntoh64(prefix));
Packit 13e616
Packit 13e616
	for (i = cl_qlist_head(l); i != cl_qlist_end(l); i = cl_qlist_next(i)) {
Packit 13e616
		osm_prefix_route_t *r = (osm_prefix_route_t *)i;
Packit 13e616
		if (!r->prefix || r->prefix == prefix) {
Packit 13e616
			route = r;
Packit 13e616
			break;
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
	if (!route)
Packit 13e616
		return 0;
Packit 13e616
Packit 13e616
	if (route->guid == 0) /* first router */
Packit 13e616
		rtr = (osm_router_t *) cl_qmap_head(&sa->p_subn->rtr_guid_tbl);
Packit 13e616
	else
Packit 13e616
		rtr = (osm_router_t *) cl_qmap_get(&sa->p_subn->rtr_guid_tbl,
Packit 13e616
						   route->guid);
Packit 13e616
Packit 13e616
	if (rtr == (osm_router_t *) cl_qmap_end(&sa->p_subn->rtr_guid_tbl))
Packit 13e616
		return 0;
Packit 13e616
Packit 13e616
	return osm_port_get_guid(osm_router_get_port_ptr(rtr));
Packit 13e616
}
Packit 13e616
Packit 13e616
ib_net16_t osm_pr_get_end_points(IN osm_sa_t * sa,
Packit 13e616
				 IN const ib_sa_mad_t *sa_mad,
Packit 13e616
				 OUT const osm_alias_guid_t ** pp_src_alias_guid,
Packit 13e616
				 OUT const osm_alias_guid_t ** pp_dest_alias_guid,
Packit 13e616
				 OUT const osm_port_t ** pp_src_port,
Packit 13e616
				 OUT const osm_port_t ** pp_dest_port,
Packit 13e616
				 OUT const ib_gid_t ** pp_sgid,
Packit 13e616
				 OUT const ib_gid_t ** pp_dgid)
Packit 13e616
{
Packit 13e616
	const ib_path_rec_t *p_pr = ib_sa_mad_get_payload_ptr(sa_mad);
Packit 13e616
	ib_net64_t comp_mask = sa_mad->comp_mask;
Packit 13e616
	ib_net64_t dest_guid;
Packit 13e616
	ib_net16_t sa_status = IB_SA_MAD_STATUS_SUCCESS;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(sa->p_log);
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   Determine what fields are valid and then get a pointer
Packit 13e616
	   to the source and destination port objects, if possible.
Packit 13e616
	 */
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   Check a few easy disqualifying cases up front before getting
Packit 13e616
	   into the endpoints.
Packit 13e616
	 */
Packit 13e616
Packit 13e616
	*pp_src_alias_guid = NULL;
Packit 13e616
	*pp_src_port = NULL;
Packit 13e616
	if (comp_mask & IB_PR_COMPMASK_SGID) {
Packit 13e616
		if (!ib_gid_is_link_local(&p_pr->sgid)) {
Packit 13e616
			if (ib_gid_get_subnet_prefix(&p_pr->sgid) !=
Packit 13e616
			    sa->p_subn->opt.subnet_prefix) {
Packit 13e616
				/*
Packit 13e616
				   This 'error' is the client's fault (bad gid)
Packit 13e616
				   so don't enter it as an error in our own log.
Packit 13e616
				   Return an error response to the client.
Packit 13e616
				 */
Packit 13e616
				OSM_LOG(sa->p_log, OSM_LOG_VERBOSE,
Packit 13e616
					"Non local SGID subnet prefix 0x%016"
Packit 13e616
					PRIx64 "\n",
Packit 13e616
					cl_ntoh64(p_pr->sgid.unicast.prefix));
Packit 13e616
				sa_status = IB_SA_MAD_STATUS_INVALID_GID;
Packit 13e616
				goto Exit;
Packit 13e616
			}
Packit 13e616
		}
Packit 13e616
Packit 13e616
		*pp_src_alias_guid = osm_get_alias_guid_by_guid(sa->p_subn,
Packit 13e616
								p_pr->sgid.unicast.interface_id);
Packit 13e616
		if (!*pp_src_alias_guid) {
Packit 13e616
			/*
Packit 13e616
			   This 'error' is the client's fault (bad gid) so
Packit 13e616
			   don't enter it as an error in our own log.
Packit 13e616
			   Return an error response to the client.
Packit 13e616
			 */
Packit 13e616
			OSM_LOG(sa->p_log, OSM_LOG_VERBOSE,
Packit 13e616
				"No source port with GUID 0x%016" PRIx64 "\n",
Packit 13e616
				cl_ntoh64(p_pr->sgid.unicast.interface_id));
Packit 13e616
			sa_status = IB_SA_MAD_STATUS_INVALID_GID;
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
		if (pp_sgid)
Packit 13e616
			*pp_sgid = &p_pr->sgid;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	if (comp_mask & IB_PR_COMPMASK_SLID) {
Packit 13e616
		*pp_src_port = osm_get_port_by_lid(sa->p_subn, p_pr->slid);
Packit 13e616
		if (!*pp_src_port) {
Packit 13e616
			/*
Packit 13e616
			   This 'error' is the client's fault (bad lid) so
Packit 13e616
			   don't enter it as an error in our own log.
Packit 13e616
			   Return an error response to the client.
Packit 13e616
			 */
Packit 13e616
			OSM_LOG(sa->p_log, OSM_LOG_VERBOSE, "No source port "
Packit 13e616
				"with LID %u\n", cl_ntoh16(p_pr->slid));
Packit 13e616
			sa_status = IB_SA_MAD_STATUS_NO_RECORDS;
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
	*pp_dest_alias_guid = NULL;
Packit 13e616
	*pp_dest_port = NULL;
Packit 13e616
	if (comp_mask & IB_PR_COMPMASK_DGID) {
Packit 13e616
		if (!ib_gid_is_link_local(&p_pr->dgid) &&
Packit 13e616
		    !ib_gid_is_multicast(&p_pr->dgid) &&
Packit 13e616
		    ib_gid_get_subnet_prefix(&p_pr->dgid) !=
Packit 13e616
		    sa->p_subn->opt.subnet_prefix) {
Packit 13e616
			dest_guid = find_router(sa, p_pr->dgid.unicast.prefix);
Packit 13e616
			if (!dest_guid) {
Packit 13e616
				char gid_str[INET6_ADDRSTRLEN];
Packit 13e616
				OSM_LOG(sa->p_log, OSM_LOG_VERBOSE,
Packit 13e616
					"Off subnet DGID %s, but router not "
Packit 13e616
					"found\n",
Packit 13e616
					inet_ntop(AF_INET6, p_pr->dgid.raw,
Packit 13e616
						  gid_str, sizeof(gid_str)));
Packit 13e616
				sa_status = IB_SA_MAD_STATUS_INVALID_GID;
Packit 13e616
				goto Exit;
Packit 13e616
			}
Packit 13e616
			if (pp_dgid)
Packit 13e616
				*pp_dgid = &p_pr->dgid;
Packit 13e616
		} else
Packit 13e616
			dest_guid = p_pr->dgid.unicast.interface_id;
Packit 13e616
Packit 13e616
		*pp_dest_alias_guid = osm_get_alias_guid_by_guid(sa->p_subn,
Packit 13e616
								 dest_guid);
Packit 13e616
		if (!*pp_dest_alias_guid) {
Packit 13e616
			/*
Packit 13e616
			   This 'error' is the client's fault (bad gid) so
Packit 13e616
			   don't enter it as an error in our own log.
Packit 13e616
			   Return an error response to the client.
Packit 13e616
			 */
Packit 13e616
			OSM_LOG(sa->p_log, OSM_LOG_VERBOSE,
Packit 13e616
				"No dest port with GUID 0x%016" PRIx64 "\n",
Packit 13e616
				cl_ntoh64(dest_guid));
Packit 13e616
			sa_status = IB_SA_MAD_STATUS_INVALID_GID;
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
	if (comp_mask & IB_PR_COMPMASK_DLID) {
Packit 13e616
		*pp_dest_port = osm_get_port_by_lid(sa->p_subn, p_pr->dlid);
Packit 13e616
		if (!*pp_dest_port) {
Packit 13e616
			/*
Packit 13e616
			   This 'error' is the client's fault (bad lid)
Packit 13e616
			   so don't enter it as an error in our own log.
Packit 13e616
			   Return an error response to the client.
Packit 13e616
			 */
Packit 13e616
			OSM_LOG(sa->p_log, OSM_LOG_VERBOSE, "No dest port "
Packit 13e616
				"with LID %u\n", cl_ntoh16(p_pr->dlid));
Packit 13e616
			sa_status = IB_SA_MAD_STATUS_NO_RECORDS;
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
Exit:
Packit 13e616
	OSM_LOG_EXIT(sa->p_log);
Packit 13e616
	return sa_status;
Packit 13e616
}
Packit 13e616
Packit 13e616
static void pr_rcv_process_world(IN osm_sa_t * sa, IN const ib_sa_mad_t * sa_mad,
Packit 13e616
				 IN const osm_port_t * requester_port,
Packit 13e616
				 IN const ib_gid_t * p_sgid,
Packit 13e616
				 IN const ib_gid_t * p_dgid,
Packit 13e616
				 IN cl_qlist_t * p_list)
Packit 13e616
{
Packit 13e616
	const cl_qmap_t *p_tbl;
Packit 13e616
	const osm_alias_guid_t *p_dest_alias_guid, *p_src_alias_guid;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(sa->p_log);
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   Iterate the entire port space over itself.
Packit 13e616
	   A path record from a port to itself is legit, so no
Packit 13e616
	   need for a special case there.
Packit 13e616
Packit 13e616
	   We compute both A -> B and B -> A, since we don't have
Packit 13e616
	   any check to determine the reversability of the paths.
Packit 13e616
	 */
Packit 13e616
	p_tbl = &sa->p_subn->alias_port_guid_tbl;
Packit 13e616
Packit 13e616
	p_dest_alias_guid = (osm_alias_guid_t *) cl_qmap_head(p_tbl);
Packit 13e616
	while (p_dest_alias_guid != (osm_alias_guid_t *) cl_qmap_end(p_tbl)) {
Packit 13e616
		p_src_alias_guid = (osm_alias_guid_t *) cl_qmap_head(p_tbl);
Packit 13e616
		while (p_src_alias_guid != (osm_alias_guid_t *) cl_qmap_end(p_tbl)) {
Packit 13e616
			pr_rcv_get_port_pair_paths(sa, sa_mad, requester_port,
Packit 13e616
						   p_src_alias_guid,
Packit 13e616
						   p_dest_alias_guid,
Packit 13e616
						   p_sgid, p_dgid, p_list);
Packit 13e616
			if (sa_mad->method == IB_MAD_METHOD_GET &&
Packit 13e616
			    cl_qlist_count(p_list) > 0)
Packit 13e616
				goto Exit;
Packit 13e616
Packit 13e616
			p_src_alias_guid =
Packit 13e616
			    (osm_alias_guid_t *) cl_qmap_next(&p_src_alias_guid->map_item);
Packit 13e616
		}
Packit 13e616
Packit 13e616
		p_dest_alias_guid =
Packit 13e616
		    (osm_alias_guid_t *) cl_qmap_next(&p_dest_alias_guid->map_item);
Packit 13e616
	}
Packit 13e616
Packit 13e616
Exit:
Packit 13e616
	OSM_LOG_EXIT(sa->p_log);
Packit 13e616
}
Packit 13e616
Packit 13e616
void osm_pr_process_half(IN osm_sa_t * sa, IN const ib_sa_mad_t * sa_mad,
Packit 13e616
				IN const osm_port_t * requester_port,
Packit 13e616
				IN const osm_alias_guid_t * p_src_alias_guid,
Packit 13e616
				IN const osm_alias_guid_t * p_dest_alias_guid,
Packit 13e616
				IN const ib_gid_t * p_sgid,
Packit 13e616
				IN const ib_gid_t * p_dgid,
Packit 13e616
				IN cl_qlist_t * p_list)
Packit 13e616
{
Packit 13e616
	const cl_qmap_t *p_tbl;
Packit 13e616
	const osm_alias_guid_t *p_alias_guid;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(sa->p_log);
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   Iterate over every port, looking for matches...
Packit 13e616
	   A path record from a port to itself is legit, so no
Packit 13e616
	   need to special case that one.
Packit 13e616
	 */
Packit 13e616
	p_tbl = &sa->p_subn->alias_port_guid_tbl;
Packit 13e616
Packit 13e616
	if (p_src_alias_guid) {
Packit 13e616
		/*
Packit 13e616
		   The src port if fixed, so iterate over destination ports.
Packit 13e616
		 */
Packit 13e616
		p_alias_guid = (osm_alias_guid_t *) cl_qmap_head(p_tbl);
Packit 13e616
		while (p_alias_guid != (osm_alias_guid_t *) cl_qmap_end(p_tbl)) {
Packit 13e616
			pr_rcv_get_port_pair_paths(sa, sa_mad, requester_port,
Packit 13e616
						   p_src_alias_guid,
Packit 13e616
						   p_alias_guid,
Packit 13e616
						   p_sgid, p_dgid, p_list);
Packit 13e616
			if (sa_mad->method == IB_MAD_METHOD_GET &&
Packit 13e616
			    cl_qlist_count(p_list) > 0)
Packit 13e616
				break;
Packit 13e616
			p_alias_guid = (osm_alias_guid_t *) cl_qmap_next(&p_alias_guid->map_item);
Packit 13e616
		}
Packit 13e616
	} else {
Packit 13e616
		/*
Packit 13e616
		   The dest port if fixed, so iterate over source ports.
Packit 13e616
		 */
Packit 13e616
		p_alias_guid = (osm_alias_guid_t *) cl_qmap_head(p_tbl);
Packit 13e616
		while (p_alias_guid != (osm_alias_guid_t *) cl_qmap_end(p_tbl)) {
Packit 13e616
			pr_rcv_get_port_pair_paths(sa, sa_mad, requester_port,
Packit 13e616
						   p_alias_guid,
Packit 13e616
						   p_dest_alias_guid, p_sgid,
Packit 13e616
						   p_dgid, p_list);
Packit 13e616
			if (sa_mad->method == IB_MAD_METHOD_GET &&
Packit 13e616
			    cl_qlist_count(p_list) > 0)
Packit 13e616
				break;
Packit 13e616
			p_alias_guid = (osm_alias_guid_t *) cl_qmap_next(&p_alias_guid->map_item);
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
	OSM_LOG_EXIT(sa->p_log);
Packit 13e616
}
Packit 13e616
Packit 13e616
void osm_pr_process_pair(IN osm_sa_t * sa, IN const ib_sa_mad_t * sa_mad,
Packit 13e616
				IN const osm_port_t * requester_port,
Packit 13e616
				IN const osm_alias_guid_t * p_src_alias_guid,
Packit 13e616
				IN const osm_alias_guid_t * p_dest_alias_guid,
Packit 13e616
				IN const ib_gid_t * p_sgid,
Packit 13e616
				IN const ib_gid_t * p_dgid,
Packit 13e616
				IN cl_qlist_t * p_list)
Packit 13e616
{
Packit 13e616
	OSM_LOG_ENTER(sa->p_log);
Packit 13e616
Packit 13e616
	pr_rcv_get_port_pair_paths(sa, sa_mad, requester_port, p_src_alias_guid,
Packit 13e616
				   p_dest_alias_guid, p_sgid, p_dgid, p_list);
Packit 13e616
Packit 13e616
	OSM_LOG_EXIT(sa->p_log);
Packit 13e616
}
Packit 13e616
Packit 13e616
static ib_api_status_t pr_match_mgrp_attributes(IN osm_sa_t * sa,
Packit 13e616
						IN const ib_sa_mad_t * sa_mad,
Packit 13e616
						IN const osm_mgrp_t * p_mgrp)
Packit 13e616
{
Packit 13e616
	const ib_path_rec_t *p_pr = ib_sa_mad_get_payload_ptr(sa_mad);
Packit 13e616
	ib_net64_t comp_mask = sa_mad->comp_mask;
Packit 13e616
	const osm_port_t *port;
Packit 13e616
	ib_api_status_t status = IB_ERROR;
Packit 13e616
	uint32_t flow_label;
Packit 13e616
	uint8_t sl, hop_limit;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(sa->p_log);
Packit 13e616
Packit 13e616
	/* check that MLID of the MC group matches the PathRecord DLID */
Packit 13e616
	if ((comp_mask & IB_PR_COMPMASK_DLID) && p_mgrp->mlid != p_pr->dlid) {
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit 13e616
			"DLID 0x%x is not MLID 0x%x for MC group\n",
Packit 13e616
			 cl_ntoh16(p_pr->dlid), cl_ntoh16(p_mgrp->mlid));
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/* If SGID and/or SLID specified, should validate as member of MC group */
Packit 13e616
	if (comp_mask & IB_PR_COMPMASK_SGID) {
Packit 13e616
		if (!osm_mgrp_get_mcm_alias_guid(p_mgrp,
Packit 13e616
						 p_pr->sgid.unicast.interface_id)) {
Packit 13e616
			char gid_str[INET6_ADDRSTRLEN];
Packit 13e616
			OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit 13e616
				"SGID %s is not a member of MC group\n",
Packit 13e616
				inet_ntop(AF_INET6, p_pr->sgid.raw,
Packit 13e616
					  gid_str, sizeof gid_str));
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
	if (comp_mask & IB_PR_COMPMASK_SLID) {
Packit 13e616
		port = osm_get_port_by_lid(sa->p_subn, p_pr->slid);
Packit 13e616
		if (!port || !osm_mgrp_get_mcm_port(p_mgrp, port->guid)) {
Packit 13e616
			OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit 13e616
				"Either no port with SLID %u found or "
Packit 13e616
				"SLID not a member of MC group\n",
Packit 13e616
				cl_ntoh16(p_pr->slid));
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/* Also, MTU, rate, packet lifetime, and raw traffic requested are not currently checked */
Packit 13e616
	if ((comp_mask & IB_PR_COMPMASK_PKEY) &&
Packit 13e616
	    p_pr->pkey != p_mgrp->mcmember_rec.pkey) {
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit 13e616
			"Pkey 0x%x doesn't match MC group Pkey 0x%x\n",
Packit 13e616
			cl_ntoh16(p_pr->pkey),
Packit 13e616
			cl_ntoh16(p_mgrp->mcmember_rec.pkey));
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	ib_member_get_sl_flow_hop(p_mgrp->mcmember_rec.sl_flow_hop,
Packit 13e616
				  &sl, &flow_label, &hop_limit);
Packit 13e616
Packit 13e616
	if ((comp_mask & IB_PR_COMPMASK_SL) && ib_path_rec_sl(p_pr) != sl) {
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit 13e616
			"SL %d doesn't match MC group SL %d\n",
Packit 13e616
			ib_path_rec_sl(p_pr), sl);
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/* If SubnAdmGet, assume NumbPaths of 1 (1.2 erratum) */
Packit 13e616
	if ((comp_mask & IB_PR_COMPMASK_NUMBPATH) &&
Packit 13e616
	    sa_mad->method != IB_MAD_METHOD_GET &&
Packit 13e616
	    ib_path_rec_num_path(p_pr) == 0) {
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit 13e616
			"Number of paths requested is 0\n");
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	if ((comp_mask & IB_PR_COMPMASK_FLOWLABEL) &&
Packit 13e616
	    ib_path_rec_flow_lbl(p_pr) != flow_label) {
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit 13e616
			"Flow label 0x%x doesn't match MC group "
Packit 13e616
			" flow label 0x%x\n",
Packit 13e616
			ib_path_rec_flow_lbl(p_pr), flow_label);
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	if ((comp_mask & IB_PR_COMPMASK_HOPLIMIT) &&
Packit 13e616
	    ib_path_rec_hop_limit(p_pr) != hop_limit) {
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit 13e616
			"Hop limit %u doesn't match MC group hop limit %u\n",
Packit 13e616
			ib_path_rec_hop_limit(p_pr), hop_limit);
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
Packit 13e616
	if ((comp_mask & IB_PR_COMPMASK_TCLASS) &&
Packit 13e616
	    p_pr->tclass != p_mgrp->mcmember_rec.tclass) {
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit 13e616
			"TClass 0x%02x doesn't match MC group TClass 0x%02x\n",
Packit 13e616
			p_pr->tclass, p_mgrp->mcmember_rec.tclass);
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	status = IB_SUCCESS;
Packit 13e616
Packit 13e616
Exit:
Packit 13e616
	OSM_LOG_EXIT(sa->p_log);
Packit 13e616
	return status;
Packit 13e616
}
Packit 13e616
Packit 13e616
static void pr_process_multicast(osm_sa_t * sa, const ib_sa_mad_t *sa_mad,
Packit 13e616
				 cl_qlist_t *list)
Packit 13e616
{
Packit 13e616
	ib_path_rec_t *pr = ib_sa_mad_get_payload_ptr(sa_mad);
Packit 13e616
	osm_mgrp_t *mgrp;
Packit 13e616
	ib_api_status_t status;
Packit 13e616
	osm_sa_item_t *pr_item;
Packit 13e616
	uint32_t flow_label;
Packit 13e616
	uint8_t sl, hop_limit;
Packit 13e616
Packit 13e616
	OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Multicast destination requested\n");
Packit 13e616
Packit 13e616
	mgrp = osm_get_mgrp_by_mgid(sa->p_subn, &pr->dgid);
Packit 13e616
	if (!mgrp) {
Packit 13e616
		char gid_str[INET6_ADDRSTRLEN];
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F09: "
Packit 13e616
			"No MC group found for PathRecord destination GID %s\n",
Packit 13e616
			inet_ntop(AF_INET6, pr->dgid.raw, gid_str,
Packit 13e616
				  sizeof gid_str));
Packit 13e616
		return;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/* Make sure the rest of the PathRecord matches the MC group attributes */
Packit 13e616
	status = pr_match_mgrp_attributes(sa, sa_mad, mgrp);
Packit 13e616
	if (status != IB_SUCCESS) {
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F19: "
Packit 13e616
			"MC group attributes don't match PathRecord request\n");
Packit 13e616
		return;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	pr_item = malloc(SA_PR_RESP_SIZE);
Packit 13e616
	if (pr_item == NULL) {
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F18: "
Packit 13e616
			"Unable to allocate path record for MC group\n");
Packit 13e616
		return;
Packit 13e616
	}
Packit 13e616
	memset(pr_item, 0, sizeof(cl_list_item_t));
Packit 13e616
Packit 13e616
	/* Copy PathRecord request into response */
Packit 13e616
	pr_item->resp.path_rec = *pr;
Packit 13e616
Packit 13e616
	/* Now, use the MC info to cruft up the PathRecord response */
Packit 13e616
	pr_item->resp.path_rec.dgid = mgrp->mcmember_rec.mgid;
Packit 13e616
	pr_item->resp.path_rec.dlid = mgrp->mcmember_rec.mlid;
Packit 13e616
	pr_item->resp.path_rec.tclass = mgrp->mcmember_rec.tclass;
Packit 13e616
	pr_item->resp.path_rec.num_path = 1;
Packit 13e616
	pr_item->resp.path_rec.pkey = mgrp->mcmember_rec.pkey;
Packit 13e616
Packit 13e616
	/* MTU, rate, and packet lifetime should be exactly */
Packit 13e616
	pr_item->resp.path_rec.mtu = (IB_PATH_SELECTOR_EXACTLY << 6) | mgrp->mcmember_rec.mtu;
Packit 13e616
	pr_item->resp.path_rec.rate = (IB_PATH_SELECTOR_EXACTLY << 6) | mgrp->mcmember_rec.rate;
Packit 13e616
	pr_item->resp.path_rec.pkt_life = (IB_PATH_SELECTOR_EXACTLY << 6) | mgrp->mcmember_rec.pkt_life;
Packit 13e616
Packit 13e616
	/* SL, Hop Limit, and Flow Label */
Packit 13e616
	ib_member_get_sl_flow_hop(mgrp->mcmember_rec.sl_flow_hop,
Packit 13e616
				  &sl, &flow_label, &hop_limit);
Packit 13e616
	ib_path_rec_set_sl(&pr_item->resp.path_rec, sl);
Packit 13e616
	ib_path_rec_set_qos_class(&pr_item->resp.path_rec, 0);
Packit 13e616
Packit 13e616
	/* HopLimit is not yet set in non link local MC groups */
Packit 13e616
	/* If it were, this would not be needed */
Packit 13e616
	if (ib_mgid_get_scope(&mgrp->mcmember_rec.mgid) !=
Packit 13e616
	    IB_MC_SCOPE_LINK_LOCAL)
Packit 13e616
		hop_limit = IB_HOPLIMIT_MAX;
Packit 13e616
Packit 13e616
	pr_item->resp.path_rec.hop_flow_raw =
Packit 13e616
	    cl_hton32(hop_limit) | (flow_label << 8);
Packit 13e616
Packit 13e616
	cl_qlist_insert_tail(list, &pr_item->list_item);
Packit 13e616
}
Packit 13e616
Packit 13e616
void osm_pr_rcv_process(IN void *context, IN void *data)
Packit 13e616
{
Packit 13e616
	osm_sa_t *sa = context;
Packit 13e616
	osm_madw_t *p_madw = data;
Packit 13e616
	const ib_sa_mad_t *p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw);
Packit 13e616
	ib_path_rec_t *p_pr = ib_sa_mad_get_payload_ptr(p_sa_mad);
Packit 13e616
	cl_qlist_t pr_list;
Packit 13e616
	const ib_gid_t *p_sgid = NULL, *p_dgid = NULL;
Packit 13e616
	const osm_alias_guid_t *p_src_alias_guid, *p_dest_alias_guid;
Packit 13e616
	const osm_port_t *p_src_port, *p_dest_port;
Packit 13e616
	osm_port_t *requester_port;
Packit 13e616
	uint8_t rate, mtu;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(sa->p_log);
Packit 13e616
Packit 13e616
	CL_ASSERT(p_madw);
Packit 13e616
Packit 13e616
	CL_ASSERT(p_sa_mad->attr_id == IB_MAD_ATTR_PATH_RECORD);
Packit 13e616
Packit 13e616
	/* we only support SubnAdmGet and SubnAdmGetTable methods */
Packit 13e616
	if (p_sa_mad->method != IB_MAD_METHOD_GET &&
Packit 13e616
	    p_sa_mad->method != IB_MAD_METHOD_GETTABLE) {
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F17: "
Packit 13e616
			"Unsupported Method (%s) for PathRecord request\n",
Packit 13e616
			ib_get_sa_method_str(p_sa_mad->method));
Packit 13e616
		osm_sa_send_error(sa, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR);
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/* Validate rate if supplied */
Packit 13e616
	if ((p_sa_mad->comp_mask & IB_PR_COMPMASK_RATESELEC) &&
Packit 13e616
	    (p_sa_mad->comp_mask & IB_PR_COMPMASK_RATE)) {
Packit 13e616
		rate = ib_path_rec_rate(p_pr);
Packit 13e616
		if (!ib_rate_is_valid(rate)) {
Packit 13e616
			osm_sa_send_error(sa, p_madw,
Packit 13e616
					  IB_SA_MAD_STATUS_REQ_INVALID);
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
	/* Validate MTU if supplied */
Packit 13e616
	if ((p_sa_mad->comp_mask & IB_PR_COMPMASK_MTUSELEC) &&
Packit 13e616
	    (p_sa_mad->comp_mask & IB_PR_COMPMASK_MTU)) {
Packit 13e616
		mtu = ib_path_rec_mtu(p_pr);
Packit 13e616
		if (!ib_mtu_is_valid(mtu)) {
Packit 13e616
			osm_sa_send_error(sa, p_madw,
Packit 13e616
					  IB_SA_MAD_STATUS_REQ_INVALID);
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/* Make sure either none or both ServiceID parameters are supplied */
Packit 13e616
	if ((p_sa_mad->comp_mask & IB_PR_COMPMASK_SERVICEID) != 0 &&
Packit 13e616
	    (p_sa_mad->comp_mask & IB_PR_COMPMASK_SERVICEID) !=
Packit 13e616
	     IB_PR_COMPMASK_SERVICEID) {
Packit 13e616
		osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_INSUF_COMPS);
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	cl_qlist_init(&pr_list);
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   Most SA functions (including this one) are read-only on the
Packit 13e616
	   subnet object, so we grab the lock non-exclusively.
Packit 13e616
	 */
Packit 13e616
	cl_plock_acquire(sa->p_lock);
Packit 13e616
Packit 13e616
	/* update the requester physical port */
Packit 13e616
	requester_port = osm_get_port_by_mad_addr(sa->p_log, sa->p_subn,
Packit 13e616
						  osm_madw_get_mad_addr_ptr
Packit 13e616
						  (p_madw));
Packit 13e616
	if (requester_port == NULL) {
Packit 13e616
		cl_plock_release(sa->p_lock);
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F16: "
Packit 13e616
			"Cannot find requester physical port\n");
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	if (OSM_LOG_IS_ACTIVE_V2(sa->p_log, OSM_LOG_DEBUG)) {
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit 13e616
			"Requester port GUID 0x%" PRIx64 "\n",
Packit 13e616
			cl_ntoh64(osm_port_get_guid(requester_port)));
Packit 13e616
		osm_dump_path_record_v2(sa->p_log, p_pr, FILE_ID, OSM_LOG_DEBUG);
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/* Handle multicast destinations separately */
Packit 13e616
	if ((p_sa_mad->comp_mask & IB_PR_COMPMASK_DGID) &&
Packit 13e616
	    ib_gid_is_multicast(&p_pr->dgid)) {
Packit 13e616
		pr_process_multicast(sa, p_sa_mad, &pr_list);
Packit 13e616
		goto Unlock;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Unicast destination requested\n");
Packit 13e616
Packit 13e616
	if (osm_pr_get_end_points(sa, p_sa_mad,
Packit 13e616
				  &p_src_alias_guid, &p_dest_alias_guid,
Packit 13e616
				  &p_src_port, &p_dest_port,
Packit 13e616
				  &p_sgid, &p_dgid) != IB_SA_MAD_STATUS_SUCCESS)
Packit 13e616
		goto Unlock;
Packit 13e616
Packit 13e616
	if (p_src_alias_guid && p_src_port &&
Packit 13e616
	    p_src_alias_guid->p_base_port != p_src_port) {
Packit 13e616
		cl_plock_release(sa->p_lock);
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_VERBOSE,
Packit 13e616
			"Requester port GUID 0x%" PRIx64 ": Port for SGUID "
Packit 13e616
			"0x%" PRIx64 " not same as port for SLID %u\n",
Packit 13e616
			cl_ntoh64(osm_port_get_guid(requester_port)),
Packit 13e616
			cl_ntoh64(p_pr->sgid.unicast.interface_id),
Packit 13e616
			cl_ntoh16(p_pr->slid));
Packit 13e616
		osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_REQ_INVALID);
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	if (p_dest_alias_guid && p_dest_port &&
Packit 13e616
	    p_dest_alias_guid->p_base_port != p_dest_port) {
Packit 13e616
		cl_plock_release(sa->p_lock);
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_VERBOSE,
Packit 13e616
			"Requester port GUID 0x%" PRIx64 ": Port for DGUID "
Packit 13e616
			"0x%" PRIx64 " not same as port for DLID %u\n",
Packit 13e616
			cl_ntoh64(osm_port_get_guid(requester_port)),
Packit 13e616
			cl_ntoh64(p_pr->dgid.unicast.interface_id),
Packit 13e616
			cl_ntoh16(p_pr->dlid));
Packit 13e616
		osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_REQ_INVALID);
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   What happens next depends on the type of endpoint information
Packit 13e616
	   that was specified....
Packit 13e616
	 */
Packit 13e616
	if (p_src_alias_guid) {
Packit 13e616
		if (p_dest_alias_guid)
Packit 13e616
			osm_pr_process_pair(sa, p_sa_mad, requester_port,
Packit 13e616
					    p_src_alias_guid, p_dest_alias_guid,
Packit 13e616
					    p_sgid, p_dgid, &pr_list);
Packit 13e616
		else if (!p_dest_port)
Packit 13e616
			osm_pr_process_half(sa, p_sa_mad, requester_port,
Packit 13e616
					    p_src_alias_guid, NULL, p_sgid,
Packit 13e616
					    p_dgid, &pr_list);
Packit 13e616
		else {
Packit 13e616
			/* Get all alias GUIDs for the dest port */
Packit 13e616
			p_dest_alias_guid = (osm_alias_guid_t *) cl_qmap_head(&sa->p_subn->alias_port_guid_tbl);
Packit 13e616
			while (p_dest_alias_guid !=
Packit 13e616
			       (osm_alias_guid_t *) cl_qmap_end(&sa->p_subn->alias_port_guid_tbl)) {
Packit 13e616
				if (osm_get_port_by_alias_guid(sa->p_subn, p_dest_alias_guid->alias_guid) ==
Packit 13e616
				    p_dest_port)
Packit 13e616
					osm_pr_process_pair(sa, p_sa_mad,
Packit 13e616
							    requester_port,
Packit 13e616
							    p_src_alias_guid,
Packit 13e616
							    p_dest_alias_guid,
Packit 13e616
							    p_sgid, p_dgid,
Packit 13e616
							    &pr_list);
Packit 13e616
				if (p_sa_mad->method == IB_MAD_METHOD_GET &&
Packit 13e616
				    cl_qlist_count(&pr_list) > 0)
Packit 13e616
					break;
Packit 13e616
Packit 13e616
				p_dest_alias_guid = (osm_alias_guid_t *) cl_qmap_next(&p_dest_alias_guid->map_item);
Packit 13e616
			}
Packit 13e616
		}
Packit 13e616
	} else {
Packit 13e616
		if (p_dest_alias_guid && !p_src_port)
Packit 13e616
			osm_pr_process_half(sa, p_sa_mad, requester_port,
Packit 13e616
					    NULL, p_dest_alias_guid, p_sgid,
Packit 13e616
					    p_dgid, &pr_list);
Packit 13e616
		else if (!p_src_port && !p_dest_port)
Packit 13e616
			/*
Packit 13e616
			   Katie, bar the door!
Packit 13e616
			 */
Packit 13e616
			pr_rcv_process_world(sa, p_sa_mad, requester_port,
Packit 13e616
					     p_sgid, p_dgid, &pr_list);
Packit 13e616
		else if (p_dest_alias_guid && p_src_port) {
Packit 13e616
			/* Get all alias GUIDs for the src port */
Packit 13e616
			p_src_alias_guid = (osm_alias_guid_t *) cl_qmap_head(&sa->p_subn->alias_port_guid_tbl);
Packit 13e616
			while (p_src_alias_guid !=
Packit 13e616
			       (osm_alias_guid_t *) cl_qmap_end(&sa->p_subn->alias_port_guid_tbl)) {
Packit 13e616
				if (osm_get_port_by_alias_guid(sa->p_subn,
Packit 13e616
							       p_src_alias_guid->alias_guid) ==
Packit 13e616
				    p_src_port)
Packit 13e616
					osm_pr_process_pair(sa, p_sa_mad,
Packit 13e616
							    requester_port,
Packit 13e616
							    p_src_alias_guid,
Packit 13e616
							    p_dest_alias_guid,
Packit 13e616
							    p_sgid, p_dgid,
Packit 13e616
							    &pr_list);
Packit 13e616
				if (p_sa_mad->method == IB_MAD_METHOD_GET &&
Packit 13e616
				    cl_qlist_count(&pr_list) > 0)
Packit 13e616
					break;
Packit 13e616
				p_src_alias_guid = (osm_alias_guid_t *) cl_qmap_next(&p_src_alias_guid->map_item);
Packit 13e616
			}
Packit 13e616
		} else if (p_src_port && !p_dest_port) {
Packit 13e616
			/* Get all alias GUIDs for the src port */
Packit 13e616
			p_src_alias_guid = (osm_alias_guid_t *) cl_qmap_head(&sa->p_subn->alias_port_guid_tbl);
Packit 13e616
			while (p_src_alias_guid !=
Packit 13e616
			       (osm_alias_guid_t *) cl_qmap_end(&sa->p_subn->alias_port_guid_tbl)) {
Packit 13e616
				if (osm_get_port_by_alias_guid(sa->p_subn,
Packit 13e616
							       p_src_alias_guid->alias_guid) ==
Packit 13e616
				    p_src_port)
Packit 13e616
					osm_pr_process_half(sa, p_sa_mad,
Packit 13e616
							    requester_port,
Packit 13e616
							    p_src_alias_guid,
Packit 13e616
							    NULL, p_sgid,
Packit 13e616
							    p_dgid, &pr_list);
Packit 13e616
				p_src_alias_guid = (osm_alias_guid_t *) cl_qmap_next(&p_src_alias_guid->map_item);
Packit 13e616
			}
Packit 13e616
		} else if (p_dest_port && !p_src_port) {
Packit 13e616
			/* Get all alias GUIDs for the dest port */
Packit 13e616
			p_dest_alias_guid = (osm_alias_guid_t *) cl_qmap_head(&sa->p_subn->alias_port_guid_tbl);
Packit 13e616
			while (p_dest_alias_guid !=
Packit 13e616
			       (osm_alias_guid_t *) cl_qmap_end(&sa->p_subn->alias_port_guid_tbl)) {
Packit 13e616
				if (osm_get_port_by_alias_guid(sa->p_subn,
Packit 13e616
							       p_dest_alias_guid->alias_guid) ==
Packit 13e616
				    p_dest_port)
Packit 13e616
					osm_pr_process_half(sa, p_sa_mad,
Packit 13e616
							    requester_port,
Packit 13e616
							    NULL,
Packit 13e616
							    p_dest_alias_guid,
Packit 13e616
							    p_sgid, p_dgid,
Packit 13e616
							    &pr_list);
Packit 13e616
				p_dest_alias_guid = (osm_alias_guid_t *) cl_qmap_next(&p_dest_alias_guid->map_item);
Packit 13e616
			}
Packit 13e616
		} else {
Packit 13e616
			/* Get all alias GUIDs for the src port */
Packit 13e616
			p_src_alias_guid = (osm_alias_guid_t *) cl_qmap_head(&sa->p_subn->alias_port_guid_tbl);
Packit 13e616
			while (p_src_alias_guid !=
Packit 13e616
			       (osm_alias_guid_t *) cl_qmap_end(&sa->p_subn->alias_port_guid_tbl)) {
Packit 13e616
				if (osm_get_port_by_alias_guid(sa->p_subn,
Packit 13e616
							       p_src_alias_guid->alias_guid) ==
Packit 13e616
				    p_src_port) {
Packit 13e616
					/* Get all alias GUIDs for the dest port */
Packit 13e616
					p_dest_alias_guid = (osm_alias_guid_t *) cl_qmap_head(&sa->p_subn->alias_port_guid_tbl);
Packit 13e616
					while (p_dest_alias_guid !=
Packit 13e616
					       (osm_alias_guid_t *) cl_qmap_end(&sa->p_subn->alias_port_guid_tbl)) {
Packit 13e616
						if (osm_get_port_by_alias_guid(sa->p_subn,
Packit 13e616
									       p_dest_alias_guid->alias_guid) ==
Packit 13e616
						    p_dest_port)
Packit 13e616
						osm_pr_process_pair(sa,
Packit 13e616
								    p_sa_mad,
Packit 13e616
								    requester_port,
Packit 13e616
								    p_src_alias_guid,
Packit 13e616
								    p_dest_alias_guid,
Packit 13e616
								    p_sgid,
Packit 13e616
								    p_dgid,
Packit 13e616
								    &pr_list);
Packit 13e616
						if (p_sa_mad->method == IB_MAD_METHOD_GET &&
Packit 13e616
						    cl_qlist_count(&pr_list) > 0)
Packit 13e616
							break;
Packit 13e616
						p_dest_alias_guid = (osm_alias_guid_t *) cl_qmap_next(&p_dest_alias_guid->map_item);
Packit 13e616
					}
Packit 13e616
				}
Packit 13e616
				if (p_sa_mad->method == IB_MAD_METHOD_GET &&
Packit 13e616
				    cl_qlist_count(&pr_list) > 0)
Packit 13e616
					break;
Packit 13e616
				p_src_alias_guid = (osm_alias_guid_t *) cl_qmap_next(&p_src_alias_guid->map_item);
Packit 13e616
			}
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
Unlock:
Packit 13e616
	cl_plock_release(sa->p_lock);
Packit 13e616
Packit 13e616
	/* Now, (finally) respond to the PathRecord request */
Packit 13e616
	osm_sa_respond(sa, p_madw, sizeof(ib_path_rec_t), &pr_list);
Packit 13e616
Packit 13e616
Exit:
Packit 13e616
	OSM_LOG_EXIT(sa->p_log);
Packit 13e616
}