osm_mcast_tbl.c revision 321936
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
56void 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
85void osm_mcast_tbl_destroy(IN osm_mcast_tbl_t * p_tbl)
86{
87	free(p_tbl->p_mask_tbl);
88}
89
90void 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
111int 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;
139done:
140	p_tbl->max_mlid_ho = mlid_offset + IB_LID_MCAST_START_HO;
141	return 0;
142}
143
144boolean_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
169boolean_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
191ib_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
222void 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
236boolean_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