2 * Copyright (c) 2004-2008 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.
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:
12 * Redistribution and use in source and binary forms, with or
13 * without modification, are permitted provided that the following
16 * - Redistributions of source code must retain the above
17 * copyright notice, this list of conditions and the following
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.
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
38 * Implementation of multicast functions.
43 #endif /* HAVE_CONFIG_H */
47 #include <opensm/osm_multicast.h>
48 #include <opensm/osm_mcm_port.h>
49 #include <opensm/osm_mtree.h>
50 #include <opensm/osm_inform.h>
52 /**********************************************************************
53 **********************************************************************/
54 void osm_mgrp_delete(IN osm_mgrp_t * const p_mgrp)
56 osm_mcm_port_t *p_mcm_port;
57 osm_mcm_port_t *p_next_mcm_port;
62 (osm_mcm_port_t *) cl_qmap_head(&p_mgrp->mcm_port_tbl);
63 while (p_next_mcm_port !=
64 (osm_mcm_port_t *) cl_qmap_end(&p_mgrp->mcm_port_tbl)) {
65 p_mcm_port = p_next_mcm_port;
67 (osm_mcm_port_t *) cl_qmap_next(&p_mcm_port->map_item);
68 osm_mcm_port_delete(p_mcm_port);
70 /* destroy the mtree_node structure */
71 osm_mtree_destroy(p_mgrp->p_root);
76 /**********************************************************************
77 **********************************************************************/
78 osm_mgrp_t *osm_mgrp_new(IN const ib_net16_t mlid)
82 p_mgrp = (osm_mgrp_t *) malloc(sizeof(*p_mgrp));
86 memset(p_mgrp, 0, sizeof(*p_mgrp));
87 cl_qmap_init(&p_mgrp->mcm_port_tbl);
89 p_mgrp->last_change_id = 0;
90 p_mgrp->last_tree_id = 0;
91 p_mgrp->to_be_deleted = FALSE;
96 /**********************************************************************
97 **********************************************************************/
98 static void mgrp_send_notice(osm_subn_t *subn, osm_log_t *log,
99 osm_mgrp_t *mgrp, unsigned num)
101 ib_mad_notice_attr_t notice;
102 ib_api_status_t status;
104 notice.generic_type = 0x83; /* generic SubnMgt type */
105 ib_notice_set_prod_type_ho(¬ice, 4); /* A Class Manager generator */
106 notice.g_or_v.generic.trap_num = CL_HTON16(num);
107 /* The sm_base_lid is saved in network order already. */
108 notice.issuer_lid = subn->sm_base_lid;
109 /* following o14-12.1.11 and table 120 p726 */
110 /* we need to provide the MGID */
111 memcpy(¬ice.data_details.ntc_64_67.gid,
112 &mgrp->mcmember_rec.mgid, sizeof(ib_gid_t));
114 /* According to page 653 - the issuer gid in this case of trap
115 is the SM gid, since the SM is the initiator of this trap. */
116 notice.issuer_gid.unicast.prefix = subn->opt.subnet_prefix;
117 notice.issuer_gid.unicast.interface_id = subn->sm_port_guid;
119 if ((status = osm_report_notice(log, subn, ¬ice)))
120 OSM_LOG(log, OSM_LOG_ERROR, "ERR 7601: "
121 "Error sending trap reports (%s)\n",
122 ib_get_err_str(status));
125 /**********************************************************************
126 **********************************************************************/
127 osm_mcm_port_t *osm_mgrp_add_port(IN osm_subn_t *subn, osm_log_t *log,
128 IN osm_mgrp_t * const p_mgrp,
129 IN const ib_gid_t * const p_port_gid,
130 IN const uint8_t join_state,
131 IN boolean_t proxy_join)
133 ib_net64_t port_guid;
134 osm_mcm_port_t *p_mcm_port;
135 cl_map_item_t *prev_item;
136 uint8_t prev_join_state = 0;
139 p_mcm_port = osm_mcm_port_new(p_port_gid, join_state, proxy_join);
143 port_guid = p_port_gid->unicast.interface_id;
146 prev_item = cl_qmap_insert(...)
147 Pointer to the item in the map with the specified key. If insertion
148 was successful, this is the pointer to the item. If an item with the
149 specified key already exists in the map, the pointer to that item is
152 prev_item = cl_qmap_insert(&p_mgrp->mcm_port_tbl,
153 port_guid, &p_mcm_port->map_item);
155 /* if already exists - revert the insertion and only update join state */
156 if (prev_item != &p_mcm_port->map_item) {
157 osm_mcm_port_delete(p_mcm_port);
158 p_mcm_port = (osm_mcm_port_t *) prev_item;
162 Join state of the end port should be the or of the
163 previous setting with the current one
165 ib_member_get_scope_state(p_mcm_port->scope_state, &prev_scope,
167 p_mcm_port->scope_state =
168 ib_member_set_scope_state(prev_scope,
169 prev_join_state | join_state);
171 /* track the fact we modified the group ports */
172 p_mgrp->last_change_id++;
175 if ((join_state & IB_JOIN_STATE_FULL) &&
176 !(prev_join_state & IB_JOIN_STATE_FULL) &&
177 (++p_mgrp->full_members == 1)) {
178 mgrp_send_notice(subn, log, p_mgrp, 66);
179 p_mgrp->to_be_deleted = 0;
185 /**********************************************************************
186 **********************************************************************/
187 int osm_mgrp_remove_port(osm_subn_t *subn, osm_log_t *log, osm_mgrp_t *mgrp,
188 osm_mcm_port_t *mcm, uint8_t join_state)
191 uint8_t port_join_state;
192 uint8_t new_join_state;
195 * according to the same o15-0.1.14 we get the stored
196 * JoinState and the request JoinState and they must be
197 * opposite to leave - otherwise just update it
199 port_join_state = mcm->scope_state & 0x0F;
200 new_join_state = port_join_state & ~join_state;
202 if (new_join_state) {
203 mcm->scope_state = new_join_state | (mcm->scope_state & 0xf0);
204 OSM_LOG(log, OSM_LOG_DEBUG,
205 "updating port 0x%" PRIx64 " JoinState 0x%x -> 0x%x\n",
206 cl_ntoh64(mcm->port_gid.unicast.interface_id),
207 port_join_state, new_join_state);
210 cl_qmap_remove_item(&mgrp->mcm_port_tbl, &mcm->map_item);
211 OSM_LOG(log, OSM_LOG_DEBUG, "removing port 0x%" PRIx64 "\n",
212 cl_ntoh64(mcm->port_gid.unicast.interface_id));
213 osm_mcm_port_delete(mcm);
214 /* track the fact we modified the group */
215 mgrp->last_change_id++;
219 /* no more full members so the group will be deleted after re-route
220 but only if it is not a well known group */
221 if ((port_join_state & IB_JOIN_STATE_FULL) &&
222 !(new_join_state & IB_JOIN_STATE_FULL) &&
223 (--mgrp->full_members == 0)) {
224 mgrp_send_notice(subn, log, mgrp, 67);
225 if (!mgrp->well_known)
226 mgrp->to_be_deleted = 1;
232 void osm_mgrp_delete_port(osm_subn_t *subn, osm_log_t *log, osm_mgrp_t *mgrp,
233 ib_net64_t port_guid)
235 cl_map_item_t *item = cl_qmap_get(&mgrp->mcm_port_tbl, port_guid);
237 if (item != cl_qmap_end(&mgrp->mcm_port_tbl))
238 osm_mgrp_remove_port(subn, log, mgrp, (osm_mcm_port_t *)item, 0xf);
241 /**********************************************************************
242 **********************************************************************/
244 osm_mgrp_is_port_present(IN const osm_mgrp_t * const p_mgrp,
245 IN const ib_net64_t port_guid,
246 OUT osm_mcm_port_t ** const pp_mcm_port)
248 cl_map_item_t *p_map_item;
252 p_map_item = cl_qmap_get(&p_mgrp->mcm_port_tbl, port_guid);
254 if (p_map_item != cl_qmap_end(&p_mgrp->mcm_port_tbl)) {
256 *pp_mcm_port = (osm_mcm_port_t *) p_map_item;
264 /**********************************************************************
265 **********************************************************************/
267 __osm_mgrp_apply_func_sub(const osm_mgrp_t * const p_mgrp,
268 const osm_mtree_node_t * const p_mtn,
269 osm_mgrp_func_t p_func, void *context)
272 uint8_t max_children;
273 osm_mtree_node_t *p_child_mtn;
275 /* Call the user, then recurse. */
276 p_func(p_mgrp, p_mtn, context);
278 max_children = osm_mtree_node_get_max_children(p_mtn);
279 for (i = 0; i < max_children; i++) {
280 p_child_mtn = osm_mtree_node_get_child(p_mtn, i);
282 __osm_mgrp_apply_func_sub(p_mgrp, p_child_mtn, p_func,
287 /**********************************************************************
288 **********************************************************************/
290 osm_mgrp_apply_func(const osm_mgrp_t * const p_mgrp,
291 osm_mgrp_func_t p_func, void *context)
293 osm_mtree_node_t *p_mtn;
298 p_mtn = p_mgrp->p_root;
301 __osm_mgrp_apply_func_sub(p_mgrp, p_mtn, p_func, context);