]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/ofed/management/opensm/opensm/osm_multicast.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / ofed / management / opensm / opensm / osm_multicast.c
1 /*
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.
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 multicast functions.
39  */
40
41 #if HAVE_CONFIG_H
42 #  include <config.h>
43 #endif                          /* HAVE_CONFIG_H */
44
45 #include <stdlib.h>
46 #include <string.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>
51
52 /**********************************************************************
53  **********************************************************************/
54 void osm_mgrp_delete(IN osm_mgrp_t * const p_mgrp)
55 {
56         osm_mcm_port_t *p_mcm_port;
57         osm_mcm_port_t *p_next_mcm_port;
58
59         CL_ASSERT(p_mgrp);
60
61         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;
66                 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);
69         }
70         /* destroy the mtree_node structure */
71         osm_mtree_destroy(p_mgrp->p_root);
72
73         free(p_mgrp);
74 }
75
76 /**********************************************************************
77  **********************************************************************/
78 osm_mgrp_t *osm_mgrp_new(IN const ib_net16_t mlid)
79 {
80         osm_mgrp_t *p_mgrp;
81
82         p_mgrp = (osm_mgrp_t *) malloc(sizeof(*p_mgrp));
83         if (!p_mgrp)
84                 return NULL;
85
86         memset(p_mgrp, 0, sizeof(*p_mgrp));
87         cl_qmap_init(&p_mgrp->mcm_port_tbl);
88         p_mgrp->mlid = mlid;
89         p_mgrp->last_change_id = 0;
90         p_mgrp->last_tree_id = 0;
91         p_mgrp->to_be_deleted = FALSE;
92
93         return p_mgrp;
94 }
95
96 /**********************************************************************
97  **********************************************************************/
98 static void mgrp_send_notice(osm_subn_t *subn, osm_log_t *log,
99                              osm_mgrp_t *mgrp, unsigned num)
100 {
101         ib_mad_notice_attr_t notice;
102         ib_api_status_t status;
103
104         notice.generic_type = 0x83;     /* generic SubnMgt type */
105         ib_notice_set_prod_type_ho(&notice, 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(&notice.data_details.ntc_64_67.gid,
112                &mgrp->mcmember_rec.mgid, sizeof(ib_gid_t));
113
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;
118
119         if ((status = osm_report_notice(log, subn, &notice)))
120                 OSM_LOG(log, OSM_LOG_ERROR, "ERR 7601: "
121                         "Error sending trap reports (%s)\n",
122                         ib_get_err_str(status));
123 }
124
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)
132 {
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;
137         uint8_t prev_scope;
138
139         p_mcm_port = osm_mcm_port_new(p_port_gid, join_state, proxy_join);
140         if (!p_mcm_port)
141                 return NULL;
142
143         port_guid = p_port_gid->unicast.interface_id;
144
145         /*
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
150            returned.
151          */
152         prev_item = cl_qmap_insert(&p_mgrp->mcm_port_tbl,
153                                    port_guid, &p_mcm_port->map_item);
154
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;
159
160                 /*
161                    o15.0.1.11
162                    Join state of the end port should be the or of the
163                    previous setting with the current one
164                  */
165                 ib_member_get_scope_state(p_mcm_port->scope_state, &prev_scope,
166                                           &prev_join_state);
167                 p_mcm_port->scope_state =
168                     ib_member_set_scope_state(prev_scope,
169                                               prev_join_state | join_state);
170         } else {
171                 /* track the fact we modified the group ports */
172                 p_mgrp->last_change_id++;
173         }
174
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;
180         }
181
182         return (p_mcm_port);
183 }
184
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)
189 {
190         int ret;
191         uint8_t port_join_state;
192         uint8_t new_join_state;
193
194         /*
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
198          */
199         port_join_state = mcm->scope_state & 0x0F;
200         new_join_state = port_join_state & ~join_state;
201
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);
208                 ret = 0;
209         } else {
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++;
216                 ret = 1;
217         }
218
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;
227         }
228
229         return ret;
230 }
231
232 void osm_mgrp_delete_port(osm_subn_t *subn, osm_log_t *log, osm_mgrp_t *mgrp,
233                           ib_net64_t port_guid)
234 {
235         cl_map_item_t *item = cl_qmap_get(&mgrp->mcm_port_tbl, port_guid);
236
237         if (item != cl_qmap_end(&mgrp->mcm_port_tbl))
238                 osm_mgrp_remove_port(subn, log, mgrp, (osm_mcm_port_t *)item, 0xf);
239 }
240
241 /**********************************************************************
242  **********************************************************************/
243 boolean_t
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)
247 {
248         cl_map_item_t *p_map_item;
249
250         CL_ASSERT(p_mgrp);
251
252         p_map_item = cl_qmap_get(&p_mgrp->mcm_port_tbl, port_guid);
253
254         if (p_map_item != cl_qmap_end(&p_mgrp->mcm_port_tbl)) {
255                 if (pp_mcm_port)
256                         *pp_mcm_port = (osm_mcm_port_t *) p_map_item;
257                 return TRUE;
258         }
259         if (pp_mcm_port)
260                 *pp_mcm_port = NULL;
261         return FALSE;
262 }
263
264 /**********************************************************************
265  **********************************************************************/
266 static void
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)
270 {
271         uint8_t i = 0;
272         uint8_t max_children;
273         osm_mtree_node_t *p_child_mtn;
274
275         /* Call the user, then recurse. */
276         p_func(p_mgrp, p_mtn, context);
277
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);
281                 if (p_child_mtn)
282                         __osm_mgrp_apply_func_sub(p_mgrp, p_child_mtn, p_func,
283                                                   context);
284         }
285 }
286
287 /**********************************************************************
288  **********************************************************************/
289 void
290 osm_mgrp_apply_func(const osm_mgrp_t * const p_mgrp,
291                     osm_mgrp_func_t p_func, void *context)
292 {
293         osm_mtree_node_t *p_mtn;
294
295         CL_ASSERT(p_mgrp);
296         CL_ASSERT(p_func);
297
298         p_mtn = p_mgrp->p_root;
299
300         if (p_mtn)
301                 __osm_mgrp_apply_func_sub(p_mgrp, p_mtn, p_func, context);
302 }