Blame opensm/osm_mcast_tbl.c

Packit 13e616
/*
Packit 13e616
 * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved.
Packit 13e616
 * Copyright (c) 2002-2009 Mellanox Technologies LTD. All rights reserved.
Packit 13e616
 * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
Packit 13e616
 * Copyright (c) 2009 HNR Consulting. 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_mcast_tbl_t.
Packit 13e616
 * This object represents a multicast forwarding table.
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 <stdlib.h>
Packit 13e616
#include <string.h>
Packit 13e616
#include <complib/cl_math.h>
Packit 13e616
#include <iba/ib_types.h>
Packit 13e616
#include <opensm/osm_file_ids.h>
Packit 13e616
#define FILE_ID OSM_FILE_MCAST_TBL_C
Packit 13e616
#include <opensm/osm_mcast_tbl.h>
Packit 13e616
Packit 13e616
void osm_mcast_tbl_init(IN osm_mcast_tbl_t * p_tbl, IN uint8_t num_ports,
Packit 13e616
			IN uint16_t capacity)
Packit 13e616
{
Packit 13e616
	CL_ASSERT(p_tbl);
Packit 13e616
	CL_ASSERT(num_ports);
Packit 13e616
Packit 13e616
	memset(p_tbl, 0, sizeof(*p_tbl));
Packit 13e616
Packit 13e616
	p_tbl->max_block_in_use = -1;
Packit 13e616
Packit 13e616
	if (capacity == 0) {
Packit 13e616
		/*
Packit 13e616
		   This switch apparently doesn't support multicast.
Packit 13e616
		   Everything is initialized to zero already, so return.
Packit 13e616
		 */
Packit 13e616
		return;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	p_tbl->num_entries = capacity;
Packit 13e616
	p_tbl->num_ports = num_ports;
Packit 13e616
	p_tbl->max_position =
Packit 13e616
	    (uint8_t) ((ROUNDUP(num_ports, IB_MCAST_MASK_SIZE) /
Packit 13e616
			IB_MCAST_MASK_SIZE) - 1);
Packit 13e616
Packit 13e616
	p_tbl->max_block = (uint16_t) ((ROUNDUP(p_tbl->num_entries,
Packit 13e616
						IB_MCAST_BLOCK_SIZE) /
Packit 13e616
					IB_MCAST_BLOCK_SIZE) - 1);
Packit 13e616
}
Packit 13e616
Packit 13e616
void osm_mcast_tbl_destroy(IN osm_mcast_tbl_t * p_tbl)
Packit 13e616
{
Packit 13e616
	free(p_tbl->p_mask_tbl);
Packit 13e616
}
Packit 13e616
Packit 13e616
void osm_mcast_tbl_set(IN osm_mcast_tbl_t * p_tbl, IN uint16_t mlid_ho,
Packit 13e616
		       IN uint8_t port)
Packit 13e616
{
Packit 13e616
	unsigned mlid_offset, mask_offset, bit_mask;
Packit 13e616
	int16_t block_num;
Packit 13e616
Packit 13e616
	CL_ASSERT(p_tbl && p_tbl->p_mask_tbl);
Packit 13e616
	CL_ASSERT(mlid_ho >= IB_LID_MCAST_START_HO);
Packit 13e616
	CL_ASSERT(mlid_ho <= p_tbl->max_mlid_ho);
Packit 13e616
Packit 13e616
	mlid_offset = mlid_ho - IB_LID_MCAST_START_HO;
Packit 13e616
	mask_offset = port / IB_MCAST_MASK_SIZE;
Packit 13e616
	bit_mask = cl_ntoh16((uint16_t) (1 << (port % IB_MCAST_MASK_SIZE)));
Packit 13e616
	(*p_tbl->p_mask_tbl)[mlid_offset][mask_offset] |= bit_mask;
Packit 13e616
Packit 13e616
	block_num = (int16_t) (mlid_offset / IB_MCAST_BLOCK_SIZE);
Packit 13e616
Packit 13e616
	if (block_num > p_tbl->max_block_in_use)
Packit 13e616
		p_tbl->max_block_in_use = (uint16_t) block_num;
Packit 13e616
}
Packit 13e616
Packit 13e616
int osm_mcast_tbl_realloc(IN osm_mcast_tbl_t * p_tbl, IN unsigned mlid_offset)
Packit 13e616
{
Packit 13e616
	size_t mft_depth, size;
Packit 13e616
	uint16_t (*p_mask_tbl)[][IB_MCAST_POSITION_MAX + 1];
Packit 13e616
Packit 13e616
	if (mlid_offset < p_tbl->mft_depth)
Packit 13e616
		goto done;
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   The number of bytes needed in the mask table is:
Packit 13e616
	   The (maximum bit mask 'position' + 1) times the
Packit 13e616
	   number of bytes in each bit mask times the
Packit 13e616
	   number of MLIDs supported by the table.
Packit 13e616
Packit 13e616
	   We must always allocate the array with the maximum position
Packit 13e616
	   since it is (and must be) defined that way the table structure
Packit 13e616
	   in order to create a pointer to a two dimensional array.
Packit 13e616
	 */
Packit 13e616
	mft_depth = (mlid_offset / IB_MCAST_BLOCK_SIZE + 1) * IB_MCAST_BLOCK_SIZE;
Packit 13e616
	size = mft_depth * (IB_MCAST_POSITION_MAX + 1) * IB_MCAST_MASK_SIZE / 8;
Packit 13e616
	p_mask_tbl = realloc(p_tbl->p_mask_tbl, size);
Packit 13e616
	if (!p_mask_tbl)
Packit 13e616
		return -1;
Packit 13e616
	memset((uint8_t *)p_mask_tbl + p_tbl->mft_depth * (IB_MCAST_POSITION_MAX + 1) * IB_MCAST_MASK_SIZE / 8,
Packit 13e616
	       0,
Packit 13e616
	       size - p_tbl->mft_depth * (IB_MCAST_POSITION_MAX + 1) * IB_MCAST_MASK_SIZE / 8);
Packit 13e616
	p_tbl->p_mask_tbl = p_mask_tbl;
Packit 13e616
	p_tbl->mft_depth = mft_depth;
Packit 13e616
done:
Packit 13e616
	p_tbl->max_mlid_ho = mlid_offset + IB_LID_MCAST_START_HO;
Packit 13e616
	return 0;
Packit 13e616
}
Packit 13e616
Packit 13e616
boolean_t osm_mcast_tbl_is_port(IN const osm_mcast_tbl_t * p_tbl,
Packit 13e616
				IN uint16_t mlid_ho, IN uint8_t port_num)
Packit 13e616
{
Packit 13e616
	unsigned mlid_offset, mask_offset, bit_mask;
Packit 13e616
Packit 13e616
	CL_ASSERT(p_tbl);
Packit 13e616
Packit 13e616
	if (p_tbl->p_mask_tbl) {
Packit 13e616
		CL_ASSERT(port_num <=
Packit 13e616
			  (p_tbl->max_position + 1) * IB_MCAST_MASK_SIZE);
Packit 13e616
		CL_ASSERT(mlid_ho >= IB_LID_MCAST_START_HO);
Packit 13e616
		CL_ASSERT(mlid_ho <= p_tbl->max_mlid_ho);
Packit 13e616
Packit 13e616
		mlid_offset = mlid_ho - IB_LID_MCAST_START_HO;
Packit 13e616
		mask_offset = port_num / IB_MCAST_MASK_SIZE;
Packit 13e616
		bit_mask = cl_ntoh16((uint16_t)
Packit 13e616
				     (1 << (port_num % IB_MCAST_MASK_SIZE)));
Packit 13e616
		return (((*p_tbl->
Packit 13e616
			  p_mask_tbl)[mlid_offset][mask_offset] & bit_mask) ==
Packit 13e616
			bit_mask);
Packit 13e616
	}
Packit 13e616
Packit 13e616
	return FALSE;
Packit 13e616
}
Packit 13e616
Packit 13e616
boolean_t osm_mcast_tbl_is_any_port(IN const osm_mcast_tbl_t * p_tbl,
Packit 13e616
				    IN uint16_t mlid_ho)
Packit 13e616
{
Packit 13e616
	unsigned mlid_offset;
Packit 13e616
	uint8_t position;
Packit 13e616
	uint16_t result = 0;
Packit 13e616
Packit 13e616
	CL_ASSERT(p_tbl);
Packit 13e616
Packit 13e616
	if (p_tbl->p_mask_tbl) {
Packit 13e616
		CL_ASSERT(mlid_ho >= IB_LID_MCAST_START_HO);
Packit 13e616
		CL_ASSERT(mlid_ho <= p_tbl->max_mlid_ho);
Packit 13e616
Packit 13e616
		mlid_offset = mlid_ho - IB_LID_MCAST_START_HO;
Packit 13e616
Packit 13e616
		for (position = 0; position <= p_tbl->max_position; position++)
Packit 13e616
			result |= (*p_tbl->p_mask_tbl)[mlid_offset][position];
Packit 13e616
	}
Packit 13e616
Packit 13e616
	return (result != 0);
Packit 13e616
}
Packit 13e616
Packit 13e616
ib_api_status_t osm_mcast_tbl_set_block(IN osm_mcast_tbl_t * p_tbl,
Packit 13e616
					IN const ib_net16_t * p_block,
Packit 13e616
					IN int16_t block_num,
Packit 13e616
					IN uint8_t position)
Packit 13e616
{
Packit 13e616
	uint32_t i;
Packit 13e616
	uint16_t mlid_start_ho;
Packit 13e616
Packit 13e616
	CL_ASSERT(p_tbl);
Packit 13e616
	CL_ASSERT(p_block);
Packit 13e616
Packit 13e616
	if (block_num > p_tbl->max_block)
Packit 13e616
		return IB_INVALID_PARAMETER;
Packit 13e616
Packit 13e616
	if (position > p_tbl->max_position)
Packit 13e616
		return IB_INVALID_PARAMETER;
Packit 13e616
Packit 13e616
	mlid_start_ho = (uint16_t) (block_num * IB_MCAST_BLOCK_SIZE);
Packit 13e616
Packit 13e616
	if (mlid_start_ho + IB_MCAST_BLOCK_SIZE - 1 > p_tbl->mft_depth)
Packit 13e616
		return IB_INVALID_PARAMETER;
Packit 13e616
Packit 13e616
	for (i = 0; i < IB_MCAST_BLOCK_SIZE; i++)
Packit 13e616
		(*p_tbl->p_mask_tbl)[mlid_start_ho + i][position] = p_block[i];
Packit 13e616
Packit 13e616
	if (block_num > p_tbl->max_block_in_use)
Packit 13e616
		p_tbl->max_block_in_use = (uint16_t) block_num;
Packit 13e616
Packit 13e616
	return IB_SUCCESS;
Packit 13e616
}
Packit 13e616
Packit 13e616
void osm_mcast_tbl_clear_mlid(IN osm_mcast_tbl_t * p_tbl, IN uint16_t mlid_ho)
Packit 13e616
{
Packit 13e616
	unsigned mlid_offset;
Packit 13e616
Packit 13e616
	CL_ASSERT(p_tbl);
Packit 13e616
	CL_ASSERT(mlid_ho >= IB_LID_MCAST_START_HO);
Packit 13e616
Packit 13e616
	mlid_offset = mlid_ho - IB_LID_MCAST_START_HO;
Packit 13e616
	if (p_tbl->p_mask_tbl && mlid_offset < p_tbl->mft_depth)
Packit 13e616
		memset((uint8_t *)p_tbl->p_mask_tbl + mlid_offset * (IB_MCAST_POSITION_MAX + 1) * IB_MCAST_MASK_SIZE / 8,
Packit 13e616
		       0,
Packit 13e616
		       (IB_MCAST_POSITION_MAX + 1) * IB_MCAST_MASK_SIZE / 8);
Packit 13e616
}
Packit 13e616
Packit 13e616
boolean_t osm_mcast_tbl_get_block(IN osm_mcast_tbl_t * p_tbl,
Packit 13e616
				  IN int16_t block_num, IN uint8_t position,
Packit 13e616
				  OUT ib_net16_t * p_block)
Packit 13e616
{
Packit 13e616
	uint32_t i;
Packit 13e616
	uint16_t mlid_start_ho;
Packit 13e616
Packit 13e616
	CL_ASSERT(p_tbl);
Packit 13e616
	CL_ASSERT(p_block);
Packit 13e616
Packit 13e616
	if (block_num > p_tbl->max_block_in_use)
Packit 13e616
		return FALSE;
Packit 13e616
Packit 13e616
	if (position > p_tbl->max_position) {
Packit 13e616
		/*
Packit 13e616
		   Caller shouldn't do this for efficiency's sake...
Packit 13e616
		 */
Packit 13e616
		memset(p_block, 0, IB_SMP_DATA_SIZE);
Packit 13e616
		return TRUE;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	CL_ASSERT(block_num * IB_MCAST_BLOCK_SIZE <= p_tbl->mft_depth);
Packit 13e616
Packit 13e616
	mlid_start_ho = (uint16_t) (block_num * IB_MCAST_BLOCK_SIZE);
Packit 13e616
Packit 13e616
	for (i = 0; i < IB_MCAST_BLOCK_SIZE; i++)
Packit 13e616
		p_block[i] = (*p_tbl->p_mask_tbl)[mlid_start_ho + i][position];
Packit 13e616
Packit 13e616
	return TRUE;
Packit 13e616
}