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