Blame opensm/osm_mcast_tbl.c

Packit Service 54dbc3
/*
Packit Service 54dbc3
 * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved.
Packit Service 54dbc3
 * Copyright (c) 2002-2009 Mellanox Technologies LTD. All rights reserved.
Packit Service 54dbc3
 * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
Packit Service 54dbc3
 * Copyright (c) 2009 HNR Consulting. All rights reserved.
Packit Service 54dbc3
 *
Packit Service 54dbc3
 * This software is available to you under a choice of one of two
Packit Service 54dbc3
 * licenses.  You may choose to be licensed under the terms of the GNU
Packit Service 54dbc3
 * General Public License (GPL) Version 2, available from the file
Packit Service 54dbc3
 * COPYING in the main directory of this source tree, or the
Packit Service 54dbc3
 * OpenIB.org BSD license below:
Packit Service 54dbc3
 *
Packit Service 54dbc3
 *     Redistribution and use in source and binary forms, with or
Packit Service 54dbc3
 *     without modification, are permitted provided that the following
Packit Service 54dbc3
 *     conditions are met:
Packit Service 54dbc3
 *
Packit Service 54dbc3
 *      - Redistributions of source code must retain the above
Packit Service 54dbc3
 *        copyright notice, this list of conditions and the following
Packit Service 54dbc3
 *        disclaimer.
Packit Service 54dbc3
 *
Packit Service 54dbc3
 *      - Redistributions in binary form must reproduce the above
Packit Service 54dbc3
 *        copyright notice, this list of conditions and the following
Packit Service 54dbc3
 *        disclaimer in the documentation and/or other materials
Packit Service 54dbc3
 *        provided with the distribution.
Packit Service 54dbc3
 *
Packit Service 54dbc3
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
Packit Service 54dbc3
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
Packit Service 54dbc3
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
Packit Service 54dbc3
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
Packit Service 54dbc3
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
Packit Service 54dbc3
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
Packit Service 54dbc3
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
Packit Service 54dbc3
 * SOFTWARE.
Packit Service 54dbc3
 *
Packit Service 54dbc3
 */
Packit Service 54dbc3
Packit Service 54dbc3
/*
Packit Service 54dbc3
 * Abstract:
Packit Service 54dbc3
 *    Implementation of osm_mcast_tbl_t.
Packit Service 54dbc3
 * This object represents a multicast forwarding table.
Packit Service 54dbc3
 * This object is part of the opensm family of objects.
Packit Service 54dbc3
 */
Packit Service 54dbc3
Packit Service 54dbc3
#if HAVE_CONFIG_H
Packit Service 54dbc3
#  include <config.h>
Packit Service 54dbc3
#endif				/* HAVE_CONFIG_H */
Packit Service 54dbc3
Packit Service 54dbc3
#include <stdlib.h>
Packit Service 54dbc3
#include <string.h>
Packit Service 54dbc3
#include <complib/cl_math.h>
Packit Service 54dbc3
#include <iba/ib_types.h>
Packit Service 54dbc3
#include <opensm/osm_file_ids.h>
Packit Service 54dbc3
#define FILE_ID OSM_FILE_MCAST_TBL_C
Packit Service 54dbc3
#include <opensm/osm_mcast_tbl.h>
Packit Service 54dbc3
Packit Service 54dbc3
void osm_mcast_tbl_init(IN osm_mcast_tbl_t * p_tbl, IN uint8_t num_ports,
Packit Service 54dbc3
			IN uint16_t capacity)
Packit Service 54dbc3
{
Packit Service 54dbc3
	CL_ASSERT(p_tbl);
Packit Service 54dbc3
	CL_ASSERT(num_ports);
Packit Service 54dbc3
Packit Service 54dbc3
	memset(p_tbl, 0, sizeof(*p_tbl));
Packit Service 54dbc3
Packit Service 54dbc3
	p_tbl->max_block_in_use = -1;
Packit Service 54dbc3
Packit Service 54dbc3
	if (capacity == 0) {
Packit Service 54dbc3
		/*
Packit Service 54dbc3
		   This switch apparently doesn't support multicast.
Packit Service 54dbc3
		   Everything is initialized to zero already, so return.
Packit Service 54dbc3
		 */
Packit Service 54dbc3
		return;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	p_tbl->num_entries = capacity;
Packit Service 54dbc3
	p_tbl->num_ports = num_ports;
Packit Service 54dbc3
	p_tbl->max_position =
Packit Service 54dbc3
	    (uint8_t) ((ROUNDUP(num_ports, IB_MCAST_MASK_SIZE) /
Packit Service 54dbc3
			IB_MCAST_MASK_SIZE) - 1);
Packit Service 54dbc3
Packit Service 54dbc3
	p_tbl->max_block = (uint16_t) ((ROUNDUP(p_tbl->num_entries,
Packit Service 54dbc3
						IB_MCAST_BLOCK_SIZE) /
Packit Service 54dbc3
					IB_MCAST_BLOCK_SIZE) - 1);
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
void osm_mcast_tbl_destroy(IN osm_mcast_tbl_t * p_tbl)
Packit Service 54dbc3
{
Packit Service 54dbc3
	free(p_tbl->p_mask_tbl);
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
void osm_mcast_tbl_set(IN osm_mcast_tbl_t * p_tbl, IN uint16_t mlid_ho,
Packit Service 54dbc3
		       IN uint8_t port)
Packit Service 54dbc3
{
Packit Service 54dbc3
	unsigned mlid_offset, mask_offset, bit_mask;
Packit Service 54dbc3
	int16_t block_num;
Packit Service 54dbc3
Packit Service 54dbc3
	CL_ASSERT(p_tbl && p_tbl->p_mask_tbl);
Packit Service 54dbc3
	CL_ASSERT(mlid_ho >= IB_LID_MCAST_START_HO);
Packit Service 54dbc3
	CL_ASSERT(mlid_ho <= p_tbl->max_mlid_ho);
Packit Service 54dbc3
Packit Service 54dbc3
	mlid_offset = mlid_ho - IB_LID_MCAST_START_HO;
Packit Service 54dbc3
	mask_offset = port / IB_MCAST_MASK_SIZE;
Packit Service 54dbc3
	bit_mask = cl_ntoh16((uint16_t) (1 << (port % IB_MCAST_MASK_SIZE)));
Packit Service 54dbc3
	(*p_tbl->p_mask_tbl)[mlid_offset][mask_offset] |= bit_mask;
Packit Service 54dbc3
Packit Service 54dbc3
	block_num = (int16_t) (mlid_offset / IB_MCAST_BLOCK_SIZE);
Packit Service 54dbc3
Packit Service 54dbc3
	if (block_num > p_tbl->max_block_in_use)
Packit Service 54dbc3
		p_tbl->max_block_in_use = (uint16_t) block_num;
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
int osm_mcast_tbl_realloc(IN osm_mcast_tbl_t * p_tbl, IN unsigned mlid_offset)
Packit Service 54dbc3
{
Packit Service 54dbc3
	size_t mft_depth, size;
Packit Service 54dbc3
	uint16_t (*p_mask_tbl)[][IB_MCAST_POSITION_MAX + 1];
Packit Service 54dbc3
Packit Service 54dbc3
	if (mlid_offset < p_tbl->mft_depth)
Packit Service 54dbc3
		goto done;
Packit Service 54dbc3
Packit Service 54dbc3
	/*
Packit Service 54dbc3
	   The number of bytes needed in the mask table is:
Packit Service 54dbc3
	   The (maximum bit mask 'position' + 1) times the
Packit Service 54dbc3
	   number of bytes in each bit mask times the
Packit Service 54dbc3
	   number of MLIDs supported by the table.
Packit Service 54dbc3
Packit Service 54dbc3
	   We must always allocate the array with the maximum position
Packit Service 54dbc3
	   since it is (and must be) defined that way the table structure
Packit Service 54dbc3
	   in order to create a pointer to a two dimensional array.
Packit Service 54dbc3
	 */
Packit Service 54dbc3
	mft_depth = (mlid_offset / IB_MCAST_BLOCK_SIZE + 1) * IB_MCAST_BLOCK_SIZE;
Packit Service 54dbc3
	size = mft_depth * (IB_MCAST_POSITION_MAX + 1) * IB_MCAST_MASK_SIZE / 8;
Packit Service 54dbc3
	p_mask_tbl = realloc(p_tbl->p_mask_tbl, size);
Packit Service 54dbc3
	if (!p_mask_tbl)
Packit Service 54dbc3
		return -1;
Packit Service 54dbc3
	memset((uint8_t *)p_mask_tbl + p_tbl->mft_depth * (IB_MCAST_POSITION_MAX + 1) * IB_MCAST_MASK_SIZE / 8,
Packit Service 54dbc3
	       0,
Packit Service 54dbc3
	       size - p_tbl->mft_depth * (IB_MCAST_POSITION_MAX + 1) * IB_MCAST_MASK_SIZE / 8);
Packit Service 54dbc3
	p_tbl->p_mask_tbl = p_mask_tbl;
Packit Service 54dbc3
	p_tbl->mft_depth = mft_depth;
Packit Service 54dbc3
done:
Packit Service 54dbc3
	p_tbl->max_mlid_ho = mlid_offset + IB_LID_MCAST_START_HO;
Packit Service 54dbc3
	return 0;
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
boolean_t osm_mcast_tbl_is_port(IN const osm_mcast_tbl_t * p_tbl,
Packit Service 54dbc3
				IN uint16_t mlid_ho, IN uint8_t port_num)
Packit Service 54dbc3
{
Packit Service 54dbc3
	unsigned mlid_offset, mask_offset, bit_mask;
Packit Service 54dbc3
Packit Service 54dbc3
	CL_ASSERT(p_tbl);
Packit Service 54dbc3
Packit Service 54dbc3
	if (p_tbl->p_mask_tbl) {
Packit Service 54dbc3
		CL_ASSERT(port_num <=
Packit Service 54dbc3
			  (p_tbl->max_position + 1) * IB_MCAST_MASK_SIZE);
Packit Service 54dbc3
		CL_ASSERT(mlid_ho >= IB_LID_MCAST_START_HO);
Packit Service 54dbc3
		CL_ASSERT(mlid_ho <= p_tbl->max_mlid_ho);
Packit Service 54dbc3
Packit Service 54dbc3
		mlid_offset = mlid_ho - IB_LID_MCAST_START_HO;
Packit Service 54dbc3
		mask_offset = port_num / IB_MCAST_MASK_SIZE;
Packit Service 54dbc3
		bit_mask = cl_ntoh16((uint16_t)
Packit Service 54dbc3
				     (1 << (port_num % IB_MCAST_MASK_SIZE)));
Packit Service 54dbc3
		return (((*p_tbl->
Packit Service 54dbc3
			  p_mask_tbl)[mlid_offset][mask_offset] & bit_mask) ==
Packit Service 54dbc3
			bit_mask);
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	return FALSE;
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
boolean_t osm_mcast_tbl_is_any_port(IN const osm_mcast_tbl_t * p_tbl,
Packit Service 54dbc3
				    IN uint16_t mlid_ho)
Packit Service 54dbc3
{
Packit Service 54dbc3
	unsigned mlid_offset;
Packit Service 54dbc3
	uint8_t position;
Packit Service 54dbc3
	uint16_t result = 0;
Packit Service 54dbc3
Packit Service 54dbc3
	CL_ASSERT(p_tbl);
Packit Service 54dbc3
Packit Service 54dbc3
	if (p_tbl->p_mask_tbl) {
Packit Service 54dbc3
		CL_ASSERT(mlid_ho >= IB_LID_MCAST_START_HO);
Packit Service 54dbc3
		CL_ASSERT(mlid_ho <= p_tbl->max_mlid_ho);
Packit Service 54dbc3
Packit Service 54dbc3
		mlid_offset = mlid_ho - IB_LID_MCAST_START_HO;
Packit Service 54dbc3
Packit Service 54dbc3
		for (position = 0; position <= p_tbl->max_position; position++)
Packit Service 54dbc3
			result |= (*p_tbl->p_mask_tbl)[mlid_offset][position];
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	return (result != 0);
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
ib_api_status_t osm_mcast_tbl_set_block(IN osm_mcast_tbl_t * p_tbl,
Packit Service 54dbc3
					IN const ib_net16_t * p_block,
Packit Service 54dbc3
					IN int16_t block_num,
Packit Service 54dbc3
					IN uint8_t position)
Packit Service 54dbc3
{
Packit Service 54dbc3
	uint32_t i;
Packit Service 54dbc3
	uint16_t mlid_start_ho;
Packit Service 54dbc3
Packit Service 54dbc3
	CL_ASSERT(p_tbl);
Packit Service 54dbc3
	CL_ASSERT(p_block);
Packit Service 54dbc3
Packit Service 54dbc3
	if (block_num > p_tbl->max_block)
Packit Service 54dbc3
		return IB_INVALID_PARAMETER;
Packit Service 54dbc3
Packit Service 54dbc3
	if (position > p_tbl->max_position)
Packit Service 54dbc3
		return IB_INVALID_PARAMETER;
Packit Service 54dbc3
Packit Service 54dbc3
	mlid_start_ho = (uint16_t) (block_num * IB_MCAST_BLOCK_SIZE);
Packit Service 54dbc3
Packit Service 54dbc3
	if (mlid_start_ho + IB_MCAST_BLOCK_SIZE - 1 > p_tbl->mft_depth)
Packit Service 54dbc3
		return IB_INVALID_PARAMETER;
Packit Service 54dbc3
Packit Service 54dbc3
	for (i = 0; i < IB_MCAST_BLOCK_SIZE; i++)
Packit Service 54dbc3
		(*p_tbl->p_mask_tbl)[mlid_start_ho + i][position] = p_block[i];
Packit Service 54dbc3
Packit Service 54dbc3
	if (block_num > p_tbl->max_block_in_use)
Packit Service 54dbc3
		p_tbl->max_block_in_use = (uint16_t) block_num;
Packit Service 54dbc3
Packit Service 54dbc3
	return IB_SUCCESS;
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
void osm_mcast_tbl_clear_mlid(IN osm_mcast_tbl_t * p_tbl, IN uint16_t mlid_ho)
Packit Service 54dbc3
{
Packit Service 54dbc3
	unsigned mlid_offset;
Packit Service 54dbc3
Packit Service 54dbc3
	CL_ASSERT(p_tbl);
Packit Service 54dbc3
	CL_ASSERT(mlid_ho >= IB_LID_MCAST_START_HO);
Packit Service 54dbc3
Packit Service 54dbc3
	mlid_offset = mlid_ho - IB_LID_MCAST_START_HO;
Packit Service 54dbc3
	if (p_tbl->p_mask_tbl && mlid_offset < p_tbl->mft_depth)
Packit Service 54dbc3
		memset((uint8_t *)p_tbl->p_mask_tbl + mlid_offset * (IB_MCAST_POSITION_MAX + 1) * IB_MCAST_MASK_SIZE / 8,
Packit Service 54dbc3
		       0,
Packit Service 54dbc3
		       (IB_MCAST_POSITION_MAX + 1) * IB_MCAST_MASK_SIZE / 8);
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
boolean_t osm_mcast_tbl_get_block(IN osm_mcast_tbl_t * p_tbl,
Packit Service 54dbc3
				  IN int16_t block_num, IN uint8_t position,
Packit Service 54dbc3
				  OUT ib_net16_t * p_block)
Packit Service 54dbc3
{
Packit Service 54dbc3
	uint32_t i;
Packit Service 54dbc3
	uint16_t mlid_start_ho;
Packit Service 54dbc3
Packit Service 54dbc3
	CL_ASSERT(p_tbl);
Packit Service 54dbc3
	CL_ASSERT(p_block);
Packit Service 54dbc3
Packit Service 54dbc3
	if (block_num > p_tbl->max_block_in_use)
Packit Service 54dbc3
		return FALSE;
Packit Service 54dbc3
Packit Service 54dbc3
	if (position > p_tbl->max_position) {
Packit Service 54dbc3
		/*
Packit Service 54dbc3
		   Caller shouldn't do this for efficiency's sake...
Packit Service 54dbc3
		 */
Packit Service 54dbc3
		memset(p_block, 0, IB_SMP_DATA_SIZE);
Packit Service 54dbc3
		return TRUE;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	CL_ASSERT(block_num * IB_MCAST_BLOCK_SIZE <= p_tbl->mft_depth);
Packit Service 54dbc3
Packit Service 54dbc3
	mlid_start_ho = (uint16_t) (block_num * IB_MCAST_BLOCK_SIZE);
Packit Service 54dbc3
Packit Service 54dbc3
	for (i = 0; i < IB_MCAST_BLOCK_SIZE; i++)
Packit Service 54dbc3
		p_block[i] = (*p_tbl->p_mask_tbl)[mlid_start_ho + i][position];
Packit Service 54dbc3
Packit Service 54dbc3
	return TRUE;
Packit Service 54dbc3
}