1 /*
2  * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved.
3  * Copyright (c) 2002-2015 Mellanox Technologies LTD. All rights reserved.
4  * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
5  * Copyright (c) 2013 Oracle and/or its affiliates. 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 multicast functions.
40  */
41 
42 #if HAVE_CONFIG_H
43 #  include <config.h>
44 #endif				/* HAVE_CONFIG_H */
45 
46 #include <stdlib.h>
47 #include <string.h>
48 #include <arpa/inet.h>
49 #include <sys/socket.h>
50 #include <opensm/osm_file_ids.h>
51 #define FILE_ID OSM_FILE_MULTICAST_C
52 #include <opensm/osm_multicast.h>
53 #include <opensm/osm_mcm_port.h>
54 #include <opensm/osm_mtree.h>
55 #include <opensm/osm_inform.h>
56 #include <opensm/osm_opensm.h>
57 
mgrp_box_new(uint16_t mlid)58 static osm_mgrp_box_t *mgrp_box_new(uint16_t mlid)
59 {
60 	osm_mgrp_box_t *mbox = malloc(sizeof(*mbox));
61 	if (!mbox)
62 		return NULL;
63 
64 	memset(mbox, 0, sizeof(*mbox));
65 	mbox->mlid = mlid;
66 	cl_qlist_init(&mbox->mgrp_list);
67 
68 	return mbox;
69 }
70 
mgrp_box_delete(osm_mgrp_box_t * mbox)71 void mgrp_box_delete(osm_mgrp_box_t *mbox)
72 {
73 	osm_mtree_destroy(mbox->root);
74 	free(mbox);
75 }
76 
mgrp_delete(IN osm_mgrp_t * p_mgrp)77 void mgrp_delete(IN osm_mgrp_t * p_mgrp)
78 {
79 	osm_mcm_alias_guid_t *p_mcm_alias_guid, *p_next_mcm_alias_guid;
80 	osm_mcm_port_t *p_mcm_port, *p_next_mcm_port;
81 
82 	CL_ASSERT(p_mgrp);
83 
84 	p_next_mcm_alias_guid =
85 	    (osm_mcm_alias_guid_t *) cl_qmap_head(&p_mgrp->mcm_alias_port_tbl);
86 	while (p_next_mcm_alias_guid !=
87 	       (osm_mcm_alias_guid_t *) cl_qmap_end(&p_mgrp->mcm_alias_port_tbl)) {
88 		p_mcm_alias_guid = p_next_mcm_alias_guid;
89 		p_next_mcm_alias_guid =
90 		    (osm_mcm_alias_guid_t *) cl_qmap_next(&p_mcm_alias_guid->map_item);
91 		osm_mcm_alias_guid_delete(&p_mcm_alias_guid);
92 	}
93 
94 	p_next_mcm_port =
95 	    (osm_mcm_port_t *) cl_qmap_head(&p_mgrp->mcm_port_tbl);
96 	while (p_next_mcm_port !=
97 	       (osm_mcm_port_t *) cl_qmap_end(&p_mgrp->mcm_port_tbl)) {
98 		p_mcm_port = p_next_mcm_port;
99 		p_next_mcm_port =
100 		    (osm_mcm_port_t *) cl_qmap_next(&p_mcm_port->map_item);
101 		osm_mcm_port_delete(p_mcm_port);
102 	}
103 
104 	free(p_mgrp);
105 }
106 
osm_mgrp_box_delete(osm_mgrp_box_t * mbox)107 void osm_mgrp_box_delete(osm_mgrp_box_t *mbox)
108 {
109 	osm_mgrp_t *mgrp;
110 
111 	while (cl_qlist_count(&mbox->mgrp_list)) {
112 		mgrp = cl_item_obj(cl_qlist_remove_head(&mbox->mgrp_list),
113 				   mgrp, list_item);
114 		mgrp_delete(mgrp);
115 	}
116 	mgrp_box_delete(mbox);
117 }
118 
osm_mgrp_new(IN osm_subn_t * subn,IN ib_net16_t mlid,IN ib_member_rec_t * mcmr)119 osm_mgrp_t *osm_mgrp_new(IN osm_subn_t * subn, IN ib_net16_t mlid,
120 			 IN ib_member_rec_t * mcmr)
121 {
122 	osm_mgrp_t *p_mgrp;
123 	osm_mgrp_box_t *mbox;
124 
125 	p_mgrp = (osm_mgrp_t *) malloc(sizeof(*p_mgrp));
126 	if (!p_mgrp)
127 		return NULL;
128 
129 	memset(p_mgrp, 0, sizeof(*p_mgrp));
130 	cl_qmap_init(&p_mgrp->mcm_port_tbl);
131 	cl_qmap_init(&p_mgrp->mcm_alias_port_tbl);
132 	p_mgrp->mlid = mlid;
133 	p_mgrp->mcmember_rec = *mcmr;
134 
135 	mbox = osm_get_mbox_by_mlid(subn, p_mgrp->mlid);
136 	if (!mbox && !(mbox = mgrp_box_new(cl_ntoh16(p_mgrp->mlid)))) {
137 		free(p_mgrp);
138 		return NULL;
139 	}
140 
141 	cl_qlist_insert_tail(&mbox->mgrp_list, &p_mgrp->list_item);
142 	subn->mboxes[mbox->mlid - IB_LID_MCAST_START_HO] = mbox;
143 
144 	cl_fmap_insert(&subn->mgrp_mgid_tbl, &p_mgrp->mcmember_rec.mgid,
145 		       &p_mgrp->map_item);
146 
147 	subn->p_osm->sa.dirty = TRUE;
148 	return p_mgrp;
149 }
150 
osm_mgrp_cleanup(osm_subn_t * subn,osm_mgrp_t * mgrp)151 void osm_mgrp_cleanup(osm_subn_t * subn, osm_mgrp_t * mgrp)
152 {
153 	osm_mgrp_box_t *mbox;
154 	osm_mcm_alias_guid_t *mcm_alias_guid;
155 	osm_mcm_port_t *mcm_port;
156 
157 	if (mgrp->full_members)
158 		return;
159 
160 	while (cl_qmap_count(&mgrp->mcm_alias_port_tbl)) {
161 		mcm_alias_guid = (osm_mcm_alias_guid_t *) cl_qmap_head(&mgrp->mcm_alias_port_tbl);
162 		cl_qmap_remove_item(&mgrp->mcm_alias_port_tbl, &mcm_alias_guid->map_item);
163 		osm_mcm_alias_guid_delete(&mcm_alias_guid);
164 	}
165 
166 	while (cl_qmap_count(&mgrp->mcm_port_tbl)) {
167 		mcm_port = (osm_mcm_port_t *) cl_qmap_head(&mgrp->mcm_port_tbl);
168 		cl_qmap_remove_item(&mgrp->mcm_port_tbl, &mcm_port->map_item);
169 		cl_qlist_remove_item(&mcm_port->port->mcm_list,
170 				     &mcm_port->list_item);
171 		osm_mcm_port_delete(mcm_port);
172 	}
173 
174 	if (mgrp->well_known)
175 		return;
176 
177 	cl_fmap_remove_item(&subn->mgrp_mgid_tbl, &mgrp->map_item);
178 
179 	mbox = osm_get_mbox_by_mlid(subn, mgrp->mlid);
180 	cl_qlist_remove_item(&mbox->mgrp_list, &mgrp->list_item);
181 	if (cl_is_qlist_empty(&mbox->mgrp_list)) {
182 		subn->mboxes[cl_ntoh16(mgrp->mlid) - IB_LID_MCAST_START_HO] = NULL;
183 		mgrp_box_delete(mbox);
184 	}
185 	free(mgrp);
186 
187 	subn->p_osm->sa.dirty = TRUE;
188 }
189 
mgrp_send_notice(osm_subn_t * subn,osm_log_t * log,osm_mgrp_t * mgrp,unsigned num)190 static void mgrp_send_notice(osm_subn_t * subn, osm_log_t * log,
191 			     osm_mgrp_t * mgrp, unsigned num)
192 {
193 	ib_mad_notice_attr_t notice;
194 	ib_api_status_t status;
195 
196 	notice.generic_type = 0x80 | IB_NOTICE_TYPE_SUBN_MGMT;	/* is generic subn mgt type */
197 	ib_notice_set_prod_type_ho(&notice, 4);	/* A Class Manager generator */
198 	notice.g_or_v.generic.trap_num = CL_HTON16(num);
199 	/* The sm_base_lid is saved in network order already. */
200 	notice.issuer_lid = subn->sm_base_lid;
201 	/* following o14-12.1.11 and table 120 p726 */
202 	/* we need to provide the MGID */
203 	memcpy(&notice.data_details.ntc_64_67.gid,
204 	       &mgrp->mcmember_rec.mgid, sizeof(ib_gid_t));
205 
206 	/* According to page 653 - the issuer gid in this case of trap
207 	   is the SM gid, since the SM is the initiator of this trap. */
208 	notice.issuer_gid.unicast.prefix = subn->opt.subnet_prefix;
209 	notice.issuer_gid.unicast.interface_id = subn->sm_port_guid;
210 
211 	if ((status = osm_report_notice(log, subn, &notice)))
212 		OSM_LOG(log, OSM_LOG_ERROR, "ERR 7601: "
213 			"Error sending trap reports (%s)\n",
214 			ib_get_err_str(status));
215 }
216 
is_qmap_empty_for_port(IN const cl_qmap_t * const p_map,IN const osm_port_t * port)217 static boolean_t is_qmap_empty_for_port(IN const cl_qmap_t * const p_map,
218 					IN const osm_port_t *port)
219 {
220 	size_t count = 0;
221 	cl_map_item_t *item;
222 	osm_mcm_alias_guid_t *mcm_alias_guid;
223 
224 	for (item = cl_qmap_head(p_map); item != cl_qmap_end(p_map);
225 	     item = cl_qmap_next(item)) {
226 		mcm_alias_guid = (osm_mcm_alias_guid_t *) item;
227 		if (mcm_alias_guid->p_base_mcm_port->port == port) {
228 			count++;
229 			break;
230 		}
231 	}
232 
233 	return (count == 0);
234 }
235 
is_qmap_empty_for_mcm_port(IN const cl_qmap_t * const p_map,IN const osm_mcm_port_t * mcm_port)236 static boolean_t is_qmap_empty_for_mcm_port(IN const cl_qmap_t * const p_map,
237 					    IN const osm_mcm_port_t *mcm_port)
238 {
239 	size_t count = 0;
240 	cl_map_item_t *item;
241 	osm_mcm_alias_guid_t *mcm_alias_guid;
242 
243 	for (item = cl_qmap_head(p_map); item != cl_qmap_end(p_map);
244 	     item = cl_qmap_next(item)) {
245 		mcm_alias_guid = (osm_mcm_alias_guid_t *) item;
246 		if (mcm_alias_guid->p_base_mcm_port == mcm_port) {
247 			count++;
248 			break;
249 		}
250 	}
251 
252 	return (count == 0);
253 }
insert_alias_guid(IN osm_mgrp_t * mgrp,IN osm_mcm_alias_guid_t * p_mcm_alias_guid)254 static osm_mcm_alias_guid_t *insert_alias_guid(IN osm_mgrp_t * mgrp,
255 					       IN osm_mcm_alias_guid_t * p_mcm_alias_guid)
256 {
257 	osm_mcm_alias_guid_t *p_mcm_alias_guid_check;
258 
259 	/* insert into mcm alias guid table */
260 	p_mcm_alias_guid_check =
261 		(osm_mcm_alias_guid_t *) cl_qmap_insert(&mgrp->mcm_alias_port_tbl,
262 							p_mcm_alias_guid->alias_guid,
263 							&p_mcm_alias_guid->map_item);
264 	if (p_mcm_alias_guid_check != (osm_mcm_alias_guid_t *) &p_mcm_alias_guid->map_item) {
265 		/* alias GUID is a duplicate */
266 		osm_mcm_alias_guid_delete(&p_mcm_alias_guid);
267 		return p_mcm_alias_guid_check;
268 	}
269 	return NULL;
270 }
271 
osm_mgrp_add_port(IN osm_subn_t * subn,osm_log_t * log,IN osm_mgrp_t * mgrp,osm_port_t * port,IN ib_member_rec_t * mcmr,IN boolean_t proxy)272 osm_mcm_port_t *osm_mgrp_add_port(IN osm_subn_t * subn, osm_log_t * log,
273 				  IN osm_mgrp_t * mgrp, osm_port_t *port,
274 				  IN ib_member_rec_t *mcmr, IN boolean_t proxy)
275 {
276 	osm_mcm_port_t *mcm_port;
277 	osm_mcm_alias_guid_t *p_mcm_alias_guid, *p_mcm_alias_guid_check;
278 	cl_map_item_t *prev_item;
279 	uint8_t prev_join_state = 0, join_state = mcmr->scope_state;
280 	uint8_t prev_scope;
281 
282 	if (OSM_LOG_IS_ACTIVE_V2(log, OSM_LOG_VERBOSE)) {
283 		char gid_str[INET6_ADDRSTRLEN];
284 		OSM_LOG(log, OSM_LOG_VERBOSE, "GUID 0x%016" PRIx64
285 			" Port 0x%016" PRIx64 " joining "
286 			"MC group %s (mlid 0x%x)\n",
287 			cl_ntoh64(mcmr->port_gid.unicast.interface_id),
288 			cl_ntoh64(port->guid),
289 			inet_ntop(AF_INET6, mgrp->mcmember_rec.mgid.raw,
290 				  gid_str, sizeof(gid_str)),
291 			cl_ntoh16(mgrp->mlid));
292 	}
293 
294 	mcm_port = osm_mcm_port_new(port, mgrp);
295 	if (!mcm_port)
296 		return NULL;
297 
298 	p_mcm_alias_guid = osm_mcm_alias_guid_new(mcm_port, mcmr, proxy);
299 	if (!p_mcm_alias_guid) {
300 		osm_mcm_port_delete(mcm_port);
301 		return NULL;
302 	}
303 
304 	/*
305 	   prev_item = cl_qmap_insert(...)
306 	   Pointer to the item in the map with the specified key.  If insertion
307 	   was successful, this is the pointer to the item.  If an item with the
308 	   specified key already exists in the map, the pointer to that item is
309 	   returned.
310 	 */
311 	prev_item = cl_qmap_insert(&mgrp->mcm_port_tbl, port->guid,
312 				   &mcm_port->map_item);
313 
314 	if (prev_item != &mcm_port->map_item) {	/* mcm port already exists */
315 		osm_mcm_port_delete(mcm_port);
316 		mcm_port = (osm_mcm_port_t *) prev_item;
317 
318 		p_mcm_alias_guid->p_base_mcm_port = (osm_mcm_port_t *) prev_item;
319 		p_mcm_alias_guid_check = insert_alias_guid(mgrp, p_mcm_alias_guid);
320 		if (p_mcm_alias_guid_check) {	/* alias GUID already exists */
321 			p_mcm_alias_guid = p_mcm_alias_guid_check;
322 			ib_member_get_scope_state(p_mcm_alias_guid->scope_state,
323 						  &prev_scope, &prev_join_state);
324 			p_mcm_alias_guid->scope_state =
325 			    ib_member_set_scope_state(prev_scope,
326 						      prev_join_state | join_state);
327 		}
328 	} else {
329 		insert_alias_guid(mgrp, p_mcm_alias_guid);
330 		cl_qlist_insert_tail(&port->mcm_list, &mcm_port->list_item);
331 		osm_sm_reroute_mlid(&subn->p_osm->sm, mgrp->mlid);
332 	}
333 
334 	/* o15.0.1.11: copy the join state */
335 	mcmr->scope_state = p_mcm_alias_guid->scope_state;
336 
337 	if ((join_state & IB_JOIN_STATE_FULL) &&
338 	    !(prev_join_state & IB_JOIN_STATE_FULL) &&
339 	    ++mgrp->full_members == 1)
340 		mgrp_send_notice(subn, log, mgrp, SM_MGID_CREATED_TRAP); /* 66 */
341 
342 	subn->p_osm->sa.dirty = TRUE;
343 	return mcm_port;
344 }
345 
osm_mgrp_remove_port(osm_subn_t * subn,osm_log_t * log,osm_mgrp_t * mgrp,osm_mcm_alias_guid_t * mcm_alias_guid,ib_member_rec_t * mcmr)346 boolean_t osm_mgrp_remove_port(osm_subn_t * subn, osm_log_t * log, osm_mgrp_t * mgrp,
347 			  osm_mcm_alias_guid_t * mcm_alias_guid,
348 			  ib_member_rec_t *mcmr)
349 {
350 	uint8_t join_state = mcmr->scope_state & 0xf;
351 	uint8_t port_join_state, new_join_state;
352 	boolean_t mgrp_deleted = FALSE;
353 
354 	/*
355 	 * according to the same o15-0.1.14 we get the stored
356 	 * JoinState and the request JoinState and they must be
357 	 * opposite to leave - otherwise just update it
358 	 */
359 	port_join_state = mcm_alias_guid->scope_state & 0x0F;
360 	new_join_state = port_join_state & ~join_state;
361 
362 	if (OSM_LOG_IS_ACTIVE_V2(log, OSM_LOG_VERBOSE)) {
363 		char gid_str[INET6_ADDRSTRLEN];
364 		OSM_LOG(log, OSM_LOG_VERBOSE,
365 			"GUID 0x%" PRIx64 " Port 0x%" PRIx64
366 			" leaving MC group %s (mlid 0x%x)\n",
367 			cl_ntoh64(mcm_alias_guid->alias_guid),
368 			cl_ntoh64(mcm_alias_guid->p_base_mcm_port->port->guid),
369 			inet_ntop(AF_INET6, mgrp->mcmember_rec.mgid.raw,
370 				  gid_str, sizeof(gid_str)),
371 			cl_ntoh16(mgrp->mlid));
372 	}
373 
374 	if (new_join_state & IB_JOIN_STATE_FULL ||
375 	    (new_join_state &&
376 	     (mgrp->full_members > (port_join_state & IB_JOIN_STATE_FULL) ? 1 : 0))) {
377 		mcm_alias_guid->scope_state =
378 		    new_join_state | (mcm_alias_guid->scope_state & 0xf0);
379 		OSM_LOG(log, OSM_LOG_DEBUG,
380 			"updating GUID 0x%" PRIx64 " port 0x%" PRIx64
381 			" JoinState 0x%x -> 0x%x\n",
382 			cl_ntoh64(mcm_alias_guid->alias_guid),
383 			cl_ntoh64(mcm_alias_guid->p_base_mcm_port->port->guid),
384 			port_join_state, new_join_state);
385 		mcmr->scope_state = mcm_alias_guid->scope_state;
386 	} else {
387 		mcmr->scope_state = mcm_alias_guid->scope_state & 0xf0;
388 		OSM_LOG(log, OSM_LOG_DEBUG, "removing alias GUID 0x%" PRIx64 "\n",
389 			cl_ntoh64(mcm_alias_guid->alias_guid));
390 		cl_qmap_remove_item(&mgrp->mcm_alias_port_tbl,
391 				    &mcm_alias_guid->map_item);
392 		if (is_qmap_empty_for_port(&mgrp->mcm_alias_port_tbl,
393 					   mcm_alias_guid->p_base_mcm_port->port)) { /* last alias in mcast group for this port */
394 			OSM_LOG(log, OSM_LOG_DEBUG, "removing port 0x%" PRIx64 "\n",
395 				cl_ntoh64(mcm_alias_guid->p_base_mcm_port->port->guid));
396 			cl_qmap_remove_item(&mgrp->mcm_port_tbl,
397 					    &mcm_alias_guid->p_base_mcm_port->map_item);
398 			cl_qlist_remove_item(&mcm_alias_guid->p_base_mcm_port->port->mcm_list,
399 					     &mcm_alias_guid->p_base_mcm_port->list_item);
400 			if (is_qmap_empty_for_mcm_port(&mgrp->mcm_alias_port_tbl,
401 						       mcm_alias_guid->p_base_mcm_port)) /* last alias in mcast group for this mcm port */
402 				osm_mcm_port_delete(mcm_alias_guid->p_base_mcm_port);
403 			osm_sm_reroute_mlid(&subn->p_osm->sm, mgrp->mlid);
404 		}
405 		osm_mcm_alias_guid_delete(&mcm_alias_guid);
406 	}
407 
408 	/* no more full members so the group will be deleted after re-route
409 	   but only if it is not a well known group */
410 	if ((port_join_state & IB_JOIN_STATE_FULL) &&
411 	    !(new_join_state & IB_JOIN_STATE_FULL) &&
412 	    --mgrp->full_members == 0) {
413 		mgrp_send_notice(subn, log, mgrp, SM_MGID_DESTROYED_TRAP); /* 67 */
414 		osm_mgrp_cleanup(subn, mgrp);
415 		mgrp_deleted = TRUE;
416 	}
417 
418 	subn->p_osm->sa.dirty = TRUE;
419 
420 	return (mgrp_deleted);
421 }
422 
osm_mgrp_delete_port(osm_subn_t * subn,osm_log_t * log,osm_mgrp_t * mgrp,osm_port_t * port)423 void osm_mgrp_delete_port(osm_subn_t * subn, osm_log_t * log, osm_mgrp_t * mgrp,
424 			  osm_port_t * port)
425 {
426 	osm_mcm_alias_guid_t *mcm_alias_guid, *next_mcm_alias_guid;
427 	ib_member_rec_t mcmrec;
428 	boolean_t mgrp_deleted = FALSE;
429 
430 	next_mcm_alias_guid = (osm_mcm_alias_guid_t *) cl_qmap_head(&mgrp->mcm_alias_port_tbl);
431 	while (next_mcm_alias_guid != (osm_mcm_alias_guid_t *) cl_qmap_end(&mgrp->mcm_alias_port_tbl) &&
432 	      !mgrp_deleted) {
433 		mcm_alias_guid = next_mcm_alias_guid;
434 		next_mcm_alias_guid = (osm_mcm_alias_guid_t *) cl_qmap_next(&next_mcm_alias_guid->map_item);
435 		if (mcm_alias_guid->p_base_mcm_port->port == port) {
436 			mcmrec.scope_state = 0xf;
437 			mgrp_deleted = osm_mgrp_remove_port(subn, log, mgrp, mcm_alias_guid,
438 					     &mcmrec);
439 		}
440 	}
441 }
442 
osm_mgrp_get_mcm_port(IN const osm_mgrp_t * p_mgrp,IN ib_net64_t port_guid)443 osm_mcm_port_t *osm_mgrp_get_mcm_port(IN const osm_mgrp_t * p_mgrp,
444 				      IN ib_net64_t port_guid)
445 {
446 	cl_map_item_t *item = cl_qmap_get(&p_mgrp->mcm_port_tbl, port_guid);
447 	if (item != cl_qmap_end(&p_mgrp->mcm_port_tbl))
448 		return (osm_mcm_port_t *) item;
449 	return NULL;
450 }
451 
osm_mgrp_get_mcm_alias_guid(IN const osm_mgrp_t * p_mgrp,IN ib_net64_t port_guid)452 osm_mcm_alias_guid_t *osm_mgrp_get_mcm_alias_guid(IN const osm_mgrp_t * p_mgrp,
453 						  IN ib_net64_t port_guid)
454 {
455 	cl_map_item_t *item = cl_qmap_get(&p_mgrp->mcm_alias_port_tbl,
456 					  port_guid);
457 	if (item != cl_qmap_end(&p_mgrp->mcm_alias_port_tbl))
458 		return (osm_mcm_alias_guid_t *) item;
459 	return NULL;
460 }
461