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
osm_mcast_tbl_init(IN osm_mcast_tbl_t * p_tbl,IN uint8_t num_ports,IN uint16_t capacity)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
osm_mcast_tbl_destroy(IN osm_mcast_tbl_t * p_tbl)85 void osm_mcast_tbl_destroy(IN osm_mcast_tbl_t * p_tbl)
86 {
87 free(p_tbl->p_mask_tbl);
88 }
89
osm_mcast_tbl_set(IN osm_mcast_tbl_t * p_tbl,IN uint16_t mlid_ho,IN uint8_t port)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
osm_mcast_tbl_realloc(IN osm_mcast_tbl_t * p_tbl,IN unsigned mlid_offset)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
osm_mcast_tbl_is_port(IN const osm_mcast_tbl_t * p_tbl,IN uint16_t mlid_ho,IN uint8_t port_num)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
osm_mcast_tbl_is_any_port(IN const osm_mcast_tbl_t * p_tbl,IN uint16_t mlid_ho)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
osm_mcast_tbl_set_block(IN osm_mcast_tbl_t * p_tbl,IN const ib_net16_t * p_block,IN int16_t block_num,IN uint8_t position)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
osm_mcast_tbl_clear_mlid(IN osm_mcast_tbl_t * p_tbl,IN uint16_t mlid_ho)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
osm_mcast_tbl_get_block(IN osm_mcast_tbl_t * p_tbl,IN int16_t block_num,IN uint8_t position,OUT ib_net16_t * p_block)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