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.
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:
13 * Redistribution and use in source and binary forms, with or
14 * without modification, are permitted provided that the following
17 * - Redistributions of source code must retain the above
18 * copyright notice, this list of conditions and the following
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.
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
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.
46 #endif /* HAVE_CONFIG_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>
56 void osm_mcast_tbl_init(IN osm_mcast_tbl_t * p_tbl, IN uint8_t num_ports,
62 memset(p_tbl, 0, sizeof(*p_tbl));
64 p_tbl->max_block_in_use = -1;
68 This switch apparently doesn't support multicast.
69 Everything is initialized to zero already, so return.
74 p_tbl->num_entries = capacity;
75 p_tbl->num_ports = num_ports;
77 (uint8_t) ((ROUNDUP(num_ports, IB_MCAST_MASK_SIZE) /
78 IB_MCAST_MASK_SIZE) - 1);
80 p_tbl->max_block = (uint16_t) ((ROUNDUP(p_tbl->num_entries,
81 IB_MCAST_BLOCK_SIZE) /
82 IB_MCAST_BLOCK_SIZE) - 1);
85 void osm_mcast_tbl_destroy(IN osm_mcast_tbl_t * p_tbl)
87 free(p_tbl->p_mask_tbl);
90 void osm_mcast_tbl_set(IN osm_mcast_tbl_t * p_tbl, IN uint16_t mlid_ho,
93 unsigned mlid_offset, mask_offset, bit_mask;
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);
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;
105 block_num = (int16_t) (mlid_offset / IB_MCAST_BLOCK_SIZE);
107 if (block_num > p_tbl->max_block_in_use)
108 p_tbl->max_block_in_use = (uint16_t) block_num;
111 int osm_mcast_tbl_realloc(IN osm_mcast_tbl_t * p_tbl, IN unsigned mlid_offset)
113 size_t mft_depth, size;
114 uint16_t (*p_mask_tbl)[][IB_MCAST_POSITION_MAX + 1];
116 if (mlid_offset < p_tbl->mft_depth)
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.
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.
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);
134 memset((uint8_t *)p_mask_tbl + p_tbl->mft_depth * (IB_MCAST_POSITION_MAX + 1) * IB_MCAST_MASK_SIZE / 8,
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;
140 p_tbl->max_mlid_ho = mlid_offset + IB_LID_MCAST_START_HO;
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)
147 unsigned mlid_offset, mask_offset, bit_mask;
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);
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)));
162 p_mask_tbl)[mlid_offset][mask_offset] & bit_mask) ==
169 boolean_t osm_mcast_tbl_is_any_port(IN const osm_mcast_tbl_t * p_tbl,
172 unsigned mlid_offset;
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);
182 mlid_offset = mlid_ho - IB_LID_MCAST_START_HO;
184 for (position = 0; position <= p_tbl->max_position; position++)
185 result |= (*p_tbl->p_mask_tbl)[mlid_offset][position];
188 return (result != 0);
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,
197 uint16_t mlid_start_ho;
202 if (block_num > p_tbl->max_block)
203 return IB_INVALID_PARAMETER;
205 if (position > p_tbl->max_position)
206 return IB_INVALID_PARAMETER;
208 mlid_start_ho = (uint16_t) (block_num * IB_MCAST_BLOCK_SIZE);
210 if (mlid_start_ho + IB_MCAST_BLOCK_SIZE - 1 > p_tbl->mft_depth)
211 return IB_INVALID_PARAMETER;
213 for (i = 0; i < IB_MCAST_BLOCK_SIZE; i++)
214 (*p_tbl->p_mask_tbl)[mlid_start_ho + i][position] = p_block[i];
216 if (block_num > p_tbl->max_block_in_use)
217 p_tbl->max_block_in_use = (uint16_t) block_num;
222 void osm_mcast_tbl_clear_mlid(IN osm_mcast_tbl_t * p_tbl, IN uint16_t mlid_ho)
224 unsigned mlid_offset;
227 CL_ASSERT(mlid_ho >= IB_LID_MCAST_START_HO);
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,
233 (IB_MCAST_POSITION_MAX + 1) * IB_MCAST_MASK_SIZE / 8);
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)
241 uint16_t mlid_start_ho;
246 if (block_num > p_tbl->max_block_in_use)
249 if (position > p_tbl->max_position) {
251 Caller shouldn't do this for efficiency's sake...
253 memset(p_block, 0, IB_SMP_DATA_SIZE);
257 CL_ASSERT(block_num * IB_MCAST_BLOCK_SIZE <= p_tbl->mft_depth);
259 mlid_start_ho = (uint16_t) (block_num * IB_MCAST_BLOCK_SIZE);
261 for (i = 0; i < IB_MCAST_BLOCK_SIZE; i++)
262 p_block[i] = (*p_tbl->p_mask_tbl)[mlid_start_ho + i][position];