1219820Sjeff/* 2219820Sjeff * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved. 3219820Sjeff * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. 4219820Sjeff * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. 5219820Sjeff * 6219820Sjeff * This software is available to you under a choice of one of two 7219820Sjeff * licenses. You may choose to be licensed under the terms of the GNU 8219820Sjeff * General Public License (GPL) Version 2, available from the file 9219820Sjeff * COPYING in the main directory of this source tree, or the 10219820Sjeff * OpenIB.org BSD license below: 11219820Sjeff * 12219820Sjeff * Redistribution and use in source and binary forms, with or 13219820Sjeff * without modification, are permitted provided that the following 14219820Sjeff * conditions are met: 15219820Sjeff * 16219820Sjeff * - Redistributions of source code must retain the above 17219820Sjeff * copyright notice, this list of conditions and the following 18219820Sjeff * disclaimer. 19219820Sjeff * 20219820Sjeff * - Redistributions in binary form must reproduce the above 21219820Sjeff * copyright notice, this list of conditions and the following 22219820Sjeff * disclaimer in the documentation and/or other materials 23219820Sjeff * provided with the distribution. 24219820Sjeff * 25219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 29219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 30219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 31219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 32219820Sjeff * SOFTWARE. 33219820Sjeff * 34219820Sjeff */ 35219820Sjeff 36219820Sjeff/* 37219820Sjeff * Abstract: 38219820Sjeff * Implementation of osm_mcast_tbl_t. 39219820Sjeff * This object represents an multicast forwarding table. 40219820Sjeff * This object is part of the opensm family of objects. 41219820Sjeff */ 42219820Sjeff 43219820Sjeff#if HAVE_CONFIG_H 44219820Sjeff# include <config.h> 45219820Sjeff#endif /* HAVE_CONFIG_H */ 46219820Sjeff 47219820Sjeff#include <stdlib.h> 48219820Sjeff#include <string.h> 49219820Sjeff#include <complib/cl_math.h> 50219820Sjeff#include <iba/ib_types.h> 51219820Sjeff#include <opensm/osm_mcast_tbl.h> 52219820Sjeff 53219820Sjeff/********************************************************************** 54219820Sjeff **********************************************************************/ 55219820Sjeffib_api_status_t 56219820Sjeffosm_mcast_tbl_init(IN osm_mcast_tbl_t * const p_tbl, 57219820Sjeff IN uint8_t const num_ports, IN uint16_t const capacity) 58219820Sjeff{ 59219820Sjeff CL_ASSERT(p_tbl); 60219820Sjeff CL_ASSERT(num_ports); 61219820Sjeff 62219820Sjeff memset(p_tbl, 0, sizeof(*p_tbl)); 63219820Sjeff 64219820Sjeff p_tbl->max_block_in_use = -1; 65219820Sjeff 66219820Sjeff if (capacity == 0) { 67219820Sjeff /* 68219820Sjeff This switch apparently doesn't support multicast. 69219820Sjeff Everything is initialized to zero already, so return. 70219820Sjeff */ 71219820Sjeff return (IB_SUCCESS); 72219820Sjeff } 73219820Sjeff 74219820Sjeff p_tbl->num_entries = capacity; 75219820Sjeff p_tbl->num_ports = num_ports; 76219820Sjeff p_tbl->max_position = 77219820Sjeff (uint8_t) ((ROUNDUP(num_ports, IB_MCAST_MASK_SIZE) / 78219820Sjeff IB_MCAST_MASK_SIZE) - 1); 79219820Sjeff 80219820Sjeff p_tbl->max_block = (uint16_t) ((ROUNDUP(p_tbl->num_entries, 81219820Sjeff IB_MCAST_BLOCK_SIZE) / 82219820Sjeff IB_MCAST_BLOCK_SIZE) - 1); 83219820Sjeff 84219820Sjeff p_tbl->max_mlid_ho = (uint16_t) (IB_LID_MCAST_START_HO + capacity - 1); 85219820Sjeff 86219820Sjeff /* 87219820Sjeff The number of bytes needed in the mask table is: 88219820Sjeff The (maximum bit mask 'position' + 1) times the 89219820Sjeff number of bytes in each bit mask times the 90219820Sjeff number of MLIDs supported by the table. 91219820Sjeff 92219820Sjeff We must always allocate the array with the maximum position 93219820Sjeff since it is (and must be) defined that way the table structure 94219820Sjeff in order to create a pointer to a two dimensional array. 95219820Sjeff */ 96219820Sjeff p_tbl->p_mask_tbl = malloc(p_tbl->num_entries * 97219820Sjeff (IB_MCAST_POSITION_MAX + 98219820Sjeff 1) * IB_MCAST_MASK_SIZE / 8); 99219820Sjeff 100219820Sjeff if (p_tbl->p_mask_tbl == NULL) 101219820Sjeff return (IB_INSUFFICIENT_MEMORY); 102219820Sjeff 103219820Sjeff memset(p_tbl->p_mask_tbl, 0, 104219820Sjeff p_tbl->num_entries * (IB_MCAST_POSITION_MAX + 105219820Sjeff 1) * IB_MCAST_MASK_SIZE / 8); 106219820Sjeff return (IB_SUCCESS); 107219820Sjeff} 108219820Sjeff 109219820Sjeff/********************************************************************** 110219820Sjeff **********************************************************************/ 111219820Sjeffvoid osm_mcast_tbl_destroy(IN osm_mcast_tbl_t * const p_tbl) 112219820Sjeff{ 113219820Sjeff free(p_tbl->p_mask_tbl); 114219820Sjeff} 115219820Sjeff 116219820Sjeff/********************************************************************** 117219820Sjeff **********************************************************************/ 118219820Sjeffvoid 119219820Sjeffosm_mcast_tbl_set(IN osm_mcast_tbl_t * const p_tbl, 120219820Sjeff IN const uint16_t mlid_ho, IN const uint8_t port) 121219820Sjeff{ 122219820Sjeff uintn_t mlid_offset; 123219820Sjeff uintn_t mask_offset; 124219820Sjeff uintn_t bit_mask; 125219820Sjeff int16_t block_num; 126219820Sjeff 127219820Sjeff CL_ASSERT(p_tbl); 128219820Sjeff CL_ASSERT(mlid_ho >= IB_LID_MCAST_START_HO); 129219820Sjeff CL_ASSERT(mlid_ho <= p_tbl->max_mlid_ho); 130219820Sjeff CL_ASSERT(p_tbl->p_mask_tbl); 131219820Sjeff 132219820Sjeff mlid_offset = mlid_ho - IB_LID_MCAST_START_HO; 133219820Sjeff mask_offset = port / IB_MCAST_MASK_SIZE; 134219820Sjeff bit_mask = cl_ntoh16((uint16_t) (1 << (port % IB_MCAST_MASK_SIZE))); 135219820Sjeff (*p_tbl->p_mask_tbl)[mlid_offset][mask_offset] |= bit_mask; 136219820Sjeff 137219820Sjeff block_num = (int16_t) (mlid_offset / IB_MCAST_BLOCK_SIZE); 138219820Sjeff 139219820Sjeff if (block_num > p_tbl->max_block_in_use) 140219820Sjeff p_tbl->max_block_in_use = (uint16_t) block_num; 141219820Sjeff} 142219820Sjeff 143219820Sjeff/********************************************************************** 144219820Sjeff **********************************************************************/ 145219820Sjeffboolean_t 146219820Sjeffosm_mcast_tbl_is_port(IN const osm_mcast_tbl_t * const p_tbl, 147219820Sjeff IN const uint16_t mlid_ho, IN const uint8_t port_num) 148219820Sjeff{ 149219820Sjeff uintn_t mlid_offset; 150219820Sjeff uintn_t mask_offset; 151219820Sjeff uintn_t bit_mask; 152219820Sjeff 153219820Sjeff CL_ASSERT(p_tbl); 154219820Sjeff 155219820Sjeff if (p_tbl->p_mask_tbl) { 156219820Sjeff CL_ASSERT(port_num <= 157219820Sjeff (p_tbl->max_position + 1) * IB_MCAST_MASK_SIZE); 158219820Sjeff CL_ASSERT(mlid_ho >= IB_LID_MCAST_START_HO); 159219820Sjeff CL_ASSERT(mlid_ho <= p_tbl->max_mlid_ho); 160219820Sjeff 161219820Sjeff mlid_offset = mlid_ho - IB_LID_MCAST_START_HO; 162219820Sjeff mask_offset = port_num / IB_MCAST_MASK_SIZE; 163219820Sjeff bit_mask = cl_ntoh16((uint16_t) 164219820Sjeff (1 << (port_num % IB_MCAST_MASK_SIZE))); 165219820Sjeff return (((*p_tbl-> 166219820Sjeff p_mask_tbl)[mlid_offset][mask_offset] & bit_mask) == 167219820Sjeff bit_mask); 168219820Sjeff } 169219820Sjeff 170219820Sjeff return (FALSE); 171219820Sjeff} 172219820Sjeff 173219820Sjeff/********************************************************************** 174219820Sjeff **********************************************************************/ 175219820Sjeffboolean_t 176219820Sjeffosm_mcast_tbl_is_any_port(IN const osm_mcast_tbl_t * const p_tbl, 177219820Sjeff IN const uint16_t mlid_ho) 178219820Sjeff{ 179219820Sjeff uintn_t mlid_offset; 180219820Sjeff uint8_t position; 181219820Sjeff uint16_t result = 0; 182219820Sjeff 183219820Sjeff CL_ASSERT(p_tbl); 184219820Sjeff 185219820Sjeff if (p_tbl->p_mask_tbl) { 186219820Sjeff CL_ASSERT(mlid_ho >= IB_LID_MCAST_START_HO); 187219820Sjeff CL_ASSERT(mlid_ho <= p_tbl->max_mlid_ho); 188219820Sjeff 189219820Sjeff mlid_offset = mlid_ho - IB_LID_MCAST_START_HO; 190219820Sjeff 191219820Sjeff for (position = 0; position <= p_tbl->max_position; position++) 192219820Sjeff result |= (*p_tbl->p_mask_tbl)[mlid_offset][position]; 193219820Sjeff } 194219820Sjeff 195219820Sjeff return (result != 0); 196219820Sjeff} 197219820Sjeff 198219820Sjeff/********************************************************************** 199219820Sjeff **********************************************************************/ 200219820Sjeffib_api_status_t 201219820Sjeffosm_mcast_tbl_set_block(IN osm_mcast_tbl_t * const p_tbl, 202219820Sjeff IN const ib_net16_t * const p_block, 203219820Sjeff IN const int16_t block_num, IN const uint8_t position) 204219820Sjeff{ 205219820Sjeff uint32_t i; 206219820Sjeff uint16_t mlid_start_ho; 207219820Sjeff 208219820Sjeff CL_ASSERT(p_tbl); 209219820Sjeff CL_ASSERT(p_block); 210219820Sjeff 211219820Sjeff if (block_num > p_tbl->max_block) 212219820Sjeff return (IB_INVALID_PARAMETER); 213219820Sjeff 214219820Sjeff if (position > p_tbl->max_position) 215219820Sjeff return (IB_INVALID_PARAMETER); 216219820Sjeff 217219820Sjeff mlid_start_ho = (uint16_t) (block_num * IB_MCAST_BLOCK_SIZE); 218219820Sjeff 219219820Sjeff if (mlid_start_ho + IB_MCAST_BLOCK_SIZE - 1 > p_tbl->max_mlid_ho) 220219820Sjeff return (IB_INVALID_PARAMETER); 221219820Sjeff 222219820Sjeff for (i = 0; i < IB_MCAST_BLOCK_SIZE; i++) 223219820Sjeff (*p_tbl->p_mask_tbl)[mlid_start_ho + i][position] = p_block[i]; 224219820Sjeff 225219820Sjeff if (block_num > p_tbl->max_block_in_use) 226219820Sjeff p_tbl->max_block_in_use = (uint16_t) block_num; 227219820Sjeff 228219820Sjeff return (IB_SUCCESS); 229219820Sjeff} 230219820Sjeff 231219820Sjeff/********************************************************************** 232219820Sjeff **********************************************************************/ 233219820Sjeffvoid 234219820Sjeffosm_mcast_tbl_clear_mlid(IN osm_mcast_tbl_t * const p_tbl, 235219820Sjeff IN const uint16_t mlid_ho) 236219820Sjeff{ 237219820Sjeff uint8_t i; 238219820Sjeff uintn_t mlid_offset; 239219820Sjeff 240219820Sjeff CL_ASSERT(p_tbl); 241219820Sjeff CL_ASSERT(mlid_ho >= IB_LID_MCAST_START_HO); 242219820Sjeff 243219820Sjeff if (p_tbl->p_mask_tbl && (mlid_ho <= p_tbl->max_mlid_ho)) { 244219820Sjeff mlid_offset = mlid_ho - IB_LID_MCAST_START_HO; 245219820Sjeff for (i = 0; i <= p_tbl->max_position; i++) 246219820Sjeff (*p_tbl->p_mask_tbl)[mlid_offset][i] = 0; 247219820Sjeff } 248219820Sjeff} 249219820Sjeff 250219820Sjeff/********************************************************************** 251219820Sjeff **********************************************************************/ 252219820Sjeffboolean_t 253219820Sjeffosm_mcast_tbl_get_block(IN osm_mcast_tbl_t * const p_tbl, 254219820Sjeff IN int16_t const block_num, 255219820Sjeff IN uint8_t const position, 256219820Sjeff OUT ib_net16_t * const p_block) 257219820Sjeff{ 258219820Sjeff uint32_t i; 259219820Sjeff uint16_t mlid_start_ho; 260219820Sjeff 261219820Sjeff CL_ASSERT(p_tbl); 262219820Sjeff CL_ASSERT(p_block); 263219820Sjeff 264219820Sjeff if (block_num > p_tbl->max_block_in_use) 265219820Sjeff return (FALSE); 266219820Sjeff 267219820Sjeff if (position > p_tbl->max_position) { 268219820Sjeff /* 269219820Sjeff Caller shouldn't do this for efficiency's sake... 270219820Sjeff */ 271219820Sjeff memset(p_block, 0, IB_SMP_DATA_SIZE); 272219820Sjeff return (TRUE); 273219820Sjeff } 274219820Sjeff 275219820Sjeff mlid_start_ho = (uint16_t) (block_num * IB_MCAST_BLOCK_SIZE); 276219820Sjeff 277219820Sjeff if (mlid_start_ho + IB_MCAST_BLOCK_SIZE - 1 > p_tbl->max_mlid_ho) 278219820Sjeff return (IB_INVALID_PARAMETER); 279219820Sjeff 280219820Sjeff for (i = 0; i < IB_MCAST_BLOCK_SIZE; i++) 281219820Sjeff p_block[i] = (*p_tbl->p_mask_tbl)[mlid_start_ho + i][position]; 282219820Sjeff 283219820Sjeff return (TRUE); 284219820Sjeff} 285