Blame opensm/osm_sa_pkey_record.c

Packit 13e616
/*
Packit 13e616
 * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved.
Packit 13e616
 * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved.
Packit 13e616
 * Copyright (c) 1996-2003 Intel Corporation. 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
#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 <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_PKEY_RECORD_C
Packit 13e616
#include <vendor/osm_vendor_api.h>
Packit 13e616
#include <opensm/osm_port.h>
Packit 13e616
#include <opensm/osm_node.h>
Packit 13e616
#include <opensm/osm_helper.h>
Packit 13e616
#include <opensm/osm_pkey.h>
Packit 13e616
#include <opensm/osm_sa.h>
Packit 13e616
Packit 13e616
#define SA_PKEY_RESP_SIZE SA_ITEM_RESP_SIZE(pkey_rec)
Packit 13e616
Packit 13e616
typedef struct osm_pkey_search_ctxt {
Packit 13e616
	const ib_pkey_table_record_t *p_rcvd_rec;
Packit 13e616
	ib_net64_t comp_mask;
Packit 13e616
	uint16_t block_num;
Packit 13e616
	cl_qlist_t *p_list;
Packit 13e616
	osm_sa_t *sa;
Packit 13e616
	const osm_physp_t *p_req_physp;
Packit 13e616
} osm_pkey_search_ctxt_t;
Packit 13e616
Packit 13e616
static void sa_pkey_create(IN osm_sa_t * sa, IN osm_physp_t * p_physp,
Packit 13e616
			   IN osm_pkey_search_ctxt_t * p_ctxt,
Packit 13e616
			   IN uint16_t block)
Packit 13e616
{
Packit 13e616
	osm_sa_item_t *p_rec_item;
Packit 13e616
	uint16_t lid;
Packit 13e616
	ib_pkey_table_t *tbl;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(sa->p_log);
Packit 13e616
Packit 13e616
	p_rec_item = malloc(SA_PKEY_RESP_SIZE);
Packit 13e616
	if (p_rec_item == NULL) {
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4602: "
Packit 13e616
			"rec_item alloc failed\n");
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	if (p_physp->p_node->node_info.node_type != IB_NODE_TYPE_SWITCH)
Packit 13e616
		lid = p_physp->port_info.base_lid;
Packit 13e616
	else
Packit 13e616
		lid = osm_node_get_base_lid(p_physp->p_node, 0);
Packit 13e616
Packit 13e616
	OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit 13e616
		"New P_Key table for: port 0x%016" PRIx64
Packit 13e616
		", lid %u, port %u Block:%u\n",
Packit 13e616
		cl_ntoh64(osm_physp_get_port_guid(p_physp)),
Packit 13e616
		cl_ntoh16(lid), osm_physp_get_port_num(p_physp), block);
Packit 13e616
Packit 13e616
	memset(p_rec_item, 0, SA_PKEY_RESP_SIZE);
Packit 13e616
Packit 13e616
	p_rec_item->resp.pkey_rec.lid = lid;
Packit 13e616
	p_rec_item->resp.pkey_rec.block_num = block;
Packit 13e616
	p_rec_item->resp.pkey_rec.port_num = osm_physp_get_port_num(p_physp);
Packit 13e616
	/* FIXME: There are ninf.PartitionCap or swinf.PartitionEnforcementCap
Packit 13e616
	   pkey entries so everything in that range is a valid block number
Packit 13e616
	   even if opensm is not using it. Return 0. However things outside
Packit 13e616
	   that range should return no entries. Not sure how to figure that
Packit 13e616
	   here? The range of pkey_tbl can be less than the cap, so
Packit 13e616
	   this falsely triggers. */
Packit 13e616
	tbl = osm_pkey_tbl_block_get(osm_physp_get_pkey_tbl(p_physp), block);
Packit 13e616
	if (tbl)
Packit 13e616
		p_rec_item->resp.pkey_rec.pkey_tbl = *tbl;
Packit 13e616
Packit 13e616
	cl_qlist_insert_tail(p_ctxt->p_list, &p_rec_item->list_item);
Packit 13e616
Packit 13e616
Exit:
Packit 13e616
	OSM_LOG_EXIT(sa->p_log);
Packit 13e616
}
Packit 13e616
Packit 13e616
static void sa_pkey_check_physp(IN osm_sa_t * sa, IN osm_physp_t * p_physp,
Packit 13e616
				osm_pkey_search_ctxt_t * p_ctxt)
Packit 13e616
{
Packit 13e616
	ib_net64_t comp_mask = p_ctxt->comp_mask;
Packit 13e616
	uint16_t block, num_blocks;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(sa->p_log);
Packit 13e616
Packit 13e616
	/* we got here with the phys port - all is left is to get the right block */
Packit 13e616
	if (comp_mask & IB_PKEY_COMPMASK_BLOCK) {
Packit 13e616
		sa_pkey_create(sa, p_physp, p_ctxt, p_ctxt->block_num);
Packit 13e616
	} else {
Packit 13e616
		num_blocks =
Packit 13e616
		    osm_pkey_tbl_get_num_blocks(osm_physp_get_pkey_tbl
Packit 13e616
						(p_physp));
Packit 13e616
		for (block = 0; block < num_blocks; block++)
Packit 13e616
			sa_pkey_create(sa, p_physp, p_ctxt, block);
Packit 13e616
	}
Packit 13e616
Packit 13e616
	OSM_LOG_EXIT(sa->p_log);
Packit 13e616
}
Packit 13e616
Packit 13e616
static void sa_pkey_by_comp_mask(IN osm_sa_t * sa, IN const osm_port_t * p_port,
Packit 13e616
				 osm_pkey_search_ctxt_t * p_ctxt)
Packit 13e616
{
Packit 13e616
	const ib_pkey_table_record_t *p_rcvd_rec;
Packit 13e616
	ib_net64_t comp_mask;
Packit 13e616
	osm_physp_t *p_physp;
Packit 13e616
	uint8_t port_num;
Packit 13e616
	uint8_t num_ports;
Packit 13e616
	const osm_physp_t *p_req_physp;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(sa->p_log);
Packit 13e616
Packit 13e616
	p_rcvd_rec = p_ctxt->p_rcvd_rec;
Packit 13e616
	comp_mask = p_ctxt->comp_mask;
Packit 13e616
	port_num = p_rcvd_rec->port_num;
Packit 13e616
	p_req_physp = p_ctxt->p_req_physp;
Packit 13e616
Packit 13e616
	/* if this is a switch port we can search all ports
Packit 13e616
	   otherwise we must be looking on port 0 */
Packit 13e616
	if (p_port->p_node->node_info.node_type != IB_NODE_TYPE_SWITCH) {
Packit 13e616
		/* we put it in the comp mask and port num */
Packit 13e616
		port_num = p_port->p_physp->port_num;
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit 13e616
			"Using Physical Default Port Number: 0x%X (for End Node)\n",
Packit 13e616
			port_num);
Packit 13e616
		comp_mask |= IB_PKEY_COMPMASK_PORT;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	if (comp_mask & IB_PKEY_COMPMASK_PORT) {
Packit 13e616
		if (port_num < osm_node_get_num_physp(p_port->p_node)) {
Packit 13e616
			p_physp =
Packit 13e616
			    osm_node_get_physp_ptr(p_port->p_node, port_num);
Packit 13e616
			/* Check that the p_physp is valid, and that is shares a pkey
Packit 13e616
			   with the p_req_physp. */
Packit 13e616
			if (p_physp &&
Packit 13e616
			    osm_physp_share_pkey(sa->p_log, p_req_physp,
Packit 13e616
						 p_physp, sa->p_subn->opt.allow_both_pkeys))
Packit 13e616
				sa_pkey_check_physp(sa, p_physp, p_ctxt);
Packit 13e616
		} else {
Packit 13e616
			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4603: "
Packit 13e616
				"Given Physical Port Number: 0x%X is out of range should be < 0x%X\n",
Packit 13e616
				port_num,
Packit 13e616
				osm_node_get_num_physp(p_port->p_node));
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
	} else {
Packit 13e616
		num_ports = osm_node_get_num_physp(p_port->p_node);
Packit 13e616
		for (port_num = 0; port_num < num_ports; port_num++) {
Packit 13e616
			p_physp =
Packit 13e616
			    osm_node_get_physp_ptr(p_port->p_node, port_num);
Packit 13e616
			if (!p_physp)
Packit 13e616
				continue;
Packit 13e616
Packit 13e616
			/* if the requester and the p_physp don't share a pkey -
Packit 13e616
			   continue */
Packit 13e616
			if (!osm_physp_share_pkey
Packit 13e616
			    (sa->p_log, p_req_physp, p_physp, sa->p_subn->opt.allow_both_pkeys))
Packit 13e616
				continue;
Packit 13e616
Packit 13e616
			sa_pkey_check_physp(sa, p_physp, p_ctxt);
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Exit:
Packit 13e616
	OSM_LOG_EXIT(sa->p_log);
Packit 13e616
}
Packit 13e616
Packit 13e616
static void sa_pkey_by_comp_mask_cb(IN cl_map_item_t * p_map_item, IN void *cxt)
Packit 13e616
{
Packit 13e616
	const osm_port_t *p_port = (osm_port_t *) p_map_item;
Packit 13e616
	osm_pkey_search_ctxt_t *p_ctxt = cxt;
Packit 13e616
Packit 13e616
	sa_pkey_by_comp_mask(p_ctxt->sa, p_port, p_ctxt);
Packit 13e616
}
Packit 13e616
Packit 13e616
void osm_pkey_rec_rcv_process(IN void *ctx, IN void *data)
Packit 13e616
{
Packit 13e616
	osm_sa_t *sa = ctx;
Packit 13e616
	osm_madw_t *p_madw = data;
Packit 13e616
	const ib_sa_mad_t *p_rcvd_mad;
Packit 13e616
	const ib_pkey_table_record_t *p_rcvd_rec;
Packit 13e616
	const osm_port_t *p_port = NULL;
Packit 13e616
	cl_qlist_t rec_list;
Packit 13e616
	osm_pkey_search_ctxt_t context;
Packit 13e616
	ib_net64_t comp_mask;
Packit 13e616
	osm_physp_t *p_req_physp;
Packit 13e616
Packit 13e616
	CL_ASSERT(sa);
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(sa->p_log);
Packit 13e616
Packit 13e616
	CL_ASSERT(p_madw);
Packit 13e616
Packit 13e616
	p_rcvd_mad = osm_madw_get_sa_mad_ptr(p_madw);
Packit 13e616
	p_rcvd_rec =
Packit 13e616
	    (ib_pkey_table_record_t *) ib_sa_mad_get_payload_ptr(p_rcvd_mad);
Packit 13e616
	comp_mask = p_rcvd_mad->comp_mask;
Packit 13e616
Packit 13e616
	CL_ASSERT(p_rcvd_mad->attr_id == IB_MAD_ATTR_PKEY_TBL_RECORD);
Packit 13e616
Packit 13e616
	/* we only support SubnAdmGet and SubnAdmGetTable methods */
Packit 13e616
	if (p_rcvd_mad->method != IB_MAD_METHOD_GET &&
Packit 13e616
	    p_rcvd_mad->method != IB_MAD_METHOD_GETTABLE) {
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4605: "
Packit 13e616
			"Unsupported Method (%s) for PKeyRecord request\n",
Packit 13e616
			ib_get_sa_method_str(p_rcvd_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
	/*
Packit 13e616
	   p922 - P_KeyTableRecords shall only be provided in response
Packit 13e616
	   to trusted requests.
Packit 13e616
	   Check that the requester is a trusted one.
Packit 13e616
	 */
Packit 13e616
	if (p_rcvd_mad->sm_key != sa->p_subn->opt.sa_key) {
Packit 13e616
		/* This is not a trusted requester! */
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4608: "
Packit 13e616
			"Ignoring PKeyRecord request from non-trusted requester"
Packit 13e616
			" with SM_Key 0x%016" PRIx64 "\n",
Packit 13e616
			cl_ntoh64(p_rcvd_mad->sm_key));
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
	cl_plock_acquire(sa->p_lock);
Packit 13e616
Packit 13e616
	/* update the requester physical port */
Packit 13e616
	p_req_physp = osm_get_physp_by_mad_addr(sa->p_log, sa->p_subn,
Packit 13e616
						osm_madw_get_mad_addr_ptr
Packit 13e616
						(p_madw));
Packit 13e616
	if (p_req_physp == NULL) {
Packit 13e616
		cl_plock_release(sa->p_lock);
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4604: "
Packit 13e616
			"Cannot find requester physical port\n");
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
	OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit 13e616
		"Requester port GUID 0x%" PRIx64 "\n",
Packit 13e616
		cl_ntoh64(osm_physp_get_port_guid(p_req_physp)));
Packit 13e616
Packit 13e616
	cl_qlist_init(&rec_list);
Packit 13e616
Packit 13e616
	context.p_rcvd_rec = p_rcvd_rec;
Packit 13e616
	context.p_list = &rec_list;
Packit 13e616
	context.comp_mask = p_rcvd_mad->comp_mask;
Packit 13e616
	context.sa = sa;
Packit 13e616
	context.block_num = cl_ntoh16(p_rcvd_rec->block_num);
Packit 13e616
	context.p_req_physp = p_req_physp;
Packit 13e616
Packit 13e616
	OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit 13e616
		"Got Query Lid:%u(%02X), Block:0x%02X(%02X), Port:0x%02X(%02X)\n",
Packit 13e616
		cl_ntoh16(p_rcvd_rec->lid),
Packit 13e616
		(comp_mask & IB_PKEY_COMPMASK_LID) != 0, p_rcvd_rec->port_num,
Packit 13e616
		(comp_mask & IB_PKEY_COMPMASK_PORT) != 0, context.block_num,
Packit 13e616
		(comp_mask & IB_PKEY_COMPMASK_BLOCK) != 0);
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   If the user specified a LID, it obviously narrows our
Packit 13e616
	   work load, since we don't have to search every port
Packit 13e616
	 */
Packit 13e616
	if (comp_mask & IB_PKEY_COMPMASK_LID) {
Packit 13e616
		p_port = osm_get_port_by_lid(sa->p_subn, p_rcvd_rec->lid);
Packit 13e616
		if (!p_port)
Packit 13e616
			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 460B: "
Packit 13e616
				"No port found with LID %u\n",
Packit 13e616
				cl_ntoh16(p_rcvd_rec->lid));
Packit 13e616
		else
Packit 13e616
			sa_pkey_by_comp_mask(sa, p_port, &context);
Packit 13e616
	} else
Packit 13e616
		cl_qmap_apply_func(&sa->p_subn->port_guid_tbl,
Packit 13e616
				   sa_pkey_by_comp_mask_cb, &context);
Packit 13e616
Packit 13e616
	cl_plock_release(sa->p_lock);
Packit 13e616
Packit 13e616
	osm_sa_respond(sa, p_madw, sizeof(ib_pkey_table_record_t), &rec_list);
Packit 13e616
Packit 13e616
Exit:
Packit 13e616
	OSM_LOG_EXIT(sa->p_log);
Packit 13e616
}