1 /* 2 * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. 3 * Copyright (c) 2002-2009 Mellanox Technologies LTD. All rights reserved. 4 * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. 5 * Copyright (c) 2009 HNR Consulting. All rights reserved. 6 * 7 * This software is available to you under a choice of one of two 8 * licenses. You may choose to be licensed under the terms of the GNU 9 * General Public License (GPL) Version 2, available from the file 10 * COPYING in the main directory of this source tree, or the 11 * OpenIB.org BSD license below: 12 * 13 * Redistribution and use in source and binary forms, with or 14 * without modification, are permitted provided that the following 15 * conditions are met: 16 * 17 * - Redistributions of source code must retain the above 18 * copyright notice, this list of conditions and the following 19 * disclaimer. 20 * 21 * - Redistributions in binary form must reproduce the above 22 * copyright notice, this list of conditions and the following 23 * disclaimer in the documentation and/or other materials 24 * provided with the distribution. 25 * 26 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 27 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 28 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 29 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 30 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 31 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 32 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 33 * SOFTWARE. 34 * 35 */ 36 37 /* 38 * Abstract: 39 * Implementation of osm_mcast_tbl_t. 40 * This object represents a multicast forwarding table. 41 * This object is part of the opensm family of objects. 42 */ 43 44 #if HAVE_CONFIG_H 45 # include <config.h> 46 #endif /* HAVE_CONFIG_H */ 47 48 #include <stdlib.h> 49 #include <string.h> 50 #include <complib/cl_math.h> 51 #include <iba/ib_types.h> 52 #include <opensm/osm_file_ids.h> 53 #define FILE_ID OSM_FILE_MCAST_TBL_C 54 #include <opensm/osm_mcast_tbl.h> 55 56 void osm_mcast_tbl_init(IN osm_mcast_tbl_t * p_tbl, IN uint8_t num_ports, 57 IN uint16_t capacity) 58 { 59 CL_ASSERT(p_tbl); 60 CL_ASSERT(num_ports); 61 62 memset(p_tbl, 0, sizeof(*p_tbl)); 63 64 p_tbl->max_block_in_use = -1; 65 66 if (capacity == 0) { 67 /* 68 This switch apparently doesn't support multicast. 69 Everything is initialized to zero already, so return. 70 */ 71 return; 72 } 73 74 p_tbl->num_entries = capacity; 75 p_tbl->num_ports = num_ports; 76 p_tbl->max_position = 77 (uint8_t) ((ROUNDUP(num_ports, IB_MCAST_MASK_SIZE) / 78 IB_MCAST_MASK_SIZE) - 1); 79 80 p_tbl->max_block = (uint16_t) ((ROUNDUP(p_tbl->num_entries, 81 IB_MCAST_BLOCK_SIZE) / 82 IB_MCAST_BLOCK_SIZE) - 1); 83 } 84 85 void osm_mcast_tbl_destroy(IN osm_mcast_tbl_t * p_tbl) 86 { 87 free(p_tbl->p_mask_tbl); 88 } 89 90 void osm_mcast_tbl_set(IN osm_mcast_tbl_t * p_tbl, IN uint16_t mlid_ho, 91 IN uint8_t port) 92 { 93 unsigned mlid_offset, mask_offset, bit_mask; 94 int16_t block_num; 95 96 CL_ASSERT(p_tbl && p_tbl->p_mask_tbl); 97 CL_ASSERT(mlid_ho >= IB_LID_MCAST_START_HO); 98 CL_ASSERT(mlid_ho <= p_tbl->max_mlid_ho); 99 100 mlid_offset = mlid_ho - IB_LID_MCAST_START_HO; 101 mask_offset = port / IB_MCAST_MASK_SIZE; 102 bit_mask = cl_ntoh16((uint16_t) (1 << (port % IB_MCAST_MASK_SIZE))); 103 (*p_tbl->p_mask_tbl)[mlid_offset][mask_offset] |= bit_mask; 104 105 block_num = (int16_t) (mlid_offset / IB_MCAST_BLOCK_SIZE); 106 107 if (block_num > p_tbl->max_block_in_use) 108 p_tbl->max_block_in_use = (uint16_t) block_num; 109 } 110 111 int osm_mcast_tbl_realloc(IN osm_mcast_tbl_t * p_tbl, IN unsigned mlid_offset) 112 { 113 size_t mft_depth, size; 114 uint16_t (*p_mask_tbl)[][IB_MCAST_POSITION_MAX + 1]; 115 116 if (mlid_offset < p_tbl->mft_depth) 117 goto done; 118 119 /* 120 The number of bytes needed in the mask table is: 121 The (maximum bit mask 'position' + 1) times the 122 number of bytes in each bit mask times the 123 number of MLIDs supported by the table. 124 125 We must always allocate the array with the maximum position 126 since it is (and must be) defined that way the table structure 127 in order to create a pointer to a two dimensional array. 128 */ 129 mft_depth = (mlid_offset / IB_MCAST_BLOCK_SIZE + 1) * IB_MCAST_BLOCK_SIZE; 130 size = mft_depth * (IB_MCAST_POSITION_MAX + 1) * IB_MCAST_MASK_SIZE / 8; 131 p_mask_tbl = realloc(p_tbl->p_mask_tbl, size); 132 if (!p_mask_tbl) 133 return -1; 134 memset((uint8_t *)p_mask_tbl + p_tbl->mft_depth * (IB_MCAST_POSITION_MAX + 1) * IB_MCAST_MASK_SIZE / 8, 135 0, 136 size - p_tbl->mft_depth * (IB_MCAST_POSITION_MAX + 1) * IB_MCAST_MASK_SIZE / 8); 137 p_tbl->p_mask_tbl = p_mask_tbl; 138 p_tbl->mft_depth = mft_depth; 139 done: 140 p_tbl->max_mlid_ho = mlid_offset + IB_LID_MCAST_START_HO; 141 return 0; 142 } 143 144 boolean_t osm_mcast_tbl_is_port(IN const osm_mcast_tbl_t * p_tbl, 145 IN uint16_t mlid_ho, IN uint8_t port_num) 146 { 147 unsigned mlid_offset, mask_offset, bit_mask; 148 149 CL_ASSERT(p_tbl); 150 151 if (p_tbl->p_mask_tbl) { 152 CL_ASSERT(port_num <= 153 (p_tbl->max_position + 1) * IB_MCAST_MASK_SIZE); 154 CL_ASSERT(mlid_ho >= IB_LID_MCAST_START_HO); 155 CL_ASSERT(mlid_ho <= p_tbl->max_mlid_ho); 156 157 mlid_offset = mlid_ho - IB_LID_MCAST_START_HO; 158 mask_offset = port_num / IB_MCAST_MASK_SIZE; 159 bit_mask = cl_ntoh16((uint16_t) 160 (1 << (port_num % IB_MCAST_MASK_SIZE))); 161 return (((*p_tbl-> 162 p_mask_tbl)[mlid_offset][mask_offset] & bit_mask) == 163 bit_mask); 164 } 165 166 return FALSE; 167 } 168 169 boolean_t osm_mcast_tbl_is_any_port(IN const osm_mcast_tbl_t * p_tbl, 170 IN uint16_t mlid_ho) 171 { 172 unsigned mlid_offset; 173 uint8_t position; 174 uint16_t result = 0; 175 176 CL_ASSERT(p_tbl); 177 178 if (p_tbl->p_mask_tbl) { 179 CL_ASSERT(mlid_ho >= IB_LID_MCAST_START_HO); 180 CL_ASSERT(mlid_ho <= p_tbl->max_mlid_ho); 181 182 mlid_offset = mlid_ho - IB_LID_MCAST_START_HO; 183 184 for (position = 0; position <= p_tbl->max_position; position++) 185 result |= (*p_tbl->p_mask_tbl)[mlid_offset][position]; 186 } 187 188 return (result != 0); 189 } 190 191 ib_api_status_t osm_mcast_tbl_set_block(IN osm_mcast_tbl_t * p_tbl, 192 IN const ib_net16_t * p_block, 193 IN int16_t block_num, 194 IN uint8_t position) 195 { 196 uint32_t i; 197 uint16_t mlid_start_ho; 198 199 CL_ASSERT(p_tbl); 200 CL_ASSERT(p_block); 201 202 if (block_num > p_tbl->max_block) 203 return IB_INVALID_PARAMETER; 204 205 if (position > p_tbl->max_position) 206 return IB_INVALID_PARAMETER; 207 208 mlid_start_ho = (uint16_t) (block_num * IB_MCAST_BLOCK_SIZE); 209 210 if (mlid_start_ho + IB_MCAST_BLOCK_SIZE - 1 > p_tbl->mft_depth) 211 return IB_INVALID_PARAMETER; 212 213 for (i = 0; i < IB_MCAST_BLOCK_SIZE; i++) 214 (*p_tbl->p_mask_tbl)[mlid_start_ho + i][position] = p_block[i]; 215 216 if (block_num > p_tbl->max_block_in_use) 217 p_tbl->max_block_in_use = (uint16_t) block_num; 218 219 return IB_SUCCESS; 220 } 221 222 void osm_mcast_tbl_clear_mlid(IN osm_mcast_tbl_t * p_tbl, IN uint16_t mlid_ho) 223 { 224 unsigned mlid_offset; 225 226 CL_ASSERT(p_tbl); 227 CL_ASSERT(mlid_ho >= IB_LID_MCAST_START_HO); 228 229 mlid_offset = mlid_ho - IB_LID_MCAST_START_HO; 230 if (p_tbl->p_mask_tbl && mlid_offset < p_tbl->mft_depth) 231 memset((uint8_t *)p_tbl->p_mask_tbl + mlid_offset * (IB_MCAST_POSITION_MAX + 1) * IB_MCAST_MASK_SIZE / 8, 232 0, 233 (IB_MCAST_POSITION_MAX + 1) * IB_MCAST_MASK_SIZE / 8); 234 } 235 236 boolean_t osm_mcast_tbl_get_block(IN osm_mcast_tbl_t * p_tbl, 237 IN int16_t block_num, IN uint8_t position, 238 OUT ib_net16_t * p_block) 239 { 240 uint32_t i; 241 uint16_t mlid_start_ho; 242 243 CL_ASSERT(p_tbl); 244 CL_ASSERT(p_block); 245 246 if (block_num > p_tbl->max_block_in_use) 247 return FALSE; 248 249 if (position > p_tbl->max_position) { 250 /* 251 Caller shouldn't do this for efficiency's sake... 252 */ 253 memset(p_block, 0, IB_SMP_DATA_SIZE); 254 return TRUE; 255 } 256 257 CL_ASSERT(block_num * IB_MCAST_BLOCK_SIZE <= p_tbl->mft_depth); 258 259 mlid_start_ho = (uint16_t) (block_num * IB_MCAST_BLOCK_SIZE); 260 261 for (i = 0; i < IB_MCAST_BLOCK_SIZE; i++) 262 p_block[i] = (*p_tbl->p_mask_tbl)[mlid_start_ho + i][position]; 263 264 return TRUE; 265 } 266